Add connection struct
This struct contains the request and response structs, represents a state and has some utility-buffers. Signed-off-by: Laslo Hunhold <dev@frign.de>
This commit is contained in:
parent
6d2fe7f29e
commit
c1b242e405
3 changed files with 86 additions and 56 deletions
84
http.c
84
http.c
|
@ -144,7 +144,7 @@ decode(const char src[PATH_MAX], char dest[PATH_MAX])
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
http_get_request(struct request *req)
|
http_get_request(int fd, struct request *req)
|
||||||
{
|
{
|
||||||
struct in6_addr addr;
|
struct in6_addr addr;
|
||||||
size_t hlen, i, mlen;
|
size_t hlen, i, mlen;
|
||||||
|
@ -158,8 +158,8 @@ http_get_request(struct request *req)
|
||||||
* receive header
|
* receive header
|
||||||
*/
|
*/
|
||||||
for (hlen = 0; ;) {
|
for (hlen = 0; ;) {
|
||||||
if ((off = read(req->fd, h + hlen, sizeof(h) - hlen)) < 0) {
|
if ((off = read(fd, h + hlen, sizeof(h) - hlen)) < 0) {
|
||||||
return http_send_status(req->fd, S_REQUEST_TIMEOUT);
|
return http_send_status(fd, S_REQUEST_TIMEOUT);
|
||||||
} else if (off == 0) {
|
} else if (off == 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -168,13 +168,13 @@ http_get_request(struct request *req)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (hlen == sizeof(h)) {
|
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 */
|
/* remove terminating empty line */
|
||||||
if (hlen < 2) {
|
if (hlen < 2) {
|
||||||
return http_send_status(req->fd, S_BAD_REQUEST);
|
return http_send_status(fd, S_BAD_REQUEST);
|
||||||
}
|
}
|
||||||
hlen -= 2;
|
hlen -= 2;
|
||||||
|
|
||||||
|
@ -194,12 +194,12 @@ http_get_request(struct request *req)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (i == NUM_REQ_METHODS) {
|
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 */
|
/* a single space must follow the method */
|
||||||
if (h[mlen] != ' ') {
|
if (h[mlen] != ' ') {
|
||||||
return http_send_status(req->fd, S_BAD_REQUEST);
|
return http_send_status(fd, S_BAD_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* basis for next step */
|
/* basis for next step */
|
||||||
|
@ -207,11 +207,11 @@ http_get_request(struct request *req)
|
||||||
|
|
||||||
/* TARGET */
|
/* TARGET */
|
||||||
if (!(q = strchr(p, ' '))) {
|
if (!(q = strchr(p, ' '))) {
|
||||||
return http_send_status(req->fd, S_BAD_REQUEST);
|
return http_send_status(fd, S_BAD_REQUEST);
|
||||||
}
|
}
|
||||||
*q = '\0';
|
*q = '\0';
|
||||||
if (q - p + 1 > PATH_MAX) {
|
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);
|
memcpy(req->target, p, q - p + 1);
|
||||||
decode(req->target, req->target);
|
decode(req->target, req->target);
|
||||||
|
@ -221,18 +221,18 @@ http_get_request(struct request *req)
|
||||||
|
|
||||||
/* HTTP-VERSION */
|
/* HTTP-VERSION */
|
||||||
if (strncmp(p, "HTTP/", sizeof("HTTP/") - 1)) {
|
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;
|
p += sizeof("HTTP/") - 1;
|
||||||
if (strncmp(p, "1.0", sizeof("1.0") - 1) &&
|
if (strncmp(p, "1.0", sizeof("1.0") - 1) &&
|
||||||
strncmp(p, "1.1", sizeof("1.1") - 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;
|
p += sizeof("1.*") - 1;
|
||||||
|
|
||||||
/* check terminator */
|
/* check terminator */
|
||||||
if (strncmp(p, "\r\n", sizeof("\r\n") - 1)) {
|
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 */
|
/* basis for next step */
|
||||||
|
@ -253,7 +253,7 @@ http_get_request(struct request *req)
|
||||||
if (i == NUM_REQ_FIELDS) {
|
if (i == NUM_REQ_FIELDS) {
|
||||||
/* unmatched field, skip this line */
|
/* unmatched field, skip this line */
|
||||||
if (!(q = strstr(p, "\r\n"))) {
|
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);
|
p = q + (sizeof("\r\n") - 1);
|
||||||
continue;
|
continue;
|
||||||
|
@ -263,7 +263,7 @@ http_get_request(struct request *req)
|
||||||
|
|
||||||
/* a single colon must follow the field name */
|
/* a single colon must follow the field name */
|
||||||
if (*p != ':') {
|
if (*p != ':') {
|
||||||
return http_send_status(req->fd, S_BAD_REQUEST);
|
return http_send_status(fd, S_BAD_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* skip whitespace */
|
/* skip whitespace */
|
||||||
|
@ -272,11 +272,11 @@ http_get_request(struct request *req)
|
||||||
|
|
||||||
/* extract field content */
|
/* extract field content */
|
||||||
if (!(q = strstr(p, "\r\n"))) {
|
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';
|
*q = '\0';
|
||||||
if (q - p + 1 > FIELD_MAX) {
|
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);
|
memcpy(req->field[i], p, q - p + 1);
|
||||||
|
|
||||||
|
@ -296,7 +296,7 @@ http_get_request(struct request *req)
|
||||||
if (p && (!q || p > q)) {
|
if (p && (!q || p > q)) {
|
||||||
/* port suffix must not be empty */
|
/* port suffix must not be empty */
|
||||||
if (*(p + 1) == '\0') {
|
if (*(p + 1) == '\0') {
|
||||||
return http_send_status(req->fd, S_BAD_REQUEST);
|
return http_send_status(fd, S_BAD_REQUEST);
|
||||||
}
|
}
|
||||||
*p = '\0';
|
*p = '\0';
|
||||||
}
|
}
|
||||||
|
@ -305,7 +305,7 @@ http_get_request(struct request *req)
|
||||||
if (q) {
|
if (q) {
|
||||||
/* brackets must be on the outside */
|
/* brackets must be on the outside */
|
||||||
if (req->field[REQ_HOST][0] != '[' || *(q + 1) != '\0') {
|
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 */
|
/* remove the right bracket */
|
||||||
|
@ -314,7 +314,7 @@ http_get_request(struct request *req)
|
||||||
|
|
||||||
/* validate the contained IPv6 address */
|
/* validate the contained IPv6 address */
|
||||||
if (inet_pton(AF_INET6, p, &addr) != 1) {
|
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 */
|
/* 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))
|
#define RELPATH(x) ((!*(x) || !strcmp(x, "/")) ? "." : ((x) + 1))
|
||||||
|
|
||||||
enum status
|
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;
|
enum status returnstatus;
|
||||||
struct in6_addr addr;
|
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,
|
if (!regexec(&(s->vhost[i].re), req->field[REQ_HOST], 0,
|
||||||
NULL, 0)) {
|
NULL, 0)) {
|
||||||
if (chdir(s->vhost[i].dir) < 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);
|
S_FORBIDDEN : S_NOT_FOUND);
|
||||||
}
|
}
|
||||||
vhostmatch = s->vhost[i].chost;
|
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) {
|
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 we have a vhost prefix, prepend it to the target */
|
||||||
if (s->vhost[i].prefix) {
|
if (s->vhost[i].prefix) {
|
||||||
if (esnprintf(tmptarget, sizeof(tmptarget), "%s%s",
|
if (esnprintf(tmptarget, sizeof(tmptarget), "%s%s",
|
||||||
s->vhost[i].prefix, realtarget)) {
|
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));
|
memcpy(realtarget, tmptarget, sizeof(realtarget));
|
||||||
}
|
}
|
||||||
|
@ -588,7 +588,7 @@ http_send_response(const struct request *req, const struct server *s)
|
||||||
/* swap out target prefix */
|
/* swap out target prefix */
|
||||||
if (esnprintf(tmptarget, sizeof(tmptarget), "%s%s",
|
if (esnprintf(tmptarget, sizeof(tmptarget), "%s%s",
|
||||||
s->map[i].to, realtarget + len)) {
|
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));
|
memcpy(realtarget, tmptarget, sizeof(realtarget));
|
||||||
break;
|
break;
|
||||||
|
@ -597,12 +597,12 @@ http_send_response(const struct request *req, const struct server *s)
|
||||||
|
|
||||||
/* normalize target */
|
/* normalize target */
|
||||||
if (normabspath(realtarget)) {
|
if (normabspath(realtarget)) {
|
||||||
return http_send_status(req->fd, S_BAD_REQUEST);
|
return http_send_status(fd, S_BAD_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* stat the target */
|
/* stat the target */
|
||||||
if (stat(RELPATH(realtarget), &st) < 0) {
|
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);
|
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 */
|
/* add / to target if not present */
|
||||||
len = strlen(realtarget);
|
len = strlen(realtarget);
|
||||||
if (len >= PATH_MAX - 2) {
|
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] != '/') {
|
if (len && realtarget[len - 1] != '/') {
|
||||||
realtarget[len] = '/';
|
realtarget[len] = '/';
|
||||||
|
@ -624,7 +624,7 @@ http_send_response(const struct request *req, const struct server *s)
|
||||||
*/
|
*/
|
||||||
if (strstr(realtarget, "/.") && strncmp(realtarget,
|
if (strstr(realtarget, "/.") && strncmp(realtarget,
|
||||||
"/.well-known/", sizeof("/.well-known/") - 1)) {
|
"/.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 */
|
/* 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 */
|
* honor that later when we fill the "Location"-field */
|
||||||
if ((ipv6host = inet_pton(AF_INET6, targethost,
|
if ((ipv6host = inet_pton(AF_INET6, targethost,
|
||||||
&addr)) < 0) {
|
&addr)) < 0) {
|
||||||
return http_send_status(req->fd,
|
return http_send_status(fd,
|
||||||
S_INTERNAL_SERVER_ERROR);
|
S_INTERNAL_SERVER_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -662,25 +662,25 @@ http_send_response(const struct request *req, const struct server *s)
|
||||||
targethost,
|
targethost,
|
||||||
ipv6host ? "]" : "", hasport ? ":" : "",
|
ipv6host ? "]" : "", hasport ? ":" : "",
|
||||||
hasport ? s->port : "", tmptarget)) {
|
hasport ? s->port : "", tmptarget)) {
|
||||||
return http_send_status(req->fd, S_REQUEST_TOO_LARGE);
|
return http_send_status(fd, S_REQUEST_TOO_LARGE);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* write relative redirection URL to response struct */
|
/* write relative redirection URL to response struct */
|
||||||
if (esnprintf(res.field[RES_LOCATION],
|
if (esnprintf(res.field[RES_LOCATION],
|
||||||
sizeof(res.field[RES_LOCATION]),
|
sizeof(res.field[RES_LOCATION]),
|
||||||
tmptarget)) {
|
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)) {
|
if (S_ISDIR(st.st_mode)) {
|
||||||
/* append docindex to target */
|
/* append docindex to target */
|
||||||
if (esnprintf(realtarget, sizeof(realtarget), "%s%s",
|
if (esnprintf(realtarget, sizeof(realtarget), "%s%s",
|
||||||
req->target, s->docindex)) {
|
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 */
|
/* 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 */
|
/* remove index suffix and serve dir */
|
||||||
realtarget[strlen(realtarget) -
|
realtarget[strlen(realtarget) -
|
||||||
strlen(s->docindex)] = '\0';
|
strlen(s->docindex)] = '\0';
|
||||||
return resp_dir(req->fd, RELPATH(realtarget), req);
|
return resp_dir(fd, RELPATH(realtarget), req);
|
||||||
} else {
|
} else {
|
||||||
/* reject */
|
/* reject */
|
||||||
if (!S_ISREG(st.st_mode) || errno == EACCES) {
|
if (!S_ISREG(st.st_mode) || errno == EACCES) {
|
||||||
return http_send_status(req->fd, S_FORBIDDEN);
|
return http_send_status(fd, S_FORBIDDEN);
|
||||||
} else {
|
} 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 */
|
/* parse field */
|
||||||
if (!strptime(req->field[REQ_IF_MODIFIED_SINCE],
|
if (!strptime(req->field[REQ_IF_MODIFIED_SINCE],
|
||||||
"%a, %d %b %Y %T GMT", &tm)) {
|
"%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 */
|
/* compare with last modification date of the file */
|
||||||
if (difftime(st.st_mtim.tv_sec, timegm(&tm)) <= 0) {
|
if (difftime(st.st_mtim.tv_sec, timegm(&tm)) <= 0) {
|
||||||
res.status = S_NOT_MODIFIED;
|
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],
|
if (esnprintf(res.field[RES_CONTENT_RANGE],
|
||||||
sizeof(res.field[RES_CONTENT_RANGE]),
|
sizeof(res.field[RES_CONTENT_RANGE]),
|
||||||
"bytes */%zu", st.st_size)) {
|
"bytes */%zu", st.st_size)) {
|
||||||
return http_send_status(req->fd,
|
return http_send_status(fd,
|
||||||
S_INTERNAL_SERVER_ERROR);
|
S_INTERNAL_SERVER_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
return http_send_header(req->fd, &res);
|
return http_send_header(fd, &res);
|
||||||
} else {
|
} 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);
|
||||||
}
|
}
|
||||||
|
|
40
http.h
40
http.h
|
@ -3,6 +3,7 @@
|
||||||
#define HTTP_H
|
#define HTTP_H
|
||||||
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
@ -27,8 +28,8 @@ enum req_method {
|
||||||
extern const char *req_method_str[];
|
extern const char *req_method_str[];
|
||||||
|
|
||||||
struct request {
|
struct request {
|
||||||
int fd;
|
char header[HEADER_MAX]; /* deprecated */
|
||||||
char header[HEADER_MAX];
|
|
||||||
enum req_method method;
|
enum req_method method;
|
||||||
char target[PATH_MAX];
|
char target[PATH_MAX];
|
||||||
char field[NUM_REQ_FIELDS][FIELD_MAX];
|
char field[NUM_REQ_FIELDS][FIELD_MAX];
|
||||||
|
@ -65,15 +66,46 @@ enum res_field {
|
||||||
|
|
||||||
extern const char *res_field_str[];
|
extern const char *res_field_str[];
|
||||||
|
|
||||||
|
enum res_type {
|
||||||
|
RESTYPE_FILE,
|
||||||
|
RESTYPE_DIR,
|
||||||
|
NUM_RES_TYPES,
|
||||||
|
};
|
||||||
|
|
||||||
struct response {
|
struct response {
|
||||||
|
enum res_type type;
|
||||||
enum status status;
|
enum status status;
|
||||||
char field[NUM_RES_FIELDS][FIELD_MAX];
|
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_header(int, const struct response *);
|
||||||
enum status http_send_status(int, enum status);
|
enum status http_send_status(int, enum status);
|
||||||
int http_get_request(struct request *);
|
int http_get_request(int fd, struct request *);
|
||||||
enum status http_send_response(const struct request *,
|
enum status http_send_response(int fd, const struct request *,
|
||||||
const struct server *);
|
const struct server *);
|
||||||
|
|
||||||
#endif /* HTTP_H */
|
#endif /* HTTP_H */
|
||||||
|
|
18
main.c
18
main.c
|
@ -25,22 +25,20 @@ static char *udsname;
|
||||||
static void
|
static void
|
||||||
serve(int infd, const struct sockaddr_storage *in_sa, const struct server *s)
|
serve(int infd, const struct sockaddr_storage *in_sa, const struct server *s)
|
||||||
{
|
{
|
||||||
struct request req;
|
struct connection c = { .fd = infd };
|
||||||
time_t t;
|
time_t t;
|
||||||
enum status status;
|
enum status status;
|
||||||
char inaddr[INET6_ADDRSTRLEN /* > INET_ADDRSTRLEN */];
|
char inaddr[INET6_ADDRSTRLEN /* > INET_ADDRSTRLEN */];
|
||||||
char tstmp[21];
|
char tstmp[21];
|
||||||
|
|
||||||
/* set connection timeout */
|
/* set connection timeout */
|
||||||
if (sock_set_timeout(infd, 30)) {
|
if (sock_set_timeout(c.fd, 30)) {
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* handle request */
|
/* handle request */
|
||||||
req.fd = infd;
|
if (!(status = http_get_request(c.fd, &c.req))) {
|
||||||
|
status = http_send_response(c.fd, &c.req, s);
|
||||||
if (!(status = http_get_request(&req))) {
|
|
||||||
status = http_send_response(&req, s);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* write output to log */
|
/* write output to log */
|
||||||
|
@ -54,12 +52,12 @@ serve(int infd, const struct sockaddr_storage *in_sa, const struct server *s)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
printf("%s\t%s\t%d\t%s\t%s\n", tstmp, inaddr, status,
|
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:
|
cleanup:
|
||||||
/* clean up and finish */
|
/* clean up and finish */
|
||||||
shutdown(infd, SHUT_RD);
|
shutdown(c.fd, SHUT_RD);
|
||||||
shutdown(infd, SHUT_WR);
|
shutdown(c.fd, SHUT_WR);
|
||||||
close(infd);
|
close(c.fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
Loading…
Reference in a new issue