OLD | NEW |
| (Empty) |
1 // Copyright 2017 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "net/spdy/hpack/hpack_decoder3.h" | |
6 | |
7 #include "base/logging.h" | |
8 #include "net/http2/decoder/decode_buffer.h" | |
9 #include "net/http2/decoder/decode_status.h" | |
10 #include "net/spdy/platform/api/spdy_estimate_memory_usage.h" | |
11 #include "net/spdy/spdy_flags.h" | |
12 | |
13 namespace net { | |
14 namespace { | |
15 const size_t kMaxDecodeBufferSizeBytes = 32 * 1024; // 32 KB | |
16 } // namespace | |
17 | |
18 HpackDecoder3::HpackDecoder3() | |
19 : hpack_decoder_(&listener_adapter_, kMaxDecodeBufferSizeBytes), | |
20 max_decode_buffer_size_bytes_(kMaxDecodeBufferSizeBytes), | |
21 header_block_started_(false) {} | |
22 | |
23 HpackDecoder3::~HpackDecoder3() {} | |
24 | |
25 void HpackDecoder3::ApplyHeaderTableSizeSetting(size_t size_setting) { | |
26 DVLOG(2) << "HpackDecoder3::ApplyHeaderTableSizeSetting"; | |
27 hpack_decoder_.ApplyHeaderTableSizeSetting(size_setting); | |
28 } | |
29 | |
30 void HpackDecoder3::HandleControlFrameHeadersStart( | |
31 SpdyHeadersHandlerInterface* handler) { | |
32 DVLOG(2) << "HpackDecoder3::HandleControlFrameHeadersStart"; | |
33 DCHECK(!header_block_started_); | |
34 listener_adapter_.set_handler(handler); | |
35 } | |
36 | |
37 bool HpackDecoder3::HandleControlFrameHeadersData(const char* headers_data, | |
38 size_t headers_data_length) { | |
39 DVLOG(2) << "HpackDecoder3::HandleControlFrameHeadersData: len=" | |
40 << headers_data_length; | |
41 if (!header_block_started_) { | |
42 // Initialize the decoding process here rather than in | |
43 // HandleControlFrameHeadersStart because that method is not always called. | |
44 header_block_started_ = true; | |
45 if (!hpack_decoder_.StartDecodingBlock()) { | |
46 header_block_started_ = false; | |
47 return false; | |
48 } | |
49 } | |
50 | |
51 // Sometimes we get a call with headers_data==nullptr and | |
52 // headers_data_length==0, in which case we need to avoid creating | |
53 // a DecodeBuffer, which would otherwise complain. | |
54 if (headers_data_length > 0) { | |
55 DCHECK_NE(headers_data, nullptr); | |
56 if (headers_data_length > max_decode_buffer_size_bytes_) { | |
57 DVLOG(1) << "max_decode_buffer_size_bytes_ < headers_data_length: " | |
58 << max_decode_buffer_size_bytes_ << " < " << headers_data_length; | |
59 return false; | |
60 } | |
61 listener_adapter_.AddToTotalHpackBytes(headers_data_length); | |
62 DecodeBuffer db(headers_data, headers_data_length); | |
63 bool ok = hpack_decoder_.DecodeFragment(&db); | |
64 DCHECK(!ok || db.Empty()) << "Remaining=" << db.Remaining(); | |
65 return ok; | |
66 } | |
67 return true; | |
68 } | |
69 | |
70 // TODO(jamessynge): Determine if compressed_len is needed; it is used to | |
71 // produce UUMA stat Net.SpdyHpackDecompressionPercentage, but only for | |
72 // SPDY3, not HTTP2. | |
73 bool HpackDecoder3::HandleControlFrameHeadersComplete(size_t* compressed_len) { | |
74 DVLOG(2) << "HpackDecoder3::HandleControlFrameHeadersComplete"; | |
75 if (compressed_len != nullptr) { | |
76 *compressed_len = listener_adapter_.total_hpack_bytes(); | |
77 } | |
78 if (!hpack_decoder_.EndDecodingBlock()) { | |
79 DVLOG(3) << "EndDecodingBlock returned false"; | |
80 return false; | |
81 } | |
82 header_block_started_ = false; | |
83 return true; | |
84 } | |
85 | |
86 const SpdyHeaderBlock& HpackDecoder3::decoded_block() const { | |
87 return listener_adapter_.decoded_block(); | |
88 } | |
89 | |
90 void HpackDecoder3::SetHeaderTableDebugVisitor( | |
91 std::unique_ptr<HpackHeaderTable::DebugVisitorInterface> visitor) { | |
92 DVLOG(2) << "HpackDecoder3::SetHeaderTableDebugVisitor"; | |
93 if (visitor != nullptr) { | |
94 listener_adapter_.SetHeaderTableDebugVisitor(std::move(visitor)); | |
95 hpack_decoder_.set_tables_debug_listener(&listener_adapter_); | |
96 } else { | |
97 hpack_decoder_.set_tables_debug_listener(nullptr); | |
98 listener_adapter_.SetHeaderTableDebugVisitor(nullptr); | |
99 } | |
100 } | |
101 | |
102 void HpackDecoder3::set_max_decode_buffer_size_bytes( | |
103 size_t max_decode_buffer_size_bytes) { | |
104 DVLOG(2) << "HpackDecoder3::set_max_decode_buffer_size_bytes"; | |
105 max_decode_buffer_size_bytes_ = max_decode_buffer_size_bytes; | |
106 hpack_decoder_.set_max_string_size_bytes(max_decode_buffer_size_bytes); | |
107 } | |
108 | |
109 size_t HpackDecoder3::EstimateMemoryUsage() const { | |
110 return SpdyEstimateMemoryUsage(hpack_decoder_); | |
111 } | |
112 | |
113 HpackDecoder3::ListenerAdapter::ListenerAdapter() : handler_(nullptr) {} | |
114 HpackDecoder3::ListenerAdapter::~ListenerAdapter() {} | |
115 | |
116 void HpackDecoder3::ListenerAdapter::set_handler( | |
117 SpdyHeadersHandlerInterface* handler) { | |
118 handler_ = handler; | |
119 } | |
120 | |
121 void HpackDecoder3::ListenerAdapter::SetHeaderTableDebugVisitor( | |
122 std::unique_ptr<HpackHeaderTable::DebugVisitorInterface> visitor) { | |
123 visitor_ = std::move(visitor); | |
124 } | |
125 | |
126 void HpackDecoder3::ListenerAdapter::OnHeaderListStart() { | |
127 DVLOG(2) << "HpackDecoder3::ListenerAdapter::OnHeaderListStart"; | |
128 total_hpack_bytes_ = 0; | |
129 total_uncompressed_bytes_ = 0; | |
130 decoded_block_.clear(); | |
131 if (handler_ != nullptr) { | |
132 handler_->OnHeaderBlockStart(); | |
133 } | |
134 } | |
135 | |
136 void HpackDecoder3::ListenerAdapter::OnHeader(HpackEntryType entry_type, | |
137 const HpackString& name, | |
138 const HpackString& value) { | |
139 DVLOG(2) << "HpackDecoder3::ListenerAdapter::OnHeader:\n name: " << name | |
140 << "\n value: " << value; | |
141 total_uncompressed_bytes_ += name.size() + value.size(); | |
142 if (handler_ == nullptr) { | |
143 DVLOG(3) << "Adding to decoded_block"; | |
144 decoded_block_.AppendValueOrAddHeader(name, value); | |
145 } else { | |
146 DVLOG(3) << "Passing to handler"; | |
147 handler_->OnHeader(name, value); | |
148 } | |
149 } | |
150 | |
151 void HpackDecoder3::ListenerAdapter::OnHeaderListEnd() { | |
152 DVLOG(2) << "HpackDecoder3::ListenerAdapter::OnHeaderListEnd"; | |
153 // We don't clear the SpdyHeaderBlock here to allow access to it until the | |
154 // next HPACK block is decoded. | |
155 if (handler_ != nullptr) { | |
156 if (FLAGS_chromium_http2_flag_log_compressed_size) { | |
157 handler_->OnHeaderBlockEnd(total_uncompressed_bytes_, total_hpack_bytes_); | |
158 } else { | |
159 handler_->OnHeaderBlockEnd(total_uncompressed_bytes_); | |
160 } | |
161 handler_ = nullptr; | |
162 } | |
163 } | |
164 | |
165 void HpackDecoder3::ListenerAdapter::OnHeaderErrorDetected( | |
166 SpdyStringPiece error_message) { | |
167 VLOG(1) << error_message; | |
168 } | |
169 | |
170 int64_t HpackDecoder3::ListenerAdapter::OnEntryInserted( | |
171 const HpackStringPair& sp, | |
172 size_t insert_count) { | |
173 DVLOG(2) << "HpackDecoder3::ListenerAdapter::OnEntryInserted: " << sp | |
174 << ", insert_count=" << insert_count; | |
175 if (visitor_ == nullptr) { | |
176 return 0; | |
177 } | |
178 HpackEntry entry(sp.name, sp.value, /*is_static*/ false, insert_count); | |
179 int64_t time_added = visitor_->OnNewEntry(entry); | |
180 DVLOG(2) << "HpackDecoder3::ListenerAdapter::OnEntryInserted: time_added=" | |
181 << time_added; | |
182 return time_added; | |
183 } | |
184 | |
185 void HpackDecoder3::ListenerAdapter::OnUseEntry(const HpackStringPair& sp, | |
186 size_t insert_count, | |
187 int64_t time_added) { | |
188 DVLOG(2) << "HpackDecoder3::ListenerAdapter::OnUseEntry: " << sp | |
189 << ", insert_count=" << insert_count | |
190 << ", time_added=" << time_added; | |
191 if (visitor_ != nullptr) { | |
192 HpackEntry entry(sp.name, sp.value, /*is_static*/ false, insert_count); | |
193 entry.set_time_added(time_added); | |
194 visitor_->OnUseEntry(entry); | |
195 } | |
196 } | |
197 | |
198 } // namespace net | |
OLD | NEW |