Chromium Code Reviews| Index: net/socket_stream/socket_stream.cc |
| diff --git a/net/socket_stream/socket_stream.cc b/net/socket_stream/socket_stream.cc |
| index a90aca6fed0eb4400af67c5f8de910a9b4c2ceda..d243fa9b88b6ff3dd09905082a3a28327c4b588d 100644 |
| --- a/net/socket_stream/socket_stream.cc |
| +++ b/net/socket_stream/socket_stream.cc |
| @@ -13,6 +13,7 @@ |
| #include "base/logging.h" |
| #include "base/message_loop.h" |
| #include "base/string_util.h" |
| +#include "net/base/auth.h" |
| #include "net/base/host_resolver.h" |
| #include "net/base/io_buffer.h" |
| #include "net/base/net_errors.h" |
| @@ -149,6 +150,31 @@ void SocketStream::Close() { |
| NewRunnableMethod(this, &SocketStream::DoLoop, OK)); |
| } |
| +void SocketStream::RestartWithAuth( |
| + const std::wstring& username, const std::wstring& password) { |
| + DCHECK(MessageLoop::current()) << |
| + "The current MessageLoop must exist"; |
| + DCHECK_EQ(MessageLoop::TYPE_IO, MessageLoop::current()->type()) << |
| + "The current MessageLoop must be TYPE_IO"; |
| + DCHECK(auth_handler_); |
| + if (!socket_.get()) { |
| + LOG(ERROR) << "Socket is closed before restarting with auth."; |
| + return; |
| + } |
| + |
| + if (auth_identity_.invalid) { |
| + // Update the username/password. |
| + auth_identity_.source = HttpAuth::IDENT_SRC_EXTERNAL; |
| + auth_identity_.invalid = false; |
| + auth_identity_.username = username; |
| + auth_identity_.password = password; |
| + } |
| + |
| + MessageLoop::current()->PostTask( |
| + FROM_HERE, |
| + NewRunnableMethod(this, &SocketStream::DoRestartWithAuth)); |
| +} |
| + |
| void SocketStream::DetachDelegate() { |
| if (!delegate_) |
| return; |
| @@ -161,6 +187,7 @@ void SocketStream::Finish() { |
| "The current MessageLoop must exist"; |
| DCHECK_EQ(MessageLoop::TYPE_IO, MessageLoop::current()->type()) << |
| "The current MessageLoop must be TYPE_IO"; |
| + DLOG(INFO) << "Finish"; |
| Delegate* delegate = delegate_; |
| delegate_ = NULL; |
| if (delegate) { |
| @@ -205,7 +232,7 @@ void SocketStream::DidReceiveData(int result) { |
| void SocketStream::DidSendData(int result) { |
| current_write_buf_ = NULL; |
| - DCHECK(result > 0); |
| + DCHECK_GT(result, 0); |
| if (!delegate_) |
| return; |
| @@ -378,6 +405,7 @@ int SocketStream::DoResolveHost() { |
| int SocketStream::DoResolveHostComplete(int result) { |
| if (result == OK) |
| next_state_ = STATE_TCP_CONNECT; |
| + // TODO(ukai): if error occured, reconsider proxy after error. |
| return result; |
| } |
| @@ -389,6 +417,7 @@ int SocketStream::DoTcpConnect() { |
| } |
| int SocketStream::DoTcpConnectComplete(int result) { |
| + // TODO(ukai): if error occured, reconsider proxy after error. |
| if (result != OK) |
| return result; |
| @@ -414,13 +443,43 @@ int SocketStream::DoWriteTunnelHeaders() { |
| tunnel_request_headers_bytes_sent_ = 0; |
| } |
| if (tunnel_request_headers_->headers_.empty()) { |
| + std::string authorization_headers; |
| + |
| + if (!auth_handler_.get()) { |
| + // First attempt. Find auth from the proxy address. |
| + HttpAuthCache::Entry* entry = auth_cache_.LookupByPath( |
| + ProxyAuthOrigin(), std::string()); |
| + if (entry && !entry->handler()->is_connection_based()) { |
| + auth_identity_.source = HttpAuth::IDENT_SRC_PATH_LOOKUP; |
| + auth_identity_.invalid = false; |
| + auth_identity_.username = entry->username(); |
| + auth_identity_.password = entry->password(); |
| + auth_handler_ = entry->handler(); |
| + } |
| + } |
| + |
| + // Support basic authentication scheme only, because we don't have |
| + // HttpRequestInfo. |
| + // TODO(ukai): Add support other authentication scheme. |
| + if (auth_handler_.get() && auth_handler_->scheme() == "basic") { |
| + std::string credentials = auth_handler_->GenerateCredentials( |
| + auth_identity_.username, |
| + auth_identity_.password, |
| + NULL, |
| + &proxy_info_); |
| + authorization_headers.append( |
| + HttpAuth::GetAuthorizationHeaderName(HttpAuth::AUTH_PROXY) + |
| + ": " + credentials + "\r\n"); |
| + } |
| + |
| tunnel_request_headers_->headers_ = StringPrintf( |
| "CONNECT %s HTTP/1.1\r\n" |
| "Host: %s\r\n" |
| "Proxy-Connection: keep-alive\r\n", |
| GetHostAndPort(url_).c_str(), |
| GetHostAndOptionalPort(url_).c_str()); |
| - // TODO(ukai): set proxy auth if necessary. |
| + if (!authorization_headers.empty()) |
| + tunnel_request_headers_->headers_ += authorization_headers; |
| tunnel_request_headers_->headers_ += "\r\n"; |
| } |
| tunnel_request_headers_->SetDataOffset(tunnel_request_headers_bytes_sent_); |
| @@ -511,8 +570,21 @@ int SocketStream::DoReadTunnelHeadersComplete(int result) { |
| } |
| return OK; |
| case 407: // Proxy Authentication Required. |
| - // TODO(ukai): handle Proxy Authentication. |
| - break; |
| + result = HandleAuthChallenge(headers.get()); |
| + if (result == ERR_PROXY_AUTH_REQUESTED && |
| + auth_handler_.get() && delegate_) { |
| + auth_info_ = new AuthChallengeInfo; |
| + auth_info_->is_proxy = true; |
| + auth_info_->host_and_port = |
| + ASCIIToWide(proxy_info_.proxy_server().host_and_port()); |
| + auth_info_->scheme = ASCIIToWide(auth_handler_->scheme()); |
| + auth_info_->realm = ASCIIToWide(auth_handler_->realm()); |
| + // Wait until RestartWithAuth or Close is called. |
| + MessageLoop::current()->PostTask( |
| + FROM_HERE, |
| + NewRunnableMethod(this, &SocketStream::DoAuthRequired)); |
| + return ERR_IO_PENDING; |
| + } |
| default: |
| break; |
| } |
| @@ -615,6 +687,80 @@ int SocketStream::DoReadWrite(int result) { |
| return ERR_IO_PENDING; |
| } |
| +GURL SocketStream::ProxyAuthOrigin() const { |
| + return GURL("http://" + proxy_info_.proxy_server().host_and_port()); |
| +} |
| + |
| +int SocketStream::HandleAuthChallenge(const HttpResponseHeaders* headers) { |
| + GURL auth_origin(ProxyAuthOrigin()); |
| + |
| + LOG(INFO) << "The proxy " << auth_origin << " requested auth"; |
| + |
| + // The auth we tried just failed, hence it can't be valid. |
| + // Remove it from the cache so it won't be used again. |
| + if (auth_handler_.get() && !auth_identity_.invalid && |
| + auth_handler_->IsFinalRound()) { |
| + if (auth_identity_.source != HttpAuth::IDENT_SRC_PATH_LOOKUP) |
| + auth_cache_.Remove(auth_origin, |
| + auth_handler_->realm(), |
| + auth_identity_.username, |
| + auth_identity_.password); |
| + auth_handler_ = NULL; |
| + auth_identity_ = HttpAuth::Identity(); |
| + } |
| + |
| + auth_identity_.invalid = true; |
| + HttpAuth::ChooseBestChallenge(headers, HttpAuth::AUTH_PROXY, auth_origin, |
| + &auth_handler_); |
| + if (!auth_handler_) { |
| + LOG(ERROR) << "Can't perform auth to the proxy " << auth_origin; |
| + return ERR_TUNNEL_CONNECTION_FAILED; |
| + } |
| + if (auth_handler_->NeedsIdentity()) { |
| + HttpAuthCache::Entry* entry = auth_cache_.LookupByRealm( |
| + auth_origin, auth_handler_->realm()); |
| + if (entry) { |
| + if (entry->handler()->scheme() != "basic") { |
| + // We only support basic authentication scheme now. |
| + // TODO(ukai): Support other authentication scheme. |
| + return ERR_TUNNEL_CONNECTION_FAILED; |
| + } |
| + auth_identity_.source = HttpAuth::IDENT_SRC_REALM_LOOKUP; |
| + auth_identity_.invalid = false; |
| + auth_identity_.username = entry->username(); |
| + auth_identity_.password = entry->password(); |
| + // Restart with auth info. |
| + } |
| + return ERR_PROXY_AUTH_REQUESTED; |
| + } else { |
| + auth_identity_.invalid = false; |
| + } |
| + return ERR_TUNNEL_CONNECTION_FAILED; |
| +} |
| + |
| +void SocketStream::DoAuthRequired() { |
| + if (delegate_ && auth_info_.get()) |
| + delegate_->OnAuthRequired(this, auth_info_.get()); |
| + else |
| + DoLoop(net::ERR_UNEXPECTED); |
| +} |
| + |
| +void SocketStream::DoRestartWithAuth() { |
| + auth_cache_.Add(ProxyAuthOrigin(), auth_handler_, |
| + auth_identity_.username, auth_identity_.password, |
| + std::string()); |
| + |
| + tunnel_request_headers_ = NULL; |
| + tunnel_request_headers_bytes_sent_ = 0; |
| + tunnel_response_headers_ = NULL; |
| + tunnel_response_headers_capacity_ = 0; |
| + tunnel_response_headers_len_ = 0; |
| + |
| + next_state_ = STATE_TCP_CONNECT; |
| + DoLoop(OK); |
| + return; |
|
tyoshino (SeeGerritForStatus)
2009/10/27 09:25:33
remove
|
| +} |
| + |
| int SocketStream::HandleCertificateError(int result) { |
| // TODO(ukai): handle cert error properly. |
| switch (result) { |