Project

General

Profile

Bug #2578 ยป ifnonematch.patch

patch on lighttpd-1.4.35-2-g3605a3b - argonel, 2014-04-17 23:38

View differences:

src/etag.c
8 8
#endif
9 9

  
10 10
#include <string.h>
11
#include <stdio.h>
11 12

  
12
int etag_is_equal(buffer *etag, const char *matches) {
13
	if (etag && !buffer_is_empty(etag) && 0 == strcmp(etag->ptr, matches)) return 1;
14
	return 0;
13
#define BEGIN tok = etag->ptr; matches = 1; state = TOKEN
14
#define TEST matches = matches && (*tok == *current)
15

  
16
int etag_is_equal(buffer *etag, const char *line, char weak_ok) {
17
    const int MALFORMED_VALUE = 0, ACCEPTED_VALUE = 1;
18
    enum { FOUND_TOKEN = 0, START, TOKEN, MAYBE_WEAK, QUOTING, TAIL } states;
19
    const char *current = line;
20
    const char *tok = etag->ptr;
21

  
22
    if (line[0] == '*' && line[1] == '\0')
23
        return ACCEPTED_VALUE;
24

  
25
    int state = START;
26
    int matches = 0;
27

  
28
    while (*current && state) {
29
        switch (state) {
30
            case START:
31
                switch (*current) {
32
                    case 'W':
33
                        state = MAYBE_WEAK;
34
                        break;
35
                    case '"':
36
                        BEGIN;
37
                        TEST;
38
                        break;
39
                    case ' ':
40
                    case '\t':
41
                        break;
42
                    default:
43
                        return MALFORMED_VALUE;
44
                }
45
            break;
46
            case MAYBE_WEAK:
47
                if (*current == '/') {
48
                    ++current;
49
                    BEGIN;
50
                    matches = matches && weak_ok;
51
                    TEST;
52
                }
53
                else
54
                    return MALFORMED_VALUE;
55
                break;
56
            case QUOTING:
57
                state = TOKEN;
58
                TEST;
59
                break;
60
            case TOKEN:
61
                switch (*current) {
62
                    case '"':
63
                        TEST;
64
                        if (matches)
65
                            state = FOUND_TOKEN;
66
                        else
67
                            state = TAIL;
68
                        break;
69
                    case '\\':
70
                        TEST;
71
                        if (state != QUOTING)
72
                            state = QUOTING;
73
                        else
74
                            state = TOKEN;
75
                        break;
76
                    case '\0':
77
                        break;
78
                    default:
79
                        TEST;
80
                        break;
81
                }
82
                break;
83
            case TAIL:
84
                switch (*current) {
85
                    case ',':
86
                    case ' ':
87
                    case '\t':
88
                        /* skip LWS */
89
                        break;
90
                    default:
91
                        state = START;
92
                        continue;
93
                }
94
                break;
95
            default:
96
                return(0);
97
        }
98

  
99
        ++current;
100
        if (matches) {
101
            if (*tok)
102
                ++tok;
103
            else
104
                matches = 0;
105
        }
106
    }
107

  
108
    return !state; /* FOUND_TOKEN = 0 */
15 109
}
16 110

  
17 111
int etag_create(buffer *etag, struct stat *st,etag_flags_t flags) {
src/etag.h
9 9

  
10 10
typedef enum { ETAG_USE_INODE = 1, ETAG_USE_MTIME = 2, ETAG_USE_SIZE = 4 } etag_flags_t;
11 11

  
12
int etag_is_equal(buffer *etag, const char *matches);
12
int etag_is_equal(buffer *etag, const char *matches, char weak_ok);
13 13
int etag_create(buffer *etag, struct stat *st, etag_flags_t flags);
14 14
int etag_mutate(buffer *mut, buffer *etag);
15 15

  
src/http-header-glue.c
259 259
	 */
260 260

  
261 261
	/* last-modified handling */
262
    char head_or_get = (con->request.http_method == HTTP_METHOD_GET ||
263
                con->request.http_method == HTTP_METHOD_HEAD);
262 264
	if (con->request.http_if_none_match) {
263
		if (etag_is_equal(con->physical.etag, con->request.http_if_none_match)) {
264
			if (con->request.http_method == HTTP_METHOD_GET ||
265
			    con->request.http_method == HTTP_METHOD_HEAD) {
266

  
265
		if (etag_is_equal(con->physical.etag, con->request.http_if_none_match, head_or_get)) {
266
			if (head_or_get) {
267 267
				con->http_status = 304;
268 268
				return HANDLER_FINISHED;
269 269
			} else {
......
272 272
				return HANDLER_FINISHED;
273 273
			}
274 274
		}
275
	} else if (con->request.http_if_modified_since &&
276
	           (con->request.http_method == HTTP_METHOD_GET ||
277
	            con->request.http_method == HTTP_METHOD_HEAD)) {
275
	} else if (con->request.http_if_modified_since && head_or_get) {
278 276
		size_t used_len;
279 277
		char *semicolon;
280 278

  
tests/cachable.t
8 8

  
9 9
use strict;
10 10
use IO::Socket;
11
use Test::More tests => 13;
11
use Test::More tests => 24;
12 12
use LightyTest;
13 13

  
14 14
my $tf = LightyTest->new();
......
117 117
$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
118 118
ok($tf->handle_http($t) == 0, 'Conditional GET - ETag + disabled etags on server side');
119 119

  
120
###############
121

  
122
ok($etag =~ /^\"(.*)\"$/, "The server must quote ETags");
123

  
124
$t->{REQUEST}  = ( <<EOF
125
GET / HTTP/1.0
126
If-None-Match: $1
127
EOF
128
 );
129
$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
130
ok($tf->handle_http($t) == 0, 'The client must send a quoted ETag');
131

  
132
$etag =~ /^(\".*)\"$/;
133
$t->{REQUEST}  = ( <<EOF
134
GET / HTTP/1.0
135
If-None-Match: $1
136
EOF
137
 );
138
$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
139
ok($tf->handle_http($t) == 0, 'The ETag must be surrounded by quotes');
140

  
141
$t->{REQUEST}  = ( <<EOF
142
GET / HTTP/1.0
143
If-None-Match: *
144
EOF
145
 );
146
$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
147
ok($tf->handle_http($t) == 0, 'An unquoted star matches any ETag');
148

  
149
$t->{REQUEST}  = ( <<EOF
150
GET / HTTP/1.0
151
If-None-Match: "*"
152
EOF
153
 );
154
$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
155
ok($tf->handle_http($t) == 0, 'A quoted star is just a regular ETag');
156

  
157
$t->{REQUEST}  = ( <<EOF
158
GET / HTTP/1.0
159
If-None-Match: W/$etag
160
EOF
161
 );
162
$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
163
ok($tf->handle_http($t) == 0, 'A weak etag matches like a regular ETag for HEAD and GET');
164

  
165
$t->{REQUEST}  = ( <<EOF
166
GET / HTTP/1.0
167
If-None-Match: W/"12345"
168
EOF
169
 );
170
$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
171
ok($tf->handle_http($t) == 0, 'However, a weak ETag is not *');
172

  
173
$t->{REQUEST}  = ( <<EOF
174
GET / HTTP/1.0
175
If-None-Match: "12345", $etag
176
EOF
177
 );
178
$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
179
ok($tf->handle_http($t) == 0, 'Client sent a list of ETags, the second matches');
180

  
181
$t->{REQUEST}  = ( <<EOF
182
GET / HTTP/1.0
183
If-None-Match: "12345", W/$etag
184
EOF
185
 );
186
$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
187
ok($tf->handle_http($t) == 0, 'The second provided ETag matches weakly');
188

  
189
$t->{REQUEST}  = ( <<EOF
190
GET / HTTP/1.0
191
If-None-Match: "12345",, ,,  ,  $etag
192
EOF
193
 );
194
$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
195
ok($tf->handle_http($t) == 0, 'Broken client did get around to sending good data');
196

  
197
$t->{REQUEST}  = ( <<EOF
198
GET / HTTP/1.0
199
If-None-Match: "1234", $etag, "brokentrailing
200
EOF
201
 );
202
$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
203
ok($tf->handle_http($t) == 0, 'Bad syntax *after* a matching ETag doesn\'t matter');
204

  
120 205
ok($tf->stop_proc == 0, "Stopping lighttpd");
121 206

  
    (1-1/1)