blob: ea3e0aa891a0b1973f65128addf9afe6ca11fbf3 [file] [log] [blame]
#include "http2/adapter/oghttp2_session.h"
namespace http2 {
namespace adapter {
void OgHttp2Session::PassthroughHeadersHandler::OnHeaderBlockStart() {
visitor_.OnBeginHeadersForStream(stream_id_);
}
void OgHttp2Session::PassthroughHeadersHandler::OnHeader(
absl::string_view key,
absl::string_view value) {
visitor_.OnHeaderForStream(stream_id_, key, value);
}
void OgHttp2Session::PassthroughHeadersHandler::OnHeaderBlockEnd(
size_t /* uncompressed_header_bytes */,
size_t /* compressed_header_bytes */) {
visitor_.OnEndHeadersForStream(stream_id_);
}
OgHttp2Session::OgHttp2Session(Http2VisitorInterface& visitor, Options options)
: visitor_(visitor), headers_handler_(visitor), options_(options) {
decoder_.set_visitor(this);
if (options_.perspective == Perspective::kServer) {
remaining_preface_ = {spdy::kHttp2ConnectionHeaderPrefix,
spdy::kHttp2ConnectionHeaderPrefixSize};
}
}
OgHttp2Session::~OgHttp2Session() {}
ssize_t OgHttp2Session::ProcessBytes(absl::string_view bytes) {
ssize_t preface_consumed = 0;
if (!remaining_preface_.empty()) {
QUICHE_VLOG(2) << "Preface bytes remaining: " << remaining_preface_.size();
// decoder_ does not understand the client connection preface.
size_t min_size = std::min(remaining_preface_.size(), bytes.size());
if (!absl::StartsWith(remaining_preface_, bytes.substr(0, min_size))) {
// Preface doesn't match!
QUICHE_DLOG(INFO) << "Preface doesn't match! Expected: ["
<< absl::CEscape(remaining_preface_) << "], actual: ["
<< absl::CEscape(bytes) << "]";
visitor_.OnConnectionError();
return -1;
}
remaining_preface_.remove_prefix(min_size);
bytes.remove_prefix(min_size);
if (!remaining_preface_.empty()) {
QUICHE_VLOG(2) << "Preface bytes remaining: "
<< remaining_preface_.size();
return min_size;
}
preface_consumed = min_size;
}
ssize_t result = decoder_.ProcessInput(bytes.data(), bytes.size());
return result < 0 ? result : result + preface_consumed;
}
int OgHttp2Session::Consume(Http2StreamId stream_id, size_t num_bytes) {
auto it = stream_map_.find(stream_id);
if (it == stream_map_.end()) {
// TODO(b/181586191): LOG_ERROR rather than QUICHE_BUG.
QUICHE_BUG(stream_consume_notfound)
<< "Stream " << stream_id << " not found";
} else {
it->second.window_manager.MarkDataFlushed(num_bytes);
}
return 0; // Remove?
}
void OgHttp2Session::EnqueueFrame(std::unique_ptr<spdy::SpdyFrameIR> frame) {
frames_.push_back(std::move(frame));
}
std::string OgHttp2Session::GetBytesToWrite(absl::optional<size_t> max_bytes) {
const size_t serialized_max =
max_bytes ? max_bytes.value() : std::numeric_limits<size_t>::max();
std::string serialized = std::move(serialized_prefix_);
while (serialized.size() < serialized_max && !frames_.empty()) {
spdy::SpdySerializedFrame frame = framer_.SerializeFrame(*frames_.front());
absl::StrAppend(&serialized, absl::string_view(frame));
frames_.pop_front();
}
if (serialized.size() > serialized_max) {
serialized_prefix_ = serialized.substr(serialized_max);
serialized.resize(serialized_max);
}
return serialized;
}
void OgHttp2Session::OnError(http2::Http2DecoderAdapter::SpdyFramerError error,
std::string detailed_error) {
QUICHE_VLOG(1) << "Error: "
<< http2::Http2DecoderAdapter::SpdyFramerErrorToString(error)
<< " details: " << detailed_error;
visitor_.OnConnectionError();
}
void OgHttp2Session::OnCommonHeader(spdy::SpdyStreamId stream_id,
size_t length,
uint8_t type,
uint8_t flags) {
visitor_.OnFrameHeader(stream_id, length, type, flags);
}
void OgHttp2Session::OnDataFrameHeader(spdy::SpdyStreamId stream_id,
size_t length,
bool fin) {
visitor_.OnBeginDataForStream(stream_id, length);
}
void OgHttp2Session::OnStreamFrameData(spdy::SpdyStreamId stream_id,
const char* data,
size_t len) {
visitor_.OnDataForStream(stream_id, absl::string_view(data, len));
}
void OgHttp2Session::OnStreamEnd(spdy::SpdyStreamId stream_id) {
visitor_.OnEndStream(stream_id);
}
void OgHttp2Session::OnStreamPadLength(spdy::SpdyStreamId /*stream_id*/,
size_t /*value*/) {
// TODO(181586191): handle padding
}
void OgHttp2Session::OnStreamPadding(spdy::SpdyStreamId stream_id, size_t len) {
// TODO(181586191): handle padding
}
spdy::SpdyHeadersHandlerInterface* OgHttp2Session::OnHeaderFrameStart(
spdy::SpdyStreamId stream_id) {
headers_handler_.set_stream_id(stream_id);
return &headers_handler_;
}
void OgHttp2Session::OnHeaderFrameEnd(spdy::SpdyStreamId stream_id) {
headers_handler_.set_stream_id(0);
}
void OgHttp2Session::OnRstStream(spdy::SpdyStreamId stream_id,
spdy::SpdyErrorCode error_code) {
visitor_.OnRstStream(stream_id, TranslateErrorCode(error_code));
visitor_.OnCloseStream(stream_id, TranslateErrorCode(error_code));
}
void OgHttp2Session::OnSettings() {
visitor_.OnSettingsStart();
}
void OgHttp2Session::OnSetting(spdy::SpdySettingsId id, uint32_t value) {
visitor_.OnSetting({id, value});
}
void OgHttp2Session::OnSettingsEnd() {
visitor_.OnSettingsEnd();
}
void OgHttp2Session::OnSettingsAck() {
visitor_.OnSettingsAck();
}
void OgHttp2Session::OnPing(spdy::SpdyPingId unique_id, bool is_ack) {
visitor_.OnPing(unique_id, is_ack);
}
void OgHttp2Session::OnGoAway(spdy::SpdyStreamId last_accepted_stream_id,
spdy::SpdyErrorCode error_code) {
received_goaway_ = true;
visitor_.OnGoAway(last_accepted_stream_id, TranslateErrorCode(error_code),
"");
}
bool OgHttp2Session::OnGoAwayFrameData(const char* goaway_data, size_t len) {
// Opaque data is currently ignored.
return true;
}
void OgHttp2Session::OnHeaders(spdy::SpdyStreamId stream_id,
bool has_priority,
int weight,
spdy::SpdyStreamId parent_stream_id,
bool exclusive,
bool fin,
bool end) {}
void OgHttp2Session::OnWindowUpdate(spdy::SpdyStreamId stream_id,
int delta_window_size) {
if (stream_id == 0) {
peer_window_ += delta_window_size;
} else {
auto it = stream_map_.find(stream_id);
if (it == stream_map_.end()) {
QUICHE_VLOG(1) << "Stream " << stream_id << " not found!";
} else {
it->second.send_window += delta_window_size;
}
}
visitor_.OnWindowUpdate(stream_id, delta_window_size);
}
void OgHttp2Session::OnPushPromise(spdy::SpdyStreamId stream_id,
spdy::SpdyStreamId promised_stream_id,
bool end) {}
void OgHttp2Session::OnContinuation(spdy::SpdyStreamId stream_id, bool end) {}
void OgHttp2Session::OnAltSvc(spdy::SpdyStreamId /*stream_id*/,
absl::string_view /*origin*/,
const spdy::SpdyAltSvcWireFormat::
AlternativeServiceVector& /*altsvc_vector*/) {
}
void OgHttp2Session::OnPriority(spdy::SpdyStreamId stream_id,
spdy::SpdyStreamId parent_stream_id,
int weight,
bool exclusive) {}
void OgHttp2Session::OnPriorityUpdate(spdy::SpdyStreamId prioritized_stream_id,
absl::string_view priority_field_value) {}
bool OgHttp2Session::OnUnknownFrame(spdy::SpdyStreamId stream_id,
uint8_t frame_type) {
return true;
}
} // namespace adapter
} // namespace http2