| 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/spdy/spdy_proxy_client_socket.h" | |
| 6 | |
| 7 #include <algorithm> // min | |
| 8 #include <memory> | |
| 9 #include <utility> | |
| 10 | |
| 11 #include "base/bind.h" | |
| 12 #include "base/bind_helpers.h" | |
| 13 #include "base/callback_helpers.h" | |
| 14 #include "base/location.h" | |
| 15 #include "base/logging.h" | |
| 16 #include "base/single_thread_task_runner.h" | |
| 17 #include "base/strings/string_util.h" | |
| 18 #include "base/threading/thread_task_runner_handle.h" | |
| 19 #include "base/values.h" | |
| 20 #include "net/base/auth.h" | |
| 21 #include "net/base/io_buffer.h" | |
| 22 #include "net/http/http_auth_cache.h" | |
| 23 #include "net/http/http_auth_handler_factory.h" | |
| 24 #include "net/http/http_request_info.h" | |
| 25 #include "net/http/http_response_headers.h" | |
| 26 #include "net/http/proxy_connect_redirect_http_stream.h" | |
| 27 #include "net/log/net_log_event_type.h" | |
| 28 #include "net/log/net_log_source_type.h" | |
| 29 #include "net/spdy/spdy_http_utils.h" | |
| 30 #include "url/gurl.h" | |
| 31 | |
| 32 namespace net { | |
| 33 | |
| 34 SpdyProxyClientSocket::SpdyProxyClientSocket( | |
| 35 const base::WeakPtr<SpdyStream>& spdy_stream, | |
| 36 const SpdyString& user_agent, | |
| 37 const HostPortPair& endpoint, | |
| 38 const HostPortPair& proxy_server, | |
| 39 const NetLogWithSource& source_net_log, | |
| 40 HttpAuthController* auth_controller) | |
| 41 : next_state_(STATE_DISCONNECTED), | |
| 42 spdy_stream_(spdy_stream), | |
| 43 endpoint_(endpoint), | |
| 44 auth_(auth_controller), | |
| 45 user_agent_(user_agent), | |
| 46 user_buffer_len_(0), | |
| 47 write_buffer_len_(0), | |
| 48 was_ever_used_(false), | |
| 49 redirect_has_load_timing_info_(false), | |
| 50 net_log_(NetLogWithSource::Make(spdy_stream->net_log().net_log(), | |
| 51 NetLogSourceType::PROXY_CLIENT_SOCKET)), | |
| 52 source_dependency_(source_net_log.source()), | |
| 53 weak_factory_(this), | |
| 54 write_callback_weak_factory_(this) { | |
| 55 request_.method = "CONNECT"; | |
| 56 request_.url = GURL("https://" + endpoint.ToString()); | |
| 57 net_log_.BeginEvent(NetLogEventType::SOCKET_ALIVE, | |
| 58 source_net_log.source().ToEventParametersCallback()); | |
| 59 net_log_.AddEvent( | |
| 60 NetLogEventType::HTTP2_PROXY_CLIENT_SESSION, | |
| 61 spdy_stream->net_log().source().ToEventParametersCallback()); | |
| 62 | |
| 63 spdy_stream_->SetDelegate(this); | |
| 64 was_ever_used_ = spdy_stream_->WasEverUsed(); | |
| 65 } | |
| 66 | |
| 67 SpdyProxyClientSocket::~SpdyProxyClientSocket() { | |
| 68 Disconnect(); | |
| 69 net_log_.EndEvent(NetLogEventType::SOCKET_ALIVE); | |
| 70 } | |
| 71 | |
| 72 const HttpResponseInfo* SpdyProxyClientSocket::GetConnectResponseInfo() const { | |
| 73 return response_.headers.get() ? &response_ : NULL; | |
| 74 } | |
| 75 | |
| 76 const scoped_refptr<HttpAuthController>& | |
| 77 SpdyProxyClientSocket::GetAuthController() const { | |
| 78 return auth_; | |
| 79 } | |
| 80 | |
| 81 int SpdyProxyClientSocket::RestartWithAuth(const CompletionCallback& callback) { | |
| 82 // A SPDY Stream can only handle a single request, so the underlying | |
| 83 // stream may not be reused and a new SpdyProxyClientSocket must be | |
| 84 // created (possibly on top of the same SPDY Session). | |
| 85 next_state_ = STATE_DISCONNECTED; | |
| 86 return OK; | |
| 87 } | |
| 88 | |
| 89 bool SpdyProxyClientSocket::IsUsingSpdy() const { | |
| 90 return true; | |
| 91 } | |
| 92 | |
| 93 NextProto SpdyProxyClientSocket::GetProxyNegotiatedProtocol() const { | |
| 94 return spdy_stream_->GetNegotiatedProtocol(); | |
| 95 } | |
| 96 | |
| 97 HttpStream* SpdyProxyClientSocket::CreateConnectResponseStream() { | |
| 98 return new ProxyConnectRedirectHttpStream( | |
| 99 redirect_has_load_timing_info_ ? &redirect_load_timing_info_ : NULL); | |
| 100 } | |
| 101 | |
| 102 // Sends a HEADERS frame to the proxy with a CONNECT request | |
| 103 // for the specified endpoint. Waits for the server to send back | |
| 104 // a HEADERS frame. OK will be returned if the status is 200. | |
| 105 // ERR_TUNNEL_CONNECTION_FAILED will be returned for any other status. | |
| 106 // In any of these cases, Read() may be called to retrieve the HTTP | |
| 107 // response body. Any other return values should be considered fatal. | |
| 108 // TODO(rch): handle 407 proxy auth requested correctly, perhaps | |
| 109 // by creating a new stream for the subsequent request. | |
| 110 // TODO(rch): create a more appropriate error code to disambiguate | |
| 111 // the HTTPS Proxy tunnel failure from an HTTP Proxy tunnel failure. | |
| 112 int SpdyProxyClientSocket::Connect(const CompletionCallback& callback) { | |
| 113 DCHECK(read_callback_.is_null()); | |
| 114 if (next_state_ == STATE_OPEN) | |
| 115 return OK; | |
| 116 | |
| 117 DCHECK_EQ(STATE_DISCONNECTED, next_state_); | |
| 118 next_state_ = STATE_GENERATE_AUTH_TOKEN; | |
| 119 | |
| 120 int rv = DoLoop(OK); | |
| 121 if (rv == ERR_IO_PENDING) | |
| 122 read_callback_ = callback; | |
| 123 return rv; | |
| 124 } | |
| 125 | |
| 126 void SpdyProxyClientSocket::Disconnect() { | |
| 127 read_buffer_queue_.Clear(); | |
| 128 user_buffer_ = NULL; | |
| 129 user_buffer_len_ = 0; | |
| 130 read_callback_.Reset(); | |
| 131 | |
| 132 write_buffer_len_ = 0; | |
| 133 write_callback_.Reset(); | |
| 134 write_callback_weak_factory_.InvalidateWeakPtrs(); | |
| 135 | |
| 136 next_state_ = STATE_DISCONNECTED; | |
| 137 | |
| 138 if (spdy_stream_.get()) { | |
| 139 // This will cause OnClose to be invoked, which takes care of | |
| 140 // cleaning up all the internal state. | |
| 141 spdy_stream_->Cancel(); | |
| 142 DCHECK(!spdy_stream_.get()); | |
| 143 } | |
| 144 } | |
| 145 | |
| 146 bool SpdyProxyClientSocket::IsConnected() const { | |
| 147 return next_state_ == STATE_OPEN; | |
| 148 } | |
| 149 | |
| 150 bool SpdyProxyClientSocket::IsConnectedAndIdle() const { | |
| 151 return IsConnected() && read_buffer_queue_.IsEmpty() && | |
| 152 spdy_stream_->IsOpen(); | |
| 153 } | |
| 154 | |
| 155 const NetLogWithSource& SpdyProxyClientSocket::NetLog() const { | |
| 156 return net_log_; | |
| 157 } | |
| 158 | |
| 159 void SpdyProxyClientSocket::SetSubresourceSpeculation() { | |
| 160 // TODO(rch): what should this implementation be? | |
| 161 } | |
| 162 | |
| 163 void SpdyProxyClientSocket::SetOmniboxSpeculation() { | |
| 164 // TODO(rch): what should this implementation be? | |
| 165 } | |
| 166 | |
| 167 bool SpdyProxyClientSocket::WasEverUsed() const { | |
| 168 return was_ever_used_ || (spdy_stream_.get() && spdy_stream_->WasEverUsed()); | |
| 169 } | |
| 170 | |
| 171 bool SpdyProxyClientSocket::WasAlpnNegotiated() const { | |
| 172 return false; | |
| 173 } | |
| 174 | |
| 175 NextProto SpdyProxyClientSocket::GetNegotiatedProtocol() const { | |
| 176 return kProtoUnknown; | |
| 177 } | |
| 178 | |
| 179 bool SpdyProxyClientSocket::GetSSLInfo(SSLInfo* ssl_info) { | |
| 180 return spdy_stream_->GetSSLInfo(ssl_info); | |
| 181 } | |
| 182 | |
| 183 void SpdyProxyClientSocket::GetConnectionAttempts( | |
| 184 ConnectionAttempts* out) const { | |
| 185 out->clear(); | |
| 186 } | |
| 187 | |
| 188 int64_t SpdyProxyClientSocket::GetTotalReceivedBytes() const { | |
| 189 NOTIMPLEMENTED(); | |
| 190 return 0; | |
| 191 } | |
| 192 | |
| 193 int SpdyProxyClientSocket::Read(IOBuffer* buf, int buf_len, | |
| 194 const CompletionCallback& callback) { | |
| 195 DCHECK(read_callback_.is_null()); | |
| 196 DCHECK(!user_buffer_.get()); | |
| 197 | |
| 198 if (next_state_ == STATE_DISCONNECTED) | |
| 199 return ERR_SOCKET_NOT_CONNECTED; | |
| 200 | |
| 201 if (next_state_ == STATE_CLOSED && read_buffer_queue_.IsEmpty()) { | |
| 202 return 0; | |
| 203 } | |
| 204 | |
| 205 DCHECK(next_state_ == STATE_OPEN || next_state_ == STATE_CLOSED); | |
| 206 DCHECK(buf); | |
| 207 size_t result = PopulateUserReadBuffer(buf->data(), buf_len); | |
| 208 if (result == 0) { | |
| 209 user_buffer_ = buf; | |
| 210 user_buffer_len_ = static_cast<size_t>(buf_len); | |
| 211 DCHECK(!callback.is_null()); | |
| 212 read_callback_ = callback; | |
| 213 return ERR_IO_PENDING; | |
| 214 } | |
| 215 user_buffer_ = NULL; | |
| 216 return result; | |
| 217 } | |
| 218 | |
| 219 size_t SpdyProxyClientSocket::PopulateUserReadBuffer(char* data, size_t len) { | |
| 220 return read_buffer_queue_.Dequeue(data, len); | |
| 221 } | |
| 222 | |
| 223 int SpdyProxyClientSocket::Write(IOBuffer* buf, int buf_len, | |
| 224 const CompletionCallback& callback) { | |
| 225 DCHECK(write_callback_.is_null()); | |
| 226 if (next_state_ != STATE_OPEN) | |
| 227 return ERR_SOCKET_NOT_CONNECTED; | |
| 228 | |
| 229 DCHECK(spdy_stream_.get()); | |
| 230 spdy_stream_->SendData(buf, buf_len, MORE_DATA_TO_SEND); | |
| 231 net_log_.AddByteTransferEvent(NetLogEventType::SOCKET_BYTES_SENT, buf_len, | |
| 232 buf->data()); | |
| 233 write_callback_ = callback; | |
| 234 write_buffer_len_ = buf_len; | |
| 235 return ERR_IO_PENDING; | |
| 236 } | |
| 237 | |
| 238 int SpdyProxyClientSocket::SetReceiveBufferSize(int32_t size) { | |
| 239 // Since this StreamSocket sits on top of a shared SpdySession, it | |
| 240 // is not safe for callers to change this underlying socket. | |
| 241 return ERR_NOT_IMPLEMENTED; | |
| 242 } | |
| 243 | |
| 244 int SpdyProxyClientSocket::SetSendBufferSize(int32_t size) { | |
| 245 // Since this StreamSocket sits on top of a shared SpdySession, it | |
| 246 // is not safe for callers to change this underlying socket. | |
| 247 return ERR_NOT_IMPLEMENTED; | |
| 248 } | |
| 249 | |
| 250 int SpdyProxyClientSocket::GetPeerAddress(IPEndPoint* address) const { | |
| 251 if (!IsConnected()) | |
| 252 return ERR_SOCKET_NOT_CONNECTED; | |
| 253 return spdy_stream_->GetPeerAddress(address); | |
| 254 } | |
| 255 | |
| 256 int SpdyProxyClientSocket::GetLocalAddress(IPEndPoint* address) const { | |
| 257 if (!IsConnected()) | |
| 258 return ERR_SOCKET_NOT_CONNECTED; | |
| 259 return spdy_stream_->GetLocalAddress(address); | |
| 260 } | |
| 261 | |
| 262 void SpdyProxyClientSocket::LogBlockedTunnelResponse() const { | |
| 263 ProxyClientSocket::LogBlockedTunnelResponse( | |
| 264 response_.headers->response_code(), | |
| 265 /* is_https_proxy = */ true); | |
| 266 } | |
| 267 | |
| 268 void SpdyProxyClientSocket::RunCallback(const CompletionCallback& callback, | |
| 269 int result) const { | |
| 270 callback.Run(result); | |
| 271 } | |
| 272 | |
| 273 void SpdyProxyClientSocket::OnIOComplete(int result) { | |
| 274 DCHECK_NE(STATE_DISCONNECTED, next_state_); | |
| 275 int rv = DoLoop(result); | |
| 276 if (rv != ERR_IO_PENDING) { | |
| 277 CompletionCallback c = read_callback_; | |
| 278 read_callback_.Reset(); | |
| 279 c.Run(rv); | |
| 280 } | |
| 281 } | |
| 282 | |
| 283 int SpdyProxyClientSocket::DoLoop(int last_io_result) { | |
| 284 DCHECK_NE(next_state_, STATE_DISCONNECTED); | |
| 285 int rv = last_io_result; | |
| 286 do { | |
| 287 State state = next_state_; | |
| 288 next_state_ = STATE_DISCONNECTED; | |
| 289 switch (state) { | |
| 290 case STATE_GENERATE_AUTH_TOKEN: | |
| 291 DCHECK_EQ(OK, rv); | |
| 292 rv = DoGenerateAuthToken(); | |
| 293 break; | |
| 294 case STATE_GENERATE_AUTH_TOKEN_COMPLETE: | |
| 295 rv = DoGenerateAuthTokenComplete(rv); | |
| 296 break; | |
| 297 case STATE_SEND_REQUEST: | |
| 298 DCHECK_EQ(OK, rv); | |
| 299 net_log_.BeginEvent( | |
| 300 NetLogEventType::HTTP_TRANSACTION_TUNNEL_SEND_REQUEST); | |
| 301 rv = DoSendRequest(); | |
| 302 break; | |
| 303 case STATE_SEND_REQUEST_COMPLETE: | |
| 304 net_log_.EndEventWithNetErrorCode( | |
| 305 NetLogEventType::HTTP_TRANSACTION_TUNNEL_SEND_REQUEST, rv); | |
| 306 rv = DoSendRequestComplete(rv); | |
| 307 if (rv >= 0 || rv == ERR_IO_PENDING) { | |
| 308 // Emit extra event so can use the same events as | |
| 309 // HttpProxyClientSocket. | |
| 310 net_log_.BeginEvent( | |
| 311 NetLogEventType::HTTP_TRANSACTION_TUNNEL_READ_HEADERS); | |
| 312 } | |
| 313 break; | |
| 314 case STATE_READ_REPLY_COMPLETE: | |
| 315 rv = DoReadReplyComplete(rv); | |
| 316 net_log_.EndEventWithNetErrorCode( | |
| 317 NetLogEventType::HTTP_TRANSACTION_TUNNEL_READ_HEADERS, rv); | |
| 318 break; | |
| 319 default: | |
| 320 NOTREACHED() << "bad state"; | |
| 321 rv = ERR_UNEXPECTED; | |
| 322 break; | |
| 323 } | |
| 324 } while (rv != ERR_IO_PENDING && next_state_ != STATE_DISCONNECTED && | |
| 325 next_state_ != STATE_OPEN); | |
| 326 return rv; | |
| 327 } | |
| 328 | |
| 329 int SpdyProxyClientSocket::DoGenerateAuthToken() { | |
| 330 next_state_ = STATE_GENERATE_AUTH_TOKEN_COMPLETE; | |
| 331 return auth_->MaybeGenerateAuthToken( | |
| 332 &request_, | |
| 333 base::Bind(&SpdyProxyClientSocket::OnIOComplete, | |
| 334 weak_factory_.GetWeakPtr()), | |
| 335 net_log_); | |
| 336 } | |
| 337 | |
| 338 int SpdyProxyClientSocket::DoGenerateAuthTokenComplete(int result) { | |
| 339 DCHECK_NE(ERR_IO_PENDING, result); | |
| 340 if (result == OK) | |
| 341 next_state_ = STATE_SEND_REQUEST; | |
| 342 return result; | |
| 343 } | |
| 344 | |
| 345 int SpdyProxyClientSocket::DoSendRequest() { | |
| 346 next_state_ = STATE_SEND_REQUEST_COMPLETE; | |
| 347 | |
| 348 // Add Proxy-Authentication header if necessary. | |
| 349 HttpRequestHeaders authorization_headers; | |
| 350 if (auth_->HaveAuth()) { | |
| 351 auth_->AddAuthorizationHeader(&authorization_headers); | |
| 352 } | |
| 353 | |
| 354 SpdyString request_line; | |
| 355 BuildTunnelRequest(endpoint_, authorization_headers, user_agent_, | |
| 356 &request_line, &request_.extra_headers); | |
| 357 | |
| 358 net_log_.AddEvent( | |
| 359 NetLogEventType::HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, | |
| 360 base::Bind(&HttpRequestHeaders::NetLogCallback, | |
| 361 base::Unretained(&request_.extra_headers), &request_line)); | |
| 362 | |
| 363 SpdyHeaderBlock headers; | |
| 364 CreateSpdyHeadersFromHttpRequest(request_, request_.extra_headers, true, | |
| 365 &headers); | |
| 366 | |
| 367 return spdy_stream_->SendRequestHeaders(std::move(headers), | |
| 368 MORE_DATA_TO_SEND); | |
| 369 } | |
| 370 | |
| 371 int SpdyProxyClientSocket::DoSendRequestComplete(int result) { | |
| 372 if (result < 0) | |
| 373 return result; | |
| 374 | |
| 375 // Wait for HEADERS frame from the server | |
| 376 next_state_ = STATE_READ_REPLY_COMPLETE; | |
| 377 return ERR_IO_PENDING; | |
| 378 } | |
| 379 | |
| 380 int SpdyProxyClientSocket::DoReadReplyComplete(int result) { | |
| 381 // We enter this method directly from DoSendRequestComplete, since | |
| 382 // we are notified by a callback when the HEADERS frame arrives. | |
| 383 | |
| 384 if (result < 0) | |
| 385 return result; | |
| 386 | |
| 387 // Require the "HTTP/1.x" status line for SSL CONNECT. | |
| 388 if (response_.headers->GetHttpVersion() < HttpVersion(1, 0)) | |
| 389 return ERR_TUNNEL_CONNECTION_FAILED; | |
| 390 | |
| 391 net_log_.AddEvent( | |
| 392 NetLogEventType::HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, | |
| 393 base::Bind(&HttpResponseHeaders::NetLogCallback, response_.headers)); | |
| 394 | |
| 395 switch (response_.headers->response_code()) { | |
| 396 case 200: // OK | |
| 397 next_state_ = STATE_OPEN; | |
| 398 return OK; | |
| 399 | |
| 400 case 302: // Found / Moved Temporarily | |
| 401 // Try to return a sanitized response so we can follow auth redirects. | |
| 402 // If we can't, fail the tunnel connection. | |
| 403 if (!SanitizeProxyRedirect(&response_)) { | |
| 404 LogBlockedTunnelResponse(); | |
| 405 return ERR_TUNNEL_CONNECTION_FAILED; | |
| 406 } | |
| 407 | |
| 408 redirect_has_load_timing_info_ = | |
| 409 spdy_stream_->GetLoadTimingInfo(&redirect_load_timing_info_); | |
| 410 // Note that this triggers a ERROR_CODE_CANCEL. | |
| 411 spdy_stream_->DetachDelegate(); | |
| 412 next_state_ = STATE_DISCONNECTED; | |
| 413 return ERR_HTTPS_PROXY_TUNNEL_RESPONSE; | |
| 414 | |
| 415 case 407: // Proxy Authentication Required | |
| 416 next_state_ = STATE_OPEN; | |
| 417 if (!SanitizeProxyAuth(&response_)) { | |
| 418 LogBlockedTunnelResponse(); | |
| 419 return ERR_TUNNEL_CONNECTION_FAILED; | |
| 420 } | |
| 421 return HandleProxyAuthChallenge(auth_.get(), &response_, net_log_); | |
| 422 | |
| 423 default: | |
| 424 // Ignore response to avoid letting the proxy impersonate the target | |
| 425 // server. (See http://crbug.com/137891.) | |
| 426 LogBlockedTunnelResponse(); | |
| 427 return ERR_TUNNEL_CONNECTION_FAILED; | |
| 428 } | |
| 429 } | |
| 430 | |
| 431 // SpdyStream::Delegate methods: | |
| 432 // Called when SYN frame has been sent. | |
| 433 // Returns true if no more data to be sent after SYN frame. | |
| 434 void SpdyProxyClientSocket::OnHeadersSent() { | |
| 435 DCHECK_EQ(next_state_, STATE_SEND_REQUEST_COMPLETE); | |
| 436 | |
| 437 OnIOComplete(OK); | |
| 438 } | |
| 439 | |
| 440 void SpdyProxyClientSocket::OnHeadersReceived( | |
| 441 const SpdyHeaderBlock& response_headers) { | |
| 442 // If we've already received the reply, existing headers are too late. | |
| 443 // TODO(mbelshe): figure out a way to make HEADERS frames useful after the | |
| 444 // initial response. | |
| 445 if (next_state_ != STATE_READ_REPLY_COMPLETE) | |
| 446 return; | |
| 447 | |
| 448 // Save the response | |
| 449 const bool headers_valid = | |
| 450 SpdyHeadersToHttpResponse(response_headers, &response_); | |
| 451 DCHECK(headers_valid); | |
| 452 | |
| 453 OnIOComplete(OK); | |
| 454 } | |
| 455 | |
| 456 // Called when data is received or on EOF (if |buffer| is NULL). | |
| 457 void SpdyProxyClientSocket::OnDataReceived(std::unique_ptr<SpdyBuffer> buffer) { | |
| 458 if (buffer) { | |
| 459 net_log_.AddByteTransferEvent(NetLogEventType::SOCKET_BYTES_RECEIVED, | |
| 460 buffer->GetRemainingSize(), | |
| 461 buffer->GetRemainingData()); | |
| 462 read_buffer_queue_.Enqueue(std::move(buffer)); | |
| 463 } else { | |
| 464 net_log_.AddByteTransferEvent(NetLogEventType::SOCKET_BYTES_RECEIVED, 0, | |
| 465 NULL); | |
| 466 } | |
| 467 | |
| 468 if (!read_callback_.is_null()) { | |
| 469 int rv = PopulateUserReadBuffer(user_buffer_->data(), user_buffer_len_); | |
| 470 CompletionCallback c = read_callback_; | |
| 471 read_callback_.Reset(); | |
| 472 user_buffer_ = NULL; | |
| 473 user_buffer_len_ = 0; | |
| 474 c.Run(rv); | |
| 475 } | |
| 476 } | |
| 477 | |
| 478 void SpdyProxyClientSocket::OnDataSent() { | |
| 479 DCHECK(!write_callback_.is_null()); | |
| 480 | |
| 481 int rv = write_buffer_len_; | |
| 482 write_buffer_len_ = 0; | |
| 483 | |
| 484 // Proxy write callbacks result in deep callback chains. Post to allow the | |
| 485 // stream's write callback chain to unwind (see crbug.com/355511). | |
| 486 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
| 487 FROM_HERE, base::Bind(&SpdyProxyClientSocket::RunCallback, | |
| 488 write_callback_weak_factory_.GetWeakPtr(), | |
| 489 base::ResetAndReturn(&write_callback_), rv)); | |
| 490 } | |
| 491 | |
| 492 void SpdyProxyClientSocket::OnTrailers(const SpdyHeaderBlock& trailers) { | |
| 493 // |spdy_stream_| is of type SPDY_BIDIRECTIONAL_STREAM, so trailers are | |
| 494 // combined with response headers and this method will not be calld. | |
| 495 NOTREACHED(); | |
| 496 } | |
| 497 | |
| 498 void SpdyProxyClientSocket::OnClose(int status) { | |
| 499 was_ever_used_ = spdy_stream_->WasEverUsed(); | |
| 500 spdy_stream_.reset(); | |
| 501 | |
| 502 bool connecting = next_state_ != STATE_DISCONNECTED && | |
| 503 next_state_ < STATE_OPEN; | |
| 504 if (next_state_ == STATE_OPEN) | |
| 505 next_state_ = STATE_CLOSED; | |
| 506 else | |
| 507 next_state_ = STATE_DISCONNECTED; | |
| 508 | |
| 509 base::WeakPtr<SpdyProxyClientSocket> weak_ptr = weak_factory_.GetWeakPtr(); | |
| 510 CompletionCallback write_callback = write_callback_; | |
| 511 write_callback_.Reset(); | |
| 512 write_buffer_len_ = 0; | |
| 513 | |
| 514 // If we're in the middle of connecting, we need to make sure | |
| 515 // we invoke the connect callback. | |
| 516 if (connecting) { | |
| 517 DCHECK(!read_callback_.is_null()); | |
| 518 CompletionCallback read_callback = read_callback_; | |
| 519 read_callback_.Reset(); | |
| 520 read_callback.Run(status); | |
| 521 } else if (!read_callback_.is_null()) { | |
| 522 // If we have a read_callback_, the we need to make sure we call it back. | |
| 523 OnDataReceived(std::unique_ptr<SpdyBuffer>()); | |
| 524 } | |
| 525 // This may have been deleted by read_callback_, so check first. | |
| 526 if (weak_ptr.get() && !write_callback.is_null()) | |
| 527 write_callback.Run(ERR_CONNECTION_CLOSED); | |
| 528 } | |
| 529 | |
| 530 NetLogSource SpdyProxyClientSocket::source_dependency() const { | |
| 531 return source_dependency_; | |
| 532 } | |
| 533 | |
| 534 } // namespace net | |
| OLD | NEW |