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 28 INIT_FUNC(mod_simple_vhost_init) { 29 return ck_calloc(1, sizeof(plugin_data)); 30 } 31 32 FREE_FUNC(mod_simple_vhost_free) { 33 plugin_data *p = p_d; 34 free(p->last_root.ptr); 35 } 36 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 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 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 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 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 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 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); 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