6 #include "stat_cache.h"
14 buffer
*path_pieces_raw
;
16 /* pieces for path creation */
25 plugin_config
**config_storage
;
29 INIT_FUNC(mod_evhost_init
) {
32 p
= calloc(1, sizeof(*p
));
34 p
->tmp_buf
= buffer_init();
39 FREE_FUNC(mod_evhost_free
) {
44 if (!p
) return HANDLER_GO_ON
;
46 if (p
->config_storage
) {
48 for (i
= 0; i
< srv
->config_context
->used
; i
++) {
49 plugin_config
*s
= p
->config_storage
[i
];
51 if (NULL
== s
) continue;
55 for (j
= 0; j
< s
->len
; j
++) {
56 buffer_free(s
->path_pieces
[j
]);
62 buffer_free(s
->path_pieces_raw
);
66 free(p
->config_storage
);
69 buffer_free(p
->tmp_buf
);
76 static void mod_evhost_parse_pattern(plugin_config
*s
) {
77 char *ptr
= s
->path_pieces_raw
->ptr
,*pos
;
79 s
->path_pieces
= NULL
;
81 for(pos
=ptr
;*ptr
;ptr
++) {
83 s
->path_pieces
= realloc(s
->path_pieces
,(s
->len
+2) * sizeof(*s
->path_pieces
));
84 s
->path_pieces
[s
->len
] = buffer_init();
85 s
->path_pieces
[s
->len
+1] = buffer_init();
87 buffer_copy_string_len(s
->path_pieces
[s
->len
],pos
,ptr
-pos
);
90 buffer_copy_string_len(s
->path_pieces
[s
->len
+1],ptr
++,2);
97 s
->path_pieces
= realloc(s
->path_pieces
,(s
->len
+1) * sizeof(*s
->path_pieces
));
98 s
->path_pieces
[s
->len
] = buffer_init();
100 buffer_copy_string_len(s
->path_pieces
[s
->len
],pos
,ptr
-pos
);
106 SETDEFAULTS_FUNC(mod_evhost_set_defaults
) {
107 plugin_data
*p
= p_d
;
113 * # define a pattern for the host url finding
115 * # %0 => domain name + tld
117 * # %2 => domain name without tld
118 * # %3 => subdomain 1 name
119 * # %4 => subdomain 2 name
120 * # %_ => fqdn (without port info)
122 * evhost.path-pattern = "/home/ckruse/dev/www/%3/htdocs/"
126 config_values_t cv
[] = {
127 { "evhost.path-pattern", NULL
, T_CONFIG_STRING
, T_CONFIG_SCOPE_CONNECTION
},
128 { NULL
, NULL
, T_CONFIG_UNSET
, T_CONFIG_SCOPE_UNSET
}
131 if (!p
) return HANDLER_ERROR
;
133 p
->config_storage
= calloc(1, srv
->config_context
->used
* sizeof(plugin_config
*));
135 for (i
= 0; i
< srv
->config_context
->used
; i
++) {
136 data_config
const* config
= (data_config
const*)srv
->config_context
->data
[i
];
139 s
= calloc(1, sizeof(plugin_config
));
140 s
->path_pieces_raw
= buffer_init();
141 s
->path_pieces
= NULL
;
144 cv
[0].destination
= s
->path_pieces_raw
;
146 p
->config_storage
[i
] = s
;
148 if (0 != config_insert_values_global(srv
, config
->value
, cv
, i
== 0 ? T_CONFIG_SCOPE_SERVER
: T_CONFIG_SCOPE_CONNECTION
)) {
149 return HANDLER_ERROR
;
152 if (!buffer_string_is_empty(s
->path_pieces_raw
)) {
153 mod_evhost_parse_pattern(s
);
157 return HANDLER_GO_ON
;
161 * assign the different parts of the domain to array-indezes (sub2.sub1.domain.tld)
169 static int mod_evhost_parse_host(connection
*con
,array
*host
) {
170 register char *ptr
= con
->uri
.authority
->ptr
+ buffer_string_length(con
->uri
.authority
);
171 char *colon
= ptr
; /* needed to filter out the colon (if exists) */
176 /* first, find the domain + tld */
177 for(;ptr
> con
->uri
.authority
->ptr
;ptr
--) {
181 } else if(*ptr
== ':') {
187 ds
= data_string_init();
188 buffer_copy_string_len(ds
->key
,CONST_STR_LEN("%0"));
190 /* if we stopped at a dot, skip the dot */
191 if (*ptr
== '.') ptr
++;
192 buffer_copy_string_len(ds
->value
, ptr
, colon
-ptr
);
194 array_insert_unique(host
,(data_unset
*)ds
);
196 /* if the : is not the start of the authority, go on parsing the hostname */
198 if (colon
!= con
->uri
.authority
->ptr
) {
199 for(ptr
= colon
- 1, i
= 1; ptr
> con
->uri
.authority
->ptr
; ptr
--) {
201 if (ptr
!= colon
- 1) {
202 /* is something between the dots */
203 ds
= data_string_init();
204 buffer_copy_string_len(ds
->key
,CONST_STR_LEN("%"));
205 buffer_append_int(ds
->key
, i
++);
206 buffer_copy_string_len(ds
->value
,ptr
+1,colon
-ptr
-1);
208 array_insert_unique(host
,(data_unset
*)ds
);
214 /* if the . is not the first charactor of the hostname */
216 ds
= data_string_init();
217 buffer_copy_string_len(ds
->key
,CONST_STR_LEN("%"));
218 buffer_append_int(ds
->key
, i
/* ++ */);
219 buffer_copy_string_len(ds
->value
,ptr
,colon
-ptr
);
221 array_insert_unique(host
,(data_unset
*)ds
);
230 static int mod_evhost_patch_connection(server
*srv
, connection
*con
, plugin_data
*p
) {
232 plugin_config
*s
= p
->config_storage
[0];
237 /* skip the first, the global context */
238 for (i
= 1; i
< srv
->config_context
->used
; i
++) {
239 data_config
*dc
= (data_config
*)srv
->config_context
->data
[i
];
240 s
= p
->config_storage
[i
];
242 /* condition didn't match */
243 if (!config_check_cond(srv
, con
, dc
)) continue;
246 for (j
= 0; j
< dc
->value
->used
; j
++) {
247 data_unset
*du
= dc
->value
->data
[j
];
249 if (buffer_is_equal_string(du
->key
, CONST_STR_LEN("evhost.path-pattern"))) {
261 static handler_t
mod_evhost_uri_handler(server
*srv
, connection
*con
, void *p_d
) {
262 plugin_data
*p
= p_d
;
267 stat_cache_entry
*sce
= NULL
;
269 /* not authority set */
270 if (buffer_string_is_empty(con
->uri
.authority
)) return HANDLER_GO_ON
;
272 mod_evhost_patch_connection(srv
, con
, p
);
274 /* missing even default(global) conf */
275 if (0 == p
->conf
.len
) {
276 return HANDLER_GO_ON
;
279 parsed_host
= array_init();
281 mod_evhost_parse_host(con
, parsed_host
);
283 /* build document-root */
284 buffer_reset(p
->tmp_buf
);
286 for (i
= 0; i
< p
->conf
.len
; i
++) {
287 ptr
= p
->conf
.path_pieces
[i
]->ptr
;
291 if (*(ptr
+1) == '%') {
293 buffer_append_string_len(p
->tmp_buf
,CONST_STR_LEN("%"));
294 } else if (*(ptr
+1) == '_' ) {
295 /* %_ == full hostname */
296 char *colon
= strchr(con
->uri
.authority
->ptr
, ':');
299 buffer_append_string_buffer(p
->tmp_buf
, con
->uri
.authority
); /* adds fqdn */
301 /* strip the port out of the authority-part of the URI scheme */
302 buffer_append_string_len(p
->tmp_buf
, con
->uri
.authority
->ptr
, colon
- con
->uri
.authority
->ptr
); /* adds fqdn */
304 } else if (NULL
!= (ds
= (data_string
*)array_get_element(parsed_host
,p
->conf
.path_pieces
[i
]->ptr
))) {
305 buffer_append_string_buffer(p
->tmp_buf
,ds
->value
);
307 /* unhandled %-sequence */
310 buffer_append_string_buffer(p
->tmp_buf
,p
->conf
.path_pieces
[i
]);
314 buffer_append_slash(p
->tmp_buf
);
316 array_free(parsed_host
);
318 if (HANDLER_ERROR
== stat_cache_get_entry(srv
, con
, p
->tmp_buf
, &sce
)) {
319 log_error_write(srv
, __FILE__
, __LINE__
, "sb", strerror(errno
), p
->tmp_buf
);
321 } else if(!S_ISDIR(sce
->st
.st_mode
)) {
322 log_error_write(srv
, __FILE__
, __LINE__
, "sb", "not a directory:", p
->tmp_buf
);
327 buffer_copy_buffer(con
->physical
.doc_root
, p
->tmp_buf
);
330 return HANDLER_GO_ON
;
333 int mod_evhost_plugin_init(plugin
*p
);
334 int mod_evhost_plugin_init(plugin
*p
) {
335 p
->version
= LIGHTTPD_VERSION_ID
;
336 p
->name
= buffer_init_string("evhost");
337 p
->init
= mod_evhost_init
;
338 p
->set_defaults
= mod_evhost_set_defaults
;
339 p
->handle_docroot
= mod_evhost_uri_handler
;
340 p
->cleanup
= mod_evhost_free
;