iodine 0.3.6 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of iodine might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +46 -0
- data/LIMITS.md +25 -0
- data/README.md +39 -80
- data/SPEC-Websocket-Draft.md +129 -4
- data/bin/echo +2 -2
- data/bin/http-hello +1 -0
- data/bin/updated api +113 -0
- data/bin/ws-echo +0 -1
- data/examples/broadcast.ru +56 -0
- data/examples/echo.ru +57 -0
- data/examples/hello.ru +30 -0
- data/examples/redis.ru +69 -0
- data/examples/shootout.ru +53 -0
- data/exe/iodine +2 -80
- data/ext/iodine/defer.c +11 -5
- data/ext/iodine/empty.h +26 -0
- data/ext/iodine/evio.h +1 -1
- data/ext/iodine/facil.c +103 -61
- data/ext/iodine/facil.h +20 -12
- data/ext/iodine/fio_dict.c +446 -0
- data/ext/iodine/fio_dict.h +90 -0
- data/ext/iodine/fio_hash_table.h +370 -0
- data/ext/iodine/fio_list.h +30 -3
- data/ext/iodine/http.c +169 -37
- data/ext/iodine/http.h +33 -10
- data/ext/iodine/http1.c +78 -42
- data/ext/iodine/http_request.c +6 -0
- data/ext/iodine/http_request.h +3 -0
- data/ext/iodine/http_response.c +43 -11
- data/ext/iodine/iodine.c +380 -0
- data/ext/iodine/iodine.h +62 -0
- data/ext/iodine/iodine_helpers.c +235 -0
- data/ext/iodine/iodine_helpers.h +13 -0
- data/ext/iodine/iodine_http.c +409 -241
- data/ext/iodine/iodine_http.h +7 -14
- data/ext/iodine/iodine_protocol.c +626 -0
- data/ext/iodine/iodine_protocol.h +13 -0
- data/ext/iodine/iodine_pubsub.c +646 -0
- data/ext/iodine/iodine_pubsub.h +27 -0
- data/ext/iodine/iodine_websockets.c +796 -0
- data/ext/iodine/iodine_websockets.h +19 -0
- data/ext/iodine/pubsub.c +544 -0
- data/ext/iodine/pubsub.h +215 -0
- data/ext/iodine/random.c +4 -4
- data/ext/iodine/rb-call.c +1 -5
- data/ext/iodine/rb-defer.c +3 -20
- data/ext/iodine/rb-rack-io.c +22 -22
- data/ext/iodine/rb-rack-io.h +3 -4
- data/ext/iodine/rb-registry.c +111 -118
- data/ext/iodine/redis_connection.c +277 -0
- data/ext/iodine/redis_connection.h +77 -0
- data/ext/iodine/redis_engine.c +398 -0
- data/ext/iodine/redis_engine.h +68 -0
- data/ext/iodine/resp.c +842 -0
- data/ext/iodine/resp.h +253 -0
- data/ext/iodine/sock.c +26 -12
- data/ext/iodine/sock.h +14 -3
- data/ext/iodine/spnlock.inc +19 -2
- data/ext/iodine/websockets.c +299 -11
- data/ext/iodine/websockets.h +159 -6
- data/lib/iodine.rb +104 -1
- data/lib/iodine/cli.rb +106 -0
- data/lib/iodine/monkeypatch.rb +40 -0
- data/lib/iodine/pubsub.rb +70 -0
- data/lib/iodine/version.rb +1 -1
- data/lib/iodine/websocket.rb +12 -0
- data/lib/rack/handler/iodine.rb +33 -7
- metadata +35 -7
- data/ext/iodine/iodine_core.c +0 -760
- data/ext/iodine/iodine_core.h +0 -79
- data/ext/iodine/iodine_websocket.c +0 -551
- data/ext/iodine/iodine_websocket.h +0 -22
- data/lib/iodine/http.rb +0 -4
data/ext/iodine/fio_list.h
CHANGED
@@ -24,6 +24,9 @@ static inline __attribute__((unused)) void fio_list_init(fio_list_s *list) {
|
|
24
24
|
/** A macro that evaluates to an initialized list head. */
|
25
25
|
#define FIO_LIST_INIT(name) \
|
26
26
|
(fio_list_s) { .next = &(name), .prev = &(name) }
|
27
|
+
/** A macro that evaluates to an initialized list head. */
|
28
|
+
#define FIO_LIST_INIT_STATIC(name) \
|
29
|
+
{ .next = &(name), .prev = &(name) }
|
27
30
|
|
28
31
|
/** Adds a list reference to the list at the specified position. */
|
29
32
|
static inline __attribute__((unused)) void fio_list_add(fio_list_s *pos,
|
@@ -44,15 +47,39 @@ fio_list_remove(fio_list_s *item) {
|
|
44
47
|
*item = (fio_list_s){.next = item, .prev = item};
|
45
48
|
return item;
|
46
49
|
}
|
50
|
+
/** Switches two list items. */
|
51
|
+
static inline __attribute__((unused)) void fio_list_switch(fio_list_s *item1,
|
52
|
+
fio_list_s *item2) {
|
53
|
+
if (item1 == item2)
|
54
|
+
return;
|
55
|
+
fio_list_s tmp = *item1;
|
56
|
+
*item1 = *item2;
|
57
|
+
*item2 = tmp;
|
58
|
+
if (item1->next == item2)
|
59
|
+
item1->next = item1;
|
60
|
+
else
|
61
|
+
item1->next->prev = item1;
|
62
|
+
if (item1->prev == item2)
|
63
|
+
item1->prev = item1;
|
64
|
+
else
|
65
|
+
item1->prev->next = item1;
|
66
|
+
}
|
67
|
+
|
68
|
+
#ifndef fio_node2obj
|
69
|
+
/** Takes a node pointer (list/hash/dict, etc') and returns it's container. */
|
70
|
+
#define fio_node2obj(type, member, ptr) \
|
71
|
+
((type *)((uintptr_t)(ptr) - (uintptr_t)(&(((type *)0)->member))))
|
72
|
+
#endif
|
47
73
|
|
48
74
|
/** Takes a list pointer and returns a pointer to it's container. */
|
49
|
-
#define fio_list_object(type, member, plist)
|
50
|
-
((type *)((uintptr_t)(plist) - (uintptr_t)(&(((type *)0)->member))))
|
75
|
+
#define fio_list_object(type, member, plist) fio_node2obj(type, member, (plist))
|
51
76
|
|
52
77
|
/** iterates the whole list. */
|
53
78
|
#define fio_list_for_each(type, member, var, head) \
|
54
79
|
for (fio_list_s *pos = (head).next->next; \
|
55
|
-
&((var) = fio_list_object(type, member, pos->prev))->member !=
|
80
|
+
(&((var) = fio_list_object(type, member, pos->prev))->member != \
|
81
|
+
&(head)) || \
|
82
|
+
((var) = NULL); \
|
56
83
|
(var) = fio_list_object(type, member, pos), pos = pos->next)
|
57
84
|
|
58
85
|
/** Removes a member from the end of the list. */
|
data/ext/iodine/http.c
CHANGED
@@ -32,14 +32,19 @@ http_on_finish_func http_get_on_finish_func(http_settings_s *settings) {
|
|
32
32
|
return (http_on_finish_func)route[settings->version];
|
33
33
|
}
|
34
34
|
|
35
|
-
void http_on_finish(void *set) {
|
35
|
+
void http_on_finish(intptr_t uuid, void *set) {
|
36
36
|
http_settings_s *settings = set;
|
37
37
|
if (http_get_on_finish_func(set))
|
38
38
|
http_get_on_finish_func(set)(set);
|
39
|
-
|
39
|
+
|
40
|
+
if (settings->on_finish)
|
41
|
+
settings->on_finish(uuid, settings->udata);
|
42
|
+
|
43
|
+
if (settings->private_metaflags & 2) {
|
40
44
|
free((void *)settings->public_folder);
|
41
|
-
if (settings->private_metaflags & 2)
|
42
45
|
free(settings);
|
46
|
+
}
|
47
|
+
(void)uuid;
|
43
48
|
}
|
44
49
|
|
45
50
|
/**
|
@@ -83,14 +88,19 @@ int http_listen(const char *port, const char *address,
|
|
83
88
|
memcpy(tmp + home_len, settings->public_folder + 1,
|
84
89
|
settings->public_folder_length); // copy also the NULL
|
85
90
|
settings->public_folder = tmp;
|
86
|
-
settings->private_metaflags |= 1;
|
87
91
|
settings->public_folder_length = strlen(settings->public_folder);
|
92
|
+
} else {
|
93
|
+
settings->public_folder = malloc(settings->public_folder_length + 1);
|
94
|
+
memcpy((void *)settings->public_folder, arg_settings.public_folder,
|
95
|
+
settings->public_folder_length);
|
96
|
+
((uint8_t *)settings->public_folder)[settings->public_folder_length] = 0;
|
88
97
|
}
|
89
98
|
}
|
90
99
|
|
91
100
|
return facil_listen(.port = port, .address = address,
|
92
101
|
.set_rw_hooks = arg_settings.set_rw_hooks,
|
93
102
|
.rw_udata = arg_settings.rw_udata,
|
103
|
+
.on_finish_rw = arg_settings.on_finish_rw,
|
94
104
|
.on_finish = http_on_finish, .on_open = on_open_callback,
|
95
105
|
.udata = settings);
|
96
106
|
}
|
@@ -117,7 +127,7 @@ struct tm *http_gmtime(const time_t *timer, struct tm *tmbuf) {
|
|
117
127
|
};
|
118
128
|
if (*timer < 0)
|
119
129
|
return gmtime_r(timer, tmbuf);
|
120
|
-
ssize_t
|
130
|
+
ssize_t a, b;
|
121
131
|
tmbuf->tm_gmtoff = 0;
|
122
132
|
tmbuf->tm_zone = "UTC";
|
123
133
|
tmbuf->tm_isdst = 0;
|
@@ -125,82 +135,83 @@ struct tm *http_gmtime(const time_t *timer, struct tm *tmbuf) {
|
|
125
135
|
tmbuf->tm_mon = 0;
|
126
136
|
// for seconds up to weekdays, we build up, as small values clean up larger
|
127
137
|
// values.
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
// day of epoch was a thursday. Add +
|
136
|
-
tmbuf->tm_wday = (
|
138
|
+
a = ((ssize_t)*timer);
|
139
|
+
b = a / 60;
|
140
|
+
tmbuf->tm_sec = a - (b * 60);
|
141
|
+
a = b / 60;
|
142
|
+
tmbuf->tm_min = b - (a * 60);
|
143
|
+
b = a / 24;
|
144
|
+
tmbuf->tm_hour = a - (b * 24);
|
145
|
+
// day of epoch was a thursday. Add + 4 so sunday == 0...
|
146
|
+
tmbuf->tm_wday = (b + 4) % 7;
|
137
147
|
// tmp == number of days since epoch
|
138
148
|
#define DAYS_PER_400_YEARS ((400 * 365) + 97)
|
139
|
-
while (
|
149
|
+
while (b >= DAYS_PER_400_YEARS) {
|
140
150
|
tmbuf->tm_year += 400;
|
141
|
-
|
151
|
+
b -= DAYS_PER_400_YEARS;
|
142
152
|
}
|
143
153
|
#undef DAYS_PER_400_YEARS
|
144
154
|
#define DAYS_PER_100_YEARS ((100 * 365) + 24)
|
145
|
-
while (
|
155
|
+
while (b >= DAYS_PER_100_YEARS) {
|
146
156
|
tmbuf->tm_year += 100;
|
147
|
-
|
157
|
+
b -= DAYS_PER_100_YEARS;
|
148
158
|
if (((tmbuf->tm_year / 100) & 3) ==
|
149
159
|
0) // leap century divisable by 400 => add leap
|
150
|
-
--
|
160
|
+
--b;
|
151
161
|
}
|
152
162
|
#undef DAYS_PER_100_YEARS
|
153
163
|
#define DAYS_PER_32_YEARS ((32 * 365) + 8)
|
154
|
-
while (
|
164
|
+
while (b >= DAYS_PER_32_YEARS) {
|
155
165
|
tmbuf->tm_year += 32;
|
156
|
-
|
166
|
+
b -= DAYS_PER_32_YEARS;
|
157
167
|
}
|
158
168
|
#undef DAYS_PER_32_YEARS
|
159
169
|
#define DAYS_PER_8_YEARS ((8 * 365) + 2)
|
160
|
-
while (
|
170
|
+
while (b >= DAYS_PER_8_YEARS) {
|
161
171
|
tmbuf->tm_year += 8;
|
162
|
-
|
172
|
+
b -= DAYS_PER_8_YEARS;
|
163
173
|
}
|
164
174
|
#undef DAYS_PER_8_YEARS
|
165
175
|
#define DAYS_PER_4_YEARS ((4 * 365) + 1)
|
166
|
-
while (
|
176
|
+
while (b >= DAYS_PER_4_YEARS) {
|
167
177
|
tmbuf->tm_year += 4;
|
168
|
-
|
178
|
+
b -= DAYS_PER_4_YEARS;
|
169
179
|
}
|
170
180
|
#undef DAYS_PER_4_YEARS
|
171
|
-
while (
|
181
|
+
while (b >= 365) {
|
172
182
|
tmbuf->tm_year += 1;
|
173
|
-
|
183
|
+
b -= 365;
|
174
184
|
if ((tmbuf->tm_year & 3) == 0) { // leap year
|
175
|
-
if (
|
176
|
-
--
|
185
|
+
if (b > 0) {
|
186
|
+
--b;
|
177
187
|
continue;
|
178
188
|
} else {
|
179
|
-
|
189
|
+
b += 365;
|
180
190
|
--tmbuf->tm_year;
|
181
191
|
break;
|
182
192
|
}
|
183
193
|
}
|
184
194
|
}
|
185
|
-
|
195
|
+
b++; /* day 1 of the year is 1, not 0. */
|
196
|
+
tmbuf->tm_yday = b;
|
186
197
|
if ((tmbuf->tm_year & 3) == 1) {
|
187
198
|
// regular year
|
188
199
|
for (size_t i = 0; i < 12; i++) {
|
189
|
-
if (
|
200
|
+
if (b <= month_len[i])
|
190
201
|
break;
|
191
|
-
|
202
|
+
b -= month_len[i];
|
192
203
|
++tmbuf->tm_mon;
|
193
204
|
}
|
194
205
|
} else {
|
195
206
|
// leap year
|
196
207
|
for (size_t i = 12; i < 24; i++) {
|
197
|
-
if (
|
208
|
+
if (b <= month_len[i])
|
198
209
|
break;
|
199
|
-
|
210
|
+
b -= month_len[i];
|
200
211
|
++tmbuf->tm_mon;
|
201
212
|
}
|
202
213
|
}
|
203
|
-
tmbuf->tm_mday =
|
214
|
+
tmbuf->tm_mday = b;
|
204
215
|
return tmbuf;
|
205
216
|
}
|
206
217
|
|
@@ -249,6 +260,91 @@ size_t http_date2str(char *target, struct tm *tmbuf) {
|
|
249
260
|
return pos - target;
|
250
261
|
}
|
251
262
|
|
263
|
+
size_t http_date2rfc2822(char *target, struct tm *tmbuf) {
|
264
|
+
char *pos = target;
|
265
|
+
uint16_t tmp;
|
266
|
+
*(uint32_t *)pos = *((uint32_t *)DAY_NAMES[tmbuf->tm_wday]);
|
267
|
+
pos[3] = ',';
|
268
|
+
pos[4] = ' ';
|
269
|
+
pos += 5;
|
270
|
+
if (tmbuf->tm_mday < 10) {
|
271
|
+
*pos = '0' + tmbuf->tm_mday;
|
272
|
+
++pos;
|
273
|
+
} else {
|
274
|
+
tmp = tmbuf->tm_mday / 10;
|
275
|
+
pos[0] = '0' + tmp;
|
276
|
+
pos[1] = '0' + (tmbuf->tm_mday - (tmp * 10));
|
277
|
+
pos += 2;
|
278
|
+
}
|
279
|
+
*(pos++) = '-';
|
280
|
+
*(uint32_t *)pos = *((uint32_t *)MONTH_NAMES[tmbuf->tm_mon]);
|
281
|
+
pos += 3;
|
282
|
+
*(pos++) = '-';
|
283
|
+
// write year.
|
284
|
+
pos += http_ul2a(pos, tmbuf->tm_year + 1900);
|
285
|
+
*(pos++) = ' ';
|
286
|
+
tmp = tmbuf->tm_hour / 10;
|
287
|
+
pos[0] = '0' + tmp;
|
288
|
+
pos[1] = '0' + (tmbuf->tm_hour - (tmp * 10));
|
289
|
+
pos[2] = ':';
|
290
|
+
tmp = tmbuf->tm_min / 10;
|
291
|
+
pos[3] = '0' + tmp;
|
292
|
+
pos[4] = '0' + (tmbuf->tm_min - (tmp * 10));
|
293
|
+
pos[5] = ':';
|
294
|
+
tmp = tmbuf->tm_sec / 10;
|
295
|
+
pos[6] = '0' + tmp;
|
296
|
+
pos[7] = '0' + (tmbuf->tm_sec - (tmp * 10));
|
297
|
+
pos += 8;
|
298
|
+
pos[0] = ' ';
|
299
|
+
*((uint32_t *)(pos + 1)) = *((uint32_t *)GMT_STR);
|
300
|
+
pos += 4;
|
301
|
+
return pos - target;
|
302
|
+
}
|
303
|
+
|
304
|
+
size_t http_date2rfc2109(char *target, struct tm *tmbuf) {
|
305
|
+
char *pos = target;
|
306
|
+
uint16_t tmp;
|
307
|
+
*(uint32_t *)pos = *((uint32_t *)DAY_NAMES[tmbuf->tm_wday]);
|
308
|
+
pos[3] = ',';
|
309
|
+
pos[4] = ' ';
|
310
|
+
pos += 5;
|
311
|
+
if (tmbuf->tm_mday < 10) {
|
312
|
+
*pos = '0' + tmbuf->tm_mday;
|
313
|
+
++pos;
|
314
|
+
} else {
|
315
|
+
tmp = tmbuf->tm_mday / 10;
|
316
|
+
pos[0] = '0' + tmp;
|
317
|
+
pos[1] = '0' + (tmbuf->tm_mday - (tmp * 10));
|
318
|
+
pos += 2;
|
319
|
+
}
|
320
|
+
*(pos++) = ' ';
|
321
|
+
*(uint32_t *)pos = *((uint32_t *)MONTH_NAMES[tmbuf->tm_mon]);
|
322
|
+
pos += 4;
|
323
|
+
// write year.
|
324
|
+
pos += http_ul2a(pos, tmbuf->tm_year + 1900);
|
325
|
+
*(pos++) = ' ';
|
326
|
+
tmp = tmbuf->tm_hour / 10;
|
327
|
+
pos[0] = '0' + tmp;
|
328
|
+
pos[1] = '0' + (tmbuf->tm_hour - (tmp * 10));
|
329
|
+
pos[2] = ':';
|
330
|
+
tmp = tmbuf->tm_min / 10;
|
331
|
+
pos[3] = '0' + tmp;
|
332
|
+
pos[4] = '0' + (tmbuf->tm_min - (tmp * 10));
|
333
|
+
pos[5] = ':';
|
334
|
+
tmp = tmbuf->tm_sec / 10;
|
335
|
+
pos[6] = '0' + tmp;
|
336
|
+
pos[7] = '0' + (tmbuf->tm_sec - (tmp * 10));
|
337
|
+
pos += 8;
|
338
|
+
*pos++ = ' ';
|
339
|
+
*pos++ = '-';
|
340
|
+
*pos++ = '0';
|
341
|
+
*pos++ = '0';
|
342
|
+
*pos++ = '0';
|
343
|
+
*pos++ = '0';
|
344
|
+
*pos = 0;
|
345
|
+
return pos - target;
|
346
|
+
}
|
347
|
+
|
252
348
|
/* Credit to Jonathan Leffler for the idea of a unified conditional */
|
253
349
|
#define hex_val(c) \
|
254
350
|
(((c) >= '0' && (c) <= '9') \
|
@@ -277,7 +373,7 @@ static inline int hex2byte(uint8_t *dest, const uint8_t *source) {
|
|
277
373
|
return -1;
|
278
374
|
return 0;
|
279
375
|
}
|
280
|
-
|
376
|
+
|
281
377
|
ssize_t http_decode_url(char *dest, const char *url_data, size_t length) {
|
282
378
|
char *pos = dest;
|
283
379
|
const char *end = url_data + length;
|
@@ -320,4 +416,40 @@ ssize_t http_decode_url_unsafe(char *dest, const char *url_data) {
|
|
320
416
|
*pos = 0;
|
321
417
|
return pos - dest;
|
322
418
|
}
|
419
|
+
|
420
|
+
ssize_t http_decode_path(char *dest, const char *url_data, size_t length) {
|
421
|
+
char *pos = dest;
|
422
|
+
const char *end = url_data + length;
|
423
|
+
while (url_data < end) {
|
424
|
+
if (*url_data == '%') {
|
425
|
+
// decode hex value
|
426
|
+
// this is a percent encoded value.
|
427
|
+
if (hex2byte((uint8_t *)pos, (uint8_t *)&url_data[1]))
|
428
|
+
return -1;
|
429
|
+
pos++;
|
430
|
+
url_data += 3;
|
431
|
+
} else
|
432
|
+
*(pos++) = *(url_data++);
|
433
|
+
}
|
434
|
+
*pos = 0;
|
435
|
+
return pos - dest;
|
436
|
+
}
|
437
|
+
|
438
|
+
ssize_t http_decode_path_unsafe(char *dest, const char *url_data) {
|
439
|
+
char *pos = dest;
|
440
|
+
while (*url_data) {
|
441
|
+
if (*url_data == '%') {
|
442
|
+
// decode hex value
|
443
|
+
// this is a percent encoded value.
|
444
|
+
if (hex2byte((uint8_t *)pos, (uint8_t *)&url_data[1]))
|
445
|
+
return -1;
|
446
|
+
pos++;
|
447
|
+
url_data += 3;
|
448
|
+
} else
|
449
|
+
*(pos++) = *(url_data++);
|
450
|
+
}
|
451
|
+
*pos = 0;
|
452
|
+
return pos - dest;
|
453
|
+
}
|
454
|
+
|
323
455
|
#undef hex_val
|
data/ext/iodine/http.h
CHANGED
@@ -28,6 +28,9 @@ typedef struct {
|
|
28
28
|
};
|
29
29
|
} http_header_s;
|
30
30
|
|
31
|
+
/** Settings typedef */
|
32
|
+
typedef struct http_settings_s http_settings_s;
|
33
|
+
|
31
34
|
/* *****************************************************************************
|
32
35
|
Core include files
|
33
36
|
*/
|
@@ -56,14 +59,14 @@ HTTP Core API & data structure
|
|
56
59
|
*/
|
57
60
|
|
58
61
|
/** Manages protocol settings for the HTTP protocol */
|
59
|
-
|
62
|
+
struct http_settings_s {
|
60
63
|
/**
|
61
64
|
The maximum size of an HTTP request's body (when posting data).
|
62
65
|
|
63
66
|
Defaults to ~ 50Mb.
|
64
67
|
*/
|
65
68
|
size_t max_body_size;
|
66
|
-
/** the callback to be performed when requests come in. */
|
69
|
+
/** REQUIRED: the callback to be performed when requests come in. */
|
67
70
|
void (*on_request)(http_request_s *request);
|
68
71
|
/**
|
69
72
|
A public folder for file transfers - allows to circumvent any application
|
@@ -74,20 +77,28 @@ typedef struct {
|
|
74
77
|
The length of the public_folder string.
|
75
78
|
*/
|
76
79
|
size_t public_folder_length;
|
77
|
-
/**
|
80
|
+
/** Opaque user data. */
|
81
|
+
void *udata;
|
82
|
+
/** Opaque user data for the optional `set_rw_hooks`. */
|
83
|
+
void *rw_udata;
|
84
|
+
/** (optional) the callback to be performed when the HTTP service closes. */
|
85
|
+
void (*on_finish)(intptr_t uuid, void *udata);
|
86
|
+
/**
|
78
87
|
* Allows a an implementation for the transport layer (i.e. TLS) without
|
79
88
|
* effecting the HTTP protocol.
|
80
89
|
*/
|
81
90
|
sock_rw_hook_s *(*set_rw_hooks)(intptr_t fduuid, void *rw_udata);
|
82
|
-
/**
|
83
|
-
|
91
|
+
/**
|
92
|
+
* A cleanup callback for the `rw_udata`.
|
93
|
+
*/
|
94
|
+
void (*on_finish_rw)(intptr_t uuid, void *rw_udata);
|
84
95
|
/**
|
85
96
|
Logging flag - set to TRUE to log static file requests.
|
86
97
|
|
87
98
|
Dynamic request logging is always the dynamic application's responsibility.
|
88
99
|
*/
|
89
100
|
uint8_t log_static;
|
90
|
-
/** An HTTP connection timeout.
|
101
|
+
/** An HTTP/1.x connection timeout. Defaults to ~5 seconds.*/
|
91
102
|
uint8_t timeout;
|
92
103
|
/**
|
93
104
|
The default HTTP version which a new connection will use. At the moment, only
|
@@ -98,7 +109,7 @@ typedef struct {
|
|
98
109
|
internal flag for library use.
|
99
110
|
*/
|
100
111
|
uint8_t private_metaflags;
|
101
|
-
}
|
112
|
+
};
|
102
113
|
|
103
114
|
typedef protocol_s *(*http_on_open_func)(intptr_t, void *);
|
104
115
|
typedef void (*http_on_finish_func)(void *);
|
@@ -139,11 +150,16 @@ struct tm *http_gmtime(const time_t *timer, struct tm *tmbuf);
|
|
139
150
|
/**
|
140
151
|
Writes an HTTP date string to the `target` buffer.
|
141
152
|
|
142
|
-
This requires
|
153
|
+
This requires ~32 bytes of space to be available at the target buffer (unless
|
154
|
+
it's a super funky year, 32 bytes is about 3 more than you need).
|
143
155
|
|
144
156
|
Returns the number of bytes actually written.
|
145
157
|
*/
|
146
158
|
size_t http_date2str(char *target, struct tm *tmbuf);
|
159
|
+
/** An alternative, RFC 2109 date representation. Requires */
|
160
|
+
size_t http_date2rfc2109(char *target, struct tm *tmbuf);
|
161
|
+
/** An alternative, RFC 2822 date representation. */
|
162
|
+
size_t http_date2rfc2822(char *target, struct tm *tmbuf);
|
147
163
|
|
148
164
|
/**
|
149
165
|
A fast, inline alternative to `sprintf(dest, "%lu", num)`.
|
@@ -155,7 +171,7 @@ A NULL terminating byte is written.
|
|
155
171
|
|
156
172
|
Returns the number of bytes actually written (excluding the NULL byte).
|
157
173
|
*/
|
158
|
-
inline size_t http_ul2a(char *dest, size_t num) {
|
174
|
+
static inline size_t http_ul2a(char *dest, size_t num) {
|
159
175
|
uint8_t digits = 1;
|
160
176
|
size_t tmp = num;
|
161
177
|
while ((tmp /= 10))
|
@@ -174,7 +190,14 @@ inline size_t http_ul2a(char *dest, size_t num) {
|
|
174
190
|
/** Decodes a URL encoded string, no buffer overflow protection. */
|
175
191
|
ssize_t http_decode_url_unsafe(char *dest, const char *url_data);
|
176
192
|
|
177
|
-
/** Decodes a URL encoded string. */
|
193
|
+
/** Decodes a URL encoded string (i.e., the "query" part of a request). */
|
178
194
|
ssize_t http_decode_url(char *dest, const char *url_data, size_t length);
|
179
195
|
|
196
|
+
/** Decodes the "path" part of a request, no buffer overflow protection. */
|
197
|
+
ssize_t http_decode_path_unsafe(char *dest, const char *url_data);
|
198
|
+
|
199
|
+
/** Decodes the "path" part of an HTTP request, no buffer overflow protection.
|
200
|
+
*/
|
201
|
+
ssize_t http_decode_path(char *dest, const char *url_data, size_t length);
|
202
|
+
|
180
203
|
#endif
|