/* Copyright 2005 Garrett Rooney. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include "etl_template.h" #include "etl_variables.h" static int load_env(void *rec, const char *key, const char *value) { etl_variable_t *env = (etl_variable_t *) rec; etl_variable_hash_set(env, key, etl_variable_make_str(value)); return 1; } static etl_error_t * brigade_write_func(void *baton, const char *data, size_t *len) { apr_bucket_brigade *bb = baton; apr_status_t apr_err = apr_brigade_write(bb, NULL, NULL, data, *len); if (apr_err) { /* XXX log error? */ return etl_error_create(ETL_EIO, "Error writing to brigade"); } return ETL_SUCCESS; } static void brigade_destroy_func(void *baton) { apr_brigade_destroy(baton); } static apr_status_t bb_output_stream_cleanup(void *baton) { etl_stream_destroy(baton); return APR_SUCCESS; } static etl_stream_t * bb_output_stream_create(apr_pool_t *pool, apr_bucket_alloc_t *bucket_alloc) { apr_bucket_brigade *bb = apr_brigade_create(pool, bucket_alloc); etl_stream_t *str = etl_stream_create(NULL /* read func */, brigade_write_func, brigade_destroy_func, bb); apr_pool_cleanup_register(pool, str, bb_output_stream_cleanup, NULL); return str; } static apr_bucket_brigade * bb_output_stream_get_brigade(etl_stream_t *stream) { return etl_stream_baton(stream); } static apr_status_t template_cleanup(void *baton) { etl_template_t *tmpl = baton; etl_template_destroy(tmpl); return APR_SUCCESS; } static void variable_destroy(void *elt, void *baton) { etl_variable_destroy(elt); } static apr_status_t environment_cleanup(void *baton) { etl_hash_t *environment = baton; etl_hash_destroy(environment, variable_destroy, NULL); return APR_SUCCESS; } static apr_status_t resolver_cleanup(void *baton) { etl_resolver_destroy(baton); return APR_SUCCESS; } static int template_example_file_handler(request_rec *r) { apr_status_t apr_err; apr_finfo_t finfo; etl_error_t *err; /* first, make sure that we're supposed to handle this, and that we were * asked for a template that's actually there. */ if (! r->handler || strcmp(r->handler, "template-example") != 0) return DECLINED; r->allowed |= (AP_METHOD_BIT << M_GET); if (r->method_number != M_GET) return HTTP_METHOD_NOT_ALLOWED; apr_err = apr_stat(&finfo, r->filename, APR_FINFO_TYPE, r->pool); if (apr_err) return HTTP_NOT_FOUND; /* ok, now that we're sure we should be handling this, lets do it. */ { etl_resolver_t *resolver; etl_hash_t *environment; etl_template_t *tmpl; etl_stream_t *out; /* first parse the template into its compiled form... */ err = etl_template_parse_file(&tmpl, r->filename); if (err) { ap_log_rerror(APLOG_MARK, APLOG_ERR, err->err, r, "error opening template file '%s' : %s", r->filename, err->msg); etl_error_clear(err); return HTTP_NOT_FOUND; } apr_pool_cleanup_register(r->pool, tmpl, template_cleanup, NULL); ap_set_content_type(r, "text/html"); /* create ourselves an environment full of variables for the templates * to play with. */ environment = etl_hash_create(); apr_pool_cleanup_register(r->pool, environment, environment_cleanup, NULL); /* Set up the usual CGI env variables. */ ap_add_common_vars(r); ap_add_cgi_vars(r); { etl_variable_t *env = etl_variable_make_hash(); apr_table_do(load_env, env, r->subprocess_env, NULL); etl_hash_set(environment, "env", env); } out = bb_output_stream_create(r->pool, r->connection->bucket_alloc); /* build a dummy resolver, real users would need to add the path * to a directory to search for files to include. */ resolver = etl_resolver_file_create(etl_array_create(0)); apr_pool_cleanup_register(r->pool, resolver, resolver_cleanup, NULL); /* now execute it, catching the output in a bucket brigade. */ err = etl_template_execute(tmpl, resolver, environment, out); if (err) { ap_log_rerror(APLOG_MARK, APLOG_ERR, err->err, r, "error executing template file '%s' : %s", r->filename, err->msg); etl_error_clear(err); return HTTP_INTERNAL_SERVER_ERROR; } /* hand it off to the rest of the output chain. */ ap_pass_brigade(r->output_filters, bb_output_stream_get_brigade(out)); } return OK; } static void template_example_register_hooks(apr_pool_t *pool) { ap_hook_handler(template_example_file_handler, NULL, NULL, APR_HOOK_MIDDLE); } module AP_MODULE_DECLARE_DATA template_example_module = { STANDARD20_MODULE_STUFF, NULL, NULL, NULL, NULL, NULL, template_example_register_hooks };