blob: 7267fefeaf3b322a71fa3d4aa479bec17d831c4c [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
[email protected]49639fa2011-12-20 23:22:419#include "base/bind.h"
10#include "base/bind_helpers.h"
[email protected]fe2f62a2010-10-01 03:34:0711#include "base/logging.h"
12#include "base/string_util.h"
13#include "googleurl/src/gurl.h"
14#include "net/base/auth.h"
15#include "net/base/io_buffer.h"
16#include "net/base/net_util.h"
17#include "net/http/http_auth_cache.h"
18#include "net/http/http_auth_handler_factory.h"
19#include "net/http/http_net_log_params.h"
20#include "net/http/http_proxy_utils.h"
[email protected]b104b502010-10-18 20:21:3121#include "net/http/http_response_headers.h"
[email protected]fe2f62a2010-10-01 03:34:0722#include "net/spdy/spdy_http_utils.h"
23
24namespace net {
25
26SpdyProxyClientSocket::SpdyProxyClientSocket(
27 SpdyStream* spdy_stream,
28 const std::string& user_agent,
29 const HostPortPair& endpoint,
30 const GURL& url,
31 const HostPortPair& proxy_server,
32 HttpAuthCache* auth_cache,
33 HttpAuthHandlerFactory* auth_handler_factory)
[email protected]49639fa2011-12-20 23:22:4134 : next_state_(STATE_DISCONNECTED),
[email protected]fe2f62a2010-10-01 03:34:0735 spdy_stream_(spdy_stream),
[email protected]fe2f62a2010-10-01 03:34:0736 endpoint_(endpoint),
37 auth_(
38 new HttpAuthController(HttpAuth::AUTH_PROXY,
[email protected]e9fa5482011-07-08 18:29:1139 GURL("https://" + proxy_server.ToString()),
[email protected]fe2f62a2010-10-01 03:34:0740 auth_cache,
41 auth_handler_factory)),
42 user_buffer_(NULL),
43 write_buffer_len_(0),
44 write_bytes_outstanding_(0),
[email protected]6af4e412011-11-29 23:39:1845 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
[email protected]fe2f62a2010-10-01 03:34:0746 net_log_(spdy_stream->net_log()) {
47 request_.method = "CONNECT";
48 request_.url = url;
49 if (!user_agent.empty())
50 request_.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent,
51 user_agent);
52 spdy_stream_->SetDelegate(this);
53 was_ever_used_ = spdy_stream_->WasEverUsed();
54}
55
56SpdyProxyClientSocket::~SpdyProxyClientSocket() {
57 Disconnect();
58}
59
[email protected]be1a48b2011-01-20 00:12:1360const HttpResponseInfo* SpdyProxyClientSocket::GetConnectResponseInfo() const {
61 return response_.headers ? &response_ : NULL;
62}
63
[email protected]511f6f52010-12-17 03:58:2964HttpStream* SpdyProxyClientSocket::CreateConnectResponseStream() {
65 DCHECK(response_stream_.get());
66 return response_stream_.release();
67}
68
[email protected]fe2f62a2010-10-01 03:34:0769// Sends a SYN_STREAM frame to the proxy with a CONNECT request
70// for the specified endpoint. Waits for the server to send back
71// a SYN_REPLY frame. OK will be returned if the status is 200.
72// ERR_TUNNEL_CONNECTION_FAILED will be returned for any other status.
73// In any of these cases, Read() may be called to retrieve the HTTP
74// response body. Any other return values should be considered fatal.
75// TODO(rch): handle 407 proxy auth requested correctly, perhaps
76// by creating a new stream for the subsequent request.
77// TODO(rch): create a more appropriate error code to disambiguate
78// the HTTPS Proxy tunnel failure from an HTTP Proxy tunnel failure.
[email protected]dbf036f2011-12-06 23:33:2479int SpdyProxyClientSocket::Connect(const CompletionCallback& callback) {
[email protected]83039bb2011-12-09 18:43:5580 DCHECK(read_callback_.is_null());
[email protected]d9da5fe2010-10-13 22:37:1681 if (next_state_ == STATE_OPEN)
[email protected]fe2f62a2010-10-01 03:34:0782 return OK;
83
[email protected]d9da5fe2010-10-13 22:37:1684 DCHECK_EQ(STATE_DISCONNECTED, next_state_);
[email protected]fe2f62a2010-10-01 03:34:0785 next_state_ = STATE_GENERATE_AUTH_TOKEN;
86
87 int rv = DoLoop(OK);
88 if (rv == ERR_IO_PENDING)
89 read_callback_ = callback;
90 return rv;
91}
92
93void SpdyProxyClientSocket::Disconnect() {
[email protected]d9da5fe2010-10-13 22:37:1694 read_buffer_.clear();
95 user_buffer_ = NULL;
[email protected]dbf036f2011-12-06 23:33:2496 read_callback_.Reset();
[email protected]d9da5fe2010-10-13 22:37:1697
98 write_buffer_len_ = 0;
99 write_bytes_outstanding_ = 0;
[email protected]83039bb2011-12-09 18:43:55100 write_callback_.Reset();
[email protected]d9da5fe2010-10-13 22:37:16101
102 next_state_ = STATE_DISCONNECTED;
103
[email protected]fe2f62a2010-10-01 03:34:07104 if (spdy_stream_)
105 // This will cause OnClose to be invoked, which takes care of
106 // cleaning up all the internal state.
107 spdy_stream_->Cancel();
108}
109
110bool SpdyProxyClientSocket::IsConnected() const {
[email protected]194c7a92011-12-03 04:54:18111 return next_state_ == STATE_OPEN;
[email protected]fe2f62a2010-10-01 03:34:07112}
113
114bool SpdyProxyClientSocket::IsConnectedAndIdle() const {
[email protected]194c7a92011-12-03 04:54:18115 return IsConnected() && read_buffer_.empty() && spdy_stream_->is_idle();
[email protected]fe2f62a2010-10-01 03:34:07116}
117
[email protected]e4be2dd2010-12-14 00:44:39118const BoundNetLog& SpdyProxyClientSocket::NetLog() const {
119 return net_log_;
120}
121
[email protected]fe2f62a2010-10-01 03:34:07122void SpdyProxyClientSocket::SetSubresourceSpeculation() {
123 // TODO(rch): what should this implementation be?
124}
125
126void SpdyProxyClientSocket::SetOmniboxSpeculation() {
127 // TODO(rch): what should this implementation be?
128}
129
130bool SpdyProxyClientSocket::WasEverUsed() const {
131 return was_ever_used_ || (spdy_stream_ && spdy_stream_->WasEverUsed());
132}
133
[email protected]7f7e92392010-10-26 18:29:29134bool SpdyProxyClientSocket::UsingTCPFastOpen() const {
135 return false;
136}
137
[email protected]5e6efa52011-06-27 17:26:41138int64 SpdyProxyClientSocket::NumBytesRead() const {
139 return -1;
140}
141
142base::TimeDelta SpdyProxyClientSocket::GetConnectTimeMicros() const {
143 return base::TimeDelta::FromMicroseconds(-1);
144}
145
[email protected]fe2f62a2010-10-01 03:34:07146int SpdyProxyClientSocket::Read(IOBuffer* buf, int buf_len,
[email protected]3f55aa12011-12-07 02:03:33147 const CompletionCallback& callback) {
[email protected]83039bb2011-12-09 18:43:55148 DCHECK(read_callback_.is_null());
[email protected]3f55aa12011-12-07 02:03:33149 DCHECK(!user_buffer_);
150
151 if (next_state_ == STATE_DISCONNECTED)
152 return ERR_SOCKET_NOT_CONNECTED;
153
154 if (next_state_ == STATE_CLOSED && read_buffer_.empty()) {
155 return 0;
156 }
157
158 DCHECK(next_state_ == STATE_OPEN || next_state_ == STATE_CLOSED);
159 DCHECK(buf);
160 user_buffer_ = new DrainableIOBuffer(buf, buf_len);
161 int result = PopulateUserReadBuffer();
162 if (result == 0) {
163 DCHECK(!callback.is_null());
164 read_callback_ = callback;
165 return ERR_IO_PENDING;
166 }
167 user_buffer_ = NULL;
168 return result;
169}
[email protected]fe2f62a2010-10-01 03:34:07170
171int SpdyProxyClientSocket::PopulateUserReadBuffer() {
172 if (!user_buffer_)
173 return ERR_IO_PENDING;
174
175 while (!read_buffer_.empty() && user_buffer_->BytesRemaining() > 0) {
176 scoped_refptr<DrainableIOBuffer> data = read_buffer_.front();
177 const int bytes_to_copy = std::min(user_buffer_->BytesRemaining(),
[email protected]87d3c4a2010-10-07 03:00:42178 data->BytesRemaining());
[email protected]fe2f62a2010-10-01 03:34:07179 memcpy(user_buffer_->data(), data->data(), bytes_to_copy);
180 user_buffer_->DidConsume(bytes_to_copy);
[email protected]d9da5fe2010-10-13 22:37:16181 if (data->BytesRemaining() == bytes_to_copy) {
[email protected]fe2f62a2010-10-01 03:34:07182 // Consumed all data from this buffer
183 read_buffer_.pop_front();
184 } else {
185 data->DidConsume(bytes_to_copy);
186 }
187 }
188
189 return user_buffer_->BytesConsumed();
190}
191
192int SpdyProxyClientSocket::Write(IOBuffer* buf, int buf_len,
[email protected]83039bb2011-12-09 18:43:55193 const CompletionCallback& callback) {
194 DCHECK(write_callback_.is_null());
[email protected]194c7a92011-12-03 04:54:18195 if (next_state_ != STATE_OPEN)
[email protected]d9da5fe2010-10-13 22:37:16196 return ERR_SOCKET_NOT_CONNECTED;
197
[email protected]194c7a92011-12-03 04:54:18198 DCHECK(spdy_stream_);
[email protected]fe2f62a2010-10-01 03:34:07199 write_bytes_outstanding_= buf_len;
200 if (buf_len <= kMaxSpdyFrameChunkSize) {
201 int rv = spdy_stream_->WriteStreamData(buf, buf_len, spdy::DATA_FLAG_NONE);
202 if (rv == ERR_IO_PENDING) {
203 write_callback_ = callback;
204 write_buffer_len_ = buf_len;
205 }
206 return rv;
207 }
208
209 // Since a SPDY Data frame can only include kMaxSpdyFrameChunkSize bytes
210 // we need to send multiple data frames
211 for (int i = 0; i < buf_len; i += kMaxSpdyFrameChunkSize) {
212 int len = std::min(kMaxSpdyFrameChunkSize, buf_len - i);
213 scoped_refptr<DrainableIOBuffer> iobuf(new DrainableIOBuffer(buf, i + len));
214 iobuf->SetOffset(i);
215 int rv = spdy_stream_->WriteStreamData(iobuf, len, spdy::DATA_FLAG_NONE);
216 if (rv > 0) {
217 write_bytes_outstanding_ -= rv;
218 } else if (rv != ERR_IO_PENDING) {
219 return rv;
220 }
221 }
222 if (write_bytes_outstanding_ > 0) {
223 write_callback_ = callback;
224 write_buffer_len_ = buf_len;
225 return ERR_IO_PENDING;
226 } else {
227 return buf_len;
228 }
229}
230
231bool SpdyProxyClientSocket::SetReceiveBufferSize(int32 size) {
[email protected]3268023f2011-05-05 00:08:10232 // Since this StreamSocket sits on top of a shared SpdySession, it
[email protected]fe2f62a2010-10-01 03:34:07233 // is not safe for callers to set change this underlying socket.
234 return false;
235}
236
237bool SpdyProxyClientSocket::SetSendBufferSize(int32 size) {
[email protected]3268023f2011-05-05 00:08:10238 // Since this StreamSocket sits on top of a shared SpdySession, it
[email protected]fe2f62a2010-10-01 03:34:07239 // is not safe for callers to set change this underlying socket.
240 return false;
241}
242
243int SpdyProxyClientSocket::GetPeerAddress(AddressList* address) const {
244 if (!IsConnected())
[email protected]88e03fa2010-10-05 03:09:04245 return ERR_SOCKET_NOT_CONNECTED;
[email protected]fe2f62a2010-10-01 03:34:07246 return spdy_stream_->GetPeerAddress(address);
247}
248
[email protected]e7f74da2011-04-19 23:49:35249int SpdyProxyClientSocket::GetLocalAddress(IPEndPoint* address) const {
250 if (!IsConnected())
251 return ERR_SOCKET_NOT_CONNECTED;
252 return spdy_stream_->GetLocalAddress(address);
253}
254
[email protected]fe2f62a2010-10-01 03:34:07255void SpdyProxyClientSocket::OnIOComplete(int result) {
[email protected]d9da5fe2010-10-13 22:37:16256 DCHECK_NE(STATE_DISCONNECTED, next_state_);
[email protected]fe2f62a2010-10-01 03:34:07257 int rv = DoLoop(result);
258 if (rv != ERR_IO_PENDING) {
[email protected]83039bb2011-12-09 18:43:55259 CompletionCallback c = read_callback_;
260 read_callback_.Reset();
261 c.Run(rv);
[email protected]fe2f62a2010-10-01 03:34:07262 }
263}
264
265int SpdyProxyClientSocket::DoLoop(int last_io_result) {
[email protected]d9da5fe2010-10-13 22:37:16266 DCHECK_NE(next_state_, STATE_DISCONNECTED);
[email protected]fe2f62a2010-10-01 03:34:07267 int rv = last_io_result;
268 do {
269 State state = next_state_;
[email protected]d9da5fe2010-10-13 22:37:16270 next_state_ = STATE_DISCONNECTED;
[email protected]fe2f62a2010-10-01 03:34:07271 switch (state) {
272 case STATE_GENERATE_AUTH_TOKEN:
273 DCHECK_EQ(OK, rv);
274 rv = DoGenerateAuthToken();
275 break;
276 case STATE_GENERATE_AUTH_TOKEN_COMPLETE:
277 rv = DoGenerateAuthTokenComplete(rv);
278 break;
279 case STATE_SEND_REQUEST:
280 DCHECK_EQ(OK, rv);
[email protected]d7fd1782011-02-08 19:16:43281 net_log_.BeginEvent(
282 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST, NULL);
[email protected]fe2f62a2010-10-01 03:34:07283 rv = DoSendRequest();
284 break;
285 case STATE_SEND_REQUEST_COMPLETE:
[email protected]d7fd1782011-02-08 19:16:43286 net_log_.EndEventWithNetErrorCode(
287 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST, rv);
[email protected]fe2f62a2010-10-01 03:34:07288 rv = DoSendRequestComplete(rv);
[email protected]fe2f62a2010-10-01 03:34:07289 break;
290 case STATE_READ_REPLY_COMPLETE:
291 rv = DoReadReplyComplete(rv);
[email protected]d7fd1782011-02-08 19:16:43292 net_log_.EndEventWithNetErrorCode(
293 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_READ_HEADERS, rv);
[email protected]fe2f62a2010-10-01 03:34:07294 break;
295 default:
296 NOTREACHED() << "bad state";
297 rv = ERR_UNEXPECTED;
298 break;
299 }
[email protected]d9da5fe2010-10-13 22:37:16300 } while (rv != ERR_IO_PENDING && next_state_ != STATE_DISCONNECTED &&
301 next_state_ != STATE_OPEN);
[email protected]fe2f62a2010-10-01 03:34:07302 return rv;
303}
304
305int SpdyProxyClientSocket::DoGenerateAuthToken() {
306 next_state_ = STATE_GENERATE_AUTH_TOKEN_COMPLETE;
[email protected]49639fa2011-12-20 23:22:41307 return auth_->MaybeGenerateAuthToken(
308 &request_,
309 base::Bind(&SpdyProxyClientSocket::OnIOComplete, base::Unretained(this)),
310 net_log_);
[email protected]fe2f62a2010-10-01 03:34:07311}
312
313int SpdyProxyClientSocket::DoGenerateAuthTokenComplete(int result) {
314 DCHECK_NE(ERR_IO_PENDING, result);
315 if (result == OK)
316 next_state_ = STATE_SEND_REQUEST;
317 return result;
318}
319
320int SpdyProxyClientSocket::DoSendRequest() {
321 next_state_ = STATE_SEND_REQUEST_COMPLETE;
322
323 // Add Proxy-Authentication header if necessary.
324 HttpRequestHeaders authorization_headers;
325 if (auth_->HaveAuth()) {
326 auth_->AddAuthorizationHeader(&authorization_headers);
327 }
328
329 std::string request_line;
330 HttpRequestHeaders request_headers;
331 BuildTunnelRequest(request_, authorization_headers, endpoint_, &request_line,
332 &request_headers);
[email protected]465aeb942010-10-14 19:58:14333 if (net_log_.IsLoggingAllEvents()) {
[email protected]fe2f62a2010-10-01 03:34:07334 net_log_.AddEvent(
335 NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
[email protected]00cd9c42010-11-02 20:15:57336 make_scoped_refptr(new NetLogHttpRequestParameter(
337 request_line, request_headers)));
[email protected]fe2f62a2010-10-01 03:34:07338 }
339
340 request_.extra_headers.MergeFrom(request_headers);
341 linked_ptr<spdy::SpdyHeaderBlock> headers(new spdy::SpdyHeaderBlock());
[email protected]7213e7c2010-10-20 15:33:52342 CreateSpdyHeadersFromHttpRequest(request_, request_headers, headers.get(),
343 true);
[email protected]fe2f62a2010-10-01 03:34:07344 // Reset the URL to be the endpoint of the connection
345 (*headers)["url"] = endpoint_.ToString();
346 headers->erase("scheme");
347 spdy_stream_->set_spdy_headers(headers);
348
349 return spdy_stream_->SendRequest(true);
350}
351
352int SpdyProxyClientSocket::DoSendRequestComplete(int result) {
353 if (result < 0)
354 return result;
355
356 // Wait for SYN_REPLY frame from the server
357 next_state_ = STATE_READ_REPLY_COMPLETE;
358 return ERR_IO_PENDING;
359}
360
361int SpdyProxyClientSocket::DoReadReplyComplete(int result) {
362 // We enter this method directly from DoSendRequestComplete, since
363 // we are notified by a callback when the SYN_REPLY frame arrives
364
365 if (result < 0)
366 return result;
367
[email protected]fe2f62a2010-10-01 03:34:07368 // Require the "HTTP/1.x" status line for SSL CONNECT.
369 if (response_.headers->GetParsedHttpVersion() < HttpVersion(1, 0))
370 return ERR_TUNNEL_CONNECTION_FAILED;
371
[email protected]d9da5fe2010-10-13 22:37:16372 next_state_ = STATE_OPEN;
[email protected]465aeb942010-10-14 19:58:14373 if (net_log_.IsLoggingAllEvents()) {
[email protected]fe2f62a2010-10-01 03:34:07374 net_log_.AddEvent(
375 NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
[email protected]00cd9c42010-11-02 20:15:57376 make_scoped_refptr(new NetLogHttpResponseParameter(response_.headers)));
[email protected]fe2f62a2010-10-01 03:34:07377 }
378
[email protected]511f6f52010-12-17 03:58:29379 if (response_.headers->response_code() == 200) {
[email protected]fe2f62a2010-10-01 03:34:07380 return OK;
[email protected]511f6f52010-12-17 03:58:29381 } else if (response_.headers->response_code() == 407) {
[email protected]fe2f62a2010-10-01 03:34:07382 return ERR_TUNNEL_CONNECTION_FAILED;
[email protected]511f6f52010-12-17 03:58:29383 } else {
384 // Immediately hand off our SpdyStream to a newly created SpdyHttpStream
385 // so that any subsequent SpdyFrames are processed in the context of
386 // the HttpStream, not the socket.
387 DCHECK(spdy_stream_);
388 SpdyStream* stream = spdy_stream_;
389 spdy_stream_ = NULL;
390 response_stream_.reset(new SpdyHttpStream(NULL, false));
391 response_stream_->InitializeWithExistingStream(stream);
392 next_state_ = STATE_DISCONNECTED;
393 return ERR_HTTPS_PROXY_TUNNEL_RESPONSE;
394 }
[email protected]fe2f62a2010-10-01 03:34:07395}
396
397// SpdyStream::Delegate methods:
398// Called when SYN frame has been sent.
399// Returns true if no more data to be sent after SYN frame.
400bool SpdyProxyClientSocket::OnSendHeadersComplete(int status) {
401 DCHECK_EQ(next_state_, STATE_SEND_REQUEST_COMPLETE);
402
403 OnIOComplete(status);
404
405 // We return true here so that we send |spdy_stream_| into
406 // STATE_OPEN (ala WebSockets).
407 return true;
408}
409
410int SpdyProxyClientSocket::OnSendBody() {
411 // Because we use |spdy_stream_| via STATE_OPEN (ala WebSockets)
412 // OnSendBody() should never be called.
413 NOTREACHED();
414 return ERR_UNEXPECTED;
415}
416
[email protected]0c9bf872011-03-04 17:53:22417int SpdyProxyClientSocket::OnSendBodyComplete(int /*status*/, bool* /*eof*/) {
[email protected]fe2f62a2010-10-01 03:34:07418 // Because we use |spdy_stream_| via STATE_OPEN (ala WebSockets)
419 // OnSendBodyComplete() should never be called.
420 NOTREACHED();
[email protected]0c9bf872011-03-04 17:53:22421 return ERR_UNEXPECTED;
[email protected]fe2f62a2010-10-01 03:34:07422}
423
424int SpdyProxyClientSocket::OnResponseReceived(
425 const spdy::SpdyHeaderBlock& response,
426 base::Time response_time,
427 int status) {
[email protected]d08358502010-12-03 22:04:03428 // If we've already received the reply, existing headers are too late.
429 // TODO(mbelshe): figure out a way to make HEADERS frames useful after the
430 // initial response.
431 if (next_state_ != STATE_READ_REPLY_COMPLETE)
432 return OK;
[email protected]fe2f62a2010-10-01 03:34:07433
[email protected]d08358502010-12-03 22:04:03434 // Save the response
435 int rv = SpdyHeadersToHttpResponse(response, &response_);
436 if (rv == ERR_INCOMPLETE_SPDY_HEADERS)
437 return rv; // More headers are coming.
[email protected]fe2f62a2010-10-01 03:34:07438
439 OnIOComplete(status);
[email protected]fe2f62a2010-10-01 03:34:07440 return OK;
441}
442
443// Called when data is received.
444void SpdyProxyClientSocket::OnDataReceived(const char* data, int length) {
445 if (length > 0) {
446 // Save the received data.
[email protected]ad8e04a2010-11-01 04:16:27447 scoped_refptr<IOBuffer> io_buffer(new IOBuffer(length));
[email protected]fe2f62a2010-10-01 03:34:07448 memcpy(io_buffer->data(), data, length);
[email protected]00cd9c42010-11-02 20:15:57449 read_buffer_.push_back(
450 make_scoped_refptr(new DrainableIOBuffer(io_buffer, length)));
[email protected]fe2f62a2010-10-01 03:34:07451 }
452
[email protected]83039bb2011-12-09 18:43:55453 if (!read_callback_.is_null()) {
[email protected]dbf036f2011-12-06 23:33:24454 int rv = PopulateUserReadBuffer();
455 CompletionCallback c = read_callback_;
456 read_callback_.Reset();
457 user_buffer_ = NULL;
458 c.Run(rv);
[email protected]fe2f62a2010-10-01 03:34:07459 }
460}
461
462void SpdyProxyClientSocket::OnDataSent(int length) {
[email protected]83039bb2011-12-09 18:43:55463 DCHECK(!write_callback_.is_null());
[email protected]fe2f62a2010-10-01 03:34:07464
465 write_bytes_outstanding_ -= length;
466
467 DCHECK_GE(write_bytes_outstanding_, 0);
468
469 if (write_bytes_outstanding_ == 0) {
470 int rv = write_buffer_len_;
471 write_buffer_len_ = 0;
472 write_bytes_outstanding_ = 0;
[email protected]83039bb2011-12-09 18:43:55473 CompletionCallback c = write_callback_;
474 write_callback_.Reset();
475 c.Run(rv);
[email protected]fe2f62a2010-10-01 03:34:07476 }
477}
478
479void SpdyProxyClientSocket::OnClose(int status) {
480 DCHECK(spdy_stream_);
[email protected]fe2f62a2010-10-01 03:34:07481 was_ever_used_ = spdy_stream_->WasEverUsed();
482 spdy_stream_ = NULL;
[email protected]d9da5fe2010-10-13 22:37:16483
484 bool connecting = next_state_ != STATE_DISCONNECTED &&
485 next_state_ < STATE_OPEN;
486 if (next_state_ == STATE_OPEN)
487 next_state_ = STATE_CLOSED;
488 else
489 next_state_ = STATE_DISCONNECTED;
490
[email protected]6af4e412011-11-29 23:39:18491 base::WeakPtr<SpdyProxyClientSocket> weak_ptr = weak_factory_.GetWeakPtr();
[email protected]83039bb2011-12-09 18:43:55492 CompletionCallback write_callback = write_callback_;
493 write_callback_.Reset();
[email protected]d9da5fe2010-10-13 22:37:16494 write_buffer_len_ = 0;
495 write_bytes_outstanding_ = 0;
496
497 // If we're in the middle of connecting, we need to make sure
498 // we invoke the connect callback.
499 if (connecting) {
[email protected]83039bb2011-12-09 18:43:55500 DCHECK(!read_callback_.is_null());
501 CompletionCallback read_callback = read_callback_;
502 read_callback_.Reset();
503 read_callback.Run(status);
504 } else if (!read_callback_.is_null()) {
[email protected]6af4e412011-11-29 23:39:18505 // If we have a read_callback_, the we need to make sure we call it back.
[email protected]d9da5fe2010-10-13 22:37:16506 OnDataReceived(NULL, 0);
507 }
[email protected]6af4e412011-11-29 23:39:18508 // This may have been deleted by read_callback_, so check first.
[email protected]83039bb2011-12-09 18:43:55509 if (weak_ptr && !write_callback.is_null())
510 write_callback.Run(ERR_CONNECTION_CLOSED);
[email protected]fe2f62a2010-10-01 03:34:07511}
512
[email protected]0c9bf872011-03-04 17:53:22513void SpdyProxyClientSocket::set_chunk_callback(ChunkCallback* /*callback*/) {
514}
515
[email protected]fe2f62a2010-10-01 03:34:07516} // namespace net