blob: bf435b940940b399749f412abf94bdf6850fc749 [file] [log] [blame]
QUICHE teama6ef0a62019-03-07 20:34:33 -05001// Copyright (c) 2013 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/quic/tools/quic_simple_server_stream.h"
6
7#include <list>
8#include <memory>
9#include <utility>
10
11#include "net/third_party/quiche/src/quic/core/http/spdy_utils.h"
12#include "net/third_party/quiche/src/quic/core/quic_utils.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050013#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h"
14#include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h"
15#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
16#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
17#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
18#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h"
19#include "net/third_party/quiche/src/quic/test_tools/quic_session_peer.h"
20#include "net/third_party/quiche/src/quic/test_tools/quic_spdy_session_peer.h"
21#include "net/third_party/quiche/src/quic/test_tools/quic_stream_peer.h"
22#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
23#include "net/third_party/quiche/src/quic/tools/quic_backend_response.h"
24#include "net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.h"
25#include "net/third_party/quiche/src/quic/tools/quic_simple_server_session.h"
26
27using testing::_;
28using testing::AnyNumber;
29using testing::InSequence;
30using testing::Invoke;
31using testing::Return;
32using testing::StrictMock;
33using testing::ValuesIn;
34
35namespace quic {
36namespace test {
37
38const size_t kFakeFrameLen = 60;
39const size_t kErrorLength = strlen(QuicSimpleServerStream::kErrorResponseBody);
40const size_t kDataFrameHeaderLength = 2;
41
42class TestStream : public QuicSimpleServerStream {
43 public:
44 TestStream(QuicStreamId stream_id,
45 QuicSpdySession* session,
46 StreamType type,
47 QuicSimpleServerBackend* quic_simple_server_backend)
48 : QuicSimpleServerStream(stream_id,
49 session,
50 type,
51 quic_simple_server_backend) {}
52
53 ~TestStream() override = default;
54
55 MOCK_METHOD1(WriteHeadersMock, void(bool fin));
56
dschinazi17d42422019-06-18 16:35:07 -070057 size_t WriteHeaders(spdy::SpdyHeaderBlock /*header_block*/,
QUICHE teama6ef0a62019-03-07 20:34:33 -050058 bool fin,
59 QuicReferenceCountedPointer<QuicAckListenerInterface>
dschinazi17d42422019-06-18 16:35:07 -070060 /*ack_listener*/) override {
QUICHE teama6ef0a62019-03-07 20:34:33 -050061 WriteHeadersMock(fin);
62 return 0;
63 }
64
65 // Expose protected QuicSimpleServerStream methods.
66 void DoSendResponse() { SendResponse(); }
67 void DoSendErrorResponse() { SendErrorResponse(); }
68
69 spdy::SpdyHeaderBlock* mutable_headers() { return &request_headers_; }
vasilvvc48c8712019-03-11 13:38:16 -070070 void set_body(std::string body) { body_ = std::move(body); }
71 const std::string& body() const { return body_; }
QUICHE teama6ef0a62019-03-07 20:34:33 -050072 int content_length() const { return content_length_; }
73
74 QuicStringPiece GetHeader(QuicStringPiece key) const {
75 auto it = request_headers_.find(key);
76 DCHECK(it != request_headers_.end());
77 return it->second;
78 }
79};
80
81namespace {
82
83class MockQuicSimpleServerSession : public QuicSimpleServerSession {
84 public:
85 const size_t kMaxStreamsForTest = 100;
86
87 MockQuicSimpleServerSession(
88 QuicConnection* connection,
89 MockQuicSessionVisitor* owner,
90 MockQuicCryptoServerStreamHelper* helper,
91 QuicCryptoServerConfig* crypto_config,
92 QuicCompressedCertsCache* compressed_certs_cache,
93 QuicSimpleServerBackend* quic_simple_server_backend)
94 : QuicSimpleServerSession(DefaultQuicConfig(),
95 CurrentSupportedVersions(),
96 connection,
97 owner,
98 helper,
99 crypto_config,
100 compressed_certs_cache,
101 quic_simple_server_backend) {
fkastenholz305e1732019-06-18 05:01:22 -0700102 if (VersionHasIetfQuicFrames(connection->transport_version())) {
fkastenholzd3a1de92019-05-15 07:00:07 -0700103 QuicSessionPeer::SetMaxOpenIncomingUnidirectionalStreams(
104 this, kMaxStreamsForTest);
105 QuicSessionPeer::SetMaxOpenIncomingBidirectionalStreams(
106 this, kMaxStreamsForTest);
107 } else {
108 QuicSessionPeer::SetMaxOpenIncomingStreams(this, kMaxStreamsForTest);
109 QuicSessionPeer::SetMaxOpenOutgoingStreams(this, kMaxStreamsForTest);
110 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500111 ON_CALL(*this, WritevData(_, _, _, _, _))
112 .WillByDefault(Invoke(MockQuicSession::ConsumeData));
113 }
114
115 MockQuicSimpleServerSession(const MockQuicSimpleServerSession&) = delete;
116 MockQuicSimpleServerSession& operator=(const MockQuicSimpleServerSession&) =
117 delete;
118 ~MockQuicSimpleServerSession() override = default;
119
fkastenholz5d880a92019-06-21 09:01:56 -0700120 MOCK_METHOD2(OnConnectionClosed,
121 void(const QuicConnectionCloseFrame& frame,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500122 ConnectionCloseSource source));
123 MOCK_METHOD1(CreateIncomingStream, QuicSpdyStream*(QuicStreamId id));
124 MOCK_METHOD5(WritevData,
125 QuicConsumedData(QuicStream* stream,
126 QuicStreamId id,
127 size_t write_length,
128 QuicStreamOffset offset,
129 StreamSendingState state));
130 MOCK_METHOD4(OnStreamHeaderList,
131 void(QuicStreamId stream_id,
132 bool fin,
133 size_t frame_len,
134 const QuicHeaderList& header_list));
135 MOCK_METHOD2(OnStreamHeadersPriority,
fayang476683a2019-07-25 12:42:16 -0700136 void(QuicStreamId stream_id,
137 const spdy::SpdyStreamPrecedence& precedence));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500138 MOCK_METHOD3(SendRstStream,
139 void(QuicStreamId stream_id,
140 QuicRstStreamErrorCode error,
141 QuicStreamOffset bytes_written));
142 MOCK_METHOD1(OnHeadersHeadOfLineBlocking, void(QuicTime::Delta delta));
143 // Matchers cannot be used on non-copyable types like SpdyHeaderBlock.
144 void PromisePushResources(
vasilvvc48c8712019-03-11 13:38:16 -0700145 const std::string& request_url,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500146 const std::list<QuicBackendResponse::ServerPushInfo>& resources,
147 QuicStreamId original_stream_id,
fayang9a423762019-07-31 08:12:58 -0700148 const spdy::SpdyStreamPrecedence& original_precedence,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500149 const spdy::SpdyHeaderBlock& original_request_headers) override {
150 original_request_headers_ = original_request_headers.Clone();
151 PromisePushResourcesMock(request_url, resources, original_stream_id,
fayang9a423762019-07-31 08:12:58 -0700152 original_precedence, original_request_headers);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500153 }
fayang9a423762019-07-31 08:12:58 -0700154 MOCK_METHOD5(PromisePushResourcesMock,
vasilvvc48c8712019-03-11 13:38:16 -0700155 void(const std::string&,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500156 const std::list<QuicBackendResponse::ServerPushInfo>&,
157 QuicStreamId,
fayang9a423762019-07-31 08:12:58 -0700158 const spdy::SpdyStreamPrecedence&,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500159 const spdy::SpdyHeaderBlock&));
160
161 using QuicSession::ActivateStream;
162
163 MOCK_METHOD1(OnStopSendingReceived, void(const QuicStopSendingFrame& frame));
164
165 spdy::SpdyHeaderBlock original_request_headers_;
166};
167
168class QuicSimpleServerStreamTest : public QuicTestWithParam<ParsedQuicVersion> {
169 public:
170 QuicSimpleServerStreamTest()
171 : connection_(
172 new StrictMock<MockQuicConnection>(&helper_,
173 &alarm_factory_,
174 Perspective::IS_SERVER,
175 SupportedVersions(GetParam()))),
176 crypto_config_(new QuicCryptoServerConfig(
177 QuicCryptoServerConfig::TESTING,
178 QuicRandom::GetInstance(),
179 crypto_test_utils::ProofSourceForTesting(),
nharper6ebe83b2019-06-13 17:43:52 -0700180 KeyExchangeSource::Default())),
QUICHE teama6ef0a62019-03-07 20:34:33 -0500181 compressed_certs_cache_(
182 QuicCompressedCertsCache::kQuicCompressedCertsCacheSize),
183 session_(connection_,
184 &session_owner_,
185 &session_helper_,
186 crypto_config_.get(),
187 &compressed_certs_cache_,
188 &memory_cache_backend_),
189 quic_response_(new QuicBackendResponse),
190 body_("hello world") {
191 connection_->set_visitor(&session_);
192 header_list_.OnHeaderBlockStart();
193 header_list_.OnHeader(":authority", "www.google.com");
194 header_list_.OnHeader(":path", "/");
195 header_list_.OnHeader(":method", "POST");
196 header_list_.OnHeader(":version", "HTTP/1.1");
197 header_list_.OnHeader("content-length", "11");
198
199 header_list_.OnHeaderBlockEnd(128, 128);
200
201 // New streams rely on having the peer's flow control receive window
202 // negotiated in the config.
203 session_.config()->SetInitialStreamFlowControlWindowToSend(
204 kInitialStreamFlowControlWindowForTest);
205 session_.config()->SetInitialSessionFlowControlWindowToSend(
206 kInitialSessionFlowControlWindowForTest);
renjietang8513ffe2019-08-12 10:08:57 -0700207 session_.Initialize();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500208 stream_ = new StrictMock<TestStream>(
209 GetNthClientInitiatedBidirectionalStreamId(
210 connection_->transport_version(), 0),
211 &session_, BIDIRECTIONAL, &memory_cache_backend_);
212 // Register stream_ in dynamic_stream_map_ and pass ownership to session_.
213 session_.ActivateStream(QuicWrapUnique(stream_));
214 connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
215 }
216
vasilvvc48c8712019-03-11 13:38:16 -0700217 const std::string& StreamBody() { return stream_->body(); }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500218
vasilvvc48c8712019-03-11 13:38:16 -0700219 std::string StreamHeadersValue(const std::string& key) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500220 return (*stream_->mutable_headers())[key].as_string();
221 }
222
QUICHE teama6ef0a62019-03-07 20:34:33 -0500223 bool HasFrameHeader() const {
224 return VersionHasDataFrameHeader(connection_->transport_version());
225 }
226
227 spdy::SpdyHeaderBlock response_headers_;
228 MockQuicConnectionHelper helper_;
229 MockAlarmFactory alarm_factory_;
230 StrictMock<MockQuicConnection>* connection_;
231 StrictMock<MockQuicSessionVisitor> session_owner_;
232 StrictMock<MockQuicCryptoServerStreamHelper> session_helper_;
233 std::unique_ptr<QuicCryptoServerConfig> crypto_config_;
234 QuicCompressedCertsCache compressed_certs_cache_;
235 QuicMemoryCacheBackend memory_cache_backend_;
236 StrictMock<MockQuicSimpleServerSession> session_;
237 StrictMock<TestStream>* stream_; // Owned by session_.
238 std::unique_ptr<QuicBackendResponse> quic_response_;
vasilvvc48c8712019-03-11 13:38:16 -0700239 std::string body_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500240 QuicHeaderList header_list_;
241 HttpEncoder encoder_;
242};
243
244INSTANTIATE_TEST_SUITE_P(Tests,
245 QuicSimpleServerStreamTest,
246 ValuesIn(AllSupportedVersions()));
247
248TEST_P(QuicSimpleServerStreamTest, TestFraming) {
249 EXPECT_CALL(session_, WritevData(_, _, _, _, _))
250 .WillRepeatedly(Invoke(MockQuicSession::ConsumeData));
251 stream_->OnStreamHeaderList(false, kFakeFrameLen, header_list_);
252 std::unique_ptr<char[]> buffer;
253 QuicByteCount header_length =
254 encoder_.SerializeDataFrameHeader(body_.length(), &buffer);
vasilvvc48c8712019-03-11 13:38:16 -0700255 std::string header = std::string(buffer.get(), header_length);
256 std::string data = HasFrameHeader() ? header + body_ : body_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500257 stream_->OnStreamFrame(
258 QuicStreamFrame(stream_->id(), /*fin=*/false, /*offset=*/0, data));
259 EXPECT_EQ("11", StreamHeadersValue("content-length"));
260 EXPECT_EQ("/", StreamHeadersValue(":path"));
261 EXPECT_EQ("POST", StreamHeadersValue(":method"));
262 EXPECT_EQ(body_, StreamBody());
263}
264
265TEST_P(QuicSimpleServerStreamTest, TestFramingOnePacket) {
266 EXPECT_CALL(session_, WritevData(_, _, _, _, _))
267 .WillRepeatedly(Invoke(MockQuicSession::ConsumeData));
268
269 stream_->OnStreamHeaderList(false, kFakeFrameLen, header_list_);
270 std::unique_ptr<char[]> buffer;
271 QuicByteCount header_length =
272 encoder_.SerializeDataFrameHeader(body_.length(), &buffer);
vasilvvc48c8712019-03-11 13:38:16 -0700273 std::string header = std::string(buffer.get(), header_length);
274 std::string data = HasFrameHeader() ? header + body_ : body_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500275 stream_->OnStreamFrame(
276 QuicStreamFrame(stream_->id(), /*fin=*/false, /*offset=*/0, data));
277 EXPECT_EQ("11", StreamHeadersValue("content-length"));
278 EXPECT_EQ("/", StreamHeadersValue(":path"));
279 EXPECT_EQ("POST", StreamHeadersValue(":method"));
280 EXPECT_EQ(body_, StreamBody());
281}
282
283TEST_P(QuicSimpleServerStreamTest, SendQuicRstStreamNoErrorInStopReading) {
284 EXPECT_CALL(session_, WritevData(_, _, _, _, _))
285 .WillRepeatedly(Invoke(MockQuicSession::ConsumeData));
286
287 EXPECT_FALSE(stream_->fin_received());
288 EXPECT_FALSE(stream_->rst_received());
289
290 stream_->set_fin_sent(true);
291 stream_->CloseWriteSide();
292
293 EXPECT_CALL(session_, SendRstStream(_, QUIC_STREAM_NO_ERROR, _)).Times(1);
294 stream_->StopReading();
295}
296
297TEST_P(QuicSimpleServerStreamTest, TestFramingExtraData) {
nharperf5e68452019-05-29 17:24:18 -0700298 if (GetParam().handshake_protocol == PROTOCOL_TLS1_3) {
299 // TODO(nharper, b/112643533): Figure out why this test fails when TLS is
300 // enabled and fix it.
301 return;
302 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500303 InSequence seq;
vasilvvc48c8712019-03-11 13:38:16 -0700304 std::string large_body = "hello world!!!!!!";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500305
306 // We'll automatically write out an error (headers + body)
307 EXPECT_CALL(*stream_, WriteHeadersMock(false));
308 if (HasFrameHeader()) {
309 EXPECT_CALL(session_, WritevData(_, _, kDataFrameHeaderLength, _, NO_FIN));
310 }
311 EXPECT_CALL(session_, WritevData(_, _, kErrorLength, _, FIN));
312
313 EXPECT_CALL(session_, SendRstStream(_, QUIC_STREAM_NO_ERROR, _)).Times(0);
314
315 stream_->OnStreamHeaderList(false, kFakeFrameLen, header_list_);
316 std::unique_ptr<char[]> buffer;
317 QuicByteCount header_length =
318 encoder_.SerializeDataFrameHeader(body_.length(), &buffer);
vasilvvc48c8712019-03-11 13:38:16 -0700319 std::string header = std::string(buffer.get(), header_length);
320 std::string data = HasFrameHeader() ? header + body_ : body_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500321
322 stream_->OnStreamFrame(
323 QuicStreamFrame(stream_->id(), /*fin=*/false, /*offset=*/0, data));
324 // Content length is still 11. This will register as an error and we won't
325 // accept the bytes.
326 header_length =
327 encoder_.SerializeDataFrameHeader(large_body.length(), &buffer);
vasilvvc48c8712019-03-11 13:38:16 -0700328 header = std::string(buffer.get(), header_length);
329 std::string data2 = HasFrameHeader() ? header + large_body : large_body;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500330 stream_->OnStreamFrame(
331 QuicStreamFrame(stream_->id(), /*fin=*/true, data.size(), data2));
332 EXPECT_EQ("11", StreamHeadersValue("content-length"));
333 EXPECT_EQ("/", StreamHeadersValue(":path"));
334 EXPECT_EQ("POST", StreamHeadersValue(":method"));
335}
336
337TEST_P(QuicSimpleServerStreamTest, SendResponseWithIllegalResponseStatus) {
nharperf5e68452019-05-29 17:24:18 -0700338 if (GetParam().handshake_protocol == PROTOCOL_TLS1_3) {
339 // TODO(nharper, b/112643533): Figure out why this test fails when TLS is
340 // enabled and fix it.
341 return;
342 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500343 // Send an illegal response with response status not supported by HTTP/2.
344 spdy::SpdyHeaderBlock* request_headers = stream_->mutable_headers();
345 (*request_headers)[":path"] = "/bar";
346 (*request_headers)[":authority"] = "www.google.com";
347 (*request_headers)[":version"] = "HTTP/1.1";
348 (*request_headers)[":method"] = "GET";
349
350 response_headers_[":version"] = "HTTP/1.1";
351 // HTTP/2 only supports integer responsecode, so "200 OK" is illegal.
352 response_headers_[":status"] = "200 OK";
353 response_headers_["content-length"] = "5";
vasilvvc48c8712019-03-11 13:38:16 -0700354 std::string body = "Yummm";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500355 std::unique_ptr<char[]> buffer;
356 QuicByteCount header_length =
357 encoder_.SerializeDataFrameHeader(body.length(), &buffer);
358
359 memory_cache_backend_.AddResponse("www.google.com", "/bar",
360 std::move(response_headers_), body);
361
362 stream_->set_fin_received(true);
363
364 InSequence s;
365 EXPECT_CALL(*stream_, WriteHeadersMock(false));
366 if (HasFrameHeader()) {
367 EXPECT_CALL(session_, WritevData(_, _, header_length, _, NO_FIN));
368 }
369 EXPECT_CALL(session_, WritevData(_, _, kErrorLength, _, FIN));
370
371 stream_->DoSendResponse();
372 EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_));
373 EXPECT_TRUE(stream_->write_side_closed());
374}
375
376TEST_P(QuicSimpleServerStreamTest, SendResponseWithIllegalResponseStatus2) {
nharperf5e68452019-05-29 17:24:18 -0700377 if (GetParam().handshake_protocol == PROTOCOL_TLS1_3) {
378 // TODO(nharper, b/112643533): Figure out why this test fails when TLS is
379 // enabled and fix it.
380 return;
381 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500382 // Send an illegal response with response status not supported by HTTP/2.
383 spdy::SpdyHeaderBlock* request_headers = stream_->mutable_headers();
384 (*request_headers)[":path"] = "/bar";
385 (*request_headers)[":authority"] = "www.google.com";
386 (*request_headers)[":version"] = "HTTP/1.1";
387 (*request_headers)[":method"] = "GET";
388
389 response_headers_[":version"] = "HTTP/1.1";
390 // HTTP/2 only supports 3-digit-integer, so "+200" is illegal.
391 response_headers_[":status"] = "+200";
392 response_headers_["content-length"] = "5";
vasilvvc48c8712019-03-11 13:38:16 -0700393 std::string body = "Yummm";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500394
395 std::unique_ptr<char[]> buffer;
396 QuicByteCount header_length =
397 encoder_.SerializeDataFrameHeader(body.length(), &buffer);
398
399 memory_cache_backend_.AddResponse("www.google.com", "/bar",
400 std::move(response_headers_), body);
401
402 stream_->set_fin_received(true);
403
404 InSequence s;
405 EXPECT_CALL(*stream_, WriteHeadersMock(false));
406 if (HasFrameHeader()) {
407 EXPECT_CALL(session_, WritevData(_, _, header_length, _, NO_FIN));
408 }
409 EXPECT_CALL(session_, WritevData(_, _, kErrorLength, _, FIN));
410
411 stream_->DoSendResponse();
412 EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_));
413 EXPECT_TRUE(stream_->write_side_closed());
414}
415
416TEST_P(QuicSimpleServerStreamTest, SendPushResponseWith404Response) {
417 // Create a new promised stream with even id().
418 auto promised_stream = new StrictMock<TestStream>(
419 GetNthServerInitiatedUnidirectionalStreamId(
renjietang8513ffe2019-08-12 10:08:57 -0700420 connection_->transport_version(), 1),
QUICHE teama6ef0a62019-03-07 20:34:33 -0500421 &session_, WRITE_UNIDIRECTIONAL, &memory_cache_backend_);
422 session_.ActivateStream(QuicWrapUnique(promised_stream));
423
424 // Send a push response with response status 404, which will be regarded as
425 // invalid server push response.
426 spdy::SpdyHeaderBlock* request_headers = promised_stream->mutable_headers();
427 (*request_headers)[":path"] = "/bar";
428 (*request_headers)[":authority"] = "www.google.com";
429 (*request_headers)[":version"] = "HTTP/1.1";
430 (*request_headers)[":method"] = "GET";
431
432 response_headers_[":version"] = "HTTP/1.1";
433 response_headers_[":status"] = "404";
434 response_headers_["content-length"] = "8";
vasilvvc48c8712019-03-11 13:38:16 -0700435 std::string body = "NotFound";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500436
437 memory_cache_backend_.AddResponse("www.google.com", "/bar",
438 std::move(response_headers_), body);
439
440 InSequence s;
441 EXPECT_CALL(session_,
442 SendRstStream(promised_stream->id(), QUIC_STREAM_CANCELLED, 0));
443
444 promised_stream->DoSendResponse();
445}
446
447TEST_P(QuicSimpleServerStreamTest, SendResponseWithValidHeaders) {
nharperf5e68452019-05-29 17:24:18 -0700448 if (GetParam().handshake_protocol == PROTOCOL_TLS1_3) {
449 // TODO(nharper, b/112643533): Figure out why this test fails when TLS is
450 // enabled and fix it.
451 return;
452 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500453 // Add a request and response with valid headers.
454 spdy::SpdyHeaderBlock* request_headers = stream_->mutable_headers();
455 (*request_headers)[":path"] = "/bar";
456 (*request_headers)[":authority"] = "www.google.com";
457 (*request_headers)[":version"] = "HTTP/1.1";
458 (*request_headers)[":method"] = "GET";
459
460 response_headers_[":version"] = "HTTP/1.1";
461 response_headers_[":status"] = "200";
462 response_headers_["content-length"] = "5";
vasilvvc48c8712019-03-11 13:38:16 -0700463 std::string body = "Yummm";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500464
465 std::unique_ptr<char[]> buffer;
466 QuicByteCount header_length =
467 encoder_.SerializeDataFrameHeader(body.length(), &buffer);
468
469 memory_cache_backend_.AddResponse("www.google.com", "/bar",
470 std::move(response_headers_), body);
471 stream_->set_fin_received(true);
472
473 InSequence s;
474 EXPECT_CALL(*stream_, WriteHeadersMock(false));
475 if (HasFrameHeader()) {
476 EXPECT_CALL(session_, WritevData(_, _, header_length, _, NO_FIN));
477 }
478 EXPECT_CALL(session_, WritevData(_, _, body.length(), _, FIN));
479
480 stream_->DoSendResponse();
481 EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_));
482 EXPECT_TRUE(stream_->write_side_closed());
483}
484
485TEST_P(QuicSimpleServerStreamTest, SendResponseWithPushResources) {
nharperf5e68452019-05-29 17:24:18 -0700486 if (GetParam().handshake_protocol == PROTOCOL_TLS1_3) {
487 // TODO(nharper, b/112643533): Figure out why this test fails when TLS is
488 // enabled and fix it.
489 return;
490 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500491 // Tests that if a response has push resources to be send, SendResponse() will
492 // call PromisePushResources() to handle these resources.
493
494 // Add a request and response with valid headers into cache.
vasilvvc48c8712019-03-11 13:38:16 -0700495 std::string host = "www.google.com";
496 std::string request_path = "/foo";
497 std::string body = "Yummm";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500498 std::unique_ptr<char[]> buffer;
499 QuicByteCount header_length =
500 encoder_.SerializeDataFrameHeader(body.length(), &buffer);
501 QuicBackendResponse::ServerPushInfo push_info(
502 QuicUrl(host, "/bar"), spdy::SpdyHeaderBlock(),
503 QuicStream::kDefaultPriority, "Push body");
504 std::list<QuicBackendResponse::ServerPushInfo> push_resources;
505 push_resources.push_back(push_info);
506 memory_cache_backend_.AddSimpleResponseWithServerPushResources(
507 host, request_path, 200, body, push_resources);
508
509 spdy::SpdyHeaderBlock* request_headers = stream_->mutable_headers();
510 (*request_headers)[":path"] = request_path;
511 (*request_headers)[":authority"] = host;
512 (*request_headers)[":version"] = "HTTP/1.1";
513 (*request_headers)[":method"] = "GET";
514
515 stream_->set_fin_received(true);
516 InSequence s;
517 EXPECT_CALL(session_, PromisePushResourcesMock(
518 host + request_path, _,
519 GetNthClientInitiatedBidirectionalStreamId(
520 connection_->transport_version(), 0),
fayang9a423762019-07-31 08:12:58 -0700521 _, _));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500522 EXPECT_CALL(*stream_, WriteHeadersMock(false));
523 if (HasFrameHeader()) {
524 EXPECT_CALL(session_, WritevData(_, _, header_length, _, NO_FIN));
525 }
526 EXPECT_CALL(session_, WritevData(_, _, body.length(), _, FIN));
527 stream_->DoSendResponse();
528 EXPECT_EQ(*request_headers, session_.original_request_headers_);
529}
530
531TEST_P(QuicSimpleServerStreamTest, PushResponseOnClientInitiatedStream) {
532 // EXPECT_QUIC_BUG tests are expensive so only run one instance of them.
533 if (GetParam() != AllSupportedVersions()[0]) {
534 return;
535 }
536
537 // Calling PushResponse() on a client initialted stream is never supposed to
538 // happen.
539 EXPECT_QUIC_BUG(stream_->PushResponse(spdy::SpdyHeaderBlock()),
540 "Client initiated stream"
541 " shouldn't be used as promised stream.");
542}
543
544TEST_P(QuicSimpleServerStreamTest, PushResponseOnServerInitiatedStream) {
nharperf5e68452019-05-29 17:24:18 -0700545 if (GetParam().handshake_protocol == PROTOCOL_TLS1_3) {
546 // TODO(nharper, b/112643533): Figure out why this test fails when TLS is
547 // enabled and fix it.
548 return;
549 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500550 // Tests that PushResponse() should take the given headers as request headers
551 // and fetch response from cache, and send it out.
552
553 // Create a stream with even stream id and test against this stream.
554 const QuicStreamId kServerInitiatedStreamId =
555 GetNthServerInitiatedUnidirectionalStreamId(
renjietangc04c85f2019-07-25 14:07:27 -0700556 connection_->transport_version(), 1);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500557 // Create a server initiated stream and pass it to session_.
558 auto server_initiated_stream =
559 new StrictMock<TestStream>(kServerInitiatedStreamId, &session_,
560 WRITE_UNIDIRECTIONAL, &memory_cache_backend_);
561 session_.ActivateStream(QuicWrapUnique(server_initiated_stream));
562
vasilvvc48c8712019-03-11 13:38:16 -0700563 const std::string kHost = "www.foo.com";
564 const std::string kPath = "/bar";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500565 spdy::SpdyHeaderBlock headers;
566 headers[":path"] = kPath;
567 headers[":authority"] = kHost;
568 headers[":version"] = "HTTP/1.1";
569 headers[":method"] = "GET";
570
571 response_headers_[":version"] = "HTTP/1.1";
572 response_headers_[":status"] = "200";
573 response_headers_["content-length"] = "5";
vasilvvc48c8712019-03-11 13:38:16 -0700574 const std::string kBody = "Hello";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500575 std::unique_ptr<char[]> buffer;
576 QuicByteCount header_length =
577 encoder_.SerializeDataFrameHeader(kBody.length(), &buffer);
578 memory_cache_backend_.AddResponse(kHost, kPath, std::move(response_headers_),
579 kBody);
580
581 // Call PushResponse() should trigger stream to fetch response from cache
582 // and send it back.
583 InSequence s;
584 EXPECT_CALL(*server_initiated_stream, WriteHeadersMock(false));
585
586 if (HasFrameHeader()) {
587 EXPECT_CALL(session_, WritevData(_, kServerInitiatedStreamId, header_length,
588 _, NO_FIN));
589 }
590 EXPECT_CALL(session_,
591 WritevData(_, kServerInitiatedStreamId, kBody.size(), _, FIN));
592 server_initiated_stream->PushResponse(std::move(headers));
593 EXPECT_EQ(kPath, server_initiated_stream->GetHeader(":path"));
594 EXPECT_EQ("GET", server_initiated_stream->GetHeader(":method"));
595}
596
597TEST_P(QuicSimpleServerStreamTest, TestSendErrorResponse) {
nharperf5e68452019-05-29 17:24:18 -0700598 if (GetParam().handshake_protocol == PROTOCOL_TLS1_3) {
599 // TODO(nharper, b/112643533): Figure out why this test fails when TLS is
600 // enabled and fix it.
601 return;
602 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500603 EXPECT_CALL(session_, SendRstStream(_, QUIC_STREAM_NO_ERROR, _)).Times(0);
604
605 stream_->set_fin_received(true);
606
607 InSequence s;
608 EXPECT_CALL(*stream_, WriteHeadersMock(false));
609 if (HasFrameHeader()) {
610 EXPECT_CALL(session_, WritevData(_, _, kDataFrameHeaderLength, _, NO_FIN));
611 }
612 EXPECT_CALL(session_, WritevData(_, _, kErrorLength, _, FIN));
613
614 stream_->DoSendErrorResponse();
615 EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_));
616 EXPECT_TRUE(stream_->write_side_closed());
617}
618
619TEST_P(QuicSimpleServerStreamTest, InvalidMultipleContentLength) {
nharperf5e68452019-05-29 17:24:18 -0700620 if (GetParam().handshake_protocol == PROTOCOL_TLS1_3) {
621 // TODO(nharper, b/112643533): Figure out why this test fails when TLS is
622 // enabled and fix it.
623 return;
624 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500625 EXPECT_CALL(session_, SendRstStream(_, QUIC_STREAM_NO_ERROR, _)).Times(0);
626
627 spdy::SpdyHeaderBlock request_headers;
628 // \000 is a way to write the null byte when followed by a literal digit.
629 header_list_.OnHeader("content-length", QuicStringPiece("11\00012", 5));
630
631 EXPECT_CALL(*stream_, WriteHeadersMock(false));
632 EXPECT_CALL(session_, WritevData(_, _, _, _, _))
633 .WillRepeatedly(Invoke(MockQuicSession::ConsumeData));
634 stream_->OnStreamHeaderList(true, kFakeFrameLen, header_list_);
635
636 EXPECT_TRUE(QuicStreamPeer::read_side_closed(stream_));
637 EXPECT_TRUE(stream_->reading_stopped());
638 EXPECT_TRUE(stream_->write_side_closed());
639}
640
641TEST_P(QuicSimpleServerStreamTest, InvalidLeadingNullContentLength) {
nharperf5e68452019-05-29 17:24:18 -0700642 if (GetParam().handshake_protocol == PROTOCOL_TLS1_3) {
643 // TODO(nharper, b/112643533): Figure out why this test fails when TLS is
644 // enabled and fix it.
645 return;
646 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500647 EXPECT_CALL(session_, SendRstStream(_, QUIC_STREAM_NO_ERROR, _)).Times(0);
648
649 spdy::SpdyHeaderBlock request_headers;
650 // \000 is a way to write the null byte when followed by a literal digit.
651 header_list_.OnHeader("content-length", QuicStringPiece("\00012", 3));
652
653 EXPECT_CALL(*stream_, WriteHeadersMock(false));
654 EXPECT_CALL(session_, WritevData(_, _, _, _, _))
655 .WillRepeatedly(Invoke(MockQuicSession::ConsumeData));
656 stream_->OnStreamHeaderList(true, kFakeFrameLen, header_list_);
657
658 EXPECT_TRUE(QuicStreamPeer::read_side_closed(stream_));
659 EXPECT_TRUE(stream_->reading_stopped());
660 EXPECT_TRUE(stream_->write_side_closed());
661}
662
663TEST_P(QuicSimpleServerStreamTest, ValidMultipleContentLength) {
664 spdy::SpdyHeaderBlock request_headers;
665 // \000 is a way to write the null byte when followed by a literal digit.
666 header_list_.OnHeader("content-length", QuicStringPiece("11\00011", 5));
667
668 stream_->OnStreamHeaderList(false, kFakeFrameLen, header_list_);
669
670 EXPECT_EQ(11, stream_->content_length());
671 EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_));
672 EXPECT_FALSE(stream_->reading_stopped());
673 EXPECT_FALSE(stream_->write_side_closed());
674}
675
676TEST_P(QuicSimpleServerStreamTest,
677 DoNotSendQuicRstStreamNoErrorWithRstReceived) {
678 InSequence s;
679 EXPECT_FALSE(stream_->reading_stopped());
680
681 EXPECT_CALL(session_, SendRstStream(_, QUIC_STREAM_NO_ERROR, _)).Times(0);
682 EXPECT_CALL(session_, SendRstStream(_, QUIC_RST_ACKNOWLEDGEMENT, _)).Times(1);
683 QuicRstStreamFrame rst_frame(kInvalidControlFrameId, stream_->id(),
684 QUIC_STREAM_CANCELLED, 1234);
685 stream_->OnStreamReset(rst_frame);
fkastenholz305e1732019-06-18 05:01:22 -0700686 if (VersionHasIetfQuicFrames(connection_->transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500687 // For V99 receiving a RST_STREAM causes a 1-way close; the test requires
688 // a full close. A CloseWriteSide closes the other half of the stream.
689 // Everything should then work properly.
690 stream_->CloseWriteSide();
691 }
692 EXPECT_TRUE(stream_->reading_stopped());
693 EXPECT_TRUE(stream_->write_side_closed());
694}
695
696TEST_P(QuicSimpleServerStreamTest, InvalidHeadersWithFin) {
697 char arr[] = {
698 0x3a, 0x68, 0x6f, 0x73, // :hos
699 0x74, 0x00, 0x00, 0x00, // t...
700 0x00, 0x00, 0x00, 0x00, // ....
701 0x07, 0x3a, 0x6d, 0x65, // .:me
702 0x74, 0x68, 0x6f, 0x64, // thod
703 0x00, 0x00, 0x00, 0x03, // ....
704 0x47, 0x45, 0x54, 0x00, // GET.
705 0x00, 0x00, 0x05, 0x3a, // ...:
706 0x70, 0x61, 0x74, 0x68, // path
707 0x00, 0x00, 0x00, 0x04, // ....
708 0x2f, 0x66, 0x6f, 0x6f, // /foo
709 0x00, 0x00, 0x00, 0x07, // ....
710 0x3a, 0x73, 0x63, 0x68, // :sch
711 0x65, 0x6d, 0x65, 0x00, // eme.
712 0x00, 0x00, 0x00, 0x00, // ....
713 0x00, 0x00, 0x08, 0x3a, // ...:
714 0x76, 0x65, 0x72, 0x73, // vers
715 0x96, 0x6f, 0x6e, 0x00, // <i(69)>on.
716 0x00, 0x00, 0x08, 0x48, // ...H
717 0x54, 0x54, 0x50, 0x2f, // TTP/
718 0x31, 0x2e, 0x31, // 1.1
719 };
720 QuicStringPiece data(arr, QUIC_ARRAYSIZE(arr));
721 QuicStreamFrame frame(stream_->id(), true, 0, data);
722 // Verify that we don't crash when we get a invalid headers in stream frame.
723 stream_->OnStreamFrame(frame);
724}
725
726} // namespace
727} // namespace test
728} // namespace quic