What Is mod_alterquery?

mod_alterquery lets you modify the QUERY_STRING portion of URIs. Think of mod_alterquery as the mod_rewrite of form data (sent by GET, not POST).

Downloading mod_alterquery

Download the source code file for mod_alterquery here.

Compiling mod_alterquery for a New Apache Installation

For the sake of completeness, let us assume you have no copy of Apache, and need to install it from scratch. The first thing to do is download the latest stable version of Apache (currently 1.3.23) from http://www.apache.org. (Currently the exact url is http://www.apache.org/dist/httpd/apache_1.3.23.tar.gz.)

You will need root access to the box on which you will install Apache. Assume all commands from here on are run as root.

First, create the directory /usr/local/src if you don't already have such a directory. Then, copy apache_1.3.23.tar.gz into that directory, unpackage it, recompress it to save space (optional), and go into the newly-created source code directory.

prompt> su -
Password:*****
prompt> mkdir -p /usr/local/src
prompt> cd /usr/local/src
prompt> cp <where_you_downloaded_it>/apache_1.3.23.tar.gz .
prompt> gunzip apache_1.3.23.tar.gz
prompt> tar -xvf apache_1.3.23.tar
prompt> gzip apache_1.3.23.tar # may as well save some space
prompt> cd apache_1.3.23
The next thing to do, if you really want to understand this process, is read the file INSTALL so that you'll understand what happens when you run "./configure; make; make install". (Nonetheless, you should be able to follow the next set of instructions blind.)

The intent, just so you know, is to leverage the flexibility of Apache's configuration options to do three things:

  1. compile the non-standard mod_alterquery
  2. compile all modules as dynamically loadable for added flexibility
  3. install to a non-standard directory for added flexibility; not using the default install directory allows you to install multiple versions of Apache on the same box.

The first thing to do is copy the mod_alterquery.c file into the correct directory in the Apache distribution:

prompt> cp <wherever_mod_alterquery_is>/mod_alterquery.c src/modules/extra

Then, run the configure shell script with the correct arguments. I am biased towards explicitly telling the configure script what I do and do not want, so that has resulted in my writing a wrapper script called runconfigure, which looks like this:

#!/bin/sh

./configure \
--enable-module=so \
--enable-module=env --enable-shared=env \
--enable-module=setenvif --enable-shared=setenvif \
--enable-module=mime --enable-shared=mime \
--enable-module=negotiation --enable-shared=negotiation \
--enable-module=alias --enable-shared=alias \
--enable-module=dir --enable-shared=dir \
--enable-module=autoindex --enable-shared=autoindex \
--enable-module=access --enable-shared=access \
--enable-module=auth --enable-shared=auth \
--enable-module=asis --enable-shared=asis \
--enable-module=include --enable-shared=include \
--enable-module=cgi --enable-shared=cgi \
--enable-module=actions --enable-shared=actions \
--enable-module=log_config --enable-shared=log_config \
--enable-module=imap --enable-shared=imap \
--add-module=src/modules/extra/mod_alterquery.c --enable-shared=alterquery \
--enable-rule=SHARED_CORE \
--prefix=/usr/local/apache_1.3.23 \
--with-layout=Apache

In the script above, you'll want to pay particular attention to the mod_alterquery line if you're curious about the configure script's syntax for accepting third-party modules.

