1 // Copyright (c) 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 "quiche/quic/core/http/quic_spdy_server_stream_base.h"
6
7 #include "absl/memory/memory.h"
8 #include "quiche/quic/core/crypto/null_encrypter.h"
9 #include "quiche/quic/platform/api/quic_flags.h"
10 #include "quiche/quic/platform/api/quic_test.h"
11 #include "quiche/quic/test_tools/qpack/qpack_test_utils.h"
12 #include "quiche/quic/test_tools/quic_spdy_session_peer.h"
13 #include "quiche/quic/test_tools/quic_stream_peer.h"
14 #include "quiche/quic/test_tools/quic_test_utils.h"
15 #include "quiche/spdy/core/http2_header_block.h"
16
17 using testing::_;
18
19 namespace quic {
20 namespace test {
21 namespace {
22
23 class TestQuicSpdyServerStream : public QuicSpdyServerStreamBase {
24 public:
TestQuicSpdyServerStream(QuicStreamId id,QuicSpdySession * session,StreamType type)25 TestQuicSpdyServerStream(QuicStreamId id, QuicSpdySession* session,
26 StreamType type)
27 : QuicSpdyServerStreamBase(id, session, type) {}
28
OnBodyAvailable()29 void OnBodyAvailable() override {}
30 };
31
32 class QuicSpdyServerStreamBaseTest : public QuicTest {
33 protected:
QuicSpdyServerStreamBaseTest()34 QuicSpdyServerStreamBaseTest()
35 : session_(new MockQuicConnection(&helper_, &alarm_factory_,
36 Perspective::IS_SERVER)) {
37 session_.Initialize();
38 session_.connection()->SetEncrypter(
39 ENCRYPTION_FORWARD_SECURE,
40 std::make_unique<NullEncrypter>(session_.perspective()));
41 stream_ =
42 new TestQuicSpdyServerStream(GetNthClientInitiatedBidirectionalStreamId(
43 session_.transport_version(), 0),
44 &session_, BIDIRECTIONAL);
45 session_.ActivateStream(absl::WrapUnique(stream_));
46 helper_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
47 }
48
49 QuicSpdyServerStreamBase* stream_ = nullptr;
50 MockQuicConnectionHelper helper_;
51 MockAlarmFactory alarm_factory_;
52 MockQuicSpdySession session_;
53 };
54
TEST_F(QuicSpdyServerStreamBaseTest,SendQuicRstStreamNoErrorWithEarlyResponse)55 TEST_F(QuicSpdyServerStreamBaseTest,
56 SendQuicRstStreamNoErrorWithEarlyResponse) {
57 stream_->StopReading();
58
59 if (session_.version().UsesHttp3()) {
60 EXPECT_CALL(session_,
61 MaybeSendStopSendingFrame(_, QuicResetStreamError::FromInternal(
62 QUIC_STREAM_NO_ERROR)))
63 .Times(1);
64 } else {
65 EXPECT_CALL(
66 session_,
67 MaybeSendRstStreamFrame(
68 _, QuicResetStreamError::FromInternal(QUIC_STREAM_NO_ERROR), _))
69 .Times(1);
70 }
71 QuicStreamPeer::SetFinSent(stream_);
72 stream_->CloseWriteSide();
73 }
74
TEST_F(QuicSpdyServerStreamBaseTest,DoNotSendQuicRstStreamNoErrorWithRstReceived)75 TEST_F(QuicSpdyServerStreamBaseTest,
76 DoNotSendQuicRstStreamNoErrorWithRstReceived) {
77 EXPECT_FALSE(stream_->reading_stopped());
78
79 EXPECT_CALL(session_,
80 MaybeSendRstStreamFrame(
81 _,
82 QuicResetStreamError::FromInternal(
83 VersionHasIetfQuicFrames(session_.transport_version())
84 ? QUIC_STREAM_CANCELLED
85 : QUIC_RST_ACKNOWLEDGEMENT),
86 _))
87 .Times(1);
88 QuicRstStreamFrame rst_frame(kInvalidControlFrameId, stream_->id(),
89 QUIC_STREAM_CANCELLED, 1234);
90 stream_->OnStreamReset(rst_frame);
91 if (VersionHasIetfQuicFrames(session_.transport_version())) {
92 // Create and inject a STOP SENDING frame to complete the close
93 // of the stream. This is only needed for version 99/IETF QUIC.
94 QuicStopSendingFrame stop_sending(kInvalidControlFrameId, stream_->id(),
95 QUIC_STREAM_CANCELLED);
96 session_.OnStopSendingFrame(stop_sending);
97 }
98
99 EXPECT_TRUE(stream_->reading_stopped());
100 EXPECT_TRUE(stream_->write_side_closed());
101 }
102
TEST_F(QuicSpdyServerStreamBaseTest,AllowExtendedConnect)103 TEST_F(QuicSpdyServerStreamBaseTest, AllowExtendedConnect) {
104 QuicHeaderList header_list;
105 header_list.OnHeaderBlockStart();
106 header_list.OnHeader(":authority", "www.google.com:4433");
107 header_list.OnHeader(":method", "CONNECT");
108 header_list.OnHeader(":protocol", "webtransport");
109 header_list.OnHeader(":path", "/path");
110 header_list.OnHeader(":scheme", "http");
111 header_list.OnHeaderBlockEnd(128, 128);
112 stream_->OnStreamHeaderList(/*fin=*/false, 0, header_list);
113 EXPECT_EQ(GetQuicReloadableFlag(quic_act_upon_invalid_header) &&
114 !session_.allow_extended_connect(),
115 stream_->rst_sent());
116 }
117
TEST_F(QuicSpdyServerStreamBaseTest,AllowExtendedConnectProtocolFirst)118 TEST_F(QuicSpdyServerStreamBaseTest, AllowExtendedConnectProtocolFirst) {
119 QuicHeaderList header_list;
120 header_list.OnHeaderBlockStart();
121 header_list.OnHeader(":protocol", "webtransport");
122 header_list.OnHeader(":authority", "www.google.com:4433");
123 header_list.OnHeader(":method", "CONNECT");
124 header_list.OnHeader(":path", "/path");
125 header_list.OnHeader(":scheme", "http");
126 header_list.OnHeaderBlockEnd(128, 128);
127 stream_->OnStreamHeaderList(/*fin=*/false, 0, header_list);
128 EXPECT_EQ(GetQuicReloadableFlag(quic_act_upon_invalid_header) &&
129 !session_.allow_extended_connect(),
130 stream_->rst_sent());
131 }
132
TEST_F(QuicSpdyServerStreamBaseTest,InvalidExtendedConnect)133 TEST_F(QuicSpdyServerStreamBaseTest, InvalidExtendedConnect) {
134 if (!session_.version().UsesHttp3()) {
135 return;
136 }
137 SetQuicReloadableFlag(quic_act_upon_invalid_header, true);
138 QuicHeaderList header_list;
139 header_list.OnHeaderBlockStart();
140 header_list.OnHeader(":authority", "www.google.com:4433");
141 header_list.OnHeader(":method", "CONNECT");
142 header_list.OnHeader(":protocol", "webtransport");
143 header_list.OnHeader(":scheme", "http");
144 header_list.OnHeaderBlockEnd(128, 128);
145
146 EXPECT_CALL(
147 session_,
148 MaybeSendRstStreamFrame(
149 _, QuicResetStreamError::FromInternal(QUIC_BAD_APPLICATION_PAYLOAD),
150 _));
151 stream_->OnStreamHeaderList(/*fin=*/false, 0, header_list);
152 EXPECT_TRUE(stream_->rst_sent());
153 }
154
TEST_F(QuicSpdyServerStreamBaseTest,VanillaConnectAllowed)155 TEST_F(QuicSpdyServerStreamBaseTest, VanillaConnectAllowed) {
156 QuicHeaderList header_list;
157 header_list.OnHeaderBlockStart();
158 header_list.OnHeader(":authority", "www.google.com:4433");
159 header_list.OnHeader(":method", "CONNECT");
160 header_list.OnHeaderBlockEnd(128, 128);
161 stream_->OnStreamHeaderList(/*fin=*/false, 0, header_list);
162 EXPECT_FALSE(stream_->rst_sent());
163 }
164
TEST_F(QuicSpdyServerStreamBaseTest,InvalidVanillaConnect)165 TEST_F(QuicSpdyServerStreamBaseTest, InvalidVanillaConnect) {
166 SetQuicReloadableFlag(quic_act_upon_invalid_header, true);
167 QuicHeaderList header_list;
168 header_list.OnHeaderBlockStart();
169 header_list.OnHeader(":authority", "www.google.com:4433");
170 header_list.OnHeader(":method", "CONNECT");
171 header_list.OnHeader(":scheme", "http");
172 header_list.OnHeaderBlockEnd(128, 128);
173
174 EXPECT_CALL(
175 session_,
176 MaybeSendRstStreamFrame(
177 _, QuicResetStreamError::FromInternal(QUIC_BAD_APPLICATION_PAYLOAD),
178 _));
179 stream_->OnStreamHeaderList(/*fin=*/false, 0, header_list);
180 EXPECT_TRUE(stream_->rst_sent());
181 }
182
TEST_F(QuicSpdyServerStreamBaseTest,InvalidNonConnectWithProtocol)183 TEST_F(QuicSpdyServerStreamBaseTest, InvalidNonConnectWithProtocol) {
184 SetQuicReloadableFlag(quic_act_upon_invalid_header, true);
185 QuicHeaderList header_list;
186 header_list.OnHeaderBlockStart();
187 header_list.OnHeader(":authority", "www.google.com:4433");
188 header_list.OnHeader(":method", "GET");
189 header_list.OnHeader(":scheme", "http");
190 header_list.OnHeader(":path", "/path");
191 header_list.OnHeader(":protocol", "webtransport");
192 header_list.OnHeaderBlockEnd(128, 128);
193
194 EXPECT_CALL(
195 session_,
196 MaybeSendRstStreamFrame(
197 _, QuicResetStreamError::FromInternal(QUIC_BAD_APPLICATION_PAYLOAD),
198 _));
199 stream_->OnStreamHeaderList(/*fin=*/false, 0, header_list);
200 EXPECT_TRUE(stream_->rst_sent());
201 }
202
TEST_F(QuicSpdyServerStreamBaseTest,InvalidRequestWithoutScheme)203 TEST_F(QuicSpdyServerStreamBaseTest, InvalidRequestWithoutScheme) {
204 SetQuicReloadableFlag(quic_act_upon_invalid_header, true);
205 // A request without :scheme should be rejected.
206 QuicHeaderList header_list;
207 header_list.OnHeaderBlockStart();
208 header_list.OnHeader(":authority", "www.google.com:4433");
209 header_list.OnHeader(":method", "GET");
210 header_list.OnHeader(":path", "/path");
211 header_list.OnHeaderBlockEnd(128, 128);
212
213 EXPECT_CALL(
214 session_,
215 MaybeSendRstStreamFrame(
216 _, QuicResetStreamError::FromInternal(QUIC_BAD_APPLICATION_PAYLOAD),
217 _));
218 stream_->OnStreamHeaderList(/*fin=*/false, 0, header_list);
219 EXPECT_TRUE(stream_->rst_sent());
220 }
221
TEST_F(QuicSpdyServerStreamBaseTest,InvalidRequestWithoutAuthority)222 TEST_F(QuicSpdyServerStreamBaseTest, InvalidRequestWithoutAuthority) {
223 SetQuicReloadableFlag(quic_act_upon_invalid_header, true);
224 // A request without :authority should be rejected.
225 QuicHeaderList header_list;
226 header_list.OnHeaderBlockStart();
227 header_list.OnHeader(":scheme", "http");
228 header_list.OnHeader(":method", "GET");
229 header_list.OnHeader(":path", "/path");
230 header_list.OnHeaderBlockEnd(128, 128);
231
232 EXPECT_CALL(
233 session_,
234 MaybeSendRstStreamFrame(
235 _, QuicResetStreamError::FromInternal(QUIC_BAD_APPLICATION_PAYLOAD),
236 _));
237 stream_->OnStreamHeaderList(/*fin=*/false, 0, header_list);
238 EXPECT_TRUE(stream_->rst_sent());
239 }
240
TEST_F(QuicSpdyServerStreamBaseTest,InvalidRequestWithoutMethod)241 TEST_F(QuicSpdyServerStreamBaseTest, InvalidRequestWithoutMethod) {
242 SetQuicReloadableFlag(quic_act_upon_invalid_header, true);
243 // A request without :method should be rejected.
244 QuicHeaderList header_list;
245 header_list.OnHeaderBlockStart();
246 header_list.OnHeader(":authority", "www.google.com:4433");
247 header_list.OnHeader(":scheme", "http");
248 header_list.OnHeader(":path", "/path");
249 header_list.OnHeaderBlockEnd(128, 128);
250
251 EXPECT_CALL(
252 session_,
253 MaybeSendRstStreamFrame(
254 _, QuicResetStreamError::FromInternal(QUIC_BAD_APPLICATION_PAYLOAD),
255 _));
256 stream_->OnStreamHeaderList(/*fin=*/false, 0, header_list);
257 EXPECT_TRUE(stream_->rst_sent());
258 }
259
TEST_F(QuicSpdyServerStreamBaseTest,InvalidRequestWithoutPath)260 TEST_F(QuicSpdyServerStreamBaseTest, InvalidRequestWithoutPath) {
261 SetQuicReloadableFlag(quic_act_upon_invalid_header, true);
262 // A request without :path should be rejected.
263 QuicHeaderList header_list;
264 header_list.OnHeaderBlockStart();
265 header_list.OnHeader(":authority", "www.google.com:4433");
266 header_list.OnHeader(":scheme", "http");
267 header_list.OnHeader(":method", "POST");
268 header_list.OnHeaderBlockEnd(128, 128);
269
270 EXPECT_CALL(
271 session_,
272 MaybeSendRstStreamFrame(
273 _, QuicResetStreamError::FromInternal(QUIC_BAD_APPLICATION_PAYLOAD),
274 _));
275 stream_->OnStreamHeaderList(/*fin=*/false, 0, header_list);
276 EXPECT_TRUE(stream_->rst_sent());
277 }
278
TEST_F(QuicSpdyServerStreamBaseTest,InvalidRequestHeader)279 TEST_F(QuicSpdyServerStreamBaseTest, InvalidRequestHeader) {
280 SetQuicReloadableFlag(quic_act_upon_invalid_header, true);
281 // A request without :path should be rejected.
282 QuicHeaderList header_list;
283 header_list.OnHeaderBlockStart();
284 header_list.OnHeader(":authority", "www.google.com:4433");
285 header_list.OnHeader(":scheme", "http");
286 header_list.OnHeader(":method", "POST");
287 header_list.OnHeader("invalid:header", "value");
288 header_list.OnHeaderBlockEnd(128, 128);
289
290 EXPECT_CALL(
291 session_,
292 MaybeSendRstStreamFrame(
293 _, QuicResetStreamError::FromInternal(QUIC_BAD_APPLICATION_PAYLOAD),
294 _));
295 stream_->OnStreamHeaderList(/*fin=*/false, 0, header_list);
296 EXPECT_TRUE(stream_->rst_sent());
297 }
298
TEST_F(QuicSpdyServerStreamBaseTest,EmptyHeaders)299 TEST_F(QuicSpdyServerStreamBaseTest, EmptyHeaders) {
300 SetQuicReloadableFlag(quic_act_upon_invalid_header, true);
301 spdy::Http2HeaderBlock empty_header;
302 quic::test::NoopQpackStreamSenderDelegate encoder_stream_sender_delegate;
303 NoopDecoderStreamErrorDelegate decoder_stream_error_delegate;
304 auto qpack_encoder =
305 std::make_unique<quic::QpackEncoder>(&decoder_stream_error_delegate);
306 qpack_encoder->set_qpack_stream_sender_delegate(
307 &encoder_stream_sender_delegate);
308 std::string payload =
309 qpack_encoder->EncodeHeaderList(stream_->id(), empty_header, nullptr);
310 std::string headers_frame_header =
311 quic::HttpEncoder::SerializeHeadersFrameHeader(payload.length());
312
313 EXPECT_CALL(
314 session_,
315 MaybeSendRstStreamFrame(
316 _, QuicResetStreamError::FromInternal(QUIC_BAD_APPLICATION_PAYLOAD),
317 _));
318 stream_->OnStreamFrame(QuicStreamFrame(
319 stream_->id(), true, 0, absl::StrCat(headers_frame_header, payload)));
320 EXPECT_TRUE(stream_->rst_sent());
321 }
322
323 } // namespace
324 } // namespace test
325 } // namespace quic
326