1 #include "first.h" 2 3 #include "base.h" 4 #include "log.h" 5 #include "buffer.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 tmp_buf; 26 buffer last_root; 27 } plugin_data; 28 29 INIT_FUNC(mod_simple_vhost_init) { 30 return calloc(1, sizeof(plugin_data)); 31 } 32 33 FREE_FUNC(mod_simple_vhost_free) { 34 plugin_data *p = p_d; 35 free(p->tmp_buf.ptr); 36 free(p->last_root.ptr); 37 } 38 39 static void mod_simple_vhost_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv) { 40 switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */ 41 case 0: /* simple-vhost.server-root */ 42 pconf->server_root = cpv->v.b; 43 break; 44 case 1: /* simple-vhost.default-host */ 45 pconf->default_host = cpv->v.b; 46 break; 47 case 2: /* simple-vhost.document-root */ 48 pconf->document_root = cpv->v.b; 49 break; 50 case 3: /* simple-vhost.debug */ 51 pconf->debug = cpv->v.shrt; 52 break; 53 default:/* should not happen */ 54 return; 55 } 56 } 57 58 static void mod_simple_vhost_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) { 59 do { 60 mod_simple_vhost_merge_config_cpv(pconf, cpv); 61 } while ((++cpv)->k_id != -1); 62 } 63 64 static void mod_simple_vhost_patch_config(request_st * const r, plugin_data * const p) { 65 p->conf = p->defaults; /* copy small struct instead of memcpy() */ 66 /*memcpy(&p->conf, &p->defaults, sizeof(plugin_config));*/ 67 for (int i = 1, used = p->nconfig; i < used; ++i) { 68 if (config_check_cond(r, (uint32_t)p->cvlist[i].k_id)) 69 mod_simple_vhost_merge_config(&p->conf, 70 p->cvlist + p->cvlist[i].v.u2[0]); 71 } 72 } 73 74 SETDEFAULTS_FUNC(mod_simple_vhost_set_defaults) { 75 static const config_plugin_keys_t cpk[] = { 76 { CONST_STR_LEN("simple-vhost.server-root"), 77 T_CONFIG_STRING, 78 T_CONFIG_SCOPE_CONNECTION } 79 ,{ CONST_STR_LEN("simple-vhost.default-host"), 80 T_CONFIG_STRING, 81 T_CONFIG_SCOPE_CONNECTION } 82 ,{ CONST_STR_LEN("simple-vhost.document-root"), 83 T_CONFIG_STRING, 84 T_CONFIG_SCOPE_CONNECTION } 85 ,{ CONST_STR_LEN("simple-vhost.debug"), 86 T_CONFIG_SHORT, 87 T_CONFIG_SCOPE_CONNECTION } 88 ,{ NULL, 0, 89 T_CONFIG_UNSET, 90 T_CONFIG_SCOPE_UNSET } 91 }; 92 93 plugin_data * const p = p_d; 94 if (!config_plugin_values_init(srv, p, cpk, "mod_simple_vhost")) 95 return HANDLER_ERROR; 96 97 /* process and validate config directives 98 * (init i to 0 if global context; to 1 to skip empty global context) */ 99 for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) { 100 config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0]; 101 for (; -1 != cpv->k_id; ++cpv) { 102 switch (cpv->k_id) { 103 case 0: /* simple-vhost.server-root */ 104 case 2: /* simple-vhost.document-root */ 105 if (!buffer_string_is_empty(cpv->v.b)) { 106 buffer *b; 107 *(const buffer **)&b = cpv->v.b; 108 buffer_append_slash(b); 109 } 110 break; 111 case 1: /* simple-vhost.default-host */ 112 case 3: /* simple-vhost.debug */ 113 break; 114 default:/* should not happen */ 115 break; 116 } 117 } 118 } 119 120 /* initialize p->defaults from global config context */ 121 if (p->nconfig > 0 && p->cvlist->v.u2[1]) { 122 const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0]; 123 if (-1 != cpv->k_id) 124 mod_simple_vhost_merge_config(&p->defaults, cpv); 125 } 126 127 return HANDLER_GO_ON; 128 } 129 130 static void build_doc_root_path(buffer *out, const buffer *sroot, const buffer *host, const buffer *droot) { 131 force_assert(!buffer_string_is_empty(sroot)); 132 buffer_copy_buffer(out, sroot); 133 134 if (!buffer_string_is_empty(host)) { 135 /* a hostname has to start with a alpha-numerical character 136 * and must not contain a slash "/" 137 */ 138 char *dp; 139 if (NULL == (dp = strchr(host->ptr, ':'))) { 140 buffer_append_string_buffer(out, host); 141 } else { 142 buffer_append_string_len(out, host->ptr, dp - host->ptr); 143 } 144 } 145 146 if (!buffer_string_is_empty(droot)) { 147 buffer_append_path_len(out, CONST_BUF_LEN(droot)); 148 } 149 else { 150 buffer_append_slash(out); 151 } 152 } 153 154 static int build_doc_root(request_st * const r, plugin_data *p, buffer *out, const buffer *host) { 155 stat_cache_entry *sce = NULL; 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 sce = stat_cache_get_entry(out); 163 if (NULL == sce) { 164 if (p->conf.debug) { 165 log_perror(r->conf.errh, __FILE__, __LINE__, "%s", out->ptr); 166 } 167 return 0; 168 } else if (!S_ISDIR(sce->st.st_mode)) { 169 return 0; 170 } 171 172 buffer_copy_buffer(&p->last_root, out); 173 return 1; 174 } 175 176 static handler_t mod_simple_vhost_docroot(request_st * const r, void *p_data) { 177 plugin_data * const p = p_data; 178 mod_simple_vhost_patch_config(r, p); 179 if (buffer_string_is_empty(p->conf.server_root)) return HANDLER_GO_ON; 180 /* build_doc_root() requires p->conf.server_root; 181 * skip module if simple-vhost.server-root not set or set to empty string */ 182 183 /* (default host and HANDLER_GO_ON instead of HANDLER_ERROR (on error) 184 * are the two differences between mod_simple_vhost and mod_vhostdb) */ 185 186 /* build document-root */ 187 buffer * const b = &p->tmp_buf; 188 const buffer *host = &r->uri.authority; 189 if ((!buffer_string_is_empty(host) && build_doc_root(r, p, b, host)) 190 || build_doc_root(r, p, b, (host = p->conf.default_host))) { 191 r->server_name = &r->server_name_buf; 192 buffer_copy_buffer(&r->server_name_buf, host); 193 buffer_copy_buffer(&r->physical.doc_root, b); 194 } 195 196 return HANDLER_GO_ON; 197 } 198 199 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