blob: e697821a098c9b03779f91dd6bd29c160cbf4fd9 [file] [log] [blame]
// Copyright (c) 2018 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/third_party/quiche/src/quic/core/http/http_decoder.h"
#include "net/third_party/quiche/src/quic/core/quic_data_reader.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_fallthrough.h"
namespace quic {
namespace {
// Create a mask that sets the last |num_bits| to 1 and the rest to 0.
inline uint8_t GetMaskFromNumBits(uint8_t num_bits) {
return (1u << num_bits) - 1;
}
// Extract |num_bits| from |flags| offset by |offset|.
uint8_t ExtractBits(uint8_t flags, uint8_t num_bits, uint8_t offset) {
return (flags >> offset) & GetMaskFromNumBits(num_bits);
}
// Length of the type field of HTTP/3 frames.
static const QuicByteCount kFrameTypeLength = 1;
} // namespace
HttpDecoder::HttpDecoder()
: visitor_(nullptr),
state_(STATE_READING_FRAME_LENGTH),
current_frame_type_(0),
current_length_field_size_(0),
remaining_length_field_length_(0),
current_frame_length_(0),
remaining_frame_length_(0),
error_(QUIC_NO_ERROR),
error_detail_(""),
has_payload_(false) {}
HttpDecoder::~HttpDecoder() {}
QuicByteCount HttpDecoder::ProcessInput(const char* data, QuicByteCount len) {
has_payload_ = false;
QuicDataReader reader(data, len);
while (error_ == QUIC_NO_ERROR && reader.BytesRemaining() != 0) {
switch (state_) {
case STATE_READING_FRAME_LENGTH:
ReadFrameLength(&reader);
break;
case STATE_READING_FRAME_TYPE:
ReadFrameType(&reader);
break;
case STATE_READING_FRAME_PAYLOAD:
ReadFramePayload(&reader);
break;
case STATE_ERROR:
break;
default:
QUIC_BUG << "Invalid state: " << state_;
}
}
if (error_ != QUIC_NO_ERROR) {
return 0;
}
return len - reader.BytesRemaining();
}
void HttpDecoder::ReadFrameLength(QuicDataReader* reader) {
DCHECK_NE(0u, reader->BytesRemaining());
BufferFrameLength(reader);
if (remaining_length_field_length_ != 0) {
return;
}
QuicDataReader length_reader(length_buffer_.data(),
current_length_field_size_);
if (!length_reader.ReadVarInt62(&current_frame_length_)) {
RaiseError(QUIC_INTERNAL_ERROR, "Unable to read frame length");
visitor_->OnError(this);
return;
}
state_ = STATE_READING_FRAME_TYPE;
remaining_frame_length_ = current_frame_length_;
}
void HttpDecoder::ReadFrameType(QuicDataReader* reader) {
DCHECK_NE(0u, reader->BytesRemaining());
if (!reader->ReadUInt8(&current_frame_type_)) {
RaiseError(QUIC_INTERNAL_ERROR, "Unable to read frame type");
return;
}
state_ = STATE_READING_FRAME_PAYLOAD;
}
void HttpDecoder::ReadFramePayload(QuicDataReader* reader) {
DCHECK_NE(0u, reader->BytesRemaining());
switch (current_frame_type_) {
case 0x0: { // DATA
if (current_frame_length_ == remaining_frame_length_) {
visitor_->OnDataFrameStart(
Http3FrameLengths(current_length_field_size_ + kFrameTypeLength,
current_frame_length_));
}
QuicByteCount bytes_to_read = std::min<QuicByteCount>(
remaining_frame_length_, reader->BytesRemaining());
QuicStringPiece payload;
if (!reader->ReadStringPiece(&payload, bytes_to_read)) {
RaiseError(QUIC_INTERNAL_ERROR, "Unable to read data");
return;
}
has_payload_ = true;
visitor_->OnDataFramePayload(payload);
remaining_frame_length_ -= payload.length();
if (remaining_frame_length_ == 0) {
state_ = STATE_READING_FRAME_LENGTH;
current_length_field_size_ = 0;
visitor_->OnDataFrameEnd();
}
return;
}
case 0x1: { // HEADERS
if (current_frame_length_ == remaining_frame_length_) {
visitor_->OnHeadersFrameStart();
}
QuicByteCount bytes_to_read = std::min<QuicByteCount>(
remaining_frame_length_, reader->BytesRemaining());
QuicStringPiece payload;
if (!reader->ReadStringPiece(&payload, bytes_to_read)) {
RaiseError(QUIC_INTERNAL_ERROR, "Unable to read data");
return;
}
visitor_->OnHeadersFramePayload(payload);
remaining_frame_length_ -= payload.length();
if (remaining_frame_length_ == 0) {
state_ = STATE_READING_FRAME_LENGTH;
current_length_field_size_ = 0;
visitor_->OnHeadersFrameEnd(current_frame_length_);
}
return;
}
case 0x2: { // PRIORITY
// TODO(rch): avoid buffering if the entire frame is present, and
// instead parse directly out of |reader|.
BufferFramePayload(reader);
if (remaining_frame_length_ == 0) {
PriorityFrame frame;
QuicDataReader reader(buffer_.data(), current_frame_length_);
if (!ParsePriorityFrame(&reader, &frame)) {
return;
}
visitor_->OnPriorityFrame(frame);
state_ = STATE_READING_FRAME_LENGTH;
current_length_field_size_ = 0;
}
return;
}
case 0x3: { // CANCEL_PUSH
// TODO(rch): Handle partial delivery.
BufferFramePayload(reader);
if (remaining_frame_length_ == 0) {
CancelPushFrame frame;
QuicDataReader reader(buffer_.data(), current_frame_length_);
if (!reader.ReadVarInt62(&frame.push_id)) {
RaiseError(QUIC_INTERNAL_ERROR, "Unable to read push_id");
return;
}
visitor_->OnCancelPushFrame(frame);
state_ = STATE_READING_FRAME_LENGTH;
current_length_field_size_ = 0;
}
return;
}
case 0x4: { // SETTINGS
// TODO(rch): Handle overly large SETTINGS frames. Either:
// 1. Impose a limit on SETTINGS frame size, and close the connection if
// exceeded
// 2. Implement a streaming parsing mode.
BufferFramePayload(reader);
if (remaining_frame_length_ == 0) {
SettingsFrame frame;
QuicDataReader reader(buffer_.data(), current_frame_length_);
if (!ParseSettingsFrame(&reader, &frame)) {
return;
}
visitor_->OnSettingsFrame(frame);
state_ = STATE_READING_FRAME_LENGTH;
current_length_field_size_ = 0;
}
return;
}
case 0x5: { // PUSH_PROMISE
if (current_frame_length_ == remaining_frame_length_) {
QuicByteCount bytes_remaining = reader->BytesRemaining();
PushId push_id;
// TODO(rch): Handle partial delivery of this field.
if (!reader->ReadVarInt62(&push_id)) {
RaiseError(QUIC_INTERNAL_ERROR, "Unable to read push_id");
return;
}
remaining_frame_length_ -= bytes_remaining - reader->BytesRemaining();
visitor_->OnPushPromiseFrameStart(push_id);
}
QuicByteCount bytes_to_read = std::min<QuicByteCount>(
remaining_frame_length_, reader->BytesRemaining());
if (bytes_to_read == 0) {
return;
}
QuicStringPiece payload;
if (!reader->ReadStringPiece(&payload, bytes_to_read)) {
RaiseError(QUIC_INTERNAL_ERROR, "Unable to read data");
return;
}
visitor_->OnPushPromiseFramePayload(payload);
remaining_frame_length_ -= payload.length();
if (remaining_frame_length_ == 0) {
state_ = STATE_READING_FRAME_LENGTH;
current_length_field_size_ = 0;
visitor_->OnPushPromiseFrameEnd();
}
return;
}
case 0x7: { // GOAWAY
BufferFramePayload(reader);
if (remaining_frame_length_ == 0) {
GoAwayFrame frame;
QuicDataReader reader(buffer_.data(), current_frame_length_);
uint64_t stream_id;
if (!reader.ReadVarInt62(&stream_id)) {
RaiseError(QUIC_INTERNAL_ERROR, "Unable to read GOAWAY stream_id");
return;
}
frame.stream_id = stream_id;
visitor_->OnGoAwayFrame(frame);
state_ = STATE_READING_FRAME_LENGTH;
current_length_field_size_ = 0;
}
return;
}
case 0xD: { // MAX_PUSH_ID
// TODO(rch): Handle partial delivery.
BufferFramePayload(reader);
if (remaining_frame_length_ == 0) {
QuicDataReader reader(buffer_.data(), current_frame_length_);
MaxPushIdFrame frame;
if (!reader.ReadVarInt62(&frame.push_id)) {
RaiseError(QUIC_INTERNAL_ERROR, "Unable to read push_id");
return;
}
visitor_->OnMaxPushIdFrame(frame);
state_ = STATE_READING_FRAME_LENGTH;
current_length_field_size_ = 0;
}
return;
}
case 0xE: { // DUPLICATE_PUSH
BufferFramePayload(reader);
if (remaining_frame_length_ != 0) {
return;
}
QuicDataReader reader(buffer_.data(), current_frame_length_);
DuplicatePushFrame frame;
if (!reader.ReadVarInt62(&frame.push_id)) {
RaiseError(QUIC_INTERNAL_ERROR, "Unable to read push_id");
return;
}
visitor_->OnDuplicatePushFrame(frame);
state_ = STATE_READING_FRAME_LENGTH;
current_length_field_size_ = 0;
return;
}
// Reserved frame types.
// TODO(rch): Since these are actually the same behavior as the
// default, we probably don't need to special case them here?
case 0xB:
QUIC_FALLTHROUGH_INTENDED;
case 0xB + 0x1F:
QUIC_FALLTHROUGH_INTENDED;
case 0xB + 0x1F * 2:
QUIC_FALLTHROUGH_INTENDED;
case 0xB + 0x1F * 3:
QUIC_FALLTHROUGH_INTENDED;
case 0xB + 0x1F * 4:
QUIC_FALLTHROUGH_INTENDED;
case 0xB + 0x1F * 5:
QUIC_FALLTHROUGH_INTENDED;
case 0xB + 0x1F * 6:
QUIC_FALLTHROUGH_INTENDED;
case 0xB + 0x1F * 7:
QUIC_FALLTHROUGH_INTENDED;
default:
DiscardFramePayload(reader);
}
}
void HttpDecoder::DiscardFramePayload(QuicDataReader* reader) {
QuicByteCount bytes_to_read = std::min<QuicByteCount>(
remaining_frame_length_, reader->BytesRemaining());
QuicStringPiece payload;
if (!reader->ReadStringPiece(&payload, bytes_to_read)) {
RaiseError(QUIC_INTERNAL_ERROR, "Unable to read frame payload");
return;
}
remaining_frame_length_ -= payload.length();
if (remaining_frame_length_ == 0) {
state_ = STATE_READING_FRAME_LENGTH;
current_length_field_size_ = 0;
}
}
void HttpDecoder::BufferFramePayload(QuicDataReader* reader) {
if (current_frame_length_ == remaining_frame_length_) {
buffer_.erase(buffer_.size());
buffer_.reserve(current_frame_length_);
}
QuicByteCount bytes_to_read = std::min<QuicByteCount>(
remaining_frame_length_, reader->BytesRemaining());
if (!reader->ReadBytes(
&(buffer_[0]) + current_frame_length_ - remaining_frame_length_,
bytes_to_read)) {
RaiseError(QUIC_INTERNAL_ERROR, "Unable to read frame payload");
return;
}
remaining_frame_length_ -= bytes_to_read;
}
void HttpDecoder::BufferFrameLength(QuicDataReader* reader) {
if (current_length_field_size_ == 0) {
current_length_field_size_ = reader->PeekVarInt62Length();
if (current_length_field_size_ == 0) {
RaiseError(QUIC_INTERNAL_ERROR, "Unable to read frame length");
visitor_->OnError(this);
return;
}
remaining_length_field_length_ = current_length_field_size_;
}
if (current_length_field_size_ == remaining_length_field_length_) {
length_buffer_.erase(length_buffer_.size());
length_buffer_.reserve(current_length_field_size_);
}
QuicByteCount bytes_to_read = std::min<QuicByteCount>(
remaining_length_field_length_, reader->BytesRemaining());
if (!reader->ReadBytes(&(length_buffer_[0]) + current_length_field_size_ -
remaining_length_field_length_,
bytes_to_read)) {
RaiseError(QUIC_INTERNAL_ERROR, "Unable to read frame length");
visitor_->OnError(this);
return;
}
remaining_length_field_length_ -= bytes_to_read;
}
void HttpDecoder::RaiseError(QuicErrorCode error, QuicString error_detail) {
state_ = STATE_ERROR;
error_ = error;
error_detail_ = std::move(error_detail);
}
bool HttpDecoder::ParsePriorityFrame(QuicDataReader* reader,
PriorityFrame* frame) {
uint8_t flags;
if (!reader->ReadUInt8(&flags)) {
RaiseError(QUIC_INTERNAL_ERROR, "Unable to read priority frame flags");
return false;
}
frame->prioritized_type =
static_cast<PriorityElementType>(ExtractBits(flags, 2, 6));
frame->dependency_type =
static_cast<PriorityElementType>(ExtractBits(flags, 2, 4));
frame->exclusive = flags % 2 == 1;
if (!reader->ReadVarInt62(&frame->prioritized_element_id)) {
RaiseError(QUIC_INTERNAL_ERROR, "Unable to read prioritized_element_id");
return false;
}
if (!reader->ReadVarInt62(&frame->element_dependency_id)) {
RaiseError(QUIC_INTERNAL_ERROR, "Unable to read element_dependency_id");
return false;
}
if (!reader->ReadUInt8(&frame->weight)) {
RaiseError(QUIC_INTERNAL_ERROR, "Unable to read priority frame weight");
return false;
}
return true;
}
bool HttpDecoder::ParseSettingsFrame(QuicDataReader* reader,
SettingsFrame* frame) {
while (!reader->IsDoneReading()) {
uint16_t id;
if (!reader->ReadUInt16(&id)) {
RaiseError(QUIC_INTERNAL_ERROR,
"Unable to read settings frame identifier");
return false;
}
uint64_t content;
if (!reader->ReadVarInt62(&content)) {
RaiseError(QUIC_INTERNAL_ERROR, "Unable to read settings frame content");
return false;
}
frame->values[id] = content;
}
return true;
}
} // namespace quic