Project

General

Profile

ticket-443.patch

moo, 2006-04-16 11:31

View differences:

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
	}