Commit 30dd84d5 authored by Dianna Hu's avatar Dianna Hu Committed by Commit Bot

Make HpackVarintDecoder support 64-bit integers.

This feature is guarded by --chromium_flag_http2_varint_decode_64_bits.

Before this change, HpackVarintDecoder only decoded integers up to 2^28
+ 2^prefix_length - 2, where prefix_length is between 3 and 7.  Trying
to decode larger integers resulted in an error.  After this change,
HpackVarintDecoder decodes any integer that can be represented on 64
bits (unsigned).  Any input that HpackVarintDecoder decoded before this
change is still decoded.

Decoded integers are used to address entries in the static and dynamic
tables, to specify string lengths, and to update the size limit of the
dynamic table, both in HTTP/2 and in QUIC.  For all of these values
there is already a limit in place that is much lower than 2^28
(otherwise a malicious client could waste hundreds of megabytes of
server memory; and if there is no such limit in place, then we already
have a problem), so making the decoder decode larger values should not
change behavior at higher levels.

To merge this feature, this change also adds an HTTP/2 platform API for
flags,  maintaining parity with SPDY and QUIC (and keeping the
separation between SPDY and HTTP/2 for ease of merging to Chromium).
This change then uses this platform API in the related files referencing
the feature flag and adds a presubmit check.

This change borrows heavily from the pre-existing SPDY and QUIC platform
API for flags.

This CL lands server changes 216463549 and 221087569 by bnc, and
218390247 by diannahu.

BUG=488484

