isomorfeus-iodine 0.7.49 → 0.7.50

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +1 -1
  3. data/CHANGELOG.md +17 -3
  4. data/Rakefile +1 -9
  5. data/examples/etag.ru +16 -0
  6. data/ext/{iodine → iodine_ext}/extconf.rb +1 -1
  7. data/ext/{iodine → iodine_ext}/fio.c +0 -0
  8. data/ext/{iodine → iodine_ext}/fio.h +0 -0
  9. data/ext/{iodine → iodine_ext}/fio_cli.c +0 -0
  10. data/ext/{iodine → iodine_ext}/fio_cli.h +189 -189
  11. data/ext/{iodine → iodine_ext}/fio_json_parser.h +687 -687
  12. data/ext/{iodine → iodine_ext}/fio_siphash.c +157 -157
  13. data/ext/{iodine → iodine_ext}/fio_siphash.h +37 -37
  14. data/ext/{iodine → iodine_ext}/fio_tls.h +129 -129
  15. data/ext/{iodine → iodine_ext}/fio_tls_missing.c +0 -0
  16. data/ext/{iodine → iodine_ext}/fio_tls_openssl.c +0 -0
  17. data/ext/{iodine → iodine_ext}/fio_tmpfile.h +0 -0
  18. data/ext/{iodine → iodine_ext}/fiobj.h +44 -44
  19. data/ext/{iodine → iodine_ext}/fiobj4fio.h +21 -21
  20. data/ext/{iodine → iodine_ext}/fiobj_ary.c +333 -333
  21. data/ext/{iodine → iodine_ext}/fiobj_ary.h +139 -139
  22. data/ext/{iodine → iodine_ext}/fiobj_data.c +0 -0
  23. data/ext/{iodine → iodine_ext}/fiobj_data.h +0 -0
  24. data/ext/{iodine → iodine_ext}/fiobj_hash.c +0 -0
  25. data/ext/{iodine → iodine_ext}/fiobj_hash.h +176 -176
  26. data/ext/{iodine → iodine_ext}/fiobj_json.c +622 -622
  27. data/ext/{iodine → iodine_ext}/fiobj_json.h +68 -68
  28. data/ext/{iodine → iodine_ext}/fiobj_mem.h +71 -71
  29. data/ext/{iodine → iodine_ext}/fiobj_mustache.c +0 -0
  30. data/ext/{iodine → iodine_ext}/fiobj_mustache.h +62 -62
  31. data/ext/{iodine → iodine_ext}/fiobj_numbers.c +0 -0
  32. data/ext/{iodine → iodine_ext}/fiobj_numbers.h +127 -127
  33. data/ext/{iodine → iodine_ext}/fiobj_str.c +0 -0
  34. data/ext/{iodine → iodine_ext}/fiobj_str.h +172 -172
  35. data/ext/{iodine → iodine_ext}/fiobject.c +0 -0
  36. data/ext/{iodine → iodine_ext}/fiobject.h +0 -0
  37. data/ext/{iodine → iodine_ext}/hpack.h +1923 -1923
  38. data/ext/{iodine → iodine_ext}/http.c +14 -27
  39. data/ext/{iodine → iodine_ext}/http.h +1002 -1002
  40. data/ext/{iodine → iodine_ext}/http1.c +0 -0
  41. data/ext/{iodine → iodine_ext}/http1.h +29 -29
  42. data/ext/{iodine → iodine_ext}/http1_parser.h +0 -0
  43. data/ext/{iodine → iodine_ext}/http_internal.c +0 -0
  44. data/ext/{iodine → iodine_ext}/http_internal.h +0 -0
  45. data/ext/{iodine → iodine_ext}/http_mime_parser.h +350 -350
  46. data/ext/{iodine → iodine_ext}/iodine.c +1 -1
  47. data/ext/{iodine → iodine_ext}/iodine.h +0 -0
  48. data/ext/{iodine → iodine_ext}/iodine_caller.c +0 -0
  49. data/ext/{iodine → iodine_ext}/iodine_caller.h +0 -0
  50. data/ext/{iodine → iodine_ext}/iodine_connection.c +0 -0
  51. data/ext/{iodine → iodine_ext}/iodine_connection.h +55 -55
  52. data/ext/{iodine → iodine_ext}/iodine_defer.c +0 -0
  53. data/ext/{iodine → iodine_ext}/iodine_defer.h +6 -6
  54. data/ext/{iodine → iodine_ext}/iodine_fiobj2rb.h +120 -120
  55. data/ext/{iodine → iodine_ext}/iodine_helpers.c +0 -0
  56. data/ext/{iodine → iodine_ext}/iodine_helpers.h +12 -12
  57. data/ext/{iodine → iodine_ext}/iodine_http.c +0 -2
  58. data/ext/{iodine → iodine_ext}/iodine_http.h +23 -23
  59. data/ext/{iodine → iodine_ext}/iodine_json.c +302 -302
  60. data/ext/{iodine → iodine_ext}/iodine_json.h +6 -6
  61. data/ext/{iodine → iodine_ext}/iodine_mustache.c +0 -0
  62. data/ext/{iodine → iodine_ext}/iodine_mustache.h +6 -6
  63. data/ext/{iodine → iodine_ext}/iodine_pubsub.c +0 -0
  64. data/ext/{iodine → iodine_ext}/iodine_pubsub.h +26 -26
  65. data/ext/{iodine → iodine_ext}/iodine_rack_io.c +0 -0
  66. data/ext/{iodine → iodine_ext}/iodine_rack_io.h +20 -20
  67. data/ext/{iodine → iodine_ext}/iodine_store.c +0 -0
  68. data/ext/{iodine → iodine_ext}/iodine_store.h +20 -20
  69. data/ext/{iodine → iodine_ext}/iodine_tcp.c +0 -0
  70. data/ext/{iodine → iodine_ext}/iodine_tcp.h +0 -0
  71. data/ext/{iodine → iodine_ext}/iodine_tls.c +0 -0
  72. data/ext/{iodine → iodine_ext}/iodine_tls.h +13 -13
  73. data/ext/{iodine → iodine_ext}/mustache_parser.h +0 -0
  74. data/ext/{iodine → iodine_ext}/redis_engine.c +0 -0
  75. data/ext/{iodine → iodine_ext}/redis_engine.h +0 -0
  76. data/ext/{iodine → iodine_ext}/resp_parser.h +0 -0
  77. data/ext/{iodine → iodine_ext}/websocket_parser.h +505 -505
  78. data/ext/{iodine → iodine_ext}/websockets.c +0 -0
  79. data/ext/{iodine → iodine_ext}/websockets.h +185 -185
  80. data/isomorfeus-iodine.gemspec +1 -2
  81. data/lib/iodine/version.rb +1 -1
  82. data/lib/iodine.rb +1 -1
  83. metadata +79 -78
