xref: /lighttpd1.4/src/mod_indexfile.c (revision 3392e8fb)
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 	if (!buffer_has_slash_suffix(&r->uri.path)) return HANDLER_GO_ON;
91 
92 	mod_indexfile_patch_config(r, p);
93 	if (NULL == p->conf.indexfiles) return HANDLER_GO_ON;
94 
95 	if (r->conf.log_request_handling) {
96 		log_error(r->conf.errh, __FILE__, __LINE__, "-- handling the request as Indexfile");
97 		log_error(r->conf.errh, __FILE__, __LINE__, "URI          : %s", r->uri.path.ptr);
98 	}
99 
100 	for (uint32_t k = 0; k < p->conf.indexfiles->used; ++k) {
101 		const data_string * const ds = (data_string *)p->conf.indexfiles->data[k];
102 		buffer * const b = (ds->value.ptr[0] != '/')
103 		  ? &r->physical.path
104 		  : &r->physical.doc_root; /* index file relative to doc_root */
105 			/* if the index-file starts with a prefix as use this file as
106 			 * index-generator */
107 
108 		/* temporarily append to base-path buffer to check existence */
109 		const uint32_t len = buffer_string_length(b);
110 		buffer_append_path_len(b, CONST_BUF_LEN(&ds->value));
111 
112 		const stat_cache_st * const st = stat_cache_path_stat(b);
113 
114 		buffer_string_set_length(b, len);
115 
116 		if (NULL == st) {
117 			switch (errno) {
118 			case ENOENT:
119 			case ENOTDIR:
120 				continue;
121 			case EACCES:
122 				r->http_status = 403;
123 				return HANDLER_FINISHED;
124 			default:
125 				/* we have no idea what happened. let's tell the user so. */
126 				r->http_status = 500;
127 				log_perror(r->conf.errh, __FILE__, __LINE__,
128 				  "index file error for request: %s -> %s",
129 				  r->uri.path.ptr, r->physical.path.ptr);
130 				return HANDLER_FINISHED;
131 			}
132 		}
133 
134 		/* found */
135 		if (ds->value.ptr[0] == '/') {
136 			/* replace uri.path */
137 			buffer_copy_buffer(&r->uri.path, &ds->value);
138 			http_header_env_set(r, CONST_STR_LEN("PATH_TRANSLATED_DIRINDEX"), CONST_BUF_LEN(&r->physical.path));
139 			buffer_copy_buffer(&r->physical.path, &r->physical.doc_root);
140 		} else {
141 			/* append to uri.path the relative path to index file (/ -> /index.php) */
142 			buffer_append_string_buffer(&r->uri.path, &ds->value);
143 		}
144 		buffer_append_string_buffer(&r->physical.path, &ds->value);
145 		return HANDLER_GO_ON;
146 	}
147 
148 	/* not found */
149 	return HANDLER_GO_ON;
150 }
151 
152 
153 int mod_indexfile_plugin_init(plugin *p);
154 int mod_indexfile_plugin_init(plugin *p) {
155 	p->version     = LIGHTTPD_VERSION_ID;
156 	p->name        = "indexfile";
157 
158 	p->init        = mod_indexfile_init;
159 	p->handle_subrequest_start = mod_indexfile_subrequest;
160 	p->set_defaults  = mod_indexfile_set_defaults;
161 
162 	return 0;
163 }
164