blob: cf7b673c5ee684ced18ba38e19e4492747dac5e8 [file] [log] [blame]
QUICHE teamfd50a402018-12-07 22:54:05 -05001// 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/third_party/quiche/src/http2/decoder/payload_decoders/goaway_payload_decoder.h"
6
7#include <stddef.h>
8
9#include "base/logging.h"
10#include "base/macros.h"
11#include "net/third_party/quiche/src/http2/decoder/decode_buffer.h"
12#include "net/third_party/quiche/src/http2/decoder/http2_frame_decoder_listener.h"
13#include "net/third_party/quiche/src/http2/http2_constants.h"
14#include "net/third_party/quiche/src/http2/http2_structures.h"
15#include "net/third_party/quiche/src/http2/platform/api/http2_bug_tracker.h"
16#include "net/third_party/quiche/src/http2/platform/api/http2_macros.h"
17
18namespace http2 {
19
20std::ostream& operator<<(std::ostream& out,
21 GoAwayPayloadDecoder::PayloadState v) {
22 switch (v) {
23 case GoAwayPayloadDecoder::PayloadState::kStartDecodingFixedFields:
24 return out << "kStartDecodingFixedFields";
25 case GoAwayPayloadDecoder::PayloadState::kHandleFixedFieldsStatus:
26 return out << "kHandleFixedFieldsStatus";
27 case GoAwayPayloadDecoder::PayloadState::kReadOpaqueData:
28 return out << "kReadOpaqueData";
29 case GoAwayPayloadDecoder::PayloadState::kResumeDecodingFixedFields:
30 return out << "kResumeDecodingFixedFields";
31 }
32 // Since the value doesn't come over the wire, only a programming bug should
33 // result in reaching this point.
34 int unknown = static_cast<int>(v);
35 HTTP2_BUG << "Invalid GoAwayPayloadDecoder::PayloadState: " << unknown;
36 return out << "GoAwayPayloadDecoder::PayloadState(" << unknown << ")";
37}
38
39DecodeStatus GoAwayPayloadDecoder::StartDecodingPayload(
40 FrameDecoderState* state,
41 DecodeBuffer* db) {
42 DVLOG(2) << "GoAwayPayloadDecoder::StartDecodingPayload: "
43 << state->frame_header();
44 DCHECK_EQ(Http2FrameType::GOAWAY, state->frame_header().type);
45 DCHECK_LE(db->Remaining(), state->frame_header().payload_length);
46 DCHECK_EQ(0, state->frame_header().flags);
47
48 state->InitializeRemainders();
49 payload_state_ = PayloadState::kStartDecodingFixedFields;
50 return ResumeDecodingPayload(state, db);
51}
52
53DecodeStatus GoAwayPayloadDecoder::ResumeDecodingPayload(
54 FrameDecoderState* state,
55 DecodeBuffer* db) {
56 DVLOG(2) << "GoAwayPayloadDecoder::ResumeDecodingPayload: remaining_payload="
57 << state->remaining_payload()
58 << ", db->Remaining=" << db->Remaining();
59
60 const Http2FrameHeader& frame_header = state->frame_header();
61 DCHECK_EQ(Http2FrameType::GOAWAY, frame_header.type);
62 DCHECK_LE(db->Remaining(), frame_header.payload_length);
63 DCHECK_NE(PayloadState::kHandleFixedFieldsStatus, payload_state_);
64
65 // |status| has to be initialized to some value to avoid compiler error in
66 // case PayloadState::kHandleFixedFieldsStatus below, but value does not
67 // matter, see DCHECK_NE above.
68 DecodeStatus status = DecodeStatus::kDecodeError;
69 size_t avail;
70 while (true) {
71 DVLOG(2) << "GoAwayPayloadDecoder::ResumeDecodingPayload payload_state_="
72 << payload_state_;
73 switch (payload_state_) {
74 case PayloadState::kStartDecodingFixedFields:
75 status = state->StartDecodingStructureInPayload(&goaway_fields_, db);
76 HTTP2_FALLTHROUGH;
77
78 case PayloadState::kHandleFixedFieldsStatus:
79 if (status == DecodeStatus::kDecodeDone) {
80 state->listener()->OnGoAwayStart(frame_header, goaway_fields_);
81 } else {
82 // Not done decoding the structure. Either we've got more payload
83 // to decode, or we've run out because the payload is too short,
84 // in which case OnFrameSizeError will have already been called.
85 DCHECK((status == DecodeStatus::kDecodeInProgress &&
86 state->remaining_payload() > 0) ||
87 (status == DecodeStatus::kDecodeError &&
88 state->remaining_payload() == 0))
89 << "\n status=" << status
90 << "; remaining_payload=" << state->remaining_payload();
91 payload_state_ = PayloadState::kResumeDecodingFixedFields;
92 return status;
93 }
94 HTTP2_FALLTHROUGH;
95
96 case PayloadState::kReadOpaqueData:
97 // The opaque data is all the remains to be decoded, so anything left
98 // in the decode buffer is opaque data.
99 avail = db->Remaining();
100 if (avail > 0) {
101 state->listener()->OnGoAwayOpaqueData(db->cursor(), avail);
102 db->AdvanceCursor(avail);
103 state->ConsumePayload(avail);
104 }
105 if (state->remaining_payload() > 0) {
106 payload_state_ = PayloadState::kReadOpaqueData;
107 return DecodeStatus::kDecodeInProgress;
108 }
109 state->listener()->OnGoAwayEnd();
110 return DecodeStatus::kDecodeDone;
111
112 case PayloadState::kResumeDecodingFixedFields:
113 status = state->ResumeDecodingStructureInPayload(&goaway_fields_, db);
114 payload_state_ = PayloadState::kHandleFixedFieldsStatus;
115 continue;
116 }
117 HTTP2_BUG << "PayloadState: " << payload_state_;
118 }
119}
120
121} // namespace http2