higgs

httpd experiment
git clone git://git.2f30.org/higgs
Log | Files | Refs

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:
Mconfig.h | 5+++--
Mhiggs.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);