summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--plop.c14
-rw-r--r--response.c104
-rw-r--r--response.h3
3 files changed, 109 insertions, 12 deletions
diff --git a/plop.c b/plop.c
index 0f045f8..da51251 100644
--- a/plop.c
+++ b/plop.c
@@ -137,17 +137,7 @@ int handle_client(lua_State * L, struct epoll_event * event)
lua_insert((*request)->lua, 1);
lua_call((*request)->lua, 5, 1);
- size_t length;
- const char * body = lua_tolstring((*request)->lua, -1, &length);
-
- if (NULL != body)
- {
- respond_with_body((*request)->fd, STATUS_OK, body, (int) length);
- }
- else
- {
- respond_only_status((*request)->fd, STATUS_INTERNAL_SERVER_ERROR);
- }
+ int result = response_send((*request)->lua, (*request)->fd);
close((*request)->fd);
@@ -157,7 +147,7 @@ int handle_client(lua_State * L, struct epoll_event * event)
*request = NULL;
}
- return 0;
+ return result;
}
/// Accepts awaiting connections if any.
diff --git a/response.c b/response.c
index df465d0..b2a72d7 100644
--- a/response.c
+++ b/response.c
@@ -1,10 +1,114 @@
#include "response.h"
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <unistd.h>
+#include <lua.h>
+
#include "http.h"
+/// Sends a response based on the current top value on the stack.
+/// \param L Lua state to send response for
+/// \param fd File descriptor of a socket to write to
+/// \return Bytes written or -1 on error
+/// \see write(2)
+// TODO: Consider splitting response_send into smaller functions.
+int response_send(lua_State * L, const int fd)
+{
+ static const char * error_response =
+ "HTTP/1.1 500\r\n"
+ "Connection: close\r\n"
+ "\r\n";
+
+ if (0 == lua_istable(L, -1) || 0 == lua_checkstack(L, 5))
+ {
+ lua_pop(L, 1);
+ return write(fd, error_response, strlen(error_response));
+ }
+
+ int bytes_total = 2048 * sizeof(char);
+ int bytes_used = 0;
+ char * buffer = malloc(bytes_total);
+
+ lua_pushstring(L, "status");
+ lua_gettable(L, -2);
+ const lua_Integer status = lua_tointeger(L, -1);
+ lua_pop(L, 1);
+
+ if (0 == status || NULL == buffer)
+ {
+ lua_pop(L, 1);
+ return write(fd, error_response, strlen(error_response));
+ }
+
+ bytes_used = snprintf(buffer, bytes_total, "HTTP/1.1 %d\r\n\r\n", (int) status) - 2;
+
+ lua_pushstring(L, "headers");
+ lua_gettable(L, -2);
+
+ if (0 == lua_istable(L, -1))
+ {
+ lua_pop(L, 2);
+ return write(fd, buffer, bytes_used + 2);
+ }
+
+ static const char * header_pattern = "%s: %s\r\n";
+
+ lua_pushnil(L);
+ while (0 != lua_next(L, -2) && 0 != lua_isstring(L, -2))
+ {
+ const char * key = lua_tostring(L, -2);
+ const char * value = lua_tostring(L, -1); // TODO: Check the type of the header's value?
+ const int bytes_left = bytes_total - bytes_used;
+ int new_bytes = snprintf(buffer + bytes_used, bytes_left, header_pattern, key, value);
+ while (bytes_left <= new_bytes)
+ {
+ bytes_total += 2048;
+ if (65536 < bytes_total)
+ {
+ free(buffer);
+ lua_pop(L, 4);
+ return write(fd, error_response, strlen(error_response));
+ }
+ buffer = realloc(buffer, bytes_total);
+ if (NULL == buffer)
+ {
+ lua_pop(L, 4);
+ return write(fd, error_response, strlen(error_response));
+ }
+ new_bytes = snprintf(buffer + bytes_used, bytes_left, header_pattern, key, value);
+ }
+ bytes_used += new_bytes;
+ lua_pop(L, 1);
+ }
+
+ if (bytes_total < bytes_used + 2)
+ {
+ bytes_total += 2;
+ buffer = realloc(buffer, bytes_total);
+ if (NULL == buffer)
+ {
+ lua_pop(L, 2);
+ return write(fd, error_response, strlen(error_response));
+ }
+ }
+
+ lua_pop(L, 1);
+ buffer[bytes_used] = '\r';
+ buffer[bytes_used + 1] = '\n';
+ bytes_used += 2;
+
+ // TODO: Add data write
+
+ int result = write(fd, buffer, bytes_used );
+ free(buffer);
+ lua_pop(L, 1);
+
+ return result;
+}
+
/// Sends a simple response only with a status to the client.
/// \param fd File descriptor of the client socket
/// \param status HTTP response status code
diff --git a/response.h b/response.h
index ec90bc5..c9b9c06 100644
--- a/response.h
+++ b/response.h
@@ -1,6 +1,9 @@
#pragma once
+#include <lua.h>
+
#include "http.h"
+int response_send(lua_State *, const int);
int respond_only_status(int, enum status);
int respond_with_body(int, enum status, const char *, int);