From 2d175dcdcefdd236336c834fb842ab132ee66d0d Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Wed, 11 Aug 2010 23:44:30 +0000 Subject: [PATCH] uhttpd: - abort file serving if client connection is lost (#7742) - don't send bad request headers twice SVN-Revision: 22602 --- package/uhttpd/Makefile | 2 +- package/uhttpd/src/uhttpd-file.c | 85 ++++++++++++++++++-------------- package/uhttpd/src/uhttpd.c | 7 --- 3 files changed, 50 insertions(+), 44 deletions(-) diff --git a/package/uhttpd/Makefile b/package/uhttpd/Makefile index 8a7b5295d9..cb85ad88c0 100644 --- a/package/uhttpd/Makefile +++ b/package/uhttpd/Makefile @@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=uhttpd -PKG_RELEASE:=13 +PKG_RELEASE:=14 PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) PKG_BUILD_DEPENDS := libcyassl liblua diff --git a/package/uhttpd/src/uhttpd-file.c b/package/uhttpd/src/uhttpd-file.c index 850a14175c..ef9a77b6cc 100644 --- a/package/uhttpd/src/uhttpd-file.c +++ b/package/uhttpd/src/uhttpd-file.c @@ -97,36 +97,39 @@ static char * uh_file_header_lookup(struct http_request *req, const char *name) return NULL; } +#define ensure_ret(x) \ + do { if( x < 0 ) return; } while(0) + static void 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))); + ensure_ret(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) { - uh_http_sendf(cl, NULL, "HTTP/%.1f 200 OK\r\n", req->version); + ensure_ret(uh_http_sendf(cl, NULL, "HTTP/%.1f 200 OK\r\n", req->version)); uh_file_response_ok_hdrs(cl, req, s); } static void 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); + ensure_ret(uh_http_sendf(cl, NULL, "HTTP/%.1f 304 Not Modified\r\n", req->version)); uh_file_response_ok_hdrs(cl, req, s); } static void uh_file_response_412(struct client *cl, struct http_request *req) { - uh_http_sendf(cl, NULL, + ensure_ret(uh_http_sendf(cl, NULL, "HTTP/%.1f 412 Precondition Failed\r\n" - "Connection: close\r\n", req->version); + "Connection: close\r\n", req->version)); } static int uh_file_if_match(struct client *cl, struct http_request *req, struct stat *s) @@ -244,6 +247,9 @@ static int uh_file_if_unmodified_since(struct client *cl, struct http_request *r } +#define ensure_out(x) \ + do { if( x < 0 ) goto out; } while(0) + static int uh_file_scandir_filter_dir(const struct dirent *e) { return strcmp(e->d_name, ".") ? 1 : 0; @@ -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 ) { @@ -278,13 +285,13 @@ static void uh_file_dirlist(struct client *cl, struct http_request *req, struct if( !stat(filename, &s) && (s.st_mode & S_IFDIR) && (s.st_mode & S_IXOTH) ) - uh_http_sendf(cl, req, + 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; } @@ -298,30 +305,37 @@ static void uh_file_dirlist(struct client *cl, struct http_request *req, struct if( !stat(filename, &s) && !(s.st_mode & S_IFDIR) && (s.st_mode & S_IROTH) ) - uh_http_sendf(cl, req, + 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, "")); + +out: + if( files ) + { + for( i = 0; i < count; i++ ) + free(files[i]); - uh_http_sendf(cl, req, "
"); - uh_http_sendf(cl, req, ""); + free(files); + } } void uh_file_request(struct client *cl, struct http_request *req, struct path_info *pi) { - int fd, rlen; + int rlen; + int fd = -1; char buf[UH_LIMIT_MSGHEAD]; /* we have a file */ @@ -338,38 +352,33 @@ void uh_file_request(struct client *cl, struct http_request *req, struct path_in /* write status */ 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 */ @@ -379,9 +388,9 @@ void uh_file_request(struct client *cl, struct http_request *req, struct path_in 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); @@ -390,8 +399,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); } diff --git a/package/uhttpd/src/uhttpd.c b/package/uhttpd/src/uhttpd.c index be882470ad..247eb79752 100644 --- a/package/uhttpd/src/uhttpd.c +++ b/package/uhttpd/src/uhttpd.c @@ -1001,13 +1001,6 @@ int main (int argc, char **argv) } } - /* 400 */ - else - { - uh_http_sendhf(cl, 400, "Bad Request", - "Malformed request received"); - } - #ifdef HAVE_TLS /* free client tls context */ if( conf.tls ) -- 2.30.2