I suggest you copy this script into the /usr/local/src/apache_1.3.23 directory, name it runconfigure, and edit it to your liking. (You did read the INSTALL file in /usr/local/src/apache1.3.23 like I recommended, didn't you? If not, following these instructions blind should still produce the correct results, but if you plan on building and understanding Apache as a regular activity, the INSTALL file is essential reading.)

Now, assuming you have the above script (or one very like it) created, the following should work fine (you are still in the /usr/local/src/apache_1.3.23 directory, and are still logged on as root). Please note that the command prompt and commands you type are in bold; output that you will see is not bold.

prompt> chmod 755 runconfigure
prompt> ./runconfigure

Configuring for Apache, Version 1.3.23
+ using installation path layout: Apache (config.layout)
+ on-the-fly added and activated alterquery module (modules/extra/mod_alterquery.o)
Creating Makefile
Creating Configuration.apaci in src
Creating Makefile in src
+ configured for Linux platform
+ setting C compiler to gcc
+ setting C pre-processor to gcc -E
+ checking for system header files
+ adding selected modules
+ using builtin Expat
+ enabling generation of Apache core as DSO
+ using -ldl for vendor DSO support
+ checking sizeof various data types
+ doing sanity check on compiler and options
Creating Makefile in src/support
Creating Makefile in src/regex
Creating Makefile in src/os/unix
Creating Makefile in src/ap
Creating Makefile in src/main
Creating Makefile in src/lib/expat-lite
Creating Makefile in src/modules/standard
Creating Makefile in src/modules/extra
prompt> make
# lots of output here
prompt> make install
# lots of output here, including.:
make[1]: Leaving directory `/usr/local/src/apache_1.3.23'
+--------------------------------------------------------+
| You now have successfully built and installed the |
| Apache 1.3 HTTP server. To verify that Apache actually |
| works correctly you now should first check the |
| (initially created or preserved) configuration files |
| |
| /usr/local/apache_1.3.23/conf/httpd.conf
| |
| and then you should be able to immediately fire up |
| Apache the first time by running: |
| |
| /usr/local/apache_1.3.23/bin/apachectl start
| |
| Thanks for using Apache. The Apache Group |
| http://www.apache.org/ |
+--------------------------------------------------------+
prompt>

Please skip ahead to the section "Using mod_alterquery."

Compiling mod_alterquery for an Existing Apache Installation.

Please Note:

The first thing to do is copy the mod_alterquery.c file into the correct directory in the Apache distribution:

prompt> cp <wherever_mod_alterquery_is>/mod_alterquery.c src/modules/extra

Then, run the Apache Extension perl script (apxs) with the correct arguments to compile mod_alterquery.c as a loadable module, then copy the module to your Apache installation's libexec directory, then add to the module loading stanzas in httpd.conf.

prompt> cd /usr/local/src/apache_1.3.23/src/modules/extra
prompt> perl /usr/local/apache_1.3.23/bin/apxs -c mod_alterquery.c
gcc -DLINUX=22 -DUSE_HSREGEX -DUSE_EXPAT -I../lib/expat-lite -fpic -DSHARED_CORE -DSHARED_MODULE -I/usr/local/apache_1.3.23/include -c mod_alterquery.c
gcc -shared -o mod_alterquery.so mod_alterquery.o
prompt> perl /usr/local/apache_1.3.23/bin/apxs -i -a -n alterquery mod_alterquery.so
[activating module `alterquery' in /usr/local/apache_1.3.23/conf/httpd.conf]
cp mod_alterquery.so /usr/local/apache_1.3.23/libexec/mod_alterquery.so
chmod 755 /usr/local/apache_1.3.23/libexec/mod_alterquery.so
cp /usr/local/apache_1.3.23/conf/httpd.conf /usr/local/apache_1.3.23/conf/httpd.conf.bak
cp /usr/local/apache_1.3.23/conf/httpd.conf.new /usr/local/apache_1.3.23/conf/httpd.conf
rm /usr/local/apache_1.3.23/conf/httpd.conf.new

Now go to the next section and use mod_alterquery.

Using mod_alterquery

The first and most important thing to remember is that the order of mod_alterquery's directives in httpd.conf matters! The basic order of directives you are looking for is this:

uri to match
command to alter QUERY_STRING of above uri
command to alter QUERY_STRING of above uri
next uri to match

command to alter QUERY_STRING of above uri
command to alter QUERY_STRING of above uri

A concrete example looks like this:

    AlterQueryForURI /cgi-bin/showpage.pl
AlterQueryRemove sid
AlterQueryChange cache 1
AlterQueryForGlobURI /servlet/ticker*
AlterQueryAdd display full

First, you need either of these two directives:

AlterQueryForURI <uri>
AlterQueryForGlobURI <globuri>

<uri> must be a URI starting from the server (or virutal server) root, such as /somedir/somefile.html --- note the leading slash. <uri> must be an exact match, whereas <globuri> can be a simple glob expression using wildcards and "?", and string sets like file.{h,c,java} and character ranges like pic[0-9][a-zA-Z].gif.

Please note that AlterQueryForGlobURI comes in very handy when you want to match URIs that might have been altered using URL rewriting by a servlet container. The string ";jsessionid=<somethingunique>" will be appended to the URI, and will be different for every user, making it impossible to do exact URI matches on anything touched by URL rewriting. Hence, instead of

    AlterQueryForURI /servlets/SomeServlet

prefer

    AlterQueryForGlobURI /servlets/SomeServlet*

to match URIs that have been altered on the fly by URL rewriting.

Follow an AlterQueryForURI or AlterQueryForGlobURI directive with one or more of the following commands to alter the QUERY_STRING associated with the URI:

NOTE that in all examples above, you can count on keys and values being matched against their unescaped values, so if you are looking to match "some value", don't enter the url-encoded "some+value", but use "some value".

Usage examples are found in the next section.

Testing mod_alterquery

Because mod_alterquery is in its infancy, I have been trying to test it in as many ways as possible, to use and verify the operation of every one of its features. This section shows the tests that you can run on mod_alterquery if you want to test it yourself.

LogLevel

I wrote mod_alterquery to produce useful debugging logs when "LogLevel debug" is set in httpd.conf. All other log levels produce no logging from mod_alterquery.

Therefore, the first test is to see if you really do get detailed logging for "LogLevel debug" and no logging for all the other LogLevels.

Configure httpd.conf with "LogLevel debug", then watch <yourapacheinstall>logs/error_log as Apache runs to see if indeed the logging is verbose. All the other tests in this section will produce lots of useful debugging info in error_log if "LogLevel debug" is set in your httpd.conf.

(Passed.)

The All-in-One

This test tries to exercise every feature of mod_alterquery's engine in one request. First, be sure the <yourapacheinstall>/cgi-bin/test-cgi shell script is executable (mine wasn't). Next, configure httpd.conf so that the following stanza appears just before "### Section 3: Virtual Hosts":

