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

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

Issue 40161: Don't read message-body for HEAD responses. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 9 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 | Annotate | Revision Log
« no previous file with comments | « net/http/http_network_transaction.h ('k') | net/http/http_network_transaction_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2008 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_network_transaction.h" 5 #include "net/http/http_network_transaction.h"
6 6
7 #include "base/scoped_ptr.h" 7 #include "base/scoped_ptr.h"
8 #include "base/compiler_specific.h" 8 #include "base/compiler_specific.h"
9 #include "base/string_util.h" 9 #include "base/string_util.h"
10 #include "base/trace_event.h" 10 #include "base/trace_event.h"
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
45 reused_socket_(false), 45 reused_socket_(false),
46 using_ssl_(false), 46 using_ssl_(false),
47 using_proxy_(false), 47 using_proxy_(false),
48 using_tunnel_(false), 48 using_tunnel_(false),
49 establishing_tunnel_(false), 49 establishing_tunnel_(false),
50 request_headers_bytes_sent_(0), 50 request_headers_bytes_sent_(0),
51 header_buf_capacity_(0), 51 header_buf_capacity_(0),
52 header_buf_len_(0), 52 header_buf_len_(0),
53 header_buf_body_offset_(-1), 53 header_buf_body_offset_(-1),
54 header_buf_http_offset_(-1), 54 header_buf_http_offset_(-1),
55 content_length_(-1), // -1 means unspecified. 55 response_body_length_(-1), // -1 means unspecified.
56 content_read_(0), 56 response_body_read_(0),
57 read_buf_len_(0), 57 read_buf_len_(0),
58 next_state_(STATE_NONE) { 58 next_state_(STATE_NONE) {
59 #if defined(OS_WIN) 59 #if defined(OS_WIN)
60 // TODO(port): Port the SSLConfigService class to Linux and Mac OS X. 60 // TODO(port): Port the SSLConfigService class to Linux and Mac OS X.
61 session->ssl_config_service()->GetSSLConfig(&ssl_config_); 61 session->ssl_config_service()->GetSSLConfig(&ssl_config_);
62 #endif 62 #endif
63 } 63 }
64 64
65 int HttpNetworkTransaction::Start(const HttpRequestInfo* request_info, 65 int HttpNetworkTransaction::Start(const HttpRequestInfo* request_info,
66 CompletionCallback* callback) { 66 CompletionCallback* callback) {
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
129 // required yet. 129 // required yet.
130 if (auth_identity_[target].source != HttpAuth::IDENT_SRC_NONE) { 130 if (auth_identity_[target].source != HttpAuth::IDENT_SRC_NONE) {
131 session_->auth_cache()->Add(AuthOrigin(target), auth_handler_[target], 131 session_->auth_cache()->Add(AuthOrigin(target), auth_handler_[target],
132 auth_identity_[target].username, auth_identity_[target].password, 132 auth_identity_[target].username, auth_identity_[target].password,
133 AuthPath(target)); 133 AuthPath(target));
134 } 134 }
135 135
136 bool keep_alive = false; 136 bool keep_alive = false;
137 if (response_.headers->IsKeepAlive()) { 137 if (response_.headers->IsKeepAlive()) {
138 // If there is a response body of known length, we need to drain it first. 138 // If there is a response body of known length, we need to drain it first.
139 if (content_length_ > 0 || chunked_decoder_.get()) { 139 if (response_body_length_ > 0 || chunked_decoder_.get()) {
140 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART; 140 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART;
141 read_buf_ = new IOBuffer(kDrainBodyBufferSize); // A bit bucket 141 read_buf_ = new IOBuffer(kDrainBodyBufferSize); // A bit bucket
142 read_buf_len_ = kDrainBodyBufferSize; 142 read_buf_len_ = kDrainBodyBufferSize;
143 return; 143 return;
144 } 144 }
145 if (content_length_ == 0) // No response body to drain. 145 if (response_body_length_ == 0) // No response body to drain.
146 keep_alive = true; 146 keep_alive = true;
147 // content_length_ is -1 and we're not using chunked encoding. We don't 147 // response_body_length_ is -1 and we're not using chunked encoding. We
148 // know the length of the response body, so we can't reuse this connection 148 // don't know the length of the response body, so we can't reuse this
149 // even though the server says it's keep-alive. 149 // connection even though the server says it's keep-alive.
150 } 150 }
151 151
152 // If the auth scheme is connection-based but the proxy/server mistakenly 152 // If the auth scheme is connection-based but the proxy/server mistakenly
153 // marks the connection as not keep-alive, the auth is going to fail, so log 153 // marks the connection as not keep-alive, the auth is going to fail, so log
154 // an error message. 154 // an error message.
155 if (!keep_alive && auth_handler_[target]->is_connection_based() && 155 if (!keep_alive && auth_handler_[target]->is_connection_based() &&
156 auth_identity_[target].source != HttpAuth::IDENT_SRC_NONE) { 156 auth_identity_[target].source != HttpAuth::IDENT_SRC_NONE) {
157 std::string auth_target(target == HttpAuth::AUTH_PROXY ? 157 std::string auth_target(target == HttpAuth::AUTH_PROXY ?
158 "proxy" : "server"); 158 "proxy" : "server");
159 LOG(ERROR) << "Can't perform " << auth_handler_[target]->scheme() 159 LOG(ERROR) << "Can't perform " << auth_handler_[target]->scheme()
(...skipping 629 matching lines...) Expand 10 before | Expand all | Expand 10 after
789 } 789 }
790 790
791 int HttpNetworkTransaction::DoReadBody() { 791 int HttpNetworkTransaction::DoReadBody() {
792 DCHECK(read_buf_); 792 DCHECK(read_buf_);
793 DCHECK(read_buf_len_ > 0); 793 DCHECK(read_buf_len_ > 0);
794 DCHECK(connection_.is_initialized()); 794 DCHECK(connection_.is_initialized());
795 795
796 next_state_ = STATE_READ_BODY_COMPLETE; 796 next_state_ = STATE_READ_BODY_COMPLETE;
797 797
798 // We may have already consumed the indicated content length. 798 // We may have already consumed the indicated content length.
799 if (content_length_ != -1 && content_read_ >= content_length_) 799 if (response_body_length_ != -1 &&
800 response_body_read_ >= response_body_length_)
800 return 0; 801 return 0;
801 802
802 // We may have some data remaining in the header buffer. 803 // We may have some data remaining in the header buffer.
803 if (header_buf_.get() && header_buf_body_offset_ < header_buf_len_) { 804 if (header_buf_.get() && header_buf_body_offset_ < header_buf_len_) {
804 int n = std::min(read_buf_len_, header_buf_len_ - header_buf_body_offset_); 805 int n = std::min(read_buf_len_, header_buf_len_ - header_buf_body_offset_);
805 memcpy(read_buf_->data(), header_buf_.get() + header_buf_body_offset_, n); 806 memcpy(read_buf_->data(), header_buf_.get() + header_buf_body_offset_, n);
806 header_buf_body_offset_ += n; 807 header_buf_body_offset_ += n;
807 if (header_buf_body_offset_ == header_buf_len_) { 808 if (header_buf_body_offset_ == header_buf_len_) {
808 header_buf_.reset(); 809 header_buf_.reset();
809 header_buf_capacity_ = 0; 810 header_buf_capacity_ = 0;
(...skipping 23 matching lines...) Expand all
833 next_state_ = STATE_READ_BODY; 834 next_state_ = STATE_READ_BODY;
834 return OK; 835 return OK;
835 } 836 }
836 } 837 }
837 838
838 bool done = false, keep_alive = false; 839 bool done = false, keep_alive = false;
839 if (result < 0) { 840 if (result < 0) {
840 // Error while reading the socket. 841 // Error while reading the socket.
841 done = true; 842 done = true;
842 } else { 843 } else {
843 content_read_ += result; 844 response_body_read_ += result;
844 if (unfiltered_eof || 845 if (unfiltered_eof ||
845 (content_length_ != -1 && content_read_ >= content_length_) || 846 (response_body_length_ != -1 &&
847 response_body_read_ >= response_body_length_) ||
846 (chunked_decoder_.get() && chunked_decoder_->reached_eof())) { 848 (chunked_decoder_.get() && chunked_decoder_->reached_eof())) {
847 done = true; 849 done = true;
848 keep_alive = response_.headers->IsKeepAlive(); 850 keep_alive = response_.headers->IsKeepAlive();
849 // We can't reuse the connection if we read more than the advertised 851 // We can't reuse the connection if we read more than the advertised
850 // content length. 852 // content length.
851 if (unfiltered_eof || 853 if (unfiltered_eof ||
852 (content_length_ != -1 && content_read_ > content_length_)) 854 (response_body_length_ != -1 &&
855 response_body_read_ > response_body_length_))
853 keep_alive = false; 856 keep_alive = false;
854 } 857 }
855 } 858 }
856 859
857 // Clean up connection_ if we are done. 860 // Clean up connection_ if we are done.
858 if (done) { 861 if (done) {
859 LogTransactionMetrics(); 862 LogTransactionMetrics();
860 if (!keep_alive) 863 if (!keep_alive)
861 connection_.set_socket(NULL); 864 connection_.set_socket(NULL);
862 connection_.Reset(); 865 connection_.Reset();
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
895 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART; 898 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART;
896 return OK; 899 return OK;
897 } 900 }
898 } 901 }
899 902
900 bool done = false, keep_alive = false; 903 bool done = false, keep_alive = false;
901 if (result < 0) { 904 if (result < 0) {
902 // Error while reading the socket. 905 // Error while reading the socket.
903 done = true; 906 done = true;
904 } else { 907 } else {
905 content_read_ += result; 908 response_body_read_ += result;
906 if (unfiltered_eof || 909 if (unfiltered_eof ||
907 (content_length_ != -1 && content_read_ >= content_length_) || 910 (response_body_length_ != -1 &&
911 response_body_read_ >= response_body_length_) ||
908 (chunked_decoder_.get() && chunked_decoder_->reached_eof())) { 912 (chunked_decoder_.get() && chunked_decoder_->reached_eof())) {
909 done = true; 913 done = true;
910 keep_alive = response_.headers->IsKeepAlive(); 914 keep_alive = response_.headers->IsKeepAlive();
911 // We can't reuse the connection if we read more than the advertised 915 // We can't reuse the connection if we read more than the advertised
912 // content length. 916 // content length.
913 if (unfiltered_eof || 917 if (unfiltered_eof ||
914 (content_length_ != -1 && content_read_ > content_length_)) 918 (response_body_length_ != -1 &&
919 response_body_read_ > response_body_length_))
915 keep_alive = false; 920 keep_alive = false;
916 } 921 }
917 } 922 }
918 923
919 if (done) { 924 if (done) {
920 DidDrainBodyForAuthRestart(keep_alive); 925 DidDrainBodyForAuthRestart(keep_alive);
921 } else { 926 } else {
922 // Keep draining. 927 // Keep draining.
923 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART; 928 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART;
924 } 929 }
925 930
926 return OK; 931 return OK;
927 } 932 }
928 933
929 void HttpNetworkTransaction::LogTransactionMetrics() const { 934 void HttpNetworkTransaction::LogTransactionMetrics() const {
930 base::TimeDelta duration = base::Time::Now() - response_.request_time; 935 base::TimeDelta duration = base::Time::Now() - response_.request_time;
931 if (60 < duration.InMinutes()) 936 if (60 < duration.InMinutes())
932 return; 937 return;
933 UMA_HISTOGRAM_LONG_TIMES("Net.Transaction_Latency", duration); 938 UMA_HISTOGRAM_LONG_TIMES("Net.Transaction_Latency", duration);
934 if (!duration.InMilliseconds()) 939 if (!duration.InMilliseconds())
935 return; 940 return;
936 UMA_HISTOGRAM_COUNTS("Net.Transaction_Bandwidth", 941 UMA_HISTOGRAM_COUNTS("Net.Transaction_Bandwidth",
937 static_cast<int> (content_read_ / duration.InMilliseconds())); 942 static_cast<int> (response_body_read_ / duration.InMilliseconds()));
938 } 943 }
939 944
940 int HttpNetworkTransaction::DidReadResponseHeaders() { 945 int HttpNetworkTransaction::DidReadResponseHeaders() {
941 scoped_refptr<HttpResponseHeaders> headers; 946 scoped_refptr<HttpResponseHeaders> headers;
942 if (has_found_status_line_start()) { 947 if (has_found_status_line_start()) {
943 headers = new HttpResponseHeaders( 948 headers = new HttpResponseHeaders(
944 HttpUtil::AssembleRawHeaders( 949 HttpUtil::AssembleRawHeaders(
945 header_buf_.get(), header_buf_body_offset_)); 950 header_buf_.get(), header_buf_body_offset_));
946 } else { 951 } else {
947 // Fabricate a status line to to preserve the HTTP/0.9 version. 952 // Fabricate a status line to to preserve the HTTP/0.9 version.
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
1016 header_buf_body_offset_ = -1; 1021 header_buf_body_offset_ = -1;
1017 next_state_ = STATE_READ_HEADERS; 1022 next_state_ = STATE_READ_HEADERS;
1018 return OK; 1023 return OK;
1019 } 1024 }
1020 1025
1021 response_.headers = headers; 1026 response_.headers = headers;
1022 response_.vary_data.Init(*request_, *response_.headers); 1027 response_.vary_data.Init(*request_, *response_.headers);
1023 1028
1024 // Figure how to determine EOF: 1029 // Figure how to determine EOF:
1025 1030
1026 // For certain responses, we know the content length is always 0. 1031 // For certain responses, we know the content length is always 0. From
1032 // RFC 2616 Section 4.3 Message Body:
1033 //
1034 // For response messages, whether or not a message-body is included with
1035 // a message is dependent on both the request method and the response
1036 // status code (section 6.1.1). All responses to the HEAD request method
1037 // MUST NOT include a message-body, even though the presence of entity-
1038 // header fields might lead one to believe they do. All 1xx
1039 // (informational), 204 (no content), and 304 (not modified) responses
1040 // MUST NOT include a message-body. All other responses do include a
1041 // message-body, although it MAY be of zero length.
1027 switch (response_.headers->response_code()) { 1042 switch (response_.headers->response_code()) {
1028 case 204: // No Content 1043 case 204: // No Content
1029 case 205: // Reset Content 1044 case 205: // Reset Content
1030 case 304: // Not Modified 1045 case 304: // Not Modified
1031 content_length_ = 0; 1046 response_body_length_ = 0;
1032 break; 1047 break;
1033 } 1048 }
1049 if (request_->method == "HEAD")
1050 response_body_length_ = 0;
1034 1051
1035 if (content_length_ == -1) { 1052 if (response_body_length_ == -1) {
1036 // Ignore spurious chunked responses from HTTP/1.0 servers and proxies. 1053 // Ignore spurious chunked responses from HTTP/1.0 servers and proxies.
1037 // Otherwise "Transfer-Encoding: chunked" trumps "Content-Length: N" 1054 // Otherwise "Transfer-Encoding: chunked" trumps "Content-Length: N"
1038 if (response_.headers->GetHttpVersion() >= HttpVersion(1, 1) && 1055 if (response_.headers->GetHttpVersion() >= HttpVersion(1, 1) &&
1039 response_.headers->HasHeaderValue("Transfer-Encoding", "chunked")) { 1056 response_.headers->HasHeaderValue("Transfer-Encoding", "chunked")) {
1040 chunked_decoder_.reset(new HttpChunkedDecoder()); 1057 chunked_decoder_.reset(new HttpChunkedDecoder());
1041 } else { 1058 } else {
1042 content_length_ = response_.headers->GetContentLength(); 1059 response_body_length_ = response_.headers->GetContentLength();
1043 // If content_length_ is still -1, then we have to wait for the server to 1060 // If response_body_length_ is still -1, then we have to wait for the
1044 // close the connection. 1061 // server to close the connection.
1045 } 1062 }
1046 } 1063 }
1047 1064
1048 int rv = HandleAuthChallenge(); 1065 int rv = HandleAuthChallenge();
1049 if (rv == WILL_RESTART_TRANSACTION) 1066 if (rv == WILL_RESTART_TRANSACTION)
1050 return OK; 1067 return OK;
1051 if (rv != OK) 1068 if (rv != OK)
1052 return rv; 1069 return rv;
1053 1070
1054 if (using_ssl_ && !establishing_tunnel_) { 1071 if (using_ssl_ && !establishing_tunnel_) {
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
1129 } 1146 }
1130 return error; 1147 return error;
1131 } 1148 }
1132 1149
1133 void HttpNetworkTransaction::ResetStateForRestart() { 1150 void HttpNetworkTransaction::ResetStateForRestart() {
1134 header_buf_.reset(); 1151 header_buf_.reset();
1135 header_buf_capacity_ = 0; 1152 header_buf_capacity_ = 0;
1136 header_buf_len_ = 0; 1153 header_buf_len_ = 0;
1137 header_buf_body_offset_ = -1; 1154 header_buf_body_offset_ = -1;
1138 header_buf_http_offset_ = -1; 1155 header_buf_http_offset_ = -1;
1139 content_length_ = -1; 1156 response_body_length_ = -1;
1140 content_read_ = 0; 1157 response_body_read_ = 0;
1141 read_buf_ = NULL; 1158 read_buf_ = NULL;
1142 read_buf_len_ = 0; 1159 read_buf_len_ = 0;
1143 request_headers_.clear(); 1160 request_headers_.clear();
1144 request_headers_bytes_sent_ = 0; 1161 request_headers_bytes_sent_ = 0;
1145 chunked_decoder_.reset(); 1162 chunked_decoder_.reset();
1146 // Reset the scoped_refptr 1163 // Reset the scoped_refptr
1147 response_.headers = NULL; 1164 response_.headers = NULL;
1148 response_.auth_challenge = NULL; 1165 response_.auth_challenge = NULL;
1149 } 1166 }
1150 1167
(...skipping 293 matching lines...) Expand 10 before | Expand all | Expand 10 after
1444 if (target == HttpAuth::AUTH_PROXY) { 1461 if (target == HttpAuth::AUTH_PROXY) {
1445 auth_info->host = ASCIIToWide(proxy_info_.proxy_server().host_and_port()); 1462 auth_info->host = ASCIIToWide(proxy_info_.proxy_server().host_and_port());
1446 } else { 1463 } else {
1447 DCHECK(target == HttpAuth::AUTH_SERVER); 1464 DCHECK(target == HttpAuth::AUTH_SERVER);
1448 auth_info->host = ASCIIToWide(request_->url.host()); 1465 auth_info->host = ASCIIToWide(request_->url.host());
1449 } 1466 }
1450 response_.auth_challenge = auth_info; 1467 response_.auth_challenge = auth_info;
1451 } 1468 }
1452 1469
1453 } // namespace net 1470 } // namespace net
OLDNEW
« no previous file with comments | « net/http/http_network_transaction.h ('k') | net/http/http_network_transaction_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698