iodine 0.2.17 → 0.3.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 (55) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +6 -0
  3. data/README.md +36 -3
  4. data/bin/config.ru +23 -2
  5. data/bin/http-hello +1 -1
  6. data/bin/ws-shootout +5 -0
  7. data/ext/iodine/defer.c +468 -0
  8. data/ext/iodine/defer.h +105 -0
  9. data/ext/iodine/evio.c +263 -0
  10. data/ext/iodine/evio.h +133 -0
  11. data/ext/iodine/extconf.rb +2 -1
  12. data/ext/iodine/facil.c +958 -0
  13. data/ext/iodine/facil.h +423 -0
  14. data/ext/iodine/http.c +90 -0
  15. data/ext/iodine/http.h +50 -12
  16. data/ext/iodine/http1.c +200 -267
  17. data/ext/iodine/http1.h +17 -26
  18. data/ext/iodine/http1_request.c +81 -0
  19. data/ext/iodine/http1_request.h +58 -0
  20. data/ext/iodine/http1_response.c +403 -0
  21. data/ext/iodine/http1_response.h +90 -0
  22. data/ext/iodine/http1_simple_parser.c +124 -108
  23. data/ext/iodine/http1_simple_parser.h +8 -3
  24. data/ext/iodine/http_request.c +104 -0
  25. data/ext/iodine/http_request.h +58 -102
  26. data/ext/iodine/http_response.c +212 -208
  27. data/ext/iodine/http_response.h +89 -252
  28. data/ext/iodine/iodine_core.c +57 -46
  29. data/ext/iodine/iodine_core.h +3 -1
  30. data/ext/iodine/iodine_http.c +105 -81
  31. data/ext/iodine/iodine_websocket.c +17 -13
  32. data/ext/iodine/iodine_websocket.h +1 -0
  33. data/ext/iodine/rb-call.c +9 -7
  34. data/ext/iodine/{rb-libasync.h → rb-defer.c} +57 -49
  35. data/ext/iodine/rb-rack-io.c +12 -6
  36. data/ext/iodine/rb-rack-io.h +1 -1
  37. data/ext/iodine/rb-registry.c +5 -2
  38. data/ext/iodine/sock.c +1159 -0
  39. data/ext/iodine/{libsock.h → sock.h} +138 -142
  40. data/ext/iodine/spnlock.inc +77 -0
  41. data/ext/iodine/websockets.c +101 -112
  42. data/ext/iodine/websockets.h +38 -19
  43. data/iodine.gemspec +3 -3
  44. data/lib/iodine/version.rb +1 -1
  45. data/lib/rack/handler/iodine.rb +6 -6
  46. metadata +23 -19
  47. data/ext/iodine/http_response_http1.h +0 -382
  48. data/ext/iodine/libasync.c +0 -570
  49. data/ext/iodine/libasync.h +0 -122
  50. data/ext/iodine/libreact.c +0 -350
  51. data/ext/iodine/libreact.h +0 -244
  52. data/ext/iodine/libserver.c +0 -957
  53. data/ext/iodine/libserver.h +0 -481
  54. data/ext/iodine/libsock.c +0 -1025
  55. data/ext/iodine/spnlock.h +0 -243
