rage-iodine 1.7.58

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