Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / net / websockets / websocket_stream.cc
index c9513d7..be2bc16 100644 (file)
@@ -8,6 +8,8 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/metrics/histogram.h"
 #include "base/metrics/sparse_histogram.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
 #include "net/base/load_flags.h"
 #include "net/http/http_request_headers.h"
 #include "net/http/http_response_headers.h"
 namespace net {
 namespace {
 
+// The timeout duration of WebSocket handshake.
+// It is defined as the same value as the TCP connection timeout value in
+// net/socket/websocket_transport_client_socket_pool.cc to make it hard for
+// JavaScript programs to recognize the timeout cause.
+const int kHandshakeTimeoutIntervalInSeconds = 240;
+
 class StreamRequestImpl;
 
 class Delegate : public URLRequest::Delegate {
@@ -86,7 +94,8 @@ class StreamRequestImpl : public WebSocketStreamRequest {
       scoped_ptr<WebSocketStream::ConnectDelegate> connect_delegate,
       scoped_ptr<WebSocketHandshakeStreamCreateHelper> create_helper)
       : delegate_(new Delegate(this)),
-        url_request_(url, DEFAULT_PRIORITY, delegate_.get(), context),
+        url_request_(context->CreateRequest(url, DEFAULT_PRIORITY,
+                                            delegate_.get(), NULL)),
         connect_delegate_(connect_delegate.Pass()),
         create_helper_(create_helper.release()) {
     create_helper_->set_failure_message(&failure_message_);
@@ -96,42 +105,56 @@ class StreamRequestImpl : public WebSocketStreamRequest {
     headers.SetHeader(HttpRequestHeaders::kOrigin, origin.string());
     headers.SetHeader(websockets::kSecWebSocketVersion,
                       websockets::kSupportedVersion);
-    url_request_.SetExtraRequestHeaders(headers);
+    url_request_->SetExtraRequestHeaders(headers);
 
     // This passes the ownership of |create_helper_| to |url_request_|.
-    url_request_.SetUserData(
+    url_request_->SetUserData(
         WebSocketHandshakeStreamBase::CreateHelper::DataKey(),
         create_helper_);
-    url_request_.SetLoadFlags(LOAD_DISABLE_CACHE |
-                              LOAD_BYPASS_CACHE |
-                              LOAD_DO_NOT_PROMPT_FOR_LOGIN);
+    url_request_->SetLoadFlags(LOAD_DISABLE_CACHE |
+                               LOAD_BYPASS_CACHE |
+                               LOAD_DO_NOT_PROMPT_FOR_LOGIN);
   }
 
   // Destroying this object destroys the URLRequest, which cancels the request
   // and so terminates the handshake if it is incomplete.
   virtual ~StreamRequestImpl() {}
 
-  void Start() {
-    url_request_.Start();
+  void Start(scoped_ptr<base::Timer> timer) {
+    DCHECK(timer);
+    TimeDelta timeout(TimeDelta::FromSeconds(
+        kHandshakeTimeoutIntervalInSeconds));
+    timer_ = timer.Pass();
+    timer_->Start(FROM_HERE, timeout,
+                  base::Bind(&StreamRequestImpl::OnTimeout,
+                             base::Unretained(this)));
+    url_request_->Start();
   }
 
   void PerformUpgrade() {
+    DCHECK(timer_);
+    timer_->Stop();
     connect_delegate_->OnSuccess(create_helper_->Upgrade());
   }
 
   void ReportFailure() {
+    DCHECK(timer_);
+    timer_->Stop();
     if (failure_message_.empty()) {
-      switch (url_request_.status().status()) {
+      switch (url_request_->status().status()) {
         case URLRequestStatus::SUCCESS:
         case URLRequestStatus::IO_PENDING:
           break;
         case URLRequestStatus::CANCELED:
-          failure_message_ = "WebSocket opening handshake was canceled";
+          if (url_request_->status().error() == ERR_TIMED_OUT)
+            failure_message_ = "WebSocket opening handshake timed out";
+          else
+            failure_message_ = "WebSocket opening handshake was canceled";
           break;
         case URLRequestStatus::FAILED:
           failure_message_ =
               std::string("Error in connection establishment: ") +
-              ErrorToString(url_request_.status().error());
+              ErrorToString(url_request_->status().error());
           break;
       }
     }
@@ -144,15 +167,19 @@ class StreamRequestImpl : public WebSocketStreamRequest {
 
   void OnFinishOpeningHandshake() {
     WebSocketDispatchOnFinishOpeningHandshake(connect_delegate(),
-                                              url_request_.url(),
-                                              url_request_.response_headers(),
-                                              url_request_.response_time());
+                                              url_request_->url(),
+                                              url_request_->response_headers(),
+                                              url_request_->response_time());
   }
 
   WebSocketStream::ConnectDelegate* connect_delegate() const {
     return connect_delegate_.get();
   }
 
+  void OnTimeout() {
+    url_request_->CancelWithError(ERR_TIMED_OUT);
+  }
+
  private:
   // |delegate_| needs to be declared before |url_request_| so that it gets
   // initialised first.
@@ -160,7 +187,7 @@ class StreamRequestImpl : public WebSocketStreamRequest {
 
   // Deleting the StreamRequestImpl object deletes this URLRequest object,
   // cancelling the whole connection.
-  URLRequest url_request_;
+  scoped_ptr<URLRequest> url_request_;
 
   scoped_ptr<WebSocketStream::ConnectDelegate> connect_delegate_;
 
@@ -169,6 +196,9 @@ class StreamRequestImpl : public WebSocketStreamRequest {
 
   // The failure message supplied by WebSocketBasicHandshakeStream, if any.
   std::string failure_message_;
+
+  // A timer for handshake timeout.
+  scoped_ptr<base::Timer> timer_;
 };
 
 class SSLErrorCallbacks : public WebSocketEventInterface::SSLErrorCallbacks {
@@ -285,7 +315,7 @@ scoped_ptr<WebSocketStreamRequest> WebSocketStream::CreateAndConnectStream(
                             origin,
                             connect_delegate.Pass(),
                             create_helper.Pass()));
-  request->Start();
+  request->Start(scoped_ptr<base::Timer>(new base::Timer(false, false)));
   return request.PassAs<WebSocketStreamRequest>();
 }
 
@@ -296,14 +326,15 @@ scoped_ptr<WebSocketStreamRequest> CreateAndConnectStreamForTesting(
     const url::Origin& origin,
     URLRequestContext* url_request_context,
     const BoundNetLog& net_log,
-    scoped_ptr<WebSocketStream::ConnectDelegate> connect_delegate) {
+    scoped_ptr<WebSocketStream::ConnectDelegate> connect_delegate,
+    scoped_ptr<base::Timer> timer) {
   scoped_ptr<StreamRequestImpl> request(
       new StreamRequestImpl(socket_url,
                             url_request_context,
                             origin,
                             connect_delegate.Pass(),
                             create_helper.Pass()));
-  request->Start();
+  request->Start(timer.Pass());
   return request.PassAs<WebSocketStreamRequest>();
 }
 
@@ -313,7 +344,7 @@ void WebSocketDispatchOnFinishOpeningHandshake(
     const scoped_refptr<HttpResponseHeaders>& headers,
     base::Time response_time) {
   DCHECK(connect_delegate);
-  if (headers) {
+  if (headers.get()) {
     connect_delegate->OnFinishOpeningHandshake(make_scoped_ptr(
         new WebSocketHandshakeResponseInfo(url,
                                            headers->response_code(),