xref: /lighttpd1.4/src/mod_indexfile.c (revision 5e14db43)
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 
INIT_FUNC(mod_indexfile_init)24 INIT_FUNC(mod_indexfile_init) {
25     return ck_calloc(1, sizeof(plugin_data));
26 }
27 
mod_indexfile_merge_config_cpv(plugin_config * const pconf,const config_plugin_value_t * const cpv)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 
mod_indexfile_merge_config(plugin_config * const pconf,const config_plugin_value_t * cpv)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 
mod_indexfile_patch_config(request_st * const r,plugin_data * const p)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 
SETDEFAULTS_FUNC(mod_indexfile_set_defaults)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 
__attribute_nonnull__()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 
URIHANDLER_FUNC(mod_indexfile_subrequest)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 __attribute_cold__
162 int mod_indexfile_plugin_init(plugin *p);
mod_indexfile_plugin_init(plugin * p)163 int mod_indexfile_plugin_init(plugin *p) {
164 	p->version     = LIGHTTPD_VERSION_ID;
165 	p->name        = "indexfile";
166 
167 	p->init        = mod_indexfile_init;
168 	p->handle_subrequest_start = mod_indexfile_subrequest;
169 	p->set_defaults  = mod_indexfile_set_defaults;
170 
171 	return 0;
172 }
173