| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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_proxy_client_socket.h" | 5 #include "net/http/http_proxy_client_socket.h" |
| 6 | 6 |
| 7 #include "base/string_util.h" | 7 #include "base/string_util.h" |
| 8 #include "base/stringprintf.h" | 8 #include "base/stringprintf.h" |
| 9 #include "googleurl/src/gurl.h" | 9 #include "googleurl/src/gurl.h" |
| 10 #include "net/base/auth.h" | 10 #include "net/base/auth.h" |
| (...skipping 19 matching lines...) Expand all Loading... |
| 30 const HostPortPair& endpoint, | 30 const HostPortPair& endpoint, |
| 31 const HostPortPair& proxy_server, | 31 const HostPortPair& proxy_server, |
| 32 HttpAuthCache* http_auth_cache, | 32 HttpAuthCache* http_auth_cache, |
| 33 HttpAuthHandlerFactory* http_auth_handler_factory, | 33 HttpAuthHandlerFactory* http_auth_handler_factory, |
| 34 bool tunnel, | 34 bool tunnel, |
| 35 bool using_spdy, | 35 bool using_spdy, |
| 36 bool is_https_proxy) | 36 bool is_https_proxy) |
| 37 : ALLOW_THIS_IN_INITIALIZER_LIST( | 37 : ALLOW_THIS_IN_INITIALIZER_LIST( |
| 38 io_callback_(this, &HttpProxyClientSocket::OnIOComplete)), | 38 io_callback_(this, &HttpProxyClientSocket::OnIOComplete)), |
| 39 next_state_(STATE_NONE), | 39 next_state_(STATE_NONE), |
| 40 old_user_callback_(NULL), | |
| 41 transport_(transport_socket), | 40 transport_(transport_socket), |
| 42 endpoint_(endpoint), | 41 endpoint_(endpoint), |
| 43 auth_(tunnel ? | 42 auth_(tunnel ? |
| 44 new HttpAuthController(HttpAuth::AUTH_PROXY, | 43 new HttpAuthController(HttpAuth::AUTH_PROXY, |
| 45 GURL((is_https_proxy ? "https://" : "http://") | 44 GURL((is_https_proxy ? "https://" : "http://") |
| 46 + proxy_server.ToString()), | 45 + proxy_server.ToString()), |
| 47 http_auth_cache, | 46 http_auth_cache, |
| 48 http_auth_handler_factory) | 47 http_auth_handler_factory) |
| 49 : NULL), | 48 : NULL), |
| 50 tunnel_(tunnel), | 49 tunnel_(tunnel), |
| 51 using_spdy_(using_spdy), | 50 using_spdy_(using_spdy), |
| 52 is_https_proxy_(is_https_proxy), | 51 is_https_proxy_(is_https_proxy), |
| 53 net_log_(transport_socket->socket()->NetLog()) { | 52 net_log_(transport_socket->socket()->NetLog()) { |
| 54 // Synthesize the bits of a request that we actually use. | 53 // Synthesize the bits of a request that we actually use. |
| 55 request_.url = request_url; | 54 request_.url = request_url; |
| 56 request_.method = "GET"; | 55 request_.method = "GET"; |
| 57 if (!user_agent.empty()) | 56 if (!user_agent.empty()) |
| 58 request_.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent, | 57 request_.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent, |
| 59 user_agent); | 58 user_agent); |
| 60 } | 59 } |
| 61 | 60 |
| 62 HttpProxyClientSocket::~HttpProxyClientSocket() { | 61 HttpProxyClientSocket::~HttpProxyClientSocket() { |
| 63 Disconnect(); | 62 Disconnect(); |
| 64 } | 63 } |
| 65 | 64 |
| 66 int HttpProxyClientSocket::RestartWithAuth(OldCompletionCallback* callback) { | 65 int HttpProxyClientSocket::RestartWithAuth(OldCompletionCallback* callback) { |
| 67 DCHECK_EQ(STATE_NONE, next_state_); | 66 DCHECK_EQ(STATE_NONE, next_state_); |
| 68 DCHECK(!old_user_callback_ && user_callback_.is_null()); | 67 DCHECK(user_callback_.is_null()); |
| 69 | 68 |
| 70 int rv = PrepareForAuthRestart(); | 69 int rv = PrepareForAuthRestart(); |
| 71 if (rv != OK || next_state_ == STATE_NONE) | 70 if (rv != OK || next_state_ == STATE_NONE) |
| 72 return rv; | 71 return rv; |
| 73 | 72 |
| 74 rv = DoLoop(OK); | 73 rv = DoLoop(OK); |
| 75 if (rv == ERR_IO_PENDING) | 74 if (rv == ERR_IO_PENDING) |
| 76 old_user_callback_ = callback; | 75 if (callback) { |
| 76 user_callback_ = base::Bind(&OldCompletionCallback::Run<int>, |
| 77 base::Unretained(callback)); |
| 78 } |
| 77 return rv; | 79 return rv; |
| 78 } | 80 } |
| 79 | 81 |
| 80 const | 82 const |
| 81 scoped_refptr<HttpAuthController>& HttpProxyClientSocket::auth_controller() { | 83 scoped_refptr<HttpAuthController>& HttpProxyClientSocket::auth_controller() { |
| 82 return auth_; | 84 return auth_; |
| 83 } | 85 } |
| 84 | 86 |
| 85 const HttpResponseInfo* HttpProxyClientSocket::GetConnectResponseInfo() const { | 87 const HttpResponseInfo* HttpProxyClientSocket::GetConnectResponseInfo() const { |
| 86 return response_.headers ? &response_ : NULL; | 88 return response_.headers ? &response_ : NULL; |
| 87 } | 89 } |
| 88 | 90 |
| 89 HttpStream* HttpProxyClientSocket::CreateConnectResponseStream() { | 91 HttpStream* HttpProxyClientSocket::CreateConnectResponseStream() { |
| 90 return new HttpBasicStream(transport_.release(), | 92 return new HttpBasicStream(transport_.release(), |
| 91 http_stream_parser_.release(), false); | 93 http_stream_parser_.release(), false); |
| 92 } | 94 } |
| 93 | 95 |
| 94 | 96 |
| 95 int HttpProxyClientSocket::Connect(OldCompletionCallback* callback) { | |
| 96 DCHECK(transport_.get()); | |
| 97 DCHECK(transport_->socket()); | |
| 98 DCHECK(!old_user_callback_ && user_callback_.is_null()); | |
| 99 | |
| 100 // TODO(rch): figure out the right way to set up a tunnel with SPDY. | |
| 101 // This approach sends the complete HTTPS request to the proxy | |
| 102 // which allows the proxy to see "private" data. Instead, we should | |
| 103 // create an SSL tunnel to the origin server using the CONNECT method | |
| 104 // inside a single SPDY stream. | |
| 105 if (using_spdy_ || !tunnel_) | |
| 106 next_state_ = STATE_DONE; | |
| 107 if (next_state_ == STATE_DONE) | |
| 108 return OK; | |
| 109 | |
| 110 DCHECK_EQ(STATE_NONE, next_state_); | |
| 111 next_state_ = STATE_GENERATE_AUTH_TOKEN; | |
| 112 | |
| 113 int rv = DoLoop(OK); | |
| 114 if (rv == ERR_IO_PENDING) | |
| 115 old_user_callback_ = callback; | |
| 116 return rv; | |
| 117 } | |
| 118 | |
| 119 int HttpProxyClientSocket::Connect(const CompletionCallback& callback) { | 97 int HttpProxyClientSocket::Connect(const CompletionCallback& callback) { |
| 120 DCHECK(transport_.get()); | 98 DCHECK(transport_.get()); |
| 121 DCHECK(transport_->socket()); | 99 DCHECK(transport_->socket()); |
| 122 DCHECK(!old_user_callback_ && user_callback_.is_null()); | 100 DCHECK(user_callback_.is_null()); |
| 123 | 101 |
| 124 // TODO(rch): figure out the right way to set up a tunnel with SPDY. | 102 // TODO(rch): figure out the right way to set up a tunnel with SPDY. |
| 125 // This approach sends the complete HTTPS request to the proxy | 103 // This approach sends the complete HTTPS request to the proxy |
| 126 // which allows the proxy to see "private" data. Instead, we should | 104 // which allows the proxy to see "private" data. Instead, we should |
| 127 // create an SSL tunnel to the origin server using the CONNECT method | 105 // create an SSL tunnel to the origin server using the CONNECT method |
| 128 // inside a single SPDY stream. | 106 // inside a single SPDY stream. |
| 129 if (using_spdy_ || !tunnel_) | 107 if (using_spdy_ || !tunnel_) |
| 130 next_state_ = STATE_DONE; | 108 next_state_ = STATE_DONE; |
| 131 if (next_state_ == STATE_DONE) | 109 if (next_state_ == STATE_DONE) |
| 132 return OK; | 110 return OK; |
| 133 | 111 |
| 134 DCHECK_EQ(STATE_NONE, next_state_); | 112 DCHECK_EQ(STATE_NONE, next_state_); |
| 135 next_state_ = STATE_GENERATE_AUTH_TOKEN; | 113 next_state_ = STATE_GENERATE_AUTH_TOKEN; |
| 136 | 114 |
| 137 int rv = DoLoop(OK); | 115 int rv = DoLoop(OK); |
| 138 if (rv == ERR_IO_PENDING) | 116 if (rv == ERR_IO_PENDING) |
| 139 user_callback_ = callback; | 117 user_callback_ = callback; |
| 140 return rv; | 118 return rv; |
| 141 } | 119 } |
| 142 | 120 |
| 143 void HttpProxyClientSocket::Disconnect() { | 121 void HttpProxyClientSocket::Disconnect() { |
| 144 if (transport_.get()) | 122 if (transport_.get()) |
| 145 transport_->socket()->Disconnect(); | 123 transport_->socket()->Disconnect(); |
| 146 | 124 |
| 147 // Reset other states to make sure they aren't mistakenly used later. | 125 // Reset other states to make sure they aren't mistakenly used later. |
| 148 // These are the states initialized by Connect(). | 126 // These are the states initialized by Connect(). |
| 149 next_state_ = STATE_NONE; | 127 next_state_ = STATE_NONE; |
| 150 old_user_callback_ = NULL; | |
| 151 user_callback_.Reset(); | 128 user_callback_.Reset(); |
| 152 } | 129 } |
| 153 | 130 |
| 154 bool HttpProxyClientSocket::IsConnected() const { | 131 bool HttpProxyClientSocket::IsConnected() const { |
| 155 return next_state_ == STATE_DONE && transport_->socket()->IsConnected(); | 132 return next_state_ == STATE_DONE && transport_->socket()->IsConnected(); |
| 156 } | 133 } |
| 157 | 134 |
| 158 bool HttpProxyClientSocket::IsConnectedAndIdle() const { | 135 bool HttpProxyClientSocket::IsConnectedAndIdle() const { |
| 159 return next_state_ == STATE_DONE && | 136 return next_state_ == STATE_DONE && |
| 160 transport_->socket()->IsConnectedAndIdle(); | 137 transport_->socket()->IsConnectedAndIdle(); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 206 | 183 |
| 207 base::TimeDelta HttpProxyClientSocket::GetConnectTimeMicros() const { | 184 base::TimeDelta HttpProxyClientSocket::GetConnectTimeMicros() const { |
| 208 if (transport_.get() && transport_->socket()) { | 185 if (transport_.get() && transport_->socket()) { |
| 209 return transport_->socket()->GetConnectTimeMicros(); | 186 return transport_->socket()->GetConnectTimeMicros(); |
| 210 } | 187 } |
| 211 NOTREACHED(); | 188 NOTREACHED(); |
| 212 return base::TimeDelta::FromMicroseconds(-1); | 189 return base::TimeDelta::FromMicroseconds(-1); |
| 213 } | 190 } |
| 214 | 191 |
| 215 int HttpProxyClientSocket::Read(IOBuffer* buf, int buf_len, | 192 int HttpProxyClientSocket::Read(IOBuffer* buf, int buf_len, |
| 216 OldCompletionCallback* callback) { | 193 const CompletionCallback& callback) { |
| 217 DCHECK(!old_user_callback_ && user_callback_.is_null()); | 194 DCHECK(user_callback_.is_null()); |
| 218 if (next_state_ != STATE_DONE) { | 195 if (next_state_ != STATE_DONE) { |
| 219 // We're trying to read the body of the response but we're still trying | 196 // We're trying to read the body of the response but we're still trying |
| 220 // to establish an SSL tunnel through the proxy. We can't read these | 197 // to establish an SSL tunnel through the proxy. We can't read these |
| 221 // bytes when establishing a tunnel because they might be controlled by | |
| 222 // an active network attacker. We don't worry about this for HTTP | |
| 223 // because an active network attacker can already control HTTP sessions. | |
| 224 // We reach this case when the user cancels a 407 proxy auth prompt. | |
| 225 // See http://crbug.com/8473. | |
| 226 DCHECK_EQ(407, response_.headers->response_code()); | |
| 227 LogBlockedTunnelResponse(response_.headers->response_code()); | |
| 228 | |
| 229 return ERR_TUNNEL_CONNECTION_FAILED; | |
| 230 } | |
| 231 | |
| 232 return transport_->socket()->Read(buf, buf_len, callback); | |
| 233 } | |
| 234 int HttpProxyClientSocket::Read(IOBuffer* buf, int buf_len, | |
| 235 const CompletionCallback& callback) { | |
| 236 DCHECK(!old_user_callback_ && user_callback_.is_null()); | |
| 237 if (next_state_ != STATE_DONE) { | |
| 238 // We're trying to read the body of the response but we're still trying | |
| 239 // to establish an SSL tunnel through the proxy. We can't read these | |
| 240 // bytes when establishing a tunnel because they might be controlled by | 198 // bytes when establishing a tunnel because they might be controlled by |
| 241 // an active network attacker. We don't worry about this for HTTP | 199 // an active network attacker. We don't worry about this for HTTP |
| 242 // because an active network attacker can already control HTTP sessions. | 200 // because an active network attacker can already control HTTP sessions. |
| 243 // We reach this case when the user cancels a 407 proxy auth prompt. | 201 // We reach this case when the user cancels a 407 proxy auth prompt. |
| 244 // See http://crbug.com/8473. | 202 // See http://crbug.com/8473. |
| 245 DCHECK_EQ(407, response_.headers->response_code()); | 203 DCHECK_EQ(407, response_.headers->response_code()); |
| 246 LogBlockedTunnelResponse(response_.headers->response_code()); | 204 LogBlockedTunnelResponse(response_.headers->response_code()); |
| 247 | 205 |
| 248 return ERR_TUNNEL_CONNECTION_FAILED; | 206 return ERR_TUNNEL_CONNECTION_FAILED; |
| 249 } | 207 } |
| 250 | 208 |
| 251 return transport_->socket()->Read(buf, buf_len, callback); | 209 return transport_->socket()->Read(buf, buf_len, callback); |
| 252 } | 210 } |
| 253 | 211 |
| 254 int HttpProxyClientSocket::Write(IOBuffer* buf, int buf_len, | 212 int HttpProxyClientSocket::Write(IOBuffer* buf, int buf_len, |
| 255 OldCompletionCallback* callback) { | 213 const CompletionCallback& callback) { |
| 256 DCHECK_EQ(STATE_DONE, next_state_); | 214 DCHECK_EQ(STATE_DONE, next_state_); |
| 257 DCHECK(!old_user_callback_); | 215 DCHECK(user_callback_.is_null()); |
| 258 | 216 |
| 259 return transport_->socket()->Write(buf, buf_len, callback); | 217 return transport_->socket()->Write(buf, buf_len, callback); |
| 260 } | 218 } |
| 261 | 219 |
| 262 bool HttpProxyClientSocket::SetReceiveBufferSize(int32 size) { | 220 bool HttpProxyClientSocket::SetReceiveBufferSize(int32 size) { |
| 263 return transport_->socket()->SetReceiveBufferSize(size); | 221 return transport_->socket()->SetReceiveBufferSize(size); |
| 264 } | 222 } |
| 265 | 223 |
| 266 bool HttpProxyClientSocket::SetSendBufferSize(int32 size) { | 224 bool HttpProxyClientSocket::SetSendBufferSize(int32 size) { |
| 267 return transport_->socket()->SetSendBufferSize(size); | 225 return transport_->socket()->SetSendBufferSize(size); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 314 } | 272 } |
| 315 | 273 |
| 316 void HttpProxyClientSocket::LogBlockedTunnelResponse(int response_code) const { | 274 void HttpProxyClientSocket::LogBlockedTunnelResponse(int response_code) const { |
| 317 LOG(WARNING) << "Blocked proxy response with status " << response_code | 275 LOG(WARNING) << "Blocked proxy response with status " << response_code |
| 318 << " to CONNECT request for " | 276 << " to CONNECT request for " |
| 319 << GetHostAndPort(request_.url) << "."; | 277 << GetHostAndPort(request_.url) << "."; |
| 320 } | 278 } |
| 321 | 279 |
| 322 void HttpProxyClientSocket::DoCallback(int result) { | 280 void HttpProxyClientSocket::DoCallback(int result) { |
| 323 DCHECK_NE(ERR_IO_PENDING, result); | 281 DCHECK_NE(ERR_IO_PENDING, result); |
| 324 DCHECK(old_user_callback_ || !user_callback_.is_null()); | 282 DCHECK(!user_callback_.is_null()); |
| 325 | 283 |
| 326 // Since Run() may result in Read being called, | 284 // Since Run() may result in Read being called, |
| 327 // clear old_user_callback_ up front. | 285 // clear user_callback_ up front. |
| 328 if (old_user_callback_) { | 286 CompletionCallback c = user_callback_; |
| 329 OldCompletionCallback* c = old_user_callback_; | 287 user_callback_.Reset(); |
| 330 old_user_callback_ = NULL; | 288 c.Run(result); |
| 331 c->Run(result); | |
| 332 } else { | |
| 333 CompletionCallback c = user_callback_; | |
| 334 user_callback_.Reset(); | |
| 335 c.Run(result); | |
| 336 } | |
| 337 } | 289 } |
| 338 | 290 |
| 339 void HttpProxyClientSocket::OnIOComplete(int result) { | 291 void HttpProxyClientSocket::OnIOComplete(int result) { |
| 340 DCHECK_NE(STATE_NONE, next_state_); | 292 DCHECK_NE(STATE_NONE, next_state_); |
| 341 DCHECK_NE(STATE_DONE, next_state_); | 293 DCHECK_NE(STATE_DONE, next_state_); |
| 342 int rv = DoLoop(result); | 294 int rv = DoLoop(result); |
| 343 if (rv != ERR_IO_PENDING) | 295 if (rv != ERR_IO_PENDING) |
| 344 DoCallback(rv); | 296 DoCallback(rv); |
| 345 } | 297 } |
| 346 | 298 |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 516 | 468 |
| 517 if (http_stream_parser_->IsResponseBodyComplete()) | 469 if (http_stream_parser_->IsResponseBodyComplete()) |
| 518 return DidDrainBodyForAuthRestart(true); | 470 return DidDrainBodyForAuthRestart(true); |
| 519 | 471 |
| 520 // Keep draining. | 472 // Keep draining. |
| 521 next_state_ = STATE_DRAIN_BODY; | 473 next_state_ = STATE_DRAIN_BODY; |
| 522 return OK; | 474 return OK; |
| 523 } | 475 } |
| 524 | 476 |
| 525 } // namespace net | 477 } // namespace net |
| OLD | NEW |