/* Copyright 1999-2004 The Apache Software Foundation * Copyright 2004 Ernst Jan Plugge * * 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. */ /* *************************************************************************** * URL Scheme module. This module provides a configuration setting to set * the scheme and default port for a location independent of the actual * protocol being served. This provides a higher level of control over * most importantly URLs in HTTP 30x redirect responses. * * Based on mod_example.c in the core httpd distribution. */ #include "httpd.h" #include "http_config.h" #include "http_core.h" #include "http_log.h" #include "http_main.h" #include "http_protocol.h" #include "http_request.h" #include "util_script.h" #include "http_connection.h" #include "apr_strings.h" #include /* * Declare ourselves so the configuration routines can find and know us. * We'll fill it in at the end of the module. */ module AP_MODULE_DECLARE_DATA urlscheme_module; /*--------------------------------------------------------------------------*/ /* */ /* Data declarations. */ /* */ /* Here are the static cells and structure declarations private to our */ /* module. */ /* */ /*--------------------------------------------------------------------------*/ /* * Configuration record. Records the scheme and default port to be used. */ typedef struct urlscheme_cfg { char *scheme; /* The scheme for this location */ apr_port_t port; /* The default port for this scheme */ char scheme_specified; /* Is the scheme specified? */ char port_specified; /* Is the default port specified? */ } urlscheme_cfg; /*--------------------------------------------------------------------------*/ /* */ /* Configuration directive handlers. */ /* */ /*--------------------------------------------------------------------------*/ /* * Set the scheme. If the argument is "default" then the module will decline * to set the scheme. Otherwise, the argument will be supplied when the * http_scheme hook is called. */ static const char *cmd_server_scheme(cmd_parms *cmd, void *mconfig, const char *arg) { urlscheme_cfg *cfg = (urlscheme_cfg *) mconfig; if (strcasecmp(arg, "default") == 0) { cfg->scheme = NULL; } else { cfg->scheme = apr_pstrdup(cmd->pool, arg); } cfg->scheme_specified = 1; return NULL; } /* * Set the default port. If the argument is "default" then the module will * decline to set the scheme's default port. Otherwise, the argument will be * supplied when the default_port hook is called. */ static const char *cmd_server_port(cmd_parms *cmd, void *mconfig, const char *arg) { urlscheme_cfg *cfg = (urlscheme_cfg *) mconfig; int port; if (strcasecmp(arg, "default") == 0) { cfg->port = 0; } else { port = atoi(arg); if (port <= 0 || port >= 65536) { /* 65536 == 1<<16 */ return apr_pstrcat(cmd->temp_pool, "The port number \"", arg, "\" is outside the appropriate range " "(i.e., 1..65535).", NULL); } cfg->port = port; } cfg->port_specified = 1; return NULL; } /*--------------------------------------------------------------------------*/ /* */ /* These routines are strictly internal to this module, and support its */ /* operation. They are not referenced by any external portion of the */ /* server. */ /* */ /*--------------------------------------------------------------------------*/ /* * Locate our directory configuration record for the current request. */ static urlscheme_cfg *our_dconfig(const request_rec *r) { return (urlscheme_cfg *) ap_get_module_config(r->per_dir_config, &urlscheme_module); } /*--------------------------------------------------------------------------*/ /* */ /* Now let's declare routines for each of the callback phase in order. */ /* */ /*--------------------------------------------------------------------------*/ /* * This function gets called to create a per-directory configuration * record. This will be called for the "default" server environment, and for * each directory for which the parser finds any of our directives applicable. * If a directory doesn't have any of our directives involved (i.e., they * aren't in the .htaccess file, or a , , or related * block), this routine will *not* be called - the configuration for the * closest ancestor is used. * * The return value is a pointer to the created module-specific * structure. */ static void *urlscheme_create_dir_config(apr_pool_t *p, char *dirspec) { urlscheme_cfg *cfg; /* * Allocate the space for our record from the pool supplied. */ cfg = (urlscheme_cfg *) apr_pcalloc(p, sizeof(urlscheme_cfg)); /* * Now fill in the defaults. If there are any `parent' configuration * records, they'll get merged as part of a separate callback. */ cfg->scheme = NULL; cfg->port = 0; cfg->scheme_specified = 0; cfg->port_specified = 0; return (void *) cfg; } /* * This function gets called to merge two per-directory configuration * records. This is typically done to cope with things like .htaccess files * or directives for directories that are beneath one for which a * configuration record was already created. The routine has the * responsibility of creating a new record and merging the contents of the * other two into it appropriately. If the module doesn't declare a merge * routine, the record for the closest ancestor location (that has one) is * used exclusively. * * The routine MUST NOT modify any of its arguments! * * The return value is a pointer to the created module-specific structure * containing the merged values. */ static void *urlscheme_merge_dir_config(apr_pool_t *p, void *parent_conf, void *newloc_conf) { urlscheme_cfg *merged_config = (urlscheme_cfg *) apr_pcalloc(p, sizeof(urlscheme_cfg)); urlscheme_cfg *pconf = (urlscheme_cfg *) parent_conf; urlscheme_cfg *nconf = (urlscheme_cfg *) newloc_conf; merged_config->scheme = pconf->scheme; merged_config->port = pconf->port; merged_config->scheme_specified = pconf->scheme_specified; merged_config->port_specified = pconf->port_specified; if (nconf->scheme_specified) { merged_config->scheme = nconf->scheme; merged_config->scheme_specified = 1; } if (nconf->port_specified) { merged_config->port = nconf->port; merged_config->port_specified = 1; } return (void *) merged_config; } /* * This callback is where this module gets a chance to set the server's * scheme. */ static const char *urlscheme_http_scheme(const request_rec *r) { urlscheme_cfg *cfg; cfg = our_dconfig(r); return cfg->scheme; } /* * This callback is where this module gets a chance to set the server's * scheme's default port. */ static apr_port_t urlscheme_default_port(const request_rec *r) { urlscheme_cfg *cfg; cfg = our_dconfig(r); return cfg->port; } /* * Each function our module provides to handle a particular hook is * specified here. The functions are registered using * ap_hook_foo(name, predecessors, successors, position) * where foo is the name of the hook. */ static void urlscheme_register_hooks(apr_pool_t *p) { ap_hook_http_scheme(urlscheme_http_scheme, NULL, NULL, APR_HOOK_FIRST); ap_hook_default_port(urlscheme_default_port, NULL, NULL, APR_HOOK_FIRST); } /*--------------------------------------------------------------------------*/ /* */ /* All of the routines have been declared now. Here's the list of */ /* directives specific to our module, and information about where they */ /* may appear and how the command parser should pass them to us for */ /* processing. Note that care must be taken to ensure that there are NO */ /* collisions of directive names between modules. */ /* */ /*--------------------------------------------------------------------------*/ /* * List of directives specific to our module. */ static const command_rec urlscheme_cmds[] = { AP_INIT_TAKE1("ServerScheme", cmd_server_scheme, NULL, OR_OPTIONS, "Set the scheme for this location"), AP_INIT_TAKE1("ServerSchemeDefaultPort", cmd_server_port, NULL, OR_OPTIONS, "Set the scheme's default port for this location"), {NULL} }; /*--------------------------------------------------------------------------*/ /* */ /* Finally, the list of callback routines and data structures that provide */ /* the static hooks into our module from the other parts of the server. */ /* */ /*--------------------------------------------------------------------------*/ /* * Module definition for configuration. If a particular callback is not * needed, replace its routine name below with the word NULL. */ module AP_MODULE_DECLARE_DATA urlscheme_module = { STANDARD20_MODULE_STUFF, urlscheme_create_dir_config, /* per-directory config creator */ urlscheme_merge_dir_config, /* dir config merger */ NULL, /* server config creator */ NULL, /* server config merger */ urlscheme_cmds, /* command table */ urlscheme_register_hooks, /* set up other request processing hooks */ };