Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(214)

Side by Side Diff: net/spdy/http2_frame_decoder_adapter.cc

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

Powered by Google App Engine
This is Rietveld 408576698