isomorfeus-iodine 0.7.44

Sign up to get free protection for your applications and to get access to all the features.
Files changed (119) hide show
  1. checksums.yaml +7 -0
  2. data/.github/ISSUE_TEMPLATE/bug_report.md +40 -0
  3. data/.gitignore +20 -0
  4. data/.rspec +2 -0
  5. data/.travis.yml +32 -0
  6. data/.yardopts +8 -0
  7. data/CHANGELOG.md +1038 -0
  8. data/Gemfile +11 -0
  9. data/LICENSE.txt +21 -0
  10. data/LIMITS.md +41 -0
  11. data/README.md +782 -0
  12. data/Rakefile +44 -0
  13. data/SPEC-PubSub-Draft.md +159 -0
  14. data/SPEC-WebSocket-Draft.md +239 -0
  15. data/bin/console +22 -0
  16. data/bin/info.md +353 -0
  17. data/bin/mustache_bench.rb +100 -0
  18. data/bin/poc/Gemfile.lock +23 -0
  19. data/bin/poc/README.md +37 -0
  20. data/bin/poc/config.ru +66 -0
  21. data/bin/poc/gemfile +1 -0
  22. data/bin/poc/www/index.html +57 -0
  23. data/examples/async_task.ru +92 -0
  24. data/examples/config.ru +56 -0
  25. data/examples/echo.ru +59 -0
  26. data/examples/hello.ru +29 -0
  27. data/examples/pubsub_engine.ru +81 -0
  28. data/examples/redis.ru +70 -0
  29. data/examples/shootout.ru +73 -0
  30. data/examples/sub-protocols.ru +90 -0
  31. data/examples/tcp_client.rb +66 -0
  32. data/examples/x-sendfile.ru +14 -0
  33. data/exe/iodine +277 -0
  34. data/ext/iodine/extconf.rb +109 -0
  35. data/ext/iodine/fio.c +11985 -0
  36. data/ext/iodine/fio.h +6373 -0
  37. data/ext/iodine/fio_cli.c +431 -0
  38. data/ext/iodine/fio_cli.h +189 -0
  39. data/ext/iodine/fio_json_parser.h +687 -0
  40. data/ext/iodine/fio_siphash.c +157 -0
  41. data/ext/iodine/fio_siphash.h +37 -0
  42. data/ext/iodine/fio_tls.h +129 -0
  43. data/ext/iodine/fio_tls_missing.c +649 -0
  44. data/ext/iodine/fio_tls_openssl.c +1056 -0
  45. data/ext/iodine/fio_tmpfile.h +50 -0
  46. data/ext/iodine/fiobj.h +44 -0
  47. data/ext/iodine/fiobj4fio.h +21 -0
  48. data/ext/iodine/fiobj_ary.c +333 -0
  49. data/ext/iodine/fiobj_ary.h +139 -0
  50. data/ext/iodine/fiobj_data.c +1185 -0
  51. data/ext/iodine/fiobj_data.h +167 -0
  52. data/ext/iodine/fiobj_hash.c +409 -0
  53. data/ext/iodine/fiobj_hash.h +176 -0
  54. data/ext/iodine/fiobj_json.c +622 -0
  55. data/ext/iodine/fiobj_json.h +68 -0
  56. data/ext/iodine/fiobj_mem.h +71 -0
  57. data/ext/iodine/fiobj_mustache.c +317 -0
  58. data/ext/iodine/fiobj_mustache.h +62 -0
  59. data/ext/iodine/fiobj_numbers.c +344 -0
  60. data/ext/iodine/fiobj_numbers.h +127 -0
  61. data/ext/iodine/fiobj_str.c +433 -0
  62. data/ext/iodine/fiobj_str.h +172 -0
  63. data/ext/iodine/fiobject.c +620 -0
  64. data/ext/iodine/fiobject.h +654 -0
  65. data/ext/iodine/hpack.h +1923 -0
  66. data/ext/iodine/http.c +2754 -0
  67. data/ext/iodine/http.h +1002 -0
  68. data/ext/iodine/http1.c +912 -0
  69. data/ext/iodine/http1.h +29 -0
  70. data/ext/iodine/http1_parser.h +873 -0
  71. data/ext/iodine/http_internal.c +1278 -0
  72. data/ext/iodine/http_internal.h +237 -0
  73. data/ext/iodine/http_mime_parser.h +350 -0
  74. data/ext/iodine/iodine.c +1430 -0
  75. data/ext/iodine/iodine.h +63 -0
  76. data/ext/iodine/iodine_caller.c +218 -0
  77. data/ext/iodine/iodine_caller.h +27 -0
  78. data/ext/iodine/iodine_connection.c +933 -0
  79. data/ext/iodine/iodine_connection.h +55 -0
  80. data/ext/iodine/iodine_defer.c +420 -0
  81. data/ext/iodine/iodine_defer.h +6 -0
  82. data/ext/iodine/iodine_fiobj2rb.h +120 -0
  83. data/ext/iodine/iodine_helpers.c +282 -0
  84. data/ext/iodine/iodine_helpers.h +12 -0
  85. data/ext/iodine/iodine_http.c +1171 -0
  86. data/ext/iodine/iodine_http.h +23 -0
  87. data/ext/iodine/iodine_json.c +302 -0
  88. data/ext/iodine/iodine_json.h +6 -0
  89. data/ext/iodine/iodine_mustache.c +567 -0
  90. data/ext/iodine/iodine_mustache.h +6 -0
  91. data/ext/iodine/iodine_pubsub.c +580 -0
  92. data/ext/iodine/iodine_pubsub.h +26 -0
  93. data/ext/iodine/iodine_rack_io.c +281 -0
  94. data/ext/iodine/iodine_rack_io.h +20 -0
  95. data/ext/iodine/iodine_store.c +142 -0
  96. data/ext/iodine/iodine_store.h +20 -0
  97. data/ext/iodine/iodine_tcp.c +346 -0
  98. data/ext/iodine/iodine_tcp.h +13 -0
  99. data/ext/iodine/iodine_tls.c +261 -0
  100. data/ext/iodine/iodine_tls.h +13 -0
  101. data/ext/iodine/mustache_parser.h +1546 -0
  102. data/ext/iodine/redis_engine.c +957 -0
  103. data/ext/iodine/redis_engine.h +79 -0
  104. data/ext/iodine/resp_parser.h +317 -0
  105. data/ext/iodine/websocket_parser.h +505 -0
  106. data/ext/iodine/websockets.c +735 -0
  107. data/ext/iodine/websockets.h +185 -0
  108. data/isomorfeus-iodine.gemspec +42 -0
  109. data/lib/iodine/connection.rb +61 -0
  110. data/lib/iodine/json.rb +42 -0
  111. data/lib/iodine/mustache.rb +113 -0
  112. data/lib/iodine/pubsub.rb +55 -0
  113. data/lib/iodine/rack_utils.rb +43 -0
  114. data/lib/iodine/tls.rb +16 -0
  115. data/lib/iodine/version.rb +3 -0
  116. data/lib/iodine.rb +274 -0
  117. data/lib/rack/handler/iodine.rb +33 -0
  118. data/logo.png +0 -0
  119. metadata +271 -0
