OLD | NEW |
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 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
120 DCHECK(auth_identity_[target].source != HttpAuth::IDENT_SRC_PATH_LOOKUP); | 120 DCHECK(auth_identity_[target].source != HttpAuth::IDENT_SRC_PATH_LOOKUP); |
121 | 121 |
122 // Add the auth entry to the cache before restarting. We don't know whether | 122 // Add the auth entry to the cache before restarting. We don't know whether |
123 // the identity is valid yet, but if it is valid we want other transactions | 123 // the identity is valid yet, but if it is valid we want other transactions |
124 // to know about it. If an entry for (origin, handler->realm()) already | 124 // to know about it. If an entry for (origin, handler->realm()) already |
125 // exists, we update it. | 125 // exists, we update it. |
126 session_->auth_cache()->Add(AuthOrigin(target), auth_handler_[target], | 126 session_->auth_cache()->Add(AuthOrigin(target), auth_handler_[target], |
127 auth_identity_[target].username, auth_identity_[target].password, | 127 auth_identity_[target].username, auth_identity_[target].password, |
128 AuthPath(target)); | 128 AuthPath(target)); |
129 | 129 |
130 next_state_ = STATE_INIT_CONNECTION; | 130 bool keep_alive = false; |
131 connection_.set_socket(NULL); | 131 if (response_.headers->IsKeepAlive()) { |
132 connection_.Reset(); | 132 // If there is a response body of known length, we need to drain it first. |
| 133 if (content_length_ > 0 || chunked_decoder_.get()) { |
| 134 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART; |
| 135 read_buf_ = new IOBuffer(kDrainBodyBufferSize); // A bit bucket |
| 136 read_buf_len_ = kDrainBodyBufferSize; |
| 137 return; |
| 138 } |
| 139 if (content_length_ == 0) // No response body to drain. |
| 140 keep_alive = true; |
| 141 // content_length_ is -1 and we're not using chunked encoding. We don't |
| 142 // know the length of the response body, so we can't reuse this connection |
| 143 // even though the server says it's keep-alive. |
| 144 } |
| 145 |
| 146 // We don't need to drain the response body, so we act as if we had drained |
| 147 // the response body. |
| 148 DidDrainBodyForAuthRestart(keep_alive); |
| 149 } |
| 150 |
| 151 void HttpNetworkTransaction::DidDrainBodyForAuthRestart(bool keep_alive) { |
| 152 if (keep_alive) { |
| 153 next_state_ = STATE_WRITE_HEADERS; |
| 154 reused_socket_ = true; |
| 155 } else { |
| 156 next_state_ = STATE_INIT_CONNECTION; |
| 157 connection_.set_socket(NULL); |
| 158 connection_.Reset(); |
| 159 } |
133 | 160 |
134 // Reset the other member variables. | 161 // Reset the other member variables. |
135 ResetStateForRestart(); | 162 ResetStateForRestart(); |
136 } | 163 } |
137 | 164 |
138 int HttpNetworkTransaction::Read(IOBuffer* buf, int buf_len, | 165 int HttpNetworkTransaction::Read(IOBuffer* buf, int buf_len, |
139 CompletionCallback* callback) { | 166 CompletionCallback* callback) { |
140 DCHECK(response_.headers); | 167 DCHECK(response_.headers); |
141 DCHECK(buf); | 168 DCHECK(buf); |
142 DCHECK(buf_len > 0); | 169 DCHECK(buf_len > 0); |
(...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
372 break; | 399 break; |
373 case STATE_READ_BODY: | 400 case STATE_READ_BODY: |
374 DCHECK(rv == OK); | 401 DCHECK(rv == OK); |
375 TRACE_EVENT_BEGIN("http.read_body", request_, request_->url.spec()); | 402 TRACE_EVENT_BEGIN("http.read_body", request_, request_->url.spec()); |
376 rv = DoReadBody(); | 403 rv = DoReadBody(); |
377 break; | 404 break; |
378 case STATE_READ_BODY_COMPLETE: | 405 case STATE_READ_BODY_COMPLETE: |
379 rv = DoReadBodyComplete(rv); | 406 rv = DoReadBodyComplete(rv); |
380 TRACE_EVENT_END("http.read_body", request_, request_->url.spec()); | 407 TRACE_EVENT_END("http.read_body", request_, request_->url.spec()); |
381 break; | 408 break; |
| 409 case STATE_DRAIN_BODY_FOR_AUTH_RESTART: |
| 410 DCHECK(rv == OK); |
| 411 TRACE_EVENT_BEGIN("http.drain_body_for_auth_restart", |
| 412 request_, request_->url.spec()); |
| 413 rv = DoDrainBodyForAuthRestart(); |
| 414 break; |
| 415 case STATE_DRAIN_BODY_FOR_AUTH_RESTART_COMPLETE: |
| 416 rv = DoDrainBodyForAuthRestartComplete(rv); |
| 417 TRACE_EVENT_END("http.drain_body_for_auth_restart", |
| 418 request_, request_->url.spec()); |
| 419 break; |
382 default: | 420 default: |
383 NOTREACHED() << "bad state"; | 421 NOTREACHED() << "bad state"; |
384 rv = ERR_FAILED; | 422 rv = ERR_FAILED; |
385 break; | 423 break; |
386 } | 424 } |
387 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); | 425 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); |
388 | 426 |
389 return rv; | 427 return rv; |
390 } | 428 } |
391 | 429 |
(...skipping 379 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
771 keep_alive = response_.headers->IsKeepAlive(); | 809 keep_alive = response_.headers->IsKeepAlive(); |
772 // We can't reuse the connection if we read more than the advertised | 810 // We can't reuse the connection if we read more than the advertised |
773 // content length, or if the tunnel was not established successfully. | 811 // content length, or if the tunnel was not established successfully. |
774 if (unfiltered_eof || | 812 if (unfiltered_eof || |
775 (content_length_ != -1 && content_read_ > content_length_) || | 813 (content_length_ != -1 && content_read_ > content_length_) || |
776 establishing_tunnel_) | 814 establishing_tunnel_) |
777 keep_alive = false; | 815 keep_alive = false; |
778 } | 816 } |
779 } | 817 } |
780 | 818 |
781 // Clean up the HttpConnection if we are done. | 819 // Clean up connection_ if we are done. |
782 if (done) { | 820 if (done) { |
783 LogTransactionMetrics(); | 821 LogTransactionMetrics(); |
784 if (!keep_alive) | 822 if (!keep_alive) |
785 connection_.set_socket(NULL); | 823 connection_.set_socket(NULL); |
786 connection_.Reset(); | 824 connection_.Reset(); |
787 // The next Read call will return 0 (EOF). | 825 // The next Read call will return 0 (EOF). |
788 } | 826 } |
789 | 827 |
790 // Clear these to avoid leaving around old state. | 828 // Clear these to avoid leaving around old state. |
791 read_buf_ = NULL; | 829 read_buf_ = NULL; |
792 read_buf_len_ = 0; | 830 read_buf_len_ = 0; |
793 | 831 |
794 return result; | 832 return result; |
795 } | 833 } |
796 | 834 |
| 835 int HttpNetworkTransaction::DoDrainBodyForAuthRestart() { |
| 836 // This method differs from DoReadBody only in the next_state_. So we just |
| 837 // call DoReadBody and override the next_state_. Perhaps there is a more |
| 838 // elegant way for these two methods to share code. |
| 839 int rv = DoReadBody(); |
| 840 DCHECK(next_state_ == STATE_READ_BODY_COMPLETE); |
| 841 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART_COMPLETE; |
| 842 return rv; |
| 843 } |
| 844 |
| 845 // TODO(wtc): The first two thirds of this method and the DoReadBodyComplete |
| 846 // method are almost the same. Figure out a good way for these two methods |
| 847 // to share code. |
| 848 int HttpNetworkTransaction::DoDrainBodyForAuthRestartComplete(int result) { |
| 849 bool unfiltered_eof = (result == 0); |
| 850 |
| 851 // Filter incoming data if appropriate. FilterBuf may return an error. |
| 852 if (result > 0 && chunked_decoder_.get()) { |
| 853 result = chunked_decoder_->FilterBuf(read_buf_->data(), result); |
| 854 if (result == 0 && !chunked_decoder_->reached_eof()) { |
| 855 // Don't signal completion of the Read call yet or else it'll look like |
| 856 // we received end-of-file. Wait for more data. |
| 857 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART; |
| 858 return OK; |
| 859 } |
| 860 } |
| 861 |
| 862 bool done = false, keep_alive = false; |
| 863 if (result < 0) { |
| 864 // Error while reading the socket. |
| 865 done = true; |
| 866 } else { |
| 867 content_read_ += result; |
| 868 if (unfiltered_eof || |
| 869 (content_length_ != -1 && content_read_ >= content_length_) || |
| 870 (chunked_decoder_.get() && chunked_decoder_->reached_eof())) { |
| 871 done = true; |
| 872 keep_alive = response_.headers->IsKeepAlive(); |
| 873 // We can't reuse the connection if we read more than the advertised |
| 874 // content length. |
| 875 if (unfiltered_eof || |
| 876 (content_length_ != -1 && content_read_ > content_length_)) |
| 877 keep_alive = false; |
| 878 } |
| 879 } |
| 880 |
| 881 if (done) { |
| 882 DidDrainBodyForAuthRestart(keep_alive); |
| 883 } else { |
| 884 // Keep draining. |
| 885 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART; |
| 886 } |
| 887 |
| 888 return OK; |
| 889 } |
| 890 |
797 void HttpNetworkTransaction::LogTransactionMetrics() const { | 891 void HttpNetworkTransaction::LogTransactionMetrics() const { |
798 base::TimeDelta duration = base::Time::Now() - response_.request_time; | 892 base::TimeDelta duration = base::Time::Now() - response_.request_time; |
799 if (60 < duration.InMinutes()) | 893 if (60 < duration.InMinutes()) |
800 return; | 894 return; |
801 UMA_HISTOGRAM_LONG_TIMES(L"Net.Transaction_Latency", duration); | 895 UMA_HISTOGRAM_LONG_TIMES(L"Net.Transaction_Latency", duration); |
802 if (!duration.InMilliseconds()) | 896 if (!duration.InMilliseconds()) |
803 return; | 897 return; |
804 UMA_HISTOGRAM_COUNTS(L"Net.Transaction_Bandwidth", | 898 UMA_HISTOGRAM_COUNTS(L"Net.Transaction_Bandwidth", |
805 static_cast<int> (content_read_ / duration.InMilliseconds())); | 899 static_cast<int> (content_read_ / duration.InMilliseconds())); |
806 } | 900 } |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
862 header_buf_len_); | 956 header_buf_len_); |
863 } | 957 } |
864 header_buf_body_offset_ = -1; | 958 header_buf_body_offset_ = -1; |
865 next_state_ = STATE_READ_HEADERS; | 959 next_state_ = STATE_READ_HEADERS; |
866 return OK; | 960 return OK; |
867 } | 961 } |
868 | 962 |
869 response_.headers = headers; | 963 response_.headers = headers; |
870 response_.vary_data.Init(*request_, *response_.headers); | 964 response_.vary_data.Init(*request_, *response_.headers); |
871 | 965 |
872 int rv = HandleAuthChallenge(); | |
873 if (rv == WILL_RESTART_TRANSACTION) { | |
874 DCHECK(next_state_ == STATE_INIT_CONNECTION); | |
875 return OK; | |
876 } | |
877 if (rv != OK) | |
878 return rv; | |
879 | |
880 // Figure how to determine EOF: | 966 // Figure how to determine EOF: |
881 | 967 |
882 // For certain responses, we know the content length is always 0. | 968 // For certain responses, we know the content length is always 0. |
883 switch (response_.headers->response_code()) { | 969 switch (response_.headers->response_code()) { |
884 case 204: // No Content | 970 case 204: // No Content |
885 case 205: // Reset Content | 971 case 205: // Reset Content |
886 case 304: // Not Modified | 972 case 304: // Not Modified |
887 content_length_ = 0; | 973 content_length_ = 0; |
888 break; | 974 break; |
889 } | 975 } |
890 | 976 |
891 if (content_length_ == -1) { | 977 if (content_length_ == -1) { |
892 // Ignore spurious chunked responses from HTTP/1.0 servers and proxies. | 978 // Ignore spurious chunked responses from HTTP/1.0 servers and proxies. |
893 // Otherwise "Transfer-Encoding: chunked" trumps "Content-Length: N" | 979 // Otherwise "Transfer-Encoding: chunked" trumps "Content-Length: N" |
894 if (response_.headers->GetHttpVersion() >= HttpVersion(1, 1) && | 980 if (response_.headers->GetHttpVersion() >= HttpVersion(1, 1) && |
895 response_.headers->HasHeaderValue("Transfer-Encoding", "chunked")) { | 981 response_.headers->HasHeaderValue("Transfer-Encoding", "chunked")) { |
896 chunked_decoder_.reset(new HttpChunkedDecoder()); | 982 chunked_decoder_.reset(new HttpChunkedDecoder()); |
897 } else { | 983 } else { |
898 content_length_ = response_.headers->GetContentLength(); | 984 content_length_ = response_.headers->GetContentLength(); |
899 // If content_length_ is still -1, then we have to wait for the server to | 985 // If content_length_ is still -1, then we have to wait for the server to |
900 // close the connection. | 986 // close the connection. |
901 } | 987 } |
902 } | 988 } |
903 | 989 |
| 990 int rv = HandleAuthChallenge(); |
| 991 if (rv == WILL_RESTART_TRANSACTION) |
| 992 return OK; |
| 993 if (rv != OK) |
| 994 return rv; |
| 995 |
904 if (using_ssl_ && !establishing_tunnel_) { | 996 if (using_ssl_ && !establishing_tunnel_) { |
905 SSLClientSocket* ssl_socket = | 997 SSLClientSocket* ssl_socket = |
906 reinterpret_cast<SSLClientSocket*>(connection_.socket()); | 998 reinterpret_cast<SSLClientSocket*>(connection_.socket()); |
907 ssl_socket->GetSSLInfo(&response_.ssl_info); | 999 ssl_socket->GetSSLInfo(&response_.ssl_info); |
908 } | 1000 } |
909 | 1001 |
910 return OK; | 1002 return OK; |
911 } | 1003 } |
912 | 1004 |
913 int HttpNetworkTransaction::HandleCertificateError(int error) { | 1005 int HttpNetworkTransaction::HandleCertificateError(int error) { |
(...skipping 359 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1273 if (target == HttpAuth::AUTH_PROXY) { | 1365 if (target == HttpAuth::AUTH_PROXY) { |
1274 auth_info->host = ASCIIToWide(proxy_info_.proxy_server()); | 1366 auth_info->host = ASCIIToWide(proxy_info_.proxy_server()); |
1275 } else { | 1367 } else { |
1276 DCHECK(target == HttpAuth::AUTH_SERVER); | 1368 DCHECK(target == HttpAuth::AUTH_SERVER); |
1277 auth_info->host = ASCIIToWide(request_->url.host()); | 1369 auth_info->host = ASCIIToWide(request_->url.host()); |
1278 } | 1370 } |
1279 response_.auth_challenge = auth_info; | 1371 response_.auth_challenge = auth_info; |
1280 } | 1372 } |
1281 | 1373 |
1282 } // namespace net | 1374 } // namespace net |
OLD | NEW |