request handling nearly done. There is a bug though. Will have to look into it tomorrow

This commit is contained in:
overflowerror 2019-03-05 23:32:43 +01:00
parent 553d40d1aa
commit 66c7604cd4
13 changed files with 532 additions and 55 deletions

View file

@ -5,29 +5,26 @@ 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
DEPS = $(OBJS:%.o=%.d)
all: $(BIN_NAME) all: $(BIN_NAME)
$(BIN_NAME): obj/main.o obj/networking.o obj/linked.o obj/logging.o obj/signals.o obj/headers.o obj/misc.o $(BIN_NAME): obj/main.o $(OBJS)
$(LD) $(LDFLAGS) -o $@ $^ $(LD) $(LDFLAGS) -o $@ $^
test: obj/test.o obj/networking.o obj/linked.o obj/logging.o obj/signals.o obj/headers.o obj/misc.o test: dependencies
test: obj/test.o $(OBJS)
$(LD) $(LDFLAGS) -o $@ $^ $(LD) $(LDFLAGS) -o $@ $^
valgrind: CFLAGS += -static -g valgrind: CFLAGS += -static -g
valgrind: clean test valgrind: clean test
valgrind --leak-check=yes ./test valgrind --leak-check=yes ./test
obj/main.o: src/networking.h src/linked.h src/logging.h src/signals.h src/misc.h src/headers.h -include $(DEPS)
obj/test.o: src/networking.h src/linked.h src/logging.h src/signals.h src/misc.h src/headers.h
obj/networking.o: src/networking.h src/headers.h src/linked.h src/logging.h src/signals.h
obj/linked.o: src/linked.h
obj/logging.o: src/logging.h
obj/signals.o: src/signals.h
obj/headers.o: src/headers.h src/misc.h
obj/misc.o: src/misc.h
obj/%.o: src/%.c obj obj/%.o: src/%.c
$(CC) $(CFLAGS) -c -o $@ $< $(CC) $(CFLAGS) -MMD -c -o $@ $<
obj: obj:
@mkdir -p obj @mkdir -p obj
@ -35,5 +32,6 @@ obj:
clean: clean:
@echo "Cleaning up..." @echo "Cleaning up..."
@rm -f obj/*.o @rm -f obj/*.o
@rm -f obj/*.d
@rm -f test @rm -f test
@rm -f $(BIN_NAME) @rm -f $(BIN_NAME)

View file

@ -1,7 +0,0 @@
#include "error.h"
void status500(struct request request, struct response response) {
}

View file

@ -1,8 +0,0 @@
#ifndef ERROR_H
#define ERROR_H
#include "misc.h"
handler_t status500;
#endif

View file

@ -4,6 +4,12 @@
#include "headers.h" #include "headers.h"
#include "misc.h" #include "misc.h"
struct headers headers_create() {
return (struct headers) {
.number = 0
};
}
int headers_find(struct headers* headers, const char* key) { int headers_find(struct headers* headers, const char* key) {
for (int i = 0; i < headers->number; i++) { for (int i = 0; i < headers->number; i++) {
if (strcmp(headers->headers[i].key, key) == 0) if (strcmp(headers->headers[i].key, key) == 0)
@ -19,12 +25,26 @@ const char* headers_get(struct headers* headers, const char* key) {
return headers->headers[tmp].value; return headers->headers[tmp].value;
} }
int headers_mod(struct headers* headers, char* key, char* value) { int headers_mod(struct headers* headers, const char* _key, const char* _value) {
char* tmp = strclone(_key);
if (tmp == NULL) {
return HEADERS_ALLOC_ERROR;
}
char* key = tmp;
tmp = strclone(_value);
if (tmp == NULL) {
return HEADERS_ALLOC_ERROR;
}
char* value = tmp;
int index = headers_find(headers, key); int index = headers_find(headers, key);
if (index < 0) { if (index < 0) {
struct header* tmp = realloc(headers->headers, (headers->number + 1) * sizeof(struct header)); struct header* tmp = realloc(headers->headers, (headers->number + 1) * sizeof(struct header));
if (tmp == NULL) { if (tmp == NULL) {
free(key);
free(value);
// we don't need to clean up this connection gets dropped anyway // we don't need to clean up this connection gets dropped anyway
return HEADERS_ALLOC_ERROR; return HEADERS_ALLOC_ERROR;
} }
@ -109,7 +129,10 @@ int headers_parse(struct headers* headers, const char* _currentHeader, size_t le
} }
} }
return headers_mod(headers, key, value); int tmp = headers_mod(headers, key, value);
free(key);
free(value);
return tmp;
} }
void headers_free(struct headers* headers) { void headers_free(struct headers* headers) {
@ -122,6 +145,14 @@ void headers_free(struct headers* headers) {
if (headers->headers != NULL) if (headers->headers != NULL)
free(headers->headers); free(headers->headers);
headers->number = 0;
}
void headers_dump(struct headers* headers, FILE* stream) {
for (int i = 0; i < headers->number; i++) {
fprintf(stream, "%s: %s\r\n", headers->headers[i].key, headers->headers[i].value);
}
} }
int headers_metadata(struct metaData* metaData, char* header) { int headers_metadata(struct metaData* metaData, char* header) {

View file

@ -1,6 +1,8 @@
#ifndef HEADERS_H #ifndef HEADERS_H
#define HEADERS_H #define HEADERS_H
#include <stdio.h>
#include "misc.h" #include "misc.h"
#define HEADERS_SUCCESS (0) #define HEADERS_SUCCESS (0)
@ -18,10 +20,12 @@ struct headers {
struct header* headers; struct header* headers;
}; };
struct headers headers_create();
const char* headers_get(struct headers* headers, const char* key); const char* headers_get(struct headers* headers, const char* key);
int headers_mod(struct headers* headers, char* key, char* value); int headers_mod(struct headers* headers, const char* key, const char* value);
int headers_parse(struct headers* headers, const char* currentHeader, size_t length); int headers_parse(struct headers* headers, const char* currentHeader, size_t length);
void headers_free(struct headers* headers); void headers_free(struct headers* headers);
void headers_dump(struct headers* headers, FILE* stream);
int headers_metadata(struct metaData* metaData, char* header); int headers_metadata(struct metaData* metaData, char* header);

View file

@ -3,6 +3,7 @@
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <stdbool.h>
enum loglevel { enum loglevel {
DEBUG, VERBOSE, INFO, WARN, ERROR, CRITICAL DEBUG, VERBOSE, INFO, WARN, ERROR, CRITICAL

View file

@ -4,6 +4,7 @@
#include "networking.h" #include "networking.h"
#include "logging.h" #include "logging.h"
#include "headers.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 NULL;
@ -13,6 +14,9 @@ int main(int argc, char** argv) {
setLogging(stderr, DEBUG, true); setLogging(stderr, DEBUG, true);
setCriticalHandler(NULL); setCriticalHandler(NULL);
struct headers headers = headers_create();
headers_mod(&headers, "Server", "CFloor 0.1");
struct networkingConfig config = { struct networkingConfig config = {
.maxConnections = 1024, .maxConnections = 1024,
.connectionTimeout = 30000, .connectionTimeout = 30000,
@ -25,9 +29,7 @@ int main(int argc, char** argv) {
} }
} }
}, },
.defaultResponse = { .defaultHeaders = headers,
.number = 0
},
.getHandler = &handlerGetter .getHandler = &handlerGetter
}; };
@ -36,4 +38,6 @@ int main(int argc, char** argv) {
while(true) { while(true) {
sleep(0xffff); sleep(0xffff);
} }
headers_free(&headers);
} }

View file

@ -1,10 +1,23 @@
#include <unistd.h> #include <unistd.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <pthread.h> #include <pthread.h>
#include "misc.h" #include "misc.h"
const char* getHTTPVersionString(enum httpVersion version) {
switch(version) {
case HTTP10:
return "HTTP/1.0";
case HTTP11:
return "HTTP/1.1";
default:
return "UNKNOWN";
}
}
int startCopyThread(int from, int to, pthread_t* thread) { int startCopyThread(int from, int to, pthread_t* thread) {
struct fileCopy* files = malloc(sizeof(struct fileCopy)); struct fileCopy* files = malloc(sizeof(struct fileCopy));
if (files < 0) if (files < 0)
@ -18,10 +31,12 @@ int startCopyThread(int from, int to, pthread_t* thread) {
void* fileCopyThread(void* data) { void* fileCopyThread(void* data) {
struct fileCopy* files = (struct fileCopy*) data; struct fileCopy* files = (struct fileCopy*) data;
char* c; char c;
while(read(files->readFd, &c, 1) > 0) while(read(files->readFd, &c, 1) > 0) {
write(files->writeFd, &c, 1); write(files->writeFd, &c, 1);
//printf("copy thread: %c\n", c);
}
close(files->readFd); close(files->readFd);
close(files->writeFd); close(files->writeFd);
@ -30,3 +45,11 @@ void* fileCopyThread(void* data) {
return NULL; return NULL;
} }
char* strclone(const char* string) {
char* result = malloc(strlen(string) + 1);
if (result == NULL)
return NULL;
strcpy(result, string);
return result;
}

View file

@ -24,21 +24,28 @@ struct metaData {
*/ */
#include "headers.h" #include "headers.h"
const char* getHTTPVersionString(enum httpVersion version);
union userData {
int integer;
void* ptr;
};
struct request { struct request {
struct metaData metaData; struct metaData metaData;
struct headers* headers; struct headers* headers;
int fd; int fd;
void* _private; void* _private;
union userData user;
}; };
struct response { struct response {
int (*sendHeader)(int statusCode, struct headers headers, struct request* request); int (*sendHeader)(int statusCode, struct headers* headers, struct request* request);
}; };
typedef void (*handler_t)(struct request request, struct response response); typedef void (*handler_t)(struct request request, struct response response);
struct fileCopy { struct fileCopy {
int readFd; int readFd;
int writeFd; int writeFd;
@ -46,4 +53,6 @@ struct fileCopy {
int startCopyThread(int from, int to, pthread_t* thread); int startCopyThread(int from, int to, pthread_t* thread);
void* fileCopyThread(void* data); void* fileCopyThread(void* data);
char* strclone(const char* string);
#endif #endif

View file

@ -15,7 +15,7 @@
#include "linked.h" #include "linked.h"
#include "logging.h" #include "logging.h"
#include "signals.h" #include "signals.h"
#include "error.h" #include "status.h"
struct networkingConfig networkingConfig; struct networkingConfig networkingConfig;
@ -158,14 +158,6 @@ int dumpHeaderBuffer(char* buffer, size_t size, struct connection* connection) {
return 0; return 0;
} }
int sendHeader(int statusCode, struct headers headers, struct request* request) {
struct connection* connection = (struct connection*) request->_private;
// send statusCode and headers
return connection->threads.responseFd;
}
static inline void stopThread(pthread_t self, pthread_t thread, bool force) { static inline void stopThread(pthread_t self, pthread_t thread, bool force) {
if (pthread_equal(self, thread)) if (pthread_equal(self, thread))
return; return;
@ -179,20 +171,61 @@ static inline void stopThread(pthread_t self, pthread_t thread, bool force) {
void safeEndConnection(struct connection* connection, bool force) { void safeEndConnection(struct connection* connection, bool force) {
pthread_t self = pthread_self(); pthread_t self = pthread_self();
debug("networking: safely shuting down the connection. %d", force);
stopThread(self, connection->threads.request, true); stopThread(self, connection->threads.request, true);
stopThread(self, connection->threads.response, force); stopThread(self, connection->threads.response, force);
stopThread(self, connection->threads.helper[0], force); stopThread(self, connection->threads.helper[0], force);
stopThread(self, connection->threads.helper[1], force); stopThread(self, connection->threads.helper[1], force);
close(connection->fd);
connection->inUse--; connection->inUse--;
} }
int sendHeader(int statusCode, struct headers* headers, struct request* request) {
debug("networking: sending headers");
struct headers defaultHeaders = networkingConfig.defaultHeaders;
for(int i = 0; i < defaultHeaders.number; i++) {
headers_mod(headers, defaultHeaders.headers[i].key, defaultHeaders.headers[i].value);
}
struct connection* connection = (struct connection*) request->_private;
int fd = connection->threads.responseFd;
FILE* stream = fdopen(dup(fd), "w");
if (stream == NULL) {
error("networking: Couldn't send header.");
return -1;
}
struct statusStrings strings = getStatusStrings(statusCode);
fprintf(stream, "%s %d %s\r\n", getHTTPVersionString(connection->metaData.httpVersion), statusCode, strings.statusString);
fprintf(stderr, "%s %d %s\r\n", getHTTPVersionString(connection->metaData.httpVersion), statusCode, strings.statusString);
headers_dump(headers, stream);
headers_dump(headers, stderr);
fprintf(stream, "\r\n");
fclose(stream);
return fd;
}
/* /*
* This thread calls the handler. * This thread calls the handler.
*/ */
void* responseThread(void* data) { void* responseThread(void* data) {
struct connection* connection = (struct connection*) data; struct connection* connection = (struct connection*) data;
debug("networking: calling response handler");
connection->threads.handler((struct request) { connection->threads.handler((struct request) {
.metaData = connection->metaData, .metaData = connection->metaData,
.headers = &(connection->headers), .headers = &(connection->headers),
@ -201,6 +234,8 @@ void* responseThread(void* data) {
}, (struct response) { }, (struct response) {
.sendHeader = sendHeader .sendHeader = sendHeader
}); });
debug("networking: response handler returned");
close(connection->threads.requestFd); close(connection->threads.requestFd);
close(connection->threads._requestFd); close(connection->threads._requestFd);
@ -256,7 +291,7 @@ void* requestThread(void* data) {
connection->threads._responseFd = response; connection->threads._responseFd = response;
connection->threads.responseFd = pipefd[1]; connection->threads.responseFd = pipefd[1];
if (startCopyThread(connection->fd, request, &(connection->threads.helper[0])) < 0) { if (startCopyThread(dup(connection->fd), request, &(connection->threads.helper[0])) < 0) {
close(request); close(request);
close(connection->threads.requestFd); close(connection->threads.requestFd);
close(response); close(response);
@ -268,7 +303,7 @@ void* requestThread(void* data) {
connection->inUse--; connection->inUse--;
return NULL; return NULL;
} }
if (startCopyThread(response, connection->fd, &(connection->threads.helper[1])) < 0) { if (startCopyThread(response, dup(connection->fd), &(connection->threads.helper[1])) < 0) {
close(request); close(request);
close(connection->threads.requestFd); close(connection->threads.requestFd);
close(response); close(response);
@ -294,7 +329,11 @@ void* requestThread(void* data) {
return NULL; return NULL;
} }
// timeout debug("networking: going to sleep");
sleep(100);
error("networking: Timeout of handler.");
error("networking: Aborting");
close(request); close(request);
close(connection->threads.requestFd); close(connection->threads.requestFd);
@ -309,6 +348,7 @@ void* requestThread(void* data) {
void startRequestHandler(struct connection* connection) { void startRequestHandler(struct connection* connection) {
connection->inUse++; connection->inUse++;
debug("networking: starting request handler");
if (pthread_create(&(connection->threads.request), NULL, &requestThread, connection) != 0) { if (pthread_create(&(connection->threads.request), NULL, &requestThread, connection) != 0) {
error("networking: Couldn't start request thread."); error("networking: Couldn't start request thread.");
warn("networking: Aborting request."); warn("networking: Aborting request.");
@ -483,6 +523,11 @@ void* listenThread(void* _bind) {
if (tmp == -1) if (tmp == -1)
continue; continue;
if (setsockopt(tmp, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof(int)) < 0) {
close(tmp);
continue;
}
bindObj->_private.socketFd = tmp; bindObj->_private.socketFd = tmp;
@ -493,7 +538,7 @@ void* listenThread(void* _bind) {
} }
if (rp == NULL) { if (rp == NULL) {
error("networking: Could not bind."); error("networking: Could not bind: %s", strerror(errno));
warn("networking: Not listening on %s:%s", bindObj->address == NULL ? "0.0.0.0" : bindObj->address, bindObj->port); warn("networking: Not listening on %s:%s", bindObj->address == NULL ? "0.0.0.0" : bindObj->address, bindObj->port);
return NULL; return NULL;
} }
@ -551,10 +596,7 @@ void* listenThread(void* _bind) {
.path = NULL, .path = NULL,
.queryString = NULL .queryString = NULL
}; };
connection->headers = (struct headers) { connection->headers = headers_create();
.number = 0,
.headers = NULL
};
connection->threads = (struct threads) { connection->threads = (struct threads) {
/* /*
* This is really hacky. pthread_t is no(t always an) integer. * This is really hacky. pthread_t is no(t always an) integer.

View file

@ -74,7 +74,7 @@ struct networkingConfig {
struct binds binds; struct binds binds;
long connectionTimeout; long connectionTimeout;
long maxConnections; long maxConnections;
struct headers defaultResponse; struct headers defaultHeaders;
handlerGetter_t getHandler; handlerGetter_t getHandler;
}; };

365
src/status.c Normal file
View file

@ -0,0 +1,365 @@
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include "status.h"
#include "misc.h"
#include "logging.h"
struct statusStrings getStatusStrings(int status) {
switch(status) {
case 100:
return (struct statusStrings) {
.statusString = "Continue",
.statusFormat = ""
};
case 101:
return (struct statusStrings) {
.statusString = "Switching Protocols",
.statusFormat = ""
};
case 102:
return (struct statusStrings) {
.statusString = "Processing",
.statusFormat = ""
};
case 200:
return (struct statusStrings) {
.statusString = "OK",
.statusFormat = ""
};
case 201:
return (struct statusStrings) {
.statusString = "Created",
.statusFormat = ""
};
case 202:
return (struct statusStrings) {
.statusString = "Accepted",
.statusFormat = ""
};
case 203:
return (struct statusStrings) {
.statusString = "Non-Authoritative Information",
.statusFormat = ""
};
case 204:
return (struct statusStrings) {
.statusString = "No Content",
.statusFormat = ""
};
case 205:
return (struct statusStrings) {
.statusString = "Reset Content",
.statusFormat = ""
};
case 206:
return (struct statusStrings) {
.statusString = "Partial Content",
.statusFormat = ""
};
case 207:
return (struct statusStrings) {
.statusString = "Multi-Status",
.statusFormat = ""
};
case 208:
return (struct statusStrings) {
.statusString = "Already Reported",
.statusFormat = ""
};
case 226:
return (struct statusStrings) {
.statusString = "IM Used",
.statusFormat = ""
};
case 300:
return (struct statusStrings) {
.statusString = "Multiple Choices",
.statusFormat = ""
};
case 301:
return (struct statusStrings) {
.statusString = "Moved Permanently",
.statusFormat = ""
};
case 302:
return (struct statusStrings) {
.statusString = "Found (Moved Temporarily)",
.statusFormat = ""
};
case 303:
return (struct statusStrings) {
.statusString = "See Other",
.statusFormat = ""
};
case 304:
return (struct statusStrings) {
.statusString = "Not Modified",
.statusFormat = ""
};
case 305:
return (struct statusStrings) {
.statusString = "Use Proxy",
.statusFormat = ""
};
case 306:
return (struct statusStrings) {
.statusString = "(reserved)",
.statusFormat = ""
};
case 307:
return (struct statusStrings) {
.statusString = "Temporary Redirect",
.statusFormat = ""
};
case 308:
return (struct statusStrings) {
.statusString = "Permanent Redirect",
.statusFormat = ""
};
case 400:
return (struct statusStrings) {
.statusString = "Bad Request",
.statusFormat = ""
};
case 401:
return (struct statusStrings) {
.statusString = "Unauthorized",
.statusFormat = ""
};
case 402:
return (struct statusStrings) {
.statusString = "Payment Required",
.statusFormat = ""
};
case 403:
return (struct statusStrings) {
.statusString = "Forbidden",
.statusFormat = ""
};
case 404:
return (struct statusStrings) {
.statusString = "Not found",
.statusFormat = ""
};
case 405:
return (struct statusStrings) {
.statusString = "Method Not Allowed",
.statusFormat = ""
};
case 406:
return (struct statusStrings) {
.statusString = "Not Acceptable",
.statusFormat = ""
};
case 407:
return (struct statusStrings) {
.statusString = "Proxy Auhentication Required",
.statusFormat = ""
};
case 408:
return (struct statusStrings) {
.statusString = "Request Timeout",
.statusFormat = ""
};
case 409:
return (struct statusStrings) {
.statusString = "Conflict",
.statusFormat = ""
};
case 410:
return (struct statusStrings) {
.statusString = "Gone",
.statusFormat = ""
};
case 411:
return (struct statusStrings) {
.statusString = "Length Required",
.statusFormat = ""
};
case 412:
return (struct statusStrings) {
.statusString = "Precondition Failed",
.statusFormat = ""
};
case 413:
return (struct statusStrings) {
.statusString = "Request Entity Too Large",
.statusFormat = ""
};
case 414:
return (struct statusStrings) {
.statusString = "URI Too Long",
.statusFormat = ""
};
case 415:
return (struct statusStrings) {
.statusString = "Unsupported Media Type",
.statusFormat = ""
};
case 416:
return (struct statusStrings) {
.statusString = "Requested Range Not Satisfiable",
.statusFormat = ""
};
case 417:
return (struct statusStrings) {
.statusString = "Expectation Failed",
.statusFormat = ""
};
case 420:
return (struct statusStrings) {
.statusString = "Policy Not Fulfilled",
.statusFormat = ""
};
case 421:
return (struct statusStrings) {
.statusString = "Misdirected Request",
.statusFormat = ""
};
case 422:
return (struct statusStrings) {
.statusString = "Unprocessable Entity",
.statusFormat = ""
};
case 423:
return (struct statusStrings) {
.statusString = "Locked",
.statusFormat = ""
};
case 424:
return (struct statusStrings) {
.statusString = "Failed Dependency",
.statusFormat = ""
};
case 426:
return (struct statusStrings) {
.statusString = "Upgrade Required",
.statusFormat = ""
};
case 428:
return (struct statusStrings) {
.statusString = "Precondition Required",
.statusFormat = ""
};
case 429:
return (struct statusStrings) {
.statusString = "Too Many Requests",
.statusFormat = ""
};
case 431:
return (struct statusStrings) {
.statusString = "Request Header Fields Too Large",
.statusFormat = ""
};
case 451:
return (struct statusStrings) {
.statusString = "Unavailable For Legal Reasons",
.statusFormat = ""
};
case 500:
return (struct statusStrings) {
.statusString = "Internal Server Error",
.statusFormat = ""
};
case 501:
return (struct statusStrings) {
.statusString = "Not Implemented",
.statusFormat = ""
};
case 502:
return (struct statusStrings) {
.statusString = "Bad Gateway",
.statusFormat = ""
};
case 503:
return (struct statusStrings) {
.statusString = "Service Unavailable",
.statusFormat = ""
};
case 504:
return (struct statusStrings) {
.statusString = "Gateway Timeout",
.statusFormat = ""
};
case 505:
return (struct statusStrings) {
.statusString = "HTTP Version Not Supported",
.statusFormat = ""
};
case 506:
return (struct statusStrings) {
.statusString = "Variant Also Negotiates",
.statusFormat = ""
};
case 507:
return (struct statusStrings) {
.statusString = "Insufficient Storage",
.statusFormat = ""
};
case 508:
return (struct statusStrings) {
.statusString = "Loop Detected",
.statusFormat = ""
};
case 509:
return (struct statusStrings) {
.statusString = "Bandwidth Limit Exceeded",
.statusFormat = ""
};
case 510:
return (struct statusStrings) {
.statusString = "Not Extended",
.statusFormat = ""
};
case 511:
return (struct statusStrings) {
.statusString = "Notwork Authentication Required",
.statusFormat = ""
};
default:
return (struct statusStrings) {
.statusString = "Unknown Status Code",
.statusFormat = "This is pretty bad."
};
}
}
void status(struct request request, struct response response, int status) {
struct headers headers = headers_create();
int fd = response.sendHeader(status, &headers, &request);
headers_free(&headers);
FILE* stream = fdopen(fd, "w");
if (stream == NULL) {
error("status: Couldn't get stream from fd: %s", strerror(errno));
return;
}
struct statusStrings string = getStatusStrings(status);
fprintf(stream, "<!DOCTYPE html>\n");
fprintf(stream, "<html>\n");
fprintf(stream, " <head>\n");
fprintf(stream, " <title>%s</title>\n", string.statusString);
fprintf(stream, " </head>\n");
fprintf(stream, " <body>\n");
fprintf(stream, " <h1>%s</h1>\n", string.statusString);
fprintf(stream, string.statusFormat, request.metaData.path);
fprintf(stream, " <hr />\n");
fprintf(stream, " </body>\n");
fprintf(stream, "<!DOCTYPE html>\n");
fclose(stream);
}
void status500(struct request request, struct response response) {
status(request, response, 500);
}

15
src/status.h Normal file
View file

@ -0,0 +1,15 @@
#ifndef STATUS_H
#define STATUS_H
#include "misc.h"
struct statusStrings {
const char* statusString;
const char* statusFormat;
};
struct statusStrings getStatusStrings(int status);
void status500(struct request request, struct response response);
#endif