blob: 43195b8ef10b41b67fbff47a066290892f308aed [file] [log] [blame]
[email protected]e92fa7e12012-02-16 23:31:221// Copyright (c) 2012 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"
[email protected]fe3b7dc2012-02-03 19:52:0917#include "net/http/http_auth_cache.h"
18#include "net/http/http_auth_handler_factory.h"
[email protected]fe2f62a2010-10-01 03:34:0719#include "net/http/http_net_log_params.h"
[email protected]b104b502010-10-18 20:21:3120#include "net/http/http_response_headers.h"
[email protected]fe2f62a2010-10-01 03:34:0721#include "net/spdy/spdy_http_utils.h"
22
23namespace net {
24
25SpdyProxyClientSocket::SpdyProxyClientSocket(
26 SpdyStream* spdy_stream,
27 const std::string& user_agent,
28 const HostPortPair& endpoint,
29 const GURL& url,
30 const HostPortPair& proxy_server,
[email protected]fe3b7dc2012-02-03 19:52:0931 HttpAuthCache* auth_cache,
32 HttpAuthHandlerFactory* auth_handler_factory)
[email protected]49639fa2011-12-20 23:22:4133 : next_state_(STATE_DISCONNECTED),
[email protected]fe2f62a2010-10-01 03:34:0734 spdy_stream_(spdy_stream),
[email protected]fe2f62a2010-10-01 03:34:0735 endpoint_(endpoint),
[email protected]fe3b7dc2012-02-03 19:52:0936 auth_(
37 new HttpAuthController(HttpAuth::AUTH_PROXY,
38 GURL("https://" + proxy_server.ToString()),
39 auth_cache,
40 auth_handler_factory)),
[email protected]fe2f62a2010-10-01 03:34:0741 user_buffer_(NULL),
42 write_buffer_len_(0),
43 write_bytes_outstanding_(0),
[email protected]6af4e412011-11-29 23:39:1844 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
[email protected]fe2f62a2010-10-01 03:34:0745 net_log_(spdy_stream->net_log()) {
46 request_.method = "CONNECT";
47 request_.url = url;
48 if (!user_agent.empty())
49 request_.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent,
50 user_agent);
51 spdy_stream_->SetDelegate(this);
52 was_ever_used_ = spdy_stream_->WasEverUsed();
53}
54
55SpdyProxyClientSocket::~SpdyProxyClientSocket() {
56 Disconnect();
57}
58
[email protected]be1a48b2011-01-20 00:12:1359const HttpResponseInfo* SpdyProxyClientSocket::GetConnectResponseInfo() const {
60 return response_.headers ? &response_ : NULL;
61}
62
[email protected]c0fe941d2012-02-25 00:15:3263const scoped_refptr<HttpAuthController>&
64SpdyProxyClientSocket::GetAuthController() const {
65 return auth_;
66}
67
68int SpdyProxyClientSocket::RestartWithAuth(const CompletionCallback& callback) {
69 // A SPDY Stream can only handle a single request, so the underlying
70 // stream may not be reused and a new SpdyProxyClientSocket must be
71 // created (possibly on top of the same SPDY Session).
72 next_state_ = STATE_DISCONNECTED;
73 return ERR_NO_KEEP_ALIVE_ON_AUTH_RESTART;
74}
75
76bool SpdyProxyClientSocket::IsUsingSpdy() const {
77 return true;
78}
79
80SSLClientSocket::NextProto
81SpdyProxyClientSocket::GetProtocolNegotiated() const {
82 // Save the negotiated protocol
83 SSLInfo ssl_info;
84 bool was_npn_negotiated;
85 SSLClientSocket::NextProto protocol_negotiated;
86 spdy_stream_->GetSSLInfo(&ssl_info, &was_npn_negotiated,
87 &protocol_negotiated);
88 return protocol_negotiated;
89}
90
[email protected]511f6f52010-12-17 03:58:2991HttpStream* SpdyProxyClientSocket::CreateConnectResponseStream() {
92 DCHECK(response_stream_.get());
93 return response_stream_.release();
94}
95
[email protected]fe2f62a2010-10-01 03:34:0796// Sends a SYN_STREAM frame to the proxy with a CONNECT request
97// for the specified endpoint. Waits for the server to send back
98// a SYN_REPLY frame. OK will be returned if the status is 200.
99// ERR_TUNNEL_CONNECTION_FAILED will be returned for any other status.
100// In any of these cases, Read() may be called to retrieve the HTTP
101// response body. Any other return values should be considered fatal.
[email protected]fe3b7dc2012-02-03 19:52:09102// TODO(rch): handle 407 proxy auth requested correctly, perhaps
103// by creating a new stream for the subsequent request.
[email protected]fe2f62a2010-10-01 03:34:07104// TODO(rch): create a more appropriate error code to disambiguate
105// the HTTPS Proxy tunnel failure from an HTTP Proxy tunnel failure.
[email protected]dbf036f2011-12-06 23:33:24106int SpdyProxyClientSocket::Connect(const CompletionCallback& callback) {
[email protected]83039bb2011-12-09 18:43:55107 DCHECK(read_callback_.is_null());
[email protected]d9da5fe2010-10-13 22:37:16108 if (next_state_ == STATE_OPEN)
[email protected]fe2f62a2010-10-01 03:34:07109 return OK;
110
[email protected]d9da5fe2010-10-13 22:37:16111 DCHECK_EQ(STATE_DISCONNECTED, next_state_);
[email protected]fe2f62a2010-10-01 03:34:07112 next_state_ = STATE_GENERATE_AUTH_TOKEN;
113
114 int rv = DoLoop(OK);
115 if (rv == ERR_IO_PENDING)
116 read_callback_ = callback;
117 return rv;
118}
119
120void SpdyProxyClientSocket::Disconnect() {
[email protected]d9da5fe2010-10-13 22:37:16121 read_buffer_.clear();
122 user_buffer_ = NULL;
[email protected]dbf036f2011-12-06 23:33:24123 read_callback_.Reset();
[email protected]d9da5fe2010-10-13 22:37:16124
125 write_buffer_len_ = 0;
126 write_bytes_outstanding_ = 0;
[email protected]83039bb2011-12-09 18:43:55127 write_callback_.Reset();
[email protected]d9da5fe2010-10-13 22:37:16128
129 next_state_ = STATE_DISCONNECTED;
130
[email protected]fe2f62a2010-10-01 03:34:07131 if (spdy_stream_)
132 // This will cause OnClose to be invoked, which takes care of
133 // cleaning up all the internal state.
134 spdy_stream_->Cancel();
135}
136
137bool SpdyProxyClientSocket::IsConnected() const {
[email protected]194c7a92011-12-03 04:54:18138 return next_state_ == STATE_OPEN;
[email protected]fe2f62a2010-10-01 03:34:07139}
140
141bool SpdyProxyClientSocket::IsConnectedAndIdle() const {
[email protected]194c7a92011-12-03 04:54:18142 return IsConnected() && read_buffer_.empty() && spdy_stream_->is_idle();
[email protected]fe2f62a2010-10-01 03:34:07143}
144
[email protected]e4be2dd2010-12-14 00:44:39145const BoundNetLog& SpdyProxyClientSocket::NetLog() const {
146 return net_log_;
147}
148
[email protected]fe2f62a2010-10-01 03:34:07149void SpdyProxyClientSocket::SetSubresourceSpeculation() {
150 // TODO(rch): what should this implementation be?
151}
152
153void SpdyProxyClientSocket::SetOmniboxSpeculation() {
154 // TODO(rch): what should this implementation be?
155}
156
157bool SpdyProxyClientSocket::WasEverUsed() const {
158 return was_ever_used_ || (spdy_stream_ && spdy_stream_->WasEverUsed());
159}
160
[email protected]7f7e92392010-10-26 18:29:29161bool SpdyProxyClientSocket::UsingTCPFastOpen() const {
162 return false;
163}
164
[email protected]5e6efa52011-06-27 17:26:41165int64 SpdyProxyClientSocket::NumBytesRead() const {
166 return -1;
167}
168
169base::TimeDelta SpdyProxyClientSocket::GetConnectTimeMicros() const {
170 return base::TimeDelta::FromMicroseconds(-1);
171}
172
[email protected]fe2f62a2010-10-01 03:34:07173int SpdyProxyClientSocket::Read(IOBuffer* buf, int buf_len,
[email protected]3f55aa12011-12-07 02:03:33174 const CompletionCallback& callback) {
[email protected]83039bb2011-12-09 18:43:55175 DCHECK(read_callback_.is_null());
[email protected]3f55aa12011-12-07 02:03:33176 DCHECK(!user_buffer_);
177
178 if (next_state_ == STATE_DISCONNECTED)
179 return ERR_SOCKET_NOT_CONNECTED;
180
181 if (next_state_ == STATE_CLOSED && read_buffer_.empty()) {
182 return 0;
183 }
184
185 DCHECK(next_state_ == STATE_OPEN || next_state_ == STATE_CLOSED);
186 DCHECK(buf);
187 user_buffer_ = new DrainableIOBuffer(buf, buf_len);
188 int result = PopulateUserReadBuffer();
189 if (result == 0) {
190 DCHECK(!callback.is_null());
191 read_callback_ = callback;
192 return ERR_IO_PENDING;
193 }
194 user_buffer_ = NULL;
195 return result;
196}
[email protected]fe2f62a2010-10-01 03:34:07197
198int SpdyProxyClientSocket::PopulateUserReadBuffer() {
199 if (!user_buffer_)
200 return ERR_IO_PENDING;
201
[email protected]e92fa7e12012-02-16 23:31:22202 int bytes_read = 0;
[email protected]fe2f62a2010-10-01 03:34:07203 while (!read_buffer_.empty() && user_buffer_->BytesRemaining() > 0) {
204 scoped_refptr<DrainableIOBuffer> data = read_buffer_.front();
205 const int bytes_to_copy = std::min(user_buffer_->BytesRemaining(),
[email protected]87d3c4a2010-10-07 03:00:42206 data->BytesRemaining());
[email protected]fe2f62a2010-10-01 03:34:07207 memcpy(user_buffer_->data(), data->data(), bytes_to_copy);
208 user_buffer_->DidConsume(bytes_to_copy);
[email protected]e92fa7e12012-02-16 23:31:22209 bytes_read += bytes_to_copy;
[email protected]d9da5fe2010-10-13 22:37:16210 if (data->BytesRemaining() == bytes_to_copy) {
[email protected]fe2f62a2010-10-01 03:34:07211 // Consumed all data from this buffer
212 read_buffer_.pop_front();
213 } else {
214 data->DidConsume(bytes_to_copy);
215 }
216 }
217
[email protected]e92fa7e12012-02-16 23:31:22218 if (bytes_read > 0 && spdy_stream_)
219 spdy_stream_->IncreaseRecvWindowSize(bytes_read);
220
[email protected]fe2f62a2010-10-01 03:34:07221 return user_buffer_->BytesConsumed();
222}
223
224int SpdyProxyClientSocket::Write(IOBuffer* buf, int buf_len,
[email protected]83039bb2011-12-09 18:43:55225 const CompletionCallback& callback) {
226 DCHECK(write_callback_.is_null());
[email protected]194c7a92011-12-03 04:54:18227 if (next_state_ != STATE_OPEN)
[email protected]d9da5fe2010-10-13 22:37:16228 return ERR_SOCKET_NOT_CONNECTED;
229
[email protected]194c7a92011-12-03 04:54:18230 DCHECK(spdy_stream_);
[email protected]fe2f62a2010-10-01 03:34:07231 write_bytes_outstanding_= buf_len;
232 if (buf_len <= kMaxSpdyFrameChunkSize) {
233 int rv = spdy_stream_->WriteStreamData(buf, buf_len, spdy::DATA_FLAG_NONE);
234 if (rv == ERR_IO_PENDING) {
235 write_callback_ = callback;
236 write_buffer_len_ = buf_len;
237 }
238 return rv;
239 }
240
241 // Since a SPDY Data frame can only include kMaxSpdyFrameChunkSize bytes
242 // we need to send multiple data frames
243 for (int i = 0; i < buf_len; i += kMaxSpdyFrameChunkSize) {
244 int len = std::min(kMaxSpdyFrameChunkSize, buf_len - i);
245 scoped_refptr<DrainableIOBuffer> iobuf(new DrainableIOBuffer(buf, i + len));
246 iobuf->SetOffset(i);
247 int rv = spdy_stream_->WriteStreamData(iobuf, len, spdy::DATA_FLAG_NONE);
248 if (rv > 0) {
249 write_bytes_outstanding_ -= rv;
250 } else if (rv != ERR_IO_PENDING) {
251 return rv;
252 }
253 }
254 if (write_bytes_outstanding_ > 0) {
255 write_callback_ = callback;
256 write_buffer_len_ = buf_len;
257 return ERR_IO_PENDING;
258 } else {
259 return buf_len;
260 }
261}
262
263bool SpdyProxyClientSocket::SetReceiveBufferSize(int32 size) {
[email protected]3268023f2011-05-05 00:08:10264 // Since this StreamSocket sits on top of a shared SpdySession, it
[email protected]fe2f62a2010-10-01 03:34:07265 // is not safe for callers to set change this underlying socket.
266 return false;
267}
268
269bool SpdyProxyClientSocket::SetSendBufferSize(int32 size) {
[email protected]3268023f2011-05-05 00:08:10270 // Since this StreamSocket sits on top of a shared SpdySession, it
[email protected]fe2f62a2010-10-01 03:34:07271 // is not safe for callers to set change this underlying socket.
272 return false;
273}
274
275int SpdyProxyClientSocket::GetPeerAddress(AddressList* address) const {
276 if (!IsConnected())
[email protected]88e03fa2010-10-05 03:09:04277 return ERR_SOCKET_NOT_CONNECTED;
[email protected]fe2f62a2010-10-01 03:34:07278 return spdy_stream_->GetPeerAddress(address);
279}
280
[email protected]e7f74da2011-04-19 23:49:35281int SpdyProxyClientSocket::GetLocalAddress(IPEndPoint* address) const {
282 if (!IsConnected())
283 return ERR_SOCKET_NOT_CONNECTED;
284 return spdy_stream_->GetLocalAddress(address);
285}
286
[email protected]fe2f62a2010-10-01 03:34:07287void SpdyProxyClientSocket::OnIOComplete(int result) {
[email protected]d9da5fe2010-10-13 22:37:16288 DCHECK_NE(STATE_DISCONNECTED, next_state_);
[email protected]fe2f62a2010-10-01 03:34:07289 int rv = DoLoop(result);
290 if (rv != ERR_IO_PENDING) {
[email protected]83039bb2011-12-09 18:43:55291 CompletionCallback c = read_callback_;
292 read_callback_.Reset();
293 c.Run(rv);
[email protected]fe2f62a2010-10-01 03:34:07294 }
295}
296
297int SpdyProxyClientSocket::DoLoop(int last_io_result) {
[email protected]d9da5fe2010-10-13 22:37:16298 DCHECK_NE(next_state_, STATE_DISCONNECTED);
[email protected]fe2f62a2010-10-01 03:34:07299 int rv = last_io_result;
300 do {
301 State state = next_state_;
[email protected]d9da5fe2010-10-13 22:37:16302 next_state_ = STATE_DISCONNECTED;
[email protected]fe2f62a2010-10-01 03:34:07303 switch (state) {
304 case STATE_GENERATE_AUTH_TOKEN:
305 DCHECK_EQ(OK, rv);
306 rv = DoGenerateAuthToken();
307 break;
308 case STATE_GENERATE_AUTH_TOKEN_COMPLETE:
309 rv = DoGenerateAuthTokenComplete(rv);
310 break;
311 case STATE_SEND_REQUEST:
312 DCHECK_EQ(OK, rv);
[email protected]d7fd1782011-02-08 19:16:43313 net_log_.BeginEvent(
314 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST, NULL);
[email protected]fe2f62a2010-10-01 03:34:07315 rv = DoSendRequest();
316 break;
317 case STATE_SEND_REQUEST_COMPLETE:
[email protected]d7fd1782011-02-08 19:16:43318 net_log_.EndEventWithNetErrorCode(
319 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST, rv);
[email protected]fe2f62a2010-10-01 03:34:07320 rv = DoSendRequestComplete(rv);
[email protected]fe2f62a2010-10-01 03:34:07321 break;
322 case STATE_READ_REPLY_COMPLETE:
323 rv = DoReadReplyComplete(rv);
[email protected]d7fd1782011-02-08 19:16:43324 net_log_.EndEventWithNetErrorCode(
325 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_READ_HEADERS, rv);
[email protected]fe2f62a2010-10-01 03:34:07326 break;
327 default:
328 NOTREACHED() << "bad state";
329 rv = ERR_UNEXPECTED;
330 break;
331 }
[email protected]d9da5fe2010-10-13 22:37:16332 } while (rv != ERR_IO_PENDING && next_state_ != STATE_DISCONNECTED &&
333 next_state_ != STATE_OPEN);
[email protected]fe2f62a2010-10-01 03:34:07334 return rv;
335}
336
337int SpdyProxyClientSocket::DoGenerateAuthToken() {
338 next_state_ = STATE_GENERATE_AUTH_TOKEN_COMPLETE;
[email protected]49639fa2011-12-20 23:22:41339 return auth_->MaybeGenerateAuthToken(
340 &request_,
341 base::Bind(&SpdyProxyClientSocket::OnIOComplete, base::Unretained(this)),
342 net_log_);
[email protected]fe2f62a2010-10-01 03:34:07343}
344
345int SpdyProxyClientSocket::DoGenerateAuthTokenComplete(int result) {
346 DCHECK_NE(ERR_IO_PENDING, result);
347 if (result == OK)
348 next_state_ = STATE_SEND_REQUEST;
349 return result;
350}
351
352int SpdyProxyClientSocket::DoSendRequest() {
353 next_state_ = STATE_SEND_REQUEST_COMPLETE;
354
355 // Add Proxy-Authentication header if necessary.
356 HttpRequestHeaders authorization_headers;
357 if (auth_->HaveAuth()) {
358 auth_->AddAuthorizationHeader(&authorization_headers);
359 }
360
361 std::string request_line;
362 HttpRequestHeaders request_headers;
363 BuildTunnelRequest(request_, authorization_headers, endpoint_, &request_line,
364 &request_headers);
[email protected]465aeb942010-10-14 19:58:14365 if (net_log_.IsLoggingAllEvents()) {
[email protected]fe2f62a2010-10-01 03:34:07366 net_log_.AddEvent(
367 NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
[email protected]00cd9c42010-11-02 20:15:57368 make_scoped_refptr(new NetLogHttpRequestParameter(
369 request_line, request_headers)));
[email protected]fe2f62a2010-10-01 03:34:07370 }
371
372 request_.extra_headers.MergeFrom(request_headers);
373 linked_ptr<spdy::SpdyHeaderBlock> headers(new spdy::SpdyHeaderBlock());
[email protected]7213e7c2010-10-20 15:33:52374 CreateSpdyHeadersFromHttpRequest(request_, request_headers, headers.get(),
375 true);
[email protected]fe2f62a2010-10-01 03:34:07376 // Reset the URL to be the endpoint of the connection
377 (*headers)["url"] = endpoint_.ToString();
378 headers->erase("scheme");
379 spdy_stream_->set_spdy_headers(headers);
380
381 return spdy_stream_->SendRequest(true);
382}
383
384int SpdyProxyClientSocket::DoSendRequestComplete(int result) {
385 if (result < 0)
386 return result;
387
388 // Wait for SYN_REPLY frame from the server
389 next_state_ = STATE_READ_REPLY_COMPLETE;
390 return ERR_IO_PENDING;
391}
392
393int SpdyProxyClientSocket::DoReadReplyComplete(int result) {
394 // We enter this method directly from DoSendRequestComplete, since
395 // we are notified by a callback when the SYN_REPLY frame arrives
396
397 if (result < 0)
398 return result;
399
[email protected]fe2f62a2010-10-01 03:34:07400 // Require the "HTTP/1.x" status line for SSL CONNECT.
401 if (response_.headers->GetParsedHttpVersion() < HttpVersion(1, 0))
402 return ERR_TUNNEL_CONNECTION_FAILED;
403
[email protected]d9da5fe2010-10-13 22:37:16404 next_state_ = STATE_OPEN;
[email protected]465aeb942010-10-14 19:58:14405 if (net_log_.IsLoggingAllEvents()) {
[email protected]fe2f62a2010-10-01 03:34:07406 net_log_.AddEvent(
407 NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
[email protected]00cd9c42010-11-02 20:15:57408 make_scoped_refptr(new NetLogHttpResponseParameter(response_.headers)));
[email protected]fe2f62a2010-10-01 03:34:07409 }
410
[email protected]511f6f52010-12-17 03:58:29411 if (response_.headers->response_code() == 200) {
[email protected]fe2f62a2010-10-01 03:34:07412 return OK;
[email protected]511f6f52010-12-17 03:58:29413 } else if (response_.headers->response_code() == 407) {
[email protected]fe3b7dc2012-02-03 19:52:09414 return ERR_TUNNEL_CONNECTION_FAILED;
[email protected]511f6f52010-12-17 03:58:29415 } else {
416 // Immediately hand off our SpdyStream to a newly created SpdyHttpStream
417 // so that any subsequent SpdyFrames are processed in the context of
418 // the HttpStream, not the socket.
419 DCHECK(spdy_stream_);
420 SpdyStream* stream = spdy_stream_;
421 spdy_stream_ = NULL;
422 response_stream_.reset(new SpdyHttpStream(NULL, false));
423 response_stream_->InitializeWithExistingStream(stream);
424 next_state_ = STATE_DISCONNECTED;
425 return ERR_HTTPS_PROXY_TUNNEL_RESPONSE;
426 }
[email protected]fe2f62a2010-10-01 03:34:07427}
428
429// SpdyStream::Delegate methods:
430// Called when SYN frame has been sent.
431// Returns true if no more data to be sent after SYN frame.
432bool SpdyProxyClientSocket::OnSendHeadersComplete(int status) {
433 DCHECK_EQ(next_state_, STATE_SEND_REQUEST_COMPLETE);
434
435 OnIOComplete(status);
436
437 // We return true here so that we send |spdy_stream_| into
438 // STATE_OPEN (ala WebSockets).
439 return true;
440}
441
442int SpdyProxyClientSocket::OnSendBody() {
443 // Because we use |spdy_stream_| via STATE_OPEN (ala WebSockets)
444 // OnSendBody() should never be called.
445 NOTREACHED();
446 return ERR_UNEXPECTED;
447}
448
[email protected]0c9bf872011-03-04 17:53:22449int SpdyProxyClientSocket::OnSendBodyComplete(int /*status*/, bool* /*eof*/) {
[email protected]fe2f62a2010-10-01 03:34:07450 // Because we use |spdy_stream_| via STATE_OPEN (ala WebSockets)
451 // OnSendBodyComplete() should never be called.
452 NOTREACHED();
[email protected]0c9bf872011-03-04 17:53:22453 return ERR_UNEXPECTED;
[email protected]fe2f62a2010-10-01 03:34:07454}
455
456int SpdyProxyClientSocket::OnResponseReceived(
457 const spdy::SpdyHeaderBlock& response,
458 base::Time response_time,
459 int status) {
[email protected]d08358502010-12-03 22:04:03460 // If we've already received the reply, existing headers are too late.
461 // TODO(mbelshe): figure out a way to make HEADERS frames useful after the
462 // initial response.
463 if (next_state_ != STATE_READ_REPLY_COMPLETE)
464 return OK;
[email protected]fe2f62a2010-10-01 03:34:07465
[email protected]d08358502010-12-03 22:04:03466 // Save the response
467 int rv = SpdyHeadersToHttpResponse(response, &response_);
468 if (rv == ERR_INCOMPLETE_SPDY_HEADERS)
469 return rv; // More headers are coming.
[email protected]fe2f62a2010-10-01 03:34:07470
471 OnIOComplete(status);
[email protected]fe2f62a2010-10-01 03:34:07472 return OK;
473}
474
475// Called when data is received.
476void SpdyProxyClientSocket::OnDataReceived(const char* data, int length) {
477 if (length > 0) {
478 // Save the received data.
[email protected]ad8e04a2010-11-01 04:16:27479 scoped_refptr<IOBuffer> io_buffer(new IOBuffer(length));
[email protected]fe2f62a2010-10-01 03:34:07480 memcpy(io_buffer->data(), data, length);
[email protected]00cd9c42010-11-02 20:15:57481 read_buffer_.push_back(
482 make_scoped_refptr(new DrainableIOBuffer(io_buffer, length)));
[email protected]fe2f62a2010-10-01 03:34:07483 }
484
[email protected]83039bb2011-12-09 18:43:55485 if (!read_callback_.is_null()) {
[email protected]dbf036f2011-12-06 23:33:24486 int rv = PopulateUserReadBuffer();
487 CompletionCallback c = read_callback_;
488 read_callback_.Reset();
489 user_buffer_ = NULL;
490 c.Run(rv);
[email protected]fe2f62a2010-10-01 03:34:07491 }
492}
493
494void SpdyProxyClientSocket::OnDataSent(int length) {
[email protected]83039bb2011-12-09 18:43:55495 DCHECK(!write_callback_.is_null());
[email protected]fe2f62a2010-10-01 03:34:07496
497 write_bytes_outstanding_ -= length;
498
499 DCHECK_GE(write_bytes_outstanding_, 0);
500
501 if (write_bytes_outstanding_ == 0) {
502 int rv = write_buffer_len_;
503 write_buffer_len_ = 0;
504 write_bytes_outstanding_ = 0;
[email protected]83039bb2011-12-09 18:43:55505 CompletionCallback c = write_callback_;
506 write_callback_.Reset();
507 c.Run(rv);
[email protected]fe2f62a2010-10-01 03:34:07508 }
509}
510
511void SpdyProxyClientSocket::OnClose(int status) {
512 DCHECK(spdy_stream_);
[email protected]fe2f62a2010-10-01 03:34:07513 was_ever_used_ = spdy_stream_->WasEverUsed();
514 spdy_stream_ = NULL;
[email protected]d9da5fe2010-10-13 22:37:16515
516 bool connecting = next_state_ != STATE_DISCONNECTED &&
517 next_state_ < STATE_OPEN;
518 if (next_state_ == STATE_OPEN)
519 next_state_ = STATE_CLOSED;
520 else
521 next_state_ = STATE_DISCONNECTED;
522
[email protected]6af4e412011-11-29 23:39:18523 base::WeakPtr<SpdyProxyClientSocket> weak_ptr = weak_factory_.GetWeakPtr();
[email protected]83039bb2011-12-09 18:43:55524 CompletionCallback write_callback = write_callback_;
525 write_callback_.Reset();
[email protected]d9da5fe2010-10-13 22:37:16526 write_buffer_len_ = 0;
527 write_bytes_outstanding_ = 0;
528
529 // If we're in the middle of connecting, we need to make sure
530 // we invoke the connect callback.
531 if (connecting) {
[email protected]83039bb2011-12-09 18:43:55532 DCHECK(!read_callback_.is_null());
533 CompletionCallback read_callback = read_callback_;
534 read_callback_.Reset();
535 read_callback.Run(status);
536 } else if (!read_callback_.is_null()) {
[email protected]6af4e412011-11-29 23:39:18537 // If we have a read_callback_, the we need to make sure we call it back.
[email protected]d9da5fe2010-10-13 22:37:16538 OnDataReceived(NULL, 0);
539 }
[email protected]6af4e412011-11-29 23:39:18540 // This may have been deleted by read_callback_, so check first.
[email protected]83039bb2011-12-09 18:43:55541 if (weak_ptr && !write_callback.is_null())
542 write_callback.Run(ERR_CONNECTION_CLOSED);
[email protected]fe2f62a2010-10-01 03:34:07543}
544
[email protected]0c9bf872011-03-04 17:53:22545void SpdyProxyClientSocket::set_chunk_callback(ChunkCallback* /*callback*/) {
546}
547
[email protected]fe2f62a2010-10-01 03:34:07548} // namespace net