X-Git-Url: http://git.archive.openwrt.org/?p=project%2Fuhttpd.git;a=blobdiff_plain;f=file.c;h=f16b893d4d1fe229d3ee9a8e9dbfaecc12536515;hp=adc8e6d42946731f88bf0367005e706aed53520b;hb=78f9f35e22c60d5748f0d69a202ca541c517f0bb;hpb=1f4c517bb889413e55ccee466d9dfe79156092e8 diff --git a/file.c b/file.c index adc8e6d..f16b893 100644 --- a/file.c +++ b/file.c @@ -34,6 +34,16 @@ static LIST_HEAD(index_files); static LIST_HEAD(dispatch_handlers); +static LIST_HEAD(pending_requests); +static int n_requests; + +struct deferred_request { + struct list_head list; + struct dispatch_handler *d; + struct client *cl; + struct path_info pi; + bool called, path; +}; struct index_file { struct list_head list; @@ -222,6 +232,7 @@ uh_path_lookup(struct client *cl, const char *url) url with trailing slash appended */ if (!slash) { uh_http_header(cl, 302, "Found"); + ustream_printf(cl->us, "Content-Length: 0\r\n"); ustream_printf(cl->us, "Location: %s%s%s\r\n\r\n", &path_phys[docroot_len], p.query ? "?" : "", @@ -274,9 +285,9 @@ static const char * uh_file_mime_lookup(const char *path) return "application/octet-stream"; } -static const char * uh_file_mktag(struct stat *s, char *buf) +static const char * uh_file_mktag(struct stat *s, char *buf, int len) { - snprintf(buf, sizeof(buf), "\"%x-%x-%x\"", + snprintf(buf, len, "\"%x-%x-%x\"", (unsigned int) s->st_ino, (unsigned int) s->st_size, (unsigned int) s->st_mtime); @@ -318,7 +329,7 @@ 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, buf)); + ustream_printf(cl->us, "ETag: %s\r\n", uh_file_mktag(s, buf, sizeof(buf))); ustream_printf(cl->us, "Last-Modified: %s\r\n", uh_file_unix2date(s->st_mtime, buf, sizeof(buf))); } @@ -347,7 +358,7 @@ static void uh_file_response_412(struct client *cl) static bool uh_file_if_match(struct client *cl, struct stat *s) { char buf[128]; - const char *tag = uh_file_mktag(s, buf); + const char *tag = uh_file_mktag(s, buf, sizeof(buf)); char *hdr = uh_file_header(cl, HDR_IF_MATCH); char *p; int i; @@ -388,7 +399,7 @@ 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) { char buf[128]; - const char *tag = uh_file_mktag(s, buf); + const char *tag = uh_file_mktag(s, buf, sizeof(buf)); char *hdr = uh_file_header(cl, HDR_IF_NONE_MATCH); char *p; int i; @@ -556,6 +567,8 @@ static void uh_file_data(struct client *cl, struct path_info *pi, int fd) !uh_file_if_range(cl, &pi->stat) || !uh_file_if_unmodified_since(cl, &pi->stat) || !uh_file_if_none_match(cl, &pi->stat)) { + ustream_printf(cl->us, "Content-Length: 0\r\n"); + ustream_printf(cl->us, "\r\n"); uh_request_done(cl); close(fd); return; @@ -647,6 +660,106 @@ dispatch_find(const char *url, struct path_info *pi) return NULL; } +static void +uh_invoke_script(struct client *cl, struct dispatch_handler *d, struct path_info *pi) +{ + char *url = blobmsg_data(blob_data(cl->hdr.head)); + + n_requests++; + d->handle_request(cl, url, pi); +} + +static void uh_complete_request(struct client *cl) +{ + struct deferred_request *dr; + + n_requests--; + + while (!list_empty(&pending_requests)) { + if (n_requests >= conf.max_script_requests) + return; + + dr = list_first_entry(&pending_requests, struct deferred_request, list); + list_del(&dr->list); + + dr->called = true; + uh_invoke_script(dr->cl, dr->d, dr->path ? &dr->pi : NULL); + } +} + + +static void +uh_free_pending_request(struct client *cl) +{ + struct deferred_request *dr = cl->dispatch.req_data; + + if (dr->called) + uh_complete_request(cl); + else + list_del(&dr->list); + free(dr); +} + +static int field_len(const char *ptr) +{ + if (!ptr) + return 0; + + return strlen(ptr) + 1; +} + +#define path_info_fields \ + _field(root) \ + _field(phys) \ + _field(name) \ + _field(info) \ + _field(query) \ + _field(auth) + +static void +uh_defer_script(struct client *cl, struct dispatch_handler *d, struct path_info *pi) +{ + struct deferred_request *dr; + char *_root, *_phys, *_name, *_info, *_query, *_auth; + + cl->dispatch.req_free = uh_free_pending_request; + + if (pi) { + /* allocate enough memory to duplicate all path_info strings in one block */ +#undef _field +#define _field(_name) &_##_name, field_len(pi->_name), + dr = calloc_a(sizeof(*dr), path_info_fields NULL); + + memcpy(&dr->pi, pi, sizeof(*pi)); + dr->path = true; + + /* copy all path_info strings */ +#undef _field +#define _field(_name) if (pi->_name) dr->pi._name = strcpy(_##_name, pi->_name); + path_info_fields + } else { + dr = calloc(1, sizeof(*dr)); + } + + cl->dispatch.req_data = dr; + dr->cl = cl; + dr->d = d; + list_add(&dr->list, &pending_requests); +} + +static void +uh_invoke_handler(struct client *cl, struct dispatch_handler *d, char *url, struct path_info *pi) +{ + if (!d->script) + return d->handle_request(cl, url, pi); + + if (n_requests >= conf.max_script_requests) + return uh_defer_script(cl, d, pi); + + cl->dispatch.req_free = uh_complete_request; + uh_invoke_script(cl, d, pi); +} + static bool __handle_file_request(struct client *cl, char *url) { static const struct blobmsg_policy hdr_policy[__HDR_MAX] = { @@ -677,7 +790,7 @@ static bool __handle_file_request(struct client *cl, char *url) d = dispatch_find(url, pi); if (d) - d->handle_request(cl, url, pi); + uh_invoke_handler(cl, d, url, pi); else uh_file_request(cl, url, pi, tb); @@ -688,15 +801,13 @@ void uh_handle_request(struct client *cl) { struct http_request *req = &cl->request; struct dispatch_handler *d; - char *url = blobmsg_data(blob_data(cl->hdr.head));; + char *url = blobmsg_data(blob_data(cl->hdr.head)); char *error_handler; req->redirect_status = 200; d = dispatch_find(url, NULL); - if (d) { - d->handle_request(cl, url, NULL); - return; - } + if (d) + return uh_invoke_handler(cl, d, url, NULL); if (__handle_file_request(cl, url)) return;