Project

General

Profile

Feature #443 » ticket-443.patch

moo, 2006-04-16 11:31

View differences:

tests/mod-redirect.t (working copy)
use strict;
use IO::Socket;
use Test::More tests => 6;
use Test::More tests => 8;
use LightyTest;
my $tf = LightyTest->new();
......
Host: vvv.example.org
EOF
);
$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 301, 'Location' => 'http://localhost:'.$tf->{PORT}.'/' } ];
$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 301, 'Location' => 'http://localhost:'.$tf->{PORT}.'/$' } ];
ok($tf->handle_http($t) == 0, 'external redirect');
$t->{REQUEST} = ( <<EOF
GET /redirect/vvv/ HTTP/1.0
Host: vvv.example.org
EOF
);
$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 301, 'Location' => 'http://localhost:'.$tf->{PORT}.'/$vvv%2f' } ];
ok($tf->handle_http($t) == 0, 'external redirect with urlencoded');
$t->{REQUEST} = ( <<EOF
GET /redirect/ HTTP/1.0
Host: zzz.example.org
Referer: zzz
EOF
);
$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 301, 'Location' => 'http://localhost:'.$tf->{PORT}.'/zzz' } ];
$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 301, 'Location' => 'http://localhost:'.$tf->{PORT}.'/%zzz' } ];
ok($tf->handle_http($t) == 0, 'external redirect with cond regsub');
$t->{REQUEST} = ( <<EOF
GET /redirect/ HTTP/1.0
Host: zzz.example.org
Referer: zzz/
EOF
);
$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 301, 'Location' => 'http://localhost:'.$tf->{PORT}.'/%zzz%2f' } ];
ok($tf->handle_http($t) == 0, 'external redirect with cond regsub and urlencoded');
$t->{REQUEST} = ( <<EOF
GET /redirect/ HTTP/1.0
Host: remoteip.example.org
EOF
);
tests/lighttpd.conf (working copy)
}
$HTTP["host"] =~ "(vvv).example.org" {
url.redirect = ( "^/redirect/$" => "http://localhost:2048/" )
url.redirect = ( "^/redirect/(.*)?$" => "http://localhost:2048/$$$!1" )
}
$HTTP["host"] =~ "(zzz).example.org" {
url.redirect = ( "^/redirect/$" => "http://localhost:2048/%1" )
$HTTP["host"] =~ "zzz.example.org" {
url.redirect = ( "^/redirect/$" => "http://localhost:2048/" )
$HTTP["referer"] =~ "(.+)" {
url.redirect = ( "^/redirect/$" => "http://localhost:2048/%%%!1" )
}
}
$HTTP["host"] =~ "(remoteip)\.example\.org" {
src/buffer.c (working copy)
map = encoded_chars_hex;
break;
case ENCODING_UNSET:
break;
return buffer_append_string_len(b, s, s_len);
}
assert(map != NULL);
src/plugin.h (working copy)
int config_setup_connection(server *srv, connection *con);
int config_patch_connection(server *srv, connection *con, comp_key_t comp);
int config_check_cond(server *srv, connection *con, data_config *dc);
int config_append_cond_match_buffer(connection *con, data_config *dc, buffer *buf, int n);
int config_append_cond_match_buffer(connection *con, data_config *dc, buffer *buf, int n, buffer_encoding_t encoding);
int config_exec_pcre_keyvalue_buffer(connection *con, pcre_keyvalue_buffer *kvb, data_config *context, buffer *match_buf, buffer *result);
#endif
src/keyvalue.h (working copy)
char *value;
} s_keyvalue;
typedef enum {
PCRE_PIECE_STRING,
PCRE_PIECE_SUB_KEY,
PCRE_PIECE_SUB_KEY_ENCODE,
PCRE_PIECE_SUB_COND,
PCRE_PIECE_SUB_COND_ENCODE
} pcre_piece_type_t;
typedef struct {
pcre_piece_type_t type;
union {
buffer *buf;
size_t num;
} u;
} pcre_piece_t;
typedef struct {
#ifdef HAVE_PCRE_H
pcre *key;
pcre_extra *key_extra;
#endif
buffer *value;
pcre_piece_t *pieces;
size_t pieces_count;
} pcre_keyvalue;
typedef enum { HTTP_AUTH_BASIC, HTTP_AUTH_DIGEST } httpauth_type;
src/keyvalue.c (working copy)
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include "server.h"
#include "keyvalue.h"
#include "buffer.h"
static keyvalue http_versions[] = {
{ HTTP_VERSION_1_1, "HTTP/1.1" },
......
return kvb;
}
static size_t pcre_keyvalue_parse_value(pcre_piece_t *result, buffer *value)
{
size_t start;
size_t i;
size_t count = 0;
size_t pattern_len = value->used - 1;
const char *pattern = value->ptr;
int lastisstring = 0;
#define ADD_PIECE_SUB(_type, _num) \
if (result) { \
result[count].type = _type; \
result[count].u.num = _num; \
} \
count ++; \
lastisstring = 0;
#define ADD_PIECE_STRING(end) \
if ((end) != start) { \
if (lastisstring) { \
if (result) { \
buffer_append_string_len(result[count - 1].u.buf, pattern + start, (end) - start); \
} \
} \
else { \
if (result) { \
result[count].type = PCRE_PIECE_STRING; \
result[count].u.buf = buffer_init(); \
buffer_append_string_len(result[count].u.buf, pattern + start, (end) - start); \
} \
count ++; \
} \
lastisstring = 1; \
}
start = 0;
for (i = 0; i < pattern_len; i++) {
if (pattern[i] == '$' || pattern[i] == '%') {
if (isdigit((unsigned char)pattern[i + 1])) {
size_t num = pattern[i + 1] - '0';
ADD_PIECE_STRING(i);
if (pattern[i] == '$') {
ADD_PIECE_SUB(PCRE_PIECE_SUB_KEY, num);
} else {
ADD_PIECE_SUB(PCRE_PIECE_SUB_COND, num);
}
i++;
start = i + 1;
} else if (pattern[i + 1] == '!' && isdigit((unsigned char)pattern[i + 2])) {
size_t num = pattern[i + 2] - '0';
ADD_PIECE_STRING(i);
if (pattern[i] == '$') {
ADD_PIECE_SUB(PCRE_PIECE_SUB_KEY_ENCODE, num);
} else {
ADD_PIECE_SUB(PCRE_PIECE_SUB_COND_ENCODE, num);
}
i += 2;
start = i + 1;
} else if (pattern[i + 1] == pattern[i]) {
ADD_PIECE_STRING(i);
start = i;
/* add the % or $ */
ADD_PIECE_STRING(i + 1);
i ++;
start = i + 1;
}
}
}
ADD_PIECE_STRING(pattern_len);
#undef ADD_PIECE_STRING
return count;
}
int pcre_keyvalue_buffer_append(pcre_keyvalue_buffer *kvb, const char *key, const char *value) {
#ifdef HAVE_PCRE_H
size_t i;
......
}
kv->value = buffer_init_string(value);
kv->pieces_count = pcre_keyvalue_parse_value(NULL, kv->value);
kv->pieces = calloc(kv->pieces_count, sizeof(*kv->pieces));
pcre_keyvalue_parse_value(kv->pieces, kv->value);
#if 0
fprintf(stderr, "pattern %s is parsed into:\n", kv->value->ptr);
for (i = 0; i < kv->pieces_count; i ++) {
if (kv->pieces[i].type == PCRE_PIECE_STRING) {
fprintf(stderr, "#%d PCRE_PIECE_STRING: %s\n", i, kv->pieces[i].u.buf->ptr);
} else {
const char *type;
switch (kv->pieces[i].type) {
case PCRE_PIECE_STRING: type = "PCRE_PIECE_STRING" ; break;
case PCRE_PIECE_SUB_KEY: type = "PCRE_PIECE_SUB_KEY" ; break;
case PCRE_PIECE_SUB_KEY_ENCODE: type = "PCRE_PIECE_SUB_KEY_ENCODE" ; break;
case PCRE_PIECE_SUB_COND: type = "PCRE_PIECE_SUB_COND" ; break;
case PCRE_PIECE_SUB_COND_ENCODE: type = "PCRE_PIECE_SUB_COND_ENCODE"; break;
default: SEGFAULT();
}
fprintf(stderr, "#%d %s: %d\n", i, type, kv->pieces[i].u.num);
}
}
#endif
kvb->used++;
src/configfile-glue.c (working copy)
#include <string.h>
#include <ctype.h>
#include "base.h"
#include "buffer.h"
......
return (config_check_cond_cached(srv, con, dc) == COND_RESULT_TRUE);
}
int config_append_cond_match_buffer(connection *con, data_config *dc, buffer *buf, int n)
int config_append_cond_match_buffer(connection *con, data_config *dc, buffer *result, int n, buffer_encoding_t encoding)
{
cond_cache_t *cache = &con->cond_cache[dc->context_ndx];
if (n > cache->patterncount) {
......
}
n <<= 1; /* n *= 2 */
buffer_append_string_len(buf,
buffer_append_string_encoded(result,
cache->comp_value->ptr + cache->matches[n],
cache->matches[n + 1] - cache->matches[n]);
cache->matches[n + 1] - cache->matches[n],
encoding);
return 1;
}
......
#ifdef HAVE_PCRE_H
pcre *match;
pcre_extra *extra;
const char *pattern;
size_t pattern_len;
int n;
int n, num;
size_t i;
pcre_keyvalue *kv;
# define N 10
......
match = kv->key;
extra = kv->key_extra;
pattern = kv->value->ptr;
pattern_len = kv->value->used - 1;
if ((n = pcre_exec(match, extra, match_buf->ptr, match_buf->used - 1, 0, 0, ovec, 3 * N)) < 0) {
if (n != PCRE_ERROR_NOMATCH) {
return n;
}
} else {
const char **list;
size_t start, end;
pcre_piece_t *pieces = kv->pieces;
size_t pieces_count = kv->pieces_count;
size_t k;
/* it matched */
pcre_get_substring_list(match_buf->ptr, ovec, n, &list);
/* search for $[0-9] */
buffer_reset(result);
start = 0; end = pattern_len;
for (k = 0; k < pattern_len; k++) {
if ((pattern[k] == '$' || pattern[k] == '%') &&
isdigit((unsigned char)pattern[k + 1])) {
/* got one */
for (k = 0; k < pieces_count; k ++) {
if (pieces[k].type == PCRE_PIECE_STRING) {
buffer_append_string_buffer(result, pieces[k].u.buf);
}
else {
num = pieces[k].u.num;
switch (pieces[k].type) {
case PCRE_PIECE_SUB_KEY:
if (num <= n) {
num <<= 1; /* num *= 2 */
buffer_append_string_len(result, match_buf->ptr + ovec[num], ovec[num + 1] - ovec[num]);
}
break;
size_t num = pattern[k + 1] - '0';
case PCRE_PIECE_SUB_KEY_ENCODE:
if (num <= n) {
num <<= 1; /* num *= 2 */
buffer_append_string_encoded(result, match_buf->ptr + ovec[num], ovec[num + 1] - ovec[num], ENCODING_REL_URI_PART);
}
break;
end = k;
case PCRE_PIECE_SUB_COND:
config_append_cond_match_buffer(con, context, result, num, ENCODING_UNSET);
break;
buffer_append_string_len(result, pattern + start, end - start);
if (pattern[k] == '$') {
/* n is always > 0 */
if (num < (size_t)n) {
buffer_append_string(result, list[num]);
}
} else {
config_append_cond_match_buffer(con, context, result, num);
case PCRE_PIECE_SUB_COND_ENCODE:
config_append_cond_match_buffer(con, context, result, num, ENCODING_REL_URI_PART);
break;
case PCRE_PIECE_STRING:
SEGFAULT();
}
k++;
start = k + 1;
}
}
buffer_append_string_len(result, pattern + start, pattern_len - start);
pcre_free(list);
return i;
}
}
(2-2/2)