iodine 0.4.19 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of iodine might be problematic. Click here for more details.

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