Index: net/http2/decoder/frame_parts.cc |
diff --git a/net/http2/decoder/frame_parts.cc b/net/http2/decoder/frame_parts.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..33cd7bfd7886c08984224ead6f3f5d8083dde3c3 |
--- /dev/null |
+++ b/net/http2/decoder/frame_parts.cc |
@@ -0,0 +1,527 @@ |
+// 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/frame_parts.h" |
+ |
+#include <type_traits> |
+ |
+#include "base/logging.h" |
+#include "net/base/escape.h" |
+#include "net/http2/http2_structures_test_util.h" |
+#include "net/http2/tools/failure.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+ |
+using base::StringPiece; |
+using std::string; |
+using ::testing::AssertionFailure; |
+using ::testing::AssertionResult; |
+using ::testing::AssertionSuccess; |
+using ::testing::ContainerEq; |
+ |
+namespace net { |
+namespace test { |
+namespace { |
+ |
+static_assert(std::is_base_of<Http2FrameDecoderListener, FrameParts>::value && |
+ !std::is_abstract<FrameParts>::value, |
+ "FrameParts needs to implement all of the methods of " |
+ "Http2FrameDecoderListener"); |
+ |
+// Compare two optional variables of the same type. |
+// TODO(jamessynge): Maybe create a ::testing::Matcher for this. |
+template <class T> |
+AssertionResult VerifyOptionalEq(const T& opt_a, const T& opt_b) { |
+ if (opt_a) { |
+ if (opt_b) { |
+ VERIFY_EQ(opt_a.value(), opt_b.value()); |
+ } else { |
+ return AssertionFailure() << "opt_b is not set; opt_a.value()=" |
+ << opt_a.value(); |
+ } |
+ } else if (opt_b) { |
+ return AssertionFailure() << "opt_a is not set; opt_b.value()=" |
+ << opt_b.value(); |
+ } |
+ return AssertionSuccess(); |
+} |
+ |
+} // namespace |
+ |
+FrameParts::FrameParts(const Http2FrameHeader& header) : frame_header(header) { |
+ VLOG(1) << "FrameParts, header: " << frame_header; |
+} |
+ |
+FrameParts::FrameParts(const Http2FrameHeader& header, StringPiece payload) |
+ : FrameParts(header) { |
+ VLOG(1) << "FrameParts with payload.size() = " << payload.size(); |
+ payload.AppendToString(&this->payload); |
+ opt_payload_length = payload.size(); |
+} |
+FrameParts::FrameParts(const Http2FrameHeader& header, |
+ StringPiece payload, |
+ size_t total_pad_length) |
+ : FrameParts(header, payload) { |
+ VLOG(1) << "FrameParts with total_pad_length=" << total_pad_length; |
+ SetTotalPadLength(total_pad_length); |
+} |
+ |
+FrameParts::FrameParts(const FrameParts& other) = default; |
+ |
+FrameParts::~FrameParts() {} |
+ |
+AssertionResult FrameParts::VerifyEquals(const FrameParts& that) const { |
+#define COMMON_MESSAGE "\n this: " << *this << "\n that: " << that |
+ |
+ VERIFY_EQ(frame_header, that.frame_header) << COMMON_MESSAGE; |
+ VERIFY_EQ(payload, that.payload) << COMMON_MESSAGE; |
+ VERIFY_EQ(padding, that.padding) << COMMON_MESSAGE; |
+ VERIFY_EQ(altsvc_origin, that.altsvc_origin) << COMMON_MESSAGE; |
+ VERIFY_EQ(altsvc_value, that.altsvc_value) << COMMON_MESSAGE; |
+ VERIFY_EQ(settings, that.settings) << COMMON_MESSAGE; |
+ |
+#define VERIFY_OPTIONAL_FIELD(field_name) \ |
+ VERIFY_SUCCESS(VerifyOptionalEq(field_name, that.field_name)) |
+ |
+ VERIFY_OPTIONAL_FIELD(opt_altsvc_origin_length) << COMMON_MESSAGE; |
+ VERIFY_OPTIONAL_FIELD(opt_altsvc_value_length) << COMMON_MESSAGE; |
+ VERIFY_OPTIONAL_FIELD(opt_goaway) << COMMON_MESSAGE; |
+ VERIFY_OPTIONAL_FIELD(opt_missing_length) << COMMON_MESSAGE; |
+ VERIFY_OPTIONAL_FIELD(opt_pad_length) << COMMON_MESSAGE; |
+ VERIFY_OPTIONAL_FIELD(opt_ping) << COMMON_MESSAGE; |
+ VERIFY_OPTIONAL_FIELD(opt_priority) << COMMON_MESSAGE; |
+ VERIFY_OPTIONAL_FIELD(opt_push_promise) << COMMON_MESSAGE; |
+ VERIFY_OPTIONAL_FIELD(opt_rst_stream_error_code) << COMMON_MESSAGE; |
+ VERIFY_OPTIONAL_FIELD(opt_window_update_increment) << COMMON_MESSAGE; |
+ |
+#undef VERIFY_OPTIONAL_FIELD |
+ |
+ return AssertionSuccess(); |
+} |
+ |
+void FrameParts::SetTotalPadLength(size_t total_pad_length) { |
+ opt_pad_length.reset(); |
+ padding.clear(); |
+ if (total_pad_length > 0) { |
+ ASSERT_LE(total_pad_length, 256u); |
+ ASSERT_TRUE(frame_header.IsPadded()); |
+ opt_pad_length = total_pad_length - 1; |
+ char zero = 0; |
+ padding.append(opt_pad_length.value(), zero); |
+ } |
+ |
+ if (opt_pad_length) { |
+ VLOG(1) << "SetTotalPadLength: pad_length=" << opt_pad_length.value(); |
+ } else { |
+ VLOG(1) << "SetTotalPadLength: has no pad length"; |
+ } |
+} |
+ |
+void FrameParts::SetAltSvcExpected(StringPiece origin, StringPiece value) { |
+ origin.AppendToString(&altsvc_origin); |
+ value.AppendToString(&altsvc_value); |
+ opt_altsvc_origin_length = origin.size(); |
+ opt_altsvc_value_length = value.size(); |
+} |
+ |
+bool FrameParts::OnFrameHeader(const Http2FrameHeader& header) { |
+ ADD_FAILURE() << "OnFrameHeader: " << *this; |
+ return true; |
+} |
+ |
+void FrameParts::OnDataStart(const Http2FrameHeader& header) { |
+ VLOG(1) << "OnDataStart: " << header; |
+ ASSERT_TRUE(StartFrameOfType(header, Http2FrameType::DATA)) << *this; |
+ opt_payload_length = header.payload_length; |
+} |
+ |
+void FrameParts::OnDataPayload(const char* data, size_t len) { |
+ VLOG(1) << "OnDataPayload: len=" << len << "; frame_header: " << frame_header; |
+ ASSERT_TRUE(InFrameOfType(Http2FrameType::DATA)) << *this; |
+ ASSERT_TRUE( |
+ AppendString(StringPiece(data, len), &payload, &opt_payload_length)); |
+} |
+ |
+void FrameParts::OnDataEnd() { |
+ VLOG(1) << "OnDataEnd; frame_header: " << frame_header; |
+ ASSERT_TRUE(EndFrameOfType(Http2FrameType::DATA)) << *this; |
+} |
+ |
+void FrameParts::OnHeadersStart(const Http2FrameHeader& header) { |
+ VLOG(1) << "OnHeadersStart: " << header; |
+ ASSERT_TRUE(StartFrameOfType(header, Http2FrameType::HEADERS)) << *this; |
+ opt_payload_length = header.payload_length; |
+} |
+ |
+void FrameParts::OnHeadersPriority(const Http2PriorityFields& priority) { |
+ VLOG(1) << "OnHeadersPriority: priority: " << priority |
+ << "; frame_header: " << frame_header; |
+ ASSERT_TRUE(InFrameOfType(Http2FrameType::HEADERS)) << *this; |
+ ASSERT_FALSE(opt_priority); |
+ opt_priority = priority; |
+ ASSERT_TRUE(opt_payload_length); |
+ opt_payload_length = |
+ opt_payload_length.value() - Http2PriorityFields::EncodedSize(); |
+} |
+ |
+void FrameParts::OnHpackFragment(const char* data, size_t len) { |
+ VLOG(1) << "OnHpackFragment: len=" << len |
+ << "; frame_header: " << frame_header; |
+ ASSERT_TRUE(got_start_callback); |
+ ASSERT_FALSE(got_end_callback); |
+ ASSERT_TRUE(FrameCanHaveHpackPayload(frame_header)) << *this; |
+ ASSERT_TRUE( |
+ AppendString(StringPiece(data, len), &payload, &opt_payload_length)); |
+} |
+ |
+void FrameParts::OnHeadersEnd() { |
+ VLOG(1) << "OnHeadersEnd; frame_header: " << frame_header; |
+ ASSERT_TRUE(EndFrameOfType(Http2FrameType::HEADERS)) << *this; |
+} |
+ |
+void FrameParts::OnPriorityFrame(const Http2FrameHeader& header, |
+ const Http2PriorityFields& priority) { |
+ VLOG(1) << "OnPriorityFrame: " << header << "; priority: " << priority; |
+ ASSERT_TRUE(StartFrameOfType(header, Http2FrameType::PRIORITY)) << *this; |
+ ASSERT_FALSE(opt_priority); |
+ opt_priority = priority; |
+ ASSERT_TRUE(EndFrameOfType(Http2FrameType::PRIORITY)) << *this; |
+} |
+ |
+void FrameParts::OnContinuationStart(const Http2FrameHeader& header) { |
+ VLOG(1) << "OnContinuationStart: " << header; |
+ ASSERT_TRUE(StartFrameOfType(header, Http2FrameType::CONTINUATION)) << *this; |
+ opt_payload_length = header.payload_length; |
+} |
+ |
+void FrameParts::OnContinuationEnd() { |
+ VLOG(1) << "OnContinuationEnd; frame_header: " << frame_header; |
+ ASSERT_TRUE(EndFrameOfType(Http2FrameType::CONTINUATION)) << *this; |
+} |
+ |
+void FrameParts::OnPadLength(size_t trailing_length) { |
+ VLOG(1) << "OnPadLength: trailing_length=" << trailing_length; |
+ ASSERT_TRUE(InPaddedFrame()) << *this; |
+ ASSERT_FALSE(opt_pad_length); |
+ ASSERT_TRUE(opt_payload_length); |
+ size_t total_padding_length = trailing_length + 1; |
+ ASSERT_GE(opt_payload_length.value(), static_cast<int>(total_padding_length)); |
+ opt_payload_length = opt_payload_length.value() - total_padding_length; |
+ opt_pad_length = trailing_length; |
+} |
+ |
+void FrameParts::OnPadding(const char* pad, size_t skipped_length) { |
+ VLOG(1) << "OnPadding: skipped_length=" << skipped_length; |
+ ASSERT_TRUE(InPaddedFrame()) << *this; |
+ ASSERT_TRUE(opt_pad_length); |
+ ASSERT_TRUE(AppendString(StringPiece(pad, skipped_length), &padding, |
+ &opt_pad_length)); |
+} |
+ |
+void FrameParts::OnRstStream(const Http2FrameHeader& header, |
+ Http2ErrorCode error_code) { |
+ VLOG(1) << "OnRstStream: " << header << "; code=" << error_code; |
+ ASSERT_TRUE(StartFrameOfType(header, Http2FrameType::RST_STREAM)) << *this; |
+ ASSERT_FALSE(opt_rst_stream_error_code); |
+ opt_rst_stream_error_code = error_code; |
+ ASSERT_TRUE(EndFrameOfType(Http2FrameType::RST_STREAM)) << *this; |
+} |
+ |
+void FrameParts::OnSettingsStart(const Http2FrameHeader& header) { |
+ VLOG(1) << "OnSettingsStart: " << header; |
+ ASSERT_TRUE(StartFrameOfType(header, Http2FrameType::SETTINGS)) << *this; |
+ ASSERT_EQ(0u, settings.size()); |
+ ASSERT_FALSE(header.IsAck()) << header; |
+} |
+ |
+void FrameParts::OnSetting(const Http2SettingFields& setting_fields) { |
+ VLOG(1) << "OnSetting: " << setting_fields; |
+ ASSERT_TRUE(InFrameOfType(Http2FrameType::SETTINGS)) << *this; |
+ settings.push_back(setting_fields); |
+} |
+ |
+void FrameParts::OnSettingsEnd() { |
+ VLOG(1) << "OnSettingsEnd; frame_header: " << frame_header; |
+ ASSERT_TRUE(EndFrameOfType(Http2FrameType::SETTINGS)) << *this; |
+} |
+ |
+void FrameParts::OnSettingsAck(const Http2FrameHeader& header) { |
+ VLOG(1) << "OnSettingsAck: " << header; |
+ ASSERT_TRUE(StartFrameOfType(header, Http2FrameType::SETTINGS)) << *this; |
+ ASSERT_EQ(0u, settings.size()); |
+ ASSERT_TRUE(header.IsAck()); |
+ ASSERT_TRUE(EndFrameOfType(Http2FrameType::SETTINGS)) << *this; |
+} |
+ |
+void FrameParts::OnPushPromiseStart(const Http2FrameHeader& header, |
+ const Http2PushPromiseFields& promise, |
+ size_t total_padding_length) { |
+ VLOG(1) << "OnPushPromiseStart header: " << header << "; promise: " << promise |
+ << "; total_padding_length: " << total_padding_length; |
+ ASSERT_TRUE(StartFrameOfType(header, Http2FrameType::PUSH_PROMISE)) << *this; |
+ ASSERT_GE(header.payload_length, Http2PushPromiseFields::EncodedSize()); |
+ opt_payload_length = |
+ header.payload_length - Http2PushPromiseFields::EncodedSize(); |
+ ASSERT_FALSE(opt_push_promise); |
+ opt_push_promise = promise; |
+ if (total_padding_length > 0) { |
+ ASSERT_GE(opt_payload_length.value(), |
+ static_cast<int>(total_padding_length)); |
+ OnPadLength(total_padding_length - 1); |
+ } else { |
+ ASSERT_FALSE(header.IsPadded()); |
+ } |
+} |
+ |
+void FrameParts::OnPushPromiseEnd() { |
+ VLOG(1) << "OnPushPromiseEnd; frame_header: " << frame_header; |
+ ASSERT_TRUE(EndFrameOfType(Http2FrameType::PUSH_PROMISE)) << *this; |
+} |
+ |
+void FrameParts::OnPing(const Http2FrameHeader& header, |
+ const Http2PingFields& ping) { |
+ VLOG(1) << "OnPing header: " << header << " ping: " << ping; |
+ ASSERT_TRUE(StartFrameOfType(header, Http2FrameType::PING)) << *this; |
+ ASSERT_FALSE(header.IsAck()); |
+ ASSERT_FALSE(opt_ping); |
+ opt_ping = ping; |
+ ASSERT_TRUE(EndFrameOfType(Http2FrameType::PING)) << *this; |
+} |
+ |
+void FrameParts::OnPingAck(const Http2FrameHeader& header, |
+ const Http2PingFields& ping) { |
+ VLOG(1) << "OnPingAck header: " << header << " ping: " << ping; |
+ ASSERT_TRUE(StartFrameOfType(header, Http2FrameType::PING)) << *this; |
+ ASSERT_TRUE(header.IsAck()); |
+ ASSERT_FALSE(opt_ping); |
+ opt_ping = ping; |
+ ASSERT_TRUE(EndFrameOfType(Http2FrameType::PING)) << *this; |
+} |
+ |
+void FrameParts::OnGoAwayStart(const Http2FrameHeader& header, |
+ const Http2GoAwayFields& goaway) { |
+ VLOG(1) << "OnGoAwayStart: " << goaway; |
+ ASSERT_TRUE(StartFrameOfType(header, Http2FrameType::GOAWAY)) << *this; |
+ ASSERT_FALSE(opt_goaway); |
+ opt_goaway = goaway; |
+ opt_payload_length = header.payload_length - Http2GoAwayFields::EncodedSize(); |
+} |
+ |
+void FrameParts::OnGoAwayOpaqueData(const char* data, size_t len) { |
+ VLOG(1) << "OnGoAwayOpaqueData: len=" << len; |
+ ASSERT_TRUE(InFrameOfType(Http2FrameType::GOAWAY)) << *this; |
+ ASSERT_TRUE( |
+ AppendString(StringPiece(data, len), &payload, &opt_payload_length)); |
+} |
+ |
+void FrameParts::OnGoAwayEnd() { |
+ VLOG(1) << "OnGoAwayEnd; frame_header: " << frame_header; |
+ ASSERT_TRUE(EndFrameOfType(Http2FrameType::GOAWAY)) << *this; |
+} |
+ |
+void FrameParts::OnWindowUpdate(const Http2FrameHeader& header, |
+ uint32_t increment) { |
+ VLOG(1) << "OnWindowUpdate header: " << header |
+ << " increment=" << increment; |
+ ASSERT_TRUE(StartFrameOfType(header, Http2FrameType::WINDOW_UPDATE)) << *this; |
+ ASSERT_FALSE(opt_window_update_increment); |
+ opt_window_update_increment = increment; |
+ ASSERT_TRUE(EndFrameOfType(Http2FrameType::WINDOW_UPDATE)) << *this; |
+} |
+ |
+void FrameParts::OnAltSvcStart(const Http2FrameHeader& header, |
+ size_t origin_length, |
+ size_t value_length) { |
+ VLOG(1) << "OnAltSvcStart: " << header |
+ << " origin_length: " << origin_length |
+ << " value_length: " << value_length; |
+ ASSERT_TRUE(StartFrameOfType(header, Http2FrameType::ALTSVC)) << *this; |
+ ASSERT_FALSE(opt_altsvc_origin_length); |
+ opt_altsvc_origin_length = origin_length; |
+ ASSERT_FALSE(opt_altsvc_value_length); |
+ opt_altsvc_value_length = value_length; |
+} |
+ |
+void FrameParts::OnAltSvcOriginData(const char* data, size_t len) { |
+ VLOG(1) << "OnAltSvcOriginData: len=" << len; |
+ ASSERT_TRUE(InFrameOfType(Http2FrameType::ALTSVC)) << *this; |
+ ASSERT_TRUE(AppendString(StringPiece(data, len), &altsvc_origin, |
+ &opt_altsvc_origin_length)); |
+} |
+ |
+void FrameParts::OnAltSvcValueData(const char* data, size_t len) { |
+ VLOG(1) << "OnAltSvcValueData: len=" << len; |
+ ASSERT_TRUE(InFrameOfType(Http2FrameType::ALTSVC)) << *this; |
+ ASSERT_TRUE(AppendString(StringPiece(data, len), &altsvc_value, |
+ &opt_altsvc_value_length)); |
+} |
+ |
+void FrameParts::OnAltSvcEnd() { |
+ VLOG(1) << "OnAltSvcEnd; frame_header: " << frame_header; |
+ ASSERT_TRUE(EndFrameOfType(Http2FrameType::ALTSVC)) << *this; |
+} |
+ |
+void FrameParts::OnUnknownStart(const Http2FrameHeader& header) { |
+ VLOG(1) << "OnUnknownStart: " << header; |
+ ASSERT_FALSE(IsSupportedHttp2FrameType(header.type)) << header; |
+ ASSERT_FALSE(got_start_callback); |
+ ASSERT_EQ(frame_header, header); |
+ got_start_callback = true; |
+ opt_payload_length = header.payload_length; |
+} |
+ |
+void FrameParts::OnUnknownPayload(const char* data, size_t len) { |
+ VLOG(1) << "OnUnknownPayload: len=" << len; |
+ ASSERT_FALSE(IsSupportedHttp2FrameType(frame_header.type)) << *this; |
+ ASSERT_TRUE(got_start_callback); |
+ ASSERT_FALSE(got_end_callback); |
+ ASSERT_TRUE( |
+ AppendString(StringPiece(data, len), &payload, &opt_payload_length)); |
+} |
+ |
+void FrameParts::OnUnknownEnd() { |
+ VLOG(1) << "OnUnknownEnd; frame_header: " << frame_header; |
+ ASSERT_FALSE(IsSupportedHttp2FrameType(frame_header.type)) << *this; |
+ ASSERT_TRUE(got_start_callback); |
+ ASSERT_FALSE(got_end_callback); |
+ got_end_callback = true; |
+} |
+ |
+void FrameParts::OnPaddingTooLong(const Http2FrameHeader& header, |
+ size_t missing_length) { |
+ VLOG(1) << "OnPaddingTooLong: " << header |
+ << "; missing_length: " << missing_length; |
+ ASSERT_EQ(frame_header, header); |
+ ASSERT_FALSE(got_end_callback); |
+ ASSERT_TRUE(FrameIsPadded(header)); |
+ ASSERT_FALSE(opt_pad_length); |
+ ASSERT_FALSE(opt_missing_length); |
+ opt_missing_length = missing_length; |
+ got_start_callback = true; |
+ got_end_callback = true; |
+} |
+ |
+void FrameParts::OnFrameSizeError(const Http2FrameHeader& header) { |
+ VLOG(1) << "OnFrameSizeError: " << header; |
+ ASSERT_EQ(frame_header, header); |
+ ASSERT_FALSE(got_end_callback); |
+ ASSERT_FALSE(has_frame_size_error); |
+ has_frame_size_error = true; |
+ got_end_callback = true; |
+} |
+ |
+void FrameParts::OutputTo(std::ostream& out) const { |
+ out << "FrameParts{\n frame_header: " << frame_header << "\n"; |
+ if (!payload.empty()) { |
+ out << " payload=\"" << EscapeQueryParamValue(payload, false) << "\"\n"; |
+ } |
+ if (!padding.empty()) { |
+ out << " padding=\"" << EscapeQueryParamValue(padding, false) << "\"\n"; |
+ } |
+ if (!altsvc_origin.empty()) { |
+ out << " altsvc_origin=\"" << EscapeQueryParamValue(altsvc_origin, false) |
+ << "\"\n"; |
+ } |
+ if (!altsvc_value.empty()) { |
+ out << " altsvc_value=\"" << EscapeQueryParamValue(altsvc_value, false) |
+ << "\"\n"; |
+ } |
+ if (opt_priority) { |
+ out << " priority=" << opt_priority.value() << "\n"; |
+ } |
+ if (opt_rst_stream_error_code) { |
+ out << " rst_stream=" << opt_rst_stream_error_code.value() << "\n"; |
+ } |
+ if (opt_push_promise) { |
+ out << " push_promise=" << opt_push_promise.value() << "\n"; |
+ } |
+ if (opt_ping) { |
+ out << " ping=" << opt_ping.value() << "\n"; |
+ } |
+ if (opt_goaway) { |
+ out << " goaway=" << opt_goaway.value() << "\n"; |
+ } |
+ if (opt_window_update_increment) { |
+ out << " window_update=" << opt_window_update_increment.value() << "\n"; |
+ } |
+ if (opt_payload_length) { |
+ out << " payload_length=" << opt_payload_length.value() << "\n"; |
+ } |
+ if (opt_pad_length) { |
+ out << " pad_length=" << opt_pad_length.value() << "\n"; |
+ } |
+ if (opt_missing_length) { |
+ out << " missing_length=" << opt_missing_length.value() << "\n"; |
+ } |
+ if (opt_altsvc_origin_length) { |
+ out << " origin_length=" << opt_altsvc_origin_length.value() << "\n"; |
+ } |
+ if (opt_altsvc_value_length) { |
+ out << " value_length=" << opt_altsvc_value_length.value() << "\n"; |
+ } |
+ if (has_frame_size_error) { |
+ out << " has_frame_size_error\n"; |
+ } |
+ if (got_start_callback) { |
+ out << " got_start_callback\n"; |
+ } |
+ if (got_end_callback) { |
+ out << " got_end_callback\n"; |
+ } |
+ for (size_t ndx = 0; ndx < settings.size(); ++ndx) { |
+ out << " setting[" << ndx << "]=" << settings[ndx]; |
+ } |
+ out << "}"; |
+} |
+ |
+AssertionResult FrameParts::StartFrameOfType( |
+ const Http2FrameHeader& header, |
+ Http2FrameType expected_frame_type) { |
+ VERIFY_EQ(header.type, expected_frame_type); |
+ VERIFY_FALSE(got_start_callback); |
+ VERIFY_FALSE(got_end_callback); |
+ VERIFY_EQ(frame_header, header); |
+ got_start_callback = true; |
+ return AssertionSuccess(); |
+} |
+ |
+AssertionResult FrameParts::InFrameOfType(Http2FrameType expected_frame_type) { |
+ VERIFY_TRUE(got_start_callback); |
+ VERIFY_FALSE(got_end_callback); |
+ VERIFY_EQ(frame_header.type, expected_frame_type); |
+ return AssertionSuccess(); |
+} |
+ |
+AssertionResult FrameParts::EndFrameOfType(Http2FrameType expected_frame_type) { |
+ VERIFY_SUCCESS(InFrameOfType(expected_frame_type)); |
+ got_end_callback = true; |
+ return AssertionSuccess(); |
+} |
+ |
+AssertionResult FrameParts::InPaddedFrame() { |
+ VERIFY_TRUE(got_start_callback); |
+ VERIFY_FALSE(got_end_callback); |
+ VERIFY_TRUE(FrameIsPadded(frame_header)); |
+ return AssertionSuccess(); |
+} |
+ |
+AssertionResult FrameParts::AppendString(StringPiece source, |
+ string* target, |
+ base::Optional<int>* opt_length) { |
+ source.AppendToString(target); |
+ if (opt_length != nullptr) { |
+ VERIFY_TRUE(*opt_length) << "Length is not set yet\n" << *this; |
+ VERIFY_LE(target->size(), static_cast<size_t>(opt_length->value())) |
+ << "String too large; source.size() = " << source.size() << "\n" |
+ << *this; |
+ } |
+ return ::testing::AssertionSuccess(); |
+} |
+ |
+std::ostream& operator<<(std::ostream& out, const FrameParts& v) { |
+ v.OutputTo(out); |
+ return out; |
+} |
+ |
+} // namespace test |
+} // namespace net |