<IfModule mod_alterquery.c>
AlterQueryForURI /cgi-bin/test-cgi
AlterQueryRemove nukekey
AlterQueryRemove removekey WRONG
AlterQueryChange changekey1 OK
AlterQueryChange changekey2 WRONG OK
AlterQueryAdd addkey OK
</IfModule>

This setup will exercise, for one URI, each feature of mod_alterquery.

Now hit the following URL (your hostname and port may be different: check your httpd.conf file): http://localhost/cgi-bin/test-cgi?keep=OK&nukekey=WRONG&removekey=WRONG&removekey=OK&changekey1=WRONG&changekey2=OK&changekey2=WRONG

Here's what should happen with each key/value pair in the query string (It also gives you a good idea of how each of mod_alterquery's three altering commands works):

And, indeed, when you hit that URL, test-cgi reports:

CGI/1.0 test script report:

argc is 0. argv is .

SERVER_SOFTWARE = Apache/1.3.23 (Unix)
SERVER_NAME = prospero.digitas.com
GATEWAY_INTERFACE = CGI/1.1
SERVER_PROTOCOL = HTTP/1.1
SERVER_PORT = 8080
REQUEST_METHOD = GET
HTTP_ACCEPT = text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,video/x-mng,image/png,image/jpeg,image/gif;q=0.2,text/css,*/*;q=0.1
PATH_INFO =
PATH_TRANSLATED =
SCRIPT_NAME = /cgi-bin/test-cgi
QUERY_STRING = keep=OK&removekey=OK&changekey1=OK&changekey2=OK&changekey2=OK&addkey=OK
REMOTE_HOST =
REMOTE_ADDR = 10.2.51.231
REMOTE_USER =
AUTH_TYPE =
CONTENT_TYPE =
CONTENT_LENGTH =

(Passed.)

URI Matching

Next, we need to be sure the query string is getting modified only for test-cgi, and not other URIs. The best way to do this is make a copy of the test-cgi shell script called test-uri, and hit it with this URL: http://localhost/cgi-bin/test-uri?keep=OK&nukekey=WRONG&removekey=WRONG&removekey=OK&changekey1=WRONG&changekey2=OK&changekey2=WRONG

This time, no modification of QUERY_STRING should happen, and you should see this:

CGI/1.0 test script report:

argc is 0. argv is .

SERVER_SOFTWARE = Apache/1.3.23 (Unix)
SERVER_NAME = prospero.digitas.com
GATEWAY_INTERFACE = CGI/1.1
SERVER_PROTOCOL = HTTP/1.1
SERVER_PORT = 8080
REQUEST_METHOD = GET
HTTP_ACCEPT = text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,video/x-mng,image/png,image/jpeg,image/gif;q=0.2,text/css,*/*;q=0.1
PATH_INFO =
PATH_TRANSLATED =
SCRIPT_NAME = /cgi-bin/test-uri
QUERY_STRING = keep=OK&nukekey=WRONG&removekey=WRONG&removekey=OK&changekey1=WRONG&changekey2=OK&changekey2=WRONG
REMOTE_HOST =
REMOTE_ADDR = 127.0.0.1
REMOTE_USER =
AUTH_TYPE =
CONTENT_TYPE =
CONTENT_LENGTH =

