Mercurial > hg > nginx-tests
comparison http_headers_multi.t @ 1766:a2572de6e840
Tests: tests for various http header variables.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Mon, 30 May 2022 21:32:08 +0300 |
parents | |
children | e44ee916b959 |
comparison
equal
deleted
inserted
replaced
1765:1d7932bc2847 | 1766:a2572de6e840 |
---|---|
1 #!/usr/bin/perl | |
2 | |
3 # (C) Maxim Dounin | |
4 # (C) Nginx, Inc. | |
5 | |
6 # Tests for handling of multiple http headers and access via variables. | |
7 | |
8 ############################################################################### | |
9 | |
10 use warnings; | |
11 use strict; | |
12 | |
13 use Test::More; | |
14 use Socket qw/ CRLF /; | |
15 | |
16 BEGIN { use FindBin; chdir($FindBin::Bin); } | |
17 | |
18 use lib 'lib'; | |
19 use Test::Nginx; | |
20 | |
21 ############################################################################### | |
22 | |
23 select STDERR; $| = 1; | |
24 select STDOUT; $| = 1; | |
25 | |
26 my $t = Test::Nginx->new()->has(qw/http rewrite proxy/)->plan(42); | |
27 | |
28 $t->write_file_expand('nginx.conf', <<'EOF'); | |
29 | |
30 %%TEST_GLOBALS%% | |
31 | |
32 daemon off; | |
33 | |
34 events { | |
35 } | |
36 | |
37 http { | |
38 %%TEST_GLOBALS_HTTP%% | |
39 | |
40 server { | |
41 listen 127.0.0.1:8080; | |
42 server_name localhost; | |
43 | |
44 location / { | |
45 add_header X-Forwarded-For $http_x_forwarded_for; | |
46 add_header X-Cookie $http_cookie; | |
47 add_header X-Foo $http_foo; | |
48 | |
49 add_header X-Cookie-Foo $cookie_foo; | |
50 add_header X-Cookie-Bar $cookie_bar; | |
51 add_header X-Cookie-Bazz $cookie_bazz; | |
52 | |
53 return 204; | |
54 } | |
55 | |
56 location /s { | |
57 add_header Cache-Control foo; | |
58 add_header Cache-Control bar; | |
59 add_header Cache-Control bazz; | |
60 | |
61 add_header Link foo; | |
62 add_header Link bar; | |
63 add_header Link bazz; | |
64 | |
65 add_header Foo foo; | |
66 add_header Foo bar; | |
67 add_header Foo bazz; | |
68 | |
69 add_header X-Sent-CC $sent_http_cache_control; | |
70 add_header X-Sent-Link $sent_http_link; | |
71 add_header X-Sent-Foo $sent_http_foo; | |
72 | |
73 return 204; | |
74 } | |
75 | |
76 location /t { | |
77 add_trailer Foo foo; | |
78 add_trailer Foo bar; | |
79 add_trailer Foo bazz; | |
80 add_trailer X-Sent-Trailer-Foo $sent_trailer_foo; | |
81 | |
82 return 200 ""; | |
83 } | |
84 | |
85 location /v { | |
86 add_header X-Forwarded-For $http_x_forwarded_for; | |
87 add_header X-Cookie $http_cookie; | |
88 | |
89 add_header X-HTTP-Host $http_host; | |
90 add_header X-User-Agent $http_user_agent; | |
91 add_header X-Referer $http_referer; | |
92 add_header X-Via $http_via; | |
93 | |
94 add_header X-Content-Length $content_length; | |
95 add_header X-Content-Type $content_type; | |
96 add_header X-Host $host; | |
97 add_header X-Remote-User $remote_user; | |
98 | |
99 return 204; | |
100 } | |
101 | |
102 location /d { | |
103 return 204; | |
104 } | |
105 | |
106 location /u { | |
107 add_header X-Upstream-Set-Cookie $upstream_http_set_cookie; | |
108 add_header X-Upstream-Bar $upstream_http_bar; | |
109 | |
110 add_header X-Upstream-Cookie-Foo $upstream_cookie_foo; | |
111 add_header X-Upstream-Cookie-Bar $upstream_cookie_bar; | |
112 add_header X-Upstream-Cookie-Bazz $upstream_cookie_bazz; | |
113 | |
114 proxy_pass http://127.0.0.1:8080/backend; | |
115 } | |
116 | |
117 location /backend { | |
118 add_header Set-Cookie foo=1; | |
119 add_header Set-Cookie bar=2; | |
120 add_header Set-Cookie bazz=3; | |
121 add_header Bar foo; | |
122 add_header Bar bar; | |
123 add_header Bar bazz; | |
124 return 204; | |
125 } | |
126 } | |
127 } | |
128 | |
129 EOF | |
130 | |
131 $t->run(); | |
132 | |
133 ############################################################################### | |
134 | |
135 # combining multiple headers: | |
136 # | |
137 # $http_cookie, $http_x_forwarded_for, $sent_http_cache_control, | |
138 # and $sent_http_link with special handling, other headers with | |
139 # general handling | |
140 | |
141 # request headers, $http_* | |
142 | |
143 like(get('/', map { "X-Forwarded-For: $_" } qw/ foo bar bazz /), | |
144 qr/X-Forwarded-For: foo, bar, bazz/, 'multi $http_x_forwarded_for'); | |
145 like(get('/', 'Cookie: foo=1', 'Cookie: bar=2', 'Cookie: bazz=3'), | |
146 qr/X-Cookie: foo=1; bar=2; bazz=3/, 'multi $http_cookie'); | |
147 | |
148 TODO: { | |
149 local $TODO = 'not yet' unless $t->has_version('1.23.0'); | |
150 | |
151 like(get('/', 'Foo: foo', 'Foo: bar', 'Foo: bazz'), | |
152 qr/X-Foo: foo, bar, bazz/, 'multi $http_foo'); | |
153 | |
154 } | |
155 | |
156 # request cookies, $cookie_* | |
157 | |
158 my $r = get('/', 'Cookie: foo=1', 'Cookie: bar=2', 'Cookie: bazz=3'); | |
159 | |
160 like($r, qr/X-Cookie-Foo: 1/, '$cookie_foo'); | |
161 like($r, qr/X-Cookie-Bar: 2/, '$cookie_bar'); | |
162 like($r, qr/X-Cookie-Bazz: 3/, '$cookie_bazz'); | |
163 | |
164 # response headers, $http_* | |
165 | |
166 $r = get('/s'); | |
167 | |
168 like($r, qr/X-Sent-CC: foo, bar, bazz/, 'multi $sent_http_cache_control'); | |
169 like($r, qr/X-Sent-Link: foo, bar, bazz/, 'multi $sent_http_link'); | |
170 | |
171 TODO: { | |
172 local $TODO = 'not yet' unless $t->has_version('1.23.0'); | |
173 | |
174 like($r, qr/X-Sent-Foo: foo, bar, bazz/, 'multi $sent_http_foo'); | |
175 | |
176 } | |
177 | |
178 # upstream response headers, $upstream_http_* | |
179 | |
180 $r = get('/u'); | |
181 | |
182 TODO: { | |
183 local $TODO = 'not yet' unless $t->has_version('1.23.0'); | |
184 | |
185 like($r, qr/X-Upstream-Set-Cookie: foo=1, bar=2, bazz=3/, | |
186 'multi $upstream_http_set_cookie'); | |
187 like($r, qr/X-Upstream-Bar: foo, bar, bazz/, 'multi $upstream_http_bar'); | |
188 | |
189 } | |
190 | |
191 # upstream response cookies, $upstream_cookie_* | |
192 | |
193 like($r, qr/X-Upstream-Cookie-Foo: 1/, '$upstream_cookie_foo'); | |
194 like($r, qr/X-Upstream-Cookie-Bar: 2/, '$upstream_cookie_bar'); | |
195 like($r, qr/X-Upstream-Cookie-Bazz: 3/, '$upstream_cookie_bazz'); | |
196 | |
197 # response trailers, $sent_trailer_* | |
198 | |
199 TODO: { | |
200 local $TODO = 'not yet' unless $t->has_version('1.23.0'); | |
201 | |
202 like(get('/t'), qr/X-Sent-Trailer-Foo: foo, bar, bazz/, | |
203 'multi $sent_trailer_foo'); | |
204 | |
205 } | |
206 | |
207 # various variables for request headers: | |
208 # | |
209 # $http_host, $http_user_agent, $http_referer | |
210 # multiple Host, User-Agent, Referer headers are invalid, but we currently | |
211 # reject only requests with multiple Host headers | |
212 # | |
213 # $http_via, $http_x_forwarded_for, $http_cookie | |
214 # multiple headers are valid | |
215 | |
216 like(get('/v'), qr/X-HTTP-Host: localhost/, '$http_host'); | |
217 like(get('/v', 'Host: foo', 'Host: bar'), | |
218 qr/400 Bad/, 'duplicate host rejected'); | |
219 | |
220 TODO: { | |
221 local $TODO = 'not yet' unless $t->has_version('1.23.0'); | |
222 | |
223 like(get('/v', 'User-Agent: foo', 'User-Agent: bar'), | |
224 qr/X-User-Agent: foo, bar/, 'multi $http_user_agent (invalid)'); | |
225 like(get('/v', 'Referer: foo', 'Referer: bar'), | |
226 qr/X-Referer: foo, bar/, 'multi $http_referer (invalid)'); | |
227 like(get('/v', 'Via: foo', 'Via: bar', 'Via: bazz'), | |
228 qr/X-Via: foo, bar, bazz/, 'multi $http_via'); | |
229 | |
230 } | |
231 | |
232 like(get('/v', 'Cookie: foo', 'Cookie: bar', 'Cookie: bazz'), | |
233 qr/X-Cookie: foo; bar; bazz/, 'multi $http_cookie'); | |
234 like(get('/v', 'X-Forwarded-For: foo', 'X-Forwarded-For: bar', | |
235 'X-Forwarded-For: bazz'), | |
236 qr/X-Forwarded-For: foo, bar, bazz/, 'multi $http_x_forwarded_for'); | |
237 | |
238 # other variables related to request headers: | |
239 # | |
240 # $content_length, $content_type, $host, $remote_user | |
241 | |
242 like(get('/v', 'Content-Length: 0'), | |
243 qr/X-Content-Length: 0/, '$content_length'); | |
244 like(get('/v', 'Content-Length: 0', 'Content-Length: 0'), | |
245 qr/400 Bad/, 'duplicate Content-Length rejected'); | |
246 | |
247 like(get('/v', 'Content-Type: foo'), | |
248 qr/X-Content-Type: foo/, '$content_type'); | |
249 | |
250 TODO: { | |
251 local $TODO = 'not yet' unless $t->has_version('1.23.0'); | |
252 | |
253 like(get('/v', 'Content-Type: foo', 'Content-Type: bar'), | |
254 qr/X-Content-Type: foo, bar/, 'multi $content_type (invalid)'); | |
255 | |
256 } | |
257 | |
258 like(http("GET /v HTTP/1.0" . CRLF . CRLF), | |
259 qr/X-Host: localhost/, '$host from server_name'); | |
260 like(http("GET /v HTTP/1.0" . CRLF . "Host: foo" . CRLF . CRLF), | |
261 qr/X-Host: foo/, '$host'); | |
262 like(http("GET /v HTTP/1.0" . CRLF . "Host: foo" . CRLF . | |
263 "Host: bar" . CRLF . CRLF), | |
264 qr/400 Bad/, 'duplicate host rejected'); | |
265 | |
266 like(get('/v', 'Authorization: Basic dXNlcjpzZWNyZXQ='), | |
267 qr/X-Remote-User: user/, '$remote_user'); | |
268 like(get('/v', 'Authorization: Basic dXNlcjpzZWNyZXQ=', | |
269 'Authorization: Basic dXNlcjpzZWNyZXQ='), | |
270 qr/400 Bad/, 'duplicate authorization rejected'); | |
271 | |
272 # request headers required to be unique: | |
273 # | |
274 # Host, If-Modified-Since, If-Unmodified-Since, If-Match, If-None-Match, | |
275 # Content-Length, Content-Range, If-Range, Transfer-Encoding, Expect, | |
276 # Authorization | |
277 | |
278 like(get('/d', 'Host: foo', 'Host: bar'), | |
279 qr/400 Bad/, 'duplicate Host rejected'); | |
280 like(get('/d', 'If-Modified-Since: foo', 'If-Modified-Since: bar'), | |
281 qr/400 Bad/, 'duplicate If-Modified-Since rejected'); | |
282 like(get('/d', 'If-Unmodified-Since: foo', 'If-Unmodified-Since: bar'), | |
283 qr/400 Bad/, 'duplicate If-Unmodified-Since rejected'); | |
284 like(get('/d', 'If-Match: foo', 'If-Match: bar'), | |
285 qr/400 Bad/, 'duplicate If-Match rejected'); | |
286 like(get('/d', 'If-None-Match: foo', 'If-None-Match: bar'), | |
287 qr/400 Bad/, 'duplicate If-None-Match rejected'); | |
288 like(get('/d', 'Content-Length: 0', 'Content-Length: 0'), | |
289 qr/400 Bad/, 'duplicate Content-Length rejected'); | |
290 like(get('/d', 'Content-Range: foo', 'Content-Range: bar'), | |
291 qr/400 Bad/, 'duplicate Content-Range rejected'); | |
292 like(get('/d', 'If-Range: foo', 'If-Range: bar'), | |
293 qr/400 Bad/, 'duplicate If-Range rejected'); | |
294 like(get('/d', 'Transfer-Encoding: foo', 'Transfer-Encoding: bar'), | |
295 qr/400 Bad/, 'duplicate Transfer-Encoding rejected'); | |
296 like(get('/d', 'Expect: foo', 'Expect: bar'), | |
297 qr/400 Bad/, 'duplicate Expect rejected'); | |
298 like(get('/d', 'Authorization: foo', 'Authorization: bar'), | |
299 qr/400 Bad/, 'duplicate Authorization rejected'); | |
300 | |
301 ############################################################################### | |
302 | |
303 sub get { | |
304 my ($url, @headers) = @_; | |
305 return http( | |
306 "GET $url HTTP/1.1" . CRLF . | |
307 'Host: localhost' . CRLF . | |
308 'Connection: close' . CRLF . | |
309 join(CRLF, @headers) . CRLF . CRLF | |
310 ); | |
311 } | |
312 | |
313 ############################################################################### |