summaryrefslogtreecommitdiff
path: root/src/fileserv.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fileserv.c')
-rw-r--r--src/fileserv.c192
1 files changed, 139 insertions, 53 deletions
diff --git a/src/fileserv.c b/src/fileserv.c
index dc218de..f25b6ad 100644
--- a/src/fileserv.c
+++ b/src/fileserv.c
@@ -42,6 +42,8 @@ char *progname;
int verbose; /* reserved for future use */
char *address = "0.0.0.0";
char *forwarded_header = "X-Forwarded-For";
+char *index_css;
+char *tmpdir;
#ifndef DEFAULT_SERVICE
# define DEFAULT_SERVICE "8080"
@@ -320,56 +322,111 @@ errno_to_http_code(int ec)
return ec == ENOENT ? MHD_HTTP_NOT_FOUND : MHD_HTTP_FORBIDDEN;
}
+typedef struct file_resp {
+ int fd;
+ char *file_name;
+ DIRCONFIG *conf;
+ struct stat st;
+ char *location;
+} FILE_RESP;
+
+static void
+file_resp_init(FILE_RESP *resp)
+{
+ memset(resp, 0, sizeof(*resp));
+ resp->fd = -1;
+}
+
+static void
+file_resp_free(FILE_RESP *resp)
+{
+ if (resp->fd >= 0)
+ close(resp->fd);
+ free(resp->file_name);
+ dirconfig_free(resp->conf);
+ free(resp->location);
+}
+
int
-get_file_name(char const *host, char const *url, char **fname, struct stat *stp)
+get_file_name(char const *host, char const *url, FILE_RESP *resp)
{
struct urimap const *map;
- char *file_name;
char *cf;
- struct stat st;
- DIRCONFIG *conf;
+
+ file_resp_init(resp);
map = urimap_find(host, url);
if (!map)
return MHD_HTTP_NOT_FOUND;
- file_name = catfile_n(map->dir, map->dir_len, url + map->uri_len);
- if (lstat(file_name, &st))
+ resp->file_name = catfile_n(map->dir, map->dir_len, url + map->uri_len);
+ if (lstat(resp->file_name, &resp->st))
return errno_to_http_code(errno);
+
+ resp->conf = dirconfig(resp->file_name, map->dir_len);
- conf = dirconfig(file_name, map->dir_len);
+ if (S_ISDIR(resp->st.st_mode)) {
+ int res;
+
+ if (url[strlen(url) - 1] != '/') {
+ resp->location = catfile(url, "");
+ return MHD_HTTP_MOVED_PERMANENTLY;
+ }
- if (S_ISDIR(st.st_mode)) {
- int res = find_index_file(file_name, conf, &cf, &st);
+ res = find_index_file(resp->file_name, resp->conf, &cf,
+ &resp->st);
if (res == MHD_HTTP_OK) {
- free(file_name);
- file_name = cf;
- } else if (conf->listing) {
+ free(resp->file_name);
+ resp->file_name = cf;
+ } else if (resp->conf->listing) {
//FIXME
- return MHD_HTTP_FORBIDDEN;
- } else
+ char *template = catfile(tmpdir, "idxXXXXXX");
+ int fd = mkstemp(template);
+ if (fd == -1) {
+ error("can't create temporary file name: %s",
+ strerror(errno));
+ /*FIXME: leak */
+ return MHD_HTTP_INTERNAL_SERVER_ERROR;
+ }
+ unlink(template);
+ free(template);
+ res = directory_index(fd, resp->conf, url,
+ resp->file_name);
+ if (res) {
+ close(fd);
+ return MHD_HTTP_FORBIDDEN;
+ }
+ fstat(fd, &resp->st);
+ resp->fd = fd;
+ return MHD_HTTP_OK;
+ } else
return res;
}
- if (S_ISLNK(st.st_mode)) {
- if (!conf->follow)
+ if (S_ISLNK(resp->st.st_mode)) {
+ if (!resp->conf->follow)
return MHD_HTTP_FORBIDDEN;
- cf = cfname(file_name);
+
+ cf = cfname(resp->file_name);
if (!cf) {
- free(file_name);
return MHD_HTTP_NOT_FOUND;
} else if (urimap_find_dir(host, cf)) {
- free(file_name);
- file_name = cf;
+ free(resp->file_name);
+ resp->file_name = cf;
} else {
- free(file_name);
free(cf);
return MHD_HTTP_NOT_FOUND;
}
- } else if (!S_ISREG(st.st_mode))
+ } else if (!S_ISREG(resp->st.st_mode)) {
return MHD_HTTP_FORBIDDEN;
-
- *fname = file_name;
- *stp = st;
+ }
+
+ resp->fd = open(resp->file_name, O_RDONLY);
+ if (resp->fd == -1) {
+ error("can't open %s: %s",
+ resp->file_name, strerror(errno));
+ return errno_to_http_code(errno);
+ }
+ fstat(resp->fd, &resp->st);
return MHD_HTTP_OK;
}
@@ -732,6 +789,27 @@ http_error(struct MHD_Connection *connection,
}
static int
+http_redirect(struct MHD_Connection *connection,
+ char const *method, char const *url,
+ int status, char const *loc)
+{
+ int ret;
+ struct MHD_Response *response;
+
+ http_log(connection, method, url, status, NULL);
+ response = MHD_create_response_from_buffer (strlen(loc),
+ xstrdup(loc),
+ MHD_RESPMEM_MUST_FREE);
+ MHD_add_response_header(response,
+ MHD_HTTP_HEADER_LOCATION,
+ loc);
+
+ ret = MHD_queue_response(connection, status, response);
+ MHD_destroy_response(response);
+ return ret;
+}
+
+static int
fileserv_handler(void *cls,
struct MHD_Connection *conn,
const char *url, const char *method,
@@ -743,11 +821,9 @@ fileserv_handler(void *cls,
char const *host = MHD_lookup_connection_value(conn,
MHD_HEADER_KIND,
MHD_HTTP_HEADER_HOST);
- char *file_name;
- struct stat st;
+ FILE_RESP resp;
struct MHD_Response *response;
int ret;
- int fd;
char const *type;
int status;
@@ -761,35 +837,39 @@ fileserv_handler(void *cls,
}
*con_cls = NULL;
- status = get_file_name(host, url, &file_name, &st);
- if (status != MHD_HTTP_OK)
+ status = get_file_name(host, url, &resp);
+ switch (status) {
+ case MHD_HTTP_OK:
+ break;
+ case MHD_HTTP_MOVED_PERMANENTLY:
+ case MHD_HTTP_FOUND:
+ ret = http_redirect(conn, method, url, status,
+ resp.location);
+ file_resp_free(&resp);
+ return ret;
+ default:
+ file_resp_free(&resp);
return http_error(conn, method, url, status, NULL);
-
- fd = open(file_name, O_RDONLY);
- if (fd == -1) {
- free(file_name);
- return http_error(conn, method, url,
- errno_to_http_code(errno),
- NULL);
}
- type = get_file_type(file_name);
- free(file_name);
+ if (resp.file_name)
+ type = get_file_type(resp.file_name);
+ else
+ type = NULL;
- response = MHD_create_response_from_fd64(st.st_size, fd);
- if (!response) {
- close(fd);
- return MHD_NO;
- }
-
- if (type)
- MHD_add_response_header(response,
- MHD_HTTP_HEADER_CONTENT_TYPE,
- type);
-
- ret = MHD_queue_response(conn, MHD_HTTP_OK, response);
- MHD_destroy_response(response);
- http_log(conn, method, url, MHD_HTTP_OK, &st);
+ response = MHD_create_response_from_fd64(resp.st.st_size, resp.fd);
+ if (response) {
+ resp.fd = -1;
+ if (type)
+ MHD_add_response_header(response,
+ MHD_HTTP_HEADER_CONTENT_TYPE,
+ type);
+ ret = MHD_queue_response(conn, MHD_HTTP_OK, response);
+ MHD_destroy_response(response);
+ http_log(conn, method, url, MHD_HTTP_OK, &resp.st);
+ } else
+ ret = MHD_NO;
+ file_resp_free(&resp);
return ret;
}
@@ -827,6 +907,9 @@ main(int argc, char **argv)
progname = argv[0];
mimetypes_error_printer = fileserv_error_printer;
+ tmpdir = getenv("TMP");
+ if (!tmpdir)
+ tmpdir = "/tmp";
while ((c = getopt(argc, argv, "a:F:fg:i:hm:p:t:x:u:v")) != EOF) {
switch (c) {
@@ -845,6 +928,9 @@ main(int argc, char **argv)
case 'h':
usage();
exit(0);
+ case 'i':
+ parse_template_file(optarg);
+ break;
case 'm':
mime_types_file = optarg;
break;

Return to:

Send suggestions and report system problems to the System administrator.