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; | 5 library shelf.request; |
6 | 6 |
7 import 'dart:async'; | 7 import 'dart:async'; |
8 | 8 |
9 import 'package:http_parser/http_parser.dart'; | 9 import 'package:http_parser/http_parser.dart'; |
10 | 10 |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
127 this.scriptName = _computeScriptName(requestedUri, url, scriptName), | 127 this.scriptName = _computeScriptName(requestedUri, url, scriptName), |
128 this._onHijack = onHijack == null ? null : new _OnHijack(onHijack), | 128 this._onHijack = onHijack == null ? null : new _OnHijack(onHijack), |
129 super(body == null ? new Stream.fromIterable([]) : body, | 129 super(body == null ? new Stream.fromIterable([]) : body, |
130 headers: headers, context: context) { | 130 headers: headers, context: context) { |
131 if (method.isEmpty) throw new ArgumentError('method cannot be empty.'); | 131 if (method.isEmpty) throw new ArgumentError('method cannot be empty.'); |
132 | 132 |
133 if (!requestedUri.isAbsolute) { | 133 if (!requestedUri.isAbsolute) { |
134 throw new ArgumentError('requstedUri must be an absolute URI.'); | 134 throw new ArgumentError('requstedUri must be an absolute URI.'); |
135 } | 135 } |
136 | 136 |
137 // TODO(kevmoo) if defined, check that scriptName is a fully-encoded, valid | |
138 // path component | |
137 if (this.scriptName.isNotEmpty && !this.scriptName.startsWith('/')) { | 139 if (this.scriptName.isNotEmpty && !this.scriptName.startsWith('/')) { |
138 throw new ArgumentError('scriptName must be empty or start with "/".'); | 140 throw new ArgumentError('scriptName must be empty or start with "/".'); |
139 } | 141 } |
140 | 142 |
141 if (this.scriptName == '/') { | 143 if (this.scriptName == '/') { |
142 throw new ArgumentError( | 144 throw new ArgumentError( |
143 'scriptName can never be "/". It should be empty instead.'); | 145 'scriptName can never be "/". It should be empty instead.'); |
144 } | 146 } |
145 | 147 |
146 if (this.scriptName.endsWith('/')) { | 148 if (this.scriptName.endsWith('/')) { |
(...skipping 14 matching lines...) Expand all Loading... | |
161 /// | 163 /// |
162 /// New key-value pairs in [context] and [headers] will be added to the copied | 164 /// New key-value pairs in [context] and [headers] will be added to the copied |
163 /// [Request]. | 165 /// [Request]. |
164 /// | 166 /// |
165 /// If [context] or [headers] includes a key that already exists, the | 167 /// If [context] or [headers] includes a key that already exists, the |
166 /// key-value pair will replace the corresponding entry in the copied | 168 /// key-value pair will replace the corresponding entry in the copied |
167 /// [Request]. | 169 /// [Request]. |
168 /// | 170 /// |
169 /// All other context and header values from the [Request] will be included | 171 /// All other context and header values from the [Request] will be included |
170 /// in the copied [Request] unchanged. | 172 /// in the copied [Request] unchanged. |
171 Request change({Map<String, String> headers, Map<String, Object> context}) { | 173 /// |
174 /// If [scriptName] is provided without [url], the corresponding path | |
175 /// component of [Request.url] is replaced in the new instance. In this case, | |
176 /// [scriptName] must match the beginning of the existing `path` component of | |
177 /// [Request.url] or an [ArgumentError] is thrown. | |
nweiz
2014/05/22 19:50:42
This paragraph is confusing. I suggest: "If [scrip
kevmoo
2014/05/22 20:38:36
Done.
nweiz
2014/05/23 21:43:34
You didn't include any explanation of the purpose.
| |
178 Request change({Map<String, String> headers, Map<String, Object> context, | |
179 String scriptName, Uri url}) { | |
172 headers = updateMap(this.headers, headers); | 180 headers = updateMap(this.headers, headers); |
173 context = updateMap(this.context, context); | 181 context = updateMap(this.context, context); |
174 | 182 |
183 if (scriptName != null && url == null) { | |
184 var path = this.url.path; | |
185 if (path.startsWith(scriptName)) { | |
186 path = path.substring(scriptName.length); | |
187 url = new Uri(path: path, query: this.url.query); | |
188 } else { | |
189 throw new ArgumentError('If scriptName is provided without url, it must' | |
190 ' match the beginning of the existing url path.'); | |
nweiz
2014/05/22 19:50:42
"match the beginning" -> "be a prefix"
kevmoo
2014/05/22 20:38:36
Done.
| |
191 } | |
192 } | |
193 | |
194 if (url == null) url = this.url; | |
195 | |
nweiz
2014/05/22 19:50:42
Nit: I'd remove this newline.
kevmoo
2014/05/22 20:38:36
Done.
| |
196 if (scriptName == null) scriptName = this.scriptName; | |
197 | |
175 return new Request(this.method, this.requestedUri, | 198 return new Request(this.method, this.requestedUri, |
176 protocolVersion: this.protocolVersion, headers: headers, url: this.url, | 199 protocolVersion: this.protocolVersion, headers: headers, url: url, |
177 scriptName: this.scriptName, body: this.read(), context: context); | 200 scriptName: scriptName, body: this.read(), context: context); |
178 } | 201 } |
179 | 202 |
180 /// Takes control of the underlying request socket. | 203 /// Takes control of the underlying request socket. |
181 /// | 204 /// |
182 /// Synchronously, this throws a [HijackException] that indicates to the | 205 /// Synchronously, this throws a [HijackException] that indicates to the |
183 /// adapter that it shouldn't emit a response itself. Asynchronously, | 206 /// adapter that it shouldn't emit a response itself. Asynchronously, |
184 /// [callback] is called with a [Stream<List<int>>] and | 207 /// [callback] is called with a [Stream<List<int>>] and |
185 /// [StreamSink<List<int>>], respectively, that provide access to the | 208 /// [StreamSink<List<int>>], respectively, that provide access to the |
186 /// underlying request socket. | 209 /// underlying request socket. |
187 /// | 210 /// |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
226 | 249 |
227 /// Computes `url` from the provided [Request] constructor arguments. | 250 /// Computes `url` from the provided [Request] constructor arguments. |
228 /// | 251 /// |
229 /// If [url] and [scriptName] are `null`, infer value from [requestedUrl], | 252 /// If [url] and [scriptName] are `null`, infer value from [requestedUrl], |
230 /// otherwise return [url]. | 253 /// otherwise return [url]. |
231 /// | 254 /// |
232 /// If [url] is provided, but [scriptName] is omitted, throws an | 255 /// If [url] is provided, but [scriptName] is omitted, throws an |
233 /// [ArgumentError]. | 256 /// [ArgumentError]. |
234 Uri _computeUrl(Uri requestedUri, Uri url, String scriptName) { | 257 Uri _computeUrl(Uri requestedUri, Uri url, String scriptName) { |
235 if (url == null && scriptName == null) { | 258 if (url == null && scriptName == null) { |
236 return new Uri(path: requestedUri.path, query: requestedUri.query, | 259 return new Uri(path: requestedUri.path, query: requestedUri.query); |
237 fragment: requestedUri.fragment); | |
238 } | 260 } |
239 | 261 |
240 if (url != null && scriptName != null) { | 262 if (url != null && scriptName != null) { |
241 if (url.scheme.isNotEmpty) throw new ArgumentError('url must be relative.'); | 263 if (url.scheme.isNotEmpty) throw new ArgumentError('url must be relative.'); |
242 return url; | 264 return url; |
243 } | 265 } |
244 | 266 |
245 throw new ArgumentError( | 267 throw new ArgumentError( |
246 'url and scriptName must both be null or both be set.'); | 268 'url and scriptName must both be null or both be set.'); |
247 } | 269 } |
(...skipping 10 matching lines...) Expand all Loading... | |
258 return ''; | 280 return ''; |
259 } | 281 } |
260 | 282 |
261 if (url != null && scriptName != null) { | 283 if (url != null && scriptName != null) { |
262 return scriptName; | 284 return scriptName; |
263 } | 285 } |
264 | 286 |
265 throw new ArgumentError( | 287 throw new ArgumentError( |
266 'url and scriptName must both be null or both be set.'); | 288 'url and scriptName must both be null or both be set.'); |
267 } | 289 } |
OLD | NEW |