QUOTE: Be your own kind of beautiful.

libhttp

A basic HTTP Framework

commit bc113ba911b1a73f7a33284923334f3390e316c7
parent 9cf6f814e802841666ed6d891f676b891205f18d
Author: Sophie <info@soophie.de>
Date:   Tue, 11 Mar 2025 15:42:50 +0000

feat: Shortened type names

Diffstat:
Msrc/libhttp.h | 239+++++++++++++++++++++++++++++++++++++------------------------------------------
1 file changed, 113 insertions(+), 126 deletions(-)

diff --git a/src/libhttp.h b/src/libhttp.h @@ -17,7 +17,7 @@ typedef enum { HTTP_ERR_INVALID_PRIVATE_KEY = 8, HTTP_ERR_READ_TIMEOUT = 9, HTTP_ERR_REQUEST_TOO_LONG = 10, -} http_error_t; +} http_err_t; typedef enum { HTTP_STATUS_CONTINUE = 100, @@ -124,7 +124,7 @@ typedef struct { char *body; long body_len; void *ext_data; -} http_request_t; +} http_req_t; typedef struct { char *version; @@ -133,7 +133,7 @@ typedef struct { int headers_len; char *body; long body_len; -} http_response_t; +} http_resp_t; struct Http { http_bind_t *binds; @@ -141,19 +141,18 @@ struct Http { pthread_t thread; bool quit; SSL_CTX *ssl_ctx; - http_response_t (*on_request_fn)(http_request_t *); + http_resp_t (*on_req_fn)(http_req_t *); }; http_t *http_init(void); void http_cleanup(http_t *http); -void http_on_request(http_t *http, http_response_t fn(http_request_t *)); -char *http_header_get(http_request_t *request, char *key); -void http_header_set(http_response_t *response, char *key, char *value); -http_response_t http_response_create(http_status_t status); -void http_response_body(http_response_t *response, char *body, long len); -void http_response_file(http_response_t *response, char *filename); -http_error_t http_bind(http_t *http, char *hostname, int port, http_host_t *hosts, int hosts_len); -http_error_t http_listen(http_t *http); +void http_on_req(http_t *http, http_resp_t fn(http_req_t *)); +char *http_header_get(http_req_t *req, char *key); +void http_header_set(http_resp_t *resp, char *key, char *value); +http_resp_t http_resp_create(http_status_t status); +void http_resp_body_set(http_resp_t *resp, char *body, long len); +http_err_t http_bind(http_t *http, char *hostname, int port, http_host_t *hosts, int hosts_len); +http_err_t http_listen(http_t *http); void http_close(http_t *http); #ifdef LIB_HTTP_IMPL @@ -171,7 +170,11 @@ void http_close(http_t *http); #include <openssl/ssl.h> #include <sys/socket.h> +#define HTTP_VERSION "HTTP/1.1" #define HTTP_MAX_REQUEST_HEAD_SIZE 1000000 +#define HTTP_SERVER_BACKLOG 5 +#define HTTP_SERVER_SLEEP_TIME 100000000 +#define HTTP_SERVER_POLL_TIME 100 http_t *http_init(void) { http_t *http = (http_t *) malloc(sizeof(http_t)); @@ -180,7 +183,7 @@ http_t *http_init(void) { .binds_len = 0, .quit = false, .ssl_ctx = NULL, - .on_request_fn = NULL, + .on_req_fn = NULL, }; return http; } @@ -189,20 +192,8 @@ void http_cleanup(http_t *http) { free(http); } -void http_on_request(http_t *http, http_response_t fn(http_request_t *)) { - http->on_request_fn = fn; -} - -char *http_read_file(char *filename) { - FILE *fp = fopen(filename, "r"); - fseek(fp, 0, SEEK_END); - long len = ftell(fp); - fseek(fp, 0, SEEK_SET); - char *content = (char *) malloc(sizeof(char) * (len + 1)); - fread(content, len, sizeof(char), fp); - content[len] = '\0'; - fclose(fp); - return content; +void http_on_req(http_t *http, http_resp_t fn(http_req_t *)) { + http->on_req_fn = fn; } const char *http_status_str(http_status_t status) { @@ -348,10 +339,10 @@ ssize_t http_write(http_conn_t *conn, char *buffer, size_t len) { return write(conn->sockfd, buffer, len); } -char *http_header_get(http_request_t *request, char *key) { - if (request->headers_len > 0) { - for (int i = 0; i < request->headers_len; i++) { - http_header_t *header = &request->headers[i]; +char *http_header_get(http_req_t *req, char *key) { + if (req->headers_len > 0) { + for (int i = 0; i < req->headers_len; i++) { + http_header_t *header = &req->headers[i]; if (strcmp(header->key, key) == 0) { return header->value; } @@ -360,10 +351,10 @@ char *http_header_get(http_request_t *request, char *key) { return NULL; } -void http_header_set(http_response_t *response, char *key, char *value) { - response->headers = (http_header_t *) realloc(response->headers, sizeof(http_header_t) * (response->headers_len + 1)); - http_header_t *new_header = &response->headers[response->headers_len]; - response->headers_len++; +void http_header_set(http_resp_t *resp, char *key, char *value) { + resp->headers = (http_header_t *) realloc(resp->headers, sizeof(http_header_t) * (resp->headers_len + 1)); + http_header_t *new_header = &resp->headers[resp->headers_len]; + resp->headers_len++; int key_len = strlen(key); new_header->key = (char *) malloc(sizeof(char) * (key_len + 1)); memcpy(new_header->key, key, key_len); @@ -374,48 +365,41 @@ void http_header_set(http_response_t *response, char *key, char *value) { new_header->value[value_len] = '\0'; } -http_response_t http_response_create(http_status_t status) { - const char *version = "HTTP/1.1"; - int version_len = strlen(version); - http_response_t response = { NULL, status, NULL, 0, NULL, 0 }; - response.version = (char *) malloc(sizeof(char) * (version_len + 1)); - memcpy(response.version, version, version_len); - response.version[version_len] = '\0'; - return response; +http_resp_t http_resp_create(http_status_t status) { + return (http_resp_t) { + .version = strdup(HTTP_VERSION), + .status = status, + .headers = NULL, + .headers_len = 0, + .body = NULL, + .body_len = 0, + }; } -void http_response_body(http_response_t *response, char *body, long len) { - if (response != NULL && body != NULL) { - response->body = (char *) malloc(sizeof(char) * len); - memcpy(response->body, body, len); - response->body_len = len; +void http_resp_body_set(http_resp_t *resp, char *body, long len) { + if (resp != NULL && body != NULL) { + resp->body = (char *) malloc(sizeof(char) * len); + memcpy(resp->body, body, len); + resp->body_len = len; char content_length[50]; snprintf(content_length, 50, "%ld", len); - http_header_set(response, (char *) "Content-Length", content_length); + http_header_set(resp, (char *) "Content-Length", content_length); } } -void http_response_file(http_response_t *response, char *filename) { - char *content = http_read_file(filename); - if (content != NULL) { - http_response_body(response, content, strlen(content)); - free(content); +void http_req_free(http_req_t *req) { + if (req->method != NULL) { + free(req->method); } -} - -void http_request_free(http_request_t *request) { - if (request->method != NULL) { - free(request->method); + if (req->url != NULL) { + free(req->url); } - if (request->url != NULL) { - free(request->url); + if (req->version != NULL) { + free(req->version); } - if (request->version != NULL) { - free(request->version); - } - if (request->headers_len > 0) { - for (int i = 0; i < request->headers_len; i++) { - http_header_t *header = &request->headers[i]; + if (req->headers_len > 0) { + for (int i = 0; i < req->headers_len; i++) { + http_header_t *header = &req->headers[i]; if (header->key != NULL) { free(header->key); } @@ -424,21 +408,21 @@ void http_request_free(http_request_t *request) { } } } - if (request->body != NULL) { - free(request->body); + if (req->body != NULL) { + free(req->body); } - if (request->ext_data != NULL) { - free(request->ext_data); + if (req->ext_data != NULL) { + free(req->ext_data); } } -void http_response_free(http_response_t *response) { - if (response->version != NULL) { - free(response->version); +void http_resp_free(http_resp_t *resp) { + if (resp->version != NULL) { + free(resp->version); } - if (response->headers_len > 0) { - for (int i = 0; i < response->headers_len; i++) { - http_header_t *header = &response->headers[i]; + if (resp->headers_len > 0) { + for (int i = 0; i < resp->headers_len; i++) { + http_header_t *header = &resp->headers[i]; if (header->key != NULL) { free(header->key); } @@ -446,18 +430,21 @@ void http_response_free(http_response_t *response) { free(header->value); } } + if (resp->headers != NULL) { + free(resp->headers); + } } - if (response->body != NULL) { - free(response->body); + if (resp->body != NULL) { + free(resp->body); } } -http_error_t http_read_request(http_conn_t *conn, http_request_t *request) { +http_err_t http_read_req(http_conn_t *conn, http_req_t *req) { int len = 0; int ln = 0; int start = 0; char buffer[HTTP_MAX_REQUEST_HEAD_SIZE]; - *request = (http_request_t) { + *req = (http_req_t) { .conn = conn, .method = NULL, .url = NULL, @@ -505,23 +492,23 @@ http_error_t http_read_request(http_conn_t *conn, http_request_t *request) { // read method if (arg == 0) { int method_length = i - start; - request->method = (char *) malloc(sizeof(char) * (method_length + 1)); - memcpy(request->method, line + start, method_length); - request->method[method_length] = '\0'; + req->method = (char *) malloc(sizeof(char) * (method_length + 1)); + memcpy(req->method, line + start, method_length); + req->method[method_length] = '\0'; } // read url if (arg == 1) { int url_length = i - start; - request->url = (char *) malloc(sizeof(char) * (url_length + 1)); - memcpy(request->url, line + start, url_length); - request->url[url_length] = '\0'; + req->url = (char *) malloc(sizeof(char) * (url_length + 1)); + memcpy(req->url, line + start, url_length); + req->url[url_length] = '\0'; } // read version if (arg == 2) { int version_length = i - start; - request->version = (char *) malloc(sizeof(char) * (version_length + 1)); - memcpy(request->version, line + start, version_length); - request->version[version_length] = '\0'; + req->version = (char *) malloc(sizeof(char) * (version_length + 1)); + memcpy(req->version, line + start, version_length); + req->version[version_length] = '\0'; } start = i + 1; arg++; @@ -531,9 +518,9 @@ http_error_t http_read_request(http_conn_t *conn, http_request_t *request) { // read headers else { int sep = 0; - request->headers = (http_header_t *) realloc(request->headers, sizeof(http_header_t) * (request->headers_len + 1)); - http_header_t *header = &request->headers[request->headers_len]; - request->headers_len++; + req->headers = (http_header_t *) realloc(req->headers, sizeof(http_header_t) * (req->headers_len + 1)); + http_header_t *header = &req->headers[req->headers_len]; + req->headers_len++; for (int i = 0; i < line_len; i++) { if (line[i] == ':') { int key_len = i; @@ -558,13 +545,13 @@ http_error_t http_read_request(http_conn_t *conn, http_request_t *request) { if (len >= 4) { char *slice = buffer + (len - 4); if (strncmp(slice, "\r\n\r\n", 4) == 0) { - char *content_length = http_header_get(request, (char *) "Content-Length"); + char *content_length = http_header_get(req, (char *) "Content-Length"); if (content_length != NULL) { - request->body_len = strtol(content_length, NULL, 10); - if (request->body_len > 0) { - request->body = (char *) malloc(sizeof(char) * (request->body_len + 1)); - http_read(conn, request->body, request->body_len); - request->body[request->body_len] = '\0'; + req->body_len = strtol(content_length, NULL, 10); + if (req->body_len > 0) { + req->body = (char *) malloc(sizeof(char) * (req->body_len + 1)); + http_read(conn, req->body, req->body_len); + req->body[req->body_len] = '\0'; } } break; @@ -574,19 +561,19 @@ http_error_t http_read_request(http_conn_t *conn, http_request_t *request) { return HTTP_ERR_OK; } -void http_write_response(http_conn_t *conn, http_response_t response) { - http_write(conn, response.version, strlen(response.version)); +void http_resp_write(http_conn_t *conn, http_resp_t resp) { + http_write(conn, resp.version, strlen(resp.version)); http_write(conn, (char *) " ", 1); char status[4]; - snprintf(status, 4, "%d", response.status); + snprintf(status, 4, "%d", resp.status); http_write(conn, status, strlen(status)); http_write(conn, (char *) " ", 1); - const char *status_message = http_status_str(response.status); + const char *status_message = http_status_str(resp.status); http_write(conn, (char *) status_message, strlen(status_message)); http_write(conn, (char *) "\r\n", 2); - if (response.headers_len > 0) { - for (int i = 0; i < response.headers_len; i++) { - http_header_t *header = &response.headers[i]; + if (resp.headers_len > 0) { + for (int i = 0; i < resp.headers_len; i++) { + http_header_t *header = &resp.headers[i]; http_write(conn, header->key, strlen(header->key)); http_write(conn, (char *) ": ", 2); http_write(conn, header->value, strlen(header->value)); @@ -594,12 +581,12 @@ void http_write_response(http_conn_t *conn, http_response_t response) { } } http_write(conn, (char *) "\r\n", 2); - if (response.body != NULL) { - http_write(conn, response.body, response.body_len); + if (resp.body != NULL) { + http_write(conn, resp.body, resp.body_len); } } -void *http_handle_client(void *ptr) { +void *http_client_handle(void *ptr) { if (!ptr) { pthread_exit(0); } @@ -622,8 +609,8 @@ void *http_handle_client(void *ptr) { pthread_exit(0); } } - http_request_t request; - http_error_t err = http_read_request(conn, &request); + http_req_t req; + http_err_t err = http_read_req(conn, &req); if (err != HTTP_ERR_OK) { if (conn->ssl != NULL) { SSL_shutdown(conn->ssl); @@ -633,14 +620,14 @@ void *http_handle_client(void *ptr) { free(conn); pthread_exit(0); } - if (request.method != NULL && request.url != NULL) { - if (conn->http->on_request_fn != NULL) { - http_response_t response = conn->http->on_request_fn(&request); - http_write_response(conn, response); - http_response_free(&response); + if (req.method != NULL && req.url != NULL) { + if (conn->http->on_req_fn != NULL) { + http_resp_t resp = conn->http->on_req_fn(&req); + http_resp_write(conn, resp); + http_resp_free(&resp); } } - http_request_free(&request); + http_req_free(&req); if (conn->ssl != NULL) { SSL_shutdown(conn->ssl); SSL_free(conn->ssl); @@ -650,7 +637,7 @@ void *http_handle_client(void *ptr) { pthread_exit(0); } -void *http_handle_server(void *ptr) { +void *http_server_handle(void *ptr) { http_t *http = (http_t *) ptr; struct pollfd fds[http->binds_len]; for (int i = 0; i < http->binds_len; i++) { @@ -660,9 +647,9 @@ void *http_handle_server(void *ptr) { while (!http->quit) { struct timespec sleep_req, sleep_rem; sleep_req.tv_sec = 0; - sleep_req.tv_nsec = 100000000; + sleep_req.tv_nsec = HTTP_SERVER_SLEEP_TIME; nanosleep(&sleep_req, &sleep_rem); - if (poll(fds, http->binds_len, 100)) { + if (poll(fds, http->binds_len, HTTP_SERVER_POLL_TIME)) { for (int i = 0; i < http->binds_len; i++) { if (fds[i].revents & POLLIN) { http_conn_t *conn = (http_conn_t *) malloc(sizeof(http_conn_t)); @@ -679,7 +666,7 @@ void *http_handle_server(void *ptr) { pthread_attr_t thread_attr; pthread_attr_init(&thread_attr); pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED); - pthread_create(&thread, &thread_attr, http_handle_client, (void *) conn); + pthread_create(&thread, &thread_attr, http_client_handle, (void *) conn); pthread_attr_destroy(&thread_attr); } } @@ -690,7 +677,7 @@ void *http_handle_server(void *ptr) { } int http_tls_sni_callback(SSL *ssl, int *al, void *arg) { - (void)(al); + (void) al; http_conn_t *conn = (http_conn_t *) arg; const char *hostname = SSL_get_servername(ssl, 0); if (hostname != NULL) { @@ -708,7 +695,7 @@ int http_tls_sni_callback(SSL *ssl, int *al, void *arg) { return SSL_TLSEXT_ERR_NOACK; } -http_error_t http_bind(http_t *http, char *hostname, int port, http_host_t *hosts, int hosts_len) { +http_err_t http_bind(http_t *http, char *hostname, int port, http_host_t *hosts, int hosts_len) { http->binds = (http_bind_t *) realloc(http->binds, sizeof(http_bind_t) * (http->binds_len + 1)); http_bind_t *http_bind = &http->binds[http->binds_len]; http_bind->sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); @@ -731,7 +718,7 @@ http_error_t http_bind(http_t *http, char *hostname, int port, http_host_t *host if (bind(http_bind->sockfd, (struct sockaddr *) &addr, sizeof(struct sockaddr_in)) < 0) { return HTTP_ERR_ADDR_IN_USE; } - if (listen(http_bind->sockfd, 5) < 0) { + if (listen(http_bind->sockfd, HTTP_SERVER_BACKLOG) < 0) { return HTTP_ERR_NO_LISTEN; } for (int i = 0; i < hosts_len; i++) { @@ -757,7 +744,7 @@ http_error_t http_bind(http_t *http, char *hostname, int port, http_host_t *host return HTTP_ERR_OK; } -http_error_t http_listen(http_t *http) { +http_err_t http_listen(http_t *http) { signal(SIGPIPE, SIG_IGN); const SSL_METHOD *method = TLS_server_method(); http->ssl_ctx = SSL_CTX_new(method); @@ -765,7 +752,7 @@ http_error_t http_listen(http_t *http) { return HTTP_ERR_NO_SSL_CONTEXT; } SSL_CTX_set_tlsext_servername_callback(http->ssl_ctx, http_tls_sni_callback); - pthread_create(&http->thread, 0, http_handle_server, (void *) http); + pthread_create(&http->thread, 0, http_server_handle, (void *) http); return HTTP_ERR_OK; }