1 // Copyright 2012 The Chromium Authors
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/http/http_stream_parser.h"
6
7 #include <algorithm>
8 #include <memory>
9 #include <string_view>
10 #include <utility>
11
12 #include "base/check.h"
13 #include "base/compiler_specific.h"
14 #include "base/containers/span.h"
15 #include "base/containers/span_writer.h"
16 #include "base/functional/bind.h"
17 #include "base/logging.h"
18 #include "base/memory/raw_ptr.h"
19 #include "base/metrics/histogram_macros.h"
20 #include "base/numerics/clamped_math.h"
21 #include "base/numerics/safe_conversions.h"
22 #include "base/strings/string_tokenizer.h"
23 #include "base/strings/string_util.h"
24 #include "base/strings/stringprintf.h"
25 #include "base/values.h"
26 #include "net/base/features.h"
27 #include "net/base/io_buffer.h"
28 #include "net/base/ip_endpoint.h"
29 #include "net/base/upload_data_stream.h"
30 #include "net/http/http_chunked_decoder.h"
31 #include "net/http/http_connection_info.h"
32 #include "net/http/http_log_util.h"
33 #include "net/http/http_request_headers.h"
34 #include "net/http/http_response_headers.h"
35 #include "net/http/http_response_info.h"
36 #include "net/http/http_status_code.h"
37 #include "net/http/http_util.h"
38 #include "net/log/net_log_event_type.h"
39 #include "net/socket/ssl_client_socket.h"
40 #include "net/socket/stream_socket.h"
41 #include "net/ssl/ssl_cert_request_info.h"
42 #include "net/ssl/ssl_info.h"
43 #include "url/gurl.h"
44 #include "url/url_canon.h"
45
46 namespace net {
47
48 namespace {
49
50 const uint64_t kMaxMergedHeaderAndBodySize = 1400;
51 const size_t kRequestBodyBufferSize = 1 << 14; // 16KB
52
GetResponseHeaderLines(const HttpResponseHeaders & headers)53 std::string GetResponseHeaderLines(const HttpResponseHeaders& headers) {
54 std::string cr_separated_headers;
55 base::StringTokenizer tokenizer(headers.raw_headers(), std::string(1, '\0'));
56 while (tokenizer.GetNext()) {
57 base::StrAppend(&cr_separated_headers, {tokenizer.token_piece(), "\n"});
58 }
59 return cr_separated_headers;
60 }
61
NetLogSendRequestBodyParams(uint64_t length,bool is_chunked,bool did_merge)62 base::Value::Dict NetLogSendRequestBodyParams(uint64_t length,
63 bool is_chunked,
64 bool did_merge) {
65 base::Value::Dict dict;
66 dict.Set("length", static_cast<int>(length));
67 dict.Set("is_chunked", is_chunked);
68 dict.Set("did_merge", did_merge);
69 return dict;
70 }
71
NetLogSendRequestBody(const NetLogWithSource & net_log,uint64_t length,bool is_chunked,bool did_merge)72 void NetLogSendRequestBody(const NetLogWithSource& net_log,
73 uint64_t length,
74 bool is_chunked,
75 bool did_merge) {
76 net_log.AddEvent(NetLogEventType::HTTP_TRANSACTION_SEND_REQUEST_BODY, [&] {
77 return NetLogSendRequestBodyParams(length, is_chunked, did_merge);
78 });
79 }
80
81 // Returns true if |error_code| is an error for which we give the server a
82 // chance to send a body containing error information, if the error was received
83 // while trying to upload a request body.
ShouldTryReadingOnUploadError(int error_code)84 bool ShouldTryReadingOnUploadError(int error_code) {
85 return (error_code == ERR_CONNECTION_RESET);
86 }
87
88 } // namespace
89
90 // Similar to DrainableIOBuffer(), but this version comes with its own
91 // storage. The motivation is to avoid repeated allocations of
92 // DrainableIOBuffer.
93 //
94 // Example:
95 //
96 // scoped_refptr<SeekableIOBuffer> buf =
97 // base::MakeRefCounted<SeekableIOBuffer>(1024);
98 // // capacity() == 1024. size() == BytesRemaining() == BytesConsumed() == 0.
99 // // data() points to the beginning of the buffer.
100 //
101 // // Read() takes an IOBuffer.
102 // int bytes_read = some_reader->Read(buf, buf->capacity());
103 // buf->DidAppend(bytes_read);
104 // // size() == BytesRemaining() == bytes_read. data() is unaffected.
105 //
106 // while (buf->BytesRemaining() > 0) {
107 // // Write() takes an IOBuffer. If it takes const char*, we could
108 /// // simply use the regular IOBuffer like buf->data() + offset.
109 // int bytes_written = Write(buf, buf->BytesRemaining());
110 // buf->DidConsume(bytes_written);
111 // }
112 // // BytesRemaining() == 0. BytesConsumed() == size().
113 // // data() points to the end of the consumed bytes (exclusive).
114 //
115 // // If you want to reuse the buffer, be sure to clear the buffer.
116 // buf->Clear();
117 // // size() == BytesRemaining() == BytesConsumed() == 0.
118 // // data() points to the beginning of the buffer.
119 //
120 class HttpStreamParser::SeekableIOBuffer : public IOBufferWithSize {
121 public:
SeekableIOBuffer(int capacity)122 explicit SeekableIOBuffer(int capacity)
123 : IOBufferWithSize(capacity), real_data_(data_), capacity_(capacity) {}
124
125 // DidConsume() changes the |data_| pointer so that |data_| always points
126 // to the first unconsumed byte.
DidConsume(int bytes)127 void DidConsume(int bytes) {
128 SetOffset(used_ + bytes);
129 }
130
131 // Returns the number of unconsumed bytes.
BytesRemaining() const132 int BytesRemaining() const {
133 return size_ - used_;
134 }
135
136 // Seeks to an arbitrary point in the buffer. The notion of bytes consumed
137 // and remaining are updated appropriately.
SetOffset(int bytes)138 void SetOffset(int bytes) {
139 DCHECK_GE(bytes, 0);
140 DCHECK_LE(bytes, size_);
141 used_ = bytes;
142 data_ = real_data_ + used_;
143 }
144
145 // Called after data is added to the buffer. Adds |bytes| added to
146 // |size_|. data() is unaffected.
DidAppend(int bytes)147 void DidAppend(int bytes) {
148 DCHECK_GE(bytes, 0);
149 DCHECK_GE(size_ + bytes, 0);
150 DCHECK_LE(size_ + bytes, capacity_);
151 size_ += bytes;
152 }
153
154 // Changes the logical size to 0, and the offset to 0.
Clear()155 void Clear() {
156 size_ = 0;
157 SetOffset(0);
158 }
159
160 // Returns the logical size of the buffer (i.e the number of bytes of data
161 // in the buffer).
size() const162 int size() const { return size_; }
163
164 // Returns the capacity of the buffer. The capacity is the size used when
165 // the object is created.
capacity() const166 int capacity() const { return capacity_; }
167
168 private:
~SeekableIOBuffer()169 ~SeekableIOBuffer() override {
170 // data_ will be deleted in IOBuffer::~IOBuffer().
171 data_ = real_data_;
172 }
173
174 raw_ptr<char, AllowPtrArithmetic> real_data_;
175 const int capacity_;
176 int size_ = 0;
177 int used_ = 0;
178 };
179
180 // 2 CRLFs + max of 8 hex chars.
181 const size_t HttpStreamParser::kChunkHeaderFooterSize = 12;
182
HttpStreamParser(StreamSocket * stream_socket,bool connection_is_reused,const GURL & url,const std::string & method,UploadDataStream * upload_data_stream,GrowableIOBuffer * read_buffer,const NetLogWithSource & net_log)183 HttpStreamParser::HttpStreamParser(StreamSocket* stream_socket,
184 bool connection_is_reused,
185 const GURL& url,
186 const std::string& method,
187 UploadDataStream* upload_data_stream,
188 GrowableIOBuffer* read_buffer,
189 const NetLogWithSource& net_log)
190 : url_(url),
191 method_(method),
192 upload_data_stream_(upload_data_stream),
193 read_buf_(read_buffer),
194 response_header_start_offset_(std::string::npos),
195 stream_socket_(stream_socket),
196 connection_is_reused_(connection_is_reused),
197 net_log_(net_log),
198 truncate_to_content_length_enabled_(base::FeatureList::IsEnabled(
199 features::kTruncateBodyToContentLength)) {
200 io_callback_ = base::BindRepeating(&HttpStreamParser::OnIOComplete,
201 weak_ptr_factory_.GetWeakPtr());
202 }
203
204 HttpStreamParser::~HttpStreamParser() = default;
205
SendRequest(const std::string & request_line,const HttpRequestHeaders & headers,const NetworkTrafficAnnotationTag & traffic_annotation,HttpResponseInfo * response,CompletionOnceCallback callback)206 int HttpStreamParser::SendRequest(
207 const std::string& request_line,
208 const HttpRequestHeaders& headers,
209 const NetworkTrafficAnnotationTag& traffic_annotation,
210 HttpResponseInfo* response,
211 CompletionOnceCallback callback) {
212 DCHECK_EQ(STATE_NONE, io_state_);
213 DCHECK(callback_.is_null());
214 DCHECK(!callback.is_null());
215 DCHECK(response);
216
217 NetLogRequestHeaders(net_log_,
218 NetLogEventType::HTTP_TRANSACTION_SEND_REQUEST_HEADERS,
219 request_line, &headers);
220
221 DVLOG(1) << __func__ << "() request_line = \"" << request_line << "\""
222 << " headers = \"" << headers.ToString() << "\"";
223 traffic_annotation_ = MutableNetworkTrafficAnnotationTag(traffic_annotation);
224 response_ = response;
225
226 // Put the peer's IP address and port into the response.
227 IPEndPoint ip_endpoint;
228 int result = stream_socket_->GetPeerAddress(&ip_endpoint);
229 if (result != OK)
230 return result;
231 response_->remote_endpoint = ip_endpoint;
232
233 std::string request = request_line + headers.ToString();
234 request_headers_length_ = request.size();
235
236 if (upload_data_stream_) {
237 request_body_send_buf_ =
238 base::MakeRefCounted<SeekableIOBuffer>(kRequestBodyBufferSize);
239 if (upload_data_stream_->is_chunked()) {
240 // Read buffer is adjusted to guarantee that |request_body_send_buf_| is
241 // large enough to hold the encoded chunk.
242 request_body_read_buf_ = base::MakeRefCounted<SeekableIOBuffer>(
243 kRequestBodyBufferSize - kChunkHeaderFooterSize);
244 } else {
245 // No need to encode request body, just send the raw data.
246 request_body_read_buf_ = request_body_send_buf_;
247 }
248 }
249
250 io_state_ = STATE_SEND_HEADERS;
251
252 // If we have a small request body, then we'll merge with the headers into a
253 // single write.
254 bool did_merge = false;
255 if (ShouldMergeRequestHeadersAndBody(request, upload_data_stream_)) {
256 int merged_size =
257 static_cast<int>(request_headers_length_ + upload_data_stream_->size());
258 auto merged_request_headers_and_body =
259 base::MakeRefCounted<IOBufferWithSize>(merged_size);
260 // We'll repurpose |request_headers_| to store the merged headers and
261 // body.
262 request_headers_ = base::MakeRefCounted<DrainableIOBuffer>(
263 merged_request_headers_and_body, merged_size);
264
265 memcpy(request_headers_->data(), request.data(), request_headers_length_);
266 request_headers_->DidConsume(request_headers_length_);
267
268 uint64_t todo = upload_data_stream_->size();
269 while (todo) {
270 int consumed = upload_data_stream_->Read(request_headers_.get(),
271 static_cast<int>(todo),
272 CompletionOnceCallback());
273 // Read() must succeed synchronously if not chunked and in memory.
274 DCHECK_GT(consumed, 0);
275 request_headers_->DidConsume(consumed);
276 todo -= consumed;
277 }
278 DCHECK(upload_data_stream_->IsEOF());
279 // Reset the offset, so the buffer can be read from the beginning.
280 request_headers_->SetOffset(0);
281 did_merge = true;
282
283 NetLogSendRequestBody(net_log_, upload_data_stream_->size(),
284 false, /* not chunked */
285 true /* merged */);
286 }
287
288 if (!did_merge) {
289 // If we didn't merge the body with the headers, then |request_headers_|
290 // contains just the HTTP headers.
291 size_t request_size = request.size();
292 scoped_refptr<StringIOBuffer> headers_io_buf =
293 base::MakeRefCounted<StringIOBuffer>(std::move(request));
294 request_headers_ = base::MakeRefCounted<DrainableIOBuffer>(
295 std::move(headers_io_buf), request_size);
296 }
297
298 result = DoLoop(OK);
299 if (result == ERR_IO_PENDING)
300 callback_ = std::move(callback);
301
302 return result > 0 ? OK : result;
303 }
304
ConfirmHandshake(CompletionOnceCallback callback)305 int HttpStreamParser::ConfirmHandshake(CompletionOnceCallback callback) {
306 int ret = stream_socket_->ConfirmHandshake(
307 base::BindOnce(&HttpStreamParser::RunConfirmHandshakeCallback,
308 weak_ptr_factory_.GetWeakPtr()));
309 if (ret == ERR_IO_PENDING)
310 confirm_handshake_callback_ = std::move(callback);
311 return ret;
312 }
313
ReadResponseHeaders(CompletionOnceCallback callback)314 int HttpStreamParser::ReadResponseHeaders(CompletionOnceCallback callback) {
315 DCHECK(io_state_ == STATE_NONE || io_state_ == STATE_DONE);
316 DCHECK(callback_.is_null());
317 DCHECK(!callback.is_null());
318 DCHECK_EQ(0u, read_buf_unused_offset_);
319 DCHECK(SendRequestBuffersEmpty());
320
321 // This function can be called with io_state_ == STATE_DONE if the
322 // connection is closed after seeing just a 1xx response code.
323 if (io_state_ == STATE_DONE)
324 return ERR_CONNECTION_CLOSED;
325
326 int result = OK;
327 io_state_ = STATE_READ_HEADERS;
328
329 if (read_buf_->offset() > 0) {
330 // Simulate the state where the data was just read from the socket.
331 result = read_buf_->offset();
332 read_buf_->set_offset(0);
333 }
334 if (result > 0)
335 io_state_ = STATE_READ_HEADERS_COMPLETE;
336
337 result = DoLoop(result);
338 if (result == ERR_IO_PENDING)
339 callback_ = std::move(callback);
340
341 return result > 0 ? OK : result;
342 }
343
ReadResponseBody(IOBuffer * buf,int buf_len,CompletionOnceCallback callback)344 int HttpStreamParser::ReadResponseBody(IOBuffer* buf,
345 int buf_len,
346 CompletionOnceCallback callback) {
347 DCHECK(io_state_ == STATE_NONE || io_state_ == STATE_DONE);
348 DCHECK(callback_.is_null());
349 DCHECK(!callback.is_null());
350 DCHECK_LE(buf_len, kMaxBufSize);
351 DCHECK(SendRequestBuffersEmpty());
352 // Added to investigate crbug.com/499663.
353 CHECK(buf);
354
355 if (io_state_ == STATE_DONE)
356 return OK;
357
358 user_read_buf_ = buf;
359 user_read_buf_len_ = base::checked_cast<size_t>(buf_len);
360 io_state_ = STATE_READ_BODY;
361
362 int result = DoLoop(OK);
363 if (result == ERR_IO_PENDING)
364 callback_ = std::move(callback);
365
366 return result;
367 }
368
OnIOComplete(int result)369 void HttpStreamParser::OnIOComplete(int result) {
370 result = DoLoop(result);
371
372 // The client callback can do anything, including destroying this class,
373 // so any pending callback must be issued after everything else is done.
374 if (result != ERR_IO_PENDING && !callback_.is_null()) {
375 std::move(callback_).Run(result);
376 }
377 }
378
DoLoop(int result)379 int HttpStreamParser::DoLoop(int result) {
380 do {
381 DCHECK_NE(ERR_IO_PENDING, result);
382 DCHECK_NE(STATE_DONE, io_state_);
383 DCHECK_NE(STATE_NONE, io_state_);
384 State state = io_state_;
385 io_state_ = STATE_NONE;
386 switch (state) {
387 case STATE_SEND_HEADERS:
388 DCHECK_EQ(OK, result);
389 result = DoSendHeaders();
390 DCHECK_NE(STATE_NONE, io_state_);
391 break;
392 case STATE_SEND_HEADERS_COMPLETE:
393 result = DoSendHeadersComplete(result);
394 DCHECK_NE(STATE_NONE, io_state_);
395 break;
396 case STATE_SEND_BODY:
397 DCHECK_EQ(OK, result);
398 result = DoSendBody();
399 DCHECK_NE(STATE_NONE, io_state_);
400 break;
401 case STATE_SEND_BODY_COMPLETE:
402 result = DoSendBodyComplete(result);
403 DCHECK_NE(STATE_NONE, io_state_);
404 break;
405 case STATE_SEND_REQUEST_READ_BODY_COMPLETE:
406 result = DoSendRequestReadBodyComplete(result);
407 DCHECK_NE(STATE_NONE, io_state_);
408 break;
409 case STATE_SEND_REQUEST_COMPLETE:
410 result = DoSendRequestComplete(result);
411 break;
412 case STATE_READ_HEADERS:
413 net_log_.BeginEvent(NetLogEventType::HTTP_STREAM_PARSER_READ_HEADERS);
414 DCHECK_GE(result, 0);
415 result = DoReadHeaders();
416 break;
417 case STATE_READ_HEADERS_COMPLETE:
418 result = DoReadHeadersComplete(result);
419 net_log_.EndEventWithNetErrorCode(
420 NetLogEventType::HTTP_STREAM_PARSER_READ_HEADERS, result);
421 break;
422 case STATE_READ_BODY:
423 DCHECK_GE(result, 0);
424 result = DoReadBody();
425 break;
426 case STATE_READ_BODY_COMPLETE:
427 result = DoReadBodyComplete(result);
428 break;
429 default:
430 NOTREACHED();
431 }
432 } while (result != ERR_IO_PENDING &&
433 (io_state_ != STATE_DONE && io_state_ != STATE_NONE));
434
435 return result;
436 }
437
DoSendHeaders()438 int HttpStreamParser::DoSendHeaders() {
439 int bytes_remaining = request_headers_->BytesRemaining();
440 DCHECK_GT(bytes_remaining, 0);
441
442 // Record our best estimate of the 'request time' as the time when we send
443 // out the first bytes of the request headers.
444 if (bytes_remaining == request_headers_->size())
445 response_->request_time = base::Time::Now();
446
447 io_state_ = STATE_SEND_HEADERS_COMPLETE;
448 return stream_socket_->Write(
449 request_headers_.get(), bytes_remaining, io_callback_,
450 NetworkTrafficAnnotationTag(traffic_annotation_));
451 }
452
DoSendHeadersComplete(int result)453 int HttpStreamParser::DoSendHeadersComplete(int result) {
454 if (result < 0) {
455 // In the unlikely case that the headers and body were merged, all the
456 // the headers were sent, but not all of the body way, and |result| is
457 // an error that this should try reading after, stash the error for now and
458 // act like the request was successfully sent.
459 io_state_ = STATE_SEND_REQUEST_COMPLETE;
460 if (request_headers_->BytesConsumed() >= request_headers_length_ &&
461 ShouldTryReadingOnUploadError(result)) {
462 upload_error_ = result;
463 return OK;
464 }
465 return result;
466 }
467
468 sent_bytes_ += result;
469 request_headers_->DidConsume(result);
470 if (request_headers_->BytesRemaining() > 0) {
471 io_state_ = STATE_SEND_HEADERS;
472 return OK;
473 }
474
475 if (upload_data_stream_ &&
476 (upload_data_stream_->is_chunked() ||
477 // !IsEOF() indicates that the body wasn't merged.
478 (upload_data_stream_->size() > 0 && !upload_data_stream_->IsEOF()))) {
479 NetLogSendRequestBody(net_log_, upload_data_stream_->size(),
480 upload_data_stream_->is_chunked(),
481 false /* not merged */);
482 io_state_ = STATE_SEND_BODY;
483 return OK;
484 }
485
486 // Finished sending the request.
487 io_state_ = STATE_SEND_REQUEST_COMPLETE;
488 return OK;
489 }
490
DoSendBody()491 int HttpStreamParser::DoSendBody() {
492 if (request_body_send_buf_->BytesRemaining() > 0) {
493 io_state_ = STATE_SEND_BODY_COMPLETE;
494 return stream_socket_->Write(
495 request_body_send_buf_.get(), request_body_send_buf_->BytesRemaining(),
496 io_callback_, NetworkTrafficAnnotationTag(traffic_annotation_));
497 }
498
499 if (upload_data_stream_->is_chunked() && sent_last_chunk_) {
500 // Finished sending the request.
501 io_state_ = STATE_SEND_REQUEST_COMPLETE;
502 return OK;
503 }
504
505 request_body_read_buf_->Clear();
506 io_state_ = STATE_SEND_REQUEST_READ_BODY_COMPLETE;
507 return upload_data_stream_->Read(
508 request_body_read_buf_.get(), request_body_read_buf_->capacity(),
509 base::BindOnce(&HttpStreamParser::OnIOComplete,
510 weak_ptr_factory_.GetWeakPtr()));
511 }
512
DoSendBodyComplete(int result)513 int HttpStreamParser::DoSendBodyComplete(int result) {
514 if (result < 0) {
515 // If |result| is an error that this should try reading after, stash the
516 // error for now and act like the request was successfully sent.
517 io_state_ = STATE_SEND_REQUEST_COMPLETE;
518 if (ShouldTryReadingOnUploadError(result)) {
519 upload_error_ = result;
520 return OK;
521 }
522 return result;
523 }
524
525 sent_bytes_ += result;
526 request_body_send_buf_->DidConsume(result);
527
528 io_state_ = STATE_SEND_BODY;
529 return OK;
530 }
531
DoSendRequestReadBodyComplete(int result)532 int HttpStreamParser::DoSendRequestReadBodyComplete(int result) {
533 // |result| is the result of read from the request body from the last call to
534 // DoSendBody().
535 if (result < 0) {
536 io_state_ = STATE_SEND_REQUEST_COMPLETE;
537 return result;
538 }
539
540 // Chunked data needs to be encoded.
541 if (upload_data_stream_->is_chunked()) {
542 if (result == 0) { // Reached the end.
543 DCHECK(upload_data_stream_->IsEOF());
544 sent_last_chunk_ = true;
545 }
546 // Encode the buffer as 1 chunk.
547 const std::string_view payload(request_body_read_buf_->data(), result);
548 request_body_send_buf_->Clear();
549 result = EncodeChunk(payload, request_body_send_buf_->span());
550 }
551
552 if (result == 0) { // Reached the end.
553 // Reaching EOF means we can finish sending request body unless the data is
554 // chunked. (i.e. No need to send the terminal chunk.)
555 DCHECK(upload_data_stream_->IsEOF());
556 DCHECK(!upload_data_stream_->is_chunked());
557 // Finished sending the request.
558 io_state_ = STATE_SEND_REQUEST_COMPLETE;
559 } else if (result > 0) {
560 request_body_send_buf_->DidAppend(result);
561 result = 0;
562 io_state_ = STATE_SEND_BODY;
563 }
564 return result;
565 }
566
DoSendRequestComplete(int result)567 int HttpStreamParser::DoSendRequestComplete(int result) {
568 DCHECK_NE(result, ERR_IO_PENDING);
569 request_headers_ = nullptr;
570 upload_data_stream_ = nullptr;
571 request_body_send_buf_ = nullptr;
572 request_body_read_buf_ = nullptr;
573
574 return result;
575 }
576
DoReadHeaders()577 int HttpStreamParser::DoReadHeaders() {
578 io_state_ = STATE_READ_HEADERS_COMPLETE;
579
580 // Grow the read buffer if necessary.
581 if (read_buf_->RemainingCapacity() == 0)
582 read_buf_->SetCapacity(read_buf_->capacity() + kHeaderBufInitialSize);
583
584 // http://crbug.com/16371: We're seeing |user_buf_->data()| return NULL.
585 // See if the user is passing in an IOBuffer with a NULL |data_|.
586 CHECK(read_buf_->data());
587
588 return stream_socket_->Read(read_buf_.get(), read_buf_->RemainingCapacity(),
589 io_callback_);
590 }
591
DoReadHeadersComplete(int result)592 int HttpStreamParser::DoReadHeadersComplete(int result) {
593 // DoReadHeadersComplete is called with the result of Socket::Read, which is a
594 // (byte_count | error), and returns (error | OK).
595
596 result = HandleReadHeaderResult(result);
597
598 // If still reading the headers, just return the result.
599 if (io_state_ == STATE_READ_HEADERS) {
600 return result;
601 }
602
603 // If the result is ERR_IO_PENDING, |io_state_| should be STATE_READ_HEADERS.
604 DCHECK_NE(ERR_IO_PENDING, result);
605
606 // TODO(mmenke): The code below is ugly and hacky. A much better and more
607 // flexible long term solution would be to separate out the read and write
608 // loops, though this would involve significant changes, both here and
609 // elsewhere (WebSockets, for instance).
610
611 // If there was an error uploading the request body, may need to adjust the
612 // result.
613 if (upload_error_ != OK) {
614 // On errors, use the original error received when sending the request.
615 // The main cases where these are different is when there's a header-related
616 // error code, or when there's an ERR_CONNECTION_CLOSED, which can result in
617 // special handling of partial responses and HTTP/0.9 responses.
618 if (result < 0) {
619 // Nothing else to do. In the HTTP/0.9 or only partial headers received
620 // cases, can normally go to other states after an error reading headers.
621 io_state_ = STATE_DONE;
622 // Don't let caller see the headers.
623 response_->headers = nullptr;
624 result = upload_error_;
625 } else {
626 // Skip over 1xx responses as usual, and allow 4xx/5xx error responses to
627 // override the error received while uploading the body. For other status
628 // codes, return the original error received when trying to upload the
629 // request body, to make sure the consumer has some indication there was
630 // an error.
631 int response_code_class = response_->headers->response_code() / 100;
632 if (response_code_class != 1 && response_code_class != 4 &&
633 response_code_class != 5) {
634 // Nothing else to do.
635 io_state_ = STATE_DONE;
636 // Don't let caller see the headers.
637 response_->headers = nullptr;
638 result = upload_error_;
639 }
640 }
641 }
642
643 // If there will be no more header reads, clear the request and response
644 // pointers, as they're no longer needed, and in some cases the body may
645 // be read after the parent class destroyed the underlying objects (See
646 // HttpResponseBodyDrainer).
647 //
648 // This is the last header read if HttpStreamParser is done, no response
649 // headers were received, or if the response code is not in the 1xx range.
650 if (io_state_ == STATE_DONE || !response_->headers ||
651 response_->headers->response_code() / 100 != 1) {
652 response_ = nullptr;
653 }
654
655 return result;
656 }
657
DoReadBody()658 int HttpStreamParser::DoReadBody() {
659 io_state_ = STATE_READ_BODY_COMPLETE;
660
661 // Added to investigate crbug.com/499663.
662 CHECK(user_read_buf_.get());
663
664 // There may be additional data after the end of the body waiting in
665 // the socket, but in order to find out, we need to read as much as possible.
666 // If there is additional data, discard it and close the connection later.
667 uint64_t remaining_read_len = user_read_buf_len_;
668 uint64_t remaining_body = 0;
669 if (truncate_to_content_length_enabled_ && !chunked_decoder_.get() &&
670 response_body_length_ >= 0) {
671 remaining_body = base::checked_cast<uint64_t>(response_body_length_ -
672 response_body_read_);
673 remaining_read_len = std::min(remaining_read_len, remaining_body);
674 }
675
676 // There may be some data left over from reading the response headers.
677 if (read_buf_->offset()) {
678 const auto read_offset_s = base::checked_cast<size_t>(read_buf_->offset());
679 CHECK_GE(read_offset_s, read_buf_unused_offset_);
680 const size_t available = read_offset_s - read_buf_unused_offset_;
681 if (available) {
682 const auto bytes_from_buffer = static_cast<size_t>(
683 std::min(uint64_t{available}, remaining_read_len));
684 user_read_buf_->span().copy_prefix_from(read_buf_->everything().subspan(
685 read_buf_unused_offset_, bytes_from_buffer));
686 read_buf_unused_offset_ += bytes_from_buffer;
687 // Clear out the remaining data if we've reached the end of the body.
688 if (truncate_to_content_length_enabled_ &&
689 (remaining_body == bytes_from_buffer) &&
690 (available > bytes_from_buffer)) {
691 read_buf_->SetCapacity(0);
692 read_buf_unused_offset_ = 0;
693 discarded_extra_data_ = true;
694 } else if (bytes_from_buffer == available) {
695 read_buf_->SetCapacity(0);
696 read_buf_unused_offset_ = 0;
697 }
698 return bytes_from_buffer;
699 }
700 read_buf_->SetCapacity(0);
701 read_buf_unused_offset_ = 0;
702 }
703
704 // Check to see if we're done reading.
705 if (IsResponseBodyComplete())
706 return 0;
707
708 // DoReadBodyComplete will truncate the amount read if necessary whether the
709 // read completes synchronously or asynchronously.
710 DCHECK_EQ(0, read_buf_->offset());
711 return stream_socket_->Read(user_read_buf_.get(),
712 base::checked_cast<int>(user_read_buf_len_),
713 io_callback_);
714 }
715
DoReadBodyComplete(int result)716 int HttpStreamParser::DoReadBodyComplete(int result) {
717 // Check to see if we've read too much and need to discard data before we
718 // increment received_bytes_ and response_body_read_ or otherwise start
719 // processing the data.
720 if (truncate_to_content_length_enabled_ && !chunked_decoder_.get() &&
721 response_body_length_ >= 0) {
722 // Calculate how much we should have been allowed to read to not go beyond
723 // the Content-Length.
724 const auto remaining_body = base::checked_cast<uint64_t>(
725 response_body_length_ - response_body_read_);
726 uint64_t remaining_read_len =
727 std::min(uint64_t{user_read_buf_len_}, remaining_body);
728 if (result > 0 && static_cast<uint64_t>(result) > remaining_read_len) {
729 // Truncate to only what is in the body.
730 result = base::checked_cast<int>(remaining_read_len);
731 discarded_extra_data_ = true;
732 }
733 }
734
735 // When the connection is closed, there are numerous ways to interpret it.
736 //
737 // - If a Content-Length header is present and the body contains exactly that
738 // number of bytes at connection close, the response is successful.
739 //
740 // - If a Content-Length header is present and the body contains fewer bytes
741 // than promised by the header at connection close, it may indicate that
742 // the connection was closed prematurely, or it may indicate that the
743 // server sent an invalid Content-Length header. Unfortunately, the invalid
744 // Content-Length header case does occur in practice and other browsers are
745 // tolerant of it. We choose to treat it as an error for now, but the
746 // download system treats it as a non-error, and URLRequestHttpJob also
747 // treats it as OK if the Content-Length is the post-decoded body content
748 // length.
749 //
750 // - If chunked encoding is used and the terminating chunk has been processed
751 // when the connection is closed, the response is successful.
752 //
753 // - If chunked encoding is used and the terminating chunk has not been
754 // processed when the connection is closed, it may indicate that the
755 // connection was closed prematurely or it may indicate that the server
756 // sent an invalid chunked encoding. We choose to treat it as
757 // an invalid chunked encoding.
758 //
759 // - If a Content-Length is not present and chunked encoding is not used,
760 // connection close is the only way to signal that the response is
761 // complete. Unfortunately, this also means that there is no way to detect
762 // early close of a connection. No error is returned.
763 if (result == 0 && !IsResponseBodyComplete() && CanFindEndOfResponse()) {
764 if (chunked_decoder_.get())
765 result = ERR_INCOMPLETE_CHUNKED_ENCODING;
766 else
767 result = ERR_CONTENT_LENGTH_MISMATCH;
768 }
769
770 if (result > 0)
771 received_bytes_ += result;
772
773 // Filter incoming data if appropriate. FilterBuf may return an error.
774 if (result > 0 && chunked_decoder_.get()) {
775 result = chunked_decoder_->FilterBuf(
776 user_read_buf_->span().first(static_cast<size_t>(result)));
777 if (result == 0 && !chunked_decoder_->reached_eof()) {
778 // Don't signal completion of the Read call yet or else it'll look like
779 // we received end-of-file. Wait for more data.
780 io_state_ = STATE_READ_BODY;
781 return OK;
782 }
783 }
784
785 if (result > 0)
786 response_body_read_ += result;
787
788 if (result <= 0 || IsResponseBodyComplete()) {
789 io_state_ = STATE_DONE;
790
791 // Save the overflow data, which can be in two places. There may be
792 // some left over in |user_read_buf_|, plus there may be more
793 // in |read_buf_|. But the part left over in |user_read_buf_| must have
794 // come from the |read_buf_|, so there's room to put it back at the
795 // start first.
796 const auto read_offset_s = base::checked_cast<size_t>(read_buf_->offset());
797 CHECK_GE(read_offset_s, read_buf_unused_offset_);
798 const size_t additional_save_amount =
799 read_offset_s - read_buf_unused_offset_;
800 int save_amount = 0;
801 if (chunked_decoder_.get()) {
802 save_amount = chunked_decoder_->bytes_after_eof();
803 } else if (response_body_length_ >= 0) {
804 int64_t extra_data_read = response_body_read_ - response_body_length_;
805 if (extra_data_read > 0) {
806 save_amount = static_cast<int>(extra_data_read);
807 if (result > 0)
808 result -= save_amount;
809 }
810 }
811
812 const auto new_capacity =
813 base::checked_cast<int>(save_amount + additional_save_amount);
814 CHECK_LE(new_capacity, kMaxBufSize);
815 if (read_buf_->capacity() < new_capacity) {
816 read_buf_->SetCapacity(new_capacity);
817 }
818
819 if (save_amount) {
820 received_bytes_ -= save_amount;
821 read_buf_->everything().copy_prefix_from(user_read_buf_->span().subspan(
822 base::checked_cast<size_t>(result),
823 base::checked_cast<size_t>(save_amount)));
824 }
825 read_buf_->set_offset(save_amount);
826 if (additional_save_amount) {
827 read_buf_->span().copy_prefix_from(read_buf_->everything().subspan(
828 read_buf_unused_offset_, additional_save_amount));
829 read_buf_->set_offset(new_capacity);
830 }
831 read_buf_unused_offset_ = 0;
832 } else {
833 // Now waiting for more of the body to be read.
834 user_read_buf_ = nullptr;
835 user_read_buf_len_ = 0;
836 }
837
838 return result;
839 }
840
HandleReadHeaderResult(int result)841 int HttpStreamParser::HandleReadHeaderResult(int result) {
842 DCHECK_EQ(0u, read_buf_unused_offset_);
843
844 if (result == 0)
845 result = ERR_CONNECTION_CLOSED;
846
847 if (result == ERR_CONNECTION_CLOSED) {
848 // The connection closed without getting any more data.
849 if (read_buf_->offset() == 0) {
850 io_state_ = STATE_DONE;
851 // If the connection has not been reused, it may have been a 0-length
852 // HTTP/0.9 responses, but it was most likely an error, so just return
853 // ERR_EMPTY_RESPONSE instead. If the connection was reused, just pass
854 // on the original connection close error, as rather than being an
855 // empty HTTP/0.9 response it's much more likely the server closed the
856 // socket before it received the request.
857 if (!connection_is_reused_)
858 return ERR_EMPTY_RESPONSE;
859 return result;
860 }
861
862 // Accepting truncated headers over HTTPS is a potential security
863 // vulnerability, so just return an error in that case.
864 //
865 // If response_header_start_offset_ is std::string::npos, this may be a < 8
866 // byte HTTP/0.9 response. However, accepting such a response over HTTPS
867 // would allow a MITM to truncate an HTTP/1.x status line to look like a
868 // short HTTP/0.9 response if the peer put a record boundary at the first 8
869 // bytes. To ensure that all response headers received over HTTPS are
870 // pristine, treat such responses as errors.
871 //
872 // TODO(mmenke): Returning ERR_RESPONSE_HEADERS_TRUNCATED when a response
873 // looks like an HTTP/0.9 response is weird. Should either come up with
874 // another error code, or, better, disable HTTP/0.9 over HTTPS (and give
875 // that a new error code).
876 if (url_.SchemeIsCryptographic()) {
877 io_state_ = STATE_DONE;
878 return ERR_RESPONSE_HEADERS_TRUNCATED;
879 }
880
881 // Parse things as well as we can and let the caller decide what to do.
882 int end_offset;
883 if (response_header_start_offset_ != std::string::npos) {
884 // The response looks to be a truncated set of HTTP headers.
885 io_state_ = STATE_READ_BODY_COMPLETE;
886 end_offset = read_buf_->offset();
887 } else {
888 // The response is apparently using HTTP/0.9. Treat the entire response
889 // as the body.
890 end_offset = 0;
891 }
892 int rv = ParseResponseHeaders(end_offset);
893 if (rv < 0)
894 return rv;
895 return result;
896 }
897
898 if (result < 0) {
899 if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
900 CHECK(url_.SchemeIsCryptographic());
901 response_->cert_request_info = base::MakeRefCounted<SSLCertRequestInfo>();
902 stream_socket_->GetSSLCertRequestInfo(response_->cert_request_info.get());
903 }
904 io_state_ = STATE_DONE;
905 return result;
906 }
907
908 // Record our best estimate of the 'response time' as the time when we read
909 // the first bytes of the response headers.
910 if (read_buf_->offset() == 0) {
911 response_->response_time = response_->original_response_time =
912 base::Time::Now();
913 // Also keep the time as base::TimeTicks for `first_response_start_time_`
914 // and `non_informational_response_start_time_`.
915 current_response_start_time_ = base::TimeTicks::Now();
916 }
917
918 // For |first_response_start_time_|, use the time that we received the first
919 // byte of *any* response- including 1XX, as per the resource timing spec for
920 // responseStart (see note at
921 // https://www.w3.org/TR/resource-timing-2/#dom-performanceresourcetiming-responsestart).
922 if (first_response_start_time_.is_null())
923 first_response_start_time_ = current_response_start_time_;
924
925 read_buf_->set_offset(read_buf_->offset() + result);
926 DCHECK_LE(read_buf_->offset(), read_buf_->capacity());
927 DCHECK_GT(result, 0);
928
929 int end_of_header_offset = FindAndParseResponseHeaders(result);
930
931 // Note: -1 is special, it indicates we haven't found the end of headers.
932 // Anything less than -1 is a Error, so we bail out.
933 if (end_of_header_offset < -1)
934 return end_of_header_offset;
935
936 if (end_of_header_offset == -1) {
937 io_state_ = STATE_READ_HEADERS;
938 // Prevent growing the headers buffer indefinitely.
939 if (read_buf_->offset() >= kMaxHeaderBufSize) {
940 io_state_ = STATE_DONE;
941 return ERR_RESPONSE_HEADERS_TOO_BIG;
942 }
943 } else {
944 CalculateResponseBodySize();
945
946 // Record the response start time if this response is not informational
947 // (non-1xx).
948 if (response_->headers->response_code() / 100 != 1) {
949 DCHECK(non_informational_response_start_time_.is_null());
950 non_informational_response_start_time_ = current_response_start_time_;
951 }
952
953 // If the body is zero length, the caller may not call ReadResponseBody,
954 // which is where any extra data is copied to read_buf_, so we move the
955 // data here.
956 const auto end_of_header_offset_s =
957 static_cast<size_t>(end_of_header_offset);
958 if (response_body_length_ == 0) {
959 base::span<uint8_t> extra_bytes =
960 read_buf_->span_before_offset().subspan(end_of_header_offset_s);
961 if (!extra_bytes.empty()) {
962 read_buf_->everything().copy_prefix_from(extra_bytes);
963 }
964 read_buf_->SetCapacity(extra_bytes.size());
965 if (response_->headers->response_code() / 100 == 1) {
966 // After processing a 1xx response, the caller will ask for the next
967 // header, so reset state to support that. We don't completely ignore a
968 // 1xx response because it cannot be returned in reply to a CONNECT
969 // request so we return OK here, which lets the caller inspect the
970 // response and reject it in the event that we're setting up a CONNECT
971 // tunnel.
972 response_header_start_offset_ = std::string::npos;
973 response_body_length_ = -1;
974 // Record the timing of the 103 Early Hints response for the experiment
975 // (https://crbug.com/1093693).
976 if (response_->headers->response_code() == HTTP_EARLY_HINTS &&
977 first_early_hints_time_.is_null()) {
978 first_early_hints_time_ = current_response_start_time_;
979 }
980 // Now waiting for the second set of headers to be read.
981 } else {
982 // Only set keep-alive based on final set of headers.
983 response_is_keep_alive_ = response_->headers->IsKeepAlive();
984
985 io_state_ = STATE_DONE;
986 }
987 return OK;
988 }
989
990 // Only set keep-alive based on final set of headers.
991 response_is_keep_alive_ = response_->headers->IsKeepAlive();
992
993 // Note where the headers stop.
994 read_buf_unused_offset_ = end_of_header_offset_s;
995 // Now waiting for the body to be read.
996 }
997 return OK;
998 }
999
RunConfirmHandshakeCallback(int rv)1000 void HttpStreamParser::RunConfirmHandshakeCallback(int rv) {
1001 std::move(confirm_handshake_callback_).Run(rv);
1002 }
1003
FindAndParseResponseHeaders(int new_bytes)1004 int HttpStreamParser::FindAndParseResponseHeaders(int new_bytes) {
1005 DCHECK_GT(new_bytes, 0);
1006 DCHECK_EQ(0u, read_buf_unused_offset_);
1007 size_t end_offset = std::string::npos;
1008
1009 // Look for the start of the status line, if it hasn't been found yet.
1010 if (response_header_start_offset_ == std::string::npos) {
1011 response_header_start_offset_ =
1012 HttpUtil::LocateStartOfStatusLine(read_buf_->span_before_offset());
1013 }
1014
1015 if (response_header_start_offset_ != std::string::npos) {
1016 // LocateEndOfHeaders looks for two line breaks in a row (With or without
1017 // carriage returns). So the end of the headers includes at most the last 3
1018 // bytes of the buffer from the past read. This optimization avoids O(n^2)
1019 // performance in the case each read only returns a couple bytes. It's not
1020 // too important in production, but for fuzzers with memory instrumentation,
1021 // it's needed to avoid timing out.
1022 size_t lower_bound =
1023 (base::ClampedNumeric<size_t>(read_buf_->offset()) - new_bytes - 3)
1024 .RawValue();
1025 size_t search_start = std::max(response_header_start_offset_, lower_bound);
1026 end_offset = HttpUtil::LocateEndOfHeaders(read_buf_->span_before_offset(),
1027 search_start);
1028 } else if (read_buf_->offset() >= 8) {
1029 // Enough data to decide that this is an HTTP/0.9 response.
1030 // 8 bytes = (4 bytes of junk) + "http".length()
1031 end_offset = 0;
1032 }
1033
1034 if (end_offset == std::string::npos)
1035 return -1;
1036
1037 int rv = ParseResponseHeaders(end_offset);
1038 if (rv < 0)
1039 return rv;
1040 return end_offset;
1041 }
1042
ParseResponseHeaders(size_t end_offset)1043 int HttpStreamParser::ParseResponseHeaders(size_t end_offset) {
1044 scoped_refptr<HttpResponseHeaders> headers;
1045 DCHECK_EQ(0u, read_buf_unused_offset_);
1046
1047 if (response_header_start_offset_ != std::string::npos) {
1048 received_bytes_ += end_offset;
1049 headers = HttpResponseHeaders::TryToCreate(
1050 base::as_string_view(read_buf_->everything().first(end_offset)));
1051 if (!headers)
1052 return ERR_INVALID_HTTP_RESPONSE;
1053 has_seen_status_line_ = true;
1054 } else {
1055 // Enough data was read -- there is no status line, so this is HTTP/0.9, or
1056 // the server is broken / doesn't speak HTTP.
1057
1058 if (has_seen_status_line_) {
1059 // If we saw a status line previously, the server can speak HTTP/1.x so it
1060 // is not reasonable to interpret the response as an HTTP/0.9 response.
1061 return ERR_INVALID_HTTP_RESPONSE;
1062 }
1063
1064 std::string_view scheme = url_.scheme_piece();
1065 if (url::DefaultPortForScheme(scheme) != url_.EffectiveIntPort()) {
1066 // If the port is not the default for the scheme, assume it's not a real
1067 // HTTP/0.9 response, and fail the request.
1068
1069 // Allow Shoutcast responses over HTTP, as it's somewhat common and relies
1070 // on HTTP/0.9 on weird ports to work.
1071 // See
1072 // https://groups.google.com/a/chromium.org/forum/#!topic/blink-dev/qS63pYso4P0
1073 if (read_buf_->offset() < 3 || scheme != "http" ||
1074 !base::EqualsCaseInsensitiveASCII(
1075 base::as_string_view(read_buf_->everything().first(3u)), "icy")) {
1076 return ERR_INVALID_HTTP_RESPONSE;
1077 }
1078 }
1079
1080 headers = base::MakeRefCounted<HttpResponseHeaders>(
1081 std::string("HTTP/0.9 200 OK"));
1082 }
1083
1084 // Check for multiple Content-Length headers when the response is not
1085 // chunked-encoded. If they exist, and have distinct values, it's a potential
1086 // response smuggling attack.
1087 if (!headers->IsChunkEncoded()) {
1088 if (HttpUtil::HeadersContainMultipleCopiesOfField(*headers,
1089 "Content-Length"))
1090 return ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_LENGTH;
1091 }
1092
1093 // Check for multiple Content-Disposition or Location headers. If they exist,
1094 // it's also a potential response smuggling attack.
1095 if (HttpUtil::HeadersContainMultipleCopiesOfField(*headers,
1096 "Content-Disposition"))
1097 return ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_DISPOSITION;
1098 if (HttpUtil::HeadersContainMultipleCopiesOfField(*headers, "Location"))
1099 return ERR_RESPONSE_HEADERS_MULTIPLE_LOCATION;
1100
1101 response_->headers = headers;
1102 if (headers->GetHttpVersion() == HttpVersion(0, 9)) {
1103 response_->connection_info = HttpConnectionInfo::kHTTP0_9;
1104 } else if (headers->GetHttpVersion() == HttpVersion(1, 0)) {
1105 response_->connection_info = HttpConnectionInfo::kHTTP1_0;
1106 } else if (headers->GetHttpVersion() == HttpVersion(1, 1)) {
1107 response_->connection_info = HttpConnectionInfo::kHTTP1_1;
1108 }
1109 DVLOG(1) << __func__ << "() content_length = \""
1110 << response_->headers->GetContentLength() << "\n\""
1111 << " headers = \"" << GetResponseHeaderLines(*response_->headers)
1112 << "\"";
1113 return OK;
1114 }
1115
CalculateResponseBodySize()1116 void HttpStreamParser::CalculateResponseBodySize() {
1117 // Figure how to determine EOF:
1118
1119 // For certain responses, we know the content length is always 0. From
1120 // RFC 7230 Section 3.3 Message Body:
1121 //
1122 // The presence of a message body in a response depends on both the
1123 // request method to which it is responding and the response status code
1124 // (Section 3.1.2). Responses to the HEAD request method (Section 4.3.2
1125 // of [RFC7231]) never include a message body because the associated
1126 // response header fields (e.g., Transfer-Encoding, Content-Length,
1127 // etc.), if present, indicate only what their values would have been if
1128 // the request method had been GET (Section 4.3.1 of [RFC7231]). 2xx
1129 // (Successful) responses to a CONNECT request method (Section 4.3.6 of
1130 // [RFC7231]) switch to tunnel mode instead of having a message body.
1131 // All 1xx (Informational), 204 (No Content), and 304 (Not Modified)
1132 // responses do not include a message body. All other responses do
1133 // include a message body, although the body might be of zero length.
1134 //
1135 // From RFC 7231 Section 6.3.6 205 Reset Content:
1136 //
1137 // Since the 205 status code implies that no additional content will be
1138 // provided, a server MUST NOT generate a payload in a 205 response.
1139 if (response_->headers->response_code() / 100 == 1) {
1140 response_body_length_ = 0;
1141 } else {
1142 switch (response_->headers->response_code()) {
1143 case HTTP_NO_CONTENT: // No Content
1144 case HTTP_RESET_CONTENT: // Reset Content
1145 case HTTP_NOT_MODIFIED: // Not Modified
1146 response_body_length_ = 0;
1147 break;
1148 }
1149 }
1150
1151 if (method_ == "HEAD") {
1152 response_body_length_ = 0;
1153 }
1154
1155 if (response_body_length_ == -1) {
1156 // "Transfer-Encoding: chunked" trumps "Content-Length: N"
1157 if (response_->headers->IsChunkEncoded()) {
1158 chunked_decoder_ = std::make_unique<HttpChunkedDecoder>();
1159 } else {
1160 response_body_length_ = response_->headers->GetContentLength();
1161 // If response_body_length_ is still -1, then we have to wait
1162 // for the server to close the connection.
1163 }
1164 }
1165 }
1166
IsResponseBodyComplete() const1167 bool HttpStreamParser::IsResponseBodyComplete() const {
1168 if (chunked_decoder_.get())
1169 return chunked_decoder_->reached_eof();
1170 if (response_body_length_ != -1)
1171 return response_body_read_ >= response_body_length_;
1172
1173 return false; // Must read to EOF.
1174 }
1175
CanFindEndOfResponse() const1176 bool HttpStreamParser::CanFindEndOfResponse() const {
1177 return chunked_decoder_.get() || response_body_length_ >= 0;
1178 }
1179
IsMoreDataBuffered() const1180 bool HttpStreamParser::IsMoreDataBuffered() const {
1181 return read_buf_->offset() > 0 &&
1182 static_cast<size_t>(read_buf_->offset()) > read_buf_unused_offset_;
1183 }
1184
CanReuseConnection() const1185 bool HttpStreamParser::CanReuseConnection() const {
1186 if (!CanFindEndOfResponse())
1187 return false;
1188
1189 if (!response_is_keep_alive_)
1190 return false;
1191
1192 // Check if extra data was received after reading the entire response body. If
1193 // extra data was received, reusing the socket is not a great idea. This does
1194 // have the down side of papering over certain server bugs, but seems to be
1195 // the best option here.
1196 //
1197 // TODO(mmenke): Consider logging this - hard to decipher socket reuse
1198 // behavior makes NetLogs harder to read.
1199 if ((IsResponseBodyComplete() && IsMoreDataBuffered()) ||
1200 discarded_extra_data_) {
1201 return false;
1202 }
1203
1204 return stream_socket_->IsConnected();
1205 }
1206
OnConnectionClose()1207 void HttpStreamParser::OnConnectionClose() {
1208 // This is to ensure `stream_socket_` doesn't get dangling on connection
1209 // close.
1210 stream_socket_ = nullptr;
1211 }
1212
EncodeChunk(std::string_view payload,base::span<uint8_t> output)1213 int HttpStreamParser::EncodeChunk(std::string_view payload,
1214 base::span<uint8_t> output) {
1215 if (output.size() < payload.size() + kChunkHeaderFooterSize) {
1216 return ERR_INVALID_ARGUMENT;
1217 }
1218
1219 auto span_writer = base::SpanWriter(output);
1220 // Add the header.
1221 const std::string header =
1222 base::StringPrintf("%X\r\n", static_cast<int>(payload.size()));
1223 span_writer.Write(base::as_byte_span(header));
1224 // Add the payload if any.
1225 if (payload.size() > 0) {
1226 span_writer.Write(base::as_byte_span(payload));
1227 }
1228 // Add the trailing CRLF.
1229 span_writer.Write(base::byte_span_from_cstring("\r\n"));
1230
1231 return span_writer.num_written();
1232 }
1233
1234 // static
ShouldMergeRequestHeadersAndBody(const std::string & request_headers,const UploadDataStream * request_body)1235 bool HttpStreamParser::ShouldMergeRequestHeadersAndBody(
1236 const std::string& request_headers,
1237 const UploadDataStream* request_body) {
1238 if (request_body != nullptr &&
1239 // IsInMemory() ensures that the request body is not chunked.
1240 request_body->IsInMemory() && request_body->size() > 0) {
1241 uint64_t merged_size = request_headers.size() + request_body->size();
1242 if (merged_size <= kMaxMergedHeaderAndBodySize)
1243 return true;
1244 }
1245 return false;
1246 }
1247
SendRequestBuffersEmpty()1248 bool HttpStreamParser::SendRequestBuffersEmpty() {
1249 return request_headers_ == nullptr && request_body_send_buf_ == nullptr &&
1250 request_body_read_buf_ == nullptr;
1251 }
1252
1253 } // namespace net
1254