| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "net/http/http_proxy_client_socket.h" | |
| 6 | |
| 7 #include "base/bind.h" | |
| 8 #include "base/bind_helpers.h" | |
| 9 #include "base/strings/string_util.h" | |
| 10 #include "base/strings/stringprintf.h" | |
| 11 #include "net/base/auth.h" | |
| 12 #include "net/base/host_port_pair.h" | |
| 13 #include "net/base/io_buffer.h" | |
| 14 #include "net/base/net_log.h" | |
| 15 #include "net/base/net_util.h" | |
| 16 #include "net/base/proxy_delegate.h" | |
| 17 #include "net/http/http_basic_stream.h" | |
| 18 #include "net/http/http_network_session.h" | |
| 19 #include "net/http/http_request_info.h" | |
| 20 #include "net/http/http_response_headers.h" | |
| 21 #include "net/http/http_stream_parser.h" | |
| 22 #include "net/http/proxy_connect_redirect_http_stream.h" | |
| 23 #include "net/socket/client_socket_handle.h" | |
| 24 #include "url/gurl.h" | |
| 25 | |
| 26 namespace net { | |
| 27 | |
| 28 HttpProxyClientSocket::HttpProxyClientSocket( | |
| 29 ClientSocketHandle* transport_socket, | |
| 30 const GURL& request_url, | |
| 31 const std::string& user_agent, | |
| 32 const HostPortPair& endpoint, | |
| 33 const HostPortPair& proxy_server, | |
| 34 HttpAuthCache* http_auth_cache, | |
| 35 HttpAuthHandlerFactory* http_auth_handler_factory, | |
| 36 bool tunnel, | |
| 37 bool using_spdy, | |
| 38 NextProto protocol_negotiated, | |
| 39 ProxyDelegate* proxy_delegate, | |
| 40 bool is_https_proxy) | |
| 41 : io_callback_(base::Bind(&HttpProxyClientSocket::OnIOComplete, | |
| 42 base::Unretained(this))), | |
| 43 next_state_(STATE_NONE), | |
| 44 transport_(transport_socket), | |
| 45 endpoint_(endpoint), | |
| 46 auth_(tunnel ? | |
| 47 new HttpAuthController(HttpAuth::AUTH_PROXY, | |
| 48 GURL((is_https_proxy ? "https://" : "http://") | |
| 49 + proxy_server.ToString()), | |
| 50 http_auth_cache, | |
| 51 http_auth_handler_factory) | |
| 52 : NULL), | |
| 53 tunnel_(tunnel), | |
| 54 using_spdy_(using_spdy), | |
| 55 protocol_negotiated_(protocol_negotiated), | |
| 56 is_https_proxy_(is_https_proxy), | |
| 57 redirect_has_load_timing_info_(false), | |
| 58 proxy_server_(proxy_server), | |
| 59 proxy_delegate_(proxy_delegate), | |
| 60 net_log_(transport_socket->socket()->NetLog()) { | |
| 61 // Synthesize the bits of a request that we actually use. | |
| 62 request_.url = request_url; | |
| 63 request_.method = "GET"; | |
| 64 if (!user_agent.empty()) | |
| 65 request_.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent, | |
| 66 user_agent); | |
| 67 } | |
| 68 | |
| 69 HttpProxyClientSocket::~HttpProxyClientSocket() { | |
| 70 Disconnect(); | |
| 71 } | |
| 72 | |
| 73 int HttpProxyClientSocket::RestartWithAuth(const CompletionCallback& callback) { | |
| 74 DCHECK_EQ(STATE_NONE, next_state_); | |
| 75 DCHECK(user_callback_.is_null()); | |
| 76 | |
| 77 int rv = PrepareForAuthRestart(); | |
| 78 if (rv != OK) | |
| 79 return rv; | |
| 80 | |
| 81 rv = DoLoop(OK); | |
| 82 if (rv == ERR_IO_PENDING) { | |
| 83 if (!callback.is_null()) | |
| 84 user_callback_ = callback; | |
| 85 } | |
| 86 | |
| 87 return rv; | |
| 88 } | |
| 89 | |
| 90 const scoped_refptr<HttpAuthController>& | |
| 91 HttpProxyClientSocket::GetAuthController() const { | |
| 92 return auth_; | |
| 93 } | |
| 94 | |
| 95 bool HttpProxyClientSocket::IsUsingSpdy() const { | |
| 96 return using_spdy_; | |
| 97 } | |
| 98 | |
| 99 NextProto HttpProxyClientSocket::GetProtocolNegotiated() const { | |
| 100 return protocol_negotiated_; | |
| 101 } | |
| 102 | |
| 103 const HttpResponseInfo* HttpProxyClientSocket::GetConnectResponseInfo() const { | |
| 104 return response_.headers.get() ? &response_ : NULL; | |
| 105 } | |
| 106 | |
| 107 HttpStream* HttpProxyClientSocket::CreateConnectResponseStream() { | |
| 108 return new ProxyConnectRedirectHttpStream( | |
| 109 redirect_has_load_timing_info_ ? &redirect_load_timing_info_ : NULL); | |
| 110 } | |
| 111 | |
| 112 | |
| 113 int HttpProxyClientSocket::Connect(const CompletionCallback& callback) { | |
| 114 DCHECK(transport_.get()); | |
| 115 DCHECK(transport_->socket()); | |
| 116 DCHECK(user_callback_.is_null()); | |
| 117 | |
| 118 // TODO(rch): figure out the right way to set up a tunnel with SPDY. | |
| 119 // This approach sends the complete HTTPS request to the proxy | |
| 120 // which allows the proxy to see "private" data. Instead, we should | |
| 121 // create an SSL tunnel to the origin server using the CONNECT method | |
| 122 // inside a single SPDY stream. | |
| 123 if (using_spdy_ || !tunnel_) | |
| 124 next_state_ = STATE_DONE; | |
| 125 if (next_state_ == STATE_DONE) | |
| 126 return OK; | |
| 127 | |
| 128 DCHECK_EQ(STATE_NONE, next_state_); | |
| 129 next_state_ = STATE_GENERATE_AUTH_TOKEN; | |
| 130 | |
| 131 int rv = DoLoop(OK); | |
| 132 if (rv == ERR_IO_PENDING) | |
| 133 user_callback_ = callback; | |
| 134 return rv; | |
| 135 } | |
| 136 | |
| 137 void HttpProxyClientSocket::Disconnect() { | |
| 138 if (transport_.get()) | |
| 139 transport_->socket()->Disconnect(); | |
| 140 | |
| 141 // Reset other states to make sure they aren't mistakenly used later. | |
| 142 // These are the states initialized by Connect(). | |
| 143 next_state_ = STATE_NONE; | |
| 144 user_callback_.Reset(); | |
| 145 } | |
| 146 | |
| 147 bool HttpProxyClientSocket::IsConnected() const { | |
| 148 return next_state_ == STATE_DONE && transport_->socket()->IsConnected(); | |
| 149 } | |
| 150 | |
| 151 bool HttpProxyClientSocket::IsConnectedAndIdle() const { | |
| 152 return next_state_ == STATE_DONE && | |
| 153 transport_->socket()->IsConnectedAndIdle(); | |
| 154 } | |
| 155 | |
| 156 const BoundNetLog& HttpProxyClientSocket::NetLog() const { | |
| 157 return net_log_; | |
| 158 } | |
| 159 | |
| 160 void HttpProxyClientSocket::SetSubresourceSpeculation() { | |
| 161 if (transport_.get() && transport_->socket()) { | |
| 162 transport_->socket()->SetSubresourceSpeculation(); | |
| 163 } else { | |
| 164 NOTREACHED(); | |
| 165 } | |
| 166 } | |
| 167 | |
| 168 void HttpProxyClientSocket::SetOmniboxSpeculation() { | |
| 169 if (transport_.get() && transport_->socket()) { | |
| 170 transport_->socket()->SetOmniboxSpeculation(); | |
| 171 } else { | |
| 172 NOTREACHED(); | |
| 173 } | |
| 174 } | |
| 175 | |
| 176 bool HttpProxyClientSocket::WasEverUsed() const { | |
| 177 if (transport_.get() && transport_->socket()) { | |
| 178 return transport_->socket()->WasEverUsed(); | |
| 179 } | |
| 180 NOTREACHED(); | |
| 181 return false; | |
| 182 } | |
| 183 | |
| 184 bool HttpProxyClientSocket::UsingTCPFastOpen() const { | |
| 185 if (transport_.get() && transport_->socket()) { | |
| 186 return transport_->socket()->UsingTCPFastOpen(); | |
| 187 } | |
| 188 NOTREACHED(); | |
| 189 return false; | |
| 190 } | |
| 191 | |
| 192 bool HttpProxyClientSocket::WasNpnNegotiated() const { | |
| 193 if (transport_.get() && transport_->socket()) { | |
| 194 return transport_->socket()->WasNpnNegotiated(); | |
| 195 } | |
| 196 NOTREACHED(); | |
| 197 return false; | |
| 198 } | |
| 199 | |
| 200 NextProto HttpProxyClientSocket::GetNegotiatedProtocol() const { | |
| 201 if (transport_.get() && transport_->socket()) { | |
| 202 return transport_->socket()->GetNegotiatedProtocol(); | |
| 203 } | |
| 204 NOTREACHED(); | |
| 205 return kProtoUnknown; | |
| 206 } | |
| 207 | |
| 208 bool HttpProxyClientSocket::GetSSLInfo(SSLInfo* ssl_info) { | |
| 209 if (transport_.get() && transport_->socket()) { | |
| 210 return transport_->socket()->GetSSLInfo(ssl_info); | |
| 211 } | |
| 212 NOTREACHED(); | |
| 213 return false; | |
| 214 } | |
| 215 | |
| 216 int HttpProxyClientSocket::Read(IOBuffer* buf, int buf_len, | |
| 217 const CompletionCallback& callback) { | |
| 218 DCHECK(user_callback_.is_null()); | |
| 219 if (next_state_ != STATE_DONE) { | |
| 220 // We're trying to read the body of the response but we're still trying | |
| 221 // to establish an SSL tunnel through the proxy. We can't read these | |
| 222 // bytes when establishing a tunnel because they might be controlled by | |
| 223 // an active network attacker. We don't worry about this for HTTP | |
| 224 // because an active network attacker can already control HTTP sessions. | |
| 225 // We reach this case when the user cancels a 407 proxy auth prompt. | |
| 226 // See http://crbug.com/8473. | |
| 227 DCHECK_EQ(407, response_.headers->response_code()); | |
| 228 LogBlockedTunnelResponse(); | |
| 229 | |
| 230 return ERR_TUNNEL_CONNECTION_FAILED; | |
| 231 } | |
| 232 | |
| 233 return transport_->socket()->Read(buf, buf_len, callback); | |
| 234 } | |
| 235 | |
| 236 int HttpProxyClientSocket::Write(IOBuffer* buf, int buf_len, | |
| 237 const CompletionCallback& callback) { | |
| 238 DCHECK_EQ(STATE_DONE, next_state_); | |
| 239 DCHECK(user_callback_.is_null()); | |
| 240 | |
| 241 return transport_->socket()->Write(buf, buf_len, callback); | |
| 242 } | |
| 243 | |
| 244 int HttpProxyClientSocket::SetReceiveBufferSize(int32 size) { | |
| 245 return transport_->socket()->SetReceiveBufferSize(size); | |
| 246 } | |
| 247 | |
| 248 int HttpProxyClientSocket::SetSendBufferSize(int32 size) { | |
| 249 return transport_->socket()->SetSendBufferSize(size); | |
| 250 } | |
| 251 | |
| 252 int HttpProxyClientSocket::GetPeerAddress(IPEndPoint* address) const { | |
| 253 return transport_->socket()->GetPeerAddress(address); | |
| 254 } | |
| 255 | |
| 256 int HttpProxyClientSocket::GetLocalAddress(IPEndPoint* address) const { | |
| 257 return transport_->socket()->GetLocalAddress(address); | |
| 258 } | |
| 259 | |
| 260 int HttpProxyClientSocket::PrepareForAuthRestart() { | |
| 261 if (!response_.headers.get()) | |
| 262 return ERR_CONNECTION_RESET; | |
| 263 | |
| 264 bool keep_alive = false; | |
| 265 if (response_.headers->IsKeepAlive() && | |
| 266 http_stream_parser_->CanFindEndOfResponse()) { | |
| 267 if (!http_stream_parser_->IsResponseBodyComplete()) { | |
| 268 next_state_ = STATE_DRAIN_BODY; | |
| 269 drain_buf_ = new IOBuffer(kDrainBodyBufferSize); | |
| 270 return OK; | |
| 271 } | |
| 272 keep_alive = true; | |
| 273 } | |
| 274 | |
| 275 // We don't need to drain the response body, so we act as if we had drained | |
| 276 // the response body. | |
| 277 return DidDrainBodyForAuthRestart(keep_alive); | |
| 278 } | |
| 279 | |
| 280 int HttpProxyClientSocket::DidDrainBodyForAuthRestart(bool keep_alive) { | |
| 281 if (keep_alive && transport_->socket()->IsConnectedAndIdle()) { | |
| 282 next_state_ = STATE_GENERATE_AUTH_TOKEN; | |
| 283 transport_->set_reuse_type(ClientSocketHandle::REUSED_IDLE); | |
| 284 } else { | |
| 285 // This assumes that the underlying transport socket is a TCP socket, | |
| 286 // since only TCP sockets are restartable. | |
| 287 next_state_ = STATE_TCP_RESTART; | |
| 288 transport_->socket()->Disconnect(); | |
| 289 } | |
| 290 | |
| 291 // Reset the other member variables. | |
| 292 drain_buf_ = NULL; | |
| 293 parser_buf_ = NULL; | |
| 294 http_stream_parser_.reset(); | |
| 295 request_line_.clear(); | |
| 296 request_headers_.Clear(); | |
| 297 response_ = HttpResponseInfo(); | |
| 298 return OK; | |
| 299 } | |
| 300 | |
| 301 void HttpProxyClientSocket::LogBlockedTunnelResponse() const { | |
| 302 ProxyClientSocket::LogBlockedTunnelResponse( | |
| 303 response_.headers->response_code(), | |
| 304 request_.url, | |
| 305 is_https_proxy_); | |
| 306 } | |
| 307 | |
| 308 void HttpProxyClientSocket::DoCallback(int result) { | |
| 309 DCHECK_NE(ERR_IO_PENDING, result); | |
| 310 DCHECK(!user_callback_.is_null()); | |
| 311 | |
| 312 // Since Run() may result in Read being called, | |
| 313 // clear user_callback_ up front. | |
| 314 CompletionCallback c = user_callback_; | |
| 315 user_callback_.Reset(); | |
| 316 c.Run(result); | |
| 317 } | |
| 318 | |
| 319 void HttpProxyClientSocket::OnIOComplete(int result) { | |
| 320 DCHECK_NE(STATE_NONE, next_state_); | |
| 321 DCHECK_NE(STATE_DONE, next_state_); | |
| 322 int rv = DoLoop(result); | |
| 323 if (rv != ERR_IO_PENDING) | |
| 324 DoCallback(rv); | |
| 325 } | |
| 326 | |
| 327 int HttpProxyClientSocket::DoLoop(int last_io_result) { | |
| 328 DCHECK_NE(next_state_, STATE_NONE); | |
| 329 DCHECK_NE(next_state_, STATE_DONE); | |
| 330 int rv = last_io_result; | |
| 331 do { | |
| 332 State state = next_state_; | |
| 333 next_state_ = STATE_NONE; | |
| 334 switch (state) { | |
| 335 case STATE_GENERATE_AUTH_TOKEN: | |
| 336 DCHECK_EQ(OK, rv); | |
| 337 rv = DoGenerateAuthToken(); | |
| 338 break; | |
| 339 case STATE_GENERATE_AUTH_TOKEN_COMPLETE: | |
| 340 rv = DoGenerateAuthTokenComplete(rv); | |
| 341 break; | |
| 342 case STATE_SEND_REQUEST: | |
| 343 DCHECK_EQ(OK, rv); | |
| 344 net_log_.BeginEvent( | |
| 345 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST); | |
| 346 rv = DoSendRequest(); | |
| 347 break; | |
| 348 case STATE_SEND_REQUEST_COMPLETE: | |
| 349 rv = DoSendRequestComplete(rv); | |
| 350 net_log_.EndEventWithNetErrorCode( | |
| 351 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST, rv); | |
| 352 break; | |
| 353 case STATE_READ_HEADERS: | |
| 354 DCHECK_EQ(OK, rv); | |
| 355 net_log_.BeginEvent( | |
| 356 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_READ_HEADERS); | |
| 357 rv = DoReadHeaders(); | |
| 358 break; | |
| 359 case STATE_READ_HEADERS_COMPLETE: | |
| 360 rv = DoReadHeadersComplete(rv); | |
| 361 net_log_.EndEventWithNetErrorCode( | |
| 362 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_READ_HEADERS, rv); | |
| 363 break; | |
| 364 case STATE_DRAIN_BODY: | |
| 365 DCHECK_EQ(OK, rv); | |
| 366 rv = DoDrainBody(); | |
| 367 break; | |
| 368 case STATE_DRAIN_BODY_COMPLETE: | |
| 369 rv = DoDrainBodyComplete(rv); | |
| 370 break; | |
| 371 case STATE_TCP_RESTART: | |
| 372 DCHECK_EQ(OK, rv); | |
| 373 rv = DoTCPRestart(); | |
| 374 break; | |
| 375 case STATE_TCP_RESTART_COMPLETE: | |
| 376 rv = DoTCPRestartComplete(rv); | |
| 377 break; | |
| 378 case STATE_DONE: | |
| 379 break; | |
| 380 default: | |
| 381 NOTREACHED() << "bad state"; | |
| 382 rv = ERR_UNEXPECTED; | |
| 383 break; | |
| 384 } | |
| 385 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE && | |
| 386 next_state_ != STATE_DONE); | |
| 387 return rv; | |
| 388 } | |
| 389 | |
| 390 int HttpProxyClientSocket::DoGenerateAuthToken() { | |
| 391 next_state_ = STATE_GENERATE_AUTH_TOKEN_COMPLETE; | |
| 392 return auth_->MaybeGenerateAuthToken(&request_, io_callback_, net_log_); | |
| 393 } | |
| 394 | |
| 395 int HttpProxyClientSocket::DoGenerateAuthTokenComplete(int result) { | |
| 396 DCHECK_NE(ERR_IO_PENDING, result); | |
| 397 if (result == OK) | |
| 398 next_state_ = STATE_SEND_REQUEST; | |
| 399 return result; | |
| 400 } | |
| 401 | |
| 402 int HttpProxyClientSocket::DoSendRequest() { | |
| 403 next_state_ = STATE_SEND_REQUEST_COMPLETE; | |
| 404 | |
| 405 // This is constructed lazily (instead of within our Start method), so that | |
| 406 // we have proxy info available. | |
| 407 if (request_line_.empty()) { | |
| 408 DCHECK(request_headers_.IsEmpty()); | |
| 409 HttpRequestHeaders authorization_headers; | |
| 410 if (auth_->HaveAuth()) | |
| 411 auth_->AddAuthorizationHeader(&authorization_headers); | |
| 412 if (proxy_delegate_) { | |
| 413 proxy_delegate_->OnBeforeTunnelRequest(proxy_server_, | |
| 414 &authorization_headers); | |
| 415 } | |
| 416 BuildTunnelRequest(request_, authorization_headers, endpoint_, | |
| 417 &request_line_, &request_headers_); | |
| 418 | |
| 419 net_log_.AddEvent( | |
| 420 NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, | |
| 421 base::Bind(&HttpRequestHeaders::NetLogCallback, | |
| 422 base::Unretained(&request_headers_), | |
| 423 &request_line_)); | |
| 424 } | |
| 425 | |
| 426 parser_buf_ = new GrowableIOBuffer(); | |
| 427 http_stream_parser_.reset(new HttpStreamParser( | |
| 428 transport_.get(), &request_, parser_buf_.get(), net_log_)); | |
| 429 return http_stream_parser_->SendRequest( | |
| 430 request_line_, request_headers_, &response_, io_callback_); | |
| 431 } | |
| 432 | |
| 433 int HttpProxyClientSocket::DoSendRequestComplete(int result) { | |
| 434 if (result < 0) | |
| 435 return result; | |
| 436 | |
| 437 next_state_ = STATE_READ_HEADERS; | |
| 438 return OK; | |
| 439 } | |
| 440 | |
| 441 int HttpProxyClientSocket::DoReadHeaders() { | |
| 442 next_state_ = STATE_READ_HEADERS_COMPLETE; | |
| 443 return http_stream_parser_->ReadResponseHeaders(io_callback_); | |
| 444 } | |
| 445 | |
| 446 int HttpProxyClientSocket::DoReadHeadersComplete(int result) { | |
| 447 if (result < 0) | |
| 448 return result; | |
| 449 | |
| 450 // Require the "HTTP/1.x" status line for SSL CONNECT. | |
| 451 if (response_.headers->GetParsedHttpVersion() < HttpVersion(1, 0)) | |
| 452 return ERR_TUNNEL_CONNECTION_FAILED; | |
| 453 | |
| 454 net_log_.AddEvent( | |
| 455 NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, | |
| 456 base::Bind(&HttpResponseHeaders::NetLogCallback, response_.headers)); | |
| 457 | |
| 458 if (proxy_delegate_) { | |
| 459 proxy_delegate_->OnTunnelHeadersReceived( | |
| 460 HostPortPair::FromURL(request_.url), | |
| 461 proxy_server_, | |
| 462 *response_.headers); | |
| 463 } | |
| 464 | |
| 465 switch (response_.headers->response_code()) { | |
| 466 case 200: // OK | |
| 467 if (http_stream_parser_->IsMoreDataBuffered()) | |
| 468 // The proxy sent extraneous data after the headers. | |
| 469 return ERR_TUNNEL_CONNECTION_FAILED; | |
| 470 | |
| 471 next_state_ = STATE_DONE; | |
| 472 return OK; | |
| 473 | |
| 474 // We aren't able to CONNECT to the remote host through the proxy. We | |
| 475 // need to be very suspicious about the response because an active network | |
| 476 // attacker can force us into this state by masquerading as the proxy. | |
| 477 // The only safe thing to do here is to fail the connection because our | |
| 478 // client is expecting an SSL protected response. | |
| 479 // See http://crbug.com/7338. | |
| 480 | |
| 481 case 302: // Found / Moved Temporarily | |
| 482 // Attempt to follow redirects from HTTPS proxies, but only if we can | |
| 483 // sanitize the response. This still allows a rogue HTTPS proxy to | |
| 484 // redirect an HTTPS site load to a similar-looking site, but no longer | |
| 485 // allows it to impersonate the site the user requested. | |
| 486 if (!is_https_proxy_ || !SanitizeProxyRedirect(&response_)) { | |
| 487 LogBlockedTunnelResponse(); | |
| 488 return ERR_TUNNEL_CONNECTION_FAILED; | |
| 489 } | |
| 490 | |
| 491 redirect_has_load_timing_info_ = transport_->GetLoadTimingInfo( | |
| 492 http_stream_parser_->IsConnectionReused(), | |
| 493 &redirect_load_timing_info_); | |
| 494 transport_.reset(); | |
| 495 http_stream_parser_.reset(); | |
| 496 return ERR_HTTPS_PROXY_TUNNEL_RESPONSE; | |
| 497 | |
| 498 case 407: // Proxy Authentication Required | |
| 499 // We need this status code to allow proxy authentication. Our | |
| 500 // authentication code is smart enough to avoid being tricked by an | |
| 501 // active network attacker. | |
| 502 // The next state is intentionally not set as it should be STATE_NONE; | |
| 503 if (!SanitizeProxyAuth(&response_)) { | |
| 504 LogBlockedTunnelResponse(); | |
| 505 return ERR_TUNNEL_CONNECTION_FAILED; | |
| 506 } | |
| 507 return HandleProxyAuthChallenge(auth_.get(), &response_, net_log_); | |
| 508 | |
| 509 default: | |
| 510 // Ignore response to avoid letting the proxy impersonate the target | |
| 511 // server. (See http://crbug.com/137891.) | |
| 512 // We lose something by doing this. We have seen proxy 403, 404, and | |
| 513 // 501 response bodies that contain a useful error message. For | |
| 514 // example, Squid uses a 404 response to report the DNS error: "The | |
| 515 // domain name does not exist." | |
| 516 LogBlockedTunnelResponse(); | |
| 517 return ERR_TUNNEL_CONNECTION_FAILED; | |
| 518 } | |
| 519 } | |
| 520 | |
| 521 int HttpProxyClientSocket::DoDrainBody() { | |
| 522 DCHECK(drain_buf_.get()); | |
| 523 DCHECK(transport_->is_initialized()); | |
| 524 next_state_ = STATE_DRAIN_BODY_COMPLETE; | |
| 525 return http_stream_parser_->ReadResponseBody( | |
| 526 drain_buf_.get(), kDrainBodyBufferSize, io_callback_); | |
| 527 } | |
| 528 | |
| 529 int HttpProxyClientSocket::DoDrainBodyComplete(int result) { | |
| 530 if (result < 0) | |
| 531 return result; | |
| 532 | |
| 533 if (http_stream_parser_->IsResponseBodyComplete()) | |
| 534 return DidDrainBodyForAuthRestart(true); | |
| 535 | |
| 536 // Keep draining. | |
| 537 next_state_ = STATE_DRAIN_BODY; | |
| 538 return OK; | |
| 539 } | |
| 540 | |
| 541 int HttpProxyClientSocket::DoTCPRestart() { | |
| 542 next_state_ = STATE_TCP_RESTART_COMPLETE; | |
| 543 return transport_->socket()->Connect( | |
| 544 base::Bind(&HttpProxyClientSocket::OnIOComplete, base::Unretained(this))); | |
| 545 } | |
| 546 | |
| 547 int HttpProxyClientSocket::DoTCPRestartComplete(int result) { | |
| 548 if (result != OK) | |
| 549 return result; | |
| 550 | |
| 551 next_state_ = STATE_GENERATE_AUTH_TOKEN; | |
| 552 return result; | |
| 553 } | |
| 554 | |
| 555 } // namespace net | |
| OLD | NEW |