mirror of
https://github.com/sigmasternchen/CFloor
synced 2025-03-15 04:18:55 +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
|
||||
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)
|
||||
|
|
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 "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;
|
||||
|
|
|
@ -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
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);
|
||||
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);
|
||||
|
||||
int strlenOfNumber(long long number);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -625,7 +625,7 @@ void* listenThread(void* _bind) {
|
|||
}
|
||||
}
|
||||
|
||||
void initNetworking(struct networkingConfig _networkingConfig) {
|
||||
void networking_init(struct networkingConfig _networkingConfig) {
|
||||
networkingConfig = _networkingConfig;
|
||||
|
||||
connectionList = linked_create();
|
||||
|
|
|
@ -84,6 +84,6 @@ struct networkingConfig {
|
|||
|
||||
#define TIMING_CLOCK CLOCK_REALTIME
|
||||
|
||||
void initNetworking(struct networkingConfig networkingConfig);
|
||||
void networking_init(struct networkingConfig networkingConfig);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue