xref: /lighttpd1.4/src/mod_simple_vhost.c (revision 5e14db43)
1 #include "first.h"
2 
3 #include "log.h"
4 #include "buffer.h"
5 #include "request.h"
6 #include "stat_cache.h"
7 
8 #include "plugin.h"
9 
10 #include <stdlib.h>
11 #include <string.h>
12 
13 typedef struct {
14     const buffer *server_root;
15     const buffer *default_host;
16     const buffer *document_root;
17     unsigned short debug;
18 } plugin_config;
19 
20 typedef struct {
21     PLUGIN_DATA;
22     plugin_config defaults;
23     plugin_config conf;
24 
25     buffer last_root;
26 } plugin_data;
27 
INIT_FUNC(mod_simple_vhost_init)28 INIT_FUNC(mod_simple_vhost_init) {
29     return ck_calloc(1, sizeof(plugin_data));
30 }
31 
FREE_FUNC(mod_simple_vhost_free)32 FREE_FUNC(mod_simple_vhost_free) {
33     plugin_data *p = p_d;
34     free(p->last_root.ptr);
35 }
36 
mod_simple_vhost_merge_config_cpv(plugin_config * const pconf,const config_plugin_value_t * const cpv)37 static void mod_simple_vhost_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: /* simple-vhost.server-root */
40         pconf->server_root = cpv->v.b;
41         break;
42       case 1: /* simple-vhost.default-host */
43         pconf->default_host = cpv->v.b;
44         break;
45       case 2: /* simple-vhost.document-root */
46         pconf->document_root = cpv->v.b;
47         break;
48       case 3: /* simple-vhost.debug */
49         pconf->debug = cpv->v.shrt;
50         break;
51       default:/* should not happen */
52         return;
53     }
54 }
55 
mod_simple_vhost_merge_config(plugin_config * const pconf,const config_plugin_value_t * cpv)56 static void mod_simple_vhost_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) {
57     do {
58         mod_simple_vhost_merge_config_cpv(pconf, cpv);
59     } while ((++cpv)->k_id != -1);
60 }
61 
mod_simple_vhost_patch_config(request_st * const r,plugin_data * const p)62 static void mod_simple_vhost_patch_config(request_st * const r, plugin_data * const p) {
63     p->conf = p->defaults; /* copy small struct instead of memcpy() */
64     /*memcpy(&p->conf, &p->defaults, sizeof(plugin_config));*/
65     for (int i = 1, used = p->nconfig; i < used; ++i) {
66         if (config_check_cond(r, (uint32_t)p->cvlist[i].k_id))
67             mod_simple_vhost_merge_config(&p->conf,
68                                           p->cvlist + p->cvlist[i].v.u2[0]);
69     }
70 }
71 
SETDEFAULTS_FUNC(mod_simple_vhost_set_defaults)72 SETDEFAULTS_FUNC(mod_simple_vhost_set_defaults) {
73     static const config_plugin_keys_t cpk[] = {
74       { CONST_STR_LEN("simple-vhost.server-root"),
75         T_CONFIG_STRING,
76         T_CONFIG_SCOPE_CONNECTION }
77      ,{ CONST_STR_LEN("simple-vhost.default-host"),
78         T_CONFIG_STRING,
79         T_CONFIG_SCOPE_CONNECTION }
80      ,{ CONST_STR_LEN("simple-vhost.document-root"),
81         T_CONFIG_STRING,
82         T_CONFIG_SCOPE_CONNECTION }
83      ,{ CONST_STR_LEN("simple-vhost.debug"),
84         T_CONFIG_SHORT,
85         T_CONFIG_SCOPE_CONNECTION }
86      ,{ NULL, 0,
87         T_CONFIG_UNSET,
88         T_CONFIG_SCOPE_UNSET }
89     };
90 
91     plugin_data * const p = p_d;
92     if (!config_plugin_values_init(srv, p, cpk, "mod_simple_vhost"))
93         return HANDLER_ERROR;
94 
95     /* process and validate config directives
96      * (init i to 0 if global context; to 1 to skip empty global context) */
97     for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) {
98         config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
99         for (; -1 != cpv->k_id; ++cpv) {
100             switch (cpv->k_id) {
101               case 0: /* simple-vhost.server-root */
102               case 2: /* simple-vhost.document-root */
103                 if (!buffer_is_blank(cpv->v.b)) {
104                     buffer *b;
105                     *(const buffer **)&b = cpv->v.b;
106                     buffer_append_slash(b);
107                 }
108                 else
109                     cpv->v.b = NULL;
110                 break;
111               case 1: /* simple-vhost.default-host */
112                 if (buffer_is_blank(cpv->v.b))
113                     cpv->v.b = NULL;
114               case 3: /* simple-vhost.debug */
115                 break;
116               default:/* should not happen */
117                 break;
118             }
119         }
120     }
121 
122     /* initialize p->defaults from global config context */
123     if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
124         const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
125         if (-1 != cpv->k_id)
126             mod_simple_vhost_merge_config(&p->defaults, cpv);
127     }
128 
129     return HANDLER_GO_ON;
130 }
131 
build_doc_root_path(buffer * out,const buffer * sroot,const buffer * host,const buffer * droot)132 static void build_doc_root_path(buffer *out, const buffer *sroot, const buffer *host, const buffer *droot) {
133 	buffer_copy_buffer(out, sroot);
134 
135 	if (host) {
136 		/* a hostname has to start with a alpha-numerical character
137 		 * and must not contain a slash "/"
138 		 */
139 		char *dp;
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 
147 	if (droot) {
148 		buffer_append_path_len(out, BUF_PTR_LEN(droot));
149 	}
150 	else {
151 		buffer_append_slash(out);
152 	}
153 }
154 
build_doc_root(request_st * const r,plugin_data * p,buffer * out,const buffer * host)155 static int build_doc_root(request_st * const r, plugin_data *p, buffer *out, const buffer *host) {
156 
157 	build_doc_root_path(out, p->conf.server_root, host, p->conf.document_root);
158 
159 	/* one-element cache (positive cache, not negative cache) */
160 	if (buffer_is_equal(out, &p->last_root)) return 1;
161 
162 	if (!stat_cache_path_isdir(out)) {
163 		if (p->conf.debug) {
164 			log_perror(r->conf.errh, __FILE__, __LINE__, "%s", out->ptr);
165 		}
166 		return 0;
167 	}
168 
169 	buffer_copy_buffer(&p->last_root, out);
170 	return 1;
171 }
172 
mod_simple_vhost_docroot(request_st * const r,void * p_data)173 static handler_t mod_simple_vhost_docroot(request_st * const r, void *p_data) {
174     plugin_data * const p = p_data;
175     mod_simple_vhost_patch_config(r, p);
176     if (!p->conf.server_root) return HANDLER_GO_ON;
177     /* build_doc_root() requires p->conf.server_root;
178      * skip module if simple-vhost.server-root not set or set to empty string */
179 
180     /* (default host and HANDLER_GO_ON instead of HANDLER_ERROR (on error)
181      *  are the two differences between mod_simple_vhost and mod_vhostdb) */
182 
183     /* build document-root */
184     buffer * const b = r->tmp_buf;/*(tmp_buf cleared before use in call below)*/
185     const buffer *host = &r->uri.authority;
186     if ((!buffer_is_blank(host) && build_doc_root(r, p, b, host))
187         || build_doc_root(r, p, b, (host = p->conf.default_host))) {
188         if (host) {
189             r->server_name = &r->server_name_buf;
190             buffer_copy_buffer(&r->server_name_buf, host);
191         }
192         buffer_copy_buffer(&r->physical.doc_root, b);
193     }
194 
195     return HANDLER_GO_ON;
196 }
197 
198 
199 __attribute_cold__
200 int mod_simple_vhost_plugin_init(plugin *p);
mod_simple_vhost_plugin_init(plugin * p)201 int mod_simple_vhost_plugin_init(plugin *p) {
202 	p->version     = LIGHTTPD_VERSION_ID;
203 	p->name        = "simple_vhost";
204 
205 	p->init        = mod_simple_vhost_init;
206 	p->set_defaults = mod_simple_vhost_set_defaults;
207 	p->handle_docroot  = mod_simple_vhost_docroot;
208 	p->cleanup     = mod_simple_vhost_free;
209 
210 	return 0;
211 }
212