added iOS source code
[wl-app.git] / iOS / Pods / Realm / include / core / realm / util / websocket.hpp
1 /*************************************************************************
2  *
3  * REALM CONFIDENTIAL
4  * __________________
5  *
6  *  [2011] - [2016] Realm Inc
7  *  All Rights Reserved.
8  *
9  * NOTICE:  All information contained herein is, and remains
10  * the property of Realm Incorporated and its suppliers,
11  * if any.  The intellectual and technical concepts contained
12  * herein are proprietary to Realm Incorporated
13  * and its suppliers and may be covered by U.S. and Foreign Patents,
14  * patents in process, and are protected by trade secret or copyright law.
15  * Dissemination of this information or reproduction of this material
16  * is strictly forbidden unless prior written permission is obtained
17  * from Realm Incorporated.
18  *
19  **************************************************************************/
20
21 #ifndef REALM_UTIL_WEBSOCKET_HPP
22 #define REALM_UTIL_WEBSOCKET_HPP
23
24 #include <random>
25 #include <system_error>
26 #include <map>
27
28 #include <realm/util/logger.hpp>
29 #include <realm/util/http.hpp>
30
31
32 namespace realm {
33 namespace util {
34 namespace websocket {
35
36 using WriteCompletionHandler =
37     std::function<void(std::error_code, size_t num_bytes_transferred)>;
38 using ReadCompletionHandler =
39     std::function<void(std::error_code, size_t num_bytes_transferred)>;
40
41 class Config {
42 public:
43     /// The Socket uses the caller supplied logger for logging.
44     virtual util::Logger& websocket_get_logger() noexcept = 0;
45
46     /// The Socket needs random numbers to satisfy the Websocket protocol.
47     /// The caller must supply a random number generator.
48     virtual std::mt19937_64& websocket_get_random() noexcept = 0;
49
50     //@{
51     /// The three functions below are used by the Socket to read and write to the underlying
52     /// stream. The functions will typically be implemented as wrappers to a TCP/TLS stream,
53     /// but could also map to pure memory streams. These functions abstract away the details of
54     /// the underlying sockets.
55     /// The functions have the same semantics as util::Socket.
56     ///
57     /// FIXME: Require that implementations ensure no callback reentrance, i.e.,
58     /// that the completion handler is never called from within the execution of
59     /// async_write(), async_read(), or async_read_until(). This guarantee is
60     /// provided by both network::Socket and network::ssl::Stream.
61     virtual void async_write(const char* data, size_t size, WriteCompletionHandler handler) = 0;
62     virtual void async_read(char* buffer, size_t size, ReadCompletionHandler handler) = 0;
63     virtual void async_read_until(char* buffer, size_t size, char delim, ReadCompletionHandler handler) = 0;
64     //@}
65
66     /// websocket_handshake_completion_handler() is called when the websocket is connected, .i.e.
67     /// after the handshake is done. It is not allowed to send messages on the socket before the
68     /// handshake is done. No message_received callbacks will be called before the handshake is done.
69     virtual void websocket_handshake_completion_handler(const HTTPHeaders&) = 0;
70
71     //@{
72     /// websocket_read_error_handler() and websocket_write_error_handler() are called when an
73     /// error occurs on the underlying stream given by the async_read and async_write functions above.
74     /// The error_code is passed through.
75     /// websocket_handshake_error_handler() will be called when there is an error in the handshake
76     /// such as "404 Not found".
77     /// websocket_protocol_error_handler() is called when there is an protocol error in the incoming
78     /// websocket messages.
79     /// After calling any of these error callbacks, the Socket will move into the stopped state, and
80     /// no more messages should be sent, or will be received.
81     /// It is safe to destroy the WebSocket object in these handlers.
82     virtual void websocket_read_error_handler(std::error_code) = 0;
83     virtual void websocket_write_error_handler(std::error_code) = 0;
84     virtual void websocket_handshake_error_handler(std::error_code, const HTTPHeaders&) = 0;
85     virtual void websocket_protocol_error_handler(std::error_code) = 0;
86     //@}
87
88     //@{
89     /// The five callback functions below are called whenever a full message has arrived.
90     /// The Socket defragments fragmented messages internally and delivers a full message.
91     /// The message is delivered in the buffer \param data of size \param size.
92     /// The buffer is only valid until the function returns.
93     /// The return value designates whether the WebSocket object should continue
94     /// processing messages. The normal return value is true. False must be returned if the
95     /// websocket object is destroyed during execution of the function.
96     virtual bool websocket_text_message_received(const char* data, size_t size);
97     virtual bool websocket_binary_message_received(const char* data, size_t size);
98     virtual bool websocket_close_message_received(const char* data, size_t size);
99     virtual bool websocket_ping_message_received(const char* data, size_t size);
100     virtual bool websocket_pong_message_received(const char* data, size_t size);
101     //@}
102 };
103
104
105 enum class Opcode {
106     continuation =  0,
107     text         =  1,
108     binary       =  2,
109     close        =  8,
110     ping         =  9,
111     pong         = 10
112 };
113
114
115 class Socket {
116 public:
117     Socket(Config&);
118     Socket(Socket&&) noexcept;
119     ~Socket() noexcept;
120
121     /// initiate_client_handshake() starts the Socket in client mode. The Socket
122     /// will send the HTTP request that initiates the WebSocket protocol and
123     /// wait for the HTTP response from the server. The HTTP request will
124     /// contain the \param request_uri in the HTTP request line. The \param host
125     /// will be sent as the value in a HTTP Host header line.
126     /// \param sec_websocket_protocol will be set as header value for
127     /// Sec-WebSocket-Protocol. Extra HTTP headers can be provided in \a headers.
128     ///
129     /// When the server responds with a valid HTTP response, the callback
130     /// function websocket_handshake_completion_handler() is called. Messages
131     /// can only be sent and received after the handshake has completed.
132     void initiate_client_handshake(const std::string& request_uri,
133                                    const std::string& host,
134                                    const std::string& sec_websocket_protocol,
135                                    HTTPHeaders headers = HTTPHeaders{});
136
137     /// initiate_server_handshake() starts the Socket in server mode. It will
138     /// wait for a HTTP request from a client and respond with a HTTP response.
139     /// After sending a HTTP response, websocket_handshake_completion_handler()
140     /// is called. Messages can only be sent and received after the handshake
141     /// has completed.
142     void initiate_server_handshake();
143
144     /// initiate_server_websocket_after_handshake() starts the Socket in a state
145     /// where it will read and write WebSocket messages but it will expect the
146     /// handshake to have been completed by the caller. The use of this
147     /// function is to perform HTTP routing externally and then start the
148     /// WebSocket in case the HTTP request is an Upgrade to WebSocket.
149     /// Typically, the caller will have used make_http_response() to send the
150     /// HTTP response itself.
151     void initiate_server_websocket_after_handshake();
152
153     /// The async_write_* functions send frames. Only one frame should be sent at a time,
154     /// meaning that the user must wait for the handler to be called before sending the next frame.
155     /// The handler is type std::function<void()> and is called when the frame has been successfully
156     /// sent. In case of errors, the Config::websocket_write_error_handler() is called.
157
158     /// async_write_frame() sends a single frame with the fin bit set to 0 or 1 from \param fin, and the opcode
159     /// set by \param opcode. The frame payload is taken from \param data of size \param size. \param handler is
160     /// called when the frame has been successfully sent. Error s are reported through
161     /// websocket_write_error_handler() in Config.
162     /// This function is rather low level and should only be used with knowledge of the WebSocket protocol.
163     /// The five utility functions below are recommended for message sending.
164     ///
165     /// FIXME: Guarantee no callback reentrance, i.e., that the completion
166     /// handler, or the error handler in case an error occurs, is never called
167     /// from within the execution of async_write_frame().
168     void async_write_frame(bool fin, Opcode opcode, const char* data, size_t size, std::function<void()> handler);
169
170     //@{
171     /// Five utility functions used to send whole messages. These five functions are implemented in terms of
172     /// async_write_frame(). These functions send whole unfragmented messages. These functions should be
173     /// preferred over async_write_frame() for most use cases.
174     ///
175     /// FIXME: Guarantee no callback reentrance, i.e., that the completion
176     /// handler, or the error handler in case an error occurs, is never called
177     /// from within the execution of async_write_text(), and its friends. This
178     /// is already assumed by the client and server implementations of the sync
179     /// protocol.
180     void async_write_text(const char* data, size_t size, std::function<void()> handler);
181     void async_write_binary(const char* data, size_t size, std::function<void()> handler);
182     void async_write_close(const char* data, size_t size, std::function<void()> handler);
183     void async_write_ping(const char* data, size_t size, std::function<void()> handler);
184     void async_write_pong(const char* data, size_t size, std::function<void()> handler);
185     //@}
186
187     /// stop() stops the socket. The socket will stop processing incoming data, sending data, and calling callbacks.
188     /// It is an error to attempt to send a message after stop() has been called. stop() will typically be called
189     /// before the underlying TCP/TLS connection is closed. The Socket can be restarted with
190     /// initiate_client_handshake() and initiate_server_handshake().
191     void stop() noexcept;
192
193 private:
194     class Impl;
195     std::unique_ptr<Impl> m_impl;
196 };
197
198
199 /// read_sec_websocket_protocol() returns the value of the
200 /// header Sec-WebSocket-Protocol in the http request \a request.
201 /// None is returned if the header Sec-WebSocket-Protocol is absent
202 /// in the request.
203 util::Optional<std::string> read_sec_websocket_protocol(const HTTPRequest& request);
204
205 /// make_http_response() takes \a request as a WebSocket handshake request,
206 /// validates it, and makes a HTTP response. If the request is invalid, the
207 /// return value is None, and ec is set to Error::bad_handshake_request.
208 util::Optional<HTTPResponse> make_http_response(const HTTPRequest& request,
209                                                 const std::string& sec_websocket_protocol,
210                                                 std::error_code& ec);
211
212 enum class Error {
213     bad_request_header_upgrade            = 1,
214     bad_request_header_connection         = 2,
215     bad_request_header_websocket_version  = 3,
216     bad_request_header_websocket_key      = 4,
217     bad_handshake_request                 = 5,
218     bad_handshake_response                = 6,
219     bad_handshake_response_404_not_found  = 7,
220     bad_handshake_response_50x_temporary  = 8,
221     bad_message                           = 9
222 };
223
224 const std::error_category& error_category() noexcept;
225
226 std::error_code make_error_code(Error) noexcept;
227
228 } // namespace websocket
229 } // namespace util
230 } // namespace realm
231
232 namespace std {
233
234 template<> struct is_error_code_enum<realm::util::websocket::Error> {
235     static const bool value = true;
236 };
237
238 } // namespace std
239
240 #endif // REALM_UTIL_WEBSOCKET_HPP