summaryrefslogtreecommitdiffstats
path: root/net/websockets/websocket_handshake_handler.h
blob: b4a0dd57e5197dd54ca406a10c34b18150ce6bcb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
// Copyright (c) 2012 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.
//
// WebSocketHandshake*Handler handles WebSocket handshake request message
// from WebKit renderer process, and WebSocket handshake response message
// from WebSocket server.
// It modifies messages for the following reason:
// - We don't trust WebKit renderer process, so we'll not expose HttpOnly
//   cookies to the renderer process, so handles HttpOnly cookies in
//   browser process.
//
// The classes below support two styles of handshake: handshake based
// on hixie-76 draft and one based on hybi-04 draft. The critical difference
// between these two is how they pass challenge and response values. Hixie-76
// based handshake appends a few bytes of binary data after header fields of
// handshake request and response. These data are called "key3" (for request)
// or "response key" (for response). On the other hand, handshake based on
// hybi-04 and later drafts put challenge and response values into handshake
// header fields, thus we do not need to send or receive extra bytes after
// handshake headers.
//
// While we are working on updating WebSocket implementation in WebKit to
// conform to the latest procotol draft, we need to accept both styles of
// handshake. After we land the protocol changes in WebKit, we will be able to
// drop codes handling old-style handshake.

#ifndef NET_WEBSOCKETS_WEBSOCKET_HANDSHAKE_HANDLER_H_
#define NET_WEBSOCKETS_WEBSOCKET_HANDSHAKE_HANDLER_H_

#include <string>
#include <vector>

#include "base/memory/ref_counted.h"
#include "net/base/net_export.h"
#include "net/http/http_request_info.h"
#include "net/http/http_response_info.h"
#include "net/spdy/spdy_framer.h"
#include "net/spdy/spdy_header_block.h"

namespace net {

class NET_EXPORT_PRIVATE WebSocketHandshakeRequestHandler {
 public:
  WebSocketHandshakeRequestHandler();
  ~WebSocketHandshakeRequestHandler() {}

  // Parses WebSocket handshake request from renderer process.
  // It assumes a WebSocket handshake request message is given at once, and
  // no other data is added to the request message.
  bool ParseRequest(const char* data, int length);

  size_t original_length() const;

  // Appends the header value pair for |name| and |value|, if |name| doesn't
  // exist.
  void AppendHeaderIfMissing(const std::string& name,
                             const std::string& value);
  // Removes the headers that matches (case insensitive).
  void RemoveHeaders(const char* const headers_to_remove[],
                     size_t headers_to_remove_len);

  // Gets request info to open WebSocket connection.
  // Fills challange data (concatenation of key1, 2 and 3 for hybi-03 and
  // earlier, or Sec-WebSocket-Key header value for hybi-04 and later)
  // in |challenge|.
  HttpRequestInfo GetRequestInfo(const GURL& url, std::string* challenge);
  // Gets request as SpdyHeaderBlock.
  // Also, fills challenge data in |challenge|.
  bool GetRequestHeaderBlock(const GURL& url,
                             SpdyHeaderBlock* headers,
                             std::string* challenge,
                             int spdy_protocol_version);
  // Gets WebSocket handshake raw request message to open WebSocket
  // connection.
  std::string GetRawRequest();
  // Calling raw_length is valid only after GetRawRquest() call.
  size_t raw_length() const;

  // Returns the value of Sec-WebSocket-Version or Sec-WebSocket-Draft header
  // (the latter is an old name of the former). Returns 0 if both headers were
  // absent, which means the handshake was based on hybi-00 (= hixie-76).
  // Should only be called after the handshake has been parsed.
  int protocol_version() const;

 private:
  std::string status_line_;
  std::string headers_;
  std::string key3_;
  int original_length_;
  int raw_length_;
  int protocol_version_;  // "-1" means we haven't parsed the handshake yet.

  DISALLOW_COPY_AND_ASSIGN(WebSocketHandshakeRequestHandler);
};

class NET_EXPORT_PRIVATE WebSocketHandshakeResponseHandler {
 public:
  WebSocketHandshakeResponseHandler();
  ~WebSocketHandshakeResponseHandler();

  // Set WebSocket protocol version before parsing the response.
  // Default is 0 (hybi-00, which is same as hixie-76).
  int protocol_version() const;
  void set_protocol_version(int protocol_version);

  // Parses WebSocket handshake response from WebSocket server.
  // Returns number of bytes in |data| used for WebSocket handshake response
  // message, including response key.  If it already got whole WebSocket
  // handshake response message, returns zero.  In other words,
  // [data + returned value, data + length) will be WebSocket frame data
  // after handshake response message.
  // TODO(ukai): fail fast when response gives wrong status code.
  size_t ParseRawResponse(const char* data, int length);
  // Returns true if it already parses full handshake response message.
  bool HasResponse() const;
  // Parses WebSocket handshake response info given as HttpResponseInfo.
  bool ParseResponseInfo(const HttpResponseInfo& response_info,
                         const std::string& challenge);
  // Parses WebSocket handshake response as SpdyHeaderBlock.
  bool ParseResponseHeaderBlock(const SpdyHeaderBlock& headers,
                                const std::string& challenge,
                                int spdy_protocol_version);

  // Gets the headers value.
  void GetHeaders(const char* const headers_to_get[],
                  size_t headers_to_get_len,
                  std::vector<std::string>* values);
  // Removes the headers that matches (case insensitive).
  void RemoveHeaders(const char* const headers_to_remove[],
                     size_t headers_to_remove_len);

  // Gets raw WebSocket handshake response received from WebSocket server.
  std::string GetRawResponse() const;

  // Gets WebSocket handshake response message sent to renderer process.
  std::string GetResponse();

 private:
  // Returns the length of response key. This function will return 0
  // if the specified WebSocket protocol version does not require
  // sending response key.
  size_t GetResponseKeySize() const;

  std::string original_;
  int original_header_length_;
  std::string status_line_;
  std::string headers_;
  std::string header_separator_;
  std::string key_;
  int protocol_version_;

  DISALLOW_COPY_AND_ASSIGN(WebSocketHandshakeResponseHandler);
};

}  // namespace net

#endif  // NET_WEBSOCKETS_WEBSOCKET_HANDSHAKE_HANDLER_H_