blob: e4f7218f7405a06831fca93dee78c6f6eddb8f49 [file] [log] [blame]
QUICHE team82dee2f2019-01-18 12:35:12 -05001// Copyright 2016 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "net/third_party/quiche/src/spdy/core/spdy_deframer_visitor.h"
6
7#include <stdlib.h>
8
9#include <algorithm>
10#include <limits>
11
QUICHE team82dee2f2019-01-18 12:35:12 -050012#include "testing/gtest/include/gtest/gtest.h"
13#include "net/third_party/quiche/src/http2/test_tools/http2_random.h"
14#include "net/third_party/quiche/src/spdy/core/hpack/hpack_constants.h"
15#include "net/third_party/quiche/src/spdy/core/mock_spdy_framer_visitor.h"
16#include "net/third_party/quiche/src/spdy/core/spdy_frame_builder.h"
17#include "net/third_party/quiche/src/spdy/core/spdy_frame_reader.h"
18#include "net/third_party/quiche/src/spdy/core/spdy_framer.h"
19#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h"
20#include "net/third_party/quiche/src/spdy/core/spdy_protocol_test_utils.h"
21#include "net/third_party/quiche/src/spdy/core/spdy_test_utils.h"
QUICHE teamded03512019-03-07 14:45:11 -080022#include "net/third_party/quiche/src/spdy/platform/api/spdy_logging.h"
QUICHE team82dee2f2019-01-18 12:35:12 -050023#include "net/third_party/quiche/src/spdy/platform/api/spdy_ptr_util.h"
24
25namespace spdy {
26namespace test {
27namespace {
28
29class SpdyDeframerVisitorTest : public ::testing::Test {
30 protected:
31 SpdyDeframerVisitorTest() : encoder_(SpdyFramer::ENABLE_COMPRESSION) {
32 decoder_.set_process_single_input_frame(true);
33 auto collector =
34 SpdyMakeUnique<DeframerCallbackCollector>(&collected_frames_);
35 auto log_and_collect =
36 SpdyDeframerVisitorInterface::LogBeforeVisiting(std::move(collector));
37 deframer_ = SpdyTestDeframer::CreateConverter(std::move(log_and_collect));
38 decoder_.set_visitor(deframer_.get());
39 }
40
41 bool DeframeInput(const char* input, size_t size) {
42 size_t input_remaining = size;
43 while (input_remaining > 0 &&
44 decoder_.spdy_framer_error() ==
45 http2::Http2DecoderAdapter::SPDY_NO_ERROR) {
46 // To make the tests more interesting, we feed random (and small) chunks
47 // into the framer. This simulates getting strange-sized reads from
48 // the socket.
49 const size_t kMaxReadSize = 32;
50 size_t bytes_read =
51 (random_.Uniform(std::min(input_remaining, kMaxReadSize))) + 1;
52 size_t bytes_processed = decoder_.ProcessInput(input, bytes_read);
53 input_remaining -= bytes_processed;
54 input += bytes_processed;
55 if (decoder_.state() ==
56 http2::Http2DecoderAdapter::SPDY_READY_FOR_FRAME) {
57 deframer_->AtFrameEnd();
58 }
59 }
60 return (input_remaining == 0 &&
61 decoder_.spdy_framer_error() ==
62 http2::Http2DecoderAdapter::SPDY_NO_ERROR);
63 }
64
65 SpdyFramer encoder_;
66 http2::Http2DecoderAdapter decoder_;
67 std::vector<CollectedFrame> collected_frames_;
68 std::unique_ptr<SpdyTestDeframer> deframer_;
69
70 private:
71 http2::test::Http2Random random_;
72};
73
74TEST_F(SpdyDeframerVisitorTest, DataFrame) {
75 const char kFrameData[] = {
76 0x00, 0x00, 0x0d, // Length = 13.
77 0x00, // DATA
78 0x08, // PADDED
79 0x00, 0x00, 0x00, 0x01, // Stream 1
80 0x07, // Pad length field.
81 'h', 'e', 'l', 'l', // Data
82 'o', // More Data
83 0x00, 0x00, 0x00, 0x00, // Padding
84 0x00, 0x00, 0x00 // More Padding
85 };
86
87 EXPECT_TRUE(DeframeInput(kFrameData, sizeof kFrameData));
88 ASSERT_EQ(1u, collected_frames_.size());
89 const CollectedFrame& cf0 = collected_frames_[0];
90 ASSERT_NE(cf0.frame_ir, nullptr);
91
92 SpdyDataIR expected_ir(/* stream_id = */ 1, "hello");
93 expected_ir.set_padding_len(8);
94 EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir));
95}
96
97TEST_F(SpdyDeframerVisitorTest, HeaderFrameWithContinuation) {
98 const char kFrameData[] = {
99 0x00, 0x00, 0x05, // Payload Length: 5
100 0x01, // Type: HEADERS
101 0x09, // Flags: PADDED | END_STREAM
102 0x00, 0x00, 0x00, 0x01, // Stream: 1
103 0x04, // Padding Length: 4
104 0x00, 0x00, 0x00, 0x00, // Padding
105 /* Second Frame */
106 0x00, 0x00, 0x12, // Payload Length: 18
107 0x09, // Type: CONTINUATION
108 0x04, // Flags: END_HEADERS
109 0x00, 0x00, 0x00, 0x01, // Stream: 1
110 0x00, // Unindexed, literal name & value
111 0x03, 0x62, 0x61, 0x72, // Name len and name (3, "bar")
112 0x03, 0x66, 0x6f, 0x6f, // Value len and value (3, "foo")
113 0x00, // Unindexed, literal name & value
114 0x03, 0x66, 0x6f, 0x6f, // Name len and name (3, "foo")
115 0x03, 0x62, 0x61, 0x72, // Value len and value (3, "bar")
116 };
117
118 EXPECT_TRUE(DeframeInput(kFrameData, sizeof kFrameData));
119 ASSERT_EQ(1u, collected_frames_.size());
120 const CollectedFrame& cf0 = collected_frames_[0];
121
122 StringPairVector headers;
123 headers.push_back({"bar", "foo"});
124 headers.push_back({"foo", "bar"});
125
126 EXPECT_TRUE(cf0.VerifyHasHeaders(headers));
127
128 SpdyHeadersIR expected_ir(/* stream_id = */ 1);
129 // Yet again SpdyFramerVisitorInterface is lossy: it doesn't call OnPadding
130 // for HEADERS, just for DATA. Sigh.
131 // expected_ir.set_padding_len(5);
132 expected_ir.set_fin(true);
133 for (const auto& nv : headers) {
134 expected_ir.SetHeader(nv.first, nv.second);
135 }
136
137 EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir));
138
139 // Confirm that mismatches are also detected.
140 headers.push_back({"baz", "bing"});
141 EXPECT_FALSE(cf0.VerifyHasHeaders(headers));
142 EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir));
143
144 headers.pop_back();
145 EXPECT_TRUE(cf0.VerifyHasHeaders(headers));
146 EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir));
147
148 expected_ir.SetHeader("baz", "bing");
149 EXPECT_FALSE(cf0.VerifyHasFrame(expected_ir));
150 EXPECT_TRUE(cf0.VerifyHasHeaders(headers));
151}
152
153TEST_F(SpdyDeframerVisitorTest, PriorityFrame) {
154 const char kFrameData[] = {
155 0x00, 0x00, 0x05, // Length: 5
156 0x02, // Type: PRIORITY
157 0x00, // Flags: none
158 0x00, 0x00, 0x00, 0x65, // Stream: 101
159 '\x80', 0x00, 0x00, 0x01, // Parent: 1 (Exclusive)
160 0x10, // Weight: 17
161 };
162
163 EXPECT_TRUE(DeframeInput(kFrameData, sizeof kFrameData));
164 ASSERT_EQ(1u, collected_frames_.size());
165 const CollectedFrame& cf0 = collected_frames_[0];
166
167 SpdyPriorityIR expected_ir(/* stream_id = */ 101,
168 /* parent_stream_id = */ 1, /* weight = */ 17,
169 /* exclusive = */ true);
170 EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir));
171
172 // Confirm that mismatches are also detected.
173 EXPECT_FALSE(cf0.VerifyHasFrame(SpdyPriorityIR(101, 1, 16, true)));
174 EXPECT_FALSE(cf0.VerifyHasFrame(SpdyPriorityIR(101, 50, 17, true)));
175 EXPECT_FALSE(cf0.VerifyHasFrame(SpdyPriorityIR(201, 1, 17, true)));
176 EXPECT_FALSE(cf0.VerifyHasFrame(SpdyPriorityIR(101, 1, 17, false)));
177}
178
179TEST_F(SpdyDeframerVisitorTest, DISABLED_RstStreamFrame) {
180 // TODO(jamessynge): Please implement.
181}
182
183TEST_F(SpdyDeframerVisitorTest, SettingsFrame) {
184 // Settings frame with two entries for the same parameter but with different
185 // values. The last one will be in the decoded SpdySettingsIR, but the vector
186 // of settings will have both, in the same order.
187 const char kFrameData[] = {
188 0x00, 0x00, 0x0c, // Length
189 0x04, // Type (SETTINGS)
190 0x00, // Flags
191 0x00, 0x00, 0x00, 0x00, // Stream id (must be zero)
192 0x00, 0x04, // Setting id (SETTINGS_INITIAL_WINDOW_SIZE)
193 0x0a, 0x0b, 0x0c, 0x0d, // Setting value
194 0x00, 0x04, // Setting id (SETTINGS_INITIAL_WINDOW_SIZE)
195 0x00, 0x00, 0x00, '\xff', // Setting value
196 };
197
198 EXPECT_TRUE(DeframeInput(kFrameData, sizeof kFrameData));
199 ASSERT_EQ(1u, collected_frames_.size());
200 const CollectedFrame& cf0 = collected_frames_[0];
201 ASSERT_NE(cf0.frame_ir, nullptr);
202
203 SpdySettingsIR expected_ir;
204 expected_ir.AddSetting(SETTINGS_INITIAL_WINDOW_SIZE, 255);
205 EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir));
206
207 SettingVector expected_settings;
208 expected_settings.push_back({SETTINGS_INITIAL_WINDOW_SIZE, 0x0a0b0c0d});
209 expected_settings.push_back({SETTINGS_INITIAL_WINDOW_SIZE, 255});
210
211 EXPECT_TRUE(cf0.VerifyHasSettings(expected_settings));
212
213 // Confirm that mismatches are also detected.
214 expected_settings.push_back({SETTINGS_INITIAL_WINDOW_SIZE, 65536});
215 EXPECT_FALSE(cf0.VerifyHasSettings(expected_settings));
216
217 expected_ir.AddSetting(SETTINGS_INITIAL_WINDOW_SIZE, 65536);
218 EXPECT_FALSE(cf0.VerifyHasFrame(expected_ir));
219
220 SpdySettingsIR unexpected_ir;
221 unexpected_ir.set_is_ack(true);
222 EXPECT_FALSE(cf0.VerifyHasFrame(unexpected_ir));
223}
224
225TEST_F(SpdyDeframerVisitorTest, DISABLED_PushPromiseFrame) {
226 // TODO(jamessynge): Please implement.
227}
228
229TEST_F(SpdyDeframerVisitorTest, DISABLED_PingFrame) {
230 // TODO(jamessynge): Please implement.
231}
232
233TEST_F(SpdyDeframerVisitorTest, DISABLED_GoAwayFrame) {
234 // TODO(jamessynge): Please implement.
235}
236
237TEST_F(SpdyDeframerVisitorTest, DISABLED_WindowUpdateFrame) {
238 // TODO(jamessynge): Please implement.
239}
240
241TEST_F(SpdyDeframerVisitorTest, DISABLED_AltSvcFrame) {
242 // TODO(jamessynge): Please implement.
243}
244
245} // namespace
246} // namespace test
247} // namespace spdy