Feature #443 » ticket-443.patch
tests/mod-redirect.t (working copy) | ||
---|---|---|
8 | 8 | |
9 | 9 |
use strict; |
10 | 10 |
use IO::Socket; |
11 |
use Test::More tests => 6;
|
|
11 |
use Test::More tests => 8;
|
|
12 | 12 |
use LightyTest; |
13 | 13 | |
14 | 14 |
my $tf = LightyTest->new(); |
... | ... | |
21 | 21 |
Host: vvv.example.org |
22 | 22 |
EOF |
23 | 23 |
); |
24 |
$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 301, 'Location' => 'http://localhost:'.$tf->{PORT}.'/' } ]; |
|
24 |
$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 301, 'Location' => 'http://localhost:'.$tf->{PORT}.'/$' } ];
|
|
25 | 25 |
ok($tf->handle_http($t) == 0, 'external redirect'); |
26 | 26 | |
27 |
$t->{REQUEST} = ( <<EOF |
|
28 |
GET /redirect/vvv/ HTTP/1.0 |
|
29 |
Host: vvv.example.org |
|
30 |
EOF |
|
31 |
); |
|
32 |
$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 301, 'Location' => 'http://localhost:'.$tf->{PORT}.'/$vvv%2f' } ]; |
|
33 |
ok($tf->handle_http($t) == 0, 'external redirect with urlencoded'); |
|
34 | ||
27 | 35 |
$t->{REQUEST} = ( <<EOF |
28 | 36 |
GET /redirect/ HTTP/1.0 |
29 | 37 |
Host: zzz.example.org |
38 |
Referer: zzz |
|
30 | 39 |
EOF |
31 | 40 |
); |
32 |
$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 301, 'Location' => 'http://localhost:'.$tf->{PORT}.'/zzz' } ]; |
|
41 |
$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 301, 'Location' => 'http://localhost:'.$tf->{PORT}.'/%zzz' } ];
|
|
33 | 42 |
ok($tf->handle_http($t) == 0, 'external redirect with cond regsub'); |
34 | 43 | |
35 | 44 |
$t->{REQUEST} = ( <<EOF |
36 | 45 |
GET /redirect/ HTTP/1.0 |
46 |
Host: zzz.example.org |
|
47 |
Referer: zzz/ |
|
48 |
EOF |
|
49 |
); |
|
50 |
$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 301, 'Location' => 'http://localhost:'.$tf->{PORT}.'/%zzz%2f' } ]; |
|
51 |
ok($tf->handle_http($t) == 0, 'external redirect with cond regsub and urlencoded'); |
|
52 | ||
53 |
$t->{REQUEST} = ( <<EOF |
|
54 |
GET /redirect/ HTTP/1.0 |
|
37 | 55 |
Host: remoteip.example.org |
38 | 56 |
EOF |
39 | 57 |
); |
tests/lighttpd.conf (working copy) | ||
---|---|---|
52 | 52 |
} |
53 | 53 | |
54 | 54 |
$HTTP["host"] =~ "(vvv).example.org" { |
55 |
url.redirect = ( "^/redirect/$" => "http://localhost:2048/" )
|
|
55 |
url.redirect = ( "^/redirect/(.*)?$" => "http://localhost:2048/$$$!1" )
|
|
56 | 56 |
} |
57 | 57 | |
58 |
$HTTP["host"] =~ "(zzz).example.org" { |
|
59 |
url.redirect = ( "^/redirect/$" => "http://localhost:2048/%1" ) |
|
58 |
$HTTP["host"] =~ "zzz.example.org" { |
|
59 |
url.redirect = ( "^/redirect/$" => "http://localhost:2048/" ) |
|
60 |
$HTTP["referer"] =~ "(.+)" { |
|
61 |
url.redirect = ( "^/redirect/$" => "http://localhost:2048/%%%!1" ) |
|
62 |
} |
|
60 | 63 |
} |
61 | 64 | |
62 | 65 |
$HTTP["host"] =~ "(remoteip)\.example\.org" { |
src/buffer.c (working copy) | ||
---|---|---|
760 | 760 |
map = encoded_chars_hex; |
761 | 761 |
break; |
762 | 762 |
case ENCODING_UNSET: |
763 |
break;
|
|
763 |
return buffer_append_string_len(b, s, s_len);
|
|
764 | 764 |
} |
765 | 765 | |
766 | 766 |
assert(map != NULL); |
src/plugin.h (working copy) | ||
---|---|---|
93 | 93 |
int config_setup_connection(server *srv, connection *con); |
94 | 94 |
int config_patch_connection(server *srv, connection *con, comp_key_t comp); |
95 | 95 |
int config_check_cond(server *srv, connection *con, data_config *dc); |
96 |
int config_append_cond_match_buffer(connection *con, data_config *dc, buffer *buf, int n); |
|
96 |
int config_append_cond_match_buffer(connection *con, data_config *dc, buffer *buf, int n, buffer_encoding_t encoding);
|
|
97 | 97 |
int config_exec_pcre_keyvalue_buffer(connection *con, pcre_keyvalue_buffer *kvb, data_config *context, buffer *match_buf, buffer *result); |
98 | 98 | |
99 | 99 |
#endif |
src/keyvalue.h (working copy) | ||
---|---|---|
49 | 49 |
char *value; |
50 | 50 |
} s_keyvalue; |
51 | 51 | |
52 |
typedef enum { |
|
53 |
PCRE_PIECE_STRING, |
|
54 |
PCRE_PIECE_SUB_KEY, |
|
55 |
PCRE_PIECE_SUB_KEY_ENCODE, |
|
56 |
PCRE_PIECE_SUB_COND, |
|
57 |
PCRE_PIECE_SUB_COND_ENCODE |
|
58 |
} pcre_piece_type_t; |
|
52 | 59 |
typedef struct { |
60 |
pcre_piece_type_t type; |
|
61 |
union { |
|
62 |
buffer *buf; |
|
63 |
size_t num; |
|
64 |
} u; |
|
65 |
} pcre_piece_t; |
|
66 | ||
67 |
typedef struct { |
|
53 | 68 |
#ifdef HAVE_PCRE_H |
54 | 69 |
pcre *key; |
55 | 70 |
pcre_extra *key_extra; |
56 | 71 |
#endif |
57 | 72 | |
58 | 73 |
buffer *value; |
74 |
pcre_piece_t *pieces; |
|
75 |
size_t pieces_count; |
|
59 | 76 |
} pcre_keyvalue; |
60 | 77 | |
61 | 78 |
typedef enum { HTTP_AUTH_BASIC, HTTP_AUTH_DIGEST } httpauth_type; |
src/keyvalue.c (working copy) | ||
---|---|---|
1 | 1 |
#include <stdlib.h> |
2 | 2 |
#include <string.h> |
3 | 3 |
#include <stdio.h> |
4 |
#include <ctype.h> |
|
4 | 5 | |
5 | 6 |
#include "server.h" |
6 | 7 |
#include "keyvalue.h" |
8 |
#include "buffer.h" |
|
7 | 9 | |
8 | 10 |
static keyvalue http_versions[] = { |
9 | 11 |
{ HTTP_VERSION_1_1, "HTTP/1.1" }, |
... | ... | |
313 | 315 |
return kvb; |
314 | 316 |
} |
315 | 317 | |
318 |
static size_t pcre_keyvalue_parse_value(pcre_piece_t *result, buffer *value) |
|
319 |
{ |
|
320 |
size_t start; |
|
321 |
size_t i; |
|
322 |
size_t count = 0; |
|
323 |
size_t pattern_len = value->used - 1; |
|
324 |
const char *pattern = value->ptr; |
|
325 |
int lastisstring = 0; |
|
326 | ||
327 |
#define ADD_PIECE_SUB(_type, _num) \ |
|
328 |
if (result) { \ |
|
329 |
result[count].type = _type; \ |
|
330 |
result[count].u.num = _num; \ |
|
331 |
} \ |
|
332 |
count ++; \ |
|
333 |
lastisstring = 0; |
|
334 | ||
335 |
#define ADD_PIECE_STRING(end) \ |
|
336 |
if ((end) != start) { \ |
|
337 |
if (lastisstring) { \ |
|
338 |
if (result) { \ |
|
339 |
buffer_append_string_len(result[count - 1].u.buf, pattern + start, (end) - start); \ |
|
340 |
} \ |
|
341 |
} \ |
|
342 |
else { \ |
|
343 |
if (result) { \ |
|
344 |
result[count].type = PCRE_PIECE_STRING; \ |
|
345 |
result[count].u.buf = buffer_init(); \ |
|
346 |
buffer_append_string_len(result[count].u.buf, pattern + start, (end) - start); \ |
|
347 |
} \ |
|
348 |
count ++; \ |
|
349 |
} \ |
|
350 |
lastisstring = 1; \ |
|
351 |
} |
|
352 | ||
353 |
start = 0; |
|
354 | ||
355 |
for (i = 0; i < pattern_len; i++) { |
|
356 |
if (pattern[i] == '$' || pattern[i] == '%') { |
|
357 |
if (isdigit((unsigned char)pattern[i + 1])) { |
|
358 |
size_t num = pattern[i + 1] - '0'; |
|
359 |
ADD_PIECE_STRING(i); |
|
360 | ||
361 |
if (pattern[i] == '$') { |
|
362 |
ADD_PIECE_SUB(PCRE_PIECE_SUB_KEY, num); |
|
363 |
} else { |
|
364 |
ADD_PIECE_SUB(PCRE_PIECE_SUB_COND, num); |
|
365 |
} |
|
366 | ||
367 |
i++; |
|
368 |
start = i + 1; |
|
369 |
} else if (pattern[i + 1] == '!' && isdigit((unsigned char)pattern[i + 2])) { |
|
370 |
size_t num = pattern[i + 2] - '0'; |
|
371 |
ADD_PIECE_STRING(i); |
|
372 | ||
373 |
if (pattern[i] == '$') { |
|
374 |
ADD_PIECE_SUB(PCRE_PIECE_SUB_KEY_ENCODE, num); |
|
375 |
} else { |
|
376 |
ADD_PIECE_SUB(PCRE_PIECE_SUB_COND_ENCODE, num); |
|
377 |
} |
|
378 | ||
379 |
i += 2; |
|
380 |
start = i + 1; |
|
381 |
} else if (pattern[i + 1] == pattern[i]) { |
|
382 |
ADD_PIECE_STRING(i); |
|
383 |
start = i; |
|
384 |
/* add the % or $ */ |
|
385 |
ADD_PIECE_STRING(i + 1); |
|
386 |
i ++; |
|
387 |
start = i + 1; |
|
388 |
} |
|
389 |
} |
|
390 |
} |
|
391 |
ADD_PIECE_STRING(pattern_len); |
|
392 |
#undef ADD_PIECE_STRING |
|
393 | ||
394 |
return count; |
|
395 |
} |
|
396 | ||
316 | 397 |
int pcre_keyvalue_buffer_append(pcre_keyvalue_buffer *kvb, const char *key, const char *value) { |
317 | 398 |
#ifdef HAVE_PCRE_H |
318 | 399 |
size_t i; |
... | ... | |
357 | 438 |
} |
358 | 439 | |
359 | 440 |
kv->value = buffer_init_string(value); |
441 |
kv->pieces_count = pcre_keyvalue_parse_value(NULL, kv->value); |
|
442 |
kv->pieces = calloc(kv->pieces_count, sizeof(*kv->pieces)); |
|
443 |
pcre_keyvalue_parse_value(kv->pieces, kv->value); |
|
444 |
#if 0 |
|
445 |
fprintf(stderr, "pattern %s is parsed into:\n", kv->value->ptr); |
|
446 |
for (i = 0; i < kv->pieces_count; i ++) { |
|
447 |
if (kv->pieces[i].type == PCRE_PIECE_STRING) { |
|
448 |
fprintf(stderr, "#%d PCRE_PIECE_STRING: %s\n", i, kv->pieces[i].u.buf->ptr); |
|
449 |
} else { |
|
450 |
const char *type; |
|
451 |
switch (kv->pieces[i].type) { |
|
452 |
case PCRE_PIECE_STRING: type = "PCRE_PIECE_STRING" ; break; |
|
453 |
case PCRE_PIECE_SUB_KEY: type = "PCRE_PIECE_SUB_KEY" ; break; |
|
454 |
case PCRE_PIECE_SUB_KEY_ENCODE: type = "PCRE_PIECE_SUB_KEY_ENCODE" ; break; |
|
455 |
case PCRE_PIECE_SUB_COND: type = "PCRE_PIECE_SUB_COND" ; break; |
|
456 |
case PCRE_PIECE_SUB_COND_ENCODE: type = "PCRE_PIECE_SUB_COND_ENCODE"; break; |
|
457 |
default: SEGFAULT(); |
|
458 |
} |
|
459 |
fprintf(stderr, "#%d %s: %d\n", i, type, kv->pieces[i].u.num); |
|
460 |
} |
|
461 |
} |
|
462 |
#endif |
|
360 | 463 | |
361 | 464 |
kvb->used++; |
362 | 465 |
src/configfile-glue.c (working copy) | ||
---|---|---|
1 | 1 |
#include <string.h> |
2 |
#include <ctype.h> |
|
3 | 2 | |
4 | 3 |
#include "base.h" |
5 | 4 |
#include "buffer.h" |
... | ... | |
446 | 445 |
return (config_check_cond_cached(srv, con, dc) == COND_RESULT_TRUE); |
447 | 446 |
} |
448 | 447 | |
449 |
int config_append_cond_match_buffer(connection *con, data_config *dc, buffer *buf, int n)
|
|
448 |
int config_append_cond_match_buffer(connection *con, data_config *dc, buffer *result, int n, buffer_encoding_t encoding)
|
|
450 | 449 |
{ |
451 | 450 |
cond_cache_t *cache = &con->cond_cache[dc->context_ndx]; |
452 | 451 |
if (n > cache->patterncount) { |
... | ... | |
454 | 453 |
} |
455 | 454 | |
456 | 455 |
n <<= 1; /* n *= 2 */ |
457 |
buffer_append_string_len(buf,
|
|
456 |
buffer_append_string_encoded(result,
|
|
458 | 457 |
cache->comp_value->ptr + cache->matches[n], |
459 |
cache->matches[n + 1] - cache->matches[n]); |
|
458 |
cache->matches[n + 1] - cache->matches[n], |
|
459 |
encoding); |
|
460 | 460 |
return 1; |
461 | 461 |
} |
462 | 462 | |
... | ... | |
468 | 468 |
#ifdef HAVE_PCRE_H |
469 | 469 |
pcre *match; |
470 | 470 |
pcre_extra *extra; |
471 |
const char *pattern; |
|
472 |
size_t pattern_len; |
|
473 |
int n; |
|
471 |
int n, num; |
|
474 | 472 |
size_t i; |
475 | 473 |
pcre_keyvalue *kv; |
476 | 474 |
# define N 10 |
... | ... | |
481 | 479 | |
482 | 480 |
match = kv->key; |
483 | 481 |
extra = kv->key_extra; |
484 |
pattern = kv->value->ptr; |
|
485 |
pattern_len = kv->value->used - 1; |
|
486 | 482 | |
487 | 483 |
if ((n = pcre_exec(match, extra, match_buf->ptr, match_buf->used - 1, 0, 0, ovec, 3 * N)) < 0) { |
488 | 484 |
if (n != PCRE_ERROR_NOMATCH) { |
489 | 485 |
return n; |
490 | 486 |
} |
491 | 487 |
} else { |
492 |
const char **list;
|
|
493 |
size_t start, end;
|
|
488 |
pcre_piece_t *pieces = kv->pieces;
|
|
489 |
size_t pieces_count = kv->pieces_count;
|
|
494 | 490 |
size_t k; |
495 | 491 | |
496 |
/* it matched */ |
|
497 |
pcre_get_substring_list(match_buf->ptr, ovec, n, &list); |
|
498 | ||
499 | 492 |
/* search for $[0-9] */ |
500 | 493 | |
501 | 494 |
buffer_reset(result); |
502 | 495 | |
503 |
start = 0; end = pattern_len; |
|
504 |
for (k = 0; k < pattern_len; k++) { |
|
505 |
if ((pattern[k] == '$' || pattern[k] == '%') && |
|
506 |
isdigit((unsigned char)pattern[k + 1])) { |
|
507 |
/* got one */ |
|
496 |
for (k = 0; k < pieces_count; k ++) { |
|
497 |
if (pieces[k].type == PCRE_PIECE_STRING) { |
|
498 |
buffer_append_string_buffer(result, pieces[k].u.buf); |
|
499 |
} |
|
500 |
else { |
|
501 |
num = pieces[k].u.num; |
|
502 |
switch (pieces[k].type) { |
|
503 |
case PCRE_PIECE_SUB_KEY: |
|
504 |
if (num <= n) { |
|
505 |
num <<= 1; /* num *= 2 */ |
|
506 |
buffer_append_string_len(result, match_buf->ptr + ovec[num], ovec[num + 1] - ovec[num]); |
|
507 |
} |
|
508 |
break; |
|
508 | 509 | |
509 |
size_t num = pattern[k + 1] - '0'; |
|
510 |
case PCRE_PIECE_SUB_KEY_ENCODE: |
|
511 |
if (num <= n) { |
|
512 |
num <<= 1; /* num *= 2 */ |
|
513 |
buffer_append_string_encoded(result, match_buf->ptr + ovec[num], ovec[num + 1] - ovec[num], ENCODING_REL_URI_PART); |
|
514 |
} |
|
515 |
break; |
|
510 | 516 | |
511 |
end = k; |
|
517 |
case PCRE_PIECE_SUB_COND: |
|
518 |
config_append_cond_match_buffer(con, context, result, num, ENCODING_UNSET); |
|
519 |
break; |
|
512 | 520 | |
513 |
buffer_append_string_len(result, pattern + start, end - start); |
|
514 | ||
515 |
if (pattern[k] == '$') { |
|
516 |
/* n is always > 0 */ |
|
517 |
if (num < (size_t)n) { |
|
518 |
buffer_append_string(result, list[num]); |
|
519 |
} |
|
520 |
} else { |
|
521 |
config_append_cond_match_buffer(con, context, result, num); |
|
521 |
case PCRE_PIECE_SUB_COND_ENCODE: |
|
522 |
config_append_cond_match_buffer(con, context, result, num, ENCODING_REL_URI_PART); |
|
523 |
break; |
|
524 |
case PCRE_PIECE_STRING: |
|
525 |
SEGFAULT(); |
|
522 | 526 |
} |
523 | ||
524 |
k++; |
|
525 |
start = k + 1; |
|
526 | 527 |
} |
527 | 528 |
} |
528 | 529 | |
529 |
buffer_append_string_len(result, pattern + start, pattern_len - start); |
|
530 | ||
531 |
pcre_free(list); |
|
532 | ||
533 | 530 |
return i; |
534 | 531 |
} |
535 | 532 |
} |
- « Previous
- 1
- 2
- Next »