1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#ifndef __HTTP_REQUEST_H
#define __HTTP_REQUEST_H
#include "ll.h"
/**
* Struct representing an HTTP request.
*
* The `method`, `http_version`, and `path` fields are heap-allocated strings
* that are owned by the struct and are freed by `request_free`.
*
* The `headers` is a linked list dictionary of headers, also freed by
* `request_free`.
*/
typedef struct {
char *method;
char *http_version;
char *path;
ll_map_t *headers;
} request_t;
/**
* Initializes a new request struct with the given method, path, and HTTP version.
*
* The `method`, `http_version`, and `path` strings are COPIED into the struct,
* so the caller still owns the original strings and must free them once they
* are no longer needed. I.e., they are all borrowed.
*
* ```
* // fine to use string literals, since they are copied
* request_t *req = request_init("GET", "/index.html", "HTTP/1.1");
* assert(strcmp(req->method, "GET") == 0);
* assert(strcmp(req->path, "/index.html") == 0);
* assert(strcmp(req->http_version, "HTTP/1.1") == 0);
* request_free(req);
* ```
* ```
* char *method = strdup("GET");
* char *path = strdup("/index.html");
* char *http_version = strdup("HTTP/1.1");
* request_t *req = request_init(method, path, http_version);
* assert(strcmp(req->method, "GET") == 0);
* assert(strcmp(req->path, "/index.html") == 0);
* assert(strcmp(req->http_version, "HTTP/1.1") == 0);
* request_free(req);
* // must also free the original strings
* free(method);
* free(path);
* free(http_version);
*
* The `headers` field is initialized as an empty linked list dictionary.
*/
request_t *request_init(const char *method, const char *path, const char *http_version);
/**
* Frees the given request struct and all the strings inside it.
*
* The `method`, `http_version`, and `path` strings are freed using free, and
* the `headers` linked list dictionary is freed using `ll_free`.
*
* ```
* request_t *req = request_init("GET", "/index.html", "HTTP/1.1");
* request_free(req);
* ```
*/
void request_free(request_t *req);
/**
* Parses an HTTP request from the given string contents, creating a new request
* struct.
*
* The function expects the contents to be a valid HTTP request with headers
* separated by '\r\n'. The first line should contain the method, path, and
* HTTP version separated by spaces. The headers should be key-value pairs
* separated by a colon and a space.
*
* It should be terminated by an additional '\r\n' after the headers.
*
* The contents string is borrowed and not touched or modified by this function
* and so it freeing it, if necessary, is the callers responsibility.
*
* The returned request should be freed using `request_free` when it is no
* longer needed.
*/
request_t *request_parse(const char *contents);
#endif /* __HTTP_REQUEST_H */