Summary Files Commits Branches @commit @diff @stats
path: root / src / http / callback_http.c
diff options
context:
space:
mode:
Commit74630b4bfe1aa887ef57ee57b22241d030b38d76 (patch)
Author
 Syndamia <kamen@syndamia.com>
2025-11-15 21:37:37 +0200
Committer
 Syndamia <kamen@syndamia.com>
2025-11-15 21:37:37 +0200
Files3d39c585df1551d69fdb83980c010ec4b579f211 /src/http/callback_http.c
tergiv-74630b4bfe1aa887ef57ee57b22241d030b38d76.tar
tergiv-74630b4bfe1aa887ef57ee57b22241d030b38d76.tar.gz
tergiv-74630b4bfe1aa887ef57ee57b22241d030b38d76.zip
Parent3bca23eaaa49fa01f60ecbc5e0a329d29f088506 (diff)
feat!: Initial web server base implementation
1 files changed, 136 insertions, 0 deletions
-rw-r--r--src/http/callback_http.c136
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";
+}