X-Git-Url: https://git.rohieb.name/openwrt.git/blobdiff_plain/cbe586a91926490315c183de105cba6ee4872d1e..502d6255c81bbbfa76c6fc153d2c57351ee85d32:/package/uhttpd/src/uhttpd-file.c diff --git a/package/uhttpd/src/uhttpd-file.c b/package/uhttpd/src/uhttpd-file.c index 81f66a34b..816a69124 100644 --- a/package/uhttpd/src/uhttpd-file.c +++ b/package/uhttpd/src/uhttpd-file.c @@ -1,7 +1,7 @@ /* * uhttpd - Tiny single-threaded httpd - Static file handler * - * Copyright (C) 2010 Jo-Philipp Wich + * Copyright (C) 2010-2011 Jo-Philipp Wich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,7 +29,7 @@ static const char * uh_file_mime_lookup(const char *path) { struct mimetype *m = &uh_mime_types[0]; - char *e; + const char *e; while( m->extn ) { @@ -37,7 +37,7 @@ static const char * uh_file_mime_lookup(const char *path) while( e >= path ) { - if( (*e == '.') && !strcasecmp(&e[1], m->extn) ) + if( (*e == '.' || *e == '/') && !strcasecmp(&e[1], m->extn) ) return m->mime; e--; @@ -97,39 +97,40 @@ static char * uh_file_header_lookup(struct http_request *req, const char *name) return NULL; } -static void uh_file_response_ok_hdrs(struct client *cl, struct http_request *req, struct stat *s) + +static int uh_file_response_ok_hdrs(struct client *cl, struct http_request *req, struct stat *s) { - uh_http_sendf(cl, NULL, "Connection: close\r\n"); + ensure_ret(uh_http_sendf(cl, NULL, "Connection: close\r\n")); if( s ) { - uh_http_sendf(cl, NULL, "ETag: %s\r\n", uh_file_mktag(s)); - uh_http_sendf(cl, NULL, "Last-Modified: %s\r\n", uh_file_unix2date(s->st_mtime)); + ensure_ret(uh_http_sendf(cl, NULL, "ETag: %s\r\n", uh_file_mktag(s))); + ensure_ret(uh_http_sendf(cl, NULL, "Last-Modified: %s\r\n", uh_file_unix2date(s->st_mtime))); } - uh_http_sendf(cl, NULL, "Date: %s\r\n", uh_file_unix2date(time(NULL))); + return uh_http_sendf(cl, NULL, "Date: %s\r\n", uh_file_unix2date(time(NULL))); } -static void uh_file_response_200(struct client *cl, struct http_request *req, struct stat *s) +static int uh_file_response_200(struct client *cl, struct http_request *req, struct stat *s) { - uh_http_sendf(cl, NULL, "HTTP/%.1f 200 OK\r\n", req->version); - uh_file_response_ok_hdrs(cl, req, s); + ensure_ret(uh_http_sendf(cl, NULL, "HTTP/%.1f 200 OK\r\n", req->version)); + return uh_file_response_ok_hdrs(cl, req, s); } -static void uh_file_response_304(struct client *cl, struct http_request *req, struct stat *s) +static int uh_file_response_304(struct client *cl, struct http_request *req, struct stat *s) { - uh_http_sendf(cl, NULL, "HTTP/%.1f 304 Not Modified\r\n", req->version); - uh_file_response_ok_hdrs(cl, req, s); + ensure_ret(uh_http_sendf(cl, NULL, "HTTP/%.1f 304 Not Modified\r\n", req->version)); + return uh_file_response_ok_hdrs(cl, req, s); } -static void uh_file_response_412(struct client *cl, struct http_request *req) +static int uh_file_response_412(struct client *cl, struct http_request *req) { - uh_http_sendf(cl, NULL, + return uh_http_sendf(cl, NULL, "HTTP/%.1f 412 Precondition Failed\r\n" "Connection: close\r\n", req->version); } -static int uh_file_if_match(struct client *cl, struct http_request *req, struct stat *s) +static int uh_file_if_match(struct client *cl, struct http_request *req, struct stat *s, int *ok) { const char *tag = uh_file_mktag(s); char *hdr = uh_file_header_lookup(req, "If-Match"); @@ -149,43 +150,44 @@ static int uh_file_if_match(struct client *cl, struct http_request *req, struct } else if( !strcmp(p, "*") || !strcmp(p, tag) ) { - return 1; + *ok = 1; + return *ok; } } - uh_file_response_412(cl, req); - return 0; + *ok = 0; + ensure_ret(uh_file_response_412(cl, req)); + return *ok; } - return 1; + *ok = 1; + return *ok; } -static int uh_file_if_modified_since(struct client *cl, struct http_request *req, struct stat *s) +static int uh_file_if_modified_since(struct client *cl, struct http_request *req, struct stat *s, int *ok) { char *hdr = uh_file_header_lookup(req, "If-Modified-Since"); + *ok = 1; if( hdr ) { - if( uh_file_date2unix(hdr) < s->st_mtime ) + if( uh_file_date2unix(hdr) >= s->st_mtime ) { - return 1; - } - else - { - uh_file_response_304(cl, req, s); - return 0; + *ok = 0; + ensure_ret(uh_file_response_304(cl, req, s)); } } - return 1; + return *ok; } -static int uh_file_if_none_match(struct client *cl, struct http_request *req, struct stat *s) +static int uh_file_if_none_match(struct client *cl, struct http_request *req, struct stat *s, int *ok) { const char *tag = uh_file_mktag(s); char *hdr = uh_file_header_lookup(req, "If-None-Match"); char *p; int i; + *ok = 1; if( hdr ) { @@ -200,47 +202,51 @@ static int uh_file_if_none_match(struct client *cl, struct http_request *req, st } else if( !strcmp(p, "*") || !strcmp(p, tag) ) { + *ok = 0; + if( (req->method == UH_HTTP_MSG_GET) || (req->method == UH_HTTP_MSG_HEAD) ) - uh_file_response_304(cl, req, s); + ensure_ret(uh_file_response_304(cl, req, s)); else - uh_file_response_412(cl, req); + ensure_ret(uh_file_response_412(cl, req)); - return 0; + break; } } } - return 1; + return *ok; } -static int uh_file_if_range(struct client *cl, struct http_request *req, struct stat *s) +static int uh_file_if_range(struct client *cl, struct http_request *req, struct stat *s, int *ok) { char *hdr = uh_file_header_lookup(req, "If-Range"); + *ok = 1; if( hdr ) { - uh_file_response_412(cl, req); - return 0; + *ok = 0; + ensure_ret(uh_file_response_412(cl, req)); } - return 1; + return *ok; } -static int uh_file_if_unmodified_since(struct client *cl, struct http_request *req, struct stat *s) +static int uh_file_if_unmodified_since(struct client *cl, struct http_request *req, struct stat *s, int *ok) { char *hdr = uh_file_header_lookup(req, "If-Unmodified-Since"); + *ok = 1; if( hdr ) { if( uh_file_date2unix(hdr) <= s->st_mtime ) { - uh_file_response_412(cl, req); - return 0; + *ok = 0; + ensure_ret(uh_file_response_412(cl, req)); } } - return 1; + return *ok; } @@ -251,17 +257,18 @@ static int uh_file_scandir_filter_dir(const struct dirent *e) static void uh_file_dirlist(struct client *cl, struct http_request *req, struct path_info *pi) { - int i, count; + int i; + int count = 0; char filename[PATH_MAX]; char *pathptr; struct dirent **files = NULL; struct stat s; - uh_http_sendf(cl, req, + ensure_out(uh_http_sendf(cl, req, "Index of %s" "

