X-Git-Url: http://git.archive.openwrt.org/?a=blobdiff_plain;f=file.c;h=5de96f8250245c5c297c41cce9183da535996889;hb=d9e7f5ff48836e23b2de63d9871d337e3a8a475c;hp=b2cfd8db646c8b2b756aaf458ba6080bc5b443f9;hpb=7333a14d21c474702376fbf0baa367d54448129a;p=project%2Fuhttpd.git diff --git a/file.c b/file.c index b2cfd8d..5de96f8 100644 --- a/file.c +++ b/file.c @@ -18,20 +18,22 @@ */ #define _BSD_SOURCE +#define _DARWIN_C_SOURCE #define _XOPEN_SOURCE 700 #include #include #include #include +#include #include #include "uhttpd.h" #include "mimetypes.h" -static char _tag[128]; static LIST_HEAD(index_files); +static LIST_HEAD(dispatch_handlers); struct index_file { struct list_head list; @@ -39,6 +41,7 @@ struct index_file { }; enum file_hdr { + HDR_AUTHORIZATION, HDR_IF_MODIFIED_SINCE, HDR_IF_UNMODIFIED_SINCE, HDR_IF_MATCH, @@ -232,8 +235,10 @@ uh_path_lookup(struct client *cl, const char *url) continue; strcpy(pathptr, idx->name); - if (!stat(path_phys, &s) && (s.st_mode & S_IFREG)) + if (!stat(path_phys, &s) && (s.st_mode & S_IFREG)) { + memcpy(&p.stat, &s, sizeof(p.stat)); break; + } *pathptr = 0; } @@ -245,13 +250,9 @@ uh_path_lookup(struct client *cl, const char *url) return p.phys ? &p : NULL; } -#ifdef __APPLE__ -time_t timegm (struct tm *tm); -#endif - static const char * uh_file_mime_lookup(const char *path) { - struct mimetype *m = &uh_mime_types[0]; + const struct mimetype *m = &uh_mime_types[0]; const char *e; while (m->extn) { @@ -270,14 +271,14 @@ static const char * uh_file_mime_lookup(const char *path) return "application/octet-stream"; } -static const char * uh_file_mktag(struct stat *s) +static const char * uh_file_mktag(struct stat *s, char *buf) { - snprintf(_tag, sizeof(_tag), "\"%x-%x-%x\"", + snprintf(buf, sizeof(buf), "\"%x-%x-%x\"", (unsigned int) s->st_ino, (unsigned int) s->st_size, (unsigned int) s->st_mtime); - return _tag; + return buf; } static time_t uh_file_date2unix(const char *date) @@ -292,13 +293,13 @@ static time_t uh_file_date2unix(const char *date) return 0; } -static char * uh_file_unix2date(time_t ts) +static char * uh_file_unix2date(time_t ts, char *buf, int len) { struct tm *t = gmtime(&ts); - strftime(_tag, sizeof(_tag), "%a, %d %b %Y %H:%M:%S GMT", t); + strftime(buf, len, "%a, %d %b %Y %H:%M:%S GMT", t); - return _tag; + return buf; } static char *uh_file_header(struct client *cl, int idx) @@ -311,12 +312,15 @@ static char *uh_file_header(struct client *cl, int idx) static void uh_file_response_ok_hdrs(struct client *cl, struct stat *s) { + char buf[128]; + if (s) { - ustream_printf(cl->us, "ETag: %s\r\n", uh_file_mktag(s)); + ustream_printf(cl->us, "ETag: %s\r\n", uh_file_mktag(s, buf)); ustream_printf(cl->us, "Last-Modified: %s\r\n", - uh_file_unix2date(s->st_mtime)); + uh_file_unix2date(s->st_mtime, buf, sizeof(buf))); } - ustream_printf(cl->us, "Date: %s\r\n", uh_file_unix2date(time(NULL))); + ustream_printf(cl->us, "Date: %s\r\n", + uh_file_unix2date(time(NULL), buf, sizeof(buf))); } static void uh_file_response_200(struct client *cl, struct stat *s) @@ -339,7 +343,8 @@ static void uh_file_response_412(struct client *cl) static bool uh_file_if_match(struct client *cl, struct stat *s) { - const char *tag = uh_file_mktag(s); + char buf[128]; + const char *tag = uh_file_mktag(s, buf); char *hdr = uh_file_header(cl, HDR_IF_MATCH); char *p; int i; @@ -379,7 +384,8 @@ static int uh_file_if_modified_since(struct client *cl, struct stat *s) static int uh_file_if_none_match(struct client *cl, struct stat *s) { - const char *tag = uh_file_mktag(s); + char buf[128]; + const char *tag = uh_file_mktag(s, buf); char *hdr = uh_file_header(cl, HDR_IF_NONE_MATCH); char *p; int i; @@ -430,20 +436,69 @@ static int uh_file_if_unmodified_since(struct client *cl, struct stat *s) return true; } +static int dirent_cmp(const struct dirent **a, const struct dirent **b) +{ + bool dir_a = !!((*a)->d_type & DT_DIR); + bool dir_b = !!((*b)->d_type & DT_DIR); + + /* directories first */ + if (dir_a != dir_b) + return dir_b - dir_a; -static int uh_file_scandir_filter_dir(const struct dirent *e) + return alphasort(a, b); +} + +static void list_entries(struct client *cl, struct dirent **files, int count, + const char *path, char *local_path) { - return strcmp(e->d_name, ".") ? 1 : 0; + const char *suffix = "/"; + const char *type = "directory"; + unsigned int mode = S_IXOTH; + struct stat s; + char *file; + char buf[128]; + int i; + + file = local_path + strlen(local_path); + for (i = 0; i < count; i++) { + const char *name = files[i]->d_name; + bool dir = !!(files[i]->d_type & DT_DIR); + + if (name[0] == '.' && name[1] == 0) + continue; + + sprintf(file, "%s", name); + if (stat(local_path, &s)) + continue; + + if (!dir) { + suffix = ""; + mode = S_IROTH; + type = uh_file_mime_lookup(local_path); + } + + if (!(s.st_mode & mode)) + continue; + + uh_chunk_printf(cl, + "
  • %s%s" + "
    modified: %s" + "
    %s - %.02f kbyte
    " + "
  • ", + path, name, suffix, + name, suffix, + uh_file_unix2date(s.st_mtime, buf, sizeof(buf)), + type, s.st_size / 1024.0); + + *file = 0; + free(files[i]); + } } static void uh_file_dirlist(struct client *cl, struct path_info *pi) { - int i; - int count = 0; - char filename[PATH_MAX]; - char *pathptr; struct dirent **files = NULL; - struct stat s; + int count = 0; uh_file_response_200(cl, NULL); ustream_printf(cl->us, "Content-Type: text/html\r\n\r\n"); @@ -453,65 +508,15 @@ static void uh_file_dirlist(struct client *cl, struct path_info *pi) "

    Index of %s


      ", pi->name, pi->name); - if ((count = scandir(pi->phys, &files, uh_file_scandir_filter_dir, - alphasort)) > 0) - { - memset(filename, 0, sizeof(filename)); - memcpy(filename, pi->phys, sizeof(filename)); - pathptr = &filename[strlen(filename)]; - - /* list subdirs */ - for (i = 0; i < count; i++) { - strncat(filename, files[i]->d_name, - sizeof(filename) - strlen(files[i]->d_name)); - - if (!stat(filename, &s) && - (s.st_mode & S_IFDIR) && (s.st_mode & S_IXOTH)) - uh_chunk_printf(cl, - "
    1. %s/" - "
      modified: %s" - "
      directory - %.02f kbyte
      " - "
    2. ", - pi->name, files[i]->d_name, - files[i]->d_name, - uh_file_unix2date(s.st_mtime), - s.st_size / 1024.0); - - *pathptr = 0; - } - - /* list files */ - for (i = 0; i < count; i++) { - strncat(filename, files[i]->d_name, - sizeof(filename) - strlen(files[i]->d_name)); - - if (!stat(filename, &s) && - !(s.st_mode & S_IFDIR) && (s.st_mode & S_IROTH)) - uh_chunk_printf(cl, - "
    3. %s" - "
      modified: %s" - "
      %s - %.02f kbyte
      " - "
    4. ", - pi->name, files[i]->d_name, - files[i]->d_name, - uh_file_unix2date(s.st_mtime), - uh_file_mime_lookup(filename), - s.st_size / 1024.0); - - *pathptr = 0; - } + count = scandir(pi->phys, &files, NULL, dirent_cmp); + if (count > 0) { + strcpy(uh_buf, pi->phys); + list_entries(cl, files, count, pi->name, uh_buf); } + free(files); uh_chunk_printf(cl, "

    "); uh_request_done(cl); - - if (files) - { - for (i = 0; i < count; i++) - free(files[i]); - - free(files); - } } static void file_write_cb(struct client *cl) @@ -577,22 +582,11 @@ static void uh_file_data(struct client *cl, struct path_info *pi, int fd) file_write_cb(cl); } -static void uh_file_request(struct client *cl, struct path_info *pi, const char *url) +static void uh_file_request(struct client *cl, const char *url, + struct path_info *pi, struct blob_attr **tb) { - static const struct blobmsg_policy hdr_policy[__HDR_MAX] = { - [HDR_IF_MODIFIED_SINCE] = { "if-modified-since", BLOBMSG_TYPE_STRING }, - [HDR_IF_UNMODIFIED_SINCE] = { "if-unmodified-since", BLOBMSG_TYPE_STRING }, - [HDR_IF_MATCH] = { "if-match", BLOBMSG_TYPE_STRING }, - [HDR_IF_NONE_MATCH] = { "if-none-match", BLOBMSG_TYPE_STRING }, - [HDR_IF_RANGE] = { "if-range", BLOBMSG_TYPE_STRING }, - }; - struct blob_attr *tb[__HDR_MAX]; int fd; - blobmsg_parse(hdr_policy, __HDR_MAX, tb, blob_data(cl->hdr.head), blob_len(cl->hdr.head)); - - cl->dispatch.file.hdr = tb; - if (!(pi->stat.st_mode & S_IROTH)) goto error; @@ -601,45 +595,111 @@ static void uh_file_request(struct client *cl, struct path_info *pi, const char if (fd < 0) goto error; + cl->dispatch.file.hdr = tb; uh_file_data(cl, pi, fd); - } else if ((pi->stat.st_mode & S_IFDIR)) { + cl->dispatch.file.hdr = NULL; + return; + } + + if ((pi->stat.st_mode & S_IFDIR)) { if (conf.no_dirlists) goto error; uh_file_dirlist(cl, pi); - } else { - goto error; + return; } - return; - error: uh_client_error(cl, 403, "Forbidden", "You don't have permission to access %s on this server.", url); } -static bool __handle_file_request(struct client *cl, const char *url) +void uh_dispatch_add(struct dispatch_handler *d) +{ + list_add_tail(&d->list, &dispatch_handlers); +} + +static struct dispatch_handler * +dispatch_find(const char *url, struct path_info *pi) +{ + struct dispatch_handler *d; + + list_for_each_entry(d, &dispatch_handlers, list) { + if (pi) { + if (d->check_url) + continue; + + if (d->check_path(pi, url)) + return d; + } else { + if (d->check_path) + continue; + + if (d->check_url(url)) + return d; + } + } + + return NULL; +} + +static bool __handle_file_request(struct client *cl, char *url) { + static const struct blobmsg_policy hdr_policy[__HDR_MAX] = { + [HDR_AUTHORIZATION] = { "authorization", BLOBMSG_TYPE_STRING }, + [HDR_IF_MODIFIED_SINCE] = { "if-modified-since", BLOBMSG_TYPE_STRING }, + [HDR_IF_UNMODIFIED_SINCE] = { "if-unmodified-since", BLOBMSG_TYPE_STRING }, + [HDR_IF_MATCH] = { "if-match", BLOBMSG_TYPE_STRING }, + [HDR_IF_NONE_MATCH] = { "if-none-match", BLOBMSG_TYPE_STRING }, + [HDR_IF_RANGE] = { "if-range", BLOBMSG_TYPE_STRING }, + }; + struct dispatch_handler *d; + struct blob_attr *tb[__HDR_MAX]; struct path_info *pi; 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; + + blobmsg_parse(hdr_policy, __HDR_MAX, tb, blob_data(cl->hdr.head), blob_len(cl->hdr.head)); + if (tb[HDR_AUTHORIZATION]) + pi->auth = blobmsg_data(tb[HDR_AUTHORIZATION]); + + if (!uh_auth_check(cl, pi)) + return true; + + d = dispatch_find(url, pi); + if (d) + d->handle_request(cl, url, pi); + else + uh_file_request(cl, url, pi, tb); return true; } -void uh_handle_file_request(struct client *cl) +void uh_handle_request(struct client *cl) { - if (__handle_file_request(cl, cl->request.url) || - __handle_file_request(cl, conf.error_handler)) + struct dispatch_handler *d; + char *url = blobmsg_data(blob_data(cl->hdr.head));; + char *error_handler; + + d = dispatch_find(url, NULL); + if (d) { + d->handle_request(cl, url, NULL); + return; + } + + if (__handle_file_request(cl, url)) + return; + + error_handler = alloca(strlen(conf.error_handler) + 1); + strcpy(error_handler, conf.error_handler); + if (__handle_file_request(cl, error_handler)) return; - uh_client_error(cl, 404, "Not Found", "The requested URL %s was not found on this server.", cl->request.url); + uh_client_error(cl, 404, "Not Found", "The requested URL %s was not found on this server.", url); }