commit c1b242e405d40067c282e8116d21c6f2641e4eee
Author:     Laslo Hunhold <[email protected]>
AuthorDate: Sat Aug 22 09:24:57 2020 +0200
Commit:     Laslo Hunhold <[email protected]>
CommitDate: Sat Aug 22 09:24:57 2020 +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]>

diff --git a/http.c b/http.c
index 2a987cb..3514f69 100644
--- 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, 
size_t *upper)
 #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 
server *s)
                        if (!regexec(&(s->vhost[i].re), req->field[REQ_HOST], 0,
                                     NULL, 0)) {
                                if (chdir(s->vhost[i].dir) < 0) {
-                                       return http_send_status(req->fd, (errno 
== EACCES) ?
+                                       return http_send_status(fd, (errno == 
EACCES) ?
                                                                S_FORBIDDEN : 
S_NOT_FOUND);
                                }
                                vhostmatch = s->vhost[i].chost;
@@ -561,14 +561,14 @@ http_send_response(const struct request *req, const 
struct server *s)
                        }
                }
                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_LARGE);
+                               return http_send_status(fd, 
S_REQUEST_TOO_LARGE);
                        }
                        memcpy(realtarget, tmptarget, sizeof(realtarget));
                }
@@ -588,7 +588,7 @@ http_send_response(const struct request *req, const struct 
server *s)
                        /* 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_LARGE);
+                               return http_send_status(fd, 
S_REQUEST_TOO_LARGE);
                        }
                        memcpy(realtarget, tmptarget, sizeof(realtarget));
                        break;
@@ -597,12 +597,12 @@ http_send_response(const struct request *req, const 
struct server *s)
 
        /* 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 
server *s)
                /* 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 
server *s)
         */
        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 
server *s)
                         * 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_ERROR);
                        }
 
@@ -662,25 +662,25 @@ http_send_response(const struct request *req, const 
struct server *s)
                                      targethost,
                                      ipv6host ? "]" : "", hasport ? ":" : "",
                                      hasport ? s->port : "", tmptarget)) {
-                               return http_send_status(req->fd, 
S_REQUEST_TOO_LARGE);
+                               return http_send_status(fd, 
S_REQUEST_TOO_LARGE);
                        }
                } 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_LARGE);
+                               return http_send_status(fd, 
S_REQUEST_TOO_LARGE);
                        }
                }
 
-               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 
struct server *s)
                                /* remove index suffix and serve dir */
                                realtarget[strlen(realtarget) -
                                           strlen(s->docindex)] = '\0';
-                               return resp_dir(req->fd, RELPATH(realtarget), 
req);
+                               return resp_dir(fd, RELPATH(realtarget), req);
                        } else {
                                /* reject */
                                if (!S_ISREG(st.st_mode) || errno == EACCES) {
-                                       return http_send_status(req->fd, 
S_FORBIDDEN);
+                                       return http_send_status(fd, 
S_FORBIDDEN);
                                } else {
-                                       return http_send_status(req->fd, 
S_NOT_FOUND);
+                                       return http_send_status(fd, 
S_NOT_FOUND);
                                }
                        }
                }
@@ -706,13 +706,13 @@ http_send_response(const struct request *req, const 
struct server *s)
                /* 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 
struct server *s)
                        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_ERROR);
                        }
 
-                       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 
server *s)
                }
        }
 
-       return resp_file(req->fd, RELPATH(realtarget), req, &st, mime, lower, 
upper);
+       return resp_file(fd, RELPATH(realtarget), req, &st, mime, lower, upper);
 }
diff --git a/http.h b/http.h
index 60e38da..44d0495 100644
--- 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
index 293f5c0..3b7cd32 100644
--- 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 
struct server *s)
                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

Reply via email to