Change-Id: Ie0788f117aba9c6d41fc31148e28c9b49e122602
Reviewed-on: https://chromium-review.googlesource.com/c/1310613Reviewed-by: default avatarBence Béky <bnc@chromium.org>
Commit-Queue: Dianna Hu <diannahu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#607349}
parent f27d45e0
...@@ -1206,6 +1206,7 @@ component("net") { ...@@ -1206,6 +1206,7 @@ component("net") {
"third_party/http2/http2_structures.h", "third_party/http2/http2_structures.h",
"third_party/http2/platform/api/http2_arraysize.h", "third_party/http2/platform/api/http2_arraysize.h",
"third_party/http2/platform/api/http2_export.h", "third_party/http2/platform/api/http2_export.h",
"third_party/http2/platform/api/http2_flags.h",
"third_party/http2/platform/api/http2_optional.h", "third_party/http2/platform/api/http2_optional.h",
"third_party/http2/platform/api/http2_ptr_util.h", "third_party/http2/platform/api/http2_ptr_util.h",
"third_party/http2/platform/api/http2_reconstruct_object.h", "third_party/http2/platform/api/http2_reconstruct_object.h",
...@@ -1214,6 +1215,8 @@ component("net") { ...@@ -1214,6 +1215,8 @@ component("net") {
"third_party/http2/platform/api/http2_string_utils.h", "third_party/http2/platform/api/http2_string_utils.h",
"third_party/http2/platform/impl/http2_arraysize_impl.h", "third_party/http2/platform/impl/http2_arraysize_impl.h",
"third_party/http2/platform/impl/http2_export_impl.h", "third_party/http2/platform/impl/http2_export_impl.h",
"third_party/http2/platform/impl/http2_flags_impl.cc",
"third_party/http2/platform/impl/http2_flags_impl.h",
"third_party/http2/platform/impl/http2_optional_impl.h", "third_party/http2/platform/impl/http2_optional_impl.h",
"third_party/http2/platform/impl/http2_ptr_util_impl.h", "third_party/http2/platform/impl/http2_ptr_util_impl.h",
"third_party/http2/platform/impl/http2_reconstruct_object_impl.h", "third_party/http2/platform/impl/http2_reconstruct_object_impl.h",
......
...@@ -29,7 +29,8 @@ void HpackBlockBuilder::AppendHighBitsAndVarint(uint8_t high_bits, ...@@ -29,7 +29,8 @@ void HpackBlockBuilder::AppendHighBitsAndVarint(uint8_t high_bits,
// After the prefix, at most 63 bits can remain to be encoded. // After the prefix, at most 63 bits can remain to be encoded.
// Each octet holds 7 bits, so at most 9 octets are necessary. // Each octet holds 7 bits, so at most 9 octets are necessary.
varint_encoder.ResumeEncoding(/* max_encoded_bytes = */ 9, &buffer_); // TODO(bnc): Move this into a constant in HpackVarintEncoder.
varint_encoder.ResumeEncoding(/* max_encoded_bytes = */ 10, &buffer_);
DCHECK(!varint_encoder.IsEncodingInProgress()); DCHECK(!varint_encoder.IsEncodingInProgress());
} }
......
...@@ -42,7 +42,77 @@ DecodeStatus HpackVarintDecoder::StartExtended(uint8_t prefix_length, ...@@ -42,7 +42,77 @@ DecodeStatus HpackVarintDecoder::StartExtended(uint8_t prefix_length,
} }
DecodeStatus HpackVarintDecoder::Resume(DecodeBuffer* db) { DecodeStatus HpackVarintDecoder::Resume(DecodeBuffer* db) {
const uint32_t kMaxOffset = 28; if (decode_64_bits_) {
// There can be at most 10 continuation bytes. Offset is zero for the
// first one and increases by 7 for each subsequent one.
const uint8_t kMaxOffset = 63;
CheckNotDone();
// Process most extension bytes without the need for overflow checking.
while (offset_ < kMaxOffset) {
if (db->Empty()) {
return DecodeStatus::kDecodeInProgress;
}
uint8_t byte = db->DecodeUInt8();
uint64_t summand = byte & 0x7f;
// Shifting a 7 bit value to the left by at most 56 places can never
// overflow on uint64_t.
DCHECK_LE(offset_, 56);
DCHECK_LE(summand, std::numeric_limits<uint64_t>::max() >> offset_);
summand <<= offset_;
// At this point,
// |value_| is at most (2^prefix_length - 1) + (2^49 - 1), and
// |summand| is at most 255 << 56 (which is smaller than 2^63),
// so adding them can never overflow on uint64_t.
DCHECK_LE(value_, std::numeric_limits<uint64_t>::max() - summand);
value_ += summand;
// Decoding ends if continuation flag is not set.
if ((byte & 0x80) == 0) {
MarkDone();
return DecodeStatus::kDecodeDone;
}
offset_ += 7;
}
if (db->Empty()) {
return DecodeStatus::kDecodeInProgress;
}
DCHECK_EQ(kMaxOffset, offset_);
uint8_t byte = db->DecodeUInt8();
// No more extension bytes are allowed after this.
if ((byte & 0x80) == 0) {
uint64_t summand = byte & 0x7f;
// Check for overflow in left shift.
if (summand <= std::numeric_limits<uint64_t>::max() >> offset_) {
summand <<= offset_;
// Check for overflow in addition.
if (value_ <= std::numeric_limits<uint64_t>::max() - summand) {
value_ += summand;
MarkDone();
return DecodeStatus::kDecodeDone;
}
}
}
// Signal error if value is too large or there are too many extension bytes.
DLOG(WARNING) << "Variable length int encoding is too large or too long. "
<< DebugString();
MarkDone();
return DecodeStatus::kDecodeError;
}
// Old code path. TODO(bnc): remove.
DCHECK(!decode_64_bits_);
const uint8_t kMaxOffset = 28;
CheckNotDone(); CheckNotDone();
do { do {
if (db->Empty()) { if (db->Empty()) {
...@@ -51,6 +121,9 @@ DecodeStatus HpackVarintDecoder::Resume(DecodeBuffer* db) { ...@@ -51,6 +121,9 @@ DecodeStatus HpackVarintDecoder::Resume(DecodeBuffer* db) {
uint8_t byte = db->DecodeUInt8(); uint8_t byte = db->DecodeUInt8();
if (offset_ == kMaxOffset && byte != 0) if (offset_ == kMaxOffset && byte != 0)
break; break;
DCHECK(offset_ <= kMaxOffset - 7 || byte == 0);
// Shifting a 7 bit value to the left by at most 21 places can never
// overflow on uint32_t. Shifting 0 to the left cannot overflow either.
value_ += (byte & 0x7f) << offset_; value_ += (byte & 0x7f) << offset_;
if ((byte & 0x80) == 0) { if ((byte & 0x80) == 0) {
MarkDone(); MarkDone();
...@@ -64,12 +137,12 @@ DecodeStatus HpackVarintDecoder::Resume(DecodeBuffer* db) { ...@@ -64,12 +137,12 @@ DecodeStatus HpackVarintDecoder::Resume(DecodeBuffer* db) {
return DecodeStatus::kDecodeError; return DecodeStatus::kDecodeError;
} }
uint32_t HpackVarintDecoder::value() const { uint64_t HpackVarintDecoder::value() const {
CheckDone(); CheckDone();
return value_; return value_;
} }
void HpackVarintDecoder::set_value(uint32_t v) { void HpackVarintDecoder::set_value(uint64_t v) {
MarkDone(); MarkDone();
value_ = v; value_ = v;
} }
......
...@@ -2,29 +2,34 @@ ...@@ -2,29 +2,34 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// HpackVarintDecoder decodes HPACK variable length unsigned integers. These // HpackVarintDecoder decodes HPACK variable length unsigned integers. In HPACK,
// integers are used to identify static or dynamic table index entries, to // these integers are used to identify static or dynamic table index entries, to
// specify string lengths, and to update the size limit of the dynamic table. // specify string lengths, and to update the size limit of the dynamic table.
// In QPACK, in addition to these uses, these integers also identify streams.
// //
// The caller will need to validate that the decoded value is in an acceptable // The caller will need to validate that the decoded value is in an acceptable
// range. // range.
// //
// In order to support naive encoders (i.e. which always output 5 extension
// bytes for a uint32 that is >= prefix_mask), the decoder supports an an
// encoding with up to 5 extension bytes, and a maximum value of 268,435,582
// (4 "full" extension bytes plus the maximum for a prefix, 127). It could be
// modified to support a lower maximum value (by requiring that extensions bytes
// be "empty"), or a larger value if valuable for some reason I can't see.
//
// For details of the encoding, see: // For details of the encoding, see:
// http://httpwg.org/specs/rfc7541.html#integer.representation // http://httpwg.org/specs/rfc7541.html#integer.representation
// //
// The decoder supports decoding integers up to 2^28 + 2^prefix_length - 2. // If GetHttp2ReloadableFlag(http2_varint_decode_64_bits) is true, then this
// decoder supports decoding any integer that can be represented on uint64_t,
// thereby exceeding the requirements for QPACK: "QPACK implementations MUST be
// able to decode integers up to 62 bits long." See
// https://quicwg.org/base-drafts/draft-ietf-quic-qpack.html#rfc.section.5.1.1
//
// If GetHttp2ReloadableFlag(http2_varint_decode_64_bits) is false, then this
// decoder supports decoding integers up to 2^28 + 2^prefix_length - 2.
// //
// TODO(jamessynge): Consider dropping support for encodings of more than 4 // This decoder supports at most 10 extension bytes (bytes following the prefix,
// bytes, including the prefix byte, as in practice we only see at most 3 bytes, // also called continuation bytes) if
// and 4 bytes would cover any desire to support large (but not ridiculously // GetHttp2ReloadableFlag(http2_varint_decode_64_bits) is true, and at most 5
// large) header values. // extension bytes if GetHttp2ReloadableFlag(http2_varint_decode_64_bits) is
// false. An encoder is allowed to zero pad the encoded integer on the left,
// thereby increasing the number of extension bytes. If an encoder uses so much
// padding that the number of extension bytes exceeds the limit, then this
// decoder signals an error.
#ifndef NET_THIRD_PARTY_HTTP2_HPACK_VARINT_HPACK_VARINT_DECODER_H_ #ifndef NET_THIRD_PARTY_HTTP2_HPACK_VARINT_HPACK_VARINT_DECODER_H_
#define NET_THIRD_PARTY_HTTP2_HPACK_VARINT_HPACK_VARINT_DECODER_H_ #define NET_THIRD_PARTY_HTTP2_HPACK_VARINT_HPACK_VARINT_DECODER_H_
...@@ -36,9 +41,18 @@ ...@@ -36,9 +41,18 @@
#include "net/third_party/http2/decoder/decode_buffer.h" #include "net/third_party/http2/decoder/decode_buffer.h"
#include "net/third_party/http2/decoder/decode_status.h" #include "net/third_party/http2/decoder/decode_status.h"
#include "net/third_party/http2/platform/api/http2_export.h" #include "net/third_party/http2/platform/api/http2_export.h"
#include "net/third_party/http2/platform/api/http2_flags.h"
#include "net/third_party/http2/platform/api/http2_string.h" #include "net/third_party/http2/platform/api/http2_string.h"
namespace http2 { namespace http2 {
// Sentinel value for |HpackVarintDecoder::offset_| to signify that decoding is
// completed. Only used in debug builds.
#ifndef NDEBUG
const uint8_t kHpackVarintDecoderOffsetDone =
std::numeric_limits<uint8_t>::max();
#endif
// Decodes an HPACK variable length unsigned integer, in a resumable fashion // Decodes an HPACK variable length unsigned integer, in a resumable fashion
// so it can handle running out of input in the DecodeBuffer. Call Start or // so it can handle running out of input in the DecodeBuffer. Call Start or
// StartExtended the first time (when decoding the byte that contains the // StartExtended the first time (when decoding the byte that contains the
...@@ -69,11 +83,11 @@ class HTTP2_EXPORT_PRIVATE HpackVarintDecoder { ...@@ -69,11 +83,11 @@ class HTTP2_EXPORT_PRIVATE HpackVarintDecoder {
// call to Start or StartExtended returned kDecodeInProgress. // call to Start or StartExtended returned kDecodeInProgress.
DecodeStatus Resume(DecodeBuffer* db); DecodeStatus Resume(DecodeBuffer* db);
uint32_t value() const; uint64_t value() const;
// This supports optimizations for the case of a varint with zero extension // This supports optimizations for the case of a varint with zero extension
// bytes, where the handling of the prefix is done by the caller. // bytes, where the handling of the prefix is done by the caller.
void set_value(uint32_t v); void set_value(uint64_t v);
// All the public methods below are for supporting assertions and tests. // All the public methods below are for supporting assertions and tests.
...@@ -91,24 +105,38 @@ class HTTP2_EXPORT_PRIVATE HpackVarintDecoder { ...@@ -91,24 +105,38 @@ class HTTP2_EXPORT_PRIVATE HpackVarintDecoder {
// Protection in case Resume is called when it shouldn't be. // Protection in case Resume is called when it shouldn't be.
void MarkDone() { void MarkDone() {
#ifndef NDEBUG #ifndef NDEBUG
offset_ = std::numeric_limits<uint32_t>::max(); offset_ = kHpackVarintDecoderOffsetDone;
#endif #endif
} }
void CheckNotDone() const { void CheckNotDone() const {
#ifndef NDEBUG #ifndef NDEBUG
DCHECK_NE(std::numeric_limits<uint32_t>::max(), offset_); DCHECK_NE(kHpackVarintDecoderOffsetDone, offset_);
#endif #endif
} }
void CheckDone() const { void CheckDone() const {
#ifndef NDEBUG #ifndef NDEBUG
DCHECK_EQ(std::numeric_limits<uint32_t>::max(), offset_); DCHECK_EQ(kHpackVarintDecoderOffsetDone, offset_);
#endif #endif
} }
// If true, decode integers up to 2^64 - 1, and accept at most 10 extension
// bytes (some of which might be padding).
// If false, decode integers up to 2^28 + 2^prefix_length - 2, and accept at
// most 5 extension bytes (some of which might be padding).
bool decode_64_bits_ = GetHttp2ReloadableFlag(http2_varint_decode_64_bits);
// These fields are initialized just to keep ASAN happy about reading // These fields are initialized just to keep ASAN happy about reading
// them from DebugString(). // them from DebugString().
uint32_t value_ = 0;
uint32_t offset_ = 0; // The encoded integer is being accumulated in |value_|. When decoding is
// complete, |value_| holds the result.
uint64_t value_ = 0;
// Each extension byte encodes in its lowest 7 bits a segment of the integer.
// |offset_| is the number of places this segment has to be shifted to the
// left for decoding. It is zero for the first extension byte, and increases
// by 7 for each subsequent extension byte.
uint8_t offset_ = 0;
}; };
} // namespace http2 } // namespace http2
......
...@@ -22,18 +22,37 @@ namespace http2 { ...@@ -22,18 +22,37 @@ namespace http2 {
namespace test { namespace test {
namespace { namespace {
class HpackVarintDecoderTest : public RandomDecoderTest, // Save previous value of flag and restore on destruction.
public ::testing::WithParamInterface< class FlagSaver {
::testing::tuple<uint8_t, const char*>> { public:
FlagSaver() = delete;
explicit FlagSaver(bool decode_64_bits)
: saved_value_(GetHttp2ReloadableFlag(http2_varint_decode_64_bits)) {
SetHttp2ReloadableFlag(http2_varint_decode_64_bits, decode_64_bits);
}
~FlagSaver() {
SetHttp2ReloadableFlag(http2_varint_decode_64_bits, saved_value_);
}
private:
const bool saved_value_;
};
class HpackVarintDecoderTest
: public RandomDecoderTest,
public ::testing::WithParamInterface<
::testing::tuple<bool, uint8_t, const char*>> {
protected: protected:
HpackVarintDecoderTest() HpackVarintDecoderTest()
: high_bits_(::testing::get<0>(GetParam())), : decode_64_bits_(::testing::get<0>(GetParam())),
suffix_(Http2HexDecode(::testing::get<1>(GetParam()))), high_bits_(::testing::get<1>(GetParam())),
suffix_(Http2HexDecode(::testing::get<2>(GetParam()))),
flag_saver_(decode_64_bits_),
prefix_length_(0) {} prefix_length_(0) {}
void DecodeExpectSuccess(Http2StringPiece data, void DecodeExpectSuccess(Http2StringPiece data,
uint32_t prefix_length, uint32_t prefix_length,
uint32_t expected_value) { uint64_t expected_value) {
Validator validator = [expected_value, this]( Validator validator = [expected_value, this](
const DecodeBuffer& db, const DecodeBuffer& db,
DecodeStatus status) -> AssertionResult { DecodeStatus status) -> AssertionResult {
...@@ -62,6 +81,8 @@ class HpackVarintDecoderTest : public RandomDecoderTest, ...@@ -62,6 +81,8 @@ class HpackVarintDecoderTest : public RandomDecoderTest,
EXPECT_TRUE(Decode(data, prefix_length, validator)); EXPECT_TRUE(Decode(data, prefix_length, validator));
} }
bool decode_64_bits() const { return decode_64_bits_; }
private: private:
AssertionResult Decode(Http2StringPiece data, AssertionResult Decode(Http2StringPiece data,
uint32_t prefix_length, uint32_t prefix_length,
...@@ -98,11 +119,16 @@ class HpackVarintDecoderTest : public RandomDecoderTest, ...@@ -98,11 +119,16 @@ class HpackVarintDecoderTest : public RandomDecoderTest,
return decoder_.Resume(b); return decoder_.Resume(b);
} }
// Test new or old behavior.
const bool decode_64_bits_;
// Bits of the first byte not part of the prefix. // Bits of the first byte not part of the prefix.
const uint8_t high_bits_; const uint8_t high_bits_;
// Extra bytes appended to the input. // Extra bytes appended to the input.
const Http2String suffix_; const Http2String suffix_;
// |flag_saver_| must preceed |decoder_| so that the flag is already set when
// |decoder_| is constructed.
FlagSaver flag_saver_;
HpackVarintDecoder decoder_; HpackVarintDecoder decoder_;
uint8_t prefix_length_; uint8_t prefix_length_;
}; };
...@@ -111,16 +137,145 @@ INSTANTIATE_TEST_CASE_P( ...@@ -111,16 +137,145 @@ INSTANTIATE_TEST_CASE_P(
HpackVarintDecoderTest, HpackVarintDecoderTest,
HpackVarintDecoderTest, HpackVarintDecoderTest,
::testing::Combine( ::testing::Combine(
// Test both the new version (supporting 64 bit integers) and the old
// one (only supporting up to 2^28 + 2^prefix_length - 2.
::testing::Bool(),
// Bits of the first byte not part of the prefix should be ignored. // Bits of the first byte not part of the prefix should be ignored.
::testing::Values(0b00000000, 0b11111111, 0b10101010), ::testing::Values(0b00000000, 0b11111111, 0b10101010),
// Extra bytes appended to the input should be ignored. // Extra bytes appended to the input should be ignored.
::testing::Values("", "00", "666f6f"))); ::testing::Values("", "00", "666f6f")));
// Test data used when decode_64_bits() == true.
struct { struct {
const char* data; const char* data;
uint32_t prefix_length; uint32_t prefix_length;
uint32_t expected_value; uint64_t expected_value;
} kSuccessTestData[] = { } kSuccessTestData[] = {
// Zero value with different prefix lengths.
{"00", 3, 0},
{"00", 4, 0},
{"00", 5, 0},
{"00", 6, 0},
{"00", 7, 0},
// Small values that fit in the prefix.
{"06", 3, 6},
{"0d", 4, 13},
{"10", 5, 16},
{"29", 6, 41},
{"56", 7, 86},
// Values of 2^n-1, which have an all-zero extension byte.
{"0700", 3, 7},
{"0f00", 4, 15},
{"1f00", 5, 31},
{"3f00", 6, 63},
{"7f00", 7, 127},
// Values of 2^n-1, plus one extra byte of padding.
{"078000", 3, 7},
{"0f8000", 4, 15},
{"1f8000", 5, 31},
{"3f8000", 6, 63},
{"7f8000", 7, 127},
// Values requiring one extension byte.
{"0760", 3, 103},
{"0f2a", 4, 57},
{"1f7f", 5, 158},
{"3f02", 6, 65},
{"7f49", 7, 200},
// Values requiring one extension byte, plus one byte of padding.
{"07e000", 3, 103},
{"0faa00", 4, 57},
{"1fff00", 5, 158},
{"3f8200", 6, 65},
{"7fc900", 7, 200},
// Values requiring one extension byte, plus two bytes of padding.
{"07e08000", 3, 103},
{"0faa8000", 4, 57},
{"1fff8000", 5, 158},
{"3f828000", 6, 65},
{"7fc98000", 7, 200},
// Values requiring one extension byte, plus the maximum amount of padding.
{"07e0808080808080808000", 3, 103},
{"0faa808080808080808000", 4, 57},
{"1fff808080808080808000", 5, 158},
{"3f82808080808080808000", 6, 65},
{"7fc9808080808080808000", 7, 200},
// Values requiring two extension bytes.
{"07b260", 3, 12345},
{"0f8a2a", 4, 5401},
{"1fa87f", 5, 16327},
{"3fd002", 6, 399},
{"7fff49", 7, 9598},
// Values requiring two extension bytes, plus one byte of padding.
{"07b2e000", 3, 12345},
{"0f8aaa00", 4, 5401},
{"1fa8ff00", 5, 16327},
{"3fd08200", 6, 399},
{"7fffc900", 7, 9598},
// Values requiring two extension bytes, plus the maximum amount of padding.
{"07b2e080808080808000", 3, 12345},
{"0f8aaa80808080808000", 4, 5401},
{"1fa8ff80808080808000", 5, 16327},
{"3fd08280808080808000", 6, 399},
{"7fffc980808080808000", 7, 9598},
// Values requiring three extension bytes.
{"078ab260", 3, 1579281},
{"0fc18a2a", 4, 689488},
{"1fada87f", 5, 2085964},
{"3fa0d002", 6, 43103},
{"7ffeff49", 7, 1212541},
// Values requiring three extension bytes, plus one byte of padding.
{"078ab2e000", 3, 1579281},
{"0fc18aaa00", 4, 689488},
{"1fada8ff00", 5, 2085964},
{"3fa0d08200", 6, 43103},
{"7ffeffc900", 7, 1212541},
// Values requiring four extension bytes.
{"079f8ab260", 3, 202147110},
{"0fa2c18a2a", 4, 88252593},
{"1fd0ada87f", 5, 266999535},
{"3ff9a0d002", 6, 5509304},
{"7f9efeff49", 7, 155189149},
// Values requiring four extension bytes, plus one byte of padding.
{"079f8ab2e000", 3, 202147110},
{"0fa2c18aaa00", 4, 88252593},
{"1fd0ada8ff00", 5, 266999535},
{"3ff9a0d08200", 6, 5509304},
{"7f9efeffc900", 7, 155189149},
// Values requiring six extension bytes.
{"0783aa9f8ab260", 3, 3311978140938},
{"0ff0b0a2c18a2a", 4, 1445930244223},
{"1fda84d0ada87f", 5, 4374519874169},
{"3fb5fbf9a0d002", 6, 90263420404},
{"7fcff19efeff49", 7, 2542616951118},
// Values requiring eight extension bytes.
{"07f19883aa9f8ab260", 3, 54263449861016696},
{"0f84fdf0b0a2c18a2a", 4, 23690121121119891},
{"1fa0dfda84d0ada87f", 5, 71672133617889215},
{"3f9ff0b5fbf9a0d002", 6, 1478875878881374},
{"7ffbc1cff19efeff49", 7, 41658236125045114},
// Values requiring ten extension bytes.
{"0794f1f19883aa9f8ab201", 3, 12832019021693745307u},
{"0fa08f84fdf0b0a2c18a01", 4, 9980690937382242223u},
{"1fbfdda0dfda84d0ada801", 5, 12131360551794650846u},
{"3f9dc79ff0b5fbf9a0d001", 6, 15006530362736632796u},
{"7f8790fbc1cff19efeff01", 7, 18445754019193211014u},
// Maximum value: 2^64-1.
{"07f8ffffffffffffffff01", 3, 18446744073709551615u},
{"0ff0ffffffffffffffff01", 4, 18446744073709551615u},
{"1fe0ffffffffffffffff01", 5, 18446744073709551615u},
{"3fc0ffffffffffffffff01", 6, 18446744073709551615u},
{"7f80ffffffffffffffff01", 7, 18446744073709551615u},
// Examples from RFC7541 C.1.
{"0a", 5, 10},
{"1f9a0a", 5, 1337},
};
// Test data used when decode_64_bits() == false.
struct {
const char* data;
uint32_t prefix_length;
uint64_t expected_value;
} kSuccessTestDataOld[] = {
// Zero value with different prefix lengths. // Zero value with different prefix lengths.
{"00", 3, 0}, {"00", 3, 0},
{"00", 4, 0}, {"00", 4, 0},
...@@ -217,19 +372,59 @@ struct { ...@@ -217,19 +372,59 @@ struct {
}; };
TEST_P(HpackVarintDecoderTest, Success) { TEST_P(HpackVarintDecoderTest, Success) {
for (size_t i = 0; i < HTTP2_ARRAYSIZE(kSuccessTestData); ++i) { if (decode_64_bits()) {
DecodeExpectSuccess(Http2HexDecode(kSuccessTestData[i].data), for (size_t i = 0; i < HTTP2_ARRAYSIZE(kSuccessTestData); ++i) {
kSuccessTestData[i].prefix_length, DecodeExpectSuccess(Http2HexDecode(kSuccessTestData[i].data),
kSuccessTestData[i].expected_value); kSuccessTestData[i].prefix_length,
kSuccessTestData[i].expected_value);
}
} else {
for (size_t i = 0; i < HTTP2_ARRAYSIZE(kSuccessTestDataOld); ++i) {
DecodeExpectSuccess(Http2HexDecode(kSuccessTestDataOld[i].data),
kSuccessTestDataOld[i].prefix_length,
kSuccessTestDataOld[i].expected_value);
}
} }
} }
// HpackVarintDecoder allows at most five extension bytes, // Test data used when decode_64_bits() == true.
// and fifth extension byte must be zero.
struct { struct {
const char* data; const char* data;
uint32_t prefix_length; uint32_t prefix_length;
} kErrorTestData[] = { } kErrorTestData[] = {
// Too many extension bytes, all 0s (except for extension bit in each byte).
{"0780808080808080808080", 3},
{"0f80808080808080808080", 4},
{"1f80808080808080808080", 5},
{"3f80808080808080808080", 6},
{"7f80808080808080808080", 7},
// Too many extension bytes, all 1s.
{"07ffffffffffffffffffff", 3},
{"0fffffffffffffffffffff", 4},
{"1fffffffffffffffffffff", 5},
{"3fffffffffffffffffffff", 6},
{"7fffffffffffffffffffff", 7},
// Value of 2^64, one higher than maximum of 2^64-1.
{"07f9ffffffffffffffff01", 3},
{"0ff1ffffffffffffffff01", 4},
{"1fe1ffffffffffffffff01", 5},
{"3fc1ffffffffffffffff01", 6},
{"7f81ffffffffffffffff01", 7},
// Maximum value: 2^64-1, with one byte of padding.
{"07f8ffffffffffffffff8100", 3},
{"0ff0ffffffffffffffff8100", 4},
{"1fe0ffffffffffffffff8100", 5},
{"3fc0ffffffffffffffff8100", 6},
{"7f80ffffffffffffffff8100", 7},
};
// Test data used when decode_64_bits() == false.
// In this mode, HpackVarintDecoder allows at most five extension bytes,
// and fifth extension byte must be zero.
struct {
const char* data;
uint32_t prefix_length;
} kErrorTestDataOld[] = {
// Maximum number of extension bytes but last byte is non-zero. // Maximum number of extension bytes but last byte is non-zero.
{"078080808001", 3}, {"078080808001", 3},
{"0f8080808001", 4}, {"0f8080808001", 4},
...@@ -251,9 +446,16 @@ struct { ...@@ -251,9 +446,16 @@ struct {
}; };
TEST_P(HpackVarintDecoderTest, Error) { TEST_P(HpackVarintDecoderTest, Error) {
for (size_t i = 0; i < HTTP2_ARRAYSIZE(kErrorTestData); ++i) { if (decode_64_bits()) {
DecodeExpectError(Http2HexDecode(kErrorTestData[i].data), for (size_t i = 0; i < HTTP2_ARRAYSIZE(kErrorTestData); ++i) {
kErrorTestData[i].prefix_length); DecodeExpectError(Http2HexDecode(kErrorTestData[i].data),
kErrorTestData[i].prefix_length);
}
} else {
for (size_t i = 0; i < HTTP2_ARRAYSIZE(kErrorTestDataOld); ++i) {
DecodeExpectError(Http2HexDecode(kErrorTestDataOld[i].data),
kErrorTestDataOld[i].prefix_length);
}
} }
} }
......
...@@ -22,11 +22,29 @@ ...@@ -22,11 +22,29 @@
using ::testing::AssertionFailure; using ::testing::AssertionFailure;
using ::testing::AssertionSuccess; using ::testing::AssertionSuccess;
using ::testing::Bool;
using ::testing::WithParamInterface;
namespace http2 { namespace http2 {
namespace test { namespace test {
namespace { namespace {
// Save previous value of flag and restore on destruction.
class FlagSaver {
public:
FlagSaver() = delete;
explicit FlagSaver(bool decode_64_bits)
: saved_value_(GetHttp2ReloadableFlag(http2_varint_decode_64_bits)) {
SetHttp2ReloadableFlag(http2_varint_decode_64_bits, decode_64_bits);
}
~FlagSaver() {
SetHttp2ReloadableFlag(http2_varint_decode_64_bits, saved_value_);
}
private:
const bool saved_value_;
};
// Returns the highest value with the specified number of extension bytes // Returns the highest value with the specified number of extension bytes
// and the specified prefix length (bits). // and the specified prefix length (bits).
uint64_t HiValueOfExtensionBytes(uint32_t extension_bytes, uint64_t HiValueOfExtensionBytes(uint32_t extension_bytes,
...@@ -35,8 +53,14 @@ uint64_t HiValueOfExtensionBytes(uint32_t extension_bytes, ...@@ -35,8 +53,14 @@ uint64_t HiValueOfExtensionBytes(uint32_t extension_bytes,
(extension_bytes == 0 ? 0 : (1LLU << (extension_bytes * 7))); (extension_bytes == 0 ? 0 : (1LLU << (extension_bytes * 7)));
} }
class HpackVarintRoundTripTest : public RandomDecoderTest { class HpackVarintRoundTripTest : public RandomDecoderTest,
public WithParamInterface<bool> {
protected: protected:
HpackVarintRoundTripTest()
: decode_64_bits_(GetParam()),
flag_saver_(decode_64_bits_),
prefix_length_(0) {}
DecodeStatus StartDecoding(DecodeBuffer* b) override { DecodeStatus StartDecoding(DecodeBuffer* b) override {
CHECK_LT(0u, b->Remaining()); CHECK_LT(0u, b->Remaining());
uint8_t prefix = b->DecodeUInt8(); uint8_t prefix = b->DecodeUInt8();
...@@ -47,7 +71,7 @@ class HpackVarintRoundTripTest : public RandomDecoderTest { ...@@ -47,7 +71,7 @@ class HpackVarintRoundTripTest : public RandomDecoderTest {
return decoder_.Resume(b); return decoder_.Resume(b);
} }
void DecodeSeveralWays(uint32_t expected_value, uint32_t expected_offset) { void DecodeSeveralWays(uint64_t expected_value, uint32_t expected_offset) {
// The validator is called after each of the several times that the input // The validator is called after each of the several times that the input
// DecodeBuffer is decoded, each with a different segmentation of the input. // DecodeBuffer is decoded, each with a different segmentation of the input.
// Validate that decoder_.value() matches the expected value. // Validate that decoder_.value() matches the expected value.
...@@ -78,7 +102,7 @@ class HpackVarintRoundTripTest : public RandomDecoderTest { ...@@ -78,7 +102,7 @@ class HpackVarintRoundTripTest : public RandomDecoderTest {
EXPECT_EQ(expected_offset, b.Offset()); EXPECT_EQ(expected_offset, b.Offset());
} }
void EncodeNoRandom(uint32_t value, uint8_t prefix_length) { void EncodeNoRandom(uint64_t value, uint8_t prefix_length) {
DCHECK_LE(3, prefix_length); DCHECK_LE(3, prefix_length);
DCHECK_LE(prefix_length, 7); DCHECK_LE(prefix_length, 7);
prefix_length_ = prefix_length; prefix_length_ = prefix_length;
...@@ -92,7 +116,7 @@ class HpackVarintRoundTripTest : public RandomDecoderTest { ...@@ -92,7 +116,7 @@ class HpackVarintRoundTripTest : public RandomDecoderTest {
ASSERT_EQ(buffer_[0], buffer_[0] & prefix_mask); ASSERT_EQ(buffer_[0], buffer_[0] & prefix_mask);
} }
void Encode(uint32_t value, uint8_t prefix_length) { void Encode(uint64_t value, uint8_t prefix_length) {
EncodeNoRandom(value, prefix_length); EncodeNoRandom(value, prefix_length);
// Add some random bits to the prefix (the first byte) above the mask. // Add some random bits to the prefix (the first byte) above the mask.
uint8_t prefix = buffer_[0]; uint8_t prefix = buffer_[0];
...@@ -105,9 +129,9 @@ class HpackVarintRoundTripTest : public RandomDecoderTest { ...@@ -105,9 +129,9 @@ class HpackVarintRoundTripTest : public RandomDecoderTest {
// HpackVarintDecoder is as expected, which also acts as confirmation that // HpackVarintDecoder is as expected, which also acts as confirmation that
// my thinking about the encodings being used by the tests, i.e. cover the // my thinking about the encodings being used by the tests, i.e. cover the
// range desired. // range desired.
void ValidateEncoding(uint32_t value, void ValidateEncoding(uint64_t value,
uint32_t minimum, uint64_t minimum,
uint32_t maximum, uint64_t maximum,
size_t expected_bytes) { size_t expected_bytes) {
ASSERT_EQ(expected_bytes, buffer_.size()); ASSERT_EQ(expected_bytes, buffer_.size());
if (expected_bytes > 1) { if (expected_bytes > 1) {
...@@ -120,7 +144,9 @@ class HpackVarintRoundTripTest : public RandomDecoderTest { ...@@ -120,7 +144,9 @@ class HpackVarintRoundTripTest : public RandomDecoderTest {
if (value == minimum) { if (value == minimum) {
EXPECT_EQ(0x80, byte) << "ndx=" << ndx; EXPECT_EQ(0x80, byte) << "ndx=" << ndx;
} else if (value == maximum) { } else if (value == maximum) {
EXPECT_EQ(0xff, byte) << "ndx=" << ndx; if (expected_bytes < 11) {
EXPECT_EQ(0xff, byte) << "ndx=" << ndx;
}
} else { } else {
EXPECT_EQ(0x80, byte & 0x80) << "ndx=" << ndx; EXPECT_EQ(0x80, byte & 0x80) << "ndx=" << ndx;
} }
...@@ -134,7 +160,9 @@ class HpackVarintRoundTripTest : public RandomDecoderTest { ...@@ -134,7 +160,9 @@ class HpackVarintRoundTripTest : public RandomDecoderTest {
EXPECT_EQ(0x01, byte); EXPECT_EQ(0x01, byte);
} }
} else if (value == maximum) { } else if (value == maximum) {
EXPECT_EQ(0x7f, byte); if (expected_bytes < 11) {
EXPECT_EQ(0x7f, byte);
}
} else { } else {
EXPECT_EQ(0x00, byte & 0x80); EXPECT_EQ(0x00, byte & 0x80);
} }
...@@ -145,14 +173,14 @@ class HpackVarintRoundTripTest : public RandomDecoderTest { ...@@ -145,14 +173,14 @@ class HpackVarintRoundTripTest : public RandomDecoderTest {
} }
} }
void EncodeAndDecodeValues(const std::set<uint32_t>& values, void EncodeAndDecodeValues(const std::set<uint64_t>& values,
uint8_t prefix_length, uint8_t prefix_length,
size_t expected_bytes) { size_t expected_bytes) {
CHECK(!values.empty()); CHECK(!values.empty());
const uint32_t minimum = *values.begin(); const uint64_t minimum = *values.begin();
const uint32_t maximum = *values.rbegin(); const uint64_t maximum = *values.rbegin();
for (const uint32_t value : values) { for (const uint64_t value : values) {
Encode(value, prefix_length); // Sets prefix_buffer_ Encode(value, prefix_length); // Sets buffer_.
std::stringstream ss; std::stringstream ss;
ss << "value=" << value << " (0x" << std::hex << value ss << "value=" << value << " (0x" << std::hex << value
...@@ -191,12 +219,15 @@ class HpackVarintRoundTripTest : public RandomDecoderTest { ...@@ -191,12 +219,15 @@ class HpackVarintRoundTripTest : public RandomDecoderTest {
} }
} }
void EncodeAndDecodeValuesInRange(uint32_t start, // Encode values (all or some of it) in [start, start+range). Check
uint32_t range, // that |start| is the smallest value and |start+range-1| is the largest value
// corresponding to |expected_bytes|, except if |expected_bytes| is maximal.
void EncodeAndDecodeValuesInRange(uint64_t start,
uint64_t range,
uint8_t prefix_length, uint8_t prefix_length,
size_t expected_bytes) { size_t expected_bytes) {
const uint8_t prefix_mask = (1 << prefix_length) - 1; const uint8_t prefix_mask = (1 << prefix_length) - 1;
const uint32_t beyond = start + range; const uint64_t beyond = start + range;
LOG(INFO) << "############################################################"; LOG(INFO) << "############################################################";
LOG(INFO) << "prefix_length=" << static_cast<int>(prefix_length); LOG(INFO) << "prefix_length=" << static_cast<int>(prefix_length);
...@@ -206,14 +237,16 @@ class HpackVarintRoundTripTest : public RandomDecoderTest { ...@@ -206,14 +237,16 @@ class HpackVarintRoundTripTest : public RandomDecoderTest {
LOG(INFO) << "beyond=" << beyond << " (" << std::hex << beyond << ")"; LOG(INFO) << "beyond=" << beyond << " (" << std::hex << beyond << ")";
LOG(INFO) << "expected_bytes=" << expected_bytes; LOG(INFO) << "expected_bytes=" << expected_bytes;
// Confirm the claim that beyond requires more bytes. if (expected_bytes < 11) {
Encode(beyond, prefix_length); // Confirm the claim that beyond requires more bytes.
EXPECT_EQ(expected_bytes + 1, buffer_.size()) << Http2HexDump(buffer_); Encode(beyond, prefix_length);
EXPECT_EQ(expected_bytes + 1, buffer_.size()) << Http2HexDump(buffer_);
}
std::set<uint32_t> values; std::set<uint64_t> values;
if (range < 200) { if (range < 200) {
// Select all values in the range. // Select all values in the range.
for (uint32_t offset = 0; offset < range; ++offset) { for (uint64_t offset = 0; offset < range; ++offset) {
values.insert(start + offset); values.insert(start + offset);
} }
} else { } else {
...@@ -221,57 +254,77 @@ class HpackVarintRoundTripTest : public RandomDecoderTest { ...@@ -221,57 +254,77 @@ class HpackVarintRoundTripTest : public RandomDecoderTest {
// values that require exactly |expected_bytes| extension bytes. // values that require exactly |expected_bytes| extension bytes.
values.insert({start, start + 1, beyond - 2, beyond - 1}); values.insert({start, start + 1, beyond - 2, beyond - 1});
while (values.size() < 100) { while (values.size() < 100) {
values.insert(start + Random().Uniform(range)); values.insert(Random().UniformInRange(start, beyond - 1));
} }
} }
EncodeAndDecodeValues(values, prefix_length, expected_bytes); EncodeAndDecodeValues(values, prefix_length, expected_bytes);
} }
// |flag_saver_| must preceed |decoder_| so that the flag is already set when
// |decoder_| is constructed.
const bool decode_64_bits_;
FlagSaver flag_saver_;
HpackVarintDecoder decoder_; HpackVarintDecoder decoder_;
Http2String buffer_; Http2String buffer_;
uint8_t prefix_length_ = 0; uint8_t prefix_length_;
}; };
INSTANTIATE_TEST_CASE_P(HpackVarintRoundTripTest,
HpackVarintRoundTripTest,
Bool());
// To help me and future debuggers of varint encodings, this LOGs out the // To help me and future debuggers of varint encodings, this LOGs out the
// transition points where a new extension byte is added. // transition points where a new extension byte is added.
TEST_F(HpackVarintRoundTripTest, Encode) { TEST_P(HpackVarintRoundTripTest, Encode) {
for (int prefix_length = 3; prefix_length <= 7; ++prefix_length) { for (int prefix_length = 3; prefix_length <= 7; ++prefix_length) {
const uint32_t a = (1 << prefix_length) - 1; const uint64_t a = HiValueOfExtensionBytes(0, prefix_length);
const uint32_t b = a + 128; const uint64_t b = HiValueOfExtensionBytes(1, prefix_length);
const uint32_t c = b + (127 << 7); const uint64_t c = HiValueOfExtensionBytes(2, prefix_length);
const uint32_t d = c + (127 << 14); const uint64_t d = HiValueOfExtensionBytes(3, prefix_length);
const uint32_t e = d + (127 << 21); const uint64_t e = HiValueOfExtensionBytes(4, prefix_length);
const uint64_t f = HiValueOfExtensionBytes(5, prefix_length);
const uint64_t g = HiValueOfExtensionBytes(6, prefix_length);
const uint64_t h = HiValueOfExtensionBytes(7, prefix_length);
const uint64_t i = HiValueOfExtensionBytes(8, prefix_length);
const uint64_t j = HiValueOfExtensionBytes(9, prefix_length);
LOG(INFO) << "############################################################"; LOG(INFO) << "############################################################";
LOG(INFO) << "prefix_length=" << prefix_length << " a=" << a LOG(INFO) << "prefix_length=" << prefix_length << " a=" << a
<< " b=" << b << " c=" << c; << " b=" << b << " c=" << c << " d=" << d << " e=" << e
<< " f=" << f << " g=" << g << " h=" << h << " i=" << i
EXPECT_EQ(a - 1, HiValueOfExtensionBytes(0, prefix_length)); << " j=" << j;
EXPECT_EQ(b - 1, HiValueOfExtensionBytes(1, prefix_length));
EXPECT_EQ(c - 1, HiValueOfExtensionBytes(2, prefix_length));
EXPECT_EQ(d - 1, HiValueOfExtensionBytes(3, prefix_length));
EXPECT_EQ(e - 1, HiValueOfExtensionBytes(4, prefix_length));
std::vector<uint32_t> values = { std::vector<uint64_t> values = {
0, 1, // Force line break. 0, 1, // Force line break.
a - 2, a - 1, a, a + 1, a + 2, // Force line break. a - 1, a, a + 1, a + 2, a + 3, // Force line break.
b - 2, b - 1, b, b + 1, b + 2, // Force line break. b - 1, b, b + 1, b + 2, b + 3, // Force line break.
c - 2, c - 1, c, c + 1, c + 2, // Force line break. c - 1, c, c + 1, c + 2, c + 3, // Force line break.
d - 2, d - 1, d, d + 1, d + 2, // Force line break. d - 1, d, d + 1, d + 2, d + 3, // Force line break.
e - 2, e - 1, e, e + 1, e + 2 // Force line break. e - 1, e, e + 1, e + 2, e + 3 // Force line break.
}; };
if (decode_64_bits_) {
for (auto value : {
f - 1, f, f + 1, f + 2, f + 3, // Force line break.
g - 1, g, g + 1, g + 2, g + 3, // Force line break.
h - 1, h, h + 1, h + 2, h + 3, // Force line break.
i - 1, i, i + 1, i + 2, i + 3, // Force line break.
j - 1, j, j + 1, j + 2, j + 3, // Force line break.
}) {
values.push_back(value);
}
}
for (uint32_t value : values) { for (uint64_t value : values) {
EncodeNoRandom(value, prefix_length); EncodeNoRandom(value, prefix_length);
Http2String dump = Http2HexDump(buffer_); Http2String dump = Http2HexDump(buffer_);
LOG(INFO) << Http2StringPrintf("%10u %0#10x ", value, value) LOG(INFO) << Http2StringPrintf("%10llu %0#18x ", value, value)
<< Http2HexDump(buffer_).substr(7); << Http2HexDump(buffer_).substr(7);
} }
} }
} }
TEST_F(HpackVarintRoundTripTest, FromSpec1337) { TEST_P(HpackVarintRoundTripTest, FromSpec1337) {
DecodeBuffer b(Http2StringPiece("\x1f\x9a\x0a")); DecodeBuffer b(Http2StringPiece("\x1f\x9a\x0a"));
uint32_t prefix_length = 5; uint32_t prefix_length = 5;
uint8_t p = b.DecodeUInt8(); uint8_t p = b.DecodeUInt8();
...@@ -288,7 +341,7 @@ TEST_F(HpackVarintRoundTripTest, FromSpec1337) { ...@@ -288,7 +341,7 @@ TEST_F(HpackVarintRoundTripTest, FromSpec1337) {
} }
// Test all the values that fit into the prefix (one less than the mask). // Test all the values that fit into the prefix (one less than the mask).
TEST_F(HpackVarintRoundTripTest, ValidatePrefixOnly) { TEST_P(HpackVarintRoundTripTest, ValidatePrefixOnly) {
for (int prefix_length = 3; prefix_length <= 7; ++prefix_length) { for (int prefix_length = 3; prefix_length <= 7; ++prefix_length) {
const uint8_t prefix_mask = (1 << prefix_length) - 1; const uint8_t prefix_mask = (1 << prefix_length) - 1;
EncodeAndDecodeValuesInRange(0, prefix_mask, prefix_length, 1); EncodeAndDecodeValuesInRange(0, prefix_mask, prefix_length, 1);
...@@ -296,48 +349,135 @@ TEST_F(HpackVarintRoundTripTest, ValidatePrefixOnly) { ...@@ -296,48 +349,135 @@ TEST_F(HpackVarintRoundTripTest, ValidatePrefixOnly) {
} }
// Test all values that require exactly 1 extension byte. // Test all values that require exactly 1 extension byte.
TEST_F(HpackVarintRoundTripTest, ValidateOneExtensionByte) { TEST_P(HpackVarintRoundTripTest, ValidateOneExtensionByte) {
for (int prefix_length = 3; prefix_length <= 7; ++prefix_length) { for (int prefix_length = 3; prefix_length <= 7; ++prefix_length) {
const uint32_t start = (1 << prefix_length) - 1; const uint64_t start = HiValueOfExtensionBytes(0, prefix_length) + 1;
EncodeAndDecodeValuesInRange(start, 128, prefix_length, 2); EncodeAndDecodeValuesInRange(start, 128, prefix_length, 2);
} }
} }
// Test *some* values that require exactly 2 extension bytes. // Test *some* values that require exactly 2 extension bytes.
TEST_F(HpackVarintRoundTripTest, ValidateTwoExtensionBytes) { TEST_P(HpackVarintRoundTripTest, ValidateTwoExtensionBytes) {
for (int prefix_length = 3; prefix_length <= 7; ++prefix_length) { for (int prefix_length = 3; prefix_length <= 7; ++prefix_length) {
const uint8_t prefix_mask = (1 << prefix_length) - 1; const uint64_t start = HiValueOfExtensionBytes(1, prefix_length) + 1;
const uint32_t start = prefix_mask + 128; const uint64_t range = 127 << 7;
const uint32_t range = 127 << 7;
EncodeAndDecodeValuesInRange(start, range, prefix_length, 3); EncodeAndDecodeValuesInRange(start, range, prefix_length, 3);
} }
} }
// Test *some* values that require 3 extension bytes. // Test *some* values that require 3 extension bytes.
TEST_F(HpackVarintRoundTripTest, ValidateThreeExtensionBytes) { TEST_P(HpackVarintRoundTripTest, ValidateThreeExtensionBytes) {
for (int prefix_length = 3; prefix_length <= 7; ++prefix_length) { for (int prefix_length = 3; prefix_length <= 7; ++prefix_length) {
const uint8_t prefix_mask = (1 << prefix_length) - 1; const uint64_t start = HiValueOfExtensionBytes(2, prefix_length) + 1;
const uint32_t start = prefix_mask + 128 + (127 << 7); const uint64_t range = 127 << 14;
const uint32_t range = 127 << 14;
EncodeAndDecodeValuesInRange(start, range, prefix_length, 4); EncodeAndDecodeValuesInRange(start, range, prefix_length, 4);
} }
} }
// Test *some* values that require 4 extension bytes. // Test *some* values that require 4 extension bytes.
TEST_F(HpackVarintRoundTripTest, ValidateFourExtensionBytes) { TEST_P(HpackVarintRoundTripTest, ValidateFourExtensionBytes) {
for (int prefix_length = 3; prefix_length <= 7; ++prefix_length) { for (int prefix_length = 3; prefix_length <= 7; ++prefix_length) {
const uint8_t prefix_mask = (1 << prefix_length) - 1; const uint64_t start = HiValueOfExtensionBytes(3, prefix_length) + 1;
const uint32_t start = prefix_mask + 128 + (127 << 7) + (127 << 14); const uint64_t range = 127 << 21;
const uint32_t range = 127 << 21;
EncodeAndDecodeValuesInRange(start, range, prefix_length, 5); EncodeAndDecodeValuesInRange(start, range, prefix_length, 5);
} }
} }
// Test *some* values that require 5 extension bytes.
TEST_P(HpackVarintRoundTripTest, ValidateFiveExtensionBytes) {
if (!decode_64_bits_) {
return;
}
for (int prefix_length = 3; prefix_length <= 7; ++prefix_length) {
const uint64_t start = HiValueOfExtensionBytes(4, prefix_length) + 1;
const uint64_t range = 127llu << 28;
EncodeAndDecodeValuesInRange(start, range, prefix_length, 6);
}
}
// Test *some* values that require 6 extension bytes.
TEST_P(HpackVarintRoundTripTest, ValidateSixExtensionBytes) {
if (!decode_64_bits_) {
return;
}
for (int prefix_length = 3; prefix_length <= 7; ++prefix_length) {
const uint64_t start = HiValueOfExtensionBytes(5, prefix_length) + 1;
const uint64_t range = 127llu << 35;
EncodeAndDecodeValuesInRange(start, range, prefix_length, 7);
}
}
// Test *some* values that require 7 extension bytes.
TEST_P(HpackVarintRoundTripTest, ValidateSevenExtensionBytes) {
if (!decode_64_bits_) {
return;
}
for (int prefix_length = 3; prefix_length <= 7; ++prefix_length) {
const uint64_t start = HiValueOfExtensionBytes(6, prefix_length) + 1;
const uint64_t range = 127llu << 42;
EncodeAndDecodeValuesInRange(start, range, prefix_length, 8);
}
}
// Test *some* values that require 8 extension bytes.
TEST_P(HpackVarintRoundTripTest, ValidateEightExtensionBytes) {
if (!decode_64_bits_) {
return;
}
for (int prefix_length = 3; prefix_length <= 7; ++prefix_length) {
const uint64_t start = HiValueOfExtensionBytes(7, prefix_length) + 1;
const uint64_t range = 127llu << 49;
EncodeAndDecodeValuesInRange(start, range, prefix_length, 9);
}
}
// Test *some* values that require 9 extension bytes.
TEST_P(HpackVarintRoundTripTest, ValidateNineExtensionBytes) {
if (!decode_64_bits_) {
return;
}
for (int prefix_length = 3; prefix_length <= 7; ++prefix_length) {
const uint64_t start = HiValueOfExtensionBytes(8, prefix_length) + 1;
const uint64_t range = 127llu << 56;
EncodeAndDecodeValuesInRange(start, range, prefix_length, 10);
}
}
// Test *some* values that require 10 extension bytes.
TEST_P(HpackVarintRoundTripTest, ValidateTenExtensionBytes) {
if (!decode_64_bits_) {
return;
}
for (int prefix_length = 3; prefix_length <= 7; ++prefix_length) {
const uint64_t start = HiValueOfExtensionBytes(9, prefix_length) + 1;
const uint64_t range = std::numeric_limits<uint64_t>::max() - start;
EncodeAndDecodeValuesInRange(start, range, prefix_length, 11);
}
}
// Test the value one larger than the largest that can be decoded. // Test the value one larger than the largest that can be decoded.
TEST_F(HpackVarintRoundTripTest, ValueTooLarge) { TEST_P(HpackVarintRoundTripTest, ValueTooLarge) {
// New implementation can decode any integer that HpackVarintEncoder can
// encode.
if (decode_64_bits_) {
return;
}
for (prefix_length_ = 3; prefix_length_ <= 7; ++prefix_length_) { for (prefix_length_ = 3; prefix_length_ <= 7; ++prefix_length_) {
const uint64_t too_large = (1 << 28) + (1 << prefix_length_) - 1; const uint64_t too_large = (1 << 28) + (1 << prefix_length_) - 1;
const uint32_t expected_offset = 6; const uint32_t expected_offset = 6;
......
// Copyright 2018 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.
#ifndef NET_THIRD_PARTY_HTTP2_PLATFORM_API_HTTP2_FLAGS_H_
#define NET_THIRD_PARTY_HTTP2_PLATFORM_API_HTTP2_FLAGS_H_
#include "net/third_party/http2/platform/impl/http2_flags_impl.h"
#define GetHttp2ReloadableFlag(flag) GetHttp2ReloadableFlagImpl(flag)
#define SetHttp2ReloadableFlag(flag, value) \
SetHttp2ReloadableFlagImpl(flag, value)
#endif // NET_THIRD_PARTY_HTTP2_PLATFORM_API_HTTP2_FLAGS_H_
// Copyright 2018 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/http2/platform/impl/http2_flags_impl.h"
bool FLAGS_chromium_flag_http2_varint_decode_64_bits = true;
// Copyright 2018 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.
#ifndef NET_THIRD_PARTY_HTTP2_PLATFORM_IMPL_HTTP2_FLAGS_IMPL_H_
#define NET_THIRD_PARTY_HTTP2_PLATFORM_IMPL_HTTP2_FLAGS_IMPL_H_
#include "net/third_party/http2/platform/api/http2_export.h"
HTTP2_EXPORT_PRIVATE extern bool
FLAGS_chromium_flag_http2_varint_decode_64_bits;
namespace http2 {
inline bool GetHttp2FlagImpl(bool flag) {
return flag;
}
inline void SetHttp2FlagImpl(bool* f, bool v) {
*f = v;
}
#define HTTP2_RELOADABLE_FLAG(flag) FLAGS_chromium_flag_##flag
#define GetHttp2ReloadableFlagImpl(flag) \
GetHttp2FlagImpl(HTTP2_RELOADABLE_FLAG(flag))
#define SetHttp2ReloadableFlagImpl(flag, value) \
SetHttp2FlagImpl(&HTTP2_RELOADABLE_FLAG(flag), value)
} // namespace http2
#endif // NET_THIRD_PARTY_HTTP2_PLATFORM_IMPL_HTTP2_FLAGS_IMPL_H_
// Copyright 2018 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.
#ifndef NET_THIRD_PARTY_HTTP2_TEST_TOOLS_HTTP2_RANDOM_H_ #ifndef NET_THIRD_PARTY_HTTP2_TEST_TOOLS_HTTP2_RANDOM_H_
#define NET_THIRD_PARTY_HTTP2_TEST_TOOLS_HTTP2_RANDOM_H_ #define NET_THIRD_PARTY_HTTP2_TEST_TOOLS_HTTP2_RANDOM_H_
...@@ -36,7 +40,7 @@ class Http2Random { ...@@ -36,7 +40,7 @@ class Http2Random {
// Return a uniformly distrubted random number in [0, n). // Return a uniformly distrubted random number in [0, n).
int32_t Uniform(int32_t n) { return Rand64() % n; } int32_t Uniform(int32_t n) { return Rand64() % n; }
// Return a uniformly distrubted random number in [lo, hi). // Return a uniformly distrubted random number in [lo, hi).
size_t UniformInRange(size_t lo, size_t hi) { int64_t UniformInRange(int64_t lo, int64_t hi) {
return lo + Rand64() % (hi - lo); return lo + Rand64() % (hi - lo);
} }
// Return an integer of logarithmically random scale. // Return an integer of logarithmically random scale.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment