comparison proxy_cache_vary.t @ 471:8816a0edfc7b

Tests: cache Vary tests.
author Maxim Dounin <mdounin@mdounin.ru>
date Fri, 10 Oct 2014 18:58:06 +0400
parents
children 4e335141aa4b
comparison
equal deleted inserted replaced
470:00275fa9091c 471:8816a0edfc7b
1 #!/usr/bin/perl
2
3 # (C) Maxim Dounin
4
5 # Tests for http proxy cache, the Vary header.
6
7 ###############################################################################
8
9 use warnings;
10 use strict;
11
12 use Test::More;
13
14 BEGIN { use FindBin; chdir($FindBin::Bin); }
15
16 use lib 'lib';
17 use Test::Nginx;
18
19 ###############################################################################
20
21 select STDERR; $| = 1;
22 select STDOUT; $| = 1;
23
24 plan(skip_all => 'win32') if $^O eq 'MSWin32';
25
26 my $t = Test::Nginx->new()->has(qw/http proxy cache gzip rewrite/)
27 ->write_file_expand('nginx.conf', <<'EOF');
28
29 %%TEST_GLOBALS%%
30
31 daemon off;
32
33 events {
34 }
35
36 http {
37 %%TEST_GLOBALS_HTTP%%
38
39 proxy_cache_path %%TESTDIR%%/cache keys_zone=one:1m inactive=5s;
40 proxy_cache_key $uri;
41
42 server {
43 listen 127.0.0.1:8080;
44 server_name localhost;
45
46 add_header X-Cache-Status $upstream_cache_status;
47
48 location / {
49 proxy_pass http://127.0.0.1:8081/;
50 proxy_cache one;
51 }
52
53 location /replace/ {
54 proxy_pass http://127.0.0.1:8081/;
55 proxy_cache one;
56 }
57
58 location /revalidate/ {
59 proxy_pass http://127.0.0.1:8081/;
60 proxy_cache one;
61 proxy_cache_revalidate on;
62 }
63
64 location /ignore/ {
65 proxy_pass http://127.0.0.1:8081/;
66 proxy_cache one;
67 proxy_ignore_headers Vary;
68 }
69 }
70
71 server {
72 listen 127.0.0.1:8081;
73 server_name localhost;
74
75 gzip on;
76 gzip_min_length 0;
77 gzip_http_version 1.0;
78 gzip_vary on;
79
80 expires 2s;
81
82 location / {
83 if ($args = "novary") {
84 return 200 "the only variant\n";
85 }
86 }
87
88 location /asterisk {
89 gzip off;
90 add_header Vary "*";
91 }
92
93 location /complex {
94 gzip off;
95 add_header Vary ",, Accept-encoding , ,";
96 }
97 }
98 }
99
100 EOF
101
102 $t->write_file('index.html', 'SEE-THIS');
103 $t->write_file('asterisk', 'SEE-THIS');
104 $t->write_file('complex', 'SEE-THIS');
105
106 $t->try_run('no proxy_ignore_headers Vary')->plan(40);
107
108 ###############################################################################
109
110 local $TODO = 'not yet';
111
112 like(get('/', 'gzip'), qr/MISS/ms, 'first request');
113 like(get('/', 'gzip'), qr/HIT/ms, 'vary match cached');
114 like(get('/', 'deflate'), qr/MISS/ms, 'vary mismatch');
115 like(get('/', 'deflate'), qr/HIT/ms, 'vary mismatch cached');
116 like(get('/', 'foo'), qr/MISS/ms, 'vary mismatch 2');
117 like(get('/', 'foo'), qr/HIT/ms, 'vary mismatch 2 cached');
118 like(get('/', 'gzip'), qr/HIT/ms, 'multiple representations cached');
119
120 SKIP: {
121 skip 'long tests', 6 unless $ENV{TEST_NGINX_UNSAFE};
122
123 # make sure all variants are properly expire
124 # and removed after inactive timeout
125
126 sleep(3);
127
128 like(get('/', 'gzip'), qr/EXPIRED/ms, 'first expired');
129 like(get('/', 'deflate'), qr/EXPIRED/ms, 'second variant expired');
130
131 like(get('/', 'gzip'), qr/HIT/ms, 'first cached after expire');
132 like(get('/', 'deflate'), qr/HIT/ms, 'second cached after expire');
133
134 sleep(12);
135
136 like(get('/', 'gzip'), qr/MISS/ms, 'first inactive removed');
137 like(get('/', 'deflate'), qr/MISS/ms, 'second variant removed');
138
139 }
140
141 SKIP: {
142 skip 'long tests', 6 unless $ENV{TEST_NGINX_UNSAFE};
143
144 # check if the variant which was loaded first will be properly
145 # removed if it's not requested (but another variant is requested
146 # at the same time)
147
148 sleep(3);
149 like(get('/', 'deflate'), qr/EXPIRED/ms, 'bump1');
150 sleep(3);
151 like(get('/', 'deflate'), qr/EXPIRED/ms, 'bump2');
152 sleep(3);
153 like(get('/', 'deflate'), qr/EXPIRED/ms, 'bump3');
154 sleep(3);
155 like(get('/', 'deflate'), qr/EXPIRED/ms, 'bump4');
156
157 TODO: {
158 local $TODO = 'not yet';
159
160 like(head('/', 'gzip'), qr/MISS/ms, 'first not bumped by second requests');
161
162 }
163
164 like(head('/', 'deflate'), qr/HIT/ms, 'second variant cached');
165
166 }
167
168 # if a response without Vary is returned to replace previously returned
169 # responses with Vary, make sure it is then used in all cases
170
171 like(get('/replace/', 'gzip'), qr/MISS/, 'replace first');
172 like(get('/replace/', 'deflate'), qr/MISS/, 'replace second');
173
174 sleep(3);
175
176 like(get('/replace/?novary', 'deflate'), qr/EXPIRED/, 'replace novary');
177 like(get('/replace/?zztest', 'gzip'), qr/HIT/, 'all replaced');
178
179 # make sure revalidation of variants works fine
180
181 like(get('/revalidate/', 'gzip'), qr/MISS/, 'revalidate first');
182 like(get('/revalidate/', 'deflate'), qr/MISS/, 'revalidate second');
183
184 sleep(3);
185
186 like(get('/revalidate/', 'gzip'), qr/REVALIDATED/, 'revalidated first');
187 like(get('/revalidate/', 'deflate'), qr/REVALIDATED/, 'revalidated second');
188 like(get('/revalidate/', 'gzip'), qr/HIT/, 'revalidate first after');
189 like(get('/revalidate/', 'deflate'), qr/HIT/, 'revalidate second after');
190
191 # if the Vary header is ignored, cached version can be returned
192 # regardless of request headers
193
194 like(get('/ignore/', 'gzip'), qr/MISS/ms, 'another request');
195 like(get('/ignore/', 'deflate'), qr/HIT/ms, 'vary ignored');
196
197 # check parsing of Vary with multiple headers listed
198
199 like(get('/complex', 'gzip'), qr/MISS/ms, 'vary complex first');
200 like(get('/complex', 'deflate'), qr/MISS/ms, 'vary complex second');
201 like(get('/complex', 'gzip'), qr/HIT/ms, 'vary complex first cached');
202 like(get('/complex', 'deflate'), qr/HIT/ms, 'vary complex second cached');
203
204 # From RFC 7231, "7.1.4. Vary",
205 # http://tools.ietf.org/html/rfc7231#section-7.1.4:
206 #
207 # A Vary field value of "*" signals that anything about the request
208 # might play a role in selecting the response representation, possibly
209 # including elements outside the message syntax (e.g., the client's
210 # network address). A recipient will not be able to determine whether
211 # this response is appropriate for a later request without forwarding
212 # the request to the origin server.
213 #
214 # In theory, If-None-Match can be used to check if the representation
215 # present in the cache is appropriate. This seems to be only possible
216 # with strong entity tags though, as representation with different
217 # content condings may share the same weak entity tag.
218
219 like(get('/asterisk', 'gzip'), qr/MISS/ms, 'vary asterisk first');
220 like(get('/asterisk', 'gzip'), qr/MISS/ms, 'vary asterisk second');
221
222 # From RFC 7234, "4.1. Calculating Secondary Keys with Vary",
223 # http://tools.ietf.org/html/rfc7234#section-4.1:
224 #
225 # The selecting header fields from two requests are defined to match if
226 # and only if those in the first request can be transformed to those in
227 # the second request by applying any of the following:
228 #
229 # o adding or removing whitespace, where allowed in the header field's
230 # syntax
231 #
232 # o combining multiple header fields with the same field name (see
233 # Section 3.2 of [RFC7230])
234 #
235 # o normalizing both header field values in a way that is known to
236 # have identical semantics, according to the header field's
237 # specification (e.g., reordering field values when order is not
238 # significant; case-normalization, where values are defined to be
239 # case-insensitive)
240 #
241 # No normalization is currently implemented.
242
243 like(get('/', 'foo, bar'), qr/MISS/ms, 'normalize first');
244
245 TODO: {
246 local $TODO = 'not yet';
247
248 like(get('/', 'foo,bar'), qr/HIT/ms, 'normalize whitespace');
249 like(get('/', 'bar,foo'), qr/HIT/ms, 'normalize order');
250
251 }
252
253 ###############################################################################
254
255 sub get {
256 my ($url, $extra) = @_;
257 return http(<<EOF);
258 GET $url HTTP/1.1
259 Host: localhost
260 Connection: close
261 Accept-Encoding: $extra
262
263 EOF
264 }
265
266 ###############################################################################