diff options
Diffstat (limited to 'usr.sbin/httpd/server_file.c')
-rw-r--r-- | usr.sbin/httpd/server_file.c | 101 |
1 files changed, 52 insertions, 49 deletions
diff --git a/usr.sbin/httpd/server_file.c b/usr.sbin/httpd/server_file.c index 0027056db0d..5a0e778dff9 100644 --- a/usr.sbin/httpd/server_file.c +++ b/usr.sbin/httpd/server_file.c @@ -1,4 +1,4 @@ -/* $OpenBSD: server_file.c,v 1.72 2022/03/02 19:52:19 tb Exp $ */ +/* $OpenBSD: server_file.c,v 1.73 2022/03/02 23:27:43 deraadt Exp $ */ /* * Copyright (c) 2006 - 2017 Reyk Floeter <reyk@openbsd.org> @@ -40,13 +40,11 @@ int server_file_access(struct httpd *, struct client *, char *, size_t); int server_file_request(struct httpd *, struct client *, - char *, struct stat *); + char *, time_t); int server_partial_file_request(struct httpd *, struct client *, - char *, struct stat *, char *); -int server_file_index(struct httpd *, struct client *, - struct stat *); -int server_file_modified_since(struct http_descriptor *, - struct stat *); + char *, time_t, char *); +int server_file_index(struct httpd *, struct client *); +int server_file_modified_since(struct http_descriptor *, time_t); int server_file_method(struct client *); int parse_range_spec(char *, size_t, struct range *); int parse_ranges(struct client *, char *, size_t); @@ -64,9 +62,7 @@ server_file_access(struct httpd *env, struct client *clt, errno = 0; - if (access(path, R_OK) == -1) { - goto fail; - } else if (stat(path, &st) == -1) { + if (stat(path, &st) == -1) { goto fail; } else if (S_ISDIR(st.st_mode)) { /* Deny access if directory indexing is disabled */ @@ -127,7 +123,7 @@ server_file_access(struct httpd *env, struct client *clt, goto fail; } - return (server_file_index(env, clt, &st)); + return (server_file_index(env, clt)); } return (ret); } else if (!S_ISREG(st.st_mode)) { @@ -139,10 +135,10 @@ server_file_access(struct httpd *env, struct client *clt, key.kv_key = "Range"; r = kv_find(&desc->http_headers, &key); if (r != NULL) - return (server_partial_file_request(env, clt, path, &st, - r->kv_value)); + return (server_partial_file_request(env, clt, path, + st.st_mtim.tv_sec, r->kv_value)); else - return (server_file_request(env, clt, path, &st)); + return (server_file_request(env, clt, path, st.st_mtim.tv_sec)); fail: switch (errno) { @@ -216,14 +212,14 @@ server_file_method(struct client *clt) int server_file_request(struct httpd *env, struct client *clt, char *path, - struct stat *st) + time_t mtim) { struct server_config *srv_conf = clt->clt_srv_conf; struct media_type *media; const char *errstr = NULL; int fd = -1, ret, code = 500; + struct stat st; size_t bufsiz; - struct stat gzst; char gzpath[PATH_MAX]; if ((ret = server_file_method(clt)) != 0) { @@ -232,11 +228,10 @@ server_file_request(struct httpd *env, struct client *clt, char *path, } media = media_find_config(env, srv_conf, path); - - if ((ret = server_file_modified_since(clt->clt_descreq, st)) != -1) { + if ((ret = server_file_modified_since(clt->clt_descreq, mtim)) != -1) { /* send the header without a body */ if ((ret = server_response_http(clt, ret, media, -1, - MINIMUM(time(NULL), st->st_mtim.tv_sec))) == -1) + MINIMUM(time(NULL), mtim))) == -1) goto fail; goto done; } @@ -256,22 +251,22 @@ server_file_request(struct httpd *env, struct client *clt, char *path, ret = snprintf(gzpath, sizeof(gzpath), "%s.gz", path); if (ret < 0 || (size_t)ret >= sizeof(gzpath)) goto abort; - if (access(gzpath, R_OK) == 0 && - stat(gzpath, &gzst) == 0) { - path = gzpath; - st = &gzst; + if ((fd = open(gzpath, O_RDONLY)) > 0) kv_add(&resp->http_headers, "Content-Encoding", "gzip"); - } } } /* Now open the file, should be readable or we have another problem */ - if ((fd = open(path, O_RDONLY)) == -1) + if (fd == -1) { + if ((fd = open(path, O_RDONLY)) == -1) + goto abort; + } + if (fstat(fd, &st) == -1) goto abort; - ret = server_response_http(clt, 200, media, st->st_size, - MINIMUM(time(NULL), st->st_mtim.tv_sec)); + ret = server_response_http(clt, 200, media, st.st_size, + MINIMUM(time(NULL), st.st_mtim.tv_sec)); switch (ret) { case -1: goto fail; @@ -296,7 +291,7 @@ server_file_request(struct httpd *env, struct client *clt, char *path, } /* Adjust read watermark to the optimal file io size */ - bufsiz = MAXIMUM(st->st_blksize, 64 * 1024); + bufsiz = MAXIMUM(st.st_blksize, 64 * 1024); bufferevent_setwatermark(clt->clt_srvbev, EV_READ, 0, bufsiz); @@ -323,7 +318,7 @@ server_file_request(struct httpd *env, struct client *clt, char *path, int server_partial_file_request(struct httpd *env, struct client *clt, char *path, - struct stat *st, char *range_str) + time_t mtim, char *range_str) { struct server_config *srv_conf = clt->clt_srv_conf; struct http_descriptor *resp = clt->clt_descresp; @@ -332,26 +327,29 @@ server_partial_file_request(struct httpd *env, struct client *clt, char *path, struct range_data *r = &clt->clt_ranges; struct range *range; size_t content_length = 0, bufsiz; + struct stat st; int code = 500, fd = -1, i, nranges, ret; char content_range[64]; const char *errstr = NULL; /* Ignore range request for methods other than GET */ if (desc->http_method != HTTP_METHOD_GET) - return server_file_request(env, clt, path, st); + return server_file_request(env, clt, path, mtim); - if ((nranges = parse_ranges(clt, range_str, st->st_size)) < 1) { + /* Now open the file, should be readable or we have another problem */ + if ((fd = open(path, O_RDONLY)) == -1) + goto abort; + if (fstat(fd, &st) == -1) + goto abort; + + if ((nranges = parse_ranges(clt, range_str, st.st_size)) < 1) { code = 416; (void)snprintf(content_range, sizeof(content_range), - "bytes */%lld", st->st_size); + "bytes */%lld", st.st_size); errstr = content_range; goto abort; } - /* Now open the file, should be readable or we have another problem */ - if ((fd = open(path, O_RDONLY)) == -1) - goto abort; - media = media_find_config(env, srv_conf, path); r->range_media = media; @@ -359,7 +357,7 @@ server_partial_file_request(struct httpd *env, struct client *clt, char *path, range = &r->range[0]; (void)snprintf(content_range, sizeof(content_range), "bytes %lld-%lld/%lld", range->start, range->end, - st->st_size); + st.st_size); if (kv_add(&resp->http_headers, "Content-Range", content_range) == NULL) goto abort; @@ -381,7 +379,7 @@ server_partial_file_request(struct httpd *env, struct client *clt, char *path, "Content-Range: bytes %lld-%lld/%lld\r\n\r\n", clt->clt_boundary, media->media_type, media->media_subtype, - range->start, range->end, st->st_size)) < 0) + range->start, range->end, st.st_size)) < 0) goto abort; /* Add data length */ @@ -406,7 +404,7 @@ server_partial_file_request(struct httpd *env, struct client *clt, char *path, r->range_toread = TOREAD_HTTP_RANGE; ret = server_response_http(clt, 206, media, content_length, - MINIMUM(time(NULL), st->st_mtim.tv_sec)); + MINIMUM(time(NULL), st.st_mtim.tv_sec)); switch (ret) { case -1: goto fail; @@ -431,7 +429,7 @@ server_partial_file_request(struct httpd *env, struct client *clt, char *path, } /* Adjust read watermark to the optimal file io size */ - bufsiz = MAXIMUM(st->st_blksize, 64 * 1024); + bufsiz = MAXIMUM(st.st_blksize, 64 * 1024); bufferevent_setwatermark(clt->clt_srvbev, EV_READ, 0, bufsiz); @@ -457,7 +455,7 @@ server_partial_file_request(struct httpd *env, struct client *clt, char *path, } int -server_file_index(struct httpd *env, struct client *clt, struct stat *st) +server_file_index(struct httpd *env, struct client *clt) { char path[PATH_MAX]; char tmstr[21]; @@ -471,6 +469,7 @@ server_file_index(struct httpd *env, struct client *clt, struct stat *st) const char *stripped, *style; char *escapeduri, *escapedhtml, *escapedpath; struct tm tm; + struct stat st; time_t t, dir_mtime; if ((ret = server_file_method(clt)) != 0) { @@ -487,9 +486,11 @@ server_file_index(struct httpd *env, struct client *clt, struct stat *st) /* Now open the file, should be readable or we have another problem */ if ((fd = open(path, O_RDONLY)) == -1) goto abort; + if (fstat(fd, &st) == -1) + goto abort; /* Save last modification time */ - dir_mtime = MINIMUM(time(NULL), st->st_mtim.tv_sec); + dir_mtime = MINIMUM(time(NULL), st.st_mtim.tv_sec); if ((evb = evbuffer_new()) == NULL) goto abort; @@ -528,15 +529,17 @@ server_file_index(struct httpd *env, struct client *clt, struct stat *st) free(escapedpath); for (i = 0; i < namesize; i++) { + struct stat subst; + dp = namelist[i]; if (skip || - fstatat(fd, dp->d_name, st, 0) == -1) { + fstatat(fd, dp->d_name, &subst, 0) == -1) { free(dp); continue; } - t = st->st_mtime; + t = subst.st_mtime; localtime_r(&t, &tm); strftime(tmstr, sizeof(tmstr), "%d-%h-%Y %R", &tm); namewidth = 51 - strlen(dp->d_name); @@ -549,7 +552,7 @@ server_file_index(struct httpd *env, struct client *clt, struct stat *st) if (dp->d_name[0] == '.' && !(dp->d_name[1] == '.' && dp->d_name[2] == '\0')) { /* ignore hidden files starting with a dot */ - } else if (S_ISDIR(st->st_mode)) { + } else if (S_ISDIR(subst.st_mode)) { namewidth -= 1; /* trailing slash */ if (evbuffer_add_printf(evb, "<a href=\"%s%s/\">%s/</a>%*s%s%20s\n", @@ -557,13 +560,13 @@ server_file_index(struct httpd *env, struct client *clt, struct stat *st) escapeduri, escapedhtml, MAXIMUM(namewidth, 0), " ", tmstr, "-") == -1) skip = 1; - } else if (S_ISREG(st->st_mode)) { + } else if (S_ISREG(subst.st_mode)) { if (evbuffer_add_printf(evb, "<a href=\"%s%s\">%s</a>%*s%s%20llu\n", strchr(escapeduri, ':') != NULL ? "./" : "", escapeduri, escapedhtml, MAXIMUM(namewidth, 0), " ", - tmstr, st->st_size) == -1) + tmstr, subst.st_size) == -1) skip = 1; } free(escapeduri); @@ -683,7 +686,7 @@ server_file_error(struct bufferevent *bev, short error, void *arg) } int -server_file_modified_since(struct http_descriptor *desc, struct stat *st) +server_file_modified_since(struct http_descriptor *desc, time_t mtim) { struct kv key, *since; struct tm tm; @@ -699,7 +702,7 @@ server_file_modified_since(struct http_descriptor *desc, struct stat *st) */ if (strptime(since->kv_value, "%a, %d %h %Y %T %Z", &tm) != NULL && - timegm(&tm) >= st->st_mtim.tv_sec) + timegm(&tm) >= mtim) return (304); } |