1 #include "base.h"
2 #include "log.h"
3 #include "buffer.h"
4 #include "stat_cache.h"
5
6 #include "plugin.h"
7
8 #include <ctype.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <errno.h>
12
13 typedef struct {
14 buffer *server_root;
15 buffer *default_host;
16 buffer *document_root;
17
18 buffer *docroot_cache_key;
19 buffer *docroot_cache_value;
20 buffer *docroot_cache_servername;
21
22 unsigned short debug;
23 } plugin_config;
24
25 typedef struct {
26 PLUGIN_DATA;
27
28 buffer *doc_root;
29
30 plugin_config **config_storage;
31 plugin_config conf;
32 } plugin_data;
33
INIT_FUNC(mod_simple_vhost_init)34 INIT_FUNC(mod_simple_vhost_init) {
35 plugin_data *p;
36
37 p = calloc(1, sizeof(*p));
38
39 p->doc_root = buffer_init();
40
41 return p;
42 }
43
FREE_FUNC(mod_simple_vhost_free)44 FREE_FUNC(mod_simple_vhost_free) {
45 plugin_data *p = p_d;
46
47 UNUSED(srv);
48
49 if (!p) return HANDLER_GO_ON;
50
51 if (p->config_storage) {
52 size_t i;
53 for (i = 0; i < srv->config_context->used; i++) {
54 plugin_config *s = p->config_storage[i];
55
56 buffer_free(s->document_root);
57 buffer_free(s->default_host);
58 buffer_free(s->server_root);
59
60 buffer_free(s->docroot_cache_key);
61 buffer_free(s->docroot_cache_value);
62 buffer_free(s->docroot_cache_servername);
63
64 free(s);
65 }
66
67 free(p->config_storage);
68 }
69
70 buffer_free(p->doc_root);
71
72 free(p);
73
74 return HANDLER_GO_ON;
75 }
76
SETDEFAULTS_FUNC(mod_simple_vhost_set_defaults)77 SETDEFAULTS_FUNC(mod_simple_vhost_set_defaults) {
78 plugin_data *p = p_d;
79 size_t i;
80
81 config_values_t cv[] = {
82 { "simple-vhost.server-root", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
83 { "simple-vhost.default-host", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
84 { "simple-vhost.document-root", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
85 { "simple-vhost.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
86 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
87 };
88
89 if (!p) return HANDLER_ERROR;
90
91 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
92
93 for (i = 0; i < srv->config_context->used; i++) {
94 plugin_config *s;
95
96 s = calloc(1, sizeof(plugin_config));
97
98 s->server_root = buffer_init();
99 s->default_host = buffer_init();
100 s->document_root = buffer_init();
101
102 s->docroot_cache_key = buffer_init();
103 s->docroot_cache_value = buffer_init();
104 s->docroot_cache_servername = buffer_init();
105
106 s->debug = 0;
107
108 cv[0].destination = s->server_root;
109 cv[1].destination = s->default_host;
110 cv[2].destination = s->document_root;
111 cv[3].destination = &(s->debug);
112
113
114 p->config_storage[i] = s;
115
116 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
117 return HANDLER_ERROR;
118 }
119 }
120
121 return HANDLER_GO_ON;
122 }
123
build_doc_root(server * srv,connection * con,plugin_data * p,buffer * out,buffer * host)124 static int build_doc_root(server *srv, connection *con, plugin_data *p, buffer *out, buffer *host) {
125 stat_cache_entry *sce = NULL;
126
127 buffer_prepare_copy(out, 128);
128
129 if (p->conf.server_root->used) {
130 buffer_copy_string_buffer(out, p->conf.server_root);
131
132 if (host->used) {
133 /* a hostname has to start with a alpha-numerical character
134 * and must not contain a slash "/"
135 */
136 char *dp;
137
138 BUFFER_APPEND_SLASH(out);
139
140 if (NULL == (dp = strchr(host->ptr, ':'))) {
141 buffer_append_string_buffer(out, host);
142 } else {
143 buffer_append_string_len(out, host->ptr, dp - host->ptr);
144 }
145 }
146 BUFFER_APPEND_SLASH(out);
147
148 if (p->conf.document_root->used > 2 && p->conf.document_root->ptr[0] == '/') {
149 buffer_append_string_len(out, p->conf.document_root->ptr + 1, p->conf.document_root->used - 2);
150 } else {
151 buffer_append_string_buffer(out, p->conf.document_root);
152 BUFFER_APPEND_SLASH(out);
153 }
154 } else {
155 buffer_copy_string_buffer(out, con->conf.document_root);
156 BUFFER_APPEND_SLASH(out);
157 }
158
159 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, out, &sce)) {
160 if (p->conf.debug) {
161 log_error_write(srv, __FILE__, __LINE__, "sb",
162 strerror(errno), out);
163 }
164 return -1;
165 } else if (!S_ISDIR(sce->st.st_mode)) {
166 return -1;
167 }
168
169 return 0;
170 }
171
172
173 #define PATCH(x) \
174 p->conf.x = s->x;
mod_simple_vhost_patch_connection(server * srv,connection * con,plugin_data * p)175 static int mod_simple_vhost_patch_connection(server *srv, connection *con, plugin_data *p) {
176 size_t i, j;
177 plugin_config *s = p->config_storage[0];
178
179 PATCH(server_root);
180 PATCH(default_host);
181 PATCH(document_root);
182
183 PATCH(docroot_cache_key);
184 PATCH(docroot_cache_value);
185 PATCH(docroot_cache_servername);
186
187 PATCH(debug);
188
189 /* skip the first, the global context */
190 for (i = 1; i < srv->config_context->used; i++) {
191 data_config *dc = (data_config *)srv->config_context->data[i];
192 s = p->config_storage[i];
193
194 /* condition didn't match */
195 if (!config_check_cond(srv, con, dc)) continue;
196
197 /* merge config */
198 for (j = 0; j < dc->value->used; j++) {
199 data_unset *du = dc->value->data[j];
200
201 if (buffer_is_equal_string(du->key, CONST_STR_LEN("simple-vhost.server-root"))) {
202 PATCH(server_root);
203 PATCH(docroot_cache_key);
204 PATCH(docroot_cache_value);
205 PATCH(docroot_cache_servername);
206 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("simple-vhost.default-host"))) {
207 PATCH(default_host);
208 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("simple-vhost.document-root"))) {
209 PATCH(document_root);
210 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("simple-vhost.debug"))) {
211 PATCH(debug);
212 }
213 }
214 }
215
216 return 0;
217 }
218 #undef PATCH
219
mod_simple_vhost_docroot(server * srv,connection * con,void * p_data)220 static handler_t mod_simple_vhost_docroot(server *srv, connection *con, void *p_data) {
221 plugin_data *p = p_data;
222
223 /*
224 * cache the last successfull translation from hostname (authority) to docroot
225 * - this saves us a stat() call
226 *
227 */
228
229 mod_simple_vhost_patch_connection(srv, con, p);
230
231 if (p->conf.docroot_cache_key->used &&
232 con->uri.authority->used &&
233 buffer_is_equal(p->conf.docroot_cache_key, con->uri.authority)) {
234 /* cache hit */
235 buffer_copy_string_buffer(con->physical.doc_root, p->conf.docroot_cache_value);
236 buffer_copy_string_buffer(con->server_name, p->conf.docroot_cache_servername);
237 } else {
238 /* build document-root */
239 if ((con->uri.authority->used == 0) ||
240 build_doc_root(srv, con, p, p->doc_root, con->uri.authority)) {
241 /* not found, fallback the default-host */
242 if (build_doc_root(srv, con, p,
243 p->doc_root,
244 p->conf.default_host)) {
245 return HANDLER_GO_ON;
246 } else {
247 buffer_copy_string_buffer(con->server_name, p->conf.default_host);
248 buffer_copy_string_buffer(con->physical.doc_root, p->doc_root);
249
250 /* do not cache default host */
251 return HANDLER_GO_ON;
252 }
253 } else {
254 buffer_copy_string_buffer(con->server_name, con->uri.authority);
255 }
256
257 /* copy to cache */
258 buffer_copy_string_buffer(p->conf.docroot_cache_key, con->uri.authority);
259 buffer_copy_string_buffer(p->conf.docroot_cache_value, p->doc_root);
260 buffer_copy_string_buffer(p->conf.docroot_cache_servername, con->server_name);
261
262 buffer_copy_string_buffer(con->physical.doc_root, p->doc_root);
263 }
264
265 return HANDLER_GO_ON;
266 }
267
268
269 int mod_simple_vhost_plugin_init(plugin *p);
mod_simple_vhost_plugin_init(plugin * p)270 int mod_simple_vhost_plugin_init(plugin *p) {
271 p->version = LIGHTTPD_VERSION_ID;
272 p->name = buffer_init_string("simple_vhost");
273
274 p->init = mod_simple_vhost_init;
275 p->set_defaults = mod_simple_vhost_set_defaults;
276 p->handle_docroot = mod_simple_vhost_docroot;
277 p->cleanup = mod_simple_vhost_free;
278
279 p->data = NULL;
280
281 return 0;
282 }
283