@@ -1,350 +1,350 @@
1
- /*
2
- Copyright: Boaz Segev, 2018-2019
3
- License: MIT
4
-
5
- Feel free to copy, use and enjoy according to the license provided.
6
- */
7
- #ifndef H_HTTP_MIME_PARSER_H
8
- #define H_HTTP_MIME_PARSER_H
9
- #include <stdint.h>
10
- #include <stdlib.h>
11
- #include <string.h>
12
-
13
- /* *****************************************************************************
14
- Known Limitations:
15
-
16
- - Doesn't support nested multipart form structures (i.e., multi-file selection).
17
- See: https://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.2
18
-
19
- To circumvent limitation, initialize a new parser to parse nested multiparts.
20
- ***************************************************************************** */
21
-
22
- /* *****************************************************************************
23
- The HTTP MIME Multipart Form Parser Type
24
- ***************************************************************************** */
25
-
26
- /** all data id read-only / for internal use */
27
- typedef struct {
28
- char *boundary;
29
- size_t boundary_len;
30
- uint8_t in_obj;
31
- uint8_t done;
32
- uint8_t error;
33
- } http_mime_parser_s;
34
-
35
- /* *****************************************************************************
36
- Callbacks to be implemented.
37
- ***************************************************************************** */
38
-
39
- /** Called when all the data is available at once. */
40
- static void http_mime_parser_on_data(http_mime_parser_s *parser, void *name,
41
- size_t name_len, void *filename,
42
- size_t filename_len, void *mimetype,
43
- size_t mimetype_len, void *value,
44
- size_t value_len);
45
-
46
- /** Called when the data didn't fit in the buffer. Data will be streamed. */
47
- static void http_mime_parser_on_partial_start(
48
- http_mime_parser_s *parser, void *name, size_t name_len, void *filename,
49
- size_t filename_len, void *mimetype, size_t mimetype_len);
50
-
51
- /** Called when partial data is available. */
52
- static void http_mime_parser_on_partial_data(http_mime_parser_s *parser,
53
- void *value, size_t value_len);
54
-
55
- /** Called when the partial data is complete. */
56
- static void http_mime_parser_on_partial_end(http_mime_parser_s *parser);
57
-
58
- /**
59
- * Called when URL decoding is required.
60
- *
61
- * Should support inplace decoding (`dest == encoded`).
62
- *
63
- * Should return the length of the decoded string.
64
- */
65
- static size_t http_mime_decode_url(char *dest, const char *encoded,
66
- size_t length);
67
-
68
- /* *****************************************************************************
69
- API
70
- ***************************************************************************** */
71
-
72
- /**
73
- * Takes the HTTP Content-Type header and initializes the parser data.
74
- *
75
- * Note: the Content-Type header should persist in memory while the parser is in
76
- * use.
77
- */
78
- static int http_mime_parser_init(http_mime_parser_s *parser, char *content_type,
79
- size_t len);
80
-
81
- /**
82
- * Consumes data from a streaming buffer.
83
- *
84
- * The data might be partially consumed, in which case the unconsumed data
85
- * should be resent to the parser as more data becomes available.
86
- *
87
- * Note: test the `parser->done` and `parser->error` flags between iterations.
88
- */
89
- static size_t http_mime_parse(http_mime_parser_s *parser, void *buffer,
90
- size_t length);
91
-
92
- /* *****************************************************************************
93
- Implementations
94
- ***************************************************************************** */
95
-
96
- /** takes the HTTP Content-Type header and initializes the parser data. */
97
- static int http_mime_parser_init(http_mime_parser_s *parser, char *content_type,
98
- size_t len) {
99
- *parser = (http_mime_parser_s){.done = 0};
100
- if (len < 14 || strncasecmp("multipart/form", content_type, 14))
101
- return -1;
102
- char *cut = memchr(content_type, ';', len);
103
- while (cut) {
104
- ++cut;
105
- len -= (size_t)(cut - content_type);
106
- while (len && cut[0] == ' ') {
107
- --len;
108
- ++cut;
109
- }
110
- if (len <= 9)
111
- return -1;
112
- if (strncasecmp("boundary=", cut, 9)) {
113
- content_type = cut;
114
- cut = memchr(cut, ';', len);
115
- continue;
116
- }
117
- cut += 9;
118
- len -= 9;
119
- content_type = cut;
120
- parser->boundary = content_type;
121
- if ((cut = memchr(content_type, ';', len)))
122
- parser->boundary_len = (size_t)(cut - content_type);
123
- else
124
- parser->boundary_len = len;
125
- return 0;
126
- }
127
- return -1;
128
- }
129
-
130
- /**
131
- * Consumes data from a streaming buffer.
132
- *
133
- * The data might be partially consumed, in which case the unconsumed data
134
- * should be resent to the parser as more data becomes available.
135
- *
136
- * Note: test the `parser->done` and `parser->error` flags between iterations.
137
- */
138
- static size_t http_mime_parse(http_mime_parser_s *parser, void *buffer,
139
- size_t length) {
140
- int first_run = 1;
141
- char *pos = buffer;
142
- const char *stop = pos + length;
143
- if (!length)
144
- goto end_of_data;
145
- consume_partial:
146
- if (parser->in_obj) {
147
- /* we're in an object longer than the buffer */
148
- char *start = pos;
149
- char *end = start;
150
- do {
151
- end = memchr(end, '\n', (size_t)(stop - end));
152
- } while (end && ++end &&
153
- (size_t)(stop - end) >= (4 + parser->boundary_len) &&
154
- (end[0] != '-' || end[1] != '-' ||
155
- memcmp(end + 2, parser->boundary, parser->boundary_len)));
156
- if (!end) {
157
- end = (char *)stop;
158
- pos = end;
159
- if (end - start)
160
- http_mime_parser_on_partial_data(parser, start, (size_t)(end - start));
161
- goto end_of_data;
162
- } else if (end + 4 + parser->boundary_len >= stop) {
163
- end -= 2;
164
- if (end[0] == '\r')
165
- --end;
166
- pos = end;
167
- if (end - start)
168
- http_mime_parser_on_partial_data(parser, start, (size_t)(end - start));
169
- goto end_of_data;
170
- }
171
- size_t len = (end - start) - 1;
172
- if (start[len - 1] == '\r')
173
- --len;
174
- if (len)
175
- http_mime_parser_on_partial_data(parser, start, len);
176
- http_mime_parser_on_partial_end(parser);
177
- pos = end;
178
- parser->in_obj = 0;
179
- first_run = 0;
180
- } else if (length < (4 + parser->boundary_len) || pos[0] != '-' ||
181
- pos[1] != '-' ||
182
- memcmp(pos + 2, parser->boundary, parser->boundary_len))
183
- goto error;
184
- /* We're at a boundary */
185
- while (pos < stop) {
186
- char *start;
187
- char *end;
188
- char *name = NULL;
189
- uint32_t name_len = 0;
190
- char *value = NULL;
191
- uint32_t value_len = 0;
192
- char *filename = NULL;
193
- uint32_t filename_len = 0;
194
- char *mime = NULL;
195
- uint32_t mime_len = 0;
196
- uint8_t header_count = 0;
197
- /* test for ending */
198
- if (pos[2 + parser->boundary_len] == '-' &&
199
- pos[3 + parser->boundary_len] == '-') {
200
- pos += 5 + parser->boundary_len;
201
- if (pos > stop)
202
- pos = (char *)stop;
203
- else if (pos < stop && pos[0] == '\n')
204
- ++pos;
205
- goto done;
206
- }
207
- start = pos + 3 + parser->boundary_len;
208
- if (start[0] == '\n') {
209
- /* should be true, unless new line marker was just '\n' */
210
- ++start;
211
- }
212
- /* consume headers */
213
- while (start + 4 < stop && start[0] != '\n' && start[1] != '\n') {
214
- end = memchr(start, '\n', (size_t)(stop - start));
215
- if (!end) {
216
- if (first_run)
217
- goto error;
218
- goto end_of_data;
219
- }
220
- if (end - start > 29 && !strncasecmp(start, "content-disposition:", 20)) {
221
- /* content-disposition header */
222
- start = memchr(start + 20, ';', end - (start + 20));
223
- // if (!start)
224
- // start = end + 1;
225
- while (start) {
226
- ++start;
227
- if (start[0] == ' ')
228
- ++start;
229
- if (start + 6 < end && !strncasecmp(start, "name=", 5)) {
230
- name = start + 5;
231
- if (name[0] == '"')
232
- ++name;
233
- start = memchr(name, ';', (size_t)(end - start));
234
- if (!start) {
235
- name_len = (size_t)(end - name);
236
- if (name[name_len - 1] == '\r')
237
- --name_len;
238
- } else {
239
- name_len = (size_t)(start - name);
240
- }
241
- if (name[name_len - 1] == '"')
242
- --name_len;
243
- } else if (start + 9 < end && !strncasecmp(start, "filename", 8)) {
244
- uint8_t encoded = 0;
245
- start += 8;
246
- if (start[0] == '*') {
247
- encoded = 1;
248
- ++start;
249
- }
250
- if (start[0] != '=')
251
- goto error;
252
- ++start;
253
- if (start[0] == ' ')
254
- ++start;
255
- if (start[0] == '"')
256
- ++start;
257
- if (filename && !encoded) {
258
- /* prefer URL encoded version */
259
- start = memchr(filename, ';', (size_t)(end - start));
260
- continue;
261
- }
262
- filename = start;
263
- start = memchr(filename, ';', (size_t)(end - start));
264
- if (!start) {
265
- filename_len = (size_t)((end - filename));
266
- if (filename[filename_len - 1] == '\r') {
267
- --filename_len;
268
- }
269
- } else {
270
- filename_len = (size_t)(start - filename);
271
- }
272
- if (filename[filename_len - 1] == '"')
273
- --filename_len;
274
- if (encoded) {
275
- ssize_t new_len =
276
- http_mime_decode_url(filename, filename, filename_len);
277
- if (new_len > 0)
278
- filename_len = new_len;
279
- }
280
- } else {
281
- start = memchr(start, ';', (size_t)(end - start));
282
- }
283
- }
284
- } else if (end - start > 14 && !strncasecmp(start, "content-type:", 13)) {
285
- /* content-type header */
286
- start += 13;
287
- if (start[0] == ' ')
288
- ++start;
289
- mime = start;
290
- start = memchr(start, ';', (size_t)(end - start));
291
- if (!start) {
292
- mime_len = (size_t)(end - mime);
293
- if (mime[mime_len - 1] == '\r')
294
- --mime_len;
295
- } else {
296
- mime_len = (size_t)(start - mime);
297
- }
298
- }
299
- start = end + 1;
300
- if (header_count++ > 4)
301
- goto error;
302
- }
303
- if (!name) {
304
- if (start + 4 >= stop)
305
- goto end_of_data;
306
- goto error;
307
- }
308
-
309
- /* advance to end of boundry */
310
- ++start;
311
- if (start[0] == '\n')
312
- ++start;
313
- value = start;
314
- end = start;
315
- do {
316
- end = memchr(end, '\n', (size_t)(stop - end));
317
- } while (end && ++end &&
318
- (size_t)(stop - end) >= (4 + parser->boundary_len) &&
319
- (end[0] != '-' || end[1] != '-' ||
320
- memcmp(end + 2, parser->boundary, parser->boundary_len)));
321
- if (!end || end + 4 + parser->boundary_len >= stop) {
322
- if (first_run) {
323
- http_mime_parser_on_partial_start(parser, name, name_len, filename,
324
- filename_len, mime, mime_len);
325
- parser->in_obj = 1;
326
- pos = value;
327
- goto consume_partial;
328
- }
329
- goto end_of_data;
330
- }
331
- value_len = (size_t)((end - value) - 1);
332
- if (value[value_len - 1] == '\r')
333
- --value_len;
334
- pos = end;
335
- http_mime_parser_on_data(parser, name, name_len, filename, filename_len,
336
- mime, mime_len, value, value_len);
337
- first_run = 0;
338
- }
339
- end_of_data:
340
- return (size_t)((uintptr_t)pos - (uintptr_t)buffer);
341
- done:
342
- parser->done = 1;
343
- parser->error = 0;
344
- return (size_t)((uintptr_t)pos - (uintptr_t)buffer);
345
- error:
346
- parser->done = 0;
347
- parser->error = 1;
348
- return (size_t)((uintptr_t)pos - (uintptr_t)buffer);
349
- }
350
- #endif
1
+ /*
2
+ Copyright: Boaz Segev, 2018-2019
3
+ License: MIT
4
+
5
+ Feel free to copy, use and enjoy according to the license provided.
6
+ */
7
+ #ifndef H_HTTP_MIME_PARSER_H
8
+ #define H_HTTP_MIME_PARSER_H
9
+ #include <stdint.h>
10
+ #include <stdlib.h>
11
+ #include <string.h>
12
+
13
+ /* *****************************************************************************
14
+ Known Limitations:
15
+
16
+ - Doesn't support nested multipart form structures (i.e., multi-file selection).
17
+ See: https://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.2
18
+
19
+ To circumvent limitation, initialize a new parser to parse nested multiparts.
20
+ ***************************************************************************** */
21
+
22
+ /* *****************************************************************************
23
+ The HTTP MIME Multipart Form Parser Type
24
+ ***************************************************************************** */
25
+
26
+ /** all data id read-only / for internal use */
27
+ typedef struct {
28
+ char *boundary;
29
+ size_t boundary_len;
30
+ uint8_t in_obj;
31
+ uint8_t done;
32
+ uint8_t error;
33
+ } http_mime_parser_s;
34
+
35
+ /* *****************************************************************************
36
+ Callbacks to be implemented.
37
+ ***************************************************************************** */
38
+
39
+ /** Called when all the data is available at once. */
40
+ static void http_mime_parser_on_data(http_mime_parser_s *parser, void *name,
41
+ size_t name_len, void *filename,
42
+ size_t filename_len, void *mimetype,
43
+ size_t mimetype_len, void *value,
44
+ size_t value_len);
45
+
46
+ /** Called when the data didn't fit in the buffer. Data will be streamed. */
47
+ static void http_mime_parser_on_partial_start(
48
+ http_mime_parser_s *parser, void *name, size_t name_len, void *filename,
49
+ size_t filename_len, void *mimetype, size_t mimetype_len);
50
+
51
+ /** Called when partial data is available. */
52
+ static void http_mime_parser_on_partial_data(http_mime_parser_s *parser,
53
+ void *value, size_t value_len);
54
+
55
+ /** Called when the partial data is complete. */
56
+ static void http_mime_parser_on_partial_end(http_mime_parser_s *parser);
57
+
58
+ /**
59
+ * Called when URL decoding is required.
60
+ *
61
+ * Should support inplace decoding (`dest == encoded`).
62
+ *
63
+ * Should return the length of the decoded string.
64
+ */
65
+ static size_t http_mime_decode_url(char *dest, const char *encoded,
66
+ size_t length);
67
+
68
+ /* *****************************************************************************
69
+ API
70
+ ***************************************************************************** */
71
+
72
+ /**
73
+ * Takes the HTTP Content-Type header and initializes the parser data.
74
+ *
75
+ * Note: the Content-Type header should persist in memory while the parser is in
76
+ * use.
77
+ */
78
+ static int http_mime_parser_init(http_mime_parser_s *parser, char *content_type,
79
+ size_t len);
80
+
81
+ /**
82
+ * Consumes data from a streaming buffer.
83
+ *
84
+ * The data might be partially consumed, in which case the unconsumed data
85
+ * should be resent to the parser as more data becomes available.
86
+ *
87
+ * Note: test the `parser->done` and `parser->error` flags between iterations.
88
+ */
89
+ static size_t http_mime_parse(http_mime_parser_s *parser, void *buffer,
90
+ size_t length);
91
+
92
+ /* *****************************************************************************
93
+ Implementations
94
+ ***************************************************************************** */
95
+
96
+ /** takes the HTTP Content-Type header and initializes the parser data. */
97
+ static int http_mime_parser_init(http_mime_parser_s *parser, char *content_type,
98
+ size_t len) {
99
+ *parser = (http_mime_parser_s){.done = 0};
100
+ if (len < 14 || strncasecmp("multipart/form", content_type, 14))
101
+ return -1;
102
+ char *cut = memchr(content_type, ';', len);
103
+ while (cut) {
104
+ ++cut;
105
+ len -= (size_t)(cut - content_type);
106
+ while (len && cut[0] == ' ') {
107
+ --len;
108
+ ++cut;
109
+ }
110
+ if (len <= 9)
111
+ return -1;
112
+ if (strncasecmp("boundary=", cut, 9)) {
113
+ content_type = cut;
114
+ cut = memchr(cut, ';', len);
115
+ continue;
116
+ }
117
+ cut += 9;
118
+ len -= 9;
119
+ content_type = cut;
120
+ parser->boundary = content_type;
121
+ if ((cut = memchr(content_type, ';', len)))
122
+ parser->boundary_len = (size_t)(cut - content_type);
123
+ else
124
+ parser->boundary_len = len;
125
+ return 0;
126
+ }
127
+ return -1;
128
+ }
129
+
130
+ /**
131
+ * Consumes data from a streaming buffer.
132
+ *
133
+ * The data might be partially consumed, in which case the unconsumed data
134
+ * should be resent to the parser as more data becomes available.
135
+ *
136
+ * Note: test the `parser->done` and `parser->error` flags between iterations.
137
+ */
138
+ static size_t http_mime_parse(http_mime_parser_s *parser, void *buffer,
139
+ size_t length) {
140
+ int first_run = 1;
141
+ char *pos = buffer;
142
+ const char *stop = pos + length;
143
+ if (!length)
144
+ goto end_of_data;
145
+ consume_partial:
146
+ if (parser->in_obj) {
147
+ /* we're in an object longer than the buffer */
148
+ char *start = pos;
149
+ char *end = start;
150
+ do {
151
+ end = memchr(end, '\n', (size_t)(stop - end));
152
+ } while (end && ++end &&
153
+ (size_t)(stop - end) >= (4 + parser->boundary_len) &&
154
+ (end[0] != '-' || end[1] != '-' ||
155
+ memcmp(end + 2, parser->boundary, parser->boundary_len)));
156
+ if (!end) {
157
+ end = (char *)stop;
158
+ pos = end;
159
+ if (end - start)
160
+ http_mime_parser_on_partial_data(parser, start, (size_t)(end - start));
161
+ goto end_of_data;
162
+ } else if (end + 4 + parser->boundary_len >= stop) {
163
+ end -= 2;
164
+ if (end[0] == '\r')
165
+ --end;
166
+ pos = end;
167
+ if (end - start)
168
+ http_mime_parser_on_partial_data(parser, start, (size_t)(end - start));
169
+ goto end_of_data;
170
+ }
171
+ size_t len = (end - start) - 1;
172
+ if (start[len - 1] == '\r')
173
+ --len;
174
+ if (len)
175
+ http_mime_parser_on_partial_data(parser, start, len);
176
+ http_mime_parser_on_partial_end(parser);
177
+ pos = end;
178
+ parser->in_obj = 0;
179
+ first_run = 0;
180
+ } else if (length < (4 + parser->boundary_len) || pos[0] != '-' ||
181
+ pos[1] != '-' ||
182
+ memcmp(pos + 2, parser->boundary, parser->boundary_len))
183
+ goto error;
184
+ /* We're at a boundary */
185
+ while (pos < stop) {
186
+ char *start;
187
+ char *end;
188
+ char *name = NULL;
189
+ uint32_t name_len = 0;
190
+ char *value = NULL;
191
+ uint32_t value_len = 0;
192
+ char *filename = NULL;
193
+ uint32_t filename_len = 0;
194
+ char *mime = NULL;
195
+ uint32_t mime_len = 0;
196
+ uint8_t header_count = 0;
197
+ /* test for ending */
198
+ if (pos[2 + parser->boundary_len] == '-' &&
199
+ pos[3 + parser->boundary_len] == '-') {
200
+ pos += 5 + parser->boundary_len;
201
+ if (pos > stop)
202
+ pos = (char *)stop;
203
+ else if (pos < stop && pos[0] == '\n')
204
+ ++pos;
205
+ goto done;
206
+ }
207
+ start = pos + 3 + parser->boundary_len;
208
+ if (start[0] == '\n') {
209
+ /* should be true, unless new line marker was just '\n' */
210
+ ++start;
211
+ }
212
+ /* consume headers */
213
+ while (start + 4 < stop && start[0] != '\n' && start[1] != '\n') {
214
+ end = memchr(start, '\n', (size_t)(stop - start));
215
+ if (!end) {
216
+ if (first_run)
217
+ goto error;
218
+ goto end_of_data;
219
+ }
220
+ if (end - start > 29 && !strncasecmp(start, "content-disposition:", 20)) {
221
+ /* content-disposition header */
222
+ start = memchr(start + 20, ';', end - (start + 20));
223
+ // if (!start)
224
+ // start = end + 1;
225
+ while (start) {
226
+ ++start;
227
+ if (start[0] == ' ')
228
+ ++start;
229
+ if (start + 6 < end && !strncasecmp(start, "name=", 5)) {
230
+ name = start + 5;
231
+ if (name[0] == '"')
232
+ ++name;
233
+ start = memchr(name, ';', (size_t)(end - start));
234
+ if (!start) {
235
+ name_len = (size_t)(end - name);
236
+ if (name[name_len - 1] == '\r')
237
+ --name_len;
238
+ } else {
239
+ name_len = (size_t)(start - name);
240
+ }
241
+ if (name[name_len - 1] == '"')
242
+ --name_len;
243
+ } else if (start + 9 < end && !strncasecmp(start, "filename", 8)) {
244
+ uint8_t encoded = 0;
245
+ start += 8;
246
+ if (start[0] == '*') {
247
+ encoded = 1;
248
+ ++start;
249
+ }
250
+ if (start[0] != '=')
251
+ goto error;
252
+ ++start;
253
+ if (start[0] == ' ')
254
+ ++start;
255
+ if (start[0] == '"')
256
+ ++start;
257
+ if (filename && !encoded) {
258
+ /* prefer URL encoded version */
259
+ start = memchr(filename, ';', (size_t)(end - start));
260
+ continue;
261
+ }
262
+ filename = start;
263
+ start = memchr(filename, ';', (size_t)(end - start));
264
+ if (!start) {
265
+ filename_len = (size_t)((end - filename));
266
+ if (filename[filename_len - 1] == '\r') {
267
+ --filename_len;
268
+ }
269
+ } else {
270
+ filename_len = (size_t)(start - filename);
271
+ }
272
+ if (filename[filename_len - 1] == '"')
273
+ --filename_len;
274
+ if (encoded) {
275
+ ssize_t new_len =
276
+ http_mime_decode_url(filename, filename, filename_len);
277
+ if (new_len > 0)
278
+ filename_len = new_len;
279
+ }
280
+ } else {
281
+ start = memchr(start, ';', (size_t)(end - start));
282
+ }
283
+ }
284
+ } else if (end - start > 14 && !strncasecmp(start, "content-type:", 13)) {
285
+ /* content-type header */
286
+ start += 13;
287
+ if (start[0] == ' ')
288
+ ++start;
289
+ mime = start;
290
+ start = memchr(start, ';', (size_t)(end - start));
291
+ if (!start) {
292
+ mime_len = (size_t)(end - mime);
293
+ if (mime[mime_len - 1] == '\r')
294
+ --mime_len;
295
+ } else {
296
+ mime_len = (size_t)(start - mime);
297
+ }
298
+ }
299
+ start = end + 1;
300
+ if (header_count++ > 4)
301
+ goto error;
302
+ }
303
+ if (!name) {
304
+ if (start + 4 >= stop)
305
+ goto end_of_data;
306
+ goto error;
307
+ }
308
+
309
+ /* advance to end of boundry */
310
+ ++start;
311
+ if (start[0] == '\n')
312
+ ++start;
313
+ value = start;
314
+ end = start;
315
+ do {
316
+ end = memchr(end, '\n', (size_t)(stop - end));
317
+ } while (end && ++end &&
318
+ (size_t)(stop - end) >= (4 + parser->boundary_len) &&
319
+ (end[0] != '-' || end[1] != '-' ||
320
+ memcmp(end + 2, parser->boundary, parser->boundary_len)));
321
+ if (!end || end + 4 + parser->boundary_len >= stop) {
322
+ if (first_run) {
323
+ http_mime_parser_on_partial_start(parser, name, name_len, filename,
324
+ filename_len, mime, mime_len);
325
+ parser->in_obj = 1;
326
+ pos = value;
327
+ goto consume_partial;
328
+ }
329
+ goto end_of_data;
330
+ }
331
+ value_len = (size_t)((end - value) - 1);
332
+ if (value[value_len - 1] == '\r')
333
+ --value_len;
334
+ pos = end;
335
+ http_mime_parser_on_data(parser, name, name_len, filename, filename_len,
336
+ mime, mime_len, value, value_len);
337
+ first_run = 0;
338
+ }
339
+ end_of_data:
340
+ return (size_t)((uintptr_t)pos - (uintptr_t)buffer);
341
+ done:
342
+ parser->done = 1;
343
+ parser->error = 0;
344
+ return (size_t)((uintptr_t)pos - (uintptr_t)buffer);
345
+ error:
346
+ parser->done = 0;
347
+ parser->error = 1;
348
+ return (size_t)((uintptr_t)pos - (uintptr_t)buffer);
349
+ }
350
+ #endif