Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(159)

Side by Side Diff: net/http/http_stream_parser.cc

Issue 403393003: HTTP retry support. Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/http/http_stream_parser.h" 5 #include "net/http/http_stream_parser.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/compiler_specific.h" 8 #include "base/compiler_specific.h"
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/metrics/histogram.h"
11 #include "base/pickle.h"
10 #include "base/strings/string_util.h" 12 #include "base/strings/string_util.h"
11 #include "base/values.h" 13 #include "base/values.h"
14 #include "crypto/secure_hash.h"
15 #include "crypto/sha2.h"
12 #include "net/base/io_buffer.h" 16 #include "net/base/io_buffer.h"
13 #include "net/base/ip_endpoint.h" 17 #include "net/base/ip_endpoint.h"
14 #include "net/base/upload_data_stream.h" 18 #include "net/base/upload_data_stream.h"
15 #include "net/http/http_chunked_decoder.h" 19 #include "net/http/http_chunked_decoder.h"
16 #include "net/http/http_request_headers.h" 20 #include "net/http/http_request_headers.h"
17 #include "net/http/http_request_info.h" 21 #include "net/http/http_request_info.h"
18 #include "net/http/http_response_headers.h" 22 #include "net/http/http_response_headers.h"
19 #include "net/http/http_util.h" 23 #include "net/http/http_util.h"
20 #include "net/socket/client_socket_handle.h" 24 #include "net/socket/client_socket_handle.h"
21 #include "net/socket/ssl_client_socket.h" 25 #include "net/socket/ssl_client_socket.h"
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
71 75
72 // Returns true if |error_code| is an error for which we give the server a 76 // Returns true if |error_code| is an error for which we give the server a
73 // chance to send a body containing error information, if the error was received 77 // chance to send a body containing error information, if the error was received
74 // while trying to upload a request body. 78 // while trying to upload a request body.
75 bool ShouldTryReadingOnUploadError(int error_code) { 79 bool ShouldTryReadingOnUploadError(int error_code) {
76 return (error_code == ERR_CONNECTION_RESET); 80 return (error_code == ERR_CONNECTION_RESET);
77 } 81 }
78 82
79 } // namespace 83 } // namespace
80 84
85 // To verify that retry attempts will not cause errors we hash all received
86 // content. When retrying we hash the content again and verify that the
87 // previous hash matches once we have received the same amount of data.
88 class HttpStreamParser::HttpStreamHash {
89 public:
90 HttpStreamHash()
91 :hash_(crypto::SecureHash::Create(crypto::SecureHash::SHA256)) {
92 }
93
94 // Add to hash.
95 void Update(const void* input, size_t len) {
96 hash_->Update(input, len);
97 }
98
99 // Finish hash once all content has been received.
100 void Finish(void* output, size_t len) {
101 hash_->Finish(output, len);
102 }
103
104 // Verify hash after serializing the state. Then deserialize so that we can
105 // keep hashing if we decide to continue fetching the content.
106 int VerifyHash() {
107 int result = OK;
108 uint8 hash[8];
109 Pickle pickle;
110 hash_->Serialize(&pickle);
111 hash_->Finish(hash, sizeof(hash));
112 DCHECK(sizeof(hash) == sizeof(previous_hash_));
113 if (memcmp(hash, previous_hash_, sizeof(previous_hash_)) != 0) {
114 result = ERR_RETRY_HASH_MISMATCH;
115 UMA_HISTOGRAM_COUNTS("Net.HttpRetry.VerifyHashFailure", 1);
116 } else {
117 PickleIterator data_iterator(pickle);
118 hash_->Deserialize(&data_iterator);
119 UMA_HISTOGRAM_COUNTS("Net.HttpRetry.VerifyHashSuccess", 1);
120 }
121
122 return result;
123 }
124
125 void SetPreviousHash(const void* hash, size_t len) {
126 DCHECK(len == sizeof(previous_hash_));
127 memcpy(previous_hash_, hash, len);
128 }
129
130 private:
131 // Hash of current attempt to retrieve the resource.
132 scoped_ptr<crypto::SecureHash> hash_;
133
134 // Hash of previous attempt to retrieve the resource.
135 uint8 previous_hash_[8];
136 };
137
81 // Similar to DrainableIOBuffer(), but this version comes with its own 138 // Similar to DrainableIOBuffer(), but this version comes with its own
82 // storage. The motivation is to avoid repeated allocations of 139 // storage. The motivation is to avoid repeated allocations of
83 // DrainableIOBuffer. 140 // DrainableIOBuffer.
84 // 141 //
85 // Example: 142 // Example:
86 // 143 //
87 // scoped_refptr<SeekableIOBuffer> buf = new SeekableIOBuffer(1024); 144 // scoped_refptr<SeekableIOBuffer> buf = new SeekableIOBuffer(1024);
88 // // capacity() == 1024. size() == BytesRemaining() == BytesConsumed() == 0. 145 // // capacity() == 1024. size() == BytesRemaining() == BytesConsumed() == 0.
89 // // data() points to the beginning of the buffer. 146 // // data() points to the beginning of the buffer.
90 // 147 //
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
181 const BoundNetLog& net_log) 238 const BoundNetLog& net_log)
182 : io_state_(STATE_NONE), 239 : io_state_(STATE_NONE),
183 request_(request), 240 request_(request),
184 request_headers_(NULL), 241 request_headers_(NULL),
185 request_headers_length_(0), 242 request_headers_length_(0),
186 read_buf_(read_buffer), 243 read_buf_(read_buffer),
187 read_buf_unused_offset_(0), 244 read_buf_unused_offset_(0),
188 response_header_start_offset_(-1), 245 response_header_start_offset_(-1),
189 received_bytes_(0), 246 received_bytes_(0),
190 response_body_length_(-1), 247 response_body_length_(-1),
248 read_offset_(0),
249 stream_hash_(new HttpStreamHash()),
191 response_body_read_(0), 250 response_body_read_(0),
192 user_read_buf_(NULL), 251 user_read_buf_(NULL),
193 user_read_buf_len_(0), 252 user_read_buf_len_(0),
194 connection_(connection), 253 connection_(connection),
195 net_log_(net_log), 254 net_log_(net_log),
196 sent_last_chunk_(false), 255 sent_last_chunk_(false),
197 upload_error_(OK), 256 upload_error_(OK),
198 weak_ptr_factory_(this) { 257 weak_ptr_factory_(this) {
199 io_callback_ = base::Bind(&HttpStreamParser::OnIOComplete, 258 io_callback_ = base::Bind(&HttpStreamParser::OnIOComplete,
200 weak_ptr_factory_.GetWeakPtr()); 259 weak_ptr_factory_.GetWeakPtr());
(...skipping 404 matching lines...) Expand 10 before | Expand all | Expand 10 after
605 response_->headers = NULL; 664 response_->headers = NULL;
606 return upload_error_; 665 return upload_error_;
607 } 666 }
608 667
609 int HttpStreamParser::DoReadBody() { 668 int HttpStreamParser::DoReadBody() {
610 io_state_ = STATE_READ_BODY_COMPLETE; 669 io_state_ = STATE_READ_BODY_COMPLETE;
611 670
612 // There may be some data left over from reading the response headers. 671 // There may be some data left over from reading the response headers.
613 if (read_buf_->offset()) { 672 if (read_buf_->offset()) {
614 int available = read_buf_->offset() - read_buf_unused_offset_; 673 int available = read_buf_->offset() - read_buf_unused_offset_;
674 if (available > 0 && read_offset_) {
675 int64 bytes_from_buffer =
676 available < read_offset_ ? available : read_offset_;
677 stream_hash_->Update((uint8*)read_buf_->StartOfBuffer() +
678 read_buf_unused_offset_, bytes_from_buffer);
679 read_buf_unused_offset_ += bytes_from_buffer;
680 read_offset_ -= bytes_from_buffer;
681 response_body_read_ += bytes_from_buffer;
682 available -= bytes_from_buffer;
683
684 if (read_offset_ == 0 && stream_hash_->VerifyHash() != OK) {
685 io_state_ = STATE_DONE;
686 return ERR_RETRY_HASH_MISMATCH;
687 }
688 }
689
615 if (available) { 690 if (available) {
616 CHECK_GT(available, 0); 691 CHECK_GT(available, 0);
617 int bytes_from_buffer = std::min(available, user_read_buf_len_); 692 int bytes_from_buffer = std::min(available, user_read_buf_len_);
618 memcpy(user_read_buf_->data(), 693 memcpy(user_read_buf_->data(),
619 read_buf_->StartOfBuffer() + read_buf_unused_offset_, 694 read_buf_->StartOfBuffer() + read_buf_unused_offset_,
620 bytes_from_buffer); 695 bytes_from_buffer);
621 read_buf_unused_offset_ += bytes_from_buffer; 696 read_buf_unused_offset_ += bytes_from_buffer;
622 if (bytes_from_buffer == available) { 697 if (bytes_from_buffer == available) {
623 read_buf_->SetCapacity(0); 698 read_buf_->SetCapacity(0);
624 read_buf_unused_offset_ = 0; 699 read_buf_unused_offset_ = 0;
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
685 // Don't signal completion of the Read call yet or else it'll look like 760 // Don't signal completion of the Read call yet or else it'll look like
686 // we received end-of-file. Wait for more data. 761 // we received end-of-file. Wait for more data.
687 io_state_ = STATE_READ_BODY; 762 io_state_ = STATE_READ_BODY;
688 return OK; 763 return OK;
689 } 764 }
690 } 765 }
691 766
692 if (result > 0) 767 if (result > 0)
693 response_body_read_ += result; 768 response_body_read_ += result;
694 769
770 if (result > 0 && read_offset_) {
771 if (result < read_offset_) {
772 read_offset_ -= result;
773 stream_hash_->Update((uint8*)user_read_buf_->data(), result);
774 result = 0;
775 } else {
776 stream_hash_->Update((uint8*)user_read_buf_->data(), read_offset_);
777 memmove(user_read_buf_->data(),
778 user_read_buf_->data() + read_offset_,
779 result - read_offset_);
780 result -= read_offset_;
781 read_offset_ = 0;
782
783 if (stream_hash_->VerifyHash() != OK){
784 io_state_ = STATE_DONE;
785 return ERR_RETRY_HASH_MISMATCH;
786 }
787 }
788
789 if (result == 0) {
790 io_state_ = STATE_READ_BODY;
791 return OK;
792 }
793 } else if (result > 0)
794 stream_hash_->Update((uint8*)user_read_buf_->data(), result);
795
695 if (result <= 0 || IsResponseBodyComplete()) { 796 if (result <= 0 || IsResponseBodyComplete()) {
696 io_state_ = STATE_DONE; 797 io_state_ = STATE_DONE;
697 798
698 // Save the overflow data, which can be in two places. There may be 799 // Save the overflow data, which can be in two places. There may be
699 // some left over in |user_read_buf_|, plus there may be more 800 // some left over in |user_read_buf_|, plus there may be more
700 // in |read_buf_|. But the part left over in |user_read_buf_| must have 801 // in |read_buf_|. But the part left over in |user_read_buf_| must have
701 // come from the |read_buf_|, so there's room to put it back at the 802 // come from the |read_buf_|, so there's room to put it back at the
702 // start first. 803 // start first.
703 int additional_save_amount = read_buf_->offset() - read_buf_unused_offset_; 804 int additional_save_amount = read_buf_->offset() - read_buf_unused_offset_;
704 int save_amount = 0; 805 int save_amount = 0;
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after
901 // it's also a potential response smuggling attack. 1002 // it's also a potential response smuggling attack.
902 if (HeadersContainMultipleCopiesOfField(*headers.get(), 1003 if (HeadersContainMultipleCopiesOfField(*headers.get(),
903 "Content-Disposition")) 1004 "Content-Disposition"))
904 return ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_DISPOSITION; 1005 return ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_DISPOSITION;
905 if (HeadersContainMultipleCopiesOfField(*headers.get(), "Location")) 1006 if (HeadersContainMultipleCopiesOfField(*headers.get(), "Location"))
906 return ERR_RESPONSE_HEADERS_MULTIPLE_LOCATION; 1007 return ERR_RESPONSE_HEADERS_MULTIPLE_LOCATION;
907 1008
908 response_->headers = headers; 1009 response_->headers = headers;
909 response_->connection_info = HttpResponseInfo::CONNECTION_INFO_HTTP1; 1010 response_->connection_info = HttpResponseInfo::CONNECTION_INFO_HTTP1;
910 response_->vary_data.Init(*request_, *response_->headers.get()); 1011 response_->vary_data.Init(*request_, *response_->headers.get());
1012 if (response_->headers->response_code() != 200)
1013 read_offset_ = 0;
911 DVLOG(1) << __FUNCTION__ << "()" 1014 DVLOG(1) << __FUNCTION__ << "()"
912 << " content_length = \"" << response_->headers->GetContentLength() 1015 << " content_length = \"" << response_->headers->GetContentLength()
913 << "\n\"" 1016 << "\n\""
914 << " headers = \"" 1017 << " headers = \""
915 << GetResponseHeaderLines(*response_->headers.get()) << "\""; 1018 << GetResponseHeaderLines(*response_->headers.get()) << "\"";
916 return OK; 1019 return OK;
917 } 1020 }
918 1021
919 void HttpStreamParser::CalculateResponseBodySize() { 1022 void HttpStreamParser::CalculateResponseBodySize() {
920 // Figure how to determine EOF: 1023 // Figure how to determine EOF:
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
988 } 1091 }
989 1092
990 void HttpStreamParser::SetConnectionReused() { 1093 void HttpStreamParser::SetConnectionReused() {
991 connection_->set_reuse_type(ClientSocketHandle::REUSED_IDLE); 1094 connection_->set_reuse_type(ClientSocketHandle::REUSED_IDLE);
992 } 1095 }
993 1096
994 bool HttpStreamParser::IsConnectionReusable() const { 1097 bool HttpStreamParser::IsConnectionReusable() const {
995 return connection_->socket() && connection_->socket()->IsConnectedAndIdle(); 1098 return connection_->socket() && connection_->socket()->IsConnectedAndIdle();
996 } 1099 }
997 1100
1101 void HttpStreamParser::SetRestartInfo(
1102 int64 read_offset, const void* hash, size_t hash_length) {
1103 read_offset_ = read_offset;
1104 stream_hash_->SetPreviousHash(hash, hash_length);
1105 }
1106
1107 void HttpStreamParser::GetHash(void* output, size_t hash_length) {
1108 stream_hash_->Finish(output, hash_length);
1109 }
1110
998 void HttpStreamParser::GetSSLInfo(SSLInfo* ssl_info) { 1111 void HttpStreamParser::GetSSLInfo(SSLInfo* ssl_info) {
999 if (request_->url.SchemeIsSecure() && connection_->socket()) { 1112 if (request_->url.SchemeIsSecure() && connection_->socket()) {
1000 SSLClientSocket* ssl_socket = 1113 SSLClientSocket* ssl_socket =
1001 static_cast<SSLClientSocket*>(connection_->socket()); 1114 static_cast<SSLClientSocket*>(connection_->socket());
1002 ssl_socket->GetSSLInfo(ssl_info); 1115 ssl_socket->GetSSLInfo(ssl_info);
1003 } 1116 }
1004 } 1117 }
1005 1118
1006 void HttpStreamParser::GetSSLCertRequestInfo( 1119 void HttpStreamParser::GetSSLCertRequestInfo(
1007 SSLCertRequestInfo* cert_request_info) { 1120 SSLCertRequestInfo* cert_request_info) {
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
1045 request_body->IsInMemory() && 1158 request_body->IsInMemory() &&
1046 request_body->size() > 0) { 1159 request_body->size() > 0) {
1047 size_t merged_size = request_headers.size() + request_body->size(); 1160 size_t merged_size = request_headers.size() + request_body->size();
1048 if (merged_size <= kMaxMergedHeaderAndBodySize) 1161 if (merged_size <= kMaxMergedHeaderAndBodySize)
1049 return true; 1162 return true;
1050 } 1163 }
1051 return false; 1164 return false;
1052 } 1165 }
1053 1166
1054 } // namespace net 1167 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698