feat: OK là ça fait trop je sais mm plus combien j'ai changé de trucs, RENDEZ LES PUSH DE LA MAISON
This commit is contained in:
parent
2255bfc2e2
commit
1771f72ecb
12 changed files with 288 additions and 49 deletions
|
|
@ -50,6 +50,10 @@ static void print_help(char *program_name)
|
|||
// limit imposed by school
|
||||
static int parse_daemon_arg(struct config *cfg)
|
||||
{
|
||||
// Multiple contradictory parameters
|
||||
if (cfg->daemon != NO_OPTION)
|
||||
return ARG_INVALID;
|
||||
|
||||
if (strcmp(optarg, "start") == 0)
|
||||
cfg->daemon = START;
|
||||
else if (strcmp(optarg, "stop") == 0)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#define CONFIG_H
|
||||
|
||||
#define _XOPEN_SOURCE 500
|
||||
#define HTTP_VERSION "HTTP/1.1"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
|
|
@ -32,6 +33,7 @@ struct config
|
|||
char *pid_file;
|
||||
char *log_file;
|
||||
bool log;
|
||||
char* protocol_version;
|
||||
|
||||
struct server_config *servers;
|
||||
enum daemon daemon;
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
*
|
||||
* @param
|
||||
*/
|
||||
void stop_daemon(int pid);
|
||||
void stop_daemon();
|
||||
|
||||
/* @brief
|
||||
*
|
||||
|
|
@ -21,6 +21,6 @@ int start_daemon(void);
|
|||
*
|
||||
* @return
|
||||
*/
|
||||
int restart_daemon(int pid);
|
||||
int restart_daemon();
|
||||
|
||||
#endif // ! DAEMON_H
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
#include "headers.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../utils/parsing/words.h"
|
||||
|
||||
|
|
@ -84,3 +86,49 @@ ssize_t parse_headers(struct http_request *res, struct string *req,
|
|||
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
struct http_header *create_header(const char *field, const char *value)
|
||||
{
|
||||
struct http_header *res = calloc(1, sizeof(struct http_header));
|
||||
if (res == NULL)
|
||||
return NULL;
|
||||
|
||||
// Field
|
||||
ssize_t field_size = strlen(field);
|
||||
if (field_size < 0)
|
||||
{
|
||||
free(res);
|
||||
return NULL;
|
||||
}
|
||||
res->field = string_create(field, field_size);
|
||||
|
||||
// Value
|
||||
ssize_t value_size = strlen(value);
|
||||
if (value_size < 0)
|
||||
{
|
||||
string_destroy(res->field);
|
||||
free(res);
|
||||
return NULL;
|
||||
}
|
||||
res->value = string_create(value, value_size);
|
||||
|
||||
return res;
|
||||
}
|
||||
void append_header(struct http_header **list, struct http_header *element)
|
||||
{
|
||||
if (list == NULL)
|
||||
return;
|
||||
|
||||
if (*list == NULL)
|
||||
*list = element;
|
||||
else
|
||||
{
|
||||
struct http_header *cur_elt = *list;
|
||||
while (cur_elt->next != NULL)
|
||||
{
|
||||
cur_elt = cur_elt->next;
|
||||
}
|
||||
|
||||
cur_elt->next = element;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,4 +59,24 @@ ssize_t parse_headers(struct http_request *res, struct string *req,
|
|||
*/
|
||||
struct http_header* get_header(struct http_header *headers, const char* field);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
*
|
||||
* @param field
|
||||
* @param value
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
struct http_header* create_header(const char* field, const char* value);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
*
|
||||
* @param field
|
||||
* @param value
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
void append_header(struct http_header **list, struct http_header *element);
|
||||
|
||||
#endif // ! HEADERS_H
|
||||
|
|
|
|||
|
|
@ -1,11 +1,14 @@
|
|||
#include "http.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../utils/files/files.h"
|
||||
#include "../utils/parsing/words.h"
|
||||
#include "../utils/time/fmt_time.h"
|
||||
#include "headers.h"
|
||||
|
||||
// === Static variables
|
||||
|
|
@ -45,7 +48,7 @@ static ssize_t parse_reqline(struct http_request *res, struct string *req)
|
|||
return ERR_HTTP_INVALID_INPUT;
|
||||
|
||||
// Target (path)
|
||||
skipped += read_word(req, i, &res->path);
|
||||
skipped += read_word(req, i, &res->target);
|
||||
if (skipped <= 0)
|
||||
return ERR_HTTP_INVALID_INPUT;
|
||||
|
||||
|
|
@ -58,29 +61,81 @@ static ssize_t parse_reqline(struct http_request *res, struct string *req)
|
|||
if (skipped <= 0)
|
||||
return ERR_HTTP_INVALID_INPUT;
|
||||
|
||||
// EOL
|
||||
if (req->data[i++] != '\n')
|
||||
// CRLF (EOL)
|
||||
if (req->data[i++] != '\r' && req->data[i++] != '\n')
|
||||
return ERR_HTTP_INVALID_INPUT;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
// Split target into path and queries
|
||||
static void split_target(struct http_request *req)
|
||||
{
|
||||
size_t i = 0;
|
||||
while (i < req->path->size)
|
||||
while (i < req->target->size)
|
||||
{
|
||||
if (req->path->data[i] == '?')
|
||||
if (req->target->data[i] == '?')
|
||||
{
|
||||
req->queries =
|
||||
string_create(req->path->data + i, req->path->size - i);
|
||||
req->path->size = i;
|
||||
string_create(req->target->data + i, req->target->size - i);
|
||||
req->target->size = i;
|
||||
return;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
// Finds a valid path based on the client input
|
||||
static bool find_target(struct http_request *req)
|
||||
{
|
||||
// Check filename
|
||||
if (!check_filename(req->target))
|
||||
return false;
|
||||
int err = is_directory(req->target->data);
|
||||
if (err == -1)
|
||||
return false;
|
||||
else if (err == 1)
|
||||
{
|
||||
if (req->target->data[req->target->size - 1] != '/')
|
||||
string_concat_str(req->target, "/", 1);
|
||||
|
||||
string_concat_str(req->target, config->servers->default_file,
|
||||
strlen(config->servers->default_file));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct string *generate_status_message(int status_code)
|
||||
{
|
||||
char *message;
|
||||
switch (status_code)
|
||||
{
|
||||
case 200:
|
||||
message = "OK";
|
||||
break;
|
||||
case 400:
|
||||
message = "Bad Request";
|
||||
break;
|
||||
case 403:
|
||||
message = "Forbidden";
|
||||
break;
|
||||
case 404:
|
||||
message = "Not Found";
|
||||
break;
|
||||
case 405:
|
||||
message = "Method Not Allowed";
|
||||
break;
|
||||
case 505:
|
||||
message = "HTTP Version Not Supported";
|
||||
break;
|
||||
default:
|
||||
message = "WTF";
|
||||
}
|
||||
|
||||
return string_create(message, strlen(message));
|
||||
}
|
||||
|
||||
// === Functions
|
||||
|
||||
void http_init(struct config *cfg)
|
||||
|
|
@ -117,31 +172,84 @@ struct http_request *parse_request(struct string *req)
|
|||
// TODO handle logs and free adequately
|
||||
struct http_response *generate_response(struct http_request *req)
|
||||
{
|
||||
// Path
|
||||
// Malloc
|
||||
struct http_response *res = calloc(1, sizeof(struct http_response));
|
||||
if (res == NULL)
|
||||
return NULL;
|
||||
|
||||
// Check filename
|
||||
if (!check_filename(req->path))
|
||||
return NULL;
|
||||
int err = is_directory(req->path->data);
|
||||
if (err == -1)
|
||||
return NULL;
|
||||
else if (err == 1)
|
||||
// Protocol
|
||||
char *protocol = "HTTP/1.1";
|
||||
res->protocol = string_create(protocol, strlen(protocol));
|
||||
|
||||
// Status code
|
||||
if (req->status_code == 0)
|
||||
{
|
||||
string_concat_str(req->path, "/", 1);
|
||||
string_concat_str(req->path, config->servers->default_file,
|
||||
strlen(config->servers->default_file));
|
||||
}
|
||||
if (!find_target(req))
|
||||
res->status_code = 404;
|
||||
else
|
||||
res->status_code = 200;
|
||||
}
|
||||
|
||||
// struct string *format_response(struct http_response *resp)
|
||||
// {}
|
||||
// Status msg
|
||||
res->status_msg = generate_status_message(res->status_code);
|
||||
|
||||
// Headers
|
||||
char *time = get_time();
|
||||
append_header(&res->headers, create_header("Date", time));
|
||||
free(time); // Yes, the one that completely disapeared this year
|
||||
if (res->status_code == 200)
|
||||
{
|
||||
char buf[21] = { 0 }; // (21 ~= log10(2^64)) + 1 (null byte)
|
||||
char *target = string_to_charptr(req->target);
|
||||
sprintf(buf, "%lu", get_file_content_size(target));
|
||||
append_header(&res->headers, create_header("Content-Length", buf));
|
||||
}
|
||||
append_header(&res->headers, create_header("Connection", "close"));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
struct string *format_response(struct http_response *resp)
|
||||
{
|
||||
// Protocol
|
||||
struct string *res =
|
||||
string_create(resp->protocol->data, resp->protocol->size);
|
||||
|
||||
string_concat_str(res, " ", 1);
|
||||
|
||||
// Status code
|
||||
char buf[4] = { 0 };
|
||||
sprintf(buf, "%d", resp->status_code);
|
||||
string_concat_str(res, buf, strlen(buf));
|
||||
|
||||
string_concat_str(res, " ", 1);
|
||||
|
||||
// Status message
|
||||
string_concat_str(res, buf, strlen(buf));
|
||||
|
||||
string_concat_str(res, "/r/n", 2);
|
||||
|
||||
// Headers
|
||||
struct http_header *cur_header = resp->headers;
|
||||
while (cur_header != NULL)
|
||||
{
|
||||
string_concat_str(res, cur_header->field->data,
|
||||
cur_header->field->size);
|
||||
|
||||
string_concat_str(res, "/r/n", 2);
|
||||
}
|
||||
|
||||
string_concat_str(res, "/r/n", 2);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void destroy_request(struct http_request *req)
|
||||
{
|
||||
if (req != NULL)
|
||||
{
|
||||
if (req->path != NULL)
|
||||
string_destroy(req->path);
|
||||
if (req->target != NULL)
|
||||
string_destroy(req->target);
|
||||
if (req->protocol != NULL)
|
||||
string_destroy(req->protocol);
|
||||
|
||||
|
|
|
|||
|
|
@ -43,10 +43,11 @@ struct http_header
|
|||
struct http_request
|
||||
{
|
||||
enum http_method method;
|
||||
struct string *path;
|
||||
struct string *target;
|
||||
struct string *queries;
|
||||
struct string *protocol;
|
||||
struct http_header *headers; // Headers linked list
|
||||
int status_code; // Set by program
|
||||
};
|
||||
|
||||
struct http_response
|
||||
|
|
@ -61,7 +62,7 @@ struct http_response
|
|||
|
||||
/* @brief Initializes the HTTP module with the given configuration
|
||||
*
|
||||
* @warning Do no use any other function of this module before calling that one
|
||||
* @warn Do no use any other function of this module before calling that one
|
||||
*
|
||||
* @param cfg
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#include <getopt.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "config/config.h"
|
||||
#include "http/http.h"
|
||||
#include "logger/logs.h"
|
||||
#include "server/server.h"
|
||||
|
||||
|
|
@ -9,12 +9,35 @@
|
|||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
// Parse config
|
||||
struct config *config = parse_configuration(argc, argv);
|
||||
if (config == NULL)
|
||||
return ERR_ARG;
|
||||
|
||||
// Initialize modules
|
||||
log_init(config);
|
||||
http_init(config);
|
||||
|
||||
// Start server
|
||||
switch (config->daemon)
|
||||
{
|
||||
NO_OPTION:
|
||||
start_server("localhost", config->servers->port);
|
||||
break;
|
||||
|
||||
START:
|
||||
start_daemon();
|
||||
break;
|
||||
|
||||
RESTART:
|
||||
restart_daemon();
|
||||
|
||||
STOP:
|
||||
stop_daemon();
|
||||
|
||||
default:
|
||||
return 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
#include "files.h"
|
||||
|
||||
#include <stdio.h>
|
||||
// #include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "../string/string.h"
|
||||
// #include "../string/string.h"
|
||||
|
||||
bool file_exists(const char *path)
|
||||
{}
|
||||
// bool file_exists(const char *path)
|
||||
// {}
|
||||
|
||||
int is_directory(const char *path)
|
||||
{
|
||||
|
|
@ -18,21 +18,21 @@ int is_directory(const char *path)
|
|||
}
|
||||
|
||||
// TODO handle logging
|
||||
struct string *get_file_content(const char *path)
|
||||
{
|
||||
// Open file
|
||||
FILE *stream = fopen(path, "r");
|
||||
if (stream == NULL)
|
||||
return NULL;
|
||||
// struct string *get_file_content(const char *path)
|
||||
// {
|
||||
// // Open file
|
||||
// FILE *stream = fopen(path, "r");
|
||||
// if (stream == NULL)
|
||||
// return NULL;
|
||||
|
||||
// Alloc result
|
||||
char buf[BUFFER_SIZE];
|
||||
struct string *res = string_create(NULL, 0);
|
||||
if (res == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
// // Alloc result
|
||||
// char buf[BUFFER_SIZE];
|
||||
// struct string *res = string_create(NULL, 0);
|
||||
// if (res == NULL)
|
||||
// {
|
||||
// return NULL;
|
||||
// }
|
||||
|
||||
int nread;
|
||||
while ((fgets(buf, BUFFER_SIZE, stream)))
|
||||
}
|
||||
// int nread;
|
||||
// while ((fgets(buf, BUFFER_SIZE, stream)))
|
||||
// }
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
// === Functions
|
||||
|
||||
|
|
@ -61,10 +62,19 @@ bool check_filename(struct string* path);
|
|||
/*
|
||||
* @brief
|
||||
*
|
||||
* @param path
|
||||
* @param filename
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
bool sanitize_filename(struct string* filename);
|
||||
|
||||
/*
|
||||
* @brief
|
||||
*
|
||||
* @param path
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
ssize_t get_file_content_size(const char* path);
|
||||
|
||||
#endif // ! FILES_H
|
||||
|
|
|
|||
|
|
@ -85,3 +85,17 @@ void string_destroy(struct string *str)
|
|||
free(str);
|
||||
}
|
||||
}
|
||||
|
||||
char *string_to_charptr(struct string *str)
|
||||
{
|
||||
if (str == NULL || str->data == NULL)
|
||||
return NULL;
|
||||
|
||||
char *res = realloc(str->data, str->size + 1);
|
||||
if (res == NULL)
|
||||
return NULL;
|
||||
|
||||
res[str->size] = '\0';
|
||||
|
||||
return res;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,4 +56,13 @@ void string_to_lowercase(struct string *str);
|
|||
*/
|
||||
void string_destroy(struct string *str);
|
||||
|
||||
/*
|
||||
** @brief Converts the string to the native C implementation
|
||||
**
|
||||
** @param str
|
||||
**
|
||||
** @return a pointer to an allocated memory zone containing the string
|
||||
*/
|
||||
char* string_to_charptr(struct string *str);
|
||||
|
||||
#endif /* ! STRING_H */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue