finished static files hosting. Added mime type definition and file sending functions. Finished send_response and changed header compose function. Some small fixes
This commit is contained in:
parent
cb9ba8e950
commit
457a52a585
@ -1,2 +1,10 @@
|
|||||||
|
struct file_s
|
||||||
|
{
|
||||||
|
char *path;
|
||||||
|
off_t size;
|
||||||
|
int fd;
|
||||||
|
};
|
||||||
|
|
||||||
char *gen_file_path(char *path);
|
char *gen_file_path(char *path);
|
||||||
int send_file(int fd, char *path);
|
int send_file(int cli_fd, struct file_s *file);
|
||||||
|
struct file_s *get_file_info(char *file_path);
|
1
include/mime.h
Normal file
1
include/mime.h
Normal file
@ -0,0 +1 @@
|
|||||||
|
char *get_mime_type(char *file_path);
|
@ -1 +0,0 @@
|
|||||||
char *get_mine_type(char *file_path);
|
|
@ -1,5 +1,10 @@
|
|||||||
|
struct header_s {
|
||||||
|
char * str;
|
||||||
|
size_t size;
|
||||||
|
};
|
||||||
|
|
||||||
char *get_path(char *request);
|
char *get_path(char *request);
|
||||||
void gen_header(int status_code, size_t file_size, char *mine_type);
|
struct header_s *gen_header(int status_code, size_t file_size, char *mime_type);
|
||||||
int send_response(int fd, char *path);
|
int send_response(int fd, char *req_path);
|
||||||
void handle_post_request(int fd, char *request);
|
void handle_post_request(int fd, char *request);
|
||||||
void handle_get_request(int fd, char *request);
|
void handle_get_request(int fd, char *request);
|
@ -1,2 +1,4 @@
|
|||||||
void err_msg(char *msg);
|
void err_msg(char *msg);
|
||||||
char *add_to_front(char **str1, char *str2);
|
char *add_to_front(char **str1, char *str2);
|
||||||
|
char *get_status_message(int status_code);
|
||||||
|
char *to_lower(char *str);
|
61
src/file.c
61
src/file.c
@ -1,9 +1,19 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <sys/sendfile.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "../include/file.h"
|
#include "../include/file.h"
|
||||||
#include "../include/utils.h"
|
#include "../include/utils.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Generate file path from request path provided
|
||||||
|
*
|
||||||
|
* @param req_path
|
||||||
|
* @return char*
|
||||||
|
*/
|
||||||
char *gen_file_path(char *req_path)
|
char *gen_file_path(char *req_path)
|
||||||
{
|
{
|
||||||
char *path = (char *)malloc(sizeof req_path);
|
char *path = (char *)malloc(sizeof req_path);
|
||||||
@ -19,7 +29,7 @@ char *gen_file_path(char *req_path)
|
|||||||
path = strcat(path, "index.html");
|
path = strcat(path, "index.html");
|
||||||
}
|
}
|
||||||
|
|
||||||
char *webroot = "../static";
|
char *webroot = "static";
|
||||||
|
|
||||||
path = realloc(path, sizeof path + sizeof webroot);
|
path = realloc(path, sizeof path + sizeof webroot);
|
||||||
path = add_to_front(&path, webroot);
|
path = add_to_front(&path, webroot);
|
||||||
@ -27,9 +37,52 @@ char *gen_file_path(char *req_path)
|
|||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
int send_file(int fd, char *req_path)
|
/**
|
||||||
|
* @brief Send file to client
|
||||||
|
*
|
||||||
|
* @param fd
|
||||||
|
* @param file_path
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
int send_file(int cli_fd, struct file_s *file)
|
||||||
{
|
{
|
||||||
char *path = gen_file_path(req_path);
|
off_t offset = 0;
|
||||||
|
if (sendfile(cli_fd, file->fd, &offset, file->size+2) < 0)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(file->fd);
|
||||||
|
free(file);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the file info
|
||||||
|
*
|
||||||
|
* @param file_path
|
||||||
|
* @return struct file_s*
|
||||||
|
*/
|
||||||
|
struct file_s *get_file_info(char *file_path)
|
||||||
|
{
|
||||||
|
struct file_s *file = (struct file_s *)malloc(sizeof(struct file_s));
|
||||||
|
|
||||||
|
if (file == NULL)
|
||||||
|
{
|
||||||
|
err_msg("couldn't create file structure");
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct stat stat_buf;
|
||||||
|
|
||||||
|
file->fd = open(file_path, O_RDONLY);
|
||||||
|
if (file->fd < 0)
|
||||||
|
{
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
fstat(file->fd, &stat_buf);
|
||||||
|
file->size = stat_buf.st_size;
|
||||||
|
|
||||||
|
return file;
|
||||||
}
|
}
|
65
src/mime.c
Normal file
65
src/mime.c
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "../include/mime.h"
|
||||||
|
#include "../include/utils.h"
|
||||||
|
|
||||||
|
#define DEFAULT_mime_TYPE "application/octet-stream"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the mime type of file
|
||||||
|
*
|
||||||
|
* @param file_path
|
||||||
|
* @return char*
|
||||||
|
*/
|
||||||
|
char *get_mime_type(char *file_path)
|
||||||
|
{
|
||||||
|
char *ext = strchr(file_path, '.');
|
||||||
|
|
||||||
|
if (ext == NULL)
|
||||||
|
{
|
||||||
|
return DEFAULT_mime_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ext++;
|
||||||
|
|
||||||
|
ext = to_lower(ext);
|
||||||
|
|
||||||
|
if (strcmp(ext, "html") == 0 || strcmp(ext, "htm") == 0)
|
||||||
|
{
|
||||||
|
return "text/html";
|
||||||
|
}
|
||||||
|
if (strcmp(ext, "jpeg") == 0 || strcmp(ext, "jpg") == 0)
|
||||||
|
{
|
||||||
|
return "image/jpg";
|
||||||
|
}
|
||||||
|
if (strcmp(ext, "css") == 0)
|
||||||
|
{
|
||||||
|
return "text/css";
|
||||||
|
}
|
||||||
|
if (strcmp(ext, "js") == 0)
|
||||||
|
{
|
||||||
|
return "application/javascript";
|
||||||
|
}
|
||||||
|
if (strcmp(ext, "json") == 0)
|
||||||
|
{
|
||||||
|
return "application/json";
|
||||||
|
}
|
||||||
|
if (strcmp(ext, "txt") == 0)
|
||||||
|
{
|
||||||
|
return "text/plain";
|
||||||
|
}
|
||||||
|
if (strcmp(ext, "gif") == 0)
|
||||||
|
{
|
||||||
|
return "image/gif";
|
||||||
|
}
|
||||||
|
if (strcmp(ext, "png") == 0)
|
||||||
|
{
|
||||||
|
return "image/png";
|
||||||
|
}
|
||||||
|
if (strcmp(ext, "ico") == 0)
|
||||||
|
{
|
||||||
|
return "image/x-icon";
|
||||||
|
}
|
||||||
|
|
||||||
|
return DEFAULT_mime_TYPE;
|
||||||
|
}
|
@ -1,5 +0,0 @@
|
|||||||
#include "../include/mine.h"
|
|
||||||
|
|
||||||
char *get_mine_type(char *file_path) {
|
|
||||||
|
|
||||||
}
|
|
120
src/request.c
120
src/request.c
@ -3,46 +3,15 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <sys/sendfile.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
|
||||||
#include "../include/request.h"
|
#include "../include/request.h"
|
||||||
#include "../include/utils.h"
|
#include "../include/utils.h"
|
||||||
|
#include "../include/file.h"
|
||||||
/**
|
#include "../include/mime.h"
|
||||||
* @brief Get the status message object
|
|
||||||
*
|
|
||||||
* @param status_code
|
|
||||||
* @return char*
|
|
||||||
*/
|
|
||||||
char *get_status_message(int status_code)
|
|
||||||
{
|
|
||||||
switch (status_code)
|
|
||||||
{
|
|
||||||
case 200:
|
|
||||||
return "OK";
|
|
||||||
case 400:
|
|
||||||
return "Internal Server Error";
|
|
||||||
case 401:
|
|
||||||
return "Unauthorized";
|
|
||||||
case 403:
|
|
||||||
return "Forbidden";
|
|
||||||
case 404:
|
|
||||||
return "NOT FOUND";
|
|
||||||
case 500:
|
|
||||||
return "Internal Server Error";
|
|
||||||
case 501:
|
|
||||||
return "Not Implemented";
|
|
||||||
case 502:
|
|
||||||
return "Bad Gateway";
|
|
||||||
default:
|
|
||||||
return "None";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the path object
|
* @brief Get the path object
|
||||||
@ -63,10 +32,10 @@ char *get_path(char *request)
|
|||||||
*
|
*
|
||||||
* @param status_code
|
* @param status_code
|
||||||
* @param file_size
|
* @param file_size
|
||||||
* @param mine_type
|
* @param mime_type
|
||||||
* @return char*
|
* @return char*
|
||||||
*/
|
*/
|
||||||
char *gen_header(int status_code, size_t file_size, char *mine_type)
|
struct header_s *gen_header(int status_code, size_t file_size, char *mime_type)
|
||||||
{
|
{
|
||||||
char *status_message = get_status_message(status_code);
|
char *status_message = get_status_message(status_code);
|
||||||
|
|
||||||
@ -74,34 +43,78 @@ char *gen_header(int status_code, size_t file_size, char *mine_type)
|
|||||||
struct tm *ptm = gmtime(&now);
|
struct tm *ptm = gmtime(&now);
|
||||||
char *curr_date = asctime(ptm);
|
char *curr_date = asctime(ptm);
|
||||||
|
|
||||||
int header_length = snprintf(NULL, 0, "HTTP/1.1 %d %s\nDate: %s\nConnection: close\nContent-Length: %d\nContent-Type: %s\n\n", status_code, status_message, curr_date, file_size, mine_type);
|
int header_length = snprintf(NULL, 0, "HTTP/1.1 %d %s\nDate: %sConnection: close\nContent-Length: %ld\nContent-Type: %s\r\n\r\n", status_code, status_message, curr_date, file_size, mime_type) + 1;
|
||||||
char *header = (char *)malloc(header_length + 1);
|
char *header_string = (char *)malloc(header_length);
|
||||||
snprintf(header, header_length + 1, "HTTP/1.1 %d %s\nDate: %s\nConnection: close\nContent-Length: %d\nContent-Type: %s\n\n", status_code, status_message, curr_date, file_size, mine_type);
|
snprintf(header_string, header_length, "HTTP/1.1 %d %s\nDate: %sConnection: close\nContent-Length: %ld\nContent-Type: %s\r\n\r\n", status_code, status_message, curr_date, file_size, mime_type);
|
||||||
printf("%s\n", header);
|
|
||||||
|
struct header_s *header = (struct header_s *)malloc(header_length + sizeof(size_t));
|
||||||
|
|
||||||
|
header->size = header_length;
|
||||||
|
header->str = header_string;
|
||||||
|
|
||||||
|
return header;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Send HTTP response
|
* @brief Send HTTP response
|
||||||
*
|
*
|
||||||
* @param fd
|
* @param fd
|
||||||
* @param file_path
|
* @param req_path
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
int send_response(int fd, char *path)
|
int send_response(int fd, char *req_path)
|
||||||
{
|
{
|
||||||
int file_fd;
|
char *file_path = gen_file_path(req_path);
|
||||||
struct stat stat_buf;
|
|
||||||
file_fd = open(file_path, O_RDONLY);
|
|
||||||
fstat(file_fd, &stat_buf);
|
|
||||||
off_t f_size = stat_buf.st_size;
|
|
||||||
off_t offset = 0;
|
|
||||||
|
|
||||||
char *mine_type;
|
struct file_s *file = get_file_info(file_path);
|
||||||
|
if (file == NULL)
|
||||||
|
{
|
||||||
|
char *msg = "Server error";
|
||||||
|
|
||||||
char *header = gen_header(200, f_size, mine_type);
|
struct header_s *header = gen_header(500, sizeof(msg), "text/plain");
|
||||||
|
send(fd, header->str, header->size - 1, 0);
|
||||||
|
|
||||||
sendfile(fd, file_fd, &offset, f_size);
|
send(fd, msg, sizeof(msg), 0);
|
||||||
close(file_fd);
|
close(fd);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (file->fd < 0)
|
||||||
|
{
|
||||||
|
char *msg = "<html>\n<body>404, Not Found. Return to home? <a href=\"/\">Home</a></body><html/>";
|
||||||
|
|
||||||
|
struct header_s *header = gen_header(404, strlen(msg), "text/html");
|
||||||
|
send(fd, header->str, header->size - 1, 0);
|
||||||
|
|
||||||
|
send(fd, msg, strlen(msg), 0);
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *mime_type = get_mime_type(file_path);
|
||||||
|
|
||||||
|
struct header_s *header = gen_header(200, file->size, mime_type);
|
||||||
|
|
||||||
|
printf("\n---\n%s\n%ld\n---\n", header->str, header->size);
|
||||||
|
|
||||||
|
int rv = send(fd, header->str, header->size - 1, 0);
|
||||||
|
|
||||||
|
if (rv < 0)
|
||||||
|
{
|
||||||
|
err_msg("couldn't send header");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (send_file(fd, file) < 0)
|
||||||
|
{
|
||||||
|
err_msg("couldn't send file");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -128,8 +141,7 @@ void handle_get_request(int fd, char *request)
|
|||||||
char *path = get_path(request);
|
char *path = get_path(request);
|
||||||
printf("Client accessed path: %s\n", path);
|
printf("Client accessed path: %s\n", path);
|
||||||
|
|
||||||
int rv = send_response(fd, path);
|
if (send_response(fd, path) < 0)
|
||||||
if (rv < 0)
|
|
||||||
{
|
{
|
||||||
err_msg("couldn't send response");
|
err_msg("couldn't send response");
|
||||||
}
|
}
|
||||||
|
10
src/server.c
10
src/server.c
@ -12,6 +12,11 @@
|
|||||||
#include "../include/utils.h"
|
#include "../include/utils.h"
|
||||||
#include "../include/request.h"
|
#include "../include/request.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handle client connection
|
||||||
|
*
|
||||||
|
* @param fd
|
||||||
|
*/
|
||||||
void handle_connection(int fd)
|
void handle_connection(int fd)
|
||||||
{
|
{
|
||||||
const size_t request_buffer_size = 512;
|
const size_t request_buffer_size = 512;
|
||||||
@ -89,9 +94,6 @@ int main(int argc, char *argv[])
|
|||||||
inet_ntop(cli_addr.ss_family, get_in_addr((struct sockaddr *)&cli_addr), s, sizeof s);
|
inet_ntop(cli_addr.ss_family, get_in_addr((struct sockaddr *)&cli_addr), s, sizeof s);
|
||||||
printf("\nGot connection from %s\n", s);
|
printf("\nGot connection from %s\n", s);
|
||||||
|
|
||||||
// | Doesn't work properly yet
|
|
||||||
// v
|
|
||||||
|
|
||||||
int pid = fork();
|
int pid = fork();
|
||||||
|
|
||||||
if (pid < 0)
|
if (pid < 0)
|
||||||
@ -100,7 +102,7 @@ int main(int argc, char *argv[])
|
|||||||
{
|
{
|
||||||
close(listenfd);
|
close(listenfd);
|
||||||
|
|
||||||
handle_connection(client_fd); // Implement
|
handle_connection(client_fd);
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
50
src/utils.c
50
src/utils.c
@ -1,4 +1,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "../include/utils.h"
|
#include "../include/utils.h"
|
||||||
|
|
||||||
@ -12,6 +15,13 @@ void err_msg(char *msg)
|
|||||||
fprintf(stderr, "Error: %s\n", msg);
|
fprintf(stderr, "Error: %s\n", msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Add str2 in front of str1
|
||||||
|
*
|
||||||
|
* @param str1
|
||||||
|
* @param str2
|
||||||
|
* @return char*
|
||||||
|
*/
|
||||||
char *add_to_front(char **str1, char *str2)
|
char *add_to_front(char **str1, char *str2)
|
||||||
{
|
{
|
||||||
char *tmp = strdup(*str1);
|
char *tmp = strdup(*str1);
|
||||||
@ -23,3 +33,43 @@ char *add_to_front(char **str1, char *str2)
|
|||||||
|
|
||||||
return *str1;
|
return *str1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the status message object
|
||||||
|
*
|
||||||
|
* @param status_code
|
||||||
|
* @return char*
|
||||||
|
*/
|
||||||
|
char *get_status_message(int status_code)
|
||||||
|
{
|
||||||
|
switch (status_code)
|
||||||
|
{
|
||||||
|
case 200:
|
||||||
|
return "OK";
|
||||||
|
case 400:
|
||||||
|
return "Internal Server Error";
|
||||||
|
case 401:
|
||||||
|
return "Unauthorized";
|
||||||
|
case 403:
|
||||||
|
return "Forbidden";
|
||||||
|
case 404:
|
||||||
|
return "NOT FOUND";
|
||||||
|
case 500:
|
||||||
|
return "Internal Server Error";
|
||||||
|
case 501:
|
||||||
|
return "Not Implemented";
|
||||||
|
case 502:
|
||||||
|
return "Bad Gateway";
|
||||||
|
default:
|
||||||
|
return "None";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char *to_lower(char *str)
|
||||||
|
{
|
||||||
|
for (char *p = str; *p != '\0'; p++)
|
||||||
|
*p = tolower(*p);
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user