1 #include "first.h" 2 3 #include <errno.h> 4 #include <stdlib.h> 5 #include <string.h> 6 7 #include "buffer.h" 8 #include "http_header.h" 9 #include "log.h" 10 #include "plugin.h" 11 #include "request.h" 12 #include "stat_cache.h" 13 14 typedef struct { 15 const array *indexfiles; 16 } plugin_config; 17 18 typedef struct { 19 PLUGIN_DATA; 20 plugin_config defaults; 21 plugin_config conf; 22 } plugin_data; 23 24 INIT_FUNC(mod_indexfile_init) { 25 return calloc(1, sizeof(plugin_data)); 26 } 27 28 static void mod_indexfile_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv) { 29 switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */ 30 case 0: /* index-file.names */ 31 case 1: /* server.indexfiles */ 32 pconf->indexfiles = cpv->v.a; 33 break; 34 default:/* should not happen */ 35 return; 36 } 37 } 38 39 static void mod_indexfile_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) { 40 do { 41 mod_indexfile_merge_config_cpv(pconf, cpv); 42 } while ((++cpv)->k_id != -1); 43 } 44 45 static void mod_indexfile_patch_config(request_st * const r, plugin_data * const p) { 46 p->conf = p->defaults; /* copy small struct instead of memcpy() */ 47 /*memcpy(&p->conf, &p->defaults, sizeof(plugin_config));*/ 48 for (int i = 1, used = p->nconfig; i < used; ++i) { 49 if (config_check_cond(r, (uint32_t)p->cvlist[i].k_id)) 50 mod_indexfile_merge_config(&p->conf,p->cvlist+p->cvlist[i].v.u2[0]); 51 } 52 } 53 54 SETDEFAULTS_FUNC(mod_indexfile_set_defaults) { 55 static const config_plugin_keys_t cpk[] = { 56 { CONST_STR_LEN("index-file.names"), 57 T_CONFIG_ARRAY_VLIST, 58 T_CONFIG_SCOPE_CONNECTION } 59 ,{ CONST_STR_LEN("server.indexfiles"), 60 T_CONFIG_ARRAY_VLIST, 61 T_CONFIG_SCOPE_CONNECTION } 62 ,{ NULL, 0, 63 T_CONFIG_UNSET, 64 T_CONFIG_SCOPE_UNSET } 65 }; 66 67 plugin_data * const p = p_d; 68 if (!config_plugin_values_init(srv, p, cpk, "mod_indexfile")) 69 return HANDLER_ERROR; 70 71 /* initialize p->defaults from global config context */ 72 if (p->nconfig > 0 && p->cvlist->v.u2[1]) { 73 const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0]; 74 if (-1 != cpv->k_id) 75 mod_indexfile_merge_config(&p->defaults, cpv); 76 } 77 78 return HANDLER_GO_ON; 79 } 80 81 __attribute_nonnull__() 82 static handler_t mod_indexfile_tryfiles(request_st * const r, const array * const indexfiles) { 83 for (uint32_t k = 0; k < indexfiles->used; ++k) { 84 const buffer * const v = &((data_string *)indexfiles->data[k])->value; 85 buffer * const b = (v->ptr[0] != '/') 86 ? &r->physical.path 87 : &r->physical.doc_root; /* index file relative to doc_root */ 88 /* if the index-file starts with a prefix as use this file as 89 * index-generator */ 90 91 /* temporarily append to base-path buffer to check existence */ 92 const uint32_t len = buffer_clen(b); 93 buffer_append_path_len(b, BUF_PTR_LEN(v)); 94 95 const stat_cache_st * const st = stat_cache_path_stat(b); 96 97 buffer_truncate(b, len); 98 99 if (NULL == st) { 100 switch (errno) { 101 case ENOENT: 102 case ENOTDIR: 103 continue; 104 case EACCES: 105 r->http_status = 403; 106 return HANDLER_FINISHED; 107 default: 108 /* we have no idea what happened. let's tell the user so. */ 109 r->http_status = 500; 110 log_perror(r->conf.errh, __FILE__, __LINE__, 111 "index file error for request: %s -> %s", 112 r->uri.path.ptr, r->physical.path.ptr); 113 return HANDLER_FINISHED; 114 } 115 } 116 117 /* found */ 118 if (v->ptr[0] == '/') { 119 /* replace uri.path */ 120 buffer_copy_buffer(&r->uri.path, v); 121 http_header_env_set(r, CONST_STR_LEN("PATH_TRANSLATED_DIRINDEX"), 122 BUF_PTR_LEN(&r->physical.path)); 123 buffer_copy_path_len2(&r->physical.path, 124 BUF_PTR_LEN(&r->physical.doc_root), 125 BUF_PTR_LEN(v)); 126 /*(XXX: not done historical, but rel_path probably should be updated)*/ 127 /*buffer_copy_buffer(&r->physical.rel_path, v);*/ 128 } else { 129 /* append to uri.path the relative path to index file (/ -> /index.php) */ 130 buffer_append_string_buffer(&r->uri.path, v); 131 buffer_append_path_len(&r->physical.path, BUF_PTR_LEN(v)); 132 /*(XXX: not done historical, but rel_path probably should be updated)*/ 133 /*buffer_append_path_len(&r->physical.rel_path, BUF_PTR_LEN(v));*/ 134 } 135 return HANDLER_GO_ON; 136 } 137 138 /* not found */ 139 return HANDLER_GO_ON; 140 } 141 142 URIHANDLER_FUNC(mod_indexfile_subrequest) { 143 if (NULL != r->handler_module) return HANDLER_GO_ON; 144 if (!buffer_has_slash_suffix(&r->uri.path)) return HANDLER_GO_ON; 145 146 plugin_data *p = p_d; 147 mod_indexfile_patch_config(r, p); 148 if (NULL == p->conf.indexfiles) return HANDLER_GO_ON; 149 150 if (r->conf.log_request_handling) { 151 log_error(r->conf.errh, __FILE__, __LINE__, 152 "-- handling the request as Indexfile"); 153 log_error(r->conf.errh, __FILE__, __LINE__, 154 "URI : %s", r->uri.path.ptr); 155 } 156 157 return mod_indexfile_tryfiles(r, p->conf.indexfiles); 158 } 159 160 161 int mod_indexfile_plugin_init(plugin *p); 162 int mod_indexfile_plugin_init(plugin *p) { 163 p->version = LIGHTTPD_VERSION_ID; 164 p->name = "indexfile"; 165 166 p->init = mod_indexfile_init; 167 p->handle_subrequest_start = mod_indexfile_subrequest; 168 p->set_defaults = mod_indexfile_set_defaults; 169 170 return 0; 171 } 172