-/* $OpenBSD: server_file.c,v 1.31 2014/08/06 11:24:12 reyk Exp $ */
+/* $OpenBSD: server_file.c,v 1.32 2014/08/08 18:29:42 reyk Exp $ */
/*
* Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
#include "httpd.h"
#include "http.h"
-int server_file_access(struct client *, char *, size_t,
+int server_file_access(struct httpd *, struct client *, char *,
+ size_t, struct stat *);
+int server_file_request(struct httpd *, struct client *, char *,
struct stat *);
int server_file_index(struct httpd *, struct client *);
+int server_file_method(struct client *);
int
-server_file_access(struct client *clt, char *path, size_t len,
- struct stat *st)
+server_file_access(struct httpd *env, struct client *clt,
+ char *path, size_t len, struct stat *st)
{
struct http_descriptor *desc = clt->clt_desc;
struct server_config *srv_conf = clt->clt_srv_conf;
struct stat stb;
char *newpath;
+ int ret;
errno = 0;
- switch (desc->http_method) {
- case HTTP_METHOD_GET:
- case HTTP_METHOD_HEAD:
- break;
- default:
- /* Other methods are not allowed */
- return (405);
- }
-
if (access(path, R_OK) == -1) {
goto fail;
} else if (stat(path, st) == -1) {
goto fail;
}
- if (!len) {
+ if (desc->http_path_alias != NULL) {
/* Recursion - the index "file" is a directory? */
errno = EINVAL;
goto fail;
srv_conf->flags & SRVFLAG_SSL ? "s" : "",
desc->http_host, desc->http_path) == -1)
return (500);
- free(desc->http_path);
- desc->http_path = newpath;
+ /* Path alias will be used for the redirection */
+ desc->http_path_alias = newpath;
/* Indicate that the file has been moved */
return (301);
}
- /* Otherwise append the default index file */
+ /* Append the default index file to the location */
+ if (asprintf(&newpath, "%s%s", desc->http_path,
+ srv_conf->index) == -1)
+ return (500);
+ desc->http_path_alias = newpath;
+ if (server_getlocation(clt, newpath) != srv_conf) {
+ /* The location has changed */
+ return (server_file(env, clt));
+ }
+
+ /* Otherwise append the default index file to the path */
if (strlcat(path, srv_conf->index, len) >= len) {
errno = EACCES;
goto fail;
}
- /* Check again but set len to 0 to avoid recursion */
- if (server_file_access(clt, path, 0, &stb) == 404) {
+ ret = server_file_access(env, clt, path, len, &stb);
+ if (ret == 404) {
/*
* Index file not found; fail if auto-indexing is
* not enabled, otherwise return success but
errno = EACCES;
goto fail;
}
- } else {
- /* return updated stat from index file */
- memcpy(st, &stb, sizeof(*st));
+
+ return (server_file_index(env, clt));
}
+ return (ret);
} else if (!S_ISREG(st->st_mode)) {
/* Don't follow symlinks and ignore special files */
errno = EACCES;
goto fail;
}
- return (0);
+ return (server_file_request(env, clt, path, st));
fail:
switch (errno) {
{
struct http_descriptor *desc = clt->clt_desc;
struct server_config *srv_conf = clt->clt_srv_conf;
- struct media_type *media;
- const char *errstr = NULL;
- int fd = -1, ret, code = 500;
char path[MAXPATHLEN];
+ const char *errstr = NULL;
+ int ret = 500;
struct stat st;
+ if (srv_conf->flags & SRVFLAG_FCGI)
+ return (server_fcgi(env, clt));
+
/* Request path is already canonicalized */
if ((size_t)snprintf(path, sizeof(path), "%s%s",
- srv_conf->root, desc->http_path) >= sizeof(path)) {
+ srv_conf->root,
+ desc->http_path_alias != NULL ?
+ desc->http_path_alias : desc->http_path) >= sizeof(path)) {
errstr = desc->http_path;
goto abort;
}
/* Returns HTTP status code on error */
- if ((ret = server_file_access(clt, path, sizeof(path), &st)) != 0) {
- code = ret;
- errstr = desc->http_path;
+ if ((ret = server_file_access(env, clt, path, sizeof(path),
+ &st)) > 0) {
+ errstr = desc->http_path_alias != NULL ?
+ desc->http_path_alias : desc->http_path;
goto abort;
}
- if (S_ISDIR(st.st_mode)) {
- /* List directory index */
- return (server_file_index(env, clt));
+ return (ret);
+
+ abort:
+ if (errstr == NULL)
+ errstr = strerror(errno);
+ server_abort_http(clt, ret, errstr);
+ return (-1);
+}
+
+int
+server_file_method(struct client *clt)
+{
+ struct http_descriptor *desc = clt->clt_desc;
+
+ switch (desc->http_method) {
+ case HTTP_METHOD_GET:
+ case HTTP_METHOD_HEAD:
+ return (0);
+ default:
+ /* Other methods are not allowed */
+ errno = EACCES;
+ return (405);
+ }
+ /* NOTREACHED */
+}
+
+int
+server_file_request(struct httpd *env, struct client *clt, char *path,
+ struct stat *st)
+{
+ struct server_config *srv_conf = clt->clt_srv_conf;
+ struct media_type *media;
+ const char *errstr = NULL;
+ int fd = -1, ret, code = 500;
+
+ if ((ret = server_file_method(clt)) != 0) {
+ code = ret;
+ goto abort;
}
/* Now open the file, should be readable or we have another problem */
goto abort;
media = media_find(env->sc_mediatypes, path);
- ret = server_response_http(clt, 200, media, st.st_size);
+ ret = server_response_http(clt, 200, media, st->st_size);
switch (ret) {
case -1:
goto fail;
struct server_config *srv_conf = clt->clt_srv_conf;
struct dirent **namelist, *dp;
int namesize, i, ret, fd = -1, namewidth, skip;
+ int code = 500;
struct evbuffer *evb = NULL;
struct media_type *media;
const char *style;
struct tm tm;
time_t t;
+ if ((ret = server_file_method(clt)) != 0) {
+ code = ret;
+ goto abort;
+ }
+
/* Request path is already canonicalized */
if ((size_t)snprintf(path, sizeof(path), "%s%s",
srv_conf->root, desc->http_path) >= sizeof(path))
close(fd);
if (evb != NULL)
evbuffer_free(evb);
- server_abort_http(clt, 500, desc->http_path);
+ server_abort_http(clt, code, desc->http_path);
return (-1);
}
-/* $OpenBSD: server_http.c,v 1.43 2014/08/08 15:46:01 reyk Exp $ */
+/* $OpenBSD: server_http.c,v 1.44 2014/08/08 18:29:42 reyk Exp $ */
/*
* Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
free(desc->http_path);
desc->http_path = NULL;
}
+ if (desc->http_path_alias != NULL) {
+ free(desc->http_path_alias);
+ desc->http_path_alias = NULL;
+ }
if (desc->http_query != NULL) {
free(desc->http_query);
desc->http_query = NULL;
char hostname[MAXHOSTNAMELEN];
struct http_descriptor *desc = clt->clt_desc;
struct server *srv = clt->clt_srv;
- struct server_config *srv_conf = &srv->srv_conf, *location;
+ struct server_config *srv_conf = &srv->srv_conf;
struct kv *kv, key, *host;
/* Canonicalize the request path */
if ((desc->http_host = strdup(hostname)) == NULL)
goto fail;
+ /* Now search for the location */
+ srv_conf = server_getlocation(clt, desc->http_path);
+
+ return (server_file(httpd, clt));
+ fail:
+ server_abort_http(clt, 400, "bad request");
+ return (-1);
+}
+
+struct server_config *
+server_getlocation(struct client *clt, const char *path)
+{
+ struct server *srv = clt->clt_srv;
+ struct server_config *srv_conf = clt->clt_srv_conf, *location;
+
/* Now search for the location */
TAILQ_FOREACH(location, &srv->srv_hosts, entry) {
if ((location->flags & SRVFLAG_LOCATION) &&
location->id == srv_conf->id &&
- fnmatch(location->location, desc->http_path,
- FNM_CASEFOLD) == 0) {
+ fnmatch(location->location, path, FNM_CASEFOLD) == 0) {
/* Replace host configuration */
clt->clt_srv_conf = srv_conf = location;
break;
}
}
- if (srv_conf->flags & SRVFLAG_FCGI)
- return (server_fcgi(httpd, clt));
- return (server_file(httpd, clt));
- fail:
- server_abort_http(clt, 400, "bad request");
- return (-1);
+ return (srv_conf);
}
int