(Passed.)

URI Glob Matching

The AlterQueryForURI command can be replaced with the more powerful AlterQueryForGlobURI command, which does not support true regular expressions, but file globbing support like that found on the Unix command line.

In cgi-bin, copy test-cgi to othertest-cgi.

In httpd.conf, change the line

    AlterQueryForURI /cgi-bin/test-cgi

to the line

    AlterQueryForURI /cgi-bin/test-*

Restart Apache.

Then hit both of these URLs and be sure you get the same result page, shown below:
http://localhost/cgi-bin/test-cgi?keep=OK&nukekey=WRONG&removekey=WRONG&removekey=OK&changekey1=WRONG&changekey2=OK&changekey2=WRONG
http://localhost/cgi-bin/test-uri?keep=OK&nukekey=WRONG&removekey=WRONG&removekey=OK&changekey1=WRONG&changekey2=OK&changekey2=WRONG

Test results:

CGI/1.0 test script report:

argc is 0. argv is .

SERVER_SOFTWARE = Apache/1.3.23 (Unix)
SERVER_NAME = prospero.digitas.com
GATEWAY_INTERFACE = CGI/1.1
SERVER_PROTOCOL = HTTP/1.1
SERVER_PORT = 8080
REQUEST_METHOD = GET
HTTP_ACCEPT = text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,video/x-mng,image/png,image/jpeg,image/gif;q=0.2,text/css,*/*;q=0.1
PATH_INFO =
PATH_TRANSLATED =
SCRIPT_NAME = /cgi-bin/test-cgi
QUERY_STRING = keep=OK&removekey=OK&changekey1=OK&changekey2=OK&changekey2=OK&addkey=OK
REMOTE_HOST =
REMOTE_ADDR = 10.2.51.231
REMOTE_USER =
AUTH_TYPE =
CONTENT_TYPE =
CONTENT_LENGTH =

On the other hand, hitting the URL http://localhost/cgi-bin/othertest-cgi?keep=OK&nukekey=WRONG&removekey=WRONG&removekey=OK&changekey1=WRONG&changekey2=OK&changekey2=WRONG should produce the following page, because the glob should not match:

CGI/1.0 test script report:

argc is 0. argv is .

SERVER_SOFTWARE = Apache/1.3.23 (Unix)
SERVER_NAME = prospero.digitas.com
GATEWAY_INTERFACE = CGI/1.1
SERVER_PROTOCOL = HTTP/1.1
SERVER_PORT = 8080
REQUEST_METHOD = GET
HTTP_ACCEPT = text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,video/x-mng,image/png,image/jpeg,image/gif;q=0.2,text/css,*/*;q=0.1
PATH_INFO =
PATH_TRANSLATED =
SCRIPT_NAME = /cgi-bin/othertest-cgi
QUERY_STRING = keep=OK&nukekey=WRONG&removekey=WRONG&removekey=OK&changekey1=WRONG&changekey2=OK&changekey2=WRONG
REMOTE_HOST =
REMOTE_ADDR = 10.2.51.231
REMOTE_USER =
AUTH_TYPE =
CONTENT_TYPE =
CONTENT_LENGTH =

(Passed.)

UU Encoding

mod_alterquery is supposed to let you enter QUERY_STRING keys and values in plain text, and take care of the UU Encoding for you. Use the following configuration in httpd.conf:

<IfModule mod_alterquery.c>
AlterQueryForURI /cgi-bin/test-cgi
AlterQueryRemove "nuke key"
AlterQueryRemove "remove key" "WRONG key?"
AlterQueryChange "change&key1" "OK!"
AlterQueryChange "change=key2" "WRONG/key" "OK?"
AlterQueryAdd "[addkey]" "OK@"
</IfModule>

Hitting the following URL
http://localhost/cgi-bin/test-cgi?keep=OK&nuke+key=WRONG&remove+key=WRONG+key%3F&remove+key=OK&change%26key1=WRONG+key%3F&changekey2=OK&change%3Dkey2=WRONG%2Fkey
should produce the following results:

