move dispatch cbs and data to one place
[project/uhttpd.git] / file.c
diff --git a/file.c b/file.c
index f1f5d6d..ae4517c 100644 (file)
--- a/file.c
+++ b/file.c
  *  limitations under the License.
  */
 
+#define _BSD_SOURCE
+#define _XOPEN_SOURCE 700
+
 #include <sys/types.h>
 #include <sys/dir.h>
+#include <time.h>
+#include <strings.h>
 
 #include <libubox/blobmsg.h>
 
@@ -65,7 +70,6 @@ static char * canonpath(const char *path, char *path_resolved)
        char path_copy[PATH_MAX];
        char *path_cpy = path_copy;
        char *path_res = path_resolved;
-       struct stat s;
 
        /* relative -> absolute */
        if (*path != '/') {
@@ -117,17 +121,14 @@ next:
 
        *path_res = '\0';
 
-       /* test access */
-       if (!stat(path_resolved, &s) && (s.st_mode & S_IROTH))
-               return path_resolved;
-
-       return NULL;
+       return path_resolved;
 }
 
 /* Returns NULL on error.
 ** NB: improperly encoded URL should give client 400 [Bad Syntax]; returning
 ** NULL here causes 404 [Not Found], but that's not too unreasonable. */
-struct path_info * uh_path_lookup(struct client *cl, const char *url)
+static struct path_info *
+uh_path_lookup(struct client *cl, const char *url)
 {
        static char path_phys[PATH_MAX];
        static char path_info[PATH_MAX];
@@ -314,10 +315,10 @@ static char * uh_file_unix2date(time_t ts)
 
 static char *uh_file_header(struct client *cl, int idx)
 {
-       if (!cl->data.file.hdr[idx])
+       if (!cl->dispatch.file.hdr[idx])
                return NULL;
 
-       return (char *) blobmsg_data(cl->data.file.hdr[idx]);
+       return (char *) blobmsg_data(cl->dispatch.file.hdr[idx]);
 }
 
 static void uh_file_response_ok_hdrs(struct client *cl, struct stat *s)
@@ -528,7 +529,7 @@ static void uh_file_dirlist(struct client *cl, struct path_info *pi)
 static void file_write_cb(struct client *cl)
 {
        char buf[512];
-       int fd = cl->data.file.fd;
+       int fd = cl->dispatch.file.fd;
        int r;
 
        while (cl->us->w.data_bytes < 256) {
@@ -549,7 +550,7 @@ static void file_write_cb(struct client *cl)
 
 static void uh_file_free(struct client *cl)
 {
-       close(cl->data.file.fd);
+       close(cl->dispatch.file.fd);
 }
 
 static void uh_file_data(struct client *cl, struct path_info *pi, int fd)
@@ -582,13 +583,14 @@ static void uh_file_data(struct client *cl, struct path_info *pi, int fd)
                return;
        }
 
-       cl->data.file.fd = fd;
-       cl->dispatch_write_cb = file_write_cb;
-       cl->dispatch_free = uh_file_free;
+       cl->dispatch.file.fd = fd;
+       cl->dispatch.write_cb = file_write_cb;
+       cl->dispatch.free = uh_file_free;
+       cl->dispatch.close_fds = uh_file_free;
        file_write_cb(cl);
 }
 
-static void uh_file_request(struct client *cl, struct path_info *pi)
+static void uh_file_request(struct client *cl, struct path_info *pi, const char *url)
 {
        static const struct blobmsg_policy hdr_policy[__HDR_MAX] = {
                [HDR_IF_MODIFIED_SINCE] = { "if-modified-since", BLOBMSG_TYPE_STRING },
@@ -602,29 +604,55 @@ static void uh_file_request(struct client *cl, struct path_info *pi)
 
        blobmsg_parse(hdr_policy, __HDR_MAX, tb, blob_data(cl->hdr.head), blob_len(cl->hdr.head));
 
-       cl->data.file.hdr = tb;
-       if ((pi->stat.st_mode & S_IFREG) && ((fd = open(pi->phys, O_RDONLY)) > 0))
+       cl->dispatch.file.hdr = tb;
+
+       if (!(pi->stat.st_mode & S_IROTH))
+               goto error;
+
+       if (pi->stat.st_mode & S_IFREG) {
+               fd = open(pi->phys, O_RDONLY);
+               if (fd < 0)
+                       goto error;
+
                uh_file_data(cl, pi, fd);
-       else if ((pi->stat.st_mode & S_IFDIR) && !conf.no_dirlists)
+       } else if ((pi->stat.st_mode & S_IFDIR)) {
+               if (conf.no_dirlists)
+                       goto error;
+
                uh_file_dirlist(cl, pi);
-       else
-               uh_client_error(cl, 403, "Forbidden",
-                               "Access to this resource is forbidden");
-       cl->data.file.hdr = NULL;
+       } else {
+               goto error;
+       }
+
+       return;
+
+error:
+       uh_client_error(cl, 403, "Forbidden",
+                       "You don't have permission to access %s on this server.",
+                       url);
 }
 
-void uh_handle_file_request(struct client *cl)
+static bool __handle_file_request(struct client *cl, const char *url)
 {
        struct path_info *pi;
 
-       pi = uh_path_lookup(cl, cl->request.url);
-       if (!pi) {
-               uh_request_done(cl);
-               return;
+       pi = uh_path_lookup(cl, url);
+       if (!pi)
+               return false;
+
+       if (!pi->redirected) {
+               uh_file_request(cl, pi, url);
+               cl->dispatch.file.hdr = NULL;
        }
 
-       if (pi->redirected)
+       return true;
+}
+
+void uh_handle_file_request(struct client *cl)
+{
+       if (__handle_file_request(cl, cl->request.url) ||
+           __handle_file_request(cl, conf.error_handler))
                return;
 
-       uh_file_request(cl, pi);
+       uh_client_error(cl, 404, "Not Found", "The requested URL %s was not found on this server.", cl->request.url);
 }