Index of %s


    ", pi->name, pi->name - ); + )); if( (count = scandir(pi->phys, &files, uh_file_scandir_filter_dir, alphasort)) > 0 ) { @@ -275,14 +282,16 @@ static void uh_file_dirlist(struct client *cl, struct http_request *req, struct strncat(filename, files[i]->d_name, sizeof(filename) - strlen(files[i]->d_name)); - if( !stat(filename, &s) && (s.st_mode & S_IFDIR) ) - uh_http_sendf(cl, req, + if( !stat(filename, &s) && + (s.st_mode & S_IFDIR) && (s.st_mode & S_IXOTH) + ) + ensure_out(uh_http_sendf(cl, req, "
  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; } @@ -293,91 +302,97 @@ static void uh_file_dirlist(struct client *cl, struct http_request *req, struct strncat(filename, files[i]->d_name, sizeof(filename) - strlen(files[i]->d_name)); - if( !stat(filename, &s) && !(s.st_mode & S_IFDIR) ) - uh_http_sendf(cl, req, + if( !stat(filename, &s) && + !(s.st_mode & S_IFDIR) && (s.st_mode & S_IROTH) + ) + ensure_out(uh_http_sendf(cl, req, "
  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; - free(files[i]); } } - free(files); + ensure_out(uh_http_sendf(cl, req, "

")); + ensure_out(uh_http_sendf(cl, req, "")); - uh_http_sendf(cl, req, "
"); - uh_http_sendf(cl, req, ""); +out: + if( files ) + { + for( i = 0; i < count; i++ ) + free(files[i]); + + free(files); + } } void uh_file_request(struct client *cl, struct http_request *req, struct path_info *pi) { - int fd, rlen; + int rlen; + int ok = 1; + int fd = -1; char buf[UH_LIMIT_MSGHEAD]; /* we have a file */ if( (pi->stat.st_mode & S_IFREG) && ((fd = open(pi->phys, O_RDONLY)) > 0) ) { /* test preconditions */ - if( - uh_file_if_modified_since(cl, req, &pi->stat) && - uh_file_if_match(cl, req, &pi->stat) && - uh_file_if_range(cl, req, &pi->stat) && - uh_file_if_unmodified_since(cl, req, &pi->stat) && - uh_file_if_none_match(cl, req, &pi->stat) - ) { + if(ok) ensure_out(uh_file_if_modified_since(cl, req, &pi->stat, &ok)); + if(ok) ensure_out(uh_file_if_match(cl, req, &pi->stat, &ok)); + if(ok) ensure_out(uh_file_if_range(cl, req, &pi->stat, &ok)); + if(ok) ensure_out(uh_file_if_unmodified_since(cl, req, &pi->stat, &ok)); + if(ok) ensure_out(uh_file_if_none_match(cl, req, &pi->stat, &ok)); + + if( ok > 0 ) + { /* write status */ - uh_file_response_200(cl, req, &pi->stat); + ensure_out(uh_file_response_200(cl, req, &pi->stat)); - uh_http_sendf(cl, NULL, "Content-Type: %s\r\n", uh_file_mime_lookup(pi->name)); - uh_http_sendf(cl, NULL, "Content-Length: %i\r\n", pi->stat.st_size); + ensure_out(uh_http_sendf(cl, NULL, "Content-Type: %s\r\n", uh_file_mime_lookup(pi->name))); + ensure_out(uh_http_sendf(cl, NULL, "Content-Length: %i\r\n", pi->stat.st_size)); /* if request was HTTP 1.1 we'll respond chunked */ if( (req->version > 1.0) && (req->method != UH_HTTP_MSG_HEAD) ) - uh_http_send(cl, NULL, "Transfer-Encoding: chunked\r\n", -1); + ensure_out(uh_http_send(cl, NULL, "Transfer-Encoding: chunked\r\n", -1)); /* close header */ - uh_http_send(cl, NULL, "\r\n", -1); + ensure_out(uh_http_send(cl, NULL, "\r\n", -1)); /* send body */ if( req->method != UH_HTTP_MSG_HEAD ) { /* pump file data */ while( (rlen = read(fd, buf, sizeof(buf))) > 0 ) - { - if( uh_http_send(cl, req, buf, rlen) < 0 ) - break; - } + ensure_out(uh_http_send(cl, req, buf, rlen)); /* send trailer in chunked mode */ - uh_http_send(cl, req, "", 0); + ensure_out(uh_http_send(cl, req, "", 0)); } } /* one of the preconditions failed, terminate opened header and exit */ else { - uh_http_send(cl, NULL, "\r\n", -1); + ensure_out(uh_http_send(cl, NULL, "\r\n", -1)); } - - close(fd); } /* directory */ - else if( pi->stat.st_mode & S_IFDIR ) + else if( (pi->stat.st_mode & S_IFDIR) && !cl->server->conf->no_dirlists ) { /* write status */ - uh_file_response_200(cl, req, NULL); + ensure_out(uh_file_response_200(cl, req, NULL)); if( req->version > 1.0 ) - uh_http_send(cl, NULL, "Transfer-Encoding: chunked\r\n", -1); + ensure_out(uh_http_send(cl, NULL, "Transfer-Encoding: chunked\r\n", -1)); - uh_http_send(cl, NULL, "Content-Type: text/html\r\n\r\n", -1); + ensure_out(uh_http_send(cl, NULL, "Content-Type: text/html\r\n\r\n", -1)); /* content */ uh_file_dirlist(cl, req, pi); @@ -386,8 +401,12 @@ void uh_file_request(struct client *cl, struct http_request *req, struct path_in /* 403 */ else { - uh_http_sendhf(cl, 403, "Forbidden", - "Access to this resource is forbidden"); + ensure_out(uh_http_sendhf(cl, 403, "Forbidden", + "Access to this resource is forbidden")); } + +out: + if( fd > -1 ) + close(fd); }