chromium/net/third_party/quiche/src/quiche/http2/core/spdy_framer_test.cc

// Copyright (c) 2012 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 "quiche/http2/core/spdy_framer.h"

#include <stdlib.h>

#include <algorithm>
#include <cstdint>
#include <cstring>
#include <ios>
#include <limits>
#include <memory>
#include <string>
#include <utility>
#include <vector>

#include "absl/base/macros.h"
#include "absl/strings/string_view.h"
#include "quiche/http2/core/array_output_buffer.h"
#include "quiche/http2/core/http2_frame_decoder_adapter.h"
#include "quiche/http2/core/recording_headers_handler.h"
#include "quiche/http2/core/spdy_alt_svc_wire_format.h"
#include "quiche/http2/core/spdy_bitmasks.h"
#include "quiche/http2/core/spdy_frame_builder.h"
#include "quiche/http2/core/spdy_headers_handler_interface.h"
#include "quiche/http2/core/spdy_protocol.h"
#include "quiche/http2/hpack/hpack_encoder.h"
#include "quiche/http2/test_tools/mock_spdy_framer_visitor.h"
#include "quiche/http2/test_tools/spdy_test_utils.h"
#include "quiche/common/platform/api/quiche_logging.h"
#include "quiche/common/platform/api/quiche_test.h"
#include "quiche/common/quiche_text_utils.h"
#include "quiche/spdy/core/http2_header_block.h"

Http2DecoderAdapter;
_;

