aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorame <[email protected]>2025-09-03 18:18:06 -0500
committerame <[email protected]>2025-09-03 18:18:06 -0500
commit1aba3757b486e28ddfb0aff67fe65e4a7a87c74f (patch)
treeb443750cc9899c6f7c265e357d5ef2605f5c95ac
parenta239a832f14ed1f7eab9b9ee75867bdc2ee2a5f9 (diff)
parent6e6e948a553cc062b439f349c0b545df0223d9a1 (diff)
merge main
-rw-r--r--docs/net/listen.md2
-rw-r--r--library/lullaby/common.lua5
-rw-r--r--library/lullaby/net.lua8
-rw-r--r--makefile9
-rw-r--r--readme.md6
-rw-r--r--src/lua.c19
-rw-r--r--src/lua.h2
-rw-r--r--src/net.c295
-rw-r--r--src/net.h2
-rw-r--r--src/net/lua.c5
-rw-r--r--src/net/util.c39
-rw-r--r--src/net/util.h3
-rw-r--r--src/types/str.c13
-rw-r--r--src/types/str.h5
14 files changed, 273 insertions, 140 deletions
diff --git a/docs/net/listen.md b/docs/net/listen.md
index 6b7f12c..333f0f2 100644
--- a/docs/net/listen.md
+++ b/docs/net/listen.md
@@ -132,7 +132,7 @@ res.header["test"] = "wowa"
res:sendfile(filepath, options?)
-res.header["Content-Type"] is set automatically depending on the file extention, using /etc/mime.types, or whatever option was supplied to listen (see listen options)
+res.header["Content-Type"] is set automatically (unless already set) depending on the file extention, using /etc/mime.types, or whatever option was supplied to listen (see listen options)
options table
diff --git a/library/lullaby/common.lua b/library/lullaby/common.lua
index 936feb9..96be2d6 100644
--- a/library/lullaby/common.lua
+++ b/library/lullaby/common.lua
@@ -9,8 +9,9 @@ meta.stream = {}
---sends the rest of a streams contents to a file
---@param T stream
---@param filename string
----@param bytes integer? max amount to read before stopping
-function meta.stream.file(T, filename, bytes) end
+---@param bytes integer? max amount to read before stopping, 0 if nil
+---@param mode string? what mode to open the file, w if nil
+function meta.stream.file(T, filename, bytes, mode) end
---reads bytes from a stream
---@param T stream
diff --git a/library/lullaby/net.lua b/library/lullaby/net.lua
index 624f78f..7ff24aa 100644
--- a/library/lullaby/net.lua
+++ b/library/lullaby/net.lua
@@ -60,12 +60,20 @@ req_table.ip = 0
---@type string
req_table.Body = ""
+---@type string
+req_table.path = ""
+
+---@type string
+req_table.rawpath = ""
+
---@type any|nil
req_table.files = {}
---@type any|nil
req_table.cookies = {}
+---@type any|nil
+req_table.query = {}
---@param T server-table
---@param route string
diff --git a/makefile b/makefile
index 0a07ae9..2e82331 100644
--- a/makefile
+++ b/makefile
@@ -1,5 +1,6 @@
CC := clang
+MAJOR_VERSION := "$(shell git -c safe.directory='*' describe --tags --abbrev=0)"
GIT_COMMIT := "$(shell git -c safe.directory='*' describe --tags)-$(shell git -c safe.directory='*' describe --always --match 'NOT A TAG')"
version ?= 5.4
@@ -9,12 +10,12 @@ ifeq ($(version),jit)
install_version = 5.1
endif
-CFLAGS := -D_GNU_SOURCE -Wall -fPIC -DGIT_COMMIT='$(GIT_COMMIT)' `pkg-config --cflags lua$(version)`
+CFLAGS := -D_GNU_SOURCE -Wall -fPIC -DGIT_COMMIT='$(GIT_COMMIT)' -DMAJOR_VERSION='$(MAJOR_VERSION)' `pkg-config --cflags lua$(version)`
LFLAGS := -lm -shared -lcrypto -lssl
LINKER := $(CC)
TARGET := lullaby.so
-INSTALL_DIR := /usr/lib64/lua/
+INSTALL := /usr/local/lib/lua/
SRCS := $(wildcard src/*.c) $(wildcard src/*/*.c)
OBJS := $(SRCS:.c=.o)
@@ -33,8 +34,8 @@ release: CFLAGS += -O3
release: all
install::
- mkdir $(INSTALL_DIR)$(install_version) -p
- cp $(TARGET) $(INSTALL_DIR)$(install_version)/$(TARGET)
+ mkdir $(INSTALL)$(install_version) -p
+ cp $(TARGET) $(INSTALL)$(install_version)/$(TARGET)
# ok so im pretty sure asan should be linked too, however dlclose needs to be masked anyways
# and since libasan needs to be the first thing to load, you'll have to add it anyways
diff --git a/readme.md b/readme.md
index 65791b7..b8a4ccb 100644
--- a/readme.md
+++ b/readme.md
@@ -41,7 +41,9 @@ build with `make`, output is `./lullaby.so` or (win)`./lullaby.dll`
windows works through msys2, install `mingw-w64-x86_64-lua` then run `make CC=gcc`
-you can install with `doas make install` which will install lullaby.so into /usr/lib64/lua/5.X/
+you can install with `doas make install` which will install lullaby.so into /usr/local/lib/lua/5.X
+
+install directory can be configured with `INSTALL=...` which defaults to /usr/local/lib/lua/, but may be wanted in /usr/lib64/lua/
lua version can be specified with `version=...`, similar to 5.1, 5.3, jit, the default it 5.4
@@ -58,6 +60,8 @@ for working on the code base, i recommend using bear to generate compile_command
* rewrite docs
* net mostly complete
+
+* portability (memmem)
----
diff --git a/src/lua.c b/src/lua.c
index 6ed46de..eedda0e 100644
--- a/src/lua.c
+++ b/src/lua.c
@@ -59,10 +59,15 @@ int _stream_file(lua_State* L){
const int CHUNK_SIZE = 4096;
uint64_t maxlen = 0;
uint64_t totallen = 0;
+ const char* mode = "w";
if(lua_gettop(L) > 2){
maxlen = lua_tointeger(L, 3);
}
+ if(lua_gettop(L) > 3){
+ mode = lua_tostring(L, 4);
+ }
+
lua_pushstring(L, "_read");
lua_gettable(L, 1);
stream_read_function rf = lua_touserdata(L, -1);
@@ -73,7 +78,7 @@ int _stream_file(lua_State* L){
const char* filename = lua_tostring(L, 2);
FILE *f;
- f = fopen(filename, "a");
+ f = fopen(filename, mode);
if(f == NULL){
luaI_error(L, -1, "unable to open file");
}
@@ -370,19 +375,21 @@ int env_table(lua_State* L, int provide_table){
return 1;
}
-//top table is prioritized
-void luaI_jointable(lua_State* L){
- int idx = lua_gettop(L) - 1;
+//main is the default values, merge is the new and overridden ones
+void luaI_jointable(lua_State* L, int main, int merge){
+ int idx = lua_gettop(L);
+
+ lua_pushvalue(L, merge);
lua_pushnil(L);
for(;lua_next(L, -2) != 0;){
lua_pushvalue(L, -2);
lua_pushvalue(L, -2);
- lua_settable(L, idx);
+ lua_settable(L, main);
lua_pop(L, 1);
}
- lua_pushvalue(L, idx);
+ lua_settop(L, idx);
}
//copys all variables from state A to B, including locals (stored in _locals)
diff --git a/src/lua.h b/src/lua.h
index 1d5bea1..d31ef58 100644
--- a/src/lua.h
+++ b/src/lua.h
@@ -40,7 +40,7 @@ void luaI_newstream(lua_State* L, stream_read_function, stream_free_function, vo
int luaI_nothing(lua_State*);
int env_table(lua_State* L, int provide_table);
-void luaI_jointable(lua_State* L);
+void luaI_jointable(lua_State* L, int main, int merge);
//generic macro that takes other macros (see below)
#define _tset_b(L, Tidx, K, V, F)\
diff --git a/src/net.c b/src/net.c
index 56601f8..e829654 100644
--- a/src/net.c
+++ b/src/net.c
@@ -2,6 +2,7 @@
#include "net/util.h"
#include "net/lua.h"
#include "net/luai.h"
+#include "types/str.h"
#include <fcntl.h>
@@ -97,7 +98,8 @@ int chunked_encoding_round(char* input, int length, struct chunked_encoding_stat
str_popb(state->buffer, 2);
state->chunk_length = strtoll(state->buffer->c, NULL, 16);
str_clear(state->buffer);
- state->reading_length = 0;
+ if(state->chunk_length != 0)
+ state->reading_length = 0;
}
} else {
int len = lesser(state->chunk_length - state->buffer->len, length - i);
@@ -389,20 +391,27 @@ int l_wss(lua_State* L){
return 1;
}
-struct _srequest_state {
+struct request_state {
SSL* ssl;
SSL_CTX* ctx;
int sock;
+ int secure;
str* buffer; //anything pre-existing
struct chunked_encoding_state* state;
};
+ssize_t _request_read(struct request_state* state, void* buffer, size_t count);
+
int _srequest_free(void** _state){
- struct _srequest_state* state = *((struct _srequest_state**)_state);
- SSL_set_shutdown(state->ssl, SSL_RECEIVED_SHUTDOWN | SSL_SENT_SHUTDOWN);
- SSL_shutdown(state->ssl);
- SSL_free(state->ssl);
- SSL_CTX_free(state->ctx);
+ struct request_state* state = *((struct request_state**)_state);
+
+ if(state->secure){
+ SSL_set_shutdown(state->ssl, SSL_RECEIVED_SHUTDOWN | SSL_SENT_SHUTDOWN);
+ SSL_shutdown(state->ssl);
+ SSL_free(state->ssl);
+ SSL_CTX_free(state->ctx);
+ }
+
close(state->sock);
if(state->state != NULL){
@@ -419,7 +428,7 @@ int _srequest_free(void** _state){
}
int _srequest_read(uint64_t reqlen, str** _output, void** _state){
- struct _srequest_state* state = *((struct _srequest_state**)_state);
+ struct request_state* state = *((struct request_state**)_state);
str* output = *_output;
//states using chunked encoding should skip this
if(state->buffer != NULL){
@@ -431,7 +440,7 @@ int _srequest_read(uint64_t reqlen, str** _output, void** _state){
char buffer[BUFFER_LEN];
memset(buffer, 0, BUFFER_LEN);
uint64_t len;
- for(; (len = SSL_read(state->ssl, buffer, BUFFER_LEN)) > 0;){
+ for(; (len = _request_read(state, buffer, BUFFER_LEN)) > 0;){
if(state->state != NULL){
chunked_encoding_round(buffer, len, state->state);
} else {
@@ -449,73 +458,75 @@ int _srequest_read(uint64_t reqlen, str** _output, void** _state){
return 1;
}
-int _srequest_chunked_encoding(char* input, int length, struct chunked_encoding_state* state){
- //printf("'%s'\n", input);
- for(int i = 0; i < length; i++){
- //printf("%i/%i\n", i, length);
- if(state->reading_length){
- str_pushl(state->buffer, input + i, 1);
+int _request(lua_State* L, struct request_state* state);
- if(state->buffer->len >= 2 && memmem(state->buffer->c + state->buffer->len - 2, 2, "\r\n", 2)){
+int l_srequest(lua_State* L){
+ struct request_state* state = calloc(sizeof * state, 1);
+ state->secure = 1;
- str_popb(state->buffer, 2);
- state->chunk_length = strtoll(state->buffer->c, NULL, 16);
- str_clear(state->buffer);
- state->reading_length = 0;
- }
- } else {
- int len = lesser(state->chunk_length - state->buffer->len, length - i);
- str_pushl(state->buffer, input + i, len);
- i += len;
+ return _request(L, state);
+}
- if(state->buffer->len >= state->chunk_length){
- state->reading_length = 1;
- str_pushl(state->content, state->buffer->c, state->buffer->len);
- str_clear(state->buffer);
- }
- }
- }
+int l_request(lua_State* L){
+ struct request_state* state = calloc(sizeof * state, 1);
+ state->secure = 0;
- //printf("buffer '%s'\n", state->buffer->c);
+ return _request(L, state);
+}
- return 0;
+ssize_t _request_read(struct request_state* state, void* buffer, size_t count){
+ if(state->secure){
+ return SSL_read(state->ssl, buffer, count);
+ } else {
+ return read(state->sock, buffer, count);
+ }
}
-int l_srequest(lua_State* L){
+ssize_t _request_write(struct request_state* state, const void* buffer, size_t count){
+ if(state->secure){
+ return SSL_write(state->ssl, buffer, count);
+ } else {
+ return write(state->sock, buffer, count);
+ }
+}
+
+int _request(lua_State* L, struct request_state* state){
int params = lua_gettop(L);
- int check = 1;
uint64_t ilen = 0;
char* request_url = (char*)lua_tolstring(L, 1, &ilen);
struct url awa = parse_url(request_url, ilen);
if(awa.proto != NULL && strcmp(awa.proto->c, "http") == 0){
- //send to l_request, todo
- abort();
+ state->secure = 0;
+ } else if (awa.proto != NULL && strcmp(awa.proto->c, "https") == 0){
+ state->secure = 1;
}
+
const char* host = awa.domain == NULL ? request_url : awa.domain->c;
- const char* port = awa.port == NULL ? "443" : awa.port->c;
+ const char* port = awa.port == NULL ?
+ (state->secure ? "443" : "80")
+ : awa.port->c;
char* path = awa.path == NULL ? "/" : awa.path->c;
- int sock = get_host((char*)host, (char*)port);
- if(sock == -1){
- //p_fatal("could not resolve address");
- //abort();
+ state->sock = get_host((char*)host, (char*)port);
+ if(state->sock == -1){
luaI_error(L, -1, "error resolving address");
}
- ssl_init();
- SSL_CTX* ctx = SSL_CTX_new(SSLv23_client_method());
- SSL* ssl = ssl_connect(ctx, sock, host);
- if(ssl == NULL) luaI_error(L, -1, "ssl_connect error");
+ if(state->secure){
+ ssl_init();
+ state->ctx = SSL_CTX_new(SSLv23_client_method());
+ state->ssl = ssl_connect(state->ctx, state->sock, host);
+ if(state->ssl == NULL) luaI_error(L, -1, "ssl_connect error");
+ }
char* cont = "";
size_t cont_len = 0;
- if(params >= check + 1){
- check++;
- switch(lua_type(L, check)){
+ if(params >= 2){
+ switch(lua_type(L, 2)){
case LUA_TNUMBER:
case LUA_TSTRING:
- cont = (char*)luaL_tolstring(L, check, &cont_len);
+ cont = (char*)luaL_tolstring(L, 2, &cont_len);
break;
default:
p_fatal("cant send type");
@@ -523,37 +534,41 @@ int l_srequest(lua_State* L){
}
}
- str* header = str_init("");
- if(params >= check + 1){
- check++;
- lua_pushnil(L);
-
- for(;lua_next(L, check) != 0;){
- str_push(header, "\r\n");
- str_push(header, lua_tostring(L, -2));
- str_push(header, ": ");
- str_push(header, lua_tostring(L, -1));
- lua_pop(L, 1);
- }
+ lua_newtable(L);
+ int header_idx = lua_gettop(L);
+ luaI_tsets(L, header_idx, "User-Agent", "lullaby/"MAJOR_VERSION);
+
+ if(params >= 3){
+ luaI_jointable(L, header_idx, 3);
}
+
+ str* header = str_init("");
+ lua_pushnil(L);
+
+ for(;lua_next(L, header_idx) != 0;){
+ str_push(header, "\r\n");
+ str_push(header, lua_tostring(L, -2));
+ str_push(header, ": ");
+ str_push(header, lua_tostring(L, -1));
+ lua_pop(L, 1);
+ }
char* action = "GET";
- if(params >= check + 1){
- check++;
- action = (char*)lua_tostring(L, check);
+ if(params >= 4){
+ action = (char*)lua_tostring(L, 4);
}
//char* req = "GET / HTTP/1.1\nHost: amyy.cc\nConnection: Close\n\n";
- char* request = calloc(cont_len + header->len + 512, sizeof * request);
+ char* request = calloc(cont_len + header->len + strlen(host) + strlen(path) + 512, sizeof * request);
sprintf(request, "%s %s HTTP/1.1\r\nHost: %s\r\nConnection: Close%s\r\n\r\n%s", action, path, host, header->c, cont);
- //printf("%s\n", request);
+
str_free(header);
- int s = SSL_write(ssl, request, strlen(request));
+ int s = _request_write(state, request, strlen(request));
free(request);
- if(s <= 0) luaI_error(L, s, "SSL_write error");
+ if(s <= 0) luaI_error(L, s, "_request_write error");
str* a = str_init("");
char buffer[BUFFER_LEN];
@@ -561,7 +576,7 @@ int l_srequest(lua_State* L){
int extra_len = 0;
char* header_eof = NULL;
- for(; (len = SSL_read(ssl, buffer, BUFFER_LEN)) > 0;){
+ for(; (len = _request_read(state, buffer, BUFFER_LEN)) > 0;){
int blen = a->len;
str_pushl(a, buffer, len);
int offset = blen >= 4 ? 4 : blen;
@@ -572,7 +587,7 @@ int l_srequest(lua_State* L){
memset(buffer, 0, BUFFER_LEN);
}
- if(len < 0) luaI_error(L, len, "SSL_read error");
+ if(len < 0) luaI_error(L, len, "read error");
if(header_eof != NULL){
lua_newtable(L);
@@ -590,32 +605,37 @@ int l_srequest(lua_State* L){
luaI_treplk(L, idx, "Path", "code");
luaI_treplk(L, idx, "Request", "version");
luaI_treplk(L, idx, "Version", "code-name");
+
+ lua_pushstring(L, "code");
+ lua_gettable(L, idx);
+ int code = atoi(lua_tostring(L, -1));
+ luaI_tseti(L, idx, "code", code);
void* encoding = parray_get(owo, "Transfer-Encoding");
- struct _srequest_state *read_state = calloc(sizeof * read_state, 1);
- read_state->ctx = ctx;
- read_state->ssl = ssl;
- read_state->sock = sock;
+ //struct _srequest_state *read_state = calloc(sizeof * read_state, 1);
+ //read_state->ctx = state->ctx;
+ //read_state->ssl = state->ssl;
+ //read_state->sock = state->sock;
if(encoding != NULL){
if(strcmp(((str*)encoding)->c, "chunked") == 0){
- struct chunked_encoding_state* state = calloc(sizeof * state, 1);
- state->reading_length = 1;
- state->buffer = str_init("");
- state->content = str_init("");
+ struct chunked_encoding_state* chunk_state = calloc(sizeof * state, 1);
+ chunk_state->reading_length = 1;
+ chunk_state->buffer = str_init("");
+ chunk_state->content = str_init("");
- chunked_encoding_round(header_eof + 4, extra_len - 4, state);
+ chunked_encoding_round(header_eof + 4, extra_len - 4, chunk_state);
memset(buffer, 0, BUFFER_LEN);
- read_state->buffer = str_init("");
- read_state->state = state;
+ state->buffer = str_init("");
+ state->state = chunk_state;
}
} else {
- read_state->buffer = str_initl(header_eof + 4, extra_len - 4);
+ state->buffer = str_initl(header_eof + 4, extra_len - 4);
}
parray_clear(owo, STR);
- luaI_newstream(L, _srequest_read, _srequest_free, read_state);
+ luaI_newstream(L, _srequest_read, _srequest_free, state);
int v = lua_gettop(L);
luaI_tsetv(L, idx, "content", v);
lua_pushvalue(L, idx);
@@ -633,32 +653,48 @@ int l_srequest(lua_State* L){
return 1;
}
-int l_request(lua_State* L){
- const char* host = luaL_checkstring(L, 1);
- int sock = get_host((char*)host, (char*)lua_tostring(L, 2));
-
- char* path = "/";
- if(lua_gettop(L) >= 3)
- path = (char*)luaL_checkstring(L, 3);
-
- //char* req = "GET / HTTP/1.1\nHost: amyy.cc\nConnection: Close\n\n";
-
- char request[2000];
- sprintf(request, "GET %s HTTP/1.1\nHost: %s\nConnection: Close\n\n", path, host);
- write(sock, request, strlen(request));
+struct net_path_t {
+ str* path;
+ parray_t* query;
+};
- str* a = str_init("");
- char buffer[512];
- int len = 0;
+void path_parse(struct net_path_t* path, str* raw){
+ path->path = str_init("");
+ path->query = parray_init();
+
+ str* query_key = str_init("");
+ str* query_value = str_init("");
+
+ str** reading = &path->path;
+
+ for(int i = 0; i <= raw->len; i++){
+ if(raw->len - i > 1){
+ switch(raw->c[i]){
+ case '&':
+ parray_set(path->query, query_key->c, query_value);
+ str_clear(query_key);
+ query_value = str_init("");
+ //dont want to break here
+ case '?':
+ reading = &query_key;
+ i++;
+ break;
+ case '=':
+ reading = &query_value;
+ i++;
+ break;
+ }
+ }
- for(; (len = read(sock, buffer, 511)) != 0;){
- str_pushl(a, buffer, len);
- memset(buffer, 0, 512);
+ str_pushl(*reading, raw->c + i, 1);
}
- lua_pushstring(L, a->c);
-
- return 1;
+ if(*reading == query_value){
+ parray_set(path->query, query_key->c, query_value);
+ } else {
+ str_free(query_value);
+ }
+ str_free(query_key);
}
#define max_uri_size 2048
@@ -687,7 +723,7 @@ void* handle_client(void *_arg){
if(val == -2) net_error(client_fd, 414);
if(val >= 0){
- str* sk = (str*)parray_get(table, "Path");
+ str* path = (str*)parray_get(table, "Path");
str* sR = (str*)parray_get(table, "Request");
str* sT = (str*)parray_get(table, "Content-Type");
str* sC = (str*)parray_get(table, "Cookie");
@@ -702,14 +738,27 @@ void* handle_client(void *_arg){
sprintf(portc, "%i", args->port);
str* aa = str_init(portc);
- str_push(aa, sk->c);
-
- larray_t* params = larray_init();
- parray_t* v = route_match(args->paths, aa->c, &params);
+ struct net_path_t parsed_path;
+ path_parse(&parsed_path, path);
- if(sT != NULL)
- rolling_file_parse(L, &files_idx, &body_idx, header + 4, sT, bite - header_eof - 4, file_cont);
+ str* decoded_path;
+ int decoded_err = percent_decode(parsed_path.path, &decoded_path);
+ larray_t* params = NULL;
+ parray_t* v = NULL;
+ if(decoded_err == 1 || args->paths == NULL){
+ net_error(client_fd, 400);
+ } else {
+ str_push(aa, decoded_path->c);
+
+ params = larray_init();
+ v = route_match(args->paths, aa->c, &params);
+
+ if(sT != NULL)
+ rolling_file_parse(L, &files_idx, &body_idx, header + 4, sT, bite - header_eof - 4, file_cont);
+ }
+
+ str_free(decoded_path);
str_free(aa);
if(v != NULL){
lua_newtable(L);
@@ -730,7 +779,17 @@ void* handle_client(void *_arg){
luaI_tsetv(L, req_idx, "cookies", lcookie);
parray_clear(cookie, STR);
- parray_remove(table, "Cookie", NONE);
+ parray_remove(table, "Cookie", STR);
+ }
+
+ if(parsed_path.query->len != 0){
+ lua_newtable(L);
+ int lquery = lua_gettop(L);
+ for(int i = 0; i != parsed_path.query->len; i++){
+ luaI_tsetsl(L, lquery, parsed_path.query->P[i].key->c, ((str*)parsed_path.query->P[i].value)->c, ((str*)parsed_path.query->P[i].value)->len);
+ }
+
+ luaI_tsetv(L, req_idx, "query", lquery);
}
lua_pushlightuserdata(L, file_cont);
@@ -746,6 +805,8 @@ void* handle_client(void *_arg){
}
luaI_tsets(L, req_idx, "ip", inet_ntoa(args->cli.sin_addr));
+ luaI_tsets(L, req_idx, "path", parsed_path.path->c);
+ luaI_tsets(L, req_idx, "rawpath", path->c);
if(bite == -1){
client_fd = -2;
@@ -771,7 +832,6 @@ void* handle_client(void *_arg){
lua_newtable(L);
int header_idx = lua_gettop(L);
luaI_tseti(L, header_idx, "Code", 200);
- luaI_tsets(L, header_idx, "Content-Type", "text/html");
luaI_tsetv(L, res_idx, "header", header_idx);
@@ -837,6 +897,9 @@ net_end:
}
+ str_free(parsed_path.path);
+ parray_clear(parsed_path.query, STR);
+
if(file_cont->boundary != NULL) str_free(file_cont->current);
if(file_cont->boundary != NULL) str_free(file_cont->boundary);
if(file_cont->boundary_id != NULL) str_free(file_cont->boundary_id);
diff --git a/src/net.h b/src/net.h
index f7fd460..76dd462 100644
--- a/src/net.h
+++ b/src/net.h
@@ -42,7 +42,7 @@ int clean_lullaby_net(lua_State* L);
static const luaL_Reg net_function_list [] = {
{"listen",l_listen},
- //{"request",l_request},
+ {"request",l_request},
{"srequest",l_srequest},
{"wss",l_wss},
diff --git a/src/net/lua.c b/src/net/lua.c
index d6bba65..2e46943 100644
--- a/src/net/lua.c
+++ b/src/net/lua.c
@@ -228,8 +228,11 @@ int l_sendfile(lua_State* L){
p_fatal("missing permissions");
}
+ lua_pushstring(L, "Content-Type");
+ lua_gettable(L, header);
+
char* ext = strrchr(path, '.');
- if(ext && mime_type != NULL){
+ if(lua_isnil(L, -1) && ext && mime_type != NULL){
char* content_type = map_get(mime_type, ext + 1);
if(content_type)
diff --git a/src/net/util.c b/src/net/util.c
index 3e91c7c..78e3043 100644
--- a/src/net/util.c
+++ b/src/net/util.c
@@ -16,16 +16,16 @@ int64_t recv_header(int client_fd, char** _buffer, char** header_eof){
return -1;
}
- if((len += n) >= MAX_HEADER_SIZE){
- return -2;
- }
-
// search the last 4 characters too if they exist
// this could probably be changed to 3
- int64_t start_len = len - 4 > 0 ? len - 4 : 0;
+ int64_t start_len = len - 4 > 0 ? len - 4 : len;
int64_t search_end = len - 4 > 0 ? n + 4 : n;
if((*header_eof = memmem(buffer + start_len, search_end, "\r\n\r\n", 4)) != NULL){
- return len;
+ return len + n;
+ }
+
+ if((len += n) >= MAX_HEADER_SIZE){
+ return -2;
}
buffer = realloc(buffer, sizeof* buffer * (len + BUFFER_SIZE + 1));
@@ -522,3 +522,30 @@ int net_error(int fd, int code){
send(fd, out, strlen(out), MSG_NOSIGNAL);
return 0;
}
+
+int percent_decode(str* input, str** _output){
+ str* output = str_init("");
+
+ //could maybe make this better by using memmem to find occurrences of %
+ for(int i = 0; i <= input->len; i++){
+ if(input->c[i] == '%' && input->len - i >= 3){
+ str* hex = str_initfl(input->c + i + 1, 2);
+
+ //casting a long to a char pointer is a horrible idea
+ long c = strtol(hex->c, NULL, 16);
+ if(c == 0){
+ str_free(hex);
+ *_output = output;
+ return 1;
+ }
+
+ str_pushl(output, ((char*)&c), 1);
+ str_free(hex);
+ i += 2;
+ } else {
+ str_pushl(output, input->c + i, 1);
+ }
+ }
+ *_output = output;
+ return 0;
+}
diff --git a/src/net/util.h b/src/net/util.h
index cfac065..b8bc824 100644
--- a/src/net/util.h
+++ b/src/net/util.h
@@ -56,3 +56,6 @@ int match_param(char* path, char* match, parray_t* arr);
void parse_mimetypes();
int net_error(int fd, int code);
+
+int percent_decode(str* input, str** _output);
+
diff --git a/src/types/str.c b/src/types/str.c
index 0c8d63a..e1818a2 100644
--- a/src/types/str.c
+++ b/src/types/str.c
@@ -16,6 +16,19 @@ str* str_initl(const char* init, size_t len){
return s;
}
+str* str_initfl(const char* init, size_t len){
+
+ str* s = malloc(sizeof * s);
+ s->_bytes = len + 1 + alloc_buffer;
+ s->c = malloc(s->_bytes);
+ if(s->c == NULL) p_fatal("failed to allocate string\n");
+ s->len = len ;
+
+ memcpy(s->c, init, (len) * sizeof * init);
+ s->c[len] = '\0';
+ return s;
+}
+
str* str_init(const char* init){
return str_initl(init, strlen(init));
}
diff --git a/src/types/str.h b/src/types/str.h
index 86490cc..e650542 100644
--- a/src/types/str.h
+++ b/src/types/str.h
@@ -12,6 +12,9 @@ typedef struct {
} str;
str* str_initl(const char*, size_t len);
+//str_initfl has the 'correct' behaviour where it forces the len and doesnt read extra bytes
+//plan to switch everything to str_initfl, when everything will work with it
+str* str_initfl(const char*, size_t len);
str* str_init(const char*);
void str_free(str*);
void str_push(str*, const char*);
@@ -19,4 +22,4 @@ void str_pushl(str*, const char*, size_t);
void str_clear(str*);
void str_popf(str*, int);
void str_popb(str*, int);
-#endif //__STR_H \ No newline at end of file
+#endif //__STR_H