Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(395)

Side by Side Diff: dart/pkg/http_base/lib/http_base.dart

Issue 445933004: Add implementations for Headers, Request, Response and dart:io/dart:html clients to http_base (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge
Patch Set: Addressed comments Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | dart/pkg/http_base/lib/http_base_html.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 http_base; 5 library http_base;
6 6
7 import 'dart:async'; 7 import 'dart:async';
8 8
9 /// These headers should be ignored by [Client]s when making requests and when
10 /// receiving headers from a HTTP server.
11 const List<String> _TRANSPORT_HEADERS =
12 const ['connection', 'upgrade', 'keep-alive', 'transfer-encoding'];
13
14 /// These headers cannot be folded into one header value via ',' joining.
15 const List<String> _COOKIE_HEADERS = const ['set-cookie', 'cookie'];
16
9 /// Representation of a set of HTTP headers. 17 /// Representation of a set of HTTP headers.
10 abstract class Headers { 18 abstract class Headers {
11 /// Returns the names of all header fields. 19 /// Returns the names of all header fields.
12 Iterable<String> get names; 20 Iterable<String> get names;
13 21
14 /// Returns `true` if a header field of the specified [name] exist. 22 /// Returns `true` if a header field of the specified [name] exist.
15 bool contains(String name); 23 bool contains(String name);
16 24
17 /// Returns the value for the header field named [name]. 25 /// Returns the value for the header field named [name].
18 /// 26 ///
19 /// The HTTP standard supports multiple values for each header field name. 27 /// The HTTP standard supports multiple values for each header field name.
20 /// Header fields with multiple values can be represented as a 28 /// Header fields with multiple values can be represented as a
21 /// comma-separated list. If a header has multiple values the returned string 29 /// comma-separated list. If a header has multiple values the returned string
22 /// is the comma-separated list of all these values. 30 /// is the comma-separated list of all these values.
23 /// 31 ///
24 /// For header field-names which do not allow combining multiple values with 32 /// For header field-names which do not allow combining multiple values with
25 /// comma, this index operator will throw `IllegalArgument`. 33 /// comma, this index operator will throw `ArgumentError`.
26 /// This is currently the case for the 'Cookie' and 'Set-Cookie' headers. Use 34 /// This is currently the case for the 'Cookie' and 'Set-Cookie' headers. Use
27 /// `getMultiple` method to iterate over the header values for these. 35 /// `getMultiple` method to iterate over the header values for these.
28 String operator [](String name); 36 String operator [](String name);
29 37
30 /// Returns the values for the header field named [name]. 38 /// Returns the values for the header field named [name].
31 /// 39 ///
32 /// The order in which the values for the field name appear is the same 40 /// The order in which the values for the field name appear is the same
33 /// as the order in which they are to be send or was received. 41 /// as the order in which they are to be send or was received.
42 ///
43 /// If there are no header values named [name] `null` will be returned.
34 Iterable<String> getMultiple(String name); 44 Iterable<String> getMultiple(String name);
35 } 45 }
36 46
47
37 /// Representation of a HTTP request. 48 /// Representation of a HTTP request.
38 abstract class Request { 49 abstract class Request {
39 /// Request method. 50 /// Request method.
40 String get method; 51 String get method;
41 52
42 /// Request url. 53 /// Request url.
43 Uri get url; 54 Uri get url;
44 55
45 /// Request headers. 56 /// Request headers.
46 Headers get headers; 57 Headers get headers;
47 58
48 /// Request body. 59 /// Request body.
49 Stream<List<int>> read(); 60 Stream<List<int>> read();
50 } 61 }
51 62
63
52 /// Representation of a HTTP response. 64 /// Representation of a HTTP response.
53 abstract class Response { 65 abstract class Response {
54 /// Response status code. 66 /// Response status code.
55 int get statusCode; 67 int get statusCode;
56 68
57 /// Response headers. 69 /// Response headers.
58 Headers get headers; 70 Headers get headers;
59 71
60 /// Response body. 72 /// Response body.
61 Stream<List<int>> read(); 73 Stream<List<int>> read();
62 } 74 }
63 75
76
64 /// Function for performing an HTTP request. 77 /// Function for performing an HTTP request.
65 /// 78 ///
66 /// The [RequestHandler] may use any transport mechanism it wants 79 /// The [RequestHandler] may use any transport mechanism it wants
67 /// (e.g. HTTP/1.1, HTTP/2.0, SPDY) to perform the HTTP request. 80 /// (e.g. HTTP/1.1, HTTP/2.0, SPDY) to perform the HTTP request.
68 /// 81 ///
69 /// [RequestHandler]s are composable. E.g. A [RequestHandler] may add an 82 /// [RequestHandler]s are composable. E.g. A [RequestHandler] may add an
70 /// 'Authorization' header to [request] and forward to another [RequestHandler]. 83 /// 'Authorization' header to [request] and forward to another [RequestHandler].
71 /// 84 ///
72 /// A [RequestHandler] may ignore connection specific headers in [request] and 85 /// A [RequestHandler] may ignore connection specific headers in [request] and
73 /// may not present them in the [Response] object. 86 /// may not present them in the [Response] object.
74 /// 87 ///
75 /// Connection specific headers: 88 /// Connection specific headers:
76 /// 'Connection', 'Upgrade', 'Keep-Alive', 'Transfer-Encoding' 89 /// 'Connection', 'Upgrade', 'Keep-Alive', 'Transfer-Encoding'
77 typedef Future<Response> RequestHandler(Request request); 90 typedef Future<Response> RequestHandler(Request request);
91
92
93 /// An implementation of [Headers].
94 class HeadersImpl implements Headers {
95 static const HeadersImpl Empty = const HeadersImpl.empty();
96
97 final Map<String, List<String>> _m;
98
99 /// Constructs a [HeadersImpl] with no headers.
100 const HeadersImpl.empty() : _m = const {};
101
102 /// Constructs a new [HeaderImpl] initialized with [map].
103 ///
104 /// [map] must contain only String keys and either String or
105 /// Iterable<String> values.
106 HeadersImpl(Map map) : _m = {} {
107 _addDiff(map);
108 }
109
110 /// Makes a copy of this [HeadersImpl] and replaces all headers in present in
111 /// [differenceMap].
112 ///
113 /// [differenceMap] must contain only String keys and either String or
114 /// Iterable<String> values.
115 HeadersImpl replace(Map differenceMap) {
116 var headers = new HeadersImpl({});
117 _m.forEach((String key, List<String> value) {
118 headers._m[key] = value;
119 });
120 headers._addDiff(differenceMap);
121 return headers;
122 }
123
124 void _addDiff(Map diff) {
125 diff.forEach((String key, value) {
126 key = key.toLowerCase();
127
128 if (value == null) {
129 _m.remove(key);
130 } else if (value is String) {
131 var values = new List(1);
132 values[0] = value;
133 _m[key] = values;
134 } else {
135 _m[key] = value.toList();
136 }
137 });
138 }
139
140 Iterable<String> get names => _m.keys;
141
142 bool contains(String name) => _m.containsKey(name.toLowerCase());
143
144 String operator [](String name) {
145 name = name.toLowerCase();
146
147 if (_COOKIE_HEADERS.contains(name)) {
148 throw new ArgumentError('Cannot use Headers[] with $name header.');
149 }
150
151 var values = _m[name];
152 if (values == null) return null;
153 if (values.length == 1) return values.first;
154 return values.join(',');
155 }
156
157 Iterable<String> getMultiple(String name) {
158 name = name.toLowerCase();
159 var values = _m[name];
160 if (values == null) return values;
161
162 if (_COOKIE_HEADERS.contains(name)) {
163 return values;
164 } else {
165 return values.expand((e) => e.split(',')).map((e) => e.trim());
166 }
167 }
168 }
169
170
171 /// Internal helper class to reduce code duplication between [RequestImpl]
172 /// and [ResponseImpl].
173 class _Message {
174 final Headers headers;
175 final Stream<List<int>> _body;
176 bool _bodyRead = false;
177
178 _Message(Headers headers_, body)
179 : headers = headers_ != null ? headers_ : HeadersImpl.Empty,
180 _body = body != null ? body : (new StreamController()..close()).stream;
181
182 /// Returns the [Stream] of bytes of this message.
183 ///
184 /// The body of a message can only be read once.
185 Stream<List<int>> read() {
186 if (_bodyRead) {
187 throw new StateError('The response stream has already been listened to.');
188 }
189 _bodyRead = true;
190 return _body;
191 }
192 }
193
194
195 /// An immutable implementation of [Request].
196 ///
197 /// The request can be modified with the copy-on-write `replace` method.
198 class RequestImpl extends _Message implements Request {
199 final String method;
200 final Uri url;
201
202 RequestImpl(this.method, this.url, {Headers headers, Stream<List<int>> body})
203 : super(headers, body);
204
205 /// Makes a copy of this [RequestImpl] by overriding `method`, `url`,
206 /// `headers` and `body` if they are not null.
207 ///
208 /// In case no [body] was supplied, the current `body` will be used and is
209 /// therefore no longer available to users. This is a transfer of the owner
210 /// of the body stream to the returned object.
211 RequestImpl replace(
212 {String method, Uri url, Headers headers, Stream<List<int>> body}) {
213 if (method == null) method = this.method;
214 if (url == null) url = this.url;
215 if (headers == null) headers = this.headers;
216 if (body == null) body = read();
217
218 return new RequestImpl(method, url, headers: headers, body: body);
219 }
220 }
221
222
223 /// An immutable implementation of [Response].
224 ///
225 /// The response can be modified with the copy-on-write `replace` method.
226 class ResponseImpl extends _Message implements Response {
227 final int statusCode;
228
229 ResponseImpl(this.statusCode, {Headers headers, Stream<List<int>> body})
230 : super(headers, body);
231
232 /// Returns a copy of this [ResponseImpl] by overriding `statusCode`,
233 /// `headers` and `body` if they are not null.
234 ///
235 /// In case no [body] was supplied, the current `body` will be used and is
236 /// therefore no longer available to users. This is a transfer of the owner
237 /// of the body stream to the returned object.
238 ResponseImpl replace(
239 {int statusCode, Headers headers, Stream<List<int>> body}) {
240 if (statusCode == null) statusCode = this.statusCode;
241 if (headers == null) headers = this.headers;
242 if (body == null) body = read();
243
244 return new ResponseImpl(statusCode, headers: headers, body: body);
245 }
246 }
OLDNEW
« no previous file with comments | « no previous file | dart/pkg/http_base/lib/http_base_html.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698