@@ -0,0 +1,90 @@
1
+ #ifndef H_HTTP1_RESPONSE_H
2
+ #define H_HTTP1_RESPONSE_H
3
+
4
+ #include "http1.h"
5
+
6
+ /* *****************************************************************************
7
+ Initialization
8
+ ***************************************************************************** */
9
+
10
+ /** Creates / allocates a protocol version's response object. */
11
+ http_response_s *http1_response_create(http_request_s *request);
12
+ /** Destroys the response object. No data is sent.*/
13
+ void http1_response_destroy(http_response_s *);
14
+ /** Sends the data and destroys the response object.*/
15
+ void http1_response_finish(http_response_s *);
16
+
17
+ /* *****************************************************************************
18
+ Writing data to the response object
19
+ ***************************************************************************** */
20
+
21
+ /**
22
+ Writes a header to the response. This function writes only the requested
23
+ number of bytes from the header name and the requested number of bytes from
24
+ the header value. It can be used even when the header name and value don't
25
+ contain NULL terminating bytes by passing the `.name_len` or `.value_len` data
26
+ in the `http_headers_s` structure.
27
+
28
+ If the header buffer is full or the headers were already sent (new headers
29
+ cannot be sent), the function will return -1.
30
+
31
+ On success, the function returns 0.
32
+ */
33
+ int http1_response_write_header_fn(http_response_s *, http_header_s header);
34
+
35
+ /**
36
+ Set / Delete a cookie using this helper function.
37
+
38
+ To set a cookie, use (in this example, a session cookie):
39
+
40
+ http_response_set_cookie(response,
41
+ .name = "my_cookie",
42
+ .value = "data");
43
+
44
+ To delete a cookie, use:
45
+
46
+ http_response_set_cookie(response,
47
+ .name = "my_cookie",
48
+ .value = NULL);
49
+
50
+ This function writes a cookie header to the response. Only the requested
51
+ number of bytes from the cookie value and name are written (if none are
52
+ provided, a terminating NULL byte is assumed).
53
+
54
+ Both the name and the value of the cookie are checked for validity (legal
55
+ characters), but other properties aren't reviewed (domain/path) - please make
56
+ sure to use only valid data, as HTTP imposes restrictions on these things.
57
+
58
+ If the header buffer is full or the headers were already sent (new headers
59
+ cannot be sent), the function will return -1.
60
+
61
+ On success, the function returns 0.
62
+ */
63
+ int http1_response_set_cookie(http_response_s *, http_cookie_s);
64
+
65
+ /**
66
+ Sends the headers (if they weren't previously sent) and writes the data to the
67
+ underlying socket.
68
+
69
+ The body will be copied to the server's outgoing buffer.
70
+
71
+ If the connection was already closed, the function will return -1. On success,
72
+ the function returns 0.
73
+ */
74
+ int http1_response_write_body(http_response_s *, const char *body,
75
+ size_t length);
76
+
77
+ /**
78
+ Sends the headers (if they weren't previously sent) and writes the data to the
79
+ underlying socket.
80
+
81
+ The server's outgoing buffer will take ownership of the file and close it
82
+ using `close` once the data was sent.
83
+
84
+ If the connection was already closed, the function will return -1. On success,
85
+ the function returns 0.
86
+ */
87
+ int http1_response_sendfile(http_response_s *, int source_fd, off_t offset,
88
+ size_t length);
89
+
90
+ #endif
@@ -4,7 +4,10 @@ license: MIT
4
4
 
5
5
  Feel free to copy, use and enjoy according to the license provided.
6
6
  */
7
+ #define _GNU_SOURCE
7
8
  #include "http1_simple_parser.h"
9
+ #include <stdlib.h>
10
+ #include <string.h>
8
11
  #include <strings.h>
9
12
 
10
13
  #ifdef __has_include
@@ -24,15 +27,17 @@ Feel free to copy, use and enjoy according to the license provided.
24
27
  Useful macros an helpers
25
28
  */
26
29
 
30
+ /*
27
31
  #define a2i(a) \
28
32
  (((a) >= '0' && a <= '9') ? ((a) - '0') : ({ \
29
33
  return -1; \
30
34
  0; \
31
35
  }))
36
+ */
32
37
 
33
38
  #define CHECK_END() \
34
39
  { \
35
- request->metadata.next = pos; \
40
+ request->udata = pos; \
36
41
  if (pos >= end) { \
37
42
  return -2; \
38
43
  } \
@@ -45,6 +50,12 @@ Useful macros an helpers
45
50
  if (*pos == '\n' || *pos == 0) \
46
51
  *(pos++) = 0; \
47
52
  }
