xref: /lighttpd1.4/src/mod_staticfile.c (revision 5e14db43)
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 
INIT_FUNC(mod_staticfile_init)33 INIT_FUNC(mod_staticfile_init) {
34     return ck_calloc(1, sizeof(plugin_data));
35 }
36 
mod_staticfile_merge_config_cpv(plugin_config * const pconf,const config_plugin_value_t * const cpv)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 
mod_staticfile_merge_config(plugin_config * const pconf,const config_plugin_value_t * cpv)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 
mod_staticfile_patch_config(request_st * const r,plugin_data * const p)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 
SETDEFAULTS_FUNC(mod_staticfile_set_defaults)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
mod_staticfile_not_handled(request_st * const r,const char * const msg)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
mod_staticfile_process(request_st * const r,plugin_config * const pconf)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 
URIHANDLER_FUNC(mod_staticfile_subrequest)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);
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