1*76404edcSAsim Jamshed #include "base.h"
2*76404edcSAsim Jamshed #include "log.h"
3*76404edcSAsim Jamshed #include "buffer.h"
4*76404edcSAsim Jamshed 
5*76404edcSAsim Jamshed #include "plugin.h"
6*76404edcSAsim Jamshed 
7*76404edcSAsim Jamshed #include <ctype.h>
8*76404edcSAsim Jamshed #include <stdlib.h>
9*76404edcSAsim Jamshed #include <string.h>
10*76404edcSAsim Jamshed #include <stdio.h>
11*76404edcSAsim Jamshed 
12*76404edcSAsim Jamshed /* plugin config for all request/connections */
13*76404edcSAsim Jamshed typedef struct {
14*76404edcSAsim Jamshed 	array *alias;
15*76404edcSAsim Jamshed } plugin_config;
16*76404edcSAsim Jamshed 
17*76404edcSAsim Jamshed typedef struct {
18*76404edcSAsim Jamshed 	PLUGIN_DATA;
19*76404edcSAsim Jamshed 
20*76404edcSAsim Jamshed 	plugin_config **config_storage;
21*76404edcSAsim Jamshed 
22*76404edcSAsim Jamshed 	plugin_config conf;
23*76404edcSAsim Jamshed } plugin_data;
24*76404edcSAsim Jamshed 
25*76404edcSAsim Jamshed /* init the plugin data */
INIT_FUNC(mod_alias_init)26*76404edcSAsim Jamshed INIT_FUNC(mod_alias_init) {
27*76404edcSAsim Jamshed 	plugin_data *p;
28*76404edcSAsim Jamshed 
29*76404edcSAsim Jamshed 	p = calloc(1, sizeof(*p));
30*76404edcSAsim Jamshed 
31*76404edcSAsim Jamshed 
32*76404edcSAsim Jamshed 
33*76404edcSAsim Jamshed 	return p;
34*76404edcSAsim Jamshed }
35*76404edcSAsim Jamshed 
36*76404edcSAsim Jamshed /* detroy the plugin data */
FREE_FUNC(mod_alias_free)37*76404edcSAsim Jamshed FREE_FUNC(mod_alias_free) {
38*76404edcSAsim Jamshed 	plugin_data *p = p_d;
39*76404edcSAsim Jamshed 
40*76404edcSAsim Jamshed 	if (!p) return HANDLER_GO_ON;
41*76404edcSAsim Jamshed 
42*76404edcSAsim Jamshed 	if (p->config_storage) {
43*76404edcSAsim Jamshed 		size_t i;
44*76404edcSAsim Jamshed 
45*76404edcSAsim Jamshed 		for (i = 0; i < srv->config_context->used; i++) {
46*76404edcSAsim Jamshed 			plugin_config *s = p->config_storage[i];
47*76404edcSAsim Jamshed 
48*76404edcSAsim Jamshed 			if(!s) continue;
49*76404edcSAsim Jamshed 
50*76404edcSAsim Jamshed 			array_free(s->alias);
51*76404edcSAsim Jamshed 
52*76404edcSAsim Jamshed 			free(s);
53*76404edcSAsim Jamshed 		}
54*76404edcSAsim Jamshed 		free(p->config_storage);
55*76404edcSAsim Jamshed 	}
56*76404edcSAsim Jamshed 
57*76404edcSAsim Jamshed 	free(p);
58*76404edcSAsim Jamshed 
59*76404edcSAsim Jamshed 	return HANDLER_GO_ON;
60*76404edcSAsim Jamshed }
61*76404edcSAsim Jamshed 
62*76404edcSAsim Jamshed /* handle plugin config and check values */
63*76404edcSAsim Jamshed 
SETDEFAULTS_FUNC(mod_alias_set_defaults)64*76404edcSAsim Jamshed SETDEFAULTS_FUNC(mod_alias_set_defaults) {
65*76404edcSAsim Jamshed 	plugin_data *p = p_d;
66*76404edcSAsim Jamshed 	size_t i = 0;
67*76404edcSAsim Jamshed 
68*76404edcSAsim Jamshed 	config_values_t cv[] = {
69*76404edcSAsim Jamshed 		{ "alias.url",                  NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
70*76404edcSAsim Jamshed 		{ NULL,                         NULL, T_CONFIG_UNSET,  T_CONFIG_SCOPE_UNSET }
71*76404edcSAsim Jamshed 	};
72*76404edcSAsim Jamshed 
73*76404edcSAsim Jamshed 	if (!p) return HANDLER_ERROR;
74*76404edcSAsim Jamshed 
75*76404edcSAsim Jamshed 	p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
76*76404edcSAsim Jamshed 
77*76404edcSAsim Jamshed 	for (i = 0; i < srv->config_context->used; i++) {
78*76404edcSAsim Jamshed 		plugin_config *s;
79*76404edcSAsim Jamshed 
80*76404edcSAsim Jamshed 		s = calloc(1, sizeof(plugin_config));
81*76404edcSAsim Jamshed 		s->alias = array_init();
82*76404edcSAsim Jamshed 		cv[0].destination = s->alias;
83*76404edcSAsim Jamshed 
84*76404edcSAsim Jamshed 		p->config_storage[i] = s;
85*76404edcSAsim Jamshed 
86*76404edcSAsim Jamshed 		if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
87*76404edcSAsim Jamshed 			return HANDLER_ERROR;
88*76404edcSAsim Jamshed 		}
89*76404edcSAsim Jamshed 		if (s->alias->used >= 2) {
90*76404edcSAsim Jamshed 			const array *a = s->alias;
91*76404edcSAsim Jamshed 			size_t j, k;
92*76404edcSAsim Jamshed 
93*76404edcSAsim Jamshed 			for (j = 0; j < a->used; j ++) {
94*76404edcSAsim Jamshed 				const buffer *prefix = a->data[a->sorted[j]]->key;
95*76404edcSAsim Jamshed 				for (k = j + 1; k < a->used; k ++) {
96*76404edcSAsim Jamshed 					const buffer *key = a->data[a->sorted[k]]->key;
97*76404edcSAsim Jamshed 
98*76404edcSAsim Jamshed 					if (key->used < prefix->used) {
99*76404edcSAsim Jamshed 						break;
100*76404edcSAsim Jamshed 					}
101*76404edcSAsim Jamshed 					if (memcmp(key->ptr, prefix->ptr, prefix->used - 1) != 0) {
102*76404edcSAsim Jamshed 						break;
103*76404edcSAsim Jamshed 					}
104*76404edcSAsim Jamshed 					/* ok, they have same prefix. check position */
105*76404edcSAsim Jamshed 					if (a->sorted[j] < a->sorted[k]) {
106*76404edcSAsim Jamshed 						log_error_write(srv, __FILE__, __LINE__, "SBSBS",
107*76404edcSAsim Jamshed 							"url.alias: `", key, "' will never match as `", prefix, "' matched first");
108*76404edcSAsim Jamshed 						return HANDLER_ERROR;
109*76404edcSAsim Jamshed 					}
110*76404edcSAsim Jamshed 				}
111*76404edcSAsim Jamshed 			}
112*76404edcSAsim Jamshed 		}
113*76404edcSAsim Jamshed 	}
114*76404edcSAsim Jamshed 
115*76404edcSAsim Jamshed 	return HANDLER_GO_ON;
116*76404edcSAsim Jamshed }
117*76404edcSAsim Jamshed 
118*76404edcSAsim Jamshed #define PATCH(x) \
119*76404edcSAsim Jamshed 	p->conf.x = s->x;
mod_alias_patch_connection(server * srv,connection * con,plugin_data * p)120*76404edcSAsim Jamshed static int mod_alias_patch_connection(server *srv, connection *con, plugin_data *p) {
121*76404edcSAsim Jamshed 	size_t i, j;
122*76404edcSAsim Jamshed 	plugin_config *s = p->config_storage[0];
123*76404edcSAsim Jamshed 
124*76404edcSAsim Jamshed 	PATCH(alias);
125*76404edcSAsim Jamshed 
126*76404edcSAsim Jamshed 	/* skip the first, the global context */
127*76404edcSAsim Jamshed 	for (i = 1; i < srv->config_context->used; i++) {
128*76404edcSAsim Jamshed 		data_config *dc = (data_config *)srv->config_context->data[i];
129*76404edcSAsim Jamshed 		s = p->config_storage[i];
130*76404edcSAsim Jamshed 
131*76404edcSAsim Jamshed 		/* condition didn't match */
132*76404edcSAsim Jamshed 		if (!config_check_cond(srv, con, dc)) continue;
133*76404edcSAsim Jamshed 
134*76404edcSAsim Jamshed 		/* merge config */
135*76404edcSAsim Jamshed 		for (j = 0; j < dc->value->used; j++) {
136*76404edcSAsim Jamshed 			data_unset *du = dc->value->data[j];
137*76404edcSAsim Jamshed 
138*76404edcSAsim Jamshed 			if (buffer_is_equal_string(du->key, CONST_STR_LEN("alias.url"))) {
139*76404edcSAsim Jamshed 				PATCH(alias);
140*76404edcSAsim Jamshed 			}
141*76404edcSAsim Jamshed 		}
142*76404edcSAsim Jamshed 	}
143*76404edcSAsim Jamshed 
144*76404edcSAsim Jamshed 	return 0;
145*76404edcSAsim Jamshed }
146*76404edcSAsim Jamshed #undef PATCH
147*76404edcSAsim Jamshed 
PHYSICALPATH_FUNC(mod_alias_physical_handler)148*76404edcSAsim Jamshed PHYSICALPATH_FUNC(mod_alias_physical_handler) {
149*76404edcSAsim Jamshed 	plugin_data *p = p_d;
150*76404edcSAsim Jamshed 	int uri_len, basedir_len;
151*76404edcSAsim Jamshed 	char *uri_ptr;
152*76404edcSAsim Jamshed 	size_t k;
153*76404edcSAsim Jamshed 
154*76404edcSAsim Jamshed 	if (con->physical.path->used == 0) return HANDLER_GO_ON;
155*76404edcSAsim Jamshed 
156*76404edcSAsim Jamshed 	mod_alias_patch_connection(srv, con, p);
157*76404edcSAsim Jamshed 
158*76404edcSAsim Jamshed 	/* not to include the tailing slash */
159*76404edcSAsim Jamshed 	basedir_len = (con->physical.basedir->used - 1) - 1;
160*76404edcSAsim Jamshed 	uri_len = con->physical.path->used - 1 - basedir_len;
161*76404edcSAsim Jamshed 	uri_ptr = con->physical.path->ptr + basedir_len;
162*76404edcSAsim Jamshed 
163*76404edcSAsim Jamshed 	for (k = 0; k < p->conf.alias->used; k++) {
164*76404edcSAsim Jamshed 		data_string *ds = (data_string *)p->conf.alias->data[k];
165*76404edcSAsim Jamshed 		int alias_len = ds->key->used - 1;
166*76404edcSAsim Jamshed 
167*76404edcSAsim Jamshed 		if (alias_len > uri_len) continue;
168*76404edcSAsim Jamshed 		if (ds->key->used == 0) continue;
169*76404edcSAsim Jamshed 
170*76404edcSAsim Jamshed 		if (0 == (con->conf.force_lowercase_filenames ?
171*76404edcSAsim Jamshed 					strncasecmp(uri_ptr, ds->key->ptr, alias_len) :
172*76404edcSAsim Jamshed 					strncmp(uri_ptr, ds->key->ptr, alias_len))) {
173*76404edcSAsim Jamshed 			/* matched */
174*76404edcSAsim Jamshed 
175*76404edcSAsim Jamshed 			buffer_copy_string_buffer(con->physical.basedir, ds->value);
176*76404edcSAsim Jamshed 			buffer_copy_string_buffer(srv->tmp_buf, ds->value);
177*76404edcSAsim Jamshed 			buffer_append_string(srv->tmp_buf, uri_ptr + alias_len);
178*76404edcSAsim Jamshed 			buffer_copy_string_buffer(con->physical.path, srv->tmp_buf);
179*76404edcSAsim Jamshed 
180*76404edcSAsim Jamshed 			return HANDLER_GO_ON;
181*76404edcSAsim Jamshed 		}
182*76404edcSAsim Jamshed 	}
183*76404edcSAsim Jamshed 
184*76404edcSAsim Jamshed 	/* not found */
185*76404edcSAsim Jamshed 	return HANDLER_GO_ON;
186*76404edcSAsim Jamshed }
187*76404edcSAsim Jamshed 
188*76404edcSAsim Jamshed /* this function is called at dlopen() time and inits the callbacks */
189*76404edcSAsim Jamshed 
190*76404edcSAsim Jamshed int mod_alias_plugin_init(plugin *p);
mod_alias_plugin_init(plugin * p)191*76404edcSAsim Jamshed int mod_alias_plugin_init(plugin *p) {
192*76404edcSAsim Jamshed 	p->version     = LIGHTTPD_VERSION_ID;
193*76404edcSAsim Jamshed 	p->name        = buffer_init_string("alias");
194*76404edcSAsim Jamshed 
195*76404edcSAsim Jamshed 	p->init           = mod_alias_init;
196*76404edcSAsim Jamshed 	p->handle_physical= mod_alias_physical_handler;
197*76404edcSAsim Jamshed 	p->set_defaults   = mod_alias_set_defaults;
198*76404edcSAsim Jamshed 	p->cleanup        = mod_alias_free;
199*76404edcSAsim Jamshed 
200*76404edcSAsim Jamshed 	p->data        = NULL;
201*76404edcSAsim Jamshed 
202*76404edcSAsim Jamshed 	return 0;
203*76404edcSAsim Jamshed }
204