http/src/http.c
SuperNovaa41 04abd8b152 progress?
2025-02-07 13:54:59 -05:00

298 lines
6.6 KiB
C

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "include/http.h"
#include "include/file.h"
http_method_t str_to_http_method(char* input)
{
if (strncmp(input, "GET", 3) == 0) {
return GET;
} else if (strncmp(input, "HEAD", 4) == 0) {
return HEAD;
}
return UNKNOWN;
}
const char* http_method_to_str(http_method_t input)
{
switch (input) {
case GET:
return "GET";
case HEAD:
return "HEAD";
case UNKNOWN:
default:
return "UNKNOWN";
}
}
const char* http_status_code_to_str(http_status_code_t code)
{
switch(code) {
case HTTP100:
return "Continue";
case HTTP101:
return "Switching Protocols";
case HTTP200:
return "OK";
case HTTP201:
return "Created";
case HTTP202:
return "Accepted";
case HTTP203:
return "Non-Authoritative Information";
case HTTP204:
return "No Content";
case HTTP205:
return "Reset Content";
case HTTP206:
return "Partial Content";
case HTTP300:
return "Multiple Choices";
case HTTP301:
return "Moved Permanently";
case HTTP302:
return "Found";
case HTTP303:
return "See Other";
case HTTP304:
return "Not Modified";
case HTTP305:
return "Use Proxy";
case HTTP307:
return "Temporary Redirect";
case HTTP400:
return "Bad Request";
case HTTP401:
return "Unauthorized";
case HTTP402:
return "Payment Required";
case HTTP403:
return "Forbidden";
case HTTP404:
return "Not Found";
case HTTP405:
return "Method Not Allowed";
case HTTP406:
return "Not Acceptable";
case HTTP407:
return "Proxy Authentication Required";
case HTTP408:
return "Request Time-out";
case HTTP409:
return "Conflict";
case HTTP410:
return "Gone";
case HTTP411:
return "Length Required";
case HTTP412:
return "Precondition Failed";
case HTTP413:
return "Request Entity Too Large";
case HTTP414:
return "Request-URI Too Large";
case HTTP415:
return "Unsupported Media Type";
case HTTP416:
return "Requested range not satisfiable";
case HTTP417:
return "Expectation Failed";
case HTTP500:
return "Internal Server Error";
case HTTP501:
return "Not Implemented";
case HTTP502:
return "Bad Gateway";
case HTTP503:
return "Service Unavailable";
case HTTP504:
return "Gateway Time-out";
case HTTP505:
return "HTTP Version not supported";
default:
return "UNKNOWN";
}
}
void init_general_headers(struct general_headers* headers)
{
headers->cache_control = "";
headers->connection = "";
headers->date = "";
headers->pragma = "";
headers->trailer = "";
headers->transfer_encoding = "";
headers->upgrade = "";
headers->via = "";
headers->warning = "";
}
void init_http_request(http_request* request)
{
init_general_headers(&(request->general_headers));
request->request_headers.accept = "";
request->request_headers.accept_charset = "";
request->request_headers.accept_encoding = "";
request->request_headers.accept_language = "";
request->request_headers.authorization = "";
request->request_headers.expect = "";
request->request_headers.from = "";
request->request_headers.host = "";
request->request_headers.if_match = "";
request->request_headers.if_modified_since = "";
request->request_headers.if_none_match = "";
request->request_headers.if_range = "";
request->request_headers.if_unmodified_since = "";
request->request_headers.max_forwards = "";
request->request_headers.proxy_authorization = "";
request->request_headers.range = "";
request->request_headers.referer = "";
request->request_headers.te = "";
request->request_headers.user_agent = "";
}
void init_http_response(http_response* response)
{
init_general_headers(&(response->general_headers));
response->response_headers.content_length = 0;
response->response_headers.accept_ranges = "";
response->response_headers.age = "";
response->response_headers.etag = "";
response->response_headers.location = "";
response->response_headers.proxy_authenticate = "";
response->response_headers.retry_after = "";
response->response_headers.server = "";
response->response_headers.vary = "";
response->response_headers.www_authenticate = "";
}
void free_http_request(http_request* request)
{
free(request->request_line.request_uri);
}
void free_http_response(http_response* response)
{
free(response->message_body);
}
void parse_request_line(char** line, http_request_line* request)
{
char *tok, *ver, *num;
tok = strtok(*line, " "); // this is the method
if (tok == NULL) {
perror("strtok");
exit(EXIT_FAILURE);
}
request->method = str_to_http_method(tok);
tok = strtok(NULL, " "); // this is the request URI
if (tok == NULL) {
perror("strtok");
exit(EXIT_FAILURE);
}
request->request_uri = (char*) malloc(strlen(tok) + 1);
strncpy(request->request_uri, tok, strlen(tok) + 1);
tok = strtok(NULL, " "); // this is the version
if (tok == NULL) {
perror("strtok");
exit(EXIT_FAILURE);
}
ver = strtok(tok, "/");
if (tok == NULL) {
perror("strtok");
exit(EXIT_FAILURE);
}
ver = strtok(NULL, "/");
if (tok == NULL) {
perror("strtok");
exit(EXIT_FAILURE);
}
num = strtok(ver, ".");
if (tok == NULL) {
perror("strtok");
exit(EXIT_FAILURE);
}
request->version.major = atoi(num);
num = strtok(NULL, ".");
if (tok == NULL) {
perror("strtok");
exit(EXIT_FAILURE);
}
request->version.minor = atoi(num);
}
void parse_http_request(char** buffer, http_request* request)
{
// going to be using strtok here to split up the request
// first lets split each line
char* line;
http_request_line r_line;
// parse the first line
line = strtok(*buffer, "\n");
if (line == NULL) {
perror("strtok");
exit(EXIT_FAILURE);
}
parse_request_line(&line, &r_line);
request->request_line = r_line;
/**
* TODO: start accepting the headers
*
* for now im going to ignore them since they're not suuuper important for simple
* operation
*
* whats important is that we have the 2 things we need to get started, the method and the URI
*/
/**
// parse the remaining lines
while (line != NULL) {
// get the rest of them
line = strtok(NULL, "\n");
}
*/
}
void create_http_response(http_request* request, http_response* response)
{
get_file_from_uri(&(request->request_line.request_uri), &(response->message_body));
init_http_response(response);
response->response_headers.content_length = strlen(response->message_body);
// HTTP/1.1
response->status.version.major = 1;
response->status.version.minor = 1;
// TODO: obviouslly add something to determine the status code to use
response->status.status_code = HTTP200;
response->status.reason_phrase = http_status_code_to_str(response->status.status_code);
response->response_headers.content_type = "text/html";
}