emme coverage


Directory: src/
File: src/http_parser.c
Date: 2026-03-27 20:24:50
Exec Total Coverage
Lines: 41 41 100.0%
Functions: 1 1 100.0%
Branches: 24 32 75.0%

Line Branch Exec Source
1 #include "http_parser.h"
2 #include <string.h>
3 #include <ctype.h>
4
5 static const size_t MAX_REQUEST_LINE = 2048;
6
7 11 int parse_http_request(char *buffer, size_t len, HttpRequest *req) {
8 11 char *cursor = buffer;
9 11 char *end = buffer + len;
10 char *line_end;
11
12 // Parse the Request-Line: METHOD SP PATH SP VERSION CRLF
13 11 line_end = strstr(cursor, "\r\n");
14
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (!line_end) return -1;
15
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 10 times.
11 if ((size_t)(line_end - cursor) > MAX_REQUEST_LINE) return -1;
16 10 *line_end = '\0';
17
18 // Extract the method
19 10 char *method = cursor;
20 10 char *space = strchr(method, ' ');
21
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9 times.
10 if (!space) return -1;
22 9 *space = '\0';
23
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (method[0] == '\0') return -1;
24
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 8 times.
35 for (char *p = method; *p; p++) {
25
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 26 times.
27 if (!isupper((unsigned char)*p)) return -1;
26 }
27 8 req->method = method;
28
29 // Extract the path
30 8 char *path = space + 1;
31 8 space = strchr(path, ' ');
32
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 7 times.
8 if (!space) return -1;
33 7 *space = '\0';
34 7 req->path = path;
35
36 // The rest is the HTTP version
37 7 char *version = space + 1;
38 7 req->version = version;
39
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (strncmp(version, "HTTP/", 5) != 0) return -1;
40
41 // Move the cursor past the CRLF
42 7 cursor = line_end + 2;
43
44 // Parse headers
45 7 req->header_count = 0;
46
4/6
✓ Branch 0 taken 50 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 45 times.
✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 5 times.
50 while (cursor < end && !(cursor[0] == '\r' && cursor[1] == '\n')) {
47 45 line_end = strstr(cursor, "\r\n");
48
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 45 times.
45 if (!line_end) break;
49 45 *line_end = '\0';
50
51 // Find the ':' separator
52 45 char *colon = strchr(cursor, ':');
53
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 45 times.
45 if (!colon) return -1;
54 45 *colon = '\0';
55 45 char *field = cursor;
56 45 char *value = colon + 1;
57
58 // Remove any leading spaces in the value
59
3/4
✓ Branch 0 taken 90 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 45 times.
✓ Branch 3 taken 45 times.
90 while (*value && isspace((unsigned char)*value)) value++;
60
61
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 43 times.
45 if (req->header_count >= MAX_HEADERS) return -1;
62 43 req->headers[req->header_count].field = field;
63 43 req->headers[req->header_count].value = value;
64 43 req->header_count++;
65
66 43 cursor = line_end + 2;
67 }
68
69 // The parser has also read the empty line separating headers and body
70 5 return 0;
71 }
72