From ce21c64809c2f09f1c5acd97c806b778acf0a2db Mon Sep 17 00:00:00 2001 From: Jeremy Lakeman Date: Mon, 24 Nov 2014 16:54:35 +1030 Subject: [PATCH] Allow serving of static http content from [etc]/static/ --- httpd.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++ httpd.h | 9 +++++- rhizome_restful.c | 20 +++---------- 3 files changed, 86 insertions(+), 17 deletions(-) diff --git a/httpd.c b/httpd.c index b8cb631c..05303e86 100644 --- a/httpd.c +++ b/httpd.c @@ -33,6 +33,7 @@ static HTTP_HANDLER root_page; static HTTP_HANDLER fav_icon_header; static HTTP_HANDLER interface_page; static HTTP_HANDLER neighbour_page; +static HTTP_HANDLER static_page; HTTP_HANDLER restful_rhizome_bundlelist_json; HTTP_HANDLER restful_rhizome_newsince; @@ -67,6 +68,7 @@ struct http_handler paths[]={ {"/rhizome/enquiry", rhizome_direct_enquiry}, {"/rhizome/manifestbyprefix/", manifest_by_prefix_page}, {"/rhizome/", rhizome_direct_dispatch}, + {"/static/", static_page}, {"/interface/", interface_page}, {"/neighbour/", neighbour_page}, {"/favicon.ico", fav_icon_header}, @@ -488,6 +490,23 @@ int http_response_form_part(httpd_request *r, const char *what, const char *part return 403; } +int http_response_init_content_range(httpd_request *r, size_t resource_length) +{ + r->http.response.header.resource_length = resource_length; + if (r->http.request_header.content_range_count == 1) { + struct http_range closed; + unsigned n = http_range_close(&closed, r->http.request_header.content_ranges, 1, resource_length); + if (n == 0 || http_range_bytes(&closed, 1) == 0) + return 416; // Request Range Not Satisfiable + r->http.response.header.content_range_start = closed.first; + r->http.response.header.content_length = closed.last - closed.first + 1; + }else{ + r->http.response.header.content_range_start = 0; + r->http.response.header.content_length = resource_length; + } + return 0; +} + static int root_page(httpd_request *r, const char *remainder) { if (*remainder) @@ -571,3 +590,58 @@ static int interface_page(httpd_request *r, const char *remainder) http_request_response_static(&r->http, 200, CONTENT_TYPE_HTML, buf, strbuf_len(b)); return 1; } + +static void finalise_union_close_file(httpd_request *r) +{ + if (r->u.file.fd==-1) + return; + close(r->u.file.fd); + r->u.file.fd=-1; +} + +static int static_file_generator(struct http_request *hr, unsigned char *buf, size_t bufsz, struct http_content_generator_result *result) +{ + struct httpd_request *r=(struct httpd_request *)hr; + uint64_t remain = r->http.response.header.content_length + r->http.response.header.content_range_start - r->u.file.offset; + if (bufsz < remain) + remain = bufsz; + ssize_t bytes = read(r->u.file.fd, buf, remain); + if (bytes == -1) + return -1; + r->u.file.offset+=bytes; + result->generated = bytes; + return (r->u.file.offset >= r->http.response.header.content_length + r->http.response.header.content_range_start)?0:1; +} + +static int static_page(httpd_request *r, const char *remainder) +{ + if (r->http.verb != HTTP_VERB_GET) + return 405; + char path[PATH_MAX]; + + if (!*remainder) + remainder="index.html"; + if (FORMF_SERVAL_ETC_PATH(path, "static/%s", remainder)==0) + return 500; + struct stat stat; + if (lstat(path, &stat)) + return 404; + + r->u.file.fd = open(path, O_RDONLY); + if (r->u.file.fd==-1) + return 404; + + r->finalise_union=finalise_union_close_file; + + // TODO find extension and set content type properly + http_response_init_content_range(r, stat.st_size); + if (r->http.response.header.content_range_start){ + if (lseek64(r->u.file.fd, r->http.response.header.content_range_start, SEEK_SET)){ + WARNF_perror("lseek(%s)", path); + return 500; + } + } + r->u.file.offset=r->http.response.header.content_range_start; + http_request_response_generated(&r->http, 200, CONTENT_TYPE_HTML, static_file_generator); + return 1; +} diff --git a/httpd.h b/httpd.h index 2e3860b7..42d18323 100644 --- a/httpd.h +++ b/httpd.h @@ -194,7 +194,13 @@ typedef struct httpd_request struct form_buf_malloc message; } sendmsg; - + + + struct { + int fd; + size_t offset; + } + file; } u; } httpd_request; @@ -208,6 +214,7 @@ int authorize_restful(struct http_request *r); int http_response_content_type(httpd_request *r, const char *what, const struct mime_content_type *ct); int http_response_content_disposition(httpd_request *r, const char *what, const char *type); int http_response_form_part(httpd_request *r, const char *what, const char *partname, const char *text, size_t textlen); +int http_response_init_content_range(httpd_request *r, size_t resource_length); int accumulate_text(httpd_request *r, const char *partname, char *textbuf, size_t textsiz, size_t *textlenp, const char *buf, size_t len); int rhizome_response_content_init_filehash(httpd_request *r, const rhizome_filehash_t *hash); diff --git a/rhizome_restful.c b/rhizome_restful.c index 280a5c12..07c2b132 100644 --- a/rhizome_restful.c +++ b/rhizome_restful.c @@ -795,22 +795,10 @@ static int rhizome_response_content_init_read_state(httpd_request *r) return 404; } assert(r->u.read_state.length != RHIZOME_SIZE_UNSET); - r->http.response.header.resource_length = r->u.read_state.length; - if (r->http.request_header.content_range_count > 0) { - assert(r->http.request_header.content_range_count == 1); - struct http_range closed; - unsigned n = http_range_close(&closed, r->http.request_header.content_ranges, 1, r->u.read_state.length); - if (n == 0 || http_range_bytes(&closed, 1) == 0) - return 416; // Request Range Not Satisfiable - r->http.response.header.content_range_start = closed.first; - r->http.response.header.content_length = closed.last - closed.first + 1; - r->u.read_state.offset = closed.first; - } else { - r->http.response.header.content_range_start = 0; - r->http.response.header.content_length = r->http.response.header.resource_length; - r->u.read_state.offset = 0; - } - return 0; + int ret = http_response_init_content_range(r, r->u.read_state.length); + if (ret==0) + r->u.read_state.offset = r->http.response.header.content_range_start; + return ret; } int rhizome_response_content_init_filehash(httpd_request *r, const rhizome_filehash_t *hash)