file handler done; dir handler next

This commit is contained in:
overflowerror 2019-03-06 16:55:41 +01:00
parent bb3719ef58
commit c9526fd23e
13 changed files with 355 additions and 7 deletions

View file

@ -1,11 +1,11 @@
CC = gcc
CFLAGS = -std=c99 -Wall -D_POSIX_C_SOURCE=201112L
CFLAGS = -std=c99 -Wall -D_POSIX_C_SOURCE=201112L -D_XOPEN_SOURCE=500 -D_GNU_SOURCE
LD = gcc
LDFLAGS = -lpthread -lrt
BIN_NAME = cfloor
OBJS = obj/networking.o obj/linked.o obj/logging.o obj/signals.o obj/headers.o obj/misc.o obj/status.o
OBJS = obj/networking.o obj/linked.o obj/logging.o obj/signals.o obj/headers.o obj/misc.o obj/status.o obj/files.o obj/mime.o
DEPS = $(OBJS:%.o=%.d)
all: $(BIN_NAME)

View file

@ -0,0 +1,169 @@
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdbool.h>
#include <limits.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include "files.h"
#include "misc.h"
#include "logging.h"
#include "status.h"
#include "mime.h"
const char* documentRoot = NULL;
bool indexes = false;
void files_init(const char* _documentRoot, bool _index) {
documentRoot = _documentRoot;
indexes = _index;
}
void showIndex(int fd, const char* path) {
FILE* stream = fdopen(fd, "w");
if (stream == NULL) {
error("status: Couldn't get stream from fd: %s", strerror(errno));
return;
}
// TODO index
fclose(stream);
}
void fuckyouHandler(struct request request, struct response response) {
struct headers headers = headers_create();
headers_mod(&headers, "Content-Type", "text/plain");
int fd = response.sendHeader(400, &headers, &request);
headers_free(&headers);
FILE* stream = fdopen(fd, "w");
if (stream == NULL) {
error("files: Couldn't get stream from fd: %s", strerror(errno));
return;
}
fprintf(stream, "Status 400\nYou know... I'm not an idiot...\n");
fclose(stream);
}
void fileHandler(struct request request, struct response response) {
if (documentRoot == NULL) {
error("files: No document root given.");
status(request, response, 500);
return;
}
char* path = request.metaData.path;
char* tmp = malloc(strlen(path) + 1 + strlen(documentRoot) + 1);
if (tmp == NULL) {
error("files: Couldn't malloc for path construction: %s", strerror(errno));
status(request, response, 500);
return;
}
strcpy(tmp, documentRoot);
strcat(tmp, "/");
strcat(tmp, path);
path = realpath(tmp, NULL);
if (path == NULL) {
free(tmp);
error("files: Couldn't get constructed realpath: %s", strerror(errno));
status(request, response, 500);
return;
}
free(tmp);
info("files: file path is: %s", path);
if (strncmp(documentRoot, path, strlen(documentRoot)) != 0) {
free(path);
warn("files: Requested path not in document root.");
fuckyouHandler(request, response);
return;
}
if (access(path, F_OK | R_OK) < 0) {
free(path);
switch(errno) {
case EACCES:
status(request, response, 403);
return;
case ENOENT:
case ENOTDIR:
status(request, response, 404);
return;
default:
warn("files: Couldn't access file: %s", strerror(errno));
status(request, response, 500);
return;
}
}
struct stat statObj;
if (stat(path, &statObj) < 0) {
free(path);
error("files: Couldn't stat file: %s", strerror(errno));
status(request, response, 500);
return;
}
if (S_ISDIR(statObj.st_mode)) {
struct headers headers = headers_create();
headers_mod(&headers, "Content-Type", "text/html; charset=utf-8");
int fd = response.sendHeader(200, &headers, &request);
headers_free(&headers);
// if indexes
showIndex(fd, path);
} else if (S_ISREG(statObj.st_mode)) {
int filefd = open(path, O_RDONLY);
if (filefd < 0) {
free(path);
status(request, response, 500);
return;
}
off_t size = statObj.st_size;
int length = strlenOfNumber(size);
tmp = malloc(length + 1);
if (tmp == NULL) {
free(path);
close(filefd);
error("files: Couldn't allocate for content length: %s", strerror(errno));
status(request, response, 500);
return;
}
snprintf(tmp, length + 1, "%ld", size);
struct headers headers = headers_create();
headers_mod(&headers, "Content-Type", getMineFromFileName(path));
headers_mod(&headers, "Content-Length", tmp);
free(tmp);
int sockfd = response.sendHeader(200, &headers, &request);
headers_free(&headers);
char c;
while(read(filefd, &c, 1))
write(sockfd, &c, 1);
close(filefd);
close(sockfd);
} else {
status(request, response, 500);
}
free(path);
}

View file

@ -0,0 +1,13 @@
#ifndef FILES_H
#define FILES_H
#include <stdbool.h>
#include "files.h"
#include "misc.h"
void files_init(const char* documentRoot, bool index);
void fileHandler(struct request request, struct response response);
#endif

View file

