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