mod_urlscheme

Purpose

mod_urlscheme is a small Apache 1.3/2.0/2.2 module that allows the Apache configuration author control over the scheme to use when constructing self-referential URLs.

Please note that this module is different from mod_scheme, which embeds the Tinyscheme interpreter into Apache. You can find that module here. I changed the name from mod_scheme to mod_urlscheme to avoid confusion.

The original module was only written to work on Apache 2.0. There is now also a version for Apache 1.3 + EAPI, although it won't work with stock 1.3. Please see the "Apache 1.3" section at the bottom of this page for details. The 2.0 module will work almost unchanged on Apache 2.2. There is a small naming change in the API that requires a slightly different version.

In several situations, Apache will attempt to construct a URL that will point to itself and will deliver the result to the client. The most notable occasion for this is when Apache is constructing a client redirect. This can for example happen when the client requests a URL that maps to a directory but doesn't include a trailing slash: Apache will send back a redirect to the same URL, but with a trailing slash appended. Other occasions include Redirect directives in the Apache configuration, or mod_proxy rewriting redirects coming from a backend server (when mod_proxy is functioning as a reverse proxy).

A self-referential URL has four distinct major components: the scheme, the hostname, the port number and the request URI, the latter including perhaps a query string and a fragment identifier. The combination of ServerName, UseCanonicalName and the use of the client's HTTP Host header allows an Apache administrator full control over the hostname and port number part of the generated URLs, but the scheme is up to Apache itself.

Normally, the scheme is always "http". A module such as mod_ssl will override this and set the scheme to "https" for those locations where it is active. But that doesn't help you when the Apache server is behind another server that will handle the HTTPS traffic for you. Imagine the following layered approach:

Now, if Apache for some reason needs to generate a redirect, the scheme on the redirect URL will be "http", because that's what Apache is serving. But that URL isn't valid on the outside: the scheme should be "https", so that the client will proceed to get the new URL from the same secure location.

One solution is to let the machine that handles the SSL work do the rewrite from http://www.example.com:81/ to https://www.example.com/. But that doesn't help you if the first machine is (for example) a dumb SSL tunnel that doesn't understand HTTP. In that case, Apache will need to be convinced its scheme is actually "https", not "http".

That's where mod_urlscheme comes in.

Download

The version for Apache 1.3 + EAPI can be downloaded here:

mod_urlscheme13.c

The Apache 2.0 module can be downloaded here:

mod_urlscheme20.c

The Apache 2.2 module can be downloaded here:

mod_urlscheme22.c

The entire module is contained within that single C source file. Rename the module version you need to mod_urlscheme.c after downloading it.

Installation

These instructions assume a Unix installation. For other systems, please consult the Apache documentation. mod_urlscheme is a very simple module that requires no special treatment. Simply put, if you can build mod_example from the stock Apache tree, then you can build mod_urlscheme as well.

Put the downloaded mod_urlscheme.c file in a temporary directory somewhere where you will compile it.

If you want to include mod_urlscheme as a static module in your Apache server, prepare your Apache source directory as per the Apache build instructions. When calling the ./configure command, include the option --with-module=experimental:/path/to/mod_urlscheme.c (for Apache 1.3: --add-module=/path/to/mod_urlscheme.c). You need to specify the full path to the source file after the colon. Then, proceed with the build instructions as you would normally. The module will be included in your Apache binary as a static module.

For a dynamic module, first install a full Apache distribution, including the apxs tool and the C headers. If you install from pre-packaged bundles, such as RPMs, you may need to separately install the development package. On RPM-based systems that usually means you need to have the httpd-devel package installed. You will also need a fully functional compiler suite installed.

Go to the directory where you put the mod_urlscheme.c file and run apxs -c mod_urlscheme.c. Refer to the Apache documentation to see if you need to specify more command line options for your system.

If the compile succeeded, you will now have a dynamic Apache module ready to use. You may need to look in the .libs subdirectory to find the actual mod_urlscheme.so file (under Unix, that is). Copy the module to the Apache module directory, which is the modules subdirectory of the server root (for Apache 1.3: the libexec subdirectory). Alternatively, you can put it in any other location; just make a note of where you put it, so you can refer to the location later on.

Build problems

If the compile fails, please check whether you can build the module mod_example from the stock Apache distribution in the same way as you're trying to build mod_urlscheme. If that doesn't work, the problem is in your system or your build procedure, and not in mod_urlscheme. Consult the Apache documentation or your system's documentation for more details.

If you're trying to build mod_urlscheme statically, try to build mod_example instead. It is in the modules/experimental subdirectory of the Apache source tree. On the ./configure command line, don't specify --enable-example, but use --with-module=experimental:/path/to/mod_example.c to include it. Again, locations will differ slightly for Apache 1.3. Read the documentation for details.

If you're trying to build mod_urlscheme dynamically, download and extract a copy of the Apache source tree. Copy the file modules/experimental/mod_example.c from there to an empty directory, and try building it using apxs -c mod_example.c from there.

Don't bother trying to build mod_urlscheme until you can get mod_example to work.

