| Index: net/websockets/websocket_handshake_draft75.cc
|
| diff --git a/net/websockets/websocket_handshake_draft75.cc b/net/websockets/websocket_handshake_draft75.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..78805fb27fc3445ba8a0b00313e587384ee9c8ea
|
| --- /dev/null
|
| +++ b/net/websockets/websocket_handshake_draft75.cc
|
| @@ -0,0 +1,156 @@
|
| +// Copyright (c) 2010 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_handshake_draft75.h"
|
| +
|
| +#include "base/ref_counted.h"
|
| +#include "base/string_util.h"
|
| +#include "net/http/http_response_headers.h"
|
| +#include "net/http/http_util.h"
|
| +
|
| +namespace net {
|
| +
|
| +const char WebSocketHandshakeDraft75::kServerHandshakeHeader[] =
|
| + "HTTP/1.1 101 Web Socket Protocol Handshake\r\n";
|
| +const size_t WebSocketHandshakeDraft75::kServerHandshakeHeaderLength =
|
| + sizeof(kServerHandshakeHeader) - 1;
|
| +
|
| +const char WebSocketHandshakeDraft75::kUpgradeHeader[] =
|
| + "Upgrade: WebSocket\r\n";
|
| +const size_t WebSocketHandshakeDraft75::kUpgradeHeaderLength =
|
| + sizeof(kUpgradeHeader) - 1;
|
| +
|
| +const char WebSocketHandshakeDraft75::kConnectionHeader[] =
|
| + "Connection: Upgrade\r\n";
|
| +const size_t WebSocketHandshakeDraft75::kConnectionHeaderLength =
|
| + sizeof(kConnectionHeader) - 1;
|
| +
|
| +WebSocketHandshakeDraft75::WebSocketHandshakeDraft75(
|
| + const GURL& url,
|
| + const std::string& origin,
|
| + const std::string& location,
|
| + const std::string& protocol)
|
| + : WebSocketHandshake(url, origin, location, protocol) {
|
| +}
|
| +
|
| +WebSocketHandshakeDraft75::~WebSocketHandshakeDraft75() {
|
| +}
|
| +
|
| +std::string WebSocketHandshakeDraft75::CreateClientHandshakeMessage() {
|
| + std::string msg;
|
| + msg = "GET ";
|
| + msg += GetResourceName();
|
| + msg += " HTTP/1.1\r\n";
|
| + msg += kUpgradeHeader;
|
| + msg += kConnectionHeader;
|
| + msg += "Host: ";
|
| + msg += GetHostFieldValue();
|
| + msg += "\r\n";
|
| + msg += "Origin: ";
|
| + msg += GetOriginFieldValue();
|
| + msg += "\r\n";
|
| + if (!protocol_.empty()) {
|
| + msg += "WebSocket-Protocol: ";
|
| + msg += protocol_;
|
| + msg += "\r\n";
|
| + }
|
| + // TODO(ukai): Add cookie if necessary.
|
| + msg += "\r\n";
|
| + return msg;
|
| +}
|
| +
|
| +int WebSocketHandshakeDraft75::ReadServerHandshake(
|
| + const char* data, size_t len) {
|
| + mode_ = MODE_INCOMPLETE;
|
| + if (len < kServerHandshakeHeaderLength) {
|
| + return -1;
|
| + }
|
| + if (!memcmp(data, kServerHandshakeHeader, kServerHandshakeHeaderLength)) {
|
| + mode_ = MODE_NORMAL;
|
| + } else {
|
| + int eoh = HttpUtil::LocateEndOfHeaders(data, len);
|
| + if (eoh < 0)
|
| + return -1;
|
| + return eoh;
|
| + }
|
| + const char* p = data + kServerHandshakeHeaderLength;
|
| + const char* end = data + len;
|
| +
|
| + if (mode_ == MODE_NORMAL) {
|
| + size_t header_size = end - p;
|
| + if (header_size < kUpgradeHeaderLength)
|
| + return -1;
|
| + if (memcmp(p, kUpgradeHeader, kUpgradeHeaderLength)) {
|
| + mode_ = MODE_FAILED;
|
| + DLOG(INFO) << "Bad Upgrade Header "
|
| + << std::string(p, kUpgradeHeaderLength);
|
| + return p - data;
|
| + }
|
| + p += kUpgradeHeaderLength;
|
| + header_size = end - p;
|
| + if (header_size < kConnectionHeaderLength)
|
| + return -1;
|
| + if (memcmp(p, kConnectionHeader, kConnectionHeaderLength)) {
|
| + mode_ = MODE_FAILED;
|
| + DLOG(INFO) << "Bad Connection Header "
|
| + << std::string(p, kConnectionHeaderLength);
|
| + return p - data;
|
| + }
|
| + p += kConnectionHeaderLength;
|
| + }
|
| +
|
| + int eoh = HttpUtil::LocateEndOfHeaders(data, len);
|
| + if (eoh == -1)
|
| + return eoh;
|
| +
|
| + scoped_refptr<HttpResponseHeaders> headers(
|
| + new HttpResponseHeaders(HttpUtil::AssembleRawHeaders(data, eoh)));
|
| + if (!ProcessHeaders(*headers)) {
|
| + DLOG(INFO) << "Process Headers failed: "
|
| + << std::string(data, eoh);
|
| + mode_ = MODE_FAILED;
|
| + }
|
| + switch (mode_) {
|
| + case MODE_NORMAL:
|
| + if (CheckResponseHeaders()) {
|
| + mode_ = MODE_CONNECTED;
|
| + } else {
|
| + mode_ = MODE_FAILED;
|
| + }
|
| + break;
|
| + default:
|
| + mode_ = MODE_FAILED;
|
| + break;
|
| + }
|
| + return eoh;
|
| +}
|
| +
|
| +bool WebSocketHandshakeDraft75::ProcessHeaders(
|
| + const HttpResponseHeaders& headers) {
|
| + if (!GetSingleHeader(headers, "websocket-origin", &ws_origin_))
|
| + return false;
|
| +
|
| + if (!GetSingleHeader(headers, "websocket-location", &ws_location_))
|
| + return false;
|
| +
|
| + // If |protocol_| is not specified by client, we don't care if there's
|
| + // protocol field or not as specified in the spec.
|
| + if (!protocol_.empty()
|
| + && !GetSingleHeader(headers, "websocket-protocol", &ws_protocol_))
|
| + return false;
|
| + return true;
|
| +}
|
| +
|
| +bool WebSocketHandshakeDraft75::CheckResponseHeaders() const {
|
| + DCHECK(mode_ == MODE_NORMAL);
|
| + if (!LowerCaseEqualsASCII(origin_, ws_origin_.c_str()))
|
| + return false;
|
| + if (location_ != ws_location_)
|
| + return false;
|
| + if (!protocol_.empty() && protocol_ != ws_protocol_)
|
| + return false;
|
| + return true;
|
| +}
|
| +
|
| +} // namespace net
|
|
|