Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(195)

Unified Diff: net/http2/decoder/http2_frame_decoder.cc

Issue 2293613002: Add new HTTP/2 and HPACK decoder in net/http2/. (Closed)
Patch Set: Replace LOG(INFO) by VLOG(2) in DecodeBufferTest.SlowDecodeTestStruct so that trybots do not fail. Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « net/http2/decoder/http2_frame_decoder.h ('k') | net/http2/decoder/http2_frame_decoder_listener.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: net/http2/decoder/http2_frame_decoder.cc
diff --git a/net/http2/decoder/http2_frame_decoder.cc b/net/http2/decoder/http2_frame_decoder.cc
new file mode 100644
index 0000000000000000000000000000000000000000..fe24f91644cdd27208f41ee9872a28407274d858
--- /dev/null
+++ b/net/http2/decoder/http2_frame_decoder.cc
@@ -0,0 +1,426 @@
+// Copyright 2016 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/http2/decoder/http2_frame_decoder.h"
+
+#include "net/http2/http2_constants.h"
+
+namespace net {
+
+std::ostream& operator<<(std::ostream& out, Http2FrameDecoder::State v) {
+ switch (v) {
+ case Http2FrameDecoder::State::kStartDecodingHeader:
+ return out << "kStartDecodingHeader";
+ case Http2FrameDecoder::State::kResumeDecodingHeader:
+ return out << "kResumeDecodingHeader";
+ case Http2FrameDecoder::State::kResumeDecodingPayload:
+ return out << "kResumeDecodingPayload";
+ case Http2FrameDecoder::State::kDiscardPayload:
+ return out << "kDiscardPayload";
+ }
+ return out << static_cast<int>(v);
+}
+
+Http2FrameDecoder::Http2FrameDecoder(Http2FrameDecoderListener* listener)
+ : state_(State::kStartDecodingHeader),
+ maximum_payload_size_(Http2SettingsInfo::DefaultMaxFrameSize()) {
+ set_listener(listener);
+}
+
+void Http2FrameDecoder::set_listener(Http2FrameDecoderListener* listener) {
+ if (listener == nullptr) {
+ listener = &no_op_listener_;
+ }
+ frame_decoder_state_.set_listener(listener);
+}
+
+Http2FrameDecoderListener* Http2FrameDecoder::listener() const {
+ return frame_decoder_state_.listener();
+}
+
+DecodeStatus Http2FrameDecoder::DecodeFrame(DecodeBuffer* db) {
+ DVLOG(2) << "Http2FrameDecoder::DecodeFrame state=" << state_;
+ switch (state_) {
+ case State::kStartDecodingHeader:
+ if (frame_decoder_state_.StartDecodingFrameHeader(db)) {
+ return StartDecodingPayload(db);
+ }
+ state_ = State::kResumeDecodingHeader;
+ return DecodeStatus::kDecodeInProgress;
+
+ case State::kResumeDecodingHeader:
+ if (frame_decoder_state_.ResumeDecodingFrameHeader(db)) {
+ return StartDecodingPayload(db);
+ }
+ return DecodeStatus::kDecodeInProgress;
+
+ case State::kResumeDecodingPayload:
+ return ResumeDecodingPayload(db);
+
+ case State::kDiscardPayload:
+ return DiscardPayload(db);
+ }
+
+ NOTREACHED();
+ return DecodeStatus::kDecodeError;
+}
+
+size_t Http2FrameDecoder::remaining_payload() const {
+ return frame_decoder_state_.remaining_payload();
+}
+
+uint32_t Http2FrameDecoder::remaining_padding() const {
+ return frame_decoder_state_.remaining_padding();
+}
+
+DecodeStatus Http2FrameDecoder::StartDecodingPayload(DecodeBuffer* db) {
+ const Http2FrameHeader& header = frame_header();
+
+ // TODO(jamessynge): Remove OnFrameHeader once done with supporting
+ // SpdyFramer's exact states.
+ if (!listener()->OnFrameHeader(header)) {
+ DVLOG(2) << "OnFrameHeader rejected the frame, will discard; header: "
+ << header;
+ state_ = State::kDiscardPayload;
+ frame_decoder_state_.InitializeRemainders();
+ return DecodeStatus::kDecodeError;
+ }
+
+ if (header.payload_length > maximum_payload_size_) {
+ DVLOG(2) << "Payload length is greater than allowed: "
+ << header.payload_length << " > " << maximum_payload_size_
+ << "\n header: " << header;
+ state_ = State::kDiscardPayload;
+ frame_decoder_state_.InitializeRemainders();
+ listener()->OnFrameSizeError(header);
+ return DecodeStatus::kDecodeError;
+ }
+
+ // The decode buffer can extend across many frames. Make sure that the
+ // buffer we pass to the start method that is specific to the frame type
+ // does not exend beyond this frame.
+ DecodeBufferSubset subset(db, header.payload_length);
+ DecodeStatus status;
+ switch (header.type) {
+ case Http2FrameType::DATA:
+ status = StartDecodingDataPayload(&subset);
+ break;
+
+ case Http2FrameType::HEADERS:
+ status = StartDecodingHeadersPayload(&subset);
+ break;
+
+ case Http2FrameType::PRIORITY:
+ status = StartDecodingPriorityPayload(&subset);
+ break;
+
+ case Http2FrameType::RST_STREAM:
+ status = StartDecodingRstStreamPayload(&subset);
+ break;
+
+ case Http2FrameType::SETTINGS:
+ status = StartDecodingSettingsPayload(&subset);
+ break;
+
+ case Http2FrameType::PUSH_PROMISE:
+ status = StartDecodingPushPromisePayload(&subset);
+ break;
+
+ case Http2FrameType::PING:
+ status = StartDecodingPingPayload(&subset);
+ break;
+
+ case Http2FrameType::GOAWAY:
+ status = StartDecodingGoAwayPayload(&subset);
+ break;
+
+ case Http2FrameType::WINDOW_UPDATE:
+ status = StartDecodingWindowUpdatePayload(&subset);
+ break;
+
+ case Http2FrameType::CONTINUATION:
+ status = StartDecodingContinuationPayload(&subset);
+ break;
+
+ case Http2FrameType::ALTSVC:
+ status = StartDecodingAltSvcPayload(&subset);
+ break;
+
+ default:
+ status = StartDecodingUnknownPayload(&subset);
+ break;
+ }
+
+ if (status == DecodeStatus::kDecodeDone) {
+ state_ = State::kStartDecodingHeader;
+ return status;
+ } else if (status == DecodeStatus::kDecodeInProgress) {
+ state_ = State::kResumeDecodingPayload;
+ return status;
+ } else {
+ state_ = State::kDiscardPayload;
+ return status;
+ }
+}
+
+DecodeStatus Http2FrameDecoder::ResumeDecodingPayload(DecodeBuffer* db) {
+ // The decode buffer can extend across many frames. Make sure that the
+ // buffer we pass to the start method that is specific to the frame type
+ // does not exend beyond this frame.
+ size_t remaining = frame_decoder_state_.remaining_total_payload();
+ DCHECK_LE(remaining, frame_header().payload_length);
+ DecodeBufferSubset subset(db, remaining);
+ DecodeStatus status;
+ switch (frame_header().type) {
+ case Http2FrameType::DATA:
+ status = ResumeDecodingDataPayload(&subset);
+ break;
+
+ case Http2FrameType::HEADERS:
+ status = ResumeDecodingHeadersPayload(&subset);
+ break;
+
+ case Http2FrameType::PRIORITY:
+ status = ResumeDecodingPriorityPayload(&subset);
+ break;
+
+ case Http2FrameType::RST_STREAM:
+ status = ResumeDecodingRstStreamPayload(&subset);
+ break;
+
+ case Http2FrameType::SETTINGS:
+ status = ResumeDecodingSettingsPayload(&subset);
+ break;
+
+ case Http2FrameType::PUSH_PROMISE:
+ status = ResumeDecodingPushPromisePayload(&subset);
+ break;
+
+ case Http2FrameType::PING:
+ status = ResumeDecodingPingPayload(&subset);
+ break;
+
+ case Http2FrameType::GOAWAY:
+ status = ResumeDecodingGoAwayPayload(&subset);
+ break;
+
+ case Http2FrameType::WINDOW_UPDATE:
+ status = ResumeDecodingWindowUpdatePayload(&subset);
+ break;
+
+ case Http2FrameType::CONTINUATION:
+ status = ResumeDecodingContinuationPayload(&subset);
+ break;
+
+ case Http2FrameType::ALTSVC:
+ status = ResumeDecodingAltSvcPayload(&subset);
+ break;
+
+ default:
+ status = ResumeDecodingUnknownPayload(&subset);
+ break;
+ }
+
+ if (status == DecodeStatus::kDecodeDone) {
+ state_ = State::kStartDecodingHeader;
+ return status;
+ } else if (status == DecodeStatus::kDecodeInProgress) {
+ return status;
+ } else {
+ state_ = State::kDiscardPayload;
+ return status;
+ }
+}
+
+// Clear any of the flags in the frame header that aren't set in valid_flags.
+void Http2FrameDecoder::RetainFlags(uint8_t valid_flags) {
+ frame_decoder_state_.RetainFlags(valid_flags);
+}
+
+// Clear all of the flags in the frame header; for use with frame types that
+// don't define any flags, such as WINDOW_UPDATE.
+void Http2FrameDecoder::ClearFlags() {
+ frame_decoder_state_.ClearFlags();
+}
+
+DecodeStatus Http2FrameDecoder::StartDecodingAltSvcPayload(DecodeBuffer* db) {
+ ClearFlags();
+ return altsvc_payload_decoder_.StartDecodingPayload(&frame_decoder_state_,
+ db);
+}
+DecodeStatus Http2FrameDecoder::ResumeDecodingAltSvcPayload(DecodeBuffer* db) {
+ // The frame is not paddable.
+ DCHECK_EQ(frame_decoder_state_.remaining_total_payload(),
+ frame_decoder_state_.remaining_payload());
+ return altsvc_payload_decoder_.ResumeDecodingPayload(&frame_decoder_state_,
+ db);
+}
+
+DecodeStatus Http2FrameDecoder::StartDecodingContinuationPayload(
+ DecodeBuffer* db) {
+ RetainFlags(Http2FrameFlag::FLAG_END_HEADERS);
+ return continuation_payload_decoder_.StartDecodingPayload(
+ &frame_decoder_state_, db);
+}
+DecodeStatus Http2FrameDecoder::ResumeDecodingContinuationPayload(
+ DecodeBuffer* db) {
+ // The frame is not paddable.
+ DCHECK_EQ(frame_decoder_state_.remaining_total_payload(),
+ frame_decoder_state_.remaining_payload());
+ return continuation_payload_decoder_.ResumeDecodingPayload(
+ &frame_decoder_state_, db);
+}
+
+DecodeStatus Http2FrameDecoder::StartDecodingDataPayload(DecodeBuffer* db) {
+ RetainFlags(Http2FrameFlag::FLAG_END_STREAM | Http2FrameFlag::FLAG_PADDED);
+ return data_payload_decoder_.StartDecodingPayload(&frame_decoder_state_, db);
+}
+DecodeStatus Http2FrameDecoder::ResumeDecodingDataPayload(DecodeBuffer* db) {
+ return data_payload_decoder_.ResumeDecodingPayload(&frame_decoder_state_, db);
+}
+
+DecodeStatus Http2FrameDecoder::StartDecodingGoAwayPayload(DecodeBuffer* db) {
+ ClearFlags();
+ return goaway_payload_decoder_.StartDecodingPayload(&frame_decoder_state_,
+ db);
+}
+DecodeStatus Http2FrameDecoder::ResumeDecodingGoAwayPayload(DecodeBuffer* db) {
+ // The frame is not paddable.
+ DCHECK_EQ(frame_decoder_state_.remaining_total_payload(),
+ frame_decoder_state_.remaining_payload());
+ return goaway_payload_decoder_.ResumeDecodingPayload(&frame_decoder_state_,
+ db);
+}
+
+DecodeStatus Http2FrameDecoder::StartDecodingHeadersPayload(DecodeBuffer* db) {
+ RetainFlags(Http2FrameFlag::FLAG_END_STREAM |
+ Http2FrameFlag::FLAG_END_HEADERS | Http2FrameFlag::FLAG_PADDED |
+ Http2FrameFlag::FLAG_PRIORITY);
+ return headers_payload_decoder_.StartDecodingPayload(&frame_decoder_state_,
+ db);
+}
+DecodeStatus Http2FrameDecoder::ResumeDecodingHeadersPayload(DecodeBuffer* db) {
+ DCHECK_LE(frame_decoder_state_.remaining_payload_and_padding(),
+ frame_header().payload_length);
+ return headers_payload_decoder_.ResumeDecodingPayload(&frame_decoder_state_,
+ db);
+}
+
+DecodeStatus Http2FrameDecoder::StartDecodingPingPayload(DecodeBuffer* db) {
+ RetainFlags(Http2FrameFlag::FLAG_ACK);
+ return ping_payload_decoder_.StartDecodingPayload(&frame_decoder_state_, db);
+}
+DecodeStatus Http2FrameDecoder::ResumeDecodingPingPayload(DecodeBuffer* db) {
+ // The frame is not paddable.
+ DCHECK_EQ(frame_decoder_state_.remaining_total_payload(),
+ frame_decoder_state_.remaining_payload());
+ return ping_payload_decoder_.ResumeDecodingPayload(&frame_decoder_state_, db);
+}
+
+DecodeStatus Http2FrameDecoder::StartDecodingPriorityPayload(DecodeBuffer* db) {
+ ClearFlags();
+ return priority_payload_decoder_.StartDecodingPayload(&frame_decoder_state_,
+ db);
+}
+DecodeStatus Http2FrameDecoder::ResumeDecodingPriorityPayload(
+ DecodeBuffer* db) {
+ // The frame is not paddable.
+ DCHECK_EQ(frame_decoder_state_.remaining_total_payload(),
+ frame_decoder_state_.remaining_payload());
+ return priority_payload_decoder_.ResumeDecodingPayload(&frame_decoder_state_,
+ db);
+}
+
+DecodeStatus Http2FrameDecoder::StartDecodingPushPromisePayload(
+ DecodeBuffer* db) {
+ RetainFlags(Http2FrameFlag::FLAG_END_HEADERS | Http2FrameFlag::FLAG_PADDED);
+ return push_promise_payload_decoder_.StartDecodingPayload(
+ &frame_decoder_state_, db);
+}
+DecodeStatus Http2FrameDecoder::ResumeDecodingPushPromisePayload(
+ DecodeBuffer* db) {
+ DCHECK_LE(frame_decoder_state_.remaining_payload_and_padding(),
+ frame_header().payload_length);
+ return push_promise_payload_decoder_.ResumeDecodingPayload(
+ &frame_decoder_state_, db);
+}
+
+DecodeStatus Http2FrameDecoder::StartDecodingRstStreamPayload(
+ DecodeBuffer* db) {
+ ClearFlags();
+ return rst_stream_payload_decoder_.StartDecodingPayload(&frame_decoder_state_,
+ db);
+}
+DecodeStatus Http2FrameDecoder::ResumeDecodingRstStreamPayload(
+ DecodeBuffer* db) {
+ // The frame is not paddable.
+ DCHECK_EQ(frame_decoder_state_.remaining_total_payload(),
+ frame_decoder_state_.remaining_payload());
+ return rst_stream_payload_decoder_.ResumeDecodingPayload(
+ &frame_decoder_state_, db);
+}
+
+DecodeStatus Http2FrameDecoder::StartDecodingSettingsPayload(DecodeBuffer* db) {
+ RetainFlags(Http2FrameFlag::FLAG_ACK);
+ return settings_payload_decoder_.StartDecodingPayload(&frame_decoder_state_,
+ db);
+}
+DecodeStatus Http2FrameDecoder::ResumeDecodingSettingsPayload(
+ DecodeBuffer* db) {
+ // The frame is not paddable.
+ DCHECK_EQ(frame_decoder_state_.remaining_total_payload(),
+ frame_decoder_state_.remaining_payload());
+ return settings_payload_decoder_.ResumeDecodingPayload(&frame_decoder_state_,
+ db);
+}
+
+DecodeStatus Http2FrameDecoder::StartDecodingUnknownPayload(DecodeBuffer* db) {
+ // We don't known what type of frame this is, so we don't know which flags
+ // are valid, so we don't touch them.
+ return unknown_payload_decoder_.StartDecodingPayload(&frame_decoder_state_,
+ db);
+}
+DecodeStatus Http2FrameDecoder::ResumeDecodingUnknownPayload(DecodeBuffer* db) {
+ // We don't known what type of frame this is, so we treat it as not paddable.
+ DCHECK_EQ(frame_decoder_state_.remaining_total_payload(),
+ frame_decoder_state_.remaining_payload());
+ return unknown_payload_decoder_.ResumeDecodingPayload(&frame_decoder_state_,
+ db);
+}
+
+DecodeStatus Http2FrameDecoder::StartDecodingWindowUpdatePayload(
+ DecodeBuffer* db) {
+ ClearFlags();
+ return window_update_payload_decoder_.StartDecodingPayload(
+ &frame_decoder_state_, db);
+}
+DecodeStatus Http2FrameDecoder::ResumeDecodingWindowUpdatePayload(
+ DecodeBuffer* db) {
+ // The frame is not paddable.
+ DCHECK_EQ(frame_decoder_state_.remaining_total_payload(),
+ frame_decoder_state_.remaining_payload());
+ return window_update_payload_decoder_.ResumeDecodingPayload(
+ &frame_decoder_state_, db);
+}
+
+DecodeStatus Http2FrameDecoder::DiscardPayload(DecodeBuffer* db) {
+ DVLOG(2) << "remaining_payload=" << frame_decoder_state_.remaining_payload_
+ << "; remaining_padding=" << frame_decoder_state_.remaining_padding_;
+ frame_decoder_state_.remaining_payload_ +=
+ frame_decoder_state_.remaining_padding_;
+ frame_decoder_state_.remaining_padding_ = 0;
+ const size_t avail = frame_decoder_state_.AvailablePayload(db);
+ DVLOG(2) << "avail=" << avail;
+ if (avail > 0) {
+ frame_decoder_state_.ConsumePayload(avail);
+ db->AdvanceCursor(avail);
+ }
+ if (frame_decoder_state_.remaining_payload_ == 0) {
+ state_ = State::kStartDecodingHeader;
+ return DecodeStatus::kDecodeDone;
+ }
+ return DecodeStatus::kDecodeInProgress;
+}
+
+} // namespace net
« no previous file with comments | « net/http2/decoder/http2_frame_decoder.h ('k') | net/http2/decoder/http2_frame_decoder_listener.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698