mirror of
https://github.com/klzgrad/naiveproxy.git
synced 2024-12-01 09:46:09 +03:00
121 lines
4.8 KiB
C++
121 lines
4.8 KiB
C++
|
// Copyright 2016 The Chromium Authors. All rights reserved.
|
||
|
// Use of this source code is governed by a BSD-style license that can be
|
||
|
// found in the LICENSE file.
|
||
|
|
||
|
#include "net/http2/decoder/payload_decoders/goaway_payload_decoder.h"
|
||
|
|
||
|
#include <stddef.h>
|
||
|
|
||
|
#include "base/logging.h"
|
||
|
#include "base/macros.h"
|
||
|
#include "net/http2/decoder/decode_buffer.h"
|
||
|
#include "net/http2/decoder/http2_frame_decoder_listener.h"
|
||
|
#include "net/http2/http2_constants.h"
|
||
|
#include "net/http2/http2_structures.h"
|
||
|
#include "net/http2/tools/http2_bug_tracker.h"
|
||
|
|
||
|
namespace net {
|
||
|
|
||
|
std::ostream& operator<<(std::ostream& out,
|
||
|
GoAwayPayloadDecoder::PayloadState v) {
|
||
|
switch (v) {
|
||
|
case GoAwayPayloadDecoder::PayloadState::kStartDecodingFixedFields:
|
||
|
return out << "kStartDecodingFixedFields";
|
||
|
case GoAwayPayloadDecoder::PayloadState::kHandleFixedFieldsStatus:
|
||
|
return out << "kHandleFixedFieldsStatus";
|
||
|
case GoAwayPayloadDecoder::PayloadState::kReadOpaqueData:
|
||
|
return out << "kReadOpaqueData";
|
||
|
case GoAwayPayloadDecoder::PayloadState::kResumeDecodingFixedFields:
|
||
|
return out << "kResumeDecodingFixedFields";
|
||
|
}
|
||
|
// Since the value doesn't come over the wire, only a programming bug should
|
||
|
// result in reaching this point.
|
||
|
int unknown = static_cast<int>(v);
|
||
|
HTTP2_BUG << "Invalid GoAwayPayloadDecoder::PayloadState: " << unknown;
|
||
|
return out << "GoAwayPayloadDecoder::PayloadState(" << unknown << ")";
|
||
|
}
|
||
|
|
||
|
DecodeStatus GoAwayPayloadDecoder::StartDecodingPayload(
|
||
|
FrameDecoderState* state,
|
||
|
DecodeBuffer* db) {
|
||
|
DVLOG(2) << "GoAwayPayloadDecoder::StartDecodingPayload: "
|
||
|
<< state->frame_header();
|
||
|
DCHECK_EQ(Http2FrameType::GOAWAY, state->frame_header().type);
|
||
|
DCHECK_LE(db->Remaining(), state->frame_header().payload_length);
|
||
|
DCHECK_EQ(0, state->frame_header().flags);
|
||
|
|
||
|
state->InitializeRemainders();
|
||
|
payload_state_ = PayloadState::kStartDecodingFixedFields;
|
||
|
return ResumeDecodingPayload(state, db);
|
||
|
}
|
||
|
|
||
|
DecodeStatus GoAwayPayloadDecoder::ResumeDecodingPayload(
|
||
|
FrameDecoderState* state,
|
||
|
DecodeBuffer* db) {
|
||
|
DVLOG(2) << "GoAwayPayloadDecoder::ResumeDecodingPayload: remaining_payload="
|
||
|
<< state->remaining_payload()
|
||
|
<< ", db->Remaining=" << db->Remaining();
|
||
|
|
||
|
const Http2FrameHeader& frame_header = state->frame_header();
|
||
|
DCHECK_EQ(Http2FrameType::GOAWAY, frame_header.type);
|
||
|
DCHECK_LE(db->Remaining(), frame_header.payload_length);
|
||
|
DCHECK_NE(PayloadState::kHandleFixedFieldsStatus, payload_state_);
|
||
|
|
||
|
// |status| has to be initialized to some value to avoid compiler error in
|
||
|
// case PayloadState::kHandleFixedFieldsStatus below, but value does not
|
||
|
// matter, see DCHECK_NE above.
|
||
|
DecodeStatus status = DecodeStatus::kDecodeError;
|
||
|
size_t avail;
|
||
|
while (true) {
|
||
|
DVLOG(2) << "GoAwayPayloadDecoder::ResumeDecodingPayload payload_state_="
|
||
|
<< payload_state_;
|
||
|
switch (payload_state_) {
|
||
|
case PayloadState::kStartDecodingFixedFields:
|
||
|
status = state->StartDecodingStructureInPayload(&goaway_fields_, db);
|
||
|
// FALLTHROUGH_INTENDED
|
||
|
|
||
|
case PayloadState::kHandleFixedFieldsStatus:
|
||
|
if (status == DecodeStatus::kDecodeDone) {
|
||
|
state->listener()->OnGoAwayStart(frame_header, goaway_fields_);
|
||
|
} else {
|
||
|
// Not done decoding the structure. Either we've got more payload
|
||
|
// to decode, or we've run out because the payload is too short,
|
||
|
// in which case OnFrameSizeError will have already been called.
|
||
|
DCHECK((status == DecodeStatus::kDecodeInProgress &&
|
||
|
state->remaining_payload() > 0) ||
|
||
|
(status == DecodeStatus::kDecodeError &&
|
||
|
state->remaining_payload() == 0))
|
||
|
<< "\n status=" << status
|
||
|
<< "; remaining_payload=" << state->remaining_payload();
|
||
|
payload_state_ = PayloadState::kResumeDecodingFixedFields;
|
||
|
return status;
|
||
|
}
|
||
|
// FALLTHROUGH_INTENDED
|
||
|
|
||
|
case PayloadState::kReadOpaqueData:
|
||
|
// The opaque data is all the remains to be decoded, so anything left
|
||
|
// in the decode buffer is opaque data.
|
||
|
avail = db->Remaining();
|
||
|
if (avail > 0) {
|
||
|
state->listener()->OnGoAwayOpaqueData(db->cursor(), avail);
|
||
|
db->AdvanceCursor(avail);
|
||
|
state->ConsumePayload(avail);
|
||
|
}
|
||
|
if (state->remaining_payload() > 0) {
|
||
|
payload_state_ = PayloadState::kReadOpaqueData;
|
||
|
return DecodeStatus::kDecodeInProgress;
|
||
|
}
|
||
|
state->listener()->OnGoAwayEnd();
|
||
|
return DecodeStatus::kDecodeDone;
|
||
|
|
||
|
case PayloadState::kResumeDecodingFixedFields:
|
||
|
status = state->ResumeDecodingStructureInPayload(&goaway_fields_, db);
|
||
|
payload_state_ = PayloadState::kHandleFixedFieldsStatus;
|
||
|
continue;
|
||
|
}
|
||
|
HTTP2_BUG << "PayloadState: " << payload_state_;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
} // namespace net
|