diff options
| author | ame <[email protected]> | 2025-06-13 20:31:24 -0500 |
|---|---|---|
| committer | ame <[email protected]> | 2025-06-13 20:31:24 -0500 |
| commit | 2efda12fcae7869bc3cc8782dbcaceae65d251f8 (patch) | |
| tree | 9f380005409549d69eb0b6cf1f2a661dbb38c03d | |
| parent | c6714b7212548a55de8ed9e22f4b416f312358b0 (diff) | |
clean net code and made net docs better
| -rw-r--r-- | docs/net/listen.md (renamed from docs/net.md) | 77 | ||||
| -rw-r--r-- | docs/net/websocket.md | 46 | ||||
| -rw-r--r-- | src/net.c | 150 | ||||
| -rw-r--r-- | src/net/common.h | 4 |
4 files changed, 82 insertions, 195 deletions
diff --git a/docs/net.md b/docs/net/listen.md index ca17da9..6b7f12c 100644 --- a/docs/net.md +++ b/docs/net/listen.md @@ -1,38 +1,25 @@ -# net
-
## listen (mostly IMPLEMENTED)
-'takes a function with 1 argument and a integer for a port
+net.listen(function, port)
(intentionally styled after expressjs:3)
the function will be ran on initilization, the argument has info on the server and functions to set it up
-**
-right now everything within a server:GET function is partially global, it can read global variables (by making a copy),
-it can not read/copy local variables or modify globals
-**
-
-allows a third optional argument that offers some other options in a table format
-
|name|default value|extra info|
|--|--|--|
-|mime.types.file**|/etc/mime.types|formated similarly to [this](https://wiki.debian.org/MIME/etc/mime.types)|
-|max.connections**|64|maximum number of connections that can be opened at the same time, will respond with error(503)|
-|max.header.size**|1<<20 (1048576)|max header size before refusing connection with error(431)|
-|max.uri.size**|idk yet|maximum uri size before refusing request with error(414)|
-|max.request.timeout**|idk yet|maximum time server will wait for request to be parsed|
+|mimetypes|/etc/mime.types|file used to auto assign content-type when using res:sendfile, nil to skip|
+|max_connections**|64|maximum number of connections that can be opened at the same time, will respond with error(503)|
+|max_header**|1<<20 (1048576)|max header size before refusing connection with error(431)|
+|max_uri**|idk yet|maximum uri size before refusing request with error(414)|
the server will send these codes for these reasons
|code|cause|
|--|--|
-|503|too many current requests, more than max.connections|
+|503|too many current requests, more than max_connections|
|500|anytime a server route crashes|
-|431|header is larger than max header size, more than max.header.size|
-|414|request uri is longer than max.uri.size|
-|408**|request took too long to read all of (recv timeout) than max.request.timeout|
-
-(more to come?**)
+|431|header is larger than max header size, more than header_size|
+|414|request uri is longer than max_uri|
```lua
llib.net.listen(function(server)
@@ -43,19 +30,7 @@ end, 80) ```lua
llib.net.listen(function(server)
...
-end, 80, {["mime.types.file"] = "/etc/mime.types"})
-```
-
-### server:lock server:unlock
-
-continues on the current thread, but pauses all other threads at that point
-
-```lua
-...
-server:lock()
---do something with a global
-server:unlock()
-...
+end, 80)
```
### server:close **
@@ -64,7 +39,7 @@ closes server ### server:GET/POST/...
-'takes a string (the path) and a function to be ran in the background on request
+server:GET(path, function)
the function has 2 arguments, the first (res) contains functions and info about resolving the request,
the second (req) contains info on the request, the path allows for wildcards, multiple get requests per path is allowed
@@ -94,40 +69,44 @@ end) #### res:write
-'takes a string
+res:write(content)
sends the string to the client, constructs a header on first call (whether or not res.header._sent is null)
(the constructed header can not be changed later on in the request*), and sends the string without closing the client
```lua
-...
res:write("<h1>hello world</h1>")
res:write("<h1>good bye world</h1>")
-...
```
*well it can but it wont do anything
#### res:send
-'takes a string
+res:send(content)
sends the string to the client, constructs a header then closes client_fd
```lua
-...
res:send("<h1>hello world</h1>")
-...
```
+functionaly identical to res:write and res:close
+
#### res:close
+res:close()
+
closes connection, sets res.client_fd to -1, any calls that use this value will fail
this will still run any selected functions!
+this is called automatically when there are no more function
+
#### res:stop
+res:stop()
+
prevents all further selected functions from running
#### res.header
@@ -137,9 +116,8 @@ table containing all head information, anything added to it will be used, certai |key|side effect|
|--|--|
|Code|Changes response note, ie: (200: OK)|
-
+|Content-Type|this is changed automatically with res:sendfile|
```lua
-...
res.header["Code"] = 404
res.header["test"] = "wowa"
-- new header will have a code of 404 (at the top duh)
@@ -148,16 +126,15 @@ res.header["test"] = "wowa" -- HTTP/1.1 404 Not Found
-- ...
-- test: wowa
-...
```
### res:sendfile
-'takes one string, which is a path that will be served, must be a file
+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)
-option table
+options table
|key|value|effect|
|--|--|--|
@@ -166,9 +143,7 @@ option table ```lua
-...
res:sendfile("./html/index.html")
-...
```
### req.parameters
@@ -193,11 +168,15 @@ these can, of course be used with wildcards however you want ### req:roll
-'takes an integer of bytes to read & parse (optional, otherwise the max amount of bytes will be read)
+req:roll(bytes?)
+
+when bytes is null it will read as much as possible (may not be the full request)
will update req according to how the bytes needed to be parsed, returns the number of bytes read (not necessarily parsed), 0 if there
is no more ready data, -1 if all data has been read, and any other values \< -1 is a recv error (add 1 to the error code)
+> waiting on a rewrite for this, all that will be changed will be how errors are returned
+
```lua
--when a request contains "hello world"
req.Body --"hello"
diff --git a/docs/net/websocket.md b/docs/net/websocket.md new file mode 100644 index 0000000..5a82a70 --- /dev/null +++ b/docs/net/websocket.md @@ -0,0 +1,46 @@ +## ws + +net.wss(url) +net.ws(url)** + +both function identically, wss just uses openssl over socket + +will call each other when the url protocol mismatches the function + +can return an error + +```lua +net.wss("amyy.cc") -- connects to wss://amyy.cc +net.wss("ws://amyy.cc") -- identical to net.wss("amyy.cc" +``` + +```lua +local con = new.ws("amyy.cc") + +while true do + local frame = con:read() + print(frame.content) +end +``` + +### con:read + +con:read() + +reads the oldest unread frame from the server or wait for the next frame + +can return an error + +return table has the frame content (.content) and opcode (.opcode) + +### con:write + +con:write(content) + +sends a frame, returns nil or an error + +### con:close + +con:close() + +calls __gc early @@ -668,10 +668,6 @@ int l_request(lua_State* L){ _Atomic size_t threads = 0;
void* handle_client(void *_arg){
- //printf("--\n");
- //pthread_mutex_lock(&mutex);
-
- //int read_state = 0;
thread_arg_struct* args = (thread_arg_struct*)_arg;
int client_fd = args->fd;
char* buffer;
@@ -679,58 +675,11 @@ void* handle_client(void *_arg){ int header_eof = -1;
lua_State* L = args->L;
luaL_openlibs(L);
- //sleep(1);
- //create state for this thread
-
- /*
- lua_State* L = luaL_newstate();
-
- luaL_openlibs(L);
- pthread_mutex_lock(&mutex);
- int old_top = lua_gettop(args->L);
- lua_getglobal(args->L, "_G");
-
-//time_start(copy)
- luaI_deepcopy(args->L, L, SKIP_GC);
-
-//time_end("copy", copy)
- lua_settop(args->L, old_top);
- pthread_mutex_unlock(&con_mutex);
-
- //l_pprint(L);
- //lua_setglobal(L, "_G");
- lua_set_global_table(L);
- pthread_mutex_unlock(&mutex);
- */
- //printf("start: %f\n",(double)(clock() - begin) / CLOCKS_PER_SEC);
- //read full request
-//time_start(recv)
char* header = NULL;
int64_t bite = recv_header(client_fd, &buffer, &header);
- header_eof = header - buffer;
- /*printf("%x = %p - %p\n", header_eof, header, buffer);
-
- if(bite == -2) net_error(client_fd, 431);
- printf("'");
- for(int i = bite - 20; i != bite; i++){
- putchar(buffer[i]);
- }
- printf("'\n");*/
- /*
-
- return NULL;
- int64_t bytes_received = recv_full_buffer(client_fd, &buffer, &header_eof, &read_state);
-
-
- for(int i = 0; i != header_eof; i++)
- putchar(buffer[i]);
- putchar('\n');
-
- //printf("hi %li:%i\n", bytes_received,header_eof);
- if(bytes_received == -2) net_error(client_fd, 431);
- */
+ header_eof = header - buffer;
if(bite > 0){
parray_t* table;
@@ -759,23 +708,8 @@ void* handle_client(void *_arg){ str* aa = str_init(portc);
str_push(aa, sk->c);
- //parray_t* v = parray_find(paths, aa->c);
larray_t* params = larray_init();
parray_t* v = route_match(paths, aa->c, ¶ms);
-
- /*for(int i = 0; i != params->len; i++){
- int id = larray_geti(params, i);
- parray_t* par = params->arr[id].value;
- printf("%i\n", i);
- for(int x = 0; x != par->len; x++){
- printf("\t%s : %s\n",par->P[x].key->c, (char*)par->P[x].value);
- }
-
- parray_clear(par, STR);
-
- }
-
- larray_clear(params);*/
if(sT != NULL)
rolling_file_parse(L, &files_idx, &body_idx, header + 4, sT, bite - header_eof - 4, file_cont);
@@ -788,7 +722,6 @@ void* handle_client(void *_arg){ int res_idx = lua_gettop(L);
//handle cookies
- //TODO: enable and test with valgrind
if(sC != NULL){
lua_newtable(L);
int lcookie = lua_gettop(L);
@@ -796,7 +729,6 @@ void* handle_client(void *_arg){ parray_t* cookie = parray_init();
gen_parse(sC->c, sC->len, &cookie);
for(int i = 0; i != cookie->len; i++){
- //printf("%s %s\n", cookie->P[i].key->c, ((str*)cookie->P[i].value)->c);
luaI_tsetsl(L, lcookie, cookie->P[i].key->c, ((str*)cookie->P[i].value)->c, ((str*)cookie->P[i].value)->len);
}
luaI_tsetv(L, req_idx, "cookies", lcookie);
@@ -804,26 +736,14 @@ void* handle_client(void *_arg){ parray_remove(table, "Cookie", NONE);
}
- /*
- //handle files
- if(sT != NULL && bytes_received > 0){
- int pf = file_parse(L, buffer + header_eof, sT, bytes_received - header_eof);
-
- if(pf >= 0){
- luaI_tsetv(L, req_idx, "files", pf);
- parray_set(table, "Body", (void*)str_init(""));
- }
- }*/
+
lua_pushlightuserdata(L, file_cont);
int ld = lua_gettop(L);
luaI_tsetv(L, req_idx, "_data", ld);
luaI_tsetv(L, req_idx, "files", files_idx);
- //printf("cookie and file: %f\n",(double)(clock() - begin) / CLOCKS_PER_SEC);
- //parray_set(table, "Body", (void*)str_initl(buffer + header_eof + 4, buffer_len - header_eof - 4));
- //luaI_tsetsl(L, req_idx, "Body", buffer + header_eof + 4, bytes_received - header_eof - 4);
luaI_tsetv(L, req_idx, "Body", body_idx);
- //printf("%s\n",buffer);
+
for(int i = 0; i != table->len; i+=1){
//printf("'%s' :: '%s'\n",table[i]->c, table[i+1]->c);
luaI_tsets(L, req_idx, table->P[i].key->c, ((str*)table->P[i].value)->c);
@@ -838,7 +758,6 @@ void* handle_client(void *_arg){ luaI_tseti(L, req_idx, "_bytes", bite - header_eof - 4);
luaI_tseti(L, req_idx, "client_fd", client_fd);
luaI_tsetcf(L, req_idx, "roll", l_roll);
- //luaI_tsetcf(L, req_idx, "continue", l_continue);
//functions
luaI_tsetcf(L, res_idx, "send", l_send);
@@ -891,7 +810,6 @@ void* handle_client(void *_arg){ int func = lua_gettop(L);
lua_assign_upvalues(L, func);
- //lua_pushvalue(L, func); // push function call
lua_pushvalue(L, res_idx); //push methods related to dealing with the request
lua_pushvalue(L, req_idx); //push info about the request
@@ -924,15 +842,6 @@ net_end: }
- void* awa;
- /*if((awa = parray_get(file_cont, "_current")) != NULL) str_free(awa);
- if((awa = parray_get(file_cont, "_boundary")) != NULL) str_free(awa);
- if((awa = parray_get(file_cont, "_boundary_id")) != NULL) str_free(awa);
- if((awa = parray_get(file_cont, "_table_idx")) != NULL) free(awa);
- if((awa = parray_get(file_cont, "_status")) != NULL) free(awa);
- if((awa = parray_get(file_cont, "_dash_count")) != NULL) free(awa);
-
- parray_clear(file_cont, NONE);*/
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);
@@ -941,19 +850,17 @@ net_end: }
parray_clear(table, STR);
}
+
if(client_fd != -1){
shutdown(client_fd, 2);
closesocket(client_fd);
}
+
free(args);
free(buffer);
lua_close(L);
- //printf("closed: %f\n",(double)(clock() - begin) / CLOCKS_PER_SEC);
- pthread_mutex_lock(&mutex);
+
threads--;
- pthread_mutex_unlock(&mutex);
- //printf("out\n");
-//time_end("full", full)
return NULL;
}
@@ -994,12 +901,6 @@ int start_serv(lua_State* L, int port){ if(listen(server_fd, max_con) < 0)
p_fatal("failed to listen\n");
- if (pthread_mutex_init(&mutex, NULL) != 0)
- p_fatal("mutex init failed\n");
-
- if (pthread_mutex_init(&con_mutex, NULL) != 0)
- p_fatal("con_mutex init failed\n");
-
for(;;){
struct sockaddr_in client_addr;
socklen_t client_addr_len = sizeof(client_addr);
@@ -1017,7 +918,6 @@ int start_serv(lua_State* L, int port){ continue;
}
- //open a state to call shit, should be somewhat thread safe
thread_arg_struct* args = malloc(sizeof * args);
args->fd = *client_fd;
@@ -1025,36 +925,19 @@ int start_serv(lua_State* L, int port){ args->cli = client_addr;
args->L = luaL_newstate();
- //luaL_openlibs(args->L);
-
- pthread_mutex_lock(&mutex);
int old_top = lua_gettop(L);
lua_getglobal(L, "_G");
- //time_start(copy)
- luaI_copyvars(L, args->L);
-
- //time_end("copy", copy)
+ luaI_copyvars(L, args->L);
lua_settop(L, old_top);
-
- //l_pprint(L);
- //lua_setglobal(L, "_G");
lua_set_global_table(args->L);
- pthread_mutex_unlock(&mutex);
- pthread_mutex_lock(&mutex);
threads++;
- pthread_mutex_unlock(&mutex);
-
- //pthread_mutex_lock(&con_mutex);
//send request to handle_client()
pthread_t thread_id;
pthread_create(&thread_id, NULL, handle_client, (void*)args);
pthread_detach(thread_id);
-
- //double lock, wait for thread to unlock it
- //pthread_mutex_lock(&con_mutex);
//handle_client((void*)args);
free(client_fd);
@@ -1120,16 +1003,6 @@ gen_reqs(TRACE); gen_reqs(PATCH);
gen_reqs(all); //non standard lol, like expressjs 'use' keyword :3
-int l_lock(lua_State* L){
- pthread_mutex_lock(&lua_mutex);
- return 0;
-}
-
-int l_unlock(lua_State* L){
- pthread_mutex_unlock(&lua_mutex);
- return 0;
-}
-
int l_listen(lua_State* L){
if(lua_gettop(L) != 2) {
@@ -1153,14 +1026,7 @@ int l_listen(lua_State* L){ luaI_tsetcf(L, mt, "TRACE", l_TRACEq);
luaI_tsetcf(L, mt, "PATCH", l_PATCHq);
luaI_tsetcf(L, mt, "all", l_allq);
- lua_pushstring(L, "lock");
- lua_pushcfunction(L, l_lock);
- lua_settable(L, -3);
-
- lua_pushstring(L, "unlock");
- lua_pushcfunction(L, l_unlock);
- lua_settable(L, -3);
-
+
lua_pushstring(L, "port");
lua_pushvalue(L, 2);
lua_settable(L, -3);
diff --git a/src/net/common.h b/src/net/common.h index 828cb04..fbafb58 100644 --- a/src/net/common.h +++ b/src/net/common.h @@ -56,10 +56,6 @@ struct sarray_t { int len; }; -static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_mutex_t con_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_mutex_t lua_mutex = PTHREAD_MUTEX_INITIALIZER; - extern map_t* mime_type; #endif |
