Cancel URLRequest with an appropriate code when WebSocket handshake succeeds

To notify the NetworkDelegate of WebSocket handshake success explicitly, this
CL introduces a new net error and cancels the URLRequest with it.

BUG=663672

Review-Url: https://codereview.chromium.org/2628333003
Cr-Commit-Position: refs/heads/master@{#444523}
diff --git a/net/base/net_error_list.h b/net/base/net_error_list.h
index 9720575..8bb47cb 100644
--- a/net/base/net_error_list.h
+++ b/net/base/net_error_list.h
@@ -382,6 +382,10 @@
 // fallback will be removed.
 NET_ERROR(SSL_OBSOLETE_CIPHER, -172)
 
+// When a WebSocket handshake is done successfully, the URLRequest is cancelled
+// with this error code.
+NET_ERROR(WEBSOCKET_HANDSHAKE_SUCCESS, -173)
+
 // Certificate error codes
 //
 // The values of certificate error codes must be consecutive.
diff --git a/net/websockets/websocket_stream.cc b/net/websockets/websocket_stream.cc
index 5920826..ca73a53 100644
--- a/net/websockets/websocket_stream.cc
+++ b/net/websockets/websocket_stream.cc
@@ -148,9 +148,13 @@
 
     timer_->Stop();
 
+    std::unique_ptr<URLRequest> url_request = std::move(url_request_);
     WebSocketHandshakeStreamBase* handshake_stream = handshake_stream_;
     handshake_stream_ = nullptr;
     connect_delegate_->OnSuccess(handshake_stream->Upgrade());
+
+    // This is safe even if |this| has already been deleted.
+    url_request->CancelWithError(ERR_WEBSOCKET_HANDSHAKE_SUCCESS);
   }
 
   std::string FailureMessageFromNetError(int net_error) {
diff --git a/net/websockets/websocket_stream_test.cc b/net/websockets/websocket_stream_test.cc
index 091c28d..78bda66 100644
--- a/net/websockets/websocket_stream_test.cc
+++ b/net/websockets/websocket_stream_test.cc
@@ -337,6 +337,8 @@
   EXPECT_TRUE(stream_);
   EXPECT_TRUE(request_info_);
   EXPECT_TRUE(response_info_);
+  EXPECT_EQ(ERR_WEBSOCKET_HANDSHAKE_SUCCESS,
+            url_request_context_host_.network_delegate().last_error());
 }
 
 TEST_F(WebSocketStreamCreateTest, HandshakeInfo) {
@@ -483,6 +485,8 @@
             "Response must not include 'Sec-WebSocket-Protocol' header "
             "if not present in request: chatv20.chromium.org",
             failure_message());
+  EXPECT_EQ(ERR_INVALID_RESPONSE,
+            url_request_context_host_.network_delegate().last_error());
 }
 
 // Missing sub-protocol response is rejected.
diff --git a/net/websockets/websocket_test_util.h b/net/websockets/websocket_test_util.h
index 6083146..23769404 100644
--- a/net/websockets/websocket_test_util.h
+++ b/net/websockets/websocket_test_util.h
@@ -126,6 +126,10 @@
   // returned pointer remains owned by this object.
   TestURLRequestContext* GetURLRequestContext();
 
+  const TestNetworkDelegate& network_delegate() const {
+    return network_delegate_;
+  }
+
  private:
   WebSocketMockClientSocketFactoryMaker maker_;
   TestURLRequestContext url_request_context_;