mirror of
https://github.com/sigmasternchen/CFloor
synced 2025-03-15 20:28:56 +00:00
file handler done; dir handler next
This commit is contained in:
parent
bb3719ef58
commit
c9526fd23e
13 changed files with 355 additions and 7 deletions
4
Makefile
4
Makefile
|
@ -1,11 +1,11 @@
|
||||||
CC = gcc
|
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
|
LD = gcc
|
||||||
LDFLAGS = -lpthread -lrt
|
LDFLAGS = -lpthread -lrt
|
||||||
|
|
||||||
BIN_NAME = cfloor
|
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)
|
DEPS = $(OBJS:%.o=%.d)
|
||||||
|
|
||||||
all: $(BIN_NAME)
|
all: $(BIN_NAME)
|
||||||
|
|
169
src/files.c
169
src/files.c
|
@ -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);
|
||||||
|
}
|
13
src/files.h
13
src/files.h
|
@ -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
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include "headers.h"
|
#include "headers.h"
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
|
#include "logging.h"
|
||||||
|
|
||||||
struct headers headers_create() {
|
struct headers headers_create() {
|
||||||
return (struct headers) {
|
return (struct headers) {
|
||||||
|
@ -35,6 +36,8 @@ int headers_mod(struct headers* headers, const char* _key, const char* _value) {
|
||||||
if (tmp == NULL) {
|
if (tmp == NULL) {
|
||||||
return HEADERS_ALLOC_ERROR;
|
return HEADERS_ALLOC_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
char* value = tmp;
|
char* value = tmp;
|
||||||
|
|
||||||
int index = headers_find(headers, key);
|
int index = headers_find(headers, key);
|
||||||
|
@ -202,11 +205,13 @@ int headers_metadata(struct metaData* metaData, char* header) {
|
||||||
if (path == NULL) {
|
if (path == NULL) {
|
||||||
return HEADERS_ALLOC_ERROR;
|
return HEADERS_ALLOC_ERROR;
|
||||||
}
|
}
|
||||||
|
strcpy(path, _path);
|
||||||
char* queryString = malloc(strlen(_queryString) + 1);
|
char* queryString = malloc(strlen(_queryString) + 1);
|
||||||
if (queryString == NULL) {
|
if (queryString == NULL) {
|
||||||
free(path);
|
free(path);
|
||||||
return HEADERS_ALLOC_ERROR;
|
return HEADERS_ALLOC_ERROR;
|
||||||
}
|
}
|
||||||
|
strcpy(queryString, _queryString);
|
||||||
|
|
||||||
metaData->method = method;
|
metaData->method = method;
|
||||||
metaData->httpVersion = httpVersion;
|
metaData->httpVersion = httpVersion;
|
||||||
|
|
|
@ -5,15 +5,19 @@
|
||||||
#include "networking.h"
|
#include "networking.h"
|
||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
#include "headers.h"
|
#include "headers.h"
|
||||||
|
#include "files.h"
|
||||||
|
|
||||||
handler_t handlerGetter(struct metaData metaData, const char* host, struct bind* bind) {
|
handler_t handlerGetter(struct metaData metaData, const char* host, struct bind* bind) {
|
||||||
return NULL;
|
return &fileHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
setLogging(stderr, DEBUG, true);
|
setLogging(stderr, DEBUG, true);
|
||||||
setCriticalHandler(NULL);
|
setCriticalHandler(NULL);
|
||||||
|
|
||||||
|
char* documentRoot = realpath(".", NULL);
|
||||||
|
files_init(documentRoot, true);
|
||||||
|
|
||||||
struct headers headers = headers_create();
|
struct headers headers = headers_create();
|
||||||
headers_mod(&headers, "Server", "CFloor 0.1");
|
headers_mod(&headers, "Server", "CFloor 0.1");
|
||||||
|
|
||||||
|
@ -33,11 +37,12 @@ int main(int argc, char** argv) {
|
||||||
.getHandler = &handlerGetter
|
.getHandler = &handlerGetter
|
||||||
};
|
};
|
||||||
|
|
||||||
initNetworking(config);
|
networking_init(config);
|
||||||
|
|
||||||
while(true) {
|
while(true) {
|
||||||
sleep(0xffff);
|
sleep(0xffff);
|
||||||
}
|
}
|
||||||
|
|
||||||
headers_free(&headers);
|
headers_free(&headers);
|
||||||
|
free(documentRoot);
|
||||||
}
|
}
|
||||||
|
|
135
src/mime.c
Normal file
135
src/mime.c
Normal 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
6
src/mime.h
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#ifndef MINE_H
|
||||||
|
#define MINE_H
|
||||||
|
|
||||||
|
const char* getMineFromFileName(const char* filename);
|
||||||
|
|
||||||
|
#endif
|
11
src/misc.c
11
src/misc.c
|
@ -54,3 +54,14 @@ char* strclone(const char* string) {
|
||||||
strcpy(result, string);
|
strcpy(result, string);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int strlenOfNumber(long long number) {
|
||||||
|
int result = 1;
|
||||||
|
|
||||||
|
while(number > 9) {
|
||||||
|
number /= 10;
|
||||||
|
result++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
|
@ -58,4 +58,6 @@ void* fileCopyThread(void* data);
|
||||||
|
|
||||||
char* strclone(const char* string);
|
char* strclone(const char* string);
|
||||||
|
|
||||||
|
int strlenOfNumber(long long number);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -625,7 +625,7 @@ void* listenThread(void* _bind) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void initNetworking(struct networkingConfig _networkingConfig) {
|
void networking_init(struct networkingConfig _networkingConfig) {
|
||||||
networkingConfig = _networkingConfig;
|
networkingConfig = _networkingConfig;
|
||||||
|
|
||||||
connectionList = linked_create();
|
connectionList = linked_create();
|
||||||
|
|
|
@ -84,6 +84,6 @@ struct networkingConfig {
|
||||||
|
|
||||||
#define TIMING_CLOCK CLOCK_REALTIME
|
#define TIMING_CLOCK CLOCK_REALTIME
|
||||||
|
|
||||||
void initNetworking(struct networkingConfig networkingConfig);
|
void networking_init(struct networkingConfig networkingConfig);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -334,6 +334,7 @@ struct statusStrings getStatusStrings(int status) {
|
||||||
|
|
||||||
void status(struct request request, struct response response, int status) {
|
void status(struct request request, struct response response, int status) {
|
||||||
struct headers headers = headers_create();
|
struct headers headers = headers_create();
|
||||||
|
headers_mod(&headers, "Content-Type", "text/html; charset=utf-8");
|
||||||
int fd = response.sendHeader(status, &headers, &request);
|
int fd = response.sendHeader(status, &headers, &request);
|
||||||
headers_free(&headers);
|
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, string.statusFormat, request.metaData.path);
|
||||||
fprintf(stream, " <hr />\n");
|
fprintf(stream, " <hr />\n");
|
||||||
fprintf(stream, " </body>\n");
|
fprintf(stream, " </body>\n");
|
||||||
fprintf(stream, "<!DOCTYPE html>\n");
|
fprintf(stream, "</html>\n");
|
||||||
|
|
||||||
fclose(stream);
|
fclose(stream);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,5 +11,6 @@ struct statusStrings {
|
||||||
struct statusStrings getStatusStrings(int status);
|
struct statusStrings getStatusStrings(int status);
|
||||||
|
|
||||||
void status500(struct request request, struct response response);
|
void status500(struct request request, struct response response);
|
||||||
|
void status(struct request request, struct response response, int status);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue