| 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()); | 
|  |