Index: net/websockets/websocket_job.cc |
diff --git a/net/websockets/websocket_job.cc b/net/websockets/websocket_job.cc |
index 77fc0582304cef9499f3bc6f46fac3161f97fc12..643977f06fc9c804b3ea5abea1dd2d7acd533242 100644 |
--- a/net/websockets/websocket_job.cc |
+++ b/net/websockets/websocket_job.cc |
@@ -24,6 +24,8 @@ |
#include "net/websockets/websocket_net_log_params.h" |
#include "net/websockets/websocket_throttle.h" |
+static const int kMaxPendingSendAllowed = 32768; // 32 kilobytes. |
+ |
namespace { |
// lower-case header names. |
@@ -178,14 +180,14 @@ int WebSocketJob::OnStartOpenConnection( |
state_ = CONNECTING; |
addresses_ = socket->address_list(); |
WebSocketThrottle::GetInstance()->PutInQueue(this); |
- if (!waiting_) { |
- int result = TrySpdyStream(); |
- if (result != ERR_IO_PENDING) |
- return result; |
+ if (waiting_) { |
+ // PutInQueue() may set |waiting_| true for throttling. In this case, |
+ // Wakeup() will be called later. |
+ callback_ = callback; |
+ AddRef(); // Balanced when callback_ becomes NULL. |
+ return ERR_IO_PENDING; |
} |
- callback_ = callback; |
- AddRef(); // Balanced when callback_ becomes NULL. |
- return ERR_IO_PENDING; // Wakeup will be called later. |
+ return TrySpdyStream(); |
} |
void WebSocketJob::OnConnected( |
@@ -276,10 +278,75 @@ void WebSocketJob::OnAuthRequired( |
} |
void WebSocketJob::OnError(const SocketStream* socket, int error) { |
- if (delegate_) |
+ if (delegate_ && error != ERR_PROTOCOL_SWITCHED) |
delegate_->OnError(socket, error); |
} |
+void WebSocketJob::OnCreatedSpdyStream(int result) { |
+ DCHECK(spdy_websocket_stream_.get()); |
+ DCHECK(socket_.get()); |
+ DCHECK_NE(ERR_IO_PENDING, result); |
+ |
+ if (state_ == CLOSED) { |
+ result = ERR_ABORTED; |
+ } else if (result == OK) { |
+ state_ = CONNECTING; |
+ result = ERR_PROTOCOL_SWITCHED; |
+ } else { |
+ spdy_websocket_stream_.reset(); |
+ } |
+ |
+ CompleteIO(result); |
+} |
+ |
+void WebSocketJob::OnSentSpdyHeaders(int result) { |
+ DCHECK_NE(INITIALIZED, state_); |
+ if (state_ != CONNECTING) |
+ return; |
+ if (delegate_) |
+ delegate_->OnSentData(socket_, handshake_request_->original_length()); |
+ handshake_request_.reset(); |
+} |
+ |
+int WebSocketJob::OnReceivedSpdyResponseHeader( |
+ const spdy::SpdyHeaderBlock& headers, int status) { |
+ DCHECK_NE(INITIALIZED, state_); |
+ if (state_ != CONNECTING) |
+ return status; |
+ if (status != OK) |
+ return status; |
+ // TODO(toyoshim): Fallback to non-spdy connection? |
+ handshake_response_->ParseResponseHeaderBlock(headers, challenge_); |
+ |
+ SaveCookiesAndNotifyHeaderComplete(); |
+ return OK; |
+} |
+ |
+void WebSocketJob::OnSentSpdyData(int amount_sent) { |
+ DCHECK_NE(INITIALIZED, state_); |
+ DCHECK_NE(CONNECTING, state_); |
+ if (state_ == CLOSED) |
+ return; |
+ if (!spdy_websocket_stream_.get()) |
+ return; |
+ OnSentData(socket_, amount_sent); |
+} |
+ |
+void WebSocketJob::OnReceivedSpdyData(const char* data, int length) { |
+ DCHECK_NE(INITIALIZED, state_); |
+ DCHECK_NE(CONNECTING, state_); |
+ if (state_ == CLOSED) |
+ return; |
+ if (!spdy_websocket_stream_.get()) |
+ return; |
+ OnReceivedData(socket_, data, length); |
+} |
+ |
+void WebSocketJob::OnCloseSpdyStream() { |
+ spdy_websocket_stream_.reset(); |
+ OnClose(socket_); |
+} |
+ |
bool WebSocketJob::SendHandshakeRequest(const char* data, int len) { |
DCHECK_EQ(state_, CONNECTING); |
if (started_to_send_handshake_request_) |
@@ -317,14 +384,22 @@ void WebSocketJob::AddCookieHeaderAndSend() { |
} |
} |
- const std::string& handshake_request = handshake_request_->GetRawRequest(); |
- handshake_request_sent_ = 0; |
- socket_->net_log()->AddEvent( |
- NetLog::TYPE_WEB_SOCKET_SEND_REQUEST_HEADERS, |
- make_scoped_refptr( |
- new NetLogWebSocketHandshakeParameter(handshake_request))); |
- socket_->SendData(handshake_request.data(), |
- handshake_request.size()); |
+ if (spdy_websocket_stream_.get()) { |
+ linked_ptr<spdy::SpdyHeaderBlock> headers(new spdy::SpdyHeaderBlock); |
+ handshake_request_->GetRequestHeaderBlock( |
+ socket_->url(), headers.get(), &challenge_); |
+ spdy_websocket_stream_->SendRequest(headers); |
+ } else { |
+ const std::string& handshake_request = |
+ handshake_request_->GetRawRequest(); |
+ handshake_request_sent_ = 0; |
+ socket_->net_log()->AddEvent( |
+ NetLog::TYPE_WEB_SOCKET_SEND_REQUEST_HEADERS, |
+ make_scoped_refptr( |
+ new NetLogWebSocketHandshakeParameter(handshake_request))); |
+ socket_->SendData(handshake_request.data(), |
+ handshake_request.size()); |
+ } |
} |
} |
@@ -464,8 +539,31 @@ int WebSocketJob::TrySpdyStream() { |
const HostPortProxyPair pair(HostPortPair::FromURL(socket_->url()), |
socket_->proxy_server()); |
if (spdy_pool->HasSession(pair)) { |
- // TODO(toyoshim): Switch to SpdyWebSocketStream here by returning |
- // ERR_PROTOCOL_SWITCHED. |
+ scoped_refptr<SpdySession> spdy_session = |
+ spdy_pool->Get(pair, *socket_->net_log()); |
+ |
+ SSLInfo ssl_info; |
+ bool was_npn_negotiated; |
+ bool use_ssl = |
+ spdy_session->GetSSLInfo(&ssl_info, &was_npn_negotiated); |
+ |
+ // Forbid wss downgrade to SPDY without SSL. |
+ if (!socket_->is_secure() || use_ssl) { |
Yuta Kitamura
2011/07/08 07:40:21
This seems right, but an identical expression "!(s
Takashi Toyoshima
2011/07/08 08:35:14
Done.
|
+ spdy_websocket_stream_.reset( |
+ new SpdyWebSocketStream(spdy_session, this)); |
+ |
+ int result = spdy_websocket_stream_->InitializeStream( |
+ socket_->url(), MEDIUM, *socket_->net_log()); |
+ if (result == OK) { |
+ OnConnected(socket_, kMaxPendingSendAllowed); |
+ return ERR_PROTOCOL_SWITCHED; |
+ } |
+ if (result == ERR_IO_PENDING) |
+ return ERR_IO_PENDING; |
+ |
+ // Fallback to WebSocket wire protocol. |
+ spdy_websocket_stream_.reset(); |
+ } |
Yuta Kitamura
2011/07/08 07:40:21
(Optional) These blocks seem nested too deeply.
G
Takashi Toyoshima
2011/07/08 08:35:14
I love it.
Done!
|
} |
} |
} |
@@ -494,7 +592,10 @@ void WebSocketJob::Wakeup() { |
} |
void WebSocketJob::RetryPendingIO() { |
- int result = TrySpdyStream(); |
+ CompleteIO(TrySpdyStream()); |
Yuta Kitamura
2011/07/08 07:40:21
TrySpdyStream() can return ERR_IO_PENDING. Is it o
Takashi Toyoshima
2011/07/08 08:35:14
Oh!
It's a bug to cause DCHECK failure !!
In that
|
+} |
+ |
+void WebSocketJob::CompleteIO(int result) { |
// |callback_| may be NULL if OnClose() or DetachDelegate() was called. |
if (callback_) { |
net::CompletionCallback* callback = callback_; |
@@ -505,12 +606,14 @@ void WebSocketJob::RetryPendingIO() { |
} |
bool WebSocketJob::SendDataInternal(const char* data, int length) { |
- // TODO(toyoshim): Call protocol specific SendData(). |
+ if (spdy_websocket_stream_.get()) |
+ return ERR_IO_PENDING == spdy_websocket_stream_->SendData(data, length); |
return socket_->SendData(data, length); |
} |
void WebSocketJob::CloseInternal() { |
- // TODO(toyoshim): Call protocol specific Close(). |
+ if (spdy_websocket_stream_.get()) |
+ spdy_websocket_stream_->Close(); |
socket_->Close(); |
} |