blob: 4c625c0df0431f5c0dcae5afe96b88de137166eb [file] [log] [blame]
// Copyright 2013 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/quic_receive_control_stream.h"
#include "net/third_party/quiche/src/quic/core/http/quic_spdy_session.h"
#include "net/third_party/quiche/src/quic/core/quic_utils.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
namespace quic {
const uint16_t kSettingsMaxHeaderListSize = 6;
const uint16_t kSettingsNumPlaceholders = 8;
// Visitor of HttpDecoder that passes data frame to QuicSpdyStream and closes
// the connection on unexpected frames.
class QuicReceiveControlStream::HttpDecoderVisitor
: public HttpDecoder::Visitor {
public:
explicit HttpDecoderVisitor(QuicReceiveControlStream* stream)
: stream_(stream) {}
HttpDecoderVisitor(const HttpDecoderVisitor&) = delete;
HttpDecoderVisitor& operator=(const HttpDecoderVisitor&) = delete;
void OnError(HttpDecoder* decoder) override {
stream_->session()->connection()->CloseConnection(
QUIC_HTTP_DECODER_ERROR, "Http decoder internal error",
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
}
void OnPriorityFrame(const PriorityFrame& frame) override {
CloseConnectionOnWrongFrame("Priority");
}
void OnCancelPushFrame(const CancelPushFrame& frame) override {
CloseConnectionOnWrongFrame("Cancel Push");
}
void OnMaxPushIdFrame(const MaxPushIdFrame& frame) override {
CloseConnectionOnWrongFrame("Max Push Id");
}
void OnGoAwayFrame(const GoAwayFrame& frame) override {
CloseConnectionOnWrongFrame("Goaway");
}
void OnSettingsFrameStart(Http3FrameLengths frame_lengths) override {
stream_->OnSettingsFrameStart(frame_lengths);
}
void OnSettingsFrame(const SettingsFrame& frame) override {
stream_->OnSettingsFrame(frame);
}
void OnDuplicatePushFrame(const DuplicatePushFrame& frame) override {
CloseConnectionOnWrongFrame("Duplicate Push");
}
void OnDataFrameStart(Http3FrameLengths frame_lengths) override {
CloseConnectionOnWrongFrame("Data");
}
void OnDataFramePayload(QuicStringPiece payload) override {
CloseConnectionOnWrongFrame("Data");
}
void OnDataFrameEnd() override { CloseConnectionOnWrongFrame("Data"); }
void OnHeadersFrameStart(Http3FrameLengths frame_length) override {
CloseConnectionOnWrongFrame("Headers");
}
void OnHeadersFramePayload(QuicStringPiece payload) override {
CloseConnectionOnWrongFrame("Headers");
}
void OnHeadersFrameEnd() override { CloseConnectionOnWrongFrame("Headers"); }
void OnPushPromiseFrameStart(PushId push_id) override {
CloseConnectionOnWrongFrame("Push Promise");
}
void OnPushPromiseFramePayload(QuicStringPiece payload) override {
CloseConnectionOnWrongFrame("Push Promise");
}
void OnPushPromiseFrameEnd() override {
CloseConnectionOnWrongFrame("Push Promise");
}
private:
void CloseConnectionOnWrongFrame(std::string frame_type) {
// TODO(renjietang): Change to HTTP/3 error type.
stream_->session()->connection()->CloseConnection(
QUIC_HTTP_DECODER_ERROR,
frame_type + " frame received on control stream",
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
}
QuicReceiveControlStream* stream_;
};
QuicReceiveControlStream::QuicReceiveControlStream(QuicStreamId id,
QuicSpdySession* session)
: QuicStream(id, session, /*is_static = */ true, READ_UNIDIRECTIONAL),
received_settings_length_(0),
http_decoder_visitor_(new HttpDecoderVisitor(this)) {
decoder_.set_visitor(http_decoder_visitor_.get());
sequencer()->set_level_triggered(true);
}
QuicReceiveControlStream::~QuicReceiveControlStream() {}
void QuicReceiveControlStream::OnStreamReset(const QuicRstStreamFrame& frame) {
// TODO(renjietang) Change the error code to H/3 specific
// HTTP_CLOSED_CRITICAL_STREAM.
session()->connection()->CloseConnection(
QUIC_INVALID_STREAM_ID, "Attempt to reset receive control stream",
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
}
void QuicReceiveControlStream::OnDataAvailable() {
iovec iov;
while (!reading_stopped() && sequencer()->PrefetchNextRegion(&iov)) {
decoder_.ProcessInput(reinterpret_cast<const char*>(iov.iov_base),
iov.iov_len);
}
}
void QuicReceiveControlStream::OnSettingsFrameStart(
Http3FrameLengths frame_lengths) {
if (received_settings_length_ != 0) {
// TODO(renjietang): Change error code to HTTP_UNEXPECTED_FRAME.
session()->connection()->CloseConnection(
QUIC_INVALID_STREAM_ID, "Settings frames are received twice.",
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
return;
}
received_settings_length_ +=
frame_lengths.header_length + frame_lengths.payload_length;
}
void QuicReceiveControlStream::OnSettingsFrame(const SettingsFrame& settings) {
QuicSpdySession* spdy_session = static_cast<QuicSpdySession*>(session());
for (auto& it : settings.values) {
uint16_t setting_id = it.first;
switch (setting_id) {
case kSettingsMaxHeaderListSize:
spdy_session->set_max_inbound_header_list_size(it.second);
break;
case kSettingsNumPlaceholders:
// TODO: Support placeholder setting
break;
default:
break;
}
}
sequencer()->MarkConsumed(received_settings_length_);
}
} // namespace quic