aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcbdev <cb@cbcdn.com>2019-06-01 21:27:52 +0200
committercbdev <cb@cbcdn.com>2019-06-01 21:27:52 +0200
commitb9297647c68c963a977e2c18f421211e24f9e85a (patch)
tree173d0533f7c76665dea9956ed4da4f3228e01dc9
parent92a291b5fae32caba2212192bc94b8ef568c362d (diff)
downloadwebsocksy-b9297647c68c963a977e2c18f421211e24f9e85a.tar.gz
websocksy-b9297647c68c963a977e2c18f421211e24f9e85a.tar.bz2
websocksy-b9297647c68c963a977e2c18f421211e24f9e85a.zip
Implement file backend
-rw-r--r--.gitignore1
-rw-r--r--makefile6
-rw-r--r--plugin.c15
-rw-r--r--plugins/backend_file.c204
-rw-r--r--plugins/backend_file.h6
-rw-r--r--plugins/makefile13
-rw-r--r--websocksy.c1
7 files changed, 234 insertions, 12 deletions
diff --git a/.gitignore b/.gitignore
index 23d0915..c97037c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
*.swp
websocksy
*.o
+*.so
diff --git a/makefile b/makefile
index 9ed6711..c389148 100644
--- a/makefile
+++ b/makefile
@@ -1,3 +1,4 @@
+.PHONY: all clean plugins
PLUGINPATH=plugins/
CFLAGS=-g -Wall -Wpedantic -DPLUGINS=\"$(PLUGINPATH)\"
@@ -7,7 +8,10 @@ OBJECTS=builtins.o network.o websocket.o plugin.o
all: websocksy
-websocksy: websocksy.c websocksy.h $(OBJECTS)
+plugins:
+ $(MAKE) -C plugins
+
+websocksy: websocksy.c websocksy.h $(OBJECTS) plugins
$(CC) $(CFLAGS) $(LDLIBS) $< -o $@ $(OBJECTS)
clean:
diff --git a/plugin.c b/plugin.c
index 30c5775..674e992 100644
--- a/plugin.c
+++ b/plugin.c
@@ -43,20 +43,12 @@ int plugin_framing_load(char* path){
DIR* directory = opendir(path);
struct dirent* file = NULL;
char plugin_path[MAX_PLUGIN_PATH] = "";
- size_t path_len;
- if(strlen(path) >= sizeof(plugin_path) - 20){
+ if(strlen(path) >= sizeof(plugin_path) - 20 || strlen(path) == 0){
fprintf(stderr, "Plugin path length exceeds limit\n");
return 1;
}
- strncpy(plugin_path, path, sizeof(plugin_path) - 2);
- if(path[strlen(path) - 1] != '/'){
- plugin_path[strlen(path)] = '/';
- plugin_path[strlen(path) + 1] = 0;
- }
- path_len = strlen(plugin_path);
-
if(!directory){
fprintf(stderr, "Failed to open directory %s: %s\n", path, strerror(errno));
return 0;
@@ -71,7 +63,8 @@ int plugin_framing_load(char* path){
if(strlen(file->d_name) < 4 || strcmp(file->d_name + strlen(file->d_name) - 3, ".so")){
continue;
}
- strncpy(plugin_path + path_len, file->d_name, sizeof(plugin_path) - path_len - 2);
+
+ snprintf(plugin_path, sizeof(plugin_path), "%s%s%s", path, (path[strlen(path) - 1] == '/') ? "" : "/", file->d_name);
if(!plugin_attach(plugin_path)){
return 1;
}
@@ -85,7 +78,7 @@ int plugin_backend_load(char* path, char* backend_requested, ws_backend* backend
char plugin_path[MAX_PLUGIN_PATH] = "";
void* handle = NULL;
- if(strlen(path) >= sizeof(plugin_path) - 30){
+ if(strlen(path) >= sizeof(plugin_path) - 30 || strlen(path) == 0){
fprintf(stderr, "Plugin path length exceeds limit\n");
return 1;
}
diff --git a/plugins/backend_file.c b/plugins/backend_file.c
new file mode 100644
index 0000000..c3ed8ea
--- /dev/null
+++ b/plugins/backend_file.c
@@ -0,0 +1,204 @@
+#include "backend_file.h"
+#include <string.h>
+#include <stdio.h>
+
+//FIXME allocated this statically because i dont want to do it properly right now tbh
+#define BACKEND_FILE_MAX_PATH 8192
+
+static char* backend_path = NULL;
+
+size_t expressions = 0;
+static char** expression = NULL;
+
+uint64_t init(){
+ //initialize the backend path to empty to be able to use it without problems later
+ backend_path = strdup("");
+
+ if(!backend_path){
+ fprintf(stderr, "Failed to allocate memory\n");
+ return 0;
+ }
+ return WEBSOCKSY_API_VERSION;
+}
+
+uint64_t configure(char* key, char* value){
+ if(!strcmp(key, "path")){
+ free(backend_path);
+ backend_path = strdup(value);
+ if(!backend_path){
+ fprintf(stderr, "Failed to allocate memory\n");
+ return 1;
+ }
+
+ if(strlen(backend_path) && backend_path[strlen(backend_path) - 1] == '/'){
+ backend_path[strlen(backend_path) - 1] = 0;
+ }
+ return 0;
+ }
+ else if(!strcmp(key, "expression")){
+ expression = realloc(expression, (expressions + 1) * sizeof(char*));
+ if(!expression){
+ fprintf(stderr, "Failed to allocate memory\n");
+ return 1;
+ }
+ expression[expressions] = strdup(value);
+ if(!expression[expressions]){
+ fprintf(stderr, "Failed to allocate memory\n");
+ return 1;
+ }
+ expressions++;
+ return 0;
+ }
+
+ fprintf(stderr, "Unknown backend configuration option %s\n", key);
+ return 1;
+}
+
+static int expression_replace(char* buffer, size_t buffer_length, size_t variable_length, char* content, size_t content_length){
+ //check whether the replacement fits
+ if(variable_length < content_length && strlen(buffer) + (content_length - variable_length) >= buffer_length){
+ fprintf(stderr, "Expression replacement buffer overrun\n");
+ return 1;
+ }
+
+ //move data after the replacement
+ memmove(buffer + content_length, buffer + variable_length, strlen(buffer) - variable_length + 1);
+
+ //insert replacement
+ memcpy(buffer, content, content_length);
+
+ return 0;
+}
+
+static int expression_resolve(char* template, size_t length, char* endpoint, size_t headers, ws_http_header* header){
+ size_t u, index_len, p, value_len, variable_len;
+ char* index, *value;
+
+ for(u = 0; template[u]; u++){
+ index_len = 0;
+ variable_len = 0;
+ value = NULL;
+ if(template[u] == '%'){
+ if(!strncmp(template + u, "%endpoint%", 10)){
+ if(strlen(endpoint) < 1){
+ return 1;
+ }
+
+ //TODO rtrim slash
+ //replace with sanitized endpoint string
+ for(p = 0; endpoint[p]; p++){
+ if(endpoint[p] == '/'){
+ endpoint[p] = '_';
+ }
+ }
+
+ value = endpoint + 1;
+ value_len = p - 1;
+ variable_len = 10;
+ }
+ else if(!strncmp(template + u, "%cookie:", 8)){
+ //scan cookie values
+ index = template + u + 8;
+ for(; index[index_len] && index[index_len] != '%'; index_len++){
+ }
+ if(!index[index_len]){
+ fprintf(stderr, "Unterminated expression variable: %s\n", index);
+ return 1;
+ }
+
+ //TODO iterate cookies
+ }
+ else if(!strncmp(template + u, "%header:", 8)){
+ //scan headers
+ index = template + u + 8;
+ for(; index[index_len] && index[index_len] != '%'; index_len++){
+ }
+ if(!index[index_len]){
+ fprintf(stderr, "Unterminated expression variable: %s\n", index);
+ return 1;
+ }
+ //find the correct header
+ for(p = 0; p < headers; p++){
+ if(strlen(header[p].tag) == index_len
+ && !strncmp(header[p].tag, index, index_len)){
+ break;
+ }
+ }
+
+ //no such header -> fail the expression
+ if(p == headers){
+ return 1;
+ }
+
+ value = header[p].value;
+ value_len = strlen(value);
+ variable_len = 8 + index_len + 1;
+ }
+
+ //perform replacement
+ if(value && expression_replace(template + u, length - u, variable_len, value, value_len)){
+ fprintf(stderr, "Expression replacement failed\n");
+ return 1;
+ }
+
+ //skip the inserted value
+ u += value_len - 1;
+ }
+ }
+
+ return 0;
+}
+
+ws_peer_info query(char* endpoint, size_t protocols, char** protocol, size_t headers, ws_http_header* header, websocket* ws){
+ size_t u, line_alloc = 0;
+ ssize_t line_length = 0;
+ char* line = NULL;
+ FILE* input = NULL;
+ char target_path[BACKEND_FILE_MAX_PATH];
+ ws_peer_info peer = {
+ .transport = peer_transport_detect,
+ };
+
+ for(u = 0; u < expressions; u++){
+ //evaluate the current expression to find a path
+ snprintf(target_path, sizeof(target_path), "%s/%s", backend_path, expression[u]);
+ if(expression_resolve(target_path + strlen(backend_path) + 1, sizeof(target_path) - strlen(backend_path) - 1, endpoint, headers, header)){
+ continue;
+ }
+
+ //check whether the file exists
+ input = fopen(target_path, "r");
+ if(!input){
+ continue;
+ }
+
+ //read it
+ for(line_length = getline(&line, &line_alloc, input); line_length >= 0; line_length = getline(&line, &line_alloc, input)){
+ //TODO evaluate line in file
+ fprintf(stderr, "File %s, line %s\n", target_path, line);
+ }
+ fclose(input);
+
+ //if peer found, break
+ if(peer.host){
+ break;
+ }
+ }
+
+ free(line);
+ return peer;
+}
+
+void cleanup(){
+ size_t u;
+
+ for(u = 0; u < expressions; u++){
+ free(expression[u]);
+ }
+ free(expression);
+ expression = NULL;
+ expressions = 0;
+
+ free(backend_path);
+ backend_path = NULL;
+}
diff --git a/plugins/backend_file.h b/plugins/backend_file.h
new file mode 100644
index 0000000..04b3528
--- /dev/null
+++ b/plugins/backend_file.h
@@ -0,0 +1,6 @@
+#include "../websocksy.h"
+
+uint64_t init();
+uint64_t configure(char* key, char* value);
+ws_peer_info query(char* endpoint, size_t protocols, char** protocol, size_t headers, ws_http_header* header, websocket* ws);
+void cleanup();
diff --git a/plugins/makefile b/plugins/makefile
new file mode 100644
index 0000000..6b413db
--- /dev/null
+++ b/plugins/makefile
@@ -0,0 +1,13 @@
+.PHONY: all clean
+PLUGINS = backend_file.so
+
+CFLAGS += -fPIC -I../
+LDFLAGS += -shared
+
+%.so :: %.c %.h
+ $(CC) $(CFLAGS) $(LDLIBS) $< -o $@ $(LDFLAGS)
+
+all: $(PLUGINS)
+
+clean:
+ $(RM) $(PLUGINS)
diff --git a/websocksy.c b/websocksy.c
index f625174..c635ca7 100644
--- a/websocksy.c
+++ b/websocksy.c
@@ -130,6 +130,7 @@ int client_connect(websocket* ws){
ws->peer = config.backend.query(ws->request_path, ws->protocols, ws->protocol, ws->headers, ws->header, ws);
if(!ws->peer.host){
//TODO check port if network socket
+ //TODO try to extract port from host if none given
//no peer provided
return 1;
}