emme coverage


Directory: src/
File: src/http_parser.c
Date: 2026-05-14 14:35:13
Exec Total Coverage
Lines: 42 42 100.0%
Functions: 1 1 100.0%
Branches: 24 32 75.0%

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