naiveproxy/net/quic/http/decoder/quic_http_frame_decoder.cc
2018-02-02 05:49:39 -05:00

456 lines
16 KiB
C++

// Copyright 2017 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/quic/http/decoder/quic_http_frame_decoder.h"
#include "net/quic/http/quic_http_constants.h"
#include "net/quic/platform/api/quic_bug_tracker.h"
#include "net/quic/platform/api/quic_logging.h"
namespace net {
std::ostream& operator<<(std::ostream& out, QuicHttpFrameDecoder::State v) {
switch (v) {
case QuicHttpFrameDecoder::State::kStartDecodingHeader:
return out << "kStartDecodingHeader";
case QuicHttpFrameDecoder::State::kResumeDecodingHeader:
return out << "kResumeDecodingHeader";
case QuicHttpFrameDecoder::State::kResumeDecodingPayload:
return out << "kResumeDecodingPayload";
case QuicHttpFrameDecoder::State::kDiscardPayload:
return out << "kDiscardPayload";
}
// 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);
QUIC_BUG << "QuicHttpFrameDecoder::State " << unknown;
return out << "QuicHttpFrameDecoder::State(" << unknown << ")";
}
QuicHttpFrameDecoder::QuicHttpFrameDecoder(
QuicHttpFrameDecoderListener* listener)
: state_(State::kStartDecodingHeader),
maximum_payload_size_(QuicHttpSettingsInfo::DefaultMaxFrameSize()) {
set_listener(listener);
}
void QuicHttpFrameDecoder::set_listener(
QuicHttpFrameDecoderListener* listener) {
if (listener == nullptr) {
listener = &no_op_listener_;
}
frame_decoder_state_.set_listener(listener);
}
QuicHttpFrameDecoderListener* QuicHttpFrameDecoder::listener() const {
return frame_decoder_state_.listener();
}
QuicHttpDecodeStatus QuicHttpFrameDecoder::DecodeFrame(
QuicHttpDecodeBuffer* db) {
DVLOG(2) << "QuicHttpFrameDecoder::DecodeFrame state=" << state_;
switch (state_) {
case State::kStartDecodingHeader:
if (frame_decoder_state_.StartDecodingFrameHeader(db)) {
return StartDecodingPayload(db);
}
state_ = State::kResumeDecodingHeader;
return QuicHttpDecodeStatus::kDecodeInProgress;
case State::kResumeDecodingHeader:
if (frame_decoder_state_.ResumeDecodingFrameHeader(db)) {
return StartDecodingPayload(db);
}
return QuicHttpDecodeStatus::kDecodeInProgress;
case State::kResumeDecodingPayload:
return ResumeDecodingPayload(db);
case State::kDiscardPayload:
return DiscardPayload(db);
}
QUIC_NOTREACHED();
return QuicHttpDecodeStatus::kDecodeError;
}
size_t QuicHttpFrameDecoder::remaining_payload() const {
return frame_decoder_state_.remaining_payload();
}
uint32_t QuicHttpFrameDecoder::remaining_padding() const {
return frame_decoder_state_.remaining_padding();
}
QuicHttpDecodeStatus QuicHttpFrameDecoder::StartDecodingPayload(
QuicHttpDecodeBuffer* db) {
const QuicHttpFrameHeader& header = frame_header();
// TODO(jamessynge): Remove OnFrameHeader once done with supporting
// SpdyFramer's exact states.
if (!listener()->OnFrameHeader(header)) {
DVLOG(2) << "OnFrameHeader rejected the frame, will discard; header: "
<< header;
state_ = State::kDiscardPayload;
frame_decoder_state_.InitializeRemainders();
return QuicHttpDecodeStatus::kDecodeError;
}
if (header.payload_length > maximum_payload_size_) {
DVLOG(2) << "Payload length is greater than allowed: "
<< header.payload_length << " > " << maximum_payload_size_
<< "\n header: " << header;
state_ = State::kDiscardPayload;
frame_decoder_state_.InitializeRemainders();
listener()->OnFrameSizeError(header);
return QuicHttpDecodeStatus::kDecodeError;
}
// The decode buffer can extend across many frames. Make sure that the
// buffer we pass to the start method that is specific to the frame type
// does not exend beyond this frame.
QuicHttpDecodeBufferSubset subset(db, header.payload_length);
QuicHttpDecodeStatus status;
switch (header.type) {
case QuicHttpFrameType::DATA:
status = StartDecodingDataPayload(&subset);
break;
case QuicHttpFrameType::HEADERS:
status = StartDecodingHeadersPayload(&subset);
break;
case QuicHttpFrameType::QUIC_HTTP_PRIORITY:
status = StartDecodingPriorityPayload(&subset);
break;
case QuicHttpFrameType::RST_STREAM:
status = StartDecodingRstStreamPayload(&subset);
break;
case QuicHttpFrameType::SETTINGS:
status = StartDecodingSettingsPayload(&subset);
break;
case QuicHttpFrameType::PUSH_PROMISE:
status = StartDecodingPushPromisePayload(&subset);
break;
case QuicHttpFrameType::PING:
status = StartDecodingPingPayload(&subset);
break;
case QuicHttpFrameType::GOAWAY:
status = StartDecodingGoAwayPayload(&subset);
break;
case QuicHttpFrameType::WINDOW_UPDATE:
status = StartDecodingWindowUpdatePayload(&subset);
break;
case QuicHttpFrameType::CONTINUATION:
status = StartDecodingContinuationPayload(&subset);
break;
case QuicHttpFrameType::ALTSVC:
status = StartDecodingAltSvcPayload(&subset);
break;
default:
status = StartDecodingUnknownPayload(&subset);
break;
}
if (status == QuicHttpDecodeStatus::kDecodeDone) {
state_ = State::kStartDecodingHeader;
return status;
} else if (status == QuicHttpDecodeStatus::kDecodeInProgress) {
state_ = State::kResumeDecodingPayload;
return status;
} else {
state_ = State::kDiscardPayload;
return status;
}
}
QuicHttpDecodeStatus QuicHttpFrameDecoder::ResumeDecodingPayload(
QuicHttpDecodeBuffer* db) {
// The decode buffer can extend across many frames. Make sure that the
// buffer we pass to the start method that is specific to the frame type
// does not exend beyond this frame.
size_t remaining = frame_decoder_state_.remaining_total_payload();
DCHECK_LE(remaining, frame_header().payload_length);
QuicHttpDecodeBufferSubset subset(db, remaining);
QuicHttpDecodeStatus status;
switch (frame_header().type) {
case QuicHttpFrameType::DATA:
status = ResumeDecodingDataPayload(&subset);
break;
case QuicHttpFrameType::HEADERS:
status = ResumeDecodingHeadersPayload(&subset);
break;
case QuicHttpFrameType::QUIC_HTTP_PRIORITY:
status = ResumeDecodingPriorityPayload(&subset);
break;
case QuicHttpFrameType::RST_STREAM:
status = ResumeDecodingRstStreamPayload(&subset);
break;
case QuicHttpFrameType::SETTINGS:
status = ResumeDecodingSettingsPayload(&subset);
break;
case QuicHttpFrameType::PUSH_PROMISE:
status = ResumeDecodingPushPromisePayload(&subset);
break;
case QuicHttpFrameType::PING:
status = ResumeDecodingPingPayload(&subset);
break;
case QuicHttpFrameType::GOAWAY:
status = ResumeDecodingGoAwayPayload(&subset);
break;
case QuicHttpFrameType::WINDOW_UPDATE:
status = ResumeDecodingWindowUpdatePayload(&subset);
break;
case QuicHttpFrameType::CONTINUATION:
status = ResumeDecodingContinuationPayload(&subset);
break;
case QuicHttpFrameType::ALTSVC:
status = ResumeDecodingAltSvcPayload(&subset);
break;
default:
status = ResumeDecodingUnknownPayload(&subset);
break;
}
if (status == QuicHttpDecodeStatus::kDecodeDone) {
state_ = State::kStartDecodingHeader;
return status;
} else if (status == QuicHttpDecodeStatus::kDecodeInProgress) {
return status;
} else {
state_ = State::kDiscardPayload;
return status;
}
}
// Clear any of the flags in the frame header that aren't set in valid_flags.
void QuicHttpFrameDecoder::RetainFlags(uint8_t valid_flags) {
frame_decoder_state_.RetainFlags(valid_flags);
}
// Clear all of the flags in the frame header; for use with frame types that
// don't define any flags, such as WINDOW_UPDATE.
void QuicHttpFrameDecoder::ClearFlags() {
frame_decoder_state_.ClearFlags();
}
QuicHttpDecodeStatus QuicHttpFrameDecoder::StartDecodingAltSvcPayload(
QuicHttpDecodeBuffer* db) {
ClearFlags();
return altsvc_payload_decoder_.StartDecodingPayload(&frame_decoder_state_,
db);
}
QuicHttpDecodeStatus QuicHttpFrameDecoder::ResumeDecodingAltSvcPayload(
QuicHttpDecodeBuffer* db) {
// The frame is not paddable.
DCHECK_EQ(frame_decoder_state_.remaining_total_payload(),
frame_decoder_state_.remaining_payload());
return altsvc_payload_decoder_.ResumeDecodingPayload(&frame_decoder_state_,
db);
}
QuicHttpDecodeStatus QuicHttpFrameDecoder::StartDecodingContinuationPayload(
QuicHttpDecodeBuffer* db) {
RetainFlags(QuicHttpFrameFlag::QUIC_HTTP_END_HEADERS);
return continuation_payload_decoder_.StartDecodingPayload(
&frame_decoder_state_, db);
}
QuicHttpDecodeStatus QuicHttpFrameDecoder::ResumeDecodingContinuationPayload(
QuicHttpDecodeBuffer* db) {
// The frame is not paddable.
DCHECK_EQ(frame_decoder_state_.remaining_total_payload(),
frame_decoder_state_.remaining_payload());
return continuation_payload_decoder_.ResumeDecodingPayload(
&frame_decoder_state_, db);
}
QuicHttpDecodeStatus QuicHttpFrameDecoder::StartDecodingDataPayload(
QuicHttpDecodeBuffer* db) {
RetainFlags(QuicHttpFrameFlag::QUIC_HTTP_END_STREAM |
QuicHttpFrameFlag::QUIC_HTTP_PADDED);
return data_payload_decoder_.StartDecodingPayload(&frame_decoder_state_, db);
}
QuicHttpDecodeStatus QuicHttpFrameDecoder::ResumeDecodingDataPayload(
QuicHttpDecodeBuffer* db) {
return data_payload_decoder_.ResumeDecodingPayload(&frame_decoder_state_, db);
}
QuicHttpDecodeStatus QuicHttpFrameDecoder::StartDecodingGoAwayPayload(
QuicHttpDecodeBuffer* db) {
ClearFlags();
return goaway_payload_decoder_.StartDecodingPayload(&frame_decoder_state_,
db);
}
QuicHttpDecodeStatus QuicHttpFrameDecoder::ResumeDecodingGoAwayPayload(
QuicHttpDecodeBuffer* db) {
// The frame is not paddable.
DCHECK_EQ(frame_decoder_state_.remaining_total_payload(),
frame_decoder_state_.remaining_payload());
return goaway_payload_decoder_.ResumeDecodingPayload(&frame_decoder_state_,
db);
}
QuicHttpDecodeStatus QuicHttpFrameDecoder::StartDecodingHeadersPayload(
QuicHttpDecodeBuffer* db) {
RetainFlags(QuicHttpFrameFlag::QUIC_HTTP_END_STREAM |
QuicHttpFrameFlag::QUIC_HTTP_END_HEADERS |
QuicHttpFrameFlag::QUIC_HTTP_PADDED |
QuicHttpFrameFlag::QUIC_HTTP_PRIORITY);
return headers_payload_decoder_.StartDecodingPayload(&frame_decoder_state_,
db);
}
QuicHttpDecodeStatus QuicHttpFrameDecoder::ResumeDecodingHeadersPayload(
QuicHttpDecodeBuffer* db) {
DCHECK_LE(frame_decoder_state_.remaining_payload_and_padding(),
frame_header().payload_length);
return headers_payload_decoder_.ResumeDecodingPayload(&frame_decoder_state_,
db);
}
QuicHttpDecodeStatus QuicHttpFrameDecoder::StartDecodingPingPayload(
QuicHttpDecodeBuffer* db) {
RetainFlags(QuicHttpFrameFlag::QUIC_HTTP_ACK);
return ping_payload_decoder_.StartDecodingPayload(&frame_decoder_state_, db);
}
QuicHttpDecodeStatus QuicHttpFrameDecoder::ResumeDecodingPingPayload(
QuicHttpDecodeBuffer* db) {
// The frame is not paddable.
DCHECK_EQ(frame_decoder_state_.remaining_total_payload(),
frame_decoder_state_.remaining_payload());
return ping_payload_decoder_.ResumeDecodingPayload(&frame_decoder_state_, db);
}
QuicHttpDecodeStatus QuicHttpFrameDecoder::StartDecodingPriorityPayload(
QuicHttpDecodeBuffer* db) {
ClearFlags();
return priority_payload_decoder_.StartDecodingPayload(&frame_decoder_state_,
db);
}
QuicHttpDecodeStatus QuicHttpFrameDecoder::ResumeDecodingPriorityPayload(
QuicHttpDecodeBuffer* db) {
// The frame is not paddable.
DCHECK_EQ(frame_decoder_state_.remaining_total_payload(),
frame_decoder_state_.remaining_payload());
return priority_payload_decoder_.ResumeDecodingPayload(&frame_decoder_state_,
db);
}
QuicHttpDecodeStatus QuicHttpFrameDecoder::StartDecodingPushPromisePayload(
QuicHttpDecodeBuffer* db) {
RetainFlags(QuicHttpFrameFlag::QUIC_HTTP_END_HEADERS |
QuicHttpFrameFlag::QUIC_HTTP_PADDED);
return push_promise_payload_decoder_.StartDecodingPayload(
&frame_decoder_state_, db);
}
QuicHttpDecodeStatus QuicHttpFrameDecoder::ResumeDecodingPushPromisePayload(
QuicHttpDecodeBuffer* db) {
DCHECK_LE(frame_decoder_state_.remaining_payload_and_padding(),
frame_header().payload_length);
return push_promise_payload_decoder_.ResumeDecodingPayload(
&frame_decoder_state_, db);
}
QuicHttpDecodeStatus QuicHttpFrameDecoder::StartDecodingRstStreamPayload(
QuicHttpDecodeBuffer* db) {
ClearFlags();
return rst_stream_payload_decoder_.StartDecodingPayload(&frame_decoder_state_,
db);
}
QuicHttpDecodeStatus QuicHttpFrameDecoder::ResumeDecodingRstStreamPayload(
QuicHttpDecodeBuffer* db) {
// The frame is not paddable.
DCHECK_EQ(frame_decoder_state_.remaining_total_payload(),
frame_decoder_state_.remaining_payload());
return rst_stream_payload_decoder_.ResumeDecodingPayload(
&frame_decoder_state_, db);
}
QuicHttpDecodeStatus QuicHttpFrameDecoder::StartDecodingSettingsPayload(
QuicHttpDecodeBuffer* db) {
RetainFlags(QuicHttpFrameFlag::QUIC_HTTP_ACK);
return settings_payload_decoder_.StartDecodingPayload(&frame_decoder_state_,
db);
}
QuicHttpDecodeStatus QuicHttpFrameDecoder::ResumeDecodingSettingsPayload(
QuicHttpDecodeBuffer* db) {
// The frame is not paddable.
DCHECK_EQ(frame_decoder_state_.remaining_total_payload(),
frame_decoder_state_.remaining_payload());
return settings_payload_decoder_.ResumeDecodingPayload(&frame_decoder_state_,
db);
}
QuicHttpDecodeStatus QuicHttpFrameDecoder::StartDecodingUnknownPayload(
QuicHttpDecodeBuffer* db) {
// We don't known what type of frame this is, so we don't know which flags
// are valid, so we don't touch them.
return unknown_payload_decoder_.StartDecodingPayload(&frame_decoder_state_,
db);
}
QuicHttpDecodeStatus QuicHttpFrameDecoder::ResumeDecodingUnknownPayload(
QuicHttpDecodeBuffer* db) {
// We don't known what type of frame this is, so we treat it as not paddable.
DCHECK_EQ(frame_decoder_state_.remaining_total_payload(),
frame_decoder_state_.remaining_payload());
return unknown_payload_decoder_.ResumeDecodingPayload(&frame_decoder_state_,
db);
}
QuicHttpDecodeStatus QuicHttpFrameDecoder::StartDecodingWindowUpdatePayload(
QuicHttpDecodeBuffer* db) {
ClearFlags();
return window_update_payload_decoder_.StartDecodingPayload(
&frame_decoder_state_, db);
}
QuicHttpDecodeStatus QuicHttpFrameDecoder::ResumeDecodingWindowUpdatePayload(
QuicHttpDecodeBuffer* db) {
// The frame is not paddable.
DCHECK_EQ(frame_decoder_state_.remaining_total_payload(),
frame_decoder_state_.remaining_payload());
return window_update_payload_decoder_.ResumeDecodingPayload(
&frame_decoder_state_, db);
}
QuicHttpDecodeStatus QuicHttpFrameDecoder::DiscardPayload(
QuicHttpDecodeBuffer* db) {
DVLOG(2) << "remaining_payload=" << frame_decoder_state_.remaining_payload_
<< "; remaining_padding=" << frame_decoder_state_.remaining_padding_;
frame_decoder_state_.remaining_payload_ +=
frame_decoder_state_.remaining_padding_;
frame_decoder_state_.remaining_padding_ = 0;
const size_t avail = frame_decoder_state_.AvailablePayload(db);
DVLOG(2) << "avail=" << avail;
if (avail > 0) {
frame_decoder_state_.ConsumePayload(avail);
db->AdvanceCursor(avail);
}
if (frame_decoder_state_.remaining_payload_ == 0) {
state_ = State::kStartDecodingHeader;
return QuicHttpDecodeStatus::kDecodeDone;
}
return QuicHttpDecodeStatus::kDecodeInProgress;
}
} // namespace net