namespace spdy {

namespace test {

namespace {

const int64_t kSize =;
char output_buffer[kSize] =;

// frame_list_char is used to hold frames to be compared with output_buffer.
const int64_t buffer_size =;
char frame_list_char[buffer_size] =;
}  // namespace

class MockDebugVisitor : public SpdyFramerDebugVisitorInterface {};

MATCHER_P(IsFrameUnionOf, frame_list, "") {}

class SpdyFramerPeer {};

class TestSpdyVisitor : public SpdyFramerVisitorInterface,
                        public SpdyFramerDebugVisitorInterface {};

class TestExtension : public ExtensionVisitorInterface {};

// Exposes SpdyUnknownIR::set_length() for testing purposes.
class TestSpdyUnknownIR : public SpdyUnknownIR {};

enum Output {};

class SpdyFramerTest : public quiche::test::QuicheTestWithParam<Output> {};

INSTANTIATE_TEST_SUITE_P();

// Test that we can encode and decode a Http2HeaderBlock in serialized form.
TEST_P(SpdyFramerTest, HeaderBlockInBuffer) {}

// Test that if there's not a full frame, we fail to parse it.
TEST_P(SpdyFramerTest, UndersizedHeaderBlockInBuffer) {}

// Test that we can encode and decode stream dependency values in a header
// frame.
TEST_P(SpdyFramerTest, HeaderStreamDependencyValues) {}

// Test that if we receive a frame with a payload length field at the default
// max size, we do not set an error in ProcessInput.
TEST_P(SpdyFramerTest, AcceptMaxFrameSizeSetting) {}

// Test that if we receive a frame with a payload length larger than the default
// max size, we set an error of SPDY_INVALID_CONTROL_FRAME_SIZE.
TEST_P(SpdyFramerTest, ExceedMaxFrameSizeSetting) {}

// Test that if we set a larger max frame size and then receive a frame with a
// payload length at that larger size, we do not set an error in ProcessInput.
TEST_P(SpdyFramerTest, AcceptLargerMaxFrameSizeSetting) {}

// Test that if we receive a DATA frame with padding length larger than the
// payload length, we set an error of SPDY_INVALID_PADDING
TEST_P(SpdyFramerTest, OversizedDataPaddingError) {}

// Test that if we receive a DATA frame with padding length not larger than the
// payload length, we do not set an error of SPDY_INVALID_PADDING
TEST_P(SpdyFramerTest, CorrectlySizedDataPaddingNoError) {}

// Test that if we receive a HEADERS frame with padding length larger than the
// payload length, we set an error of SPDY_INVALID_PADDING
TEST_P(SpdyFramerTest, OversizedHeadersPaddingError) {}

// Test that if we receive a HEADERS frame with padding length not larger
// than the payload length, we do not set an error of SPDY_INVALID_PADDING
TEST_P(SpdyFramerTest, CorrectlySizedHeadersPaddingNoError) {}

// Test that if we receive a DATA with stream ID zero, we signal an error
// (but don't crash).
TEST_P(SpdyFramerTest, DataWithStreamIdZero) {}

// Test that if we receive a HEADERS with stream ID zero, we signal an error
// (but don't crash).
TEST_P(SpdyFramerTest, HeadersWithStreamIdZero) {}

// Test that if we receive a PRIORITY with stream ID zero, we signal an error
// (but don't crash).
TEST_P(SpdyFramerTest, PriorityWithStreamIdZero) {}

// Test that if we receive a RST_STREAM with stream ID zero, we signal an error
// (but don't crash).
TEST_P(SpdyFramerTest, RstStreamWithStreamIdZero) {}

// Test that if we receive a SETTINGS with stream ID other than zero,
// we signal an error (but don't crash).
TEST_P(SpdyFramerTest, SettingsWithStreamIdNotZero) {}

// Test that if we receive a GOAWAY with stream ID other than zero,
// we signal an error (but don't crash).
TEST_P(SpdyFramerTest, GoawayWithStreamIdNotZero) {}

// Test that if we receive a CONTINUATION with stream ID zero, we signal
// SPDY_INVALID_STREAM_ID.
TEST_P(SpdyFramerTest, ContinuationWithStreamIdZero) {}

// Test that if we receive a PUSH_PROMISE with stream ID zero, we signal
// SPDY_INVALID_STREAM_ID.
TEST_P(SpdyFramerTest, PushPromiseWithStreamIdZero) {}

// Test that if we receive a PUSH_PROMISE with promised stream ID zero, we
// signal SPDY_INVALID_CONTROL_FRAME.
TEST_P(SpdyFramerTest, PushPromiseWithPromisedStreamIdZero) {}

TEST_P(SpdyFramerTest, MultiValueHeader) {}

TEST_P(SpdyFramerTest, CompressEmptyHeaders) {}

TEST_P(SpdyFramerTest, Basic) {}

// Verifies that the decoder stops delivering events after a user error.
TEST_P(SpdyFramerTest, BasicWithError) {}

// Test that the FIN flag on a data frame signifies EOF.
TEST_P(SpdyFramerTest, FinOnDataFrame) {}

TEST_P(SpdyFramerTest, FinOnHeadersFrame) {}

// Verify we can decompress the stream even if handed over to the
// framer 1 byte at a time.
TEST_P(SpdyFramerTest, UnclosedStreamDataCompressorsOneByteAtATime) {}

TEST_P(SpdyFramerTest, WindowUpdateFrame) {}

TEST_P(SpdyFramerTest, CreateDataFrame) {}

TEST_P(SpdyFramerTest, CreateRstStream) {}

TEST_P(SpdyFramerTest, CreateSettings) {}

TEST_P(SpdyFramerTest, CreatePingFrame) {}

TEST_P(SpdyFramerTest, CreateGoAway) {}

TEST_P(SpdyFramerTest, CreateHeadersUncompressed) {}

TEST_P(SpdyFramerTest, CreateWindowUpdate) {}

TEST_P(SpdyFramerTest, CreatePushPromiseUncompressed) {}

// Regression test for https://crbug.com/464748.
TEST_P(SpdyFramerTest, GetNumberRequiredContinuationFrames) {}

TEST_P(SpdyFramerTest, CreateContinuationUncompressed) {}

// Test that if we send an unexpected CONTINUATION
// we signal an error (but don't crash).
TEST_P(SpdyFramerTest, SendUnexpectedContinuation) {}

TEST_P(SpdyFramerTest, CreatePushPromiseThenContinuationUncompressed) {}

TEST_P(SpdyFramerTest, CreateAltSvc) {}

TEST_P(SpdyFramerTest, CreatePriority) {}

TEST_P(SpdyFramerTest, CreatePriorityUpdate) {}

TEST_P(SpdyFramerTest, CreateAcceptCh) {}

TEST_P(SpdyFramerTest, CreateUnknown) {}

// Test serialization of a SpdyUnknownIR with a defined type, a length field
// that does not match the payload size and in fact exceeds framer limits, and a
// stream ID that effectively flips the reserved bit.
TEST_P(SpdyFramerTest, CreateUnknownUnchecked) {}

TEST_P(SpdyFramerTest, ReadCompressedHeadersHeaderBlock) {}

TEST_P(SpdyFramerTest, ReadCompressedHeadersHeaderBlockWithHalfClose) {}

TEST_P(SpdyFramerTest, TooLargeHeadersFrameUsesContinuation) {}

TEST_P(SpdyFramerTest, MultipleContinuationFramesWithIterator) {}

TEST_P(SpdyFramerTest, PushPromiseFramesWithIterator) {}

class SpdyControlFrameIteratorTest : public quiche::test::QuicheTest {};

TEST_F(SpdyControlFrameIteratorTest, RstStreamFrameWithIterator) {}

TEST_F(SpdyControlFrameIteratorTest, SettingsFrameWithIterator) {}

TEST_F(SpdyControlFrameIteratorTest, PingFrameWithIterator) {}

TEST_F(SpdyControlFrameIteratorTest, GoAwayFrameWithIterator) {}

TEST_F(SpdyControlFrameIteratorTest, WindowUpdateFrameWithIterator) {}

TEST_F(SpdyControlFrameIteratorTest, AtlSvcFrameWithIterator) {}

TEST_F(SpdyControlFrameIteratorTest, PriorityFrameWithIterator) {}

TEST_P(SpdyFramerTest, TooLargePushPromiseFrameUsesContinuation) {}

// Check that the framer stops delivering header data chunks once the visitor
// declares it doesn't want any more. This is important to guard against
// "zip bomb" types of attacks.
TEST_P(SpdyFramerTest, ControlFrameMuchTooLarge) {}

TEST_P(SpdyFramerTest, ControlFrameSizesAreValidated) {}

TEST_P(SpdyFramerTest, ReadZeroLenSettingsFrame) {}

// Tests handling of SETTINGS frames with invalid length.
TEST_P(SpdyFramerTest, ReadBogusLenSettingsFrame) {}

// Tests handling of larger SETTINGS frames.
TEST_P(SpdyFramerTest, ReadLargeSettingsFrame) {}

// Tests handling of SETTINGS frame with duplicate entries.
TEST_P(SpdyFramerTest, ReadDuplicateSettings) {}

// Tests handling of SETTINGS frame with a setting we don't recognize.
TEST_P(SpdyFramerTest, ReadUnknownSettingsId) {}

TEST_P(SpdyFramerTest, ReadKnownAndUnknownSettingsWithExtension) {}

// Tests handling of SETTINGS frame with entries out of order.
TEST_P(SpdyFramerTest, ReadOutOfOrderSettings) {}

TEST_P(SpdyFramerTest, ProcessSettingsAckFrame) {}

TEST_P(SpdyFramerTest, ProcessDataFrameWithPadding) {}

TEST_P(SpdyFramerTest, ReadWindowUpdate) {}

TEST_P(SpdyFramerTest, ReadCompressedPushPromise) {}

TEST_P(SpdyFramerTest, ReadHeadersWithContinuation) {}

TEST_P(SpdyFramerTest, ReadHeadersWithContinuationAndFin) {}

TEST_P(SpdyFramerTest, ReadPushPromiseWithContinuation) {}

// Receiving an unknown frame when a continuation is expected should
// result in a SPDY_UNEXPECTED_FRAME error
TEST_P(SpdyFramerTest, ReceiveUnknownMidContinuation) {}

// Receiving an unknown frame when a continuation is expected should
// result in a SPDY_UNEXPECTED_FRAME error
TEST_P(SpdyFramerTest, ReceiveUnknownMidContinuationWithExtension) {}

TEST_P(SpdyFramerTest, ReceiveContinuationOnWrongStream) {}

TEST_P(SpdyFramerTest, ReadContinuationOutOfOrder) {}

TEST_P(SpdyFramerTest, ExpectContinuationReceiveData) {}

TEST_P(SpdyFramerTest, ExpectContinuationReceiveControlFrame) {}

TEST_P(SpdyFramerTest, ReadGarbage) {}

TEST_P(SpdyFramerTest, ReadUnknownExtensionFrame) {}

TEST_P(SpdyFramerTest, ReadUnknownExtensionFrameWithExtension) {}

TEST_P(SpdyFramerTest, ReadGarbageWithValidLength) {}

TEST_P(SpdyFramerTest, ReadGarbageHPACKEncoding) {}

TEST_P(SpdyFramerTest, SizesTest) {}

TEST_P(SpdyFramerTest, StateToStringTest) {}

TEST_P(SpdyFramerTest, SpdyFramerErrorToStringTest) {}

TEST_P(SpdyFramerTest, DataFrameFlagsV4) {}

TEST_P(SpdyFramerTest, RstStreamFrameFlags) {}

TEST_P(SpdyFramerTest, SettingsFrameFlags) {}

TEST_P(SpdyFramerTest, GoawayFrameFlags) {}

TEST_P(SpdyFramerTest, HeadersFrameFlags) {}

TEST_P(SpdyFramerTest, PingFrameFlags) {}

TEST_P(SpdyFramerTest, WindowUpdateFrameFlags) {}

TEST_P(SpdyFramerTest, PushPromiseFrameFlags) {}

TEST_P(SpdyFramerTest, ContinuationFrameFlags) {}

// TODO(mlavan): Add TEST_P(SpdyFramerTest, AltSvcFrameFlags)

// Test handling of a RST_STREAM with out-of-bounds status codes.
TEST_P(SpdyFramerTest, RstStreamStatusBounds) {}

// Test handling of GOAWAY frames with out-of-bounds status code.
TEST_P(SpdyFramerTest, GoAwayStatusBounds) {}

// Tests handling of a GOAWAY frame with out-of-bounds stream ID.
TEST_P(SpdyFramerTest, GoAwayStreamIdBounds) {}

TEST_P(SpdyFramerTest, OnAltSvcWithOrigin) {}

TEST_P(SpdyFramerTest, OnAltSvcNoOrigin) {}

TEST_P(SpdyFramerTest, OnAltSvcEmptyProtocolId) {}

TEST_P(SpdyFramerTest, OnAltSvcBadLengths) {}

// Tests handling of ALTSVC frames delivered in small chunks.
TEST_P(SpdyFramerTest, ReadChunkedAltSvcFrame) {}

// While RFC7838 Section 4 says that an ALTSVC frame on stream 0 with empty
// origin MUST be ignored, it is not implemented at the framer level: instead,
// such frames are passed on to the consumer.
TEST_P(SpdyFramerTest, ReadAltSvcFrame) {}

// An ALTSVC frame with invalid Alt-Svc-Field-Value results in an error.
TEST_P(SpdyFramerTest, ErrorOnAltSvcFrameWithInvalidValue) {}

TEST_P(SpdyFramerTest, ReadPriorityUpdateFrame) {}

TEST_P(SpdyFramerTest, ReadPriorityUpdateFrameWithEmptyPriorityFieldValue) {}

TEST_P(SpdyFramerTest, PriorityUpdateFrameWithEmptyPayload) {}

TEST_P(SpdyFramerTest, PriorityUpdateFrameWithShortPayload) {}

TEST_P(SpdyFramerTest, PriorityUpdateFrameOnIncorrectStream) {}

TEST_P(SpdyFramerTest, PriorityUpdateFramePrioritizingIncorrectStream) {}

// Tests handling of PRIORITY frames.
TEST_P(SpdyFramerTest, ReadPriority) {}

// Tests handling of PRIORITY frame with incorrect size.
TEST_P(SpdyFramerTest, ReadIncorrectlySizedPriority) {}

// Tests handling of PING frame with incorrect size.
TEST_P(SpdyFramerTest, ReadIncorrectlySizedPing) {}

// Tests handling of WINDOW_UPDATE frame with incorrect size.
TEST_P(SpdyFramerTest, ReadIncorrectlySizedWindowUpdate) {}

// Tests handling of RST_STREAM frame with incorrect size.
TEST_P(SpdyFramerTest, ReadIncorrectlySizedRstStream) {}

// Regression test for https://crbug.com/548674:
// RST_STREAM with payload must not be accepted.
TEST_P(SpdyFramerTest, ReadInvalidRstStreamWithPayload) {}

// Test that SpdyFramer processes all passed input in one call to ProcessInput.
TEST_P(SpdyFramerTest, ProcessAllInput) {}

namespace {
void CheckFrameAndIRSize(SpdyFrameIR* ir, SpdyFramer* framer,
                         ArrayOutputBuffer* array_output_buffer) {}
}  // namespace

TEST_P(SpdyFramerTest, SpdyFrameIRSize) {}

}  // namespace test

}  // namespace spdy