data/ext/iodine/http.h ADDED
@@ -0,0 +1,1002 @@
1
+ #ifndef H_HTTP_H
2
+ /*
3
+ Copyright: Boaz Segev, 2016-2019
4
+ License: MIT
5
+
6
+ Feel free to copy, use and enjoy according to the license provided.
7
+ */
8
+ #define H_HTTP_H
9
+
10
+ #include <fio.h>
11
+
12
+ #include <fiobj.h>
13
+
14
+ #include <time.h>
15
+
16
+ /* support C++ */
17
+ #ifdef __cplusplus
18
+ extern "C" {
19
+ #endif
20
+
21
+ /* *****************************************************************************
22
+ Compile Time Settings
23
+ ***************************************************************************** */
24
+
25
+ /** When a new connection is accepted, it will be immediately declined with a
26
+ * 503 service unavailable (server busy) response unless the following number of
27
+ * file descriptors is available.*/
28
+ #ifndef HTTP_BUSY_UNLESS_HAS_FDS
29
+ #define HTTP_BUSY_UNLESS_HAS_FDS 64
30
+ #endif
31
+
32
+ #ifndef HTTP_DEFAULT_BODY_LIMIT
33
+ #define HTTP_DEFAULT_BODY_LIMIT (1024 * 1024 * 50)
34
+ #endif
35
+
36
+ #ifndef HTTP_MAX_HEADER_COUNT
37
+ #define HTTP_MAX_HEADER_COUNT 128
38
+ #endif
39
+
40
+ #ifndef HTTP_MAX_HEADER_LENGTH
41
+ /** the default maximum length for a single header line */
42
+ #define HTTP_MAX_HEADER_LENGTH 8192
43
+ #endif
44
+
45
+ #ifndef FIO_HTTP_EXACT_LOGGING
46
+ /**
47
+ * By default, facil.io logs the HTTP request cycle using a fuzzy starting point
48
+ * (a close enough timestamp).
49
+ *
50
+ * The fuzzy timestamp includes delays that aren't related to the HTTP request,
51
+ * sometimes including time that was spent waiting on the client. On the other
52
+ * hand, `FIO_HTTP_EXACT_LOGGING` excludes time that the client might have been
53
+ * waiting for facil.io to read data from the network.
54
+ *
55
+ * Due to the preference to err on the side of causion, fuzzy time-stamping is
56
+ * the default.
57
+ */
58
+ #define FIO_HTTP_EXACT_LOGGING 0
59
+ #endif
60
+
61
+ /** the `http_listen settings, see details in the struct definition. */
62
+ typedef struct http_settings_s http_settings_s;
63
+
64
+ /* *****************************************************************************
65
+ The Request / Response type and functions
66
+ ***************************************************************************** */
67
+
68
+ /**
69
+ * A generic HTTP handle used for HTTP request/response data.
70
+ *
71
+ * The `http_s` data can only be accessed safely from within the `on_request`
72
+ * HTTP callback OR an `http_defer` callback.
73
+ */
74
+ typedef struct {
75
+ /** the HTTP request's "head" starts with a private data used by facil.io */
76
+ struct {
77
+ /** the function touting table - used by facil.io, don't use directly! */
78
+ void *vtbl;
79
+ /** the connection's owner / uuid - used by facil.io, don't use directly! */
80
+ uintptr_t flag;
81
+ /** The response headers, if they weren't sent. Don't access directly. */
82
+ FIOBJ out_headers;
83
+ } private_data;
84
+ /** a time merker indicating when the request was received. */
85
+ struct timespec received_at;
86
+ /** a String containing the method data (supports non-standard methods. */
87
+ FIOBJ method;
88
+ /** The status string, for response objects (client mode response). */
89
+ FIOBJ status_str;
90
+ /** The HTTP version string, if any. */
91
+ FIOBJ version;
92
+ /** The status used for the response (or if the object is a response).
93
+ *
94
+ * When sending a request, the status should be set to 0.
95
+ */
96
+ uintptr_t status;
97
+ /** The request path, if any. */
98
+ FIOBJ path;
99
+ /** The request query, if any. */
100
+ FIOBJ query;
101
+ /** a hash of general header data. When a header is set multiple times (such
102
+ * as cookie headers), an Array will be used instead of a String. */
103
+ FIOBJ headers;
104
+ /**
105
+ * a placeholder for a hash of cookie data.
106
+ * the hash will be initialized when parsing the request.
107
+ */
108
+ FIOBJ cookies;
109
+ /**
110
+ * a placeholder for a hash of request data.
111
+ * the hash will be initialized when parsing the request.
112
+ */
113
+ FIOBJ params;
114
+ /**
115
+ * a reader for body data (might be a temporary file or a string or NULL).
116
+ * see fiobj_data.h for details.
117
+ */
118
+ FIOBJ body;
119
+ /** an opaque user data pointer, to be used BEFORE calling `http_defer`. */
120
+ void *udata;
121
+ } http_s;
122
+
123
+ /**
124
+ * This is a helper for setting cookie data.
125
+
126
+ This struct is used together with the `http_response_set_cookie`. i.e.:
127
+
128
+ http_response_set_cookie(response,
129
+ .name = "my_cookie",
130
+ .value = "data" );
131
+
132
+ */
133
+ typedef struct {
134
+ /** The cookie's name (Symbol). */
135
+ const char *name;
136
+ /** The cookie's value (leave blank to delete cookie). */
137
+ const char *value;
138
+ /** The cookie's domain (optional). */
139
+ const char *domain;
140
+ /** The cookie's path (optional). */
141
+ const char *path;
142
+ /** The cookie name's size in bytes or a terminating NUL will be assumed.*/
143
+ size_t name_len;
144
+ /** The cookie value's size in bytes or a terminating NUL will be assumed.*/
145
+ size_t value_len;
146
+ /** The cookie domain's size in bytes or a terminating NUL will be assumed.*/
147
+ size_t domain_len;
148
+ /** The cookie path's size in bytes or a terminating NULL will be assumed.*/
149
+ size_t path_len;
150
+ /** Max Age (how long should the cookie persist), in seconds (0 == session).*/
151
+ int max_age;
152
+ /** Limit cookie to secure connections.*/
153
+ unsigned secure : 1;
154
+ /** Limit cookie to HTTP (intended to prevent javascript access/hijacking).*/
155
+ unsigned http_only : 1;
156
+ } http_cookie_args_s;
157
+
158
+ /**
159
+ * Sets a response header, taking ownership of the value object, but NOT the
160
+ * name object (so name objects could be reused in future responses).
161
+ *
162
+ * Returns -1 on error and 0 on success.
163
+ */
164
+ int http_set_header(http_s *h, FIOBJ name, FIOBJ value);
165
+
166
+ /**
167
+ * Sets a response header.
168
+ *
169
+ * Returns -1 on error and 0 on success.
170
+ */
171
+ int http_set_header2(http_s *h, fio_str_info_s name, fio_str_info_s value);
172
+
173
+ /**
174
+ * Sets a response cookie.
175
+ *
176
+ * Returns -1 on error and 0 on success.
177
+ *
178
+ * Note: Long cookie names and long cookie values will be considered a security
179
+ * violation and an error will be returned. It should be noted that most
180
+ * proxies and servers will refuse long cookie names or values and many impose
181
+ * total header lengths (including cookies) of ~8Kib.
182
+ */
183
+ int http_set_cookie(http_s *h, http_cookie_args_s);
184
+ #define http_set_cookie(http___handle, ...) \
185
+ http_set_cookie((http___handle), (http_cookie_args_s){__VA_ARGS__})
186
+
187
+ /**
188
+ * Sends the response headers and body.
189
+ *
190
+ * **Note**: The body is *copied* to the HTTP stream and it's memory should be
191
+ * freed by the calling function.
192
+ *
193
+ * Returns -1 on error and 0 on success.
194
+ *
195
+ * AFTER THIS FUNCTION IS CALLED, THE `http_s` OBJECT IS NO LONGER VALID.
196
+ */
197
+ int http_send_body(http_s *h, void *data, uintptr_t length);
198
+
199
+ /**
200
+ * Sends the response headers and the specified file (the response's body).
201
+ *
202
+ * The file is closed automatically.
203
+ *
204
+ * Returns -1 on error and 0 on success.
205
+ *
206
+ * AFTER THIS FUNCTION IS CALLED, THE `http_s` OBJECT IS NO LONGER VALID.
207
+ */
208
+ int http_sendfile(http_s *h, int fd, uintptr_t length, uintptr_t offset);
209
+
210
+ /**
211
+ * Sends the response headers and the specified file (the response's body).
212
+ *
213
+ * The `local` and `encoded` strings will be joined into a single string that
214
+ * represent the file name. Either or both of these strings can be empty.
215
+ *
216
+ * The `encoded` string will be URL decoded while the `local` string will used
217
+ * as is.
218
+ *
219
+ * Returns 0 on success. A success value WILL CONSUME the `http_s` handle (it
220
+ * will become invalid).
221
+ *
222
+ * Returns -1 on error (The `http_s` handle should still be used).
223
+ */
224
+ int http_sendfile2(http_s *h, const char *prefix, size_t prefix_len,
225
+ const char *encoded, size_t encoded_len);
226
+
227
+ /**
228
+ * Sends an HTTP error response.
229
+ *
230
+ * Returns -1 on error and 0 on success.
231
+ *
232
+ * AFTER THIS FUNCTION IS CALLED, THE `http_s` OBJECT IS NO LONGER VALID.
233
+ *
234
+ * The `uuid` and `settings` arguments are only required if the `http_s` handle
235
+ * is NULL.
236
+ */
237
+ int http_send_error(http_s *h, size_t error_code);
238
+
239
+ /**
240
+ * Sends the response headers for a header only response.
241
+ *
242
+ * AFTER THIS FUNCTION IS CALLED, THE `http_s` OBJECT IS NO LONGER VALID.
243
+ */
244
+ void http_finish(http_s *h);
245
+
246
+ /**
247
+ * Pushes a data response when supported (HTTP/2 only).
248
+ *
249
+ * Returns -1 on error and 0 on success.
250
+ */
251
+ int http_push_data(http_s *h, void *data, uintptr_t length, FIOBJ mime_type);
252
+
253
+ /**
254
+ * Pushes a file response when supported (HTTP/2 only).
255
+ *
256
+ * If `mime_type` is NULL, an attempt at automatic detection using `filename`
257
+ * will be made.
258
+ *
259
+ * Returns -1 on error and 0 on success.
260
+ */
261
+ int http_push_file(http_s *h, FIOBJ filename, FIOBJ mime_type);
262
+
263
+ /* *****************************************************************************
264
+ HTTP evented API (pause / resume HTTp handling)
265
+ ***************************************************************************** */
266
+
267
+ typedef struct http_pause_handle_s http_pause_handle_s;
268
+ /**
269
+ * Pauses the request / response handling and INVALIDATES the current `http_s`
270
+ * handle (no `http` functions can be called).
271
+ *
272
+ * The `http_resume` function MUST be called (at some point) using the opaque
273
+ * `http` pointer given to the callback `task`.
274
+ *
275
+ * The opaque `http` pointer is only valid for a single call to `http_resume`
276
+ * and can't be used by any other `http` function (it's a different data type).
277
+ *
278
+ * Note: the current `http_s` handle will become invalid once this function is
279
+ * called and it's data might be deallocated, invalid or used by a different
280
+ * thread.
281
+ */
282
+ void http_pause(http_s *h, void (*task)(http_pause_handle_s *http));
283
+
284
+ /**
285
+ * Resumes a request / response handling within a task and INVALIDATES the
286
+ * current `http_s` handle.
287
+ *
288
+ * The `task` MUST call one of the `http_send_*`, `http_finish`, or
289
+ * `http_pause`functions.
290
+ *
291
+ * The (optional) `fallback` will receive the opaque `udata` that was stored in
292
+ * the HTTP handle and can be used for cleanup.
293
+ *
294
+ * Note: `http_resume` can only be called after calling `http_pause` and
295
+ * entering it's task.
296
+ *
297
+ * Note: the current `http_s` handle will become invalid once this function is
298
+ * called and it's data might be deallocated, invalidated or used by a
299
+ * different thread.
300
+ */
301
+ void http_resume(http_pause_handle_s *http, void (*task)(http_s *h),
302
+ void (*fallback)(void *udata));
303
+
304
+ /** Returns the `udata` associated with the paused opaque handle */
305
+ void *http_paused_udata_get(http_pause_handle_s *http);
306
+
307
+ /**
308
+ * Sets the `udata` associated with the paused opaque handle, returning the
309
+ * old value.
310
+ */
311
+ void *http_paused_udata_set(http_pause_handle_s *http, void *udata);
312
+
313
+ /* *****************************************************************************
314
+ HTTP Connections - Listening / Connecting / Hijacking
315
+ ***************************************************************************** */
316
+
317
+ /** The HTTP settings. */
318
+ struct http_settings_s {
319
+ /** Callback for normal HTTP requests. */
320
+ void (*on_request)(http_s *request);
321
+ /**
322
+ * Callback for Upgrade and EventSource (SSE) requests.
323
+ *
324
+ * SSE/EventSource requests set the `requested_protocol` string to `"sse"`.
325
+ */
326
+ void (*on_upgrade)(http_s *request, char *requested_protocol, size_t len);
327
+ /** CLIENT REQUIRED: a callback for the HTTP response. */
328
+ void (*on_response)(http_s *response);
329
+ /** (optional) the callback to be performed when the HTTP service closes. */
330
+ void (*on_finish)(struct http_settings_s *settings);
331
+ /** Opaque user data. Facil.io will ignore this field, but you can use it. */
332
+ void *udata;
333
+ /**
334
+ * A public folder for file transfers - allows to circumvent any application
335
+ * layer logic and simply serve static files.
336
+ *
337
+ * Supports automatic `gz` pre-compressed alternatives.
338
+ */
339
+ const char *public_folder;
340
+ /**
341
+ * The length of the public_folder string.
342
+ */
343
+ size_t public_folder_length;
344
+ /**
345
+ * The maximum number of bytes allowed for the request string (method, path,
346
+ * query), header names and fields.
347
+ *
348
+ * Defaults to 32Kib (which is about 4 times more than I would recommend).
349
+ *
350
+ * This reflects the total overall size. On HTTP/1.1, each header line (name +
351
+ * value pair) is also limitied to a hardcoded HTTP_MAX_HEADER_LENGTH bytes.
352
+ */
353
+ size_t max_header_size;
354
+ /**
355
+ * The maximum size of an HTTP request's body (posting / downloading).
356
+ *
357
+ * Defaults to ~ 50Mb.
358
+ */
359
+ size_t max_body_size;
360
+ /**
361
+ * The maximum number of clients that are allowed to connect concurrently.
362
+ *
363
+ * This value's default setting is usually for the best.
364
+ *
365
+ * The default value is computed according to the server's capacity, leaving
366
+ * some breathing room for other network and disk operations.
367
+ *
368
+ * Note: clients, by the nature of socket programming, are counted according
369
+ * to their internal file descriptor (`fd`) value. Open files and other
370
+ * sockets count towards a server's limit.
371
+ */
372
+ intptr_t max_clients;
373
+ /** SSL/TLS support. */
374
+ void *tls;
375
+ /** reserved for future use. */
376
+ intptr_t reserved1;
377
+ /** reserved for future use. */
378
+ intptr_t reserved2;
379
+ /** reserved for future use. */
380
+ intptr_t reserved3;
381
+ /**
382
+ * The maximum websocket message size/buffer (in bytes) for Websocket
383
+ * connections. Defaults to ~250KB.
384
+ */
385
+ size_t ws_max_msg_size;
386
+ /**
387
+ * An HTTP/1.x connection timeout.
388
+ *
389
+ * `http_listen` defaults to ~40s and `http_connect` defaults to ~30s.
390
+ *
391
+ * Note: the connection might be closed (by other side) before timeout occurs.
392
+ */
393
+ uint8_t timeout;
394
+ /**
395
+ * Timeout for the websocket connections, a ping will be sent whenever the
396
+ * timeout is reached. Defaults to 40 seconds.
397
+ *
398
+ * Connections are only closed when a ping cannot be sent (the network layer
399
+ * fails). Pongs are ignored.
400
+ */
401
+ uint8_t ws_timeout;
402
+ /** Logging flag - set to TRUE to log HTTP requests. */
403
+ uint8_t log;
404
+ /** a read only flag set automatically to indicate the protocol's mode. */
405
+ uint8_t is_client;
406
+ };
407
+
408
+ /**
409
+ * Listens to HTTP connections at the specified `port`.
410
+ *
411
+ * Leave as NULL to ignore IP binding.
412
+ *
413
+ * Returns -1 on error and the socket's uuid on success.
414
+ *
415
+ * the `on_finish` callback is always called.
416
+ */
417
+ intptr_t http_listen(const char *port, const char *binding,
418
+ struct http_settings_s);
419
+ /** Listens to HTTP connections at the specified `port` and `binding`. */
420
+ #define http_listen(port, binding, ...) \
421
+ http_listen((port), (binding), (struct http_settings_s){__VA_ARGS__})
422
+
423
+ /**
424
+ * Connects to an HTTP server as a client.
425
+ *
426
+ * Upon a successful connection, the `on_response` callback is called with an
427
+ * empty `http_s*` handler (status == 0). Use the same API to set it's content
428
+ * and send the request to the server. The next`on_response` will contain the
429
+ * response.
430
+ *
431
+ * `address` should contain a full URL style address for the server. i.e.:
432
+ *
433
+ * "http:/www.example.com:8080/"
434
+ *
435
+ * If an `address` includes a path or query data, they will be automatically
436
+ * attached (both of them) to the HTTP handl'es `path` property. i.e.
437
+ *
438
+ * "http:/www.example.com:8080/my_path?foo=bar"
439
+ * // will result in:
440
+ * fiobj_obj2cstr(h->path).data; //=> "/my_path?foo=bar"
441
+ *
442
+ * To open a Websocket connection, it's possible to use the `ws` protocol
443
+ * signature. However, it would be better to use the `websocket_connect`
444
+ * function instead.
445
+ *
446
+ * Returns -1 on error and the socket's uuid on success.
447
+ *
448
+ * The `on_finish` callback is always called.
449
+ */
450
+ intptr_t http_connect(const char *url, const char *unix_address,
451
+ struct http_settings_s);
452
+ #define http_connect(url, unix_address, ...) \
453
+ http_connect((url), (unix_address), (struct http_settings_s){__VA_ARGS__})
454
+
455
+ /**
456
+ * Returns the settings used to setup the connection or NULL on error.
457
+ */
458
+ struct http_settings_s *http_settings(http_s *h);
459
+
460
+ /**
461
+ * Returns the direct address of the connected peer (likely an intermediary).
462
+ */
463
+ fio_str_info_s http_peer_addr(http_s *h);
464
+
465
+ /**
466
+ * Hijacks the socket away from the HTTP protocol and away from facil.io.
467
+ *
468
+ * It's possible to hijack the socket and than reconnect it to a new protocol
469
+ * object.
470
+ *
471
+ * It's possible to call `http_finish` immediately after calling `http_hijack`
472
+ * in order to send the outgoing headers.
473
+ *
474
+ * If any additional HTTP functions are called after the hijacking, the protocol
475
+ * object might attempt to continue reading data from the buffer.
476
+ *
477
+ * Returns the underlining socket connection's uuid. If `leftover` isn't NULL,
478
+ * it will be populated with any remaining data in the HTTP buffer (the data
479
+ * will be automatically deallocated, so copy the data when in need).
480
+ *
481
+ * WARNING: this isn't a good way to handle HTTP connections, especially as
482
+ * HTTP/2 enters the picture.
483
+ */
484
+ intptr_t http_hijack(http_s *h, fio_str_info_s *leftover);
485
+
486
+ /* *****************************************************************************
487
+ Websocket Upgrade (Server and Client connection establishment)
488
+ ***************************************************************************** */
489
+
490
+ /**
491
+ * The type for a Websocket handle, used to identify a Websocket connection.
492
+ *
493
+ * Similar to an `http_s` handle, it is only valid within the scope of the
494
+ * specific connection (the callbacks / tasks) and shouldn't be stored or
495
+ * accessed otherwise.
496
+ */
497
+ typedef struct ws_s ws_s;
498
+
499
+ /**
500
+ * This struct is used for the named arguments in the `http_upgrade2ws`
501
+ * function and macro.
502
+ */
503
+ typedef struct {
504
+ /**
505
+ * The (optional) on_message callback will be called whenever a websocket
506
+ * message is received for this connection.
507
+ *
508
+ * The data received points to the websocket's message buffer and it will be
509
+ * overwritten once the function exits (it cannot be saved for later, but it
510
+ * can be copied).
511
+ */
512
+ void (*on_message)(ws_s *ws, fio_str_info_s msg, uint8_t is_text);
513
+ /**
514
+ * The (optional) on_open callback will be called once the websocket
515
+ * connection is established and before is is registered with `facil`, so no
516
+ * `on_message` events are raised before `on_open` returns.
517
+ */
518
+ void (*on_open)(ws_s *ws);
519
+ /**
520
+ * The (optional) on_ready callback will be after a the underlying socket's
521
+ * buffer changes it's state from full to empty.
522
+ *
523
+ * If the socket's buffer is never used, the callback is never called.
524
+ */
525
+ void (*on_ready)(ws_s *ws);
526
+ /**
527
+ * The (optional) on_shutdown callback will be called if a websocket
528
+ * connection is still open while the server is shutting down (called before
529
+ * `on_close`).
530
+ */
531
+ void (*on_shutdown)(ws_s *ws);
532
+ /**
533
+ * The (optional) on_close callback will be called once a websocket connection
534
+ * is terminated or failed to be established.
535
+ *
536
+ * The `uuid` is the connection's unique ID that can identify the Websocket. A
537
+ * value of `uuid == 0` indicates the Websocket connection wasn't established
538
+ * (an error occurred).
539
+ *
540
+ * The `udata` is the user data as set during the upgrade or using the
541
+ * `websocket_udata_set` function.
542
+ */
543
+ void (*on_close)(intptr_t uuid, void *udata);
544
+ /** Opaque user data. */
545
+ void *udata;
546
+ } websocket_settings_s;
547
+
548
+ /**
549
+ * Upgrades an HTTP/1.1 connection to a Websocket connection.
550
+ *
551
+ * This function will end the HTTP stage of the connection and attempt to
552
+ * "upgrade" to a Websockets connection.
553
+ *
554
+ * Thie `http_s` handle will be invalid after this call and the `udata` will be
555
+ * set to the new Websocket `udata`.
556
+ *
557
+ * A client connection's `on_finish` callback will be called (since the HTTP
558
+ * stage has finished).
559
+ */
560
+ int http_upgrade2ws(http_s *http, websocket_settings_s);
561
+
562
+ /** This macro allows easy access to the `http_upgrade2ws` function. The macro
563
+ * allows the use of named arguments, using the `websocket_settings_s` struct
564
+ * members. i.e.:
565
+ *
566
+ * on_message(ws_s * ws, char * data, size_t size, int is_text) {
567
+ * ; // ... this is the websocket on_message callback
568
+ * websocket_write(ws, data, size, is_text); // a simple echo example
569
+ * }
570
+ *
571
+ * on_upgrade(http_s* h) {
572
+ * http_upgrade2ws( .http = h, .on_message = on_message);
573
+ * }
574
+ */
575
+ #define http_upgrade2ws(http, ...) \
576
+ http_upgrade2ws((http), (websocket_settings_s){__VA_ARGS__})
577
+
578
+ /**
579
+ * Connects to a Websocket service according to the provided address.
580
+ *
581
+ * This is a somewhat naive connector object, it doesn't perform any
582
+ * authentication or other logical handling. However, it's quire easy to author
583
+ * a complext authentication logic using a combination of `http_connect` and
584
+ * `http_upgrade2ws`.
585
+ *
586
+ * Returns the uuid for the future websocket on success.
587
+ *
588
+ * Returns -1 on error;
589
+ */
590
+ int websocket_connect(const char *url, websocket_settings_s settings);
591
+ #define websocket_connect(url, ...) \
592
+ websocket_connect((url), (websocket_settings_s){__VA_ARGS__})
593
+
594
+ #include <websockets.h>
595
+
596
+ /* *****************************************************************************
597
+ EventSource Support (SSE)
598
+ ***************************************************************************** */
599
+
600
+ /**
601
+ * The type for the EventSource (SSE) handle, used to identify an SSE
602
+ * connection.
603
+ */
604
+ typedef struct http_sse_s http_sse_s;
605
+
606
+ /**
607
+ * This struct is used for the named arguments in the `http_upgrade2sse`
608
+ * function and macro.
609
+ */
610
+ struct http_sse_s {
611
+ /**
612
+ * The (optional) on_open callback will be called once the EventSource
613
+ * connection is established.
614
+ */
615
+ void (*on_open)(http_sse_s *sse);
616
+ /**
617
+ * The (optional) on_ready callback will be after a the underlying socket's
618
+ * buffer changes it's state to empty.
619
+ *
620
+ * If the socket's buffer is never used, the callback is never called.
621
+ */
622
+ void (*on_ready)(http_sse_s *sse);
623
+ /**
624
+ * The (optional) on_shutdown callback will be called if a connection is still
625
+ * open while the server is shutting down (called before `on_close`).
626
+ */
627
+ void (*on_shutdown)(http_sse_s *sse);
628
+ /**
629
+ * The (optional) on_close callback will be called once a connection is
630
+ * terminated or failed to be established.
631
+ *
632
+ * The `udata` passed to the `http_upgrade2sse` function is available
633
+ * through the `http_sse_s` pointer (`sse->udata`).
634
+ */
635
+ void (*on_close)(http_sse_s *sse);
636
+ /** Opaque user data. */
637
+ void *udata;
638
+ };
639
+
640
+ /**
641
+ * Upgrades an HTTP connection to an EventSource (SSE) connection.
642
+ *
643
+ * The `http_s` handle will be invalid after this call.
644
+ *
645
+ * On HTTP/1.1 connections, this will preclude future requests using the same
646
+ * connection.
647
+ */
648
+ int http_upgrade2sse(http_s *h, http_sse_s);
649
+
650
+ /** This macro allows easy access to the `http_upgrade2sse` function. The macro
651
+ * allows the use of named arguments, using the `websocket_settings_s` struct
652
+ * members. i.e.:
653
+ *
654
+ * on_open_sse(sse_s * sse) {
655
+ * http_sse_subscribe(sse, .channel = CHANNEL_NAME);
656
+ * }
657
+ *
658
+ * on_upgrade(http_s* h) {
659
+ * http_upgrade2sse(h, .on_open = on_open_sse);
660
+ * }
661
+ */
662
+ #define http_upgrade2sse(h, ...) \
663
+ http_upgrade2sse((h), (http_sse_s){__VA_ARGS__})
664
+
665
+ /**
666
+ * Sets the ping interval for SSE connections.
667
+ */
668
+ void http_sse_set_timout(http_sse_s *sse, uint8_t timeout);
669
+
670
+ struct http_sse_subscribe_args {
671
+ /** The channel name used for the subscription. */
672
+ fio_str_info_s channel;
673
+ /** The optional on message callback. If missing, Data is directly writen. */
674
+ void (*on_message)(http_sse_s *sse, fio_str_info_s channel,
675
+ fio_str_info_s msg, void *udata);
676
+ /** An optional callback for when a subscription is fully canceled. */
677
+ void (*on_unsubscribe)(void *udata);
678
+ /** Opaque user */
679
+ void *udata;
680
+ /** A callback for pattern matching. */
681
+ fio_match_fn match;
682
+ };
683
+
684
+ /**
685
+ * Subscribes to a channel for direct message deliverance. See {struct
686
+ * http_sse_subscribe_args} for possible arguments.
687
+ *
688
+ * Returns a subscription ID on success and 0 on failure.
689
+ *
690
+ * To unsubscripbe from the channel, use `http_sse_unsubscribe` (NOT
691
+ * `fio_unsubscribe`).
692
+ *
693
+ * All subscriptions are automatically cleared once the connection is closed.
694
+ */
695
+ uintptr_t http_sse_subscribe(http_sse_s *sse,
696
+ struct http_sse_subscribe_args args);
697
+
698
+ /** This macro allows easy access to the `http_sse_subscribe` function. */
699
+ #define http_sse_subscribe(sse, ...) \
700
+ http_sse_subscribe((sse), (struct http_sse_subscribe_args){__VA_ARGS__})
701
+
702
+ /**
703
+ * Cancels a subscription and invalidates the subscription object.
704
+ */
705
+ void http_sse_unsubscribe(http_sse_s *sse, uintptr_t subscription);
706
+
707
+ /**
708
+ * Named arguments for the {http_sse_write} function.
709
+ *
710
+ * These arguments list the possible fields for the SSE event.
711
+ *
712
+ * Event fields listed here:
713
+ * https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events
714
+ */
715
+ struct http_sse_write_args {
716
+ fio_str_info_s id; /* (optional) sets the `id` event property. */
717
+ fio_str_info_s event; /* (optional) sets the `event` event property. */
718
+ fio_str_info_s data; /* (optional) sets the `data` event property. */
719
+ intptr_t retry; /* (optional) sets the `retry` event property. */
720
+ };
721
+
722
+ /**
723
+ * Writes data to an EventSource (SSE) connection.
724
+ *
725
+ * See the {struct http_sse_write_args} for possible named arguments.
726
+ */
727
+ int http_sse_write(http_sse_s *sse, struct http_sse_write_args);
728
+ #define http_sse_write(sse, ...) \
729
+ http_sse_write((sse), (struct http_sse_write_args){__VA_ARGS__})
730
+
731
+ /**
732
+ * Get the connection's UUID (for `fio_defer_io_task`, pub/sub, etc').
733
+ */
734
+ intptr_t http_sse2uuid(http_sse_s *sse);
735
+
736
+ /**
737
+ * Closes an EventSource (SSE) connection.
738
+ */
739
+ int http_sse_close(http_sse_s *sse);
740
+
741
+ /**
742
+ * Duplicates an SSE handle by reference, remember to http_sse_free.
743
+ *
744
+ * Returns the same object (increases a reference count, no allocation is made).
745
+ */
746
+ http_sse_s *http_sse_dup(http_sse_s *sse);
747
+
748
+ /**
749
+ * Frees an SSE handle by reference (decreases the reference count).
750
+ */
751
+ void http_sse_free(http_sse_s *sse);
752
+
753
+ /* *****************************************************************************
754
+ HTTP GET and POST parsing helpers
755
+ ***************************************************************************** */
756
+
757
+ /**
758
+ * Attempts to decode the request's body.
759
+ *
760
+ * Supported Types include:
761
+ * * application/x-www-form-urlencoded
762
+ * * application/json
763
+ * * multipart/form-data
764
+ *
765
+ * This should be called before `http_parse_query`, in order to support JSON
766
+ * data.
767
+ *
768
+ * If the JSON data isn't an object, it will be saved under the key "JSON" in
769
+ * the `params` hash.
770
+ *
771
+ * If the `multipart/form-data` type contains JSON files, they will NOT be
772
+ * parsed (they will behave like any other file, with `data`, `type` and
773
+ * `filename` keys assigned). This allows non-object JSON data (such as array)
774
+ * to be handled by the app.
775
+ */
776
+ int http_parse_body(http_s *h);
777
+
778
+ /**
779
+ * Parses the query part of an HTTP request/response. Uses `http_add2hash`.
780
+ *
781
+ * This should be called after the `http_parse_body` function, just in case the
782
+ * body is JSON that doesn't have an object at it's root.
783
+ */
784
+ void http_parse_query(http_s *h);
785
+
786
+ /** Parses any Cookie / Set-Cookie headers, using the `http_add2hash` scheme. */
787
+ void http_parse_cookies(http_s *h, uint8_t is_url_encoded);
788
+
789
+ /**
790
+ * Adds a named parameter to the hash, converting a string to an object and
791
+ * resolving nesting references and URL decoding if required.
792
+ *
793
+ * i.e.:
794
+ *
795
+ * * "name[]" references a nested Array (nested in the Hash).
796
+ * * "name[key]" references a nested Hash.
797
+ * * "name[][key]" references a nested Hash within an array. Hash keys will be
798
+ * unique (repeating a key advances the hash).
799
+ * * These rules can be nested (i.e. "name[][key1][][key2]...")
800
+ * * "name[][]" is an error (there's no way for the parser to analyze
801
+ * dimensions)
802
+ *
803
+ * Note: names can't begin with "[" or end with "]" as these are reserved
804
+ * characters.
805
+ */
806
+ int http_add2hash(FIOBJ dest, char *name, size_t name_len, char *value,
807
+ size_t value_len, uint8_t encoded);
808
+
809
+ /**
810
+ * Adds a named parameter to the hash, using an existing object and resolving
811
+ * nesting references.
812
+ *
813
+ * i.e.:
814
+ *
815
+ * * "name[]" references a nested Array (nested in the Hash).
816
+ * * "name[key]" references a nested Hash.
817
+ * * "name[][key]" references a nested Hash within an array. Hash keys will be
818
+ * unique (repeating a key advances the array).
819
+ * * These rules can be nested (i.e. "name[][key1][][key2]...")
820
+ * * "name[][]" is an error (there's no way for the parser to analyze
821
+ * dimensions)
822
+ *
823
+ * Note: names can't begin with "[" or end with "]" as these are reserved
824
+ * characters.
825
+ */
826
+ int http_add2hash2(FIOBJ dest, char *name, size_t name_len, FIOBJ value,
827
+ uint8_t encoded);
828
+
829
+ /* *****************************************************************************
830
+ HTTP Status Strings and Mime-Type helpers
831
+ ***************************************************************************** */
832
+
833
+ /** Returns a human readable string related to the HTTP status number. */
834
+ fio_str_info_s http_status2str(uintptr_t status);
835
+
836
+ /** Registers a Mime-Type to be associated with the file extension. */
837
+ void http_mimetype_register(char *file_ext, size_t file_ext_len,
838
+ FIOBJ mime_type_str);
839
+
840
+ /**
841
+ * Finds the mime-type associated with the file extension, returning a String on
842
+ * success and FIOBJ_INVALID on failure.
843
+ *
844
+ * Remember to call `fiobj_free`.
845
+ */
846
+ FIOBJ http_mimetype_find(char *file_ext, size_t file_ext_len);
847
+
848
+ /**
849
+ * Returns the mime-type associated with the URL or the default mime-type for
850
+ * HTTP.
851
+ *
852
+ * Remember to call `fiobj_free`.
853
+ */
854
+ FIOBJ http_mimetype_find2(FIOBJ url);
855
+
856
+ /** Clears the Mime-Type registry (it will be empty after this call). */
857
+ void http_mimetype_clear(void);
858
+
859
+ /* *****************************************************************************
860
+ Commonly used headers (fiobj Symbol objects)
861
+ ***************************************************************************** */
862
+
863
+ extern FIOBJ HTTP_HEADER_ACCEPT;
864
+ extern FIOBJ HTTP_HEADER_CACHE_CONTROL;
865
+ extern FIOBJ HTTP_HEADER_CONNECTION;
866
+ extern FIOBJ HTTP_HEADER_CONTENT_ENCODING;
867
+ extern FIOBJ HTTP_HEADER_CONTENT_LENGTH;
868
+ extern FIOBJ HTTP_HEADER_CONTENT_RANGE;
869
+ extern FIOBJ HTTP_HEADER_CONTENT_TYPE;
870
+ extern FIOBJ HTTP_HEADER_COOKIE;
871
+ extern FIOBJ HTTP_HEADER_DATE;
872
+ extern FIOBJ HTTP_HEADER_ETAG;
873
+ extern FIOBJ HTTP_HEADER_HOST;
874
+ extern FIOBJ HTTP_HEADER_LAST_MODIFIED;
875
+ extern FIOBJ HTTP_HEADER_ORIGIN;
876
+ extern FIOBJ HTTP_HEADER_SET_COOKIE;
877
+ extern FIOBJ HTTP_HEADER_UPGRADE;
878
+
879
+ /* *****************************************************************************
880
+ HTTP General Helper functions that could be used globally
881
+ ***************************************************************************** */
882
+
883
+ /**
884
+ * Returns a String object representing the unparsed HTTP request (HTTP version
885
+ * is capped at HTTP/1.1). Mostly usable for proxy usage and debugging.
886
+ */
887
+ FIOBJ http_req2str(http_s *h);
888
+
889
+ /**
890
+ * Writes a log line to `stderr` about the request / response object.
891
+ *
892
+ * This function is called automatically if the `.log` setting is enabled.
893
+ */
894
+ void http_write_log(http_s *h);
895
+ /* *****************************************************************************
896
+ HTTP Time related helper functions that could be used globally
897
+ ***************************************************************************** */
898
+
899
+ /**
900
+ A faster (yet less localized) alternative to `gmtime_r`.
901
+
902
+ See the libc `gmtime_r` documentation for details.
903
+
904
+ Falls back to `gmtime_r` for dates before epoch.
905
+ */
906
+ struct tm *http_gmtime(time_t timer, struct tm *tmbuf);
907
+
908
+ /** Writes an RFC 7231 date representation (HTTP date format) to target. */
909
+ size_t http_date2rfc7231(char *target, struct tm *tmbuf);
910
+ /** Writes an RFC 2109 date representation to target. */
911
+ size_t http_date2rfc2109(char *target, struct tm *tmbuf);
912
+ /** Writes an RFC 2822 date representation to target. */
913
+ size_t http_date2rfc2822(char *target, struct tm *tmbuf);
914
+ /**
915
+ Writes an HTTP date string to the `target` buffer.
916
+
917
+ This requires ~32 bytes of space to be available at the target buffer (unless
918
+ it's a super funky year, 32 bytes is about 3 more than you need).
919
+
920
+ Returns the number of bytes actually written.
921
+ */
922
+ static inline size_t http_date2str(char *target, struct tm *tmbuf) {
923
+ return http_date2rfc7231(target, tmbuf);
924
+ }
925
+
926
+ /**
927
+ * Prints Unix time to a HTTP time formatted string.
928
+ *
929
+ * This variation implements cached results for faster processing, at the
930
+ * price of a less accurate string.
931
+ */
932
+ size_t http_time2str(char *target, const time_t t);
933
+
934
+ /* *****************************************************************************
935
+ HTTP URL decoding helper functions that might be used globally
936
+ ***************************************************************************** */
937
+
938
+ /** Decodes a URL encoded string, no buffer overflow protection. */
939
+ ssize_t http_decode_url_unsafe(char *dest, const char *url_data);
940
+
941
+ /** Decodes a URL encoded string (query / form data). */
942
+ ssize_t http_decode_url(char *dest, const char *url_data, size_t length);
943
+
944
+ /** Decodes the "path" part of a request, no buffer overflow protection. */
945
+ ssize_t http_decode_path_unsafe(char *dest, const char *url_data);
946
+
947
+ /**
948
+ * Decodes the "path" part of an HTTP request, no buffer overflow protection.
949
+ */
950
+ ssize_t http_decode_path(char *dest, const char *url_data, size_t length);
951
+
952
+ /* *****************************************************************************
953
+ HTTP URL parsing
954
+ ***************************************************************************** */
955
+
956
+ /** the result returned by `http_url_parse` */
957
+ typedef fio_url_s http_url_s
958
+ __attribute__((deprecated("use fio_url_s instead")));
959
+
960
+ /**
961
+ * Parses the URI returning it's components and their lengths (no decoding
962
+ * performed, doesn't accept decoded URIs).
963
+ *
964
+ * The returned string are NOT NUL terminated, they are merely locations within
965
+ * the original string.
966
+ *
967
+ * This function expects any of the following formats:
968
+ *
969
+ * * `/complete_path?query#target`
970
+ *
971
+ * i.e.: /index.html?page=1#list
972
+ *
973
+ * * `host:port/complete_path?query#target`
974
+ *
975
+ * i.e.:
976
+ * example.com
977
+ * example.com/index.html
978
+ * example.com:8080/index.html
979
+ * example.com:8080/index.html?key=val#target
980
+ *
981
+ * * `user:password@host:port/path?query#target`
982
+ *
983
+ * i.e.: user:1234@example.com:8080/index.html
984
+ *
985
+ * * `schema://user:password@host:port/path?query#target`
986
+ *
987
+ * i.e.: http://example.com/index.html?page=1#list
988
+ *
989
+ * Invalid formats might produce unexpected results. No error testing performed.
990
+ */
991
+ #define http_url_parse(url, len) fio_url_parse((url), (len))
992
+
993
+ #if DEBUG
994
+ void http_tests(void);
995
+ #endif
996
+
997
+ /* support C++ */
998
+ #ifdef __cplusplus
999
+ }
1000
+ #endif
1001
+
1002
+ #endif /* H_HTTP_H */