blob: 251ada249290936d98e08922681be383246551b4 [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]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,
[email protected]fe3b7dc2012-02-03 19:52:0930 HttpAuthCache* auth_cache,
31 HttpAuthHandlerFactory* auth_handler_factory)
[email protected]49639fa2011-12-20 23:22:4132 : next_state_(STATE_DISCONNECTED),
[email protected]fe2f62a2010-10-01 03:34:0733 spdy_stream_(spdy_stream),
[email protected]fe2f62a2010-10-01 03:34:0734 endpoint_(endpoint),
[email protected]fe3b7dc2012-02-03 19:52:0935 auth_(
36 new HttpAuthController(HttpAuth::AUTH_PROXY,
37 GURL("https://" + proxy_server.ToString()),
38 auth_cache,
39 auth_handler_factory)),
[email protected]fe2f62a2010-10-01 03:34:0740 user_buffer_(NULL),
41 write_buffer_len_(0),
42 write_bytes_outstanding_(0),
[email protected]6af4e412011-11-29 23:39:1843 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
[email protected]fe2f62a2010-10-01 03:34:0744 net_log_(spdy_stream->net_log()) {
45 request_.method = "CONNECT";
46 request_.url = url;
47 if (!user_agent.empty())
48 request_.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent,
49 user_agent);
50 spdy_stream_->SetDelegate(this);
51 was_ever_used_ = spdy_stream_->WasEverUsed();
52}
53
54SpdyProxyClientSocket::~SpdyProxyClientSocket() {
55 Disconnect();
56}
57
[email protected]be1a48b2011-01-20 00:12:1358const HttpResponseInfo* SpdyProxyClientSocket::GetConnectResponseInfo() const {
59 return response_.headers ? &response_ : NULL;
60}
61
[email protected]c0fe941d2012-02-25 00:15:3262const scoped_refptr<HttpAuthController>&
63SpdyProxyClientSocket::GetAuthController() const {
64 return auth_;
65}
66
67int SpdyProxyClientSocket::RestartWithAuth(const CompletionCallback& 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;
[email protected]0c5fb722012-02-28 11:50:3572 return OK;
[email protected]c0fe941d2012-02-25 00:15:3273}
74
75bool SpdyProxyClientSocket::IsUsingSpdy() const {
76 return true;
77}
78
[email protected]8e3c78cb2012-03-31 03:58:4679NextProto SpdyProxyClientSocket::GetProtocolNegotiated() const {
[email protected]c0fe941d2012-02-25 00:15:3280 // Save the negotiated protocol
81 SSLInfo ssl_info;
82 bool was_npn_negotiated;
[email protected]8e3c78cb2012-03-31 03:58:4683 NextProto protocol_negotiated;
[email protected]c0fe941d2012-02-25 00:15:3284 spdy_stream_->GetSSLInfo(&ssl_info, &was_npn_negotiated,
85 &protocol_negotiated);
86 return protocol_negotiated;
87}
88
[email protected]511f6f52010-12-17 03:58:2989HttpStream* SpdyProxyClientSocket::CreateConnectResponseStream() {
90 DCHECK(response_stream_.get());
91 return response_stream_.release();
92}
93
[email protected]fe2f62a2010-10-01 03:34:0794// Sends a SYN_STREAM frame to the proxy with a CONNECT request
95// for the specified endpoint. Waits for the server to send back
96// a SYN_REPLY frame. OK will be returned if the status is 200.
97// ERR_TUNNEL_CONNECTION_FAILED will be returned for any other status.
98// In any of these cases, Read() may be called to retrieve the HTTP
99// response body. Any other return values should be considered fatal.
[email protected]fe3b7dc2012-02-03 19:52:09100// TODO(rch): handle 407 proxy auth requested correctly, perhaps
101// by creating a new stream for the subsequent request.
[email protected]fe2f62a2010-10-01 03:34:07102// TODO(rch): create a more appropriate error code to disambiguate
103// the HTTPS Proxy tunnel failure from an HTTP Proxy tunnel failure.
[email protected]dbf036f2011-12-06 23:33:24104int SpdyProxyClientSocket::Connect(const CompletionCallback& callback) {
[email protected]83039bb2011-12-09 18:43:55105 DCHECK(read_callback_.is_null());
[email protected]d9da5fe2010-10-13 22:37:16106 if (next_state_ == STATE_OPEN)
[email protected]fe2f62a2010-10-01 03:34:07107 return OK;
108
[email protected]d9da5fe2010-10-13 22:37:16109 DCHECK_EQ(STATE_DISCONNECTED, next_state_);
[email protected]fe2f62a2010-10-01 03:34:07110 next_state_ = STATE_GENERATE_AUTH_TOKEN;
111
112 int rv = DoLoop(OK);
113 if (rv == ERR_IO_PENDING)
114 read_callback_ = callback;
115 return rv;
116}
117
118void SpdyProxyClientSocket::Disconnect() {
[email protected]d9da5fe2010-10-13 22:37:16119 read_buffer_.clear();
120 user_buffer_ = NULL;
[email protected]dbf036f2011-12-06 23:33:24121 read_callback_.Reset();
[email protected]d9da5fe2010-10-13 22:37:16122
123 write_buffer_len_ = 0;
124 write_bytes_outstanding_ = 0;
[email protected]83039bb2011-12-09 18:43:55125 write_callback_.Reset();
[email protected]d9da5fe2010-10-13 22:37:16126
127 next_state_ = STATE_DISCONNECTED;
128
[email protected]fe2f62a2010-10-01 03:34:07129 if (spdy_stream_)
130 // This will cause OnClose to be invoked, which takes care of
131 // cleaning up all the internal state.
132 spdy_stream_->Cancel();
133}
134
135bool SpdyProxyClientSocket::IsConnected() const {
[email protected]194c7a92011-12-03 04:54:18136 return next_state_ == STATE_OPEN;
[email protected]fe2f62a2010-10-01 03:34:07137}
138
139bool SpdyProxyClientSocket::IsConnectedAndIdle() const {
[email protected]194c7a92011-12-03 04:54:18140 return IsConnected() && read_buffer_.empty() && spdy_stream_->is_idle();
[email protected]fe2f62a2010-10-01 03:34:07141}
142
[email protected]e4be2dd2010-12-14 00:44:39143const BoundNetLog& SpdyProxyClientSocket::NetLog() const {
144 return net_log_;
145}
146
[email protected]fe2f62a2010-10-01 03:34:07147void SpdyProxyClientSocket::SetSubresourceSpeculation() {
148 // TODO(rch): what should this implementation be?
149}
150
151void SpdyProxyClientSocket::SetOmniboxSpeculation() {
152 // TODO(rch): what should this implementation be?
153}
154
155bool SpdyProxyClientSocket::WasEverUsed() const {
156 return was_ever_used_ || (spdy_stream_ && spdy_stream_->WasEverUsed());
157}
158
[email protected]7f7e92392010-10-26 18:29:29159bool SpdyProxyClientSocket::UsingTCPFastOpen() const {
160 return false;
161}
162
[email protected]5e6efa52011-06-27 17:26:41163int64 SpdyProxyClientSocket::NumBytesRead() const {
164 return -1;
165}
166
167base::TimeDelta SpdyProxyClientSocket::GetConnectTimeMicros() const {
168 return base::TimeDelta::FromMicroseconds(-1);
169}
170
[email protected]2d88e7d2012-07-19 17:55:17171bool SpdyProxyClientSocket::WasNpnNegotiated() const {
172 return false;
173}
174
[email protected]33661e482012-04-03 16:16:26175NextProto SpdyProxyClientSocket::GetNegotiatedProtocol() const {
176 return kProtoUnknown;
177}
178
[email protected]2d88e7d2012-07-19 17:55:17179bool SpdyProxyClientSocket::GetSSLInfo(SSLInfo* ssl_info) {
180 bool was_npn_negotiated;
181 NextProto protocol_negotiated;
182 return spdy_stream_->GetSSLInfo(ssl_info, &was_npn_negotiated,
183 &protocol_negotiated);
184}
185
[email protected]fe2f62a2010-10-01 03:34:07186int SpdyProxyClientSocket::Read(IOBuffer* buf, int buf_len,
[email protected]3f55aa12011-12-07 02:03:33187 const CompletionCallback& callback) {
[email protected]83039bb2011-12-09 18:43:55188 DCHECK(read_callback_.is_null());
[email protected]3f55aa12011-12-07 02:03:33189 DCHECK(!user_buffer_);
190
191 if (next_state_ == STATE_DISCONNECTED)
192 return ERR_SOCKET_NOT_CONNECTED;
193
194 if (next_state_ == STATE_CLOSED && read_buffer_.empty()) {
195 return 0;
196 }
197
198 DCHECK(next_state_ == STATE_OPEN || next_state_ == STATE_CLOSED);
199 DCHECK(buf);
200 user_buffer_ = new DrainableIOBuffer(buf, buf_len);
201 int result = PopulateUserReadBuffer();
202 if (result == 0) {
203 DCHECK(!callback.is_null());
204 read_callback_ = callback;
205 return ERR_IO_PENDING;
206 }
207 user_buffer_ = NULL;
208 return result;
209}
[email protected]fe2f62a2010-10-01 03:34:07210
211int SpdyProxyClientSocket::PopulateUserReadBuffer() {
212 if (!user_buffer_)
213 return ERR_IO_PENDING;
214
[email protected]e92fa7e12012-02-16 23:31:22215 int bytes_read = 0;
[email protected]fe2f62a2010-10-01 03:34:07216 while (!read_buffer_.empty() && user_buffer_->BytesRemaining() > 0) {
217 scoped_refptr<DrainableIOBuffer> data = read_buffer_.front();
218 const int bytes_to_copy = std::min(user_buffer_->BytesRemaining(),
[email protected]87d3c4a2010-10-07 03:00:42219 data->BytesRemaining());
[email protected]fe2f62a2010-10-01 03:34:07220 memcpy(user_buffer_->data(), data->data(), bytes_to_copy);
221 user_buffer_->DidConsume(bytes_to_copy);
[email protected]e92fa7e12012-02-16 23:31:22222 bytes_read += bytes_to_copy;
[email protected]d9da5fe2010-10-13 22:37:16223 if (data->BytesRemaining() == bytes_to_copy) {
[email protected]fe2f62a2010-10-01 03:34:07224 // Consumed all data from this buffer
225 read_buffer_.pop_front();
226 } else {
227 data->DidConsume(bytes_to_copy);
228 }
229 }
230
[email protected]e92fa7e12012-02-16 23:31:22231 if (bytes_read > 0 && spdy_stream_)
232 spdy_stream_->IncreaseRecvWindowSize(bytes_read);
233
[email protected]fe2f62a2010-10-01 03:34:07234 return user_buffer_->BytesConsumed();
235}
236
237int SpdyProxyClientSocket::Write(IOBuffer* buf, int buf_len,
[email protected]83039bb2011-12-09 18:43:55238 const CompletionCallback& callback) {
239 DCHECK(write_callback_.is_null());
[email protected]194c7a92011-12-03 04:54:18240 if (next_state_ != STATE_OPEN)
[email protected]d9da5fe2010-10-13 22:37:16241 return ERR_SOCKET_NOT_CONNECTED;
242
[email protected]194c7a92011-12-03 04:54:18243 DCHECK(spdy_stream_);
[email protected]fe2f62a2010-10-01 03:34:07244 write_bytes_outstanding_= buf_len;
245 if (buf_len <= kMaxSpdyFrameChunkSize) {
[email protected]ff98d7f02012-03-22 21:44:19246 int rv = spdy_stream_->WriteStreamData(buf, buf_len, DATA_FLAG_NONE);
[email protected]fe2f62a2010-10-01 03:34:07247 if (rv == ERR_IO_PENDING) {
248 write_callback_ = callback;
249 write_buffer_len_ = buf_len;
250 }
251 return rv;
252 }
253
254 // Since a SPDY Data frame can only include kMaxSpdyFrameChunkSize bytes
255 // we need to send multiple data frames
256 for (int i = 0; i < buf_len; i += kMaxSpdyFrameChunkSize) {
257 int len = std::min(kMaxSpdyFrameChunkSize, buf_len - i);
258 scoped_refptr<DrainableIOBuffer> iobuf(new DrainableIOBuffer(buf, i + len));
259 iobuf->SetOffset(i);
[email protected]ff98d7f02012-03-22 21:44:19260 int rv = spdy_stream_->WriteStreamData(iobuf, len, DATA_FLAG_NONE);
[email protected]fe2f62a2010-10-01 03:34:07261 if (rv > 0) {
262 write_bytes_outstanding_ -= rv;
263 } else if (rv != ERR_IO_PENDING) {
264 return rv;
265 }
266 }
267 if (write_bytes_outstanding_ > 0) {
268 write_callback_ = callback;
269 write_buffer_len_ = buf_len;
270 return ERR_IO_PENDING;
271 } else {
272 return buf_len;
273 }
274}
275
276bool SpdyProxyClientSocket::SetReceiveBufferSize(int32 size) {
[email protected]3268023f2011-05-05 00:08:10277 // Since this StreamSocket sits on top of a shared SpdySession, it
[email protected]fe2f62a2010-10-01 03:34:07278 // is not safe for callers to set change this underlying socket.
279 return false;
280}
281
282bool SpdyProxyClientSocket::SetSendBufferSize(int32 size) {
[email protected]3268023f2011-05-05 00:08:10283 // Since this StreamSocket sits on top of a shared SpdySession, it
[email protected]fe2f62a2010-10-01 03:34:07284 // is not safe for callers to set change this underlying socket.
285 return false;
286}
287
[email protected]a3528692012-06-08 00:11:42288int SpdyProxyClientSocket::GetPeerAddress(IPEndPoint* address) const {
[email protected]fe2f62a2010-10-01 03:34:07289 if (!IsConnected())
[email protected]88e03fa2010-10-05 03:09:04290 return ERR_SOCKET_NOT_CONNECTED;
[email protected]fe2f62a2010-10-01 03:34:07291 return spdy_stream_->GetPeerAddress(address);
292}
293
[email protected]e7f74da2011-04-19 23:49:35294int SpdyProxyClientSocket::GetLocalAddress(IPEndPoint* address) const {
295 if (!IsConnected())
296 return ERR_SOCKET_NOT_CONNECTED;
297 return spdy_stream_->GetLocalAddress(address);
298}
299
[email protected]fe2f62a2010-10-01 03:34:07300void SpdyProxyClientSocket::OnIOComplete(int result) {
[email protected]d9da5fe2010-10-13 22:37:16301 DCHECK_NE(STATE_DISCONNECTED, next_state_);
[email protected]fe2f62a2010-10-01 03:34:07302 int rv = DoLoop(result);
303 if (rv != ERR_IO_PENDING) {
[email protected]83039bb2011-12-09 18:43:55304 CompletionCallback c = read_callback_;
305 read_callback_.Reset();
306 c.Run(rv);
[email protected]fe2f62a2010-10-01 03:34:07307 }
308}
309
310int SpdyProxyClientSocket::DoLoop(int last_io_result) {
[email protected]d9da5fe2010-10-13 22:37:16311 DCHECK_NE(next_state_, STATE_DISCONNECTED);
[email protected]fe2f62a2010-10-01 03:34:07312 int rv = last_io_result;
313 do {
314 State state = next_state_;
[email protected]d9da5fe2010-10-13 22:37:16315 next_state_ = STATE_DISCONNECTED;
[email protected]fe2f62a2010-10-01 03:34:07316 switch (state) {
317 case STATE_GENERATE_AUTH_TOKEN:
318 DCHECK_EQ(OK, rv);
319 rv = DoGenerateAuthToken();
320 break;
321 case STATE_GENERATE_AUTH_TOKEN_COMPLETE:
322 rv = DoGenerateAuthTokenComplete(rv);
323 break;
324 case STATE_SEND_REQUEST:
325 DCHECK_EQ(OK, rv);
[email protected]d7fd1782011-02-08 19:16:43326 net_log_.BeginEvent(
[email protected]b618d1e2012-06-13 20:45:43327 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST);
[email protected]fe2f62a2010-10-01 03:34:07328 rv = DoSendRequest();
329 break;
330 case STATE_SEND_REQUEST_COMPLETE:
[email protected]d7fd1782011-02-08 19:16:43331 net_log_.EndEventWithNetErrorCode(
332 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST, rv);
[email protected]fe2f62a2010-10-01 03:34:07333 rv = DoSendRequestComplete(rv);
[email protected]fe2f62a2010-10-01 03:34:07334 break;
335 case STATE_READ_REPLY_COMPLETE:
336 rv = DoReadReplyComplete(rv);
[email protected]d7fd1782011-02-08 19:16:43337 net_log_.EndEventWithNetErrorCode(
338 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_READ_HEADERS, rv);
[email protected]fe2f62a2010-10-01 03:34:07339 break;
340 default:
341 NOTREACHED() << "bad state";
342 rv = ERR_UNEXPECTED;
343 break;
344 }
[email protected]d9da5fe2010-10-13 22:37:16345 } while (rv != ERR_IO_PENDING && next_state_ != STATE_DISCONNECTED &&
346 next_state_ != STATE_OPEN);
[email protected]fe2f62a2010-10-01 03:34:07347 return rv;
348}
349
350int SpdyProxyClientSocket::DoGenerateAuthToken() {
351 next_state_ = STATE_GENERATE_AUTH_TOKEN_COMPLETE;
[email protected]49639fa2011-12-20 23:22:41352 return auth_->MaybeGenerateAuthToken(
353 &request_,
354 base::Bind(&SpdyProxyClientSocket::OnIOComplete, base::Unretained(this)),
355 net_log_);
[email protected]fe2f62a2010-10-01 03:34:07356}
357
358int SpdyProxyClientSocket::DoGenerateAuthTokenComplete(int result) {
359 DCHECK_NE(ERR_IO_PENDING, result);
360 if (result == OK)
361 next_state_ = STATE_SEND_REQUEST;
362 return result;
363}
364
365int SpdyProxyClientSocket::DoSendRequest() {
366 next_state_ = STATE_SEND_REQUEST_COMPLETE;
367
368 // Add Proxy-Authentication header if necessary.
369 HttpRequestHeaders authorization_headers;
370 if (auth_->HaveAuth()) {
371 auth_->AddAuthorizationHeader(&authorization_headers);
372 }
373
374 std::string request_line;
375 HttpRequestHeaders request_headers;
376 BuildTunnelRequest(request_, authorization_headers, endpoint_, &request_line,
377 &request_headers);
[email protected]3abacd62012-06-10 20:20:32378
379 net_log_.AddEvent(
380 NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
381 base::Bind(&HttpRequestHeaders::NetLogCallback,
382 base::Unretained(&request_headers),
383 &request_line));
[email protected]fe2f62a2010-10-01 03:34:07384
385 request_.extra_headers.MergeFrom(request_headers);
[email protected]0a01d890fc2012-07-18 17:24:05386 scoped_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock());
[email protected]7213e7c2010-10-20 15:33:52387 CreateSpdyHeadersFromHttpRequest(request_, request_headers, headers.get(),
[email protected]0e861e92012-03-15 18:42:19388 spdy_stream_->GetProtocolVersion(), true);
[email protected]fe2f62a2010-10-01 03:34:07389 // Reset the URL to be the endpoint of the connection
[email protected]0e861e92012-03-15 18:42:19390 if (spdy_stream_->GetProtocolVersion() > 2) {
391 (*headers)[":path"] = endpoint_.ToString();
392 headers->erase(":scheme");
393 } else {
394 (*headers)["url"] = endpoint_.ToString();
395 headers->erase("scheme");
396 }
[email protected]0a01d890fc2012-07-18 17:24:05397 spdy_stream_->set_spdy_headers(headers.Pass());
[email protected]fe2f62a2010-10-01 03:34:07398
399 return spdy_stream_->SendRequest(true);
400}
401
402int SpdyProxyClientSocket::DoSendRequestComplete(int result) {
403 if (result < 0)
404 return result;
405
406 // Wait for SYN_REPLY frame from the server
407 next_state_ = STATE_READ_REPLY_COMPLETE;
408 return ERR_IO_PENDING;
409}
410
411int SpdyProxyClientSocket::DoReadReplyComplete(int result) {
412 // We enter this method directly from DoSendRequestComplete, since
413 // we are notified by a callback when the SYN_REPLY frame arrives
414
415 if (result < 0)
416 return result;
417
[email protected]fe2f62a2010-10-01 03:34:07418 // Require the "HTTP/1.x" status line for SSL CONNECT.
419 if (response_.headers->GetParsedHttpVersion() < HttpVersion(1, 0))
420 return ERR_TUNNEL_CONNECTION_FAILED;
421
[email protected]d9da5fe2010-10-13 22:37:16422 next_state_ = STATE_OPEN;
[email protected]3abacd62012-06-10 20:20:32423 net_log_.AddEvent(
424 NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
425 base::Bind(&HttpResponseHeaders::NetLogCallback, response_.headers));
[email protected]fe2f62a2010-10-01 03:34:07426
[email protected]511f6f52010-12-17 03:58:29427 if (response_.headers->response_code() == 200) {
[email protected]fe2f62a2010-10-01 03:34:07428 return OK;
[email protected]511f6f52010-12-17 03:58:29429 } else if (response_.headers->response_code() == 407) {
[email protected]b40d5cb2012-02-27 05:30:18430 return HandleProxyAuthChallenge(auth_, &response_, net_log_);
[email protected]511f6f52010-12-17 03:58:29431 } else {
432 // Immediately hand off our SpdyStream to a newly created SpdyHttpStream
433 // so that any subsequent SpdyFrames are processed in the context of
434 // the HttpStream, not the socket.
435 DCHECK(spdy_stream_);
436 SpdyStream* stream = spdy_stream_;
437 spdy_stream_ = NULL;
438 response_stream_.reset(new SpdyHttpStream(NULL, false));
439 response_stream_->InitializeWithExistingStream(stream);
440 next_state_ = STATE_DISCONNECTED;
441 return ERR_HTTPS_PROXY_TUNNEL_RESPONSE;
442 }
[email protected]fe2f62a2010-10-01 03:34:07443}
444
445// SpdyStream::Delegate methods:
446// Called when SYN frame has been sent.
447// Returns true if no more data to be sent after SYN frame.
448bool SpdyProxyClientSocket::OnSendHeadersComplete(int status) {
449 DCHECK_EQ(next_state_, STATE_SEND_REQUEST_COMPLETE);
450
451 OnIOComplete(status);
452
453 // We return true here so that we send |spdy_stream_| into
454 // STATE_OPEN (ala WebSockets).
455 return true;
456}
457
458int SpdyProxyClientSocket::OnSendBody() {
459 // Because we use |spdy_stream_| via STATE_OPEN (ala WebSockets)
460 // OnSendBody() should never be called.
461 NOTREACHED();
462 return ERR_UNEXPECTED;
463}
464
[email protected]0c9bf872011-03-04 17:53:22465int SpdyProxyClientSocket::OnSendBodyComplete(int /*status*/, bool* /*eof*/) {
[email protected]fe2f62a2010-10-01 03:34:07466 // Because we use |spdy_stream_| via STATE_OPEN (ala WebSockets)
467 // OnSendBodyComplete() should never be called.
468 NOTREACHED();
[email protected]0c9bf872011-03-04 17:53:22469 return ERR_UNEXPECTED;
[email protected]fe2f62a2010-10-01 03:34:07470}
471
472int SpdyProxyClientSocket::OnResponseReceived(
[email protected]ff98d7f02012-03-22 21:44:19473 const SpdyHeaderBlock& response,
[email protected]fe2f62a2010-10-01 03:34:07474 base::Time response_time,
475 int status) {
[email protected]d08358502010-12-03 22:04:03476 // If we've already received the reply, existing headers are too late.
477 // TODO(mbelshe): figure out a way to make HEADERS frames useful after the
478 // initial response.
479 if (next_state_ != STATE_READ_REPLY_COMPLETE)
480 return OK;
[email protected]fe2f62a2010-10-01 03:34:07481
[email protected]d08358502010-12-03 22:04:03482 // Save the response
[email protected]d42dedd02012-04-03 19:42:06483 if (!SpdyHeadersToHttpResponse(
484 response, spdy_stream_->GetProtocolVersion(), &response_))
485 return ERR_INCOMPLETE_SPDY_HEADERS;
[email protected]fe2f62a2010-10-01 03:34:07486
487 OnIOComplete(status);
[email protected]fe2f62a2010-10-01 03:34:07488 return OK;
489}
490
491// Called when data is received.
492void SpdyProxyClientSocket::OnDataReceived(const char* data, int length) {
493 if (length > 0) {
494 // Save the received data.
[email protected]ad8e04a2010-11-01 04:16:27495 scoped_refptr<IOBuffer> io_buffer(new IOBuffer(length));
[email protected]fe2f62a2010-10-01 03:34:07496 memcpy(io_buffer->data(), data, length);
[email protected]00cd9c42010-11-02 20:15:57497 read_buffer_.push_back(
498 make_scoped_refptr(new DrainableIOBuffer(io_buffer, length)));
[email protected]fe2f62a2010-10-01 03:34:07499 }
500
[email protected]83039bb2011-12-09 18:43:55501 if (!read_callback_.is_null()) {
[email protected]dbf036f2011-12-06 23:33:24502 int rv = PopulateUserReadBuffer();
503 CompletionCallback c = read_callback_;
504 read_callback_.Reset();
505 user_buffer_ = NULL;
506 c.Run(rv);
[email protected]fe2f62a2010-10-01 03:34:07507 }
508}
509
510void SpdyProxyClientSocket::OnDataSent(int length) {
[email protected]83039bb2011-12-09 18:43:55511 DCHECK(!write_callback_.is_null());
[email protected]fe2f62a2010-10-01 03:34:07512
513 write_bytes_outstanding_ -= length;
514
515 DCHECK_GE(write_bytes_outstanding_, 0);
516
517 if (write_bytes_outstanding_ == 0) {
518 int rv = write_buffer_len_;
519 write_buffer_len_ = 0;
520 write_bytes_outstanding_ = 0;
[email protected]83039bb2011-12-09 18:43:55521 CompletionCallback c = write_callback_;
522 write_callback_.Reset();
523 c.Run(rv);
[email protected]fe2f62a2010-10-01 03:34:07524 }
525}
526
527void SpdyProxyClientSocket::OnClose(int status) {
528 DCHECK(spdy_stream_);
[email protected]fe2f62a2010-10-01 03:34:07529 was_ever_used_ = spdy_stream_->WasEverUsed();
530 spdy_stream_ = NULL;
[email protected]d9da5fe2010-10-13 22:37:16531
532 bool connecting = next_state_ != STATE_DISCONNECTED &&
533 next_state_ < STATE_OPEN;
534 if (next_state_ == STATE_OPEN)
535 next_state_ = STATE_CLOSED;
536 else
537 next_state_ = STATE_DISCONNECTED;
538
[email protected]6af4e412011-11-29 23:39:18539 base::WeakPtr<SpdyProxyClientSocket> weak_ptr = weak_factory_.GetWeakPtr();
[email protected]83039bb2011-12-09 18:43:55540 CompletionCallback write_callback = write_callback_;
541 write_callback_.Reset();
[email protected]d9da5fe2010-10-13 22:37:16542 write_buffer_len_ = 0;
543 write_bytes_outstanding_ = 0;
544
545 // If we're in the middle of connecting, we need to make sure
546 // we invoke the connect callback.
547 if (connecting) {
[email protected]83039bb2011-12-09 18:43:55548 DCHECK(!read_callback_.is_null());
549 CompletionCallback read_callback = read_callback_;
550 read_callback_.Reset();
551 read_callback.Run(status);
552 } else if (!read_callback_.is_null()) {
[email protected]6af4e412011-11-29 23:39:18553 // If we have a read_callback_, the we need to make sure we call it back.
[email protected]d9da5fe2010-10-13 22:37:16554 OnDataReceived(NULL, 0);
555 }
[email protected]6af4e412011-11-29 23:39:18556 // This may have been deleted by read_callback_, so check first.
[email protected]83039bb2011-12-09 18:43:55557 if (weak_ptr && !write_callback.is_null())
558 write_callback.Run(ERR_CONNECTION_CLOSED);
[email protected]fe2f62a2010-10-01 03:34:07559}
560
[email protected]fe2f62a2010-10-01 03:34:07561} // namespace net