aboutsummaryrefslogtreecommitdiff
path: root/c-httpd/httpserver.h
diff options
context:
space:
mode:
authorMitja Felicijan <mitja.felicijan@gmail.com>2025-03-11 22:32:56 +0100
committerMitja Felicijan <mitja.felicijan@gmail.com>2025-03-11 22:32:56 +0100
commit29fb1c172b2b235a6484f23f8d5b391f877e98eb (patch)
tree7c8008a2c692af9104e0a9e91358779db99e7d28 /c-httpd/httpserver.h
parent68ac646c552980e8119e0a789b83ba82d0a594a4 (diff)
downloadprobe-29fb1c172b2b235a6484f23f8d5b391f877e98eb.tar.gz
Added simple HTTPD server in C
Diffstat (limited to 'c-httpd/httpserver.h')
-rw-r--r--c-httpd/httpserver.h2818
1 files changed, 2818 insertions, 0 deletions
diff --git a/c-httpd/httpserver.h b/c-httpd/httpserver.h
new file mode 100644
index 0000000..26fb0c7
--- /dev/null
+++ b/c-httpd/httpserver.h
@@ -0,0 +1,2818 @@
1// httpserver.h has been automatically generated from httpserver.m4 and the
2// source files under /src
3#ifndef HTTPSERVER_H
4#define HTTPSERVER_H
5#line 1 "api.h"
6#ifndef HS_API_H
7#define HS_API_H
8/** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
9 * @file api.h
10 *
11 * MIT License
12 *
13 * Copyright (c) 2019 Jeremy Williams
14 *
15 * Permission is hereby granted, free of charge, to any person obtaining a copy
16 * of this software and associated documentation files (the "Software"), to deal
17 * in the Software without restriction, including without limitation the rights
18 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
19 * copies of the Software, and to permit persons to whom the Software is
20 * furnished to do so, subject to the following conditions:
21 *
22 * The above copyright notice and this permission notice shall be included in
23 * all copies or substantial portions of the Software.
24 *
25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31 * SOFTWARE.
32 *
33 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
34 *
35 * httpserver.h (0.9.0)
36 *
37 * Description:
38 *
39 * A single header C library for building non-blocking event driven HTTP
40 * servers
41 *
42 * Usage:
43 *
44 * Do this:
45 * #define HTTPSERVER_IMPL
46 * before you include this file in *one* C or C++ file to create the
47 * implementation.
48 *
49 * // i.e. it should look like this:
50 * #include ...
51 * #include ...
52 * #include ...
53 * #define HTTPSERVER_IMPL
54 * #include "httpserver.h"
55 *
56 * There are some #defines that can be configured. This must be done in the
57 * same file that you define HTTPSERVER_IMPL These defines have default values
58 * and will need to be #undef'd and redefined to configure them.
59 *
60 * HTTP_REQUEST_BUF_SIZE - default 1024 - The initial size in bytes of the
61 * read buffer for the request. This buffer grows automatically if it's
62 * capacity is reached but it certain environments it may be optimal to
63 * change this value.
64 *
65 * HTTP_RESPONSE_BUF_SIZE - default 1024 - Same as above except for the
66 * response buffer.
67 *
68 * HTTP_REQUEST_TIMEOUT - default 20 - The amount of seconds the request
69 * will wait for activity on the socket before closing. This only applies mid
70 * request. For the amount of time to hold onto keep-alive connections see
71 * below.
72 *
73 * HTTP_KEEP_ALIVE_TIMEOUT - default 120 - The amount of seconds to keep a
74 * connection alive a keep-alive request has completed.
75 *
76 * HTTP_MAX_TOTAL_EST_MEM_USAGE - default 4294967296 (4GB) - This is the
77 * amount of read/write buffer space that is allowed to be allocated
78 * across all requests before new requests will get 503 responses.
79 *
80 * HTTP_MAX_TOKEN_LENGTH - default 8192 (8KB) - This is the max size of any
81 * non body http tokens. i.e: header names, header values, url length,
82 * etc.
83 *
84 * HTTP_MAX_REQUEST_BUF_SIZE - default 8388608 (8MB) - This is the maximum
85 * amount of bytes that the request buffer will grow to. If the body of
86 * the request + headers cannot fit in this size the request body will be
87 * streamed in.
88 *
89 * For more details see the documentation of the interface and the example
90 * below.
91 *
92 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
93
94#ifdef __cplusplus
95extern "C" {
96#endif
97
98// String type used to read the request details. The char pointer is NOT null
99// terminated.
100struct http_string_s;
101
102struct http_server_s;
103struct http_request_s;
104struct http_response_s;
105
106/**
107 * Get the event loop descriptor that the server is running on.
108 *
109 * This will be an epoll fd when running on Linux or a kqueue on BSD. This can
110 * be used to listen for activity on sockets, etc. The only caveat is that the
111 * user data must be set to a struct where the first member is the function
112 * pointer to a callback that will handle the event. i.e:
113 *
114 * For kevent:
115 *
116 * struct foo {
117 * void (*handler)(struct kevent*);
118 * ...
119 * }
120 *
121 * // Set ev.udata to a foo pointer when registering the event.
122 *
123 * For epoll:
124 *
125 * struct foo {
126 * void (*handler)(struct epoll_event*);
127 * ...
128 * }
129 *
130 * // Set ev.data.ptr to a foo pointer when registering the event.
131 *
132 * @param server The server.
133 *
134 * @return The descriptor of the event loop.
135 */
136int http_server_loop(struct http_server_s *server);
137
138/**
139 * Allocates and initializes the http server.
140 *
141 * @param port The port to listen on.
142 * @param handler The callback that will fire to handle requests.
143 *
144 * @return Pointer to the allocated server.
145 */
146struct http_server_s *
147http_server_init(int port, void (*handler)(struct http_request_s *));
148
149/**
150 * Listens on the server socket and starts an event loop.
151 *
152 * During normal operation this function will not return.
153 *
154 * @param server The server.
155 * @param ipaddr The ip to bind to if NULL binds to all interfaces.
156 *
157 * @return Error code if the server fails.
158 */
159int http_server_listen_addr(struct http_server_s *server, const char *ipaddr);
160
161/**
162 * See http_server_listen_addr
163 */
164int http_server_listen(struct http_server_s *server);
165
166/**
167 * Poll the server socket on specific interface.
168 *
169 * Use this listen call in place of the one above when you want to integrate
170 * an http server into an existing application that has a loop already and you
171 * want to use the polling functionality instead. This works well for
172 * applications like games that have a constant update loop.
173 *
174 * @param server The server.
175 * @param ipaddr The ip to bind to if NULL bind to all.
176 *
177 * @return Error code if the poll fails.
178 */
179int http_server_listen_addr_poll(struct http_server_s *server,
180 const char *ipaddr);
181
182/**
183 * Poll the server socket on all interfaces. See http_server_listen_addr_poll
184 *
185 * @param server The server.
186 *
187 * @return Error code if the poll fails.
188 */
189int http_server_listen_poll(struct http_server_s *server);
190/**
191 * Poll of the request sockets.
192 *
193 * Call this function in your update loop. It will trigger the request handler
194 * once if there is a request ready. It should be called in a loop until it
195 * returns 0.
196 *
197 * @param server The server.
198 *
199 * @return Returns 1 if a request was handled and 0 if no requests were handled.
200 */
201int http_server_poll(struct http_server_s *server);
202
203/**
204 * Check if a request flag is set.
205 *
206 * The flags that can be queried are listed below:
207 *
208 * HTTP_FLG_STREAMED
209 *
210 * This flag will be set when the request body is chunked or the body is too
211 * large to fit in memory are once. This means that the
212 * http_request_read_chunk function must be used to read the body piece by
213 * piece.
214 *
215 * @param request The request.
216 * @param flag One of the flags listed above.
217 *
218 * @return 1 or 0 if the flag is set or not respectively.
219 */
220int http_request_has_flag(struct http_request_s *request, int flag);
221
222/**
223 * Returns the request method as it was read from the HTTP request line.
224 *
225 * @param request The request.
226 *
227 * @return The HTTP method.
228 */
229struct http_string_s http_request_method(struct http_request_s *request);
230
231/**
232 * Returns the full request target (url) from the HTTP request line.
233 *
234 * @param request The request.
235 *
236 * @return The target.
237 */
238struct http_string_s http_request_target(struct http_request_s *request);
239
240/**
241 * Retrieves the request body.
242 *
243 * @param request The request.
244 *
245 * @return The request body. If no request body was sent buf and len of the
246 * string will be set to 0.
247 */
248struct http_string_s http_request_body(struct http_request_s *request);
249
250/**
251 * Returns the request header value for the given header key.
252 *
253 * @param request The request.
254 * @param key The case insensitive header key to search for.
255 *
256 * @return The value for the header matching the key. Will be length 0 if not
257 * found.
258 */
259struct http_string_s http_request_header(struct http_request_s *request,
260 char const *key);
261
262/**
263 * Iterate over the request headers.
264 *
265 * Each call will set key and val to the key and value of the next header.
266 *
267 * @param request The request.
268 * @param[out] key The key of the header.
269 * @param[out] value The key of the header.
270 * @param[inout] iter Should be initialized to 0 before calling. Pass back in
271 * with each consecutive call.
272 *
273 * @return 0 when there are no more headers.
274 */
275int http_request_iterate_headers(struct http_request_s *request,
276 struct http_string_s *key,
277 struct http_string_s *val, int *iter);
278
279/**
280 * Stores an arbitrary userdata pointer for this request.
281 *
282 * This is not used by the library in any way and is strictly for you, the
283 * application programmer to make use of.
284 *
285 * @param request The request.
286 * @param data Opaque pointer to user data.
287 */
288void http_request_set_userdata(struct http_request_s *request, void *data);
289
290/**
291 * Retrieve the opaque data pointer that was set with http_request_set_userdata.
292 *
293 * @param request The request.
294 */
295void *http_request_userdata(struct http_request_s *request);
296
297/**
298 * Stores a server wide opaque pointer for future retrieval.
299 *
300 * This is not used by the library in any way and is strictly for you, the
301 * application programmer to make use of.
302 *
303 * @param server The server.
304 * @param data Opaque data pointer.
305 */
306void http_server_set_userdata(struct http_server_s *server, void *data);
307
308/**
309 * Retrieve the server wide userdata pointer.
310 *
311 * @param request The request.
312 */
313void *http_request_server_userdata(struct http_request_s *request);
314
315/**
316 * Sets how the request will handle it's connection
317 *
318 * By default the server will inspect the Connection header and the HTTP
319 * version to determine whether the connection should be kept alive or not.
320 * Use this function to override that behaviour to force the connection to
321 * keep-alive or close by passing in the HTTP_KEEP_ALIVE or HTTP_CLOSE
322 * directives respectively. This may provide a minor performance improvement
323 * in cases where you control client and server and want to always close or
324 * keep the connection alive.
325 *
326 * @param request The request.
327 * @param directive One of HTTP_KEEP_ALIVE or HTTP_CLOSE
328 */
329void http_request_connection(struct http_request_s *request, int directive);
330
331/**
332 * Frees the buffer of a request.
333 *
334 * When reading in the HTTP request the server allocates a buffer to store
335 * the request details such as the headers, method, body, etc. By default this
336 * memory will be freed when http_respond is called. This function lets you
337 * free that memory before the http_respond call. This can be useful if you
338 * have requests that take a long time to complete and you don't require the
339 * request data. Accessing any http_string_s's will be invalid after this call.
340 *
341 * @param request The request to free the buffer of.
342 */
343void http_request_free_buffer(struct http_request_s *request);
344
345/**
346 * Allocates an http response.
347 *
348 * This memory will be freed when http_respond is called.
349 *
350 * @return Allocated response.
351 */
352struct http_response_s *http_response_init();
353
354/**
355 * Set the response status.
356 *
357 * Accepts values between 100 and 599 inclusive. Any other value will map to
358 * 500.
359 *
360 * @param response The response struct to set status on.
361 * @param status The HTTP status code.
362 */
363void http_response_status(struct http_response_s *response, int status);
364
365/**
366 * Sets an HTTP response header.
367 *
368 * @param response The response struct to set the header on.
369 * @param key The null-terminated key of the header eg: Content-Type
370 * @param value The null-terminated value of the header eg: application/json
371 */
372void http_response_header(struct http_response_s *response, char const *key,
373 char const *value);
374
375/**
376 * Set the response body.
377 *
378 * The caller is responsible for freeing any memory that
379 * may have been allocated for the body. It is safe to free this memory AFTER
380 * http_respond has been called. If responding with chunked transfer encoding
381 * this will become a single chunk. This procedure can be used again to set
382 * subsequent chunks.
383 *
384 * @param response The response struct to set the body for.
385 * @param body The body of the response.
386 * @param length The length of the body
387 */
388void http_response_body(struct http_response_s *response, char const *body,
389 int length);
390
391/**
392 * Starts writing the response to the client.
393 *
394 * Any memory allocated for the response body or response headers is safe to
395 * free after this call. Adds the default HTTP response headers, Date and
396 * Connection.
397 *
398 * @param request The request to respond to.
399 * @param response The response to respond with.
400 */
401void http_respond(struct http_request_s *request,
402 struct http_response_s *response);
403
404/**
405 * Writes a chunk to the client.
406 *
407 * The notify_done callback will be called when the write is complete. This call
408 * consumes the response so a new response will need to be initialized for each
409 * chunk. The response status of the request will be the response status that is
410 * set when http_respond_chunk is called the first time. Any headers set for the
411 * first call will be sent as the response headers. Transfer-Encoding header
412 * will automatically be set to chunked. Headers set for subsequent calls will
413 * be ignored.
414 *
415 * @param request The request to respond to.
416 * @param response The response to respond with.
417 * @param notify_done The callback that's used to signal user code that another
418 * chunk is ready to be written out.
419 */
420void http_respond_chunk(struct http_request_s *request,
421 struct http_response_s *response,
422 void (*notify_done)(struct http_request_s *));
423
424/**
425 * Ends the chunked response.
426 *
427 * Used to signal end of transmission on chunked requests. Any headers set
428 * before this call will be included as what the HTTP spec refers to as
429 * 'trailers' which are essentially more response headers.
430 *
431 * @param request The request to respond to.
432 * @param response The response to respond with.
433 */
434void http_respond_chunk_end(struct http_request_s *request,
435 struct http_response_s *response);
436
437/**
438 * Read a chunk of the request body.
439 *
440 * If a request has Transfer-Encoding: chunked or the body is too big to fit in
441 * memory all at once you cannot read the body in the typical way. Instead you
442 * need to call this function to read one chunk at a time. To check if the
443 * request requires this type of reading you can call the http_request_has_flag
444 * function to check if the HTTP_FLG_STREAMED flag is set. To read a streamed
445 * body you pass a callback that will be called when the chunk is ready. When
446 * the callback is called you can use 'http_request_chunk' to get the current
447 * chunk. When done with that chunk call this function again to request the
448 * next chunk. If the chunk has size 0 then the request body has been completely
449 * read and you can now respond.
450 *
451 * @param request The request.
452 * @param chunk_cb Callback for when the chunk is ready.
453 */
454void http_request_read_chunk(struct http_request_s *request,
455 void (*chunk_cb)(struct http_request_s *));
456
457/**
458 * Returns the current chunk of the request body.
459 *
460 * This chunk is only valid until the next call to 'http_request_read_chunk'.
461 *
462 * @param request The request.
463 *
464 * @return The chunk data.
465 */
466struct http_string_s http_request_chunk(struct http_request_s *request);
467
468#define http_request_read_body http_request_read_chunk
469
470#ifdef __cplusplus
471}
472#endif
473
474// Minimal example usage.
475#ifdef HTTPSERVER_EXAMPLE
476
477#define RESPONSE "Hello, World!"
478
479void handle_request(struct http_request_s *request) {
480 struct http_response_s *response = http_response_init();
481 http_response_status(response, 200);
482 http_response_header(response, "Content-Type", "text/plain");
483 http_response_body(response, RESPONSE, sizeof(RESPONSE) - 1);
484 http_respond(request, response);
485}
486
487int main() {
488 struct http_server_s *server = http_server_init(8080, handle_request);
489 http_server_listen(server);
490}
491
492#endif
493
494#endif
495
496#line 1 "common.h"
497#ifndef HS_COMMON_H
498#define HS_COMMON_H
499
500// http session states
501#define HTTP_SESSION_INIT 0
502#define HTTP_SESSION_READ 1
503#define HTTP_SESSION_WRITE 2
504#define HTTP_SESSION_NOP 3
505
506#define HTTP_REQUEST_TIMEOUT 20
507
508#define HTTP_FLAG_SET(var, flag) var |= flag
509#define HTTP_FLAG_CLEAR(var, flag) var &= ~flag
510#define HTTP_FLAG_CHECK(var, flag) (var & flag)
511
512#define HTTP_AUTOMATIC 0x8
513#define HTTP_CHUNKED_RESPONSE 0x20
514
515#define HTTP_KEEP_ALIVE 1
516#define HTTP_CLOSE 0
517
518#include <arpa/inet.h>
519#include <sys/socket.h>
520#ifdef KQUEUE
521#include <sys/event.h>
522#else
523#include <sys/epoll.h>
524#endif
525
526#ifdef EPOLL
527typedef void (*epoll_cb_t)(struct epoll_event *);
528#endif
529
530typedef struct http_ev_cb_s {
531#ifdef KQUEUE
532 void (*handler)(struct kevent *ev);
533#else
534 epoll_cb_t handler;
535#endif
536} ev_cb_t;
537
538struct hsh_buffer_s {
539 char *buf;
540 int32_t capacity;
541 int32_t length;
542 int32_t index;
543 int32_t after_headers_index;
544 int8_t sequence_id;
545};
546
547enum hsh_token_e {
548 HSH_TOK_METHOD,
549 HSH_TOK_TARGET,
550 HSH_TOK_VERSION,
551 HSH_TOK_HEADER_KEY,
552 HSH_TOK_HEADER_VALUE,
553 HSH_TOK_HEADERS_DONE,
554 HSH_TOK_BODY,
555 HSH_TOK_NONE,
556 HSH_TOK_ERR
557};
558
559struct hsh_token_s {
560 enum hsh_token_e type;
561 uint8_t flags;
562 int len;
563 int index;
564};
565
566struct hsh_parser_s {
567 int64_t content_length;
568 int64_t content_remaining;
569 struct hsh_token_s token;
570 int16_t limit_count;
571 int16_t limit_max;
572 int8_t state;
573 int8_t flags;
574 int8_t sequence_id;
575};
576
577struct hs_token_array_s {
578 struct hsh_token_s *buf;
579 int capacity;
580 int size;
581};
582
583typedef struct http_request_s {
584#ifdef KQUEUE
585 void (*handler)(struct kevent *ev);
586#else
587 epoll_cb_t handler;
588 epoll_cb_t timer_handler;
589 int timerfd;
590#endif
591 void (*chunk_cb)(struct http_request_s *);
592 void *data;
593 struct hsh_buffer_s buffer;
594 struct hsh_parser_s parser;
595 struct hs_token_array_s tokens;
596 int state;
597 int socket;
598 int timeout;
599 int64_t bytes_written;
600 struct http_server_s *server;
601 char flags;
602} http_request_t;
603
604typedef struct http_server_s {
605#ifdef KQUEUE
606 void (*handler)(struct kevent *ev);
607#else
608 epoll_cb_t handler;
609 epoll_cb_t timer_handler;
610#endif
611 int64_t memused;
612 int socket;
613 int port;
614 int loop;
615 int timerfd;
616 socklen_t len;
617 void (*request_handler)(http_request_t *);
618 struct sockaddr_in addr;
619 void *data;
620 char date[32];
621} http_server_t;
622
623#endif
624
625#line 1 "buffer_util.h"
626#ifndef HS_BUFFER_UTIL_H
627#define HS_BUFFER_UTIL_H
628
629#include <stdlib.h>
630
631#ifndef HTTPSERVER_IMPL
632// #include "common.h"
633#endif
634
635static inline void _hs_buffer_free(struct hsh_buffer_s *buffer,
636 int64_t *memused) {
637 if (buffer->buf) {
638 free(buffer->buf);
639 *memused -= buffer->capacity;
640 buffer->buf = NULL;
641 }
642}
643
644#endif
645
646#line 1 "request_util.h"
647#ifndef HS_REQUEST_UTIL_H
648#define HS_REQUEST_UTIL_H
649
650// #include "common.h"
651
652// http version indicators
653#define HTTP_1_0 0
654#define HTTP_1_1 1
655
656struct http_string_s {
657 char const *buf;
658 int len;
659};
660
661typedef struct http_string_s http_string_t;
662
663http_string_t hs_get_token_string(http_request_t *request,
664 enum hsh_token_e token_type);
665http_string_t hs_request_header(http_request_t *request, char const *key);
666void hs_request_detect_keep_alive_flag(http_request_t *request);
667int hs_request_iterate_headers(http_request_t *request, http_string_t *key,
668 http_string_t *val, int *iter);
669void hs_request_set_keep_alive_flag(http_request_t *request, int directive);
670http_string_t hs_request_chunk(struct http_request_s *request);
671
672#endif
673
674#line 1 "parser.h"
675#ifndef HTTP_PARSER_H
676#define HTTP_PARSER_H
677
678// HSH_TOK_HEADERS_DONE flags
679#define HSH_TOK_FLAG_NO_BODY 0x1
680#define HSH_TOK_FLAG_STREAMED_BODY 0x2
681
682// HSH_TOK_BODY flags
683#define HSH_TOK_FLAG_BODY_FINAL 0x1
684#define HSH_TOK_FLAG_SMALL_BODY 0x2
685
686struct hsh_token_s hsh_parser_exec(struct hsh_parser_s *parser,
687 struct hsh_buffer_s *buffer,
688 int max_buf_capacity);
689void hsh_parser_init(struct hsh_parser_s *parser);
690
691#endif
692
693#line 1 "read_socket.h"
694#ifndef HS_READ_SOCKET_H
695#define HS_READ_SOCKET_H
696
697#define HTTP_FLG_STREAMED 0x1
698
699#include <stdint.h>
700
701struct http_request_s;
702
703// Response code for hs_read_socket
704enum hs_read_rc_e {
705 // Execution was successful
706 HS_READ_RC_SUCCESS,
707 // There was an error parsing the HTTP request
708 HS_READ_RC_PARSE_ERR,
709 // There was an error reading the socket
710 HS_READ_RC_SOCKET_ERR
711};
712
713// Holds configuration options for the hs_read_socket procedure.
714struct hs_read_opts_s {
715 // Restricts the request buffer from ever growing larger than this size
716 int64_t max_request_buf_capacity;
717 // The value to be compared to the return of the read call to determine if
718 // the connection has been closed. Should generally be 0 in normal operation
719 // using sockets but can be useful to change if you want to use files instead
720 // of sockets for testing.
721 int eof_rc;
722 // The initial capacity that is allocated for the request buffer
723 int initial_request_buf_capacity;
724};
725
726enum hs_read_rc_e
727hs_read_request_and_exec_user_cb(struct http_request_s *request,
728 struct hs_read_opts_s opts);
729
730#endif
731
732#line 1 "respond.h"
733#ifndef HS_RESPOND_H
734#define HS_RESPOND_H
735
736#define HTTP_RESPONSE_BUF_SIZE 1024
737
738struct http_request_s;
739
740typedef void (*hs_req_fn_t)(struct http_request_s *);
741
742// Represents a single header of an HTTP response.
743typedef struct http_header_s {
744 // The key of the header eg: Content-Type
745 char const *key;
746 // The value of the header eg: application/json
747 char const *value;
748 // Pointer to the next header in the linked list.
749 struct http_header_s *next;
750} http_header_t;
751
752// Represents the response of an HTTP request before it is serialized on the
753// wire.
754typedef struct http_response_s {
755 // Head of the linked list of response headers
756 http_header_t *headers;
757 // The complete body of the response or the chunk if generating a chunked
758 // response.
759 char const *body;
760 // The length of the body or chunk.
761 int content_length;
762 // The HTTP status code for the response.
763 int status;
764} http_response_t;
765
766http_response_t *hs_response_init();
767void hs_response_set_header(http_response_t *response, char const *key,
768 char const *value);
769void hs_response_set_status(http_response_t *response, int status);
770void hs_response_set_body(http_response_t *response, char const *body,
771 int length);
772void hs_request_respond(struct http_request_s *request,
773 http_response_t *response, hs_req_fn_t http_write);
774void hs_request_respond_chunk(struct http_request_s *request,
775 http_response_t *response, hs_req_fn_t cb,
776 hs_req_fn_t http_write);
777void hs_request_respond_chunk_end(struct http_request_s *request,
778 http_response_t *response,
779 hs_req_fn_t http_write);
780void hs_request_respond_error(struct http_request_s *request, int code,
781 char const *message, hs_req_fn_t http_write);
782
783#endif
784
785#line 1 "server.h"
786#ifndef HS_SERVER_H
787#define HS_SERVER_H
788
789#ifdef KQUEUE
790
791struct kevent;
792
793typedef void (*hs_evt_cb_t)(struct kevent *ev);
794
795#else
796
797struct epoll_event;
798
799typedef void (*hs_evt_cb_t)(struct epoll_event *ev);
800
801#endif
802
803struct http_request_s;
804struct http_server_s;
805
806void hs_server_listen_on_addr(struct http_server_s *serv, const char *ipaddr);
807int hs_server_run_event_loop(struct http_server_s *serv, const char *ipaddr);
808void hs_generate_date_time(char *datetime);
809struct http_server_s *hs_server_init(int port,
810 void (*handler)(struct http_request_s *),
811 hs_evt_cb_t accept_cb,
812 hs_evt_cb_t timer_cb);
813int hs_server_poll_events(struct http_server_s *serv);
814
815#endif
816
817#line 1 "write_socket.h"
818#ifndef HS_WRITE_SOCKET_H
819#define HS_WRITE_SOCKET_H
820
821#define HTTP_KEEP_ALIVE_TIMEOUT 120
822
823struct http_request_s;
824
825// Response code for hs_write_socket
826enum hs_write_rc_e {
827 // Successful and has written the full response
828 HS_WRITE_RC_SUCCESS,
829 // Successful and has written the full chunk
830 HS_WRITE_RC_SUCCESS_CHUNK,
831 // Successful, has written the full response and the socket should be closed
832 HS_WRITE_RC_SUCCESS_CLOSE,
833 // Successful but has not written the full response, wait for write ready
834 HS_WRITE_RC_CONTINUE,
835 // Error writing to the socket
836 HS_WRITE_RC_SOCKET_ERR
837};
838
839enum hs_write_rc_e hs_write_socket(struct http_request_s *request);
840
841#endif
842
843#line 1 "connection.h"
844#ifndef HS_CONNECTION_H
845#define HS_CONNECTION_H
846
847// Forward declarations
848struct http_request_s;
849struct http_server_s;
850
851#ifdef KQUEUE
852struct kevent;
853typedef void (*hs_io_cb_t)(struct kevent *ev);
854#else
855struct epoll_event;
856typedef void (*hs_io_cb_t)(struct epoll_event *ev);
857#endif
858
859/* Closes the requests socket and frees its resources.
860 *
861 * Removes all event watchers from the request socket and frees any allocated
862 * buffers associated with the request struct.
863 *
864 * @param request The request to close
865 */
866void hs_request_terminate_connection(struct http_request_s *request);
867
868/* Accepts connections on the server socket in a loop until it would block.
869 *
870 * When a connection is accepted a request struct is allocated and initialized
871 * and the request socket is set to non-blocking mode. Event watchers are set
872 * on the socket to call io_cb with a read/write ready event occurs. If the
873 * server has reached max_mem_usage the err_responder function is called to
874 * handle the issue.
875 *
876 * @param server The http server struct.
877 * @param io_cb The callback function to respond to events on the request socket
878 * @param epoll_timer_cb The callback function to respond to timer events for
879 * epoll. Can be NULL if not using epoll.
880 * @param err_responder The procedure to call when memory usage has reached the
881 * given limit. Typically this could respond with a 503 error and close the
882 * connection.
883 * @param max_mem_usage The limit at which err_responder should be called
884 * instead of regular operation.
885 */
886struct http_request_s *hs_server_accept_connection(struct http_server_s *server,
887 hs_io_cb_t io_cb,
888 hs_io_cb_t epoll_timer_cb);
889
890#endif
891
892#line 1 "io_events.h"
893#ifndef HS_IO_EVENTS_H
894#define HS_IO_EVENTS_H
895
896#define HTTP_REQUEST_BUF_SIZE 1024
897#define HTTP_MAX_REQUEST_BUF_SIZE 8388608 // 8mb
898#define HTTP_MAX_TOTAL_EST_MEM_USAGE 4294967296 // 4gb
899
900struct http_request_s;
901
902void hs_request_begin_write(struct http_request_s *request);
903void hs_request_begin_read(struct http_request_s *request);
904
905#ifdef KQUEUE
906
907struct kevent;
908
909void hs_on_kqueue_server_event(struct kevent *ev);
910
911#else
912
913struct epoll_event;
914
915void hs_on_epoll_server_connection_event(struct epoll_event *ev);
916void hs_on_epoll_server_timer_event(struct epoll_event *ev);
917
918#endif
919
920#endif
921
922#ifdef HTTPSERVER_IMPL
923#ifndef HTTPSERVER_IMPL_ONCE
924#define HTTPSERVER_IMPL_ONCE
925#line 1 "api.c"
926#include <stdlib.h>
927
928#ifndef HTTPSERVER_IMPL
929#include "api.h"
930#include "buffer_util.h"
931#include "common.h"
932#include "io_events.h"
933#include "request_util.h"
934#include "respond.h"
935#include "server.h"
936#endif
937
938int http_request_has_flag(http_request_t *request, int flag) {
939 return HTTP_FLAG_CHECK(request->flags, flag);
940}
941
942int http_server_loop(http_server_t *server) { return server->loop; }
943
944http_server_t *http_server_init(int port, void (*handler)(http_request_t *)) {
945#ifdef KQUEUE
946 return hs_server_init(port, handler, hs_on_kqueue_server_event, NULL);
947#else
948 return hs_server_init(port, handler, hs_on_epoll_server_connection_event,
949 hs_on_epoll_server_timer_event);
950#endif
951}
952
953void http_request_free_buffer(http_request_t *request) {
954 _hs_buffer_free(&request->buffer, &request->server->memused);
955}
956
957void *http_request_userdata(http_request_t *request) { return request->data; }
958
959void http_request_set_userdata(http_request_t *request, void *data) {
960 request->data = data;
961}
962
963void http_server_set_userdata(struct http_server_s *serv, void *data) {
964 serv->data = data;
965}
966
967void *http_request_server_userdata(struct http_request_s *request) {
968 return request->server->data;
969}
970
971int http_request_iterate_headers(http_request_t *request, http_string_t *key,
972 http_string_t *val, int *iter) {
973 return hs_request_iterate_headers(request, key, val, iter);
974}
975
976http_string_t http_request_header(http_request_t *request, char const *key) {
977 return hs_request_header(request, key);
978}
979
980void http_request_connection(http_request_t *request, int directive) {
981 hs_request_set_keep_alive_flag(request, directive);
982}
983
984http_string_t http_request_chunk(struct http_request_s *request) {
985 return hs_request_chunk(request);
986}
987
988http_response_t *http_response_init() { return hs_response_init(); }
989
990void http_response_header(http_response_t *response, char const *key,
991 char const *value) {
992 return hs_response_set_header(response, key, value);
993}
994
995void http_response_status(http_response_t *response, int status) {
996 hs_response_set_status(response, status);
997}
998
999void http_response_body(http_response_t *response, char const *body,
1000 int length) {
1001 hs_response_set_body(response, body, length);
1002}
1003
1004void http_respond(http_request_t *request, http_response_t *response) {
1005 hs_request_respond(request, response, hs_request_begin_write);
1006}
1007
1008void http_respond_chunk(http_request_t *request, http_response_t *response,
1009 void (*cb)(http_request_t *)) {
1010 hs_request_respond_chunk(request, response, cb, hs_request_begin_write);
1011}
1012
1013void http_respond_chunk_end(http_request_t *request,
1014 http_response_t *response) {
1015 hs_request_respond_chunk_end(request, response, hs_request_begin_write);
1016}
1017
1018http_string_t http_request_method(http_request_t *request) {
1019 return hs_get_token_string(request, HSH_TOK_METHOD);
1020}
1021
1022http_string_t http_request_target(http_request_t *request) {
1023 return hs_get_token_string(request, HSH_TOK_TARGET);
1024}
1025
1026http_string_t http_request_body(http_request_t *request) {
1027 return hs_get_token_string(request, HSH_TOK_BODY);
1028}
1029
1030int http_server_listen(http_server_t *serv) {
1031 return hs_server_run_event_loop(serv, NULL);
1032}
1033
1034int http_server_listen_addr(http_server_t *serv, const char *ipaddr) {
1035 return hs_server_run_event_loop(serv, ipaddr);
1036}
1037
1038int http_server_poll(http_server_t *serv) {
1039 return hs_server_poll_events(serv);
1040}
1041
1042int http_server_listen_poll(http_server_t *serv) {
1043 hs_server_listen_on_addr(serv, NULL);
1044 return 0;
1045}
1046
1047int http_server_listen_addr_poll(http_server_t *serv, const char *ipaddr) {
1048 hs_server_listen_on_addr(serv, ipaddr);
1049 return 0;
1050}
1051
1052void http_request_read_chunk(struct http_request_s *request,
1053 void (*chunk_cb)(struct http_request_s *)) {
1054 request->state = HTTP_SESSION_READ;
1055 request->chunk_cb = chunk_cb;
1056 hs_request_begin_read(request);
1057}
1058
1059#line 1 "request_util.c"
1060#include <stdlib.h>
1061#include <string.h>
1062
1063#ifndef HTTPSERVER_IMPL
1064#include "common.h"
1065#include "request_util.h"
1066#endif
1067
1068int _hs_case_insensitive_cmp(char const *a, char const *b, int len) {
1069 for (int i = 0; i < len; i++) {
1070 char c1 = a[i] >= 'A' && a[i] <= 'Z' ? a[i] + 32 : a[i];
1071 char c2 = b[i] >= 'A' && b[i] <= 'Z' ? b[i] + 32 : b[i];
1072 if (c1 != c2)
1073 return 0;
1074 }
1075 return 1;
1076}
1077
1078http_string_t hs_get_token_string(http_request_t *request,
1079 enum hsh_token_e token_type) {
1080 http_string_t str = {0, 0};
1081 if (request->tokens.buf == NULL)
1082 return str;
1083 for (int i = 0; i < request->tokens.size; i++) {
1084 struct hsh_token_s token = request->tokens.buf[i];
1085 if (token.type == token_type) {
1086 str.buf = &request->buffer.buf[token.index];
1087 str.len = token.len;
1088 return str;
1089 }
1090 }
1091 return str;
1092}
1093
1094http_string_t hs_request_header(http_request_t *request, char const *key) {
1095 int len = strlen(key);
1096 for (int i = 0; i < request->tokens.size; i++) {
1097 struct hsh_token_s token = request->tokens.buf[i];
1098 if (token.type == HSH_TOK_HEADER_KEY && token.len == len) {
1099 if (_hs_case_insensitive_cmp(&request->buffer.buf[token.index], key,
1100 len)) {
1101 token = request->tokens.buf[i + 1];
1102 return (http_string_t){.buf = &request->buffer.buf[token.index],
1103 .len = token.len};
1104 }
1105 }
1106 }
1107 return (http_string_t){};
1108}
1109
1110void hs_request_detect_keep_alive_flag(http_request_t *request) {
1111 http_string_t str = hs_get_token_string(request, HSH_TOK_VERSION);
1112 if (str.buf == NULL)
1113 return;
1114 int version = str.buf[str.len - 1] == '1';
1115 str = hs_request_header(request, "Connection");
1116 if ((str.len == 5 && _hs_case_insensitive_cmp(str.buf, "close", 5)) ||
1117 (str.len == 0 && version == HTTP_1_0)) {
1118 HTTP_FLAG_CLEAR(request->flags, HTTP_KEEP_ALIVE);
1119 } else {
1120 HTTP_FLAG_SET(request->flags, HTTP_KEEP_ALIVE);
1121 }
1122}
1123
1124int _hs_get_header_key_val(http_request_t *request, http_string_t *key,
1125 http_string_t *val, int iter) {
1126 struct hsh_token_s token = request->tokens.buf[iter];
1127 if (request->tokens.buf[iter].type == HSH_TOK_HEADERS_DONE)
1128 return 0;
1129 *key = (http_string_t){.buf = &request->buffer.buf[token.index],
1130 .len = token.len};
1131 token = request->tokens.buf[iter + 1];
1132 *val = (http_string_t){.buf = &request->buffer.buf[token.index],
1133 .len = token.len};
1134 return 1;
1135}
1136
1137int hs_request_iterate_headers(http_request_t *request, http_string_t *key,
1138 http_string_t *val, int *iter) {
1139 if (*iter == 0) {
1140 for (; *iter < request->tokens.size; (*iter)++) {
1141 struct hsh_token_s token = request->tokens.buf[*iter];
1142 if (token.type == HSH_TOK_HEADER_KEY) {
1143 int more = _hs_get_header_key_val(request, key, val, *iter);
1144 (*iter)++;
1145 return more;
1146 }
1147 }
1148 return 0;
1149 } else {
1150 (*iter)++;
1151 int more = _hs_get_header_key_val(request, key, val, *iter);
1152 (*iter)++;
1153 return more;
1154 }
1155}
1156
1157void hs_request_set_keep_alive_flag(http_request_t *request, int directive) {
1158 if (directive == HTTP_KEEP_ALIVE) {
1159 HTTP_FLAG_CLEAR(request->flags, HTTP_AUTOMATIC);
1160 HTTP_FLAG_SET(request->flags, HTTP_KEEP_ALIVE);
1161 } else if (directive == HTTP_CLOSE) {
1162 HTTP_FLAG_CLEAR(request->flags, HTTP_AUTOMATIC);
1163 HTTP_FLAG_CLEAR(request->flags, HTTP_KEEP_ALIVE);
1164 }
1165}
1166
1167http_string_t hs_request_chunk(struct http_request_s *request) {
1168 struct hsh_token_s token = request->tokens.buf[request->tokens.size - 1];
1169 return (http_string_t){.buf = &request->buffer.buf[token.index],
1170 .len = token.len};
1171}
1172
1173#line 1 "parser.c"
1174
1175#line 1 "/Users/jeremywilliams/code/httpserver.h/src/parser.rl"
1176#include <string.h>
1177#include <stdlib.h>
1178
1179#ifndef HTTPSERVER_IMPL
1180#include "common.h"
1181#include "parser.h"
1182#endif
1183
1184#define HSH_P_FLAG_CHUNKED 0x1
1185#define HSH_P_FLAG_TOKEN_READY 0x2
1186#define HSH_P_FLAG_DONE 0x4
1187
1188#define HSH_ENTER_TOKEN(tok_type, max_len) \
1189 parser->token.type = tok_type; \
1190 parser->token.index = p - buffer->buf; \
1191 parser->token.flags = 0; \
1192 parser->limit_count = 0; \
1193 parser->limit_max = max_len;
1194
1195
1196#line 232 "/Users/jeremywilliams/code/httpserver.h/src/parser.rl"
1197
1198
1199
1200#line 28 "/Users/jeremywilliams/code/httpserver.h/build/src/parser.c"
1201static const char _hsh_http_actions[] = {
1202 0, 1, 2, 1, 6, 1, 10, 1,
1203 13, 1, 14, 1, 15, 1, 16, 1,
1204 17, 1, 18, 2, 0, 10, 2, 1,
1205 10, 2, 4, 10, 2, 5, 14, 2,
1206 5, 16, 2, 5, 17, 2, 7, 10,
1207 2, 8, 10, 2, 10, 11, 2, 12,
1208 13, 2, 13, 14, 3, 3, 9, 10,
1209 3, 4, 10, 6, 3, 7, 4, 10,
1210 3, 9, 3, 10, 3, 13, 5, 14,
1211 3, 13, 14, 12, 3, 14, 12, 13,
1212 4, 5, 14, 12, 13, 4, 13, 5,
1213 14, 12, 4, 14, 12, 13, 15
1214};
1215
1216static const short _hsh_http_key_offsets[] = {
1217 0, 0, 4, 9, 10, 11, 12, 13,
1218 14, 15, 16, 17, 18, 20, 21, 22,
1219 39, 53, 55, 58, 60, 61, 79, 94,
1220 110, 126, 142, 158, 174, 190, 205, 221,
1221 237, 253, 269, 285, 301, 315, 317, 322,
1222 324, 328, 344, 360, 376, 392, 408, 424,
1223 440, 455, 471, 487, 503, 519, 535, 551,
1224 567, 583, 597, 599, 603, 606, 609, 612,
1225 615, 618, 621, 622, 623, 624, 631, 632,
1226 632, 633, 634, 635, 642, 643, 643, 644,
1227 652, 661, 669, 677, 686, 688, 697, 698,
1228 699, 699, 699, 713, 713, 713, 721, 729,
1229 729, 729
1230};
1231
1232static const char _hsh_http_trans_keys[] = {
1233 65, 90, 97, 122, 32, 65, 90, 97,
1234 122, 32, 32, 72, 84, 84, 80, 47,
1235 49, 46, 48, 49, 13, 10, 9, 32,
1236 34, 44, 47, 67, 84, 99, 116, 123,
1237 125, 40, 41, 58, 64, 91, 93, 9,
1238 32, 34, 44, 47, 58, 123, 125, 40,
1239 41, 59, 64, 91, 93, 9, 32, 9,
1240 13, 32, 10, 13, 10, 9, 13, 32,
1241 34, 44, 47, 67, 84, 99, 116, 123,
1242 125, 40, 41, 58, 64, 91, 93, 9,
1243 10, 32, 34, 44, 47, 58, 123, 125,
1244 40, 41, 59, 64, 91, 93, 9, 32,
1245 34, 44, 47, 58, 79, 111, 123, 125,
1246 40, 41, 59, 64, 91, 93, 9, 32,
1247 34, 44, 47, 58, 78, 110, 123, 125,
1248 40, 41, 59, 64, 91, 93, 9, 32,
1249 34, 44, 47, 58, 84, 116, 123, 125,
1250 40, 41, 59, 64, 91, 93, 9, 32,
1251 34, 44, 47, 58, 69, 101, 123, 125,
1252 40, 41, 59, 64, 91, 93, 9, 32,
1253 34, 44, 47, 58, 78, 110, 123, 125,
1254 40, 41, 59, 64, 91, 93, 9, 32,
1255 34, 44, 47, 58, 84, 116, 123, 125,
1256 40, 41, 59, 64, 91, 93, 9, 32,
1257 34, 44, 45, 47, 58, 123, 125, 40,
1258 41, 59, 64, 91, 93, 9, 32, 34,
1259 44, 47, 58, 76, 108, 123, 125, 40,
1260 41, 59, 64, 91, 93, 9, 32, 34,
1261 44, 47, 58, 69, 101, 123, 125, 40,
1262 41, 59, 64, 91, 93, 9, 32, 34,
1263 44, 47, 58, 78, 110, 123, 125, 40,
1264 41, 59, 64, 91, 93, 9, 32, 34,
1265 44, 47, 58, 71, 103, 123, 125, 40,
1266 41, 59, 64, 91, 93, 9, 32, 34,
1267 44, 47, 58, 84, 116, 123, 125, 40,
1268 41, 59, 64, 91, 93, 9, 32, 34,
1269 44, 47, 58, 72, 104, 123, 125, 40,
1270 41, 59, 64, 91, 93, 9, 32, 34,
1271 44, 47, 58, 123, 125, 40, 41, 59,
1272 64, 91, 93, 9, 32, 9, 13, 32,
1273 48, 57, 10, 13, 10, 13, 48, 57,
1274 9, 32, 34, 44, 47, 58, 82, 114,
1275 123, 125, 40, 41, 59, 64, 91, 93,
1276 9, 32, 34, 44, 47, 58, 65, 97,
1277 123, 125, 40, 41, 59, 64, 91, 93,
1278 9, 32, 34, 44, 47, 58, 78, 110,
1279 123, 125, 40, 41, 59, 64, 91, 93,
1280 9, 32, 34, 44, 47, 58, 83, 115,
1281 123, 125, 40, 41, 59, 64, 91, 93,
1282 9, 32, 34, 44, 47, 58, 70, 102,
1283 123, 125, 40, 41, 59, 64, 91, 93,
1284 9, 32, 34, 44, 47, 58, 69, 101,
1285 123, 125, 40, 41, 59, 64, 91, 93,
1286 9, 32, 34, 44, 47, 58, 82, 114,
1287 123, 125, 40, 41, 59, 64, 91, 93,
1288 9, 32, 34, 44, 45, 47, 58, 123,
1289 125, 40, 41, 59, 64, 91, 93, 9,
1290 32, 34, 44, 47, 58, 69, 101, 123,
1291 125, 40, 41, 59, 64, 91, 93, 9,
1292 32, 34, 44, 47, 58, 78, 110, 123,
1293 125, 40, 41, 59, 64, 91, 93, 9,
1294 32, 34, 44, 47, 58, 67, 99, 123,
1295 125, 40, 41, 59, 64, 91, 93, 9,
1296 32, 34, 44, 47, 58, 79, 111, 123,
1297 125, 40, 41, 59, 64, 91, 93, 9,
1298 32, 34, 44, 47, 58, 68, 100, 123,
1299 125, 40, 41, 59, 64, 91, 93, 9,
1300 32, 34, 44, 47, 58, 73, 105, 123,
1301 125, 40, 41, 59, 64, 91, 93, 9,
1302 32, 34, 44, 47, 58, 78, 110, 123,
1303 125, 40, 41, 59, 64, 91, 93, 9,
1304 32, 34, 44, 47, 58, 71, 103, 123,
1305 125, 40, 41, 59, 64, 91, 93, 9,
1306 32, 34, 44, 47, 58, 123, 125, 40,
1307 41, 59, 64, 91, 93, 9, 32, 9,
1308 13, 32, 99, 10, 13, 104, 10, 13,
1309 117, 10, 13, 110, 10, 13, 107, 10,
1310 13, 101, 10, 13, 100, 13, 10, 48,
1311 13, 48, 57, 65, 70, 97, 102, 10,
1312 13, 10, 48, 13, 48, 57, 65, 70,
1313 97, 102, 10, 48, 13, 48, 49, 57,
1314 65, 70, 97, 102, 10, 13, 48, 49,
1315 57, 65, 70, 97, 102, 13, 48, 49,
1316 57, 65, 70, 97, 102, 13, 48, 49,
1317 57, 65, 70, 97, 102, 10, 13, 48,
1318 49, 57, 65, 70, 97, 102, 13, 48,
1319 10, 13, 48, 49, 57, 65, 70, 97,
1320 102, 13, 10, 9, 32, 34, 44, 47,
1321 58, 123, 125, 40, 41, 59, 64, 91,
1322 93, 13, 48, 49, 57, 65, 70, 97,
1323 102, 13, 48, 49, 57, 65, 70, 97,
1324 102, 0
1325};
1326
1327static const char _hsh_http_single_lengths[] = {
1328 0, 0, 1, 1, 1, 1, 1, 1,
1329 1, 1, 1, 1, 0, 1, 1, 11,
1330 8, 2, 3, 2, 1, 12, 9, 10,
1331 10, 10, 10, 10, 10, 9, 10, 10,
1332 10, 10, 10, 10, 8, 2, 3, 2,
1333 2, 10, 10, 10, 10, 10, 10, 10,
1334 9, 10, 10, 10, 10, 10, 10, 10,
1335 10, 8, 2, 4, 3, 3, 3, 3,
1336 3, 3, 1, 1, 1, 1, 1, 0,
1337 1, 1, 1, 1, 1, 0, 1, 2,
1338 3, 2, 2, 3, 2, 3, 1, 1,
1339 0, 0, 8, 0, 0, 2, 2, 0,
1340 0, 0
1341};
1342
1343static const char _hsh_http_range_lengths[] = {
1344 0, 2, 2, 0, 0, 0, 0, 0,
1345 0, 0, 0, 0, 1, 0, 0, 3,
1346 3, 0, 0, 0, 0, 3, 3, 3,
1347 3, 3, 3, 3, 3, 3, 3, 3,
1348 3, 3, 3, 3, 3, 0, 1, 0,
1349 1, 3, 3, 3, 3, 3, 3, 3,
1350 3, 3, 3, 3, 3, 3, 3, 3,
1351 3, 3, 0, 0, 0, 0, 0, 0,
1352 0, 0, 0, 0, 0, 3, 0, 0,
1353 0, 0, 0, 3, 0, 0, 0, 3,
1354 3, 3, 3, 3, 0, 3, 0, 0,
1355 0, 0, 3, 0, 0, 3, 3, 0,
1356 0, 0
1357};
1358
1359static const short _hsh_http_index_offsets[] = {
1360 0, 0, 3, 7, 9, 11, 13, 15,
1361 17, 19, 21, 23, 25, 27, 29, 31,
1362 46, 58, 61, 65, 68, 70, 86, 99,
1363 113, 127, 141, 155, 169, 183, 196, 210,
1364 224, 238, 252, 266, 280, 292, 295, 300,
1365 303, 307, 321, 335, 349, 363, 377, 391,
1366 405, 418, 432, 446, 460, 474, 488, 502,
1367 516, 530, 542, 545, 550, 554, 558, 562,
1368 566, 570, 574, 576, 578, 580, 585, 587,
1369 588, 590, 592, 594, 599, 601, 602, 604,
1370 610, 617, 623, 629, 636, 639, 646, 648,
1371 650, 651, 652, 664, 665, 666, 672, 678,
1372 679, 680
1373};
1374
1375static const char _hsh_http_indicies[] = {
1376 1, 1, 0, 2, 3, 3, 0, 0,
1377 4, 6, 5, 7, 0, 8, 0, 9,
1378 0, 10, 0, 11, 0, 12, 0, 13,
1379 0, 14, 0, 15, 0, 16, 0, 0,
1380 0, 0, 0, 0, 18, 19, 18, 19,
1381 0, 0, 0, 0, 0, 17, 0, 0,
1382 0, 0, 0, 21, 0, 0, 0, 0,
1383 0, 20, 22, 22, 0, 24, 25, 24,
1384 23, 0, 27, 26, 28, 0, 0, 30,
1385 0, 0, 0, 0, 31, 32, 31, 32,
1386 0, 0, 0, 0, 0, 29, 0, 33,
1387 0, 0, 0, 0, 21, 0, 0, 0,
1388 0, 0, 20, 0, 0, 0, 0, 0,
1389 21, 34, 34, 0, 0, 0, 0, 0,
1390 20, 0, 0, 0, 0, 0, 21, 35,
1391 35, 0, 0, 0, 0, 0, 20, 0,
1392 0, 0, 0, 0, 21, 36, 36, 0,
1393 0, 0, 0, 0, 20, 0, 0, 0,
1394 0, 0, 21, 37, 37, 0, 0, 0,
1395 0, 0, 20, 0, 0, 0, 0, 0,
1396 21, 38, 38, 0, 0, 0, 0, 0,
1397 20, 0, 0, 0, 0, 0, 21, 39,
1398 39, 0, 0, 0, 0, 0, 20, 0,
1399 0, 0, 0, 40, 0, 21, 0, 0,
1400 0, 0, 0, 20, 0, 0, 0, 0,
1401 0, 21, 41, 41, 0, 0, 0, 0,
1402 0, 20, 0, 0, 0, 0, 0, 21,
1403 42, 42, 0, 0, 0, 0, 0, 20,
1404 0, 0, 0, 0, 0, 21, 43, 43,
1405 0, 0, 0, 0, 0, 20, 0, 0,
1406 0, 0, 0, 21, 44, 44, 0, 0,
1407 0, 0, 0, 20, 0, 0, 0, 0,
1408 0, 21, 45, 45, 0, 0, 0, 0,
1409 0, 20, 0, 0, 0, 0, 0, 21,
1410 46, 46, 0, 0, 0, 0, 0, 20,
1411 0, 0, 0, 0, 0, 47, 0, 0,
1412 0, 0, 0, 20, 48, 48, 0, 49,
1413 25, 49, 50, 23, 28, 27, 26, 0,
1414 27, 51, 26, 0, 0, 0, 0, 0,
1415 21, 52, 52, 0, 0, 0, 0, 0,
1416 20, 0, 0, 0, 0, 0, 21, 53,
1417 53, 0, 0, 0, 0, 0, 20, 0,
1418 0, 0, 0, 0, 21, 54, 54, 0,
1419 0, 0, 0, 0, 20, 0, 0, 0,
1420 0, 0, 21, 55, 55, 0, 0, 0,
1421 0, 0, 20, 0, 0, 0, 0, 0,
1422 21, 56, 56, 0, 0, 0, 0, 0,
1423 20, 0, 0, 0, 0, 0, 21, 57,
1424 57, 0, 0, 0, 0, 0, 20, 0,
1425 0, 0, 0, 0, 21, 58, 58, 0,
1426 0, 0, 0, 0, 20, 0, 0, 0,
1427 0, 59, 0, 21, 0, 0, 0, 0,
1428 0, 20, 0, 0, 0, 0, 0, 21,
1429 60, 60, 0, 0, 0, 0, 0, 20,
1430 0, 0, 0, 0, 0, 21, 61, 61,
1431 0, 0, 0, 0, 0, 20, 0, 0,
1432 0, 0, 0, 21, 62, 62, 0, 0,
1433 0, 0, 0, 20, 0, 0, 0, 0,
1434 0, 21, 63, 63, 0, 0, 0, 0,
1435 0, 20, 0, 0, 0, 0, 0, 21,
1436 64, 64, 0, 0, 0, 0, 0, 20,
1437 0, 0, 0, 0, 0, 21, 65, 65,
1438 0, 0, 0, 0, 0, 20, 0, 0,
1439 0, 0, 0, 21, 66, 66, 0, 0,
1440 0, 0, 0, 20, 0, 0, 0, 0,
1441 0, 21, 67, 67, 0, 0, 0, 0,
1442 0, 20, 0, 0, 0, 0, 0, 68,
1443 0, 0, 0, 0, 0, 20, 69, 69,
1444 0, 70, 25, 70, 71, 23, 0, 27,
1445 72, 26, 0, 27, 73, 26, 0, 27,
1446 74, 26, 0, 27, 75, 26, 0, 27,
1447 76, 26, 0, 27, 77, 26, 78, 0,
1448 79, 0, 81, 80, 82, 83, 83, 83,
1449 0, 84, 0, 85, 86, 0, 87, 0,
1450 89, 88, 90, 91, 91, 91, 0, 92,
1451 0, 93, 95, 94, 96, 97, 98, 98,
1452 98, 94, 99, 96, 97, 98, 98, 98,
1453 94, 101, 102, 103, 103, 103, 100, 104,
1454 97, 98, 98, 98, 94, 105, 96, 97,
1455 98, 98, 98, 94, 106, 95, 94, 107,
1456 96, 97, 98, 98, 98, 94, 108, 0,
1457 109, 0, 110, 111, 0, 0, 0, 0,
1458 0, 21, 0, 0, 0, 0, 0, 20,
1459 112, 0, 101, 102, 103, 103, 103, 100,
1460 96, 97, 98, 98, 98, 94, 0, 113,
1461 114, 0
1462};
1463
1464static const char _hsh_http_trans_targs[] = {
1465 0, 2, 3, 2, 4, 4, 5, 6,
1466 7, 8, 9, 10, 11, 12, 13, 14,
1467 15, 16, 23, 41, 16, 17, 18, 19,
1468 18, 39, 19, 20, 21, 16, 22, 23,
1469 41, 90, 24, 25, 26, 27, 28, 29,
1470 30, 31, 32, 33, 34, 35, 36, 37,
1471 38, 38, 40, 40, 42, 43, 44, 45,
1472 46, 47, 48, 49, 50, 51, 52, 53,
1473 54, 55, 56, 57, 58, 59, 59, 60,
1474 61, 62, 63, 64, 65, 19, 67, 68,
1475 69, 72, 70, 69, 71, 91, 73, 92,
1476 75, 86, 76, 75, 77, 78, 79, 84,
1477 80, 82, 79, 81, 79, 80, 82, 79,
1478 83, 93, 85, 94, 87, 95, 96, 97,
1479 91, 96, 97
1480};
1481
1482static const char _hsh_http_trans_actions[] = {
1483 17, 19, 3, 5, 22, 5, 3, 1,
1484 0, 0, 0, 0, 0, 0, 0, 3,
1485 0, 64, 64, 64, 5, 3, 0, 25,
1486 25, 56, 5, 3, 5, 52, 52, 52,
1487 52, 43, 5, 5, 5, 5, 5, 5,
1488 5, 5, 5, 5, 5, 5, 5, 3,
1489 0, 25, 60, 37, 5, 5, 5, 5,
1490 5, 5, 5, 5, 5, 5, 5, 5,
1491 5, 5, 5, 5, 3, 0, 25, 25,
1492 5, 5, 5, 5, 5, 40, 0, 0,
1493 46, 0, 0, 7, 0, 28, 0, 11,
1494 46, 0, 0, 7, 0, 28, 76, 9,
1495 76, 49, 72, 76, 80, 80, 68, 85,
1496 76, 90, 76, 90, 0, 11, 31, 34,
1497 9, 13, 15
1498};
1499
1500static const char _hsh_http_eof_actions[] = {
1501 0, 17, 17, 17, 17, 17, 17, 17,
1502 17, 17, 17, 17, 17, 17, 17, 17,
1503 17, 17, 17, 17, 17, 17, 17, 17,
1504 17, 17, 17, 17, 17, 17, 17, 17,
1505 17, 17, 17, 17, 17, 17, 17, 17,
1506 17, 17, 17, 17, 17, 17, 17, 17,
1507 17, 17, 17, 17, 17, 17, 17, 17,
1508 17, 17, 17, 17, 17, 17, 17, 17,
1509 17, 17, 17, 17, 17, 17, 17, 17,
1510 17, 17, 17, 17, 17, 17, 17, 17,
1511 17, 17, 17, 17, 17, 17, 17, 17,
1512 0, 0, 0, 0, 0, 0, 0, 0,
1513 0, 0
1514};
1515
1516static const int hsh_http_start = 1;
1517static const int hsh_http_first_final = 90;
1518static const int hsh_http_error = 0;
1519
1520static const int hsh_http_en_chunk_end = 66;
1521static const int hsh_http_en_chunked_body = 74;
1522static const int hsh_http_en_small_body = 88;
1523static const int hsh_http_en_large_body = 89;
1524static const int hsh_http_en_main = 1;
1525
1526
1527#line 235 "/Users/jeremywilliams/code/httpserver.h/src/parser.rl"
1528
1529void hsh_parser_init(struct hsh_parser_s* parser) {
1530 memset(parser, 0, sizeof(struct hsh_parser_s));
1531 parser->state = hsh_http_start;
1532}
1533
1534struct hsh_token_s hsh_parser_exec(struct hsh_parser_s* parser, struct hsh_buffer_s* buffer, int max_buf_capacity) {
1535 struct hsh_token_s none = {};
1536 none.type = HSH_TOK_NONE;
1537 if (HTTP_FLAG_CHECK(parser->flags, HSH_P_FLAG_DONE) || parser->sequence_id == buffer->sequence_id) {
1538 return none;
1539 }
1540 int cs = parser->state;
1541 char* eof = NULL;
1542 char *p = buffer->buf + buffer->index;
1543 char *pe = buffer->buf + buffer->length;
1544
1545#line 373 "/Users/jeremywilliams/code/httpserver.h/build/src/parser.c"
1546 {
1547 int _klen;
1548 unsigned int _trans;
1549 const char *_acts;
1550 unsigned int _nacts;
1551 const char *_keys;
1552
1553 if ( p == pe )
1554 goto _test_eof;
1555 if ( cs == 0 )
1556 goto _out;
1557_resume:
1558 _keys = _hsh_http_trans_keys + _hsh_http_key_offsets[cs];
1559 _trans = _hsh_http_index_offsets[cs];
1560
1561 _klen = _hsh_http_single_lengths[cs];
1562 if ( _klen > 0 ) {
1563 const char *_lower = _keys;
1564 const char *_mid;
1565 const char *_upper = _keys + _klen - 1;
1566 while (1) {
1567 if ( _upper < _lower )
1568 break;
1569
1570 _mid = _lower + ((_upper-_lower) >> 1);
1571 if ( (*p) < *_mid )
1572 _upper = _mid - 1;
1573 else if ( (*p) > *_mid )
1574 _lower = _mid + 1;
1575 else {
1576 _trans += (unsigned int)(_mid - _keys);
1577 goto _match;
1578 }
1579 }
1580 _keys += _klen;
1581 _trans += _klen;
1582 }
1583
1584 _klen = _hsh_http_range_lengths[cs];
1585 if ( _klen > 0 ) {
1586 const char *_lower = _keys;
1587 const char *_mid;
1588 const char *_upper = _keys + (_klen<<1) - 2;
1589 while (1) {
1590 if ( _upper < _lower )
1591 break;
1592
1593 _mid = _lower + (((_upper-_lower) >> 1) & ~1);
1594 if ( (*p) < _mid[0] )
1595 _upper = _mid - 2;
1596 else if ( (*p) > _mid[1] )
1597 _lower = _mid + 2;
1598 else {
1599 _trans += (unsigned int)((_mid - _keys)>>1);
1600 goto _match;
1601 }
1602 }
1603 _trans += _klen;
1604 }
1605
1606_match:
1607 _trans = _hsh_http_indicies[_trans];
1608 cs = _hsh_http_trans_targs[_trans];
1609
1610 if ( _hsh_http_trans_actions[_trans] == 0 )
1611 goto _again;
1612
1613 _acts = _hsh_http_actions + _hsh_http_trans_actions[_trans];
1614 _nacts = (unsigned int) *_acts++;
1615 while ( _nacts-- > 0 )
1616 {
1617 switch ( *_acts++ )
1618 {
1619 case 0:
1620#line 23 "/Users/jeremywilliams/code/httpserver.h/src/parser.rl"
1621 { HSH_ENTER_TOKEN(HSH_TOK_METHOD, 32) }
1622 break;
1623 case 1:
1624#line 24 "/Users/jeremywilliams/code/httpserver.h/src/parser.rl"
1625 { HSH_ENTER_TOKEN(HSH_TOK_TARGET, 1024) }
1626 break;
1627 case 2:
1628#line 25 "/Users/jeremywilliams/code/httpserver.h/src/parser.rl"
1629 { HSH_ENTER_TOKEN(HSH_TOK_VERSION, 16) }
1630 break;
1631 case 3:
1632#line 26 "/Users/jeremywilliams/code/httpserver.h/src/parser.rl"
1633 { HSH_ENTER_TOKEN(HSH_TOK_HEADER_KEY, 256) }
1634 break;
1635 case 4:
1636#line 27 "/Users/jeremywilliams/code/httpserver.h/src/parser.rl"
1637 { HSH_ENTER_TOKEN(HSH_TOK_HEADER_VALUE, 4096) }
1638 break;
1639 case 5:
1640#line 28 "/Users/jeremywilliams/code/httpserver.h/src/parser.rl"
1641 {
1642 parser->token.type = HSH_TOK_BODY;
1643 parser->token.flags = 0;
1644 parser->token.index = p - buffer->buf;
1645 }
1646 break;
1647 case 6:
1648#line 33 "/Users/jeremywilliams/code/httpserver.h/src/parser.rl"
1649 {
1650 parser->token.len = p - (buffer->buf + parser->token.index);
1651 // hsh_token_array_push(&parser->tokens, parser->token);
1652 HTTP_FLAG_SET(parser->flags, HSH_P_FLAG_TOKEN_READY);
1653 {p++; goto _out; }
1654 }
1655 break;
1656 case 7:
1657#line 40 "/Users/jeremywilliams/code/httpserver.h/src/parser.rl"
1658 {
1659 parser->content_length *= 10;
1660 parser->content_length += (*p) - '0';
1661 }
1662 break;
1663 case 8:
1664#line 45 "/Users/jeremywilliams/code/httpserver.h/src/parser.rl"
1665 {
1666 HTTP_FLAG_SET(parser->flags, HSH_P_FLAG_CHUNKED);
1667 }
1668 break;
1669 case 9:
1670#line 49 "/Users/jeremywilliams/code/httpserver.h/src/parser.rl"
1671 {
1672 parser->limit_count = 0;
1673 parser->limit_max = 256;
1674 }
1675 break;
1676 case 10:
1677#line 54 "/Users/jeremywilliams/code/httpserver.h/src/parser.rl"
1678 {
1679 parser->limit_count++;
1680 if (parser->limit_count > parser->limit_max) {
1681 // parser->rc = (int8_t)HSH_PARSER_ERR;
1682 {p++; goto _out; }
1683 }
1684 }
1685 break;
1686 case 11:
1687#line 62 "/Users/jeremywilliams/code/httpserver.h/src/parser.rl"
1688 {
1689 buffer->after_headers_index = p - buffer->buf + 1;
1690 parser->content_remaining = parser->content_length;
1691 parser->token = (struct hsh_token_s){ };
1692 parser->token.type = HSH_TOK_HEADERS_DONE;
1693 HTTP_FLAG_SET(parser->flags, HSH_P_FLAG_TOKEN_READY);
1694 if (HTTP_FLAG_CHECK(parser->flags, HSH_P_FLAG_CHUNKED)) {
1695 HTTP_FLAG_SET(parser->token.flags, HSH_TOK_FLAG_STREAMED_BODY);
1696 cs = 74;
1697 {p++; goto _out; }
1698 } else if (parser->content_length == 0) {
1699 HTTP_FLAG_SET(parser->token.flags, HSH_TOK_FLAG_NO_BODY);
1700 {p++; goto _out; }
1701 // The body won't fit into the buffer at maximum capacity.
1702 } else if (parser->content_length > max_buf_capacity - buffer->after_headers_index) {
1703 HTTP_FLAG_SET(parser->token.flags, HSH_TOK_FLAG_STREAMED_BODY);
1704 cs = 89;
1705 {p++; goto _out; }
1706 } else {
1707 // Resize the buffer to hold the full body
1708 if (parser->content_length + buffer->after_headers_index > buffer->capacity) {
1709 buffer->buf = (char*)realloc(buffer->buf, parser->content_length + buffer->after_headers_index);
1710 buffer->capacity = parser->content_length + buffer->after_headers_index;
1711 }
1712 cs = 88;
1713 {p++; goto _out; }
1714 }
1715 }
1716 break;
1717 case 12:
1718#line 91 "/Users/jeremywilliams/code/httpserver.h/src/parser.rl"
1719 {
1720 parser->content_length = 0;
1721 }
1722 break;
1723 case 13:
1724#line 95 "/Users/jeremywilliams/code/httpserver.h/src/parser.rl"
1725 {
1726 if ((*p) >= 'A' && (*p) <= 'F') {
1727 parser->content_length *= 0x10;
1728 parser->content_length += (*p) - 55;
1729 } else if ((*p) >= 'a' && (*p) <= 'f') {
1730 parser->content_length *= 0x10;
1731 parser->content_length += (*p) - 87;
1732 } else if ((*p) >= '0' && (*p) <= '9') {
1733 parser->content_length *= 0x10;
1734 parser->content_length += (*p) - '0';
1735 }
1736 }
1737 break;
1738 case 14:
1739#line 108 "/Users/jeremywilliams/code/httpserver.h/src/parser.rl"
1740 {
1741 char* last_body_byte = buffer->buf + parser->token.index + parser->content_length - 1;
1742 if (pe >= last_body_byte) {
1743 p = last_body_byte;
1744 parser->token.len = parser->content_length;
1745 HTTP_FLAG_SET(parser->flags, HSH_P_FLAG_TOKEN_READY);
1746 cs = 66;
1747 {p++; goto _out; }
1748 // The current chunk is at the end of the buffer and the buffer cannot be expanded.
1749 // Move the remaining contents of the buffer to just after the headers to free up
1750 // capacity in the buffer.
1751 } else if (p - buffer->buf + parser->content_length > max_buf_capacity) {
1752 memcpy(buffer->buf + buffer->after_headers_index, p, pe - p);
1753 buffer->length = buffer->after_headers_index + pe - p;
1754 p = buffer->buf + buffer->after_headers_index;
1755 parser->token.index = buffer->after_headers_index;
1756 parser->sequence_id = buffer->sequence_id;
1757 p--;
1758 {p++; goto _out; }
1759 }
1760 }
1761 break;
1762 case 15:
1763#line 130 "/Users/jeremywilliams/code/httpserver.h/src/parser.rl"
1764 {
1765 // write 0 byte body to tokens
1766 parser->token.type = HSH_TOK_BODY;
1767 parser->token.index = 0;
1768 parser->token.len = 0;
1769 parser->token.flags = HSH_TOK_FLAG_BODY_FINAL;
1770 HTTP_FLAG_SET(parser->flags, HSH_P_FLAG_TOKEN_READY);
1771 HTTP_FLAG_SET(parser->flags, HSH_P_FLAG_DONE);
1772 {p++; goto _out; }
1773 }
1774 break;
1775 case 16:
1776#line 141 "/Users/jeremywilliams/code/httpserver.h/src/parser.rl"
1777 {
1778 parser->token.index = buffer->after_headers_index;
1779 parser->token.len = parser->content_length;
1780 HTTP_FLAG_SET(parser->token.flags, HSH_TOK_FLAG_SMALL_BODY);
1781 char* last_body_byte = buffer->buf + parser->token.index + parser->content_length - 1;
1782 if (pe >= last_body_byte) {
1783 HTTP_FLAG_SET(parser->flags, HSH_P_FLAG_TOKEN_READY);
1784 HTTP_FLAG_SET(parser->flags, HSH_P_FLAG_DONE);
1785 }
1786 p = pe;
1787 p--;
1788 {p++; goto _out; }
1789 }
1790 break;
1791 case 17:
1792#line 155 "/Users/jeremywilliams/code/httpserver.h/src/parser.rl"
1793 {
1794 parser->token.index = buffer->after_headers_index;
1795 char* last_body_byte = buffer->buf + buffer->after_headers_index + parser->content_remaining - 1;
1796 if (pe >= last_body_byte) {
1797 parser->token.flags = HSH_TOK_FLAG_BODY_FINAL;
1798 parser->token.len = parser->content_remaining;
1799 parser->content_remaining = 0;
1800 HTTP_FLAG_SET(parser->flags, HSH_P_FLAG_TOKEN_READY);
1801 HTTP_FLAG_SET(parser->flags, HSH_P_FLAG_DONE);
1802 } else {
1803 parser->token.len = pe - p;
1804 parser->content_remaining -= parser->token.len;
1805 HTTP_FLAG_SET(parser->flags, HSH_P_FLAG_TOKEN_READY);
1806 p = buffer->buf + buffer->after_headers_index;
1807 buffer->length = buffer->after_headers_index;
1808 parser->sequence_id = buffer->sequence_id;
1809 }
1810 p--;
1811 {p++; goto _out; }
1812 }
1813 break;
1814 case 18:
1815#line 176 "/Users/jeremywilliams/code/httpserver.h/src/parser.rl"
1816 {
1817 // parser->rc = (int8_t)HSH_PARSER_ERR;
1818 {p++; goto _out; }
1819 }
1820 break;
1821#line 649 "/Users/jeremywilliams/code/httpserver.h/build/src/parser.c"
1822 }
1823 }
1824
1825_again:
1826 if ( cs == 0 )
1827 goto _out;
1828 if ( ++p != pe )
1829 goto _resume;
1830 _test_eof: {}
1831 if ( p == eof )
1832 {
1833 const char *__acts = _hsh_http_actions + _hsh_http_eof_actions[cs];
1834 unsigned int __nacts = (unsigned int) *__acts++;
1835 while ( __nacts-- > 0 ) {
1836 switch ( *__acts++ ) {
1837 case 18:
1838#line 176 "/Users/jeremywilliams/code/httpserver.h/src/parser.rl"
1839 {
1840 // parser->rc = (int8_t)HSH_PARSER_ERR;
1841 {p++; goto _out; }
1842 }
1843 break;
1844#line 672 "/Users/jeremywilliams/code/httpserver.h/build/src/parser.c"
1845 }
1846 }
1847 }
1848
1849 _out: {}
1850 }
1851
1852#line 252 "/Users/jeremywilliams/code/httpserver.h/src/parser.rl"
1853 parser->state = cs;
1854 buffer->index = p - buffer->buf;
1855 if (HTTP_FLAG_CHECK(parser->flags, HSH_P_FLAG_TOKEN_READY)) {
1856 HTTP_FLAG_CLEAR(parser->flags, HSH_P_FLAG_TOKEN_READY);
1857 return parser->token;
1858 } else {
1859 parser->sequence_id = buffer->sequence_id;
1860 return none;
1861 }
1862}
1863
1864#line 1 "read_socket.c"
1865#include <assert.h>
1866#include <stdlib.h>
1867#include <string.h>
1868#include <unistd.h>
1869
1870#ifndef HTTPSERVER_IMPL
1871#include "common.h"
1872#include "parser.h"
1873#include "read_socket.h"
1874#endif
1875
1876void _hs_token_array_push(struct hs_token_array_s *array,
1877 struct hsh_token_s a) {
1878 if (array->size == array->capacity) {
1879 array->capacity *= 2;
1880 array->buf = (struct hsh_token_s *)realloc(
1881 array->buf, array->capacity * sizeof(struct hsh_token_s));
1882 assert(array->buf != NULL);
1883 }
1884 array->buf[array->size] = a;
1885 array->size++;
1886}
1887
1888void _hs_buffer_init(struct hsh_buffer_s *buffer, int initial_capacity,
1889 int64_t *memused) {
1890 *buffer = (struct hsh_buffer_s){0};
1891 buffer->buf = (char *)calloc(1, initial_capacity);
1892 *memused += initial_capacity;
1893 assert(buffer->buf != NULL);
1894 buffer->capacity = initial_capacity;
1895}
1896
1897int _hs_read_into_buffer(struct hsh_buffer_s *buffer, int request_socket,
1898 int64_t *server_memused,
1899 int64_t max_request_buf_capacity) {
1900 int bytes;
1901 do {
1902 bytes = read(request_socket, buffer->buf + buffer->length,
1903 buffer->capacity - buffer->length);
1904 if (bytes > 0)
1905 buffer->length += bytes;
1906
1907 if (buffer->length == buffer->capacity &&
1908 buffer->capacity != max_request_buf_capacity) {
1909 *server_memused -= buffer->capacity;
1910 buffer->capacity *= 2;
1911 if (buffer->capacity > max_request_buf_capacity) {
1912 buffer->capacity = max_request_buf_capacity;
1913 }
1914 *server_memused += buffer->capacity;
1915 buffer->buf = (char *)realloc(buffer->buf, buffer->capacity);
1916 assert(buffer->buf != NULL);
1917 }
1918 } while (bytes > 0 && buffer->capacity < max_request_buf_capacity);
1919
1920 buffer->sequence_id++;
1921
1922 return bytes;
1923}
1924
1925int _hs_buffer_requires_read(struct hsh_buffer_s *buffer) {
1926 return buffer->index >= buffer->length;
1927}
1928
1929void _hs_exec_callback(http_request_t *request,
1930 void (*cb)(struct http_request_s *)) {
1931 request->state = HTTP_SESSION_NOP;
1932 cb(request);
1933}
1934
1935enum hs_read_rc_e
1936_hs_parse_buffer_and_exec_user_cb(http_request_t *request,
1937 int max_request_buf_capacity) {
1938 enum hs_read_rc_e rc = HS_READ_RC_SUCCESS;
1939
1940 do {
1941 struct hsh_token_s token = hsh_parser_exec(
1942 &request->parser, &request->buffer, max_request_buf_capacity);
1943
1944 switch (token.type) {
1945 case HSH_TOK_HEADERS_DONE:
1946 _hs_token_array_push(&request->tokens, token);
1947 if (HTTP_FLAG_CHECK(token.flags, HSH_TOK_FLAG_STREAMED_BODY) ||
1948 HTTP_FLAG_CHECK(token.flags, HSH_TOK_FLAG_NO_BODY)) {
1949 HTTP_FLAG_SET(request->flags, HTTP_FLG_STREAMED);
1950 _hs_exec_callback(request, request->server->request_handler);
1951 return rc;
1952 }
1953 break;
1954 case HSH_TOK_BODY:
1955 _hs_token_array_push(&request->tokens, token);
1956 if (HTTP_FLAG_CHECK(token.flags, HSH_TOK_FLAG_SMALL_BODY)) {
1957 _hs_exec_callback(request, request->server->request_handler);
1958 } else {
1959 if (HTTP_FLAG_CHECK(token.flags, HSH_TOK_FLAG_BODY_FINAL) &&
1960 token.len > 0) {
1961 _hs_exec_callback(request, request->chunk_cb);
1962
1963 // A zero length body is used to indicate to the user code that the
1964 // body has finished streaming. This is natural when dealing with
1965 // chunked request bodies but requires us to inject a zero length
1966 // body for non-chunked requests.
1967 struct hsh_token_s token = {};
1968 memset(&token, 0, sizeof(struct hsh_token_s));
1969 token.type = HSH_TOK_BODY;
1970 _hs_token_array_push(&request->tokens, token);
1971 _hs_exec_callback(request, request->chunk_cb);
1972 } else {
1973 _hs_exec_callback(request, request->chunk_cb);
1974 }
1975 }
1976 return rc;
1977 case HSH_TOK_ERR:
1978 return HS_READ_RC_PARSE_ERR;
1979 case HSH_TOK_NONE:
1980 return rc;
1981 default:
1982 _hs_token_array_push(&request->tokens, token);
1983 break;
1984 }
1985 } while (1);
1986}
1987
1988// Reads the request socket if required and parses HTTP in a non-blocking
1989// manner.
1990//
1991// It should be called when a new connection is established and when a read
1992// ready event occurs for the request socket. It parses the HTTP request and
1993// fills the tokens array of the request struct. It will also invoke the
1994// request_hander callback and the chunk_cb callback in the appropriate
1995// scenarios.
1996enum hs_read_rc_e hs_read_request_and_exec_user_cb(http_request_t *request,
1997 struct hs_read_opts_s opts) {
1998 request->state = HTTP_SESSION_READ;
1999 request->timeout = HTTP_REQUEST_TIMEOUT;
2000
2001 if (request->buffer.buf == NULL) {
2002 _hs_buffer_init(&request->buffer, opts.initial_request_buf_capacity,
2003 &request->server->memused);
2004 hsh_parser_init(&request->parser);
2005 }
2006
2007 if (_hs_buffer_requires_read(&request->buffer)) {
2008 int bytes = _hs_read_into_buffer(&request->buffer, request->socket,
2009 &request->server->memused,
2010 opts.max_request_buf_capacity);
2011
2012 if (bytes == opts.eof_rc) {
2013 return HS_READ_RC_SOCKET_ERR;
2014 }
2015 }
2016
2017 return _hs_parse_buffer_and_exec_user_cb(request,
2018 opts.max_request_buf_capacity);
2019}
2020
2021#line 1 "respond.c"
2022#include <assert.h>
2023#include <stdarg.h>
2024#include <stdint.h>
2025#include <stdio.h>
2026#include <stdlib.h>
2027#include <string.h>
2028
2029#ifndef HTTPSERVER_IMPL
2030#include "buffer_util.h"
2031#include "common.h"
2032#include "request_util.h"
2033#include "respond.h"
2034#endif
2035
2036char const *hs_status_text[] = {
2037 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
2038 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
2039 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
2040 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
2041 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
2042 "", "", "", "", "",
2043
2044 // 100s
2045 "Continue", "Switching Protocols", "", "", "", "", "", "", "", "", "", "",
2046 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
2047 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
2048 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
2049 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
2050 "", "", "", "", "", "", "", "", "", "", "", "",
2051
2052 // 200s
2053 "OK", "Created", "Accepted", "Non-Authoritative Information", "No Content",
2054 "Reset Content", "Partial Content", "", "", "",
2055
2056 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
2057 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
2058 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
2059 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
2060 "", "", "", "", "", "", "", "", "", "", "", "", "", "",
2061
2062 // 300s
2063 "Multiple Choices", "Moved Permanently", "Found", "See Other",
2064 "Not Modified", "Use Proxy", "", "Temporary Redirect", "", "",
2065
2066 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
2067 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
2068 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
2069 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
2070 "", "", "", "", "", "", "", "", "", "", "", "", "", "",
2071
2072 // 400s
2073 "Bad Request", "Unauthorized", "Payment Required", "Forbidden", "Not Found",
2074 "Method Not Allowed", "Not Acceptable", "Proxy Authentication Required",
2075 "Request Timeout", "Conflict",
2076
2077 "Gone", "Length Required", "", "Payload Too Large", "", "", "", "", "", "",
2078
2079 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
2080 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
2081 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
2082 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
2083 "", "", "", "",
2084
2085 // 500s
2086 "Internal Server Error", "Not Implemented", "Bad Gateway",
2087 "Service Unavailable", "Gateway Timeout", "", "", "", "", "",
2088
2089 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
2090 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
2091 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
2092 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
2093 "", "", "", "", "", "", "", "", "", "", "", "", "", ""};
2094typedef struct {
2095 char *buf;
2096 int capacity;
2097 int size;
2098 int64_t *memused;
2099} grwprintf_t;
2100
2101void _grwprintf_init(grwprintf_t *ctx, int capacity, int64_t *memused) {
2102 ctx->memused = memused;
2103 ctx->size = 0;
2104 ctx->buf = (char *)malloc(capacity);
2105 *ctx->memused += capacity;
2106 assert(ctx->buf != NULL);
2107 ctx->capacity = capacity;
2108}
2109
2110void _grwmemcpy(grwprintf_t *ctx, char const *src, int size) {
2111 if (ctx->size + size > ctx->capacity) {
2112 *ctx->memused -= ctx->capacity;
2113 ctx->capacity = ctx->size + size;
2114 *ctx->memused += ctx->capacity;
2115 ctx->buf = (char *)realloc(ctx->buf, ctx->capacity);
2116 assert(ctx->buf != NULL);
2117 }
2118 memcpy(ctx->buf + ctx->size, src, size);
2119 ctx->size += size;
2120}
2121
2122void _grwprintf(grwprintf_t *ctx, char const *fmt, ...) {
2123 va_list args;
2124 va_start(args, fmt);
2125
2126 int bytes =
2127 vsnprintf(ctx->buf + ctx->size, ctx->capacity - ctx->size, fmt, args);
2128 if (bytes + ctx->size > ctx->capacity) {
2129 *ctx->memused -= ctx->capacity;
2130 while (bytes + ctx->size > ctx->capacity)
2131 ctx->capacity *= 2;
2132 *ctx->memused += ctx->capacity;
2133 ctx->buf = (char *)realloc(ctx->buf, ctx->capacity);
2134 assert(ctx->buf != NULL);
2135 bytes +=
2136 vsnprintf(ctx->buf + ctx->size, ctx->capacity - ctx->size, fmt, args);
2137 }
2138 ctx->size += bytes;
2139
2140 va_end(args);
2141}
2142
2143void _http_serialize_headers_list(http_response_t *response,
2144 grwprintf_t *printctx) {
2145 http_header_t *header = response->headers;
2146 while (header) {
2147 _grwprintf(printctx, "%s: %s\r\n", header->key, header->value);
2148 header = header->next;
2149 }
2150 _grwprintf(printctx, "\r\n");
2151}
2152
2153void _http_serialize_headers(http_request_t *request, http_response_t *response,
2154 grwprintf_t *printctx) {
2155 if (HTTP_FLAG_CHECK(request->flags, HTTP_AUTOMATIC)) {
2156 hs_request_detect_keep_alive_flag(request);
2157 }
2158 if (HTTP_FLAG_CHECK(request->flags, HTTP_KEEP_ALIVE)) {
2159 hs_response_set_header(response, "Connection", "keep-alive");
2160 } else {
2161 hs_response_set_header(response, "Connection", "close");
2162 }
2163 _grwprintf(printctx, "HTTP/1.1 %d %s\r\nDate: %s\r\n", response->status,
2164 hs_status_text[response->status], request->server->date);
2165 if (!HTTP_FLAG_CHECK(request->flags, HTTP_CHUNKED_RESPONSE)) {
2166 _grwprintf(printctx, "Content-Length: %d\r\n", response->content_length);
2167 }
2168 _http_serialize_headers_list(response, printctx);
2169}
2170
2171void _http_perform_response(http_request_t *request, http_response_t *response,
2172 grwprintf_t *printctx, hs_req_fn_t http_write) {
2173 http_header_t *header = response->headers;
2174 while (header) {
2175 http_header_t *tmp = header;
2176 header = tmp->next;
2177 free(tmp);
2178 }
2179 _hs_buffer_free(&request->buffer, &request->server->memused);
2180 free(response);
2181 request->buffer.buf = printctx->buf;
2182 request->buffer.length = printctx->size;
2183 request->buffer.capacity = printctx->capacity;
2184 request->bytes_written = 0;
2185 request->state = HTTP_SESSION_WRITE;
2186 http_write(request);
2187}
2188
2189// See api.h http_response_header
2190void hs_response_set_header(http_response_t *response, char const *key,
2191 char const *value) {
2192 http_header_t *header = (http_header_t *)malloc(sizeof(http_header_t));
2193 assert(header != NULL);
2194 header->key = key;
2195 header->value = value;
2196 http_header_t *prev = response->headers;
2197 header->next = prev;
2198 response->headers = header;
2199}
2200
2201// Serializes the response into the request buffer and calls http_write.
2202// See api.h http_respond for more details
2203void hs_request_respond(http_request_t *request, http_response_t *response,
2204 hs_req_fn_t http_write) {
2205 grwprintf_t printctx;
2206 _grwprintf_init(&printctx, HTTP_RESPONSE_BUF_SIZE, &request->server->memused);
2207 _http_serialize_headers(request, response, &printctx);
2208 if (response->body) {
2209 _grwmemcpy(&printctx, response->body, response->content_length);
2210 }
2211 _http_perform_response(request, response, &printctx, http_write);
2212}
2213
2214// Serializes a chunk into the request buffer and calls http_write.
2215// See api.h http_respond_chunk for more details.
2216void hs_request_respond_chunk(http_request_t *request,
2217 http_response_t *response, hs_req_fn_t cb,
2218 hs_req_fn_t http_write) {
2219 grwprintf_t printctx;
2220 _grwprintf_init(&printctx, HTTP_RESPONSE_BUF_SIZE, &request->server->memused);
2221 if (!HTTP_FLAG_CHECK(request->flags, HTTP_CHUNKED_RESPONSE)) {
2222 HTTP_FLAG_SET(request->flags, HTTP_CHUNKED_RESPONSE);
2223 hs_response_set_header(response, "Transfer-Encoding", "chunked");
2224 _http_serialize_headers(request, response, &printctx);
2225 }
2226 request->chunk_cb = cb;
2227 _grwprintf(&printctx, "%X\r\n", response->content_length);
2228 _grwmemcpy(&printctx, response->body, response->content_length);
2229 _grwprintf(&printctx, "\r\n");
2230 _http_perform_response(request, response, &printctx, http_write);
2231}
2232
2233// Serializes the zero sized final chunk into the request buffer and calls
2234// http_write. See api.h http_respond_chunk_end for more details.
2235void hs_request_respond_chunk_end(http_request_t *request,
2236 http_response_t *response,
2237 hs_req_fn_t http_write) {
2238 grwprintf_t printctx;
2239 _grwprintf_init(&printctx, HTTP_RESPONSE_BUF_SIZE, &request->server->memused);
2240 _grwprintf(&printctx, "0\r\n");
2241 _http_serialize_headers_list(response, &printctx);
2242 _grwprintf(&printctx, "\r\n");
2243 HTTP_FLAG_CLEAR(request->flags, HTTP_CHUNKED_RESPONSE);
2244 _http_perform_response(request, response, &printctx, http_write);
2245}
2246
2247// See api.h http_response_status
2248void hs_response_set_status(http_response_t *response, int status) {
2249 response->status = status > 599 || status < 100 ? 500 : status;
2250}
2251
2252// See api.h http_response_body
2253void hs_response_set_body(http_response_t *response, char const *body,
2254 int length) {
2255 response->body = body;
2256 response->content_length = length;
2257}
2258
2259// See api.h http_response_init
2260http_response_t *hs_response_init() {
2261 http_response_t *response =
2262 (http_response_t *)calloc(1, sizeof(http_response_t));
2263 assert(response != NULL);
2264 response->status = 200;
2265 return response;
2266}
2267
2268// Simple less flexible interface for responses, used for errors.
2269void hs_request_respond_error(http_request_t *request, int code,
2270 char const *message, hs_req_fn_t http_write) {
2271 struct http_response_s *response = hs_response_init();
2272 hs_response_set_status(response, code);
2273 hs_response_set_header(response, "Content-Type", "text/plain");
2274 hs_response_set_body(response, message, strlen(message));
2275 hs_request_respond(request, response, http_write);
2276 http_write(request);
2277}
2278
2279#line 1 "server.c"
2280#include <arpa/inet.h>
2281#include <assert.h>
2282#include <fcntl.h>
2283#include <netinet/in.h>
2284#include <signal.h>
2285#include <stdlib.h>
2286#include <sys/socket.h>
2287#include <time.h>
2288
2289#ifdef EPOLL
2290#include <sys/epoll.h>
2291#include <sys/timerfd.h>
2292#else
2293#include <sys/event.h>
2294#endif
2295
2296#ifndef HTTPSERVER_IMPL
2297#include "common.h"
2298#include "server.h"
2299#endif
2300
2301void _hs_bind_localhost(int s, struct sockaddr_in *addr, const char *ipaddr,
2302 int port) {
2303 addr->sin_family = AF_INET;
2304 if (ipaddr == NULL) {
2305 addr->sin_addr.s_addr = INADDR_ANY;
2306 } else {
2307 addr->sin_addr.s_addr = inet_addr(ipaddr);
2308 }
2309 addr->sin_port = htons(port);
2310 int rc = bind(s, (struct sockaddr *)addr, sizeof(struct sockaddr_in));
2311 if (rc < 0) {
2312 exit(1);
2313 }
2314}
2315
2316#ifdef KQUEUE
2317
2318void _hs_add_server_sock_events(http_server_t *serv) {
2319 struct kevent ev_set;
2320 EV_SET(&ev_set, serv->socket, EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, serv);
2321 kevent(serv->loop, &ev_set, 1, NULL, 0, NULL);
2322}
2323
2324void _hs_server_init_events(http_server_t *serv, hs_evt_cb_t unused) {
2325 (void)unused;
2326
2327 serv->loop = kqueue();
2328 struct kevent ev_set;
2329 EV_SET(&ev_set, 1, EVFILT_TIMER, EV_ADD | EV_ENABLE, NOTE_SECONDS, 1, serv);
2330 kevent(serv->loop, &ev_set, 1, NULL, 0, NULL);
2331}
2332
2333int hs_server_run_event_loop(http_server_t *serv, const char *ipaddr) {
2334 hs_server_listen_on_addr(serv, ipaddr);
2335
2336 struct kevent ev_list[1];
2337
2338 while (1) {
2339 int nev = kevent(serv->loop, NULL, 0, ev_list, 1, NULL);
2340 for (int i = 0; i < nev; i++) {
2341 ev_cb_t *ev_cb = (ev_cb_t *)ev_list[i].udata;
2342 ev_cb->handler(&ev_list[i]);
2343 }
2344 }
2345 return 0;
2346}
2347
2348int hs_server_poll_events(http_server_t *serv) {
2349 struct kevent ev;
2350 struct timespec ts = {0, 0};
2351 int nev = kevent(serv->loop, NULL, 0, &ev, 1, &ts);
2352 if (nev <= 0)
2353 return nev;
2354 ev_cb_t *ev_cb = (ev_cb_t *)ev.udata;
2355 ev_cb->handler(&ev);
2356 return nev;
2357}
2358
2359#else
2360
2361void _hs_server_init_events(http_server_t *serv, hs_evt_cb_t timer_cb) {
2362 serv->loop = epoll_create1(0);
2363 serv->timer_handler = timer_cb;
2364
2365 int tfd = timerfd_create(CLOCK_MONOTONIC, 0);
2366 struct itimerspec ts = {};
2367 ts.it_value.tv_sec = 1;
2368 ts.it_interval.tv_sec = 1;
2369 timerfd_settime(tfd, 0, &ts, NULL);
2370
2371 struct epoll_event ev;
2372 ev.events = EPOLLIN | EPOLLET;
2373 ev.data.ptr = &serv->timer_handler;
2374 epoll_ctl(serv->loop, EPOLL_CTL_ADD, tfd, &ev);
2375 serv->timerfd = tfd;
2376}
2377
2378void _hs_add_server_sock_events(http_server_t *serv) {
2379 struct epoll_event ev;
2380 ev.events = EPOLLIN | EPOLLET;
2381 ev.data.ptr = serv;
2382 epoll_ctl(serv->loop, EPOLL_CTL_ADD, serv->socket, &ev);
2383}
2384
2385int hs_server_run_event_loop(http_server_t *serv, const char *ipaddr) {
2386 hs_server_listen_on_addr(serv, ipaddr);
2387 struct epoll_event ev_list[1];
2388 while (1) {
2389 int nev = epoll_wait(serv->loop, ev_list, 1, -1);
2390 for (int i = 0; i < nev; i++) {
2391 ev_cb_t *ev_cb = (ev_cb_t *)ev_list[i].data.ptr;
2392 ev_cb->handler(&ev_list[i]);
2393 }
2394 }
2395 return 0;
2396}
2397
2398int hs_server_poll_events(http_server_t *serv) {
2399 struct epoll_event ev;
2400 int nev = epoll_wait(serv->loop, &ev, 1, 0);
2401 if (nev <= 0)
2402 return nev;
2403 ev_cb_t *ev_cb = (ev_cb_t *)ev.data.ptr;
2404 ev_cb->handler(&ev);
2405 return nev;
2406}
2407
2408#endif
2409
2410void hs_server_listen_on_addr(http_server_t *serv, const char *ipaddr) {
2411 // Ignore SIGPIPE. We handle these errors at the call site.
2412 signal(SIGPIPE, SIG_IGN);
2413 serv->socket = socket(AF_INET, SOCK_STREAM, 0);
2414 int flag = 1;
2415 setsockopt(serv->socket, SOL_SOCKET, SO_REUSEPORT, &flag, sizeof(flag));
2416 _hs_bind_localhost(serv->socket, &serv->addr, ipaddr, serv->port);
2417 serv->len = sizeof(serv->addr);
2418 int flags = fcntl(serv->socket, F_GETFL, 0);
2419 fcntl(serv->socket, F_SETFL, flags | O_NONBLOCK);
2420 listen(serv->socket, 128);
2421 _hs_add_server_sock_events(serv);
2422}
2423
2424void hs_generate_date_time(char *datetime) {
2425 time_t rawtime;
2426 struct tm *timeinfo;
2427 time(&rawtime);
2428 timeinfo = gmtime(&rawtime);
2429 strftime(datetime, 32, "%a, %d %b %Y %T GMT", timeinfo);
2430}
2431
2432http_server_t *hs_server_init(int port, void (*handler)(http_request_t *),
2433 hs_evt_cb_t accept_cb,
2434 hs_evt_cb_t epoll_timer_cb) {
2435 http_server_t *serv = (http_server_t *)malloc(sizeof(http_server_t));
2436 assert(serv != NULL);
2437 serv->port = port;
2438 serv->memused = 0;
2439 serv->handler = accept_cb;
2440 _hs_server_init_events(serv, epoll_timer_cb);
2441 hs_generate_date_time(serv->date);
2442 serv->request_handler = handler;
2443 return serv;
2444}
2445
2446#line 1 "write_socket.c"
2447#include <errno.h>
2448#include <unistd.h>
2449
2450#ifndef HTTPSERVER_IMPL
2451#include "common.h"
2452#include "write_socket.h"
2453#endif
2454
2455#ifdef DEBUG
2456#define write hs_test_write
2457ssize_t hs_test_write(int fd, char const *data, size_t size);
2458#endif
2459
2460// Writes response bytes from the buffer out to the socket.
2461//
2462// Runs when we get a socket ready to write event or when initiating an HTTP
2463// response and writing to the socket for the first time. If the response is
2464// chunked the chunk_cb callback will be invoked signalling to the user code
2465// that another chunk is ready to be written.
2466enum hs_write_rc_e hs_write_socket(http_request_t *request) {
2467 int bytes =
2468 write(request->socket, request->buffer.buf + request->bytes_written,
2469 request->buffer.length - request->bytes_written);
2470 if (bytes > 0)
2471 request->bytes_written += bytes;
2472
2473 enum hs_write_rc_e rc = HS_WRITE_RC_SUCCESS;
2474
2475 if (errno == EPIPE) {
2476 rc = HS_WRITE_RC_SOCKET_ERR;
2477 } else {
2478 if (request->bytes_written != request->buffer.length) {
2479 // All bytes of the body were not written and we need to wait until the
2480 // socket is writable again to complete the write
2481 rc = HS_WRITE_RC_CONTINUE;
2482 } else if (HTTP_FLAG_CHECK(request->flags, HTTP_CHUNKED_RESPONSE)) {
2483 // All bytes of the chunk were written and we need to get the next chunk
2484 // from the application.
2485 rc = HS_WRITE_RC_SUCCESS_CHUNK;
2486 } else {
2487 if (HTTP_FLAG_CHECK(request->flags, HTTP_KEEP_ALIVE)) {
2488 rc = HS_WRITE_RC_SUCCESS;
2489 } else {
2490 rc = HS_WRITE_RC_SUCCESS_CLOSE;
2491 }
2492 }
2493 }
2494
2495 return rc;
2496}
2497
2498#line 1 "connection.c"
2499#include <assert.h>
2500#include <fcntl.h>
2501#include <stdlib.h>
2502#include <sys/socket.h>
2503#include <unistd.h>
2504
2505#ifdef KQUEUE
2506#include <sys/event.h>
2507#else
2508#include <sys/epoll.h>
2509#include <sys/timerfd.h>
2510#include <time.h>
2511#endif
2512
2513#ifndef HTTPSERVER_IMPL
2514#include "buffer_util.h"
2515#include "common.h"
2516#include "connection.h"
2517#endif
2518
2519#ifdef KQUEUE
2520
2521void _hs_delete_events(http_request_t *request) {
2522 struct kevent ev_set;
2523 EV_SET(&ev_set, request->socket, EVFILT_TIMER, EV_DELETE, 0, 0, request);
2524 kevent(request->server->loop, &ev_set, 1, NULL, 0, NULL);
2525}
2526
2527void _hs_add_timer_event(http_request_t *request, hs_io_cb_t unused) {
2528 (void)unused;
2529
2530 struct kevent ev_set;
2531 EV_SET(&ev_set, request->socket, EVFILT_TIMER, EV_ADD | EV_ENABLE, 0, 1000,
2532 request);
2533 kevent(request->server->loop, &ev_set, 1, NULL, 0, NULL);
2534}
2535
2536#else
2537
2538void _hs_delete_events(http_request_t *request) {
2539 epoll_ctl(request->server->loop, EPOLL_CTL_DEL, request->socket, NULL);
2540 epoll_ctl(request->server->loop, EPOLL_CTL_DEL, request->timerfd, NULL);
2541 close(request->timerfd);
2542}
2543
2544void _hs_add_timer_event(http_request_t *request, hs_io_cb_t timer_cb) {
2545 request->timer_handler = timer_cb;
2546
2547 // Watch for read events
2548 struct epoll_event ev;
2549 ev.events = EPOLLIN | EPOLLET;
2550 ev.data.ptr = request;
2551 epoll_ctl(request->server->loop, EPOLL_CTL_ADD, request->socket, &ev);
2552
2553 // Add timer to timeout requests.
2554 int tfd = timerfd_create(CLOCK_MONOTONIC, 0);
2555 struct itimerspec ts = {};
2556 ts.it_value.tv_sec = 1;
2557 ts.it_interval.tv_sec = 1;
2558 timerfd_settime(tfd, 0, &ts, NULL);
2559
2560 ev.events = EPOLLIN | EPOLLET;
2561 ev.data.ptr = &request->timer_handler;
2562 epoll_ctl(request->server->loop, EPOLL_CTL_ADD, tfd, &ev);
2563 request->timerfd = tfd;
2564}
2565
2566#endif
2567
2568void hs_request_terminate_connection(http_request_t *request) {
2569 _hs_delete_events(request);
2570 close(request->socket);
2571 _hs_buffer_free(&request->buffer, &request->server->memused);
2572 free(request->tokens.buf);
2573 request->tokens.buf = NULL;
2574 free(request);
2575}
2576
2577void _hs_token_array_init(struct hs_token_array_s *array, int capacity) {
2578 array->buf =
2579 (struct hsh_token_s *)malloc(sizeof(struct hsh_token_s) * capacity);
2580 assert(array->buf != NULL);
2581 array->size = 0;
2582 array->capacity = capacity;
2583}
2584
2585http_request_t *_hs_request_init(int sock, http_server_t *server,
2586 hs_io_cb_t io_cb) {
2587 http_request_t *request = (http_request_t *)calloc(1, sizeof(http_request_t));
2588 assert(request != NULL);
2589 request->socket = sock;
2590 request->server = server;
2591 request->handler = io_cb;
2592 request->timeout = HTTP_REQUEST_TIMEOUT;
2593 request->flags = HTTP_AUTOMATIC;
2594 request->parser = (struct hsh_parser_s){};
2595 request->buffer = (struct hsh_buffer_s){};
2596 request->tokens.buf = NULL;
2597 _hs_token_array_init(&request->tokens, 32);
2598 return request;
2599}
2600
2601http_request_t *hs_server_accept_connection(http_server_t *server,
2602 hs_io_cb_t io_cb,
2603 hs_io_cb_t epoll_timer_cb) {
2604 http_request_t *request = NULL;
2605 int sock = 0;
2606
2607 sock = accept(server->socket, (struct sockaddr *)&server->addr, &server->len);
2608
2609 if (sock > 0) {
2610 int flags = fcntl(sock, F_GETFL, 0);
2611 fcntl(sock, F_SETFL, flags | O_NONBLOCK);
2612
2613 request = _hs_request_init(sock, server, io_cb);
2614 _hs_add_timer_event(request, epoll_timer_cb);
2615 }
2616 return request;
2617}
2618
2619#line 1 "io_events.c"
2620#include <stdlib.h>
2621
2622#ifdef KQUEUE
2623#include <sys/event.h>
2624#else
2625#include <stdint.h>
2626#include <sys/epoll.h>
2627#include <unistd.h>
2628#endif
2629
2630#ifndef HTTPSERVER_IMPL
2631#include "buffer_util.h"
2632#include "common.h"
2633#include "connection.h"
2634#include "io_events.h"
2635#include "read_socket.h"
2636#include "respond.h"
2637#include "server.h"
2638#include "write_socket.h"
2639#endif
2640
2641void _hs_read_socket_and_handle_return_code(http_request_t *request) {
2642 struct hs_read_opts_s opts;
2643 opts.initial_request_buf_capacity = HTTP_REQUEST_BUF_SIZE;
2644 opts.max_request_buf_capacity = HTTP_MAX_REQUEST_BUF_SIZE;
2645 opts.eof_rc = 0;
2646
2647 enum hs_read_rc_e rc = hs_read_request_and_exec_user_cb(request, opts);
2648 switch (rc) {
2649 case HS_READ_RC_PARSE_ERR:
2650 hs_request_respond_error(request, 400, "Bad Request",
2651 hs_request_begin_write);
2652 break;
2653 case HS_READ_RC_SOCKET_ERR:
2654 hs_request_terminate_connection(request);
2655 break;
2656 case HS_READ_RC_SUCCESS:
2657 break;
2658 }
2659}
2660
2661void hs_request_begin_read(http_request_t *request);
2662
2663void _hs_write_socket_and_handle_return_code(http_request_t *request) {
2664 enum hs_write_rc_e rc = hs_write_socket(request);
2665
2666 request->timeout = rc == HS_WRITE_RC_SUCCESS ? HTTP_KEEP_ALIVE_TIMEOUT
2667 : HTTP_REQUEST_TIMEOUT;
2668
2669 if (rc != HS_WRITE_RC_CONTINUE)
2670 _hs_buffer_free(&request->buffer, &request->server->memused);
2671
2672 switch (rc) {
2673 case HS_WRITE_RC_SUCCESS_CLOSE:
2674 case HS_WRITE_RC_SOCKET_ERR:
2675 // Error or response complete, connection: close
2676 hs_request_terminate_connection(request);
2677 break;
2678 case HS_WRITE_RC_SUCCESS:
2679 // Response complete, keep-alive connection
2680 hs_request_begin_read(request);
2681 break;
2682 case HS_WRITE_RC_SUCCESS_CHUNK:
2683 // Finished writing chunk, request next
2684 request->state = HTTP_SESSION_NOP;
2685 request->chunk_cb(request);
2686 break;
2687 case HS_WRITE_RC_CONTINUE:
2688 break;
2689 }
2690}
2691
2692void _hs_accept_and_begin_request_cycle(http_server_t *server,
2693 hs_io_cb_t on_client_connection_cb,
2694 hs_io_cb_t on_timer_event_cb) {
2695 http_request_t *request = NULL;
2696 while ((request = hs_server_accept_connection(server, on_client_connection_cb,
2697 on_timer_event_cb))) {
2698 if (server->memused > HTTP_MAX_TOTAL_EST_MEM_USAGE) {
2699 hs_request_respond_error(request, 503, "Service Unavailable",
2700 hs_request_begin_write);
2701 } else {
2702 hs_request_begin_read(request);
2703 }
2704 }
2705}
2706
2707#ifdef KQUEUE
2708
2709void _hs_on_kqueue_client_connection_event(struct kevent *ev) {
2710 http_request_t *request = (http_request_t *)ev->udata;
2711 if (ev->filter == EVFILT_TIMER) {
2712 request->timeout -= 1;
2713 if (request->timeout == 0)
2714 hs_request_terminate_connection(request);
2715 } else {
2716 if (request->state == HTTP_SESSION_READ) {
2717 _hs_read_socket_and_handle_return_code(request);
2718 } else if (request->state == HTTP_SESSION_WRITE) {
2719 _hs_write_socket_and_handle_return_code(request);
2720 }
2721 }
2722}
2723
2724void hs_on_kqueue_server_event(struct kevent *ev) {
2725 http_server_t *server = (http_server_t *)ev->udata;
2726 if (ev->filter == EVFILT_TIMER) {
2727 hs_generate_date_time(server->date);
2728 } else {
2729 _hs_accept_and_begin_request_cycle(
2730 server, _hs_on_kqueue_client_connection_event, NULL);
2731 }
2732}
2733
2734#else
2735
2736void _hs_on_epoll_client_connection_event(struct epoll_event *ev) {
2737 http_request_t *request = (http_request_t *)ev->data.ptr;
2738 if (request->state == HTTP_SESSION_READ) {
2739 _hs_read_socket_and_handle_return_code(request);
2740 } else if (request->state == HTTP_SESSION_WRITE) {
2741 _hs_write_socket_and_handle_return_code(request);
2742 }
2743}
2744
2745void _hs_on_epoll_request_timer_event(struct epoll_event *ev) {
2746 http_request_t *request =
2747 (http_request_t *)((char *)ev->data.ptr - sizeof(epoll_cb_t));
2748 uint64_t res;
2749 int bytes = read(request->timerfd, &res, sizeof(res));
2750 (void)bytes; // suppress warning
2751 request->timeout -= 1;
2752 if (request->timeout == 0)
2753 hs_request_terminate_connection(request);
2754}
2755
2756void hs_on_epoll_server_connection_event(struct epoll_event *ev) {
2757 _hs_accept_and_begin_request_cycle((http_server_t *)ev->data.ptr,
2758 _hs_on_epoll_client_connection_event,
2759 _hs_on_epoll_request_timer_event);
2760}
2761
2762void hs_on_epoll_server_timer_event(struct epoll_event *ev) {
2763 http_server_t *server =
2764 (http_server_t *)((char *)ev->data.ptr - sizeof(epoll_cb_t));
2765 uint64_t res;
2766 int bytes = read(server->timerfd, &res, sizeof(res));
2767 (void)bytes; // suppress warning
2768 hs_generate_date_time(server->date);
2769}
2770
2771#endif
2772
2773void _hs_add_write_event(http_request_t *request) {
2774#ifdef KQUEUE
2775 struct kevent ev_set[2];
2776 EV_SET(&ev_set[0], request->socket, EVFILT_WRITE, EV_ADD | EV_CLEAR, 0, 0,
2777 request);
2778 EV_SET(&ev_set[1], request->socket, EVFILT_READ, EV_DISABLE, 0, 0, request);
2779 kevent(request->server->loop, ev_set, 2, NULL, 0, NULL);
2780#else
2781 struct epoll_event ev;
2782 ev.events = EPOLLOUT | EPOLLET;
2783 ev.data.ptr = request;
2784 epoll_ctl(request->server->loop, EPOLL_CTL_MOD, request->socket, &ev);
2785#endif
2786}
2787
2788void hs_request_begin_write(http_request_t *request) {
2789 request->state = HTTP_SESSION_WRITE;
2790 _hs_add_write_event(request);
2791 _hs_write_socket_and_handle_return_code(request);
2792}
2793
2794void _hs_add_read_event(http_request_t *request) {
2795#ifdef KQUEUE
2796 // No action needed for kqueue since it's read event stays active. Should
2797 // it be disabled during write?
2798 struct kevent ev_set;
2799 EV_SET(&ev_set, request->socket, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0,
2800 request);
2801 kevent(request->server->loop, &ev_set, 1, NULL, 0, NULL);
2802#else
2803 struct epoll_event ev;
2804 ev.events = EPOLLIN | EPOLLET;
2805 ev.data.ptr = request;
2806 epoll_ctl(request->server->loop, EPOLL_CTL_MOD, request->socket, &ev);
2807#endif
2808}
2809
2810void hs_request_begin_read(http_request_t *request) {
2811 request->state = HTTP_SESSION_READ;
2812 _hs_add_read_event(request);
2813 _hs_read_socket_and_handle_return_code(request);
2814}
2815
2816#endif
2817#endif
2818#endif