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

Unified 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 side-by-side diff with in-line comments
Download patch
« 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 »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: net/http/http_network_transaction.cc
===================================================================
--- net/http/http_network_transaction.cc (revision 9963)
+++ net/http/http_network_transaction.cc (working copy)
@@ -127,10 +127,37 @@
auth_identity_[target].username, auth_identity_[target].password,
AuthPath(target));
- next_state_ = STATE_INIT_CONNECTION;
- connection_.set_socket(NULL);
- connection_.Reset();
+ bool keep_alive = false;
+ if (response_.headers->IsKeepAlive()) {
+ // If there is a response body of known length, we need to drain it first.
+ if (content_length_ > 0 || chunked_decoder_.get()) {
+ next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART;
+ read_buf_ = new IOBuffer(kDrainBodyBufferSize); // A bit bucket
+ read_buf_len_ = kDrainBodyBufferSize;
+ return;
+ }
+ if (content_length_ == 0) // No response body to drain.
+ keep_alive = true;
+ // content_length_ is -1 and we're not using chunked encoding. We don't
+ // know the length of the response body, so we can't reuse this connection
+ // even though the server says it's keep-alive.
+ }
+ // We don't need to drain the response body, so we act as if we had drained
+ // the response body.
+ DidDrainBodyForAuthRestart(keep_alive);
+}
+
+void HttpNetworkTransaction::DidDrainBodyForAuthRestart(bool keep_alive) {
+ if (keep_alive) {
+ next_state_ = STATE_WRITE_HEADERS;
+ reused_socket_ = true;
+ } else {
+ next_state_ = STATE_INIT_CONNECTION;
+ connection_.set_socket(NULL);
+ connection_.Reset();
+ }
+
// Reset the other member variables.
ResetStateForRestart();
}
@@ -379,6 +406,17 @@
rv = DoReadBodyComplete(rv);
TRACE_EVENT_END("http.read_body", request_, request_->url.spec());
break;
+ case STATE_DRAIN_BODY_FOR_AUTH_RESTART:
+ DCHECK(rv == OK);
+ TRACE_EVENT_BEGIN("http.drain_body_for_auth_restart",
+ request_, request_->url.spec());
+ rv = DoDrainBodyForAuthRestart();
+ break;
+ case STATE_DRAIN_BODY_FOR_AUTH_RESTART_COMPLETE:
+ rv = DoDrainBodyForAuthRestartComplete(rv);
+ TRACE_EVENT_END("http.drain_body_for_auth_restart",
+ request_, request_->url.spec());
+ break;
default:
NOTREACHED() << "bad state";
rv = ERR_FAILED;
@@ -778,7 +816,7 @@
}
}
- // Clean up the HttpConnection if we are done.
+ // Clean up connection_ if we are done.
if (done) {
LogTransactionMetrics();
if (!keep_alive)
@@ -794,6 +832,62 @@
return result;
}
+int HttpNetworkTransaction::DoDrainBodyForAuthRestart() {
+ // This method differs from DoReadBody only in the next_state_. So we just
+ // call DoReadBody and override the next_state_. Perhaps there is a more
+ // elegant way for these two methods to share code.
+ int rv = DoReadBody();
+ DCHECK(next_state_ == STATE_READ_BODY_COMPLETE);
+ next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART_COMPLETE;
+ return rv;
+}
+
+// TODO(wtc): The first two thirds of this method and the DoReadBodyComplete
+// method are almost the same. Figure out a good way for these two methods
+// to share code.
+int HttpNetworkTransaction::DoDrainBodyForAuthRestartComplete(int result) {
+ bool unfiltered_eof = (result == 0);
+
+ // Filter incoming data if appropriate. FilterBuf may return an error.
+ if (result > 0 && chunked_decoder_.get()) {
+ result = chunked_decoder_->FilterBuf(read_buf_->data(), result);
+ if (result == 0 && !chunked_decoder_->reached_eof()) {
+ // Don't signal completion of the Read call yet or else it'll look like
+ // we received end-of-file. Wait for more data.
+ next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART;
+ return OK;
+ }
+ }
+
+ bool done = false, keep_alive = false;
+ if (result < 0) {
+ // Error while reading the socket.
+ done = true;
+ } else {
+ content_read_ += result;
+ if (unfiltered_eof ||
+ (content_length_ != -1 && content_read_ >= content_length_) ||
+ (chunked_decoder_.get() && chunked_decoder_->reached_eof())) {
+ done = true;
+ keep_alive = response_.headers->IsKeepAlive();
+ // We can't reuse the connection if we read more than the advertised
+ // content length.
+ if (unfiltered_eof ||
+ (content_length_ != -1 && content_read_ > content_length_))
+ keep_alive = false;
+ }
+ }
+
+ if (done) {
+ DidDrainBodyForAuthRestart(keep_alive);
+ } else {
+ // Keep draining.
+ next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART;
+ }
+
+ return OK;
+}
+
void HttpNetworkTransaction::LogTransactionMetrics() const {
base::TimeDelta duration = base::Time::Now() - response_.request_time;
if (60 < duration.InMinutes())
@@ -869,14 +963,6 @@
response_.headers = headers;
response_.vary_data.Init(*request_, *response_.headers);
- int rv = HandleAuthChallenge();
- if (rv == WILL_RESTART_TRANSACTION) {
- DCHECK(next_state_ == STATE_INIT_CONNECTION);
- return OK;
- }
- if (rv != OK)
- return rv;
-
// Figure how to determine EOF:
// For certain responses, we know the content length is always 0.
@@ -901,6 +987,12 @@
}
}
+ int rv = HandleAuthChallenge();
+ if (rv == WILL_RESTART_TRANSACTION)
+ return OK;
+ if (rv != OK)
+ return rv;
+
if (using_ssl_ && !establishing_tunnel_) {
SSLClientSocket* ssl_socket =
reinterpret_cast<SSLClientSocket*>(connection_.socket());
« 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