blob: 6ef88e78c27b94beda26c426d42a01d31ce432d0 [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),
47 eof_has_been_read_(false),
48 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]d9da5fe2010-10-13 22:37:16126 return next_state_ == STATE_OPEN || next_state_ == STATE_CLOSED;
[email protected]fe2f62a2010-10-01 03:34:07127}
128
129bool SpdyProxyClientSocket::IsConnectedAndIdle() const {
[email protected]43549a8f2011-05-16 23:37:15130 return IsConnected() && spdy_stream_.get() != NULL &&
131 !spdy_stream_->is_idle();
[email protected]fe2f62a2010-10-01 03:34:07132}
133
[email protected]e4be2dd2010-12-14 00:44:39134const BoundNetLog& SpdyProxyClientSocket::NetLog() const {
135 return net_log_;
136}
137
[email protected]fe2f62a2010-10-01 03:34:07138void SpdyProxyClientSocket::SetSubresourceSpeculation() {
139 // TODO(rch): what should this implementation be?
140}
141
142void SpdyProxyClientSocket::SetOmniboxSpeculation() {
143 // TODO(rch): what should this implementation be?
144}
145
146bool SpdyProxyClientSocket::WasEverUsed() const {
147 return was_ever_used_ || (spdy_stream_ && spdy_stream_->WasEverUsed());
148}
149
[email protected]7f7e92392010-10-26 18:29:29150bool SpdyProxyClientSocket::UsingTCPFastOpen() const {
151 return false;
152}
153
[email protected]5e6efa52011-06-27 17:26:41154int64 SpdyProxyClientSocket::NumBytesRead() const {
155 return -1;
156}
157
158base::TimeDelta SpdyProxyClientSocket::GetConnectTimeMicros() const {
159 return base::TimeDelta::FromMicroseconds(-1);
160}
161
[email protected]fe2f62a2010-10-01 03:34:07162int SpdyProxyClientSocket::Read(IOBuffer* buf, int buf_len,
[email protected]f1f3f0f82011-10-01 20:38:10163 OldCompletionCallback* callback) {
[email protected]fe2f62a2010-10-01 03:34:07164 DCHECK(!read_callback_);
165 DCHECK(!user_buffer_);
166
[email protected]d9da5fe2010-10-13 22:37:16167 if (next_state_ == STATE_DISCONNECTED)
168 return ERR_SOCKET_NOT_CONNECTED;
169
170 if (!spdy_stream_ && read_buffer_.empty()) {
[email protected]fe2f62a2010-10-01 03:34:07171 if (eof_has_been_read_)
172 return ERR_CONNECTION_CLOSED;
173 eof_has_been_read_ = true;
174 return 0;
175 }
176
[email protected]d9da5fe2010-10-13 22:37:16177 DCHECK(next_state_ == STATE_OPEN || next_state_ == STATE_CLOSED);
[email protected]fe2f62a2010-10-01 03:34:07178 DCHECK(buf);
179 user_buffer_ = new DrainableIOBuffer(buf, buf_len);
180 int result = PopulateUserReadBuffer();
181 if (result == 0) {
182 DCHECK(callback);
183 read_callback_ = callback;
184 return ERR_IO_PENDING;
185 }
186 user_buffer_ = NULL;
187 return result;
188}
189
190int SpdyProxyClientSocket::PopulateUserReadBuffer() {
191 if (!user_buffer_)
192 return ERR_IO_PENDING;
193
194 while (!read_buffer_.empty() && user_buffer_->BytesRemaining() > 0) {
195 scoped_refptr<DrainableIOBuffer> data = read_buffer_.front();
196 const int bytes_to_copy = std::min(user_buffer_->BytesRemaining(),
[email protected]87d3c4a2010-10-07 03:00:42197 data->BytesRemaining());
[email protected]fe2f62a2010-10-01 03:34:07198 memcpy(user_buffer_->data(), data->data(), bytes_to_copy);
199 user_buffer_->DidConsume(bytes_to_copy);
[email protected]d9da5fe2010-10-13 22:37:16200 if (data->BytesRemaining() == bytes_to_copy) {
[email protected]fe2f62a2010-10-01 03:34:07201 // Consumed all data from this buffer
202 read_buffer_.pop_front();
203 } else {
204 data->DidConsume(bytes_to_copy);
205 }
206 }
207
208 return user_buffer_->BytesConsumed();
209}
210
211int SpdyProxyClientSocket::Write(IOBuffer* buf, int buf_len,
[email protected]f1f3f0f82011-10-01 20:38:10212 OldCompletionCallback* callback) {
[email protected]fe2f62a2010-10-01 03:34:07213 DCHECK(!write_callback_);
[email protected]d9da5fe2010-10-13 22:37:16214 if (next_state_ == STATE_DISCONNECTED)
215 return ERR_SOCKET_NOT_CONNECTED;
216
[email protected]fe2f62a2010-10-01 03:34:07217 if (!spdy_stream_)
218 return ERR_CONNECTION_CLOSED;
219
220 write_bytes_outstanding_= buf_len;
221 if (buf_len <= kMaxSpdyFrameChunkSize) {
222 int rv = spdy_stream_->WriteStreamData(buf, buf_len, spdy::DATA_FLAG_NONE);
223 if (rv == ERR_IO_PENDING) {
224 write_callback_ = callback;
225 write_buffer_len_ = buf_len;
226 }
227 return rv;
228 }
229
230 // Since a SPDY Data frame can only include kMaxSpdyFrameChunkSize bytes
231 // we need to send multiple data frames
232 for (int i = 0; i < buf_len; i += kMaxSpdyFrameChunkSize) {
233 int len = std::min(kMaxSpdyFrameChunkSize, buf_len - i);
234 scoped_refptr<DrainableIOBuffer> iobuf(new DrainableIOBuffer(buf, i + len));
235 iobuf->SetOffset(i);
236 int rv = spdy_stream_->WriteStreamData(iobuf, len, spdy::DATA_FLAG_NONE);
237 if (rv > 0) {
238 write_bytes_outstanding_ -= rv;
239 } else if (rv != ERR_IO_PENDING) {
240 return rv;
241 }
242 }
243 if (write_bytes_outstanding_ > 0) {
244 write_callback_ = callback;
245 write_buffer_len_ = buf_len;
246 return ERR_IO_PENDING;
247 } else {
248 return buf_len;
249 }
250}
251
252bool SpdyProxyClientSocket::SetReceiveBufferSize(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
258bool SpdyProxyClientSocket::SetSendBufferSize(int32 size) {
[email protected]3268023f2011-05-05 00:08:10259 // Since this StreamSocket sits on top of a shared SpdySession, it
[email protected]fe2f62a2010-10-01 03:34:07260 // is not safe for callers to set change this underlying socket.
261 return false;
262}
263
264int SpdyProxyClientSocket::GetPeerAddress(AddressList* address) const {
265 if (!IsConnected())
[email protected]88e03fa2010-10-05 03:09:04266 return ERR_SOCKET_NOT_CONNECTED;
[email protected]fe2f62a2010-10-01 03:34:07267 return spdy_stream_->GetPeerAddress(address);
268}
269
[email protected]e7f74da2011-04-19 23:49:35270int SpdyProxyClientSocket::GetLocalAddress(IPEndPoint* address) const {
271 if (!IsConnected())
272 return ERR_SOCKET_NOT_CONNECTED;
273 return spdy_stream_->GetLocalAddress(address);
274}
275
[email protected]fe2f62a2010-10-01 03:34:07276void SpdyProxyClientSocket::OnIOComplete(int result) {
[email protected]d9da5fe2010-10-13 22:37:16277 DCHECK_NE(STATE_DISCONNECTED, next_state_);
[email protected]fe2f62a2010-10-01 03:34:07278 int rv = DoLoop(result);
279 if (rv != ERR_IO_PENDING) {
[email protected]f1f3f0f82011-10-01 20:38:10280 OldCompletionCallback* c = read_callback_;
[email protected]fe2f62a2010-10-01 03:34:07281 read_callback_ = NULL;
282 c->Run(rv);
283 }
284}
285
286int SpdyProxyClientSocket::DoLoop(int last_io_result) {
[email protected]d9da5fe2010-10-13 22:37:16287 DCHECK_NE(next_state_, STATE_DISCONNECTED);
[email protected]fe2f62a2010-10-01 03:34:07288 int rv = last_io_result;
289 do {
290 State state = next_state_;
[email protected]d9da5fe2010-10-13 22:37:16291 next_state_ = STATE_DISCONNECTED;
[email protected]fe2f62a2010-10-01 03:34:07292 switch (state) {
293 case STATE_GENERATE_AUTH_TOKEN:
294 DCHECK_EQ(OK, rv);
295 rv = DoGenerateAuthToken();
296 break;
297 case STATE_GENERATE_AUTH_TOKEN_COMPLETE:
298 rv = DoGenerateAuthTokenComplete(rv);
299 break;
300 case STATE_SEND_REQUEST:
301 DCHECK_EQ(OK, rv);
[email protected]d7fd1782011-02-08 19:16:43302 net_log_.BeginEvent(
303 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST, NULL);
[email protected]fe2f62a2010-10-01 03:34:07304 rv = DoSendRequest();
305 break;
306 case STATE_SEND_REQUEST_COMPLETE:
[email protected]d7fd1782011-02-08 19:16:43307 net_log_.EndEventWithNetErrorCode(
308 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST, rv);
[email protected]fe2f62a2010-10-01 03:34:07309 rv = DoSendRequestComplete(rv);
[email protected]fe2f62a2010-10-01 03:34:07310 break;
311 case STATE_READ_REPLY_COMPLETE:
312 rv = DoReadReplyComplete(rv);
[email protected]d7fd1782011-02-08 19:16:43313 net_log_.EndEventWithNetErrorCode(
314 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_READ_HEADERS, rv);
[email protected]fe2f62a2010-10-01 03:34:07315 break;
316 default:
317 NOTREACHED() << "bad state";
318 rv = ERR_UNEXPECTED;
319 break;
320 }
[email protected]d9da5fe2010-10-13 22:37:16321 } while (rv != ERR_IO_PENDING && next_state_ != STATE_DISCONNECTED &&
322 next_state_ != STATE_OPEN);
[email protected]fe2f62a2010-10-01 03:34:07323 return rv;
324}
325
326int SpdyProxyClientSocket::DoGenerateAuthToken() {
327 next_state_ = STATE_GENERATE_AUTH_TOKEN_COMPLETE;
328 return auth_->MaybeGenerateAuthToken(&request_, &io_callback_, net_log_);
329}
330
331int SpdyProxyClientSocket::DoGenerateAuthTokenComplete(int result) {
332 DCHECK_NE(ERR_IO_PENDING, result);
333 if (result == OK)
334 next_state_ = STATE_SEND_REQUEST;
335 return result;
336}
337
338int SpdyProxyClientSocket::DoSendRequest() {
339 next_state_ = STATE_SEND_REQUEST_COMPLETE;
340
341 // Add Proxy-Authentication header if necessary.
342 HttpRequestHeaders authorization_headers;
343 if (auth_->HaveAuth()) {
344 auth_->AddAuthorizationHeader(&authorization_headers);
345 }
346
347 std::string request_line;
348 HttpRequestHeaders request_headers;
349 BuildTunnelRequest(request_, authorization_headers, endpoint_, &request_line,
350 &request_headers);
[email protected]465aeb942010-10-14 19:58:14351 if (net_log_.IsLoggingAllEvents()) {
[email protected]fe2f62a2010-10-01 03:34:07352 net_log_.AddEvent(
353 NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
[email protected]00cd9c42010-11-02 20:15:57354 make_scoped_refptr(new NetLogHttpRequestParameter(
355 request_line, request_headers)));
[email protected]fe2f62a2010-10-01 03:34:07356 }
357
358 request_.extra_headers.MergeFrom(request_headers);
359 linked_ptr<spdy::SpdyHeaderBlock> headers(new spdy::SpdyHeaderBlock());
[email protected]7213e7c2010-10-20 15:33:52360 CreateSpdyHeadersFromHttpRequest(request_, request_headers, headers.get(),
361 true);
[email protected]fe2f62a2010-10-01 03:34:07362 // Reset the URL to be the endpoint of the connection
363 (*headers)["url"] = endpoint_.ToString();
364 headers->erase("scheme");
365 spdy_stream_->set_spdy_headers(headers);
366
367 return spdy_stream_->SendRequest(true);
368}
369
370int SpdyProxyClientSocket::DoSendRequestComplete(int result) {
371 if (result < 0)
372 return result;
373
374 // Wait for SYN_REPLY frame from the server
375 next_state_ = STATE_READ_REPLY_COMPLETE;
376 return ERR_IO_PENDING;
377}
378
379int SpdyProxyClientSocket::DoReadReplyComplete(int result) {
380 // We enter this method directly from DoSendRequestComplete, since
381 // we are notified by a callback when the SYN_REPLY frame arrives
382
383 if (result < 0)
384 return result;
385
[email protected]fe2f62a2010-10-01 03:34:07386 // Require the "HTTP/1.x" status line for SSL CONNECT.
387 if (response_.headers->GetParsedHttpVersion() < HttpVersion(1, 0))
388 return ERR_TUNNEL_CONNECTION_FAILED;
389
[email protected]d9da5fe2010-10-13 22:37:16390 next_state_ = STATE_OPEN;
[email protected]465aeb942010-10-14 19:58:14391 if (net_log_.IsLoggingAllEvents()) {
[email protected]fe2f62a2010-10-01 03:34:07392 net_log_.AddEvent(
393 NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
[email protected]00cd9c42010-11-02 20:15:57394 make_scoped_refptr(new NetLogHttpResponseParameter(response_.headers)));
[email protected]fe2f62a2010-10-01 03:34:07395 }
396
[email protected]511f6f52010-12-17 03:58:29397 if (response_.headers->response_code() == 200) {
[email protected]fe2f62a2010-10-01 03:34:07398 return OK;
[email protected]511f6f52010-12-17 03:58:29399 } else if (response_.headers->response_code() == 407) {
[email protected]15a3c2082011-11-21 18:32:01400 int rv = HandleAuthChallenge(auth_, &response_, net_log_);
401 if (rv != ERR_PROXY_AUTH_REQUESTED) {
402 return rv;
403 }
404 // SPDY only supports basic and digest auth
405 if (auth_->auth_info() &&
406 (auth_->auth_info()->scheme == "basic" ||
407 auth_->auth_info()->scheme == "digest")) {
408 return ERR_PROXY_AUTH_REQUESTED;
409 }
[email protected]fe2f62a2010-10-01 03:34:07410 return ERR_TUNNEL_CONNECTION_FAILED;
[email protected]511f6f52010-12-17 03:58:29411 } else {
412 // Immediately hand off our SpdyStream to a newly created SpdyHttpStream
413 // so that any subsequent SpdyFrames are processed in the context of
414 // the HttpStream, not the socket.
415 DCHECK(spdy_stream_);
416 SpdyStream* stream = spdy_stream_;
417 spdy_stream_ = NULL;
418 response_stream_.reset(new SpdyHttpStream(NULL, false));
419 response_stream_->InitializeWithExistingStream(stream);
420 next_state_ = STATE_DISCONNECTED;
421 return ERR_HTTPS_PROXY_TUNNEL_RESPONSE;
422 }
[email protected]fe2f62a2010-10-01 03:34:07423}
424
425// SpdyStream::Delegate methods:
426// Called when SYN frame has been sent.
427// Returns true if no more data to be sent after SYN frame.
428bool SpdyProxyClientSocket::OnSendHeadersComplete(int status) {
429 DCHECK_EQ(next_state_, STATE_SEND_REQUEST_COMPLETE);
430
431 OnIOComplete(status);
432
433 // We return true here so that we send |spdy_stream_| into
434 // STATE_OPEN (ala WebSockets).
435 return true;
436}
437
438int SpdyProxyClientSocket::OnSendBody() {
439 // Because we use |spdy_stream_| via STATE_OPEN (ala WebSockets)
440 // OnSendBody() should never be called.
441 NOTREACHED();
442 return ERR_UNEXPECTED;
443}
444
[email protected]0c9bf872011-03-04 17:53:22445int SpdyProxyClientSocket::OnSendBodyComplete(int /*status*/, bool* /*eof*/) {
[email protected]fe2f62a2010-10-01 03:34:07446 // Because we use |spdy_stream_| via STATE_OPEN (ala WebSockets)
447 // OnSendBodyComplete() should never be called.
448 NOTREACHED();
[email protected]0c9bf872011-03-04 17:53:22449 return ERR_UNEXPECTED;
[email protected]fe2f62a2010-10-01 03:34:07450}
451
452int SpdyProxyClientSocket::OnResponseReceived(
453 const spdy::SpdyHeaderBlock& response,
454 base::Time response_time,
455 int status) {
[email protected]d08358502010-12-03 22:04:03456 // If we've already received the reply, existing headers are too late.
457 // TODO(mbelshe): figure out a way to make HEADERS frames useful after the
458 // initial response.
459 if (next_state_ != STATE_READ_REPLY_COMPLETE)
460 return OK;
[email protected]fe2f62a2010-10-01 03:34:07461
[email protected]d08358502010-12-03 22:04:03462 // Save the response
463 int rv = SpdyHeadersToHttpResponse(response, &response_);
464 if (rv == ERR_INCOMPLETE_SPDY_HEADERS)
465 return rv; // More headers are coming.
[email protected]fe2f62a2010-10-01 03:34:07466
467 OnIOComplete(status);
[email protected]fe2f62a2010-10-01 03:34:07468 return OK;
469}
470
471// Called when data is received.
472void SpdyProxyClientSocket::OnDataReceived(const char* data, int length) {
473 if (length > 0) {
474 // Save the received data.
[email protected]ad8e04a2010-11-01 04:16:27475 scoped_refptr<IOBuffer> io_buffer(new IOBuffer(length));
[email protected]fe2f62a2010-10-01 03:34:07476 memcpy(io_buffer->data(), data, length);
[email protected]00cd9c42010-11-02 20:15:57477 read_buffer_.push_back(
478 make_scoped_refptr(new DrainableIOBuffer(io_buffer, length)));
[email protected]fe2f62a2010-10-01 03:34:07479 }
480
481 if (read_callback_) {
482 int rv = PopulateUserReadBuffer();
[email protected]f1f3f0f82011-10-01 20:38:10483 OldCompletionCallback* c = read_callback_;
[email protected]fe2f62a2010-10-01 03:34:07484 read_callback_ = NULL;
485 user_buffer_ = NULL;
486 c->Run(rv);
487 }
488}
489
490void SpdyProxyClientSocket::OnDataSent(int length) {
491 DCHECK(write_callback_);
492
493 write_bytes_outstanding_ -= length;
494
495 DCHECK_GE(write_bytes_outstanding_, 0);
496
497 if (write_bytes_outstanding_ == 0) {
498 int rv = write_buffer_len_;
499 write_buffer_len_ = 0;
500 write_bytes_outstanding_ = 0;
[email protected]f1f3f0f82011-10-01 20:38:10501 OldCompletionCallback* c = write_callback_;
[email protected]fe2f62a2010-10-01 03:34:07502 write_callback_ = NULL;
503 c->Run(rv);
504 }
505}
506
507void SpdyProxyClientSocket::OnClose(int status) {
508 DCHECK(spdy_stream_);
[email protected]fe2f62a2010-10-01 03:34:07509 was_ever_used_ = spdy_stream_->WasEverUsed();
510 spdy_stream_ = NULL;
[email protected]d9da5fe2010-10-13 22:37:16511
512 bool connecting = next_state_ != STATE_DISCONNECTED &&
513 next_state_ < STATE_OPEN;
514 if (next_state_ == STATE_OPEN)
515 next_state_ = STATE_CLOSED;
516 else
517 next_state_ = STATE_DISCONNECTED;
518
[email protected]f1f3f0f82011-10-01 20:38:10519 OldCompletionCallback* write_callback = write_callback_;
[email protected]fe2f62a2010-10-01 03:34:07520 write_callback_ = NULL;
[email protected]d9da5fe2010-10-13 22:37:16521 write_buffer_len_ = 0;
522 write_bytes_outstanding_ = 0;
523
524 // If we're in the middle of connecting, we need to make sure
525 // we invoke the connect callback.
526 if (connecting) {
527 DCHECK(read_callback_);
[email protected]f1f3f0f82011-10-01 20:38:10528 OldCompletionCallback* read_callback = read_callback_;
[email protected]d9da5fe2010-10-13 22:37:16529 read_callback_ = NULL;
530 read_callback->Run(status);
531 } else if (read_callback_) {
532 // If we have a read_callback, the we need to make sure we call it back
533 OnDataReceived(NULL, 0);
534 }
535 if (write_callback)
536 write_callback->Run(ERR_CONNECTION_CLOSED);
[email protected]fe2f62a2010-10-01 03:34:07537}
538
[email protected]0c9bf872011-03-04 17:53:22539void SpdyProxyClientSocket::set_chunk_callback(ChunkCallback* /*callback*/) {
540}
541
[email protected]fe2f62a2010-10-01 03:34:07542} // namespace net