#include "http/http.h" #include /* Debug */ #include #include #include #include "utils/colors.h" http_t *http_parse(char *request_str, int sockfd) { http_t *request = malloc(sizeof(http_t)); if (request == NULL) { return NULL; } /* Insert socket file descriptor */ request->sockfd = sockfd; /* Parse HTTP method */ char *pch = strtok(request_str, " "); if (pch == NULL) { return NULL; } printf("[http] method: %s\n", pch); http_parse_method(request, pch); /* Parse location */ pch = strtok(NULL, " "); if (pch == NULL) { return NULL; } printf("[http] location: %s\n", pch); strncpy(request->location, pch, LOCATION_LEN); /* Parse location path */ /* TODO: Prevent Path Traversal */ if (strcmp(request->location, "/") == 0) { snprintf(request->location_path, LOCATION_LEN, "%s/index.html", WWW); } else { snprintf(request->location_path, LOCATION_LEN, "%s%s", WWW, request->location); } fprintf(stdout, "[http] location path: %s\n", request->location_path); /* Parse HTTP version */ pch = strtok(NULL, " \r\n"); if (pch == NULL) { return NULL; } printf("[http] version: %s\n", pch); strncpy(request->http_version, pch, HTTP_VERSION_LEN); /* Parse other stuff... */ return request; } void http_parse_method(http_t *request, const char *method) { if (strcmp(method, "GET") == 0) { request->method = GET; return; } if (strcmp(method, "POST") == 0) { request->method = POST; return; } http_send_not_implemented(request); } void http_send_response(http_t *request) { FILE *file = fopen(request->location_path, "rb"); if (file == NULL) { /* 404 */ http_send_not_found(request); return; } /* Retrieve correct Content-Type */ char content_type[1024]; http_get_content_type(request, content_type); /* Retrieve file size */ fseek(file, 0, SEEK_END); const size_t content_length = ftell(file); /* Returns the read bytes (we're at the end, so the file size) */ rewind(file); /* Retrieve file data */ char *file_data = malloc(content_length); if (file_data == NULL) { fclose(file); fprintf(stderr, RED "Unable to allocate file data\n"); return; } /* Read 1 byte until content_length from file and put in file_data */ fread(file_data, 1, content_length, file); fclose(file); char response_header[1024]; snprintf(response_header, sizeof response_header, "%s 200 OK\r\n" "Content-Type: %s\r\n" "Content-Length: %zu\r\n" "Connection: close\r\n" "\r\n", request->http_version, content_type, content_length); send(request->sockfd, response_header, strlen(response_header), 0); send(request->sockfd, file_data, content_length, 0); free(file_data); } void http_get_content_type(http_t *request, char *content_type) { char *ptr = strrchr(request->location_path, '.'); if (ptr == NULL) { http_send_not_found(request); return; } ptr += 1; char ct[32]; /* TODO: Improve content_type (used to test) */ if (strcmp(ptr, "html") == 0 || strcmp(ptr, "css") == 0 || strcmp(ptr, "javascript") == 0) { strncpy(ct, "text", sizeof ct); } if (strcmp(ptr, "jpg") == 0 || strcmp(ptr, "png") == 0) { strncpy(ct, "image", sizeof ct); } snprintf(content_type, 1024, "%s/%s", ct, ptr); } void http_send_not_implemented(http_t *request) { const char response[1024] = "HTTP/1.1 501 Not Implemented\r\n" "Content-Type: text/html\r\n" "Content-Length: 216\r\n" "\r\n" "\n" "\n" " 501 Not Implemented\n" "\n" "\n" "

501 Not Implemented

\n" "\n" ""; const size_t response_len = strlen(response); send(request->sockfd, response, response_len, 0); } void http_send_not_found(http_t *request) { const char response[1024] = "HTTP/1.1 404 Not Found\r\n" "Content-Type: text/html\r\n" "Content-Length: 216\r\n" "\r\n" "\n" "\n" " 404 Not Found\n" "\n" "\n" "

404 Not Found.

\n" "\n" ""; const size_t response_len = strlen(response); send(request->sockfd, response, response_len, 0); } void http_free(http_t *request) { free(request); }