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 #ifndef NET_HTTP_HTTP_STREAM_PARSER_H_ 6 #define NET_HTTP_HTTP_STREAM_PARSER_H_ 7 8 #include <stddef.h> 9 #include <stdint.h> 10 11 #include <memory> 12 #include <string> 13 #include <string_view> 14 15 #include "base/memory/raw_ptr.h" 16 #include "base/memory/scoped_refptr.h" 17 #include "base/memory/weak_ptr.h" 18 #include "base/time/time.h" 19 #include "crypto/ec_private_key.h" 20 #include "net/base/completion_once_callback.h" 21 #include "net/base/completion_repeating_callback.h" 22 #include "net/base/net_errors.h" 23 #include "net/base/net_export.h" 24 #include "net/log/net_log_with_source.h" 25 #include "net/traffic_annotation/network_traffic_annotation.h" 26 27 namespace net { 28 29 class DrainableIOBuffer; 30 class GrowableIOBuffer; 31 class HttpChunkedDecoder; 32 struct HttpRequestInfo; 33 class HttpRequestHeaders; 34 class HttpResponseInfo; 35 class IOBuffer; 36 class StreamSocket; 37 class UploadDataStream; 38 39 class NET_EXPORT_PRIVATE HttpStreamParser { 40 public: 41 // |connection_is_reused| must be |true| if |stream_socket| has previously 42 // been used successfully for an HTTP/1.x request. 43 // 44 // Any data in |read_buffer| will be used before reading from the socket 45 // and any data left over after parsing the stream will be put into 46 // |read_buffer|. The left over data will start at offset 0 and the 47 // buffer's offset will be set to the first free byte. |read_buffer| may 48 // have its capacity changed. 49 // 50 // It is not safe to call into the HttpStreamParser after destroying the 51 // |stream_socket|. 52 HttpStreamParser(StreamSocket* stream_socket, 53 bool connection_is_reused, 54 const HttpRequestInfo* request, 55 GrowableIOBuffer* read_buffer, 56 const NetLogWithSource& net_log); 57 58 HttpStreamParser(const HttpStreamParser&) = delete; 59 HttpStreamParser& operator=(const HttpStreamParser&) = delete; 60 61 virtual ~HttpStreamParser(); 62 63 // These functions implement the interface described in HttpStream with 64 // some additional functionality 65 int SendRequest(const std::string& request_line, 66 const HttpRequestHeaders& headers, 67 const NetworkTrafficAnnotationTag& traffic_annotation, 68 HttpResponseInfo* response, 69 CompletionOnceCallback callback); 70 71 int ConfirmHandshake(CompletionOnceCallback callback); 72 73 int ReadResponseHeaders(CompletionOnceCallback callback); 74 75 int ReadResponseBody(IOBuffer* buf, 76 int buf_len, 77 CompletionOnceCallback callback); 78 79 bool IsResponseBodyComplete() const; 80 81 bool CanFindEndOfResponse() const; 82 83 bool IsMoreDataBuffered() const; 84 85 // Returns true if the underlying connection can be reused. 86 // The connection can be reused if: 87 // * It's still connected. 88 // * The response headers indicate the connection can be kept alive. 89 // * The end of the response can be found, though it may not have yet been 90 // received. 91 // 92 // Note that if response headers have yet to be received, this will return 93 // false. 94 bool CanReuseConnection() const; 95 96 // Called when stream is closed. 97 void OnConnectionClose(); 98 received_bytes()99 int64_t received_bytes() const { return received_bytes_; } 100 sent_bytes()101 int64_t sent_bytes() const { return sent_bytes_; } 102 first_response_start_time()103 base::TimeTicks first_response_start_time() const { 104 return first_response_start_time_; 105 } non_informational_response_start_time()106 base::TimeTicks non_informational_response_start_time() const { 107 return non_informational_response_start_time_; 108 } first_early_hints_time()109 base::TimeTicks first_early_hints_time() { return first_early_hints_time_; } 110 111 // Encodes the given |payload| in the chunked format to |output|. 112 // Returns the number of bytes written to |output|. |output_size| should 113 // be large enough to store the encoded chunk, which is payload.size() + 114 // kChunkHeaderFooterSize. Returns ERR_INVALID_ARGUMENT if |output_size| 115 // is not large enough. 116 // 117 // The output will look like: "HEX\r\n[payload]\r\n" 118 // where HEX is a length in hexdecimal (without the "0x" prefix). 119 static int EncodeChunk(std::string_view payload, 120 char* output, 121 size_t output_size); 122 123 // Returns true if request headers and body should be merged (i.e. the 124 // sum is small enough and the body is in memory, and not chunked). 125 static bool ShouldMergeRequestHeadersAndBody( 126 const std::string& request_headers, 127 const UploadDataStream* request_body); 128 129 // The number of extra bytes required to encode a chunk. 130 static const size_t kChunkHeaderFooterSize; 131 132 private: 133 class SeekableIOBuffer; 134 135 // FOO_COMPLETE states implement the second half of potentially asynchronous 136 // operations and don't necessarily mean that FOO is complete. 137 enum State { 138 // STATE_NONE indicates that this is waiting on an external call before 139 // continuing. 140 STATE_NONE, 141 STATE_SEND_HEADERS, 142 STATE_SEND_HEADERS_COMPLETE, 143 STATE_SEND_BODY, 144 STATE_SEND_BODY_COMPLETE, 145 STATE_SEND_REQUEST_READ_BODY_COMPLETE, 146 STATE_SEND_REQUEST_COMPLETE, 147 STATE_READ_HEADERS, 148 STATE_READ_HEADERS_COMPLETE, 149 STATE_READ_BODY, 150 STATE_READ_BODY_COMPLETE, 151 STATE_DONE 152 }; 153 154 // The number of bytes by which the header buffer is grown when it reaches 155 // capacity. 156 static const int kHeaderBufInitialSize = 4 * 1024; // 4K 157 158 // |kMaxHeaderBufSize| is the number of bytes that the response headers can 159 // grow to. If the body start is not found within this range of the 160 // response, the transaction will fail with ERR_RESPONSE_HEADERS_TOO_BIG. 161 // Note: |kMaxHeaderBufSize| should be a multiple of |kHeaderBufInitialSize|. 162 static const int kMaxHeaderBufSize = kHeaderBufInitialSize * 64; // 256K 163 164 // The maximum sane buffer size. 165 static const int kMaxBufSize = 2 * 1024 * 1024; // 2M 166 167 // Handle callbacks. 168 void OnIOComplete(int result); 169 170 // Try to make progress sending/receiving the request/response. 171 int DoLoop(int result); 172 173 // The implementations of each state of the state machine. 174 int DoSendHeaders(); 175 int DoSendHeadersComplete(int result); 176 int DoSendBody(); 177 int DoSendBodyComplete(int result); 178 int DoSendRequestReadBodyComplete(int result); 179 int DoSendRequestComplete(int result); 180 int DoReadHeaders(); 181 int DoReadHeadersComplete(int result); 182 int DoReadBody(); 183 int DoReadBodyComplete(int result); 184 185 // This handles most of the logic for DoReadHeadersComplete. 186 int HandleReadHeaderResult(int result); 187 188 void RunConfirmHandshakeCallback(int rv); 189 190 // Examines |read_buf_| to find the start and end of the headers. If they are 191 // found, parse them with DoParseResponseHeaders(). Return the offset for 192 // the end of the headers, or -1 if the complete headers were not found, or 193 // with a net::Error if we encountered an error during parsing. 194 // 195 // |new_bytes| is the number of new bytes that have been appended to the end 196 // of |read_buf_| since the last call to this method (which must have returned 197 // -1). 198 int FindAndParseResponseHeaders(int new_bytes); 199 200 // Parse the headers into response_. Returns OK on success or a net::Error on 201 // failure. 202 int ParseResponseHeaders(int end_of_header_offset); 203 204 // Examine the parsed headers to try to determine the response body size. 205 void CalculateResponseBodySize(); 206 207 // Check if buffers used to send the request are empty. 208 bool SendRequestBuffersEmpty(); 209 210 // Next state of the request, when the current one completes. 211 State io_state_ = STATE_NONE; 212 213 // Null when read state machine is invoked. 214 raw_ptr<const HttpRequestInfo, AcrossTasksDanglingUntriaged> request_; 215 216 // The request header data. May include a merged request body. 217 scoped_refptr<DrainableIOBuffer> request_headers_; 218 219 // Size of just the request headers. May be less than the length of 220 // |request_headers_| if the body was merged with the headers. 221 int request_headers_length_ = 0; 222 223 // Temporary buffer for reading. 224 scoped_refptr<GrowableIOBuffer> read_buf_; 225 226 // Offset of the first unused byte in |read_buf_|. May be nonzero due to 227 // body data in the same packet as header data but is zero when reading 228 // headers. 229 int read_buf_unused_offset_ = 0; 230 231 // The amount beyond |read_buf_unused_offset_| where the status line starts; 232 // std::string::npos if not found yet. 233 size_t response_header_start_offset_; 234 235 // The amount of received data. If connection is reused then intermediate 236 // value may be bigger than final. 237 int64_t received_bytes_ = 0; 238 239 // The amount of sent data. 240 int64_t sent_bytes_ = 0; 241 242 // The parsed response headers. Owned by the caller of SendRequest. This 243 // cannot be safely accessed after reading the final set of headers, as the 244 // caller of SendRequest may have been destroyed - this happens in the case an 245 // HttpResponseBodyDrainer is used. 246 raw_ptr<HttpResponseInfo, AcrossTasksDanglingUntriaged> response_ = nullptr; 247 248 // Time at which the first bytes of the first header response including 249 // informational responses (1xx) are about to be parsed. This corresponds to 250 // |LoadTimingInfo::receive_headers_start|. See also comments there. 251 base::TimeTicks first_response_start_time_; 252 253 // Time at which the first bytes of the current header response are about to 254 // be parsed. This is reset every time new response headers including 255 // non-informational responses (1xx) are parsed. 256 base::TimeTicks current_response_start_time_; 257 258 // Time at which the first byte of the non-informational header response 259 // (non-1xx) are about to be parsed. This corresponds to 260 // |LoadTimingInfo::receive_non_informational_headers_start|. See also 261 // comments there. 262 base::TimeTicks non_informational_response_start_time_; 263 264 // Time at which the first 103 Early Hints response is received. This 265 // corresponds to |LoadTimingInfo::first_early_hints_time|. 266 base::TimeTicks first_early_hints_time_; 267 268 // Indicates the content length. If this value is less than zero 269 // (and chunked_decoder_ is null), then we must read until the server 270 // closes the connection. 271 int64_t response_body_length_ = -1; 272 273 // True if reading a keep-alive response. False if not, or if don't yet know. 274 bool response_is_keep_alive_ = false; 275 276 // True if we've seen a response that has an HTTP status line. This is 277 // persistent across multiple response parsing. If we see a status line 278 // for a response, this will remain true forever. 279 bool has_seen_status_line_ = false; 280 281 // Keep track of the number of response body bytes read so far. 282 int64_t response_body_read_ = 0; 283 284 // Helper if the data is chunked. 285 std::unique_ptr<HttpChunkedDecoder> chunked_decoder_; 286 287 // Where the caller wants the body data. 288 scoped_refptr<IOBuffer> user_read_buf_; 289 int user_read_buf_len_ = 0; 290 291 // The callback to notify a user that the handshake has been confirmed. 292 CompletionOnceCallback confirm_handshake_callback_; 293 294 // The callback to notify a user that their request or response is 295 // complete or there was an error 296 CompletionOnceCallback callback_; 297 298 // The underlying socket, owned by the caller. The HttpStreamParser must be 299 // destroyed before the caller destroys the socket, or relinquishes ownership 300 // of it. 301 raw_ptr<StreamSocket> stream_socket_; 302 303 // Whether the socket has already been used. Only used in HTTP/0.9 detection 304 // logic. 305 const bool connection_is_reused_; 306 307 NetLogWithSource net_log_; 308 309 // Callback to be used when doing IO. 310 CompletionRepeatingCallback io_callback_; 311 312 // Buffer used to read the request body from UploadDataStream. 313 scoped_refptr<SeekableIOBuffer> request_body_read_buf_; 314 // Buffer used to send the request body. This points the same buffer as 315 // |request_body_read_buf_| unless the data is chunked. 316 scoped_refptr<SeekableIOBuffer> request_body_send_buf_; 317 bool sent_last_chunk_ = false; 318 319 // Whether the Content-Length was known and extra data was discarded. 320 bool discarded_extra_data_ = false; 321 322 // Whether the response body should be truncated to the Content-Length. 323 const bool truncate_to_content_length_enabled_; 324 325 // Error received when uploading the body, if any. 326 int upload_error_ = OK; 327 328 MutableNetworkTrafficAnnotationTag traffic_annotation_; 329 330 base::WeakPtrFactory<HttpStreamParser> weak_ptr_factory_{this}; 331 }; 332 333 } // namespace net 334 335 #endif // NET_HTTP_HTTP_STREAM_PARSER_H_ 336