Hello again.
Attached is an updated version of my mod_include patch to add query string
parsing. (See original thread here:
http://www.mail-archive.com/dev%40httpd.apache.org/msg17657.html)
This works with the current 2.1 branch in CVS and implements a number of
the suggestions from the first thread:
1. This is a seperate module, mod_include_query.c, which hooks into
mod_include via the ap_register_include_handler optional function. So this
isn't technically a patch, it's a new file. :)
2. Adds support for query strings delimited by semicolon (;).
3. Adds a bit of namespace protection by prepending all query string
variables with a leading underscore (_). This prevents someone from using
this feature to override important environment variables, unless you begin
your important environment variables with an underscore.
4. Adds support for variables with multiple values. So a query string like
?multi=one&multi=two&multi=three&foo=bar
will generate the following variables:
_multi = one,two,three
_multi[0] = one
_multi[1] = two
_multi[2] = three
_foo = bar
_foo[0] = bar
The disadvantage is that single variables will be getting added to the
table twice, as _foo and _foo[0] demonstrate. Since the number of
variables on a query string is generally small, I don't see this as a big
problem. However, we may want to add an ability to turn multiple
processing off. I'm not sure how this would be implimented yet (is
mod_include's #config handler hookable in any way? If not, perhaps I could
add a hook mechanism to it.)
Mr. Andr� Malo also suggested modifying #set to access query string vars,
but again I don't know if this is possible without mucking about in
mod_include.c itself. I will investigate creating a hooking mechanism for
existing directives, because that would be cool if it can be done.
mod_include_query.c is attached. To enable it you'll have to add it to
modules/filters/config.m4:
APACHE_MODULE(include_query, SSI query string extensions, , , yes)
Feedback is welcomed, of course. Enjoy!
--
Mike Friedman
/*
* mod_include_query.c
*
* This module extends mod_include by adding query string parsing
* functionality.
*
* Copyright (C) 2003 Mike Friedman ([EMAIL PROTECTED])
*
*/
#include "apr.h"
#include "apr_strings.h"
#include "apr_thread_proc.h"
#include "apr_hash.h"
#include "apr_user.h"
#include "apr_lib.h"
#include "apr_optional.h"
#define APR_WANT_STRFUNC
#define APR_WANT_MEMFUNC
#include "apr_want.h"
#include "ap_config.h"
#include "util_filter.h"
#include "httpd.h"
#include "http_config.h"
#include "http_core.h"
#include "http_request.h"
#include "http_core.h"
#include "http_protocol.h"
#include "http_log.h"
#include "http_main.h"
#include "util_script.h"
#include "http_core.h"
#include "mod_include.h"
static APR_OPTIONAL_FN_TYPE(ap_register_include_handler) *query_pfn_reg_with_ssi;
static APR_OPTIONAL_FN_TYPE(ap_ssi_get_tag_and_value) *query_pfn_gtv;
static APR_OPTIONAL_FN_TYPE(ap_ssi_parse_string) *query_pfn_ps;
static apr_status_t handle_parseqs(include_ctx_t *ctx, ap_filter_t *f,
apr_bucket_brigade *bb) {
request_rec *r = f->r;
char *tag = NULL;
char *tag_val = NULL;
char qsa[1024];
char fname[256];
char vtmp[256];
apr_hash_t *pcount = apr_hash_make(r->pool); // qs param counts
int *cnt;
if (ctx->argc) {
ap_log_rerror(APLOG_MARK,
(ctx->flags & SSI_FLAG_PRINTING)
? APLOG_ERR : APLOG_WARNING,
0, r, "parseqs directive does not take tags in %s",
r->filename);
}
if (!(ctx->flags & SSI_FLAG_PRINTING)) {
return APR_SUCCESS;
}
if (ctx->argc) {
SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
return APR_SUCCESS;
}
strncpy(qsa, apr_table_get(r->subprocess_env, "QUERY_STRING"), sizeof(qsa));
char *qsa_ptr = qsa;
int i = 0;
/*
* Loop over the query string chars. If we encounter &, ; or \0, set
* that char to \0 and work on the sub-string. Else keep going.
* When we get to the end of the string, strlen will be false.
*/
while (strlen(qsa_ptr)) {
if ((qsa_ptr[i] == '&') || (qsa_ptr[i] == ';') || (qsa_ptr[i] == '\0')) {
qsa_ptr[i] = '\0';
/*
* Loop over the sub-string to split it into name=value
* pairs
*/
int j;
char *val_ptr;
for (j = 0; j <= strlen(qsa_ptr); j++) {
if (qsa_ptr[j] == '=') {
qsa_ptr[j] = '\0';
val_ptr = (qsa_ptr + ++j);
j = strlen(qsa_ptr);
}
}
/* precede the name with a _ for security */
strcpy(fname, "_");
strncat(fname, qsa_ptr, strlen(qsa_ptr));
/*
* add or increment this var's count in the hash table
* (start at zero)
*/
cnt = (int *)(apr_hash_get(pcount, fname, strlen(fname)));
if (cnt) {
(*cnt)++;
apr_hash_set(pcount, fname, strlen(fname), cnt);
} else {
cnt = (int *)(apr_palloc(r->pool, sizeof(int)));
*cnt = 0;
apr_hash_set(pcount, fname, strlen(fname), cnt);
}
/* add the var to the environment table, or append if it exists */
if (*cnt == 0) {
apr_table_setn(r->subprocess_env,
apr_pstrdup(r->pool, fname),
apr_pstrdup(r->pool, val_ptr));
} else {
strncpy(vtmp, apr_table_get(r->subprocess_env, fname), sizeof(vtmp));
sprintf(vtmp, "%s,%s", vtmp, val_ptr);
apr_table_setn(r->subprocess_env,
apr_pstrdup(r->pool, fname),
apr_pstrdup(r->pool, vtmp));
}
/* add the "array" element to the environment table */
sprintf(vtmp, "%s[%d]", fname, *cnt);
apr_table_setn(r->subprocess_env,
apr_pstrdup(r->pool, vtmp),
apr_pstrdup(r->pool, val_ptr));
strcpy(fname, "");
strcpy(vtmp, "");
val_ptr = "";
qsa_ptr += ++i;
i = 0;
}
else {
i++;
}
}
return APR_SUCCESS;
}
static int query_post_config(apr_pool_t *p, apr_pool_t *plog,
apr_pool_t *ptemp, server_rec *s)
{
query_pfn_reg_with_ssi = APR_RETRIEVE_OPTIONAL_FN(ap_register_include_handler);
query_pfn_gtv = APR_RETRIEVE_OPTIONAL_FN(ap_ssi_get_tag_and_value);
query_pfn_ps = APR_RETRIEVE_OPTIONAL_FN(ap_ssi_parse_string);
if ((query_pfn_reg_with_ssi) && (query_pfn_gtv) && (query_pfn_ps)) {
/* register our directive name with mod_include.c */
query_pfn_reg_with_ssi("parseqs", handle_parseqs);
}
return OK;
}
static void register_hooks(apr_pool_t *p)
{
static const char * const aszPre[] = { "mod_include.c", NULL };
// ap_hook_handler(cgi_handler, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_post_config(query_post_config, aszPre, NULL, APR_HOOK_REALLY_FIRST);
}
module AP_MODULE_DECLARE_DATA include_query_module = {
STANDARD20_MODULE_STUFF,
NULL, /* create per-directory config struct */
NULL, /* merge per-directiry config struct */
NULL, /* create per-server config struct */
NULL, /* merge per-server config struct */
NULL, /* command apr_table_t */
register_hooks /* register hooks */
};