blob: 0575bb0149353143bcf999f84c794071735a03cb [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;
[email protected]0c5fb722012-02-28 11:50:3573 return OK;
[email protected]c0fe941d2012-02-25 00:15:3274}
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(),
[email protected]0e861e92012-03-15 18:42:19375 spdy_stream_->GetProtocolVersion(), true);
[email protected]fe2f62a2010-10-01 03:34:07376 // Reset the URL to be the endpoint of the connection
[email protected]0e861e92012-03-15 18:42:19377 if (spdy_stream_->GetProtocolVersion() > 2) {
378 (*headers)[":path"] = endpoint_.ToString();
379 headers->erase(":scheme");
380 } else {
381 (*headers)["url"] = endpoint_.ToString();
382 headers->erase("scheme");
383 }
[email protected]fe2f62a2010-10-01 03:34:07384 spdy_stream_->set_spdy_headers(headers);
385
386 return spdy_stream_->SendRequest(true);
387}
388
389int SpdyProxyClientSocket::DoSendRequestComplete(int result) {
390 if (result < 0)
391 return result;
392
393 // Wait for SYN_REPLY frame from the server
394 next_state_ = STATE_READ_REPLY_COMPLETE;
395 return ERR_IO_PENDING;
396}
397
398int SpdyProxyClientSocket::DoReadReplyComplete(int result) {
399 // We enter this method directly from DoSendRequestComplete, since
400 // we are notified by a callback when the SYN_REPLY frame arrives
401
402 if (result < 0)
403 return result;
404
[email protected]fe2f62a2010-10-01 03:34:07405 // Require the "HTTP/1.x" status line for SSL CONNECT.
406 if (response_.headers->GetParsedHttpVersion() < HttpVersion(1, 0))
407 return ERR_TUNNEL_CONNECTION_FAILED;
408
[email protected]d9da5fe2010-10-13 22:37:16409 next_state_ = STATE_OPEN;
[email protected]465aeb942010-10-14 19:58:14410 if (net_log_.IsLoggingAllEvents()) {
[email protected]fe2f62a2010-10-01 03:34:07411 net_log_.AddEvent(
412 NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
[email protected]00cd9c42010-11-02 20:15:57413 make_scoped_refptr(new NetLogHttpResponseParameter(response_.headers)));
[email protected]fe2f62a2010-10-01 03:34:07414 }
415
[email protected]511f6f52010-12-17 03:58:29416 if (response_.headers->response_code() == 200) {
[email protected]fe2f62a2010-10-01 03:34:07417 return OK;
[email protected]511f6f52010-12-17 03:58:29418 } else if (response_.headers->response_code() == 407) {
[email protected]b40d5cb2012-02-27 05:30:18419 return HandleProxyAuthChallenge(auth_, &response_, net_log_);
[email protected]511f6f52010-12-17 03:58:29420 } else {
421 // Immediately hand off our SpdyStream to a newly created SpdyHttpStream
422 // so that any subsequent SpdyFrames are processed in the context of
423 // the HttpStream, not the socket.
424 DCHECK(spdy_stream_);
425 SpdyStream* stream = spdy_stream_;
426 spdy_stream_ = NULL;
427 response_stream_.reset(new SpdyHttpStream(NULL, false));
428 response_stream_->InitializeWithExistingStream(stream);
429 next_state_ = STATE_DISCONNECTED;
430 return ERR_HTTPS_PROXY_TUNNEL_RESPONSE;
431 }
[email protected]fe2f62a2010-10-01 03:34:07432}
433
434// SpdyStream::Delegate methods:
435// Called when SYN frame has been sent.
436// Returns true if no more data to be sent after SYN frame.
437bool SpdyProxyClientSocket::OnSendHeadersComplete(int status) {
438 DCHECK_EQ(next_state_, STATE_SEND_REQUEST_COMPLETE);
439
440 OnIOComplete(status);
441
442 // We return true here so that we send |spdy_stream_| into
443 // STATE_OPEN (ala WebSockets).
444 return true;
445}
446
447int SpdyProxyClientSocket::OnSendBody() {
448 // Because we use |spdy_stream_| via STATE_OPEN (ala WebSockets)
449 // OnSendBody() should never be called.
450 NOTREACHED();
451 return ERR_UNEXPECTED;
452}
453
[email protected]0c9bf872011-03-04 17:53:22454int SpdyProxyClientSocket::OnSendBodyComplete(int /*status*/, bool* /*eof*/) {
[email protected]fe2f62a2010-10-01 03:34:07455 // Because we use |spdy_stream_| via STATE_OPEN (ala WebSockets)
456 // OnSendBodyComplete() should never be called.
457 NOTREACHED();
[email protected]0c9bf872011-03-04 17:53:22458 return ERR_UNEXPECTED;
[email protected]fe2f62a2010-10-01 03:34:07459}
460
461int SpdyProxyClientSocket::OnResponseReceived(
462 const spdy::SpdyHeaderBlock& response,
463 base::Time response_time,
464 int status) {
[email protected]d08358502010-12-03 22:04:03465 // If we've already received the reply, existing headers are too late.
466 // TODO(mbelshe): figure out a way to make HEADERS frames useful after the
467 // initial response.
468 if (next_state_ != STATE_READ_REPLY_COMPLETE)
469 return OK;
[email protected]fe2f62a2010-10-01 03:34:07470
[email protected]d08358502010-12-03 22:04:03471 // Save the response
472 int rv = SpdyHeadersToHttpResponse(response, &response_);
473 if (rv == ERR_INCOMPLETE_SPDY_HEADERS)
474 return rv; // More headers are coming.
[email protected]fe2f62a2010-10-01 03:34:07475
476 OnIOComplete(status);
[email protected]fe2f62a2010-10-01 03:34:07477 return OK;
478}
479
480// Called when data is received.
481void SpdyProxyClientSocket::OnDataReceived(const char* data, int length) {
482 if (length > 0) {
483 // Save the received data.
[email protected]ad8e04a2010-11-01 04:16:27484 scoped_refptr<IOBuffer> io_buffer(new IOBuffer(length));
[email protected]fe2f62a2010-10-01 03:34:07485 memcpy(io_buffer->data(), data, length);
[email protected]00cd9c42010-11-02 20:15:57486 read_buffer_.push_back(
487 make_scoped_refptr(new DrainableIOBuffer(io_buffer, length)));
[email protected]fe2f62a2010-10-01 03:34:07488 }
489
[email protected]83039bb2011-12-09 18:43:55490 if (!read_callback_.is_null()) {
[email protected]dbf036f2011-12-06 23:33:24491 int rv = PopulateUserReadBuffer();
492 CompletionCallback c = read_callback_;
493 read_callback_.Reset();
494 user_buffer_ = NULL;
495 c.Run(rv);
[email protected]fe2f62a2010-10-01 03:34:07496 }
497}
498
499void SpdyProxyClientSocket::OnDataSent(int length) {
[email protected]83039bb2011-12-09 18:43:55500 DCHECK(!write_callback_.is_null());
[email protected]fe2f62a2010-10-01 03:34:07501
502 write_bytes_outstanding_ -= length;
503
504 DCHECK_GE(write_bytes_outstanding_, 0);
505
506 if (write_bytes_outstanding_ == 0) {
507 int rv = write_buffer_len_;
508 write_buffer_len_ = 0;
509 write_bytes_outstanding_ = 0;
[email protected]83039bb2011-12-09 18:43:55510 CompletionCallback c = write_callback_;
511 write_callback_.Reset();
512 c.Run(rv);
[email protected]fe2f62a2010-10-01 03:34:07513 }
514}
515
516void SpdyProxyClientSocket::OnClose(int status) {
517 DCHECK(spdy_stream_);
[email protected]fe2f62a2010-10-01 03:34:07518 was_ever_used_ = spdy_stream_->WasEverUsed();
519 spdy_stream_ = NULL;
[email protected]d9da5fe2010-10-13 22:37:16520
521 bool connecting = next_state_ != STATE_DISCONNECTED &&
522 next_state_ < STATE_OPEN;
523 if (next_state_ == STATE_OPEN)
524 next_state_ = STATE_CLOSED;
525 else
526 next_state_ = STATE_DISCONNECTED;
527
[email protected]6af4e412011-11-29 23:39:18528 base::WeakPtr<SpdyProxyClientSocket> weak_ptr = weak_factory_.GetWeakPtr();
[email protected]83039bb2011-12-09 18:43:55529 CompletionCallback write_callback = write_callback_;
530 write_callback_.Reset();
[email protected]d9da5fe2010-10-13 22:37:16531 write_buffer_len_ = 0;
532 write_bytes_outstanding_ = 0;
533
534 // If we're in the middle of connecting, we need to make sure
535 // we invoke the connect callback.
536 if (connecting) {
[email protected]83039bb2011-12-09 18:43:55537 DCHECK(!read_callback_.is_null());
538 CompletionCallback read_callback = read_callback_;
539 read_callback_.Reset();
540 read_callback.Run(status);
541 } else if (!read_callback_.is_null()) {
[email protected]6af4e412011-11-29 23:39:18542 // If we have a read_callback_, the we need to make sure we call it back.
[email protected]d9da5fe2010-10-13 22:37:16543 OnDataReceived(NULL, 0);
544 }
[email protected]6af4e412011-11-29 23:39:18545 // This may have been deleted by read_callback_, so check first.
[email protected]83039bb2011-12-09 18:43:55546 if (weak_ptr && !write_callback.is_null())
547 write_callback.Run(ERR_CONNECTION_CLOSED);
[email protected]fe2f62a2010-10-01 03:34:07548}
549
[email protected]0c9bf872011-03-04 17:53:22550void SpdyProxyClientSocket::set_chunk_callback(ChunkCallback* /*callback*/) {
551}
552
[email protected]fe2f62a2010-10-01 03:34:07553} // namespace net