• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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