CGI/1.0 test script report:

argc is 0. argv is .

SERVER_SOFTWARE = Apache/1.3.23 (Unix)
SERVER_NAME = prospero.digitas.com
GATEWAY_INTERFACE = CGI/1.1
SERVER_PROTOCOL = HTTP/1.1
SERVER_PORT = 8080
REQUEST_METHOD = GET
HTTP_ACCEPT = text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,video/x-mng,image/png,image/jpeg,image/gif;q=0.2,text/css,*/*;q=0.1
PATH_INFO =
PATH_TRANSLATED =
SCRIPT_NAME = /cgi-bin/test-cgi
QUERY_STRING = keep=OK&remove+key=OK&change%26key1=OK!&changekey2=OK&change%3Dkey2=OK%3f&%5baddkey%5d=OK@
REMOTE_HOST =
REMOTE_ADDR = 127.0.0.1
REMOTE_USER =
AUTH_TYPE =
CONTENT_TYPE =
CONTENT_LENGTH =

(Passed.)

Processing Only GET Requests

mod_alterquery only processes QUERY_STRING, as passed after the "?" part of any GET request. Passing the same test data as a POST from an html form should make mod_alterquery not process the request.

Configure httpd.conf with the following:

<IfModule mod_alterquery.c>
    AlterQueryForURI /cgi-bin/test-cgi
    AlterQueryChange "addkey" "WRONG"
</IfModule>

Then, create the following html file, named test.html,  in your apache's htdocs directory:

<html>
<body>
<form action="/cgi-bin/test-cgi" method="POST">
<input type="hidden" name="changekey1" value="OK">
<input type="submit" name="submit" value="submit">
</form>
</body>
</html>

Then, hit this url: http://localhost/test.html, hit the "submit" button , and be sure the QUERY_STRING remains empty, as shown in the following result page:

CGI/1.0 test script report:

argc is 0. argv is .

SERVER_SOFTWARE = Apache/1.3.23 (Unix)
SERVER_NAME = prospero.digitas.com
GATEWAY_INTERFACE = CGI/1.1
SERVER_PROTOCOL = HTTP/1.1
SERVER_PORT = 8080
REQUEST_METHOD = POST
HTTP_ACCEPT = text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,video/x-mng,image/png,image/jpeg,image/gif;q=0.2,text/css,*/*;q=0.1
PATH_INFO =
PATH_TRANSLATED =
SCRIPT_NAME = /cgi-bin/test-cgi
QUERY_STRING =
REMOTE_HOST =
REMOTE_ADDR = 127.0.0.1
REMOTE_USER =
AUTH_TYPE =
CONTENT_TYPE = application/x-www-form-urlencoded
CONTENT_LENGTH = 27

(Passed.)

mod_jk and jsessionid URL Rewriting

mod_alterquery is of no use unless we can prove it has no unanticipated side effects on something like the mod_jk plugin, and Tomcat's URL rewriting for session management.

The first thing you need to do is install Tomcat (I use version 3.3a in my example here) and install (or compile and install) the mod_jk plugin for Apache.

Installing Tomcat is easy, and therefore will only be summarised: ensure a recent JDK is installed on your system (just a matter of downloading from java.sun.com and unzipping it), then get Tomcat from jakarta.apache.org and unzip it.

You can download a precompiled mod_jk plugin from jakarta.apache.org if you'd like, but I'll cover its custom compilation and installation here, seeing as you're likely getting the hang of doing such things if you're using mod_alterquery. ;-)

First, download Tomcat's source code from jakarta.apache.org and untar it someplace convenient. Then, cd to <somedir>jakarta-tomcat-3.3a-src/src/native/mod_jk/apache1.3. You'll see Makefile.<someOS>. In my case, Makefile.linux exists, so I'm in luck. Copy Makefile.linux (or Makefile.<whateverOS>) to Makefile, and edit the following lines of the Makefile:

# JAVA_HOME=
OS=linux
JAVA_INCL=-I /include -I /include/
JAVA_LIB=-L /jre/lib/ -L /lib//native_threads
#ifndef APXS
APXS=/usr/sbin/apxs
#endif

On my system, I have multiple installations of the JDK, Apache, etc, so I like to be explicit as possible with my Makefiles. So, I uncomment JAVA_HOME so that I can set it explicitly, and I remove the "#ifndev APXS" and "#endif" lines because I am going to explicitly set APXS. On my system, I end up with this:

