added iOS source code
[wl-app.git] / iOS / Pods / Realm / include / core / realm / util / http.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_HTTP_HPP
22 #define REALM_UTIL_HTTP_HPP
23
24 #include <map>
25 #include <system_error>
26 #include <iosfwd>
27 #include <locale>
28
29 #include <realm/util/optional.hpp>
30 #include <realm/util/network.hpp>
31 #include <realm/string_data.hpp>
32
33 namespace realm {
34 namespace util {
35 enum class HTTPParserError {
36     None = 0,
37     ContentTooLong,
38     HeaderLineTooLong,
39     MalformedResponse,
40     MalformedRequest,
41 };
42 std::error_code make_error_code(HTTPParserError);
43 } // namespace util
44 } // namespace realm
45
46 namespace std {
47     template<>
48     struct is_error_code_enum<realm::util::HTTPParserError>: std::true_type {};
49 }
50
51 namespace realm {
52 namespace util {
53
54 /// See: https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
55 ///
56 /// It is guaranteed that the backing integer value of this enum corresponds
57 /// to the numerical code representing the status.
58 enum class HTTPStatus {
59     Unknown = 0,
60
61     Continue = 100,
62     SwitchingProtocols = 101,
63
64     Ok = 200,
65     Created = 201,
66     Accepted = 202,
67     NonAuthoritative = 203,
68     NoContent = 204,
69     ResetContent = 205,
70     PartialContent = 206,
71
72     MultipleChoices = 300,
73     MovedPermanently = 301,
74     Found = 302,
75     SeeOther = 303,
76     NotModified = 304,
77     UseProxy = 305,
78     SwitchProxy = 306,
79     TemporaryRedirect = 307,
80     PermanentRedirect = 308,
81
82     BadRequest = 400,
83     Unauthorized = 401,
84     PaymentRequired = 402,
85     Forbidden = 403,
86     NotFound = 404,
87     MethodNotAllowed = 405,
88     NotAcceptable = 406,
89     ProxyAuthenticationRequired = 407,
90     RequestTimeout = 408,
91     Conflict = 409,
92     Gone = 410,
93     LengthRequired = 411,
94     PreconditionFailed = 412,
95     PayloadTooLarge = 413,
96     UriTooLong = 414,
97     UnsupportedMediaType = 415,
98     RangeNotSatisfiable = 416,
99     ExpectationFailed = 417,
100     ImATeapot = 418,
101     MisdirectedRequest = 421,
102     UpgradeRequired = 426,
103     PreconditionRequired = 428,
104     TooManyRequests = 429,
105     RequestHeaderFieldsTooLarge = 431,
106     UnavailableForLegalReasons = 451,
107
108     InternalServerError = 500,
109     NotImplemented = 501,
110     BadGateway = 502,
111     ServiceUnavailable = 503,
112     GatewayTimeout = 504,
113     HttpVersionNotSupported = 505,
114     VariantAlsoNegotiates = 506,
115     NotExtended = 510,
116     NetworkAuthenticationRequired = 511,
117 };
118
119 /// See: https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
120 enum class HTTPMethod {
121     Options,
122     Get,
123     Head,
124     Post,
125     Put,
126     Delete,
127     Trace,
128     Connect,
129 };
130
131 struct HTTPAuthorization {
132     std::string scheme;
133     std::map<std::string, std::string> values;
134 };
135
136 HTTPAuthorization parse_authorization(const std::string&);
137
138 struct CaseInsensitiveCompare {
139     bool operator()(const std::string& a, const std::string& b) const
140     {
141         auto cmp = [](char lhs, char rhs) {
142             return std::tolower(lhs, std::locale::classic()) <
143                    std::tolower(rhs, std::locale::classic());
144         };
145         return std::lexicographical_compare(begin(a), end(a), begin(b), end(b), cmp);
146     }
147 };
148
149 /// Case-insensitive map suitable for storing HTTP headers.
150 using HTTPHeaders = std::map<std::string, std::string, CaseInsensitiveCompare>;
151
152 struct HTTPRequest {
153     HTTPMethod method = HTTPMethod::Get;
154     HTTPHeaders headers;
155     std::string path;
156
157     /// If the request object has a body, the Content-Length header MUST be
158     /// set to a string representation of the number of bytes in the body.
159     /// FIXME: Relax this restriction, and also support Transfer-Encoding
160     /// and other HTTP/1.1 features.
161     Optional<std::string> body;
162 };
163
164 struct HTTPResponse {
165     HTTPStatus status = HTTPStatus::Unknown;
166     HTTPHeaders headers;
167
168     // A body is only read from the response stream if the server sent the
169     // Content-Length header.
170     // FIXME: Support other transfer methods, including Transfer-Encoding and
171     // HTTP/1.1 features.
172     Optional<std::string> body;
173 };
174
175
176 /// Serialize HTTP request to output stream.
177 std::ostream& operator<<(std::ostream&, const HTTPRequest&);
178 /// Serialize HTTP response to output stream.
179 std::ostream& operator<<(std::ostream&, const HTTPResponse&);
180 /// Serialize HTTP method to output stream ("GET", "POST", etc.).
181 std::ostream& operator<<(std::ostream&, HTTPMethod);
182 /// Serialize HTTP status to output stream, include reason string ("200 OK" etc.)
183 std::ostream& operator<<(std::ostream&, HTTPStatus);
184
185 struct HTTPParserBase {
186     // FIXME: Generally useful?
187     struct CallocDeleter {
188         void operator()(void* ptr)
189         {
190             std::free(ptr);
191         }
192     };
193
194     HTTPParserBase()
195     {
196         // Allocating read buffer with calloc to avoid accidentally spilling
197         // data from other sessions in case of a buffer overflow exploit.
198         m_read_buffer.reset(static_cast<char*>(std::calloc(read_buffer_size, 1)));
199     }
200     virtual ~HTTPParserBase() {}
201
202     std::string m_write_buffer;
203     std::unique_ptr<char[], CallocDeleter> m_read_buffer;
204     Optional<size_t> m_found_content_length;
205     static const size_t read_buffer_size = 8192;
206     static const size_t max_header_line_length = read_buffer_size;
207
208     /// Parses the contents of m_read_buffer as a HTTP header line,
209     /// and calls on_header() as appropriate. on_header() will be called at
210     /// most once per invocation.
211     /// Returns false if the contents of m_read_buffer is not a valid HTTP
212     /// header line.
213     bool parse_header_line(size_t len);
214
215     virtual std::error_code on_first_line(StringData line) = 0;
216     virtual void on_header(StringData key, StringData value) = 0;
217     virtual void on_body(StringData body) = 0;
218     virtual void on_complete(std::error_code = std::error_code{}) = 0;
219
220     /// If the input matches a known HTTP method string, return the appropriate
221     /// HTTPMethod enum value. Otherwise, returns none.
222     static Optional<HTTPMethod> parse_method_string(StringData method);
223
224     /// Interpret line as the first line of an HTTP request. If the return value
225     /// is true, out_method and out_uri have been assigned the appropriate
226     /// values found in the request line.
227     static bool parse_first_line_of_request(StringData line, HTTPMethod& out_method,
228                                             StringData& out_uri);
229
230     /// Interpret line as the first line of an HTTP response. If the return
231     /// value is true, out_status and out_reason have been assigned the
232     /// appropriate values found in the response line.
233     static bool parse_first_line_of_response(StringData line, HTTPStatus& out_status,
234                                              StringData& out_reason);
235
236     void set_write_buffer(const HTTPRequest&);
237     void set_write_buffer(const HTTPResponse&);
238 };
239
240 template<class Socket>
241 struct HTTPParser: protected HTTPParserBase {
242     explicit HTTPParser(Socket& socket) : m_socket(socket)
243     {}
244
245     void read_first_line()
246     {
247         auto handler = [this](std::error_code ec, size_t n) {
248             if (ec == error::operation_aborted) {
249                 return;
250             }
251             if (ec) {
252                 on_complete(ec);
253                 return;
254             }
255             ec = on_first_line(StringData(m_read_buffer.get(), n));
256             if (ec) {
257                 on_complete(ec);
258                 return;
259             }
260             read_headers();
261         };
262         m_socket.async_read_until(m_read_buffer.get(), max_header_line_length, '\n',
263                                   std::move(handler));
264     }
265
266     void read_headers()
267     {
268         auto handler = [this](std::error_code ec, size_t n) {
269             if (ec == error::operation_aborted) {
270                 return;
271             }
272             if (ec) {
273                 on_complete(ec);
274                 return;
275             }
276             if (n <= 2) {
277                 read_body();
278                 return;
279             }
280             parse_header_line(n);
281             // FIXME: Limit the total size of headers. Apache uses 8K.
282             read_headers();
283         };
284         m_socket.async_read_until(m_read_buffer.get(), max_header_line_length, '\n',
285                                   std::move(handler));
286     }
287
288     void read_body()
289     {
290         if (m_found_content_length) {
291             // FIXME: Support longer bodies.
292             // FIXME: Support multipart and other body types (no body shaming).
293             if (*m_found_content_length > read_buffer_size) {
294                 on_complete(HTTPParserError::ContentTooLong);
295                 return;
296             }
297
298             auto handler = [this](std::error_code ec, size_t n) {
299                 if (ec == error::operation_aborted) {
300                     return;
301                 }
302                 if (!ec) {
303                     on_body(StringData(m_read_buffer.get(), n));
304                 }
305                 on_complete(ec);
306             };
307             m_socket.async_read(m_read_buffer.get(), *m_found_content_length,
308                                 std::move(handler));
309         }
310         else {
311             // No body, just finish.
312             on_complete();
313         }
314     }
315
316     void write_buffer(std::function<void(std::error_code, size_t)> handler)
317     {
318         m_socket.async_write(m_write_buffer.data(), m_write_buffer.size(),
319                              std::move(handler));
320     }
321
322     Socket& m_socket;
323 };
324
325 template<class Socket>
326 struct HTTPClient: protected HTTPParser<Socket> {
327     using Handler = void(HTTPResponse, std::error_code);
328
329     explicit HTTPClient(Socket& socket) : HTTPParser<Socket>(socket) {}
330
331     /// Serialize and send \a request over the connected socket asynchronously.
332     ///
333     /// When the response has been received, or an error occurs, \a handler will
334     /// be invoked with the appropriate parameters. The HTTPResponse object
335     /// passed to \a handler will only be complete in non-error conditions, but
336     /// may be partially populated.
337     ///
338     /// It is an error to start a request before the \a handler of a previous
339     /// request has been invoked. It is permitted to call async_request() from
340     /// the handler, unless an error has been reported representing a condition
341     /// where the underlying socket is no longer able to communicate (for
342     /// example, if it has been closed).
343     ///
344     /// If a request is already in progress, an exception will be thrown.
345     ///
346     /// This method is *NOT* thread-safe.
347     void async_request(const HTTPRequest& request, std::function<Handler> handler)
348     {
349         if (REALM_UNLIKELY(m_handler)) {
350             throw std::runtime_error("Request already in progress.");
351         }
352         this->set_write_buffer(request);
353         m_handler = std::move(handler);
354         this->write_buffer([this](std::error_code ec, size_t bytes_written) {
355             static_cast<void>(bytes_written);
356             if (ec == error::operation_aborted) {
357                 return;
358             }
359             if (ec) {
360                 this->on_complete(ec);
361                 return;
362             }
363             this->read_first_line();
364         });
365     }
366
367 private:
368     std::function<Handler> m_handler;
369     HTTPResponse m_response;
370
371     std::error_code on_first_line(StringData line) override final
372     {
373         HTTPStatus status;
374         StringData reason;
375         if (this->parse_first_line_of_response(line, status, reason)) {
376             m_response.status = status;
377             static_cast<void>(reason); // Ignore for now.
378             return std::error_code{};
379         }
380         return HTTPParserError::MalformedResponse;
381     }
382
383     void on_header(StringData key, StringData value) override final
384     {
385         // FIXME: Multiple headers with the same key should show up as a
386         // comma-separated list of their values, rather than overwriting.
387         m_response.headers[std::string(key)] = std::string(value);
388     }
389
390     void on_body(StringData body) override final
391     {
392         m_response.body = std::string(body);
393     }
394
395     void on_complete(std::error_code ec) override final
396     {
397         auto handler = std::move(m_handler); // Nullifies m_handler
398         handler(std::move(m_response), ec);
399     }
400 };
401
402 template<class Socket>
403 struct HTTPServer: protected HTTPParser<Socket> {
404     using RequestHandler = void(HTTPRequest, std::error_code);
405     using RespondHandler = void(std::error_code);
406
407     explicit HTTPServer(Socket& socket): HTTPParser<Socket>(socket)
408     {}
409
410     /// Receive a request on the underlying socket asynchronously.
411     ///
412     /// This function starts an asynchronous read operation and keeps reading
413     /// until an HTTP request has been received. \a handler is invoked when a
414     /// request has been received, or an error occurs.
415     ///
416     /// After a request is received, callers MUST invoke async_send_response()
417     /// to provide the client with a valid HTTP response, unless the error
418     /// passed to the handler represents a condition where the underlying socket
419     /// is no longer able to communicate (for example, if it has been closed).
420     ///
421     /// It is an error to attempt to receive a request before any previous
422     /// requests have been fully responded to, i.e. the \a handler argument of
423     /// async_send_response() must have been invoked before attempting to
424     /// receive the next request.
425     ///
426     /// This function is *NOT* thread-safe.
427     void async_receive_request(std::function<RequestHandler> handler)
428     {
429         if (REALM_UNLIKELY(m_request_handler)) {
430             throw std::runtime_error("Response already in progress.");
431         }
432         m_request_handler = std::move(handler);
433         this->read_first_line();
434     }
435
436     /// Send an HTTP response to a client asynchronously.
437     ///
438     /// This function starts an asynchronous write operation on the underlying
439     /// socket. \a handler is invoked when the response has been written to the
440     /// socket, or an error occurs.
441     ///
442     /// It is an error to call async_receive_request() again before \a handler
443     /// has been invoked, and it is an error to call async_send_response()
444     /// before the \a handler of a previous invocation has been invoked.
445     ///
446     /// This function is *NOT* thread-safe.
447     void async_send_response(const HTTPResponse& response,
448                              std::function<RespondHandler> handler)
449     {
450         if (REALM_UNLIKELY(!m_request_handler)) {
451             throw std::runtime_error("No request in progress.");
452         }
453         if (m_respond_handler) {
454             // FIXME: Proper exception type.
455             throw std::runtime_error("Already responding to request");
456         }
457         m_respond_handler = std::move(handler);
458         this->set_write_buffer(response);
459         this->write_buffer([this](std::error_code ec, size_t) {
460             if (ec == error::operation_aborted) {
461                 return;
462             }
463             m_request_handler = nullptr;
464             auto handler = std::move(m_respond_handler);
465             handler(ec);
466         });;
467     }
468
469 private:
470     std::function<RequestHandler> m_request_handler;
471     std::function<RespondHandler> m_respond_handler;
472     HTTPRequest m_request;
473
474     std::error_code on_first_line(StringData line) override final
475     {
476         HTTPMethod method;
477         StringData uri;
478         if (this->parse_first_line_of_request(line, method, uri)) {
479             m_request.method = method;
480             m_request.path = uri;
481             return std::error_code{};
482         }
483         return HTTPParserError::MalformedRequest;
484     }
485
486     void on_header(StringData key, StringData value) override final
487     {
488         // FIXME: Multiple headers with the same key should show up as a
489         // comma-separated list of their values, rather than overwriting.
490         m_request.headers[std::string(key)] = std::string(value);
491     }
492
493     void on_body(StringData body) override final
494     {
495         m_request.body = std::string(body);
496     }
497
498     void on_complete(std::error_code ec) override final
499     {
500         // Deliberately not nullifying m_request_handler so that we can
501         // check for invariants in async_send_response.
502         m_request_handler(std::move(m_request), ec);
503     }
504 };
505
506 } // namespace util
507 } // namespace realm
508
509
510 #endif // REALM_UTIL_HTTP_HPP
511