If file non existant crashing resolved
This commit is contained in:
@@ -40,7 +40,7 @@ void http_request_set(HttpRequest *__req, char *key, char *value) {
|
|||||||
else if (!strcmp(key, "Upgrade-Insecure-Requests"))
|
else if (!strcmp(key, "Upgrade-Insecure-Requests"))
|
||||||
__req->upgrade_insecure_requests = value;
|
__req->upgrade_insecure_requests = value;
|
||||||
else if (!strcmp(key, "Accept"))
|
else if (!strcmp(key, "Accept"))
|
||||||
;
|
free(value);
|
||||||
// __req->accept = value;
|
// __req->accept = value;
|
||||||
else if (!strcmp(key, "Sec-Fetch-Site"))
|
else if (!strcmp(key, "Sec-Fetch-Site"))
|
||||||
__req->sec_fetch_site = value;
|
__req->sec_fetch_site = value;
|
||||||
@@ -52,9 +52,12 @@ void http_request_set(HttpRequest *__req, char *key, char *value) {
|
|||||||
__req->accept_encoding = value;
|
__req->accept_encoding = value;
|
||||||
else if (!strcmp(key, "Connection"))
|
else if (!strcmp(key, "Connection"))
|
||||||
__req->connection = value;
|
__req->connection = value;
|
||||||
|
else
|
||||||
|
free(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
HttpRequest *handle_request(char *__req) {
|
HttpRequest *handle_request(char *__req) {
|
||||||
|
printf("%s\n", __req);
|
||||||
HttpRequest *request = malloc(sizeof(HttpRequest));
|
HttpRequest *request = malloc(sizeof(HttpRequest));
|
||||||
unsigned int line_count = 0;
|
unsigned int line_count = 0;
|
||||||
char *line_start = __req;
|
char *line_start = __req;
|
||||||
@@ -62,9 +65,7 @@ HttpRequest *handle_request(char *__req) {
|
|||||||
while ((line_end = strchr(line_start, '\n')) != NULL) {
|
while ((line_end = strchr(line_start, '\n')) != NULL) {
|
||||||
line_count++;
|
line_count++;
|
||||||
size_t l_length = line_end - line_start;
|
size_t l_length = line_end - line_start;
|
||||||
char *line = malloc(sizeof(char) * l_length);
|
char line[l_length];
|
||||||
if (line == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
strncpy(line, line_start, l_length);
|
strncpy(line, line_start, l_length);
|
||||||
line[l_length - 1] = 0;
|
line[l_length - 1] = 0;
|
||||||
@@ -79,20 +80,49 @@ HttpRequest *handle_request(char *__req) {
|
|||||||
request->path = path;
|
request->path = path;
|
||||||
} else {
|
} else {
|
||||||
char key[100] = {0};
|
char key[100] = {0};
|
||||||
char *value = malloc(sizeof(char) * 256);
|
|
||||||
char *colon_pos = strchr(line, ':');
|
char *colon_pos = strchr(line, ':');
|
||||||
if (colon_pos != NULL) {
|
if (colon_pos != NULL) {
|
||||||
size_t k_length = colon_pos - line;
|
size_t k_length = colon_pos - line;
|
||||||
strncpy(key, line, k_length);
|
strncpy(key, line, k_length);
|
||||||
|
|
||||||
|
size_t v_length = l_length - k_length - 3;
|
||||||
|
char *value = malloc(sizeof(char) * v_length);
|
||||||
strcpy(value, colon_pos + 2);
|
strcpy(value, colon_pos + 2);
|
||||||
http_request_set(request, key, value);
|
http_request_set(request, key, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: Analyze line
|
// TODO: Analyze line
|
||||||
free(line);
|
|
||||||
line_start = line_end + 1;
|
line_start = line_end + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void free_request(HttpRequest *__req) {
|
||||||
|
if (__req == NULL)
|
||||||
|
return;
|
||||||
|
if (__req->path != NULL)
|
||||||
|
free(__req->path);
|
||||||
|
if (__req->host != NULL)
|
||||||
|
free(__req->host);
|
||||||
|
if (__req->sec_fetch_dest != NULL)
|
||||||
|
free(__req->sec_fetch_dest);
|
||||||
|
if (__req->user_agent != NULL)
|
||||||
|
free(__req->user_agent);
|
||||||
|
if (__req->upgrade_insecure_requests != NULL)
|
||||||
|
free(__req->upgrade_insecure_requests);
|
||||||
|
if (__req->accept != NULL)
|
||||||
|
free(__req->accept);
|
||||||
|
if (__req->sec_fetch_site != NULL)
|
||||||
|
free(__req->sec_fetch_site);
|
||||||
|
if (__req->sec_fetch_mode != NULL)
|
||||||
|
free(__req->sec_fetch_mode);
|
||||||
|
if (__req->accept_language != NULL)
|
||||||
|
free(__req->accept_language);
|
||||||
|
if (__req->accept_encoding != NULL)
|
||||||
|
free(__req->accept_encoding);
|
||||||
|
if (__req->connection != NULL)
|
||||||
|
free(__req->connection);
|
||||||
|
|
||||||
|
free(__req);
|
||||||
|
}
|
||||||
|
|||||||
@@ -20,5 +20,6 @@ typedef struct {
|
|||||||
|
|
||||||
HttpRequest *handle_request(char *__req);
|
HttpRequest *handle_request(char *__req);
|
||||||
void print_request(const HttpRequest *__req);
|
void print_request(const HttpRequest *__req);
|
||||||
|
void free_request(HttpRequest *__req);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#include "http_content_type.h"
|
|
||||||
#include "http_response.h"
|
#include "http_response.h"
|
||||||
|
#include "http_content_type.h"
|
||||||
#include "http_status.h"
|
#include "http_status.h"
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -31,15 +31,18 @@ bool construct_response(HttpResponse __res, char *out) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void http_respond(HttpResponse __res, int clientfd) {
|
void http_respond(HttpResponse *__res, int clientfd) {
|
||||||
|
if (__res == NULL)
|
||||||
|
return;
|
||||||
char response[BUFSIZ];
|
char response[BUFSIZ];
|
||||||
// TODO: Handle return
|
// TODO: Handle return
|
||||||
construct_response(__res, response);
|
construct_response(*__res, response);
|
||||||
|
|
||||||
send(clientfd, response, strlen(response), 0);
|
send(clientfd, response, strlen(response), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *read_file(const char *__path) {
|
char *read_file(const char *__path) {
|
||||||
|
// If the file does not exist
|
||||||
if (access(__path, F_OK) != 0) {
|
if (access(__path, F_OK) != 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -48,10 +51,12 @@ char *read_file(const char *__path) {
|
|||||||
if (f == NULL) {
|
if (f == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
// Get the length of the file
|
||||||
fseek(f, 0, SEEK_END);
|
fseek(f, 0, SEEK_END);
|
||||||
size_t length = ftell(f);
|
size_t length = ftell(f);
|
||||||
rewind(f);
|
rewind(f);
|
||||||
|
|
||||||
|
// Initialize a value to get the content
|
||||||
char *content = malloc(length * sizeof(char));
|
char *content = malloc(length * sizeof(char));
|
||||||
|
|
||||||
if (content == NULL) {
|
if (content == NULL) {
|
||||||
@@ -59,6 +64,7 @@ char *read_file(const char *__path) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Read the file into content and set the last char to \0
|
||||||
size_t bytesRead = fread(content, sizeof(char), length, f);
|
size_t bytesRead = fread(content, sizeof(char), length, f);
|
||||||
content[bytesRead] = 0;
|
content[bytesRead] = 0;
|
||||||
|
|
||||||
@@ -72,10 +78,13 @@ HttpResponse *from_file(const char *__path) {
|
|||||||
if (content == NULL)
|
if (content == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
HttpResponse response = {.status_code = HTTP_OK,
|
HttpResponse response = {
|
||||||
.content_length = strlen(content),
|
.status_code = HTTP_OK,
|
||||||
.content_type = HTTP_CT_HTML,
|
.content_length = strlen(content),
|
||||||
.body = content};
|
.content_type = HTTP_CT_HTML,
|
||||||
|
.body = content,
|
||||||
|
.body_in_heap = true,
|
||||||
|
};
|
||||||
|
|
||||||
HttpResponse *res = malloc(sizeof(response));
|
HttpResponse *res = malloc(sizeof(response));
|
||||||
*res = response;
|
*res = response;
|
||||||
@@ -84,7 +93,7 @@ HttpResponse *from_file(const char *__path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void free_response(HttpResponse *__res) {
|
void free_response(HttpResponse *__res) {
|
||||||
if (__res->body != NULL)
|
if (__res->body != NULL && __res->body_in_heap)
|
||||||
free(__res->body);
|
free(__res->body);
|
||||||
|
|
||||||
free(__res);
|
free(__res);
|
||||||
|
|||||||
@@ -11,12 +11,19 @@ typedef struct {
|
|||||||
HttpContentType content_type;
|
HttpContentType content_type;
|
||||||
size_t content_length;
|
size_t content_length;
|
||||||
char *body;
|
char *body;
|
||||||
|
bool body_in_heap;
|
||||||
} HttpResponse;
|
} HttpResponse;
|
||||||
|
|
||||||
|
// It will create a string respecting the Hypertext Transfer Protocol.
|
||||||
|
//
|
||||||
|
// To then be sent to the client.
|
||||||
bool construct_response(HttpResponse __res, char *out);
|
bool construct_response(HttpResponse __res, char *out);
|
||||||
|
|
||||||
void http_respond(HttpResponse __res, int clientfd);
|
// Respond a http response to the client (clientfd);
|
||||||
|
void http_respond(HttpResponse *__res, int clientfd);
|
||||||
|
// Read a file from a specified path
|
||||||
char *read_file(const char *__path);
|
char *read_file(const char *__path);
|
||||||
|
// Given a path will return a HttpResponse
|
||||||
HttpResponse *from_file(const char *__path);
|
HttpResponse *from_file(const char *__path);
|
||||||
void free_response(HttpResponse *__res);
|
void free_response(HttpResponse *__res);
|
||||||
|
|
||||||
|
|||||||
98
http/http_server.c
Normal file
98
http/http_server.c
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
#include "http_server.h"
|
||||||
|
#include "http_content_type.h"
|
||||||
|
#include "http_request.h"
|
||||||
|
#include "http_response.h"
|
||||||
|
#include "http_status.h"
|
||||||
|
#include <asm-generic/socket.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
HttpServerRunStatus http_server_setup(HttpServer *s) {
|
||||||
|
int opt = 1;
|
||||||
|
|
||||||
|
if ((s->server_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
|
||||||
|
return HTTP_SRS_SOCKET_FAILED;
|
||||||
|
|
||||||
|
if (setsockopt(s->server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)))
|
||||||
|
return HTTP_SRS_SETSOCKOPT_FAILED;
|
||||||
|
|
||||||
|
if (s->address == NULL) {
|
||||||
|
printf("Setting server address\n");
|
||||||
|
s->address = malloc(sizeof(*s->address));
|
||||||
|
s->address->sin_family = AF_INET;
|
||||||
|
s->address->sin_addr.s_addr = INADDR_ANY;
|
||||||
|
s->address->sin_port = htons(s->port);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bind(s->server_fd, (struct sockaddr *)s->address, sizeof(*s->address)) <
|
||||||
|
0)
|
||||||
|
return HTTP_SRS_BIND_FAILED;
|
||||||
|
|
||||||
|
if (listen(s->server_fd, s->workers) < 0)
|
||||||
|
return HTTP_SRS_LISTEN_FAILED;
|
||||||
|
|
||||||
|
return HTTP_SRS_SETUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpServerRunStatus http_server_run(HttpServer *s) {
|
||||||
|
int client_fd;
|
||||||
|
ssize_t valread;
|
||||||
|
|
||||||
|
socklen_t addrlen = sizeof(*s->address);
|
||||||
|
|
||||||
|
if ((client_fd =
|
||||||
|
accept(s->server_fd, (struct sockaddr *)s->address, &addrlen)) < 0)
|
||||||
|
return HTTP_SRS_ACCEPT_FAILED;
|
||||||
|
|
||||||
|
char request[BUFSIZ] = {0};
|
||||||
|
|
||||||
|
if ((valread = read(client_fd, request, 1024 - 1)) < 0)
|
||||||
|
return HTTP_SRS_READ_FAILED;
|
||||||
|
|
||||||
|
HttpRequest *req = handle_request(request);
|
||||||
|
if (req == NULL)
|
||||||
|
return HTTP_SRS_HANDLE_REQUEST_FAILED;
|
||||||
|
|
||||||
|
HttpResponse *res;
|
||||||
|
|
||||||
|
if (!strcmp(req->path, "/")) {
|
||||||
|
res = from_file("./" DEFAULT_HTML);
|
||||||
|
} else {
|
||||||
|
char path[] = ".";
|
||||||
|
strcat(path, req->path);
|
||||||
|
res = from_file(path);
|
||||||
|
}
|
||||||
|
// print_request(req);
|
||||||
|
// free_request(req);
|
||||||
|
if (res == NULL) {
|
||||||
|
HttpResponse __res = {
|
||||||
|
.status_code = HTTP_NOT_FOUND,
|
||||||
|
.body = "",
|
||||||
|
.content_type = HTTP_CT_PLAIN_TEXT,
|
||||||
|
.content_length = 1,
|
||||||
|
.body_in_heap = false,
|
||||||
|
};
|
||||||
|
res = malloc(sizeof(__res));
|
||||||
|
*res = __res;
|
||||||
|
}
|
||||||
|
|
||||||
|
http_respond(res, client_fd);
|
||||||
|
free_response(res);
|
||||||
|
close(client_fd);
|
||||||
|
|
||||||
|
return HTTP_SRS_RUNNING;
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpServerRunStatus http_server_stop(HttpServer *s) {
|
||||||
|
|
||||||
|
close(s->server_fd);
|
||||||
|
|
||||||
|
if (s->address != NULL)
|
||||||
|
free(s->address);
|
||||||
|
|
||||||
|
return HTTP_SRS_STOPPED;
|
||||||
|
}
|
||||||
35
http/http_server.h
Normal file
35
http/http_server.h
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
#ifndef HTTP_SERVER_H
|
||||||
|
#define HTTP_SERVER_H
|
||||||
|
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
|
||||||
|
#ifndef DEFAULT_HTML
|
||||||
|
#define DEFAULT_HTML "index.html"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
HTTP_SRS_RUNNING = 0,
|
||||||
|
HTTP_SRS_SETUP,
|
||||||
|
HTTP_SRS_STOPPED,
|
||||||
|
HTTP_SRS_SOCKET_FAILED,
|
||||||
|
HTTP_SRS_SETSOCKOPT_FAILED,
|
||||||
|
HTTP_SRS_BIND_FAILED,
|
||||||
|
HTTP_SRS_LISTEN_FAILED,
|
||||||
|
HTTP_SRS_ACCEPT_FAILED,
|
||||||
|
HTTP_SRS_READ_FAILED,
|
||||||
|
HTTP_SRS_HANDLE_REQUEST_FAILED,
|
||||||
|
} HttpServerRunStatus;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int port;
|
||||||
|
int server_fd;
|
||||||
|
unsigned int workers;
|
||||||
|
struct sockaddr_in *address;
|
||||||
|
} HttpServer;
|
||||||
|
|
||||||
|
HttpServerRunStatus http_server_setup(HttpServer *s);
|
||||||
|
HttpServerRunStatus http_server_run(HttpServer *s);
|
||||||
|
HttpServerRunStatus http_server_stop(HttpServer *s);
|
||||||
|
|
||||||
|
#endif
|
||||||
68
main.c
68
main.c
@@ -1,73 +1,23 @@
|
|||||||
#include "http/http_request.h"
|
#include "http/http_server.h"
|
||||||
#include "http/http_response.h"
|
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#define DEFAULT_HTML "index.html"
|
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
|
HttpServer server = {.port = 8080, .workers = 3};
|
||||||
|
if (http_server_setup(&server) != HTTP_SRS_SETUP)
|
||||||
|
exit(1);
|
||||||
|
|
||||||
const int PORT = 8080;
|
HttpServerRunStatus status;
|
||||||
|
|
||||||
int serverfd, clientfd;
|
while ((status = http_server_run(&server)) == HTTP_SRS_RUNNING)
|
||||||
ssize_t valread;
|
;
|
||||||
|
|
||||||
struct sockaddr_in address;
|
printf("Status: %d\n", status);
|
||||||
int opt = 1;
|
|
||||||
socklen_t addrlen = sizeof(address);
|
|
||||||
char request[BUFSIZ] = {0};
|
|
||||||
|
|
||||||
if ((serverfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
http_server_stop(&server);
|
||||||
perror("socket failed");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Forcefully attaching socket to the port 8080
|
|
||||||
if (setsockopt(serverfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) {
|
|
||||||
perror("setsockopt");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
address.sin_family = AF_INET;
|
|
||||||
address.sin_addr.s_addr = INADDR_ANY;
|
|
||||||
address.sin_port = htons(PORT);
|
|
||||||
|
|
||||||
if (bind(serverfd, (struct sockaddr *)&address, sizeof(address)) < 0) {
|
|
||||||
perror("bind failed");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
if (listen(serverfd, 3) < 0) {
|
|
||||||
perror("listen");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
if ((clientfd = accept(serverfd, (struct sockaddr *)&address, &addrlen)) <
|
|
||||||
0) {
|
|
||||||
perror("accept");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
valread = read(clientfd, request,
|
|
||||||
1024 - 1); // subtract 1 for the null
|
|
||||||
// terminator at the end
|
|
||||||
HttpRequest *req = handle_request(request);
|
|
||||||
HttpResponse *res;
|
|
||||||
if (!strcmp(req->path, "/")) {
|
|
||||||
res = from_file("./" DEFAULT_HTML);
|
|
||||||
} else {
|
|
||||||
char path[] = ".";
|
|
||||||
strcat(path, req->path);
|
|
||||||
res = from_file(path);
|
|
||||||
}
|
|
||||||
free(req);
|
|
||||||
http_respond(*res, clientfd);
|
|
||||||
free_response(res);
|
|
||||||
|
|
||||||
// closing the connected socket
|
|
||||||
close(clientfd);
|
|
||||||
// closing the listening socket
|
|
||||||
close(clientfd);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,11 @@ kind "StaticLib"
|
|||||||
language "C"
|
language "C"
|
||||||
targetdir "bin/%{cfg.buildcfg}"
|
targetdir "bin/%{cfg.buildcfg}"
|
||||||
|
|
||||||
|
filter "configurations:Debug"
|
||||||
|
symbols "On"
|
||||||
|
buildoptions { "-g3", "-O0", "-fno-inline" } -- Ensure debug symbols are generated for static library
|
||||||
|
optimize "Off"
|
||||||
|
|
||||||
files {
|
files {
|
||||||
"http/*.c",
|
"http/*.c",
|
||||||
"http/*.h"
|
"http/*.h"
|
||||||
|
|||||||
Reference in New Issue
Block a user