OLD | NEW |
| (Empty) |
1 // Copyright 2016 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/http2_frame_decoder_adapter.h" | |
6 | |
7 // Logging policy: If an error in the input is detected, VLOG(n) is used so that | |
8 // the option exists to debug the situation. Otherwise, this code mostly uses | |
9 // DVLOG so that the logging does not slow down production code when things are | |
10 // working OK. | |
11 | |
12 #include <stddef.h> | |
13 | |
14 #include <cstdint> | |
15 #include <cstring> | |
16 #include <utility> | |
17 | |
18 #include "base/logging.h" | |
19 #include "base/optional.h" | |
20 #include "base/sys_byteorder.h" | |
21 #include "net/http2/decoder/decode_buffer.h" | |
22 #include "net/http2/decoder/decode_status.h" | |
23 #include "net/http2/decoder/http2_frame_decoder.h" | |
24 #include "net/http2/decoder/http2_frame_decoder_listener.h" | |
25 #include "net/http2/http2_constants.h" | |
26 #include "net/http2/http2_structures.h" | |
27 #include "net/spdy/hpack/hpack_decoder_interface.h" | |
28 #include "net/spdy/hpack/hpack_header_table.h" | |
29 #include "net/spdy/platform/api/spdy_estimate_memory_usage.h" | |
30 #include "net/spdy/platform/api/spdy_string.h" | |
31 #include "net/spdy/spdy_alt_svc_wire_format.h" | |
32 #include "net/spdy/spdy_bug_tracker.h" | |
33 #include "net/spdy/spdy_frame_builder.h" | |
34 #include "net/spdy/spdy_header_block.h" | |
35 #include "net/spdy/spdy_headers_handler_interface.h" | |
36 #include "net/spdy/spdy_protocol.h" | |
37 | |
38 namespace net { | |
39 | |
40 namespace { | |
41 | |
42 const bool kHasPriorityFields = true; | |
43 const bool kNotHasPriorityFields = false; | |
44 | |
45 bool IsPaddable(Http2FrameType type) { | |
46 return type == Http2FrameType::DATA || type == Http2FrameType::HEADERS || | |
47 type == Http2FrameType::PUSH_PROMISE; | |
48 } | |
49 | |
50 SpdyFrameType ToSpdyFrameType(Http2FrameType type) { | |
51 return ParseFrameType(static_cast<uint8_t>(type)); | |
52 } | |
53 | |
54 uint64_t ToSpdyPingId(const Http2PingFields& ping) { | |
55 uint64_t v; | |
56 std::memcpy(&v, ping.opaque_data, Http2PingFields::EncodedSize()); | |
57 return base::NetToHost64(v); | |
58 } | |
59 | |
60 // Overwrites the fields of the header with invalid values, for the purpose | |
61 // of identifying reading of unset fields. Only takes effect for debug builds. | |
62 // In Address Sanatizer builds, it also marks the fields as un-readable. | |
63 void CorruptFrameHeader(Http2FrameHeader* header) { | |
64 #ifndef NDEBUG | |
65 // Beyond a valid payload length, which is 2^24 - 1. | |
66 header->payload_length = 0x1010dead; | |
67 // An unsupported frame type. | |
68 header->type = Http2FrameType(0x80); | |
69 DCHECK(!IsSupportedHttp2FrameType(header->type)); | |
70 // Frame flag bits that aren't used by any supported frame type. | |
71 header->flags = Http2FrameFlag(0xd2); | |
72 // A stream id with the reserved high-bit (R in the RFC) set. | |
73 // 2129510127 when the high-bit is cleared. | |
74 header->stream_id = 0xfeedbeef; | |
75 #endif | |
76 } | |
77 | |
78 class Http2DecoderAdapter : public SpdyFramerDecoderAdapter, | |
79 public Http2FrameDecoderListener { | |
80 typedef SpdyFramer::SpdyState SpdyState; | |
81 typedef SpdyFramer::SpdyFramerError SpdyFramerError; | |
82 | |
83 public: | |
84 explicit Http2DecoderAdapter(SpdyFramer* outer_framer) | |
85 : SpdyFramerDecoderAdapter(), outer_framer_(outer_framer) { | |
86 DVLOG(1) << "Http2DecoderAdapter ctor, outer_framer=" << outer_framer; | |
87 ResetInternal(); | |
88 } | |
89 ~Http2DecoderAdapter() override {} | |
90 | |
91 // =========================================================================== | |
92 // Implementations of the pure virtual methods from SpdyFramerDecoderAdapter; | |
93 // the other virtual methods of SpdyFramerDecoderAdapter have satsifactory | |
94 // default implementations. | |
95 | |
96 void set_extension_visitor(ExtensionVisitorInterface* visitor) override { | |
97 extension_ = visitor; | |
98 } | |
99 | |
100 // Passes the call on to the HPACK decoder. | |
101 void SetDecoderHeaderTableDebugVisitor( | |
102 std::unique_ptr<HpackHeaderTable::DebugVisitorInterface> visitor) | |
103 override { | |
104 GetHpackDecoder()->SetHeaderTableDebugVisitor(std::move(visitor)); | |
105 } | |
106 | |
107 size_t ProcessInput(const char* data, size_t len) override { | |
108 size_t limit = outer_framer_->recv_frame_size_limit(); | |
109 frame_decoder_->set_maximum_payload_size(limit); | |
110 | |
111 size_t total_processed = 0; | |
112 while (len > 0 && spdy_state_ != SpdyFramer::SPDY_ERROR) { | |
113 // Process one at a time so that we update the adapter's internal | |
114 // state appropriately. | |
115 const size_t processed = ProcessInputFrame(data, len); | |
116 | |
117 // We had some data, and weren't in an error state, so should have | |
118 // processed/consumed at least one byte of it, even if we then ended up | |
119 // in an error state. | |
120 DCHECK(processed > 0) << "processed=" << processed | |
121 << " spdy_state_=" << spdy_state_ | |
122 << " spdy_framer_error_=" << spdy_framer_error_; | |
123 | |
124 data += processed; | |
125 len -= processed; | |
126 total_processed += processed; | |
127 if (process_single_input_frame() || processed == 0) { | |
128 break; | |
129 } | |
130 } | |
131 return total_processed; | |
132 } | |
133 | |
134 void Reset() override { ResetInternal(); } | |
135 | |
136 SpdyState state() const override { return spdy_state_; } | |
137 | |
138 SpdyFramerError spdy_framer_error() const override { | |
139 return spdy_framer_error_; | |
140 } | |
141 | |
142 bool probable_http_response() const override { | |
143 return latched_probable_http_response_; | |
144 } | |
145 | |
146 size_t EstimateMemoryUsage() const override { | |
147 // Skip |frame_decoder_|, |frame_header_| and |hpack_first_frame_header_| as | |
148 // they don't allocate. | |
149 return SpdyEstimateMemoryUsage(alt_svc_origin_) + | |
150 SpdyEstimateMemoryUsage(alt_svc_value_); | |
151 } | |
152 // =========================================================================== | |
153 // Implementations of the methods declared by Http2FrameDecoderListener. | |
154 | |
155 // Called once the common frame header has been decoded for any frame. | |
156 // This function is largely based on SpdyFramer::ValidateFrameHeader | |
157 // and some parts of SpdyFramer::ProcessCommonHeader. | |
158 bool OnFrameHeader(const Http2FrameHeader& header) override { | |
159 DVLOG(1) << "OnFrameHeader: " << header; | |
160 decoded_frame_header_ = true; | |
161 if (!latched_probable_http_response_) { | |
162 latched_probable_http_response_ = header.IsProbableHttpResponse(); | |
163 } | |
164 const uint8_t raw_frame_type = static_cast<uint8_t>(header.type); | |
165 visitor()->OnCommonHeader(header.stream_id, header.payload_length, | |
166 raw_frame_type, header.flags); | |
167 if (has_expected_frame_type_ && header.type != expected_frame_type_) { | |
168 // Report an unexpected frame error and close the connection if we | |
169 // expect a known frame type (probably CONTINUATION) and receive an | |
170 // unknown frame. | |
171 VLOG(1) << "The framer was expecting to receive a " | |
172 << expected_frame_type_ | |
173 << " frame, but instead received an unknown frame of type " | |
174 << header.type; | |
175 SetSpdyErrorAndNotify(SpdyFramerError::SPDY_UNEXPECTED_FRAME); | |
176 return false; | |
177 } | |
178 if (!IsSupportedHttp2FrameType(header.type)) { | |
179 if (extension_ != nullptr) { | |
180 // Unknown frames will be passed to the registered extension. | |
181 return true; | |
182 } | |
183 // In HTTP2 we ignore unknown frame types for extensibility, as long as | |
184 // the rest of the control frame header is valid. | |
185 // We rely on the visitor to check validity of stream_id. | |
186 bool valid_stream = | |
187 visitor()->OnUnknownFrame(header.stream_id, raw_frame_type); | |
188 if (!valid_stream) { | |
189 // Report an invalid frame error if the stream_id is not valid. | |
190 VLOG(1) << "Unknown control frame type " << header.type | |
191 << " received on invalid stream " << header.stream_id; | |
192 SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_CONTROL_FRAME); | |
193 return false; | |
194 } else { | |
195 DVLOG(1) << "Ignoring unknown frame type " << header.type; | |
196 return true; | |
197 } | |
198 } | |
199 | |
200 SpdyFrameType frame_type = ToSpdyFrameType(header.type); | |
201 if (!IsValidHTTP2FrameStreamId(header.stream_id, frame_type)) { | |
202 VLOG(1) << "The framer received an invalid streamID of " | |
203 << header.stream_id << " for a frame of type " << header.type; | |
204 SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_STREAM_ID); | |
205 return false; | |
206 } | |
207 | |
208 if (has_expected_frame_type_ && header.type != expected_frame_type_) { | |
209 VLOG(1) << "Expected frame type " << expected_frame_type_ << ", not " | |
210 << header.type; | |
211 SetSpdyErrorAndNotify(SpdyFramerError::SPDY_UNEXPECTED_FRAME); | |
212 return false; | |
213 } | |
214 | |
215 if (!has_expected_frame_type_ && | |
216 header.type == Http2FrameType::CONTINUATION) { | |
217 VLOG(1) << "Got CONTINUATION frame when not expected."; | |
218 SetSpdyErrorAndNotify(SpdyFramerError::SPDY_UNEXPECTED_FRAME); | |
219 return false; | |
220 } | |
221 | |
222 if (header.type == Http2FrameType::DATA) { | |
223 // For some reason SpdyFramer still rejects invalid DATA frame flags. | |
224 uint8_t valid_flags = Http2FrameFlag::PADDED | Http2FrameFlag::END_STREAM; | |
225 if (header.HasAnyFlags(~valid_flags)) { | |
226 SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_DATA_FRAME_FLAGS); | |
227 return false; | |
228 } | |
229 } | |
230 | |
231 return true; | |
232 } | |
233 | |
234 void OnDataStart(const Http2FrameHeader& header) override { | |
235 DVLOG(1) << "OnDataStart: " << header; | |
236 | |
237 if (IsOkToStartFrame(header) && HasRequiredStreamId(header)) { | |
238 frame_header_ = header; | |
239 has_frame_header_ = true; | |
240 visitor()->OnDataFrameHeader(header.stream_id, header.payload_length, | |
241 header.IsEndStream()); | |
242 } | |
243 } | |
244 | |
245 void OnDataPayload(const char* data, size_t len) override { | |
246 DVLOG(1) << "OnDataPayload: len=" << len; | |
247 DCHECK(has_frame_header_); | |
248 DCHECK_EQ(frame_header_.type, Http2FrameType::DATA); | |
249 visitor()->OnStreamFrameData(frame_header().stream_id, data, len); | |
250 } | |
251 | |
252 void OnDataEnd() override { | |
253 DVLOG(1) << "OnDataEnd"; | |
254 DCHECK(has_frame_header_); | |
255 DCHECK_EQ(frame_header_.type, Http2FrameType::DATA); | |
256 if (frame_header().IsEndStream()) { | |
257 visitor()->OnStreamEnd(frame_header().stream_id); | |
258 } | |
259 opt_pad_length_.reset(); | |
260 } | |
261 | |
262 void OnHeadersStart(const Http2FrameHeader& header) override { | |
263 DVLOG(1) << "OnHeadersStart: " << header; | |
264 if (IsOkToStartFrame(header) && HasRequiredStreamId(header)) { | |
265 frame_header_ = header; | |
266 has_frame_header_ = true; | |
267 if (header.HasPriority()) { | |
268 // Once we've got the priority fields, then we can report the arrival | |
269 // of this HEADERS frame. | |
270 on_headers_called_ = false; | |
271 return; | |
272 } | |
273 on_headers_called_ = true; | |
274 ReportReceiveCompressedFrame(header); | |
275 visitor()->OnHeaders(header.stream_id, kNotHasPriorityFields, | |
276 0, // priority | |
277 0, // parent_stream_id | |
278 false, // exclusive | |
279 header.IsEndStream(), header.IsEndHeaders()); | |
280 CommonStartHpackBlock(); | |
281 } | |
282 } | |
283 | |
284 void OnHeadersPriority(const Http2PriorityFields& priority) override { | |
285 DVLOG(1) << "OnHeadersPriority: " << priority; | |
286 DCHECK(has_frame_header_); | |
287 DCHECK_EQ(frame_type(), Http2FrameType::HEADERS) << frame_header_; | |
288 DCHECK(frame_header_.HasPriority()); | |
289 DCHECK(!on_headers_called_); | |
290 on_headers_called_ = true; | |
291 ReportReceiveCompressedFrame(frame_header_); | |
292 visitor()->OnHeaders(frame_header_.stream_id, kHasPriorityFields, | |
293 priority.weight, priority.stream_dependency, | |
294 priority.is_exclusive, frame_header_.IsEndStream(), | |
295 frame_header_.IsEndHeaders()); | |
296 CommonStartHpackBlock(); | |
297 } | |
298 | |
299 void OnHpackFragment(const char* data, size_t len) override { | |
300 DVLOG(1) << "OnHpackFragment: len=" << len; | |
301 on_hpack_fragment_called_ = true; | |
302 if (!GetHpackDecoder()->HandleControlFrameHeadersData(data, len)) { | |
303 SetSpdyErrorAndNotify(SpdyFramerError::SPDY_DECOMPRESS_FAILURE); | |
304 return; | |
305 } | |
306 } | |
307 | |
308 void OnHeadersEnd() override { | |
309 DVLOG(1) << "OnHeadersEnd"; | |
310 CommonHpackFragmentEnd(); | |
311 opt_pad_length_.reset(); | |
312 } | |
313 | |
314 void OnPriorityFrame(const Http2FrameHeader& header, | |
315 const Http2PriorityFields& priority) override { | |
316 DVLOG(1) << "OnPriorityFrame: " << header << "; priority: " << priority; | |
317 if (IsOkToStartFrame(header) && HasRequiredStreamId(header)) { | |
318 visitor()->OnPriority(header.stream_id, priority.stream_dependency, | |
319 priority.weight, priority.is_exclusive); | |
320 } | |
321 } | |
322 | |
323 void OnContinuationStart(const Http2FrameHeader& header) override { | |
324 DVLOG(1) << "OnContinuationStart: " << header; | |
325 if (IsOkToStartFrame(header) && HasRequiredStreamId(header)) { | |
326 DCHECK(has_hpack_first_frame_header_); | |
327 if (header.stream_id != hpack_first_frame_header_.stream_id) { | |
328 SetSpdyErrorAndNotify(SpdyFramerError::SPDY_UNEXPECTED_FRAME); | |
329 return; | |
330 } | |
331 frame_header_ = header; | |
332 has_frame_header_ = true; | |
333 ReportReceiveCompressedFrame(header); | |
334 visitor()->OnContinuation(header.stream_id, header.IsEndHeaders()); | |
335 } | |
336 } | |
337 | |
338 void OnContinuationEnd() override { | |
339 DVLOG(1) << "OnContinuationEnd"; | |
340 CommonHpackFragmentEnd(); | |
341 } | |
342 | |
343 void OnPadLength(size_t trailing_length) override { | |
344 DVLOG(1) << "OnPadLength: " << trailing_length; | |
345 opt_pad_length_ = trailing_length; | |
346 if (frame_header_.type == Http2FrameType::DATA) { | |
347 visitor()->OnStreamPadding(stream_id(), 1); | |
348 } else if (frame_header_.type == Http2FrameType::HEADERS) { | |
349 CHECK_LT(trailing_length, 256u); | |
350 } | |
351 } | |
352 | |
353 void OnPadding(const char* padding, size_t skipped_length) override { | |
354 DVLOG(1) << "OnPadding: " << skipped_length; | |
355 if (frame_header_.type == Http2FrameType::DATA) { | |
356 visitor()->OnStreamPadding(stream_id(), skipped_length); | |
357 } else { | |
358 MaybeAnnounceEmptyFirstHpackFragment(); | |
359 } | |
360 } | |
361 | |
362 void OnRstStream(const Http2FrameHeader& header, | |
363 Http2ErrorCode http2_error_code) override { | |
364 DVLOG(1) << "OnRstStream: " << header << "; code=" << http2_error_code; | |
365 if (IsOkToStartFrame(header) && HasRequiredStreamId(header)) { | |
366 SpdyErrorCode error_code = | |
367 ParseErrorCode(static_cast<uint32_t>(http2_error_code)); | |
368 visitor()->OnRstStream(header.stream_id, error_code); | |
369 } | |
370 } | |
371 | |
372 void OnSettingsStart(const Http2FrameHeader& header) override { | |
373 DVLOG(1) << "OnSettingsStart: " << header; | |
374 if (IsOkToStartFrame(header) && HasRequiredStreamIdZero(header)) { | |
375 frame_header_ = header; | |
376 has_frame_header_ = true; | |
377 visitor()->OnSettings(0); | |
378 } | |
379 } | |
380 | |
381 void OnSetting(const Http2SettingFields& setting_fields) override { | |
382 DVLOG(1) << "OnSetting: " << setting_fields; | |
383 const uint16_t parameter = static_cast<uint16_t>(setting_fields.parameter); | |
384 SpdySettingsIds setting_id; | |
385 if (!ParseSettingsId(parameter, &setting_id)) { | |
386 if (extension_ == nullptr) { | |
387 DVLOG(1) << "Ignoring unknown setting id: " << setting_fields; | |
388 } else { | |
389 extension_->OnSetting(parameter, setting_fields.value); | |
390 } | |
391 return; | |
392 } | |
393 visitor()->OnSetting(setting_id, setting_fields.value); | |
394 } | |
395 | |
396 void OnSettingsEnd() override { | |
397 DVLOG(1) << "OnSettingsEnd"; | |
398 visitor()->OnSettingsEnd(); | |
399 } | |
400 | |
401 void OnSettingsAck(const Http2FrameHeader& header) override { | |
402 DVLOG(1) << "OnSettingsAck: " << header; | |
403 if (IsOkToStartFrame(header) && HasRequiredStreamIdZero(header)) { | |
404 visitor()->OnSettingsAck(); | |
405 } | |
406 } | |
407 | |
408 void OnPushPromiseStart(const Http2FrameHeader& header, | |
409 const Http2PushPromiseFields& promise, | |
410 size_t total_padding_length) override { | |
411 DVLOG(1) << "OnPushPromiseStart: " << header << "; promise: " << promise | |
412 << "; total_padding_length: " << total_padding_length; | |
413 if (IsOkToStartFrame(header) && HasRequiredStreamId(header)) { | |
414 if (promise.promised_stream_id == 0) { | |
415 SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_CONTROL_FRAME); | |
416 return; | |
417 } | |
418 frame_header_ = header; | |
419 has_frame_header_ = true; | |
420 ReportReceiveCompressedFrame(header); | |
421 visitor()->OnPushPromise(header.stream_id, promise.promised_stream_id, | |
422 header.IsEndHeaders()); | |
423 CommonStartHpackBlock(); | |
424 } | |
425 } | |
426 | |
427 void OnPushPromiseEnd() override { | |
428 DVLOG(1) << "OnPushPromiseEnd"; | |
429 CommonHpackFragmentEnd(); | |
430 opt_pad_length_.reset(); | |
431 } | |
432 | |
433 void OnPing(const Http2FrameHeader& header, | |
434 const Http2PingFields& ping) override { | |
435 DVLOG(1) << "OnPing: " << header << "; ping: " << ping; | |
436 if (IsOkToStartFrame(header) && HasRequiredStreamIdZero(header)) { | |
437 visitor()->OnPing(ToSpdyPingId(ping), false); | |
438 } | |
439 } | |
440 | |
441 void OnPingAck(const Http2FrameHeader& header, | |
442 const Http2PingFields& ping) override { | |
443 DVLOG(1) << "OnPingAck: " << header << "; ping: " << ping; | |
444 if (IsOkToStartFrame(header) && HasRequiredStreamIdZero(header)) { | |
445 visitor()->OnPing(ToSpdyPingId(ping), true); | |
446 } | |
447 } | |
448 | |
449 void OnGoAwayStart(const Http2FrameHeader& header, | |
450 const Http2GoAwayFields& goaway) override { | |
451 DVLOG(1) << "OnGoAwayStart: " << header << "; goaway: " << goaway; | |
452 if (IsOkToStartFrame(header) && HasRequiredStreamIdZero(header)) { | |
453 frame_header_ = header; | |
454 has_frame_header_ = true; | |
455 SpdyErrorCode error_code = | |
456 ParseErrorCode(static_cast<uint32_t>(goaway.error_code)); | |
457 visitor()->OnGoAway(goaway.last_stream_id, error_code); | |
458 } | |
459 } | |
460 | |
461 void OnGoAwayOpaqueData(const char* data, size_t len) override { | |
462 DVLOG(1) << "OnGoAwayOpaqueData: len=" << len; | |
463 visitor()->OnGoAwayFrameData(data, len); | |
464 } | |
465 | |
466 void OnGoAwayEnd() override { | |
467 DVLOG(1) << "OnGoAwayEnd"; | |
468 visitor()->OnGoAwayFrameData(nullptr, 0); | |
469 } | |
470 | |
471 void OnWindowUpdate(const Http2FrameHeader& header, | |
472 uint32_t increment) override { | |
473 DVLOG(1) << "OnWindowUpdate: " << header << "; increment=" << increment; | |
474 if (IsOkToStartFrame(header)) { | |
475 visitor()->OnWindowUpdate(header.stream_id, increment); | |
476 } | |
477 } | |
478 | |
479 // Per RFC7838, an ALTSVC frame on stream 0 with origin_length == 0, or one on | |
480 // a stream other than stream 0 with origin_length != 0 MUST be ignored. All | |
481 // frames are decoded by Http2DecoderAdapter, and it is left to the consumer | |
482 // (listener) to implement this behavior. | |
483 void OnAltSvcStart(const Http2FrameHeader& header, | |
484 size_t origin_length, | |
485 size_t value_length) override { | |
486 DVLOG(1) << "OnAltSvcStart: " << header | |
487 << "; origin_length: " << origin_length | |
488 << "; value_length: " << value_length; | |
489 if (!IsOkToStartFrame(header)) { | |
490 return; | |
491 } | |
492 frame_header_ = header; | |
493 has_frame_header_ = true; | |
494 alt_svc_origin_.clear(); | |
495 alt_svc_value_.clear(); | |
496 } | |
497 | |
498 void OnAltSvcOriginData(const char* data, size_t len) override { | |
499 DVLOG(1) << "OnAltSvcOriginData: len=" << len; | |
500 alt_svc_origin_.append(data, len); | |
501 } | |
502 | |
503 // Called when decoding the Alt-Svc-Field-Value of an ALTSVC; | |
504 // the field is uninterpreted. | |
505 void OnAltSvcValueData(const char* data, size_t len) override { | |
506 DVLOG(1) << "OnAltSvcValueData: len=" << len; | |
507 alt_svc_value_.append(data, len); | |
508 } | |
509 | |
510 void OnAltSvcEnd() override { | |
511 DVLOG(1) << "OnAltSvcEnd: origin.size(): " << alt_svc_origin_.size() | |
512 << "; value.size(): " << alt_svc_value_.size(); | |
513 SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector; | |
514 if (!SpdyAltSvcWireFormat::ParseHeaderFieldValue(alt_svc_value_, | |
515 &altsvc_vector)) { | |
516 DLOG(ERROR) << "SpdyAltSvcWireFormat::ParseHeaderFieldValue failed."; | |
517 SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_CONTROL_FRAME); | |
518 return; | |
519 } | |
520 visitor()->OnAltSvc(frame_header_.stream_id, alt_svc_origin_, | |
521 altsvc_vector); | |
522 // We assume that ALTSVC frames are rare, so get rid of the storage. | |
523 alt_svc_origin_.clear(); | |
524 alt_svc_origin_.shrink_to_fit(); | |
525 alt_svc_value_.clear(); | |
526 alt_svc_value_.shrink_to_fit(); | |
527 } | |
528 | |
529 // Except for BLOCKED frames, all other unknown frames are either dropped or | |
530 // passed to a registered extension. | |
531 void OnUnknownStart(const Http2FrameHeader& header) override { | |
532 DVLOG(1) << "OnUnknownStart: " << header; | |
533 if (IsOkToStartFrame(header)) { | |
534 if (extension_ != nullptr) { | |
535 const uint8_t type = static_cast<uint8_t>(header.type); | |
536 const uint8_t flags = static_cast<uint8_t>(header.flags); | |
537 handling_extension_payload_ = extension_->OnFrameHeader( | |
538 header.stream_id, header.payload_length, type, flags); | |
539 } | |
540 } | |
541 } | |
542 | |
543 void OnUnknownPayload(const char* data, size_t len) override { | |
544 if (handling_extension_payload_) { | |
545 extension_->OnFramePayload(data, len); | |
546 } else { | |
547 DVLOG(1) << "OnUnknownPayload: len=" << len; | |
548 } | |
549 } | |
550 | |
551 void OnUnknownEnd() override { | |
552 DVLOG(1) << "OnUnknownEnd"; | |
553 handling_extension_payload_ = false; | |
554 } | |
555 | |
556 void OnPaddingTooLong(const Http2FrameHeader& header, | |
557 size_t missing_length) override { | |
558 DVLOG(1) << "OnPaddingTooLong: " << header | |
559 << "; missing_length: " << missing_length; | |
560 if (header.type == Http2FrameType::DATA) { | |
561 if (header.payload_length == 0) { | |
562 DCHECK_EQ(1u, missing_length); | |
563 SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_DATA_FRAME_FLAGS); | |
564 return; | |
565 } | |
566 visitor()->OnStreamPadding(header.stream_id, 1); | |
567 } | |
568 SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_PADDING); | |
569 } | |
570 | |
571 void OnFrameSizeError(const Http2FrameHeader& header) override { | |
572 DVLOG(1) << "OnFrameSizeError: " << header; | |
573 size_t recv_limit = outer_framer_->recv_frame_size_limit(); | |
574 if (header.payload_length > recv_limit) { | |
575 SetSpdyErrorAndNotify(SpdyFramerError::SPDY_OVERSIZED_PAYLOAD); | |
576 return; | |
577 } | |
578 if (header.type != Http2FrameType::DATA && | |
579 header.payload_length > recv_limit) { | |
580 SetSpdyErrorAndNotify(SpdyFramerError::SPDY_CONTROL_PAYLOAD_TOO_LARGE); | |
581 return; | |
582 } | |
583 switch (header.type) { | |
584 case Http2FrameType::GOAWAY: | |
585 case Http2FrameType::ALTSVC: | |
586 SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_CONTROL_FRAME); | |
587 break; | |
588 default: | |
589 SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_CONTROL_FRAME_SIZE); | |
590 } | |
591 } | |
592 | |
593 private: | |
594 // Decodes the input up to the next frame boundary (i.e. at most one frame), | |
595 // stopping early if an error is detected. | |
596 size_t ProcessInputFrame(const char* data, size_t len) { | |
597 DCHECK_NE(spdy_state_, SpdyState::SPDY_ERROR); | |
598 DecodeBuffer db(data, len); | |
599 DecodeStatus status = frame_decoder_->DecodeFrame(&db); | |
600 if (spdy_state_ != SpdyFramer::SPDY_ERROR) { | |
601 DetermineSpdyState(status); | |
602 } else { | |
603 VLOG(1) << "ProcessInputFrame spdy_framer_error_=" | |
604 << SpdyFramer::SpdyFramerErrorToString(spdy_framer_error_); | |
605 if (spdy_framer_error_ == SpdyFramerError::SPDY_INVALID_PADDING && | |
606 has_frame_header_ && frame_type() != Http2FrameType::DATA) { | |
607 // spdy_framer_test checks that all of the available frame payload | |
608 // has been consumed, so do that. | |
609 size_t total = remaining_total_payload(); | |
610 if (total <= frame_header().payload_length) { | |
611 size_t avail = db.MinLengthRemaining(total); | |
612 VLOG(1) << "Skipping past " << avail << " bytes, of " << total | |
613 << " total remaining in the frame's payload."; | |
614 db.AdvanceCursor(avail); | |
615 } else { | |
616 SPDY_BUG << "Total remaining (" << total | |
617 << ") should not be greater than the payload length; " | |
618 << frame_header(); | |
619 } | |
620 } | |
621 } | |
622 return db.Offset(); | |
623 } | |
624 | |
625 // After decoding, determine the next SpdyState. Only called if the current | |
626 // state is NOT SpdyState::SPDY_ERROR (i.e. if none of the callback methods | |
627 // detected an error condition), because otherwise we assume that the callback | |
628 // method has set spdy_framer_error_ appropriately. | |
629 void DetermineSpdyState(DecodeStatus status) { | |
630 DCHECK_EQ(spdy_framer_error_, SpdyFramer::SPDY_NO_ERROR); | |
631 DCHECK(!HasError()) << spdy_framer_error_; | |
632 switch (status) { | |
633 case DecodeStatus::kDecodeDone: | |
634 DVLOG(1) << "ProcessInputFrame -> DecodeStatus::kDecodeDone"; | |
635 ResetBetweenFrames(); | |
636 break; | |
637 case DecodeStatus::kDecodeInProgress: | |
638 DVLOG(1) << "ProcessInputFrame -> DecodeStatus::kDecodeInProgress"; | |
639 if (decoded_frame_header_) { | |
640 if (IsDiscardingPayload()) { | |
641 set_spdy_state(SpdyState::SPDY_IGNORE_REMAINING_PAYLOAD); | |
642 } else if (has_frame_header_ && | |
643 frame_type() == Http2FrameType::DATA) { | |
644 if (IsReadingPaddingLength()) { | |
645 set_spdy_state(SpdyState::SPDY_READ_DATA_FRAME_PADDING_LENGTH); | |
646 } else if (IsSkippingPadding()) { | |
647 set_spdy_state(SpdyState::SPDY_CONSUME_PADDING); | |
648 } else { | |
649 set_spdy_state(SpdyState::SPDY_FORWARD_STREAM_FRAME); | |
650 } | |
651 } else { | |
652 set_spdy_state(SpdyState::SPDY_CONTROL_FRAME_PAYLOAD); | |
653 } | |
654 } else { | |
655 set_spdy_state(SpdyState::SPDY_READING_COMMON_HEADER); | |
656 } | |
657 break; | |
658 case DecodeStatus::kDecodeError: | |
659 VLOG(1) << "ProcessInputFrame -> DecodeStatus::kDecodeError"; | |
660 if (IsDiscardingPayload()) { | |
661 if (remaining_total_payload() == 0) { | |
662 // Push the Http2FrameDecoder out of state kDiscardPayload now | |
663 // since doing so requires no input. | |
664 DecodeBuffer tmp("", 0); | |
665 DecodeStatus status = frame_decoder_->DecodeFrame(&tmp); | |
666 if (status != DecodeStatus::kDecodeDone) { | |
667 SPDY_BUG << "Expected to be done decoding the frame, not " | |
668 << status; | |
669 SetSpdyErrorAndNotify(SpdyFramer::SPDY_INTERNAL_FRAMER_ERROR); | |
670 } else if (spdy_framer_error_ != SpdyFramer::SPDY_NO_ERROR) { | |
671 SPDY_BUG << "Expected to have no error, not " | |
672 << SpdyFramer::SpdyFramerErrorToString( | |
673 spdy_framer_error_); | |
674 } else { | |
675 ResetBetweenFrames(); | |
676 } | |
677 } else { | |
678 set_spdy_state(SpdyState::SPDY_IGNORE_REMAINING_PAYLOAD); | |
679 } | |
680 } else { | |
681 SetSpdyErrorAndNotify(SpdyFramer::SPDY_INVALID_CONTROL_FRAME); | |
682 } | |
683 break; | |
684 } | |
685 } | |
686 | |
687 void ResetBetweenFrames() { | |
688 CorruptFrameHeader(&frame_header_); | |
689 decoded_frame_header_ = false; | |
690 has_frame_header_ = false; | |
691 set_spdy_state(SpdyState::SPDY_READY_FOR_FRAME); | |
692 } | |
693 | |
694 // ResetInternal is called from the constructor, and during tests, but not | |
695 // otherwise (i.e. not between every frame). | |
696 void ResetInternal() { | |
697 set_spdy_state(SpdyState::SPDY_READY_FOR_FRAME); | |
698 spdy_framer_error_ = SpdyFramerError::SPDY_NO_ERROR; | |
699 | |
700 decoded_frame_header_ = false; | |
701 has_frame_header_ = false; | |
702 on_headers_called_ = false; | |
703 on_hpack_fragment_called_ = false; | |
704 latched_probable_http_response_ = false; | |
705 has_expected_frame_type_ = false; | |
706 | |
707 CorruptFrameHeader(&frame_header_); | |
708 CorruptFrameHeader(&hpack_first_frame_header_); | |
709 | |
710 frame_decoder_.reset(new Http2FrameDecoder(this)); | |
711 } | |
712 | |
713 void set_spdy_state(SpdyState v) { | |
714 DVLOG(2) << "set_spdy_state(" << SpdyFramer::StateToString(v) << ")"; | |
715 spdy_state_ = v; | |
716 } | |
717 | |
718 void SetSpdyErrorAndNotify(SpdyFramerError error) { | |
719 if (HasError()) { | |
720 DCHECK_EQ(spdy_state_, SpdyState::SPDY_ERROR); | |
721 } else { | |
722 VLOG(2) << "SetSpdyErrorAndNotify(" | |
723 << SpdyFramer::SpdyFramerErrorToString(error) << ")"; | |
724 DCHECK_NE(error, SpdyFramerError::SPDY_NO_ERROR); | |
725 spdy_framer_error_ = error; | |
726 set_spdy_state(SpdyState::SPDY_ERROR); | |
727 frame_decoder_->set_listener(&no_op_listener_); | |
728 visitor()->OnError(outer_framer_); | |
729 } | |
730 } | |
731 | |
732 bool HasError() const { | |
733 if (spdy_state_ == SpdyState::SPDY_ERROR) { | |
734 DCHECK_NE(spdy_framer_error(), SpdyFramerError::SPDY_NO_ERROR); | |
735 return true; | |
736 } else { | |
737 DCHECK_EQ(spdy_framer_error(), SpdyFramerError::SPDY_NO_ERROR); | |
738 return false; | |
739 } | |
740 } | |
741 | |
742 const Http2FrameHeader& frame_header() const { | |
743 DCHECK(has_frame_header_); | |
744 return frame_header_; | |
745 } | |
746 | |
747 uint32_t stream_id() const { return frame_header().stream_id; } | |
748 | |
749 Http2FrameType frame_type() const { return frame_header().type; } | |
750 | |
751 size_t remaining_total_payload() const { | |
752 DCHECK(has_frame_header_); | |
753 size_t remaining = frame_decoder_->remaining_payload(); | |
754 if (IsPaddable(frame_type()) && frame_header_.IsPadded()) { | |
755 remaining += frame_decoder_->remaining_padding(); | |
756 } | |
757 return remaining; | |
758 } | |
759 | |
760 bool IsReadingPaddingLength() { | |
761 bool result = frame_header_.IsPadded() && !opt_pad_length_; | |
762 DVLOG(2) << "Http2DecoderAdapter::IsReadingPaddingLength: " << result; | |
763 return result; | |
764 } | |
765 bool IsSkippingPadding() { | |
766 bool result = frame_header_.IsPadded() && opt_pad_length_ && | |
767 frame_decoder_->remaining_payload() == 0 && | |
768 frame_decoder_->remaining_padding() > 0; | |
769 DVLOG(2) << "Http2DecoderAdapter::IsSkippingPadding: " << result; | |
770 return result; | |
771 } | |
772 bool IsDiscardingPayload() { | |
773 bool result = | |
774 decoded_frame_header_ && frame_decoder_->IsDiscardingPayload(); | |
775 DVLOG(2) << "Http2DecoderAdapter::IsDiscardingPayload: " << result; | |
776 return result; | |
777 } | |
778 // Called from OnXyz or OnXyzStart methods to decide whether it is OK to | |
779 // handle the callback. | |
780 bool IsOkToStartFrame(const Http2FrameHeader& header) { | |
781 DVLOG(3) << "IsOkToStartFrame"; | |
782 if (HasError()) { | |
783 VLOG(2) << "HasError()"; | |
784 return false; | |
785 } | |
786 DCHECK(!has_frame_header_); | |
787 if (has_expected_frame_type_ && header.type != expected_frame_type_) { | |
788 VLOG(1) << "Expected frame type " << expected_frame_type_ << ", not " | |
789 << header.type; | |
790 SetSpdyErrorAndNotify(SpdyFramerError::SPDY_UNEXPECTED_FRAME); | |
791 return false; | |
792 } | |
793 | |
794 return true; | |
795 } | |
796 | |
797 bool HasRequiredStreamId(uint32_t stream_id) { | |
798 DVLOG(3) << "HasRequiredStreamId: " << stream_id; | |
799 if (HasError()) { | |
800 VLOG(2) << "HasError()"; | |
801 return false; | |
802 } | |
803 if (stream_id != 0) { | |
804 return true; | |
805 } | |
806 VLOG(1) << "Stream Id is required, but zero provided"; | |
807 SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_STREAM_ID); | |
808 return false; | |
809 } | |
810 | |
811 bool HasRequiredStreamId(const Http2FrameHeader& header) { | |
812 return HasRequiredStreamId(header.stream_id); | |
813 } | |
814 | |
815 bool HasRequiredStreamIdZero(uint32_t stream_id) { | |
816 DVLOG(3) << "HasRequiredStreamIdZero: " << stream_id; | |
817 if (HasError()) { | |
818 VLOG(2) << "HasError()"; | |
819 return false; | |
820 } | |
821 if (stream_id == 0) { | |
822 return true; | |
823 } | |
824 VLOG(1) << "Stream Id was not zero, as required: " << stream_id; | |
825 SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_STREAM_ID); | |
826 return false; | |
827 } | |
828 | |
829 bool HasRequiredStreamIdZero(const Http2FrameHeader& header) { | |
830 return HasRequiredStreamIdZero(header.stream_id); | |
831 } | |
832 | |
833 void ReportReceiveCompressedFrame(const Http2FrameHeader& header) { | |
834 if (debug_visitor() != nullptr) { | |
835 size_t total = header.payload_length + Http2FrameHeader::EncodedSize(); | |
836 debug_visitor()->OnReceiveCompressedFrame( | |
837 header.stream_id, ToSpdyFrameType(header.type), total); | |
838 } | |
839 } | |
840 | |
841 HpackDecoderInterface* GetHpackDecoder() { | |
842 if (hpack_decoder_ == nullptr) { | |
843 hpack_decoder_ = outer_framer_->GetHpackDecoderForAdapter(); | |
844 } | |
845 return hpack_decoder_; | |
846 } | |
847 | |
848 void CommonStartHpackBlock() { | |
849 DVLOG(1) << "CommonStartHpackBlock"; | |
850 DCHECK(!has_hpack_first_frame_header_); | |
851 if (!frame_header_.IsEndHeaders()) { | |
852 hpack_first_frame_header_ = frame_header_; | |
853 has_hpack_first_frame_header_ = true; | |
854 } else { | |
855 CorruptFrameHeader(&hpack_first_frame_header_); | |
856 } | |
857 on_hpack_fragment_called_ = false; | |
858 SpdyHeadersHandlerInterface* handler = | |
859 visitor()->OnHeaderFrameStart(stream_id()); | |
860 if (handler == nullptr) { | |
861 SPDY_BUG << "visitor_->OnHeaderFrameStart returned nullptr"; | |
862 SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INTERNAL_FRAMER_ERROR); | |
863 return; | |
864 } | |
865 GetHpackDecoder()->HandleControlFrameHeadersStart(handler); | |
866 } | |
867 | |
868 // SpdyFramer calls HandleControlFrameHeadersData even if there are zero | |
869 // fragment bytes in the first frame, so do the same. | |
870 void MaybeAnnounceEmptyFirstHpackFragment() { | |
871 if (!on_hpack_fragment_called_) { | |
872 OnHpackFragment(nullptr, 0); | |
873 DCHECK(on_hpack_fragment_called_); | |
874 } | |
875 } | |
876 | |
877 void CommonHpackFragmentEnd() { | |
878 DVLOG(1) << "CommonHpackFragmentEnd: stream_id=" << stream_id(); | |
879 if (HasError()) { | |
880 VLOG(1) << "HasError(), returning"; | |
881 return; | |
882 } | |
883 DCHECK(has_frame_header_); | |
884 MaybeAnnounceEmptyFirstHpackFragment(); | |
885 if (frame_header_.IsEndHeaders()) { | |
886 DCHECK_EQ(has_hpack_first_frame_header_, | |
887 frame_type() == Http2FrameType::CONTINUATION) | |
888 << frame_header(); | |
889 has_expected_frame_type_ = false; | |
890 if (GetHpackDecoder()->HandleControlFrameHeadersComplete(nullptr)) { | |
891 visitor()->OnHeaderFrameEnd(stream_id(), true); | |
892 } else { | |
893 SetSpdyErrorAndNotify(SpdyFramerError::SPDY_DECOMPRESS_FAILURE); | |
894 return; | |
895 } | |
896 const Http2FrameHeader& first = | |
897 frame_type() == Http2FrameType::CONTINUATION | |
898 ? hpack_first_frame_header_ | |
899 : frame_header_; | |
900 if (first.type == Http2FrameType::HEADERS && first.IsEndStream()) { | |
901 visitor()->OnStreamEnd(first.stream_id); | |
902 } | |
903 hpack_decoder_ = nullptr; | |
904 has_hpack_first_frame_header_ = false; | |
905 CorruptFrameHeader(&hpack_first_frame_header_); | |
906 } else { | |
907 DCHECK(has_hpack_first_frame_header_); | |
908 has_expected_frame_type_ = true; | |
909 expected_frame_type_ = Http2FrameType::CONTINUATION; | |
910 } | |
911 } | |
912 | |
913 // The SpdyFramer that created this Http2FrameDecoderAdapter. | |
914 SpdyFramer* const outer_framer_; | |
915 | |
916 // If non-null, unknown frames and settings are passed to the extension. | |
917 ExtensionVisitorInterface* extension_ = nullptr; | |
918 | |
919 // The HPACK decoder that we're using for the HPACK block that is currently | |
920 // being decoded. Cleared at the end of the block. Owned by the SpdyFramer. | |
921 HpackDecoderInterface* hpack_decoder_ = nullptr; | |
922 | |
923 // The HTTP/2 frame decoder. Accessed via a unique_ptr to allow replacement | |
924 // (e.g. in tests) when Reset() is called. | |
925 std::unique_ptr<Http2FrameDecoder> frame_decoder_; | |
926 | |
927 // The most recently decoded frame header; invalid after we reached the end | |
928 // of that frame. | |
929 Http2FrameHeader frame_header_; | |
930 | |
931 // If decoding an HPACK block that is split across multiple frames, this holds | |
932 // the frame header of the HEADERS or PUSH_PROMISE that started the block. | |
933 Http2FrameHeader hpack_first_frame_header_; | |
934 | |
935 // Amount of trailing padding. Currently used just as an indicator of whether | |
936 // OnPadLength has been called. | |
937 base::Optional<size_t> opt_pad_length_; | |
938 | |
939 // Temporary buffers for the AltSvc fields. | |
940 SpdyString alt_svc_origin_; | |
941 SpdyString alt_svc_value_; | |
942 | |
943 // Listener used if we transition to an error state; the listener ignores all | |
944 // the callbacks. | |
945 Http2FrameDecoderNoOpListener no_op_listener_; | |
946 | |
947 // Next frame type expected. Currently only used for CONTINUATION frames, | |
948 // but could be used for detecting whether the first frame is a SETTINGS | |
949 // frame. | |
950 // TODO(jamessyng): Provide means to indicate that decoder should require | |
951 // SETTINGS frame as the first frame. | |
952 Http2FrameType expected_frame_type_; | |
953 | |
954 // Attempt to duplicate the SpdyState and SpdyFramerError values that | |
955 // SpdyFramer sets. Values determined by getting tests to pass. | |
956 SpdyState spdy_state_; | |
957 SpdyFramerError spdy_framer_error_; | |
958 | |
959 // Has OnFrameHeader been called? | |
960 bool decoded_frame_header_ = false; | |
961 | |
962 // Have we recorded an Http2FrameHeader for the current frame? | |
963 // We only do so if the decoder will make multiple callbacks for | |
964 // the frame; for example, for PING frames we don't make record | |
965 // the frame header, but for ALTSVC we do. | |
966 bool has_frame_header_ = false; | |
967 | |
968 // Have we recorded an Http2FrameHeader for the current HPACK block? | |
969 // True only for multi-frame HPACK blocks. | |
970 bool has_hpack_first_frame_header_ = false; | |
971 | |
972 // Has OnHeaders() already been called for current HEADERS block? Only | |
973 // meaningful between OnHeadersStart and OnHeadersPriority. | |
974 bool on_headers_called_; | |
975 | |
976 // Has OnHpackFragment() already been called for current HPACK block? | |
977 // SpdyFramer will pass an empty buffer to the HPACK decoder if a HEADERS | |
978 // or PUSH_PROMISE has no HPACK data in it (e.g. a HEADERS frame with only | |
979 // padding). Detect that condition and replicate the behavior using this | |
980 // field. | |
981 bool on_hpack_fragment_called_; | |
982 | |
983 // Have we seen a frame header that appears to be an HTTP/1 response? | |
984 bool latched_probable_http_response_ = false; | |
985 | |
986 // Is expected_frame_type_ set? | |
987 bool has_expected_frame_type_ = false; | |
988 | |
989 // Is the current frame payload destined for |extension_|? | |
990 bool handling_extension_payload_ = false; | |
991 }; | |
992 | |
993 } // namespace | |
994 | |
995 std::unique_ptr<SpdyFramerDecoderAdapter> CreateHttp2FrameDecoderAdapter( | |
996 SpdyFramer* outer_framer) { | |
997 return std::unique_ptr<SpdyFramerDecoderAdapter>( | |
998 new Http2DecoderAdapter(outer_framer)); | |
999 } | |
1000 | |
1001 } // namespace net | |
OLD | NEW |