summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/net.gyp6
-rw-r--r--net/spdy/hpack_constants.h13
-rw-r--r--net/spdy/hpack_decoder.cc86
-rw-r--r--net/spdy/hpack_decoder.h64
-rw-r--r--net/spdy/hpack_decoder_test.cc98
-rw-r--r--net/spdy/hpack_input_stream.cc117
-rw-r--r--net/spdy/hpack_input_stream.h79
-rw-r--r--net/spdy/hpack_input_stream_test.cc490
-rw-r--r--net/spdy/hpack_output_stream.cc29
-rw-r--r--net/spdy/hpack_output_stream.h12
10 files changed, 974 insertions, 20 deletions
diff --git a/net/net.gyp b/net/net.gyp
index a4fc685..f499758 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -1012,6 +1012,8 @@
'spdy/buffered_spdy_framer.cc',
'spdy/buffered_spdy_framer.h',
'spdy/hpack_constants.h',
+ 'spdy/hpack_decoder.cc',
+ 'spdy/hpack_decoder.h',
'spdy/hpack_encoder.cc',
'spdy/hpack_encoder.h',
'spdy/hpack_encoding_context.cc',
@@ -1020,6 +1022,8 @@
'spdy/hpack_entry.h',
'spdy/hpack_header_table.cc',
'spdy/hpack_header_table.h',
+ 'spdy/hpack_input_stream.cc',
+ 'spdy/hpack_input_stream.h',
'spdy/hpack_output_stream.cc',
'spdy/hpack_output_stream.h',
'spdy/hpack_string_util.cc',
@@ -1964,10 +1968,12 @@
'socket_stream/socket_stream_metrics_unittest.cc',
'socket_stream/socket_stream_unittest.cc',
'spdy/buffered_spdy_framer_unittest.cc',
+ 'spdy/hpack_decoder_test.cc',
'spdy/hpack_encoder_test.cc',
'spdy/hpack_encoding_context_test.cc',
'spdy/hpack_entry_test.cc',
'spdy/hpack_header_table_test.cc',
+ 'spdy/hpack_input_stream_test.cc',
'spdy/hpack_output_stream_test.cc',
'spdy/hpack_string_util_test.cc',
'spdy/mock_spdy_framer_visitor.cc',
diff --git a/net/spdy/hpack_constants.h b/net/spdy/hpack_constants.h
index 3b37d3d..dd1f2c6 100644
--- a/net/spdy/hpack_constants.h
+++ b/net/spdy/hpack_constants.h
@@ -13,15 +13,20 @@
namespace net {
+// An HpackPrefix signifies |bits| stored in the top |bit_size| bits
+// of an octet.
+struct HpackPrefix {
+ uint8 bits;
+ size_t bit_size;
+};
+
// The marker for a string literal that is stored unmodified (i.e.,
// without Huffman encoding) (from 4.1.2).
-const uint8 kStringLiteralIdentityEncoded = 0x0;
-const uint8 kStringLiteralIdentityEncodedSize = 1;
+const HpackPrefix kStringLiteralIdentityEncoded = { 0x0, 1 };
// The opcode for a literal header field without indexing (from
// 4.3.1).
-const uint8 kLiteralNoIndexOpcode = 0x01;
-const uint8 kLiteralNoIndexOpcodeSize = 2;
+const HpackPrefix kLiteralNoIndexOpcode = { 0x01, 2 };
} // namespace net
diff --git a/net/spdy/hpack_decoder.cc b/net/spdy/hpack_decoder.cc
new file mode 100644
index 0000000..060a88c
--- /dev/null
+++ b/net/spdy/hpack_decoder.cc
@@ -0,0 +1,86 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/spdy/hpack_decoder.h"
+
+#include "base/basictypes.h"
+#include "net/spdy/hpack_constants.h"
+#include "net/spdy/hpack_output_stream.h"
+
+namespace net {
+
+using base::StringPiece;
+
+HpackDecoder::HpackDecoder(uint32 max_string_literal_size)
+ : max_string_literal_size_(max_string_literal_size) {}
+
+HpackDecoder::~HpackDecoder() {}
+
+bool HpackDecoder::DecodeHeaderSet(StringPiece input,
+ HpackHeaderPairVector* header_list) {
+ HpackInputStream input_stream(max_string_literal_size_, input);
+ while (input_stream.HasMoreData()) {
+ // May add to |header_list|.
+ if (!ProcessNextHeaderRepresentation(&input_stream, header_list))
+ return false;
+ }
+
+ // After processing opcodes, emit everything in the reference set
+ // that hasn't already been emitted.
+ for (size_t i = 1; i <= context_.GetMutableEntryCount(); ++i) {
+ if (context_.IsReferencedAt(i) &&
+ (context_.GetTouchCountAt(i) == HpackEncodingContext::kUntouched)) {
+ header_list->push_back(
+ HpackHeaderPair(context_.GetNameAt(i).as_string(),
+ context_.GetValueAt(i).as_string()));
+ }
+ context_.ClearTouchesAt(i);
+ }
+
+ return true;
+}
+
+bool HpackDecoder::ProcessNextHeaderRepresentation(
+ HpackInputStream* input_stream, HpackHeaderPairVector* header_list) {
+ // Implements 4.3.1. Literal Header Field without Indexing.
+ if (input_stream->MatchPrefixAndConsume(kLiteralNoIndexOpcode)) {
+ StringPiece name;
+ if (!DecodeNextName(input_stream, &name))
+ return false;
+
+ StringPiece value;
+ if (!DecodeNextValue(input_stream, &value))
+ return false;
+
+ header_list->push_back(
+ HpackHeaderPair(name.as_string(), value.as_string()));
+ return true;
+ }
+
+ return false;
+}
+
+bool HpackDecoder::DecodeNextName(
+ HpackInputStream* input_stream, StringPiece* next_name) {
+ uint32 index_or_zero = 0;
+ if (!input_stream->DecodeNextUint32(&index_or_zero))
+ return false;
+
+ if (index_or_zero == 0)
+ return input_stream->DecodeNextStringLiteral(next_name);
+
+ uint32 index = index_or_zero;
+ if (index > context_.GetEntryCount())
+ return false;
+
+ *next_name = context_.GetNameAt(index_or_zero);
+ return true;
+}
+
+bool HpackDecoder::DecodeNextValue(
+ HpackInputStream* input_stream, StringPiece* next_name) {
+ return input_stream->DecodeNextStringLiteral(next_name);
+}
+
+} // namespace net
diff --git a/net/spdy/hpack_decoder.h b/net/spdy/hpack_decoder.h
new file mode 100644
index 0000000..3230fde
--- /dev/null
+++ b/net/spdy/hpack_decoder.h
@@ -0,0 +1,64 @@
+// Copyright 2014 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_SPDY_HPACK_DECODER_H_
+#define NET_SPDY_HPACK_DECODER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/macros.h"
+#include "base/strings/string_piece.h"
+#include "net/base/net_export.h"
+#include "net/spdy/hpack_encoding_context.h"
+#include "net/spdy/hpack_input_stream.h" // For HpackHeaderPairVector.
+
+namespace net {
+
+// An HpackDecoder decodes header sets as outlined in
+// http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-05
+// .
+class NET_EXPORT_PRIVATE HpackDecoder {
+ public:
+ explicit HpackDecoder(uint32 max_string_literal_size);
+ ~HpackDecoder();
+
+ // Decodes the given string into the given header set. Returns
+ // whether or not the decoding was successful.
+ //
+ // TODO(akalin): Emit the headers via a callback/delegate instead of
+ // putting them into a vector.
+ bool DecodeHeaderSet(base::StringPiece input,
+ HpackHeaderPairVector* header_list);
+
+ // Accessors for testing.
+
+ bool DecodeNextNameForTest(HpackInputStream* input_stream,
+ base::StringPiece* next_name) {
+ return DecodeNextName(input_stream, next_name);
+ }
+
+ private:
+ const uint32 max_string_literal_size_;
+ HpackEncodingContext context_;
+
+ // Tries to process the next header representation and maybe emit
+ // headers into |header_list| according to it. Returns true if
+ // successful, or false if an error was encountered.
+ bool ProcessNextHeaderRepresentation(
+ HpackInputStream* input_stream,
+ HpackHeaderPairVector* header_list);
+
+ bool DecodeNextName(HpackInputStream* input_stream,
+ base::StringPiece* next_name);
+ bool DecodeNextValue(HpackInputStream* input_stream,
+ base::StringPiece* next_name);
+
+ DISALLOW_COPY_AND_ASSIGN(HpackDecoder);
+};
+
+} // namespace net
+
+#endif // NET_SPDY_HPACK_DECODER_H_
diff --git a/net/spdy/hpack_decoder_test.cc b/net/spdy/hpack_decoder_test.cc
new file mode 100644
index 0000000..dcc5ad8
--- /dev/null
+++ b/net/spdy/hpack_decoder_test.cc
@@ -0,0 +1,98 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/spdy/hpack_decoder.h"
+
+#include <map>
+#include <string>
+
+#include "base/basictypes.h"
+#include "net/spdy/hpack_encoder.h"
+#include "net/spdy/hpack_input_stream.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+namespace {
+
+using base::StringPiece;
+using std::string;
+
+// Decoding an encoded name with a valid string literal should work.
+TEST(HpackDecoderTest, DecodeNextNameLiteral) {
+ HpackDecoder decoder(kuint32max);
+ HpackInputStream input_stream(kuint32max, StringPiece("\x00\x04name", 6));
+
+ StringPiece string_piece;
+ EXPECT_TRUE(decoder.DecodeNextNameForTest(&input_stream, &string_piece));
+ EXPECT_EQ("name", string_piece);
+ EXPECT_FALSE(input_stream.HasMoreData());
+}
+
+// Decoding an encoded name with a valid index should work.
+TEST(HpackDecoderTest, DecodeNextNameIndexed) {
+ HpackDecoder decoder(kuint32max);
+ HpackInputStream input_stream(kuint32max, "\x01");
+
+ StringPiece string_piece;
+ EXPECT_TRUE(decoder.DecodeNextNameForTest(&input_stream, &string_piece));
+ EXPECT_EQ(":authority", string_piece);
+ EXPECT_FALSE(input_stream.HasMoreData());
+}
+
+// Decoding an encoded name with an invalid index should fail.
+TEST(HpackDecoderTest, DecodeNextNameInvalidIndex) {
+ // One more than the number of static table entries.
+ HpackDecoder decoder(kuint32max);
+ HpackInputStream input_stream(kuint32max, "\x3d");
+
+ StringPiece string_piece;
+ EXPECT_FALSE(decoder.DecodeNextNameForTest(&input_stream, &string_piece));
+}
+
+// Decoding two valid encoded literal headers with no indexing should
+// work.
+TEST(HpackDecoderTest, LiteralHeaderNoIndexing) {
+ HpackDecoder decoder(kuint32max);
+ HpackHeaderPairVector header_list;
+ // First header with indexed name, second header with string literal
+ // name.
+ EXPECT_TRUE(decoder.DecodeHeaderSet(
+ "\x44\x0c/sample/path\x40\x06:path2\x0e/sample/path/2",
+ &header_list));
+ std::map<string, string> header_set(header_list.begin(), header_list.end());
+
+ std::map<string, string> expected_header_set;
+ expected_header_set[":path"] = "/sample/path";
+ expected_header_set[":path2"] = "/sample/path/2";
+ EXPECT_EQ(expected_header_set, header_set);
+}
+
+// Round-tripping the header set from E.2.1 should work.
+TEST(HpackDecoderTest, BasicE21) {
+ HpackEncoder encoder(kuint32max);
+
+ std::map<string, string> expected_header_set;
+ expected_header_set[":method"] = "GET";
+ expected_header_set[":scheme"] = "http";
+ expected_header_set[":path"] = "/";
+ expected_header_set[":authority"] = "www.example.com";
+
+ string encoded_header_set;
+ EXPECT_TRUE(encoder.EncodeHeaderSet(
+ expected_header_set, &encoded_header_set));
+
+ HpackDecoder decoder(kuint32max);
+ HpackHeaderPairVector header_list;
+ EXPECT_TRUE(decoder.DecodeHeaderSet(encoded_header_set, &header_list));
+ std::map<string, string> header_set(header_list.begin(), header_list.end());
+ EXPECT_EQ(expected_header_set, header_set);
+}
+
+// TODO(akalin): Add test to exercise emission of the reference set
+// once we can decode opcodes that add to the reference set.
+
+} // namespace
+
+} // namespace net
diff --git a/net/spdy/hpack_input_stream.cc b/net/spdy/hpack_input_stream.cc
new file mode 100644
index 0000000..8dc30e1
--- /dev/null
+++ b/net/spdy/hpack_input_stream.cc
@@ -0,0 +1,117 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/spdy/hpack_input_stream.h"
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+namespace net {
+
+using base::StringPiece;
+
+HpackInputStream::HpackInputStream(uint32 max_string_literal_size,
+ StringPiece buffer)
+ : max_string_literal_size_(max_string_literal_size),
+ buffer_(buffer),
+ bit_offset_(0) {}
+
+HpackInputStream::~HpackInputStream() {}
+
+bool HpackInputStream::HasMoreData() const {
+ return !buffer_.empty();
+}
+
+bool HpackInputStream::MatchPrefixAndConsume(HpackPrefix prefix) {
+ DCHECK_GT(prefix.bit_size, 0u);
+ DCHECK_LE(prefix.bit_size, 8u);
+
+ uint8 next_octet = 0;
+ if (!PeekNextOctet(&next_octet))
+ return false;
+
+ if ((next_octet >> (8 - prefix.bit_size)) == prefix.bits) {
+ bit_offset_ = prefix.bit_size;
+ return true;
+ }
+
+ return false;
+}
+
+bool HpackInputStream::PeekNextOctet(uint8* next_octet) {
+ if ((bit_offset_ > 0) || buffer_.empty())
+ return false;
+
+ *next_octet = buffer_[0];
+ return true;
+}
+
+bool HpackInputStream::DecodeNextOctet(uint8* next_octet) {
+ if (!PeekNextOctet(next_octet))
+ return false;
+
+ buffer_.remove_prefix(1);
+ return true;
+}
+
+bool HpackInputStream::DecodeNextUint32(uint32* I) {
+ size_t N = 8 - bit_offset_;
+ DCHECK_GT(N, 0u);
+ DCHECK_LE(N, 8u);
+
+ bit_offset_ = 0;
+
+ *I = 0;
+
+ uint8 next_marker = (1 << N) - 1;
+ uint8 next_octet = 0;
+ if (!DecodeNextOctet(&next_octet))
+ return false;
+ *I = next_octet & next_marker;
+
+ bool has_more = (*I == next_marker);
+ size_t shift = 0;
+ while (has_more && (shift < 32)) {
+ uint8 next_octet = 0;
+ if (!DecodeNextOctet(&next_octet))
+ return false;
+ has_more = (next_octet & 0x80) != 0;
+ next_octet &= 0x7f;
+ uint32 addend = next_octet << shift;
+ // Check for overflow.
+ if ((addend >> shift) != next_octet) {
+ return false;
+ }
+ *I += addend;
+ shift += 7;
+ }
+
+ return !has_more;
+}
+
+// TODO(akalin): Figure out how to handle the storage for
+// Huffman-encoded sequences.
+bool HpackInputStream::DecodeNextStringLiteral(StringPiece* str) {
+ if (MatchPrefixAndConsume(kStringLiteralIdentityEncoded)) {
+ uint32 size = 0;
+ if (!DecodeNextUint32(&size))
+ return false;
+
+ if (size > max_string_literal_size_)
+ return false;
+
+ if (size > buffer_.size())
+ return false;
+
+ *str = StringPiece(buffer_.data(), size);
+ buffer_.remove_prefix(size);
+ return true;
+ }
+
+ // TODO(akalin): Handle Huffman-encoded sequences.
+
+ return false;
+}
+
+} // namespace net
diff --git a/net/spdy/hpack_input_stream.h b/net/spdy/hpack_input_stream.h
new file mode 100644
index 0000000..17a057a
--- /dev/null
+++ b/net/spdy/hpack_input_stream.h
@@ -0,0 +1,79 @@
+// Copyright 2014 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_SPDY_HPACK_INPUT_STREAM_H_
+#define NET_SPDY_HPACK_INPUT_STREAM_H_
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/macros.h"
+#include "base/strings/string_piece.h"
+#include "net/base/net_export.h"
+#include "net/spdy/hpack_constants.h" // For HpackPrefix.
+
+// All section references below are to
+// http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-05
+// .
+
+namespace net {
+
+// TODO(akalin): When we use a callback/delegate instead of a vector,
+// use StringPiece instead of string.
+typedef std::pair<std::string, std::string> HpackHeaderPair;
+typedef std::vector<HpackHeaderPair> HpackHeaderPairVector;
+
+// An HpackInputStream handles all the low-level details of decoding
+// header fields.
+class NET_EXPORT_PRIVATE HpackInputStream {
+ public:
+ // |max_string_literal_size| is the largest that any one string
+ // literal (header name or header value) can be.
+ HpackInputStream(uint32 max_string_literal_size, base::StringPiece buffer);
+ ~HpackInputStream();
+
+ // Returns whether or not there is more data to process.
+ bool HasMoreData() const;
+
+ // If the next octet has the top |size| bits equal to |bits|,
+ // consumes it and returns true. Otherwise, consumes nothing and
+ // returns false.
+ bool MatchPrefixAndConsume(HpackPrefix prefix);
+
+ // The Decode* functions return true and fill in their arguments if
+ // decoding was successful, or false if an error was encountered.
+
+ bool DecodeNextUint32(uint32* I);
+ bool DecodeNextStringLiteral(base::StringPiece* str);
+
+ // Accessors for testing.
+
+ void SetBitOffsetForTest(size_t bit_offset) {
+ bit_offset_ = bit_offset;
+ }
+
+ bool DecodeNextUint32ForTest(uint32* I) {
+ return DecodeNextUint32(I);
+ }
+
+ bool DecodeNextStringLiteralForTest(base::StringPiece *str) {
+ return DecodeNextStringLiteral(str);
+ }
+
+ private:
+ const uint32 max_string_literal_size_;
+ base::StringPiece buffer_;
+ size_t bit_offset_;
+
+ bool PeekNextOctet(uint8* next_octet);
+
+ bool DecodeNextOctet(uint8* next_octet);
+
+ DISALLOW_COPY_AND_ASSIGN(HpackInputStream);
+};
+
+} // namespace net
+
+#endif // NET_SPDY_HPACK_INPUT_STREAM_H_
diff --git a/net/spdy/hpack_input_stream_test.cc b/net/spdy/hpack_input_stream_test.cc
new file mode 100644
index 0000000..049fc2cf
--- /dev/null
+++ b/net/spdy/hpack_input_stream_test.cc
@@ -0,0 +1,490 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/spdy/hpack_input_stream.h"
+
+#include <string>
+#include <vector>
+
+#include "base/strings/string_piece.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+namespace {
+
+using base::StringPiece;
+using std::string;
+
+// Utility function to decode an assumed-valid uint32 with an N-bit
+// prefix.
+uint32 DecodeValidUint32(uint8 N, StringPiece str) {
+ EXPECT_GT(N, 0);
+ EXPECT_LE(N, 8);
+ HpackInputStream input_stream(kuint32max, str);
+ input_stream.SetBitOffsetForTest(8 - N);
+ uint32 I;
+ EXPECT_TRUE(input_stream.DecodeNextUint32ForTest(&I));
+ return I;
+}
+
+// Utility function to decode an assumed-invalid uint32 with an N-bit
+// prefix.
+void ExpectDecodeUint32Invalid(uint8 N, StringPiece str) {
+ EXPECT_GT(N, 0);
+ EXPECT_LE(N, 8);
+ HpackInputStream input_stream(kuint32max, str);
+ input_stream.SetBitOffsetForTest(8 - N);
+ uint32 I;
+ EXPECT_FALSE(input_stream.DecodeNextUint32ForTest(&I));
+}
+
+// The {Number}ByteIntegersEightBitPrefix tests below test that
+// certain integers are decoded correctly with an 8-bit prefix in
+// exactly {Number} bytes.
+
+TEST(HpackInputStreamTest, OneByteIntegersEightBitPrefix) {
+ // Minimum.
+ EXPECT_EQ(0x00u, DecodeValidUint32(8, string("\x00", 1)));
+ EXPECT_EQ(0x7fu, DecodeValidUint32(8, "\x7f"));
+ // Maximum.
+ EXPECT_EQ(0xfeu, DecodeValidUint32(8, "\xfe"));
+ // Invalid.
+ ExpectDecodeUint32Invalid(8, "\xff");
+}
+
+TEST(HpackInputStreamTest, TwoByteIntegersEightBitPrefix) {
+ // Minimum.
+ EXPECT_EQ(0xffu, DecodeValidUint32(8, string("\xff\x00", 2)));
+ EXPECT_EQ(0x0100u, DecodeValidUint32(8, "\xff\x01"));
+ // Maximum.
+ EXPECT_EQ(0x017eu, DecodeValidUint32(8, "\xff\x7f"));
+ // Invalid.
+ ExpectDecodeUint32Invalid(8, "\xff\x80");
+ ExpectDecodeUint32Invalid(8, "\xff\xff");
+}
+
+TEST(HpackInputStreamTest, ThreeByteIntegersEightBitPrefix) {
+ // Minimum.
+ EXPECT_EQ(0x017fu, DecodeValidUint32(8, "\xff\x80\x01"));
+ EXPECT_EQ(0x0fffu, DecodeValidUint32(8, "\xff\x80\x1e"));
+ // Maximum.
+ EXPECT_EQ(0x40feu, DecodeValidUint32(8, "\xff\xff\x7f"));
+ // Invalid.
+ ExpectDecodeUint32Invalid(8, "\xff\x80\x00");
+ ExpectDecodeUint32Invalid(8, "\xff\xff\x00");
+ ExpectDecodeUint32Invalid(8, "\xff\xff\x80");
+ ExpectDecodeUint32Invalid(8, "\xff\xff\xff");
+}
+
+TEST(HpackInputStreamTest, FourByteIntegersEightBitPrefix) {
+ // Minimum.
+ EXPECT_EQ(0x40ffu, DecodeValidUint32(8, "\xff\x80\x80\x01"));
+ EXPECT_EQ(0xffffu, DecodeValidUint32(8, "\xff\x80\xfe\x03"));
+ // Maximum.
+ EXPECT_EQ(0x002000feu, DecodeValidUint32(8, "\xff\xff\xff\x7f"));
+ // Invalid.
+ ExpectDecodeUint32Invalid(8, "\xff\xff\x80\x00");
+ ExpectDecodeUint32Invalid(8, "\xff\xff\xff\x00");
+ ExpectDecodeUint32Invalid(8, "\xff\xff\xff\x80");
+ ExpectDecodeUint32Invalid(8, "\xff\xff\xff\xff");
+}
+
+TEST(HpackInputStreamTest, FiveByteIntegersEightBitPrefix) {
+ // Minimum.
+ EXPECT_EQ(0x002000ffu, DecodeValidUint32(8, "\xff\x80\x80\x80\x01"));
+ EXPECT_EQ(0x00ffffffu, DecodeValidUint32(8, "\xff\x80\xfe\xff\x07"));
+ // Maximum.
+ EXPECT_EQ(0x100000feu, DecodeValidUint32(8, "\xff\xff\xff\xff\x7f"));
+ // Invalid.
+ ExpectDecodeUint32Invalid(8, "\xff\xff\xff\x80\x00");
+ ExpectDecodeUint32Invalid(8, "\xff\xff\xff\xff\x00");
+ ExpectDecodeUint32Invalid(8, "\xff\xff\xff\xff\x80");
+ ExpectDecodeUint32Invalid(8, "\xff\xff\xff\xff\xff");
+}
+
+TEST(HpackInputStreamTest, SixByteIntegersEightBitPrefix) {
+ // Minimum.
+ EXPECT_EQ(0x100000ffu, DecodeValidUint32(8, "\xff\x80\x80\x80\x80\x01"));
+ // Maximum.
+ EXPECT_EQ(0xffffffffu, DecodeValidUint32(8, "\xff\x80\xfe\xff\xff\x0f"));
+ // Invalid.
+ ExpectDecodeUint32Invalid(8, "\xff\x80\x80\x80\x80\x00");
+ ExpectDecodeUint32Invalid(8, "\xff\x80\xfe\xff\xff\x10");
+ ExpectDecodeUint32Invalid(8, "\xff\xff\xff\xff\xff\xff");
+}
+
+// There are no valid uint32 encodings that are greater than six
+// bytes.
+TEST(HpackInputStreamTest, SevenByteIntegersEightBitPrefix) {
+ ExpectDecodeUint32Invalid(8, "\xff\x80\x80\x80\x80\x80\x00");
+ ExpectDecodeUint32Invalid(8, "\xff\x80\x80\x80\x80\x80\x01");
+ ExpectDecodeUint32Invalid(8, "\xff\xff\xff\xff\xff\xff\xff");
+}
+
+// The {Number}ByteIntegersOneToSevenBitPrefix tests below test that
+// certain integers are encoded correctly with an N-bit prefix in
+// exactly {Number} bytes for N in {1, 2, ..., 7}.
+
+TEST(HpackInputStreamTest, OneByteIntegersOneToSevenBitPrefixes) {
+ // Minimums.
+ EXPECT_EQ(0x00u, DecodeValidUint32(7, string("\x00", 1)));
+ EXPECT_EQ(0x00u, DecodeValidUint32(7, string("\x80", 1)));
+ EXPECT_EQ(0x00u, DecodeValidUint32(6, string("\x00", 1)));
+ EXPECT_EQ(0x00u, DecodeValidUint32(6, string("\xc0", 1)));
+ EXPECT_EQ(0x00u, DecodeValidUint32(5, string("\x00", 1)));
+ EXPECT_EQ(0x00u, DecodeValidUint32(5, string("\xe0", 1)));
+ EXPECT_EQ(0x00u, DecodeValidUint32(4, string("\x00", 1)));
+ EXPECT_EQ(0x00u, DecodeValidUint32(4, string("\xf0", 1)));
+ EXPECT_EQ(0x00u, DecodeValidUint32(3, string("\x00", 1)));
+ EXPECT_EQ(0x00u, DecodeValidUint32(3, string("\xf8", 1)));
+ EXPECT_EQ(0x00u, DecodeValidUint32(2, string("\x00", 1)));
+ EXPECT_EQ(0x00u, DecodeValidUint32(2, string("\xfc", 1)));
+ EXPECT_EQ(0x00u, DecodeValidUint32(1, string("\x00", 1)));
+ EXPECT_EQ(0x00u, DecodeValidUint32(1, string("\xfe", 1)));
+
+ // Maximums.
+ EXPECT_EQ(0x7eu, DecodeValidUint32(7, "\x7e"));
+ EXPECT_EQ(0x7eu, DecodeValidUint32(7, "\xfe"));
+ EXPECT_EQ(0x3eu, DecodeValidUint32(6, "\x3e"));
+ EXPECT_EQ(0x3eu, DecodeValidUint32(6, "\xfe"));
+ EXPECT_EQ(0x1eu, DecodeValidUint32(5, "\x1e"));
+ EXPECT_EQ(0x1eu, DecodeValidUint32(5, "\xfe"));
+ EXPECT_EQ(0x0eu, DecodeValidUint32(4, "\x0e"));
+ EXPECT_EQ(0x0eu, DecodeValidUint32(4, "\xfe"));
+ EXPECT_EQ(0x06u, DecodeValidUint32(3, "\x06"));
+ EXPECT_EQ(0x06u, DecodeValidUint32(3, "\xfe"));
+ EXPECT_EQ(0x02u, DecodeValidUint32(2, "\x02"));
+ EXPECT_EQ(0x02u, DecodeValidUint32(2, "\xfe"));
+ EXPECT_EQ(0x00u, DecodeValidUint32(1, string("\x00", 1)));
+ EXPECT_EQ(0x00u, DecodeValidUint32(1, string("\xfe", 1)));
+
+ // Invalid.
+ ExpectDecodeUint32Invalid(7, "\x7f");
+ ExpectDecodeUint32Invalid(7, "\xff");
+ ExpectDecodeUint32Invalid(6, "\x3f");
+ ExpectDecodeUint32Invalid(6, "\xff");
+ ExpectDecodeUint32Invalid(5, "\x1f");
+ ExpectDecodeUint32Invalid(5, "\xff");
+ ExpectDecodeUint32Invalid(4, "\x0f");
+ ExpectDecodeUint32Invalid(4, "\xff");
+ ExpectDecodeUint32Invalid(3, "\x07");
+ ExpectDecodeUint32Invalid(3, "\xff");
+ ExpectDecodeUint32Invalid(2, "\x03");
+ ExpectDecodeUint32Invalid(2, "\xff");
+ ExpectDecodeUint32Invalid(1, "\x01");
+ ExpectDecodeUint32Invalid(1, "\xff");
+}
+
+TEST(HpackInputStreamTest, TwoByteIntegersOneToSevenBitPrefixes) {
+ // Minimums.
+ EXPECT_EQ(0x7fu, DecodeValidUint32(7, string("\x7f\x00", 2)));
+ EXPECT_EQ(0x7fu, DecodeValidUint32(7, string("\xff\x00", 2)));
+ EXPECT_EQ(0x3fu, DecodeValidUint32(6, string("\x3f\x00", 2)));
+ EXPECT_EQ(0x3fu, DecodeValidUint32(6, string("\xff\x00", 2)));
+ EXPECT_EQ(0x1fu, DecodeValidUint32(5, string("\x1f\x00", 2)));
+ EXPECT_EQ(0x1fu, DecodeValidUint32(5, string("\xff\x00", 2)));
+ EXPECT_EQ(0x0fu, DecodeValidUint32(4, string("\x0f\x00", 2)));
+ EXPECT_EQ(0x0fu, DecodeValidUint32(4, string("\xff\x00", 2)));
+ EXPECT_EQ(0x07u, DecodeValidUint32(3, string("\x07\x00", 2)));
+ EXPECT_EQ(0x07u, DecodeValidUint32(3, string("\xff\x00", 2)));
+ EXPECT_EQ(0x03u, DecodeValidUint32(2, string("\x03\x00", 2)));
+ EXPECT_EQ(0x03u, DecodeValidUint32(2, string("\xff\x00", 2)));
+ EXPECT_EQ(0x01u, DecodeValidUint32(1, string("\x01\x00", 2)));
+ EXPECT_EQ(0x01u, DecodeValidUint32(1, string("\xff\x00", 2)));
+
+ // Maximums.
+ EXPECT_EQ(0xfeu, DecodeValidUint32(7, "\x7f\x7f"));
+ EXPECT_EQ(0xfeu, DecodeValidUint32(7, "\xff\x7f"));
+ EXPECT_EQ(0xbeu, DecodeValidUint32(6, "\x3f\x7f"));
+ EXPECT_EQ(0xbeu, DecodeValidUint32(6, "\xff\x7f"));
+ EXPECT_EQ(0x9eu, DecodeValidUint32(5, "\x1f\x7f"));
+ EXPECT_EQ(0x9eu, DecodeValidUint32(5, "\xff\x7f"));
+ EXPECT_EQ(0x8eu, DecodeValidUint32(4, "\x0f\x7f"));
+ EXPECT_EQ(0x8eu, DecodeValidUint32(4, "\xff\x7f"));
+ EXPECT_EQ(0x86u, DecodeValidUint32(3, "\x07\x7f"));
+ EXPECT_EQ(0x86u, DecodeValidUint32(3, "\xff\x7f"));
+ EXPECT_EQ(0x82u, DecodeValidUint32(2, "\x03\x7f"));
+ EXPECT_EQ(0x82u, DecodeValidUint32(2, "\xff\x7f"));
+ EXPECT_EQ(0x80u, DecodeValidUint32(1, "\x01\x7f"));
+ EXPECT_EQ(0x80u, DecodeValidUint32(1, "\xff\x7f"));
+
+ // Invalid.
+ ExpectDecodeUint32Invalid(7, "\x7f\x80");
+ ExpectDecodeUint32Invalid(7, "\xff\xff");
+ ExpectDecodeUint32Invalid(6, "\x3f\x80");
+ ExpectDecodeUint32Invalid(6, "\xff\xff");
+ ExpectDecodeUint32Invalid(5, "\x1f\x80");
+ ExpectDecodeUint32Invalid(5, "\xff\xff");
+ ExpectDecodeUint32Invalid(4, "\x0f\x80");
+ ExpectDecodeUint32Invalid(4, "\xff\xff");
+ ExpectDecodeUint32Invalid(3, "\x07\x80");
+ ExpectDecodeUint32Invalid(3, "\xff\xff");
+ ExpectDecodeUint32Invalid(2, "\x03\x80");
+ ExpectDecodeUint32Invalid(2, "\xff\xff");
+ ExpectDecodeUint32Invalid(1, "\x01\x80");
+ ExpectDecodeUint32Invalid(1, "\xff\xff");
+}
+
+TEST(HpackInputStreamTest, ThreeByteIntegersOneToSevenBitPrefixes) {
+ // Minimums.
+ EXPECT_EQ(0xffu, DecodeValidUint32(7, "\x7f\x80\x01"));
+ EXPECT_EQ(0xffu, DecodeValidUint32(7, "\xff\x80\x01"));
+ EXPECT_EQ(0xbfu, DecodeValidUint32(6, "\x3f\x80\x01"));
+ EXPECT_EQ(0xbfu, DecodeValidUint32(6, "\xff\x80\x01"));
+ EXPECT_EQ(0x9fu, DecodeValidUint32(5, "\x1f\x80\x01"));
+ EXPECT_EQ(0x9fu, DecodeValidUint32(5, "\xff\x80\x01"));
+ EXPECT_EQ(0x8fu, DecodeValidUint32(4, "\x0f\x80\x01"));
+ EXPECT_EQ(0x8fu, DecodeValidUint32(4, "\xff\x80\x01"));
+ EXPECT_EQ(0x87u, DecodeValidUint32(3, "\x07\x80\x01"));
+ EXPECT_EQ(0x87u, DecodeValidUint32(3, "\xff\x80\x01"));
+ EXPECT_EQ(0x83u, DecodeValidUint32(2, "\x03\x80\x01"));
+ EXPECT_EQ(0x83u, DecodeValidUint32(2, "\xff\x80\x01"));
+ EXPECT_EQ(0x81u, DecodeValidUint32(1, "\x01\x80\x01"));
+ EXPECT_EQ(0x81u, DecodeValidUint32(1, "\xff\x80\x01"));
+
+ // Maximums.
+ EXPECT_EQ(0x407eu, DecodeValidUint32(7, "\x7f\xff\x7f"));
+ EXPECT_EQ(0x407eu, DecodeValidUint32(7, "\xff\xff\x7f"));
+ EXPECT_EQ(0x403eu, DecodeValidUint32(6, "\x3f\xff\x7f"));
+ EXPECT_EQ(0x403eu, DecodeValidUint32(6, "\xff\xff\x7f"));
+ EXPECT_EQ(0x401eu, DecodeValidUint32(5, "\x1f\xff\x7f"));
+ EXPECT_EQ(0x401eu, DecodeValidUint32(5, "\xff\xff\x7f"));
+ EXPECT_EQ(0x400eu, DecodeValidUint32(4, "\x0f\xff\x7f"));
+ EXPECT_EQ(0x400eu, DecodeValidUint32(4, "\xff\xff\x7f"));
+ EXPECT_EQ(0x4006u, DecodeValidUint32(3, "\x07\xff\x7f"));
+ EXPECT_EQ(0x4006u, DecodeValidUint32(3, "\xff\xff\x7f"));
+ EXPECT_EQ(0x4002u, DecodeValidUint32(2, "\x03\xff\x7f"));
+ EXPECT_EQ(0x4002u, DecodeValidUint32(2, "\xff\xff\x7f"));
+ EXPECT_EQ(0x4000u, DecodeValidUint32(1, "\x01\xff\x7f"));
+ EXPECT_EQ(0x4000u, DecodeValidUint32(1, "\xff\xff\x7f"));
+
+ // Invalid.
+ ExpectDecodeUint32Invalid(7, "\x7f\xff\x80");
+ ExpectDecodeUint32Invalid(7, "\xff\xff\xff");
+ ExpectDecodeUint32Invalid(6, "\x3f\xff\x80");
+ ExpectDecodeUint32Invalid(6, "\xff\xff\xff");
+ ExpectDecodeUint32Invalid(5, "\x1f\xff\x80");
+ ExpectDecodeUint32Invalid(5, "\xff\xff\xff");
+ ExpectDecodeUint32Invalid(4, "\x0f\xff\x80");
+ ExpectDecodeUint32Invalid(4, "\xff\xff\xff");
+ ExpectDecodeUint32Invalid(3, "\x07\xff\x80");
+ ExpectDecodeUint32Invalid(3, "\xff\xff\xff");
+ ExpectDecodeUint32Invalid(2, "\x03\xff\x80");
+ ExpectDecodeUint32Invalid(2, "\xff\xff\xff");
+ ExpectDecodeUint32Invalid(1, "\x01\xff\x80");
+ ExpectDecodeUint32Invalid(1, "\xff\xff\xff");
+}
+
+TEST(HpackInputStreamTest, FourByteIntegersOneToSevenBitPrefixes) {
+ // Minimums.
+ EXPECT_EQ(0x407fu, DecodeValidUint32(7, "\x7f\x80\x80\x01"));
+ EXPECT_EQ(0x407fu, DecodeValidUint32(7, "\xff\x80\x80\x01"));
+ EXPECT_EQ(0x403fu, DecodeValidUint32(6, "\x3f\x80\x80\x01"));
+ EXPECT_EQ(0x403fu, DecodeValidUint32(6, "\xff\x80\x80\x01"));
+ EXPECT_EQ(0x401fu, DecodeValidUint32(5, "\x1f\x80\x80\x01"));
+ EXPECT_EQ(0x401fu, DecodeValidUint32(5, "\xff\x80\x80\x01"));
+ EXPECT_EQ(0x400fu, DecodeValidUint32(4, "\x0f\x80\x80\x01"));
+ EXPECT_EQ(0x400fu, DecodeValidUint32(4, "\xff\x80\x80\x01"));
+ EXPECT_EQ(0x4007u, DecodeValidUint32(3, "\x07\x80\x80\x01"));
+ EXPECT_EQ(0x4007u, DecodeValidUint32(3, "\xff\x80\x80\x01"));
+ EXPECT_EQ(0x4003u, DecodeValidUint32(2, "\x03\x80\x80\x01"));
+ EXPECT_EQ(0x4003u, DecodeValidUint32(2, "\xff\x80\x80\x01"));
+ EXPECT_EQ(0x4001u, DecodeValidUint32(1, "\x01\x80\x80\x01"));
+ EXPECT_EQ(0x4001u, DecodeValidUint32(1, "\xff\x80\x80\x01"));
+
+ // Maximums.
+ EXPECT_EQ(0x20007eu, DecodeValidUint32(7, "\x7f\xff\xff\x7f"));
+ EXPECT_EQ(0x20007eu, DecodeValidUint32(7, "\xff\xff\xff\x7f"));
+ EXPECT_EQ(0x20003eu, DecodeValidUint32(6, "\x3f\xff\xff\x7f"));
+ EXPECT_EQ(0x20003eu, DecodeValidUint32(6, "\xff\xff\xff\x7f"));
+ EXPECT_EQ(0x20001eu, DecodeValidUint32(5, "\x1f\xff\xff\x7f"));
+ EXPECT_EQ(0x20001eu, DecodeValidUint32(5, "\xff\xff\xff\x7f"));
+ EXPECT_EQ(0x20000eu, DecodeValidUint32(4, "\x0f\xff\xff\x7f"));
+ EXPECT_EQ(0x20000eu, DecodeValidUint32(4, "\xff\xff\xff\x7f"));
+ EXPECT_EQ(0x200006u, DecodeValidUint32(3, "\x07\xff\xff\x7f"));
+ EXPECT_EQ(0x200006u, DecodeValidUint32(3, "\xff\xff\xff\x7f"));
+ EXPECT_EQ(0x200002u, DecodeValidUint32(2, "\x03\xff\xff\x7f"));
+ EXPECT_EQ(0x200002u, DecodeValidUint32(2, "\xff\xff\xff\x7f"));
+ EXPECT_EQ(0x200000u, DecodeValidUint32(1, "\x01\xff\xff\x7f"));
+ EXPECT_EQ(0x200000u, DecodeValidUint32(1, "\xff\xff\xff\x7f"));
+
+ // Invalid.
+ ExpectDecodeUint32Invalid(7, "\x7f\xff\xff\x80");
+ ExpectDecodeUint32Invalid(7, "\xff\xff\xff\xff");
+ ExpectDecodeUint32Invalid(6, "\x3f\xff\xff\x80");
+ ExpectDecodeUint32Invalid(6, "\xff\xff\xff\xff");
+ ExpectDecodeUint32Invalid(5, "\x1f\xff\xff\x80");
+ ExpectDecodeUint32Invalid(5, "\xff\xff\xff\xff");
+ ExpectDecodeUint32Invalid(4, "\x0f\xff\xff\x80");
+ ExpectDecodeUint32Invalid(4, "\xff\xff\xff\xff");
+ ExpectDecodeUint32Invalid(3, "\x07\xff\xff\x80");
+ ExpectDecodeUint32Invalid(3, "\xff\xff\xff\xff");
+ ExpectDecodeUint32Invalid(2, "\x03\xff\xff\x80");
+ ExpectDecodeUint32Invalid(2, "\xff\xff\xff\xff");
+ ExpectDecodeUint32Invalid(1, "\x01\xff\xff\x80");
+ ExpectDecodeUint32Invalid(1, "\xff\xff\xff\xff");
+}
+
+TEST(HpackInputStreamTest, FiveByteIntegersOneToSevenBitPrefixes) {
+ // Minimums.
+ EXPECT_EQ(0x20007fu, DecodeValidUint32(7, "\x7f\x80\x80\x80\x01"));
+ EXPECT_EQ(0x20007fu, DecodeValidUint32(7, "\xff\x80\x80\x80\x01"));
+ EXPECT_EQ(0x20003fu, DecodeValidUint32(6, "\x3f\x80\x80\x80\x01"));
+ EXPECT_EQ(0x20003fu, DecodeValidUint32(6, "\xff\x80\x80\x80\x01"));
+ EXPECT_EQ(0x20001fu, DecodeValidUint32(5, "\x1f\x80\x80\x80\x01"));
+ EXPECT_EQ(0x20001fu, DecodeValidUint32(5, "\xff\x80\x80\x80\x01"));
+ EXPECT_EQ(0x20000fu, DecodeValidUint32(4, "\x0f\x80\x80\x80\x01"));
+ EXPECT_EQ(0x20000fu, DecodeValidUint32(4, "\xff\x80\x80\x80\x01"));
+ EXPECT_EQ(0x200007u, DecodeValidUint32(3, "\x07\x80\x80\x80\x01"));
+ EXPECT_EQ(0x200007u, DecodeValidUint32(3, "\xff\x80\x80\x80\x01"));
+ EXPECT_EQ(0x200003u, DecodeValidUint32(2, "\x03\x80\x80\x80\x01"));
+ EXPECT_EQ(0x200003u, DecodeValidUint32(2, "\xff\x80\x80\x80\x01"));
+ EXPECT_EQ(0x200001u, DecodeValidUint32(1, "\x01\x80\x80\x80\x01"));
+ EXPECT_EQ(0x200001u, DecodeValidUint32(1, "\xff\x80\x80\x80\x01"));
+
+ // Maximums.
+ EXPECT_EQ(0x1000007eu, DecodeValidUint32(7, "\x7f\xff\xff\xff\x7f"));
+ EXPECT_EQ(0x1000007eu, DecodeValidUint32(7, "\xff\xff\xff\xff\x7f"));
+ EXPECT_EQ(0x1000003eu, DecodeValidUint32(6, "\x3f\xff\xff\xff\x7f"));
+ EXPECT_EQ(0x1000003eu, DecodeValidUint32(6, "\xff\xff\xff\xff\x7f"));
+ EXPECT_EQ(0x1000001eu, DecodeValidUint32(5, "\x1f\xff\xff\xff\x7f"));
+ EXPECT_EQ(0x1000001eu, DecodeValidUint32(5, "\xff\xff\xff\xff\x7f"));
+ EXPECT_EQ(0x1000000eu, DecodeValidUint32(4, "\x0f\xff\xff\xff\x7f"));
+ EXPECT_EQ(0x1000000eu, DecodeValidUint32(4, "\xff\xff\xff\xff\x7f"));
+ EXPECT_EQ(0x10000006u, DecodeValidUint32(3, "\x07\xff\xff\xff\x7f"));
+ EXPECT_EQ(0x10000006u, DecodeValidUint32(3, "\xff\xff\xff\xff\x7f"));
+ EXPECT_EQ(0x10000002u, DecodeValidUint32(2, "\x03\xff\xff\xff\x7f"));
+ EXPECT_EQ(0x10000002u, DecodeValidUint32(2, "\xff\xff\xff\xff\x7f"));
+ EXPECT_EQ(0x10000000u, DecodeValidUint32(1, "\x01\xff\xff\xff\x7f"));
+ EXPECT_EQ(0x10000000u, DecodeValidUint32(1, "\xff\xff\xff\xff\x7f"));
+
+ // Invalid.
+ ExpectDecodeUint32Invalid(7, "\x7f\xff\xff\xff\x80");
+ ExpectDecodeUint32Invalid(7, "\xff\xff\xff\xff\xff");
+ ExpectDecodeUint32Invalid(6, "\x3f\xff\xff\xff\x80");
+ ExpectDecodeUint32Invalid(6, "\xff\xff\xff\xff\xff");
+ ExpectDecodeUint32Invalid(5, "\x1f\xff\xff\xff\x80");
+ ExpectDecodeUint32Invalid(5, "\xff\xff\xff\xff\xff");
+ ExpectDecodeUint32Invalid(4, "\x0f\xff\xff\xff\x80");
+ ExpectDecodeUint32Invalid(4, "\xff\xff\xff\xff\xff");
+ ExpectDecodeUint32Invalid(3, "\x07\xff\xff\xff\x80");
+ ExpectDecodeUint32Invalid(3, "\xff\xff\xff\xff\xff");
+ ExpectDecodeUint32Invalid(2, "\x03\xff\xff\xff\x80");
+ ExpectDecodeUint32Invalid(2, "\xff\xff\xff\xff\xff");
+ ExpectDecodeUint32Invalid(1, "\x01\xff\xff\xff\x80");
+ ExpectDecodeUint32Invalid(1, "\xff\xff\xff\xff\xff");
+}
+
+TEST(HpackInputStreamTest, SixByteIntegersOneToSevenBitPrefixes) {
+ // Minimums.
+ EXPECT_EQ(0x1000007fu, DecodeValidUint32(7, "\x7f\x80\x80\x80\x80\x01"));
+ EXPECT_EQ(0x1000007fu, DecodeValidUint32(7, "\xff\x80\x80\x80\x80\x01"));
+ EXPECT_EQ(0x1000003fu, DecodeValidUint32(6, "\x3f\x80\x80\x80\x80\x01"));
+ EXPECT_EQ(0x1000003fu, DecodeValidUint32(6, "\xff\x80\x80\x80\x80\x01"));
+ EXPECT_EQ(0x1000001fu, DecodeValidUint32(5, "\x1f\x80\x80\x80\x80\x01"));
+ EXPECT_EQ(0x1000001fu, DecodeValidUint32(5, "\xff\x80\x80\x80\x80\x01"));
+ EXPECT_EQ(0x1000000fu, DecodeValidUint32(4, "\x0f\x80\x80\x80\x80\x01"));
+ EXPECT_EQ(0x1000000fu, DecodeValidUint32(4, "\xff\x80\x80\x80\x80\x01"));
+ EXPECT_EQ(0x10000007u, DecodeValidUint32(3, "\x07\x80\x80\x80\x80\x01"));
+ EXPECT_EQ(0x10000007u, DecodeValidUint32(3, "\xff\x80\x80\x80\x80\x01"));
+ EXPECT_EQ(0x10000003u, DecodeValidUint32(2, "\x03\x80\x80\x80\x80\x01"));
+ EXPECT_EQ(0x10000003u, DecodeValidUint32(2, "\xff\x80\x80\x80\x80\x01"));
+ EXPECT_EQ(0x10000001u, DecodeValidUint32(1, "\x01\x80\x80\x80\x80\x01"));
+ EXPECT_EQ(0x10000001u, DecodeValidUint32(1, "\xff\x80\x80\x80\x80\x01"));
+
+ // Maximums.
+ EXPECT_EQ(0xffffffffu, DecodeValidUint32(7, "\x7f\x80\xff\xff\xff\x0f"));
+ EXPECT_EQ(0xffffffffu, DecodeValidUint32(7, "\xff\x80\xff\xff\xff\x0f"));
+ EXPECT_EQ(0xffffffffu, DecodeValidUint32(6, "\x3f\xc0\xff\xff\xff\x0f"));
+ EXPECT_EQ(0xffffffffu, DecodeValidUint32(6, "\xff\xc0\xff\xff\xff\x0f"));
+ EXPECT_EQ(0xffffffffu, DecodeValidUint32(5, "\x1f\xe0\xff\xff\xff\x0f"));
+ EXPECT_EQ(0xffffffffu, DecodeValidUint32(5, "\xff\xe0\xff\xff\xff\x0f"));
+ EXPECT_EQ(0xffffffffu, DecodeValidUint32(4, "\x0f\xf0\xff\xff\xff\x0f"));
+ EXPECT_EQ(0xffffffffu, DecodeValidUint32(4, "\xff\xf0\xff\xff\xff\x0f"));
+ EXPECT_EQ(0xffffffffu, DecodeValidUint32(3, "\x07\xf8\xff\xff\xff\x0f"));
+ EXPECT_EQ(0xffffffffu, DecodeValidUint32(3, "\xff\xf8\xff\xff\xff\x0f"));
+ EXPECT_EQ(0xffffffffu, DecodeValidUint32(2, "\x03\xfc\xff\xff\xff\x0f"));
+ EXPECT_EQ(0xffffffffu, DecodeValidUint32(2, "\xff\xfc\xff\xff\xff\x0f"));
+ EXPECT_EQ(0xffffffffu, DecodeValidUint32(1, "\x01\xfe\xff\xff\xff\x0f"));
+ EXPECT_EQ(0xffffffffu, DecodeValidUint32(1, "\xff\xfe\xff\xff\xff\x0f"));
+
+ // Invalid.
+ ExpectDecodeUint32Invalid(7, "\x7f\x80\xff\xff\xff\x10");
+ ExpectDecodeUint32Invalid(7, "\xff\x80\xff\xff\xff\xff");
+ ExpectDecodeUint32Invalid(6, "\x3f\xc0\xff\xff\xff\x10");
+ ExpectDecodeUint32Invalid(6, "\xff\xc0\xff\xff\xff\xff");
+ ExpectDecodeUint32Invalid(5, "\x1f\xe0\xff\xff\xff\x10");
+ ExpectDecodeUint32Invalid(5, "\xff\xe0\xff\xff\xff\xff");
+ ExpectDecodeUint32Invalid(4, "\x0f\xf0\xff\xff\xff\x10");
+ ExpectDecodeUint32Invalid(4, "\xff\xf0\xff\xff\xff\xff");
+ ExpectDecodeUint32Invalid(3, "\x07\xf8\xff\xff\xff\x10");
+ ExpectDecodeUint32Invalid(3, "\xff\xf8\xff\xff\xff\xff");
+ ExpectDecodeUint32Invalid(2, "\x03\xfc\xff\xff\xff\x10");
+ ExpectDecodeUint32Invalid(2, "\xff\xfc\xff\xff\xff\xff");
+ ExpectDecodeUint32Invalid(1, "\x01\xfe\xff\xff\xff\x10");
+ ExpectDecodeUint32Invalid(1, "\xff\xfe\xff\xff\xff\xff");
+}
+
+// There are no valid uint32 encodings that are greater than six
+// bytes.
+TEST(HpackInputStreamTest, SevenByteIntegersOneToSevenBitPrefixes) {
+ ExpectDecodeUint32Invalid(7, "\x7f\x80\x80\x80\x80\x80\x00");
+ ExpectDecodeUint32Invalid(7, "\x7f\x80\x80\x80\x80\x80\x01");
+ ExpectDecodeUint32Invalid(7, "\xff\xff\xff\xff\xff\xff\xff");
+ ExpectDecodeUint32Invalid(6, "\x3f\x80\x80\x80\x80\x80\x00");
+ ExpectDecodeUint32Invalid(6, "\x3f\x80\x80\x80\x80\x80\x01");
+ ExpectDecodeUint32Invalid(6, "\xff\xff\xff\xff\xff\xff\xff");
+ ExpectDecodeUint32Invalid(5, "\x1f\x80\x80\x80\x80\x80\x00");
+ ExpectDecodeUint32Invalid(5, "\x1f\x80\x80\x80\x80\x80\x01");
+ ExpectDecodeUint32Invalid(5, "\xff\xff\xff\xff\xff\xff\xff");
+ ExpectDecodeUint32Invalid(4, "\x0f\x80\x80\x80\x80\x80\x00");
+ ExpectDecodeUint32Invalid(4, "\x0f\x80\x80\x80\x80\x80\x01");
+ ExpectDecodeUint32Invalid(4, "\xff\xff\xff\xff\xff\xff\xff");
+ ExpectDecodeUint32Invalid(3, "\x07\x80\x80\x80\x80\x80\x00");
+ ExpectDecodeUint32Invalid(3, "\x07\x80\x80\x80\x80\x80\x01");
+ ExpectDecodeUint32Invalid(3, "\xff\xff\xff\xff\xff\xff\xff");
+ ExpectDecodeUint32Invalid(2, "\x03\x80\x80\x80\x80\x80\x00");
+ ExpectDecodeUint32Invalid(2, "\x03\x80\x80\x80\x80\x80\x01");
+ ExpectDecodeUint32Invalid(2, "\xff\xff\xff\xff\xff\xff\xff");
+ ExpectDecodeUint32Invalid(1, "\x01\x80\x80\x80\x80\x80\x00");
+ ExpectDecodeUint32Invalid(1, "\x01\x80\x80\x80\x80\x80\x01");
+ ExpectDecodeUint32Invalid(1, "\xff\xff\xff\xff\xff\xff\xff");
+}
+
+// Decoding a valid encoded string literal should work.
+TEST(HpackInputStreamTest, DecodeNextStringLiteral) {
+ HpackInputStream input_stream(kuint32max, "\x0estring literal");
+
+ EXPECT_TRUE(input_stream.HasMoreData());
+ StringPiece string_piece;
+ EXPECT_TRUE(input_stream.DecodeNextStringLiteralForTest(&string_piece));
+ EXPECT_EQ("string literal", string_piece);
+ EXPECT_FALSE(input_stream.HasMoreData());
+}
+
+// Decoding an encoded string literal with size larger than
+// |max_string_literal_size_| should fail.
+TEST(HpackInputStreamTest, DecodeNextStringLiteralSizeLimit) {
+ HpackInputStream input_stream(13, "\x0estring literal");
+
+ EXPECT_TRUE(input_stream.HasMoreData());
+ StringPiece string_piece;
+ EXPECT_FALSE(input_stream.DecodeNextStringLiteralForTest(&string_piece));
+}
+
+// Decoding an encoded string literal with size larger than the
+// remainder of the buffer should fail.
+TEST(HpackInputStreamTest, DecodeNextStringLiteralInvalidSize) {
+ // Set the length to be one more than it should be.
+ HpackInputStream input_stream(kuint32max, "\x0fstring literal");
+
+ EXPECT_TRUE(input_stream.HasMoreData());
+ StringPiece string_piece;
+ EXPECT_FALSE(input_stream.DecodeNextStringLiteralForTest(&string_piece));
+}
+
+} // namespace
+
+} // namespace net
diff --git a/net/spdy/hpack_output_stream.cc b/net/spdy/hpack_output_stream.cc
index 0a20d96..e499fbf 100644
--- a/net/spdy/hpack_output_stream.cc
+++ b/net/spdy/hpack_output_stream.cc
@@ -5,7 +5,8 @@
#include "net/spdy/hpack_output_stream.h"
#include "base/logging.h"
-#include "net/spdy/hpack_constants.h"
+
+using base::StringPiece;
namespace net {
@@ -18,9 +19,9 @@ HpackOutputStream::HpackOutputStream(uint32 max_string_literal_size)
HpackOutputStream::~HpackOutputStream() {}
bool HpackOutputStream::AppendLiteralHeaderNoIndexingWithName(
- base::StringPiece name, base::StringPiece value) {
- AppendBits(kLiteralNoIndexOpcode, kLiteralNoIndexOpcodeSize);
- AppendBits(0x0, 8 - kLiteralNoIndexOpcodeSize);
+ StringPiece name, StringPiece value) {
+ AppendPrefix(kLiteralNoIndexOpcode);
+ AppendBits(0x0, 8 - kLiteralNoIndexOpcode.bit_size);
if (!AppendStringLiteral(name))
return false;
if (!AppendStringLiteral(value))
@@ -37,15 +38,15 @@ void HpackOutputStream::TakeString(string* output) {
bit_offset_ = 0;
}
-void HpackOutputStream::AppendBits(uint8 bits, size_t size) {
- DCHECK_GT(size, 0u);
- DCHECK_LE(size, 8u);
- DCHECK_EQ(bits >> size, 0);
- size_t new_bit_offset = bit_offset_ + size;
+void HpackOutputStream::AppendBits(uint8 bits, size_t bit_size) {
+ DCHECK_GT(bit_size, 0u);
+ DCHECK_LE(bit_size, 8u);
+ DCHECK_EQ(bits >> bit_size, 0);
+ size_t new_bit_offset = bit_offset_ + bit_size;
if (bit_offset_ == 0) {
// Buffer ends on a byte boundary.
- DCHECK_LE(size, 8u);
- buffer_.append(1, bits << (8 - size));
+ DCHECK_LE(bit_size, 8u);
+ buffer_.append(1, bits << (8 - bit_size));
} else if (new_bit_offset <= 8) {
// Buffer does not end on a byte boundary but the given bits fit
// in the remainder of the last byte.
@@ -59,6 +60,10 @@ void HpackOutputStream::AppendBits(uint8 bits, size_t size) {
bit_offset_ = new_bit_offset % 8;
}
+void HpackOutputStream::AppendPrefix(HpackPrefix prefix) {
+ AppendBits(prefix.bits, prefix.bit_size);
+}
+
void HpackOutputStream::AppendUint32(uint32 I) {
// The algorithm below is adapted from the pseudocode in 4.1.1.
size_t N = 8 - bit_offset_;
@@ -79,7 +84,7 @@ void HpackOutputStream::AppendUint32(uint32 I) {
bool HpackOutputStream::AppendStringLiteral(base::StringPiece str) {
DCHECK_EQ(bit_offset_, 0u);
// TODO(akalin): Implement Huffman encoding.
- AppendBits(kStringLiteralIdentityEncoded, kStringLiteralIdentityEncodedSize);
+ AppendPrefix(kStringLiteralIdentityEncoded);
if (str.size() > max_string_literal_size_)
return false;
AppendUint32(static_cast<uint32>(str.size()));
diff --git a/net/spdy/hpack_output_stream.h b/net/spdy/hpack_output_stream.h
index f041171..f82ec92 100644
--- a/net/spdy/hpack_output_stream.h
+++ b/net/spdy/hpack_output_stream.h
@@ -12,6 +12,7 @@
#include "base/macros.h"
#include "base/strings/string_piece.h"
#include "net/base/net_export.h"
+#include "net/spdy/hpack_constants.h" // For HpackPrefix.
#include "net/spdy/hpack_encoding_context.h"
// All section references below are to
@@ -54,11 +55,14 @@ class NET_EXPORT_PRIVATE HpackOutputStream {
}
private:
- // Appends the lower |size| bits of |bits| to the internal buffer.
+ // Appends the lower |bit_size| bits of |bits| to the internal buffer.
//
- // |size| must be > 0 and <= 8. |bits| must not have any bits set
- // |other than the lower |size| bits.
- void AppendBits(uint8 bits, size_t size);
+ // |bit_size| must be > 0 and <= 8. |bits| must not have any bits
+ // set other than the lower |bit_size| bits.
+ void AppendBits(uint8 bits, size_t bit_size);
+
+ // Simply forwards to AppendBits(prefix.bits, prefix.bit-size).
+ void AppendPrefix(HpackPrefix prefix);
// Appends the given integer using the representation described in
// 4.1.1. If the internal buffer ends on a byte boundary, the prefix