Coverage Report

Created: 2026-02-14 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/llhttp/src/native/api.c
Line
Count
Source
1
#include <stdlib.h>
2
#include <stdio.h>
3
#include <string.h>
4
5
#include "llhttp.h"
6
7
#define CALLBACK_MAYBE(PARSER, NAME)                                          \
8
289k
  do {                                                                        \
9
289k
    const llhttp_settings_t* settings;                                        \
10
289k
    settings = (const llhttp_settings_t*) (PARSER)->settings;                 \
11
289k
    if (settings == NULL || settings->NAME == NULL) {                         \
12
254k
      err = 0;                                                                \
13
254k
      break;                                                                  \
14
254k
    }                                                                         \
15
289k
    err = settings->NAME((PARSER));                                           \
16
34.9k
  } while (0)
17
18
#define SPAN_CALLBACK_MAYBE(PARSER, NAME, START, LEN)                         \
19
134k
  do {                                                                        \
20
134k
    const llhttp_settings_t* settings;                                        \
21
134k
    settings = (const llhttp_settings_t*) (PARSER)->settings;                 \
22
134k
    if (settings == NULL || settings->NAME == NULL) {                         \
23
134k
      err = 0;                                                                \
24
134k
      break;                                                                  \
25
134k
    }                                                                         \
26
134k
    err = settings->NAME((PARSER), (START), (LEN));                           \
27
0
    if (err == -1) {                                                          \
28
0
      err = HPE_USER;                                                         \
29
0
      llhttp_set_error_reason((PARSER), "Span callback error in " #NAME);     \
30
0
    }                                                                         \
31
0
  } while (0)
32
33
void llhttp_init(llhttp_t* parser, llhttp_type_t type,
34
5.18k
                 const llhttp_settings_t* settings) {
35
5.18k
  llhttp__internal_init(parser);
36
37
5.18k
  parser->type = type;
38
5.18k
  parser->settings = (void*) settings;
39
5.18k
}
40
41
42
#if defined(__wasm__)
43
44
extern int wasm_on_message_begin(llhttp_t * p);
45
extern int wasm_on_url(llhttp_t* p, const char* at, size_t length);
46
extern int wasm_on_status(llhttp_t* p, const char* at, size_t length);
47
extern int wasm_on_header_field(llhttp_t* p, const char* at, size_t length);
48
extern int wasm_on_header_value(llhttp_t* p, const char* at, size_t length);
49
extern int wasm_on_headers_complete(llhttp_t * p, int status_code,
50
                                    uint8_t upgrade, int should_keep_alive);
51
extern int wasm_on_body(llhttp_t* p, const char* at, size_t length);
52
extern int wasm_on_message_complete(llhttp_t * p);
53
54
static int wasm_on_headers_complete_wrap(llhttp_t* p) {
55
  return wasm_on_headers_complete(p, p->status_code, p->upgrade,
56
                                  llhttp_should_keep_alive(p));
57
}
58
59
const llhttp_settings_t wasm_settings = {
60
  .on_message_begin = wasm_on_message_begin,
61
  .on_url = wasm_on_url,
62
  .on_status = wasm_on_status,
63
  .on_header_field = wasm_on_header_field,
64
  .on_header_value = wasm_on_header_value,
65
  .on_headers_complete = wasm_on_headers_complete_wrap,
66
  .on_body = wasm_on_body,
67
  .on_message_complete = wasm_on_message_complete,
68
};
69
70
71
llhttp_t* llhttp_alloc(llhttp_type_t type) {
72
  llhttp_t* parser = malloc(sizeof(llhttp_t));
73
  llhttp_init(parser, type, &wasm_settings);
74
  return parser;
75
}
76
77
void llhttp_free(llhttp_t* parser) {
78
  free(parser);
79
}
80
81
#endif  // defined(__wasm__)
82
83
/* Some getters required to get stuff from the parser */
84
85
0
uint8_t llhttp_get_type(llhttp_t* parser) {
86
0
  return parser->type;
87
0
}
88
89
0
uint8_t llhttp_get_http_major(llhttp_t* parser) {
90
0
  return parser->http_major;
91
0
}
92
93
0
uint8_t llhttp_get_http_minor(llhttp_t* parser) {
94
0
  return parser->http_minor;
95
0
}
96
97
0
uint8_t llhttp_get_method(llhttp_t* parser) {
98
0
  return parser->method;
99
0
}
100
101
0
int llhttp_get_status_code(llhttp_t* parser) {
102
0
  return parser->status_code;
103
0
}
104
105
0
uint8_t llhttp_get_upgrade(llhttp_t* parser) {
106
0
  return parser->upgrade;
107
0
}
108
109
110
0
void llhttp_reset(llhttp_t* parser) {
111
0
  llhttp_type_t type = parser->type;
112
0
  const llhttp_settings_t* settings = parser->settings;
113
0
  void* data = parser->data;
114
0
  uint16_t lenient_flags = parser->lenient_flags;
115
116
0
  llhttp__internal_init(parser);
117
118
0
  parser->type = type;
119
0
  parser->settings = (void*) settings;
120
0
  parser->data = data;
121
0
  parser->lenient_flags = lenient_flags;
122
0
}
123
124
125
5.18k
llhttp_errno_t llhttp_execute(llhttp_t* parser, const char* data, size_t len) {
126
5.18k
  return llhttp__internal_execute(parser, data, data + len);
127
5.18k
}
128
129
130
5.18k
void llhttp_settings_init(llhttp_settings_t* settings) {
131
5.18k
  memset(settings, 0, sizeof(*settings));
132
5.18k
}
133
134
135
0
llhttp_errno_t llhttp_finish(llhttp_t* parser) {
136
0
  int err;
137
138
  /* We're in an error state. Don't bother doing anything. */
139
0
  if (parser->error != 0) {
140
0
    return 0;
141
0
  }
142
143
0
  switch (parser->finish) {
144
0
    case HTTP_FINISH_SAFE_WITH_CB:
145
0
      CALLBACK_MAYBE(parser, on_message_complete);
146
0
      if (err != HPE_OK) return err;
147
148
    /* FALLTHROUGH */
149
0
    case HTTP_FINISH_SAFE:
150
0
      return HPE_OK;
151
0
    case HTTP_FINISH_UNSAFE:
152
0
      parser->reason = "Invalid EOF state";
153
0
      return HPE_INVALID_EOF_STATE;
154
0
    default:
155
0
      abort();
156
0
  }
157
0
}
158
159
160
0
void llhttp_pause(llhttp_t* parser) {
161
0
  if (parser->error != HPE_OK) {
162
0
    return;
163
0
  }
164
165
0
  parser->error = HPE_PAUSED;
166
0
  parser->reason = "Paused";
167
0
}
168
169
170
0
void llhttp_resume(llhttp_t* parser) {
171
0
  if (parser->error != HPE_PAUSED) {
172
0
    return;
173
0
  }
174
175
0
  parser->error = 0;
176
0
}
177
178
179
0
void llhttp_resume_after_upgrade(llhttp_t* parser) {
180
0
  if (parser->error != HPE_PAUSED_UPGRADE) {
181
0
    return;
182
0
  }
183
184
0
  parser->error = 0;
185
0
}
186
187
188
0
llhttp_errno_t llhttp_get_errno(const llhttp_t* parser) {
189
0
  return parser->error;
190
0
}
191
192
193
0
const char* llhttp_get_error_reason(const llhttp_t* parser) {
194
0
  return parser->reason;
195
0
}
196
197
198
0
void llhttp_set_error_reason(llhttp_t* parser, const char* reason) {
199
0
  parser->reason = reason;
200
0
}
201
202
203
0
const char* llhttp_get_error_pos(const llhttp_t* parser) {
204
0
  return parser->error_pos;
205
0
}
206
207
208
0
const char* llhttp_errno_name(llhttp_errno_t err) {
209
0
#define HTTP_ERRNO_GEN(CODE, NAME, _) case HPE_##NAME: return "HPE_" #NAME;
210
0
  switch (err) {
211
0
    HTTP_ERRNO_MAP(HTTP_ERRNO_GEN)
212
0
    default: abort();
213
0
  }
214
0
#undef HTTP_ERRNO_GEN
215
0
}
216
217
218
0
const char* llhttp_method_name(llhttp_method_t method) {
219
0
#define HTTP_METHOD_GEN(NUM, NAME, STRING) case HTTP_##NAME: return #STRING;
220
0
  switch (method) {
221
0
    HTTP_ALL_METHOD_MAP(HTTP_METHOD_GEN)
222
0
    default: abort();
223
0
  }
224
0
#undef HTTP_METHOD_GEN
225
0
}
226
227
0
const char* llhttp_status_name(llhttp_status_t status) {
228
0
#define HTTP_STATUS_GEN(NUM, NAME, STRING) case HTTP_STATUS_##NAME: return #STRING;
229
0
  switch (status) {
230
0
    HTTP_STATUS_MAP(HTTP_STATUS_GEN)
231
0
    default: abort();
232
0
  }
233
0
#undef HTTP_STATUS_GEN
234
0
}
235
236
237
5.18k
void llhttp_set_lenient_headers(llhttp_t* parser, int enabled) {
238
5.18k
  if (enabled) {
239
3.63k
    parser->lenient_flags |= LENIENT_HEADERS;
240
3.63k
  } else {
241
1.55k
    parser->lenient_flags &= ~LENIENT_HEADERS;
242
1.55k
  }
243
5.18k
}
244
245
246
5.18k
void llhttp_set_lenient_chunked_length(llhttp_t* parser, int enabled) {
247
5.18k
  if (enabled) {
248
2.42k
    parser->lenient_flags |= LENIENT_CHUNKED_LENGTH;
249
2.76k
  } else {
250
2.76k
    parser->lenient_flags &= ~LENIENT_CHUNKED_LENGTH;
251
2.76k
  }
252
5.18k
}
253
254
255
5.18k
void llhttp_set_lenient_keep_alive(llhttp_t* parser, int enabled) {
256
5.18k
  if (enabled) {
257
3.74k
    parser->lenient_flags |= LENIENT_KEEP_ALIVE;
258
3.74k
  } else {
259
1.44k
    parser->lenient_flags &= ~LENIENT_KEEP_ALIVE;
260
1.44k
  }
261
5.18k
}
262
263
0
void llhttp_set_lenient_transfer_encoding(llhttp_t* parser, int enabled) {
264
0
  if (enabled) {
265
0
    parser->lenient_flags |= LENIENT_TRANSFER_ENCODING;
266
0
  } else {
267
0
    parser->lenient_flags &= ~LENIENT_TRANSFER_ENCODING;
268
0
  }
269
0
}
270
271
0
void llhttp_set_lenient_version(llhttp_t* parser, int enabled) {
272
0
  if (enabled) {
273
0
    parser->lenient_flags |= LENIENT_VERSION;
274
0
  } else {
275
0
    parser->lenient_flags &= ~LENIENT_VERSION;
276
0
  }
277
0
}
278
279
0
void llhttp_set_lenient_data_after_close(llhttp_t* parser, int enabled) {
280
0
  if (enabled) {
281
0
    parser->lenient_flags |= LENIENT_DATA_AFTER_CLOSE;
282
0
  } else {
283
0
    parser->lenient_flags &= ~LENIENT_DATA_AFTER_CLOSE;
284
0
  }
285
0
}
286
287
0
void llhttp_set_lenient_optional_lf_after_cr(llhttp_t* parser, int enabled) {
288
0
  if (enabled) {
289
0
    parser->lenient_flags |= LENIENT_OPTIONAL_LF_AFTER_CR;
290
0
  } else {
291
0
    parser->lenient_flags &= ~LENIENT_OPTIONAL_LF_AFTER_CR;
292
0
  }
293
0
}
294
295
0
void llhttp_set_lenient_optional_crlf_after_chunk(llhttp_t* parser, int enabled) {
296
0
  if (enabled) {
297
0
    parser->lenient_flags |= LENIENT_OPTIONAL_CRLF_AFTER_CHUNK;
298
0
  } else {
299
0
    parser->lenient_flags &= ~LENIENT_OPTIONAL_CRLF_AFTER_CHUNK;
300
0
  }
301
0
}
302
303
0
void llhttp_set_lenient_optional_cr_before_lf(llhttp_t* parser, int enabled) {
304
0
  if (enabled) {
305
0
    parser->lenient_flags |= LENIENT_OPTIONAL_CR_BEFORE_LF;
306
0
  } else {
307
0
    parser->lenient_flags &= ~LENIENT_OPTIONAL_CR_BEFORE_LF;
308
0
  }
309
0
}
310
311
0
void llhttp_set_lenient_spaces_after_chunk_size(llhttp_t* parser, int enabled) {
312
0
  if (enabled) {
313
0
    parser->lenient_flags |= LENIENT_SPACES_AFTER_CHUNK_SIZE;
314
0
  } else {
315
0
    parser->lenient_flags &= ~LENIENT_SPACES_AFTER_CHUNK_SIZE;
316
0
  }
317
0
}
318
319
/* Callbacks */
320
321
322
39.9k
int llhttp__on_message_begin(llhttp_t* s, const char* p, const char* endp) {
323
39.9k
  int err;
324
39.9k
  CALLBACK_MAYBE(s, on_message_begin);
325
39.9k
  return err;
326
39.9k
}
327
328
329
16.2k
int llhttp__on_protocol(llhttp_t* s, const char* p, const char* endp) {
330
16.2k
  int err;
331
16.2k
  SPAN_CALLBACK_MAYBE(s, on_protocol, p, endp - p);
332
16.2k
  return err;
333
16.2k
}
334
335
336
16.1k
int llhttp__on_protocol_complete(llhttp_t* s, const char* p, const char* endp) {
337
16.1k
  int err;
338
16.1k
  CALLBACK_MAYBE(s, on_protocol_complete);
339
16.1k
  return err;
340
16.1k
}
341
342
343
33.3k
int llhttp__on_url(llhttp_t* s, const char* p, const char* endp) {
344
33.3k
  int err;
345
33.3k
  SPAN_CALLBACK_MAYBE(s, on_url, p, endp - p);
346
33.3k
  return err;
347
33.3k
}
348
349
350
33.0k
int llhttp__on_url_complete(llhttp_t* s, const char* p, const char* endp) {
351
33.0k
  int err;
352
33.0k
  CALLBACK_MAYBE(s, on_url_complete);
353
33.0k
  return err;
354
33.0k
}
355
356
357
442
int llhttp__on_status(llhttp_t* s, const char* p, const char* endp) {
358
442
  int err;
359
442
  SPAN_CALLBACK_MAYBE(s, on_status, p, endp - p);
360
442
  return err;
361
442
}
362
363
364
4.53k
int llhttp__on_status_complete(llhttp_t* s, const char* p, const char* endp) {
365
4.53k
  int err;
366
4.53k
  CALLBACK_MAYBE(s, on_status_complete);
367
4.53k
  return err;
368
4.53k
}
369
370
371
34.3k
int llhttp__on_method(llhttp_t* s, const char* p, const char* endp) {
372
34.3k
  int err;
373
34.3k
  SPAN_CALLBACK_MAYBE(s, on_method, p, endp - p);
374
34.3k
  return err;
375
34.3k
}
376
377
378
33.7k
int llhttp__on_method_complete(llhttp_t* s, const char* p, const char* endp) {
379
33.7k
  int err;
380
33.7k
  CALLBACK_MAYBE(s, on_method_complete);
381
33.7k
  return err;
382
33.7k
}
383
384
385
15.7k
int llhttp__on_version(llhttp_t* s, const char* p, const char* endp) {
386
15.7k
  int err;
387
15.7k
  SPAN_CALLBACK_MAYBE(s, on_version, p, endp - p);
388
15.7k
  return err;
389
15.7k
}
390
391
392
15.6k
int llhttp__on_version_complete(llhttp_t* s, const char* p, const char* endp) {
393
15.6k
  int err;
394
15.6k
  CALLBACK_MAYBE(s, on_version_complete);
395
15.6k
  return err;
396
15.6k
}
397
398
399
11.1k
int llhttp__on_header_field(llhttp_t* s, const char* p, const char* endp) {
400
11.1k
  int err;
401
11.1k
  SPAN_CALLBACK_MAYBE(s, on_header_field, p, endp - p);
402
11.1k
  return err;
403
11.1k
}
404
405
406
10.9k
int llhttp__on_header_field_complete(llhttp_t* s, const char* p, const char* endp) {
407
10.9k
  int err;
408
10.9k
  CALLBACK_MAYBE(s, on_header_field_complete);
409
10.9k
  return err;
410
10.9k
}
411
412
413
12.2k
int llhttp__on_header_value(llhttp_t* s, const char* p, const char* endp) {
414
12.2k
  int err;
415
12.2k
  SPAN_CALLBACK_MAYBE(s, on_header_value, p, endp - p);
416
12.2k
  return err;
417
12.2k
}
418
419
420
10.2k
int llhttp__on_header_value_complete(llhttp_t* s, const char* p, const char* endp) {
421
10.2k
  int err;
422
10.2k
  CALLBACK_MAYBE(s, on_header_value_complete);
423
10.2k
  return err;
424
10.2k
}
425
426
427
35.9k
int llhttp__on_headers_complete(llhttp_t* s, const char* p, const char* endp) {
428
35.9k
  int err;
429
35.9k
  CALLBACK_MAYBE(s, on_headers_complete);
430
35.9k
  return err;
431
35.9k
}
432
433
434
34.9k
int llhttp__on_message_complete(llhttp_t* s, const char* p, const char* endp) {
435
34.9k
  int err;
436
34.9k
  CALLBACK_MAYBE(s, on_message_complete);
437
34.9k
  return err;
438
34.9k
}
439
440
441
8.01k
int llhttp__on_body(llhttp_t* s, const char* p, const char* endp) {
442
8.01k
  int err;
443
8.01k
  SPAN_CALLBACK_MAYBE(s, on_body, p, endp - p);
444
8.01k
  return err;
445
8.01k
}
446
447
448
8.44k
int llhttp__on_chunk_header(llhttp_t* s, const char* p, const char* endp) {
449
8.44k
  int err;
450
8.44k
  CALLBACK_MAYBE(s, on_chunk_header);
451
8.44k
  return err;
452
8.44k
}
453
454
455
1.85k
int llhttp__on_chunk_extension_name(llhttp_t* s, const char* p, const char* endp) {
456
1.85k
  int err;
457
1.85k
  SPAN_CALLBACK_MAYBE(s, on_chunk_extension_name, p, endp - p);
458
1.85k
  return err;
459
1.85k
}
460
461
462
1.84k
int llhttp__on_chunk_extension_name_complete(llhttp_t* s, const char* p, const char* endp) {
463
1.84k
  int err;
464
1.84k
  CALLBACK_MAYBE(s, on_chunk_extension_name_complete);
465
1.84k
  return err;
466
1.84k
}
467
468
469
1.16k
int llhttp__on_chunk_extension_value(llhttp_t* s, const char* p, const char* endp) {
470
1.16k
  int err;
471
1.16k
  SPAN_CALLBACK_MAYBE(s, on_chunk_extension_value, p, endp - p);
472
1.16k
  return err;
473
1.16k
}
474
475
476
1.12k
int llhttp__on_chunk_extension_value_complete(llhttp_t* s, const char* p, const char* endp) {
477
1.12k
  int err;
478
1.12k
  CALLBACK_MAYBE(s, on_chunk_extension_value_complete);
479
1.12k
  return err;
480
1.12k
}
481
482
483
8.28k
int llhttp__on_chunk_complete(llhttp_t* s, const char* p, const char* endp) {
484
8.28k
  int err;
485
8.28k
  CALLBACK_MAYBE(s, on_chunk_complete);
486
8.28k
  return err;
487
8.28k
}
488
489
490
34.7k
int llhttp__on_reset(llhttp_t* s, const char* p, const char* endp) {
491
34.7k
  int err;
492
34.7k
  CALLBACK_MAYBE(s, on_reset);
493
34.7k
  return err;
494
34.7k
}
495
496
497
/* Private */
498
499
500
void llhttp__debug(llhttp_t* s, const char* p, const char* endp,
501
0
                   const char* msg) {
502
0
  if (p == endp) {
503
0
    fprintf(stderr, "p=%p type=%d flags=%02x next=null debug=%s\n", s, s->type,
504
0
            s->flags, msg);
505
0
  } else {
506
    fprintf(stderr, "p=%p type=%d flags=%02x next=%02x   debug=%s\n", s,
507
0
            s->type, s->flags, *p, msg);
508
0
  }
509
0
}