mirror of
https://github.com/sigmasternchen/CFloor
synced 2025-03-15 20:28:56 +00:00
request handling nearly done. There is a bug though. Will have to look into it tomorrow
This commit is contained in:
parent
553d40d1aa
commit
66c7604cd4
13 changed files with 532 additions and 55 deletions
22
Makefile
22
Makefile
|
@ -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)
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
|
|
||||||
|
|
||||||
#include "error.h"
|
|
||||||
|
|
||||||
void status500(struct request request, struct response response) {
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
#ifndef ERROR_H
|
|
||||||
#define ERROR_H
|
|
||||||
|
|
||||||
#include "misc.h"
|
|
||||||
|
|
||||||
handler_t status500;
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
10
src/main.c
10
src/main.c
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
27
src/misc.c
27
src/misc.c
|
@ -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;
|
||||||
|
}
|
||||||
|
|
13
src/misc.h
13
src/misc.h
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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
365
src/status.c
Normal 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
15
src/status.h
Normal 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
|
Loading…
Reference in a new issue