mirror of
https://github.com/klzgrad/naiveproxy.git
synced 2024-11-25 06:46:09 +03:00
328 lines
12 KiB
C++
328 lines
12 KiB
C++
// Copyright (c) 2012 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/spdy/buffered_spdy_framer.h"
|
|
|
|
#include <algorithm>
|
|
#include <utility>
|
|
|
|
#include "base/logging.h"
|
|
#include "base/strings/string_util.h"
|
|
#include "base/trace_event/memory_usage_estimator.h"
|
|
|
|
namespace net {
|
|
|
|
namespace {
|
|
|
|
// GOAWAY frame debug data is only buffered up to this many bytes.
|
|
size_t kGoAwayDebugDataMaxSize = 1024;
|
|
|
|
} // namespace
|
|
|
|
BufferedSpdyFramer::BufferedSpdyFramer(uint32_t max_header_list_size,
|
|
const NetLogWithSource& net_log)
|
|
: spdy_framer_(spdy::SpdyFramer::ENABLE_COMPRESSION),
|
|
visitor_(NULL),
|
|
frames_received_(0),
|
|
max_header_list_size_(max_header_list_size),
|
|
net_log_(net_log) {
|
|
// Do not bother decoding response header payload above the limit.
|
|
deframer_.GetHpackDecoder()->set_max_decode_buffer_size_bytes(
|
|
max_header_list_size_);
|
|
}
|
|
|
|
BufferedSpdyFramer::~BufferedSpdyFramer() = default;
|
|
|
|
void BufferedSpdyFramer::set_visitor(
|
|
BufferedSpdyFramerVisitorInterface* visitor) {
|
|
visitor_ = visitor;
|
|
deframer_.set_visitor(this);
|
|
}
|
|
|
|
void BufferedSpdyFramer::set_debug_visitor(
|
|
spdy::SpdyFramerDebugVisitorInterface* debug_visitor) {
|
|
spdy_framer_.set_debug_visitor(debug_visitor);
|
|
deframer_.set_debug_visitor(debug_visitor);
|
|
}
|
|
|
|
void BufferedSpdyFramer::OnError(
|
|
http2::Http2DecoderAdapter::SpdyFramerError spdy_framer_error) {
|
|
visitor_->OnError(spdy_framer_error);
|
|
}
|
|
|
|
void BufferedSpdyFramer::OnHeaders(spdy::SpdyStreamId stream_id,
|
|
bool has_priority,
|
|
int weight,
|
|
spdy::SpdyStreamId parent_stream_id,
|
|
bool exclusive,
|
|
bool fin,
|
|
bool end) {
|
|
frames_received_++;
|
|
DCHECK(!control_frame_fields_.get());
|
|
control_frame_fields_ = std::make_unique<ControlFrameFields>();
|
|
control_frame_fields_->type = spdy::SpdyFrameType::HEADERS;
|
|
control_frame_fields_->stream_id = stream_id;
|
|
control_frame_fields_->has_priority = has_priority;
|
|
if (control_frame_fields_->has_priority) {
|
|
control_frame_fields_->weight = weight;
|
|
control_frame_fields_->parent_stream_id = parent_stream_id;
|
|
control_frame_fields_->exclusive = exclusive;
|
|
}
|
|
control_frame_fields_->fin = fin;
|
|
}
|
|
|
|
void BufferedSpdyFramer::OnDataFrameHeader(spdy::SpdyStreamId stream_id,
|
|
size_t length,
|
|
bool fin) {
|
|
frames_received_++;
|
|
visitor_->OnDataFrameHeader(stream_id, length, fin);
|
|
}
|
|
|
|
void BufferedSpdyFramer::OnStreamFrameData(spdy::SpdyStreamId stream_id,
|
|
const char* data,
|
|
size_t len) {
|
|
visitor_->OnStreamFrameData(stream_id, data, len);
|
|
}
|
|
|
|
void BufferedSpdyFramer::OnStreamEnd(spdy::SpdyStreamId stream_id) {
|
|
visitor_->OnStreamEnd(stream_id);
|
|
}
|
|
|
|
void BufferedSpdyFramer::OnStreamPadLength(spdy::SpdyStreamId stream_id,
|
|
size_t value) {
|
|
// Deliver the stream pad length byte for flow control handling.
|
|
visitor_->OnStreamPadding(stream_id, 1);
|
|
}
|
|
|
|
void BufferedSpdyFramer::OnStreamPadding(spdy::SpdyStreamId stream_id,
|
|
size_t len) {
|
|
visitor_->OnStreamPadding(stream_id, len);
|
|
}
|
|
|
|
spdy::SpdyHeadersHandlerInterface* BufferedSpdyFramer::OnHeaderFrameStart(
|
|
spdy::SpdyStreamId stream_id) {
|
|
coalescer_ =
|
|
std::make_unique<HeaderCoalescer>(max_header_list_size_, net_log_);
|
|
return coalescer_.get();
|
|
}
|
|
|
|
void BufferedSpdyFramer::OnHeaderFrameEnd(spdy::SpdyStreamId stream_id) {
|
|
if (coalescer_->error_seen()) {
|
|
visitor_->OnStreamError(stream_id,
|
|
"Could not parse Spdy Control Frame Header.");
|
|
control_frame_fields_.reset();
|
|
return;
|
|
}
|
|
DCHECK(control_frame_fields_.get());
|
|
switch (control_frame_fields_->type) {
|
|
case spdy::SpdyFrameType::HEADERS:
|
|
visitor_->OnHeaders(
|
|
control_frame_fields_->stream_id, control_frame_fields_->has_priority,
|
|
control_frame_fields_->weight,
|
|
control_frame_fields_->parent_stream_id,
|
|
control_frame_fields_->exclusive, control_frame_fields_->fin,
|
|
coalescer_->release_headers());
|
|
break;
|
|
case spdy::SpdyFrameType::PUSH_PROMISE:
|
|
visitor_->OnPushPromise(control_frame_fields_->stream_id,
|
|
control_frame_fields_->promised_stream_id,
|
|
coalescer_->release_headers());
|
|
break;
|
|
default:
|
|
DCHECK(false) << "Unexpect control frame type: "
|
|
<< control_frame_fields_->type;
|
|
break;
|
|
}
|
|
control_frame_fields_.reset(NULL);
|
|
}
|
|
|
|
void BufferedSpdyFramer::OnSettings() {
|
|
visitor_->OnSettings();
|
|
}
|
|
|
|
void BufferedSpdyFramer::OnSetting(spdy::SpdySettingsId id, uint32_t value) {
|
|
visitor_->OnSetting(id, value);
|
|
}
|
|
|
|
void BufferedSpdyFramer::OnSettingsAck() {
|
|
visitor_->OnSettingsAck();
|
|
}
|
|
|
|
void BufferedSpdyFramer::OnSettingsEnd() {
|
|
visitor_->OnSettingsEnd();
|
|
}
|
|
|
|
void BufferedSpdyFramer::OnPing(spdy::SpdyPingId unique_id, bool is_ack) {
|
|
visitor_->OnPing(unique_id, is_ack);
|
|
}
|
|
|
|
void BufferedSpdyFramer::OnRstStream(spdy::SpdyStreamId stream_id,
|
|
spdy::SpdyErrorCode error_code) {
|
|
visitor_->OnRstStream(stream_id, error_code);
|
|
}
|
|
void BufferedSpdyFramer::OnGoAway(spdy::SpdyStreamId last_accepted_stream_id,
|
|
spdy::SpdyErrorCode error_code) {
|
|
DCHECK(!goaway_fields_);
|
|
goaway_fields_ = std::make_unique<GoAwayFields>();
|
|
goaway_fields_->last_accepted_stream_id = last_accepted_stream_id;
|
|
goaway_fields_->error_code = error_code;
|
|
}
|
|
|
|
bool BufferedSpdyFramer::OnGoAwayFrameData(const char* goaway_data,
|
|
size_t len) {
|
|
if (len > 0) {
|
|
if (goaway_fields_->debug_data.size() < kGoAwayDebugDataMaxSize) {
|
|
goaway_fields_->debug_data.append(
|
|
goaway_data, std::min(len, kGoAwayDebugDataMaxSize -
|
|
goaway_fields_->debug_data.size()));
|
|
}
|
|
return true;
|
|
}
|
|
visitor_->OnGoAway(goaway_fields_->last_accepted_stream_id,
|
|
goaway_fields_->error_code, goaway_fields_->debug_data);
|
|
goaway_fields_.reset();
|
|
return true;
|
|
}
|
|
|
|
void BufferedSpdyFramer::OnWindowUpdate(spdy::SpdyStreamId stream_id,
|
|
int delta_window_size) {
|
|
visitor_->OnWindowUpdate(stream_id, delta_window_size);
|
|
}
|
|
|
|
void BufferedSpdyFramer::OnPushPromise(spdy::SpdyStreamId stream_id,
|
|
spdy::SpdyStreamId promised_stream_id,
|
|
bool end) {
|
|
frames_received_++;
|
|
DCHECK(!control_frame_fields_.get());
|
|
control_frame_fields_ = std::make_unique<ControlFrameFields>();
|
|
control_frame_fields_->type = spdy::SpdyFrameType::PUSH_PROMISE;
|
|
control_frame_fields_->stream_id = stream_id;
|
|
control_frame_fields_->promised_stream_id = promised_stream_id;
|
|
}
|
|
|
|
void BufferedSpdyFramer::OnAltSvc(
|
|
spdy::SpdyStreamId stream_id,
|
|
base::StringPiece origin,
|
|
const spdy::SpdyAltSvcWireFormat::AlternativeServiceVector& altsvc_vector) {
|
|
visitor_->OnAltSvc(stream_id, origin, altsvc_vector);
|
|
}
|
|
|
|
void BufferedSpdyFramer::OnContinuation(spdy::SpdyStreamId stream_id,
|
|
bool end) {}
|
|
|
|
bool BufferedSpdyFramer::OnUnknownFrame(spdy::SpdyStreamId stream_id,
|
|
uint8_t frame_type) {
|
|
return visitor_->OnUnknownFrame(stream_id, frame_type);
|
|
}
|
|
|
|
size_t BufferedSpdyFramer::ProcessInput(const char* data, size_t len) {
|
|
return deframer_.ProcessInput(data, len);
|
|
}
|
|
|
|
void BufferedSpdyFramer::UpdateHeaderDecoderTableSize(uint32_t value) {
|
|
deframer_.GetHpackDecoder()->ApplyHeaderTableSizeSetting(value);
|
|
}
|
|
|
|
void BufferedSpdyFramer::Reset() {
|
|
deframer_.Reset();
|
|
}
|
|
|
|
http2::Http2DecoderAdapter::SpdyFramerError
|
|
BufferedSpdyFramer::spdy_framer_error() const {
|
|
return deframer_.spdy_framer_error();
|
|
}
|
|
|
|
http2::Http2DecoderAdapter::SpdyState BufferedSpdyFramer::state() const {
|
|
return deframer_.state();
|
|
}
|
|
|
|
bool BufferedSpdyFramer::MessageFullyRead() {
|
|
return state() == http2::Http2DecoderAdapter::SPDY_FRAME_COMPLETE;
|
|
}
|
|
|
|
bool BufferedSpdyFramer::HasError() {
|
|
return deframer_.HasError();
|
|
}
|
|
|
|
// TODO(jgraettinger): Eliminate uses of this method (prefer
|
|
// spdy::SpdyRstStreamIR).
|
|
std::unique_ptr<spdy::SpdySerializedFrame> BufferedSpdyFramer::CreateRstStream(
|
|
spdy::SpdyStreamId stream_id,
|
|
spdy::SpdyErrorCode error_code) const {
|
|
spdy::SpdyRstStreamIR rst_ir(stream_id, error_code);
|
|
return std::make_unique<spdy::SpdySerializedFrame>(
|
|
spdy_framer_.SerializeRstStream(rst_ir));
|
|
}
|
|
|
|
// TODO(jgraettinger): Eliminate uses of this method (prefer
|
|
// spdy::SpdySettingsIR).
|
|
std::unique_ptr<spdy::SpdySerializedFrame> BufferedSpdyFramer::CreateSettings(
|
|
const spdy::SettingsMap& values) const {
|
|
spdy::SpdySettingsIR settings_ir;
|
|
for (spdy::SettingsMap::const_iterator it = values.begin();
|
|
it != values.end(); ++it) {
|
|
settings_ir.AddSetting(it->first, it->second);
|
|
}
|
|
return std::make_unique<spdy::SpdySerializedFrame>(
|
|
spdy_framer_.SerializeSettings(settings_ir));
|
|
}
|
|
|
|
// TODO(jgraettinger): Eliminate uses of this method (prefer spdy::SpdyPingIR).
|
|
std::unique_ptr<spdy::SpdySerializedFrame> BufferedSpdyFramer::CreatePingFrame(
|
|
spdy::SpdyPingId unique_id,
|
|
bool is_ack) const {
|
|
spdy::SpdyPingIR ping_ir(unique_id);
|
|
ping_ir.set_is_ack(is_ack);
|
|
return std::make_unique<spdy::SpdySerializedFrame>(
|
|
spdy_framer_.SerializePing(ping_ir));
|
|
}
|
|
|
|
// TODO(jgraettinger): Eliminate uses of this method (prefer
|
|
// spdy::SpdyWindowUpdateIR).
|
|
std::unique_ptr<spdy::SpdySerializedFrame>
|
|
BufferedSpdyFramer::CreateWindowUpdate(spdy::SpdyStreamId stream_id,
|
|
uint32_t delta_window_size) const {
|
|
spdy::SpdyWindowUpdateIR update_ir(stream_id, delta_window_size);
|
|
return std::make_unique<spdy::SpdySerializedFrame>(
|
|
spdy_framer_.SerializeWindowUpdate(update_ir));
|
|
}
|
|
|
|
// TODO(jgraettinger): Eliminate uses of this method (prefer spdy::SpdyDataIR).
|
|
std::unique_ptr<spdy::SpdySerializedFrame> BufferedSpdyFramer::CreateDataFrame(
|
|
spdy::SpdyStreamId stream_id,
|
|
const char* data,
|
|
uint32_t len,
|
|
spdy::SpdyDataFlags flags) {
|
|
spdy::SpdyDataIR data_ir(stream_id, base::StringPiece(data, len));
|
|
data_ir.set_fin((flags & spdy::DATA_FLAG_FIN) != 0);
|
|
return std::make_unique<spdy::SpdySerializedFrame>(
|
|
spdy_framer_.SerializeData(data_ir));
|
|
}
|
|
|
|
// TODO(jgraettinger): Eliminate uses of this method (prefer
|
|
// spdy::SpdyPriorityIR).
|
|
std::unique_ptr<spdy::SpdySerializedFrame> BufferedSpdyFramer::CreatePriority(
|
|
spdy::SpdyStreamId stream_id,
|
|
spdy::SpdyStreamId dependency_id,
|
|
int weight,
|
|
bool exclusive) const {
|
|
spdy::SpdyPriorityIR priority_ir(stream_id, dependency_id, weight, exclusive);
|
|
return std::make_unique<spdy::SpdySerializedFrame>(
|
|
spdy_framer_.SerializePriority(priority_ir));
|
|
}
|
|
|
|
size_t BufferedSpdyFramer::EstimateMemoryUsage() const {
|
|
return base::trace_event::EstimateMemoryUsage(spdy_framer_) +
|
|
base::trace_event::EstimateMemoryUsage(deframer_) +
|
|
base::trace_event::EstimateMemoryUsage(coalescer_) +
|
|
base::trace_event::EstimateMemoryUsage(control_frame_fields_) +
|
|
base::trace_event::EstimateMemoryUsage(goaway_fields_);
|
|
}
|
|
|
|
size_t BufferedSpdyFramer::GoAwayFields::EstimateMemoryUsage() const {
|
|
return base::trace_event::EstimateMemoryUsage(debug_data);
|
|
}
|
|
|
|
} // namespace net
|