blob: 43ec5b2313b8792b310f6d579559bc8188278c85 [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]aa19cfc2013-05-23 16:41:3811#include "base/callback_helpers.h"
[email protected]fe2f62a2010-10-01 03:34:0712#include "base/logging.h"
13#include "base/string_util.h"
[email protected]f6c63db52013-02-02 00:35:2214#include "base/values.h"
[email protected]fe2f62a2010-10-01 03:34:0715#include "googleurl/src/gurl.h"
16#include "net/base/auth.h"
17#include "net/base/io_buffer.h"
18#include "net/base/net_util.h"
[email protected]fe3b7dc2012-02-03 19:52:0919#include "net/http/http_auth_cache.h"
20#include "net/http/http_auth_handler_factory.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(
[email protected]d26ff352013-05-13 08:48:2827 const base::WeakPtr<SpdyStream>& spdy_stream,
[email protected]fe2f62a2010-10-01 03:34:0728 const std::string& user_agent,
29 const HostPortPair& endpoint,
30 const GURL& url,
31 const HostPortPair& proxy_server,
[email protected]f6c63db52013-02-02 00:35:2232 const BoundNetLog& source_net_log,
[email protected]fe3b7dc2012-02-03 19:52:0933 HttpAuthCache* auth_cache,
34 HttpAuthHandlerFactory* auth_handler_factory)
[email protected]49639fa2011-12-20 23:22:4135 : next_state_(STATE_DISCONNECTED),
[email protected]fe2f62a2010-10-01 03:34:0736 spdy_stream_(spdy_stream),
[email protected]fe2f62a2010-10-01 03:34:0737 endpoint_(endpoint),
[email protected]fe3b7dc2012-02-03 19:52:0938 auth_(
39 new HttpAuthController(HttpAuth::AUTH_PROXY,
40 GURL("https://" + proxy_server.ToString()),
41 auth_cache,
42 auth_handler_factory)),
[email protected]ca690b02013-04-17 10:38:4343 user_buffer_len_(0),
[email protected]fe2f62a2010-10-01 03:34:0744 write_buffer_len_(0),
[email protected]aa249b52013-04-30 01:04:3245 weak_factory_(this),
[email protected]f6c63db52013-02-02 00:35:2246 net_log_(BoundNetLog::Make(spdy_stream->net_log().net_log(),
47 NetLog::SOURCE_PROXY_CLIENT_SOCKET)) {
[email protected]fe2f62a2010-10-01 03:34:0748 request_.method = "CONNECT";
49 request_.url = url;
50 if (!user_agent.empty())
51 request_.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent,
52 user_agent);
[email protected]f6c63db52013-02-02 00:35:2253
54 net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE,
55 source_net_log.source().ToEventParametersCallback());
56 net_log_.AddEvent(
57 NetLog::TYPE_SPDY_PROXY_CLIENT_SESSION,
58 spdy_stream->net_log().source().ToEventParametersCallback());
59
[email protected]fe2f62a2010-10-01 03:34:0760 spdy_stream_->SetDelegate(this);
61 was_ever_used_ = spdy_stream_->WasEverUsed();
62}
63
64SpdyProxyClientSocket::~SpdyProxyClientSocket() {
65 Disconnect();
[email protected]f6c63db52013-02-02 00:35:2266 net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE);
[email protected]fe2f62a2010-10-01 03:34:0767}
68
[email protected]be1a48b2011-01-20 00:12:1369const HttpResponseInfo* SpdyProxyClientSocket::GetConnectResponseInfo() const {
70 return response_.headers ? &response_ : NULL;
71}
72
[email protected]c0fe941d2012-02-25 00:15:3273const scoped_refptr<HttpAuthController>&
74SpdyProxyClientSocket::GetAuthController() const {
75 return auth_;
76}
77
78int SpdyProxyClientSocket::RestartWithAuth(const CompletionCallback& callback) {
79 // A SPDY Stream can only handle a single request, so the underlying
80 // stream may not be reused and a new SpdyProxyClientSocket must be
81 // created (possibly on top of the same SPDY Session).
82 next_state_ = STATE_DISCONNECTED;
[email protected]0c5fb722012-02-28 11:50:3583 return OK;
[email protected]c0fe941d2012-02-25 00:15:3284}
85
86bool SpdyProxyClientSocket::IsUsingSpdy() const {
87 return true;
88}
89
[email protected]8e3c78cb2012-03-31 03:58:4690NextProto SpdyProxyClientSocket::GetProtocolNegotiated() const {
[email protected]c0fe941d2012-02-25 00:15:3291 // Save the negotiated protocol
92 SSLInfo ssl_info;
93 bool was_npn_negotiated;
[email protected]8e3c78cb2012-03-31 03:58:4694 NextProto protocol_negotiated;
[email protected]c0fe941d2012-02-25 00:15:3295 spdy_stream_->GetSSLInfo(&ssl_info, &was_npn_negotiated,
96 &protocol_negotiated);
97 return protocol_negotiated;
98}
99
[email protected]511f6f52010-12-17 03:58:29100HttpStream* SpdyProxyClientSocket::CreateConnectResponseStream() {
101 DCHECK(response_stream_.get());
102 return response_stream_.release();
103}
104
[email protected]fe2f62a2010-10-01 03:34:07105// Sends a SYN_STREAM frame to the proxy with a CONNECT request
106// for the specified endpoint. Waits for the server to send back
107// a SYN_REPLY frame. OK will be returned if the status is 200.
108// ERR_TUNNEL_CONNECTION_FAILED will be returned for any other status.
109// In any of these cases, Read() may be called to retrieve the HTTP
110// response body. Any other return values should be considered fatal.
[email protected]fe3b7dc2012-02-03 19:52:09111// TODO(rch): handle 407 proxy auth requested correctly, perhaps
112// by creating a new stream for the subsequent request.
[email protected]fe2f62a2010-10-01 03:34:07113// TODO(rch): create a more appropriate error code to disambiguate
114// the HTTPS Proxy tunnel failure from an HTTP Proxy tunnel failure.
[email protected]dbf036f2011-12-06 23:33:24115int SpdyProxyClientSocket::Connect(const CompletionCallback& callback) {
[email protected]83039bb2011-12-09 18:43:55116 DCHECK(read_callback_.is_null());
[email protected]d9da5fe2010-10-13 22:37:16117 if (next_state_ == STATE_OPEN)
[email protected]fe2f62a2010-10-01 03:34:07118 return OK;
119
[email protected]d9da5fe2010-10-13 22:37:16120 DCHECK_EQ(STATE_DISCONNECTED, next_state_);
[email protected]fe2f62a2010-10-01 03:34:07121 next_state_ = STATE_GENERATE_AUTH_TOKEN;
122
123 int rv = DoLoop(OK);
124 if (rv == ERR_IO_PENDING)
125 read_callback_ = callback;
126 return rv;
127}
128
129void SpdyProxyClientSocket::Disconnect() {
[email protected]ca690b02013-04-17 10:38:43130 read_buffer_queue_.Clear();
[email protected]d9da5fe2010-10-13 22:37:16131 user_buffer_ = NULL;
[email protected]ca690b02013-04-17 10:38:43132 user_buffer_len_ = 0;
[email protected]dbf036f2011-12-06 23:33:24133 read_callback_.Reset();
[email protected]d9da5fe2010-10-13 22:37:16134
135 write_buffer_len_ = 0;
[email protected]83039bb2011-12-09 18:43:55136 write_callback_.Reset();
[email protected]d9da5fe2010-10-13 22:37:16137
138 next_state_ = STATE_DISCONNECTED;
139
[email protected]f6a78292013-03-09 14:36:34140 if (spdy_stream_) {
[email protected]fe2f62a2010-10-01 03:34:07141 // This will cause OnClose to be invoked, which takes care of
142 // cleaning up all the internal state.
143 spdy_stream_->Cancel();
[email protected]d26ff352013-05-13 08:48:28144 DCHECK(!spdy_stream_);
[email protected]f6a78292013-03-09 14:36:34145 }
[email protected]fe2f62a2010-10-01 03:34:07146}
147
148bool SpdyProxyClientSocket::IsConnected() const {
[email protected]194c7a92011-12-03 04:54:18149 return next_state_ == STATE_OPEN;
[email protected]fe2f62a2010-10-01 03:34:07150}
151
152bool SpdyProxyClientSocket::IsConnectedAndIdle() const {
[email protected]ca690b02013-04-17 10:38:43153 return IsConnected() && read_buffer_queue_.IsEmpty() &&
154 spdy_stream_->is_idle();
[email protected]fe2f62a2010-10-01 03:34:07155}
156
[email protected]e4be2dd2010-12-14 00:44:39157const BoundNetLog& SpdyProxyClientSocket::NetLog() const {
158 return net_log_;
159}
160
[email protected]fe2f62a2010-10-01 03:34:07161void SpdyProxyClientSocket::SetSubresourceSpeculation() {
162 // TODO(rch): what should this implementation be?
163}
164
165void SpdyProxyClientSocket::SetOmniboxSpeculation() {
166 // TODO(rch): what should this implementation be?
167}
168
169bool SpdyProxyClientSocket::WasEverUsed() const {
170 return was_ever_used_ || (spdy_stream_ && spdy_stream_->WasEverUsed());
171}
172
[email protected]7f7e92392010-10-26 18:29:29173bool SpdyProxyClientSocket::UsingTCPFastOpen() const {
174 return false;
175}
176
[email protected]2d88e7d2012-07-19 17:55:17177bool SpdyProxyClientSocket::WasNpnNegotiated() const {
178 return false;
179}
180
[email protected]33661e482012-04-03 16:16:26181NextProto SpdyProxyClientSocket::GetNegotiatedProtocol() const {
182 return kProtoUnknown;
183}
184
[email protected]2d88e7d2012-07-19 17:55:17185bool SpdyProxyClientSocket::GetSSLInfo(SSLInfo* ssl_info) {
186 bool was_npn_negotiated;
187 NextProto protocol_negotiated;
188 return spdy_stream_->GetSSLInfo(ssl_info, &was_npn_negotiated,
189 &protocol_negotiated);
190}
191
[email protected]fe2f62a2010-10-01 03:34:07192int SpdyProxyClientSocket::Read(IOBuffer* buf, int buf_len,
[email protected]3f55aa12011-12-07 02:03:33193 const CompletionCallback& callback) {
[email protected]83039bb2011-12-09 18:43:55194 DCHECK(read_callback_.is_null());
[email protected]3f55aa12011-12-07 02:03:33195 DCHECK(!user_buffer_);
196
197 if (next_state_ == STATE_DISCONNECTED)
198 return ERR_SOCKET_NOT_CONNECTED;
199
[email protected]ca690b02013-04-17 10:38:43200 if (next_state_ == STATE_CLOSED && read_buffer_queue_.IsEmpty()) {
[email protected]3f55aa12011-12-07 02:03:33201 return 0;
202 }
203
204 DCHECK(next_state_ == STATE_OPEN || next_state_ == STATE_CLOSED);
205 DCHECK(buf);
[email protected]ca690b02013-04-17 10:38:43206 size_t result = PopulateUserReadBuffer(buf->data(), buf_len);
[email protected]3f55aa12011-12-07 02:03:33207 if (result == 0) {
[email protected]ca690b02013-04-17 10:38:43208 user_buffer_ = buf;
209 user_buffer_len_ = static_cast<size_t>(buf_len);
[email protected]3f55aa12011-12-07 02:03:33210 DCHECK(!callback.is_null());
211 read_callback_ = callback;
212 return ERR_IO_PENDING;
213 }
214 user_buffer_ = NULL;
215 return result;
216}
[email protected]fe2f62a2010-10-01 03:34:07217
[email protected]ca690b02013-04-17 10:38:43218size_t SpdyProxyClientSocket::PopulateUserReadBuffer(char* data, size_t len) {
[email protected]09a8d9172013-04-17 19:23:49219 return read_buffer_queue_.Dequeue(data, len);
[email protected]fe2f62a2010-10-01 03:34:07220}
221
222int SpdyProxyClientSocket::Write(IOBuffer* buf, int buf_len,
[email protected]83039bb2011-12-09 18:43:55223 const CompletionCallback& callback) {
224 DCHECK(write_callback_.is_null());
[email protected]194c7a92011-12-03 04:54:18225 if (next_state_ != STATE_OPEN)
[email protected]d9da5fe2010-10-13 22:37:16226 return ERR_SOCKET_NOT_CONNECTED;
227
[email protected]194c7a92011-12-03 04:54:18228 DCHECK(spdy_stream_);
[email protected]aa19cfc2013-05-23 16:41:38229 spdy_stream_->SendStreamData(buf, buf_len, DATA_FLAG_NONE);
230 net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_SENT,
231 buf_len, buf->data());
232 write_callback_ = callback;
233 write_buffer_len_ = buf_len;
234 return ERR_IO_PENDING;
[email protected]fe2f62a2010-10-01 03:34:07235}
236
237bool SpdyProxyClientSocket::SetReceiveBufferSize(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
243bool SpdyProxyClientSocket::SetSendBufferSize(int32 size) {
[email protected]3268023f2011-05-05 00:08:10244 // Since this StreamSocket sits on top of a shared SpdySession, it
[email protected]fe2f62a2010-10-01 03:34:07245 // is not safe for callers to set change this underlying socket.
246 return false;
247}
248
[email protected]a3528692012-06-08 00:11:42249int SpdyProxyClientSocket::GetPeerAddress(IPEndPoint* address) const {
[email protected]fe2f62a2010-10-01 03:34:07250 if (!IsConnected())
[email protected]88e03fa2010-10-05 03:09:04251 return ERR_SOCKET_NOT_CONNECTED;
[email protected]fe2f62a2010-10-01 03:34:07252 return spdy_stream_->GetPeerAddress(address);
253}
254
[email protected]e7f74da2011-04-19 23:49:35255int SpdyProxyClientSocket::GetLocalAddress(IPEndPoint* address) const {
256 if (!IsConnected())
257 return ERR_SOCKET_NOT_CONNECTED;
258 return spdy_stream_->GetLocalAddress(address);
259}
260
[email protected]4eddbc732012-08-09 05:40:17261void SpdyProxyClientSocket::LogBlockedTunnelResponse() const {
262 ProxyClientSocket::LogBlockedTunnelResponse(
263 response_.headers->response_code(),
264 request_.url,
265 /* is_https_proxy = */ true);
266}
267
[email protected]fe2f62a2010-10-01 03:34:07268void SpdyProxyClientSocket::OnIOComplete(int result) {
[email protected]d9da5fe2010-10-13 22:37:16269 DCHECK_NE(STATE_DISCONNECTED, next_state_);
[email protected]fe2f62a2010-10-01 03:34:07270 int rv = DoLoop(result);
271 if (rv != ERR_IO_PENDING) {
[email protected]83039bb2011-12-09 18:43:55272 CompletionCallback c = read_callback_;
273 read_callback_.Reset();
274 c.Run(rv);
[email protected]fe2f62a2010-10-01 03:34:07275 }
276}
277
278int SpdyProxyClientSocket::DoLoop(int last_io_result) {
[email protected]d9da5fe2010-10-13 22:37:16279 DCHECK_NE(next_state_, STATE_DISCONNECTED);
[email protected]fe2f62a2010-10-01 03:34:07280 int rv = last_io_result;
281 do {
282 State state = next_state_;
[email protected]d9da5fe2010-10-13 22:37:16283 next_state_ = STATE_DISCONNECTED;
[email protected]fe2f62a2010-10-01 03:34:07284 switch (state) {
285 case STATE_GENERATE_AUTH_TOKEN:
286 DCHECK_EQ(OK, rv);
287 rv = DoGenerateAuthToken();
288 break;
289 case STATE_GENERATE_AUTH_TOKEN_COMPLETE:
290 rv = DoGenerateAuthTokenComplete(rv);
291 break;
292 case STATE_SEND_REQUEST:
293 DCHECK_EQ(OK, rv);
[email protected]f6c63db52013-02-02 00:35:22294 net_log_.BeginEvent(NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST);
[email protected]fe2f62a2010-10-01 03:34:07295 rv = DoSendRequest();
296 break;
297 case STATE_SEND_REQUEST_COMPLETE:
[email protected]d7fd1782011-02-08 19:16:43298 net_log_.EndEventWithNetErrorCode(
299 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST, rv);
[email protected]fe2f62a2010-10-01 03:34:07300 rv = DoSendRequestComplete(rv);
[email protected]f6c63db52013-02-02 00:35:22301 if (rv >= 0 || rv == ERR_IO_PENDING) {
302 // Emit extra event so can use the same events as
303 // HttpProxyClientSocket.
304 net_log_.BeginEvent(
305 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_READ_HEADERS);
306 }
[email protected]fe2f62a2010-10-01 03:34:07307 break;
308 case STATE_READ_REPLY_COMPLETE:
309 rv = DoReadReplyComplete(rv);
[email protected]d7fd1782011-02-08 19:16:43310 net_log_.EndEventWithNetErrorCode(
311 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_READ_HEADERS, rv);
[email protected]fe2f62a2010-10-01 03:34:07312 break;
313 default:
314 NOTREACHED() << "bad state";
315 rv = ERR_UNEXPECTED;
316 break;
317 }
[email protected]d9da5fe2010-10-13 22:37:16318 } while (rv != ERR_IO_PENDING && next_state_ != STATE_DISCONNECTED &&
319 next_state_ != STATE_OPEN);
[email protected]fe2f62a2010-10-01 03:34:07320 return rv;
321}
322
323int SpdyProxyClientSocket::DoGenerateAuthToken() {
324 next_state_ = STATE_GENERATE_AUTH_TOKEN_COMPLETE;
[email protected]49639fa2011-12-20 23:22:41325 return auth_->MaybeGenerateAuthToken(
326 &request_,
[email protected]f6a78292013-03-09 14:36:34327 base::Bind(&SpdyProxyClientSocket::OnIOComplete,
328 weak_factory_.GetWeakPtr()),
[email protected]49639fa2011-12-20 23:22:41329 net_log_);
[email protected]fe2f62a2010-10-01 03:34:07330}
331
332int SpdyProxyClientSocket::DoGenerateAuthTokenComplete(int result) {
333 DCHECK_NE(ERR_IO_PENDING, result);
334 if (result == OK)
335 next_state_ = STATE_SEND_REQUEST;
336 return result;
337}
338
339int SpdyProxyClientSocket::DoSendRequest() {
340 next_state_ = STATE_SEND_REQUEST_COMPLETE;
341
342 // Add Proxy-Authentication header if necessary.
343 HttpRequestHeaders authorization_headers;
344 if (auth_->HaveAuth()) {
345 auth_->AddAuthorizationHeader(&authorization_headers);
346 }
347
348 std::string request_line;
349 HttpRequestHeaders request_headers;
350 BuildTunnelRequest(request_, authorization_headers, endpoint_, &request_line,
351 &request_headers);
[email protected]3abacd62012-06-10 20:20:32352
353 net_log_.AddEvent(
354 NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
355 base::Bind(&HttpRequestHeaders::NetLogCallback,
356 base::Unretained(&request_headers),
357 &request_line));
[email protected]fe2f62a2010-10-01 03:34:07358
359 request_.extra_headers.MergeFrom(request_headers);
[email protected]0a01d890fc2012-07-18 17:24:05360 scoped_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock());
[email protected]7213e7c2010-10-20 15:33:52361 CreateSpdyHeadersFromHttpRequest(request_, request_headers, headers.get(),
[email protected]0e861e92012-03-15 18:42:19362 spdy_stream_->GetProtocolVersion(), true);
[email protected]fe2f62a2010-10-01 03:34:07363 // Reset the URL to be the endpoint of the connection
[email protected]0e861e92012-03-15 18:42:19364 if (spdy_stream_->GetProtocolVersion() > 2) {
365 (*headers)[":path"] = endpoint_.ToString();
366 headers->erase(":scheme");
367 } else {
368 (*headers)["url"] = endpoint_.ToString();
369 headers->erase("scheme");
370 }
[email protected]0a01d890fc2012-07-18 17:24:05371 spdy_stream_->set_spdy_headers(headers.Pass());
[email protected]fe2f62a2010-10-01 03:34:07372
373 return spdy_stream_->SendRequest(true);
374}
375
376int SpdyProxyClientSocket::DoSendRequestComplete(int result) {
377 if (result < 0)
378 return result;
379
380 // Wait for SYN_REPLY frame from the server
381 next_state_ = STATE_READ_REPLY_COMPLETE;
382 return ERR_IO_PENDING;
383}
384
385int SpdyProxyClientSocket::DoReadReplyComplete(int result) {
386 // We enter this method directly from DoSendRequestComplete, since
387 // we are notified by a callback when the SYN_REPLY frame arrives
388
389 if (result < 0)
390 return result;
391
[email protected]fe2f62a2010-10-01 03:34:07392 // Require the "HTTP/1.x" status line for SSL CONNECT.
393 if (response_.headers->GetParsedHttpVersion() < HttpVersion(1, 0))
394 return ERR_TUNNEL_CONNECTION_FAILED;
395
[email protected]3abacd62012-06-10 20:20:32396 net_log_.AddEvent(
397 NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
398 base::Bind(&HttpResponseHeaders::NetLogCallback, response_.headers));
[email protected]fe2f62a2010-10-01 03:34:07399
[email protected]4eddbc732012-08-09 05:40:17400 switch (response_.headers->response_code()) {
401 case 200: // OK
402 next_state_ = STATE_OPEN;
403 return OK;
404
405 case 302: // Found / Moved Temporarily
406 // Try to return a sanitized response so we can follow auth redirects.
407 // If we can't, fail the tunnel connection.
408 if (SanitizeProxyRedirect(&response_, request_.url)) {
409 // Immediately hand off our SpdyStream to a newly created
410 // SpdyHttpStream so that any subsequent SpdyFrames are processed in
411 // the context of the HttpStream, not the socket.
412 DCHECK(spdy_stream_);
[email protected]d26ff352013-05-13 08:48:28413 base::WeakPtr<SpdyStream> stream = spdy_stream_;
414 spdy_stream_.reset();
[email protected]4eddbc732012-08-09 05:40:17415 response_stream_.reset(new SpdyHttpStream(NULL, false));
416 response_stream_->InitializeWithExistingStream(stream);
417 next_state_ = STATE_DISCONNECTED;
418 return ERR_HTTPS_PROXY_TUNNEL_RESPONSE;
419 } else {
420 LogBlockedTunnelResponse();
421 return ERR_TUNNEL_CONNECTION_FAILED;
422 }
423
424 case 407: // Proxy Authentication Required
425 next_state_ = STATE_OPEN;
426 return HandleProxyAuthChallenge(auth_, &response_, net_log_);
427
428 default:
429 // Ignore response to avoid letting the proxy impersonate the target
430 // server. (See http://crbug.com/137891.)
431 LogBlockedTunnelResponse();
432 return ERR_TUNNEL_CONNECTION_FAILED;
[email protected]511f6f52010-12-17 03:58:29433 }
[email protected]fe2f62a2010-10-01 03:34:07434}
435
436// SpdyStream::Delegate methods:
437// Called when SYN frame has been sent.
438// Returns true if no more data to be sent after SYN frame.
[email protected]d46715c2013-04-15 00:21:42439SpdySendStatus SpdyProxyClientSocket::OnSendHeadersComplete() {
[email protected]fe2f62a2010-10-01 03:34:07440 DCHECK_EQ(next_state_, STATE_SEND_REQUEST_COMPLETE);
441
[email protected]d46715c2013-04-15 00:21:42442 OnIOComplete(OK);
[email protected]fe2f62a2010-10-01 03:34:07443
444 // We return true here so that we send |spdy_stream_| into
445 // STATE_OPEN (ala WebSockets).
[email protected]d46715c2013-04-15 00:21:42446 return NO_MORE_DATA_TO_SEND;
[email protected]fe2f62a2010-10-01 03:34:07447}
448
[email protected]63c8cb02013-05-22 22:34:04449void SpdyProxyClientSocket::OnSendBody() {
[email protected]fe2f62a2010-10-01 03:34:07450 // Because we use |spdy_stream_| via STATE_OPEN (ala WebSockets)
[email protected]63c8cb02013-05-22 22:34:04451 // OnSendBody() must never be called.
452 CHECK(false);
[email protected]fe2f62a2010-10-01 03:34:07453}
454
[email protected]aa19cfc2013-05-23 16:41:38455SpdySendStatus SpdyProxyClientSocket::OnSendBodyComplete() {
[email protected]fe2f62a2010-10-01 03:34:07456 // Because we use |spdy_stream_| via STATE_OPEN (ala WebSockets)
[email protected]63c8cb02013-05-22 22:34:04457 // OnSendBodyComplete() must never be called.
458 CHECK(false);
[email protected]d46715c2013-04-15 00:21:42459 return NO_MORE_DATA_TO_SEND;
[email protected]fe2f62a2010-10-01 03:34:07460}
461
462int SpdyProxyClientSocket::OnResponseReceived(
[email protected]ff98d7f02012-03-22 21:44:19463 const SpdyHeaderBlock& response,
[email protected]fe2f62a2010-10-01 03:34:07464 base::Time response_time,
465 int status) {
[email protected]d08358502010-12-03 22:04:03466 // If we've already received the reply, existing headers are too late.
467 // TODO(mbelshe): figure out a way to make HEADERS frames useful after the
468 // initial response.
469 if (next_state_ != STATE_READ_REPLY_COMPLETE)
470 return OK;
[email protected]fe2f62a2010-10-01 03:34:07471
[email protected]d08358502010-12-03 22:04:03472 // Save the response
[email protected]d42dedd02012-04-03 19:42:06473 if (!SpdyHeadersToHttpResponse(
474 response, spdy_stream_->GetProtocolVersion(), &response_))
475 return ERR_INCOMPLETE_SPDY_HEADERS;
[email protected]fe2f62a2010-10-01 03:34:07476
477 OnIOComplete(status);
[email protected]fe2f62a2010-10-01 03:34:07478 return OK;
479}
480
[email protected]050b3602012-08-15 04:10:49481void SpdyProxyClientSocket::OnHeadersSent() {
482 // Proxy client sockets don't send any HEADERS frame.
483 NOTREACHED();
484}
485
[email protected]ca690b02013-04-17 10:38:43486// Called when data is received or on EOF (if |buffer| is NULL).
487int SpdyProxyClientSocket::OnDataReceived(scoped_ptr<SpdyBuffer> buffer) {
488 if (buffer) {
489 net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_RECEIVED,
490 buffer->GetRemainingSize(),
491 buffer->GetRemainingData());
492 read_buffer_queue_.Enqueue(buffer.Pass());
493 } else {
494 net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_RECEIVED, 0, NULL);
[email protected]fe2f62a2010-10-01 03:34:07495 }
496
[email protected]83039bb2011-12-09 18:43:55497 if (!read_callback_.is_null()) {
[email protected]ca690b02013-04-17 10:38:43498 int rv = PopulateUserReadBuffer(user_buffer_->data(), user_buffer_len_);
[email protected]dbf036f2011-12-06 23:33:24499 CompletionCallback c = read_callback_;
500 read_callback_.Reset();
501 user_buffer_ = NULL;
[email protected]ca690b02013-04-17 10:38:43502 user_buffer_len_ = 0;
[email protected]dbf036f2011-12-06 23:33:24503 c.Run(rv);
[email protected]fe2f62a2010-10-01 03:34:07504 }
[email protected]5c6908e2012-08-06 18:53:47505 return OK;
[email protected]fe2f62a2010-10-01 03:34:07506}
507
[email protected]aa19cfc2013-05-23 16:41:38508void SpdyProxyClientSocket::OnDataSent() {
[email protected]83039bb2011-12-09 18:43:55509 DCHECK(!write_callback_.is_null());
[email protected]fe2f62a2010-10-01 03:34:07510
[email protected]aa19cfc2013-05-23 16:41:38511 int rv = write_buffer_len_;
512 write_buffer_len_ = 0;
513 ResetAndReturn(&write_callback_).Run(rv);
[email protected]fe2f62a2010-10-01 03:34:07514}
515
516void SpdyProxyClientSocket::OnClose(int status) {
[email protected]fe2f62a2010-10-01 03:34:07517 was_ever_used_ = spdy_stream_->WasEverUsed();
[email protected]d26ff352013-05-13 08:48:28518 spdy_stream_.reset();
[email protected]d9da5fe2010-10-13 22:37:16519
520 bool connecting = next_state_ != STATE_DISCONNECTED &&
521 next_state_ < STATE_OPEN;
522 if (next_state_ == STATE_OPEN)
523 next_state_ = STATE_CLOSED;
524 else
525 next_state_ = STATE_DISCONNECTED;
526
[email protected]6af4e412011-11-29 23:39:18527 base::WeakPtr<SpdyProxyClientSocket> weak_ptr = weak_factory_.GetWeakPtr();
[email protected]83039bb2011-12-09 18:43:55528 CompletionCallback write_callback = write_callback_;
529 write_callback_.Reset();
[email protected]d9da5fe2010-10-13 22:37:16530 write_buffer_len_ = 0;
[email protected]d9da5fe2010-10-13 22:37:16531
532 // If we're in the middle of connecting, we need to make sure
533 // we invoke the connect callback.
534 if (connecting) {
[email protected]83039bb2011-12-09 18:43:55535 DCHECK(!read_callback_.is_null());
536 CompletionCallback read_callback = read_callback_;
537 read_callback_.Reset();
538 read_callback.Run(status);
539 } else if (!read_callback_.is_null()) {
[email protected]6af4e412011-11-29 23:39:18540 // If we have a read_callback_, the we need to make sure we call it back.
[email protected]ca690b02013-04-17 10:38:43541 OnDataReceived(scoped_ptr<SpdyBuffer>());
[email protected]d9da5fe2010-10-13 22:37:16542 }
[email protected]6af4e412011-11-29 23:39:18543 // This may have been deleted by read_callback_, so check first.
[email protected]83039bb2011-12-09 18:43:55544 if (weak_ptr && !write_callback.is_null())
545 write_callback.Run(ERR_CONNECTION_CLOSED);
[email protected]fe2f62a2010-10-01 03:34:07546}
547
[email protected]fe2f62a2010-10-01 03:34:07548} // namespace net