From 18b2a4391fe8d442e917f5b2c2f26b18ec9374ac Mon Sep 17 00:00:00 2001 From: Aki Date: Thu, 4 Mar 2021 22:22:28 +0100 Subject: Partially implementd writing --- default.lua | 8 +++- plop.c | 8 ---- stream.c | 139 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- stream.h | 5 +++ 4 files changed, 148 insertions(+), 12 deletions(-) diff --git a/default.lua b/default.lua index 7100927..56e5082 100644 --- a/default.lua +++ b/default.lua @@ -32,6 +32,10 @@ return function (stream) headers_table = HEADER:format(headers_table, header, value) end local response = RESPONSE:format(method, path, version, headers_table) - local headers = {Connection="close", ["Content-Length"]=#response, ["Content-Type"]="text/html"} - return {status=status, headers=headers, data=response} + stream:write( + "HTTP/1.1 ", status, "\r\n", + "Connection: close\r\n", + "Content-Length: ", #response, "\r\n", + "Content-Type: text/html\r\n\r\n", response) + stream:flush() end diff --git a/plop.c b/plop.c index 34c8d06..6c2717b 100644 --- a/plop.c +++ b/plop.c @@ -164,14 +164,6 @@ int plop_handle_client(lua_State * L, struct epoll_event * event) { case LUA_OK: { - int n = lua_gettop(c->L); - - if (0 == n) - { - lua_pushnil(c->L); - } - - response_send(c->L, c->fd); connection_free(L, c); return 0; } diff --git a/stream.c b/stream.c index d456619..0863cfd 100644 --- a/stream.c +++ b/stream.c @@ -38,11 +38,15 @@ int stream_push_new(lua_State * L, const int fd) lua_rawset(L, -3); lua_pushliteral(L, "write"); - lua_pushnil(L); // TODO: Implement writing operation. + lua_pushcfunction(L, stream_write); lua_rawset(L, -3); lua_pushliteral(L, "flush"); - lua_pushnil(L); // TODO: Implement flush for output buffer. + lua_pushcfunction(L, stream_flush); + lua_rawset(L, -3); + + lua_pushliteral(L, "flush"); + lua_pushcfunction(L, stream_flush); lua_rawset(L, -3); } lua_rawset(L, -3); @@ -262,3 +266,134 @@ int stream_readk(lua_State * L, int status, lua_KContext ctx) return lua_gettop(L); } + +/// Writes to output buffer. +/// \param L Lua state in which Stream resides +/// \return Number of the results pushed to the stack +int stream_write(lua_State * L) +{ + const int n = lua_gettop(L); + if (2 > n) + { + lua_pushliteral(L, "At least two arguments expected"); + return lua_error(L); + } + + struct stream * s = lua_touserdata(L, 1); + + if (NULL == s) + { + lua_pushliteral(L, "Missing stream argument"); + return lua_error(L); + } + + if (NULL == s->out.data) + { + void * buffer = malloc(1024); + + if (NULL == buffer) + { + lua_pushliteral(L, "Could not allocate buffer for stream"); + return lua_error(L); + } + + s->out.data = buffer; + s->out.allocated = 1024; + s->out.length = 0; + s->out.offset = 0; + s->out.next = 0; + } + + for (int i = 2; n >= i; ++i) + { + size_t data_length; + const char * data = lua_tolstring(L, i, &data_length); + const int free_space = s->out.allocated - s->out.length; + + if (free_space >= (int) data_length) + { + memcpy(&s->out.data[s->out.length], data, data_length); + s->out.length += (int) data_length; + } + else + { + // TODO: grow + } + } + + lua_pop(L, n); + return 0; +} + +/// Flushes the contents of output buffer writing it to the socket. +/// \param L Lua state in which Stream resides +/// \return Number of the results pushed to the stack +int stream_flush(lua_State * L) +{ + const int n = lua_gettop(L); + + if (1 != n) + { + lua_pushliteral(L, "Expected one argument"); + return lua_error(L); + } + + struct stream * s = lua_touserdata(L, 1); + + if (NULL == s) + { + lua_pushliteral(L, "Missing stream argument"); + return lua_error(L); + } + + const int bytes_written = write(s->fd, s->out.data, s->out.length); + + if (-1 == bytes_written) + { + // TODO: Errors and yield + } + else + { + s->out.length -= bytes_written; + } + + lua_pop(L, 1); + return 0; +} + +/// Continuation of the flush operation. +/// \param L Lua state in which Stream resides +/// \param status Unused +/// \param ctx TODO +/// \return Number of the results pushed to the stack +int stream_flushk(lua_State * L, const int status, lua_KContext ctx) +{ + return 0; +} + +/// Discards the contents of output buffer without writing it anywhere. +/// \param L Lua state in which Stream resides +/// \return Number of the results pushed to the stack +int stream_discard(lua_State * L) +{ + const int n = lua_gettop(L); + + if (1 != n) + { + lua_pushliteral(L, "Expected one argument"); + return lua_error(L); + } + + struct stream * s = lua_touserdata(L, 1); + + if (NULL == s) + { + lua_pushliteral(L, "Missing stream argument"); + return lua_error(L); + } + + s->out.length = 0; + + lua_pop(L, 1); + return 0; +} diff --git a/stream.h b/stream.h index f1bc32c..5119fcc 100644 --- a/stream.h +++ b/stream.h @@ -15,9 +15,14 @@ struct stream { int fd; struct buffer in; + struct buffer out; }; int stream_push_new(lua_State *, const int); int stream_gc(lua_State *); int stream_read(lua_State *); int stream_readk(lua_State *, const int, lua_KContext); +int stream_write(lua_State *); +int stream_flush(lua_State *); +int stream_flushk(lua_State *, const int, lua_KContext); +int stream_discard(lua_State *); -- cgit v1.1