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 |