#include #include #include #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"; }