| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "net/http/http_stream_parser.h" | |
| 6 | |
| 7 #include "base/bind.h" | |
| 8 #include "base/compiler_specific.h" | |
| 9 #include "base/logging.h" | |
| 10 #include "base/profiler/scoped_tracker.h" | |
| 11 #include "base/strings/string_util.h" | |
| 12 #include "base/values.h" | |
| 13 #include "net/base/io_buffer.h" | |
| 14 #include "net/base/ip_endpoint.h" | |
| 15 #include "net/base/upload_data_stream.h" | |
| 16 #include "net/http/http_chunked_decoder.h" | |
| 17 #include "net/http/http_request_headers.h" | |
| 18 #include "net/http/http_request_info.h" | |
| 19 #include "net/http/http_response_headers.h" | |
| 20 #include "net/http/http_util.h" | |
| 21 #include "net/socket/client_socket_handle.h" | |
| 22 #include "net/socket/ssl_client_socket.h" | |
| 23 | |
| 24 namespace net { | |
| 25 | |
| 26 namespace { | |
| 27 | |
| 28 const uint64 kMaxMergedHeaderAndBodySize = 1400; | |
| 29 const size_t kRequestBodyBufferSize = 1 << 14; // 16KB | |
| 30 | |
| 31 std::string GetResponseHeaderLines(const HttpResponseHeaders& headers) { | |
| 32 std::string raw_headers = headers.raw_headers(); | |
| 33 const char* null_separated_headers = raw_headers.c_str(); | |
| 34 const char* header_line = null_separated_headers; | |
| 35 std::string cr_separated_headers; | |
| 36 while (header_line[0] != 0) { | |
| 37 cr_separated_headers += header_line; | |
| 38 cr_separated_headers += "\n"; | |
| 39 header_line += strlen(header_line) + 1; | |
| 40 } | |
| 41 return cr_separated_headers; | |
| 42 } | |
| 43 | |
| 44 // Return true if |headers| contain multiple |field_name| fields with different | |
| 45 // values. | |
| 46 bool HeadersContainMultipleCopiesOfField(const HttpResponseHeaders& headers, | |
| 47 const std::string& field_name) { | |
| 48 void* it = NULL; | |
| 49 std::string field_value; | |
| 50 if (!headers.EnumerateHeader(&it, field_name, &field_value)) | |
| 51 return false; | |
| 52 // There's at least one |field_name| header. Check if there are any more | |
| 53 // such headers, and if so, return true if they have different values. | |
| 54 std::string field_value2; | |
| 55 while (headers.EnumerateHeader(&it, field_name, &field_value2)) { | |
| 56 if (field_value != field_value2) | |
| 57 return true; | |
| 58 } | |
| 59 return false; | |
| 60 } | |
| 61 | |
| 62 base::Value* NetLogSendRequestBodyCallback(uint64 length, | |
| 63 bool is_chunked, | |
| 64 bool did_merge, | |
| 65 NetLog::LogLevel /* log_level */) { | |
| 66 base::DictionaryValue* dict = new base::DictionaryValue(); | |
| 67 dict->SetInteger("length", static_cast<int>(length)); | |
| 68 dict->SetBoolean("is_chunked", is_chunked); | |
| 69 dict->SetBoolean("did_merge", did_merge); | |
| 70 return dict; | |
| 71 } | |
| 72 | |
| 73 // Returns true if |error_code| is an error for which we give the server a | |
| 74 // chance to send a body containing error information, if the error was received | |
| 75 // while trying to upload a request body. | |
| 76 bool ShouldTryReadingOnUploadError(int error_code) { | |
| 77 return (error_code == ERR_CONNECTION_RESET); | |
| 78 } | |
| 79 | |
| 80 } // namespace | |
| 81 | |
| 82 // Similar to DrainableIOBuffer(), but this version comes with its own | |
| 83 // storage. The motivation is to avoid repeated allocations of | |
| 84 // DrainableIOBuffer. | |
| 85 // | |
| 86 // Example: | |
| 87 // | |
| 88 // scoped_refptr<SeekableIOBuffer> buf = new SeekableIOBuffer(1024); | |
| 89 // // capacity() == 1024. size() == BytesRemaining() == BytesConsumed() == 0. | |
| 90 // // data() points to the beginning of the buffer. | |
| 91 // | |
| 92 // // Read() takes an IOBuffer. | |
| 93 // int bytes_read = some_reader->Read(buf, buf->capacity()); | |
| 94 // buf->DidAppend(bytes_read); | |
| 95 // // size() == BytesRemaining() == bytes_read. data() is unaffected. | |
| 96 // | |
| 97 // while (buf->BytesRemaining() > 0) { | |
| 98 // // Write() takes an IOBuffer. If it takes const char*, we could | |
| 99 /// // simply use the regular IOBuffer like buf->data() + offset. | |
| 100 // int bytes_written = Write(buf, buf->BytesRemaining()); | |
| 101 // buf->DidConsume(bytes_written); | |
| 102 // } | |
| 103 // // BytesRemaining() == 0. BytesConsumed() == size(). | |
| 104 // // data() points to the end of the consumed bytes (exclusive). | |
| 105 // | |
| 106 // // If you want to reuse the buffer, be sure to clear the buffer. | |
| 107 // buf->Clear(); | |
| 108 // // size() == BytesRemaining() == BytesConsumed() == 0. | |
| 109 // // data() points to the beginning of the buffer. | |
| 110 // | |
| 111 class HttpStreamParser::SeekableIOBuffer : public IOBuffer { | |
| 112 public: | |
| 113 explicit SeekableIOBuffer(int capacity) | |
| 114 : IOBuffer(capacity), | |
| 115 real_data_(data_), | |
| 116 capacity_(capacity), | |
| 117 size_(0), | |
| 118 used_(0) { | |
| 119 } | |
| 120 | |
| 121 // DidConsume() changes the |data_| pointer so that |data_| always points | |
| 122 // to the first unconsumed byte. | |
| 123 void DidConsume(int bytes) { | |
| 124 SetOffset(used_ + bytes); | |
| 125 } | |
| 126 | |
| 127 // Returns the number of unconsumed bytes. | |
| 128 int BytesRemaining() const { | |
| 129 return size_ - used_; | |
| 130 } | |
| 131 | |
| 132 // Seeks to an arbitrary point in the buffer. The notion of bytes consumed | |
| 133 // and remaining are updated appropriately. | |
| 134 void SetOffset(int bytes) { | |
| 135 DCHECK_GE(bytes, 0); | |
| 136 DCHECK_LE(bytes, size_); | |
| 137 used_ = bytes; | |
| 138 data_ = real_data_ + used_; | |
| 139 } | |
| 140 | |
| 141 // Called after data is added to the buffer. Adds |bytes| added to | |
| 142 // |size_|. data() is unaffected. | |
| 143 void DidAppend(int bytes) { | |
| 144 DCHECK_GE(bytes, 0); | |
| 145 DCHECK_GE(size_ + bytes, 0); | |
| 146 DCHECK_LE(size_ + bytes, capacity_); | |
| 147 size_ += bytes; | |
| 148 } | |
| 149 | |
| 150 // Changes the logical size to 0, and the offset to 0. | |
| 151 void Clear() { | |
| 152 size_ = 0; | |
| 153 SetOffset(0); | |
| 154 } | |
| 155 | |
| 156 // Returns the logical size of the buffer (i.e the number of bytes of data | |
| 157 // in the buffer). | |
| 158 int size() const { return size_; } | |
| 159 | |
| 160 // Returns the capacity of the buffer. The capacity is the size used when | |
| 161 // the object is created. | |
| 162 int capacity() const { return capacity_; }; | |
| 163 | |
| 164 private: | |
| 165 ~SeekableIOBuffer() override { | |
| 166 // data_ will be deleted in IOBuffer::~IOBuffer(). | |
| 167 data_ = real_data_; | |
| 168 } | |
| 169 | |
| 170 char* real_data_; | |
| 171 const int capacity_; | |
| 172 int size_; | |
| 173 int used_; | |
| 174 }; | |
| 175 | |
| 176 // 2 CRLFs + max of 8 hex chars. | |
| 177 const size_t HttpStreamParser::kChunkHeaderFooterSize = 12; | |
| 178 | |
| 179 HttpStreamParser::HttpStreamParser(ClientSocketHandle* connection, | |
| 180 const HttpRequestInfo* request, | |
| 181 GrowableIOBuffer* read_buffer, | |
| 182 const BoundNetLog& net_log) | |
| 183 : io_state_(STATE_NONE), | |
| 184 request_(request), | |
| 185 request_headers_(NULL), | |
| 186 request_headers_length_(0), | |
| 187 read_buf_(read_buffer), | |
| 188 read_buf_unused_offset_(0), | |
| 189 response_header_start_offset_(-1), | |
| 190 received_bytes_(0), | |
| 191 response_body_length_(-1), | |
| 192 response_body_read_(0), | |
| 193 user_read_buf_(NULL), | |
| 194 user_read_buf_len_(0), | |
| 195 connection_(connection), | |
| 196 net_log_(net_log), | |
| 197 sent_last_chunk_(false), | |
| 198 upload_error_(OK), | |
| 199 weak_ptr_factory_(this) { | |
| 200 io_callback_ = base::Bind(&HttpStreamParser::OnIOComplete, | |
| 201 weak_ptr_factory_.GetWeakPtr()); | |
| 202 } | |
| 203 | |
| 204 HttpStreamParser::~HttpStreamParser() { | |
| 205 } | |
| 206 | |
| 207 int HttpStreamParser::SendRequest(const std::string& request_line, | |
| 208 const HttpRequestHeaders& headers, | |
| 209 HttpResponseInfo* response, | |
| 210 const CompletionCallback& callback) { | |
| 211 DCHECK_EQ(STATE_NONE, io_state_); | |
| 212 DCHECK(callback_.is_null()); | |
| 213 DCHECK(!callback.is_null()); | |
| 214 DCHECK(response); | |
| 215 | |
| 216 net_log_.AddEvent( | |
| 217 NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST_HEADERS, | |
| 218 base::Bind(&HttpRequestHeaders::NetLogCallback, | |
| 219 base::Unretained(&headers), | |
| 220 &request_line)); | |
| 221 | |
| 222 DVLOG(1) << __FUNCTION__ << "()" | |
| 223 << " request_line = \"" << request_line << "\"" | |
| 224 << " headers = \"" << headers.ToString() << "\""; | |
| 225 response_ = response; | |
| 226 | |
| 227 // Put the peer's IP address and port into the response. | |
| 228 IPEndPoint ip_endpoint; | |
| 229 int result = connection_->socket()->GetPeerAddress(&ip_endpoint); | |
| 230 if (result != OK) | |
| 231 return result; | |
| 232 response_->socket_address = HostPortPair::FromIPEndPoint(ip_endpoint); | |
| 233 | |
| 234 std::string request = request_line + headers.ToString(); | |
| 235 request_headers_length_ = request.size(); | |
| 236 | |
| 237 if (request_->upload_data_stream != NULL) { | |
| 238 request_body_send_buf_ = new SeekableIOBuffer(kRequestBodyBufferSize); | |
| 239 if (request_->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_ = | |
| 243 new SeekableIOBuffer(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, request_->upload_data_stream)) { | |
| 256 int merged_size = static_cast<int>( | |
| 257 request_headers_length_ + request_->upload_data_stream->size()); | |
| 258 scoped_refptr<IOBuffer> merged_request_headers_and_body( | |
| 259 new IOBuffer(merged_size)); | |
| 260 // We'll repurpose |request_headers_| to store the merged headers and | |
| 261 // body. | |
| 262 request_headers_ = new DrainableIOBuffer( | |
| 263 merged_request_headers_and_body.get(), merged_size); | |
| 264 | |
| 265 memcpy(request_headers_->data(), request.data(), request_headers_length_); | |
| 266 request_headers_->DidConsume(request_headers_length_); | |
| 267 | |
| 268 uint64 todo = request_->upload_data_stream->size(); | |
| 269 while (todo) { | |
| 270 int consumed = request_->upload_data_stream->Read( | |
| 271 request_headers_.get(), static_cast<int>(todo), CompletionCallback()); | |
| 272 DCHECK_GT(consumed, 0); // Read() won't fail if not chunked. | |
| 273 request_headers_->DidConsume(consumed); | |
| 274 todo -= consumed; | |
| 275 } | |
| 276 DCHECK(request_->upload_data_stream->IsEOF()); | |
| 277 // Reset the offset, so the buffer can be read from the beginning. | |
| 278 request_headers_->SetOffset(0); | |
| 279 did_merge = true; | |
| 280 | |
| 281 net_log_.AddEvent( | |
| 282 NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST_BODY, | |
| 283 base::Bind(&NetLogSendRequestBodyCallback, | |
| 284 request_->upload_data_stream->size(), | |
| 285 false, /* not chunked */ | |
| 286 true /* merged */)); | |
| 287 } | |
| 288 | |
| 289 if (!did_merge) { | |
| 290 // If we didn't merge the body with the headers, then |request_headers_| | |
| 291 // contains just the HTTP headers. | |
| 292 scoped_refptr<StringIOBuffer> headers_io_buf(new StringIOBuffer(request)); | |
| 293 request_headers_ = | |
| 294 new DrainableIOBuffer(headers_io_buf.get(), headers_io_buf->size()); | |
| 295 } | |
| 296 | |
| 297 result = DoLoop(OK); | |
| 298 if (result == ERR_IO_PENDING) | |
| 299 callback_ = callback; | |
| 300 | |
| 301 return result > 0 ? OK : result; | |
| 302 } | |
| 303 | |
| 304 int HttpStreamParser::ReadResponseHeaders(const CompletionCallback& callback) { | |
| 305 DCHECK(io_state_ == STATE_NONE || io_state_ == STATE_DONE); | |
| 306 DCHECK(callback_.is_null()); | |
| 307 DCHECK(!callback.is_null()); | |
| 308 DCHECK_EQ(0, read_buf_unused_offset_); | |
| 309 | |
| 310 // This function can be called with io_state_ == STATE_DONE if the | |
| 311 // connection is closed after seeing just a 1xx response code. | |
| 312 if (io_state_ == STATE_DONE) | |
| 313 return ERR_CONNECTION_CLOSED; | |
| 314 | |
| 315 int result = OK; | |
| 316 io_state_ = STATE_READ_HEADERS; | |
| 317 | |
| 318 if (read_buf_->offset() > 0) { | |
| 319 // Simulate the state where the data was just read from the socket. | |
| 320 result = read_buf_->offset(); | |
| 321 read_buf_->set_offset(0); | |
| 322 } | |
| 323 if (result > 0) | |
| 324 io_state_ = STATE_READ_HEADERS_COMPLETE; | |
| 325 | |
| 326 result = DoLoop(result); | |
| 327 if (result == ERR_IO_PENDING) | |
| 328 callback_ = callback; | |
| 329 | |
| 330 return result > 0 ? OK : result; | |
| 331 } | |
| 332 | |
| 333 void HttpStreamParser::Close(bool not_reusable) { | |
| 334 if (not_reusable && connection_->socket()) | |
| 335 connection_->socket()->Disconnect(); | |
| 336 connection_->Reset(); | |
| 337 } | |
| 338 | |
| 339 int HttpStreamParser::ReadResponseBody(IOBuffer* buf, int buf_len, | |
| 340 const CompletionCallback& callback) { | |
| 341 DCHECK(io_state_ == STATE_NONE || io_state_ == STATE_DONE); | |
| 342 DCHECK(callback_.is_null()); | |
| 343 DCHECK(!callback.is_null()); | |
| 344 DCHECK_LE(buf_len, kMaxBufSize); | |
| 345 | |
| 346 if (io_state_ == STATE_DONE) | |
| 347 return OK; | |
| 348 | |
| 349 user_read_buf_ = buf; | |
| 350 user_read_buf_len_ = buf_len; | |
| 351 io_state_ = STATE_READ_BODY; | |
| 352 | |
| 353 int result = DoLoop(OK); | |
| 354 if (result == ERR_IO_PENDING) | |
| 355 callback_ = callback; | |
| 356 | |
| 357 return result; | |
| 358 } | |
| 359 | |
| 360 void HttpStreamParser::OnIOComplete(int result) { | |
| 361 // TODO(vadimt): Remove ScopedTracker below once crbug.com/418183 is fixed. | |
| 362 tracked_objects::ScopedTracker tracking_profile( | |
| 363 FROM_HERE_WITH_EXPLICIT_FUNCTION( | |
| 364 "418183 DidCompleteReadWrite => HttpStreamParser::OnIOComplete")); | |
| 365 | |
| 366 result = DoLoop(result); | |
| 367 | |
| 368 // The client callback can do anything, including destroying this class, | |
| 369 // so any pending callback must be issued after everything else is done. | |
| 370 if (result != ERR_IO_PENDING && !callback_.is_null()) { | |
| 371 // TODO(vadimt): Remove ScopedTracker below once crbug.com/424359 is fixed. | |
| 372 tracked_objects::ScopedTracker tracking_profile( | |
| 373 FROM_HERE_WITH_EXPLICIT_FUNCTION( | |
| 374 "424359 HttpStreamParser::OnIOComplete callback")); | |
| 375 | |
| 376 CompletionCallback c = callback_; | |
| 377 callback_.Reset(); | |
| 378 c.Run(result); | |
| 379 } | |
| 380 } | |
| 381 | |
| 382 int HttpStreamParser::DoLoop(int result) { | |
| 383 // TODO(vadimt): Remove ScopedTracker below once crbug.com/424359 is fixed. | |
| 384 tracked_objects::ScopedTracker tracking_profile( | |
| 385 FROM_HERE_WITH_EXPLICIT_FUNCTION("424359 HttpStreamParser::DoLoop")); | |
| 386 | |
| 387 do { | |
| 388 DCHECK_NE(ERR_IO_PENDING, result); | |
| 389 DCHECK_NE(STATE_DONE, io_state_); | |
| 390 DCHECK_NE(STATE_NONE, io_state_); | |
| 391 State state = io_state_; | |
| 392 io_state_ = STATE_NONE; | |
| 393 switch (state) { | |
| 394 case STATE_SEND_HEADERS: | |
| 395 DCHECK_EQ(OK, result); | |
| 396 result = DoSendHeaders(); | |
| 397 break; | |
| 398 case STATE_SEND_HEADERS_COMPLETE: | |
| 399 result = DoSendHeadersComplete(result); | |
| 400 break; | |
| 401 case STATE_SEND_BODY: | |
| 402 DCHECK_EQ(OK, result); | |
| 403 result = DoSendBody(); | |
| 404 break; | |
| 405 case STATE_SEND_BODY_COMPLETE: | |
| 406 result = DoSendBodyComplete(result); | |
| 407 break; | |
| 408 case STATE_SEND_REQUEST_READ_BODY_COMPLETE: | |
| 409 result = DoSendRequestReadBodyComplete(result); | |
| 410 break; | |
| 411 case STATE_READ_HEADERS: | |
| 412 net_log_.BeginEvent(NetLog::TYPE_HTTP_STREAM_PARSER_READ_HEADERS); | |
| 413 DCHECK_GE(result, 0); | |
| 414 result = DoReadHeaders(); | |
| 415 break; | |
| 416 case STATE_READ_HEADERS_COMPLETE: | |
| 417 result = DoReadHeadersComplete(result); | |
| 418 net_log_.EndEventWithNetErrorCode( | |
| 419 NetLog::TYPE_HTTP_STREAM_PARSER_READ_HEADERS, result); | |
| 420 break; | |
| 421 case STATE_READ_BODY: | |
| 422 DCHECK_GE(result, 0); | |
| 423 result = DoReadBody(); | |
| 424 break; | |
| 425 case STATE_READ_BODY_COMPLETE: | |
| 426 result = DoReadBodyComplete(result); | |
| 427 break; | |
| 428 default: | |
| 429 NOTREACHED(); | |
| 430 break; | |
| 431 } | |
| 432 } while (result != ERR_IO_PENDING && | |
| 433 (io_state_ != STATE_DONE && io_state_ != STATE_NONE)); | |
| 434 | |
| 435 return result; | |
| 436 } | |
| 437 | |
| 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 connection_->socket() | |
| 449 ->Write(request_headers_.get(), bytes_remaining, io_callback_); | |
| 450 } | |
| 451 | |
| 452 int HttpStreamParser::DoSendHeadersComplete(int result) { | |
| 453 if (result < 0) { | |
| 454 // In the unlikely case that the headers and body were merged, all the | |
| 455 // the headers were sent, but not all of the body way, and |result| is | |
| 456 // an error that this should try reading after, stash the error for now and | |
| 457 // act like the request was successfully sent. | |
| 458 if (request_headers_->BytesConsumed() >= request_headers_length_ && | |
| 459 ShouldTryReadingOnUploadError(result)) { | |
| 460 upload_error_ = result; | |
| 461 return OK; | |
| 462 } | |
| 463 return result; | |
| 464 } | |
| 465 | |
| 466 request_headers_->DidConsume(result); | |
| 467 if (request_headers_->BytesRemaining() > 0) { | |
| 468 io_state_ = STATE_SEND_HEADERS; | |
| 469 return OK; | |
| 470 } | |
| 471 | |
| 472 if (request_->upload_data_stream != NULL && | |
| 473 (request_->upload_data_stream->is_chunked() || | |
| 474 // !IsEOF() indicates that the body wasn't merged. | |
| 475 (request_->upload_data_stream->size() > 0 && | |
| 476 !request_->upload_data_stream->IsEOF()))) { | |
| 477 net_log_.AddEvent( | |
| 478 NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST_BODY, | |
| 479 base::Bind(&NetLogSendRequestBodyCallback, | |
| 480 request_->upload_data_stream->size(), | |
| 481 request_->upload_data_stream->is_chunked(), | |
| 482 false /* not merged */)); | |
| 483 io_state_ = STATE_SEND_BODY; | |
| 484 return OK; | |
| 485 } | |
| 486 | |
| 487 // Finished sending the request. | |
| 488 return OK; | |
| 489 } | |
| 490 | |
| 491 int HttpStreamParser::DoSendBody() { | |
| 492 if (request_body_send_buf_->BytesRemaining() > 0) { | |
| 493 io_state_ = STATE_SEND_BODY_COMPLETE; | |
| 494 return connection_->socket() | |
| 495 ->Write(request_body_send_buf_.get(), | |
| 496 request_body_send_buf_->BytesRemaining(), | |
| 497 io_callback_); | |
| 498 } | |
| 499 | |
| 500 if (request_->upload_data_stream->is_chunked() && sent_last_chunk_) { | |
| 501 // Finished sending the request. | |
| 502 return OK; | |
| 503 } | |
| 504 | |
| 505 request_body_read_buf_->Clear(); | |
| 506 io_state_ = STATE_SEND_REQUEST_READ_BODY_COMPLETE; | |
| 507 return request_->upload_data_stream->Read(request_body_read_buf_.get(), | |
| 508 request_body_read_buf_->capacity(), | |
| 509 io_callback_); | |
| 510 } | |
| 511 | |
| 512 int HttpStreamParser::DoSendBodyComplete(int result) { | |
| 513 if (result < 0) { | |
| 514 // If |result| is an error that this should try reading after, stash the | |
| 515 // error for now and act like the request was successfully sent. | |
| 516 if (ShouldTryReadingOnUploadError(result)) { | |
| 517 upload_error_ = result; | |
| 518 return OK; | |
| 519 } | |
| 520 return result; | |
| 521 } | |
| 522 | |
| 523 request_body_send_buf_->DidConsume(result); | |
| 524 | |
| 525 io_state_ = STATE_SEND_BODY; | |
| 526 return OK; | |
| 527 } | |
| 528 | |
| 529 int HttpStreamParser::DoSendRequestReadBodyComplete(int result) { | |
| 530 // |result| is the result of read from the request body from the last call to | |
| 531 // DoSendBody(). | |
| 532 DCHECK_GE(result, 0); // There won't be errors. | |
| 533 | |
| 534 // Chunked data needs to be encoded. | |
| 535 if (request_->upload_data_stream->is_chunked()) { | |
| 536 if (result == 0) { // Reached the end. | |
| 537 DCHECK(request_->upload_data_stream->IsEOF()); | |
| 538 sent_last_chunk_ = true; | |
| 539 } | |
| 540 // Encode the buffer as 1 chunk. | |
| 541 const base::StringPiece payload(request_body_read_buf_->data(), result); | |
| 542 request_body_send_buf_->Clear(); | |
| 543 result = EncodeChunk(payload, | |
| 544 request_body_send_buf_->data(), | |
| 545 request_body_send_buf_->capacity()); | |
| 546 } | |
| 547 | |
| 548 if (result == 0) { // Reached the end. | |
| 549 // Reaching EOF means we can finish sending request body unless the data is | |
| 550 // chunked. (i.e. No need to send the terminal chunk.) | |
| 551 DCHECK(request_->upload_data_stream->IsEOF()); | |
| 552 DCHECK(!request_->upload_data_stream->is_chunked()); | |
| 553 // Finished sending the request. | |
| 554 } else if (result > 0) { | |
| 555 request_body_send_buf_->DidAppend(result); | |
| 556 result = 0; | |
| 557 io_state_ = STATE_SEND_BODY; | |
| 558 } | |
| 559 return result; | |
| 560 } | |
| 561 | |
| 562 int HttpStreamParser::DoReadHeaders() { | |
| 563 io_state_ = STATE_READ_HEADERS_COMPLETE; | |
| 564 | |
| 565 // Grow the read buffer if necessary. | |
| 566 if (read_buf_->RemainingCapacity() == 0) | |
| 567 read_buf_->SetCapacity(read_buf_->capacity() + kHeaderBufInitialSize); | |
| 568 | |
| 569 // http://crbug.com/16371: We're seeing |user_buf_->data()| return NULL. | |
| 570 // See if the user is passing in an IOBuffer with a NULL |data_|. | |
| 571 CHECK(read_buf_->data()); | |
| 572 | |
| 573 return connection_->socket() | |
| 574 ->Read(read_buf_.get(), read_buf_->RemainingCapacity(), io_callback_); | |
| 575 } | |
| 576 | |
| 577 int HttpStreamParser::DoReadHeadersComplete(int result) { | |
| 578 result = HandleReadHeaderResult(result); | |
| 579 | |
| 580 // TODO(mmenke): The code below is ugly and hacky. A much better and more | |
| 581 // flexible long term solution would be to separate out the read and write | |
| 582 // loops, though this would involve significant changes, both here and | |
| 583 // elsewhere (WebSockets, for instance). | |
| 584 | |
| 585 // If still reading the headers, or there was no error uploading the request | |
| 586 // body, just return the result. | |
| 587 if (io_state_ == STATE_READ_HEADERS || upload_error_ == OK) | |
| 588 return result; | |
| 589 | |
| 590 // If the result is ERR_IO_PENDING, |io_state_| should be STATE_READ_HEADERS. | |
| 591 DCHECK_NE(ERR_IO_PENDING, result); | |
| 592 | |
| 593 // On errors, use the original error received when sending the request. | |
| 594 // The main cases where these are different is when there's a header-related | |
| 595 // error code, or when there's an ERR_CONNECTION_CLOSED, which can result in | |
| 596 // special handling of partial responses and HTTP/0.9 responses. | |
| 597 if (result < 0) { | |
| 598 // Nothing else to do. In the HTTP/0.9 or only partial headers received | |
| 599 // cases, can normally go to other states after an error reading headers. | |
| 600 io_state_ = STATE_DONE; | |
| 601 // Don't let caller see the headers. | |
| 602 response_->headers = NULL; | |
| 603 return upload_error_; | |
| 604 } | |
| 605 | |
| 606 // Skip over 1xx responses as usual, and allow 4xx/5xx error responses to | |
| 607 // override the error received while uploading the body. | |
| 608 int response_code_class = response_->headers->response_code() / 100; | |
| 609 if (response_code_class == 1 || response_code_class == 4 || | |
| 610 response_code_class == 5) { | |
| 611 return result; | |
| 612 } | |
| 613 | |
| 614 // All other status codes are not allowed after an error during upload, to | |
| 615 // make sure the consumer has some indication there was an error. | |
| 616 | |
| 617 // Nothing else to do. | |
| 618 io_state_ = STATE_DONE; | |
| 619 // Don't let caller see the headers. | |
| 620 response_->headers = NULL; | |
| 621 return upload_error_; | |
| 622 } | |
| 623 | |
| 624 int HttpStreamParser::DoReadBody() { | |
| 625 io_state_ = STATE_READ_BODY_COMPLETE; | |
| 626 | |
| 627 // There may be some data left over from reading the response headers. | |
| 628 if (read_buf_->offset()) { | |
| 629 int available = read_buf_->offset() - read_buf_unused_offset_; | |
| 630 if (available) { | |
| 631 CHECK_GT(available, 0); | |
| 632 int bytes_from_buffer = std::min(available, user_read_buf_len_); | |
| 633 memcpy(user_read_buf_->data(), | |
| 634 read_buf_->StartOfBuffer() + read_buf_unused_offset_, | |
| 635 bytes_from_buffer); | |
| 636 read_buf_unused_offset_ += bytes_from_buffer; | |
| 637 if (bytes_from_buffer == available) { | |
| 638 read_buf_->SetCapacity(0); | |
| 639 read_buf_unused_offset_ = 0; | |
| 640 } | |
| 641 return bytes_from_buffer; | |
| 642 } else { | |
| 643 read_buf_->SetCapacity(0); | |
| 644 read_buf_unused_offset_ = 0; | |
| 645 } | |
| 646 } | |
| 647 | |
| 648 // Check to see if we're done reading. | |
| 649 if (IsResponseBodyComplete()) | |
| 650 return 0; | |
| 651 | |
| 652 DCHECK_EQ(0, read_buf_->offset()); | |
| 653 return connection_->socket() | |
| 654 ->Read(user_read_buf_.get(), user_read_buf_len_, io_callback_); | |
| 655 } | |
| 656 | |
| 657 int HttpStreamParser::DoReadBodyComplete(int result) { | |
| 658 // When the connection is closed, there are numerous ways to interpret it. | |
| 659 // | |
| 660 // - If a Content-Length header is present and the body contains exactly that | |
| 661 // number of bytes at connection close, the response is successful. | |
| 662 // | |
| 663 // - If a Content-Length header is present and the body contains fewer bytes | |
| 664 // than promised by the header at connection close, it may indicate that | |
| 665 // the connection was closed prematurely, or it may indicate that the | |
| 666 // server sent an invalid Content-Length header. Unfortunately, the invalid | |
| 667 // Content-Length header case does occur in practice and other browsers are | |
| 668 // tolerant of it. We choose to treat it as an error for now, but the | |
| 669 // download system treats it as a non-error, and URLRequestHttpJob also | |
| 670 // treats it as OK if the Content-Length is the post-decoded body content | |
| 671 // length. | |
| 672 // | |
| 673 // - If chunked encoding is used and the terminating chunk has been processed | |
| 674 // when the connection is closed, the response is successful. | |
| 675 // | |
| 676 // - If chunked encoding is used and the terminating chunk has not been | |
| 677 // processed when the connection is closed, it may indicate that the | |
| 678 // connection was closed prematurely or it may indicate that the server | |
| 679 // sent an invalid chunked encoding. We choose to treat it as | |
| 680 // an invalid chunked encoding. | |
| 681 // | |
| 682 // - If a Content-Length is not present and chunked encoding is not used, | |
| 683 // connection close is the only way to signal that the response is | |
| 684 // complete. Unfortunately, this also means that there is no way to detect | |
| 685 // early close of a connection. No error is returned. | |
| 686 if (result == 0 && !IsResponseBodyComplete() && CanFindEndOfResponse()) { | |
| 687 if (chunked_decoder_.get()) | |
| 688 result = ERR_INCOMPLETE_CHUNKED_ENCODING; | |
| 689 else | |
| 690 result = ERR_CONTENT_LENGTH_MISMATCH; | |
| 691 } | |
| 692 | |
| 693 if (result > 0) | |
| 694 received_bytes_ += result; | |
| 695 | |
| 696 // Filter incoming data if appropriate. FilterBuf may return an error. | |
| 697 if (result > 0 && chunked_decoder_.get()) { | |
| 698 result = chunked_decoder_->FilterBuf(user_read_buf_->data(), result); | |
| 699 if (result == 0 && !chunked_decoder_->reached_eof()) { | |
| 700 // Don't signal completion of the Read call yet or else it'll look like | |
| 701 // we received end-of-file. Wait for more data. | |
| 702 io_state_ = STATE_READ_BODY; | |
| 703 return OK; | |
| 704 } | |
| 705 } | |
| 706 | |
| 707 if (result > 0) | |
| 708 response_body_read_ += result; | |
| 709 | |
| 710 if (result <= 0 || IsResponseBodyComplete()) { | |
| 711 io_state_ = STATE_DONE; | |
| 712 | |
| 713 // Save the overflow data, which can be in two places. There may be | |
| 714 // some left over in |user_read_buf_|, plus there may be more | |
| 715 // in |read_buf_|. But the part left over in |user_read_buf_| must have | |
| 716 // come from the |read_buf_|, so there's room to put it back at the | |
| 717 // start first. | |
| 718 int additional_save_amount = read_buf_->offset() - read_buf_unused_offset_; | |
| 719 int save_amount = 0; | |
| 720 if (chunked_decoder_.get()) { | |
| 721 save_amount = chunked_decoder_->bytes_after_eof(); | |
| 722 } else if (response_body_length_ >= 0) { | |
| 723 int64 extra_data_read = response_body_read_ - response_body_length_; | |
| 724 if (extra_data_read > 0) { | |
| 725 save_amount = static_cast<int>(extra_data_read); | |
| 726 if (result > 0) | |
| 727 result -= save_amount; | |
| 728 } | |
| 729 } | |
| 730 | |
| 731 CHECK_LE(save_amount + additional_save_amount, kMaxBufSize); | |
| 732 if (read_buf_->capacity() < save_amount + additional_save_amount) { | |
| 733 read_buf_->SetCapacity(save_amount + additional_save_amount); | |
| 734 } | |
| 735 | |
| 736 if (save_amount) { | |
| 737 received_bytes_ -= save_amount; | |
| 738 memcpy(read_buf_->StartOfBuffer(), user_read_buf_->data() + result, | |
| 739 save_amount); | |
| 740 } | |
| 741 read_buf_->set_offset(save_amount); | |
| 742 if (additional_save_amount) { | |
| 743 memmove(read_buf_->data(), | |
| 744 read_buf_->StartOfBuffer() + read_buf_unused_offset_, | |
| 745 additional_save_amount); | |
| 746 read_buf_->set_offset(save_amount + additional_save_amount); | |
| 747 } | |
| 748 read_buf_unused_offset_ = 0; | |
| 749 } else { | |
| 750 // Now waiting for more of the body to be read. | |
| 751 user_read_buf_ = NULL; | |
| 752 user_read_buf_len_ = 0; | |
| 753 } | |
| 754 | |
| 755 return result; | |
| 756 } | |
| 757 | |
| 758 int HttpStreamParser::HandleReadHeaderResult(int result) { | |
| 759 DCHECK_EQ(0, read_buf_unused_offset_); | |
| 760 | |
| 761 if (result == 0) | |
| 762 result = ERR_CONNECTION_CLOSED; | |
| 763 | |
| 764 if (result < 0 && result != ERR_CONNECTION_CLOSED) { | |
| 765 io_state_ = STATE_DONE; | |
| 766 return result; | |
| 767 } | |
| 768 // If we've used the connection before, then we know it is not a HTTP/0.9 | |
| 769 // response and return ERR_CONNECTION_CLOSED. | |
| 770 if (result == ERR_CONNECTION_CLOSED && read_buf_->offset() == 0 && | |
| 771 connection_->is_reused()) { | |
| 772 io_state_ = STATE_DONE; | |
| 773 return result; | |
| 774 } | |
| 775 | |
| 776 // Record our best estimate of the 'response time' as the time when we read | |
| 777 // the first bytes of the response headers. | |
| 778 if (read_buf_->offset() == 0 && result != ERR_CONNECTION_CLOSED) | |
| 779 response_->response_time = base::Time::Now(); | |
| 780 | |
| 781 if (result == ERR_CONNECTION_CLOSED) { | |
| 782 // The connection closed before we detected the end of the headers. | |
| 783 if (read_buf_->offset() == 0) { | |
| 784 // The connection was closed before any data was sent. Likely an error | |
| 785 // rather than empty HTTP/0.9 response. | |
| 786 io_state_ = STATE_DONE; | |
| 787 return ERR_EMPTY_RESPONSE; | |
| 788 } else if (request_->url.SchemeIsSecure()) { | |
| 789 // The connection was closed in the middle of the headers. For HTTPS we | |
| 790 // don't parse partial headers. Return a different error code so that we | |
| 791 // know that we shouldn't attempt to retry the request. | |
| 792 io_state_ = STATE_DONE; | |
| 793 return ERR_RESPONSE_HEADERS_TRUNCATED; | |
| 794 } | |
| 795 // Parse things as well as we can and let the caller decide what to do. | |
| 796 int end_offset; | |
| 797 if (response_header_start_offset_ >= 0) { | |
| 798 io_state_ = STATE_READ_BODY_COMPLETE; | |
| 799 end_offset = read_buf_->offset(); | |
| 800 } else { | |
| 801 // Now waiting for the body to be read. | |
| 802 end_offset = 0; | |
| 803 } | |
| 804 int rv = DoParseResponseHeaders(end_offset); | |
| 805 if (rv < 0) | |
| 806 return rv; | |
| 807 return result; | |
| 808 } | |
| 809 | |
| 810 read_buf_->set_offset(read_buf_->offset() + result); | |
| 811 DCHECK_LE(read_buf_->offset(), read_buf_->capacity()); | |
| 812 DCHECK_GE(result, 0); | |
| 813 | |
| 814 int end_of_header_offset = ParseResponseHeaders(); | |
| 815 | |
| 816 // Note: -1 is special, it indicates we haven't found the end of headers. | |
| 817 // Anything less than -1 is a net::Error, so we bail out. | |
| 818 if (end_of_header_offset < -1) | |
| 819 return end_of_header_offset; | |
| 820 | |
| 821 if (end_of_header_offset == -1) { | |
| 822 io_state_ = STATE_READ_HEADERS; | |
| 823 // Prevent growing the headers buffer indefinitely. | |
| 824 if (read_buf_->offset() >= kMaxHeaderBufSize) { | |
| 825 io_state_ = STATE_DONE; | |
| 826 return ERR_RESPONSE_HEADERS_TOO_BIG; | |
| 827 } | |
| 828 } else { | |
| 829 CalculateResponseBodySize(); | |
| 830 // If the body is zero length, the caller may not call ReadResponseBody, | |
| 831 // which is where any extra data is copied to read_buf_, so we move the | |
| 832 // data here. | |
| 833 if (response_body_length_ == 0) { | |
| 834 int extra_bytes = read_buf_->offset() - end_of_header_offset; | |
| 835 if (extra_bytes) { | |
| 836 CHECK_GT(extra_bytes, 0); | |
| 837 memmove(read_buf_->StartOfBuffer(), | |
| 838 read_buf_->StartOfBuffer() + end_of_header_offset, | |
| 839 extra_bytes); | |
| 840 } | |
| 841 read_buf_->SetCapacity(extra_bytes); | |
| 842 if (response_->headers->response_code() / 100 == 1) { | |
| 843 // After processing a 1xx response, the caller will ask for the next | |
| 844 // header, so reset state to support that. We don't completely ignore a | |
| 845 // 1xx response because it cannot be returned in reply to a CONNECT | |
| 846 // request so we return OK here, which lets the caller inspect the | |
| 847 // response and reject it in the event that we're setting up a CONNECT | |
| 848 // tunnel. | |
| 849 response_header_start_offset_ = -1; | |
| 850 response_body_length_ = -1; | |
| 851 // Now waiting for the second set of headers to be read. | |
| 852 } else { | |
| 853 io_state_ = STATE_DONE; | |
| 854 } | |
| 855 return OK; | |
| 856 } | |
| 857 | |
| 858 // Note where the headers stop. | |
| 859 read_buf_unused_offset_ = end_of_header_offset; | |
| 860 // Now waiting for the body to be read. | |
| 861 } | |
| 862 return result; | |
| 863 } | |
| 864 | |
| 865 int HttpStreamParser::ParseResponseHeaders() { | |
| 866 int end_offset = -1; | |
| 867 DCHECK_EQ(0, read_buf_unused_offset_); | |
| 868 | |
| 869 // Look for the start of the status line, if it hasn't been found yet. | |
| 870 if (response_header_start_offset_ < 0) { | |
| 871 response_header_start_offset_ = HttpUtil::LocateStartOfStatusLine( | |
| 872 read_buf_->StartOfBuffer(), read_buf_->offset()); | |
| 873 } | |
| 874 | |
| 875 if (response_header_start_offset_ >= 0) { | |
| 876 end_offset = HttpUtil::LocateEndOfHeaders(read_buf_->StartOfBuffer(), | |
| 877 read_buf_->offset(), | |
| 878 response_header_start_offset_); | |
| 879 } else if (read_buf_->offset() >= 8) { | |
| 880 // Enough data to decide that this is an HTTP/0.9 response. | |
| 881 // 8 bytes = (4 bytes of junk) + "http".length() | |
| 882 end_offset = 0; | |
| 883 } | |
| 884 | |
| 885 if (end_offset == -1) | |
| 886 return -1; | |
| 887 | |
| 888 int rv = DoParseResponseHeaders(end_offset); | |
| 889 if (rv < 0) | |
| 890 return rv; | |
| 891 return end_offset; | |
| 892 } | |
| 893 | |
| 894 int HttpStreamParser::DoParseResponseHeaders(int end_offset) { | |
| 895 scoped_refptr<HttpResponseHeaders> headers; | |
| 896 DCHECK_EQ(0, read_buf_unused_offset_); | |
| 897 | |
| 898 if (response_header_start_offset_ >= 0) { | |
| 899 received_bytes_ += end_offset; | |
| 900 headers = new HttpResponseHeaders(HttpUtil::AssembleRawHeaders( | |
| 901 read_buf_->StartOfBuffer(), end_offset)); | |
| 902 } else { | |
| 903 // Enough data was read -- there is no status line. | |
| 904 headers = new HttpResponseHeaders(std::string("HTTP/0.9 200 OK")); | |
| 905 } | |
| 906 | |
| 907 // Check for multiple Content-Length headers with no Transfer-Encoding header. | |
| 908 // If they exist, and have distinct values, it's a potential response | |
| 909 // smuggling attack. | |
| 910 if (!headers->HasHeader("Transfer-Encoding")) { | |
| 911 if (HeadersContainMultipleCopiesOfField(*headers.get(), "Content-Length")) | |
| 912 return ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_LENGTH; | |
| 913 } | |
| 914 | |
| 915 // Check for multiple Content-Disposition or Location headers. If they exist, | |
| 916 // it's also a potential response smuggling attack. | |
| 917 if (HeadersContainMultipleCopiesOfField(*headers.get(), | |
| 918 "Content-Disposition")) | |
| 919 return ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_DISPOSITION; | |
| 920 if (HeadersContainMultipleCopiesOfField(*headers.get(), "Location")) | |
| 921 return ERR_RESPONSE_HEADERS_MULTIPLE_LOCATION; | |
| 922 | |
| 923 response_->headers = headers; | |
| 924 response_->connection_info = HttpResponseInfo::CONNECTION_INFO_HTTP1; | |
| 925 response_->vary_data.Init(*request_, *response_->headers.get()); | |
| 926 DVLOG(1) << __FUNCTION__ << "()" | |
| 927 << " content_length = \"" << response_->headers->GetContentLength() | |
| 928 << "\n\"" | |
| 929 << " headers = \"" | |
| 930 << GetResponseHeaderLines(*response_->headers.get()) << "\""; | |
| 931 return OK; | |
| 932 } | |
| 933 | |
| 934 void HttpStreamParser::CalculateResponseBodySize() { | |
| 935 // Figure how to determine EOF: | |
| 936 | |
| 937 // For certain responses, we know the content length is always 0. From | |
| 938 // RFC 2616 Section 4.3 Message Body: | |
| 939 // | |
| 940 // For response messages, whether or not a message-body is included with | |
| 941 // a message is dependent on both the request method and the response | |
| 942 // status code (section 6.1.1). All responses to the HEAD request method | |
| 943 // MUST NOT include a message-body, even though the presence of entity- | |
| 944 // header fields might lead one to believe they do. All 1xx | |
| 945 // (informational), 204 (no content), and 304 (not modified) responses | |
| 946 // MUST NOT include a message-body. All other responses do include a | |
| 947 // message-body, although it MAY be of zero length. | |
| 948 if (response_->headers->response_code() / 100 == 1) { | |
| 949 response_body_length_ = 0; | |
| 950 } else { | |
| 951 switch (response_->headers->response_code()) { | |
| 952 case 204: // No Content | |
| 953 case 205: // Reset Content | |
| 954 case 304: // Not Modified | |
| 955 response_body_length_ = 0; | |
| 956 break; | |
| 957 } | |
| 958 } | |
| 959 if (request_->method == "HEAD") | |
| 960 response_body_length_ = 0; | |
| 961 | |
| 962 if (response_body_length_ == -1) { | |
| 963 // "Transfer-Encoding: chunked" trumps "Content-Length: N" | |
| 964 if (response_->headers->IsChunkEncoded()) { | |
| 965 chunked_decoder_.reset(new HttpChunkedDecoder()); | |
| 966 } else { | |
| 967 response_body_length_ = response_->headers->GetContentLength(); | |
| 968 // If response_body_length_ is still -1, then we have to wait | |
| 969 // for the server to close the connection. | |
| 970 } | |
| 971 } | |
| 972 } | |
| 973 | |
| 974 UploadProgress HttpStreamParser::GetUploadProgress() const { | |
| 975 if (!request_->upload_data_stream) | |
| 976 return UploadProgress(); | |
| 977 | |
| 978 return UploadProgress(request_->upload_data_stream->position(), | |
| 979 request_->upload_data_stream->size()); | |
| 980 } | |
| 981 | |
| 982 bool HttpStreamParser::IsResponseBodyComplete() const { | |
| 983 if (chunked_decoder_.get()) | |
| 984 return chunked_decoder_->reached_eof(); | |
| 985 if (response_body_length_ != -1) | |
| 986 return response_body_read_ >= response_body_length_; | |
| 987 | |
| 988 return false; // Must read to EOF. | |
| 989 } | |
| 990 | |
| 991 bool HttpStreamParser::CanFindEndOfResponse() const { | |
| 992 return chunked_decoder_.get() || response_body_length_ >= 0; | |
| 993 } | |
| 994 | |
| 995 bool HttpStreamParser::IsMoreDataBuffered() const { | |
| 996 return read_buf_->offset() > read_buf_unused_offset_; | |
| 997 } | |
| 998 | |
| 999 bool HttpStreamParser::IsConnectionReused() const { | |
| 1000 ClientSocketHandle::SocketReuseType reuse_type = connection_->reuse_type(); | |
| 1001 return connection_->is_reused() || | |
| 1002 reuse_type == ClientSocketHandle::UNUSED_IDLE; | |
| 1003 } | |
| 1004 | |
| 1005 void HttpStreamParser::SetConnectionReused() { | |
| 1006 connection_->set_reuse_type(ClientSocketHandle::REUSED_IDLE); | |
| 1007 } | |
| 1008 | |
| 1009 bool HttpStreamParser::IsConnectionReusable() const { | |
| 1010 return connection_->socket() && connection_->socket()->IsConnectedAndIdle(); | |
| 1011 } | |
| 1012 | |
| 1013 void HttpStreamParser::GetSSLInfo(SSLInfo* ssl_info) { | |
| 1014 if (request_->url.SchemeIsSecure() && connection_->socket()) { | |
| 1015 SSLClientSocket* ssl_socket = | |
| 1016 static_cast<SSLClientSocket*>(connection_->socket()); | |
| 1017 ssl_socket->GetSSLInfo(ssl_info); | |
| 1018 } | |
| 1019 } | |
| 1020 | |
| 1021 void HttpStreamParser::GetSSLCertRequestInfo( | |
| 1022 SSLCertRequestInfo* cert_request_info) { | |
| 1023 if (request_->url.SchemeIsSecure() && connection_->socket()) { | |
| 1024 SSLClientSocket* ssl_socket = | |
| 1025 static_cast<SSLClientSocket*>(connection_->socket()); | |
| 1026 ssl_socket->GetSSLCertRequestInfo(cert_request_info); | |
| 1027 } | |
| 1028 } | |
| 1029 | |
| 1030 int HttpStreamParser::EncodeChunk(const base::StringPiece& payload, | |
| 1031 char* output, | |
| 1032 size_t output_size) { | |
| 1033 if (output_size < payload.size() + kChunkHeaderFooterSize) | |
| 1034 return ERR_INVALID_ARGUMENT; | |
| 1035 | |
| 1036 char* cursor = output; | |
| 1037 // Add the header. | |
| 1038 const int num_chars = base::snprintf(output, output_size, | |
| 1039 "%X\r\n", | |
| 1040 static_cast<int>(payload.size())); | |
| 1041 cursor += num_chars; | |
| 1042 // Add the payload if any. | |
| 1043 if (payload.size() > 0) { | |
| 1044 memcpy(cursor, payload.data(), payload.size()); | |
| 1045 cursor += payload.size(); | |
| 1046 } | |
| 1047 // Add the trailing CRLF. | |
| 1048 memcpy(cursor, "\r\n", 2); | |
| 1049 cursor += 2; | |
| 1050 | |
| 1051 return cursor - output; | |
| 1052 } | |
| 1053 | |
| 1054 // static | |
| 1055 bool HttpStreamParser::ShouldMergeRequestHeadersAndBody( | |
| 1056 const std::string& request_headers, | |
| 1057 const UploadDataStream* request_body) { | |
| 1058 if (request_body != NULL && | |
| 1059 // IsInMemory() ensures that the request body is not chunked. | |
| 1060 request_body->IsInMemory() && | |
| 1061 request_body->size() > 0) { | |
| 1062 uint64 merged_size = request_headers.size() + request_body->size(); | |
| 1063 if (merged_size <= kMaxMergedHeaderAndBodySize) | |
| 1064 return true; | |
| 1065 } | |
| 1066 return false; | |
| 1067 } | |
| 1068 | |
| 1069 } // namespace net | |
| OLD | NEW |