OLD | NEW |
(Empty) | |
| 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 |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 library shelf.request; |
| 6 |
| 7 import 'dart:async'; |
| 8 import 'dart:collection'; |
| 9 |
| 10 import 'package:collection/wrappers.dart'; |
| 11 import 'package:path/path.dart' as p; |
| 12 |
| 13 import 'message.dart'; |
| 14 import 'util.dart'; |
| 15 |
| 16 /// Represents an HTTP request to be processed by a Shelf application. |
| 17 class Request extends Message { |
| 18 /// The remainder of the [requestedUri] path designating the virtual |
| 19 /// "location" of the request's target within the handler. |
| 20 /// |
| 21 /// [pathInfo] may be an empty string, if [requestedUri ]targets the handler |
| 22 /// root and does not have a trailing slash. |
| 23 /// |
| 24 /// [pathInfo] is never null. If it is not empty, it will start with `/`. |
| 25 /// |
| 26 /// [scriptName] and [pathInfo] combine to create a valid path that should |
| 27 /// correspond to the [requestedUri] path. |
| 28 final String pathInfo; |
| 29 |
| 30 /// The portion of the request URL that follows the "?", if any. |
| 31 final String queryString; |
| 32 |
| 33 /// The HTTP request method, such as "GET" or "POST". |
| 34 final String method; |
| 35 |
| 36 /// The initial portion of the [requestedUri] path that corresponds to the |
| 37 /// handler. |
| 38 /// |
| 39 /// [scriptName] allows a handler to know its virtual "location". |
| 40 /// |
| 41 /// If the handler corresponds to the "root" of a server, it will be an |
| 42 /// empty string, otherwise it will start with a `/` |
| 43 /// |
| 44 /// [scriptName] and [pathInfo] combine to create a valid path that should |
| 45 /// correspond to the [requestedUri] path. |
| 46 final String scriptName; |
| 47 |
| 48 /// The HTTP protocol version used in the request, either "1.0" or "1.1". |
| 49 final String protocolVersion; |
| 50 |
| 51 /// The original [Uri] for the request. |
| 52 final Uri requestedUri; |
| 53 |
| 54 /// If this is non-`null` and the requested resource hasn't been modified |
| 55 /// since this date and time, the server should return a 304 Not Modified |
| 56 /// response. |
| 57 /// |
| 58 /// This is parsed from the If-Modified-Since header in [headers]. If |
| 59 /// [headers] doesn't have an If-Modified-Since header, this will be `null`. |
| 60 DateTime get ifModifiedSince { |
| 61 if (_ifModifiedSinceCache != null) return _ifModifiedSinceCache; |
| 62 if (!headers.containsKey('if-modified-since')) return null; |
| 63 _ifModifiedSinceCache = parseHttpDate(headers['if-modified-since']); |
| 64 return _ifModifiedSinceCache; |
| 65 } |
| 66 DateTime _ifModifiedSinceCache; |
| 67 |
| 68 Request(this.pathInfo, String queryString, this.method, |
| 69 this.scriptName, this.protocolVersion, this.requestedUri, |
| 70 Map<String, String> headers, {Stream<List<int>> body}) |
| 71 : this.queryString = queryString == null ? '' : queryString, |
| 72 super(new UnmodifiableMapView(new HashMap.from(headers)), |
| 73 body == null ? new Stream.fromIterable([]) : body) { |
| 74 if (method.isEmpty) throw new ArgumentError('method cannot be empty.'); |
| 75 |
| 76 if (scriptName.isNotEmpty && !scriptName.startsWith('/')) { |
| 77 throw new ArgumentError('scriptName must be empty or start with "/".'); |
| 78 } |
| 79 |
| 80 if (scriptName == '/') { |
| 81 throw new ArgumentError( |
| 82 'scriptName can never be "/". It should be empty instead.'); |
| 83 } |
| 84 |
| 85 if (scriptName.endsWith('/')) { |
| 86 throw new ArgumentError('scriptName must not end with "/".'); |
| 87 } |
| 88 |
| 89 if (pathInfo.isNotEmpty && !pathInfo.startsWith('/')) { |
| 90 throw new ArgumentError('pathInfo must be empty or start with "/".'); |
| 91 } |
| 92 |
| 93 if (scriptName.isEmpty && pathInfo.isEmpty) { |
| 94 throw new ArgumentError('scriptName and pathInfo cannot both be empty.'); |
| 95 } |
| 96 } |
| 97 |
| 98 /// Convenience property to access [pathInfo] data as a [List]. |
| 99 List<String> get pathSegments { |
| 100 var segs = p.url.split(pathInfo); |
| 101 if (segs.length > 0) { |
| 102 assert(segs.first == p.url.separator); |
| 103 segs.removeAt(0); |
| 104 } |
| 105 return segs; |
| 106 } |
| 107 } |
OLD | NEW |