commit 658fe48bb83e3a288ba0afd557b7887eaea65192 Author: cdricms <36056008+cdricms@users.noreply.github.com> Date: Mon Oct 28 12:06:06 2024 +0100 batman diff --git a/http/http_content_type.c b/http/http_content_type.c new file mode 100644 index 0000000..774200a --- /dev/null +++ b/http/http_content_type.c @@ -0,0 +1,68 @@ +#include "http_content_type.h" +#include + +void http_content_type(HttpContentType __content_type, char *__out, + size_t __size) { + switch (__content_type) { + case HTTP_CT_PLAIN_TEXT: { + char ct[] = "text/plain"; + strlcpy(__out, ct, __size); + } break; + case HTTP_CT_HTML: { + char ct[] = "text/html"; + strlcpy(__out, ct, __size); + } break; + case HTTP_CT_JSON: { + char ct[] = "application/json"; + strlcpy(__out, ct, __size); + } break; + case HTTP_CT_XML: { + char ct[] = "application/xml"; + strlcpy(__out, ct, __size); + } break; + case HTTP_CT_CSS: { + char ct[] = "text/css"; + strlcpy(__out, ct, __size); + } break; + case HTTP_CT_JAVASCRIPT: { + char ct[] = "application/javascript"; + strlcpy(__out, ct, __size); + } break; + case HTTP_CT_JPEG: { + char ct[] = "image/jpeg"; + strlcpy(__out, ct, __size); + } break; + case HTTP_CT_PNG: { + char ct[] = "image/png"; + strlcpy(__out, ct, __size); + } break; + case HTTP_CT_GIF: { + char ct[] = "image/gif"; + strlcpy(__out, ct, __size); + } break; + case HTTP_CT_MPEG: { + char ct[] = "audio/mpeg"; + strlcpy(__out, ct, __size); + } break; + case HTTP_CT_MP4: { + char ct[] = "video/mp4"; + strlcpy(__out, ct, __size); + } break; + case HTTP_CT_PDF: { + char ct[] = "application/pdf"; + strlcpy(__out, ct, __size); + } break; + case HTTP_CT_ZIP: { + char ct[] = "application/zip"; + strlcpy(__out, ct, __size); + } break; + case HTTP_CT_FORM_ENCODED: { + char ct[] = "application/x-www-form-urlencoded"; + strlcpy(__out, ct, __size); + } break; + case HTTP_CT_FORM_DATA: { + char ct[] = "multipart/form-data"; + strlcpy(__out, ct, __size); + } break; + } +} diff --git a/http/http_content_type.h b/http/http_content_type.h new file mode 100644 index 0000000..8a125ca --- /dev/null +++ b/http/http_content_type.h @@ -0,0 +1,27 @@ +#ifndef HTTP_CONTENT_TYPE_H +#define HTTP_CONTENT_TYPE_H + +#include + +typedef enum { + HTTP_CT_PLAIN_TEXT = 0, // text/plain + HTTP_CT_HTML, // text/html + HTTP_CT_JSON, // application/json + HTTP_CT_XML, // application/xml + HTTP_CT_CSS, // text/css + HTTP_CT_JAVASCRIPT, // application/javascript + HTTP_CT_JPEG, // image/jpeg + HTTP_CT_PNG, // image/png + HTTP_CT_GIF, // image/gif + HTTP_CT_MPEG, // audio/mpeg + HTTP_CT_MP4, // video/mp4 + HTTP_CT_PDF, // application/pdf + HTTP_CT_ZIP, // application/zip + HTTP_CT_FORM_ENCODED, // application/x-www-form-urlencoded + HTTP_CT_FORM_DATA // multipart/form-data +} HttpContentType; + +void http_content_type(HttpContentType __content_type, char *__out, + size_t __size); + +#endif diff --git a/http/http_method.c b/http/http_method.c new file mode 100644 index 0000000..47970a7 --- /dev/null +++ b/http/http_method.c @@ -0,0 +1,43 @@ +#include "http_method.h" +#include + +void http_method(HttpMethod __method, char *__out, size_t __size) { + switch (__method) { + case HTTP_METHOD_GET: { + char method[] = "GET"; + strlcpy(__out, method, __size); + } break; + case HTTP_METHOD_POST: { + char method[] = "POST"; + strlcpy(__out, method, __size); + } break; + case HTTP_METHOD_PUT: { + char method[] = "PUT"; + strlcpy(__out, method, __size); + } break; + case HTTP_METHOD_DELETE: { + char method[] = "DELETE"; + strlcpy(__out, method, __size); + } break; + case HTTP_METHOD_PATCH: { + char method[] = "PATCH"; + strlcpy(__out, method, __size); + } break; + case HTTP_METHOD_HEAD: { + char method[] = "HEAD"; + strlcpy(__out, method, __size); + } break; + case HTTP_METHOD_OPTIONS: { + char method[] = "OPTIONS"; + strlcpy(__out, method, __size); + } break; + case HTTP_METHOD_CONNECT: { + char method[] = "CONNECT"; + strlcpy(__out, method, __size); + } break; + case HTTP_METHOD_TRACE: { + char method[] = "TRACE"; + strlcpy(__out, method, __size); + } break; + } +} diff --git a/http/http_method.h b/http/http_method.h new file mode 100644 index 0000000..ac743fe --- /dev/null +++ b/http/http_method.h @@ -0,0 +1,20 @@ +#ifndef HTTP_METHOD_H +#define HTTP_METHOD_H + +#include + +typedef enum { + HTTP_METHOD_GET = 0, + HTTP_METHOD_POST, + HTTP_METHOD_PUT, + HTTP_METHOD_DELETE, + HTTP_METHOD_PATCH, + HTTP_METHOD_HEAD, + HTTP_METHOD_OPTIONS, + HTTP_METHOD_CONNECT, + HTTP_METHOD_TRACE, +} HttpMethod; + +void http_method(HttpMethod __method, char *__out, size_t __size); + +#endif diff --git a/http/http_response.c b/http/http_response.c new file mode 100644 index 0000000..6a8c86d --- /dev/null +++ b/http/http_response.c @@ -0,0 +1,34 @@ +#include "http_content_type.h" +#include "http_response.h" +#include "http_status.h" +#include +#include + +bool construct_response(HttpResponse __res, char *out) { + unsigned long length; + if ((length = strlen(__res.body)) > __res.content_length) { + fprintf(stderr, "[ERROR] %s: %lu > %lu", + "The size of the body is greater than what was set in " + "content_length.", + length, __res.content_length); + return false; + } + + char status_message[256]; + http_status_message(__res.status_code, status_message, 256); + char content_type[256]; + http_content_type(__res.content_type, content_type, 256); + sprintf( + out, + "HTTP/1.1 %d %s\r\nContent-Type: %s\r\nContent-Length: %lu\r\n\r\n%s", + __res.status_code, status_message, content_type, __res.content_length, + __res.body); + + return true; +} + +void http_respond(HttpResponse __res) { + char response[BUFSIZ]; + // TODO: Handle return + construct_response(__res, response); +} diff --git a/http/http_response.h b/http/http_response.h new file mode 100644 index 0000000..8671210 --- /dev/null +++ b/http/http_response.h @@ -0,0 +1,18 @@ +#ifndef HTTP_RESPONSE_H +#define HTTP_RESPONSE_H + +#include "http_content_type.h" +#include "http_status.h" +#include +#include + +typedef struct { + HttpStatus status_code; + HttpContentType content_type; + size_t content_length; + char *body; +} HttpResponse; + +bool construct_response(HttpResponse __res, char *out); + +#endif diff --git a/http/http_status.c b/http/http_status.c new file mode 100644 index 0000000..775237f --- /dev/null +++ b/http/http_status.c @@ -0,0 +1,263 @@ +#include "http_status.h" +#include + +void http_status_message(HttpStatus __status, char *msg, size_t __size) { + switch (__status) { + case HTTP_CONTINUE: { + char http_continue[] = "Continue"; + strlcpy(msg, http_continue, __size); + } break; + case HTTP_SWITCHING_PROTOCOLS: { + char http_switching_protocols[] = "Switching Protocols"; + strlcpy(msg, http_switching_protocols, __size); + } break; + case HTTP_PROCESSING: { + char http_processing[] = "Processing"; + strlcpy(msg, http_processing, __size); + } break; + case HTTP_EARLY_HINTS: { + char http_early_hints[] = "Early Hints"; + strlcpy(msg, http_early_hints, __size); + } break; + case HTTP_OK: { + char http_ok[] = "Ok"; + strlcpy(msg, http_ok, __size); + } break; + case HTTP_CREATED: { + char http_created[] = "Created"; + strlcpy(msg, http_created, __size); + } break; + case HTTP_ACCEPTED: { + char http_accepted[] = "Accepted"; + strlcpy(msg, http_accepted, __size); + } break; + case HTTP_NON_AUTHORITATIVE_INFORMATION: { + char http_non_authoritative_information[] = + "Non Authoritative Information"; + strlcpy(msg, http_non_authoritative_information, __size); + } break; + case HTTP_NO_CONTENT: { + char http_no_content[] = "No Content"; + strlcpy(msg, http_no_content, __size); + } break; + case HTTP_RESET_CONTENT: { + char http_reset_content[] = "Reset Content"; + strlcpy(msg, http_reset_content, __size); + } break; + case HTTP_PARTIAL_CONTENT: { + char http_partial_content[] = "Partial Content"; + strlcpy(msg, http_partial_content, __size); + } break; + case HTTP_MULTI_STATUS: { + char http_multi_status[] = "Multi Status"; + strlcpy(msg, http_multi_status, __size); + } break; + case HTTP_ALREADY_REPORTED: { + char http_already_reported[] = "Already Reported"; + strlcpy(msg, http_already_reported, __size); + } break; + case HTTP_IM_USED: { + char http_im_used[] = "Im Used"; + strlcpy(msg, http_im_used, __size); + } break; + + case HTTP_MULTIPLE_CHOICES: { + char http_multiple_choices[] = "Multiple Choices"; + strlcpy(msg, http_multiple_choices, __size); + } break; + case HTTP_MOVED_PERMANENTLY: { + char http_moved_permanently[] = "Moved Permanently"; + strlcpy(msg, http_moved_permanently, __size); + } break; + case HTTP_FOUND: { + char http_found[] = "Found"; + strlcpy(msg, http_found, __size); + } break; + case HTTP_SEE_OTHER: { + char http_see_other[] = "See Other"; + strlcpy(msg, http_see_other, __size); + } break; + case HTTP_NOT_MODIFIED: { + char http_not_modified[] = "Not Modified"; + strlcpy(msg, http_not_modified, __size); + } break; + case HTTP_USE_PROXY: { + char http_use_proxy[] = "Use Proxy"; + strlcpy(msg, http_use_proxy, __size); + } break; + case HTTP_TEMPORARY_REDIRECT: { + char http_temporary_redirect[] = "Temporary Redirect"; + strlcpy(msg, http_temporary_redirect, __size); + } break; + case HTTP_PERMANENT_REDIRECT: { + char http_permanent_redirect[] = "Permanent Redirect"; + strlcpy(msg, http_permanent_redirect, __size); + } break; + + case HTTP_BAD_REQUEST: { + char http_bad_request[] = "Bad Request"; + strlcpy(msg, http_bad_request, __size); + } break; + case HTTP_UNAUTHORIZED: { + char http_unauthorized[] = "Unauthorized"; + strlcpy(msg, http_unauthorized, __size); + } break; + case HTTP_PAYMENT_REQUIRED: { + char http_payment_required[] = "Payment Required"; + strlcpy(msg, http_payment_required, __size); + } break; + case HTTP_FORBIDDEN: { + char http_forbidden[] = "Forbidden"; + strlcpy(msg, http_forbidden, __size); + } break; + case HTTP_NOT_FOUND: { + char http_not_found[] = "Not Found"; + strlcpy(msg, http_not_found, __size); + } break; + case HTTP_METHOD_NOT_ALLOWED: { + char http_method_not_allowed[] = "Method Not Allowed"; + strlcpy(msg, http_method_not_allowed, __size); + } break; + case HTTP_NOT_ACCEPTABLE: { + char http_not_acceptable[] = "Not Acceptable"; + strlcpy(msg, http_not_acceptable, __size); + } break; + case HTTP_PROXY_AUTHENTICATION_REQUIRED: { + char http_proxy_authentication_required[] = + "Proxy Authentication Required"; + strlcpy(msg, http_proxy_authentication_required, __size); + } break; + case HTTP_REQUEST_TIMEOUT: { + char http_request_timeout[] = "Request Timeout"; + strlcpy(msg, http_request_timeout, __size); + } break; + case HTTP_CONFLICT: { + char http_conflict[] = "Conflict"; + strlcpy(msg, http_conflict, __size); + } break; + case HTTP_GONE: { + char http_gone[] = "Gone"; + strlcpy(msg, http_gone, __size); + } break; + case HTTP_LENGTH_REQUIRED: { + char http_length_required[] = "Length Required"; + strlcpy(msg, http_length_required, __size); + } break; + case HTTP_PRECONDITION_FAILED: { + char http_precondition_failed[] = "Precondition Failed"; + strlcpy(msg, http_precondition_failed, __size); + } break; + case HTTP_PAYLOAD_TOO_LARGE: { + char http_payload_too_large[] = "Payload Too Large"; + strlcpy(msg, http_payload_too_large, __size); + } break; + case HTTP_URI_TOO_LONG: { + char http_uri_too_long[] = "Uri Too Long"; + strlcpy(msg, http_uri_too_long, __size); + } break; + case HTTP_UNSUPPORTED_MEDIA_TYPE: { + char http_unsupported_media_type[] = "Unsupported Media Type"; + strlcpy(msg, http_unsupported_media_type, __size); + } break; + case HTTP_RANGE_NOT_SATISFIABLE: { + char http_range_not_satisfiable[] = "Range Not Satisfiable"; + strlcpy(msg, http_range_not_satisfiable, __size); + } break; + case HTTP_EXPECTATION_FAILED: { + char http_expectation_failed[] = "Expectation Failed"; + strlcpy(msg, http_expectation_failed, __size); + } break; + case HTTP_IM_A_TEAPOT: { + char http_im_a_teapot[] = "Im A Teapot"; + strlcpy(msg, http_im_a_teapot, __size); + } break; + case HTTP_MISDIRECTED_REQUEST: { + char http_misdirected_request[] = "Misdirected Request"; + strlcpy(msg, http_misdirected_request, __size); + } break; + case HTTP_UNPROCESSABLE_ENTITY: { + char http_unprocessable_entity[] = "Unprocessable Entity"; + strlcpy(msg, http_unprocessable_entity, __size); + } break; + case HTTP_LOCKED: { + char http_locked[] = "Locked"; + strlcpy(msg, http_locked, __size); + } break; + case HTTP_FAILED_DEPENDENCY: { + char http_failed_dependency[] = "Failed Dependency"; + strlcpy(msg, http_failed_dependency, __size); + } break; + case HTTP_TOO_EARLY: { + char http_too_early[] = "Too Early"; + strlcpy(msg, http_too_early, __size); + } break; + case HTTP_UPGRADE_REQUIRED: { + char http_upgrade_required[] = "Upgrade Required"; + strlcpy(msg, http_upgrade_required, __size); + } break; + case HTTP_PRECONDITION_REQUIRED: { + char http_precondition_required[] = "Precondition Required"; + strlcpy(msg, http_precondition_required, __size); + } break; + case HTTP_TOO_MANY_REQUESTS: { + char http_too_many_requests[] = "Too Many Requests"; + strlcpy(msg, http_too_many_requests, __size); + } break; + case HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE: { + char http_request_header_fields_too_large[] = + "Request Header Fields Too Large"; + strlcpy(msg, http_request_header_fields_too_large, __size); + } break; + case HTTP_UNAVAILABLE_FOR_LEGAL_REASONS: { + char http_unavailable_for_legal_reasons[] = + "Unavailable For Legal Reasons"; + strlcpy(msg, http_unavailable_for_legal_reasons, __size); + } break; + + case HTTP_INTERNAL_SERVER_ERROR: { + char http_internal_server_error[] = "Internal Server Error"; + strlcpy(msg, http_internal_server_error, __size); + } break; + case HTTP_NOT_IMPLEMENTED: { + char http_not_implemented[] = "Not Implemented"; + strlcpy(msg, http_not_implemented, __size); + } break; + case HTTP_BAD_GATEWAY: { + char http_bad_gateway[] = "Bad Gateway"; + strlcpy(msg, http_bad_gateway, __size); + } break; + case HTTP_SERVICE_UNAVAILABLE: { + char http_service_unavailable[] = "Service Unavailable"; + strlcpy(msg, http_service_unavailable, __size); + } break; + case HTTP_GATEWAY_TIMEOUT: { + char http_gateway_timeout[] = "Gateway Timeout"; + strlcpy(msg, http_gateway_timeout, __size); + } break; + case HTTP_HTTP_VERSION_NOT_SUPPORTED: { + char http_http_version_not_supported[] = "Http Version Not Supported"; + strlcpy(msg, http_http_version_not_supported, __size); + } break; + case HTTP_VARIANT_ALSO_NEGOTIATES: { + char http_variant_also_negotiates[] = "Variant Also Negotiates"; + strlcpy(msg, http_variant_also_negotiates, __size); + } break; + case HTTP_INSUFFICIENT_STORAGE: { + char http_insufficient_storage[] = "Insufficient Storage"; + strlcpy(msg, http_insufficient_storage, __size); + } break; + case HTTP_LOOP_DETECTED: { + char http_loop_detected[] = "Loop Detected"; + strlcpy(msg, http_loop_detected, __size); + } break; + case HTTP_NOT_EXTENDED: { + char http_not_extended[] = "Not Extended"; + strlcpy(msg, http_not_extended, __size); + } break; + case HTTP_NETWORK_AUTHENTICATION_REQUIRED: { + char http_network_authentication_required[] = + "Network Authentication Required"; + strlcpy(msg, http_network_authentication_required, __size); + } break; + } +} diff --git a/http/http_status.h b/http/http_status.h new file mode 100644 index 0000000..2252068 --- /dev/null +++ b/http/http_status.h @@ -0,0 +1,77 @@ +#ifndef HTTP_STATUS_H +#define HTTP_STATUS_H + +#include +typedef enum { + HTTP_CONTINUE = 100, + HTTP_SWITCHING_PROTOCOLS = 101, + HTTP_PROCESSING = 102, + HTTP_EARLY_HINTS = 103, + + HTTP_OK = 200, + HTTP_CREATED = 201, + HTTP_ACCEPTED = 202, + HTTP_NON_AUTHORITATIVE_INFORMATION = 203, + HTTP_NO_CONTENT = 204, + HTTP_RESET_CONTENT = 205, + HTTP_PARTIAL_CONTENT = 206, + HTTP_MULTI_STATUS = 207, + HTTP_ALREADY_REPORTED = 208, + HTTP_IM_USED = 226, + + HTTP_MULTIPLE_CHOICES = 300, + HTTP_MOVED_PERMANENTLY = 301, + HTTP_FOUND = 302, + HTTP_SEE_OTHER = 303, + HTTP_NOT_MODIFIED = 304, + HTTP_USE_PROXY = 305, + HTTP_TEMPORARY_REDIRECT = 307, + HTTP_PERMANENT_REDIRECT = 308, + + HTTP_BAD_REQUEST = 400, + HTTP_UNAUTHORIZED = 401, + HTTP_PAYMENT_REQUIRED = 402, + HTTP_FORBIDDEN = 403, + HTTP_NOT_FOUND = 404, + HTTP_METHOD_NOT_ALLOWED = 405, + HTTP_NOT_ACCEPTABLE = 406, + HTTP_PROXY_AUTHENTICATION_REQUIRED = 407, + HTTP_REQUEST_TIMEOUT = 408, + HTTP_CONFLICT = 409, + HTTP_GONE = 410, + HTTP_LENGTH_REQUIRED = 411, + HTTP_PRECONDITION_FAILED = 412, + HTTP_PAYLOAD_TOO_LARGE = 413, + HTTP_URI_TOO_LONG = 414, + HTTP_UNSUPPORTED_MEDIA_TYPE = 415, + HTTP_RANGE_NOT_SATISFIABLE = 416, + HTTP_EXPECTATION_FAILED = 417, + HTTP_IM_A_TEAPOT = 418, // Easter egg + HTTP_MISDIRECTED_REQUEST = 421, + HTTP_UNPROCESSABLE_ENTITY = 422, + HTTP_LOCKED = 423, + HTTP_FAILED_DEPENDENCY = 424, + HTTP_TOO_EARLY = 425, + HTTP_UPGRADE_REQUIRED = 426, + HTTP_PRECONDITION_REQUIRED = 428, + HTTP_TOO_MANY_REQUESTS = 429, + HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE = 431, + HTTP_UNAVAILABLE_FOR_LEGAL_REASONS = 451, + + HTTP_INTERNAL_SERVER_ERROR = 500, + HTTP_NOT_IMPLEMENTED = 501, + HTTP_BAD_GATEWAY = 502, + HTTP_SERVICE_UNAVAILABLE = 503, + HTTP_GATEWAY_TIMEOUT = 504, + HTTP_HTTP_VERSION_NOT_SUPPORTED = 505, + HTTP_VARIANT_ALSO_NEGOTIATES = 506, + HTTP_INSUFFICIENT_STORAGE = 507, + HTTP_LOOP_DETECTED = 508, + HTTP_NOT_EXTENDED = 510, + HTTP_NETWORK_AUTHENTICATION_REQUIRED = 511 + +} HttpStatus; + +void http_status_message(HttpStatus __status, char *msg, size_t __size); + +#endif // HTTP_STATUS_H diff --git a/main.c b/main.c new file mode 100644 index 0000000..0e8109a --- /dev/null +++ b/main.c @@ -0,0 +1,19 @@ +#include "http/http_response.h" +#include "http/http_status.h" +#include +#include + +int main() { + + char body[BUFSIZ] = "

Bonsoir

"; + HttpResponse response = {.status_code = HTTP_OK, + .content_type = HTTP_CT_HTML, + .content_length = strlen(body), + .body = body}; + + char out[BUFSIZ]; + construct_response(response, out); + + printf("%s", out); + return 0; +}