JAVA_HOME=/usr/local/jdk1.3.1_01
OS=linux

JAVA_INCL=-I /include -I /include/
JAVA_LIB=-L /jre/lib/ -L /lib//native_threads
APXS=/usr/local/mwood/apache_1.3.23/bin/apxs

Once you have edited this portion of your copy of Makefile, type "make", and you will end up with the mod_jk.so shared object (ie, dynamically loadable library) in the directory.

Copy mod_jk.so to <yourapacheinstalldir>/libexec.

Now you just have to edit Apache's httpd.conf to load and configure the mod_jk plugin. But, because the whole purpose of this exercise is to test mod_jk with mod_alterquery, let's kill two birds with one stone and configure for both.

The easiest way to configure mod_jk is to add this line to the bottom of httpd.conf, just before Section 3, Virtual Hosts, and just after the mod_alterquery stanza.

Include <tomcatinstalldir>/conf/auto/mod_jk.conf

This will add the LoadModule and AddModule lines for mod_jk, in addition to all of mod_jk's other configuration directives. Please keep in mind that the last module loaded by LoadModule in httpd.conf is the first module that Apache invokes when calling all of its handlers. With mod_jk now the penultimate module to be loaded (and therefore the second to be called when Apache is invoking handlers), it still gets first crack at the QUERY_STRING. Why is this? mod_alterquery only implements Apache's Post Read Request handler, which is the first handler to get called for each module. mod_jk does not implement this handler, so Apache will skip past mod_jk and then invoke mod_alterquery's Post Read Request handler, which will alter the QUERY_STRING. When Apache gets to the Filename-to-URI Translation phase, mod_jk is the first module to get called. mod_jk does implement this handler, and so will get called, but by this time, mod_alterquery has already had a chance to do its job and alter a QUERY_STRING before mod_jk might pass it on to a servlet.

Also, my Apache runs on port 8080, as does Tomcat's HTTP 1.0 handler, so in server.xml, I comment out Tomcat's HTTP 1.0 handler like so:       

<!--
<Http10Connector   port="8080"
               secure="false"
               maxThreads="100"
               maxSpareThreads="50"
               minSpareThreads="10" />
-->

Now I go to Tomcat's bin directory and create the mod_jk configuration file like so:

./tomcat.sh start jkconf

Now Apache and Tomcat are configured well enough to perform our next test. (A better configuration involves hand-tuning to allow Apache to serve static content found in the directories of Tomcat's web applications, but that is outside the scope of our test.)

After starting Tomcat and Apache, turn off cookies in your browser to force Tomcat to track sessions with URL rewriting. Go to Tomcat's built-in Sessions Example at http://localhost/examples/servlet/SessionExample and add key/value pairs to the QUERY_STRING using the "GET based form." Then click on the bottom link, "URL encoded," to satisfy yourself that mod_alterquery does not hamper URL rewriting for URLs that it does not have an AlterQueryForURI command for in httpd.conf.

Next, change mod_alterquery's configuration in httpd.conf to this:

<IfModule mod_alterquery.c>
    AlterQueryForGlobURI "/examples/servlet/SessionExample*"
    AlterQueryRemove "dataname" "WRONG"
    AlterQueryRemove "datavalue" "WRONG"
</IfModule>

Please note we have to use the AlterQueryForGlobURI command, with an asterisk on the end of the servlet name, because URL rewriting will add ";jsessionid=zmg61q7ys1" to the end of the URI before the  "?key=val&key2=val2" QUERY_STRING. When Apache separates out the QUERY_STRING from the URI, ";jsessionid=zmg61q7ys1 " will still be appended to the URI. This part of the URI has to (obviously) be different for each user, so you must use glob matching.

Shut down your browser to clear your session, and restart Tomcat and Apache.

Now go to http://localhost/examples/servlet/SessionExample and use the "GET based form" to add session attribute name "WRONG" and session attribute value "WRONG". Submitting the query should prevent the key/value pair from being added to your session, because the QUERY_STRING will be modified by mod_alterquery before mod_jk can pass it on to Tomcat.

(Passed.)

Conclusion

I don't forsee widespread need for something as strange as mod_alterquery. Nonetheless, if you've found yourself needing to alter the QUERY_STRING on the fly, I hope mod_alterquery performs well for you.