1 // Copyright 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 "quiche/quic/core/http/quic_spdy_client_stream.h"
6
7 #include <memory>
8 #include <string>
9 #include <utility>
10
11 #include "absl/strings/str_cat.h"
12 #include "quiche/quic/core/crypto/null_encrypter.h"
13 #include "quiche/quic/core/http/quic_spdy_client_session.h"
14 #include "quiche/quic/core/http/spdy_utils.h"
15 #include "quiche/quic/core/quic_error_codes.h"
16 #include "quiche/quic/core/quic_utils.h"
17 #include "quiche/quic/platform/api/quic_logging.h"
18 #include "quiche/quic/platform/api/quic_socket_address.h"
19 #include "quiche/quic/platform/api/quic_test.h"
20 #include "quiche/quic/test_tools/crypto_test_utils.h"
21 #include "quiche/quic/test_tools/quic_spdy_session_peer.h"
22 #include "quiche/quic/test_tools/quic_test_utils.h"
23 #include "quiche/common/simple_buffer_allocator.h"
24
25 using spdy::Http2HeaderBlock;
26 using testing::_;
27 using testing::StrictMock;
28
29 namespace quic {
30 namespace test {
31
32 namespace {
33
34 class MockQuicSpdyClientSession : public QuicSpdyClientSession {
35 public:
MockQuicSpdyClientSession(const ParsedQuicVersionVector & supported_versions,QuicConnection * connection)36 explicit MockQuicSpdyClientSession(
37 const ParsedQuicVersionVector& supported_versions,
38 QuicConnection* connection)
39 : QuicSpdyClientSession(
40 DefaultQuicConfig(), supported_versions, connection,
41 QuicServerId("example.com", 443, false), &crypto_config_),
42 crypto_config_(crypto_test_utils::ProofVerifierForTesting()) {}
43 MockQuicSpdyClientSession(const MockQuicSpdyClientSession&) = delete;
44 MockQuicSpdyClientSession& operator=(const MockQuicSpdyClientSession&) =
45 delete;
46 ~MockQuicSpdyClientSession() override = default;
47
48 MOCK_METHOD(bool, WriteControlFrame,
49 (const QuicFrame& frame, TransmissionType type), (override));
50
51 using QuicSession::ActivateStream;
52
53 private:
54 QuicCryptoClientConfig crypto_config_;
55 };
56
57 class QuicSpdyClientStreamTest : public QuicTestWithParam<ParsedQuicVersion> {
58 public:
59 class StreamVisitor;
60
QuicSpdyClientStreamTest()61 QuicSpdyClientStreamTest()
62 : connection_(new StrictMock<MockQuicConnection>(
63 &helper_, &alarm_factory_, Perspective::IS_CLIENT,
64 SupportedVersions(GetParam()))),
65 session_(connection_->supported_versions(), connection_),
66 body_("hello world") {
67 session_.Initialize();
68 connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
69 connection_->SetEncrypter(
70 ENCRYPTION_FORWARD_SECURE,
71 std::make_unique<NullEncrypter>(connection_->perspective()));
72 headers_[":status"] = "200";
73 headers_["content-length"] = "11";
74
75 auto stream = std::make_unique<QuicSpdyClientStream>(
76 GetNthClientInitiatedBidirectionalStreamId(
77 connection_->transport_version(), 0),
78 &session_, BIDIRECTIONAL);
79 stream_ = stream.get();
80 session_.ActivateStream(std::move(stream));
81
82 stream_visitor_ = std::make_unique<StreamVisitor>();
83 stream_->set_visitor(stream_visitor_.get());
84 }
85
86 class StreamVisitor : public QuicSpdyClientStream::Visitor {
OnClose(QuicSpdyStream * stream)87 void OnClose(QuicSpdyStream* stream) override {
88 QUIC_DVLOG(1) << "stream " << stream->id();
89 }
90 };
91
92 MockQuicConnectionHelper helper_;
93 MockAlarmFactory alarm_factory_;
94 StrictMock<MockQuicConnection>* connection_;
95
96 MockQuicSpdyClientSession session_;
97 QuicSpdyClientStream* stream_;
98 std::unique_ptr<StreamVisitor> stream_visitor_;
99 Http2HeaderBlock headers_;
100 std::string body_;
101 };
102
103 INSTANTIATE_TEST_SUITE_P(Tests, QuicSpdyClientStreamTest,
104 ::testing::ValuesIn(AllSupportedVersions()),
105 ::testing::PrintToStringParamName());
106
TEST_P(QuicSpdyClientStreamTest,TestReceivingIllegalResponseStatusCode)107 TEST_P(QuicSpdyClientStreamTest, TestReceivingIllegalResponseStatusCode) {
108 headers_[":status"] = "200 ok";
109
110 EXPECT_CALL(session_, WriteControlFrame(_, _));
111 EXPECT_CALL(*connection_,
112 OnStreamReset(stream_->id(), QUIC_BAD_APPLICATION_PAYLOAD));
113 auto headers = AsHeaderList(headers_);
114 stream_->OnStreamHeaderList(false, headers.uncompressed_header_bytes(),
115 headers);
116 EXPECT_THAT(stream_->stream_error(),
117 IsStreamError(QUIC_BAD_APPLICATION_PAYLOAD));
118 EXPECT_EQ(stream_->ietf_application_error(),
119 static_cast<uint64_t>(QuicHttp3ErrorCode::GENERAL_PROTOCOL_ERROR));
120 }
121
TEST_P(QuicSpdyClientStreamTest,InvalidResponseHeader)122 TEST_P(QuicSpdyClientStreamTest, InvalidResponseHeader) {
123 SetQuicReloadableFlag(quic_act_upon_invalid_header, true);
124 auto headers = AsHeaderList(std::vector<std::pair<std::string, std::string>>{
125 {":status", "200"}, {":path", "/foo"}});
126 EXPECT_CALL(*connection_,
127 OnStreamReset(stream_->id(), QUIC_BAD_APPLICATION_PAYLOAD));
128 stream_->OnStreamHeaderList(false, headers.uncompressed_header_bytes(),
129 headers);
130 EXPECT_THAT(stream_->stream_error(),
131 IsStreamError(QUIC_BAD_APPLICATION_PAYLOAD));
132 EXPECT_EQ(stream_->ietf_application_error(),
133 static_cast<uint64_t>(QuicHttp3ErrorCode::GENERAL_PROTOCOL_ERROR));
134 }
135
TEST_P(QuicSpdyClientStreamTest,MissingStatusCode)136 TEST_P(QuicSpdyClientStreamTest, MissingStatusCode) {
137 SetQuicReloadableFlag(quic_act_upon_invalid_header, true);
138 auto headers = AsHeaderList(
139 std::vector<std::pair<std::string, std::string>>{{"key", "value"}});
140 EXPECT_CALL(*connection_,
141 OnStreamReset(stream_->id(), QUIC_BAD_APPLICATION_PAYLOAD));
142 stream_->OnStreamHeaderList(false, headers.uncompressed_header_bytes(),
143 headers);
144 EXPECT_THAT(stream_->stream_error(),
145 IsStreamError(QUIC_BAD_APPLICATION_PAYLOAD));
146 EXPECT_EQ(stream_->ietf_application_error(),
147 static_cast<uint64_t>(QuicHttp3ErrorCode::GENERAL_PROTOCOL_ERROR));
148 }
149
TEST_P(QuicSpdyClientStreamTest,TestFraming)150 TEST_P(QuicSpdyClientStreamTest, TestFraming) {
151 auto headers = AsHeaderList(headers_);
152 stream_->OnStreamHeaderList(false, headers.uncompressed_header_bytes(),
153 headers);
154 quiche::QuicheBuffer header = HttpEncoder::SerializeDataFrameHeader(
155 body_.length(), quiche::SimpleBufferAllocator::Get());
156 std::string data = VersionUsesHttp3(connection_->transport_version())
157 ? absl::StrCat(header.AsStringView(), body_)
158 : body_;
159 stream_->OnStreamFrame(
160 QuicStreamFrame(stream_->id(), /*fin=*/false, /*offset=*/0, data));
161 EXPECT_EQ("200", stream_->response_headers().find(":status")->second);
162 EXPECT_EQ(200, stream_->response_code());
163 EXPECT_EQ(body_, stream_->data());
164 }
165
TEST_P(QuicSpdyClientStreamTest,HostAllowedInResponseHeader)166 TEST_P(QuicSpdyClientStreamTest, HostAllowedInResponseHeader) {
167 SetQuicReloadableFlag(quic_act_upon_invalid_header, true);
168 auto headers = AsHeaderList(std::vector<std::pair<std::string, std::string>>{
169 {":status", "200"}, {"host", "example.com"}});
170 EXPECT_CALL(*connection_, OnStreamReset(stream_->id(), _)).Times(0u);
171 stream_->OnStreamHeaderList(false, headers.uncompressed_header_bytes(),
172 headers);
173 EXPECT_THAT(stream_->stream_error(), IsStreamError(QUIC_STREAM_NO_ERROR));
174 EXPECT_EQ(stream_->ietf_application_error(),
175 static_cast<uint64_t>(QuicHttp3ErrorCode::HTTP3_NO_ERROR));
176 }
177
TEST_P(QuicSpdyClientStreamTest,Test100ContinueBeforeSuccessful)178 TEST_P(QuicSpdyClientStreamTest, Test100ContinueBeforeSuccessful) {
179 // First send 100 Continue.
180 headers_[":status"] = "100";
181 auto headers = AsHeaderList(headers_);
182 stream_->OnStreamHeaderList(false, headers.uncompressed_header_bytes(),
183 headers);
184 ASSERT_EQ(stream_->preliminary_headers().size(), 1);
185 EXPECT_EQ("100",
186 stream_->preliminary_headers().front().find(":status")->second);
187 EXPECT_EQ(0u, stream_->response_headers().size());
188 EXPECT_EQ(100, stream_->response_code());
189 EXPECT_EQ("", stream_->data());
190 // Then send 200 OK.
191 headers_[":status"] = "200";
192 headers = AsHeaderList(headers_);
193 stream_->OnStreamHeaderList(false, headers.uncompressed_header_bytes(),
194 headers);
195 quiche::QuicheBuffer header = HttpEncoder::SerializeDataFrameHeader(
196 body_.length(), quiche::SimpleBufferAllocator::Get());
197 std::string data = VersionUsesHttp3(connection_->transport_version())
198 ? absl::StrCat(header.AsStringView(), body_)
199 : body_;
200 stream_->OnStreamFrame(
201 QuicStreamFrame(stream_->id(), /*fin=*/false, /*offset=*/0, data));
202 // Make sure the 200 response got parsed correctly.
203 EXPECT_EQ("200", stream_->response_headers().find(":status")->second);
204 EXPECT_EQ(200, stream_->response_code());
205 EXPECT_EQ(body_, stream_->data());
206 // Make sure the 100 response is still available.
207 ASSERT_EQ(stream_->preliminary_headers().size(), 1);
208 EXPECT_EQ("100",
209 stream_->preliminary_headers().front().find(":status")->second);
210 }
211
TEST_P(QuicSpdyClientStreamTest,TestUnknownInformationalBeforeSuccessful)212 TEST_P(QuicSpdyClientStreamTest, TestUnknownInformationalBeforeSuccessful) {
213 // First send 199, an unknown Informational (1XX).
214 headers_[":status"] = "199";
215 auto headers = AsHeaderList(headers_);
216 stream_->OnStreamHeaderList(false, headers.uncompressed_header_bytes(),
217 headers);
218 ASSERT_EQ(stream_->preliminary_headers().size(), 1);
219 EXPECT_EQ("199",
220 stream_->preliminary_headers().front().find(":status")->second);
221 EXPECT_EQ(0u, stream_->response_headers().size());
222 EXPECT_EQ(199, stream_->response_code());
223 EXPECT_EQ("", stream_->data());
224 // Then send 200 OK.
225 headers_[":status"] = "200";
226 headers = AsHeaderList(headers_);
227 stream_->OnStreamHeaderList(false, headers.uncompressed_header_bytes(),
228 headers);
229 quiche::QuicheBuffer header = HttpEncoder::SerializeDataFrameHeader(
230 body_.length(), quiche::SimpleBufferAllocator::Get());
231 std::string data = VersionUsesHttp3(connection_->transport_version())
232 ? absl::StrCat(header.AsStringView(), body_)
233 : body_;
234 stream_->OnStreamFrame(
235 QuicStreamFrame(stream_->id(), /*fin=*/false, /*offset=*/0, data));
236 // Make sure the 200 response got parsed correctly.
237 EXPECT_EQ("200", stream_->response_headers().find(":status")->second);
238 EXPECT_EQ(200, stream_->response_code());
239 EXPECT_EQ(body_, stream_->data());
240 // Make sure the 199 response is still available.
241 ASSERT_EQ(stream_->preliminary_headers().size(), 1);
242 EXPECT_EQ("199",
243 stream_->preliminary_headers().front().find(":status")->second);
244 }
245
TEST_P(QuicSpdyClientStreamTest,TestMultipleInformationalBeforeSuccessful)246 TEST_P(QuicSpdyClientStreamTest, TestMultipleInformationalBeforeSuccessful) {
247 // First send 100 Continue.
248 headers_[":status"] = "100";
249 auto headers = AsHeaderList(headers_);
250 stream_->OnStreamHeaderList(false, headers.uncompressed_header_bytes(),
251 headers);
252 ASSERT_EQ(stream_->preliminary_headers().size(), 1);
253 EXPECT_EQ("100",
254 stream_->preliminary_headers().front().find(":status")->second);
255 EXPECT_EQ(0u, stream_->response_headers().size());
256 EXPECT_EQ(100, stream_->response_code());
257 EXPECT_EQ("", stream_->data());
258
259 // Then send 199, an unknown Informational (1XX).
260 headers_[":status"] = "199";
261 headers = AsHeaderList(headers_);
262 stream_->OnStreamHeaderList(false, headers.uncompressed_header_bytes(),
263 headers);
264 ASSERT_EQ(stream_->preliminary_headers().size(), 2);
265 EXPECT_EQ("100",
266 stream_->preliminary_headers().front().find(":status")->second);
267 EXPECT_EQ("199",
268 stream_->preliminary_headers().back().find(":status")->second);
269 EXPECT_EQ(0u, stream_->response_headers().size());
270 EXPECT_EQ(199, stream_->response_code());
271 EXPECT_EQ("", stream_->data());
272
273 // Then send 200 OK.
274 headers_[":status"] = "200";
275 headers = AsHeaderList(headers_);
276 stream_->OnStreamHeaderList(false, headers.uncompressed_header_bytes(),
277 headers);
278 quiche::QuicheBuffer header = HttpEncoder::SerializeDataFrameHeader(
279 body_.length(), quiche::SimpleBufferAllocator::Get());
280 std::string data = VersionUsesHttp3(connection_->transport_version())
281 ? absl::StrCat(header.AsStringView(), body_)
282 : body_;
283 stream_->OnStreamFrame(
284 QuicStreamFrame(stream_->id(), /*fin=*/false, /*offset=*/0, data));
285
286 // Make sure the 200 response got parsed correctly.
287 EXPECT_EQ("200", stream_->response_headers().find(":status")->second);
288 EXPECT_EQ(200, stream_->response_code());
289 EXPECT_EQ(body_, stream_->data());
290
291 // Make sure the informational responses are still available.
292 ASSERT_EQ(stream_->preliminary_headers().size(), 2);
293 EXPECT_EQ("100",
294 stream_->preliminary_headers().front().find(":status")->second);
295 EXPECT_EQ("199",
296 stream_->preliminary_headers().back().find(":status")->second);
297 }
298
TEST_P(QuicSpdyClientStreamTest,TestReceiving101)299 TEST_P(QuicSpdyClientStreamTest, TestReceiving101) {
300 // 101 "Switching Protocols" is forbidden in HTTP/3 as per the
301 // "HTTP Upgrade" section of draft-ietf-quic-http.
302 headers_[":status"] = "101";
303 EXPECT_CALL(session_, WriteControlFrame(_, _));
304 EXPECT_CALL(*connection_,
305 OnStreamReset(stream_->id(), QUIC_BAD_APPLICATION_PAYLOAD));
306 auto headers = AsHeaderList(headers_);
307 stream_->OnStreamHeaderList(false, headers.uncompressed_header_bytes(),
308 headers);
309 EXPECT_THAT(stream_->stream_error(),
310 IsStreamError(QUIC_BAD_APPLICATION_PAYLOAD));
311 }
312
TEST_P(QuicSpdyClientStreamTest,TestFramingOnePacket)313 TEST_P(QuicSpdyClientStreamTest, TestFramingOnePacket) {
314 auto headers = AsHeaderList(headers_);
315 stream_->OnStreamHeaderList(false, headers.uncompressed_header_bytes(),
316 headers);
317 quiche::QuicheBuffer header = HttpEncoder::SerializeDataFrameHeader(
318 body_.length(), quiche::SimpleBufferAllocator::Get());
319 std::string data = VersionUsesHttp3(connection_->transport_version())
320 ? absl::StrCat(header.AsStringView(), body_)
321 : body_;
322 stream_->OnStreamFrame(
323 QuicStreamFrame(stream_->id(), /*fin=*/false, /*offset=*/0, data));
324 EXPECT_EQ("200", stream_->response_headers().find(":status")->second);
325 EXPECT_EQ(200, stream_->response_code());
326 EXPECT_EQ(body_, stream_->data());
327 }
328
TEST_P(QuicSpdyClientStreamTest,QUIC_TEST_DISABLED_IN_CHROME (TestFramingExtraData))329 TEST_P(QuicSpdyClientStreamTest,
330 QUIC_TEST_DISABLED_IN_CHROME(TestFramingExtraData)) {
331 std::string large_body = "hello world!!!!!!";
332
333 auto headers = AsHeaderList(headers_);
334 stream_->OnStreamHeaderList(false, headers.uncompressed_header_bytes(),
335 headers);
336 // The headers should parse successfully.
337 EXPECT_THAT(stream_->stream_error(), IsQuicStreamNoError());
338 EXPECT_EQ("200", stream_->response_headers().find(":status")->second);
339 EXPECT_EQ(200, stream_->response_code());
340 quiche::QuicheBuffer header = HttpEncoder::SerializeDataFrameHeader(
341 large_body.length(), quiche::SimpleBufferAllocator::Get());
342 std::string data = VersionUsesHttp3(connection_->transport_version())
343 ? absl::StrCat(header.AsStringView(), large_body)
344 : large_body;
345 EXPECT_CALL(session_, WriteControlFrame(_, _));
346 EXPECT_CALL(*connection_,
347 OnStreamReset(stream_->id(), QUIC_BAD_APPLICATION_PAYLOAD));
348
349 stream_->OnStreamFrame(
350 QuicStreamFrame(stream_->id(), /*fin=*/false, /*offset=*/0, data));
351
352 EXPECT_NE(QUIC_STREAM_NO_ERROR, stream_->stream_error());
353 EXPECT_EQ(stream_->ietf_application_error(),
354 static_cast<uint64_t>(QuicHttp3ErrorCode::GENERAL_PROTOCOL_ERROR));
355 }
356
357 // Test that receiving trailing headers (on the headers stream), containing a
358 // final offset, results in the stream being closed at that byte offset.
TEST_P(QuicSpdyClientStreamTest,ReceivingTrailers)359 TEST_P(QuicSpdyClientStreamTest, ReceivingTrailers) {
360 // There is no kFinalOffsetHeaderKey if trailers are sent on the
361 // request/response stream.
362 if (VersionUsesHttp3(connection_->transport_version())) {
363 return;
364 }
365
366 // Send headers as usual.
367 auto headers = AsHeaderList(headers_);
368 stream_->OnStreamHeaderList(false, headers.uncompressed_header_bytes(),
369 headers);
370
371 // Send trailers before sending the body. Even though a FIN has been received
372 // the stream should not be closed, as it does not yet have all the data bytes
373 // promised by the final offset field.
374 Http2HeaderBlock trailer_block;
375 trailer_block["trailer key"] = "trailer value";
376 trailer_block[kFinalOffsetHeaderKey] = absl::StrCat(body_.size());
377 auto trailers = AsHeaderList(trailer_block);
378 stream_->OnStreamHeaderList(true, trailers.uncompressed_header_bytes(),
379 trailers);
380
381 // Now send the body, which should close the stream as the FIN has been
382 // received, as well as all data.
383 quiche::QuicheBuffer header = HttpEncoder::SerializeDataFrameHeader(
384 body_.length(), quiche::SimpleBufferAllocator::Get());
385 std::string data = VersionUsesHttp3(connection_->transport_version())
386 ? absl::StrCat(header.AsStringView(), body_)
387 : body_;
388 stream_->OnStreamFrame(
389 QuicStreamFrame(stream_->id(), /*fin=*/false, /*offset=*/0, data));
390 EXPECT_TRUE(stream_->reading_stopped());
391 }
392
393 } // namespace
394 } // namespace test
395 } // namespace quic
396