summaryrefslogtreecommitdiff
path: root/chromium/net/third_party/quiche/src/quic/core/qpack
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2020-03-11 11:32:04 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2020-03-18 13:40:17 +0000
commit31ccca0778db85c159634478b4ec7997f6704860 (patch)
tree3d33fc3afd9d5ec95541e1bbe074a9cf8da12a0e /chromium/net/third_party/quiche/src/quic/core/qpack
parent248b70b82a40964d5594eb04feca0fa36716185d (diff)
downloadqtwebengine-chromium-31ccca0778db85c159634478b4ec7997f6704860.tar.gz
BASELINE: Update Chromium to 80.0.3987.136
Change-Id: I98e1649aafae85ba3a83e67af00bb27ef301db7b Reviewed-by: Jüri Valdmann <juri.valdmann@qt.io>
Diffstat (limited to 'chromium/net/third_party/quiche/src/quic/core/qpack')
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/offline/README.md28
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/offline/qpack_offline_decoder.cc312
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/offline/qpack_offline_decoder.h86
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.cc34
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.h19
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager_test.cc82
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator.cc79
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator.h82
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator_test.cc158
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder.cc8
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h5
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_receiver.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_receiver.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender.cc20
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender.h1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender_test.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test.cc67
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.cc88
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.h103
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.cc60
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h27
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_receiver.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_receiver.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.cc31
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.h1
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender_test.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test.cc9
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test_utils.cc16
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test_utils.h40
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.cc3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.h18
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder.cc110
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder.h42
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder_test.cc97
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder.cc18
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder.h15
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder_test.cc148
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instructions.cc (renamed from chromium/net/third_party/quiche/src/quic/core/qpack/qpack_constants.cc)131
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instructions.h (renamed from chromium/net/third_party/quiche/src/quic/core/qpack/qpack_constants.h)71
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_offline_decoder_bin.cc (renamed from chromium/net/third_party/quiche/src/quic/core/qpack/offline/qpack_offline_decoder_bin.cc)3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.cc28
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.h3
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_round_trip_test.cc8
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.cc23
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.h40
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/qpack_utils.h23
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/qpack/value_splitting_header_list_test.cc70
47 files changed, 873 insertions, 1346 deletions
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/offline/README.md b/chromium/net/third_party/quiche/src/quic/core/qpack/offline/README.md
deleted file mode 100644
index 4f6697c66b5..00000000000
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/offline/README.md
+++ /dev/null
@@ -1,28 +0,0 @@
-# QPACK Offline Interop Testing tools
-
-See
-[QPACK Offline Interop](https://github.com/quicwg/base-drafts/wiki/QPACK-Offline-Interop)
-for description of test data format.
-
-Example usage:
-
-```shell
-$ # Download test data
-$ cd $TEST_DATA
-$ git clone https://github.com/qpackers/qifs.git
-$ TEST_ENCODED_DATA=`pwd`/qifs/encoded/qpack-03
-$ TEST_QIF_DATA=`pwd`/qifs/qifs
-$
-$ # Decode encoded test data in four files and verify that they match
-$ # the original headers in corresponding files
-$ $BIN/qpack_offline_decoder \
-> $TEST_ENCODED_DATA/f5/fb-req.qifencoded.4096.100.0 \
-> $TEST_QIF_DATA/fb-req.qif
-> $TEST_ENCODED_DATA/h2o/fb-req-hq.out.512.0.1 \
-> $TEST_QIF_DATA/fb-req-hq.qif
-> $TEST_ENCODED_DATA/ls-qpack/fb-resp-hq.out.0.0.0 \
-> $TEST_QIF_DATA/fb-resp-hq.qif
-> $TEST_ENCODED_DATA/proxygen/netbsd.qif.proxygen.out.4096.0.0 \
-> $TEST_QIF_DATA/netbsd.qif
-$
-```
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/offline/qpack_offline_decoder.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/offline/qpack_offline_decoder.cc
deleted file mode 100644
index 379cb6ad835..00000000000
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/offline/qpack_offline_decoder.cc
+++ /dev/null
@@ -1,312 +0,0 @@
-// Copyright (c) 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/quiche/src/quic/core/qpack/offline/qpack_offline_decoder.h"
-
-#include <cstdint>
-#include <string>
-#include <utility>
-
-#include "net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.h"
-#include "net/third_party/quiche/src/quic/core/quic_types.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_endian.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_file_utils.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
-
-namespace quic {
-
-QpackOfflineDecoder::QpackOfflineDecoder()
- : encoder_stream_error_detected_(false) {}
-
-bool QpackOfflineDecoder::DecodeAndVerifyOfflineData(
- QuicStringPiece input_filename,
- QuicStringPiece expected_headers_filename) {
- if (!ParseInputFilename(input_filename)) {
- QUIC_LOG(ERROR) << "Error parsing input filename " << input_filename;
- return false;
- }
-
- if (!DecodeHeaderBlocksFromFile(input_filename)) {
- QUIC_LOG(ERROR) << "Error decoding header blocks in " << input_filename;
- return false;
- }
-
- if (!VerifyDecodedHeaderLists(expected_headers_filename)) {
- QUIC_LOG(ERROR) << "Header lists decoded from " << input_filename
- << " to not match expected headers parsed from "
- << expected_headers_filename;
- return false;
- }
-
- return true;
-}
-
-void QpackOfflineDecoder::OnEncoderStreamError(QuicStringPiece error_message) {
- QUIC_LOG(ERROR) << "Encoder stream error: " << error_message;
- encoder_stream_error_detected_ = true;
-}
-
-bool QpackOfflineDecoder::ParseInputFilename(QuicStringPiece input_filename) {
- auto pieces = QuicTextUtils::Split(input_filename, '.');
-
- if (pieces.size() < 3) {
- QUIC_LOG(ERROR) << "Not enough fields in input filename " << input_filename;
- return false;
- }
-
- auto piece_it = pieces.rbegin();
-
- // Acknowledgement mode: 1 for immediate, 0 for none.
- bool immediate_acknowledgement = false;
- if (*piece_it == "0") {
- immediate_acknowledgement = false;
- } else if (*piece_it == "1") {
- immediate_acknowledgement = true;
- } else {
- QUIC_LOG(ERROR)
- << "Header acknowledgement field must be 0 or 1 in input filename "
- << input_filename;
- return false;
- }
-
- ++piece_it;
-
- // Maximum allowed number of blocked streams.
- uint64_t max_blocked_streams = 0;
- if (!QuicTextUtils::StringToUint64(*piece_it, &max_blocked_streams)) {
- QUIC_LOG(ERROR) << "Error parsing part of input filename \"" << *piece_it
- << "\" as an integer.";
- return false;
- }
-
- ++piece_it;
-
- // Maximum Dynamic Table Capacity in bytes
- uint64_t maximum_dynamic_table_capacity = 0;
- if (!QuicTextUtils::StringToUint64(*piece_it,
- &maximum_dynamic_table_capacity)) {
- QUIC_LOG(ERROR) << "Error parsing part of input filename \"" << *piece_it
- << "\" as an integer.";
- return false;
- }
- qpack_decoder_ = std::make_unique<QpackDecoder>(
- maximum_dynamic_table_capacity, max_blocked_streams, this);
- qpack_decoder_->set_qpack_stream_sender_delegate(
- &decoder_stream_sender_delegate_);
-
- // The initial dynamic table capacity is zero according to
- // https://quicwg.org/base-drafts/draft-ietf-quic-qpack.html#eviction.
- // However, for historical reasons, offline interop encoders use
- // |maximum_dynamic_table_capacity| as initial capacity.
- qpack_decoder_->OnSetDynamicTableCapacity(maximum_dynamic_table_capacity);
-
- return true;
-}
-
-bool QpackOfflineDecoder::DecodeHeaderBlocksFromFile(
- QuicStringPiece input_filename) {
- // Store data in |input_data_storage|; use a QuicStringPiece to efficiently
- // keep track of remaining portion yet to be decoded.
- std::string input_data_storage;
- ReadFileContents(input_filename, &input_data_storage);
- QuicStringPiece input_data(input_data_storage);
-
- while (!input_data.empty()) {
- // Parse stream_id and length.
- if (input_data.size() < sizeof(uint64_t) + sizeof(uint32_t)) {
- QUIC_LOG(ERROR) << "Unexpected end of input file.";
- return false;
- }
-
- uint64_t stream_id = QuicEndian::NetToHost64(
- *reinterpret_cast<const uint64_t*>(input_data.data()));
- input_data = input_data.substr(sizeof(uint64_t));
-
- uint32_t length = QuicEndian::NetToHost32(
- *reinterpret_cast<const uint32_t*>(input_data.data()));
- input_data = input_data.substr(sizeof(uint32_t));
-
- if (input_data.size() < length) {
- QUIC_LOG(ERROR) << "Unexpected end of input file.";
- return false;
- }
-
- // Parse data.
- QuicStringPiece data = input_data.substr(0, length);
- input_data = input_data.substr(length);
-
- // Process data.
- if (stream_id == 0) {
- qpack_decoder_->encoder_stream_receiver()->Decode(data);
-
- if (encoder_stream_error_detected_) {
- QUIC_LOG(ERROR) << "Error detected on encoder stream.";
- return false;
- }
- } else {
- auto headers_handler = std::make_unique<test::TestHeadersHandler>();
- auto progressive_decoder = qpack_decoder_->CreateProgressiveDecoder(
- stream_id, headers_handler.get());
-
- progressive_decoder->Decode(data);
- progressive_decoder->EndHeaderBlock();
-
- if (headers_handler->decoding_error_detected()) {
- QUIC_LOG(ERROR) << "Sync decoding error on stream " << stream_id << ": "
- << headers_handler->error_message();
- return false;
- }
-
- decoders_.push_back({std::move(headers_handler),
- std::move(progressive_decoder), stream_id});
- }
-
- // Move decoded header lists from TestHeadersHandlers and append them to
- // |decoded_header_lists_| while preserving the order in |decoders_|.
- while (!decoders_.empty() &&
- decoders_.front().headers_handler->decoding_completed()) {
- Decoder* decoder = &decoders_.front();
-
- if (decoder->headers_handler->decoding_error_detected()) {
- QUIC_LOG(ERROR) << "Async decoding error on stream "
- << decoder->stream_id << ": "
- << decoder->headers_handler->error_message();
- return false;
- }
-
- if (!decoder->headers_handler->decoding_completed()) {
- QUIC_LOG(ERROR) << "Decoding incomplete after reading entire"
- " file, on stream "
- << decoder->stream_id;
- return false;
- }
-
- decoded_header_lists_.push_back(
- decoder->headers_handler->ReleaseHeaderList());
- decoders_.pop_front();
- }
- }
-
- if (!decoders_.empty()) {
- DCHECK(!decoders_.front().headers_handler->decoding_completed());
-
- QUIC_LOG(ERROR) << "Blocked decoding uncomplete after reading entire"
- " file, on stream "
- << decoders_.front().stream_id;
- return false;
- }
-
- return true;
-}
-
-bool QpackOfflineDecoder::VerifyDecodedHeaderLists(
- QuicStringPiece expected_headers_filename) {
- // Store data in |expected_headers_data_storage|; use a QuicStringPiece to
- // efficiently keep track of remaining portion yet to be decoded.
- std::string expected_headers_data_storage;
- ReadFileContents(expected_headers_filename, &expected_headers_data_storage);
- QuicStringPiece expected_headers_data(expected_headers_data_storage);
-
- while (!decoded_header_lists_.empty()) {
- spdy::SpdyHeaderBlock decoded_header_list =
- std::move(decoded_header_lists_.front());
- decoded_header_lists_.pop_front();
-
- spdy::SpdyHeaderBlock expected_header_list;
- if (!ReadNextExpectedHeaderList(&expected_headers_data,
- &expected_header_list)) {
- QUIC_LOG(ERROR)
- << "Error parsing expected header list to match next decoded "
- "header list.";
- return false;
- }
-
- if (!CompareHeaderBlocks(std::move(decoded_header_list),
- std::move(expected_header_list))) {
- QUIC_LOG(ERROR) << "Decoded header does not match expected header.";
- return false;
- }
- }
-
- if (!expected_headers_data.empty()) {
- QUIC_LOG(ERROR)
- << "Not enough encoded header lists to match expected ones.";
- return false;
- }
-
- return true;
-}
-
-bool QpackOfflineDecoder::ReadNextExpectedHeaderList(
- QuicStringPiece* expected_headers_data,
- spdy::SpdyHeaderBlock* expected_header_list) {
- while (true) {
- QuicStringPiece::size_type endline = expected_headers_data->find('\n');
-
- // Even last header list must be followed by an empty line.
- if (endline == QuicStringPiece::npos) {
- QUIC_LOG(ERROR) << "Unexpected end of expected header list file.";
- return false;
- }
-
- if (endline == 0) {
- // Empty line indicates end of header list.
- *expected_headers_data = expected_headers_data->substr(1);
- return true;
- }
-
- QuicStringPiece header_field = expected_headers_data->substr(0, endline);
- auto pieces = QuicTextUtils::Split(header_field, '\t');
-
- if (pieces.size() != 2) {
- QUIC_LOG(ERROR) << "Header key and value must be separated by TAB.";
- return false;
- }
-
- expected_header_list->AppendValueOrAddHeader(pieces[0], pieces[1]);
-
- *expected_headers_data = expected_headers_data->substr(endline + 1);
- }
-}
-
-bool QpackOfflineDecoder::CompareHeaderBlocks(
- spdy::SpdyHeaderBlock decoded_header_list,
- spdy::SpdyHeaderBlock expected_header_list) {
- if (decoded_header_list == expected_header_list) {
- return true;
- }
-
- // The h2o decoder reshuffles the "content-length" header and pseudo-headers,
- // see
- // https://github.com/qpackers/qifs/blob/master/encoded/qpack-03/h2o/README.md.
- // Remove such headers one by one if they match.
- const char* kContentLength = "content-length";
- const char* kPseudoHeaderPrefix = ":";
- for (spdy::SpdyHeaderBlock::iterator decoded_it = decoded_header_list.begin();
- decoded_it != decoded_header_list.end();) {
- const QuicStringPiece key = decoded_it->first;
- if (key != kContentLength &&
- !QuicTextUtils::StartsWith(key, kPseudoHeaderPrefix)) {
- ++decoded_it;
- continue;
- }
- spdy::SpdyHeaderBlock::iterator expected_it =
- expected_header_list.find(key);
- if (expected_it == expected_header_list.end() ||
- decoded_it->second != expected_it->second) {
- ++decoded_it;
- continue;
- }
- // SpdyHeaderBlock does not support erasing by iterator, only by key.
- ++decoded_it;
- expected_header_list.erase(key);
- // This will invalidate |key|.
- decoded_header_list.erase(key);
- }
-
- return decoded_header_list == expected_header_list;
-}
-
-} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/offline/qpack_offline_decoder.h b/chromium/net/third_party/quiche/src/quic/core/qpack/offline/qpack_offline_decoder.h
deleted file mode 100644
index c12c49181fa..00000000000
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/offline/qpack_offline_decoder.h
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright (c) 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 QUICHE_QUIC_CORE_QPACK_OFFLINE_QPACK_OFFLINE_DECODER_H_
-#define QUICHE_QUIC_CORE_QPACK_OFFLINE_QPACK_OFFLINE_DECODER_H_
-
-#include <list>
-
-#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h"
-#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.h"
-#include "net/third_party/quiche/src/quic/core/qpack/qpack_utils.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
-#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h"
-
-namespace quic {
-
-// A decoder to read encoded data from a file, decode it, and compare to
-// a list of expected header lists read from another file. File format is
-// described at
-// https://github.com/quicwg/base-drafts/wiki/QPACK-Offline-Interop.
-class QpackOfflineDecoder : public QpackDecoder::EncoderStreamErrorDelegate {
- public:
- QpackOfflineDecoder();
- ~QpackOfflineDecoder() override = default;
-
- // Read encoded header blocks and encoder stream data from |input_filename|
- // and decode them, read expected header lists from
- // |expected_headers_filename|, and compare decoded header lists to expected
- // ones. Returns true if there is an equal number of them and the
- // corresponding ones match, false otherwise.
- bool DecodeAndVerifyOfflineData(QuicStringPiece input_filename,
- QuicStringPiece expected_headers_filename);
-
- // QpackDecoder::EncoderStreamErrorDelegate implementation:
- void OnEncoderStreamError(QuicStringPiece error_message) override;
-
- private:
- // Data structure to hold TestHeadersHandler and QpackProgressiveDecoder until
- // decoding of a header header block (and all preceding header blocks) is
- // complete.
- struct Decoder {
- std::unique_ptr<test::TestHeadersHandler> headers_handler;
- std::unique_ptr<QpackProgressiveDecoder> progressive_decoder;
- uint64_t stream_id;
- };
-
- // Parse decoder parameters from |input_filename| and set up |qpack_decoder_|
- // accordingly.
- bool ParseInputFilename(QuicStringPiece input_filename);
-
- // Read encoded header blocks and encoder stream data from |input_filename|,
- // pass them to |qpack_decoder_| for decoding, and add decoded header lists to
- // |decoded_header_lists_|.
- bool DecodeHeaderBlocksFromFile(QuicStringPiece input_filename);
-
- // Read expected header lists from |expected_headers_filename| and verify
- // decoded header lists in |decoded_header_lists_| against them.
- bool VerifyDecodedHeaderLists(QuicStringPiece expected_headers_filename);
-
- // Parse next header list from |*expected_headers_data| into
- // |*expected_header_list|, removing consumed data from the beginning of
- // |*expected_headers_data|. Returns true on success, false if parsing fails.
- bool ReadNextExpectedHeaderList(QuicStringPiece* expected_headers_data,
- spdy::SpdyHeaderBlock* expected_header_list);
-
- // Compare two header lists. Allow for different orders of certain headers as
- // described at
- // https://github.com/qpackers/qifs/blob/master/encoded/qpack-03/h2o/README.md.
- bool CompareHeaderBlocks(spdy::SpdyHeaderBlock decoded_header_list,
- spdy::SpdyHeaderBlock expected_header_list);
-
- bool encoder_stream_error_detected_;
- NoopQpackStreamSenderDelegate decoder_stream_sender_delegate_;
- std::unique_ptr<QpackDecoder> qpack_decoder_;
-
- // Objects necessary for decoding, one list element for each header block.
- std::list<Decoder> decoders_;
-
- // Decoded header lists.
- std::list<spdy::SpdyHeaderBlock> decoded_header_lists_;
-};
-
-} // namespace quic
-
-#endif // QUICHE_QUIC_CORE_QPACK_OFFLINE_QPACK_OFFLINE_DECODER_H_
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.cc
index ffec17280f6..3544f1ca10b 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.cc
@@ -24,7 +24,7 @@ bool QpackBlockingManager::OnHeaderAcknowledgement(QuicStreamId stream_id) {
const uint64_t required_index_count = RequiredInsertCount(indices);
if (known_received_count_ < required_index_count) {
- IncreaseKnownReceivedCountTo(required_index_count);
+ known_received_count_ = required_index_count;
}
DecreaseReferenceCounts(indices);
@@ -56,7 +56,7 @@ bool QpackBlockingManager::OnInsertCountIncrement(uint64_t increment) {
return false;
}
- IncreaseKnownReceivedCountTo(known_received_count_ + increment);
+ known_received_count_ += increment;
return true;
}
@@ -68,16 +68,6 @@ void QpackBlockingManager::OnHeaderBlockSent(QuicStreamId stream_id,
header_blocks_[stream_id].push_back(std::move(indices));
}
-void QpackBlockingManager::OnReferenceSentOnEncoderStream(
- uint64_t inserted_index,
- uint64_t referred_index) {
- auto result = unacked_encoder_stream_references_.insert(
- {inserted_index, referred_index});
- // Each dynamic table entry can refer to at most one |referred_index|.
- DCHECK(result.second);
- IncreaseReferenceCounts({referred_index});
-}
-
bool QpackBlockingManager::blocking_allowed_on_stream(
QuicStreamId stream_id,
uint64_t maximum_blocked_streams) const {
@@ -141,26 +131,6 @@ uint64_t QpackBlockingManager::RequiredInsertCount(const IndexSet& indices) {
return *indices.rbegin() + 1;
}
-void QpackBlockingManager::IncreaseKnownReceivedCountTo(
- uint64_t new_known_received_count) {
- DCHECK_GT(new_known_received_count, known_received_count_);
-
- known_received_count_ = new_known_received_count;
-
- // Remove referred indices with key less than new Known Received Count from
- // |unacked_encoder_stream_references_| and |entry_reference_counts_|.
- IndexSet acknowledged_references;
- auto it = unacked_encoder_stream_references_.begin();
- while (it != unacked_encoder_stream_references_.end() &&
- it->first < known_received_count_) {
- acknowledged_references.insert(it->second);
- ++it;
- }
- unacked_encoder_stream_references_.erase(
- unacked_encoder_stream_references_.begin(), it);
- DecreaseReferenceCounts(acknowledged_references);
-}
-
void QpackBlockingManager::IncreaseReferenceCounts(const IndexSet& indices) {
for (const uint64_t index : indices) {
auto it = entry_reference_counts_.lower_bound(index);
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.h
index 60f7db7060a..6d2df9cfcf8 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.h
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.h
@@ -48,12 +48,6 @@ class QUIC_EXPORT_PRIVATE QpackBlockingManager {
// entries with |indices|. |indices| must not be empty.
void OnHeaderBlockSent(QuicStreamId stream_id, IndexSet indices);
- // Called when sending Insert With Name Reference or Duplicate instruction on
- // encoder stream, inserting entry |inserted_index| referring to
- // |referred_index|.
- void OnReferenceSentOnEncoderStream(uint64_t inserted_index,
- uint64_t referred_index);
-
// Returns true if sending blocking references on stream |stream_id| would not
// increase the total number of blocked streams above
// |maximum_blocked_streams|. Note that if |stream_id| is already blocked
@@ -85,11 +79,6 @@ class QUIC_EXPORT_PRIVATE QpackBlockingManager {
using HeaderBlocksForStream = std::list<IndexSet>;
using HeaderBlocks = QuicUnorderedMap<QuicStreamId, HeaderBlocksForStream>;
- // Increases |known_received_count_| to |new_known_received_count|, which must
- // me larger than |known_received_count_|. Removes acknowledged references
- // from |unacked_encoder_stream_references_|.
- void IncreaseKnownReceivedCountTo(uint64_t new_known_received_count);
-
// Increase or decrease the reference count for each index in |indices|.
void IncreaseReferenceCounts(const IndexSet& indices);
void DecreaseReferenceCounts(const IndexSet& indices);
@@ -98,13 +87,7 @@ class QUIC_EXPORT_PRIVATE QpackBlockingManager {
// Must not contain a stream id with an empty queue.
HeaderBlocks header_blocks_;
- // Unacknowledged references on the encoder stream.
- // The key is the absolute index of the inserted entry,
- // the mapped value is the absolute index of the entry referred.
- std::map<uint64_t, uint64_t> unacked_encoder_stream_references_;
-
- // Number of references in |header_blocks_| and
- // |unacked_encoder_stream_references_| for each entry index.
+ // Number of references in |header_blocks_| for each entry index.
std::map<uint64_t, uint64_t> entry_reference_counts_;
uint64_t known_received_count_;
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager_test.cc
index 64bfb97f71d..d92dda549ef 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager_test.cc
@@ -236,88 +236,6 @@ TEST_F(QpackBlockingManagerTest, CancelStream) {
manager_.smallest_blocking_index());
}
-TEST_F(QpackBlockingManagerTest,
- ReferenceOnEncoderStreamUnblockedByInsertCountIncrement) {
- EXPECT_EQ(0u, manager_.known_received_count());
- EXPECT_EQ(std::numeric_limits<uint64_t>::max(),
- manager_.smallest_blocking_index());
-
- // Entry 1 refers to entry 0.
- manager_.OnReferenceSentOnEncoderStream(1, 0);
- // Entry 2 also refers to entry 0.
- manager_.OnReferenceSentOnEncoderStream(2, 0);
-
- EXPECT_EQ(0u, manager_.known_received_count());
- EXPECT_EQ(0u, manager_.smallest_blocking_index());
-
- // Acknowledging entry 1 still leaves one unacknowledged reference to entry 0.
- EXPECT_TRUE(manager_.OnInsertCountIncrement(2));
-
- EXPECT_EQ(2u, manager_.known_received_count());
- EXPECT_EQ(0u, manager_.smallest_blocking_index());
-
- // Entry 3 also refers to entry 2.
- manager_.OnReferenceSentOnEncoderStream(3, 2);
-
- EXPECT_EQ(2u, manager_.known_received_count());
- EXPECT_EQ(0u, manager_.smallest_blocking_index());
-
- // Acknowledging entry 2 removes last reference to entry 0.
- EXPECT_TRUE(manager_.OnInsertCountIncrement(1));
-
- EXPECT_EQ(3u, manager_.known_received_count());
- EXPECT_EQ(2u, manager_.smallest_blocking_index());
-
- // Acknowledging entry 4 (and implicitly 3) removes reference to entry 2.
- EXPECT_TRUE(manager_.OnInsertCountIncrement(2));
-
- EXPECT_EQ(5u, manager_.known_received_count());
- EXPECT_EQ(std::numeric_limits<uint64_t>::max(),
- manager_.smallest_blocking_index());
-}
-
-TEST_F(QpackBlockingManagerTest,
- ReferenceOnEncoderStreamUnblockedByHeaderAcknowledgement) {
- EXPECT_EQ(0u, manager_.known_received_count());
- EXPECT_EQ(std::numeric_limits<uint64_t>::max(),
- manager_.smallest_blocking_index());
-
- // Entry 1 refers to entry 0.
- manager_.OnReferenceSentOnEncoderStream(1, 0);
- // Entry 2 also refers to entry 0.
- manager_.OnReferenceSentOnEncoderStream(2, 0);
-
- EXPECT_EQ(0u, manager_.known_received_count());
- EXPECT_EQ(0u, manager_.smallest_blocking_index());
-
- // Acknowledging a header block with entries up to 1 still leave one
- // unacknowledged reference to entry 0.
- manager_.OnHeaderBlockSent(/* stream_id = */ 0, {0, 1});
- manager_.OnHeaderAcknowledgement(/* stream_id = */ 0);
-
- EXPECT_EQ(2u, manager_.known_received_count());
- EXPECT_EQ(0u, manager_.smallest_blocking_index());
-
- // Entry 3 also refers to entry 2.
- manager_.OnReferenceSentOnEncoderStream(3, 2);
-
- // Acknowledging a header block with entries up to 2 removes last reference to
- // entry 0.
- manager_.OnHeaderBlockSent(/* stream_id = */ 0, {2, 0, 2});
- manager_.OnHeaderAcknowledgement(/* stream_id = */ 0);
-
- EXPECT_EQ(3u, manager_.known_received_count());
- EXPECT_EQ(2u, manager_.smallest_blocking_index());
-
- // Acknowledging entry 4 (and implicitly 3) removes reference to entry 2.
- manager_.OnHeaderBlockSent(/* stream_id = */ 0, {1, 4, 2, 0});
- manager_.OnHeaderAcknowledgement(/* stream_id = */ 0);
-
- EXPECT_EQ(5u, manager_.known_received_count());
- EXPECT_EQ(std::numeric_limits<uint64_t>::max(),
- manager_.smallest_blocking_index());
-}
-
TEST_F(QpackBlockingManagerTest, BlockingAllowedOnStream) {
const QuicStreamId kStreamId1 = 1;
const QuicStreamId kStreamId2 = 2;
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator.cc
index 9cce57365b6..e16aa5a2de7 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator.cc
@@ -8,6 +8,12 @@
namespace quic {
+namespace {
+
+size_t kHeaderFieldSizeOverhead = 32;
+
+}
+
QpackDecodedHeadersAccumulator::QpackDecodedHeadersAccumulator(
QuicStreamId id,
QpackDecoder* qpack_decoder,
@@ -15,12 +21,13 @@ QpackDecodedHeadersAccumulator::QpackDecodedHeadersAccumulator(
size_t max_header_list_size)
: decoder_(qpack_decoder->CreateProgressiveDecoder(id, this)),
visitor_(visitor),
- uncompressed_header_bytes_(0),
+ max_header_list_size_(max_header_list_size),
+ uncompressed_header_bytes_including_overhead_(0),
+ uncompressed_header_bytes_without_overhead_(0),
compressed_header_bytes_(0),
+ header_list_size_limit_exceeded_(false),
headers_decoded_(false),
- blocked_(false),
error_detected_(false) {
- quic_header_list_.set_max_header_list_size(max_header_list_size);
quic_header_list_.OnHeaderBlockStart();
}
@@ -28,8 +35,21 @@ void QpackDecodedHeadersAccumulator::OnHeaderDecoded(QuicStringPiece name,
QuicStringPiece value) {
DCHECK(!error_detected_);
- uncompressed_header_bytes_ += name.size() + value.size();
- quic_header_list_.OnHeader(name, value);
+ uncompressed_header_bytes_without_overhead_ += name.size() + value.size();
+
+ if (header_list_size_limit_exceeded_) {
+ return;
+ }
+
+ uncompressed_header_bytes_including_overhead_ +=
+ name.size() + value.size() + kHeaderFieldSizeOverhead;
+
+ if (uncompressed_header_bytes_including_overhead_ > max_header_list_size_) {
+ header_list_size_limit_exceeded_ = true;
+ quic_header_list_.Clear();
+ } else {
+ quic_header_list_.OnHeader(name, value);
+ }
}
void QpackDecodedHeadersAccumulator::OnDecodingCompleted() {
@@ -37,12 +57,12 @@ void QpackDecodedHeadersAccumulator::OnDecodingCompleted() {
DCHECK(!error_detected_);
headers_decoded_ = true;
- quic_header_list_.OnHeaderBlockEnd(uncompressed_header_bytes_,
- compressed_header_bytes_);
- if (blocked_) {
- visitor_->OnHeadersDecoded(quic_header_list_);
- }
+ quic_header_list_.OnHeaderBlockEnd(
+ uncompressed_header_bytes_without_overhead_, compressed_header_bytes_);
+
+ // Might destroy |this|.
+ visitor_->OnHeadersDecoded(std::move(quic_header_list_));
}
void QpackDecodedHeadersAccumulator::OnDecodingErrorDetected(
@@ -51,51 +71,24 @@ void QpackDecodedHeadersAccumulator::OnDecodingErrorDetected(
DCHECK(!headers_decoded_);
error_detected_ = true;
- // Copy error message to ensure it remains valid for the lifetime of |this|.
- error_message_.assign(error_message.data(), error_message.size());
-
- if (blocked_) {
- visitor_->OnHeaderDecodingError();
- }
+ // Might destroy |this|.
+ visitor_->OnHeaderDecodingError(error_message);
}
-bool QpackDecodedHeadersAccumulator::Decode(QuicStringPiece data) {
+void QpackDecodedHeadersAccumulator::Decode(QuicStringPiece data) {
DCHECK(!error_detected_);
compressed_header_bytes_ += data.size();
+ // Might destroy |this|.
decoder_->Decode(data);
-
- return !error_detected_;
}
-QpackDecodedHeadersAccumulator::Status
-QpackDecodedHeadersAccumulator::EndHeaderBlock() {
+void QpackDecodedHeadersAccumulator::EndHeaderBlock() {
DCHECK(!error_detected_);
DCHECK(!headers_decoded_);
+ // Might destroy |this|.
decoder_->EndHeaderBlock();
-
- if (error_detected_) {
- DCHECK(!headers_decoded_);
- return Status::kError;
- }
-
- if (headers_decoded_) {
- return Status::kSuccess;
- }
-
- blocked_ = true;
- return Status::kBlocked;
-}
-
-const QuicHeaderList& QpackDecodedHeadersAccumulator::quic_header_list() const {
- DCHECK(!error_detected_);
- return quic_header_list_;
-}
-
-QuicStringPiece QpackDecodedHeadersAccumulator::error_message() const {
- DCHECK(error_detected_);
- return error_message_;
}
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator.h
index c64932214dc..0a2db6a348d 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator.h
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator.h
@@ -20,32 +20,30 @@ class QpackDecoder;
// A class that creates and owns a QpackProgressiveDecoder instance, accumulates
// decoded headers in a QuicHeaderList, and keeps track of uncompressed and
-// compressed size so that it can be passed to QuicHeaderList::EndHeaderBlock().
+// compressed size so that it can be passed to
+// QuicHeaderList::OnHeaderBlockEnd().
class QUIC_EXPORT_PRIVATE QpackDecodedHeadersAccumulator
: public QpackProgressiveDecoder::HeadersHandlerInterface {
public:
- // Return value for EndHeaderBlock().
- enum class Status {
- // Headers have been successfully decoded.
- kSuccess,
- // An error has occurred.
- kError,
- // Decoding is blocked.
- kBlocked
- };
-
- // Visitor interface used for blocked decoding. Exactly one visitor method
- // will be called if EndHeaderBlock() returned kBlocked. No visitor method
- // will be called if EndHeaderBlock() returned any other value.
- class Visitor {
+ // Visitor interface to signal success or error.
+ // Exactly one method will be called.
+ // Methods may be called synchronously from Decode() and EndHeaderBlock(),
+ // or asynchronously.
+ // Method implementations are allowed to destroy |this|.
+ class QUIC_EXPORT_PRIVATE Visitor {
public:
virtual ~Visitor() = default;
- // Called when headers are successfully decoded.
+ // Called when headers are successfully decoded. If header list size
+ // exceeds the limit specified via |max_header_list_size| in
+ // QpackDecodedHeadersAccumulator constructor, then |headers| will be empty,
+ // but will still have the correct compressed and uncompressed size
+ // information. However, header_list_size_limit_exceeded() is recommended
+ // instead of headers.empty() to check whether header size exceeds limit.
virtual void OnHeadersDecoded(QuicHeaderList headers) = 0;
// Called when an error has occurred.
- virtual void OnHeaderDecodingError() = 0;
+ virtual void OnHeaderDecodingError(QuicStringPiece error_message) = 0;
};
QpackDecodedHeadersAccumulator(QuicStreamId id,
@@ -60,42 +58,48 @@ class QUIC_EXPORT_PRIVATE QpackDecodedHeadersAccumulator
void OnDecodingCompleted() override;
void OnDecodingErrorDetected(QuicStringPiece error_message) override;
- // Decode payload data. Returns true on success, false on error.
+ // Decode payload data.
// Must not be called if an error has been detected.
// Must not be called after EndHeaderBlock().
- bool Decode(QuicStringPiece data);
+ void Decode(QuicStringPiece data);
// Signal end of HEADERS frame.
// Must not be called if an error has been detected.
// Must not be called more that once.
- // Returns kSuccess if headers can be readily decoded.
- // Returns kError if an error occurred.
- // Returns kBlocked if headers cannot be decoded at the moment, in which case
- // exactly one Visitor method will be called as soon as sufficient data
- // is received on the QPACK decoder stream.
- Status EndHeaderBlock();
-
- // Returns accumulated header list.
- const QuicHeaderList& quic_header_list() const;
-
- // Returns error message.
- // Must not be called unless an error has been detected.
- // TODO(b/124216424): Add accessor for error code, return HTTP_EXCESSIVE_LOAD
- // or HTTP_QPACK_DECOMPRESSION_FAILED.
- QuicStringPiece error_message() const;
+ void EndHeaderBlock();
+
+ // Returns true if the uncompressed size of the header list, including an
+ // overhead for each header field, exceeds |max_header_list_size| passed in
+ // the constructor.
+ bool header_list_size_limit_exceeded() const {
+ return header_list_size_limit_exceeded_;
+ }
private:
std::unique_ptr<QpackProgressiveDecoder> decoder_;
Visitor* visitor_;
+ // Maximum header list size including overhead.
+ size_t max_header_list_size_;
+ // Uncompressed header list size including overhead, for enforcing the limit.
+ size_t uncompressed_header_bytes_including_overhead_;
QuicHeaderList quic_header_list_;
- size_t uncompressed_header_bytes_;
+ // Uncompressed header list size with overhead,
+ // for passing in to QuicHeaderList::OnHeaderBlockEnd().
+ size_t uncompressed_header_bytes_without_overhead_;
+ // Compressed header list size
+ // for passing in to QuicHeaderList::OnHeaderBlockEnd().
size_t compressed_header_bytes_;
- // Set to true when OnDecodingCompleted() is called.
+
+ // True if the header size limit has been exceeded.
+ // Input data is still fed to QpackProgressiveDecoder.
+ bool header_list_size_limit_exceeded_;
+
+ // The following two members are only used for DCHECKs.
+
+ // True if headers have been completedly and successfully decoded.
bool headers_decoded_;
- // Set to true when EndHeaderBlock() returns kBlocked.
- bool blocked_;
+ // True if an error has been detected during decoding.
bool error_detected_;
- std::string error_message_;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator_test.cc
index 1d60660e9c4..6616517330f 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator_test.cc
@@ -7,16 +7,17 @@
#include <cstring>
#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h"
-#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.h"
-#include "net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
+#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_decoder_test_utils.h"
+#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_test_utils.h"
+using ::testing::_;
using ::testing::ElementsAre;
using ::testing::Eq;
using ::testing::Pair;
+using ::testing::SaveArg;
using ::testing::StrictMock;
-using Status = quic::QpackDecodedHeadersAccumulator::Status;
namespace quic {
namespace test {
@@ -37,15 +38,15 @@ const uint64_t kMaximumBlockedStreams = 1;
// Header Acknowledgement decoder stream instruction with stream_id = 1.
const char* const kHeaderAcknowledgement = "\x81";
-} // anonymous namespace
-
-class NoopVisitor : public QpackDecodedHeadersAccumulator::Visitor {
+class MockVisitor : public QpackDecodedHeadersAccumulator::Visitor {
public:
- ~NoopVisitor() override = default;
- void OnHeadersDecoded(QuicHeaderList /* headers */) override {}
- void OnHeaderDecodingError() override {}
+ ~MockVisitor() override = default;
+ MOCK_METHOD1(OnHeadersDecoded, void(QuicHeaderList headers));
+ MOCK_METHOD1(OnHeaderDecodingError, void(QuicStringPiece error_message));
};
+} // anonymous namespace
+
class QpackDecodedHeadersAccumulatorTest : public QuicTest {
protected:
QpackDecodedHeadersAccumulatorTest()
@@ -63,91 +64,143 @@ class QpackDecodedHeadersAccumulatorTest : public QuicTest {
NoopEncoderStreamErrorDelegate encoder_stream_error_delegate_;
StrictMock<MockQpackStreamSenderDelegate> decoder_stream_sender_delegate_;
QpackDecoder qpack_decoder_;
- NoopVisitor visitor_;
+ StrictMock<MockVisitor> visitor_;
QpackDecodedHeadersAccumulator accumulator_;
};
// HEADERS frame payload must have a complete Header Block Prefix.
TEST_F(QpackDecodedHeadersAccumulatorTest, EmptyPayload) {
- EXPECT_EQ(Status::kError, accumulator_.EndHeaderBlock());
- EXPECT_EQ("Incomplete header data prefix.", accumulator_.error_message());
+ EXPECT_CALL(visitor_,
+ OnHeaderDecodingError(Eq("Incomplete header data prefix.")));
+ accumulator_.EndHeaderBlock();
}
// HEADERS frame payload must have a complete Header Block Prefix.
TEST_F(QpackDecodedHeadersAccumulatorTest, TruncatedHeaderBlockPrefix) {
- EXPECT_TRUE(accumulator_.Decode(QuicTextUtils::HexDecode("00")));
- EXPECT_EQ(Status::kError, accumulator_.EndHeaderBlock());
- EXPECT_EQ("Incomplete header data prefix.", accumulator_.error_message());
+ accumulator_.Decode(QuicTextUtils::HexDecode("00"));
+
+ EXPECT_CALL(visitor_,
+ OnHeaderDecodingError(Eq("Incomplete header data prefix.")));
+ accumulator_.EndHeaderBlock();
}
TEST_F(QpackDecodedHeadersAccumulatorTest, EmptyHeaderList) {
- EXPECT_TRUE(accumulator_.Decode(QuicTextUtils::HexDecode("0000")));
- EXPECT_EQ(Status::kSuccess, accumulator_.EndHeaderBlock());
+ std::string encoded_data(QuicTextUtils::HexDecode("0000"));
+ accumulator_.Decode(encoded_data);
- EXPECT_TRUE(accumulator_.quic_header_list().empty());
+ QuicHeaderList header_list;
+ EXPECT_CALL(visitor_, OnHeadersDecoded(_)).WillOnce(SaveArg<0>(&header_list));
+ accumulator_.EndHeaderBlock();
+ EXPECT_FALSE(accumulator_.header_list_size_limit_exceeded());
+
+ EXPECT_EQ(0u, header_list.uncompressed_header_bytes());
+ EXPECT_EQ(encoded_data.size(), header_list.compressed_header_bytes());
+ EXPECT_TRUE(header_list.empty());
}
// This payload is the prefix of a valid payload, but EndHeaderBlock() is called
// before it can be completely decoded.
TEST_F(QpackDecodedHeadersAccumulatorTest, TruncatedPayload) {
- EXPECT_TRUE(accumulator_.Decode(QuicTextUtils::HexDecode("00002366")));
- EXPECT_EQ(Status::kError, accumulator_.EndHeaderBlock());
- EXPECT_EQ("Incomplete header block.", accumulator_.error_message());
+ accumulator_.Decode(QuicTextUtils::HexDecode("00002366"));
+
+ EXPECT_CALL(visitor_, OnHeaderDecodingError(Eq("Incomplete header block.")));
+ accumulator_.EndHeaderBlock();
}
// This payload is invalid because it refers to a non-existing static entry.
TEST_F(QpackDecodedHeadersAccumulatorTest, InvalidPayload) {
- EXPECT_FALSE(accumulator_.Decode(QuicTextUtils::HexDecode("0000ff23ff24")));
- EXPECT_EQ("Static table entry not found.", accumulator_.error_message());
+ EXPECT_CALL(visitor_,
+ OnHeaderDecodingError(Eq("Static table entry not found.")));
+ accumulator_.Decode(QuicTextUtils::HexDecode("0000ff23ff24"));
}
TEST_F(QpackDecodedHeadersAccumulatorTest, Success) {
std::string encoded_data(QuicTextUtils::HexDecode("000023666f6f03626172"));
- EXPECT_TRUE(accumulator_.Decode(encoded_data));
- EXPECT_EQ(Status::kSuccess, accumulator_.EndHeaderBlock());
+ accumulator_.Decode(encoded_data);
- const QuicHeaderList& header_list = accumulator_.quic_header_list();
- EXPECT_THAT(header_list, ElementsAre(Pair("foo", "bar")));
+ QuicHeaderList header_list;
+ EXPECT_CALL(visitor_, OnHeadersDecoded(_)).WillOnce(SaveArg<0>(&header_list));
+ accumulator_.EndHeaderBlock();
+ EXPECT_FALSE(accumulator_.header_list_size_limit_exceeded());
+ EXPECT_THAT(header_list, ElementsAre(Pair("foo", "bar")));
EXPECT_EQ(strlen("foo") + strlen("bar"),
header_list.uncompressed_header_bytes());
EXPECT_EQ(encoded_data.size(), header_list.compressed_header_bytes());
}
-TEST_F(QpackDecodedHeadersAccumulatorTest, ExceedingLimit) {
+// Test that Decode() calls are not ignored after header list limit is exceeded,
+// otherwise decoding could fail with "incomplete header block" error.
+TEST_F(QpackDecodedHeadersAccumulatorTest, ExceedLimitThenSplitInstruction) {
// Total length of header list exceeds kMaxHeaderListSize.
- EXPECT_TRUE(accumulator_.Decode(QuicTextUtils::HexDecode(
+ accumulator_.Decode(QuicTextUtils::HexDecode(
"0000" // header block prefix
"26666f6f626172" // header key: "foobar"
"7d61616161616161616161616161616161616161" // header value: 'a' 125 times
"616161616161616161616161616161616161616161616161616161616161616161616161"
"616161616161616161616161616161616161616161616161616161616161616161616161"
- "61616161616161616161616161616161616161616161616161616161616161616161")));
- EXPECT_EQ(Status::kSuccess, accumulator_.EndHeaderBlock());
+ "61616161616161616161616161616161616161616161616161616161616161616161"
+ "ff")); // first byte of a two-byte long Indexed Header Field instruction
+ accumulator_.Decode(QuicTextUtils::HexDecode(
+ "0f" // second byte of a two-byte long Indexed Header Field instruction
+ ));
+
+ EXPECT_CALL(visitor_, OnHeadersDecoded(_));
+ accumulator_.EndHeaderBlock();
+ EXPECT_TRUE(accumulator_.header_list_size_limit_exceeded());
+}
- // QuicHeaderList signals header list over limit by clearing it.
- EXPECT_TRUE(accumulator_.quic_header_list().empty());
+// Test that header list limit enforcement works with blocked encoding.
+TEST_F(QpackDecodedHeadersAccumulatorTest, ExceedLimitBlocked) {
+ // Total length of header list exceeds kMaxHeaderListSize.
+ accumulator_.Decode(QuicTextUtils::HexDecode(
+ "0200" // header block prefix
+ "80" // reference to dynamic table entry not yet received
+ "26666f6f626172" // header key: "foobar"
+ "7d61616161616161616161616161616161616161" // header value: 'a' 125 times
+ "616161616161616161616161616161616161616161616161616161616161616161616161"
+ "616161616161616161616161616161616161616161616161616161616161616161616161"
+ "61616161616161616161616161616161616161616161616161616161616161616161"));
+ accumulator_.EndHeaderBlock();
+
+ // Set dynamic table capacity.
+ qpack_decoder_.OnSetDynamicTableCapacity(kMaxDynamicTableCapacity);
+ // Adding dynamic table entry unblocks decoding.
+ EXPECT_CALL(decoder_stream_sender_delegate_,
+ WriteStreamData(Eq(kHeaderAcknowledgement)));
+
+ EXPECT_CALL(visitor_, OnHeadersDecoded(_));
+ qpack_decoder_.OnInsertWithoutNameReference("foo", "bar");
+ EXPECT_TRUE(accumulator_.header_list_size_limit_exceeded());
}
TEST_F(QpackDecodedHeadersAccumulatorTest, BlockedDecoding) {
// Reference to dynamic table entry not yet received.
- EXPECT_TRUE(accumulator_.Decode(QuicTextUtils::HexDecode("020080")));
- EXPECT_EQ(Status::kBlocked, accumulator_.EndHeaderBlock());
+ std::string encoded_data(QuicTextUtils::HexDecode("020080"));
+ accumulator_.Decode(encoded_data);
+ accumulator_.EndHeaderBlock();
// Set dynamic table capacity.
qpack_decoder_.OnSetDynamicTableCapacity(kMaxDynamicTableCapacity);
// Adding dynamic table entry unblocks decoding.
EXPECT_CALL(decoder_stream_sender_delegate_,
WriteStreamData(Eq(kHeaderAcknowledgement)));
+
+ QuicHeaderList header_list;
+ EXPECT_CALL(visitor_, OnHeadersDecoded(_)).WillOnce(SaveArg<0>(&header_list));
qpack_decoder_.OnInsertWithoutNameReference("foo", "bar");
- EXPECT_THAT(accumulator_.quic_header_list(), ElementsAre(Pair("foo", "bar")));
+ EXPECT_FALSE(accumulator_.header_list_size_limit_exceeded());
+ EXPECT_THAT(header_list, ElementsAre(Pair("foo", "bar")));
+ EXPECT_EQ(strlen("foo") + strlen("bar"),
+ header_list.uncompressed_header_bytes());
+ EXPECT_EQ(encoded_data.size(), header_list.compressed_header_bytes());
}
TEST_F(QpackDecodedHeadersAccumulatorTest,
BlockedDecodingUnblockedBeforeEndOfHeaderBlock) {
// Reference to dynamic table entry not yet received.
- EXPECT_TRUE(accumulator_.Decode(QuicTextUtils::HexDecode("020080")));
+ accumulator_.Decode(QuicTextUtils::HexDecode("020080"));
// Set dynamic table capacity.
qpack_decoder_.OnSetDynamicTableCapacity(kMaxDynamicTableCapacity);
@@ -157,11 +210,34 @@ TEST_F(QpackDecodedHeadersAccumulatorTest,
// Rest of header block: same entry again.
EXPECT_CALL(decoder_stream_sender_delegate_,
WriteStreamData(Eq(kHeaderAcknowledgement)));
- EXPECT_TRUE(accumulator_.Decode(QuicTextUtils::HexDecode("80")));
- EXPECT_EQ(Status::kSuccess, accumulator_.EndHeaderBlock());
+ accumulator_.Decode(QuicTextUtils::HexDecode("80"));
- EXPECT_THAT(accumulator_.quic_header_list(),
- ElementsAre(Pair("foo", "bar"), Pair("foo", "bar")));
+ QuicHeaderList header_list;
+ EXPECT_CALL(visitor_, OnHeadersDecoded(_)).WillOnce(SaveArg<0>(&header_list));
+ accumulator_.EndHeaderBlock();
+ EXPECT_FALSE(accumulator_.header_list_size_limit_exceeded());
+
+ EXPECT_THAT(header_list, ElementsAre(Pair("foo", "bar"), Pair("foo", "bar")));
+}
+
+// Regression test for https://crbug.com/1024263.
+TEST_F(QpackDecodedHeadersAccumulatorTest,
+ BlockedDecodingUnblockedAndErrorBeforeEndOfHeaderBlock) {
+ // Required Insert Count higher than number of entries causes decoding to be
+ // blocked.
+ accumulator_.Decode(QuicTextUtils::HexDecode("0200"));
+ // Indexed Header Field instruction addressing dynamic table entry with
+ // relative index 0, absolute index 0.
+ accumulator_.Decode(QuicTextUtils::HexDecode("80"));
+ // Relative index larger than or equal to Base is invalid.
+ accumulator_.Decode(QuicTextUtils::HexDecode("81"));
+
+ // Set dynamic table capacity.
+ qpack_decoder_.OnSetDynamicTableCapacity(kMaxDynamicTableCapacity);
+
+ // Adding dynamic table entry unblocks decoding. Error is detected.
+ EXPECT_CALL(visitor_, OnHeaderDecodingError(Eq("Invalid relative index.")));
+ qpack_decoder_.OnInsertWithoutNameReference("foo", "bar");
}
} // namespace test
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder.cc
index 4f39e3b39b2..3ae6bce6e6b 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder.cc
@@ -27,10 +27,10 @@ QpackDecoder::QpackDecoder(
QpackDecoder::~QpackDecoder() {}
void QpackDecoder::OnStreamReset(QuicStreamId stream_id) {
- // TODO(bnc): SendStreamCancellation should not be called if maximum dynamic
- // table capacity is zero.
- decoder_stream_sender_.SendStreamCancellation(stream_id);
- decoder_stream_sender_.Flush();
+ if (header_table_.maximum_dynamic_table_capacity() > 0) {
+ decoder_stream_sender_.SendStreamCancellation(stream_id);
+ decoder_stream_sender_.Flush();
+ }
}
bool QpackDecoder::OnStreamBlocked(QuicStreamId stream_id) {
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h
index 113c6ea8e4a..4ac1e449bc6 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h
@@ -95,6 +95,11 @@ class QUIC_EXPORT_PRIVATE QpackDecoder
return &encoder_stream_receiver_;
}
+ // True if any dynamic table entries have been referenced from a header block.
+ bool dynamic_table_entry_referenced() const {
+ return header_table_.dynamic_table_entry_referenced();
+ }
+
private:
EncoderStreamErrorDelegate* const encoder_stream_error_delegate_;
QpackEncoderStreamReceiver encoder_stream_receiver_;
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_receiver.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_receiver.cc
index 559ce433376..2ba89d48a82 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_receiver.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_receiver.cc
@@ -6,7 +6,7 @@
#include "net/third_party/quiche/src/http2/decoder/decode_buffer.h"
#include "net/third_party/quiche/src/http2/decoder/decode_status.h"
-#include "net/third_party/quiche/src/quic/core/qpack/qpack_constants.h"
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_instructions.h"
namespace quic {
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_receiver.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_receiver.h
index 60719399d8b..396c6df8779 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_receiver.h
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_receiver.h
@@ -23,7 +23,7 @@ class QUIC_EXPORT_PRIVATE QpackDecoderStreamReceiver
public:
// An interface for handling instructions decoded from the decoder stream, see
// https://quicwg.org/base-drafts/draft-ietf-quic-qpack.html#rfc.section.5.3
- class Delegate {
+ class QUIC_EXPORT_PRIVATE Delegate {
public:
virtual ~Delegate() = default;
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender.cc
index 68e4d67816c..72a446b420a 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender.cc
@@ -8,7 +8,7 @@
#include <limits>
#include <string>
-#include "net/third_party/quiche/src/quic/core/qpack/qpack_constants.h"
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_instructions.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
namespace quic {
@@ -16,25 +16,19 @@ namespace quic {
QpackDecoderStreamSender::QpackDecoderStreamSender() : delegate_(nullptr) {}
void QpackDecoderStreamSender::SendInsertCountIncrement(uint64_t increment) {
- values_.varint = increment;
-
- instruction_encoder_.Encode(InsertCountIncrementInstruction(), values_,
- &buffer_);
+ instruction_encoder_.Encode(
+ QpackInstructionWithValues::InsertCountIncrement(increment), &buffer_);
}
void QpackDecoderStreamSender::SendHeaderAcknowledgement(
QuicStreamId stream_id) {
- values_.varint = stream_id;
-
- instruction_encoder_.Encode(HeaderAcknowledgementInstruction(), values_,
- &buffer_);
+ instruction_encoder_.Encode(
+ QpackInstructionWithValues::HeaderAcknowledgement(stream_id), &buffer_);
}
void QpackDecoderStreamSender::SendStreamCancellation(QuicStreamId stream_id) {
- values_.varint = stream_id;
-
- instruction_encoder_.Encode(StreamCancellationInstruction(), values_,
- &buffer_);
+ instruction_encoder_.Encode(
+ QpackInstructionWithValues::StreamCancellation(stream_id), &buffer_);
}
void QpackDecoderStreamSender::Flush() {
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender.h
index 93d95d91476..d9033b04dee 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender.h
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender.h
@@ -44,7 +44,6 @@ class QUIC_EXPORT_PRIVATE QpackDecoderStreamSender {
private:
QpackStreamSenderDelegate* delegate_;
QpackInstructionEncoder instruction_encoder_;
- QpackInstructionEncoder::Values values_;
std::string buffer_;
};
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender_test.cc
index 6e042590833..e3dc12497e3 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender_test.cc
@@ -4,9 +4,9 @@
#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender.h"
-#include "net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
+#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_test_utils.h"
using ::testing::Eq;
using ::testing::StrictMock;
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test.cc
index d0ff30ff679..1fc5802d83c 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test.cc
@@ -6,14 +6,16 @@
#include <algorithm>
-#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.h"
-#include "net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
+#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_decoder_test_utils.h"
+#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_test_utils.h"
#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h"
+using ::testing::_;
using ::testing::Eq;
+using ::testing::Invoke;
using ::testing::Mock;
using ::testing::Sequence;
using ::testing::StrictMock;
@@ -42,6 +44,15 @@ class QpackDecoderTest : public QuicTestWithParam<FragmentMode> {
~QpackDecoderTest() override = default;
+ void SetUp() override {
+ // Destroy QpackProgressiveDecoder on error to test that it does not crash.
+ // See https://crbug.com/1025209.
+ ON_CALL(handler_, OnDecodingErrorDetected(_))
+ .WillByDefault(Invoke([this](QuicStringPiece /* error_message */) {
+ progressive_decoder_.reset();
+ }));
+ }
+
void DecodeEncoderStreamData(QuicStringPiece data) {
qpack_decoder_.encoder_stream_receiver()->Decode(data);
}
@@ -61,7 +72,7 @@ class QpackDecoderTest : public QuicTestWithParam<FragmentMode> {
void DecodeData(QuicStringPiece data) {
auto fragment_size_generator =
FragmentModeToFragmentSizeGenerator(fragment_mode_);
- while (!data.empty()) {
+ while (progressive_decoder_ && !data.empty()) {
size_t fragment_size = std::min(fragment_size_generator(), data.size());
progressive_decoder_->Decode(data.substr(0, fragment_size));
data = data.substr(fragment_size);
@@ -70,9 +81,11 @@ class QpackDecoderTest : public QuicTestWithParam<FragmentMode> {
// Signal end of header block to QpackProgressiveDecoder.
void EndDecoding() {
- progressive_decoder_->EndHeaderBlock();
- // |progressive_decoder_| is kept alive so that it can
- // handle callbacks later in case of blocked decoding.
+ if (progressive_decoder_) {
+ progressive_decoder_->EndHeaderBlock();
+ }
+ // If no error was detected, |*progressive_decoder_| is kept alive so that
+ // it can handle callbacks later in case of blocked decoding.
}
// Decode an entire header block.
@@ -105,6 +118,18 @@ TEST_P(QpackDecoderTest, NoPrefix) {
DecodeHeaderBlock(QuicTextUtils::HexDecode("00"));
}
+// Regression test for https://1025209: QpackProgressiveDecoder must not crash
+// in Decode() if it is destroyed by handler_.OnDecodingErrorDetected().
+TEST_P(QpackDecoderTest, InvalidPrefix) {
+ StartDecoding();
+
+ EXPECT_CALL(handler_,
+ OnDecodingErrorDetected(Eq("Encoded integer too large.")));
+
+ // Encoded Required Insert Count in Header Data Prefix is too large.
+ DecodeData(QuicTextUtils::HexDecode("ffffffffffffffffffffffffffff"));
+}
+
TEST_P(QpackDecoderTest, EmptyHeaderBlock) {
EXPECT_CALL(handler_, OnDecodingCompleted());
@@ -780,16 +805,15 @@ TEST_P(QpackDecoderTest, BlockedDecodingUnblockedBeforeEndOfHeaderBlock) {
// entry with relative index 0, absolute index 0.
"d1")); // Static table entry with index 17.
+ // Set dynamic table capacity to 1024.
+ DecodeEncoderStreamData(QuicTextUtils::HexDecode("3fe107"));
+
// Add literal entry with name "foo" and value "bar". Decoding is now
// unblocked because dynamic table Insert Count reached the Required Insert
// Count of the header block. |handler_| methods are called immediately for
// the already consumed part of the header block.
EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("bar")));
EXPECT_CALL(handler_, OnHeaderDecoded(Eq(":method"), Eq("GET")));
-
- // Set dynamic table capacity to 1024.
- DecodeEncoderStreamData(QuicTextUtils::HexDecode("3fe107"));
- // Add literal entry with name "foo" and value "bar".
DecodeEncoderStreamData(QuicTextUtils::HexDecode("6294e703626172"));
Mock::VerifyAndClearExpectations(&handler_);
@@ -809,6 +833,29 @@ TEST_P(QpackDecoderTest, BlockedDecodingUnblockedBeforeEndOfHeaderBlock) {
EndDecoding();
}
+// Regression test for https://crbug.com/1024263.
+TEST_P(QpackDecoderTest,
+ BlockedDecodingUnblockedAndErrorBeforeEndOfHeaderBlock) {
+ StartDecoding();
+ DecodeData(QuicTextUtils::HexDecode(
+ "0200" // Required Insert Count 1 and Delta Base 0.
+ // Base is 1 + 0 = 1.
+ "80" // Indexed Header Field instruction addressing dynamic table
+ // entry with relative index 0, absolute index 0.
+ "81")); // Relative index 1 is equal to Base, therefore invalid.
+
+ // Set dynamic table capacity to 1024.
+ DecodeEncoderStreamData(QuicTextUtils::HexDecode("3fe107"));
+
+ // Add literal entry with name "foo" and value "bar". Decoding is now
+ // unblocked because dynamic table Insert Count reached the Required Insert
+ // Count of the header block. |handler_| methods are called immediately for
+ // the already consumed part of the header block.
+ EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("bar")));
+ EXPECT_CALL(handler_, OnDecodingErrorDetected(Eq("Invalid relative index.")));
+ DecodeEncoderStreamData(QuicTextUtils::HexDecode("6294e703626172"));
+}
+
// Make sure that Required Insert Count is compared to Insert Count,
// not size of dynamic table.
TEST_P(QpackDecoderTest, BlockedDecodingAndEvictedEntries) {
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.cc
deleted file mode 100644
index eaf66648cb0..00000000000
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.cc
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright (c) 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/quiche/src/quic/core/qpack/qpack_decoder_test_utils.h"
-
-#include <algorithm>
-#include <cstddef>
-#include <utility>
-
-#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
-
-namespace quic {
-namespace test {
-
-void NoopEncoderStreamErrorDelegate::OnEncoderStreamError(
- QuicStringPiece /*error_message*/) {}
-
-TestHeadersHandler::TestHeadersHandler()
- : decoding_completed_(false), decoding_error_detected_(false) {}
-
-void TestHeadersHandler::OnHeaderDecoded(QuicStringPiece name,
- QuicStringPiece value) {
- ASSERT_FALSE(decoding_completed_);
- ASSERT_FALSE(decoding_error_detected_);
-
- header_list_.AppendValueOrAddHeader(name, value);
-}
-
-void TestHeadersHandler::OnDecodingCompleted() {
- ASSERT_FALSE(decoding_completed_);
- ASSERT_FALSE(decoding_error_detected_);
-
- decoding_completed_ = true;
-}
-
-void TestHeadersHandler::OnDecodingErrorDetected(
- QuicStringPiece error_message) {
- ASSERT_FALSE(decoding_completed_);
- ASSERT_FALSE(decoding_error_detected_);
-
- decoding_error_detected_ = true;
- error_message_.assign(error_message.data(), error_message.size());
-}
-
-spdy::SpdyHeaderBlock TestHeadersHandler::ReleaseHeaderList() {
- DCHECK(decoding_completed_);
- DCHECK(!decoding_error_detected_);
-
- return std::move(header_list_);
-}
-
-bool TestHeadersHandler::decoding_completed() const {
- return decoding_completed_;
-}
-
-bool TestHeadersHandler::decoding_error_detected() const {
- return decoding_error_detected_;
-}
-
-const std::string& TestHeadersHandler::error_message() const {
- DCHECK(decoding_error_detected_);
- return error_message_;
-}
-
-void QpackDecode(
- uint64_t maximum_dynamic_table_capacity,
- uint64_t maximum_blocked_streams,
- QpackDecoder::EncoderStreamErrorDelegate* encoder_stream_error_delegate,
- QpackStreamSenderDelegate* decoder_stream_sender_delegate,
- QpackProgressiveDecoder::HeadersHandlerInterface* handler,
- const FragmentSizeGenerator& fragment_size_generator,
- QuicStringPiece data) {
- QpackDecoder decoder(maximum_dynamic_table_capacity, maximum_blocked_streams,
- encoder_stream_error_delegate);
- decoder.set_qpack_stream_sender_delegate(decoder_stream_sender_delegate);
- auto progressive_decoder =
- decoder.CreateProgressiveDecoder(/* stream_id = */ 1, handler);
- while (!data.empty()) {
- size_t fragment_size = std::min(fragment_size_generator(), data.size());
- progressive_decoder->Decode(data.substr(0, fragment_size));
- data = data.substr(fragment_size);
- }
- progressive_decoder->EndHeaderBlock();
-}
-
-} // namespace test
-} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.h
deleted file mode 100644
index 6505b60a1fe..00000000000
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.h
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright (c) 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 QUICHE_QUIC_CORE_QPACK_QPACK_DECODER_TEST_UTILS_H_
-#define QUICHE_QUIC_CORE_QPACK_QPACK_DECODER_TEST_UTILS_H_
-
-#include <string>
-
-#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h"
-#include "net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.h"
-#include "net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
-#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h"
-
-namespace quic {
-namespace test {
-
-// QpackDecoder::EncoderStreamErrorDelegate implementation that does nothing.
-class NoopEncoderStreamErrorDelegate
- : public QpackDecoder::EncoderStreamErrorDelegate {
- public:
- ~NoopEncoderStreamErrorDelegate() override = default;
-
- void OnEncoderStreamError(QuicStringPiece error_message) override;
-};
-
-// Mock QpackDecoder::EncoderStreamErrorDelegate implementation.
-class MockEncoderStreamErrorDelegate
- : public QpackDecoder::EncoderStreamErrorDelegate {
- public:
- ~MockEncoderStreamErrorDelegate() override = default;
-
- MOCK_METHOD1(OnEncoderStreamError, void(QuicStringPiece error_message));
-};
-
-// HeadersHandlerInterface implementation that collects decoded headers
-// into a SpdyHeaderBlock.
-class TestHeadersHandler
- : public QpackProgressiveDecoder::HeadersHandlerInterface {
- public:
- TestHeadersHandler();
- ~TestHeadersHandler() override = default;
-
- // HeadersHandlerInterface implementation:
- void OnHeaderDecoded(QuicStringPiece name, QuicStringPiece value) override;
- void OnDecodingCompleted() override;
- void OnDecodingErrorDetected(QuicStringPiece error_message) override;
-
- // Release decoded header list. Must only be called if decoding is complete
- // and no errors have been detected.
- spdy::SpdyHeaderBlock ReleaseHeaderList();
-
- bool decoding_completed() const;
- bool decoding_error_detected() const;
- const std::string& error_message() const;
-
- private:
- spdy::SpdyHeaderBlock header_list_;
- bool decoding_completed_;
- bool decoding_error_detected_;
- std::string error_message_;
-};
-
-class MockHeadersHandler
- : public QpackProgressiveDecoder::HeadersHandlerInterface {
- public:
- MockHeadersHandler() = default;
- MockHeadersHandler(const MockHeadersHandler&) = delete;
- MockHeadersHandler& operator=(const MockHeadersHandler&) = delete;
- ~MockHeadersHandler() override = default;
-
- MOCK_METHOD2(OnHeaderDecoded,
- void(QuicStringPiece name, QuicStringPiece value));
- MOCK_METHOD0(OnDecodingCompleted, void());
- MOCK_METHOD1(OnDecodingErrorDetected, void(QuicStringPiece error_message));
-};
-
-class NoOpHeadersHandler
- : public QpackProgressiveDecoder::HeadersHandlerInterface {
- public:
- ~NoOpHeadersHandler() override = default;
-
- void OnHeaderDecoded(QuicStringPiece /*name*/,
- QuicStringPiece /*value*/) override {}
- void OnDecodingCompleted() override {}
- void OnDecodingErrorDetected(QuicStringPiece /*error_message*/) override {}
-};
-
-void QpackDecode(
- uint64_t maximum_dynamic_table_capacity,
- uint64_t maximum_blocked_streams,
- QpackDecoder::EncoderStreamErrorDelegate* encoder_stream_error_delegate,
- QpackStreamSenderDelegate* decoder_stream_sender_delegate,
- QpackProgressiveDecoder::HeadersHandlerInterface* handler,
- const FragmentSizeGenerator& fragment_size_generator,
- QuicStringPiece data);
-
-} // namespace test
-} // namespace quic
-
-#endif // QUICHE_QUIC_CORE_QPACK_QPACK_DECODER_TEST_UTILS_H_
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.cc
index 319af82115a..59e172ec75a 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.cc
@@ -7,7 +7,6 @@
#include <algorithm>
#include <utility>
-#include "net/third_party/quiche/src/quic/core/qpack/qpack_constants.h"
#include "net/third_party/quiche/src/quic/core/qpack/qpack_index_conversions.h"
#include "net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder.h"
#include "net/third_party/quiche/src/quic/core/qpack/qpack_required_insert_count.h"
@@ -42,47 +41,37 @@ QpackEncoder::QpackEncoder(
QpackEncoder::~QpackEncoder() {}
// static
-QpackEncoder::InstructionWithValues QpackEncoder::EncodeIndexedHeaderField(
+QpackInstructionWithValues QpackEncoder::EncodeIndexedHeaderField(
bool is_static,
uint64_t index,
QpackBlockingManager::IndexSet* referred_indices) {
- InstructionWithValues instruction{QpackIndexedHeaderFieldInstruction(), {}};
- instruction.values.s_bit = is_static;
- instruction.values.varint = index;
// Add |index| to |*referred_indices| only if entry is in the dynamic table.
if (!is_static) {
referred_indices->insert(index);
}
- return instruction;
+ return QpackInstructionWithValues::IndexedHeaderField(is_static, index);
}
// static
-QpackEncoder::InstructionWithValues
+QpackInstructionWithValues
QpackEncoder::EncodeLiteralHeaderFieldWithNameReference(
bool is_static,
uint64_t index,
QuicStringPiece value,
QpackBlockingManager::IndexSet* referred_indices) {
- InstructionWithValues instruction{
- QpackLiteralHeaderFieldNameReferenceInstruction(), {}};
- instruction.values.s_bit = is_static;
- instruction.values.varint = index;
- instruction.values.value = value;
// Add |index| to |*referred_indices| only if entry is in the dynamic table.
if (!is_static) {
referred_indices->insert(index);
}
- return instruction;
+ return QpackInstructionWithValues::LiteralHeaderFieldNameReference(
+ is_static, index, value);
}
// static
-QpackEncoder::InstructionWithValues QpackEncoder::EncodeLiteralHeaderField(
+QpackInstructionWithValues QpackEncoder::EncodeLiteralHeaderField(
QuicStringPiece name,
QuicStringPiece value) {
- InstructionWithValues instruction{QpackLiteralHeaderFieldInstruction(), {}};
- instruction.values.name = name;
- instruction.values.value = value;
- return instruction;
+ return QpackInstructionWithValues::LiteralHeaderField(name, value);
}
QpackEncoder::Instructions QpackEncoder::FirstPassEncode(
@@ -142,6 +131,7 @@ QpackEncoder::Instructions QpackEncoder::FirstPassEncode(
instructions.push_back(
EncodeIndexedHeaderField(is_static, index, referred_indices));
smallest_blocking_index = std::min(smallest_blocking_index, index);
+ header_table_.set_dynamic_table_entry_referenced();
break;
}
@@ -159,11 +149,10 @@ QpackEncoder::Instructions QpackEncoder::FirstPassEncode(
QpackAbsoluteIndexToEncoderStreamRelativeIndex(
index, header_table_.inserted_entry_count()));
auto entry = header_table_.InsertEntry(name, value);
- blocking_manager_.OnReferenceSentOnEncoderStream(
- entry->InsertionIndex(), index);
instructions.push_back(EncodeIndexedHeaderField(
is_static, entry->InsertionIndex(), referred_indices));
smallest_blocking_index = std::min(smallest_blocking_index, index);
+ header_table_.set_dynamic_table_entry_referenced();
break;
}
@@ -218,11 +207,10 @@ QpackEncoder::Instructions QpackEncoder::FirstPassEncode(
index, header_table_.inserted_entry_count()),
value);
auto entry = header_table_.InsertEntry(name, value);
- blocking_manager_.OnReferenceSentOnEncoderStream(
- entry->InsertionIndex(), index);
instructions.push_back(EncodeIndexedHeaderField(
is_static, entry->InsertionIndex(), referred_indices));
smallest_blocking_index = std::min(smallest_blocking_index, index);
+ header_table_.set_dynamic_table_entry_referenced();
break;
}
@@ -233,6 +221,7 @@ QpackEncoder::Instructions QpackEncoder::FirstPassEncode(
instructions.push_back(EncodeLiteralHeaderFieldWithNameReference(
is_static, index, value, referred_indices));
smallest_blocking_index = std::min(smallest_blocking_index, index);
+ header_table_.set_dynamic_table_entry_referenced();
break;
}
@@ -329,29 +318,24 @@ std::string QpackEncoder::SecondPassEncode(
std::string encoded_headers;
// Header block prefix.
- QpackInstructionEncoder::Values values;
- values.varint = QpackEncodeRequiredInsertCount(required_insert_count,
- header_table_.max_entries());
- values.varint2 = 0; // Delta Base.
- values.s_bit = false; // Delta Base sign.
- const uint64_t base = required_insert_count;
+ instruction_encoder.Encode(
+ QpackInstructionWithValues::Prefix(QpackEncodeRequiredInsertCount(
+ required_insert_count, header_table_.max_entries())),
+ &encoded_headers);
- instruction_encoder.Encode(QpackPrefixInstruction(), values,
- &encoded_headers);
+ const uint64_t base = required_insert_count;
for (auto& instruction : instructions) {
// Dynamic table references must be transformed from absolute to relative
// indices.
- if ((instruction.instruction == QpackIndexedHeaderFieldInstruction() ||
- instruction.instruction ==
+ if ((instruction.instruction() == QpackIndexedHeaderFieldInstruction() ||
+ instruction.instruction() ==
QpackLiteralHeaderFieldNameReferenceInstruction()) &&
- !instruction.values.s_bit) {
- instruction.values.varint =
- QpackAbsoluteIndexToRequestStreamRelativeIndex(
- instruction.values.varint, base);
+ !instruction.s_bit()) {
+ instruction.set_varint(QpackAbsoluteIndexToRequestStreamRelativeIndex(
+ instruction.varint(), base));
}
- instruction_encoder.Encode(instruction.instruction, instruction.values,
- &encoded_headers);
+ instruction_encoder.Encode(instruction, &encoded_headers);
}
return encoded_headers;
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h
index 1ed56a82e11..e635e3bf04b 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h
@@ -14,6 +14,7 @@
#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_receiver.h"
#include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.h"
#include "net/third_party/quiche/src/quic/core/qpack/qpack_header_table.h"
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_instructions.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_exported_stats.h"
@@ -87,39 +88,35 @@ class QUIC_EXPORT_PRIVATE QpackEncoder
return &decoder_stream_receiver_;
}
+ // True if any dynamic table entries have been referenced from a header block.
+ bool dynamic_table_entry_referenced() const {
+ return header_table_.dynamic_table_entry_referenced();
+ }
+
private:
friend class test::QpackEncoderPeer;
- // TODO(bnc): Consider moving this class to QpackInstructionEncoder or
- // qpack_constants, adding factory methods, one for each instruction, and
- // changing QpackInstructionEncoder::Encoder() to take an
- // InstructionWithValues struct instead of separate |instruction| and |values|
- // arguments.
- struct InstructionWithValues {
- // |instruction| is not owned.
- const QpackInstruction* instruction;
- QpackInstructionEncoder::Values values;
- };
- using Instructions = std::vector<InstructionWithValues>;
+ using Instructions = std::vector<QpackInstructionWithValues>;
// Generate indexed header field instruction
// and optionally update |*referred_indices|.
- static InstructionWithValues EncodeIndexedHeaderField(
+ static QpackInstructionWithValues EncodeIndexedHeaderField(
bool is_static,
uint64_t index,
QpackBlockingManager::IndexSet* referred_indices);
// Generate literal header field with name reference instruction
// and optionally update |*referred_indices|.
- static InstructionWithValues EncodeLiteralHeaderFieldWithNameReference(
+ static QpackInstructionWithValues EncodeLiteralHeaderFieldWithNameReference(
bool is_static,
uint64_t index,
QuicStringPiece value,
QpackBlockingManager::IndexSet* referred_indices);
// Generate literal header field instruction.
- static InstructionWithValues EncodeLiteralHeaderField(QuicStringPiece name,
- QuicStringPiece value);
+ static QpackInstructionWithValues EncodeLiteralHeaderField(
+ QuicStringPiece name,
+ QuicStringPiece value);
// Performs first pass of two-pass encoding: represent each header field in
// |*header_list| as a reference to an existing entry, the name of an existing
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_receiver.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_receiver.cc
index 3f8ef08a7ee..c46cc3c0f41 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_receiver.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_receiver.cc
@@ -6,7 +6,7 @@
#include "net/third_party/quiche/src/http2/decoder/decode_buffer.h"
#include "net/third_party/quiche/src/http2/decoder/decode_status.h"
-#include "net/third_party/quiche/src/quic/core/qpack/qpack_constants.h"
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_instructions.h"
namespace quic {
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_receiver.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_receiver.h
index 8da3147d1ea..b393b546b60 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_receiver.h
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_receiver.h
@@ -22,7 +22,7 @@ class QUIC_EXPORT_PRIVATE QpackEncoderStreamReceiver
public:
// An interface for handling instructions decoded from the encoder stream, see
// https://quicwg.org/base-drafts/draft-ietf-quic-qpack.html#rfc.section.5.2
- class Delegate {
+ class QUIC_EXPORT_PRIVATE Delegate {
public:
virtual ~Delegate() = default;
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.cc
index 4a7f12cd3a3..5182864ce6d 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.cc
@@ -8,7 +8,7 @@
#include <limits>
#include <string>
-#include "net/third_party/quiche/src/quic/core/qpack/qpack_constants.h"
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_instructions.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
namespace quic {
@@ -19,35 +19,28 @@ void QpackEncoderStreamSender::SendInsertWithNameReference(
bool is_static,
uint64_t name_index,
QuicStringPiece value) {
- values_.s_bit = is_static;
- values_.varint = name_index;
- values_.value = value;
-
- instruction_encoder_.Encode(InsertWithNameReferenceInstruction(), values_,
- &buffer_);
+ instruction_encoder_.Encode(
+ QpackInstructionWithValues::InsertWithNameReference(is_static, name_index,
+ value),
+ &buffer_);
}
void QpackEncoderStreamSender::SendInsertWithoutNameReference(
QuicStringPiece name,
QuicStringPiece value) {
- values_.name = name;
- values_.value = value;
-
- instruction_encoder_.Encode(InsertWithoutNameReferenceInstruction(), values_,
- &buffer_);
+ instruction_encoder_.Encode(
+ QpackInstructionWithValues::InsertWithoutNameReference(name, value),
+ &buffer_);
}
void QpackEncoderStreamSender::SendDuplicate(uint64_t index) {
- values_.varint = index;
-
- instruction_encoder_.Encode(DuplicateInstruction(), values_, &buffer_);
+ instruction_encoder_.Encode(QpackInstructionWithValues::Duplicate(index),
+ &buffer_);
}
void QpackEncoderStreamSender::SendSetDynamicTableCapacity(uint64_t capacity) {
- values_.varint = capacity;
-
- instruction_encoder_.Encode(SetDynamicTableCapacityInstruction(), values_,
- &buffer_);
+ instruction_encoder_.Encode(
+ QpackInstructionWithValues::SetDynamicTableCapacity(capacity), &buffer_);
}
QuicByteCount QpackEncoderStreamSender::Flush() {
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.h
index efbfbc632d5..de9e8f14839 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.h
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.h
@@ -50,7 +50,6 @@ class QUIC_EXPORT_PRIVATE QpackEncoderStreamSender {
private:
QpackStreamSenderDelegate* delegate_;
QpackInstructionEncoder instruction_encoder_;
- QpackInstructionEncoder::Values values_;
std::string buffer_;
};
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender_test.cc
index 80a6ed3c06f..0a42df220cb 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender_test.cc
@@ -4,9 +4,9 @@
#include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.h"
-#include "net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
+#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_test_utils.h"
using ::testing::Eq;
using ::testing::StrictMock;
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test.cc
index 6f2efe3aecc..6b92e4bfc95 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test.cc
@@ -7,13 +7,12 @@
#include <limits>
#include <string>
-#include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test_utils.h"
-#include "net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.h"
-#include "net/third_party/quiche/src/quic/core/qpack/qpack_utils.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
-#include "net/third_party/quiche/src/quic/test_tools/qpack_encoder_peer.h"
-#include "net/third_party/quiche/src/quic/test_tools/qpack_header_table_peer.h"
+#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_encoder_peer.h"
+#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_encoder_test_utils.h"
+#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_header_table_peer.h"
+#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_test_utils.h"
using ::testing::_;
using ::testing::Eq;
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test_utils.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test_utils.cc
deleted file mode 100644
index d91d3d13d5e..00000000000
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test_utils.cc
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright (c) 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/quiche/src/quic/core/qpack/qpack_encoder_test_utils.h"
-
-#include "net/third_party/quiche/src/spdy/core/hpack/hpack_encoder.h"
-
-namespace quic {
-namespace test {
-
-void NoopDecoderStreamErrorDelegate::OnDecoderStreamError(
- QuicStringPiece /*error_message*/) {}
-
-} // namespace test
-} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test_utils.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test_utils.h
deleted file mode 100644
index b1103dae6c3..00000000000
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test_utils.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright (c) 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 QUICHE_QUIC_CORE_QPACK_QPACK_ENCODER_TEST_UTILS_H_
-#define QUICHE_QUIC_CORE_QPACK_QPACK_ENCODER_TEST_UTILS_H_
-
-#include <string>
-
-#include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h"
-#include "net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
-#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h"
-
-namespace quic {
-namespace test {
-
-// QpackEncoder::DecoderStreamErrorDelegate implementation that does nothing.
-class NoopDecoderStreamErrorDelegate
- : public QpackEncoder::DecoderStreamErrorDelegate {
- public:
- ~NoopDecoderStreamErrorDelegate() override = default;
-
- void OnDecoderStreamError(QuicStringPiece error_message) override;
-};
-
-// Mock QpackEncoder::DecoderStreamErrorDelegate implementation.
-class MockDecoderStreamErrorDelegate
- : public QpackEncoder::DecoderStreamErrorDelegate {
- public:
- ~MockDecoderStreamErrorDelegate() override = default;
-
- MOCK_METHOD1(OnDecoderStreamError, void(QuicStringPiece error_message));
-};
-
-} // namespace test
-} // namespace quic
-
-#endif // QUICHE_QUIC_CORE_QPACK_QPACK_ENCODER_TEST_UTILS_H_
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.cc
index ff9be9a79fd..4cafa196815 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.cc
@@ -17,7 +17,8 @@ QpackHeaderTable::QpackHeaderTable()
dynamic_table_capacity_(0),
maximum_dynamic_table_capacity_(0),
max_entries_(0),
- dropped_entry_count_(0) {}
+ dropped_entry_count_(0),
+ dynamic_table_entry_referenced_(false) {}
QpackHeaderTable::~QpackHeaderTable() {
for (auto& entry : observers_) {
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.h
index 78d85f6ae29..dd5ca3ba3e5 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.h
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_header_table.h
@@ -40,7 +40,7 @@ class QUIC_EXPORT_PRIVATE QpackHeaderTable {
enum class MatchType { kNameAndValue, kName, kNoMatch };
// Observer interface for dynamic table insertion.
- class Observer {
+ class QUIC_EXPORT_PRIVATE Observer {
public:
virtual ~Observer() = default;
@@ -98,6 +98,11 @@ class QUIC_EXPORT_PRIVATE QpackHeaderTable {
// This method must only be called at most once.
void SetMaximumDynamicTableCapacity(uint64_t maximum_dynamic_table_capacity);
+ // Get |maximum_dynamic_table_capacity_|.
+ uint64_t maximum_dynamic_table_capacity() const {
+ return maximum_dynamic_table_capacity_;
+ }
+
// Register an observer to be notified when inserted_entry_count() reaches
// |required_insert_count|. After the notification, |observer| automatically
// gets unregistered. Each observer must only be registered at most once.
@@ -130,6 +135,13 @@ class QUIC_EXPORT_PRIVATE QpackHeaderTable {
// The returned index might not be the index of a valid entry.
uint64_t draining_index(float draining_fraction) const;
+ void set_dynamic_table_entry_referenced() {
+ dynamic_table_entry_referenced_ = true;
+ }
+ bool dynamic_table_entry_referenced() const {
+ return dynamic_table_entry_referenced_;
+ }
+
private:
friend class test::QpackHeaderTablePeer;
@@ -192,6 +204,10 @@ class QUIC_EXPORT_PRIVATE QpackHeaderTable {
// Observers waiting to be notified, sorted by required insert count.
std::multimap<uint64_t, Observer*> observers_;
+
+ // True if any dynamic table entries have been referenced from a header block.
+ // Set directly by the encoder or decoder. Used for stats.
+ bool dynamic_table_entry_referenced_;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder.cc
index 187894d374e..fede8e307df 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder.cc
@@ -32,44 +32,48 @@ QpackInstructionDecoder::QpackInstructionDecoder(const QpackLanguage* language,
error_detected_(false),
state_(State::kStartInstruction) {}
-void QpackInstructionDecoder::Decode(QuicStringPiece data) {
+bool QpackInstructionDecoder::Decode(QuicStringPiece data) {
DCHECK(!data.empty());
DCHECK(!error_detected_);
while (true) {
+ bool success = true;
size_t bytes_consumed = 0;
switch (state_) {
case State::kStartInstruction:
- DoStartInstruction(data);
+ success = DoStartInstruction(data);
break;
case State::kStartField:
- DoStartField();
+ success = DoStartField();
break;
case State::kReadBit:
- DoReadBit(data);
+ success = DoReadBit(data);
break;
case State::kVarintStart:
- bytes_consumed = DoVarintStart(data);
+ success = DoVarintStart(data, &bytes_consumed);
break;
case State::kVarintResume:
- bytes_consumed = DoVarintResume(data);
+ success = DoVarintResume(data, &bytes_consumed);
break;
case State::kVarintDone:
- DoVarintDone();
+ success = DoVarintDone();
break;
case State::kReadString:
- bytes_consumed = DoReadString(data);
+ success = DoReadString(data, &bytes_consumed);
break;
case State::kReadStringDone:
- DoReadStringDone();
+ success = DoReadStringDone();
break;
}
- if (error_detected_) {
- return;
+ if (!success) {
+ return false;
}
+ // |success| must be false if an error is detected.
+ DCHECK(!error_detected_);
+
DCHECK_LE(bytes_consumed, data.size());
data = QuicStringPiece(data.data() + bytes_consumed,
@@ -78,35 +82,37 @@ void QpackInstructionDecoder::Decode(QuicStringPiece data) {
// Stop processing if no more data but next state would require it.
if (data.empty() && (state_ != State::kStartField) &&
(state_ != State::kVarintDone) && (state_ != State::kReadStringDone)) {
- return;
+ return true;
}
}
+
+ return true;
}
bool QpackInstructionDecoder::AtInstructionBoundary() const {
return state_ == State::kStartInstruction;
}
-void QpackInstructionDecoder::DoStartInstruction(QuicStringPiece data) {
+bool QpackInstructionDecoder::DoStartInstruction(QuicStringPiece data) {
DCHECK(!data.empty());
instruction_ = LookupOpcode(data[0]);
field_ = instruction_->fields.begin();
state_ = State::kStartField;
+ return true;
}
-void QpackInstructionDecoder::DoStartField() {
+bool QpackInstructionDecoder::DoStartField() {
if (field_ == instruction_->fields.end()) {
// Completed decoding this instruction.
if (!delegate_->OnInstructionDecoded(instruction_)) {
- error_detected_ = true;
- return;
+ return false;
}
state_ = State::kStartInstruction;
- return;
+ return true;
}
switch (field_->type) {
@@ -114,15 +120,18 @@ void QpackInstructionDecoder::DoStartField() {
case QpackInstructionFieldType::kName:
case QpackInstructionFieldType::kValue:
state_ = State::kReadBit;
- return;
+ return true;
case QpackInstructionFieldType::kVarint:
case QpackInstructionFieldType::kVarint2:
state_ = State::kVarintStart;
- return;
+ return true;
+ default:
+ QUIC_BUG << "Invalid field type.";
+ return false;
}
}
-void QpackInstructionDecoder::DoReadBit(QuicStringPiece data) {
+bool QpackInstructionDecoder::DoReadBit(QuicStringPiece data) {
DCHECK(!data.empty());
switch (field_->type) {
@@ -133,7 +142,7 @@ void QpackInstructionDecoder::DoReadBit(QuicStringPiece data) {
++field_;
state_ = State::kStartField;
- return;
+ return true;
}
case QpackInstructionFieldType::kName:
case QpackInstructionFieldType::kValue: {
@@ -144,14 +153,16 @@ void QpackInstructionDecoder::DoReadBit(QuicStringPiece data) {
state_ = State::kVarintStart;
- return;
+ return true;
}
default:
- DCHECK(false);
+ QUIC_BUG << "Invalid field type.";
+ return false;
}
}
-size_t QpackInstructionDecoder::DoVarintStart(QuicStringPiece data) {
+bool QpackInstructionDecoder::DoVarintStart(QuicStringPiece data,
+ size_t* bytes_consumed) {
DCHECK(!data.empty());
DCHECK(field_->type == QpackInstructionFieldType::kVarint ||
field_->type == QpackInstructionFieldType::kVarint2 ||
@@ -162,24 +173,25 @@ size_t QpackInstructionDecoder::DoVarintStart(QuicStringPiece data) {
http2::DecodeStatus status =
varint_decoder_.Start(data[0], field_->param, &buffer);
- size_t bytes_consumed = 1 + buffer.Offset();
+ *bytes_consumed = 1 + buffer.Offset();
switch (status) {
case http2::DecodeStatus::kDecodeDone:
state_ = State::kVarintDone;
- return bytes_consumed;
+ return true;
case http2::DecodeStatus::kDecodeInProgress:
state_ = State::kVarintResume;
- return bytes_consumed;
+ return true;
case http2::DecodeStatus::kDecodeError:
OnError("Encoded integer too large.");
- return bytes_consumed;
+ return false;
default:
QUIC_BUG << "Unknown decode status " << status;
- return bytes_consumed;
+ return false;
}
}
-size_t QpackInstructionDecoder::DoVarintResume(QuicStringPiece data) {
+bool QpackInstructionDecoder::DoVarintResume(QuicStringPiece data,
+ size_t* bytes_consumed) {
DCHECK(!data.empty());
DCHECK(field_->type == QpackInstructionFieldType::kVarint ||
field_->type == QpackInstructionFieldType::kVarint2 ||
@@ -189,25 +201,25 @@ size_t QpackInstructionDecoder::DoVarintResume(QuicStringPiece data) {
http2::DecodeBuffer buffer(data);
http2::DecodeStatus status = varint_decoder_.Resume(&buffer);
- size_t bytes_consumed = buffer.Offset();
+ *bytes_consumed = buffer.Offset();
switch (status) {
case http2::DecodeStatus::kDecodeDone:
state_ = State::kVarintDone;
- return bytes_consumed;
+ return true;
case http2::DecodeStatus::kDecodeInProgress:
- DCHECK_EQ(bytes_consumed, data.size());
+ DCHECK_EQ(*bytes_consumed, data.size());
DCHECK(buffer.Empty());
- return bytes_consumed;
+ return true;
case http2::DecodeStatus::kDecodeError:
OnError("Encoded integer too large.");
- return bytes_consumed;
+ return false;
default:
QUIC_BUG << "Unknown decode status " << status;
- return bytes_consumed;
+ return false;
}
}
-void QpackInstructionDecoder::DoVarintDone() {
+bool QpackInstructionDecoder::DoVarintDone() {
DCHECK(field_->type == QpackInstructionFieldType::kVarint ||
field_->type == QpackInstructionFieldType::kVarint2 ||
field_->type == QpackInstructionFieldType::kName ||
@@ -218,7 +230,7 @@ void QpackInstructionDecoder::DoVarintDone() {
++field_;
state_ = State::kStartField;
- return;
+ return true;
}
if (field_->type == QpackInstructionFieldType::kVarint2) {
@@ -226,13 +238,13 @@ void QpackInstructionDecoder::DoVarintDone() {
++field_;
state_ = State::kStartField;
- return;
+ return true;
}
string_length_ = varint_decoder_.value();
if (string_length_ > kStringLiteralLengthLimit) {
OnError("String literal too long.");
- return;
+ return false;
}
std::string* const string =
@@ -242,15 +254,17 @@ void QpackInstructionDecoder::DoVarintDone() {
if (string_length_ == 0) {
++field_;
state_ = State::kStartField;
- return;
+ return true;
}
string->reserve(string_length_);
state_ = State::kReadString;
+ return true;
}
-size_t QpackInstructionDecoder::DoReadString(QuicStringPiece data) {
+bool QpackInstructionDecoder::DoReadString(QuicStringPiece data,
+ size_t* bytes_consumed) {
DCHECK(!data.empty());
DCHECK(field_->type == QpackInstructionFieldType::kName ||
field_->type == QpackInstructionFieldType::kValue);
@@ -259,18 +273,17 @@ size_t QpackInstructionDecoder::DoReadString(QuicStringPiece data) {
(field_->type == QpackInstructionFieldType::kName) ? &name_ : &value_;
DCHECK_LT(string->size(), string_length_);
- size_t bytes_consumed =
- std::min(string_length_ - string->size(), data.size());
- string->append(data.data(), bytes_consumed);
+ *bytes_consumed = std::min(string_length_ - string->size(), data.size());
+ string->append(data.data(), *bytes_consumed);
DCHECK_LE(string->size(), string_length_);
if (string->size() == string_length_) {
state_ = State::kReadStringDone;
}
- return bytes_consumed;
+ return true;
}
-void QpackInstructionDecoder::DoReadStringDone() {
+bool QpackInstructionDecoder::DoReadStringDone() {
DCHECK(field_->type == QpackInstructionFieldType::kName ||
field_->type == QpackInstructionFieldType::kValue);
@@ -285,13 +298,14 @@ void QpackInstructionDecoder::DoReadStringDone() {
huffman_decoder_.Decode(*string, &decoded_value);
if (!huffman_decoder_.InputProperlyTerminated()) {
OnError("Error in Huffman-encoded string.");
- return;
+ return false;
}
*string = std::move(decoded_value);
}
++field_;
state_ = State::kStartField;
+ return true;
}
const QpackInstruction* QpackInstructionDecoder::LookupOpcode(
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder.h
index f478c249b07..4c217731a92 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder.h
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder.h
@@ -11,7 +11,7 @@
#include "net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_decoder.h"
#include "net/third_party/quiche/src/http2/hpack/varint/hpack_varint_decoder.h"
-#include "net/third_party/quiche/src/quic/core/qpack/qpack_constants.h"
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_instructions.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
@@ -33,11 +33,15 @@ class QUIC_EXPORT_PRIVATE QpackInstructionDecoder {
// Returns true if decoded fields are valid.
// Returns false otherwise, in which case QpackInstructionDecoder stops
// decoding: Delegate methods will not be called, and Decode() must not be
- // called.
+ // called. Implementations are allowed to destroy the
+ // QpackInstructionDecoder instance synchronously if OnInstructionDecoded()
+ // returns false.
virtual bool OnInstructionDecoded(const QpackInstruction* instruction) = 0;
// Called by QpackInstructionDecoder if an error has occurred.
// No more data is processed afterwards.
+ // Implementations are allowed to destroy the QpackInstructionDecoder
+ // instance synchronously.
virtual void OnError(QuicStringPiece error_message) = 0;
};
@@ -48,8 +52,9 @@ class QUIC_EXPORT_PRIVATE QpackInstructionDecoder {
QpackInstructionDecoder& operator=(const QpackInstructionDecoder&) = delete;
// Provide a data fragment to decode. Must not be called after an error has
- // occurred. Must not be called with empty |data|.
- void Decode(QuicStringPiece data);
+ // occurred. Must not be called with empty |data|. Return true on success,
+ // false on error (in which case Delegate::OnError() is called synchronously).
+ bool Decode(QuicStringPiece data);
// Returns true if no decoding has taken place yet or if the last instruction
// has been entirely parsed.
@@ -84,18 +89,19 @@ class QUIC_EXPORT_PRIVATE QpackInstructionDecoder {
kReadStringDone
};
- // One method for each state. Some take input data and return the number of
- // octets processed. Some take input data but do have void return type
- // because they not consume any bytes. Some do not take any arguments because
- // they only change internal state.
- void DoStartInstruction(QuicStringPiece data);
- void DoStartField();
- void DoReadBit(QuicStringPiece data);
- size_t DoVarintStart(QuicStringPiece data);
- size_t DoVarintResume(QuicStringPiece data);
- void DoVarintDone();
- size_t DoReadString(QuicStringPiece data);
- void DoReadStringDone();
+ // One method for each state. They each return true on success, false on
+ // error (in which case |this| might already be destroyed). Some take input
+ // data and set |*bytes_consumed| to the number of octets processed. Some
+ // take input data but do not consume any bytes. Some do not take any
+ // arguments because they only change internal state.
+ bool DoStartInstruction(QuicStringPiece data);
+ bool DoStartField();
+ bool DoReadBit(QuicStringPiece data);
+ bool DoVarintStart(QuicStringPiece data, size_t* bytes_consumed);
+ bool DoVarintResume(QuicStringPiece data, size_t* bytes_consumed);
+ bool DoVarintDone();
+ bool DoReadString(QuicStringPiece data, size_t* bytes_consumed);
+ bool DoReadStringDone();
// Identify instruction based on opcode encoded in |byte|.
// Returns a pointer to an element of |*language_|.
@@ -127,8 +133,8 @@ class QUIC_EXPORT_PRIVATE QpackInstructionDecoder {
// Decoder instance for decoding Huffman encoded strings.
http2::HpackHuffmanDecoder huffman_decoder_;
- // True if a decoding error has been detected either by
- // QpackInstructionDecoder or by Delegate.
+ // True if a decoding error has been detected by QpackInstructionDecoder.
+ // Only used in DCHECKs.
bool error_detected_;
// Decoding state.
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder_test.cc
index 2d57f5c5320..c066827d295 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_decoder_test.cc
@@ -6,15 +6,16 @@
#include <algorithm>
-#include "net/third_party/quiche/src/quic/core/qpack/qpack_constants.h"
-#include "net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.h"
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_instructions.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
+#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_test_utils.h"
using ::testing::_;
using ::testing::Eq;
using ::testing::Expectation;
+using ::testing::Invoke;
using ::testing::Return;
using ::testing::StrictMock;
using ::testing::Values;
@@ -64,36 +65,52 @@ class MockDelegate : public QpackInstructionDecoder::Delegate {
};
class QpackInstructionDecoderTest : public QuicTestWithParam<FragmentMode> {
- public:
+ protected:
QpackInstructionDecoderTest()
- : decoder_(TestLanguage(), &delegate_), fragment_mode_(GetParam()) {}
+ : decoder_(std::make_unique<QpackInstructionDecoder>(TestLanguage(),
+ &delegate_)),
+ fragment_mode_(GetParam()) {}
~QpackInstructionDecoderTest() override = default;
- protected:
+ void SetUp() override {
+ // Destroy QpackInstructionDecoder on error to test that it does not crash.
+ // See https://crbug.com/1025209.
+ ON_CALL(delegate_, OnError(_))
+ .WillByDefault(Invoke(
+ [this](QuicStringPiece /* error_message */) { decoder_.reset(); }));
+ }
+
// Decode one full instruction with fragment sizes dictated by
// |fragment_mode_|.
- // Verifies that AtInstructionBoundary() returns true before and after the
+ // Assumes that |data| is a single complete instruction, and accordingly
+ // verifies that AtInstructionBoundary() returns true before and after the
// instruction, and returns false while decoding is in progress.
+ // Assumes that delegate methods destroy |decoder_| if they return false.
void DecodeInstruction(QuicStringPiece data) {
- EXPECT_TRUE(decoder_.AtInstructionBoundary());
+ EXPECT_TRUE(decoder_->AtInstructionBoundary());
FragmentSizeGenerator fragment_size_generator =
FragmentModeToFragmentSizeGenerator(fragment_mode_);
while (!data.empty()) {
size_t fragment_size = std::min(fragment_size_generator(), data.size());
- decoder_.Decode(data.substr(0, fragment_size));
+ bool success = decoder_->Decode(data.substr(0, fragment_size));
+ if (!decoder_) {
+ EXPECT_FALSE(success);
+ return;
+ }
+ EXPECT_TRUE(success);
data = data.substr(fragment_size);
if (!data.empty()) {
- EXPECT_FALSE(decoder_.AtInstructionBoundary());
+ EXPECT_FALSE(decoder_->AtInstructionBoundary());
}
}
- EXPECT_TRUE(decoder_.AtInstructionBoundary());
+ EXPECT_TRUE(decoder_->AtInstructionBoundary());
}
StrictMock<MockDelegate> delegate_;
- QpackInstructionDecoder decoder_;
+ std::unique_ptr<QpackInstructionDecoder> decoder_;
private:
const FragmentMode fragment_mode_;
@@ -108,60 +125,82 @@ TEST_P(QpackInstructionDecoderTest, SBitAndVarint2) {
EXPECT_CALL(delegate_, OnInstructionDecoded(TestInstruction1()));
DecodeInstruction(QuicTextUtils::HexDecode("7f01ff65"));
- EXPECT_TRUE(decoder_.s_bit());
- EXPECT_EQ(64u, decoder_.varint());
- EXPECT_EQ(356u, decoder_.varint2());
+ EXPECT_TRUE(decoder_->s_bit());
+ EXPECT_EQ(64u, decoder_->varint());
+ EXPECT_EQ(356u, decoder_->varint2());
EXPECT_CALL(delegate_, OnInstructionDecoded(TestInstruction1()));
DecodeInstruction(QuicTextUtils::HexDecode("05c8"));
- EXPECT_FALSE(decoder_.s_bit());
- EXPECT_EQ(5u, decoder_.varint());
- EXPECT_EQ(200u, decoder_.varint2());
+ EXPECT_FALSE(decoder_->s_bit());
+ EXPECT_EQ(5u, decoder_->varint());
+ EXPECT_EQ(200u, decoder_->varint2());
}
TEST_P(QpackInstructionDecoderTest, NameAndValue) {
EXPECT_CALL(delegate_, OnInstructionDecoded(TestInstruction2()));
DecodeInstruction(QuicTextUtils::HexDecode("83666f6f03626172"));
- EXPECT_EQ("foo", decoder_.name());
- EXPECT_EQ("bar", decoder_.value());
+ EXPECT_EQ("foo", decoder_->name());
+ EXPECT_EQ("bar", decoder_->value());
EXPECT_CALL(delegate_, OnInstructionDecoded(TestInstruction2()));
DecodeInstruction(QuicTextUtils::HexDecode("8000"));
- EXPECT_EQ("", decoder_.name());
- EXPECT_EQ("", decoder_.value());
+ EXPECT_EQ("", decoder_->name());
+ EXPECT_EQ("", decoder_->value());
EXPECT_CALL(delegate_, OnInstructionDecoded(TestInstruction2()));
DecodeInstruction(QuicTextUtils::HexDecode("c294e7838c767f"));
- EXPECT_EQ("foo", decoder_.name());
- EXPECT_EQ("bar", decoder_.value());
+ EXPECT_EQ("foo", decoder_->name());
+ EXPECT_EQ("bar", decoder_->value());
}
TEST_P(QpackInstructionDecoderTest, InvalidHuffmanEncoding) {
EXPECT_CALL(delegate_, OnError(Eq("Error in Huffman-encoded string.")));
- decoder_.Decode(QuicTextUtils::HexDecode("c1ff"));
+ DecodeInstruction(QuicTextUtils::HexDecode("c1ff"));
}
TEST_P(QpackInstructionDecoderTest, InvalidVarintEncoding) {
EXPECT_CALL(delegate_, OnError(Eq("Encoded integer too large.")));
- decoder_.Decode(QuicTextUtils::HexDecode("ffffffffffffffffffffff"));
+ DecodeInstruction(QuicTextUtils::HexDecode("ffffffffffffffffffffff"));
}
TEST_P(QpackInstructionDecoderTest, DelegateSignalsError) {
// First instruction is valid.
Expectation first_call =
EXPECT_CALL(delegate_, OnInstructionDecoded(TestInstruction1()))
- .WillOnce(Return(true));
+ .WillOnce(Invoke(
+ [this](const QpackInstruction * /* instruction */) -> bool {
+ EXPECT_EQ(1u, decoder_->varint());
+ return true;
+ }));
+
// Second instruction is invalid. Decoding must halt.
EXPECT_CALL(delegate_, OnInstructionDecoded(TestInstruction1()))
.After(first_call)
- .WillOnce(Return(false));
- decoder_.Decode(QuicTextUtils::HexDecode("01000200030004000500"));
+ .WillOnce(
+ Invoke([this](const QpackInstruction * /* instruction */) -> bool {
+ EXPECT_EQ(2u, decoder_->varint());
+ return false;
+ }));
+
+ EXPECT_FALSE(
+ decoder_->Decode(QuicTextUtils::HexDecode("01000200030004000500")));
+}
- EXPECT_EQ(2u, decoder_.varint());
+// QpackInstructionDecoder must not crash if it is destroyed from a
+// Delegate::OnInstructionDecoded() call as long as it returns false.
+TEST_P(QpackInstructionDecoderTest, DelegateSignalsErrorAndDestroysDecoder) {
+ EXPECT_CALL(delegate_, OnInstructionDecoded(TestInstruction1()))
+ .WillOnce(
+ Invoke([this](const QpackInstruction * /* instruction */) -> bool {
+ EXPECT_EQ(1u, decoder_->varint());
+ decoder_.reset();
+ return false;
+ }));
+ DecodeInstruction(QuicTextUtils::HexDecode("0100"));
}
} // namespace
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder.cc
index 5845a748ffc..a87489d9e67 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder.cc
@@ -16,13 +16,13 @@ namespace quic {
QpackInstructionEncoder::QpackInstructionEncoder()
: byte_(0), state_(State::kOpcode), instruction_(nullptr) {}
-void QpackInstructionEncoder::Encode(const QpackInstruction* instruction,
- const Values& values,
- std::string* output) {
- DCHECK(instruction);
+void QpackInstructionEncoder::Encode(
+ const QpackInstructionWithValues& instruction_with_values,
+ std::string* output) {
+ DCHECK(instruction_with_values.instruction());
state_ = State::kOpcode;
- instruction_ = instruction;
+ instruction_ = instruction_with_values.instruction();
field_ = instruction_->fields.begin();
// Field list must not be empty.
@@ -37,13 +37,15 @@ void QpackInstructionEncoder::Encode(const QpackInstruction* instruction,
DoStartField();
break;
case State::kSbit:
- DoSBit(values.s_bit);
+ DoSBit(instruction_with_values.s_bit());
break;
case State::kVarintEncode:
- DoVarintEncode(values.varint, values.varint2, output);
+ DoVarintEncode(instruction_with_values.varint(),
+ instruction_with_values.varint2(), output);
break;
case State::kStartString:
- DoStartString(values.name, values.value);
+ DoStartString(instruction_with_values.name(),
+ instruction_with_values.value());
break;
case State::kWriteString:
DoWriteString(output);
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder.h
index 1ca52e667ec..04b2888172e 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder.h
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder.h
@@ -8,7 +8,7 @@
#include <cstdint>
#include <string>
-#include "net/third_party/quiche/src/quic/core/qpack/qpack_constants.h"
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_instructions.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
@@ -19,23 +19,12 @@ namespace quic {
// fields that follow each instruction.
class QUIC_EXPORT_PRIVATE QpackInstructionEncoder {
public:
- // Storage for field values to be encoded.
- // The encoded instruction determines which values are actually used.
- struct Values {
- bool s_bit;
- uint64_t varint;
- uint64_t varint2;
- QuicStringPiece name;
- QuicStringPiece value;
- };
-
QpackInstructionEncoder();
QpackInstructionEncoder(const QpackInstructionEncoder&) = delete;
QpackInstructionEncoder& operator=(const QpackInstructionEncoder&) = delete;
// Append encoded instruction to |output|.
- void Encode(const QpackInstruction* instruction,
- const Values& values,
+ void Encode(const QpackInstructionWithValues& instruction_with_values,
std::string* output);
private:
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder_test.cc
index 0d172cd6847..79dfe2af379 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder_test.cc
@@ -8,10 +8,44 @@
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
-using ::testing::Values;
-
namespace quic {
namespace test {
+
+class QpackInstructionWithValuesPeer {
+ public:
+ static QpackInstructionWithValues CreateQpackInstructionWithValues(
+ const QpackInstruction* instruction) {
+ QpackInstructionWithValues instruction_with_values;
+ instruction_with_values.instruction_ = instruction;
+ return instruction_with_values;
+ }
+
+ static void set_s_bit(QpackInstructionWithValues* instruction_with_values,
+ bool s_bit) {
+ instruction_with_values->s_bit_ = s_bit;
+ }
+
+ static void set_varint(QpackInstructionWithValues* instruction_with_values,
+ uint64_t varint) {
+ instruction_with_values->varint_ = varint;
+ }
+
+ static void set_varint2(QpackInstructionWithValues* instruction_with_values,
+ uint64_t varint2) {
+ instruction_with_values->varint2_ = varint2;
+ }
+
+ static void set_name(QpackInstructionWithValues* instruction_with_values,
+ QuicStringPiece name) {
+ instruction_with_values->name_ = name;
+ }
+
+ static void set_value(QpackInstructionWithValues* instruction_with_values,
+ QuicStringPiece value) {
+ instruction_with_values->value_ = value;
+ }
+};
+
namespace {
class QpackInstructionEncoderTest : public QuicTest {
@@ -20,9 +54,9 @@ class QpackInstructionEncoderTest : public QuicTest {
~QpackInstructionEncoderTest() override = default;
// Append encoded |instruction| to |output_|.
- void EncodeInstruction(const QpackInstruction* instruction,
- const QpackInstructionEncoder::Values& values) {
- encoder_.Encode(instruction, values, &output_);
+ void EncodeInstruction(
+ const QpackInstructionWithValues& instruction_with_values) {
+ encoder_.Encode(instruction_with_values, &output_);
}
// Compare substring appended to |output_| since last EncodedSegmentMatches()
@@ -44,13 +78,15 @@ TEST_F(QpackInstructionEncoderTest, Varint) {
const QpackInstruction instruction{QpackInstructionOpcode{0x00, 0x80},
{{QpackInstructionFieldType::kVarint, 7}}};
- QpackInstructionEncoder::Values values;
- values.varint = 5;
- EncodeInstruction(&instruction, values);
+ auto instruction_with_values =
+ QpackInstructionWithValuesPeer::CreateQpackInstructionWithValues(
+ &instruction);
+ QpackInstructionWithValuesPeer::set_varint(&instruction_with_values, 5);
+ EncodeInstruction(instruction_with_values);
EXPECT_TRUE(EncodedSegmentMatches("05"));
- values.varint = 127;
- EncodeInstruction(&instruction, values);
+ QpackInstructionWithValuesPeer::set_varint(&instruction_with_values, 127);
+ EncodeInstruction(instruction_with_values);
EXPECT_TRUE(EncodedSegmentMatches("7f00"));
}
@@ -61,17 +97,19 @@ TEST_F(QpackInstructionEncoderTest, SBitAndTwoVarint2) {
{QpackInstructionFieldType::kVarint, 5},
{QpackInstructionFieldType::kVarint2, 8}}};
- QpackInstructionEncoder::Values values;
- values.s_bit = true;
- values.varint = 5;
- values.varint2 = 200;
- EncodeInstruction(&instruction, values);
+ auto instruction_with_values =
+ QpackInstructionWithValuesPeer::CreateQpackInstructionWithValues(
+ &instruction);
+ QpackInstructionWithValuesPeer::set_s_bit(&instruction_with_values, true);
+ QpackInstructionWithValuesPeer::set_varint(&instruction_with_values, 5);
+ QpackInstructionWithValuesPeer::set_varint2(&instruction_with_values, 200);
+ EncodeInstruction(instruction_with_values);
EXPECT_TRUE(EncodedSegmentMatches("a5c8"));
- values.s_bit = false;
- values.varint = 31;
- values.varint2 = 356;
- EncodeInstruction(&instruction, values);
+ QpackInstructionWithValuesPeer::set_s_bit(&instruction_with_values, false);
+ QpackInstructionWithValuesPeer::set_varint(&instruction_with_values, 31);
+ QpackInstructionWithValuesPeer::set_varint2(&instruction_with_values, 356);
+ EncodeInstruction(instruction_with_values);
EXPECT_TRUE(EncodedSegmentMatches("9f00ff65"));
}
@@ -81,17 +119,19 @@ TEST_F(QpackInstructionEncoderTest, SBitAndVarintAndValue) {
{QpackInstructionFieldType::kVarint, 5},
{QpackInstructionFieldType::kValue, 7}}};
- QpackInstructionEncoder::Values values;
- values.s_bit = true;
- values.varint = 100;
- values.value = "foo";
- EncodeInstruction(&instruction, values);
+ auto instruction_with_values =
+ QpackInstructionWithValuesPeer::CreateQpackInstructionWithValues(
+ &instruction);
+ QpackInstructionWithValuesPeer::set_s_bit(&instruction_with_values, true);
+ QpackInstructionWithValuesPeer::set_varint(&instruction_with_values, 100);
+ QpackInstructionWithValuesPeer::set_value(&instruction_with_values, "foo");
+ EncodeInstruction(instruction_with_values);
EXPECT_TRUE(EncodedSegmentMatches("ff458294e7"));
- values.s_bit = false;
- values.varint = 3;
- values.value = "bar";
- EncodeInstruction(&instruction, values);
+ QpackInstructionWithValuesPeer::set_s_bit(&instruction_with_values, false);
+ QpackInstructionWithValuesPeer::set_varint(&instruction_with_values, 3);
+ QpackInstructionWithValuesPeer::set_value(&instruction_with_values, "bar");
+ EncodeInstruction(instruction_with_values);
EXPECT_TRUE(EncodedSegmentMatches("c303626172"));
}
@@ -99,17 +139,19 @@ TEST_F(QpackInstructionEncoderTest, Name) {
const QpackInstruction instruction{QpackInstructionOpcode{0xe0, 0xe0},
{{QpackInstructionFieldType::kName, 4}}};
- QpackInstructionEncoder::Values values;
- values.name = "";
- EncodeInstruction(&instruction, values);
+ auto instruction_with_values =
+ QpackInstructionWithValuesPeer::CreateQpackInstructionWithValues(
+ &instruction);
+ QpackInstructionWithValuesPeer::set_name(&instruction_with_values, "");
+ EncodeInstruction(instruction_with_values);
EXPECT_TRUE(EncodedSegmentMatches("e0"));
- values.name = "foo";
- EncodeInstruction(&instruction, values);
+ QpackInstructionWithValuesPeer::set_name(&instruction_with_values, "foo");
+ EncodeInstruction(instruction_with_values);
EXPECT_TRUE(EncodedSegmentMatches("f294e7"));
- values.name = "bar";
- EncodeInstruction(&instruction, values);
+ QpackInstructionWithValuesPeer::set_name(&instruction_with_values, "bar");
+ EncodeInstruction(instruction_with_values);
EXPECT_TRUE(EncodedSegmentMatches("e3626172"));
}
@@ -117,17 +159,19 @@ TEST_F(QpackInstructionEncoderTest, Value) {
const QpackInstruction instruction{QpackInstructionOpcode{0xf0, 0xf0},
{{QpackInstructionFieldType::kValue, 3}}};
- QpackInstructionEncoder::Values values;
- values.value = "";
- EncodeInstruction(&instruction, values);
+ auto instruction_with_values =
+ QpackInstructionWithValuesPeer::CreateQpackInstructionWithValues(
+ &instruction);
+ QpackInstructionWithValuesPeer::set_value(&instruction_with_values, "");
+ EncodeInstruction(instruction_with_values);
EXPECT_TRUE(EncodedSegmentMatches("f0"));
- values.value = "foo";
- EncodeInstruction(&instruction, values);
+ QpackInstructionWithValuesPeer::set_value(&instruction_with_values, "foo");
+ EncodeInstruction(instruction_with_values);
EXPECT_TRUE(EncodedSegmentMatches("fa94e7"));
- values.value = "bar";
- EncodeInstruction(&instruction, values);
+ QpackInstructionWithValuesPeer::set_value(&instruction_with_values, "bar");
+ EncodeInstruction(instruction_with_values);
EXPECT_TRUE(EncodedSegmentMatches("f3626172"));
}
@@ -137,17 +181,19 @@ TEST_F(QpackInstructionEncoderTest, SBitAndNameAndValue) {
{QpackInstructionFieldType::kName, 2},
{QpackInstructionFieldType::kValue, 7}}};
- QpackInstructionEncoder::Values values;
- values.s_bit = false;
- values.name = "";
- values.value = "";
- EncodeInstruction(&instruction, values);
+ auto instruction_with_values =
+ QpackInstructionWithValuesPeer::CreateQpackInstructionWithValues(
+ &instruction);
+ QpackInstructionWithValuesPeer::set_s_bit(&instruction_with_values, false);
+ QpackInstructionWithValuesPeer::set_name(&instruction_with_values, "");
+ QpackInstructionWithValuesPeer::set_value(&instruction_with_values, "");
+ EncodeInstruction(instruction_with_values);
EXPECT_TRUE(EncodedSegmentMatches("f000"));
- values.s_bit = true;
- values.name = "foo";
- values.value = "bar";
- EncodeInstruction(&instruction, values);
+ QpackInstructionWithValuesPeer::set_s_bit(&instruction_with_values, true);
+ QpackInstructionWithValuesPeer::set_name(&instruction_with_values, "foo");
+ QpackInstructionWithValuesPeer::set_value(&instruction_with_values, "bar");
+ EncodeInstruction(instruction_with_values);
EXPECT_TRUE(EncodedSegmentMatches("fe94e703626172"));
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_constants.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instructions.cc
index 6644918b34a..a6a7529bf09 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_constants.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instructions.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "net/third_party/quiche/src/quic/core/qpack/qpack_constants.h"
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_instructions.h"
#include <limits>
@@ -199,4 +199,133 @@ const QpackLanguage* QpackRequestStreamLanguage() {
return language;
}
+// static
+QpackInstructionWithValues QpackInstructionWithValues::InsertWithNameReference(
+ bool is_static,
+ uint64_t name_index,
+ QuicStringPiece value) {
+ QpackInstructionWithValues instruction_with_values;
+ instruction_with_values.instruction_ = InsertWithNameReferenceInstruction();
+ instruction_with_values.s_bit_ = is_static;
+ instruction_with_values.varint_ = name_index;
+ instruction_with_values.value_ = value;
+
+ return instruction_with_values;
+}
+
+// static
+QpackInstructionWithValues
+QpackInstructionWithValues::InsertWithoutNameReference(QuicStringPiece name,
+ QuicStringPiece value) {
+ QpackInstructionWithValues instruction_with_values;
+ instruction_with_values.instruction_ =
+ InsertWithoutNameReferenceInstruction();
+ instruction_with_values.name_ = name;
+ instruction_with_values.value_ = value;
+
+ return instruction_with_values;
+}
+
+// static
+QpackInstructionWithValues QpackInstructionWithValues::Duplicate(
+ uint64_t index) {
+ QpackInstructionWithValues instruction_with_values;
+ instruction_with_values.instruction_ = DuplicateInstruction();
+ instruction_with_values.varint_ = index;
+
+ return instruction_with_values;
+}
+
+// static
+QpackInstructionWithValues QpackInstructionWithValues::SetDynamicTableCapacity(
+ uint64_t capacity) {
+ QpackInstructionWithValues instruction_with_values;
+ instruction_with_values.instruction_ = SetDynamicTableCapacityInstruction();
+ instruction_with_values.varint_ = capacity;
+
+ return instruction_with_values;
+}
+
+// static
+QpackInstructionWithValues QpackInstructionWithValues::InsertCountIncrement(
+ uint64_t increment) {
+ QpackInstructionWithValues instruction_with_values;
+ instruction_with_values.instruction_ = InsertCountIncrementInstruction();
+ instruction_with_values.varint_ = increment;
+
+ return instruction_with_values;
+}
+
+// static
+QpackInstructionWithValues QpackInstructionWithValues::HeaderAcknowledgement(
+ uint64_t stream_id) {
+ QpackInstructionWithValues instruction_with_values;
+ instruction_with_values.instruction_ = HeaderAcknowledgementInstruction();
+ instruction_with_values.varint_ = stream_id;
+
+ return instruction_with_values;
+}
+
+// static
+QpackInstructionWithValues QpackInstructionWithValues::StreamCancellation(
+ uint64_t stream_id) {
+ QpackInstructionWithValues instruction_with_values;
+ instruction_with_values.instruction_ = StreamCancellationInstruction();
+ instruction_with_values.varint_ = stream_id;
+
+ return instruction_with_values;
+}
+
+// static
+QpackInstructionWithValues QpackInstructionWithValues::Prefix(
+ uint64_t required_insert_count) {
+ QpackInstructionWithValues instruction_with_values;
+ instruction_with_values.instruction_ = QpackPrefixInstruction();
+ instruction_with_values.varint_ = required_insert_count;
+ instruction_with_values.varint2_ = 0; // Delta Base.
+ instruction_with_values.s_bit_ = false; // Delta Base sign.
+
+ return instruction_with_values;
+}
+
+// static
+QpackInstructionWithValues QpackInstructionWithValues::IndexedHeaderField(
+ bool is_static,
+ uint64_t index) {
+ QpackInstructionWithValues instruction_with_values;
+ instruction_with_values.instruction_ = QpackIndexedHeaderFieldInstruction();
+ instruction_with_values.s_bit_ = is_static;
+ instruction_with_values.varint_ = index;
+
+ return instruction_with_values;
+}
+
+// static
+QpackInstructionWithValues
+QpackInstructionWithValues::LiteralHeaderFieldNameReference(
+ bool is_static,
+ uint64_t index,
+ QuicStringPiece value) {
+ QpackInstructionWithValues instruction_with_values;
+ instruction_with_values.instruction_ =
+ QpackLiteralHeaderFieldNameReferenceInstruction();
+ instruction_with_values.s_bit_ = is_static;
+ instruction_with_values.varint_ = index;
+ instruction_with_values.value_ = value;
+
+ return instruction_with_values;
+}
+
+// static
+QpackInstructionWithValues QpackInstructionWithValues::LiteralHeaderField(
+ QuicStringPiece name,
+ QuicStringPiece value) {
+ QpackInstructionWithValues instruction_with_values;
+ instruction_with_values.instruction_ = QpackLiteralHeaderFieldInstruction();
+ instruction_with_values.name_ = name;
+ instruction_with_values.value_ = value;
+
+ return instruction_with_values;
+}
+
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_constants.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instructions.h
index 35e4d560bef..0ff18bff254 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_constants.h
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_instructions.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef QUICHE_QUIC_CORE_QPACK_QPACK_CONSTANTS_H_
-#define QUICHE_QUIC_CORE_QPACK_QPACK_CONSTANTS_H_
+#ifndef QUICHE_QUIC_CORE_QPACK_QPACK_INSTRUCTIONS_H_
+#define QUICHE_QUIC_CORE_QPACK_QPACK_INSTRUCTIONS_H_
#include <cstdint>
#include <string>
@@ -11,9 +11,14 @@
#include <vector>
#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
namespace quic {
+namespace test {
+class QpackInstructionWithValuesPeer;
+} // namespace test
+
// Each instruction is identified with an opcode in the first byte.
// |mask| determines which bits are part of the opcode.
// |value| is the value of these bits. (Other bits in value must be zero.)
@@ -137,6 +142,66 @@ const QpackInstruction* QpackLiteralHeaderFieldInstruction();
// Request and push stream language.
const QpackLanguage* QpackRequestStreamLanguage();
+// Storage for instruction and field values to be encoded.
+// This class can only be instantiated using factory methods that take exactly
+// the arguments that the corresponding instruction needs.
+class QUIC_EXPORT_PRIVATE QpackInstructionWithValues {
+ public:
+ // 5.2 Encoder stream instructions
+ static QpackInstructionWithValues InsertWithNameReference(
+ bool is_static,
+ uint64_t name_index,
+ QuicStringPiece value);
+ static QpackInstructionWithValues InsertWithoutNameReference(
+ QuicStringPiece name,
+ QuicStringPiece value);
+ static QpackInstructionWithValues Duplicate(uint64_t index);
+ static QpackInstructionWithValues SetDynamicTableCapacity(uint64_t capacity);
+
+ // 5.3 Decoder stream instructions
+ static QpackInstructionWithValues InsertCountIncrement(uint64_t increment);
+ static QpackInstructionWithValues HeaderAcknowledgement(uint64_t stream_id);
+ static QpackInstructionWithValues StreamCancellation(uint64_t stream_id);
+
+ // 5.4.1. Header data prefix. Delta Base is hardcoded to be zero.
+ static QpackInstructionWithValues Prefix(uint64_t required_insert_count);
+
+ // 5.4.2. Request and push stream instructions
+ static QpackInstructionWithValues IndexedHeaderField(bool is_static,
+ uint64_t index);
+ static QpackInstructionWithValues LiteralHeaderFieldNameReference(
+ bool is_static,
+ uint64_t index,
+ QuicStringPiece value);
+ static QpackInstructionWithValues LiteralHeaderField(QuicStringPiece name,
+ QuicStringPiece value);
+
+ const QpackInstruction* instruction() const { return instruction_; }
+ bool s_bit() const { return s_bit_; }
+ uint64_t varint() const { return varint_; }
+ uint64_t varint2() const { return varint2_; }
+ QuicStringPiece name() const { return name_; }
+ QuicStringPiece value() const { return value_; }
+
+ // Used by QpackEncoder, because in the first pass it stores absolute indices,
+ // which are converted into relative indices in the second pass after base is
+ // determined.
+ void set_varint(uint64_t varint) { varint_ = varint; }
+
+ private:
+ friend test::QpackInstructionWithValuesPeer;
+
+ QpackInstructionWithValues() = default;
+
+ // |*instruction| is not owned.
+ const QpackInstruction* instruction_;
+ bool s_bit_;
+ uint64_t varint_;
+ uint64_t varint2_;
+ QuicStringPiece name_;
+ QuicStringPiece value_;
+};
+
} // namespace quic
-#endif // QUICHE_QUIC_CORE_QPACK_QPACK_CONSTANTS_H_
+#endif // QUICHE_QUIC_CORE_QPACK_QPACK_INSTRUCTIONS_H_
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/offline/qpack_offline_decoder_bin.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_offline_decoder_bin.cc
index d72b0003da4..327816e8cb2 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/offline/qpack_offline_decoder_bin.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_offline_decoder_bin.cc
@@ -2,14 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "net/third_party/quiche/src/quic/core/qpack/offline/qpack_offline_decoder.h"
-
#include <cstddef>
#include <iostream>
#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
+#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_offline_decoder.h"
int main(int argc, char* argv[]) {
const char* usage =
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.cc
index 3c0b0f546fa..c9e19d2d013 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.cc
@@ -8,8 +8,8 @@
#include <limits>
#include <utility>
-#include "net/third_party/quiche/src/quic/core/qpack/qpack_constants.h"
#include "net/third_party/quiche/src/quic/core/qpack/qpack_index_conversions.h"
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_instructions.h"
#include "net/third_party/quiche/src/quic/core/qpack/qpack_required_insert_count.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
@@ -57,11 +57,13 @@ void QpackProgressiveDecoder::Decode(QuicStringPiece data) {
while (!prefix_decoded_) {
DCHECK(!blocked_);
- prefix_decoder_->Decode(data.substr(0, 1));
- if (error_detected_) {
+ if (!prefix_decoder_->Decode(data.substr(0, 1))) {
return;
}
+ // |prefix_decoder_->Decode()| must return false if an error is detected.
+ DCHECK(!error_detected_);
+
data = data.substr(1);
if (data.empty()) {
return;
@@ -115,20 +117,28 @@ void QpackProgressiveDecoder::OnError(QuicStringPiece error_message) {
DCHECK(!error_detected_);
error_detected_ = true;
+ // Might destroy |this|.
handler_->OnDecodingErrorDetected(error_message);
}
void QpackProgressiveDecoder::OnInsertCountReachedThreshold() {
DCHECK(blocked_);
+ // Clear |blocked_| before calling instruction_decoder_.Decode() below,
+ // because that might destroy |this| and ~QpackProgressiveDecoder() needs to
+ // know not to call UnregisterObserver().
+ blocked_ = false;
+ enforcer_->OnStreamUnblocked(stream_id_);
+
if (!buffer_.empty()) {
- instruction_decoder_.Decode(buffer_);
+ std::string buffer(std::move(buffer_));
buffer_.clear();
+ if (!instruction_decoder_.Decode(buffer)) {
+ // |this| might be destroyed.
+ return;
+ }
}
- blocked_ = false;
- enforcer_->OnStreamUnblocked(stream_id_);
-
if (!decoding_) {
FinishDecoding();
}
@@ -163,6 +173,7 @@ bool QpackProgressiveDecoder::DoIndexedHeaderFieldInstruction() {
return false;
}
+ header_table_->set_dynamic_table_entry_referenced();
handler_->OnHeaderDecoded(entry->name(), entry->value());
return true;
}
@@ -202,6 +213,7 @@ bool QpackProgressiveDecoder::DoIndexedHeaderFieldPostBaseInstruction() {
return false;
}
+ header_table_->set_dynamic_table_entry_referenced();
handler_->OnHeaderDecoded(entry->name(), entry->value());
return true;
}
@@ -231,6 +243,7 @@ bool QpackProgressiveDecoder::DoLiteralHeaderFieldNameReferenceInstruction() {
return false;
}
+ header_table_->set_dynamic_table_entry_referenced();
handler_->OnHeaderDecoded(entry->name(), instruction_decoder_.value());
return true;
}
@@ -270,6 +283,7 @@ bool QpackProgressiveDecoder::DoLiteralHeaderFieldPostBaseInstruction() {
return false;
}
+ header_table_->set_dynamic_table_entry_referenced();
handler_->OnHeaderDecoded(entry->name(), instruction_decoder_.value());
return true;
}
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.h
index 2f306c8e19c..6599c1a3ff8 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.h
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.h
@@ -44,7 +44,8 @@ class QUIC_EXPORT_PRIVATE QpackProgressiveDecoder
virtual void OnDecodingCompleted() = 0;
// Called when a decoding error has occurred. No other methods will be
- // called afterwards.
+ // called afterwards. Implementations are allowed to destroy
+ // the QpackProgressiveDecoder instance synchronously.
virtual void OnDecodingErrorDetected(QuicStringPiece error_message) = 0;
};
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_round_trip_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_round_trip_test.cc
index 567676c75d2..f0dc797fa3b 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_round_trip_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_round_trip_test.cc
@@ -5,15 +5,13 @@
#include <string>
#include <tuple>
-#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.h"
-#include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder_test_utils.h"
-#include "net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.h"
-#include "net/third_party/quiche/src/quic/core/qpack/qpack_utils.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_decoder_test_utils.h"
+#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_encoder_test_utils.h"
+#include "net/third_party/quiche/src/quic/test_tools/qpack/qpack_test_utils.h"
#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h"
-using ::testing::Combine;
using ::testing::Values;
namespace quic {
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.cc
deleted file mode 100644
index 2d4a72e71b0..00000000000
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.cc
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright (c) 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/quiche/src/quic/core/qpack/qpack_test_utils.h"
-
-#include <limits>
-
-namespace quic {
-namespace test {
-
-FragmentSizeGenerator FragmentModeToFragmentSizeGenerator(
- FragmentMode fragment_mode) {
- switch (fragment_mode) {
- case FragmentMode::kSingleChunk:
- return []() { return std::numeric_limits<size_t>::max(); };
- case FragmentMode::kOctetByOctet:
- return []() { return 1; };
- }
-}
-
-} // namespace test
-} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.h
deleted file mode 100644
index 42fa383a3ea..00000000000
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_test_utils.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright (c) 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 QUICHE_QUIC_CORE_QPACK_QPACK_TEST_UTILS_H_
-#define QUICHE_QUIC_CORE_QPACK_QPACK_TEST_UTILS_H_
-
-#include <cstddef>
-#include <functional>
-
-#include "net/third_party/quiche/src/quic/core/qpack/qpack_stream_sender_delegate.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
-
-namespace quic {
-namespace test {
-
-// Called repeatedly to determine the size of each fragment when encoding or
-// decoding. Must return a positive value.
-using FragmentSizeGenerator = std::function<size_t()>;
-
-enum class FragmentMode {
- kSingleChunk,
- kOctetByOctet,
-};
-
-FragmentSizeGenerator FragmentModeToFragmentSizeGenerator(
- FragmentMode fragment_mode);
-
-// Mock QpackUnidirectionalStreamSenderDelegate implementation.
-class MockQpackStreamSenderDelegate : public QpackStreamSenderDelegate {
- public:
- ~MockQpackStreamSenderDelegate() override = default;
-
- MOCK_METHOD1(WriteStreamData, void(QuicStringPiece data));
-};
-
-} // namespace test
-} // namespace quic
-
-#endif // QUICHE_QUIC_CORE_QPACK_QPACK_TEST_UTILS_H_
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_utils.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_utils.h
deleted file mode 100644
index 1b63422d4ac..00000000000
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_utils.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright (c) 2019 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 QUICHE_QUIC_CORE_QPACK_QPACK_UTILS_H_
-#define QUICHE_QUIC_CORE_QPACK_QPACK_UTILS_H_
-
-#include "net/third_party/quiche/src/quic/core/qpack/qpack_stream_sender_delegate.h"
-
-namespace quic {
-// TODO(renjietang): Move this class to qpack_test_utils.h once it is not needed
-// in QuicSpdySession.
-class QUIC_EXPORT_PRIVATE NoopQpackStreamSenderDelegate
- : public QpackStreamSenderDelegate {
- public:
- ~NoopQpackStreamSenderDelegate() override = default;
-
- void WriteStreamData(QuicStringPiece /*data*/) override {}
-};
-
-} // namespace quic
-
-#endif // QUICHE_QUIC_CORE_QPACK_QPACK_UTILS_H_
diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/value_splitting_header_list_test.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/value_splitting_header_list_test.cc
index 03a5eb03def..bab52386512 100644
--- a/chromium/net/third_party/quiche/src/quic/core/qpack/value_splitting_header_list_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/core/qpack/value_splitting_header_list_test.cc
@@ -60,10 +60,16 @@ TEST(ValueSplittingHeaderListTest, Comparison) {
EXPECT_FALSE(it1 == it2);
EXPECT_TRUE(it1 != it2);
}
- ++it2;
+ if (j < kEnd - 1) {
+ ASSERT_NE(it2, headers.end());
+ ++it2;
+ }
}
- ++it1;
+ if (i < kEnd - 1) {
+ ASSERT_NE(it1, headers.end());
+ ++it1;
+ }
}
}
@@ -75,37 +81,37 @@ TEST(ValueSplittingHeaderListTest, Empty) {
EXPECT_EQ(headers.begin(), headers.end());
}
-struct {
- const char* name;
- QuicStringPiece value;
- std::vector<const char*> expected_values;
-} kTestData[]{
- // Empty value.
- {"foo", "", {""}},
- // Trivial case.
- {"foo", "bar", {"bar"}},
- // Simple split.
- {"foo", {"bar\0baz", 7}, {"bar", "baz"}},
- {"cookie", "foo;bar", {"foo", "bar"}},
- {"cookie", "foo; bar", {"foo", "bar"}},
- // Empty fragments with \0 separator.
- {"foo", {"\0", 1}, {"", ""}},
- {"bar", {"foo\0", 4}, {"foo", ""}},
- {"baz", {"\0bar", 4}, {"", "bar"}},
- {"qux", {"\0foobar\0", 8}, {"", "foobar", ""}},
- // Empty fragments with ";" separator.
- {"cookie", ";", {"", ""}},
- {"cookie", "foo;", {"foo", ""}},
- {"cookie", ";bar", {"", "bar"}},
- {"cookie", ";foobar;", {"", "foobar", ""}},
- // Empty fragments with "; " separator.
- {"cookie", "; ", {"", ""}},
- {"cookie", "foo; ", {"foo", ""}},
- {"cookie", "; bar", {"", "bar"}},
- {"cookie", "; foobar; ", {"", "foobar", ""}},
-};
-
TEST(ValueSplittingHeaderListTest, Split) {
+ struct {
+ const char* name;
+ QuicStringPiece value;
+ std::vector<const char*> expected_values;
+ } kTestData[]{
+ // Empty value.
+ {"foo", "", {""}},
+ // Trivial case.
+ {"foo", "bar", {"bar"}},
+ // Simple split.
+ {"foo", {"bar\0baz", 7}, {"bar", "baz"}},
+ {"cookie", "foo;bar", {"foo", "bar"}},
+ {"cookie", "foo; bar", {"foo", "bar"}},
+ // Empty fragments with \0 separator.
+ {"foo", {"\0", 1}, {"", ""}},
+ {"bar", {"foo\0", 4}, {"foo", ""}},
+ {"baz", {"\0bar", 4}, {"", "bar"}},
+ {"qux", {"\0foobar\0", 8}, {"", "foobar", ""}},
+ // Empty fragments with ";" separator.
+ {"cookie", ";", {"", ""}},
+ {"cookie", "foo;", {"foo", ""}},
+ {"cookie", ";bar", {"", "bar"}},
+ {"cookie", ";foobar;", {"", "foobar", ""}},
+ // Empty fragments with "; " separator.
+ {"cookie", "; ", {"", ""}},
+ {"cookie", "foo; ", {"foo", ""}},
+ {"cookie", "; bar", {"", "bar"}},
+ {"cookie", "; foobar; ", {"", "foobar", ""}},
+ };
+
for (size_t i = 0; i < QUIC_ARRAYSIZE(kTestData); ++i) {
spdy::SpdyHeaderBlock block;
block[kTestData[i].name] = kTestData[i].value;