diff options
| Commit | 74630b4bfe1aa887ef57ee57b22241d030b38d76 (patch) | |
|---|---|---|
| Author | 2025-11-15 21:37:37 +0200 | |
| Committer | 2025-11-15 21:37:37 +0200 | |
| Files | 3d39c585df1551d69fdb83980c010ec4b579f211 /src/http/callback_http.c | |
| tergiv-74630b4bfe1aa887ef57ee57b22241d030b38d76.tar tergiv-74630b4bfe1aa887ef57ee57b22241d030b38d76.tar.gz tergiv-74630b4bfe1aa887ef57ee57b22241d030b38d76.zip | ||
| Parent | 3bca23eaaa49fa01f60ecbc5e0a329d29f088506 (diff) | |
feat!: Initial web server base implementation
1 files changed, 136 insertions, 0 deletions
| -rw-r--r-- | src/http/callback_http.c | 136 |
diff --git a/src/http/callback_http.c b/src/http/callback_http.c new file mode 100644 index 0000000..5b2b944 --- /dev/null +++ b/src/http/callback_http.c @@ -0,0 +1,136 @@ +#include "callback_http.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "../utils/strings.h" +#include "http_headers.h" +#include "request_method.h" +#include "response_code.h" + +static const char* SEPS = " \n\r"; +#define return_bad_request() { \ + args->output = "HTTP/1.1 400 Bad Request"; \ + args->output_size = 24; \ + return; \ + } + +static void append_header(enum HttpHeader header, const char* value, const char** parts_array, size_t *ind); + +void callback_http(callback_args* args) { + if (args->extra == NULL) { + printf("No HTTP callbacks were set!"); + return; + } + + http_callbacks *callbacks = args->extra; + + /* Parse input request */ + + client_message in_message = { + .method = RM_UNKNOWN, + .url = NULL, + .version = NULL, + .headers = { 0 }, + }; + + /** Request method **/ + + char* word = strtok(args->input, SEPS); + if (word == NULL) return_bad_request() + + for (enum RequestMethod rm = RM_GET; rm < RM_UNKNOWN; rm++) { + if (streq(REQUEST_METHOD_NAME[rm], word)) { + in_message.method = rm; + break; + } + } + + if (in_message.method == RM_UNKNOWN) + return_bad_request() + + /** URL **/ + + word = strtok(NULL, SEPS); + if (word == NULL) return_bad_request() + + in_message.url = word; + + /** HTTP version **/ + + word = strtok(NULL, SEPS); + if (word == NULL || !streq("HTTP/1.1", word)) + return_bad_request() + + in_message.version = word; + + /** Headers **/ + + word = strtok(NULL, ":\n\r"); + + while(word != NULL) { + enum HttpHeader he = 0; + + while (he < HE_LENGTH) { + if (streq(HTTP_HEADER_NAME[he], word)) + break; + ++he; + } + word = strtok(NULL, "\n\r"); + + if (word == NULL) break; + + if (he < HE_LENGTH) { + while (*word == ' ') ++word; + in_message.headers[he] = word; + } + + word = strtok(NULL, ":\n\r"); + } + + /* Respond to request */ + + response_message out_message = { + .response_code = RC_500_INTERNAL_SERVER_ERRROR, + + .headers = { 0 }, + + .body = NULL, + .body_size = 0, + .free_body = 0, + }; + + if (in_message.method < RM_UNKNOWN) + callbacks->all_callbacks[in_message.method](&in_message, &out_message); + else + printf("Unsupported method!"); + + const char* response[1024] = { 0 }; + size_t rind = 0; + + response[rind++] = "HTTP/1.1 "; + response[rind++] = RESPONSE_CODE_NAME[out_message.response_code]; + response[rind++] = "\n"; + + for (enum HttpHeader he = 0; he < HE_LENGTH; he++) { + if (out_message.headers[he] != NULL) + append_header(he, out_message.headers[he], response, &rind); + } + + response[rind++] = "\n"; + + if (out_message.body != NULL && out_message.body_size > 0) + response[rind++] = out_message.body; + + args->output = concat_array(response, rind, &args->output_size); + args->free_output = 1; + + if (out_message.free_body) + free(out_message.body); +} + +static void append_header(enum HttpHeader header, const char* value, const char** parts_array, size_t *ind) { + parts_array[(*ind)++] = HTTP_HEADER_NAME[header]; + parts_array[(*ind)++] = ": "; + parts_array[(*ind)++] = value; + parts_array[(*ind)++] = "\n"; +} |
