| /* Licensed to the Apache Software Foundation (ASF) under one or more | |
| * contributor license agreements. See the NOTICE file distributed with | |
| * this work for additional information regarding copyright ownership. | |
| * The ASF licenses this file to You 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 "mod_proxy.h" | |
| #include "apr_dbm.h" | |
| module AP_MODULE_DECLARE_DATA proxy_express_module; | |
| #include "apr_version.h" | |
| #if !APR_VERSION_AT_LEAST(2,0,0) | |
| #include "apu_version.h" | |
| #endif | |
| static int proxy_available = 0; | |
| typedef struct { | |
| const char *dbmfile; | |
| const char *dbmtype; | |
| int enabled; | |
| } express_server_conf; | |
| static const char *set_dbmfile(cmd_parms *cmd, | |
| void *dconf, | |
| const char *arg) | |
| { | |
| express_server_conf *sconf; | |
| sconf = ap_get_module_config(cmd->server->module_config, &proxy_express_module); | |
| if ((sconf->dbmfile = ap_server_root_relative(cmd->pool, arg)) == NULL) { | |
| return apr_pstrcat(cmd->pool, "ProxyExpressDBMFile: bad path to file: ", | |
| arg, NULL); | |
| } | |
| return NULL; | |
| } | |
| static const char *set_dbmtype(cmd_parms *cmd, | |
| void *dconf, | |
| const char *arg) | |
| { | |
| express_server_conf *sconf; | |
| sconf = ap_get_module_config(cmd->server->module_config, &proxy_express_module); | |
| sconf->dbmtype = arg; | |
| return NULL; | |
| } | |
| static const char *set_enabled(cmd_parms *cmd, | |
| void *dconf, | |
| int flag) | |
| { | |
| express_server_conf *sconf; | |
| sconf = ap_get_module_config(cmd->server->module_config, &proxy_express_module); | |
| sconf->enabled = flag; | |
| return NULL; | |
| } | |
| static void *server_create(apr_pool_t *p, server_rec *s) | |
| { | |
| express_server_conf *a; | |
| a = (express_server_conf *)apr_pcalloc(p, sizeof(express_server_conf)); | |
| a->dbmfile = NULL; | |
| a->dbmtype = "default"; | |
| a->enabled = 0; | |
| return (void *)a; | |
| } | |
| static void *server_merge(apr_pool_t *p, void *basev, void *overridesv) | |
| { | |
| express_server_conf *a, *base, *overrides; | |
| a = (express_server_conf *)apr_pcalloc(p, | |
| sizeof(express_server_conf)); | |
| base = (express_server_conf *)basev; | |
| overrides = (express_server_conf *)overridesv; | |
| a->dbmfile = (overrides->dbmfile) ? overrides->dbmfile : base->dbmfile; | |
| a->dbmtype = (overrides->dbmtype) ? overrides->dbmtype : base->dbmtype; | |
| a->enabled = (overrides->enabled) ? overrides->enabled : base->enabled; | |
| return (void *)a; | |
| } | |
| static int post_config(apr_pool_t *p, | |
| apr_pool_t *plog, | |
| apr_pool_t *ptemp, | |
| server_rec *s) | |
| { | |
| proxy_available = (ap_find_linked_module("mod_proxy.c") != NULL); | |
| return OK; | |
| } | |
| static int xlate_name(request_rec *r) | |
| { | |
| int i; | |
| const char *name; | |
| char *backend = NULL; | |
| apr_dbm_t *db; | |
| apr_status_t rv; | |
| apr_datum_t key, val; | |
| struct proxy_alias *ralias; | |
| proxy_dir_conf *dconf; | |
| express_server_conf *sconf; | |
| #if APU_MAJOR_VERSION > 1 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 7) | |
| const apr_dbm_driver_t *driver; | |
| const apu_err_t *err; | |
| #endif | |
| sconf = ap_get_module_config(r->server->module_config, &proxy_express_module); | |
| dconf = ap_get_module_config(r->per_dir_config, &proxy_module); | |
| if (!sconf->enabled) { | |
| return DECLINED; | |
| } | |
| ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01001) "proxy_express: Enabled"); | |
| if (!sconf->dbmfile || (r->filename && strncmp(r->filename, "proxy:", 6) == 0)) { | |
| /* it should be go on as an internal proxy request */ | |
| return DECLINED; | |
| } | |
| ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01002) | |
| "proxy_express: Opening DBM file: %s (%s)", | |
| sconf->dbmfile, sconf->dbmtype); | |
| #if APU_MAJOR_VERSION > 1 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 7) | |
| rv = apr_dbm_get_driver(&driver, sconf->dbmtype, &err, r->pool); | |
| if (rv != APR_SUCCESS) { | |
| ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, | |
| APLOGNO(10275) "The dbm library '%s' could not be loaded: %s (%s: %d)", | |
| sconf->dbmtype, err->msg, err->reason, err->rc); | |
| return DECLINED; | |
| } | |
| rv = apr_dbm_open2(&db, driver, sconf->dbmfile, APR_DBM_READONLY, | |
| APR_OS_DEFAULT, r->pool); | |
| if (rv != APR_SUCCESS) { | |
| ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, | |
| APLOGNO(10276) "The '%s' file '%s' could not be loaded", | |
| sconf->dbmtype, sconf->dbmfile); | |
| return DECLINED; | |
| } | |
| #else | |
| rv = apr_dbm_open_ex(&db, sconf->dbmtype, sconf->dbmfile, APR_DBM_READONLY, | |
| APR_OS_DEFAULT, r->pool); | |
| if (rv != APR_SUCCESS) { | |
| return DECLINED; | |
| } | |
| #endif | |
| name = ap_get_server_name(r); | |
| ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01003) | |
| "proxy_express: looking for %s", name); | |
| key.dptr = (char *)name; | |
| key.dsize = strlen(key.dptr); | |
| rv = apr_dbm_fetch(db, key, &val); | |
| if (rv == APR_SUCCESS) { | |
| backend = apr_pstrmemdup(r->pool, val.dptr, val.dsize); | |
| } | |
| apr_dbm_close(db); | |
| if (rv != APR_SUCCESS || !backend) { | |
| return DECLINED; | |
| } | |
| ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01004) | |
| "proxy_express: found %s -> %s", name, backend); | |
| r->filename = apr_pstrcat(r->pool, "proxy:", backend, r->uri, NULL); | |
| r->handler = "proxy-server"; | |
| r->proxyreq = PROXYREQ_REVERSE; | |
| ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01005) | |
| "proxy_express: rewritten as: %s", r->filename); | |
| ralias = (struct proxy_alias *)dconf->raliases->elts; | |
| /* | |
| * See if we have already added a ProxyPassReverse entry | |
| * for this host... If so, don't do it again. | |
| */ | |
| /* | |
| * NOTE: dconf is process specific so this will only | |
| * work as long as we maintain that this process | |
| * or thread is handling the backend | |
| */ | |
| for (i = 0; i < dconf->raliases->nelts; i++, ralias++) { | |
| if (strcasecmp(backend, ralias->real) == 0) { | |
| ralias = NULL; | |
| break; | |
| } | |
| } | |
| /* Didn't find one... add it */ | |
| if (!ralias) { | |
| ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01006) | |
| "proxy_express: adding PPR entry"); | |
| ralias = apr_array_push(dconf->raliases); | |
| ralias->fake = "/"; | |
| ralias->real = apr_pstrdup(dconf->raliases->pool, backend); | |
| ralias->flags = 0; | |
| } | |
| return OK; | |
| } | |
| static const command_rec command_table[] = { | |
| AP_INIT_FLAG("ProxyExpressEnable", set_enabled, NULL, OR_FILEINFO, | |
| "Enable the ProxyExpress functionality"), | |
| AP_INIT_TAKE1("ProxyExpressDBMFile", set_dbmfile, NULL, OR_FILEINFO, | |
| "Location of ProxyExpressDBMFile file"), | |
| AP_INIT_TAKE1("ProxyExpressDBMType", set_dbmtype, NULL, OR_FILEINFO, | |
| "Type of ProxyExpressDBMFile file"), | |
| { NULL } | |
| }; | |
| static void register_hooks(apr_pool_t *p) | |
| { | |
| ap_hook_post_config(post_config, NULL, NULL, APR_HOOK_LAST); | |
| ap_hook_translate_name(xlate_name, NULL, NULL, APR_HOOK_FIRST); | |
| } | |
| /* the main config structure */ | |
| AP_DECLARE_MODULE(proxy_express) = | |
| { | |
| STANDARD20_MODULE_STUFF, | |
| NULL, /* create per-dir config structures */ | |
| NULL, /* merge per-dir config structures */ | |
| server_create, /* create per-server config structures */ | |
| server_merge, /* merge per-server config structures */ | |
| command_table, /* table of config file commands */ | |
| register_hooks /* register hooks */ | |
| }; |