Reduce global state by localizing the server-struct

The server-struct variable s was global, which made it readable and
modifiable from any point in the code. Making it a local variable in
main() instead and passing it as a pointer to constant memory to each
function needing it makes much more sense and allows the compiler to
warn us if we do try to modify it, which it wouldn't have before.

Signed-off-by: Laslo Hunhold <dev@frign.de>
This commit is contained in:
Laslo Hunhold 2020-08-17 11:37:25 +02:00
parent 3bd49b2456
commit 65600ffe7a
No known key found for this signature in database
GPG key ID: 69576BD24CFCB980
5 changed files with 36 additions and 38 deletions

48
http.c
View file

@ -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(int fd, const struct request *req) 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;
@ -547,27 +547,27 @@ http_send_response(int fd, const struct request *req)
/* match vhost */ /* match vhost */
vhostmatch = NULL; vhostmatch = NULL;
if (s.vhost) { if (s->vhost) {
for (i = 0; i < s.vhost_len; i++) { for (i = 0; i < s->vhost_len; i++) {
/* switch to vhost directory if there is a match */ /* switch to vhost directory if there is a match */
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(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;
break; break;
} }
} }
if (i == s.vhost_len) { if (i == s->vhost_len) {
return http_send_status(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(fd, S_REQUEST_TOO_LARGE); return http_send_status(fd, S_REQUEST_TOO_LARGE);
} }
memcpy(realtarget, tmptarget, sizeof(realtarget)); memcpy(realtarget, tmptarget, sizeof(realtarget));
@ -575,19 +575,19 @@ http_send_response(int fd, const struct request *req)
} }
/* apply target prefix mapping */ /* apply target prefix mapping */
for (i = 0; i < s.map_len; i++) { for (i = 0; i < s->map_len; i++) {
len = strlen(s.map[i].from); len = strlen(s->map[i].from);
if (!strncmp(realtarget, s.map[i].from, len)) { if (!strncmp(realtarget, s->map[i].from, len)) {
/* match canonical host if vhosts are enabled and /* match canonical host if vhosts are enabled and
* the mapping specifies a canonical host */ * the mapping specifies a canonical host */
if (s.vhost && s.map[i].chost && if (s->vhost && s->map[i].chost &&
strcmp(s.map[i].chost, vhostmatch)) { strcmp(s->map[i].chost, vhostmatch)) {
continue; continue;
} }
/* 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(fd, S_REQUEST_TOO_LARGE); return http_send_status(fd, S_REQUEST_TOO_LARGE);
} }
memcpy(realtarget, tmptarget, sizeof(realtarget)); memcpy(realtarget, tmptarget, sizeof(realtarget));
@ -628,7 +628,7 @@ http_send_response(int fd, const struct request *req)
} }
/* redirect if targets differ, host is non-canonical or we prefixed */ /* redirect if targets differ, host is non-canonical or we prefixed */
if (strcmp(req->target, realtarget) || (s.vhost && vhostmatch && if (strcmp(req->target, realtarget) || (s->vhost && vhostmatch &&
strcmp(req->field[REQ_HOST], vhostmatch))) { strcmp(req->field[REQ_HOST], vhostmatch))) {
res.status = S_MOVED_PERMANENTLY; res.status = S_MOVED_PERMANENTLY;
@ -636,14 +636,14 @@ http_send_response(int fd, const struct request *req)
encode(realtarget, tmptarget); encode(realtarget, tmptarget);
/* determine target location */ /* determine target location */
if (s.vhost) { if (s->vhost) {
/* absolute redirection URL */ /* absolute redirection URL */
targethost = req->field[REQ_HOST][0] ? vhostmatch ? targethost = req->field[REQ_HOST][0] ? vhostmatch ?
vhostmatch : req->field[REQ_HOST] : s.host ? vhostmatch : req->field[REQ_HOST] : s->host ?
s.host : "localhost"; s->host : "localhost";
/* do we need to add a port to the Location? */ /* do we need to add a port to the Location? */
hasport = s.port && strcmp(s.port, "80"); hasport = s->port && strcmp(s->port, "80");
/* RFC 2732 specifies to use brackets for IPv6-addresses /* RFC 2732 specifies to use brackets for IPv6-addresses
* in URLs, so we need to check if our host is one and * in URLs, so we need to check if our host is one and
@ -661,7 +661,7 @@ http_send_response(int fd, const struct request *req)
ipv6host ? "[" : "", ipv6host ? "[" : "",
targethost, targethost,
ipv6host ? "]" : "", hasport ? ":" : "", ipv6host ? "]" : "", hasport ? ":" : "",
hasport ? s.port : "", tmptarget)) { hasport ? s->port : "", tmptarget)) {
return http_send_status(fd, S_REQUEST_TOO_LARGE); return http_send_status(fd, S_REQUEST_TOO_LARGE);
} }
} else { } else {
@ -679,16 +679,16 @@ http_send_response(int fd, const struct request *req)
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(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 */
if (stat(RELPATH(realtarget), &st) < 0 || !S_ISREG(st.st_mode)) { if (stat(RELPATH(realtarget), &st) < 0 || !S_ISREG(st.st_mode)) {
if (s.listdirs) { if (s->listdirs) {
/* 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(fd, RELPATH(realtarget), req); return resp_dir(fd, RELPATH(realtarget), req);
} else { } else {
/* reject */ /* reject */

5
http.h
View file

@ -4,6 +4,8 @@
#include <limits.h> #include <limits.h>
#include "util.h"
#define HEADER_MAX 4096 #define HEADER_MAX 4096
#define FIELD_MAX 200 #define FIELD_MAX 200
@ -69,6 +71,7 @@ struct response {
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(int, struct request *); int http_get_request(int, struct request *);
enum status http_send_response(int, const struct request *); enum status http_send_response(int, const struct request *,
const struct server *);
#endif /* HTTP_H */ #endif /* HTTP_H */

16
main.c
View file

@ -23,7 +23,7 @@
static char *udsname; static char *udsname;
static void static void
serve(int infd, const struct sockaddr_storage *in_sa) serve(int infd, const struct sockaddr_storage *in_sa, const struct server *s)
{ {
struct request req; struct request req;
time_t t; time_t t;
@ -38,7 +38,7 @@ serve(int infd, const struct sockaddr_storage *in_sa)
/* handle request */ /* handle request */
if (!(status = http_get_request(infd, &req))) { if (!(status = http_get_request(infd, &req))) {
status = http_send_response(infd, &req); status = http_send_response(infd, &req, s);
} }
/* write output to log */ /* write output to log */
@ -177,6 +177,9 @@ main(int argc, char *argv[])
struct group *grp = NULL; struct group *grp = NULL;
struct passwd *pwd = NULL; struct passwd *pwd = NULL;
struct rlimit rlim; struct rlimit rlim;
struct server s = {
.docindex = "index.html",
};
struct sockaddr_storage in_sa; struct sockaddr_storage in_sa;
size_t i; size_t i;
socklen_t in_sa_len; socklen_t in_sa_len;
@ -190,13 +193,6 @@ main(int argc, char *argv[])
char *user = "nobody"; char *user = "nobody";
char *group = "nogroup"; char *group = "nogroup";
s.host = s.port = NULL;
s.vhost = NULL;
s.map = NULL;
s.vhost_len = s.map_len = 0;
s.docindex = "index.html";
s.listdirs = 0;
ARGBEGIN { ARGBEGIN {
case 'd': case 'd':
servedir = EARGF(usage()); servedir = EARGF(usage());
@ -372,7 +368,7 @@ main(int argc, char *argv[])
/* fork and handle */ /* fork and handle */
switch (fork()) { switch (fork()) {
case 0: case 0:
serve(infd, &in_sa); serve(infd, &in_sa, &s);
exit(0); exit(0);
break; break;
case -1: case -1:

1
util.c
View file

@ -16,7 +16,6 @@
#include "util.h" #include "util.h"
char *argv0; char *argv0;
struct server s;
static void static void
verr(const char *fmt, va_list ap) verr(const char *fmt, va_list ap)

4
util.h
View file

@ -23,7 +23,7 @@ struct map {
char *to; char *to;
}; };
extern struct server { struct server {
char *host; char *host;
char *port; char *port;
char *docindex; char *docindex;
@ -32,7 +32,7 @@ extern struct server {
size_t vhost_len; size_t vhost_len;
struct map *map; struct map *map;
size_t map_len; size_t map_len;
} s; };
#undef MIN #undef MIN
#define MIN(x,y) ((x) < (y) ? (x) : (y)) #define MIN(x,y) ((x) < (y) ? (x) : (y))