| Index: pkg/shelf/lib/src/request.dart
|
| diff --git a/pkg/shelf/lib/src/request.dart b/pkg/shelf/lib/src/request.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..731a8ea6b4034fe27a6389b471c4b92322885073
|
| --- /dev/null
|
| +++ b/pkg/shelf/lib/src/request.dart
|
| @@ -0,0 +1,107 @@
|
| +// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
|
| +// for details. All rights reserved. Use of this source code is governed by a
|
| +// BSD-style license that can be found in the LICENSE file.
|
| +
|
| +library shelf.request;
|
| +
|
| +import 'dart:async';
|
| +import 'dart:collection';
|
| +
|
| +import 'package:collection/wrappers.dart';
|
| +import 'package:path/path.dart' as p;
|
| +
|
| +import 'message.dart';
|
| +import 'util.dart';
|
| +
|
| +/// Represents an HTTP request to be processed by a Shelf application.
|
| +class Request extends Message {
|
| + /// The remainder of the [requestedUri] path designating the virtual
|
| + /// "location" of the request's target within the handler.
|
| + ///
|
| + /// [pathInfo] may be an empty string, if [requestedUri ]targets the handler
|
| + /// root and does not have a trailing slash.
|
| + ///
|
| + /// [pathInfo] is never null. If it is not empty, it will start with `/`.
|
| + ///
|
| + /// [scriptName] and [pathInfo] combine to create a valid path that should
|
| + /// correspond to the [requestedUri] path.
|
| + final String pathInfo;
|
| +
|
| + /// The portion of the request URL that follows the "?", if any.
|
| + final String queryString;
|
| +
|
| + /// The HTTP request method, such as "GET" or "POST".
|
| + final String method;
|
| +
|
| + /// The initial portion of the [requestedUri] path that corresponds to the
|
| + /// handler.
|
| + ///
|
| + /// [scriptName] allows a handler to know its virtual "location".
|
| + ///
|
| + /// If the handler corresponds to the "root" of a server, it will be an
|
| + /// empty string, otherwise it will start with a `/`
|
| + ///
|
| + /// [scriptName] and [pathInfo] combine to create a valid path that should
|
| + /// correspond to the [requestedUri] path.
|
| + final String scriptName;
|
| +
|
| + /// The HTTP protocol version used in the request, either "1.0" or "1.1".
|
| + final String protocolVersion;
|
| +
|
| + /// The original [Uri] for the request.
|
| + final Uri requestedUri;
|
| +
|
| + /// If this is non-`null` and the requested resource hasn't been modified
|
| + /// since this date and time, the server should return a 304 Not Modified
|
| + /// response.
|
| + ///
|
| + /// This is parsed from the If-Modified-Since header in [headers]. If
|
| + /// [headers] doesn't have an If-Modified-Since header, this will be `null`.
|
| + DateTime get ifModifiedSince {
|
| + if (_ifModifiedSinceCache != null) return _ifModifiedSinceCache;
|
| + if (!headers.containsKey('if-modified-since')) return null;
|
| + _ifModifiedSinceCache = parseHttpDate(headers['if-modified-since']);
|
| + return _ifModifiedSinceCache;
|
| + }
|
| + DateTime _ifModifiedSinceCache;
|
| +
|
| + Request(this.pathInfo, String queryString, this.method,
|
| + this.scriptName, this.protocolVersion, this.requestedUri,
|
| + Map<String, String> headers, {Stream<List<int>> body})
|
| + : this.queryString = queryString == null ? '' : queryString,
|
| + super(new UnmodifiableMapView(new HashMap.from(headers)),
|
| + body == null ? new Stream.fromIterable([]) : body) {
|
| + if (method.isEmpty) throw new ArgumentError('method cannot be empty.');
|
| +
|
| + if (scriptName.isNotEmpty && !scriptName.startsWith('/')) {
|
| + throw new ArgumentError('scriptName must be empty or start with "/".');
|
| + }
|
| +
|
| + if (scriptName == '/') {
|
| + throw new ArgumentError(
|
| + 'scriptName can never be "/". It should be empty instead.');
|
| + }
|
| +
|
| + if (scriptName.endsWith('/')) {
|
| + throw new ArgumentError('scriptName must not end with "/".');
|
| + }
|
| +
|
| + if (pathInfo.isNotEmpty && !pathInfo.startsWith('/')) {
|
| + throw new ArgumentError('pathInfo must be empty or start with "/".');
|
| + }
|
| +
|
| + if (scriptName.isEmpty && pathInfo.isEmpty) {
|
| + throw new ArgumentError('scriptName and pathInfo cannot both be empty.');
|
| + }
|
| + }
|
| +
|
| + /// Convenience property to access [pathInfo] data as a [List].
|
| + List<String> get pathSegments {
|
| + var segs = p.url.split(pathInfo);
|
| + if (segs.length > 0) {
|
| + assert(segs.first == p.url.separator);
|
| + segs.removeAt(0);
|
| + }
|
| + return segs;
|
| + }
|
| +}
|
|
|