@ -3,6 +3,7 @@
#include "headers.h"
#include "misc.h"
#include "logging.h"
struct headers headers_create() {
return (struct headers) {
@ -35,6 +36,8 @@ int headers_mod(struct headers* headers, const char* _key, const char* _value) {
if (tmp == NULL) {
return HEADERS_ALLOC_ERROR;
}
char* value = tmp;
int index = headers_find(headers, key);
@ -202,11 +205,13 @@ int headers_metadata(struct metaData* metaData, char* header) {
if (path == NULL) {
return HEADERS_ALLOC_ERROR;
}
strcpy(path, _path);
char* queryString = malloc(strlen(_queryString) + 1);
if (queryString == NULL) {
free(path);
return HEADERS_ALLOC_ERROR;
}
strcpy(queryString, _queryString);
metaData->method = method;
metaData->httpVersion = httpVersion;

View file

@ -5,15 +5,19 @@
#include "networking.h"
#include "logging.h"
#include "headers.h"
#include "files.h"
handler_t handlerGetter(struct metaData metaData, const char* host, struct bind* bind) {
return NULL;
return &fileHandler;
}
int main(int argc, char** argv) {
setLogging(stderr, DEBUG, true);
setCriticalHandler(NULL);
char* documentRoot = realpath(".", NULL);
files_init(documentRoot, true);
struct headers headers = headers_create();
headers_mod(&headers, "Server", "CFloor 0.1");
@ -33,11 +37,12 @@ int main(int argc, char** argv) {
.getHandler = &handlerGetter
};
initNetworking(config);
networking_init(config);
while(true) {
sleep(0xffff);
}
headers_free(&headers);
free(documentRoot);
}

135
src/mime.c Normal file
View file

@ -0,0 +1,135 @@
#include <string.h>
#include <stdio.h>
#include "mime.h"
struct mime {
const char* mime;
int number;
const char** extensions;
} mimelist[] = {
{
.mime = "application/pdf",
.number = 1,
.extensions = (const char* []) {
"pdf"
}
},{
.mime = "text/css",
.number = 1,
.extensions = (const char* []) {
"css"
}
},{
.mime = "application/html",
.number = 2,
.extensions = (const char* []) {
"html",
"htm"
}
},{
.mime = "application/javascript",
.number = 1,
.extensions = (const char* []) {
"js"
}
},{
.mime = "application/json",
.number = 1,
.extensions = (const char* []) {
"json"
}
},{
.mime = "application/xml",
.number = 1,
.extensions = (const char* []) {
"xml"
}
},{
.mime = "image/jpeg",
.number = 2,
.extensions = (const char* []) {
"jpg",
"jpeg"
}
},{
.mime = "image/gif",
.number = 1,
.extensions = (const char* []) {
"gif"
}
},{
.mime = "image/x-icon",
.number = 1,
.extensions = (const char* []) {
"ico"
}
},{
.mime = "image/png",
.number = 1,
.extensions = (const char* []) {
"png"
}
},{
.mime = "image/svg+xml",
.number = 1,
.extensions = (const char* []) {
"svg"
}
},{
.mime = "audio/mpeg",
.number = 1,
.extensions = (const char* []) {
"mpga"
}
},{
.mime = "video/mpeg",
.number = 1,
.extensions = (const char* []) {
"mpeg"
}
},{
.mime = "audio/mp4",
.number = 4,
.extensions = (const char* []) {
"mp4a",
"m4a"
}
},{
.mime = "video/mp4",
.number = 1,
.extensions = (const char* []) {
"mp4"
}
},{
.mime = "video/webm",
.number = 1,
.extensions = (const char* []) {
"webm"
}
},
};
const char* unknownMime = "application/octet-stream";
const char* getMineFromFileName(const char* filename) {
const char* extension = NULL;
const char* tmp = filename;
while ((tmp = strcasestr(tmp, ".")) != NULL) {
tmp += 1;
extension = tmp;
}
if (extension == NULL)
return unknownMime;
for (int i = 0; i < (sizeof(mimelist) / sizeof(mimelist[0])); i++) {
for(int j = 0; j < mimelist[i].number; j++) {
if (strcmp(extension, mimelist[i].extensions[j]) == 0)
return mimelist[i].mime;
}
}
return unknownMime;
}

6
src/mime.h Normal file
View file

@ -0,0 +1,6 @@
#ifndef MINE_H
#define MINE_H
const char* getMineFromFileName(const char* filename);
#endif

View file

@ -54,3 +54,14 @@ char* strclone(const char* string) {
strcpy(result, string);
return result;
}
int strlenOfNumber(long long number) {
int result = 1;
while(number > 9) {
number /= 10;
result++;
}
return result;
}

View file

@ -58,4 +58,6 @@ void* fileCopyThread(void* data);
char* strclone(const char* string);
int strlenOfNumber(long long number);
#endif

View file

@ -625,7 +625,7 @@ void* listenThread(void* _bind) {
}
}
void initNetworking(struct networkingConfig _networkingConfig) {
void networking_init(struct networkingConfig _networkingConfig) {
networkingConfig = _networkingConfig;
connectionList = linked_create();

View file

@ -84,6 +84,6 @@ struct networkingConfig {
#define TIMING_CLOCK CLOCK_REALTIME
void initNetworking(struct networkingConfig networkingConfig);
void networking_init(struct networkingConfig networkingConfig);
#endif

View file

@ -334,6 +334,7 @@ struct statusStrings getStatusStrings(int status) {
void status(struct request request, struct response response, int status) {
struct headers headers = headers_create();
headers_mod(&headers, "Content-Type", "text/html; charset=utf-8");
int fd = response.sendHeader(status, &headers, &request);
headers_free(&headers);
@ -355,7 +356,7 @@ void status(struct request request, struct response response, int status) {
fprintf(stream, string.statusFormat, request.metaData.path);
fprintf(stream, " <hr />\n");
fprintf(stream, " </body>\n");
fprintf(stream, "<!DOCTYPE html>\n");
fprintf(stream, "</html>\n");
fclose(stream);
}

View file

@ -11,5 +11,6 @@ struct statusStrings {
struct statusStrings getStatusStrings(int status);
void status500(struct request request, struct response response);
void status(struct request request, struct response response, int status);
#endif