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