blob: 7dbf83e085512cb89b31af4e7328948320a477f3 [file] [log] [blame]
[email protected]43549a8f2011-05-16 23:37:151// Copyright (c) 2011 The Chromium Authors. All rights reserved.
[email protected]fe2f62a2010-10-01 03:34:072// 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
9#include "base/logging.h"
10#include "base/string_util.h"
11#include "googleurl/src/gurl.h"
12#include "net/base/auth.h"
13#include "net/base/io_buffer.h"
14#include "net/base/net_util.h"
15#include "net/http/http_auth_cache.h"
16#include "net/http/http_auth_handler_factory.h"
17#include "net/http/http_net_log_params.h"
18#include "net/http/http_proxy_utils.h"
[email protected]b104b502010-10-18 20:21:3119#include "net/http/http_response_headers.h"
[email protected]fe2f62a2010-10-01 03:34:0720#include "net/spdy/spdy_http_utils.h"
21
22namespace net {
23
24SpdyProxyClientSocket::SpdyProxyClientSocket(
25 SpdyStream* spdy_stream,
26 const std::string& user_agent,
27 const HostPortPair& endpoint,
28 const GURL& url,
29 const HostPortPair& proxy_server,
30 HttpAuthCache* auth_cache,
31 HttpAuthHandlerFactory* auth_handler_factory)
32 : ALLOW_THIS_IN_INITIALIZER_LIST(
33 io_callback_(this, &SpdyProxyClientSocket::OnIOComplete)),
[email protected]d9da5fe2010-10-13 22:37:1634 next_state_(STATE_DISCONNECTED),
[email protected]fe2f62a2010-10-01 03:34:0735 spdy_stream_(spdy_stream),
36 read_callback_(NULL),
37 write_callback_(NULL),
38 endpoint_(endpoint),
39 auth_(
40 new HttpAuthController(HttpAuth::AUTH_PROXY,
[email protected]e9fa5482011-07-08 18:29:1141 GURL("https://" + proxy_server.ToString()),
[email protected]fe2f62a2010-10-01 03:34:0742 auth_cache,
43 auth_handler_factory)),
44 user_buffer_(NULL),
45 write_buffer_len_(0),
46 write_bytes_outstanding_(0),
[email protected]6af4e412011-11-29 23:39:1847 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
[email protected]fe2f62a2010-10-01 03:34:0748 net_log_(spdy_stream->net_log()) {
49 request_.method = "CONNECT";
50 request_.url = url;
51 if (!user_agent.empty())
52 request_.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent,
53 user_agent);
54 spdy_stream_->SetDelegate(this);
55 was_ever_used_ = spdy_stream_->WasEverUsed();
56}
57
58SpdyProxyClientSocket::~SpdyProxyClientSocket() {
59 Disconnect();
60}
61
[email protected]be1a48b2011-01-20 00:12:1362const HttpResponseInfo* SpdyProxyClientSocket::GetConnectResponseInfo() const {
63 return response_.headers ? &response_ : NULL;
64}
65
[email protected]15a3c2082011-11-21 18:32:0166int SpdyProxyClientSocket::RestartWithAuth(OldCompletionCallback* callback) {
67 // A SPDY Stream can only handle a single request, so the underlying
68 // stream may not be reused and a new SpdyProxyClientSocket must be
69 // created (possibly on top of the same SPDY Session).
70 next_state_ = STATE_DISCONNECTED;
71 return OK;
72}
73
74const
75scoped_refptr<HttpAuthController>& SpdyProxyClientSocket::auth_controller() {
76 return auth_;
77}
78
[email protected]511f6f52010-12-17 03:58:2979HttpStream* SpdyProxyClientSocket::CreateConnectResponseStream() {
80 DCHECK(response_stream_.get());
81 return response_stream_.release();
82}
83
[email protected]fe2f62a2010-10-01 03:34:0784// Sends a SYN_STREAM frame to the proxy with a CONNECT request
85// for the specified endpoint. Waits for the server to send back
86// a SYN_REPLY frame. OK will be returned if the status is 200.
87// ERR_TUNNEL_CONNECTION_FAILED will be returned for any other status.
88// In any of these cases, Read() may be called to retrieve the HTTP
89// response body. Any other return values should be considered fatal.
90// TODO(rch): handle 407 proxy auth requested correctly, perhaps
91// by creating a new stream for the subsequent request.
92// TODO(rch): create a more appropriate error code to disambiguate
93// the HTTPS Proxy tunnel failure from an HTTP Proxy tunnel failure.
[email protected]f1f3f0f82011-10-01 20:38:1094int SpdyProxyClientSocket::Connect(OldCompletionCallback* callback) {
[email protected]fe2f62a2010-10-01 03:34:0795 DCHECK(!read_callback_);
[email protected]d9da5fe2010-10-13 22:37:1696 if (next_state_ == STATE_OPEN)
[email protected]fe2f62a2010-10-01 03:34:0797 return OK;
98
[email protected]d9da5fe2010-10-13 22:37:1699 DCHECK_EQ(STATE_DISCONNECTED, next_state_);
[email protected]fe2f62a2010-10-01 03:34:07100 next_state_ = STATE_GENERATE_AUTH_TOKEN;
101
102 int rv = DoLoop(OK);
103 if (rv == ERR_IO_PENDING)
104 read_callback_ = callback;
105 return rv;
106}
107
108void SpdyProxyClientSocket::Disconnect() {
[email protected]d9da5fe2010-10-13 22:37:16109 read_buffer_.clear();
110 user_buffer_ = NULL;
111 read_callback_ = NULL;
112
113 write_buffer_len_ = 0;
114 write_bytes_outstanding_ = 0;
115 write_callback_ = NULL;
116
117 next_state_ = STATE_DISCONNECTED;
118
[email protected]fe2f62a2010-10-01 03:34:07119 if (spdy_stream_)
120 // This will cause OnClose to be invoked, which takes care of
121 // cleaning up all the internal state.
122 spdy_stream_->Cancel();
123}
124
125bool SpdyProxyClientSocket::IsConnected() const {
[email protected]194c7a92011-12-03 04:54:18126 return next_state_ == STATE_OPEN;
[email protected]fe2f62a2010-10-01 03:34:07127}
128
129bool SpdyProxyClientSocket::IsConnectedAndIdle() const {
[email protected]194c7a92011-12-03 04:54:18130 return IsConnected() && read_buffer_.empty() && spdy_stream_->is_idle();
[email protected]fe2f62a2010-10-01 03:34:07131}
132
[email protected]e4be2dd2010-12-14 00:44:39133const BoundNetLog& SpdyProxyClientSocket::NetLog() const {
134 return net_log_;
135}
136
[email protected]fe2f62a2010-10-01 03:34:07137void SpdyProxyClientSocket::SetSubresourceSpeculation() {
138 // TODO(rch): what should this implementation be?
139}
140
141void SpdyProxyClientSocket::SetOmniboxSpeculation() {
142 // TODO(rch): what should this implementation be?
143}
144
145bool SpdyProxyClientSocket::WasEverUsed() const {
146 return was_ever_used_ || (spdy_stream_ && spdy_stream_->WasEverUsed());
147}
148
[email protected]7f7e92392010-10-26 18:29:29149bool SpdyProxyClientSocket::UsingTCPFastOpen() const {
150 return false;
151}
152
[email protected]5e6efa52011-06-27 17:26:41153int64 SpdyProxyClientSocket::NumBytesRead() const {
154 return -1;
155}
156
157base::TimeDelta SpdyProxyClientSocket::GetConnectTimeMicros() const {
158 return base::TimeDelta::FromMicroseconds(-1);
159}
160
[email protected]fe2f62a2010-10-01 03:34:07161int SpdyProxyClientSocket::Read(IOBuffer* buf, int buf_len,
[email protected]f1f3f0f82011-10-01 20:38:10162 OldCompletionCallback* callback) {
[email protected]fe2f62a2010-10-01 03:34:07163 DCHECK(!read_callback_);
164 DCHECK(!user_buffer_);
165
[email protected]d9da5fe2010-10-13 22:37:16166 if (next_state_ == STATE_DISCONNECTED)
167 return ERR_SOCKET_NOT_CONNECTED;
168
[email protected]194c7a92011-12-03 04:54:18169 if (next_state_ == STATE_CLOSED && read_buffer_.empty()) {
[email protected]fe2f62a2010-10-01 03:34:07170 return 0;
171 }
172
[email protected]d9da5fe2010-10-13 22:37:16173 DCHECK(next_state_ == STATE_OPEN || next_state_ == STATE_CLOSED);
[email protected]fe2f62a2010-10-01 03:34:07174 DCHECK(buf);
175 user_buffer_ = new DrainableIOBuffer(buf, buf_len);
176 int result = PopulateUserReadBuffer();
177 if (result == 0) {
178 DCHECK(callback);
179 read_callback_ = callback;
180 return ERR_IO_PENDING;
181 }
182 user_buffer_ = NULL;
183 return result;
184}
185
186int SpdyProxyClientSocket::PopulateUserReadBuffer() {
187 if (!user_buffer_)
188 return ERR_IO_PENDING;
189
190 while (!read_buffer_.empty() && user_buffer_->BytesRemaining() > 0) {
191 scoped_refptr<DrainableIOBuffer> data = read_buffer_.front();
192 const int bytes_to_copy = std::min(user_buffer_->BytesRemaining(),
[email protected]87d3c4a2010-10-07 03:00:42193 data->BytesRemaining());
[email protected]fe2f62a2010-10-01 03:34:07194 memcpy(user_buffer_->data(), data->data(), bytes_to_copy);
195 user_buffer_->DidConsume(bytes_to_copy);
[email protected]d9da5fe2010-10-13 22:37:16196 if (data->BytesRemaining() == bytes_to_copy) {
[email protected]fe2f62a2010-10-01 03:34:07197 // Consumed all data from this buffer
198 read_buffer_.pop_front();
199 } else {
200 data->DidConsume(bytes_to_copy);
201 }
202 }
203
204 return user_buffer_->BytesConsumed();
205}
206
207int SpdyProxyClientSocket::Write(IOBuffer* buf, int buf_len,
[email protected]f1f3f0f82011-10-01 20:38:10208 OldCompletionCallback* callback) {
[email protected]fe2f62a2010-10-01 03:34:07209 DCHECK(!write_callback_);
[email protected]194c7a92011-12-03 04:54:18210 if (next_state_ != STATE_OPEN)
[email protected]d9da5fe2010-10-13 22:37:16211 return ERR_SOCKET_NOT_CONNECTED;
212
[email protected]194c7a92011-12-03 04:54:18213 DCHECK(spdy_stream_);
[email protected]fe2f62a2010-10-01 03:34:07214 write_bytes_outstanding_= buf_len;
215 if (buf_len <= kMaxSpdyFrameChunkSize) {
216 int rv = spdy_stream_->WriteStreamData(buf, buf_len, spdy::DATA_FLAG_NONE);
217 if (rv == ERR_IO_PENDING) {
218 write_callback_ = callback;
219 write_buffer_len_ = buf_len;
220 }
221 return rv;
222 }
223
224 // Since a SPDY Data frame can only include kMaxSpdyFrameChunkSize bytes
225 // we need to send multiple data frames
226 for (int i = 0; i < buf_len; i += kMaxSpdyFrameChunkSize) {
227 int len = std::min(kMaxSpdyFrameChunkSize, buf_len - i);
228 scoped_refptr<DrainableIOBuffer> iobuf(new DrainableIOBuffer(buf, i + len));
229 iobuf->SetOffset(i);
230 int rv = spdy_stream_->WriteStreamData(iobuf, len, spdy::DATA_FLAG_NONE);
231 if (rv > 0) {
232 write_bytes_outstanding_ -= rv;
233 } else if (rv != ERR_IO_PENDING) {
234 return rv;
235 }
236 }
237 if (write_bytes_outstanding_ > 0) {
238 write_callback_ = callback;
239 write_buffer_len_ = buf_len;
240 return ERR_IO_PENDING;
241 } else {
242 return buf_len;
243 }
244}
245
246bool SpdyProxyClientSocket::SetReceiveBufferSize(int32 size) {
[email protected]3268023f2011-05-05 00:08:10247 // Since this StreamSocket sits on top of a shared SpdySession, it
[email protected]fe2f62a2010-10-01 03:34:07248 // is not safe for callers to set change this underlying socket.
249 return false;
250}
251
252bool SpdyProxyClientSocket::SetSendBufferSize(int32 size) {
[email protected]3268023f2011-05-05 00:08:10253 // Since this StreamSocket sits on top of a shared SpdySession, it
[email protected]fe2f62a2010-10-01 03:34:07254 // is not safe for callers to set change this underlying socket.
255 return false;
256}
257
258int SpdyProxyClientSocket::GetPeerAddress(AddressList* address) const {
259 if (!IsConnected())
[email protected]88e03fa2010-10-05 03:09:04260 return ERR_SOCKET_NOT_CONNECTED;
[email protected]fe2f62a2010-10-01 03:34:07261 return spdy_stream_->GetPeerAddress(address);
262}
263
[email protected]e7f74da2011-04-19 23:49:35264int SpdyProxyClientSocket::GetLocalAddress(IPEndPoint* address) const {
265 if (!IsConnected())
266 return ERR_SOCKET_NOT_CONNECTED;
267 return spdy_stream_->GetLocalAddress(address);
268}
269
[email protected]fe2f62a2010-10-01 03:34:07270void SpdyProxyClientSocket::OnIOComplete(int result) {
[email protected]d9da5fe2010-10-13 22:37:16271 DCHECK_NE(STATE_DISCONNECTED, next_state_);
[email protected]fe2f62a2010-10-01 03:34:07272 int rv = DoLoop(result);
273 if (rv != ERR_IO_PENDING) {
[email protected]f1f3f0f82011-10-01 20:38:10274 OldCompletionCallback* c = read_callback_;
[email protected]fe2f62a2010-10-01 03:34:07275 read_callback_ = NULL;
276 c->Run(rv);
277 }
278}
279
280int SpdyProxyClientSocket::DoLoop(int last_io_result) {
[email protected]d9da5fe2010-10-13 22:37:16281 DCHECK_NE(next_state_, STATE_DISCONNECTED);
[email protected]fe2f62a2010-10-01 03:34:07282 int rv = last_io_result;
283 do {
284 State state = next_state_;
[email protected]d9da5fe2010-10-13 22:37:16285 next_state_ = STATE_DISCONNECTED;
[email protected]fe2f62a2010-10-01 03:34:07286 switch (state) {
287 case STATE_GENERATE_AUTH_TOKEN:
288 DCHECK_EQ(OK, rv);
289 rv = DoGenerateAuthToken();
290 break;
291 case STATE_GENERATE_AUTH_TOKEN_COMPLETE:
292 rv = DoGenerateAuthTokenComplete(rv);
293 break;
294 case STATE_SEND_REQUEST:
295 DCHECK_EQ(OK, rv);
[email protected]d7fd1782011-02-08 19:16:43296 net_log_.BeginEvent(
297 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST, NULL);
[email protected]fe2f62a2010-10-01 03:34:07298 rv = DoSendRequest();
299 break;
300 case STATE_SEND_REQUEST_COMPLETE:
[email protected]d7fd1782011-02-08 19:16:43301 net_log_.EndEventWithNetErrorCode(
302 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST, rv);
[email protected]fe2f62a2010-10-01 03:34:07303 rv = DoSendRequestComplete(rv);
[email protected]fe2f62a2010-10-01 03:34:07304 break;
305 case STATE_READ_REPLY_COMPLETE:
306 rv = DoReadReplyComplete(rv);
[email protected]d7fd1782011-02-08 19:16:43307 net_log_.EndEventWithNetErrorCode(
308 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_READ_HEADERS, rv);
[email protected]fe2f62a2010-10-01 03:34:07309 break;
310 default:
311 NOTREACHED() << "bad state";
312 rv = ERR_UNEXPECTED;
313 break;
314 }
[email protected]d9da5fe2010-10-13 22:37:16315 } while (rv != ERR_IO_PENDING && next_state_ != STATE_DISCONNECTED &&
316 next_state_ != STATE_OPEN);
[email protected]fe2f62a2010-10-01 03:34:07317 return rv;
318}
319
320int SpdyProxyClientSocket::DoGenerateAuthToken() {
321 next_state_ = STATE_GENERATE_AUTH_TOKEN_COMPLETE;
322 return auth_->MaybeGenerateAuthToken(&request_, &io_callback_, net_log_);
323}
324
325int SpdyProxyClientSocket::DoGenerateAuthTokenComplete(int result) {
326 DCHECK_NE(ERR_IO_PENDING, result);
327 if (result == OK)
328 next_state_ = STATE_SEND_REQUEST;
329 return result;
330}
331
332int SpdyProxyClientSocket::DoSendRequest() {
333 next_state_ = STATE_SEND_REQUEST_COMPLETE;
334
335 // Add Proxy-Authentication header if necessary.
336 HttpRequestHeaders authorization_headers;
337 if (auth_->HaveAuth()) {
338 auth_->AddAuthorizationHeader(&authorization_headers);
339 }
340
341 std::string request_line;
342 HttpRequestHeaders request_headers;
343 BuildTunnelRequest(request_, authorization_headers, endpoint_, &request_line,
344 &request_headers);
[email protected]465aeb942010-10-14 19:58:14345 if (net_log_.IsLoggingAllEvents()) {
[email protected]fe2f62a2010-10-01 03:34:07346 net_log_.AddEvent(
347 NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
[email protected]00cd9c42010-11-02 20:15:57348 make_scoped_refptr(new NetLogHttpRequestParameter(
349 request_line, request_headers)));
[email protected]fe2f62a2010-10-01 03:34:07350 }
351
352 request_.extra_headers.MergeFrom(request_headers);
353 linked_ptr<spdy::SpdyHeaderBlock> headers(new spdy::SpdyHeaderBlock());
[email protected]7213e7c2010-10-20 15:33:52354 CreateSpdyHeadersFromHttpRequest(request_, request_headers, headers.get(),
355 true);
[email protected]fe2f62a2010-10-01 03:34:07356 // Reset the URL to be the endpoint of the connection
357 (*headers)["url"] = endpoint_.ToString();
358 headers->erase("scheme");
359 spdy_stream_->set_spdy_headers(headers);
360
361 return spdy_stream_->SendRequest(true);
362}
363
364int SpdyProxyClientSocket::DoSendRequestComplete(int result) {
365 if (result < 0)
366 return result;
367
368 // Wait for SYN_REPLY frame from the server
369 next_state_ = STATE_READ_REPLY_COMPLETE;
370 return ERR_IO_PENDING;
371}
372
373int SpdyProxyClientSocket::DoReadReplyComplete(int result) {
374 // We enter this method directly from DoSendRequestComplete, since
375 // we are notified by a callback when the SYN_REPLY frame arrives
376
377 if (result < 0)
378 return result;
379
[email protected]fe2f62a2010-10-01 03:34:07380 // Require the "HTTP/1.x" status line for SSL CONNECT.
381 if (response_.headers->GetParsedHttpVersion() < HttpVersion(1, 0))
382 return ERR_TUNNEL_CONNECTION_FAILED;
383
[email protected]d9da5fe2010-10-13 22:37:16384 next_state_ = STATE_OPEN;
[email protected]465aeb942010-10-14 19:58:14385 if (net_log_.IsLoggingAllEvents()) {
[email protected]fe2f62a2010-10-01 03:34:07386 net_log_.AddEvent(
387 NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
[email protected]00cd9c42010-11-02 20:15:57388 make_scoped_refptr(new NetLogHttpResponseParameter(response_.headers)));
[email protected]fe2f62a2010-10-01 03:34:07389 }
390
[email protected]511f6f52010-12-17 03:58:29391 if (response_.headers->response_code() == 200) {
[email protected]fe2f62a2010-10-01 03:34:07392 return OK;
[email protected]511f6f52010-12-17 03:58:29393 } else if (response_.headers->response_code() == 407) {
[email protected]15a3c2082011-11-21 18:32:01394 int rv = HandleAuthChallenge(auth_, &response_, net_log_);
395 if (rv != ERR_PROXY_AUTH_REQUESTED) {
396 return rv;
397 }
398 // SPDY only supports basic and digest auth
399 if (auth_->auth_info() &&
400 (auth_->auth_info()->scheme == "basic" ||
401 auth_->auth_info()->scheme == "digest")) {
402 return ERR_PROXY_AUTH_REQUESTED;
403 }
[email protected]fe2f62a2010-10-01 03:34:07404 return ERR_TUNNEL_CONNECTION_FAILED;
[email protected]511f6f52010-12-17 03:58:29405 } else {
406 // Immediately hand off our SpdyStream to a newly created SpdyHttpStream
407 // so that any subsequent SpdyFrames are processed in the context of
408 // the HttpStream, not the socket.
409 DCHECK(spdy_stream_);
410 SpdyStream* stream = spdy_stream_;
411 spdy_stream_ = NULL;
412 response_stream_.reset(new SpdyHttpStream(NULL, false));
413 response_stream_->InitializeWithExistingStream(stream);
414 next_state_ = STATE_DISCONNECTED;
415 return ERR_HTTPS_PROXY_TUNNEL_RESPONSE;
416 }
[email protected]fe2f62a2010-10-01 03:34:07417}
418
419// SpdyStream::Delegate methods:
420// Called when SYN frame has been sent.
421// Returns true if no more data to be sent after SYN frame.
422bool SpdyProxyClientSocket::OnSendHeadersComplete(int status) {
423 DCHECK_EQ(next_state_, STATE_SEND_REQUEST_COMPLETE);
424
425 OnIOComplete(status);
426
427 // We return true here so that we send |spdy_stream_| into
428 // STATE_OPEN (ala WebSockets).
429 return true;
430}
431
432int SpdyProxyClientSocket::OnSendBody() {
433 // Because we use |spdy_stream_| via STATE_OPEN (ala WebSockets)
434 // OnSendBody() should never be called.
435 NOTREACHED();
436 return ERR_UNEXPECTED;
437}
438
[email protected]0c9bf872011-03-04 17:53:22439int SpdyProxyClientSocket::OnSendBodyComplete(int /*status*/, bool* /*eof*/) {
[email protected]fe2f62a2010-10-01 03:34:07440 // Because we use |spdy_stream_| via STATE_OPEN (ala WebSockets)
441 // OnSendBodyComplete() should never be called.
442 NOTREACHED();
[email protected]0c9bf872011-03-04 17:53:22443 return ERR_UNEXPECTED;
[email protected]fe2f62a2010-10-01 03:34:07444}
445
446int SpdyProxyClientSocket::OnResponseReceived(
447 const spdy::SpdyHeaderBlock& response,
448 base::Time response_time,
449 int status) {
[email protected]d08358502010-12-03 22:04:03450 // If we've already received the reply, existing headers are too late.
451 // TODO(mbelshe): figure out a way to make HEADERS frames useful after the
452 // initial response.
453 if (next_state_ != STATE_READ_REPLY_COMPLETE)
454 return OK;
[email protected]fe2f62a2010-10-01 03:34:07455
[email protected]d08358502010-12-03 22:04:03456 // Save the response
457 int rv = SpdyHeadersToHttpResponse(response, &response_);
458 if (rv == ERR_INCOMPLETE_SPDY_HEADERS)
459 return rv; // More headers are coming.
[email protected]fe2f62a2010-10-01 03:34:07460
461 OnIOComplete(status);
[email protected]fe2f62a2010-10-01 03:34:07462 return OK;
463}
464
465// Called when data is received.
466void SpdyProxyClientSocket::OnDataReceived(const char* data, int length) {
467 if (length > 0) {
468 // Save the received data.
[email protected]ad8e04a2010-11-01 04:16:27469 scoped_refptr<IOBuffer> io_buffer(new IOBuffer(length));
[email protected]fe2f62a2010-10-01 03:34:07470 memcpy(io_buffer->data(), data, length);
[email protected]00cd9c42010-11-02 20:15:57471 read_buffer_.push_back(
472 make_scoped_refptr(new DrainableIOBuffer(io_buffer, length)));
[email protected]fe2f62a2010-10-01 03:34:07473 }
474
475 if (read_callback_) {
476 int rv = PopulateUserReadBuffer();
[email protected]f1f3f0f82011-10-01 20:38:10477 OldCompletionCallback* c = read_callback_;
[email protected]fe2f62a2010-10-01 03:34:07478 read_callback_ = NULL;
479 user_buffer_ = NULL;
480 c->Run(rv);
481 }
482}
483
484void SpdyProxyClientSocket::OnDataSent(int length) {
485 DCHECK(write_callback_);
486
487 write_bytes_outstanding_ -= length;
488
489 DCHECK_GE(write_bytes_outstanding_, 0);
490
491 if (write_bytes_outstanding_ == 0) {
492 int rv = write_buffer_len_;
493 write_buffer_len_ = 0;
494 write_bytes_outstanding_ = 0;
[email protected]f1f3f0f82011-10-01 20:38:10495 OldCompletionCallback* c = write_callback_;
[email protected]fe2f62a2010-10-01 03:34:07496 write_callback_ = NULL;
497 c->Run(rv);
498 }
499}
500
501void SpdyProxyClientSocket::OnClose(int status) {
502 DCHECK(spdy_stream_);
[email protected]fe2f62a2010-10-01 03:34:07503 was_ever_used_ = spdy_stream_->WasEverUsed();
504 spdy_stream_ = NULL;
[email protected]d9da5fe2010-10-13 22:37:16505
506 bool connecting = next_state_ != STATE_DISCONNECTED &&
507 next_state_ < STATE_OPEN;
508 if (next_state_ == STATE_OPEN)
509 next_state_ = STATE_CLOSED;
510 else
511 next_state_ = STATE_DISCONNECTED;
512
[email protected]6af4e412011-11-29 23:39:18513 base::WeakPtr<SpdyProxyClientSocket> weak_ptr = weak_factory_.GetWeakPtr();
[email protected]f1f3f0f82011-10-01 20:38:10514 OldCompletionCallback* write_callback = write_callback_;
[email protected]fe2f62a2010-10-01 03:34:07515 write_callback_ = NULL;
[email protected]d9da5fe2010-10-13 22:37:16516 write_buffer_len_ = 0;
517 write_bytes_outstanding_ = 0;
518
519 // If we're in the middle of connecting, we need to make sure
520 // we invoke the connect callback.
521 if (connecting) {
522 DCHECK(read_callback_);
[email protected]f1f3f0f82011-10-01 20:38:10523 OldCompletionCallback* read_callback = read_callback_;
[email protected]d9da5fe2010-10-13 22:37:16524 read_callback_ = NULL;
525 read_callback->Run(status);
526 } else if (read_callback_) {
[email protected]6af4e412011-11-29 23:39:18527 // If we have a read_callback_, the we need to make sure we call it back.
[email protected]d9da5fe2010-10-13 22:37:16528 OnDataReceived(NULL, 0);
529 }
[email protected]6af4e412011-11-29 23:39:18530 // This may have been deleted by read_callback_, so check first.
531 if (weak_ptr && write_callback)
[email protected]d9da5fe2010-10-13 22:37:16532 write_callback->Run(ERR_CONNECTION_CLOSED);
[email protected]fe2f62a2010-10-01 03:34:07533}
534
[email protected]0c9bf872011-03-04 17:53:22535void SpdyProxyClientSocket::set_chunk_callback(ChunkCallback* /*callback*/) {
536}
537
[email protected]fe2f62a2010-10-01 03:34:07538} // namespace net