Patch for: http://trac.lighttpd.net/trac/ticket/911 Allows $n and %n references to be actively urlencoded by using the # character. Example: $HTTP["referer"] =~ "(.+)" { url.redirect = ( "(.*)" => "http://www.mydomain.com/myscript.php?&ref=%#1" ) } So $n and %n are original values, while $#n and %#n are urlencoded values. This affects both mod_redirect and mod_rewrite. diff -Nur ../lighttpd-1.4.18/src/mod_redirect.c ./src/mod_redirect.c --- ../lighttpd-1.4.18/src/mod_redirect.c 2007-04-10 09:52:58.000000000 +0200 +++ ./src/mod_redirect.c 2008-01-15 10:34:37.000000000 +0100 @@ -13,6 +13,22 @@ #include "config.h" #endif +/* Helper function */ +int config_append_cond_match_buffer_encoded(connection *con, data_config *dc, buffer *buf, int n) +{ + cond_cache_t *cache = &con->cond_cache[dc->context_ndx]; + if (n > cache->patterncount) { + return 0; + } + + n <<= 1; /* n *= 2 */ + buffer_append_string_encoded(buf, + cache->comp_value->ptr + cache->matches[n], + cache->matches[n + 1] - cache->matches[n], + ENCODING_REL_URI_PART); + return 1; +} + typedef struct { pcre_keyvalue_buffer *redirect; data_config *context; /* to which apply me */ @@ -216,10 +232,16 @@ start = 0; end = pattern_len; for (k = 0; k < pattern_len; k++) { if ((pattern[k] == '$' || pattern[k] == '%') && - isdigit((unsigned char)pattern[k + 1])) { + (isdigit((unsigned char)pattern[k + 1]) || + (pattern[k + 1] == '#' && pattern_len > k+2 && isdigit((unsigned char)pattern[k + 2])))) { + /* got one */ - - size_t num = pattern[k + 1] - '0'; + size_t num = 0; + if(pattern[k + 1] == '#') { + num = pattern[k + 2] - '0'; + } else { + num = pattern[k + 1] - '0'; + } end = k; @@ -228,7 +250,11 @@ if (pattern[k] == '$') { /* n is always > 0 */ if (num < (size_t)n) { - buffer_append_string(p->location, list[num]); + if(pattern[k + 1] == '#') { + buffer_append_string_encoded(p->location, list[num], strlen(list[num]), ENCODING_REL_URI_PART); + } else { + buffer_append_string(p->location, list[num]); // HERE + } } } else if (p->conf.context == NULL) { /* we have no context, we are global */ @@ -236,10 +262,19 @@ "used a rewrite containing a %[0-9]+ in the global scope, ignored:", kv->value); } else { - config_append_cond_match_buffer(con, p->conf.context, p->location, num); + if(pattern[k + 1] == '#') { + config_append_cond_match_buffer_encoded(con, p->conf.context, p->location, num); + } else { + config_append_cond_match_buffer(con, p->conf.context, p->location, num); + } } - k++; + if(pattern[k + 1] == '#') { + k += 2; + } else { + k++; + } + start = k + 1; } } diff -Nur ../lighttpd-1.4.18/src/mod_rewrite.c ./src/mod_rewrite.c --- ../lighttpd-1.4.18/src/mod_rewrite.c 2007-04-10 09:52:58.000000000 +0200 +++ ./src/mod_rewrite.c 2008-01-15 10:34:30.000000000 +0100 @@ -12,6 +12,22 @@ #include "config.h" #endif +/* Helper function */ +int config_append_cond_match_buffer_encoded(connection *con, data_config *dc, buffer *buf, int n) +{ + cond_cache_t *cache = &con->cond_cache[dc->context_ndx]; + if (n > cache->patterncount) { + return 0; + } + + n <<= 1; /* n *= 2 */ + buffer_append_string_encoded(buf, + cache->comp_value->ptr + cache->matches[n], + cache->matches[n + 1] - cache->matches[n], + ENCODING_REL_URI_PART); + return 1; +} + typedef struct { #ifdef HAVE_PCRE_H pcre *key; @@ -386,10 +402,16 @@ start = 0; end = pattern_len; for (k = 0; k < pattern_len; k++) { if ((pattern[k] == '$' || pattern[k] == '%') && - isdigit((unsigned char)pattern[k + 1])) { + (isdigit((unsigned char)pattern[k + 1]) || + (pattern[k + 1] == '#' && pattern_len > k+2 && isdigit((unsigned char)pattern[k + 2])))) { /* got one */ - size_t num = pattern[k + 1] - '0'; + size_t num = 0; + if(pattern[k + 1] == '#') { + num = pattern[k + 2] - '0'; + } else { + num = pattern[k + 1] - '0'; + } end = k; @@ -398,7 +420,11 @@ if (pattern[k] == '$') { /* n is always > 0 */ if (num < (size_t)n) { - buffer_append_string(con->request.uri, list[num]); + if(pattern[k + 1] == '#') { + buffer_append_string_encoded(con->request.uri, list[num], strlen(list[num]), ENCODING_REL_URI_PART); + } else { + buffer_append_string(con->request.uri, list[num]); + } } } else if (p->conf.context == NULL) { /* we have no context, we are global */ @@ -407,10 +433,19 @@ rule->value); } else { - config_append_cond_match_buffer(con, p->conf.context, con->request.uri, num); + if(pattern[k + 1] == '#') { + config_append_cond_match_buffer_encoded(con, p->conf.context, con->request.uri, num); + } else { + config_append_cond_match_buffer(con, p->conf.context, con->request.uri, num); + } } - k++; + if(pattern[k + 1] == '#') { + k += 2; + } else { + k++; + } + start = k + 1; } }