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 | |
| tergiv-74630b4bfe1aa887ef57ee57b22241d030b38d76.tar tergiv-74630b4bfe1aa887ef57ee57b22241d030b38d76.tar.gz tergiv-74630b4bfe1aa887ef57ee57b22241d030b38d76.zip | ||
| Parent | 3bca23eaaa49fa01f60ecbc5e0a329d29f088506 (diff) | |
feat!: Initial web server base implementation
5 files changed, 239 insertions, 0 deletions
| -rw-r--r-- | src/http/callback_http.c | 136 | ||||
| -rw-r--r-- | src/http/callback_http.h | 38 | ||||
| -rw-r--r-- | src/http/http_headers.h | 17 | ||||
| -rw-r--r-- | src/http/request_method.h | 30 | ||||
| -rw-r--r-- | src/http/response_code.h | 18 |
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"; +} diff --git a/src/http/callback_http.h b/src/http/callback_http.h new file mode 100644 index 0000000..5f38c86 --- /dev/null +++ b/src/http/callback_http.h @@ -0,0 +1,38 @@ +#ifndef __TERGIV_CALLBACK_HTTP +#define __TERGIV_CALLBACK_HTTP + +#include "../sockets/socket_server.h" +#include "request_method.h" +#include "response_code.h" +#include "http_headers.h" + +void callback_http(callback_args* args); + +typedef struct client_message { + enum RequestMethod method; + char* url; + char* version; + char* headers[HE_LENGTH]; +} client_message; + +typedef struct response_message { + enum ResponseCode response_code; + + char* headers[HE_LENGTH]; + + char* body; + size_t body_size; + int free_body; +} response_message; + +typedef struct http_callbacks { + union { + struct { + void (*get_callback)(client_message* in_message, response_message* out_message); + }; + void (*all_callbacks[RM_UNKNOWN])(client_message* in_message, response_message* out_message); + }; + +} http_callbacks; + +#endif /* __TERGIV_CALLBACK_HTTP */ diff --git a/src/http/http_headers.h b/src/http/http_headers.h new file mode 100644 index 0000000..0e83dfd --- /dev/null +++ b/src/http/http_headers.h @@ -0,0 +1,17 @@ +#ifndef __TERGIV_HTTP_HEADERS +#define __TERGIV_HTTP_HEADERS + +enum HttpHeader { + HE_Host = 0, + HE_Content_Length, + HE_Content_Type, + HE_LENGTH, +}; + +static const char* HTTP_HEADER_NAME[] = { + "Host", + "Content-Length", + "Content-Type", +}; + +#endif /* __TERGIV_HTTP_HEADERS */ diff --git a/src/http/request_method.h b/src/http/request_method.h new file mode 100644 index 0000000..32ec13e --- /dev/null +++ b/src/http/request_method.h @@ -0,0 +1,30 @@ +#ifndef __TERGIV_REQUEST_METHOD +#define __TERGIV_REQUEST_METHOD + +enum RequestMethod { + RM_GET = 0, + RM_HEAD, + RM_OPTIONS, + RM_TRACE, + RM_PUT, + RM_DELETE, + RM_POST, + RM_PATCH, + RM_CONNECT, + RM_UNKNOWN +}; + +static const char* REQUEST_METHOD_NAME[] = { + "GET", + "HEAD", + "OPTIONS", + "TRACE", + "PUT", + "DELETE", + "POST", + "PATCH", + "CONNECT", + 0 +}; + +#endif /* __TERGIV_REQUEST_METHOD */ diff --git a/src/http/response_code.h b/src/http/response_code.h new file mode 100644 index 0000000..f5cd191 --- /dev/null +++ b/src/http/response_code.h @@ -0,0 +1,18 @@ +#ifndef __TERGIV_RESPONSE_CODE +#define __TERGIV_RESPONSE_CODE + +enum ResponseCode { + RC_200_OK, + RC_403_FORBIDDEN, + RC_404_NOT_FOUND, + RC_500_INTERNAL_SERVER_ERRROR, + RC_LENGTH +}; + +static const char* RESPONSE_CODE_NAME[] = { + "200 OK", + "403 FORBIDDEN", + "404 NOT_FOUND", +}; + +#endif /* __TERGIV_RESPONSE_CODE */ |
