1 #include "first.h" 2 3 #include "log.h" 4 #include "buffer.h" 5 6 #include "plugin.h" 7 8 #include "request.h" 9 #include "response.h" 10 #include "stat_cache.h" 11 12 #include <stdlib.h> 13 #include <string.h> 14 15 /** 16 * this is a staticfile for a lighttpd plugin 17 * 18 */ 19 20 21 typedef struct { 22 const array *exclude_ext; 23 unsigned short etags_used; 24 unsigned short disable_pathinfo; 25 } plugin_config; 26 27 typedef struct { 28 PLUGIN_DATA; 29 plugin_config defaults; 30 plugin_config conf; 31 } plugin_data; 32 33 INIT_FUNC(mod_staticfile_init) { 34 return calloc(1, sizeof(plugin_data)); 35 } 36 37 static void mod_staticfile_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv) { 38 switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */ 39 case 0: /* static-file.exclude-extensions */ 40 pconf->exclude_ext = cpv->v.a; 41 break; 42 case 1: /* static-file.etags */ 43 pconf->etags_used = cpv->v.u; 44 break; 45 case 2: /* static-file.disable-pathinfo */ 46 pconf->disable_pathinfo = cpv->v.u; 47 break; 48 default:/* should not happen */ 49 return; 50 } 51 } 52 53 static void mod_staticfile_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) { 54 do { 55 mod_staticfile_merge_config_cpv(pconf, cpv); 56 } while ((++cpv)->k_id != -1); 57 } 58 59 static void mod_staticfile_patch_config(request_st * const r, plugin_data * const p) { 60 p->conf = p->defaults; /* copy small struct instead of memcpy() */ 61 /*memcpy(&p->conf, &p->defaults, sizeof(plugin_config));*/ 62 for (int i = 1, used = p->nconfig; i < used; ++i) { 63 if (config_check_cond(r, (uint32_t)p->cvlist[i].k_id)) 64 mod_staticfile_merge_config(&p->conf, 65 p->cvlist + p->cvlist[i].v.u2[0]); 66 } 67 } 68 69 SETDEFAULTS_FUNC(mod_staticfile_set_defaults) { 70 static const config_plugin_keys_t cpk[] = { 71 { CONST_STR_LEN("static-file.exclude-extensions"), 72 T_CONFIG_ARRAY_VLIST, 73 T_CONFIG_SCOPE_CONNECTION } 74 ,{ CONST_STR_LEN("static-file.etags"), 75 T_CONFIG_BOOL, 76 T_CONFIG_SCOPE_CONNECTION } 77 ,{ CONST_STR_LEN("static-file.disable-pathinfo"), 78 T_CONFIG_BOOL, 79 T_CONFIG_SCOPE_CONNECTION } 80 ,{ NULL, 0, 81 T_CONFIG_UNSET, 82 T_CONFIG_SCOPE_UNSET } 83 }; 84 85 plugin_data * const p = p_d; 86 if (!config_plugin_values_init(srv, p, cpk, "mod_staticfile")) 87 return HANDLER_ERROR; 88 89 /* initialize p->defaults from global config context */ 90 p->defaults.etags_used = 1; /* etags enabled */ 91 if (p->nconfig > 0 && p->cvlist->v.u2[1]) { 92 const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0]; 93 if (-1 != cpv->k_id) 94 mod_staticfile_merge_config(&p->defaults, cpv); 95 } 96 97 return HANDLER_GO_ON; 98 } 99 100 __attribute_cold__ 101 static handler_t 102 mod_staticfile_not_handled(request_st * const r, const char * const msg) 103 { 104 if (r->conf.log_request_handling) 105 log_error(r->conf.errh, __FILE__, __LINE__, 106 "-- NOT handling file as static file, %s forbidden", msg); 107 return HANDLER_GO_ON; 108 } 109 110 static handler_t 111 mod_staticfile_process (request_st * const r, plugin_config * const pconf) 112 { 113 if (pconf->disable_pathinfo && !buffer_is_blank(&r->pathinfo)) { 114 return mod_staticfile_not_handled(r, "pathinfo"); 115 } 116 117 if (pconf->exclude_ext 118 && array_match_value_suffix(pconf->exclude_ext, &r->physical.path)) { 119 return mod_staticfile_not_handled(r, "extension"); 120 } 121 122 if (!pconf->etags_used) r->conf.etag_flags = 0; 123 124 /* r->tmp_sce is set in http_response_physical_path_check() and is valid 125 * in handle_subrequest_start callback -- handle_subrequest_start callbacks 126 * should not change r->physical.path (or should invalidate r->tmp_sce) */ 127 if (r->tmp_sce && !buffer_is_equal(&r->tmp_sce->name, &r->physical.path)) 128 r->tmp_sce = NULL; 129 130 http_response_send_file(r, &r->physical.path, r->tmp_sce); 131 132 return HANDLER_FINISHED; 133 } 134 135 URIHANDLER_FUNC(mod_staticfile_subrequest) { 136 if (NULL != r->handler_module) return HANDLER_GO_ON; 137 if (!http_method_get_head_query_post(r->http_method)) return HANDLER_GO_ON; 138 /* r->physical.path is non-empty for handle_subrequest_start */ 139 /*if (buffer_is_blank(&r->physical.path)) return HANDLER_GO_ON;*/ 140 141 plugin_data * const p = p_d; 142 mod_staticfile_patch_config(r, p); 143 144 return mod_staticfile_process(r, &p->conf); 145 } 146 147 148 __attribute_cold__ 149 int mod_staticfile_plugin_init(plugin *p); 150 int mod_staticfile_plugin_init(plugin *p) { 151 p->version = LIGHTTPD_VERSION_ID; 152 p->name = "staticfile"; 153 154 p->init = mod_staticfile_init; 155 p->handle_subrequest_start = mod_staticfile_subrequest; 156 p->set_defaults = mod_staticfile_set_defaults; 157 158 return 0; 159 } 160