Diff for /embedaddon/lighttpd/src/mod_staticfile.c between versions 1.1.1.2 and 1.1.1.3

version 1.1.1.2, 2014/06/15 20:20:06 version 1.1.1.3, 2016/11/02 10:35:00
Line 1 Line 1
   #include "first.h"
   
 #include "base.h"  #include "base.h"
 #include "log.h"  #include "log.h"
 #include "buffer.h"  #include "buffer.h"
Line 32  typedef struct { Line 34  typedef struct {
 typedef struct {  typedef struct {
         PLUGIN_DATA;          PLUGIN_DATA;
   
         buffer *range_buf;  
   
         plugin_config **config_storage;          plugin_config **config_storage;
   
         plugin_config conf;          plugin_config conf;
Line 45  INIT_FUNC(mod_staticfile_init) { Line 45  INIT_FUNC(mod_staticfile_init) {
   
         p = calloc(1, sizeof(*p));          p = calloc(1, sizeof(*p));
   
         p->range_buf = buffer_init();  
   
         return p;          return p;
 }  }
   
Line 63  FREE_FUNC(mod_staticfile_free) { Line 61  FREE_FUNC(mod_staticfile_free) {
                 for (i = 0; i < srv->config_context->used; i++) {                  for (i = 0; i < srv->config_context->used; i++) {
                         plugin_config *s = p->config_storage[i];                          plugin_config *s = p->config_storage[i];
   
                           if (NULL == s) continue;
   
                         array_free(s->exclude_ext);                          array_free(s->exclude_ext);
   
                         free(s);                          free(s);
                 }                  }
                 free(p->config_storage);                  free(p->config_storage);
         }          }
         buffer_free(p->range_buf);  
   
         free(p);          free(p);
   
Line 94  SETDEFAULTS_FUNC(mod_staticfile_set_defaults) { Line 93  SETDEFAULTS_FUNC(mod_staticfile_set_defaults) {
         p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));          p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
   
         for (i = 0; i < srv->config_context->used; i++) {          for (i = 0; i < srv->config_context->used; i++) {
                   data_config const* config = (data_config const*)srv->config_context->data[i];
                 plugin_config *s;                  plugin_config *s;
   
                 s = calloc(1, sizeof(plugin_config));                  s = calloc(1, sizeof(plugin_config));
Line 107  SETDEFAULTS_FUNC(mod_staticfile_set_defaults) { Line 107  SETDEFAULTS_FUNC(mod_staticfile_set_defaults) {
   
                 p->config_storage[i] = s;                  p->config_storage[i] = s;
   
                if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {                if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
                         return HANDLER_ERROR;                          return HANDLER_ERROR;
                 }                  }
         }          }
Line 151  static int mod_staticfile_patch_connection(server *srv Line 151  static int mod_staticfile_patch_connection(server *srv
 }  }
 #undef PATCH  #undef PATCH
   
 static int http_response_parse_range(server *srv, connection *con, plugin_data *p) {  
         int multipart = 0;  
         int error;  
         off_t start, end;  
         const char *s, *minus;  
         char *boundary = "fkj49sn38dcn3";  
         data_string *ds;  
         stat_cache_entry *sce = NULL;  
         buffer *content_type = NULL;  
   
         if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {  
                 SEGFAULT();  
         }  
   
         start = 0;  
         end = sce->st.st_size - 1;  
   
         con->response.content_length = 0;  
   
         if (NULL != (ds = (data_string *)array_get_element(con->response.headers, "Content-Type"))) {  
                 content_type = ds->value;  
         }  
   
         for (s = con->request.http_range, error = 0;  
              !error && *s && NULL != (minus = strchr(s, '-')); ) {  
                 char *err;  
                 off_t la, le;  
   
                 if (s == minus) {  
                         /* -<stop> */  
   
                         le = strtoll(s, &err, 10);  
   
                         if (le == 0) {  
                                 /* RFC 2616 - 14.35.1 */  
   
                                 con->http_status = 416;  
                                 error = 1;  
                         } else if (*err == '\0') {  
                                 /* end */  
                                 s = err;  
   
                                 end = sce->st.st_size - 1;  
                                 start = sce->st.st_size + le;  
                         } else if (*err == ',') {  
                                 multipart = 1;  
                                 s = err + 1;  
   
                                 end = sce->st.st_size - 1;  
                                 start = sce->st.st_size + le;  
                         } else {  
                                 error = 1;  
                         }  
   
                 } else if (*(minus+1) == '\0' || *(minus+1) == ',') {  
                         /* <start>- */  
   
                         la = strtoll(s, &err, 10);  
   
                         if (err == minus) {  
                                 /* ok */  
   
                                 if (*(err + 1) == '\0') {  
                                         s = err + 1;  
   
                                         end = sce->st.st_size - 1;  
                                         start = la;  
   
                                 } else if (*(err + 1) == ',') {  
                                         multipart = 1;  
                                         s = err + 2;  
   
                                         end = sce->st.st_size - 1;  
                                         start = la;  
                                 } else {  
                                         error = 1;  
                                 }  
                         } else {  
                                 /* error */  
                                 error = 1;  
                         }  
                 } else {  
                         /* <start>-<stop> */  
   
                         la = strtoll(s, &err, 10);  
   
                         if (err == minus) {  
                                 le = strtoll(minus+1, &err, 10);  
   
                                 /* RFC 2616 - 14.35.1 */  
                                 if (la > le) {  
                                         error = 1;  
                                 }  
   
                                 if (*err == '\0') {  
                                         /* ok, end*/  
                                         s = err;  
   
                                         end = le;  
                                         start = la;  
                                 } else if (*err == ',') {  
                                         multipart = 1;  
                                         s = err + 1;  
   
                                         end = le;  
                                         start = la;  
                                 } else {  
                                         /* error */  
   
                                         error = 1;  
                                 }  
                         } else {  
                                 /* error */  
   
                                 error = 1;  
                         }  
                 }  
   
                 if (!error) {  
                         if (start < 0) start = 0;  
   
                         /* RFC 2616 - 14.35.1 */  
                         if (end > sce->st.st_size - 1) end = sce->st.st_size - 1;  
   
                         if (start > sce->st.st_size - 1) {  
                                 error = 1;  
   
                                 con->http_status = 416;  
                         }  
                 }  
   
                 if (!error) {  
                         if (multipart) {  
                                 /* write boundary-header */  
                                 buffer *b;  
   
                                 b = chunkqueue_get_append_buffer(con->write_queue);  
   
                                 buffer_copy_string_len(b, CONST_STR_LEN("\r\n--"));  
                                 buffer_append_string(b, boundary);  
   
                                 /* write Content-Range */  
                                 buffer_append_string_len(b, CONST_STR_LEN("\r\nContent-Range: bytes "));  
                                 buffer_append_off_t(b, start);  
                                 buffer_append_string_len(b, CONST_STR_LEN("-"));  
                                 buffer_append_off_t(b, end);  
                                 buffer_append_string_len(b, CONST_STR_LEN("/"));  
                                 buffer_append_off_t(b, sce->st.st_size);  
   
                                 buffer_append_string_len(b, CONST_STR_LEN("\r\nContent-Type: "));  
                                 buffer_append_string_buffer(b, content_type);  
   
                                 /* write END-OF-HEADER */  
                                 buffer_append_string_len(b, CONST_STR_LEN("\r\n\r\n"));  
   
                                 con->response.content_length += b->used - 1;  
   
                         }  
   
                         chunkqueue_append_file(con->write_queue, con->physical.path, start, end - start + 1);  
                         con->response.content_length += end - start + 1;  
                 }  
         }  
   
         /* something went wrong */  
         if (error) return -1;  
   
         if (multipart) {  
                 /* add boundary end */  
                 buffer *b;  
   
                 b = chunkqueue_get_append_buffer(con->write_queue);  
   
                 buffer_copy_string_len(b, "\r\n--", 4);  
                 buffer_append_string(b, boundary);  
                 buffer_append_string_len(b, "--\r\n", 4);  
   
                 con->response.content_length += b->used - 1;  
   
                 /* set header-fields */  
   
                 buffer_copy_string_len(p->range_buf, CONST_STR_LEN("multipart/byteranges; boundary="));  
                 buffer_append_string(p->range_buf, boundary);  
   
                 /* overwrite content-type */  
                 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(p->range_buf));  
         } else {  
                 /* add Content-Range-header */  
   
                 buffer_copy_string_len(p->range_buf, CONST_STR_LEN("bytes "));  
                 buffer_append_off_t(p->range_buf, start);  
                 buffer_append_string_len(p->range_buf, CONST_STR_LEN("-"));  
                 buffer_append_off_t(p->range_buf, end);  
                 buffer_append_string_len(p->range_buf, CONST_STR_LEN("/"));  
                 buffer_append_off_t(p->range_buf, sce->st.st_size);  
   
                 response_header_insert(srv, con, CONST_STR_LEN("Content-Range"), CONST_BUF_LEN(p->range_buf));  
         }  
   
         /* ok, the file is set-up */  
         return 0;  
 }  
   
 URIHANDLER_FUNC(mod_staticfile_subrequest) {  URIHANDLER_FUNC(mod_staticfile_subrequest) {
         plugin_data *p = p_d;          plugin_data *p = p_d;
         size_t k;          size_t k;
         stat_cache_entry *sce = NULL;  
         buffer *mtime = NULL;  
         data_string *ds;          data_string *ds;
         int allow_caching = 1;  
   
         /* someone else has done a decision for us */          /* someone else has done a decision for us */
         if (con->http_status != 0) return HANDLER_GO_ON;          if (con->http_status != 0) return HANDLER_GO_ON;
        if (con->uri.path->used == 0) return HANDLER_GO_ON;        if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
        if (con->physical.path->used == 0) return HANDLER_GO_ON;        if (buffer_is_empty(con->physical.path)) return HANDLER_GO_ON;
   
         /* someone else has handled this request */          /* someone else has handled this request */
         if (con->mode != DIRECT) return HANDLER_GO_ON;          if (con->mode != DIRECT) return HANDLER_GO_ON;
Line 382  URIHANDLER_FUNC(mod_staticfile_subrequest) { Line 176  URIHANDLER_FUNC(mod_staticfile_subrequest) {
   
         mod_staticfile_patch_connection(srv, con, p);          mod_staticfile_patch_connection(srv, con, p);
   
        if (p->conf.disable_pathinfo && 0 != con->request.pathinfo->used) {        if (p->conf.disable_pathinfo && !buffer_string_is_empty(con->request.pathinfo)) {
                 if (con->conf.log_request_handling) {                  if (con->conf.log_request_handling) {
                         log_error_write(srv, __FILE__, __LINE__,  "s",  "-- NOT handling file as static file, pathinfo forbidden");                          log_error_write(srv, __FILE__, __LINE__,  "s",  "-- NOT handling file as static file, pathinfo forbidden");
                 }                  }
Line 393  URIHANDLER_FUNC(mod_staticfile_subrequest) { Line 187  URIHANDLER_FUNC(mod_staticfile_subrequest) {
         for (k = 0; k < p->conf.exclude_ext->used; k++) {          for (k = 0; k < p->conf.exclude_ext->used; k++) {
                 ds = (data_string *)p->conf.exclude_ext->data[k];                  ds = (data_string *)p->conf.exclude_ext->data[k];
   
                if (ds->value->used == 0) continue;                if (buffer_is_empty(ds->value)) continue;
   
                if (buffer_is_equal_right_len(con->physical.path, ds->value, ds->value->used - 1)) {                if (buffer_is_equal_right_len(con->physical.path, ds->value, buffer_string_length(ds->value))) {
                         if (con->conf.log_request_handling) {                          if (con->conf.log_request_handling) {
                                 log_error_write(srv, __FILE__, __LINE__,  "s",  "-- NOT handling file as static file, extension forbidden");                                  log_error_write(srv, __FILE__, __LINE__,  "s",  "-- NOT handling file as static file, extension forbidden");
                         }                          }
Line 408  URIHANDLER_FUNC(mod_staticfile_subrequest) { Line 202  URIHANDLER_FUNC(mod_staticfile_subrequest) {
                 log_error_write(srv, __FILE__, __LINE__,  "s",  "-- handling file as static file");                  log_error_write(srv, __FILE__, __LINE__,  "s",  "-- handling file as static file");
         }          }
   
        if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {        if (!p->conf.etags_used) con->etag_flags = 0;
                con->http_status = 403;        http_response_send_file(srv, con, con->physical.path);
 
                log_error_write(srv, __FILE__, __LINE__, "sbsb", 
                                "not a regular file:", con->uri.path, 
                                "->", con->physical.path); 
 
                return HANDLER_FINISHED; 
        } 
 
        /* we only handline regular files */ 
#ifdef HAVE_LSTAT 
        if ((sce->is_symlink == 1) && !con->conf.follow_symlink) { 
                con->http_status = 403; 
 
                if (con->conf.log_request_handling) { 
                        log_error_write(srv, __FILE__, __LINE__,  "s",  "-- access denied due symlink restriction"); 
                        log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path); 
                } 
 
                buffer_reset(con->physical.path); 
                return HANDLER_FINISHED; 
        } 
#endif 
        if (!S_ISREG(sce->st.st_mode)) { 
                con->http_status = 404; 
 
                if (con->conf.log_file_not_found) { 
                        log_error_write(srv, __FILE__, __LINE__, "sbsb", 
                                        "not a regular file:", con->uri.path, 
                                        "->", sce->name); 
                } 
 
                return HANDLER_FINISHED; 
        } 
 
        /* mod_compress might set several data directly, don't overwrite them */ 
 
        /* set response content-type, if not set already */ 
 
        if (NULL == array_get_element(con->response.headers, "Content-Type")) { 
                if (buffer_is_empty(sce->content_type)) { 
                        /* we are setting application/octet-stream, but also announce that 
                         * this header field might change in the seconds few requests  
                         * 
                         * This should fix the aggressive caching of FF and the script download 
                         * seen by the first installations 
                         */ 
                        response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("application/octet-stream")); 
 
                        allow_caching = 0; 
                } else { 
                        response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type)); 
                } 
        } 
 
        if (con->conf.range_requests) { 
                response_header_overwrite(srv, con, CONST_STR_LEN("Accept-Ranges"), CONST_STR_LEN("bytes")); 
        } 
 
        if (allow_caching) { 
                if (p->conf.etags_used && con->etag_flags != 0 && !buffer_is_empty(sce->etag)) { 
                        if (NULL == array_get_element(con->response.headers, "ETag")) { 
                                /* generate e-tag */ 
                                etag_mutate(con->physical.etag, sce->etag); 
 
                                response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag)); 
                        } 
                } 
 
                /* prepare header */ 
                if (NULL == (ds = (data_string *)array_get_element(con->response.headers, "Last-Modified"))) { 
                        mtime = strftime_cache_get(srv, sce->st.st_mtime); 
                        response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime)); 
                } else { 
                        mtime = ds->value; 
                } 
 
                if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, mtime)) { 
                        return HANDLER_FINISHED; 
                } 
        } 
 
        if (con->request.http_range && con->conf.range_requests) { 
                int do_range_request = 1; 
                /* check if we have a conditional GET */ 
 
                if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "If-Range"))) { 
                        /* if the value is the same as our ETag, we do a Range-request, 
                         * otherwise a full 200 */ 
 
                        if (ds->value->ptr[0] == '"') { 
                                /** 
                                 * client wants a ETag 
                                 */ 
                                if (!con->physical.etag) { 
                                        do_range_request = 0; 
                                } else if (!buffer_is_equal(ds->value, con->physical.etag)) { 
                                        do_range_request = 0; 
                                } 
                        } else if (!mtime) { 
                                /** 
                                 * we don't have a Last-Modified and can match the If-Range:  
                                 * 
                                 * sending all 
                                 */ 
                                do_range_request = 0; 
                        } else if (!buffer_is_equal(ds->value, mtime)) { 
                                do_range_request = 0; 
                        } 
                } 
 
                if (do_range_request) { 
                        /* content prepared, I'm done */ 
                        con->file_finished = 1; 
 
                        if (0 == http_response_parse_range(srv, con, p)) { 
                                con->http_status = 206; 
                        } 
                        return HANDLER_FINISHED; 
                } 
        } 
 
        /* if we are still here, prepare body */ 
 
        /* we add it here for all requests 
         * the HEAD request will drop it afterwards again 
         */ 
        http_chunk_append_file(srv, con, con->physical.path, 0, sce->st.st_size); 
 
        con->http_status = 200; 
        con->file_finished = 1; 
   
         return HANDLER_FINISHED;          return HANDLER_FINISHED;
 }  }

Removed from v.1.1.1.2  
changed lines
  Added in v.1.1.1.3


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>