Index: net/websockets/websocket_basic_handshake_stream.cc |
diff --git a/net/websockets/websocket_basic_handshake_stream.cc b/net/websockets/websocket_basic_handshake_stream.cc |
deleted file mode 100644 |
index 7d993114034836a3f92d0f153ece8e340cb953fd..0000000000000000000000000000000000000000 |
--- a/net/websockets/websocket_basic_handshake_stream.cc |
+++ /dev/null |
@@ -1,701 +0,0 @@ |
-// Copyright 2013 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "net/websockets/websocket_basic_handshake_stream.h" |
- |
-#include <algorithm> |
-#include <iterator> |
-#include <set> |
-#include <string> |
-#include <vector> |
- |
-#include "base/base64.h" |
-#include "base/basictypes.h" |
-#include "base/bind.h" |
-#include "base/compiler_specific.h" |
-#include "base/containers/hash_tables.h" |
-#include "base/logging.h" |
-#include "base/metrics/histogram.h" |
-#include "base/metrics/sparse_histogram.h" |
-#include "base/stl_util.h" |
-#include "base/strings/string_number_conversions.h" |
-#include "base/strings/string_piece.h" |
-#include "base/strings/string_util.h" |
-#include "base/strings/stringprintf.h" |
-#include "base/time/time.h" |
-#include "crypto/random.h" |
-#include "net/base/io_buffer.h" |
-#include "net/http/http_request_headers.h" |
-#include "net/http/http_request_info.h" |
-#include "net/http/http_response_body_drainer.h" |
-#include "net/http/http_response_headers.h" |
-#include "net/http/http_status_code.h" |
-#include "net/http/http_stream_parser.h" |
-#include "net/socket/client_socket_handle.h" |
-#include "net/socket/websocket_transport_client_socket_pool.h" |
-#include "net/websockets/websocket_basic_stream.h" |
-#include "net/websockets/websocket_deflate_predictor.h" |
-#include "net/websockets/websocket_deflate_predictor_impl.h" |
-#include "net/websockets/websocket_deflate_stream.h" |
-#include "net/websockets/websocket_deflater.h" |
-#include "net/websockets/websocket_extension_parser.h" |
-#include "net/websockets/websocket_handshake_challenge.h" |
-#include "net/websockets/websocket_handshake_constants.h" |
-#include "net/websockets/websocket_handshake_request_info.h" |
-#include "net/websockets/websocket_handshake_response_info.h" |
-#include "net/websockets/websocket_stream.h" |
- |
-namespace net { |
- |
-namespace { |
- |
-const char kConnectionErrorStatusLine[] = "HTTP/1.1 503 Connection Error"; |
- |
-// TODO(yhirano): Remove these functions once http://crbug.com/399535 is fixed. |
-NOINLINE void RunCallbackWithOk(const CompletionCallback& callback, |
- int result) { |
- DCHECK_EQ(result, OK); |
- callback.Run(OK); |
-} |
- |
-NOINLINE void RunCallbackWithInvalidResponseCausedByRedirect( |
- const CompletionCallback& callback, |
- int result) { |
- DCHECK_EQ(result, ERR_INVALID_RESPONSE); |
- callback.Run(ERR_INVALID_RESPONSE); |
-} |
- |
-NOINLINE void RunCallbackWithInvalidResponse( |
- const CompletionCallback& callback, |
- int result) { |
- DCHECK_EQ(result, ERR_INVALID_RESPONSE); |
- callback.Run(ERR_INVALID_RESPONSE); |
-} |
- |
-NOINLINE void RunCallback(const CompletionCallback& callback, int result) { |
- callback.Run(result); |
-} |
- |
-} // namespace |
- |
-// TODO(ricea): If more extensions are added, replace this with a more general |
-// mechanism. |
-struct WebSocketExtensionParams { |
- WebSocketExtensionParams() |
- : deflate_enabled(false), |
- client_window_bits(15), |
- deflate_mode(WebSocketDeflater::TAKE_OVER_CONTEXT) {} |
- |
- bool deflate_enabled; |
- int client_window_bits; |
- WebSocketDeflater::ContextTakeOverMode deflate_mode; |
-}; |
- |
-namespace { |
- |
-enum GetHeaderResult { |
- GET_HEADER_OK, |
- GET_HEADER_MISSING, |
- GET_HEADER_MULTIPLE, |
-}; |
- |
-std::string MissingHeaderMessage(const std::string& header_name) { |
- return std::string("'") + header_name + "' header is missing"; |
-} |
- |
-std::string MultipleHeaderValuesMessage(const std::string& header_name) { |
- return |
- std::string("'") + |
- header_name + |
- "' header must not appear more than once in a response"; |
-} |
- |
-std::string GenerateHandshakeChallenge() { |
- std::string raw_challenge(websockets::kRawChallengeLength, '\0'); |
- crypto::RandBytes(string_as_array(&raw_challenge), raw_challenge.length()); |
- std::string encoded_challenge; |
- base::Base64Encode(raw_challenge, &encoded_challenge); |
- return encoded_challenge; |
-} |
- |
-void AddVectorHeaderIfNonEmpty(const char* name, |
- const std::vector<std::string>& value, |
- HttpRequestHeaders* headers) { |
- if (value.empty()) |
- return; |
- headers->SetHeader(name, JoinString(value, ", ")); |
-} |
- |
-GetHeaderResult GetSingleHeaderValue(const HttpResponseHeaders* headers, |
- const base::StringPiece& name, |
- std::string* value) { |
- void* state = nullptr; |
- size_t num_values = 0; |
- std::string temp_value; |
- while (headers->EnumerateHeader(&state, name, &temp_value)) { |
- if (++num_values > 1) |
- return GET_HEADER_MULTIPLE; |
- *value = temp_value; |
- } |
- return num_values > 0 ? GET_HEADER_OK : GET_HEADER_MISSING; |
-} |
- |
-bool ValidateHeaderHasSingleValue(GetHeaderResult result, |
- const std::string& header_name, |
- std::string* failure_message) { |
- if (result == GET_HEADER_MISSING) { |
- *failure_message = MissingHeaderMessage(header_name); |
- return false; |
- } |
- if (result == GET_HEADER_MULTIPLE) { |
- *failure_message = MultipleHeaderValuesMessage(header_name); |
- return false; |
- } |
- DCHECK_EQ(result, GET_HEADER_OK); |
- return true; |
-} |
- |
-bool ValidateUpgrade(const HttpResponseHeaders* headers, |
- std::string* failure_message) { |
- std::string value; |
- GetHeaderResult result = |
- GetSingleHeaderValue(headers, websockets::kUpgrade, &value); |
- if (!ValidateHeaderHasSingleValue(result, |
- websockets::kUpgrade, |
- failure_message)) { |
- return false; |
- } |
- |
- if (!LowerCaseEqualsASCII(value, websockets::kWebSocketLowercase)) { |
- *failure_message = |
- "'Upgrade' header value is not 'WebSocket': " + value; |
- return false; |
- } |
- return true; |
-} |
- |
-bool ValidateSecWebSocketAccept(const HttpResponseHeaders* headers, |
- const std::string& expected, |
- std::string* failure_message) { |
- std::string actual; |
- GetHeaderResult result = |
- GetSingleHeaderValue(headers, websockets::kSecWebSocketAccept, &actual); |
- if (!ValidateHeaderHasSingleValue(result, |
- websockets::kSecWebSocketAccept, |
- failure_message)) { |
- return false; |
- } |
- |
- if (expected != actual) { |
- *failure_message = "Incorrect 'Sec-WebSocket-Accept' header value"; |
- return false; |
- } |
- return true; |
-} |
- |
-bool ValidateConnection(const HttpResponseHeaders* headers, |
- std::string* failure_message) { |
- // Connection header is permitted to contain other tokens. |
- if (!headers->HasHeader(HttpRequestHeaders::kConnection)) { |
- *failure_message = MissingHeaderMessage(HttpRequestHeaders::kConnection); |
- return false; |
- } |
- if (!headers->HasHeaderValue(HttpRequestHeaders::kConnection, |
- websockets::kUpgrade)) { |
- *failure_message = "'Connection' header value must contain 'Upgrade'"; |
- return false; |
- } |
- return true; |
-} |
- |
-bool ValidateSubProtocol( |
- const HttpResponseHeaders* headers, |
- const std::vector<std::string>& requested_sub_protocols, |
- std::string* sub_protocol, |
- std::string* failure_message) { |
- void* state = nullptr; |
- std::string value; |
- base::hash_set<std::string> requested_set(requested_sub_protocols.begin(), |
- requested_sub_protocols.end()); |
- int count = 0; |
- bool has_multiple_protocols = false; |
- bool has_invalid_protocol = false; |
- |
- while (!has_invalid_protocol || !has_multiple_protocols) { |
- std::string temp_value; |
- if (!headers->EnumerateHeader( |
- &state, websockets::kSecWebSocketProtocol, &temp_value)) |
- break; |
- value = temp_value; |
- if (requested_set.count(value) == 0) |
- has_invalid_protocol = true; |
- if (++count > 1) |
- has_multiple_protocols = true; |
- } |
- |
- if (has_multiple_protocols) { |
- *failure_message = |
- MultipleHeaderValuesMessage(websockets::kSecWebSocketProtocol); |
- return false; |
- } else if (count > 0 && requested_sub_protocols.size() == 0) { |
- *failure_message = |
- std::string("Response must not include 'Sec-WebSocket-Protocol' " |
- "header if not present in request: ") |
- + value; |
- return false; |
- } else if (has_invalid_protocol) { |
- *failure_message = |
- "'Sec-WebSocket-Protocol' header value '" + |
- value + |
- "' in response does not match any of sent values"; |
- return false; |
- } else if (requested_sub_protocols.size() > 0 && count == 0) { |
- *failure_message = |
- "Sent non-empty 'Sec-WebSocket-Protocol' header " |
- "but no response was received"; |
- return false; |
- } |
- *sub_protocol = value; |
- return true; |
-} |
- |
-bool DeflateError(std::string* message, const base::StringPiece& piece) { |
- *message = "Error in permessage-deflate: "; |
- piece.AppendToString(message); |
- return false; |
-} |
- |
-bool ValidatePerMessageDeflateExtension(const WebSocketExtension& extension, |
- std::string* failure_message, |
- WebSocketExtensionParams* params) { |
- static const char kClientPrefix[] = "client_"; |
- static const char kServerPrefix[] = "server_"; |
- static const char kNoContextTakeover[] = "no_context_takeover"; |
- static const char kMaxWindowBits[] = "max_window_bits"; |
- const size_t kPrefixLen = arraysize(kClientPrefix) - 1; |
- static_assert(kPrefixLen == arraysize(kServerPrefix) - 1, |
- "the strings server and client must be the same length"); |
- typedef std::vector<WebSocketExtension::Parameter> ParameterVector; |
- |
- DCHECK_EQ("permessage-deflate", extension.name()); |
- const ParameterVector& parameters = extension.parameters(); |
- std::set<std::string> seen_names; |
- for (ParameterVector::const_iterator it = parameters.begin(); |
- it != parameters.end(); ++it) { |
- const std::string& name = it->name(); |
- if (seen_names.count(name) != 0) { |
- return DeflateError( |
- failure_message, |
- "Received duplicate permessage-deflate extension parameter " + name); |
- } |
- seen_names.insert(name); |
- const std::string client_or_server(name, 0, kPrefixLen); |
- const bool is_client = (client_or_server == kClientPrefix); |
- if (!is_client && client_or_server != kServerPrefix) { |
- return DeflateError( |
- failure_message, |
- "Received an unexpected permessage-deflate extension parameter"); |
- } |
- const std::string rest(name, kPrefixLen); |
- if (rest == kNoContextTakeover) { |
- if (it->HasValue()) { |
- return DeflateError(failure_message, |
- "Received invalid " + name + " parameter"); |
- } |
- if (is_client) |
- params->deflate_mode = WebSocketDeflater::DO_NOT_TAKE_OVER_CONTEXT; |
- } else if (rest == kMaxWindowBits) { |
- if (!it->HasValue()) |
- return DeflateError(failure_message, name + " must have value"); |
- int bits = 0; |
- if (!base::StringToInt(it->value(), &bits) || bits < 8 || bits > 15 || |
- it->value()[0] == '0' || |
- it->value().find_first_not_of("0123456789") != std::string::npos) { |
- return DeflateError(failure_message, |
- "Received invalid " + name + " parameter"); |
- } |
- if (is_client) |
- params->client_window_bits = bits; |
- } else { |
- return DeflateError( |
- failure_message, |
- "Received an unexpected permessage-deflate extension parameter"); |
- } |
- } |
- params->deflate_enabled = true; |
- return true; |
-} |
- |
-bool ValidateExtensions(const HttpResponseHeaders* headers, |
- const std::vector<std::string>& requested_extensions, |
- std::string* extensions, |
- std::string* failure_message, |
- WebSocketExtensionParams* params) { |
- void* state = nullptr; |
- std::string value; |
- std::vector<std::string> accepted_extensions; |
- // TODO(ricea): If adding support for additional extensions, generalise this |
- // code. |
- bool seen_permessage_deflate = false; |
- while (headers->EnumerateHeader( |
- &state, websockets::kSecWebSocketExtensions, &value)) { |
- WebSocketExtensionParser parser; |
- parser.Parse(value); |
- if (parser.has_error()) { |
- // TODO(yhirano) Set appropriate failure message. |
- *failure_message = |
- "'Sec-WebSocket-Extensions' header value is " |
- "rejected by the parser: " + |
- value; |
- return false; |
- } |
- if (parser.extension().name() == "permessage-deflate") { |
- if (seen_permessage_deflate) { |
- *failure_message = "Received duplicate permessage-deflate response"; |
- return false; |
- } |
- seen_permessage_deflate = true; |
- if (!ValidatePerMessageDeflateExtension( |
- parser.extension(), failure_message, params)) |
- return false; |
- } else { |
- *failure_message = |
- "Found an unsupported extension '" + |
- parser.extension().name() + |
- "' in 'Sec-WebSocket-Extensions' header"; |
- return false; |
- } |
- accepted_extensions.push_back(value); |
- } |
- *extensions = JoinString(accepted_extensions, ", "); |
- return true; |
-} |
- |
-} // namespace |
- |
-WebSocketBasicHandshakeStream::WebSocketBasicHandshakeStream( |
- scoped_ptr<ClientSocketHandle> connection, |
- WebSocketStream::ConnectDelegate* connect_delegate, |
- bool using_proxy, |
- std::vector<std::string> requested_sub_protocols, |
- std::vector<std::string> requested_extensions, |
- std::string* failure_message) |
- : state_(connection.release(), using_proxy), |
- connect_delegate_(connect_delegate), |
- http_response_info_(nullptr), |
- requested_sub_protocols_(requested_sub_protocols), |
- requested_extensions_(requested_extensions), |
- failure_message_(failure_message) { |
- DCHECK(connect_delegate); |
- DCHECK(failure_message); |
-} |
- |
-WebSocketBasicHandshakeStream::~WebSocketBasicHandshakeStream() {} |
- |
-int WebSocketBasicHandshakeStream::InitializeStream( |
- const HttpRequestInfo* request_info, |
- RequestPriority priority, |
- const BoundNetLog& net_log, |
- const CompletionCallback& callback) { |
- url_ = request_info->url; |
- state_.Initialize(request_info, priority, net_log, callback); |
- return OK; |
-} |
- |
-int WebSocketBasicHandshakeStream::SendRequest( |
- const HttpRequestHeaders& headers, |
- HttpResponseInfo* response, |
- const CompletionCallback& callback) { |
- DCHECK(!headers.HasHeader(websockets::kSecWebSocketKey)); |
- DCHECK(!headers.HasHeader(websockets::kSecWebSocketProtocol)); |
- DCHECK(!headers.HasHeader(websockets::kSecWebSocketExtensions)); |
- DCHECK(headers.HasHeader(HttpRequestHeaders::kOrigin)); |
- DCHECK(headers.HasHeader(websockets::kUpgrade)); |
- DCHECK(headers.HasHeader(HttpRequestHeaders::kConnection)); |
- DCHECK(headers.HasHeader(websockets::kSecWebSocketVersion)); |
- DCHECK(parser()); |
- |
- http_response_info_ = response; |
- |
- // Create a copy of the headers object, so that we can add the |
- // Sec-WebSockey-Key header. |
- HttpRequestHeaders enriched_headers; |
- enriched_headers.CopyFrom(headers); |
- std::string handshake_challenge; |
- if (handshake_challenge_for_testing_) { |
- handshake_challenge = *handshake_challenge_for_testing_; |
- handshake_challenge_for_testing_.reset(); |
- } else { |
- handshake_challenge = GenerateHandshakeChallenge(); |
- } |
- enriched_headers.SetHeader(websockets::kSecWebSocketKey, handshake_challenge); |
- |
- AddVectorHeaderIfNonEmpty(websockets::kSecWebSocketExtensions, |
- requested_extensions_, |
- &enriched_headers); |
- AddVectorHeaderIfNonEmpty(websockets::kSecWebSocketProtocol, |
- requested_sub_protocols_, |
- &enriched_headers); |
- |
- handshake_challenge_response_ = |
- ComputeSecWebSocketAccept(handshake_challenge); |
- |
- DCHECK(connect_delegate_); |
- scoped_ptr<WebSocketHandshakeRequestInfo> request( |
- new WebSocketHandshakeRequestInfo(url_, base::Time::Now())); |
- request->headers.CopyFrom(enriched_headers); |
- connect_delegate_->OnStartOpeningHandshake(request.Pass()); |
- |
- return parser()->SendRequest( |
- state_.GenerateRequestLine(), enriched_headers, response, callback); |
-} |
- |
-int WebSocketBasicHandshakeStream::ReadResponseHeaders( |
- const CompletionCallback& callback) { |
- // HttpStreamParser uses a weak pointer when reading from the |
- // socket, so it won't be called back after being destroyed. The |
- // HttpStreamParser is owned by HttpBasicState which is owned by this object, |
- // so this use of base::Unretained() is safe. |
- int rv = parser()->ReadResponseHeaders( |
- base::Bind(&WebSocketBasicHandshakeStream::ReadResponseHeadersCallback, |
- base::Unretained(this), |
- callback)); |
- if (rv == ERR_IO_PENDING) |
- return rv; |
- bool is_redirect = false; |
- return ValidateResponse(rv, &is_redirect); |
-} |
- |
-int WebSocketBasicHandshakeStream::ReadResponseBody( |
- IOBuffer* buf, |
- int buf_len, |
- const CompletionCallback& callback) { |
- return parser()->ReadResponseBody(buf, buf_len, callback); |
-} |
- |
-void WebSocketBasicHandshakeStream::Close(bool not_reusable) { |
- // This class ignores the value of |not_reusable| and never lets the socket be |
- // re-used. |
- if (parser()) |
- parser()->Close(true); |
-} |
- |
-bool WebSocketBasicHandshakeStream::IsResponseBodyComplete() const { |
- return parser()->IsResponseBodyComplete(); |
-} |
- |
-bool WebSocketBasicHandshakeStream::CanFindEndOfResponse() const { |
- return parser() && parser()->CanFindEndOfResponse(); |
-} |
- |
-bool WebSocketBasicHandshakeStream::IsConnectionReused() const { |
- return parser()->IsConnectionReused(); |
-} |
- |
-void WebSocketBasicHandshakeStream::SetConnectionReused() { |
- parser()->SetConnectionReused(); |
-} |
- |
-bool WebSocketBasicHandshakeStream::IsConnectionReusable() const { |
- return false; |
-} |
- |
-int64 WebSocketBasicHandshakeStream::GetTotalReceivedBytes() const { |
- return 0; |
-} |
- |
-bool WebSocketBasicHandshakeStream::GetLoadTimingInfo( |
- LoadTimingInfo* load_timing_info) const { |
- return state_.connection()->GetLoadTimingInfo(IsConnectionReused(), |
- load_timing_info); |
-} |
- |
-void WebSocketBasicHandshakeStream::GetSSLInfo(SSLInfo* ssl_info) { |
- parser()->GetSSLInfo(ssl_info); |
-} |
- |
-void WebSocketBasicHandshakeStream::GetSSLCertRequestInfo( |
- SSLCertRequestInfo* cert_request_info) { |
- parser()->GetSSLCertRequestInfo(cert_request_info); |
-} |
- |
-bool WebSocketBasicHandshakeStream::IsSpdyHttpStream() const { return false; } |
- |
-void WebSocketBasicHandshakeStream::Drain(HttpNetworkSession* session) { |
- HttpResponseBodyDrainer* drainer = new HttpResponseBodyDrainer(this); |
- drainer->Start(session); |
- // |drainer| will delete itself. |
-} |
- |
-void WebSocketBasicHandshakeStream::SetPriority(RequestPriority priority) { |
- // TODO(ricea): See TODO comment in HttpBasicStream::SetPriority(). If it is |
- // gone, then copy whatever has happened there over here. |
-} |
- |
-UploadProgress WebSocketBasicHandshakeStream::GetUploadProgress() const { |
- return UploadProgress(); |
-} |
- |
-HttpStream* WebSocketBasicHandshakeStream::RenewStreamForAuth() { |
- // Return null because we don't support renewing the stream. |
- return nullptr; |
-} |
- |
-scoped_ptr<WebSocketStream> WebSocketBasicHandshakeStream::Upgrade() { |
- // The HttpStreamParser object has a pointer to our ClientSocketHandle. Make |
- // sure it does not touch it again before it is destroyed. |
- state_.DeleteParser(); |
- WebSocketTransportClientSocketPool::UnlockEndpoint(state_.connection()); |
- scoped_ptr<WebSocketStream> basic_stream( |
- new WebSocketBasicStream(state_.ReleaseConnection(), |
- state_.read_buf(), |
- sub_protocol_, |
- extensions_)); |
- DCHECK(extension_params_.get()); |
- if (extension_params_->deflate_enabled) { |
- UMA_HISTOGRAM_ENUMERATION( |
- "Net.WebSocket.DeflateMode", |
- extension_params_->deflate_mode, |
- WebSocketDeflater::NUM_CONTEXT_TAKEOVER_MODE_TYPES); |
- |
- return scoped_ptr<WebSocketStream>( |
- new WebSocketDeflateStream(basic_stream.Pass(), |
- extension_params_->deflate_mode, |
- extension_params_->client_window_bits, |
- scoped_ptr<WebSocketDeflatePredictor>( |
- new WebSocketDeflatePredictorImpl))); |
- } else { |
- return basic_stream.Pass(); |
- } |
-} |
- |
-void WebSocketBasicHandshakeStream::SetWebSocketKeyForTesting( |
- const std::string& key) { |
- handshake_challenge_for_testing_.reset(new std::string(key)); |
-} |
- |
-void WebSocketBasicHandshakeStream::ReadResponseHeadersCallback( |
- const CompletionCallback& callback, |
- int result) { |
- bool is_redirect = false; |
- int rv = ValidateResponse(result, &is_redirect); |
- |
- // TODO(yhirano): Simplify this statement once http://crbug.com/399535 is |
- // fixed. |
- switch (rv) { |
- case OK: |
- RunCallbackWithOk(callback, rv); |
- break; |
- case ERR_INVALID_RESPONSE: |
- if (is_redirect) |
- RunCallbackWithInvalidResponseCausedByRedirect(callback, rv); |
- else |
- RunCallbackWithInvalidResponse(callback, rv); |
- break; |
- default: |
- RunCallback(callback, rv); |
- break; |
- } |
-} |
- |
-void WebSocketBasicHandshakeStream::OnFinishOpeningHandshake() { |
- DCHECK(http_response_info_); |
- WebSocketDispatchOnFinishOpeningHandshake(connect_delegate_, |
- url_, |
- http_response_info_->headers, |
- http_response_info_->response_time); |
-} |
- |
-int WebSocketBasicHandshakeStream::ValidateResponse(int rv, |
- bool* is_redirect) { |
- DCHECK(http_response_info_); |
- *is_redirect = false; |
- // Most net errors happen during connection, so they are not seen by this |
- // method. The histogram for error codes is created in |
- // Delegate::OnResponseStarted in websocket_stream.cc instead. |
- if (rv >= 0) { |
- const HttpResponseHeaders* headers = http_response_info_->headers.get(); |
- const int response_code = headers->response_code(); |
- *is_redirect = HttpResponseHeaders::IsRedirectResponseCode(response_code); |
- UMA_HISTOGRAM_SPARSE_SLOWLY("Net.WebSocket.ResponseCode", response_code); |
- switch (response_code) { |
- case HTTP_SWITCHING_PROTOCOLS: |
- OnFinishOpeningHandshake(); |
- return ValidateUpgradeResponse(headers); |
- |
- // We need to pass these through for authentication to work. |
- case HTTP_UNAUTHORIZED: |
- case HTTP_PROXY_AUTHENTICATION_REQUIRED: |
- return OK; |
- |
- // Other status codes are potentially risky (see the warnings in the |
- // WHATWG WebSocket API spec) and so are dropped by default. |
- default: |
- // A WebSocket server cannot be using HTTP/0.9, so if we see version |
- // 0.9, it means the response was garbage. |
- // Reporting "Unexpected response code: 200" in this case is not |
- // helpful, so use a different error message. |
- if (headers->GetHttpVersion() == HttpVersion(0, 9)) { |
- set_failure_message( |
- "Error during WebSocket handshake: Invalid status line"); |
- } else { |
- set_failure_message(base::StringPrintf( |
- "Error during WebSocket handshake: Unexpected response code: %d", |
- headers->response_code())); |
- } |
- OnFinishOpeningHandshake(); |
- return ERR_INVALID_RESPONSE; |
- } |
- } else { |
- if (rv == ERR_EMPTY_RESPONSE) { |
- set_failure_message( |
- "Connection closed before receiving a handshake response"); |
- return rv; |
- } |
- set_failure_message(std::string("Error during WebSocket handshake: ") + |
- ErrorToString(rv)); |
- OnFinishOpeningHandshake(); |
- // Some error codes (for example ERR_CONNECTION_CLOSED) get changed to OK at |
- // higher levels. To prevent an unvalidated connection getting erroneously |
- // upgraded, don't pass through the status code unchanged if it is |
- // HTTP_SWITCHING_PROTOCOLS. |
- if (http_response_info_->headers && |
- http_response_info_->headers->response_code() == |
- HTTP_SWITCHING_PROTOCOLS) { |
- http_response_info_->headers->ReplaceStatusLine( |
- kConnectionErrorStatusLine); |
- } |
- return rv; |
- } |
-} |
- |
-int WebSocketBasicHandshakeStream::ValidateUpgradeResponse( |
- const HttpResponseHeaders* headers) { |
- extension_params_.reset(new WebSocketExtensionParams); |
- std::string failure_message; |
- if (ValidateUpgrade(headers, &failure_message) && |
- ValidateSecWebSocketAccept( |
- headers, handshake_challenge_response_, &failure_message) && |
- ValidateConnection(headers, &failure_message) && |
- ValidateSubProtocol(headers, |
- requested_sub_protocols_, |
- &sub_protocol_, |
- &failure_message) && |
- ValidateExtensions(headers, |
- requested_extensions_, |
- &extensions_, |
- &failure_message, |
- extension_params_.get())) { |
- return OK; |
- } |
- set_failure_message("Error during WebSocket handshake: " + failure_message); |
- return ERR_INVALID_RESPONSE; |
-} |
- |
-void WebSocketBasicHandshakeStream::set_failure_message( |
- const std::string& failure_message) { |
- *failure_message_ = failure_message; |
-} |
- |
-} // namespace net |