If you are using Apache 1.3, and you're getting error messages saying that request_rec doesn't have a member named ctx, or about the function ap_ctx_set() not being declared, then you don't have EAPI in your Apache build. See the Apache 1.3 section at the bottom of this document. If you do have EAPI in your Apache build, then you need to make sure that the include files from EAPI (ap_ctx.h in particular) are in the same place as the other Apache include files.

Configuration

If you compiled mod_urlscheme as a dynamic module, include the following line in your httpd.conf:

LoadModule urlscheme_module modules/mod_urlscheme.so

Or for Apache 1.3 + EAPI:
LoadModule urlscheme_module libexec/mod_urlscheme.so
AddModule mod_urlscheme.c
The latter of the two lines should go after the ClearModuleList directive, among the other AddModule directives.

If you didn't put the module in the server root, you need to specify the full path to the module as the second argument to the LoadModule directive.

mod_urlscheme provides two configuration directives:

ServerScheme <scheme> | default: This directive specifies the URL scheme to use for the locations that this directive applies to. If the scheme is default, then the module will not attempt to force the scheme, and leave the decision up to other modules, if any.

ServerSchemeDefaultPort <port> | default: This directive specifies the default port for the URL scheme in use. If, for example, the scheme is "https" and the server's port is 443, then the generated URL doesn't have to be https://www.example.com:443/; the port number may be omitted. To allow Apache to omit the default port number, it needs to know what the default port number is. This directive tells Apache that. It is a companion to ServerScheme, and the two are usually used together. Again, specifying default will cause mod_urlscheme to not attempt to force the default port at all.

Both directives may appear anywhere in your httpd.conf, and may even appear in .htaccess if AllowOverride Options is in effect for that directory.

As a concrete example, the following snippet from httpd.conf will implement the scenario outlined above. It was written for Apache 2.0, and the 1.3 equivalent will probably look a bit different, but I don't use 1.3 myself.

Listen 80
Listen 81

#
# Virtual host for port 80: regular HTTP requests
#
<VirtualHost _default_:80>

  ServerName www.example.com:80
  UseCanonicalName on

  # Other directives for port 80

</VirtualHost>

#
# Virtual host for port 81: HTTPS requests, but with the SSL traffic handled
# by another machine, which is expected to forward the resulting decrypted
# request to port 81.
#
<VirtualHost _default_:81>

  ServerName www.example.com:443
  UseCanonicalName on

  ServerScheme https
  ServerSchemeDefaultPort 443

  # Other directives for port 81

</VirtualHost>

What's the deal with Apache 1.3 + EAPI?

This module was originally written for Apache 2.0. That version of Apache has two extremely convenient hooks for implementing this module. They are called ap_http_method and ap_default_port. (The former is a slight misnomer because the HTTP method is typically "GET" or "POST"; "http" and "https" are URL schemes, not HTTP methods. The name was fixed in the 2.2 version of Apache.) The main user of these hooks is mod_ssl, because it needs them for pretty much the same purpose I do: making sure self-referential URLs use https.

However, Apache 1.3 doesn't provide these hooks. They are hardcoded to "http" and "80" respectively, unless you're using Netware. Netware has a special arrangement for SSL. This also means, of course, that the hooks are not available to mod_ssl on Apache 1.3. So how does mod_ssl for Apache 1.3 solve this problem?

It does this by patching the core Apache server before building it. It includes a few API enhancements named "EAPI", and one of those enhancements is to provide a way to customize ap_http_method and ap_default_port, although not quite as a hook. It then builds itself as a module which takes advantage of EAPI. This is one of the reasons why you can't build mod_ssl for Apache 1.3 against a precompiled stock Apache 1.3 build. You need to build mod_ssl against an Apache 1.3 source tree that includes the EAPI stuff.

Without EAPI, it's very difficult to achieve the same functionality. With some fancy content handler tricks you might be able to get away with it, but that would be much more difficult, much more error-prone, and a lot more work. So I decided to not even try. If you want to use mod_urlscheme.c on Apache 1.3, you must have EAPI. The easiest way is to just build Apache with mod_ssl, but you could conceivably just patch a stock Apache tree with nothing more than EAPI. I haven't actually tried that myself, but it should work. If you're worried about the bloat of including mod_ssl if you don't need it, don't be. If you build mod_ssl as a dynamic module, and then never load it using a LoadModule directive, then you don't pay the additional cost. You just pay a tiny extra cost for EAPI itself, because it makes a few internal Apache structures a little bit larger.

The net result is that mod_urlscheme.c works with Apache 1.3, but only if you have EAPI or mod_ssl. If you don't have either, it won't work, and I'm not going to write a version that will work, because there is no clean and simple way to do it without patching the Apache core.

If you want a copy of EAPI, download a copy of the source code of mod_ssl for Apache 1.3. EAPI can be found in the pkg.eapi subdirectory of the source archive.

Author and license

mod_urlscheme was written by Ernst Jan Plugge <rmc@dds.nl>. It is based on the mod_example source code in the 1.3.34, 2.0.50 and 2.2.0 Apache source trees.

The module is licensed under the Apache license 2.0.