1 // Copyright 2013 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 #ifndef NET_WEBSOCKETS_WEBSOCKET_TEST_UTIL_H_
6 #define NET_WEBSOCKETS_WEBSOCKET_TEST_UTIL_H_
7 
8 #include <stdint.h>
9 
10 #include <memory>
11 #include <string>
12 #include <utility>
13 #include <vector>
14 
15 #include "base/macros.h"
16 #include "net/http/http_basic_state.h"
17 #include "net/http/http_request_headers.h"
18 #include "net/http/http_stream_parser.h"
19 #include "net/socket/client_socket_handle.h"
20 #include "net/third_party/quiche/src/spdy/core/spdy_header_block.h"
21 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
22 #include "net/url_request/url_request_test_util.h"
23 #include "net/websockets/websocket_handshake_stream_create_helper.h"
24 #include "net/websockets/websocket_stream.h"
25 
26 namespace url {
27 class Origin;
28 }  // namespace url
29 
30 namespace net {
31 
32 using WebSocketExtraHeaders = std::vector<std::pair<std::string, std::string>>;
33 
34 class MockClientSocketFactory;
35 class WebSocketBasicHandshakeStream;
36 class ProxyResolutionService;
37 class SequencedSocketData;
38 class IPEndPoint;
39 struct SSLSocketDataProvider;
40 
41 class LinearCongruentialGenerator {
42  public:
43   explicit LinearCongruentialGenerator(uint32_t seed);
44   uint32_t Generate();
45 
46  private:
47   uint64_t current_;
48 };
49 
50 // Converts a vector of header key-value pairs into a single string.
51 std::string WebSocketExtraHeadersToString(const WebSocketExtraHeaders& headers);
52 
53 // Converts a vector of header key-value pairs into an HttpRequestHeaders
54 HttpRequestHeaders WebSocketExtraHeadersToHttpRequestHeaders(
55     const WebSocketExtraHeaders& headers);
56 
57 // Generates a standard WebSocket handshake request. The challenge key used is
58 // "dGhlIHNhbXBsZSBub25jZQ==". Each header in |extra_headers| must be terminated
59 // with "\r\n".
60 std::string WebSocketStandardRequest(
61     const std::string& path,
62     const std::string& host,
63     const url::Origin& origin,
64     const std::string& send_additional_request_headers,
65     const std::string& extra_headers);
66 
67 // Generates a standard WebSocket handshake request. The challenge key used is
68 // "dGhlIHNhbXBsZSBub25jZQ==". |cookies| must be empty or terminated with
69 // "\r\n". Each header in |extra_headers| must be terminated with "\r\n".
70 std::string WebSocketStandardRequestWithCookies(
71     const std::string& path,
72     const std::string& host,
73     const url::Origin& origin,
74     const std::string& cookies,
75     const std::string& send_additional_request_headers,
76     const std::string& extra_headers);
77 
78 // A response with the appropriate accept header to match the above
79 // challenge key. Each header in |extra_headers| must be terminated with
80 // "\r\n".
81 std::string WebSocketStandardResponse(const std::string& extra_headers);
82 
83 // WebSocketCommonTestHeaders() generates a common set of request headers
84 // corresponding to WebSocketStandardRequest("/", "www.example.org",
85 // url::Origin::Create(GURL("http://origin.example.org")), "", "")
86 HttpRequestHeaders WebSocketCommonTestHeaders();
87 
88 // Generates a handshake request header block when using WebSockets over HTTP/2.
89 spdy::SpdyHeaderBlock WebSocketHttp2Request(
90     const std::string& path,
91     const std::string& authority,
92     const std::string& origin,
93     const WebSocketExtraHeaders& extra_headers);
94 
95 // Generates a handshake response header block when using WebSockets over
96 // HTTP/2.
97 spdy::SpdyHeaderBlock WebSocketHttp2Response(
98     const WebSocketExtraHeaders& extra_headers);
99 
100 // This class provides a convenient way to construct a MockClientSocketFactory
101 // for WebSocket tests.
102 class WebSocketMockClientSocketFactoryMaker {
103  public:
104   WebSocketMockClientSocketFactoryMaker();
105   ~WebSocketMockClientSocketFactoryMaker();
106 
107   // Tell the factory to create a socket which expects |expect_written| to be
108   // written, and responds with |return_to_read|. The test will fail if the
109   // expected text is not written, or all the bytes are not read. This adds data
110   // for a new mock-socket using AddRawExpections(), and so can be called
111   // multiple times to queue up multiple mock sockets, but usually in those
112   // cases the lower-level AddRawExpections() interface is more appropriate.
113   void SetExpectations(const std::string& expect_written,
114                        const std::string& return_to_read);
115 
116   // A low-level interface to permit arbitrary expectations to be added. The
117   // mock sockets will be created in the same order that they were added.
118   void AddRawExpectations(std::unique_ptr<SequencedSocketData> socket_data);
119 
120   // Allow an SSL socket data provider to be added. You must also supply a mock
121   // transport socket for it to use. If the mock SSL handshake fails then the
122   // mock transport socket will connect but have nothing read or written. If the
123   // mock handshake succeeds then the data from the underlying transport socket
124   // will be passed through unchanged (without encryption).
125   void AddSSLSocketDataProvider(
126       std::unique_ptr<SSLSocketDataProvider> ssl_socket_data);
127 
128   // Call to get a pointer to the factory, which remains owned by this object.
129   MockClientSocketFactory* factory();
130 
131  private:
132   struct Detail;
133   std::unique_ptr<Detail> detail_;
134 
135   DISALLOW_COPY_AND_ASSIGN(WebSocketMockClientSocketFactoryMaker);
136 };
137 
138 // This class encapsulates the details of creating a
139 // TestURLRequestContext that returns mock ClientSocketHandles that do what is
140 // required by the tests.
141 struct WebSocketTestURLRequestContextHost {
142  public:
143   WebSocketTestURLRequestContextHost();
144   ~WebSocketTestURLRequestContextHost();
145 
SetExpectationsWebSocketTestURLRequestContextHost146   void SetExpectations(const std::string& expect_written,
147                        const std::string& return_to_read) {
148     maker_.SetExpectations(expect_written, return_to_read);
149   }
150 
151   void AddRawExpectations(std::unique_ptr<SequencedSocketData> socket_data);
152 
153   // Allow an SSL socket data provider to be added.
154   void AddSSLSocketDataProvider(
155       std::unique_ptr<SSLSocketDataProvider> ssl_socket_data);
156 
157   // Allow a proxy to be set. Usage:
158   //   SetProxyConfig("proxy1:8000");
159   // Any syntax accepted by net::ProxyConfig::ParseFromString() will work.
160   // Do not call after GetURLRequestContext() has been called.
161   void SetProxyConfig(const std::string& proxy_rules);
162 
163   // Call after calling one of SetExpections() or AddRawExpectations(). The
164   // returned pointer remains owned by this object.
165   TestURLRequestContext* GetURLRequestContext();
166 
network_delegateWebSocketTestURLRequestContextHost167   const TestNetworkDelegate& network_delegate() const {
168     return network_delegate_;
169   }
170 
171  private:
172   WebSocketMockClientSocketFactoryMaker maker_;
173   TestURLRequestContext url_request_context_;
174   TestNetworkDelegate network_delegate_;
175   std::unique_ptr<ProxyResolutionService> proxy_resolution_service_;
176   bool url_request_context_initialized_;
177 
178   DISALLOW_COPY_AND_ASSIGN(WebSocketTestURLRequestContextHost);
179 };
180 
181 // WebSocketStream::ConnectDelegate implementation that does nothing.
182 class DummyConnectDelegate : public WebSocketStream::ConnectDelegate {
183  public:
184   DummyConnectDelegate() = default;
185   ~DummyConnectDelegate() override = default;
OnCreateRequest(URLRequest * url_request)186   void OnCreateRequest(URLRequest* url_request) override {}
OnSuccess(std::unique_ptr<WebSocketStream> stream,std::unique_ptr<WebSocketHandshakeResponseInfo> response)187   void OnSuccess(
188       std::unique_ptr<WebSocketStream> stream,
189       std::unique_ptr<WebSocketHandshakeResponseInfo> response) override {}
OnFailure(const std::string & message)190   void OnFailure(const std::string& message) override {}
OnStartOpeningHandshake(std::unique_ptr<WebSocketHandshakeRequestInfo> request)191   void OnStartOpeningHandshake(
192       std::unique_ptr<WebSocketHandshakeRequestInfo> request) override {}
OnSSLCertificateError(std::unique_ptr<WebSocketEventInterface::SSLErrorCallbacks> ssl_error_callbacks,int net_error,const SSLInfo & ssl_info,bool fatal)193   void OnSSLCertificateError(
194       std::unique_ptr<WebSocketEventInterface::SSLErrorCallbacks>
195           ssl_error_callbacks,
196       int net_error,
197       const SSLInfo& ssl_info,
198       bool fatal) override {}
199   int OnAuthRequired(const AuthChallengeInfo& auth_info,
200                      scoped_refptr<HttpResponseHeaders> response_headers,
201                      const IPEndPoint& remote_endpoint,
202                      base::OnceCallback<void(const AuthCredentials*)> callback,
203                      base::Optional<AuthCredentials>* credentials) override;
204 };
205 
206 // WebSocketStreamRequestAPI implementation that sets the value of
207 // Sec-WebSocket-Key to the deterministic key that is used by tests.
208 class TestWebSocketStreamRequestAPI : public WebSocketStreamRequestAPI {
209  public:
210   TestWebSocketStreamRequestAPI() = default;
211   ~TestWebSocketStreamRequestAPI() override = default;
212   void OnBasicHandshakeStreamCreated(
213       WebSocketBasicHandshakeStream* handshake_stream) override;
214   void OnHttp2HandshakeStreamCreated(
215       WebSocketHttp2HandshakeStream* handshake_stream) override;
OnFailure(const std::string & message)216   void OnFailure(const std::string& message) override {}
217 };
218 
219 // A sub-class of WebSocketHandshakeStreamCreateHelper which sets a
220 // deterministic key to use in the WebSocket handshake, and uses a dummy
221 // ConnectDelegate and WebSocketStreamRequestAPI.
222 class TestWebSocketHandshakeStreamCreateHelper
223     : public WebSocketHandshakeStreamCreateHelper {
224  public:
225   // Constructor for using dummy ConnectDelegate and WebSocketStreamRequestAPI.
TestWebSocketHandshakeStreamCreateHelper()226   TestWebSocketHandshakeStreamCreateHelper()
227       : WebSocketHandshakeStreamCreateHelper(&connect_delegate_,
228                                              /* requested_subprotocols = */ {},
229                                              &request_) {}
230 
231   ~TestWebSocketHandshakeStreamCreateHelper() override = default;
232 
233  private:
234   DummyConnectDelegate connect_delegate_;
235   TestWebSocketStreamRequestAPI request_;
236 
237   DISALLOW_COPY_AND_ASSIGN(TestWebSocketHandshakeStreamCreateHelper);
238 };
239 
240 }  // namespace net
241 
242 #endif  // NET_WEBSOCKETS_WEBSOCKET_TEST_UTIL_H_
243