OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library shelf.request_test; | 5 library shelf.request_test; |
6 | 6 |
7 import 'dart:async'; | 7 import 'dart:async'; |
8 | 8 |
9 import 'package:shelf/shelf.dart'; | 9 import 'package:shelf/shelf.dart'; |
10 import 'package:unittest/unittest.dart'; | 10 import 'package:unittest/unittest.dart'; |
11 | 11 |
12 import 'test_util.dart'; | 12 import 'test_util.dart'; |
13 | 13 |
14 Request _request([Map<String, String> headers, Stream<List<int>> body]) { | 14 Request _request([Map<String, String> headers, Stream<List<int>> body]) { |
15 return new Request("GET", LOCALHOST_URI, headers: headers, body: body); | 15 return new Request("GET", LOCALHOST_URI, headers: headers, body: body); |
16 } | 16 } |
17 | 17 |
18 void main() { | 18 void main() { |
19 group('constructor', () { | 19 group('constructor', () { |
20 test('protocolVersion defaults to "1.1"', () { | 20 test('protocolVersion defaults to "1.1"', () { |
21 var request = new Request('GET', LOCALHOST_URI); | 21 var request = new Request('GET', LOCALHOST_URI); |
22 expect(request.protocolVersion, '1.1'); | 22 expect(request.protocolVersion, '1.1'); |
23 }); | 23 }); |
24 | 24 |
25 test('provide non-default protocolVersion', () { | 25 test('provide non-default protocolVersion', () { |
26 var request = new Request('GET', LOCALHOST_URI, protocolVersion: '1.0'); | 26 var request = new Request('GET', LOCALHOST_URI, protocolVersion: '1.0'); |
27 expect(request.protocolVersion, '1.0'); | 27 expect(request.protocolVersion, '1.0'); |
28 }); | 28 }); |
29 | 29 |
30 test('requestedUri must be absolute', () { | 30 group("url", () { |
31 expect(() => new Request('GET', Uri.parse('/path')), | 31 test("defaults to the requestedUri's relativized path and query", () { |
32 throwsArgumentError); | 32 var request = new Request( |
| 33 'GET', Uri.parse("http://localhost/foo/bar?q=1")); |
| 34 expect(request.url, equals(Uri.parse("foo/bar?q=1"))); |
| 35 }); |
| 36 |
| 37 test("is inferred from handlerPath if possible", () { |
| 38 var request = new Request( |
| 39 'GET', Uri.parse("http://localhost/foo/bar?q=1"), |
| 40 handlerPath: '/foo/'); |
| 41 expect(request.url, equals(Uri.parse("bar?q=1"))); |
| 42 }); |
| 43 |
| 44 test("uses the given value if passed", () { |
| 45 var request = new Request( |
| 46 'GET', Uri.parse("http://localhost/foo/bar?q=1"), |
| 47 url: Uri.parse("bar?q=1")); |
| 48 expect(request.url, equals(Uri.parse("bar?q=1"))); |
| 49 }); |
33 }); | 50 }); |
34 | 51 |
35 test('if uri is null, scriptName must be null', () { | 52 group("handlerPath", () { |
36 expect(() => new Request('GET', Uri.parse('/path'), | 53 test("defaults to '/'", () { |
37 scriptName: '/script/name'), throwsArgumentError); | 54 var request = new Request( |
| 55 'GET', Uri.parse("http://localhost/foo/bar")); |
| 56 expect(request.handlerPath, equals('/')); |
| 57 }); |
| 58 |
| 59 test("is inferred from url if possible", () { |
| 60 var request = new Request( |
| 61 'GET', Uri.parse("http://localhost/foo/bar?q=1"), |
| 62 url: Uri.parse("bar?q=1")); |
| 63 expect(request.handlerPath, equals("/foo/")); |
| 64 }); |
| 65 |
| 66 test("uses the given value if passed", () { |
| 67 var request = new Request( |
| 68 'GET', Uri.parse("http://localhost/foo/bar?q=1"), |
| 69 handlerPath: '/foo/'); |
| 70 expect(request.handlerPath, equals("/foo/")); |
| 71 }); |
| 72 |
| 73 test("adds a trailing slash to the given value if necessary", () { |
| 74 var request = new Request( |
| 75 'GET', Uri.parse("http://localhost/foo/bar?q=1"), |
| 76 handlerPath: '/foo'); |
| 77 expect(request.handlerPath, equals("/foo/")); |
| 78 expect(request.url, equals(Uri.parse("bar?q=1"))); |
| 79 }); |
38 }); | 80 }); |
39 | 81 |
40 test('if scriptName is null, uri must be null', () { | 82 group("errors", () { |
41 var relativeUri = new Uri(path: '/cool/beans.html'); | 83 group('requestedUri', () { |
42 expect(() => new Request('GET', Uri.parse('/path'), | 84 test('must be absolute', () { |
43 url: relativeUri), throwsArgumentError); | 85 expect(() => new Request('GET', Uri.parse('/path')), |
44 }); | 86 throwsArgumentError); |
| 87 }); |
45 | 88 |
46 test('uri must be relative', () { | 89 test('may not have a fragment', () { |
47 var relativeUri = Uri.parse('http://localhost/test'); | 90 expect(() { |
| 91 new Request('GET', Uri.parse('http://localhost/#fragment')); |
| 92 }, throwsArgumentError); |
| 93 }); |
| 94 }); |
48 | 95 |
49 expect(() => new Request('GET', LOCALHOST_URI, | 96 group('url', () { |
50 url: relativeUri, scriptName: '/news'), | 97 test('must be relative', () { |
51 throwsArgumentError); | 98 expect(() { |
| 99 new Request('GET', Uri.parse('http://localhost/test'), |
| 100 url: Uri.parse('http://localhost/test')); |
| 101 }, throwsArgumentError); |
| 102 }); |
52 | 103 |
53 // NOTE: explicitly testing fragments due to Issue 18053 | 104 test('may not be root-relative', () { |
54 relativeUri = Uri.parse('http://localhost/test#fragment'); | 105 expect(() { |
| 106 new Request('GET', Uri.parse('http://localhost/test'), |
| 107 url: Uri.parse('/test')); |
| 108 }, throwsArgumentError); |
| 109 }); |
55 | 110 |
56 expect(() => new Request('GET', LOCALHOST_URI, | 111 test('may not have a fragment', () { |
57 url: relativeUri, scriptName: '/news'), | 112 expect(() { |
58 throwsArgumentError); | 113 new Request('GET', Uri.parse('http://localhost/test'), |
59 }); | 114 url: Uri.parse('test#fragment')); |
| 115 }, throwsArgumentError); |
| 116 }); |
60 | 117 |
61 test('uri and scriptName', () { | 118 test('must be a suffix of requestedUri', () { |
62 var pathInfo = '/pages/page.html?utm_source=ABC123'; | 119 expect(() { |
63 var scriptName = '/assets/static'; | 120 new Request('GET', Uri.parse('http://localhost/dir/test'), |
64 var fullUrl = 'http://localhost/other_path/other_resource.asp'; | 121 url: Uri.parse('dir')); |
65 var request = new Request('GET', Uri.parse(fullUrl), | 122 }, throwsArgumentError); |
66 url: Uri.parse(pathInfo), scriptName: scriptName); | 123 }); |
67 | 124 |
68 expect(request.scriptName, scriptName); | 125 test('must have the same query parameters as requestedUri', () { |
69 expect(request.url.path, '/pages/page.html'); | 126 expect(() { |
70 expect(request.url.query, 'utm_source=ABC123'); | 127 new Request( |
71 }); | 128 'GET', |
| 129 Uri.parse('http://localhost/test?q=1&r=2'), |
| 130 url: Uri.parse('test?q=2&r=1')); |
| 131 }, throwsArgumentError); |
72 | 132 |
73 test('minimal uri', () { | 133 // Order matters for query parameters. |
74 var pathInfo = '/'; | 134 expect(() { |
75 var scriptName = '/assets/static'; | 135 new Request('GET', Uri.parse('http://localhost/test?q=1&r=2'), |
76 var fullUrl = 'http://localhost$scriptName$pathInfo'; | 136 url: Uri.parse('test?r=2&q=1')); |
77 var request = new Request('GET', Uri.parse(fullUrl), | 137 }, throwsArgumentError); |
78 url: Uri.parse(pathInfo), scriptName: scriptName); | 138 }); |
| 139 }); |
79 | 140 |
80 expect(request.scriptName, scriptName); | 141 group('handlerPath', () { |
81 expect(request.url.path, '/'); | 142 test('must be a prefix of requestedUri', () { |
82 expect(request.url.query, ''); | 143 expect(() { |
83 }); | 144 new Request('GET', Uri.parse('http://localhost/dir/test'), |
| 145 handlerPath: '/test'); |
| 146 }, throwsArgumentError); |
| 147 }); |
84 | 148 |
85 test('invalid url', () { | 149 test('must start with "/"', () { |
86 var testUrl = 'page'; | 150 expect(() { |
87 var scriptName = '/assets/static'; | 151 new Request('GET', Uri.parse('http://localhost/test'), |
88 var fullUrl = 'http://localhost$scriptName$testUrl'; | 152 handlerPath: 'test'); |
| 153 }, throwsArgumentError); |
| 154 }); |
| 155 }); |
89 | 156 |
90 expect(() => new Request('GET', Uri.parse(fullUrl), | 157 group('handlerPath + url must', () { |
91 url: Uri.parse(testUrl), scriptName: scriptName), | 158 test('be requestedUrl path', () { |
92 throwsArgumentError); | 159 expect(() { |
93 }); | 160 new Request('GET', Uri.parse('http://localhost/foo/bar/baz'), |
| 161 handlerPath: '/foo/', |
| 162 url: Uri.parse('baz')); |
| 163 }, throwsArgumentError); |
| 164 }); |
94 | 165 |
95 test('scriptName with no leading slash', () { | 166 test('be on a path boundary', () { |
96 var pathInfo = '/page'; | 167 expect(() { |
97 var scriptName = 'assets/static'; | 168 new Request('GET', Uri.parse('http://localhost/foo/bar/baz'), |
98 var fullUrl = 'http://localhost/assets/static/pages'; | 169 handlerPath: '/foo/ba', |
99 | 170 url: Uri.parse('r/baz')); |
100 expect(() => new Request('GET',Uri.parse(fullUrl), | 171 }, throwsArgumentError); |
101 url: Uri.parse(pathInfo), scriptName: scriptName), | 172 }); |
102 throwsArgumentError); | 173 }); |
103 | |
104 pathInfo = '/assets/static/page'; | |
105 scriptName = '/'; | |
106 fullUrl = 'http://localhost/assets/static/pages'; | |
107 | |
108 expect(() => new Request('GET',Uri.parse(fullUrl), | |
109 url: Uri.parse(pathInfo), scriptName: scriptName), | |
110 throwsArgumentError); | |
111 }); | |
112 | |
113 test('scriptName that is only a slash', () { | |
114 var pathInfo = '/assets/static/page'; | |
115 var scriptName = '/'; | |
116 var fullUrl = 'http://localhost/assets/static/pages'; | |
117 | |
118 expect(() => new Request('GET',Uri.parse(fullUrl), | |
119 url: Uri.parse(pathInfo), scriptName: scriptName), | |
120 throwsArgumentError); | |
121 }); | 174 }); |
122 }); | 175 }); |
123 | 176 |
124 group("ifModifiedSince", () { | 177 group("ifModifiedSince", () { |
125 test("is null without an If-Modified-Since header", () { | 178 test("is null without an If-Modified-Since header", () { |
126 var request = _request(); | 179 var request = _request(); |
127 expect(request.ifModifiedSince, isNull); | 180 expect(request.ifModifiedSince, isNull); |
128 }); | 181 }); |
129 | 182 |
130 test("comes from the Last-Modified header", () { | 183 test("comes from the Last-Modified header", () { |
131 var request = _request({ | 184 var request = _request({ |
132 'if-modified-since': 'Sun, 06 Nov 1994 08:49:37 GMT' | 185 'if-modified-since': 'Sun, 06 Nov 1994 08:49:37 GMT' |
133 }); | 186 }); |
134 expect(request.ifModifiedSince, | 187 expect(request.ifModifiedSince, |
135 equals(DateTime.parse("1994-11-06 08:49:37z"))); | 188 equals(DateTime.parse("1994-11-06 08:49:37z"))); |
136 }); | 189 }); |
137 }); | 190 }); |
138 | 191 |
139 group('change', () { | 192 group('change', () { |
140 test('with no arguments returns instance with equal values', () { | 193 test('with no arguments returns instance with equal values', () { |
141 var controller = new StreamController(); | 194 var controller = new StreamController(); |
142 | 195 |
143 var uri = Uri.parse('https://test.example.com/static/file.html'); | 196 var uri = Uri.parse('https://test.example.com/static/file.html'); |
144 | 197 |
145 var request = new Request('GET', uri, | 198 var request = new Request('GET', uri, |
146 protocolVersion: '2.0', | 199 protocolVersion: '2.0', |
147 headers: {'header1': 'header value 1'}, | 200 headers: {'header1': 'header value 1'}, |
148 url: Uri.parse('/file.html'), | 201 url: Uri.parse('file.html'), |
149 scriptName: '/static', | 202 handlerPath: '/static/', |
150 body: controller.stream, | 203 body: controller.stream, |
151 context: {'context1': 'context value 1'}); | 204 context: {'context1': 'context value 1'}); |
152 | 205 |
153 var copy = request.change(); | 206 var copy = request.change(); |
154 | 207 |
155 expect(copy.method, request.method); | 208 expect(copy.method, request.method); |
156 expect(copy.requestedUri, request.requestedUri); | 209 expect(copy.requestedUri, request.requestedUri); |
157 expect(copy.protocolVersion, request.protocolVersion); | 210 expect(copy.protocolVersion, request.protocolVersion); |
158 expect(copy.headers, same(request.headers)); | 211 expect(copy.headers, same(request.headers)); |
159 expect(copy.url, request.url); | 212 expect(copy.url, request.url); |
160 expect(copy.scriptName, request.scriptName); | 213 expect(copy.handlerPath, request.handlerPath); |
161 expect(copy.context, same(request.context)); | 214 expect(copy.context, same(request.context)); |
162 expect(copy.readAsString(), completion('hello, world')); | 215 expect(copy.readAsString(), completion('hello, world')); |
163 | 216 |
164 controller.add(HELLO_BYTES); | 217 controller.add(HELLO_BYTES); |
165 return new Future(() { | 218 return new Future(() { |
166 controller | 219 controller |
167 ..add(WORLD_BYTES) | 220 ..add(WORLD_BYTES) |
168 ..close(); | 221 ..close(); |
169 }); | 222 }); |
170 }); | 223 }); |
171 | 224 |
172 group('with just scriptName', () { | 225 group('with path', () { |
173 test('updates url if scriptName matches existing url', () { | 226 test('updates handlerPath and url', () { |
174 var uri = Uri.parse('https://test.example.com/static/file.html'); | 227 var uri = Uri.parse('https://test.example.com/static/dir/file.html'); |
175 var request = new Request('GET', uri); | 228 var request = new Request('GET', uri, |
176 var copy = request.change(scriptName: '/static'); | 229 handlerPath: '/static/', url: Uri.parse('dir/file.html')); |
| 230 var copy = request.change(path: 'dir'); |
177 | 231 |
178 expect(copy.scriptName, '/static'); | 232 expect(copy.handlerPath, '/static/dir/'); |
179 expect(copy.url, Uri.parse('/file.html')); | 233 expect(copy.url, Uri.parse('file.html')); |
180 }); | 234 }); |
181 | 235 |
182 test('throws if striptName does not match existing url', () { | 236 test('allows a trailing slash', () { |
183 var uri = Uri.parse('https://test.example.com/static/file.html'); | 237 var uri = Uri.parse('https://test.example.com/static/dir/file.html'); |
184 var request = new Request('GET', uri); | 238 var request = new Request('GET', uri, |
| 239 handlerPath: '/static/', url: Uri.parse('dir/file.html')); |
| 240 var copy = request.change(path: 'dir/'); |
185 | 241 |
186 expect(() => request.change(scriptName: '/nope'), throwsArgumentError); | 242 expect(copy.handlerPath, '/static/dir/'); |
| 243 expect(copy.url, Uri.parse('file.html')); |
187 }); | 244 }); |
188 }); | |
189 | 245 |
190 test('url', () { | 246 test('throws if path does not match existing uri', () { |
191 var uri = Uri.parse('https://test.example.com/static/file.html'); | 247 var uri = Uri.parse('https://test.example.com/static/dir/file.html'); |
192 var request = new Request('GET', uri); | 248 var request = new Request('GET', uri, |
193 var copy = request.change(url: Uri.parse('/other_path/file.html')); | 249 handlerPath: '/static/', url: Uri.parse('dir/file.html')); |
194 | 250 |
195 expect(copy.scriptName, ''); | 251 expect(() => request.change(path: 'wrong'), throwsArgumentError); |
196 expect(copy.url, Uri.parse('/other_path/file.html')); | 252 }); |
197 }); | |
198 | 253 |
199 test('scriptName and url', () { | 254 test("throws if path isn't a path boundary", () { |
200 var uri = Uri.parse('https://test.example.com/static/file.html'); | 255 var uri = Uri.parse('https://test.example.com/static/dir/file.html'); |
201 var request = new Request('GET', uri); | 256 var request = new Request('GET', uri, |
202 var copy = request.change(scriptName: '/dynamic', | 257 handlerPath: '/static/', url: Uri.parse('dir/file.html')); |
203 url: Uri.parse('/other_path/file.html')); | |
204 | 258 |
205 expect(copy.scriptName, '/dynamic'); | 259 expect(() => request.change(path: 'di'), throwsArgumentError); |
206 expect(copy.url, Uri.parse('/other_path/file.html')); | 260 }); |
207 }); | 261 }); |
208 }); | 262 }); |
209 } | 263 } |
OLD | NEW |