1#include <ctype.h>
2#include <stdio.h>
3
4#include "http_message.h"
5
6//------------------------------------------------------------------------------
7// Internal functions
8//------------------------------------------------------------------------------
9
10/**
11 * @brief Callback for HTTP parser's on_message_begin event.
12 * @param p The HTTP parser instance.
13 * @return 0 to continue parsing.
14 */
15static int on_message_begin(llhttp_t* p);
16
17/**
18 * @brief Callback for HTTP parser's on_headers_complete event.
19 * @param p The HTTP parser instance.
20 * @return 0 to continue parsing.
21 */
22static int on_headers_complete(llhttp_t* p);
23
24/**
25 * @brief Callback for HTTP parser's on_message_complete event.
26 * @param p The HTTP parser instance.
27 * @return HPE_PAUSED to stop parsing.
28 */
29static int on_message_complete(llhttp_t* p);
30
31/**
32 * @brief Callback for HTTP parser's on_url event.
33 * @param p The HTTP parser instance.
34 * @param at Pointer to the URL data.
35 * @param l Length of the URL data.
36 * @return 0 to continue parsing.
37 */
38static int on_url(llhttp_t* p, cstr at, size_t l);
39
40/**
41 * @brief Callback for HTTP parser's on_header_field event.
42 * @param p The HTTP parser instance.
43 * @param at Pointer to the header field data.
44 * @param l Length of the header field data.
45 * @return 0 to continue parsing.
46 */
47static int on_header_field(llhttp_t* p, cstr at, size_t l);
48
49/**
50 * @brief Callback for HTTP parser's on_header_value event.
51 * @param p The HTTP parser instance.
52 * @param at Pointer to the header value data.
53 * @param l Length of the header value data.
54 * @return 0 to continue parsing.
55 */
56static int on_header_value(llhttp_t* p, cstr at, size_t l);
57
58/**
59 * @brief Callback for HTTP parser's on_body event.
60 * @param p The HTTP parser instance.
61 * @param at Pointer to the body data.
62 * @param l Length of the body data.
63 * @return 0 to continue parsing.
64 */
65static int on_body(llhttp_t* p, cstr at, size_t l);
66
67//------------------------------------------------------------------------------
68// HTTP Request
69//------------------------------------------------------------------------------
70
71/**
72 * @brief Converts a string to lowercase.
73 * @param s The string to convert.
74 * @return The converted lowercase string.
75 */
76ucstr lcase(char* s)
77{
78 for(int i = 0; s[i]; i++)
79 {
80 s[i] = tolower(s[i]);
81 }
82
83 return (ucstr)s;
84}
85
86static void process_header(vws_http_msg* req)
87{
88 if (req->value->size != 0)
89 {
90 // We've got a complete field-value pair.
91
92 // Null-terminate
93 vws_buffer_append(req->field, (ucstr)"\0", 1);
94 vws_buffer_append(req->value, (ucstr)"\0", 1);
95
96 ucstr field = lcase((cstr)req->field->data);
97 ucstr data = req->value->data;
98 vws_map_set(&req->headers, (cstr)field, (cstr)data);
99
100 // Reset for the next field-value pair.
101 vws_buffer_clear(req->field);
102 vws_buffer_clear(req->value);
103 }
104}
105
106vws_http_msg* vws_http_msg_new(int mode)
107{
108 vws_http_msg* req = vws.malloc(sizeof(vws_http_msg));
109 req->parser = vws.malloc(sizeof(llhttp_t));
110 req->settings = vws.malloc(sizeof(llhttp_settings_t));
111 req->url = vws_buffer_new();
112 req->body = vws_buffer_new();
113 req->field = vws_buffer_new();
114 req->value = vws_buffer_new();
115 req->headers_complete = false;
116 req->done = false;
117
118 llhttp_settings_init(req->settings);
119
120 req->settings->on_message_begin = on_message_begin;
121 req->settings->on_headers_complete = on_headers_complete;
122 req->settings->on_message_complete = on_message_complete;
123 req->settings->on_url = on_url;
124 req->settings->on_header_field = on_header_field;
125 req->settings->on_header_value = on_header_value;
126 req->settings->on_body = on_body;
127
128 llhttp_init(req->parser, mode, req->settings);
129 req->parser->data = req;
130
131 sc_map_init_str(&req->headers, 0, 0);
132
133 return req;
134}
135
136void vws_http_msg_free(vws_http_msg* req)
137{
138 if (req == NULL)
139 {
140 return;
141 }
142
143 cstr key; cstr value;
144 sc_map_foreach(&req->headers, key, value)
145 {
146 vws.free(key);
147 vws.free(value);
148 }
149
150 sc_map_term_str(&req->headers);
151 vws_buffer_free(req->url);
152 vws_buffer_free(req->body);
153 vws_buffer_free(req->field);
154 vws_buffer_free(req->value);
155 vws.free(req->parser);
156 vws.free(req->settings);
157 vws.free(req);
158}
159
160int on_message_begin(llhttp_t* p)
161{
162 return 0;
163}
164
165int on_headers_complete(llhttp_t* p)
166{
167 vws_http_msg* req = p->data;
168 req->headers_complete = true;
169
170 // Process final header, if any.
171 process_header(req);
172
173 return 0;
174}
175
176int on_message_complete(llhttp_t* p)
177{
178 vws_http_msg* req = p->data;
179 req->done = true;
180
181 // We have a complete message. Pause the parser.
182 return HPE_PAUSED;
183}
184
185int on_url(llhttp_t* p, cstr at, size_t l)
186{
187 vws_http_msg* req = p->data;
188 vws_buffer_append(req->url, (ucstr)at, l);
189
190 return 0;
191}
192
193int on_header_field(llhttp_t* p, cstr at, size_t l)
194{
195 vws_http_msg* req = p->data;
196
197 process_header(req);
198
199 // Start new field
200 vws_buffer_append(req->field, (ucstr)at, l);
201
202 return 0;
203}
204
205int on_header_value(llhttp_t* p, cstr at, size_t l)
206{
207 vws_http_msg* req = p->data;
208 vws_buffer_append(req->value, (ucstr)at, l);
209
210 return 0;
211}
212
213int on_body(llhttp_t* p, cstr at, size_t l)
214{
215 vws_http_msg* req = p->data;
216 vws_buffer_append(req->url, (ucstr)at, l);
217
218 return 0;
219}
220
221int vws_http_msg_parse(vws_http_msg* req, cstr data, size_t size)
222{
223 enum llhttp_errno rc = llhttp_execute(req->parser, data, size);
224
225 if (rc != HPE_OK)
226 {
227 // If paused
228 if ((rc == HPE_PAUSED) || (rc == HPE_PAUSED_UPGRADE))
229 {
230 // Only legit reason to pause is on_message_complete() and therefore
231 // done() will be set to true. If we pause for any other reason this
232 // is error.
233 if (req->done == false)
234 {
235 // Fatal error. Message is messed up somehow.
236 return -1;
237 }
238 }
239 else
240 {
241 // All other errors. Message is messed up somehow.
242 return -1;
243 }
244 }
245
246 // If the HTTP message was fully parsed
247 if (req->done == true)
248 {
249 // llhttp_execute() internal cursor stops at the end of first http
250 // message. We compute the amount of data consumed by using
251 // llhttp_get_error_pos() to get the position of the last parsed byte
252 // and subtract from that address the start address of "data". This is
253 // the number of bytes consumed by the completed message out of the
254 // total bytes in "data". Note that if data consists of only a single
255 // HTTP message, then there will be zero bytes left. If however there is
256 // another request, or data from from UPGRADE, then there can be
257 // additional data
258
259 return llhttp_get_error_pos(req->parser) - data;
260 }
261
262 // The HTTP message is not completely parsed and therefore all data provided
263 // was consumed in message parsing.
264 return size;
265}
266