[hackers] [quark][PATCH] Add skeleton for keep-alive connections

From: José Miguel Sánchez García <soy.jmi2k_AT_gmail.com>
Date: Thu, 29 Oct 2020 10:16:36 +0000

The bare minimum has been implemented, it is currently unused. It allows
the server to maintain a stateful connection with the client. Also,
keep-alive connections are more efficient than successive
request/response pairs of connections.
---
 http.c | 21 +++++++++++++++++++--
 http.h |  9 +++++++++
 main.c | 23 +++++++++++++++++++++--
 3 files changed, 49 insertions(+), 4 deletions(-)
diff --git a/http.c b/http.c
index f1e15a4..5b8848e 100644
--- a/http.c
+++ b/http.c
_AT_@ -17,6 +17,7 @@
 #include <unistd.h>
 
 #include "config.h"
+#include "data.h"
 #include "http.h"
 #include "util.h"
 
_AT_@ -57,6 +58,11 @@ const char *res_field_str[] = {
 	[RES_CONTENT_TYPE]   = "Content-Type",
 };
 
+const char *lifetime_str[] = {
+	[LT_CLOSE]      = "close",
+	[LT_KEEP_ALIVE] = "keep-alive",
+};
+
 enum status
 http_prepare_header_buf(const struct response *res, struct buffer *buf)
 {
_AT_@ -75,8 +81,9 @@ http_prepare_header_buf(const struct response *res, struct buffer *buf)
 	if (buffer_appendf(buf,
 	                   "HTTP/1.1 %d %s\r\n"
 	                   "Date: %s\r\n"
-	                   "Connection: close\r\n",
-	                   res->status, status_str[res->status], tstmp)) {
+	                   "Connection: %s\r\n",
+	                   res->status, status_str[res->status], tstmp,
+			   lifetime_str[res->lifetime])) {
 		goto err;
 	}
 
_AT_@ -839,6 +846,9 @@ void
 http_prepare_error_response(const struct request *req,
                             struct response *res, enum status s)
 {
+	struct buffer buf;
+	size_t progress;
+
 	/* used later */
 	(void)req;
 
_AT_@ -861,4 +871,11 @@ http_prepare_error_response(const struct request *req,
 			res->status = S_INTERNAL_SERVER_ERROR;
 		}
 	}
+
+	if (data_prepare_error_buf(res, &buf, &progress)
+	    || esnprintf(res->field[RES_CONTENT_LENGTH],
+	              sizeof(res->field[RES_CONTENT_LENGTH]),
+	              "%zu", buf.len)) {
+		s = S_INTERNAL_SERVER_ERROR;
+	}
 }
diff --git a/http.h b/http.h
index bfaa807..0e2367b 100644
--- a/http.h
+++ b/http.h
_AT_@ -69,9 +69,17 @@ enum res_type {
 	NUM_RES_TYPES,
 };
 
+enum lifetime {
+	LT_CLOSE,
+	LT_KEEP_ALIVE,
+};
+
+extern const char *lifetime_str[];
+
 struct response {
 	enum res_type type;
 	enum status status;
+	enum lifetime lifetime;
 	char field[NUM_RES_FIELDS][FIELD_MAX];
 	char uri[PATH_MAX];
 	char path[PATH_MAX];
_AT_@ -83,6 +91,7 @@ struct response {
 
 enum conn_state {
 	C_VACANT,
+	C_START,
 	C_RECV_HEADER,
 	C_SEND_HEADER,
 	C_SEND_BODY,
diff --git a/main.c b/main.c
index d64774b..8917138 100644
--- a/main.c
+++ b/main.c
_AT_@ -60,9 +60,14 @@ serve(struct connection *c, const struct server *srv)
 
 	switch (c->state) {
 	case C_VACANT:
+		/* we were passed a "fresh" connection, reset all state */
+
+		c->state = C_START;
+		/* fallthrough */
+	case C_START:
 		/*
-		 * we were passed a "fresh" connection which should now
-		 * try to receive the header, reset buf beforehand
+		 * we start handling a request, so we first must try to
+		 * receive the header, reset buf beforehand
 		 */
 		memset(&c->buf, 0, sizeof(c->buf));
 
_AT_@ -146,6 +151,20 @@ response:
 err:
 	logmsg(c);
 
+	/* don't cleanup if we keep the connection alive */
+	if (c->res.lifetime == LT_KEEP_ALIVE) {
+		/*
+		 * if the length is unspecified, a keep-alive connection will
+		 * wait timeout: kill the connection to avoid it
+		 */
+		if (c->res.field[RES_CONTENT_LENGTH][0] == '\0') {
+			c->res.status = S_INTERNAL_SERVER_ERROR;
+		} else {
+			c->state = C_START;
+			return;
+		}
+	}
+
 	/* clean up and finish */
 	shutdown(c->fd, SHUT_RD);
 	shutdown(c->fd, SHUT_WR);
-- 
2.29.0
Received on Thu Oct 29 2020 - 11:16:36 CET

This archive was generated by hypermail 2.3.0 : Thu Oct 29 2020 - 11:36:32 CET