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