298 lines
6.6 KiB
C
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";
|
|
|
|
|
|
}
|