53
+ #undef EAT_EOL
54
+ #define EAT_EOL() \
55
+ { \
56
+ *(pos++) = 0; \
57
+ *(pos++) = 0; \
58
+ }
48
59
 
49
60
  static inline char *seek_to_char(char *start, char *end, char tok) {
50
61
  while (start < end) {
@@ -84,96 +95,89 @@ static inline char *seek_to_2eol(char *start, char *end) {
84
95
 
85
96
  /* reviews the latest header and updates any required data in the request
86
97
  * structure. */
87
- static inline ssize_t review_header_data(http_request_s *request, char *tmp) {
88
- // if (request->headers[request->headers_count].name_length == 4 &&
89
- // strncmp(request->headers[request->headers_count].name, HOST, 4) == 0)
90
- // {
91
- // request->host = (void*)tmp;
92
- // request->host_len =
93
- // request->headers[request->headers_count].value_length;
94
- // } else
95
- if (request->headers[request->headers_count].name_length == 4 &&
96
- *((uint32_t *)request->headers[request->headers_count].name) ==
97
- *((uint32_t *)HOST)) { // exact match
98
- request->host = (void *)tmp;
99
- request->host_len = request->headers[request->headers_count].value_length;
100
- } else if (request->headers[request->headers_count].name_length == 12 &&
101
- *((uint64_t *)(request->headers[request->headers_count].name +
102
- 3)) ==
98
+ static inline ssize_t review_header_data(http_request_s *request,
99
+ http_header_s *header) {
100
+ if (header->name_len == 4 &&
101
+ *((uint32_t *)header->name) == *((uint32_t *)HOST)) { // exact match
102
+ request->host = (void *)header->data;
103
+ request->host_len = header->data_len;
104
+ } else if (header->name_len == 12 &&
105
+ *((uint64_t *)(header->name + 3)) ==
103
106
  *((uint64_t *)(CONTENT_TYPE + 3))) { // almost
104
- request->content_type = (void *)tmp;
105
- request->content_type_len =
106
- request->headers[request->headers_count].value_length;
107
- } else if (request->headers[request->headers_count].name_length == 14 &&
108
- *((uint64_t *)(request->headers[request->headers_count].name +
109
- 3)) ==
107
+ request->content_type = (void *)header->data;
108
+ request->content_type_len = header->data_len;
109
+ } else if (header->name_len == 14 &&
110
+ *((uint64_t *)(header->name + 3)) ==
110
111
  *((uint64_t *)(CONTENT_LENGTH + 3))) { // close match
111
112
  // tmp still holds a pointer to the value
112
113
  size_t c_len = 0;
114
+ char *tmp = (char *)header->data;
113
115
  while (*tmp) {
114
- c_len = (c_len * 10) + a2i(*tmp);
116
+ if ((*tmp) >= '0' && (*tmp) <= '9')
117
+ c_len = (c_len * 10) + ((*tmp) - '0');
118
+ else
119
+ return -1;
115
120
  ++tmp;
116
121
  };
117
122
  request->content_length = c_len;
118
- } else if (request->headers[request->headers_count].name_length == 7 &&
119
- *((uint64_t *)request->headers[request->headers_count].name) ==
120
- *((uint64_t *)UPGRADE)) { // matches also the NULL character
121
- request->upgrade = (void *)tmp;
122
- request->upgrade_len =
123
- request->headers[request->headers_count].value_length;
124
- } else if (request->headers[request->headers_count].name_length == 10 &&
125
- *((uint64_t *)request->headers[request->headers_count].name) ==
123
+ } else if (header->name_len == 7 &&
124
+ *((uint64_t *)header->name) ==
125
+ *((uint64_t *)UPGRADE)) { // matches also the NUL character
126
+ request->upgrade = (void *)header->data;
127
+ request->upgrade_len = header->data_len;
128
+ } else if (header->name_len == 10 &&
129
+ *((uint64_t *)header->name) ==
126
130
  *((uint64_t *)CONNECTION)) { // a close enough match
127
- request->connection = (void *)tmp;
128
- request->connection_len =
129
- request->headers[request->headers_count].value_length;
131
+ request->connection = (void *)header->data;
132
+ request->connection_len = header->data_len;
130
133
  }
131
134
  return 0;
132
135
  }
133
136
 
134
137
  #else
135
138
  /* unknown header case */
139
+ #define to_lower(c)
136
140
 
137
141
  static inline ssize_t review_header_data(http_request_s *request,
138
- uint8_t *tmp) {
139
- if (request->headers[request->headers_count].name_length == 4 &&
140
- strncasecmp(request->headers[request->headers_count].name, HOST, 4) ==
141
- 0) {
142
- request->host = (void *)tmp;
143
- request->host_len = request->headers[request->headers_count].value_length;
144
- } else if (request->headers[request->headers_count].name_length == 12 &&
145
- strncasecmp(request->headers[request->headers_count].name,
146
- CONTENT_TYPE, 12) == 0) {
147
- request->content_type = (void *)tmp;
148
- request->content_type_len =
149
- request->headers[request->headers_count].value_length;
150
- } else if (request->headers[request->headers_count].name_length == 14 &&
151
- strncasecmp(request->headers[request->headers_count].name,
152
- CONTENT_LENGTH, 14) == 0) {
142
+ http_header_s *header) {
143
+ if (header->name_len == 4 &&
144
+ strncasecmp((char *)header->name, HOST, 4) == 0) {
145
+ request->host = (void *)header->data;
146
+ request->host_len = header->data_len;
147
+ } else if (header->name_len == 12 &&
148
+ strncasecmp((char *)header->name, CONTENT_TYPE, 12) == 0) {
149
+ request->content_type = (void *)header->data;
150
+ request->content_type_len = header->data_len;
151
+ } else if (header->name_len == 14 &&
152
+ strncasecmp((char *)header->name, CONTENT_LENGTH, 14) == 0) {
153
153
  // tmp still holds a pointer to the value
154
154
  size_t c_len = 0;
155
+ char *tmp = (char *)header->data;
155
156
  while (*tmp) {
156
- c_len = (c_len * 10) + a2i(*tmp);
157
+ if ((*tmp) >= '0' && (*tmp) <= '9')
158
+ c_len = (c_len * 10) + ((*tmp) - '0');
159
+ else
160
+ return -1;
157
161
  ++tmp;
158
162
  };
159
163
  request->content_length = c_len;
160
- } else if (request->headers[request->headers_count].name_length == 7 &&
161
- strncasecmp(request->headers[request->headers_count].name, UPGRADE,
162
- 7) == 0) {
163
- request->upgrade = (void *)tmp;
164
- request->upgrade_len =
165
- request->headers[request->headers_count].value_length;
166
- } else if (request->headers[request->headers_count].name_length == 10 &&
167
- strncasecmp(request->headers[request->headers_count].name,
168
- CONNECTION, 10) == 0) {
169
- request->connection = (void *)tmp;
170
- request->connection_len =
171
- request->headers[request->headers_count].value_length;
164
+ } else if (header->name_len == 7 &&
165
+ strncasecmp((char *)header->name, UPGRADE, 7) == 0) {
166
+ request->upgrade = (void *)header->data;
167
+ request->upgrade_len = header->data_len;
168
+ } else if (header->name_len == 10 &&
169
+ strncasecmp((char *)header->name, CONNECTION, 10) == 0) {
170
+ request->connection = (void *)header->data;
171
+ request->connection_len = header->data_len;
172
172
  }
173
173
  return 0;
174
174
  }
175
175
  #endif
176
176
 
177
+ static void no_on_header_found(http_request_s *request, http_header_s *header) {
178
+ (void)request;
179
+ (void)header;
180
+ }
177
181
  /* *****************************************************************************
178
182
  The (public) parsing
179
183
  */
@@ -194,33 +198,40 @@ buffer
194
198
  and the same `http_request_s` should be returned to the parsed on the "next
195
199
  round", only the `len` argument is expected to grow.
196
200
  */
197
- ssize_t http1_parse_request_headers(void *buffer, size_t len,
198
- http_request_s *request) {
199
- if (request == NULL || buffer == NULL || request->metadata.max_headers == 0)
201
+ ssize_t http1_parse_request_headers(
202
+ void *buffer, size_t len, http_request_s *request,
203
+ void (*on_header_found)(http_request_s *request, http_header_s *header)) {
204
+ if (request == NULL || buffer == NULL)
200
205
  return -1;
206
+ if (!on_header_found)
207
+ on_header_found = no_on_header_found;
201
208
  if (request->body_str || request->body_file > 0)
202
209
  return 0;
203
210
  if (len == 0)
204
211
  return -2;
205
- char *pos = buffer;
206
- char *end = buffer + len;
212
+ http_header_s header;
213
+ char *pos = (char *)buffer;
214
+ char *end = (char *)buffer + len;
207
215
  char *next, *tmp;
208
216
  // collect method and restart parser if already collected
209
217
  if (request->method == NULL) {
210
218
  // eat empty spaces
211
219
  while ((*pos == '\n' || *pos == '\r') && pos < end)
212
220
  ++pos;
221
+ CHECK_END();
213
222
  request->method = (char *)pos;
214
223
  next = seek_to_char(pos, end, ' ');
215
- if (next == NULL)
216
- return -1; /* there should be a limit to all fragmentations. */
224
+ if (next == NULL) {
225
+ request->method = NULL;
226
+ return -2;
227
+ }
217
228
  request->method_len = (uintptr_t)next - (uintptr_t)pos;
218
229
  pos = next;
219
230
  *(pos++) = 0;
220
231
  CHECK_END();
221
232
  } else {
222
- /* use the `next` pointer to store current position in the buffer */
223
- pos = request->metadata.next;
233
+ /* use the `udata` pointer to store current position in the buffer */
234
+ pos = request->udata;
224
235
  CHECK_END();
225
236
  }
226
237
  // collect path
@@ -252,14 +263,16 @@ ssize_t http1_parse_request_headers(void *buffer, size_t len,
252
263
  EAT_EOL();
253
264
  CHECK_END();
254
265
  }
266
+
255
267
  // collect headers
256
- while (pos < end && *pos != '\n' && *pos != '\r' &&
257
- *pos != 0) { /* NUL as term? */
258
- if (request->headers_count >= request->metadata.max_headers)
268
+ while (pos < end && *pos != 0) { /* NUL as term */
269
+ if (request->headers_count >= HTTP1_MAX_HEADER_COUNT)
259
270
  return -1;
260
271
  next = seek_to_2eol(pos, end);
261
272
  if (next == NULL)
262
273
  return -2;
274
+ if (next == pos) /*headers finished */
275
+ break;
263
276
  #if defined(HTTP_HEADERS_LOWERCASE) && HTTP_HEADERS_LOWERCASE == 1
264
277
  tmp = pos;
265
278
  while (tmp < next && *tmp != ':') {
@@ -273,29 +286,29 @@ ssize_t http1_parse_request_headers(void *buffer, size_t len,
273
286
  if (!tmp)
274
287
  return -1;
275
288
  #endif
276
- request->headers[request->headers_count].name = (void *)pos;
277
- request->headers[request->headers_count].name_length = tmp - pos;
289
+ header.name = (void *)pos;
290
+ header.name_len = (uintptr_t)(tmp - pos);
278
291
  *(tmp++) = 0;
279
292
  if (*tmp == ' ')
280
293
  *(tmp++) = 0;
281
- request->headers[request->headers_count].value = (char *)tmp;
282
- request->headers[request->headers_count].value_length = next - tmp;
294
+ header.data = (void *)tmp;
295
+ header.data_len = (uintptr_t)(next - tmp);
283
296
  // eat EOL before content-length processing.
284
297
  pos = next;
285
298
  EAT_EOL();
286
299
  // print debug info
287
- // fprintf(stderr, "Got header %s (%u): %s (%u)\n",
288
- // request->headers[request->headers_count].name,
289
- // request->headers[request->headers_count].name_length,
290
- // request->headers[request->headers_count].value,
291
- // request->headers[request->headers_count].value_length);
300
+ // fprintf(stderr, "Got header %s (%u): %s (%u)\n", header.name,
301
+ // header.name_len, header.data, header.data_len);
292
302
  // check special headers and assign value.
293
- review_header_data(request, tmp);
294
- // advance header position
303
+ review_header_data(request, &header);
295
304
  request->headers_count += 1;
305
+ on_header_found(request, &header);
306
+ // advance header position
296
307
  CHECK_END();
297
308
  }
298
- // check if the body is contained within the buffer
309
+ // Did we break because there's no more data or end of headers?
310
+ CHECK_END();
311
+ // "eat" the end of headers line and finish processing.
299
312
  EAT_EOL();
300
313
  if (request->content_length &&
301
314
  (end - pos) >= (ssize_t)request->content_length) {
@@ -308,9 +321,8 @@ ssize_t http1_parse_request_headers(void *buffer, size_t len,
308
321
  // request->body_str);
309
322
  return (ssize_t)(pos - (char *)buffer) + request->content_length;
310
323
  }
311
-
312
324
  // we're done.
313
- return pos - (char *)buffer;
325
+ return (ssize_t)(pos - (char *)buffer);
314
326
  }
315
327
 
316
328
  /**
@@ -347,28 +359,26 @@ ssize_t http1_parse_request_body(void *buffer, size_t len,
347
359
  if (request->body_file == -1)
348
360
  return -1;
349
361
  // use the `next` field to store parser state.
350
- uintptr_t *tmp = (uintptr_t *)(&request->metadata.next);
362
+ uintptr_t *tmp = (uintptr_t *)(&request->udata);
351
363
  *tmp = 0;
352
364
  }
353
365
  // make sure we have anything to read. This might be an initializing call.
354
366
  if (len == 0)
355
- return ((uintptr_t)(request->metadata.next)) >= request->content_length
356
- ? 0
357
- : (-2);
367
+ return ((uintptr_t)(request->udata)) >= request->content_length ? 0 : (-2);
358
368
  // Calculate how much of the buffer should be read.
359
369
  ssize_t to_read =
360
- ((request->content_length - ((uintptr_t)request->metadata.next)) < len)
361
- ? (request->content_length - ((uintptr_t)request->metadata.next))
370
+ ((request->content_length - ((uintptr_t)request->udata)) < len)
371
+ ? (request->content_length - ((uintptr_t)request->udata))
362
372
  : len;
363
373
  // write the data to the temporary file.
364
374
  if (write(request->body_file, buffer, to_read) < to_read)
365
375
  return -1;
366
376
  // update the `next` field data with the received content length
367
- uintptr_t *tmp = (uintptr_t *)(&request->metadata.next);
377
+ uintptr_t *tmp = (uintptr_t *)(&request->udata);
368
378
  *tmp += to_read; // request->metadata.next += to_read;
369
379
 
370
380
  // check the state and return.
371
- if (((uintptr_t)request->metadata.next) >= request->content_length) {
381
+ if (((uintptr_t)request->udata) >= request->content_length) {
372
382
  lseek(request->body_file, 0, SEEK_SET);
373
383
  return to_read;
374
384
  }
@@ -377,9 +387,11 @@ ssize_t http1_parse_request_body(void *buffer, size_t len,
377
387
 
378
388
  #if defined(DEBUG) && DEBUG == 1
379
389
 
390
+ // #include "http1_request.h"
391
+
380
392
  #include <time.h>
381
393
 
382
- void http_parser_test(void) {
394
+ void http1_parser_test(void) {
383
395
  char request_text[] = "GET /?a=b HTTP/1.1\r\n"
384
396
  "Host: local\r\n"
385
397
  "Upgrade: websocket\r\n"
@@ -388,11 +400,9 @@ void http_parser_test(void) {
388
400
  "\r\n"
389
401
  "Hello World!\r\n";
390
402
  size_t request_length = sizeof(request_text) - 1;
391
- uint8_t request_mem[HTTP_REQUEST_SIZE(24)] = {};
392
- http_request_s *request = (void *)request_mem;
393
- *request = (http_request_s){.metadata.max_headers = 24};
403
+ http_request_s *request = http_request_create(HTTP_V1);
394
404
  ssize_t ret =
395
- http1_parse_request_headers(request_text, request_length, request);
405
+ http1_parse_request_headers(request_text, request_length, request, NULL);
396
406
  if (ret == -1) {
397
407
  fprintf(stderr, "* Parser FAILED -1.\n");
398
408
  } else if (ret == -2) {
@@ -436,7 +446,12 @@ void http_parser_test(void) {
436
446
  "Connection: close\r\n"
437
447
  "\r\n"
438
448
  "Hello World!\r\n";
439
- http1_parse_request_headers(request_text2, request_length, request);
449
+ if (http1_parse_request_headers(request_text2, request_length, request,
450
+ NULL) <= 0 ||
451
+ (request->upgrade_len != 9)) {
452
+ fprintf(stderr, "* HTTP/1.1 simple_parser unknown error\n");
453
+ return;
454
+ }
440
455
  http_request_clear(request);
441
456
  }
442
457
  end = clock();
@@ -450,16 +465,17 @@ void http_parser_test(void) {
450
465
  "\r\n"
451
466
  "Hello World!\r\n";
452
467
  fprintf(stderr, "start\n");
453
- if (http1_parse_request_headers(request_text2, 7, request) != -2)
468
+ if (http1_parse_request_headers(request_text2, 7, request, NULL) != -2)
454
469
  fprintf(stderr, "Fragmented Parsing FAILED\n");
455
470
  fprintf(stderr, "step\n");
456
- if (http1_parse_request_headers(request_text2, 27, request) != -2)
471
+ if (http1_parse_request_headers(request_text2, 27, request, NULL) != -2)
457
472
  fprintf(stderr, "Fragmented Parsing FAILED\n");
458
473
  fprintf(stderr, "step\n");
459
- if (http1_parse_request_headers(request_text2, 38, request) != -2)
474
+ if (http1_parse_request_headers(request_text2, 38, request, NULL) != -2)
460
475
  fprintf(stderr, "Fragmented Parsing FAILED\n");
461
476
  fprintf(stderr, "step\n");
462
- if ((ret = http1_parse_request_headers(request_text2, 98, request)) != 94)
477
+ if ((ret = http1_parse_request_headers(request_text2, 98, request, NULL)) !=
478
+ 94)
463
479
  fprintf(stderr, "Fragmented Parsing (some body) FAILED\n");
464
480
  fprintf(stderr, "read: %lu\n", ret);
465
481
  if ((ret += http1_parse_request_body(request_text2 + ret,
@@ -474,7 +490,7 @@ void http_parser_test(void) {
474
490
  perror("Couldn't read temporary file");
475
491
  fprintf(stderr, "Body:\n%.*s\n", (int)request->content_length, request_text);
476
492
 
477
- http_request_clear(request);
493
+ http_request_destroy(request);
478
494
  }
479
495
 
480
496
  #endif