• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "net/websockets/websocket_handshake_draft75.h"
6 
7 #include "base/memory/ref_counted.h"
8 #include "base/string_util.h"
9 #include "net/http/http_response_headers.h"
10 #include "net/http/http_util.h"
11 
12 namespace net {
13 
14 const char WebSocketHandshakeDraft75::kServerHandshakeHeader[] =
15     "HTTP/1.1 101 Web Socket Protocol Handshake\r\n";
16 const size_t WebSocketHandshakeDraft75::kServerHandshakeHeaderLength =
17     sizeof(kServerHandshakeHeader) - 1;
18 
19 const char WebSocketHandshakeDraft75::kUpgradeHeader[] =
20     "Upgrade: WebSocket\r\n";
21 const size_t WebSocketHandshakeDraft75::kUpgradeHeaderLength =
22     sizeof(kUpgradeHeader) - 1;
23 
24 const char WebSocketHandshakeDraft75::kConnectionHeader[] =
25     "Connection: Upgrade\r\n";
26 const size_t WebSocketHandshakeDraft75::kConnectionHeaderLength =
27     sizeof(kConnectionHeader) - 1;
28 
WebSocketHandshakeDraft75(const GURL & url,const std::string & origin,const std::string & location,const std::string & protocol)29 WebSocketHandshakeDraft75::WebSocketHandshakeDraft75(
30     const GURL& url,
31     const std::string& origin,
32     const std::string& location,
33     const std::string& protocol)
34     : WebSocketHandshake(url, origin, location, protocol) {
35 }
36 
~WebSocketHandshakeDraft75()37 WebSocketHandshakeDraft75::~WebSocketHandshakeDraft75() {
38 }
39 
CreateClientHandshakeMessage()40 std::string WebSocketHandshakeDraft75::CreateClientHandshakeMessage() {
41   std::string msg;
42   msg = "GET ";
43   msg += GetResourceName();
44   msg += " HTTP/1.1\r\n";
45   msg += kUpgradeHeader;
46   msg += kConnectionHeader;
47   msg += "Host: ";
48   msg += GetHostFieldValue();
49   msg += "\r\n";
50   msg += "Origin: ";
51   msg += GetOriginFieldValue();
52   msg += "\r\n";
53   if (!protocol_.empty()) {
54     msg += "WebSocket-Protocol: ";
55     msg += protocol_;
56     msg += "\r\n";
57   }
58   // TODO(ukai): Add cookie if necessary.
59   msg += "\r\n";
60   return msg;
61 }
62 
ReadServerHandshake(const char * data,size_t len)63 int WebSocketHandshakeDraft75::ReadServerHandshake(
64     const char* data, size_t len) {
65   mode_ = MODE_INCOMPLETE;
66   if (len < kServerHandshakeHeaderLength) {
67     return -1;
68   }
69   if (!memcmp(data, kServerHandshakeHeader, kServerHandshakeHeaderLength)) {
70     mode_ = MODE_NORMAL;
71   } else {
72     int eoh = HttpUtil::LocateEndOfHeaders(data, len);
73     if (eoh < 0)
74       return -1;
75     return eoh;
76   }
77   const char* p = data + kServerHandshakeHeaderLength;
78   const char* end = data + len;
79 
80   if (mode_ == MODE_NORMAL) {
81     size_t header_size = end - p;
82     if (header_size < kUpgradeHeaderLength)
83       return -1;
84     if (memcmp(p, kUpgradeHeader, kUpgradeHeaderLength)) {
85       mode_ = MODE_FAILED;
86       DVLOG(1) << "Bad Upgrade Header " << std::string(p, kUpgradeHeaderLength);
87       return p - data;
88     }
89     p += kUpgradeHeaderLength;
90     header_size = end - p;
91     if (header_size < kConnectionHeaderLength)
92       return -1;
93     if (memcmp(p, kConnectionHeader, kConnectionHeaderLength)) {
94       mode_ = MODE_FAILED;
95       DVLOG(1) << "Bad Connection Header "
96                << std::string(p, kConnectionHeaderLength);
97       return p - data;
98     }
99     p += kConnectionHeaderLength;
100   }
101 
102   int eoh = HttpUtil::LocateEndOfHeaders(data, len);
103   if (eoh == -1)
104     return eoh;
105 
106   scoped_refptr<HttpResponseHeaders> headers(
107       new HttpResponseHeaders(HttpUtil::AssembleRawHeaders(data, eoh)));
108   if (!ProcessHeaders(*headers)) {
109     DVLOG(1) << "Process Headers failed: " << std::string(data, eoh);
110     mode_ = MODE_FAILED;
111   }
112   switch (mode_) {
113     case MODE_NORMAL:
114       if (CheckResponseHeaders()) {
115         mode_ = MODE_CONNECTED;
116       } else {
117         mode_ = MODE_FAILED;
118       }
119       break;
120     default:
121       mode_ = MODE_FAILED;
122       break;
123   }
124   return eoh;
125 }
126 
ProcessHeaders(const HttpResponseHeaders & headers)127 bool WebSocketHandshakeDraft75::ProcessHeaders(
128     const HttpResponseHeaders& headers) {
129   if (!GetSingleHeader(headers, "websocket-origin", &ws_origin_))
130     return false;
131 
132   if (!GetSingleHeader(headers, "websocket-location", &ws_location_))
133     return false;
134 
135   // If |protocol_| is not specified by client, we don't care if there's
136   // protocol field or not as specified in the spec.
137   if (!protocol_.empty()
138       && !GetSingleHeader(headers, "websocket-protocol", &ws_protocol_))
139     return false;
140   return true;
141 }
142 
CheckResponseHeaders() const143 bool WebSocketHandshakeDraft75::CheckResponseHeaders() const {
144   DCHECK(mode_ == MODE_NORMAL);
145   if (!LowerCaseEqualsASCII(origin_, ws_origin_.c_str()))
146     return false;
147   if (location_ != ws_location_)
148     return false;
149   if (!protocol_.empty() && protocol_ != ws_protocol_)
150     return false;
151   return true;
152 }
153 
154 }  // namespace net
155