blob: 484be0ca903961ab344d4cc5cce9e56984611a3c [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),
[email protected]6af4e412011-11-29 23:39:1848 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
[email protected]fe2f62a2010-10-01 03:34:0749 net_log_(spdy_stream->net_log()) {
50 request_.method = "CONNECT";
51 request_.url = url;
52 if (!user_agent.empty())
53 request_.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent,
54 user_agent);
55 spdy_stream_->SetDelegate(this);
56 was_ever_used_ = spdy_stream_->WasEverUsed();
57}
58
59SpdyProxyClientSocket::~SpdyProxyClientSocket() {
60 Disconnect();
61}
62
[email protected]be1a48b2011-01-20 00:12:1363const HttpResponseInfo* SpdyProxyClientSocket::GetConnectResponseInfo() const {
64 return response_.headers ? &response_ : NULL;
65}
66
[email protected]15a3c2082011-11-21 18:32:0167int SpdyProxyClientSocket::RestartWithAuth(OldCompletionCallback* callback) {
68 // A SPDY Stream can only handle a single request, so the underlying
69 // stream may not be reused and a new SpdyProxyClientSocket must be
70 // created (possibly on top of the same SPDY Session).
71 next_state_ = STATE_DISCONNECTED;
72 return OK;
73}
74
75const
76scoped_refptr<HttpAuthController>& SpdyProxyClientSocket::auth_controller() {
77 return auth_;
78}
79
[email protected]511f6f52010-12-17 03:58:2980HttpStream* SpdyProxyClientSocket::CreateConnectResponseStream() {
81 DCHECK(response_stream_.get());
82 return response_stream_.release();
83}
84
[email protected]fe2f62a2010-10-01 03:34:0785// Sends a SYN_STREAM frame to the proxy with a CONNECT request
86// for the specified endpoint. Waits for the server to send back
87// a SYN_REPLY frame. OK will be returned if the status is 200.
88// ERR_TUNNEL_CONNECTION_FAILED will be returned for any other status.
89// In any of these cases, Read() may be called to retrieve the HTTP
90// response body. Any other return values should be considered fatal.
91// TODO(rch): handle 407 proxy auth requested correctly, perhaps
92// by creating a new stream for the subsequent request.
93// TODO(rch): create a more appropriate error code to disambiguate
94// the HTTPS Proxy tunnel failure from an HTTP Proxy tunnel failure.
[email protected]f1f3f0f82011-10-01 20:38:1095int SpdyProxyClientSocket::Connect(OldCompletionCallback* callback) {
[email protected]fe2f62a2010-10-01 03:34:0796 DCHECK(!read_callback_);
[email protected]d9da5fe2010-10-13 22:37:1697 if (next_state_ == STATE_OPEN)
[email protected]fe2f62a2010-10-01 03:34:0798 return OK;
99
[email protected]d9da5fe2010-10-13 22:37:16100 DCHECK_EQ(STATE_DISCONNECTED, next_state_);
[email protected]fe2f62a2010-10-01 03:34:07101 next_state_ = STATE_GENERATE_AUTH_TOKEN;
102
103 int rv = DoLoop(OK);
104 if (rv == ERR_IO_PENDING)
105 read_callback_ = callback;
106 return rv;
107}
108
109void SpdyProxyClientSocket::Disconnect() {
[email protected]d9da5fe2010-10-13 22:37:16110 read_buffer_.clear();
111 user_buffer_ = NULL;
112 read_callback_ = NULL;
113
114 write_buffer_len_ = 0;
115 write_bytes_outstanding_ = 0;
116 write_callback_ = NULL;
117
118 next_state_ = STATE_DISCONNECTED;
119
[email protected]fe2f62a2010-10-01 03:34:07120 if (spdy_stream_)
121 // This will cause OnClose to be invoked, which takes care of
122 // cleaning up all the internal state.
123 spdy_stream_->Cancel();
124}
125
126bool SpdyProxyClientSocket::IsConnected() const {
[email protected]d9da5fe2010-10-13 22:37:16127 return next_state_ == STATE_OPEN || next_state_ == STATE_CLOSED;
[email protected]fe2f62a2010-10-01 03:34:07128}
129
130bool SpdyProxyClientSocket::IsConnectedAndIdle() const {
[email protected]43549a8f2011-05-16 23:37:15131 return IsConnected() && spdy_stream_.get() != NULL &&
132 !spdy_stream_->is_idle();
[email protected]fe2f62a2010-10-01 03:34:07133}
134
[email protected]e4be2dd2010-12-14 00:44:39135const BoundNetLog& SpdyProxyClientSocket::NetLog() const {
136 return net_log_;
137}
138
[email protected]fe2f62a2010-10-01 03:34:07139void SpdyProxyClientSocket::SetSubresourceSpeculation() {
140 // TODO(rch): what should this implementation be?
141}
142
143void SpdyProxyClientSocket::SetOmniboxSpeculation() {
144 // TODO(rch): what should this implementation be?
145}
146
147bool SpdyProxyClientSocket::WasEverUsed() const {
148 return was_ever_used_ || (spdy_stream_ && spdy_stream_->WasEverUsed());
149}
150
[email protected]7f7e92392010-10-26 18:29:29151bool SpdyProxyClientSocket::UsingTCPFastOpen() const {
152 return false;
153}
154
[email protected]5e6efa52011-06-27 17:26:41155int64 SpdyProxyClientSocket::NumBytesRead() const {
156 return -1;
157}
158
159base::TimeDelta SpdyProxyClientSocket::GetConnectTimeMicros() const {
160 return base::TimeDelta::FromMicroseconds(-1);
161}
162
[email protected]fe2f62a2010-10-01 03:34:07163int SpdyProxyClientSocket::Read(IOBuffer* buf, int buf_len,
[email protected]f1f3f0f82011-10-01 20:38:10164 OldCompletionCallback* callback) {
[email protected]fe2f62a2010-10-01 03:34:07165 DCHECK(!read_callback_);
166 DCHECK(!user_buffer_);
167
[email protected]d9da5fe2010-10-13 22:37:16168 if (next_state_ == STATE_DISCONNECTED)
169 return ERR_SOCKET_NOT_CONNECTED;
170
171 if (!spdy_stream_ && read_buffer_.empty()) {
[email protected]fe2f62a2010-10-01 03:34:07172 if (eof_has_been_read_)
173 return ERR_CONNECTION_CLOSED;
174 eof_has_been_read_ = true;
175 return 0;
176 }
177
[email protected]d9da5fe2010-10-13 22:37:16178 DCHECK(next_state_ == STATE_OPEN || next_state_ == STATE_CLOSED);
[email protected]fe2f62a2010-10-01 03:34:07179 DCHECK(buf);
180 user_buffer_ = new DrainableIOBuffer(buf, buf_len);
181 int result = PopulateUserReadBuffer();
182 if (result == 0) {
183 DCHECK(callback);
184 read_callback_ = callback;
185 return ERR_IO_PENDING;
186 }
187 user_buffer_ = NULL;
188 return result;
189}
190
191int SpdyProxyClientSocket::PopulateUserReadBuffer() {
192 if (!user_buffer_)
193 return ERR_IO_PENDING;
194
195 while (!read_buffer_.empty() && user_buffer_->BytesRemaining() > 0) {
196 scoped_refptr<DrainableIOBuffer> data = read_buffer_.front();
197 const int bytes_to_copy = std::min(user_buffer_->BytesRemaining(),
[email protected]87d3c4a2010-10-07 03:00:42198 data->BytesRemaining());
[email protected]fe2f62a2010-10-01 03:34:07199 memcpy(user_buffer_->data(), data->data(), bytes_to_copy);
200 user_buffer_->DidConsume(bytes_to_copy);
[email protected]d9da5fe2010-10-13 22:37:16201 if (data->BytesRemaining() == bytes_to_copy) {
[email protected]fe2f62a2010-10-01 03:34:07202 // Consumed all data from this buffer
203 read_buffer_.pop_front();
204 } else {
205 data->DidConsume(bytes_to_copy);
206 }
207 }
208
209 return user_buffer_->BytesConsumed();
210}
211
212int SpdyProxyClientSocket::Write(IOBuffer* buf, int buf_len,
[email protected]f1f3f0f82011-10-01 20:38:10213 OldCompletionCallback* callback) {
[email protected]fe2f62a2010-10-01 03:34:07214 DCHECK(!write_callback_);
[email protected]d9da5fe2010-10-13 22:37:16215 if (next_state_ == STATE_DISCONNECTED)
216 return ERR_SOCKET_NOT_CONNECTED;
217
[email protected]fe2f62a2010-10-01 03:34:07218 if (!spdy_stream_)
219 return ERR_CONNECTION_CLOSED;
220
221 write_bytes_outstanding_= buf_len;
222 if (buf_len <= kMaxSpdyFrameChunkSize) {
223 int rv = spdy_stream_->WriteStreamData(buf, buf_len, spdy::DATA_FLAG_NONE);
224 if (rv == ERR_IO_PENDING) {
225 write_callback_ = callback;
226 write_buffer_len_ = buf_len;
227 }
228 return rv;
229 }
230
231 // Since a SPDY Data frame can only include kMaxSpdyFrameChunkSize bytes
232 // we need to send multiple data frames
233 for (int i = 0; i < buf_len; i += kMaxSpdyFrameChunkSize) {
234 int len = std::min(kMaxSpdyFrameChunkSize, buf_len - i);
235 scoped_refptr<DrainableIOBuffer> iobuf(new DrainableIOBuffer(buf, i + len));
236 iobuf->SetOffset(i);
237 int rv = spdy_stream_->WriteStreamData(iobuf, len, spdy::DATA_FLAG_NONE);
238 if (rv > 0) {
239 write_bytes_outstanding_ -= rv;
240 } else if (rv != ERR_IO_PENDING) {
241 return rv;
242 }
243 }
244 if (write_bytes_outstanding_ > 0) {
245 write_callback_ = callback;
246 write_buffer_len_ = buf_len;
247 return ERR_IO_PENDING;
248 } else {
249 return buf_len;
250 }
251}
252
253bool SpdyProxyClientSocket::SetReceiveBufferSize(int32 size) {
[email protected]3268023f2011-05-05 00:08:10254 // Since this StreamSocket sits on top of a shared SpdySession, it
[email protected]fe2f62a2010-10-01 03:34:07255 // is not safe for callers to set change this underlying socket.
256 return false;
257}
258
259bool SpdyProxyClientSocket::SetSendBufferSize(int32 size) {
[email protected]3268023f2011-05-05 00:08:10260 // Since this StreamSocket sits on top of a shared SpdySession, it
[email protected]fe2f62a2010-10-01 03:34:07261 // is not safe for callers to set change this underlying socket.
262 return false;
263}
264
265int SpdyProxyClientSocket::GetPeerAddress(AddressList* address) const {
266 if (!IsConnected())
[email protected]88e03fa2010-10-05 03:09:04267 return ERR_SOCKET_NOT_CONNECTED;
[email protected]fe2f62a2010-10-01 03:34:07268 return spdy_stream_->GetPeerAddress(address);
269}
270
[email protected]e7f74da2011-04-19 23:49:35271int SpdyProxyClientSocket::GetLocalAddress(IPEndPoint* address) const {
272 if (!IsConnected())
273 return ERR_SOCKET_NOT_CONNECTED;
274 return spdy_stream_->GetLocalAddress(address);
275}
276
[email protected]fe2f62a2010-10-01 03:34:07277void SpdyProxyClientSocket::OnIOComplete(int result) {
[email protected]d9da5fe2010-10-13 22:37:16278 DCHECK_NE(STATE_DISCONNECTED, next_state_);
[email protected]fe2f62a2010-10-01 03:34:07279 int rv = DoLoop(result);
280 if (rv != ERR_IO_PENDING) {
[email protected]f1f3f0f82011-10-01 20:38:10281 OldCompletionCallback* c = read_callback_;
[email protected]fe2f62a2010-10-01 03:34:07282 read_callback_ = NULL;
283 c->Run(rv);
284 }
285}
286
287int SpdyProxyClientSocket::DoLoop(int last_io_result) {
[email protected]d9da5fe2010-10-13 22:37:16288 DCHECK_NE(next_state_, STATE_DISCONNECTED);
[email protected]fe2f62a2010-10-01 03:34:07289 int rv = last_io_result;
290 do {
291 State state = next_state_;
[email protected]d9da5fe2010-10-13 22:37:16292 next_state_ = STATE_DISCONNECTED;
[email protected]fe2f62a2010-10-01 03:34:07293 switch (state) {
294 case STATE_GENERATE_AUTH_TOKEN:
295 DCHECK_EQ(OK, rv);
296 rv = DoGenerateAuthToken();
297 break;
298 case STATE_GENERATE_AUTH_TOKEN_COMPLETE:
299 rv = DoGenerateAuthTokenComplete(rv);
300 break;
301 case STATE_SEND_REQUEST:
302 DCHECK_EQ(OK, rv);
[email protected]d7fd1782011-02-08 19:16:43303 net_log_.BeginEvent(
304 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST, NULL);
[email protected]fe2f62a2010-10-01 03:34:07305 rv = DoSendRequest();
306 break;
307 case STATE_SEND_REQUEST_COMPLETE:
[email protected]d7fd1782011-02-08 19:16:43308 net_log_.EndEventWithNetErrorCode(
309 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST, rv);
[email protected]fe2f62a2010-10-01 03:34:07310 rv = DoSendRequestComplete(rv);
[email protected]fe2f62a2010-10-01 03:34:07311 break;
312 case STATE_READ_REPLY_COMPLETE:
313 rv = DoReadReplyComplete(rv);
[email protected]d7fd1782011-02-08 19:16:43314 net_log_.EndEventWithNetErrorCode(
315 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_READ_HEADERS, rv);
[email protected]fe2f62a2010-10-01 03:34:07316 break;
317 default:
318 NOTREACHED() << "bad state";
319 rv = ERR_UNEXPECTED;
320 break;
321 }
[email protected]d9da5fe2010-10-13 22:37:16322 } while (rv != ERR_IO_PENDING && next_state_ != STATE_DISCONNECTED &&
323 next_state_ != STATE_OPEN);
[email protected]fe2f62a2010-10-01 03:34:07324 return rv;
325}
326
327int SpdyProxyClientSocket::DoGenerateAuthToken() {
328 next_state_ = STATE_GENERATE_AUTH_TOKEN_COMPLETE;
329 return auth_->MaybeGenerateAuthToken(&request_, &io_callback_, net_log_);
330}
331
332int SpdyProxyClientSocket::DoGenerateAuthTokenComplete(int result) {
333 DCHECK_NE(ERR_IO_PENDING, result);
334 if (result == OK)
335 next_state_ = STATE_SEND_REQUEST;
336 return result;
337}
338
339int SpdyProxyClientSocket::DoSendRequest() {
340 next_state_ = STATE_SEND_REQUEST_COMPLETE;
341
342 // Add Proxy-Authentication header if necessary.
343 HttpRequestHeaders authorization_headers;
344 if (auth_->HaveAuth()) {
345 auth_->AddAuthorizationHeader(&authorization_headers);
346 }
347
348 std::string request_line;
349 HttpRequestHeaders request_headers;
350 BuildTunnelRequest(request_, authorization_headers, endpoint_, &request_line,
351 &request_headers);
[email protected]465aeb942010-10-14 19:58:14352 if (net_log_.IsLoggingAllEvents()) {
[email protected]fe2f62a2010-10-01 03:34:07353 net_log_.AddEvent(
354 NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
[email protected]00cd9c42010-11-02 20:15:57355 make_scoped_refptr(new NetLogHttpRequestParameter(
356 request_line, request_headers)));
[email protected]fe2f62a2010-10-01 03:34:07357 }
358
359 request_.extra_headers.MergeFrom(request_headers);
360 linked_ptr<spdy::SpdyHeaderBlock> headers(new spdy::SpdyHeaderBlock());
[email protected]7213e7c2010-10-20 15:33:52361 CreateSpdyHeadersFromHttpRequest(request_, request_headers, headers.get(),
362 true);
[email protected]fe2f62a2010-10-01 03:34:07363 // Reset the URL to be the endpoint of the connection
364 (*headers)["url"] = endpoint_.ToString();
365 headers->erase("scheme");
366 spdy_stream_->set_spdy_headers(headers);
367
368 return spdy_stream_->SendRequest(true);
369}
370
371int SpdyProxyClientSocket::DoSendRequestComplete(int result) {
372 if (result < 0)
373 return result;
374
375 // Wait for SYN_REPLY frame from the server
376 next_state_ = STATE_READ_REPLY_COMPLETE;
377 return ERR_IO_PENDING;
378}
379
380int SpdyProxyClientSocket::DoReadReplyComplete(int result) {
381 // We enter this method directly from DoSendRequestComplete, since
382 // we are notified by a callback when the SYN_REPLY frame arrives
383
384 if (result < 0)
385 return result;
386
[email protected]fe2f62a2010-10-01 03:34:07387 // Require the "HTTP/1.x" status line for SSL CONNECT.
388 if (response_.headers->GetParsedHttpVersion() < HttpVersion(1, 0))
389 return ERR_TUNNEL_CONNECTION_FAILED;
390
[email protected]d9da5fe2010-10-13 22:37:16391 next_state_ = STATE_OPEN;
[email protected]465aeb942010-10-14 19:58:14392 if (net_log_.IsLoggingAllEvents()) {
[email protected]fe2f62a2010-10-01 03:34:07393 net_log_.AddEvent(
394 NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
[email protected]00cd9c42010-11-02 20:15:57395 make_scoped_refptr(new NetLogHttpResponseParameter(response_.headers)));
[email protected]fe2f62a2010-10-01 03:34:07396 }
397
[email protected]511f6f52010-12-17 03:58:29398 if (response_.headers->response_code() == 200) {
[email protected]fe2f62a2010-10-01 03:34:07399 return OK;
[email protected]511f6f52010-12-17 03:58:29400 } else if (response_.headers->response_code() == 407) {
[email protected]15a3c2082011-11-21 18:32:01401 int rv = HandleAuthChallenge(auth_, &response_, net_log_);
402 if (rv != ERR_PROXY_AUTH_REQUESTED) {
403 return rv;
404 }
405 // SPDY only supports basic and digest auth
406 if (auth_->auth_info() &&
407 (auth_->auth_info()->scheme == "basic" ||
408 auth_->auth_info()->scheme == "digest")) {
409 return ERR_PROXY_AUTH_REQUESTED;
410 }
[email protected]fe2f62a2010-10-01 03:34:07411 return ERR_TUNNEL_CONNECTION_FAILED;
[email protected]511f6f52010-12-17 03:58:29412 } else {
413 // Immediately hand off our SpdyStream to a newly created SpdyHttpStream
414 // so that any subsequent SpdyFrames are processed in the context of
415 // the HttpStream, not the socket.
416 DCHECK(spdy_stream_);
417 SpdyStream* stream = spdy_stream_;
418 spdy_stream_ = NULL;
419 response_stream_.reset(new SpdyHttpStream(NULL, false));
420 response_stream_->InitializeWithExistingStream(stream);
421 next_state_ = STATE_DISCONNECTED;
422 return ERR_HTTPS_PROXY_TUNNEL_RESPONSE;
423 }
[email protected]fe2f62a2010-10-01 03:34:07424}
425
426// SpdyStream::Delegate methods:
427// Called when SYN frame has been sent.
428// Returns true if no more data to be sent after SYN frame.
429bool SpdyProxyClientSocket::OnSendHeadersComplete(int status) {
430 DCHECK_EQ(next_state_, STATE_SEND_REQUEST_COMPLETE);
431
432 OnIOComplete(status);
433
434 // We return true here so that we send |spdy_stream_| into
435 // STATE_OPEN (ala WebSockets).
436 return true;
437}
438
439int SpdyProxyClientSocket::OnSendBody() {
440 // Because we use |spdy_stream_| via STATE_OPEN (ala WebSockets)
441 // OnSendBody() should never be called.
442 NOTREACHED();
443 return ERR_UNEXPECTED;
444}
445
[email protected]0c9bf872011-03-04 17:53:22446int SpdyProxyClientSocket::OnSendBodyComplete(int /*status*/, bool* /*eof*/) {
[email protected]fe2f62a2010-10-01 03:34:07447 // Because we use |spdy_stream_| via STATE_OPEN (ala WebSockets)
448 // OnSendBodyComplete() should never be called.
449 NOTREACHED();
[email protected]0c9bf872011-03-04 17:53:22450 return ERR_UNEXPECTED;
[email protected]fe2f62a2010-10-01 03:34:07451}
452
453int SpdyProxyClientSocket::OnResponseReceived(
454 const spdy::SpdyHeaderBlock& response,
455 base::Time response_time,
456 int status) {
[email protected]d08358502010-12-03 22:04:03457 // If we've already received the reply, existing headers are too late.
458 // TODO(mbelshe): figure out a way to make HEADERS frames useful after the
459 // initial response.
460 if (next_state_ != STATE_READ_REPLY_COMPLETE)
461 return OK;
[email protected]fe2f62a2010-10-01 03:34:07462
[email protected]d08358502010-12-03 22:04:03463 // Save the response
464 int rv = SpdyHeadersToHttpResponse(response, &response_);
465 if (rv == ERR_INCOMPLETE_SPDY_HEADERS)
466 return rv; // More headers are coming.
[email protected]fe2f62a2010-10-01 03:34:07467
468 OnIOComplete(status);
[email protected]fe2f62a2010-10-01 03:34:07469 return OK;
470}
471
472// Called when data is received.
473void SpdyProxyClientSocket::OnDataReceived(const char* data, int length) {
474 if (length > 0) {
475 // Save the received data.
[email protected]ad8e04a2010-11-01 04:16:27476 scoped_refptr<IOBuffer> io_buffer(new IOBuffer(length));
[email protected]fe2f62a2010-10-01 03:34:07477 memcpy(io_buffer->data(), data, length);
[email protected]00cd9c42010-11-02 20:15:57478 read_buffer_.push_back(
479 make_scoped_refptr(new DrainableIOBuffer(io_buffer, length)));
[email protected]fe2f62a2010-10-01 03:34:07480 }
481
482 if (read_callback_) {
483 int rv = PopulateUserReadBuffer();
[email protected]f1f3f0f82011-10-01 20:38:10484 OldCompletionCallback* c = read_callback_;
[email protected]fe2f62a2010-10-01 03:34:07485 read_callback_ = NULL;
486 user_buffer_ = NULL;
487 c->Run(rv);
488 }
489}
490
491void SpdyProxyClientSocket::OnDataSent(int length) {
492 DCHECK(write_callback_);
493
494 write_bytes_outstanding_ -= length;
495
496 DCHECK_GE(write_bytes_outstanding_, 0);
497
498 if (write_bytes_outstanding_ == 0) {
499 int rv = write_buffer_len_;
500 write_buffer_len_ = 0;
501 write_bytes_outstanding_ = 0;
[email protected]f1f3f0f82011-10-01 20:38:10502 OldCompletionCallback* c = write_callback_;
[email protected]fe2f62a2010-10-01 03:34:07503 write_callback_ = NULL;
504 c->Run(rv);
505 }
506}
507
508void SpdyProxyClientSocket::OnClose(int status) {
509 DCHECK(spdy_stream_);
[email protected]fe2f62a2010-10-01 03:34:07510 was_ever_used_ = spdy_stream_->WasEverUsed();
511 spdy_stream_ = NULL;
[email protected]d9da5fe2010-10-13 22:37:16512
513 bool connecting = next_state_ != STATE_DISCONNECTED &&
514 next_state_ < STATE_OPEN;
515 if (next_state_ == STATE_OPEN)
516 next_state_ = STATE_CLOSED;
517 else
518 next_state_ = STATE_DISCONNECTED;
519
[email protected]6af4e412011-11-29 23:39:18520 base::WeakPtr<SpdyProxyClientSocket> weak_ptr = weak_factory_.GetWeakPtr();
[email protected]f1f3f0f82011-10-01 20:38:10521 OldCompletionCallback* write_callback = write_callback_;
[email protected]fe2f62a2010-10-01 03:34:07522 write_callback_ = NULL;
[email protected]d9da5fe2010-10-13 22:37:16523 write_buffer_len_ = 0;
524 write_bytes_outstanding_ = 0;
525
526 // If we're in the middle of connecting, we need to make sure
527 // we invoke the connect callback.
528 if (connecting) {
529 DCHECK(read_callback_);
[email protected]f1f3f0f82011-10-01 20:38:10530 OldCompletionCallback* read_callback = read_callback_;
[email protected]d9da5fe2010-10-13 22:37:16531 read_callback_ = NULL;
532 read_callback->Run(status);
533 } else if (read_callback_) {
[email protected]6af4e412011-11-29 23:39:18534 // If we have a read_callback_, the we need to make sure we call it back.
[email protected]d9da5fe2010-10-13 22:37:16535 OnDataReceived(NULL, 0);
536 }
[email protected]6af4e412011-11-29 23:39:18537 // This may have been deleted by read_callback_, so check first.
538 if (weak_ptr && write_callback)
[email protected]d9da5fe2010-10-13 22:37:16539 write_callback->Run(ERR_CONNECTION_CLOSED);
[email protected]fe2f62a2010-10-01 03:34:07540}
541
[email protected]0c9bf872011-03-04 17:53:22542void SpdyProxyClientSocket::set_chunk_callback(ChunkCallback* /*callback*/) {
543}
544
[email protected]fe2f62a2010-10-01 03:34:07545} // namespace net