commit 6e62158577100f0e2f7715a75e30e5a38b66284e
parent 42f02badb681823743ce1105ddfffcb90dd1e92a
Author: FRIGN <dev@frign.de>
Date: Sat, 5 Dec 2015 00:35:50 +0100
Add readline()
In quark we used fdopen() to do the socket-handling, but this is not
the best solution and it's guaranteed to run into trouble sooner or
later.
The real deal is to actually poll on the socket-fd. This actually
allows us to implement the timeout in a much saner way than fiddling
with the socket.
If we reach the timeout, the handle()-function breaks off and we
stop.
Additionally, 30 seconds are way too long for a timeout, but if it turns
out to be standardized or whatever, it can be changed in config.h.
Diffstat:
M | config.h | | | 5 | +++-- |
M | higgs.c | | | 105 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------ |
2 files changed, 85 insertions(+), 25 deletions(-)
diff --git a/config.h b/config.h
@@ -1,4 +1,5 @@
/* higgs settings */
static const char *servername = "127.0.0.1";
-static const char *serverport = "8081";
-static const int maxnprocs = 512;
+static const char *serverport = "8081";
+static const int maxnprocs = 512;
+static const int timeout = 2000; /* in ms */
diff --git a/higgs.c b/higgs.c
@@ -1,6 +1,7 @@
#include <errno.h>
#include <limits.h>
#include <netdb.h>
+#include <poll.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
@@ -15,15 +16,85 @@
#include "config.h"
-char response[] = "HTTP/1.1 200 OK\r\n"
-"Connection: close\r\n"
-"Date: Thu, 03 Dec 2015 15:18:45 GMT\r\n"
-"Content-Type: text/html; charset=UTF-8\r\n\r\n"
-"<!DOCTYPE html><html><head><title>Bye-bye baby bye-bye</title>"
-"<style>body { background-color: #111 }"
-"h1 { font-size:4cm; text-align: center; color: black;"
-" text-shadow: 0 0 2mm red}</style></head>"
-"<body><h1>Goodbye, world!</h1></body></html>\r\n";
+int
+readline(char **buf, size_t *buflen, int fd)
+{
+ /* todo: properly return I/O and internal errors differently, so it's
+ * possible to give a 500-error when we have a malloc-problem
+ * but a timeout error when the user timed out */
+ struct pollfd pollit = { .fd = fd, .events = POLLIN | POLLPRI };
+ size_t off = 0;
+ int ret;
+ char c;
+
+ if (!*buf) {
+ if (!(*buf = malloc(BUFSIZ)))
+ return -1;
+ *buflen = BUFSIZ;
+ }
+again:
+ switch (ret = poll(&pollit, 1, timeout)) {
+ case 0: /* timeout */
+ return -1;
+ case -1: /* error */
+ return -1;
+ default: /* state change */
+ if (!(pollit.revents & (POLLIN | POLLPRI)))
+ return -1;
+
+ while (read(fd, &c, 1) == 1) {
+ if (c == '\n')
+ goto end;
+ if (c == '\r')
+ continue;
+ (*buf)[off] = c;
+ off++;
+ if (off >= *buflen) {
+ if (!(*buf = realloc(*buf, *buflen + BUFSIZ)))
+ return -1;
+ *buflen += BUFSIZ;
+ }
+ }
+
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+ goto again;
+ return -1;
+ }
+end:
+ (*buf)[off] = '\0';
+ return off;
+}
+
+void
+handle(int fd)
+{
+ size_t buflen = 0;
+ char *buf = NULL, *p, *url;
+
+readline:
+ /* check "METHOD URL HTTP-VERSION" */
+ if (readline(&buf, &buflen, fd) < 0)
+ goto servererr;
+ if (strncmp(buf, "GET ", 4))
+ goto clienterr;
+ if (!(p = strchr(buf + 4, ' ')) || p == buf + 4)
+ goto clienterr;
+ if (!(url = strndup(buf + 4, p - (buf + 4))))
+ goto servererr;
+ if (strncmp(p + 1, "HTTP/", 5))
+ goto clienterr;
+
+ printf("200 |%s|\n", url);
+ return;
+servererr:
+ /* 500 internal server error */
+ printf("500 |%s|\n", url);
+ return;
+clienterr:
+ /* 400 Bad Request */
+ printf("400 |%s|\n", url);
+ return;
+}
int
main()
@@ -41,7 +112,7 @@ main()
return 1;
}
- /*setbuf(stdout, NULL);*/ /* unbuffered stdout */
+ setbuf(stdout, NULL); /* unbuffered stdout */
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
@@ -85,22 +156,10 @@ main()
continue;
} else if (pid == 0) {
close(listenfd);
-
- /* close socket after timeout */
- tv.tv_sec = 30;
- tv.tv_usec = 0;
- if (setsockopt(reqfd, SOL_SOCKET, SO_RCVTIMEO,
- &tv, sizeof(tv)) < 0) {
- fprintf(stderr, "error\tsetsockopt SO_RCVTIMEO"
- "failed: %s\n", strerror(errno));
- }
-
- write(reqfd, response, sizeof(response) - 1);
-
+ handle(reqfd);
shutdown(reqfd, SHUT_RD);
shutdown(reqfd, SHUT_WR);
close(reqfd);
- printf("request:\n");
exit(0);
} else {
close(reqfd);