1 // Copyright (c) 2012 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/tools/quic_simple_server_stream.h"
6
7 #include <cstdint>
8 #include <list>
9 #include <optional>
10 #include <utility>
11
12 #include "absl/strings/numbers.h"
13 #include "absl/strings/str_cat.h"
14 #include "absl/strings/string_view.h"
15 #include "quiche/quic/core/http/quic_spdy_stream.h"
16 #include "quiche/quic/core/http/spdy_utils.h"
17 #include "quiche/quic/core/http/web_transport_http3.h"
18 #include "quiche/quic/core/quic_error_codes.h"
19 #include "quiche/quic/core/quic_utils.h"
20 #include "quiche/quic/platform/api/quic_bug_tracker.h"
21 #include "quiche/quic/platform/api/quic_flags.h"
22 #include "quiche/quic/platform/api/quic_logging.h"
23 #include "quiche/quic/tools/quic_simple_server_session.h"
24 #include "quiche/spdy/core/spdy_protocol.h"
25
26 using spdy::Http2HeaderBlock;
27
28 namespace quic {
29
QuicSimpleServerStream(QuicStreamId id,QuicSpdySession * session,StreamType type,QuicSimpleServerBackend * quic_simple_server_backend)30 QuicSimpleServerStream::QuicSimpleServerStream(
31 QuicStreamId id, QuicSpdySession* session, StreamType type,
32 QuicSimpleServerBackend* quic_simple_server_backend)
33 : QuicSpdyServerStreamBase(id, session, type),
34 content_length_(-1),
35 generate_bytes_length_(0),
36 quic_simple_server_backend_(quic_simple_server_backend) {
37 QUICHE_DCHECK(quic_simple_server_backend_);
38 }
39
QuicSimpleServerStream(PendingStream * pending,QuicSpdySession * session,QuicSimpleServerBackend * quic_simple_server_backend)40 QuicSimpleServerStream::QuicSimpleServerStream(
41 PendingStream* pending, QuicSpdySession* session,
42 QuicSimpleServerBackend* quic_simple_server_backend)
43 : QuicSpdyServerStreamBase(pending, session),
44 content_length_(-1),
45 generate_bytes_length_(0),
46 quic_simple_server_backend_(quic_simple_server_backend) {
47 QUICHE_DCHECK(quic_simple_server_backend_);
48 }
49
~QuicSimpleServerStream()50 QuicSimpleServerStream::~QuicSimpleServerStream() {
51 quic_simple_server_backend_->CloseBackendResponseStream(this);
52 }
53
OnInitialHeadersComplete(bool fin,size_t frame_len,const QuicHeaderList & header_list)54 void QuicSimpleServerStream::OnInitialHeadersComplete(
55 bool fin, size_t frame_len, const QuicHeaderList& header_list) {
56 QuicSpdyStream::OnInitialHeadersComplete(fin, frame_len, header_list);
57 // QuicSpdyStream::OnInitialHeadersComplete() may have already sent error
58 // response.
59 if (!response_sent_ &&
60 !SpdyUtils::CopyAndValidateHeaders(header_list, &content_length_,
61 &request_headers_)) {
62 QUIC_DVLOG(1) << "Invalid headers";
63 SendErrorResponse();
64 }
65 ConsumeHeaderList();
66
67 // CONNECT requests do not carry any message content but carry data after the
68 // headers, so they require sending the response right after parsing the
69 // headers even though the FIN bit has not been received on the request
70 // stream.
71 if (!fin && !response_sent_ && IsConnectRequest()) {
72 if (quic_simple_server_backend_ == nullptr) {
73 QUIC_DVLOG(1) << "Backend is missing on CONNECT headers.";
74 SendErrorResponse();
75 return;
76 }
77
78 if (web_transport() != nullptr) {
79 QuicSimpleServerBackend::WebTransportResponse response =
80 quic_simple_server_backend_->ProcessWebTransportRequest(
81 request_headers_, web_transport());
82 if (response.response_headers[":status"] == "200") {
83 WriteHeaders(std::move(response.response_headers), false, nullptr);
84 if (response.visitor != nullptr) {
85 web_transport()->SetVisitor(std::move(response.visitor));
86 }
87 web_transport()->HeadersReceived(request_headers_);
88 } else {
89 WriteHeaders(std::move(response.response_headers), true, nullptr);
90 }
91 return;
92 }
93
94 quic_simple_server_backend_->HandleConnectHeaders(request_headers_,
95 /*request_handler=*/this);
96 }
97 }
98
OnBodyAvailable()99 void QuicSimpleServerStream::OnBodyAvailable() {
100 while (HasBytesToRead()) {
101 struct iovec iov;
102 if (GetReadableRegions(&iov, 1) == 0) {
103 // No more data to read.
104 break;
105 }
106 QUIC_DVLOG(1) << "Stream " << id() << " processed " << iov.iov_len
107 << " bytes.";
108 body_.append(static_cast<char*>(iov.iov_base), iov.iov_len);
109
110 if (content_length_ >= 0 &&
111 body_.size() > static_cast<uint64_t>(content_length_)) {
112 QUIC_DVLOG(1) << "Body size (" << body_.size() << ") > content length ("
113 << content_length_ << ").";
114 SendErrorResponse();
115 return;
116 }
117 MarkConsumed(iov.iov_len);
118 }
119
120 if (!sequencer()->IsClosed()) {
121 if (IsConnectRequest()) {
122 HandleRequestConnectData(/*fin_received=*/false);
123 }
124 sequencer()->SetUnblocked();
125 return;
126 }
127
128 // If the sequencer is closed, then all the body, including the fin, has been
129 // consumed.
130 OnFinRead();
131
132 if (write_side_closed() || fin_buffered()) {
133 return;
134 }
135
136 if (IsConnectRequest()) {
137 HandleRequestConnectData(/*fin_received=*/true);
138 } else {
139 SendResponse();
140 }
141 }
142
HandleRequestConnectData(bool fin_received)143 void QuicSimpleServerStream::HandleRequestConnectData(bool fin_received) {
144 QUICHE_DCHECK(IsConnectRequest());
145
146 if (quic_simple_server_backend_ == nullptr) {
147 QUIC_DVLOG(1) << "Backend is missing on CONNECT data.";
148 ResetWriteSide(
149 QuicResetStreamError::FromInternal(QUIC_STREAM_CONNECT_ERROR));
150 return;
151 }
152
153 // Clear `body_`, so only new data is sent to the backend next time.
154 std::string data = std::move(body_);
155 body_.clear();
156
157 quic_simple_server_backend_->HandleConnectData(data,
158 /*data_complete=*/fin_received,
159 this);
160 }
161
SendResponse()162 void QuicSimpleServerStream::SendResponse() {
163 QUICHE_DCHECK(!IsConnectRequest());
164
165 if (request_headers_.empty()) {
166 QUIC_DVLOG(1) << "Request headers empty.";
167 SendErrorResponse();
168 return;
169 }
170
171 if (content_length_ > 0 &&
172 static_cast<uint64_t>(content_length_) != body_.size()) {
173 QUIC_DVLOG(1) << "Content length (" << content_length_ << ") != body size ("
174 << body_.size() << ").";
175 SendErrorResponse();
176 return;
177 }
178
179 if (!request_headers_.contains(":authority")) {
180 QUIC_DVLOG(1) << "Request headers do not contain :authority.";
181 SendErrorResponse();
182 return;
183 }
184
185 if (!request_headers_.contains(":path")) {
186 QUIC_DVLOG(1) << "Request headers do not contain :path.";
187 SendErrorResponse();
188 return;
189 }
190
191 if (quic_simple_server_backend_ == nullptr) {
192 QUIC_DVLOG(1) << "Backend is missing in SendResponse().";
193 SendErrorResponse();
194 return;
195 }
196
197 if (web_transport() != nullptr) {
198 QuicSimpleServerBackend::WebTransportResponse response =
199 quic_simple_server_backend_->ProcessWebTransportRequest(
200 request_headers_, web_transport());
201 if (response.response_headers[":status"] == "200") {
202 WriteHeaders(std::move(response.response_headers), false, nullptr);
203 if (response.visitor != nullptr) {
204 web_transport()->SetVisitor(std::move(response.visitor));
205 }
206 web_transport()->HeadersReceived(request_headers_);
207 } else {
208 WriteHeaders(std::move(response.response_headers), true, nullptr);
209 }
210 return;
211 }
212
213 // Fetch the response from the backend interface and wait for callback once
214 // response is ready
215 quic_simple_server_backend_->FetchResponseFromBackend(request_headers_, body_,
216 this);
217 }
218
connection_id() const219 QuicConnectionId QuicSimpleServerStream::connection_id() const {
220 return spdy_session()->connection_id();
221 }
222
stream_id() const223 QuicStreamId QuicSimpleServerStream::stream_id() const { return id(); }
224
peer_host() const225 std::string QuicSimpleServerStream::peer_host() const {
226 return spdy_session()->peer_address().host().ToString();
227 }
228
GetStream()229 QuicSpdyStream* QuicSimpleServerStream::GetStream() { return this; }
230
231 namespace {
232
233 class DelayedResponseAlarm : public QuicAlarm::DelegateWithContext {
234 public:
DelayedResponseAlarm(QuicSimpleServerStream * stream,const QuicBackendResponse * response)235 DelayedResponseAlarm(QuicSimpleServerStream* stream,
236 const QuicBackendResponse* response)
237 : QuicAlarm::DelegateWithContext(
238 stream->spdy_session()->connection()->context()),
239 stream_(stream),
240 response_(response) {
241 stream_ = stream;
242 response_ = response;
243 }
244
245 ~DelayedResponseAlarm() override = default;
246
OnAlarm()247 void OnAlarm() override { stream_->Respond(response_); }
248
249 private:
250 QuicSimpleServerStream* stream_;
251 const QuicBackendResponse* response_;
252 };
253
254 } // namespace
255
OnResponseBackendComplete(const QuicBackendResponse * response)256 void QuicSimpleServerStream::OnResponseBackendComplete(
257 const QuicBackendResponse* response) {
258 if (response == nullptr) {
259 QUIC_DVLOG(1) << "Response not found in cache.";
260 SendNotFoundResponse();
261 return;
262 }
263
264 auto delay = response->delay();
265 if (delay.IsZero()) {
266 Respond(response);
267 return;
268 }
269
270 auto* connection = session()->connection();
271 delayed_response_alarm_.reset(connection->alarm_factory()->CreateAlarm(
272 new DelayedResponseAlarm(this, response)));
273 delayed_response_alarm_->Set(connection->clock()->Now() + delay);
274 }
275
Respond(const QuicBackendResponse * response)276 void QuicSimpleServerStream::Respond(const QuicBackendResponse* response) {
277 // Send Early Hints first.
278 for (const auto& headers : response->early_hints()) {
279 QUIC_DVLOG(1) << "Stream " << id() << " sending an Early Hints response: "
280 << headers.DebugString();
281 WriteHeaders(headers.Clone(), false, nullptr);
282 }
283
284 if (response->response_type() == QuicBackendResponse::CLOSE_CONNECTION) {
285 QUIC_DVLOG(1) << "Special response: closing connection.";
286 OnUnrecoverableError(QUIC_NO_ERROR, "Toy server forcing close");
287 return;
288 }
289
290 if (response->response_type() == QuicBackendResponse::IGNORE_REQUEST) {
291 QUIC_DVLOG(1) << "Special response: ignoring request.";
292 return;
293 }
294
295 if (response->response_type() == QuicBackendResponse::BACKEND_ERR_RESPONSE) {
296 QUIC_DVLOG(1) << "Quic Proxy: Backend connection error.";
297 /*502 Bad Gateway
298 The server was acting as a gateway or proxy and received an
299 invalid response from the upstream server.*/
300 SendErrorResponse(502);
301 return;
302 }
303
304 // Examing response status, if it was not pure integer as typical h2
305 // response status, send error response. Notice that
306 // QuicHttpResponseCache push urls are strictly authority + path only,
307 // scheme is not included (see |QuicHttpResponseCache::GetKey()|).
308 std::string request_url = request_headers_[":authority"].as_string() +
309 request_headers_[":path"].as_string();
310 int response_code;
311 const Http2HeaderBlock& response_headers = response->headers();
312 if (!ParseHeaderStatusCode(response_headers, &response_code)) {
313 auto status = response_headers.find(":status");
314 if (status == response_headers.end()) {
315 QUIC_LOG(WARNING)
316 << ":status not present in response from cache for request "
317 << request_url;
318 } else {
319 QUIC_LOG(WARNING) << "Illegal (non-integer) response :status from cache: "
320 << status->second << " for request " << request_url;
321 }
322 SendErrorResponse();
323 return;
324 }
325
326 if (response->response_type() == QuicBackendResponse::INCOMPLETE_RESPONSE) {
327 QUIC_DVLOG(1)
328 << "Stream " << id()
329 << " sending an incomplete response, i.e. no trailer, no fin.";
330 SendIncompleteResponse(response->headers().Clone(), response->body());
331 return;
332 }
333
334 if (response->response_type() == QuicBackendResponse::GENERATE_BYTES) {
335 QUIC_DVLOG(1) << "Stream " << id() << " sending a generate bytes response.";
336 std::string path = request_headers_[":path"].as_string().substr(1);
337 if (!absl::SimpleAtoi(path, &generate_bytes_length_)) {
338 QUIC_LOG(ERROR) << "Path is not a number.";
339 SendNotFoundResponse();
340 return;
341 }
342 Http2HeaderBlock headers = response->headers().Clone();
343 headers["content-length"] = absl::StrCat(generate_bytes_length_);
344
345 WriteHeaders(std::move(headers), false, nullptr);
346 QUICHE_DCHECK(!response_sent_);
347 response_sent_ = true;
348
349 WriteGeneratedBytes();
350
351 return;
352 }
353
354 QUIC_DVLOG(1) << "Stream " << id() << " sending response.";
355 SendHeadersAndBodyAndTrailers(response->headers().Clone(), response->body(),
356 response->trailers().Clone());
357 }
358
SendStreamData(absl::string_view data,bool close_stream)359 void QuicSimpleServerStream::SendStreamData(absl::string_view data,
360 bool close_stream) {
361 // Doesn't make sense to call this without data or `close_stream`.
362 QUICHE_DCHECK(!data.empty() || close_stream);
363
364 if (close_stream) {
365 SendHeadersAndBodyAndTrailers(
366 /*response_headers=*/std::nullopt, data,
367 /*response_trailers=*/spdy::Http2HeaderBlock());
368 } else {
369 SendIncompleteResponse(/*response_headers=*/std::nullopt, data);
370 }
371 }
372
TerminateStreamWithError(QuicResetStreamError error)373 void QuicSimpleServerStream::TerminateStreamWithError(
374 QuicResetStreamError error) {
375 QUIC_DVLOG(1) << "Stream " << id() << " abruptly terminating with error "
376 << error.internal_code();
377 ResetWriteSide(error);
378 }
379
OnCanWrite()380 void QuicSimpleServerStream::OnCanWrite() {
381 QuicSpdyStream::OnCanWrite();
382 WriteGeneratedBytes();
383 }
384
WriteGeneratedBytes()385 void QuicSimpleServerStream::WriteGeneratedBytes() {
386 static size_t kChunkSize = 1024;
387 while (!HasBufferedData() && generate_bytes_length_ > 0) {
388 size_t len = std::min<size_t>(kChunkSize, generate_bytes_length_);
389 std::string data(len, 'a');
390 generate_bytes_length_ -= len;
391 bool fin = generate_bytes_length_ == 0;
392 WriteOrBufferBody(data, fin);
393 }
394 }
395
SendNotFoundResponse()396 void QuicSimpleServerStream::SendNotFoundResponse() {
397 QUIC_DVLOG(1) << "Stream " << id() << " sending not found response.";
398 Http2HeaderBlock headers;
399 headers[":status"] = "404";
400 headers["content-length"] = absl::StrCat(strlen(kNotFoundResponseBody));
401 SendHeadersAndBody(std::move(headers), kNotFoundResponseBody);
402 }
403
SendErrorResponse()404 void QuicSimpleServerStream::SendErrorResponse() { SendErrorResponse(0); }
405
SendErrorResponse(int resp_code)406 void QuicSimpleServerStream::SendErrorResponse(int resp_code) {
407 QUIC_DVLOG(1) << "Stream " << id() << " sending error response.";
408 if (!reading_stopped()) {
409 StopReading();
410 }
411 Http2HeaderBlock headers;
412 if (resp_code <= 0) {
413 headers[":status"] = "500";
414 } else {
415 headers[":status"] = absl::StrCat(resp_code);
416 }
417 headers["content-length"] = absl::StrCat(strlen(kErrorResponseBody));
418 SendHeadersAndBody(std::move(headers), kErrorResponseBody);
419 }
420
SendIncompleteResponse(std::optional<Http2HeaderBlock> response_headers,absl::string_view body)421 void QuicSimpleServerStream::SendIncompleteResponse(
422 std::optional<Http2HeaderBlock> response_headers, absl::string_view body) {
423 // Headers should be sent iff not sent in a previous response.
424 QUICHE_DCHECK_NE(response_headers.has_value(), response_sent_);
425
426 if (response_headers.has_value()) {
427 QUIC_DLOG(INFO) << "Stream " << id() << " writing headers (fin = false) : "
428 << response_headers.value().DebugString();
429 // Do not mark response sent for early 100 continue response.
430 int response_code;
431 if (!ParseHeaderStatusCode(*response_headers, &response_code) ||
432 response_code != 100) {
433 response_sent_ = true;
434 }
435 WriteHeaders(std::move(response_headers).value(), /*fin=*/false, nullptr);
436 }
437
438 QUIC_DLOG(INFO) << "Stream " << id()
439 << " writing body (fin = false) with size: " << body.size();
440 if (!body.empty()) {
441 WriteOrBufferBody(body, /*fin=*/false);
442 }
443 }
444
SendHeadersAndBody(Http2HeaderBlock response_headers,absl::string_view body)445 void QuicSimpleServerStream::SendHeadersAndBody(
446 Http2HeaderBlock response_headers, absl::string_view body) {
447 SendHeadersAndBodyAndTrailers(std::move(response_headers), body,
448 Http2HeaderBlock());
449 }
450
SendHeadersAndBodyAndTrailers(std::optional<Http2HeaderBlock> response_headers,absl::string_view body,Http2HeaderBlock response_trailers)451 void QuicSimpleServerStream::SendHeadersAndBodyAndTrailers(
452 std::optional<Http2HeaderBlock> response_headers, absl::string_view body,
453 Http2HeaderBlock response_trailers) {
454 // Headers should be sent iff not sent in a previous response.
455 QUICHE_DCHECK_NE(response_headers.has_value(), response_sent_);
456
457 if (response_headers.has_value()) {
458 // Send the headers, with a FIN if there's nothing else to send.
459 bool send_fin = (body.empty() && response_trailers.empty());
460 QUIC_DLOG(INFO) << "Stream " << id()
461 << " writing headers (fin = " << send_fin
462 << ") : " << response_headers.value().DebugString();
463 WriteHeaders(std::move(response_headers).value(), send_fin, nullptr);
464 response_sent_ = true;
465 if (send_fin) {
466 // Nothing else to send.
467 return;
468 }
469 }
470
471 // Send the body, with a FIN if there's no trailers to send.
472 bool send_fin = response_trailers.empty();
473 QUIC_DLOG(INFO) << "Stream " << id() << " writing body (fin = " << send_fin
474 << ") with size: " << body.size();
475 if (!body.empty() || send_fin) {
476 WriteOrBufferBody(body, send_fin);
477 }
478 if (send_fin) {
479 // Nothing else to send.
480 return;
481 }
482
483 // Send the trailers. A FIN is always sent with trailers.
484 QUIC_DLOG(INFO) << "Stream " << id() << " writing trailers (fin = true): "
485 << response_trailers.DebugString();
486 WriteTrailers(std::move(response_trailers), nullptr);
487 }
488
IsConnectRequest() const489 bool QuicSimpleServerStream::IsConnectRequest() const {
490 auto method_it = request_headers_.find(":method");
491 return method_it != request_headers_.end() && method_it->second == "CONNECT";
492 }
493
OnInvalidHeaders()494 void QuicSimpleServerStream::OnInvalidHeaders() {
495 QUIC_DVLOG(1) << "Invalid headers";
496 SendErrorResponse(400);
497 }
498
499 const char* const QuicSimpleServerStream::kErrorResponseBody = "bad";
500 const char* const QuicSimpleServerStream::kNotFoundResponseBody =
501 "file not found";
502
503 } // namespace quic
504