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

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

Issue 21433: Perform HTTP authentication over a keep-alive connection.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Last upload before checkin Created 11 years, 10 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 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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
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
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
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