Introduction
Introduction Statistics Contact Development Disclaimer Help
Add connection struct - quark - quark web server
git clone git://git.suckless.org/quark
Log
Files
Refs
LICENSE
---
commit c1b242e405d40067c282e8116d21c6f2641e4eee
parent 6d2fe7f29e12190d9be062852cf3f21b7f695369
Author: Laslo Hunhold <[email protected]>
Date: Sat, 22 Aug 2020 09:24:57 +0200
Add connection struct
This struct contains the request and response structs, represents a state
and has some utility-buffers.
Signed-off-by: Laslo Hunhold <[email protected]>
Diffstat:
M http.c | 84 ++++++++++++++++-------------…
M http.h | 40 ++++++++++++++++++++++++++++-…
M main.c | 18 ++++++++----------
3 files changed, 86 insertions(+), 56 deletions(-)
---
diff --git a/http.c b/http.c
@@ -144,7 +144,7 @@ decode(const char src[PATH_MAX], char dest[PATH_MAX])
}
int
-http_get_request(struct request *req)
+http_get_request(int fd, struct request *req)
{
struct in6_addr addr;
size_t hlen, i, mlen;
@@ -158,8 +158,8 @@ http_get_request(struct request *req)
* receive header
*/
for (hlen = 0; ;) {
- if ((off = read(req->fd, h + hlen, sizeof(h) - hlen)) < 0) {
- return http_send_status(req->fd, S_REQUEST_TIMEOUT);
+ if ((off = read(fd, h + hlen, sizeof(h) - hlen)) < 0) {
+ return http_send_status(fd, S_REQUEST_TIMEOUT);
} else if (off == 0) {
break;
}
@@ -168,13 +168,13 @@ http_get_request(struct request *req)
break;
}
if (hlen == sizeof(h)) {
- return http_send_status(req->fd, S_REQUEST_TOO_LARGE);
+ return http_send_status(fd, S_REQUEST_TOO_LARGE);
}
}
/* remove terminating empty line */
if (hlen < 2) {
- return http_send_status(req->fd, S_BAD_REQUEST);
+ return http_send_status(fd, S_BAD_REQUEST);
}
hlen -= 2;
@@ -194,12 +194,12 @@ http_get_request(struct request *req)
}
}
if (i == NUM_REQ_METHODS) {
- return http_send_status(req->fd, S_METHOD_NOT_ALLOWED);
+ return http_send_status(fd, S_METHOD_NOT_ALLOWED);
}
/* a single space must follow the method */
if (h[mlen] != ' ') {
- return http_send_status(req->fd, S_BAD_REQUEST);
+ return http_send_status(fd, S_BAD_REQUEST);
}
/* basis for next step */
@@ -207,11 +207,11 @@ http_get_request(struct request *req)
/* TARGET */
if (!(q = strchr(p, ' '))) {
- return http_send_status(req->fd, S_BAD_REQUEST);
+ return http_send_status(fd, S_BAD_REQUEST);
}
*q = '\0';
if (q - p + 1 > PATH_MAX) {
- return http_send_status(req->fd, S_REQUEST_TOO_LARGE);
+ return http_send_status(fd, S_REQUEST_TOO_LARGE);
}
memcpy(req->target, p, q - p + 1);
decode(req->target, req->target);
@@ -221,18 +221,18 @@ http_get_request(struct request *req)
/* HTTP-VERSION */
if (strncmp(p, "HTTP/", sizeof("HTTP/") - 1)) {
- return http_send_status(req->fd, S_BAD_REQUEST);
+ return http_send_status(fd, S_BAD_REQUEST);
}
p += sizeof("HTTP/") - 1;
if (strncmp(p, "1.0", sizeof("1.0") - 1) &&
strncmp(p, "1.1", sizeof("1.1") - 1)) {
- return http_send_status(req->fd, S_VERSION_NOT_SUPPORTED);
+ return http_send_status(fd, S_VERSION_NOT_SUPPORTED);
}
p += sizeof("1.*") - 1;
/* check terminator */
if (strncmp(p, "\r\n", sizeof("\r\n") - 1)) {
- return http_send_status(req->fd, S_BAD_REQUEST);
+ return http_send_status(fd, S_BAD_REQUEST);
}
/* basis for next step */
@@ -253,7 +253,7 @@ http_get_request(struct request *req)
if (i == NUM_REQ_FIELDS) {
/* unmatched field, skip this line */
if (!(q = strstr(p, "\r\n"))) {
- return http_send_status(req->fd, S_BAD_REQUEST…
+ return http_send_status(fd, S_BAD_REQUEST);
}
p = q + (sizeof("\r\n") - 1);
continue;
@@ -263,7 +263,7 @@ http_get_request(struct request *req)
/* a single colon must follow the field name */
if (*p != ':') {
- return http_send_status(req->fd, S_BAD_REQUEST);
+ return http_send_status(fd, S_BAD_REQUEST);
}
/* skip whitespace */
@@ -272,11 +272,11 @@ http_get_request(struct request *req)
/* extract field content */
if (!(q = strstr(p, "\r\n"))) {
- return http_send_status(req->fd, S_BAD_REQUEST);
+ return http_send_status(fd, S_BAD_REQUEST);
}
*q = '\0';
if (q - p + 1 > FIELD_MAX) {
- return http_send_status(req->fd, S_REQUEST_TOO_LARGE);
+ return http_send_status(fd, S_REQUEST_TOO_LARGE);
}
memcpy(req->field[i], p, q - p + 1);
@@ -296,7 +296,7 @@ http_get_request(struct request *req)
if (p && (!q || p > q)) {
/* port suffix must not be empty */
if (*(p + 1) == '\0') {
- return http_send_status(req->fd, S_BAD_REQUEST);
+ return http_send_status(fd, S_BAD_REQUEST);
}
*p = '\0';
}
@@ -305,7 +305,7 @@ http_get_request(struct request *req)
if (q) {
/* brackets must be on the outside */
if (req->field[REQ_HOST][0] != '[' || *(q + 1) != '\0') {
- return http_send_status(req->fd, S_BAD_REQUEST);
+ return http_send_status(fd, S_BAD_REQUEST);
}
/* remove the right bracket */
@@ -314,7 +314,7 @@ http_get_request(struct request *req)
/* validate the contained IPv6 address */
if (inet_pton(AF_INET6, p, &addr) != 1) {
- return http_send_status(req->fd, S_BAD_REQUEST);
+ return http_send_status(fd, S_BAD_REQUEST);
}
/* copy it into the host field */
@@ -528,7 +528,7 @@ parse_range(const char *str, size_t size, size_t *lower, si…
#define RELPATH(x) ((!*(x) || !strcmp(x, "/")) ? "." : ((x) + 1))
enum status
-http_send_response(const struct request *req, const struct server *s)
+http_send_response(int fd, const struct request *req, const struct server *s)
{
enum status returnstatus;
struct in6_addr addr;
@@ -553,7 +553,7 @@ http_send_response(const struct request *req, const struct …
if (!regexec(&(s->vhost[i].re), req->field[REQ_HOST], …
NULL, 0)) {
if (chdir(s->vhost[i].dir) < 0) {
- return http_send_status(req->fd, (errn…
+ return http_send_status(fd, (errno == …
S_FORBIDDEN : …
}
vhostmatch = s->vhost[i].chost;
@@ -561,14 +561,14 @@ http_send_response(const struct request *req, const struc…
}
}
if (i == s->vhost_len) {
- return http_send_status(req->fd, S_NOT_FOUND);
+ return http_send_status(fd, S_NOT_FOUND);
}
/* if we have a vhost prefix, prepend it to the target */
if (s->vhost[i].prefix) {
if (esnprintf(tmptarget, sizeof(tmptarget), "%s%s",
s->vhost[i].prefix, realtarget)) {
- return http_send_status(req->fd, S_REQUEST_TOO…
+ return http_send_status(fd, S_REQUEST_TOO_LARG…
}
memcpy(realtarget, tmptarget, sizeof(realtarget));
}
@@ -588,7 +588,7 @@ http_send_response(const struct request *req, const struct …
/* swap out target prefix */
if (esnprintf(tmptarget, sizeof(tmptarget), "%s%s",
s->map[i].to, realtarget + len)) {
- return http_send_status(req->fd, S_REQUEST_TOO…
+ return http_send_status(fd, S_REQUEST_TOO_LARG…
}
memcpy(realtarget, tmptarget, sizeof(realtarget));
break;
@@ -597,12 +597,12 @@ http_send_response(const struct request *req, const struc…
/* normalize target */
if (normabspath(realtarget)) {
- return http_send_status(req->fd, S_BAD_REQUEST);
+ return http_send_status(fd, S_BAD_REQUEST);
}
/* stat the target */
if (stat(RELPATH(realtarget), &st) < 0) {
- return http_send_status(req->fd, (errno == EACCES) ?
+ return http_send_status(fd, (errno == EACCES) ?
S_FORBIDDEN : S_NOT_FOUND);
}
@@ -610,7 +610,7 @@ http_send_response(const struct request *req, const struct …
/* add / to target if not present */
len = strlen(realtarget);
if (len >= PATH_MAX - 2) {
- return http_send_status(req->fd, S_REQUEST_TOO_LARGE);
+ return http_send_status(fd, S_REQUEST_TOO_LARGE);
}
if (len && realtarget[len - 1] != '/') {
realtarget[len] = '/';
@@ -624,7 +624,7 @@ http_send_response(const struct request *req, const struct …
*/
if (strstr(realtarget, "/.") && strncmp(realtarget,
"/.well-known/", sizeof("/.well-known/") - 1)) {
- return http_send_status(req->fd, S_FORBIDDEN);
+ return http_send_status(fd, S_FORBIDDEN);
}
/* redirect if targets differ, host is non-canonical or we prefixed */
@@ -650,7 +650,7 @@ http_send_response(const struct request *req, const struct …
* honor that later when we fill the "Location"-field …
if ((ipv6host = inet_pton(AF_INET6, targethost,
&addr)) < 0) {
- return http_send_status(req->fd,
+ return http_send_status(fd,
S_INTERNAL_SERVER_ERRO…
}
@@ -662,25 +662,25 @@ http_send_response(const struct request *req, const struc…
targethost,
ipv6host ? "]" : "", hasport ? ":" : "",
hasport ? s->port : "", tmptarget)) {
- return http_send_status(req->fd, S_REQUEST_TOO…
+ return http_send_status(fd, S_REQUEST_TOO_LARG…
}
} else {
/* write relative redirection URL to response struct */
if (esnprintf(res.field[RES_LOCATION],
sizeof(res.field[RES_LOCATION]),
tmptarget)) {
- return http_send_status(req->fd, S_REQUEST_TOO…
+ return http_send_status(fd, S_REQUEST_TOO_LARG…
}
}
- return http_send_header(req->fd, &res);
+ return http_send_header(fd, &res);
}
if (S_ISDIR(st.st_mode)) {
/* append docindex to target */
if (esnprintf(realtarget, sizeof(realtarget), "%s%s",
req->target, s->docindex)) {
- return http_send_status(req->fd, S_REQUEST_TOO_LARGE);
+ return http_send_status(fd, S_REQUEST_TOO_LARGE);
}
/* stat the docindex, which must be a regular file */
@@ -689,13 +689,13 @@ http_send_response(const struct request *req, const struc…
/* remove index suffix and serve dir */
realtarget[strlen(realtarget) -
strlen(s->docindex)] = '\0';
- return resp_dir(req->fd, RELPATH(realtarget), …
+ return resp_dir(fd, RELPATH(realtarget), req);
} else {
/* reject */
if (!S_ISREG(st.st_mode) || errno == EACCES) {
- return http_send_status(req->fd, S_FOR…
+ return http_send_status(fd, S_FORBIDDE…
} else {
- return http_send_status(req->fd, S_NOT…
+ return http_send_status(fd, S_NOT_FOUN…
}
}
}
@@ -706,13 +706,13 @@ http_send_response(const struct request *req, const struc…
/* parse field */
if (!strptime(req->field[REQ_IF_MODIFIED_SINCE],
"%a, %d %b %Y %T GMT", &tm)) {
- return http_send_status(req->fd, S_BAD_REQUEST);
+ return http_send_status(fd, S_BAD_REQUEST);
}
/* compare with last modification date of the file */
if (difftime(st.st_mtim.tv_sec, timegm(&tm)) <= 0) {
res.status = S_NOT_MODIFIED;
- return http_send_header(req->fd, &res);
+ return http_send_header(fd, &res);
}
}
@@ -725,13 +725,13 @@ http_send_response(const struct request *req, const struc…
if (esnprintf(res.field[RES_CONTENT_RANGE],
sizeof(res.field[RES_CONTENT_RANGE]),
"bytes */%zu", st.st_size)) {
- return http_send_status(req->fd,
+ return http_send_status(fd,
S_INTERNAL_SERVER_ERRO…
}
- return http_send_header(req->fd, &res);
+ return http_send_header(fd, &res);
} else {
- return http_send_status(req->fd, returnstatus);
+ return http_send_status(fd, returnstatus);
}
}
@@ -746,5 +746,5 @@ http_send_response(const struct request *req, const struct …
}
}
- return resp_file(req->fd, RELPATH(realtarget), req, &st, mime, lower, …
+ return resp_file(fd, RELPATH(realtarget), req, &st, mime, lower, upper…
}
diff --git a/http.h b/http.h
@@ -3,6 +3,7 @@
#define HTTP_H
#include <limits.h>
+#include <sys/stat.h>
#include "util.h"
@@ -27,8 +28,8 @@ enum req_method {
extern const char *req_method_str[];
struct request {
- int fd;
- char header[HEADER_MAX];
+ char header[HEADER_MAX]; /* deprecated */
+
enum req_method method;
char target[PATH_MAX];
char field[NUM_REQ_FIELDS][FIELD_MAX];
@@ -65,15 +66,46 @@ enum res_field {
extern const char *res_field_str[];
+enum res_type {
+ RESTYPE_FILE,
+ RESTYPE_DIR,
+ NUM_RES_TYPES,
+};
+
struct response {
+ enum res_type type;
enum status status;
char field[NUM_RES_FIELDS][FIELD_MAX];
+ char path[PATH_MAX];
+ struct stat st;
+ struct {
+ char *mime;
+ size_t lower;
+ size_t upper;
+ } file;
+};
+
+enum conn_state {
+ C_VACANT,
+ C_RECV_HEADER,
+ C_SEND_HEADER,
+ C_SEND_DATA,
+ NUM_CONN_STATES,
+};
+
+struct connection {
+ enum conn_state state;
+ int fd;
+ char header[HEADER_MAX]; /* general req/res-header buffer */
+ size_t off; /* general offset (header/file/dir) */
+ struct request req;
+ struct response res;
};
enum status http_send_header(int, const struct response *);
enum status http_send_status(int, enum status);
-int http_get_request(struct request *);
-enum status http_send_response(const struct request *,
+int http_get_request(int fd, struct request *);
+enum status http_send_response(int fd, const struct request *,
const struct server *);
#endif /* HTTP_H */
diff --git a/main.c b/main.c
@@ -25,22 +25,20 @@ static char *udsname;
static void
serve(int infd, const struct sockaddr_storage *in_sa, const struct server *s)
{
- struct request req;
+ struct connection c = { .fd = infd };
time_t t;
enum status status;
char inaddr[INET6_ADDRSTRLEN /* > INET_ADDRSTRLEN */];
char tstmp[21];
/* set connection timeout */
- if (sock_set_timeout(infd, 30)) {
+ if (sock_set_timeout(c.fd, 30)) {
goto cleanup;
}
/* handle request */
- req.fd = infd;
-
- if (!(status = http_get_request(&req))) {
- status = http_send_response(&req, s);
+ if (!(status = http_get_request(c.fd, &c.req))) {
+ status = http_send_response(c.fd, &c.req, s);
}
/* write output to log */
@@ -54,12 +52,12 @@ serve(int infd, const struct sockaddr_storage *in_sa, const…
goto cleanup;
}
printf("%s\t%s\t%d\t%s\t%s\n", tstmp, inaddr, status,
- req.field[REQ_HOST], req.target);
+ c.req.field[REQ_HOST], c.req.target);
cleanup:
/* clean up and finish */
- shutdown(infd, SHUT_RD);
- shutdown(infd, SHUT_WR);
- close(infd);
+ shutdown(c.fd, SHUT_RD);
+ shutdown(c.fd, SHUT_WR);
+ close(c.fd);
}
static void
You are viewing proxied material from suckless.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.