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