| // 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 size_t 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() {} | |
| size_t HttpDecoder::ProcessInput(const char* data, size_t len) { | |
| has_payload_ = false; | |
| QuicDataReader reader(data, len, NETWORK_BYTE_ORDER); | |
| 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_, NETWORK_BYTE_ORDER); | |
| if (!length_reader.ReadVarInt62(¤t_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(¤t_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_)); | |
| } | |
| size_t bytes_to_read = | |
| std::min<size_t>(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(); | |
| } | |
| size_t bytes_to_read = | |
| std::min<size_t>(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(); | |
| } | |
| 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_, | |
| NETWORK_BYTE_ORDER); | |
| 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_, | |
| NETWORK_BYTE_ORDER); | |
| 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_, | |
| NETWORK_BYTE_ORDER); | |
| 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_) { | |
| size_t 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); | |
| } | |
| size_t bytes_to_read = | |
| std::min<size_t>(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_, | |
| NETWORK_BYTE_ORDER); | |
| 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_, | |
| NETWORK_BYTE_ORDER); | |
| 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_, | |
| NETWORK_BYTE_ORDER); | |
| 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) { | |
| size_t bytes_to_read = | |
| std::min<size_t>(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_); | |
| } | |
| size_t bytes_to_read = | |
| std::min<size_t>(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_); | |
| } | |
| size_t bytes_to_read = std::min<size_t>(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 |