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

Side by Side Diff: sdk/lib/io/http_headers.dart

Issue 11316044: Added file missing file from previous commit (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 1 month 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 | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2012, 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 class _HttpHeaders implements HttpHeaders {
6 _HttpHeaders() : _headers = new Map<String, List<String>>();
7
8 List<String> operator[](String name) {
9 name = name.toLowerCase();
10 return _headers[name];
11 }
12
13 String value(String name) {
14 name = name.toLowerCase();
15 List<String> values = _headers[name];
16 if (values == null) return null;
17 if (values.length > 1) {
18 throw new HttpException("More than one value for header $name");
19 }
20 return values[0];
21 }
22
23 void add(String name, Object value) {
24 _checkMutable();
25 if (value is List) {
26 for (int i = 0; i < value.length; i++) {
27 _add(name, value[i]);
28 }
29 } else {
30 _add(name, value);
31 }
32 }
33
34 void set(String name, Object value) {
35 name = name.toLowerCase();
36 _checkMutable();
37 removeAll(name);
38 add(name, value);
39 }
40
41 void remove(String name, Object value) {
42 _checkMutable();
43 name = name.toLowerCase();
44 List<String> values = _headers[name];
45 if (values != null) {
46 int index = values.indexOf(value);
47 if (index != -1) {
48 values.removeRange(index, 1);
49 }
50 }
51 }
52
53 void removeAll(String name) {
54 _checkMutable();
55 name = name.toLowerCase();
56 _headers.remove(name);
57 }
58
59 void forEach(void f(String name, List<String> values)) {
60 _headers.forEach(f);
61 }
62
63 void noFolding(String name) {
64 if (_noFoldingHeaders == null) _noFoldingHeaders = new List<String>();
65 _noFoldingHeaders.add(name);
66 }
67
68 String get host => _host;
69
70 void set host(String host) {
71 _checkMutable();
72 _host = host;
73 _updateHostHeader();
74 }
75
76 int get port => _port;
77
78 void set port(int port) {
79 _checkMutable();
80 _port = port;
81 _updateHostHeader();
82 }
83
84 Date get ifModifiedSince {
85 List<String> values = _headers["if-modified-since"];
86 if (values != null) {
87 try {
88 return _HttpUtils.parseDate(values[0]);
89 } on Exception catch (e) {
90 return null;
91 }
92 }
93 return null;
94 }
95
96 void set ifModifiedSince(Date ifModifiedSince) {
97 _checkMutable();
98 // Format "ifModifiedSince" header with date in Greenwich Mean Time (GMT).
99 String formatted = _HttpUtils.formatDate(ifModifiedSince.toUtc());
100 _set("if-modified-since", formatted);
101 }
102
103 Date get date {
104 List<String> values = _headers["date"];
105 if (values != null) {
106 try {
107 return _HttpUtils.parseDate(values[0]);
108 } on Exception catch (e) {
109 return null;
110 }
111 }
112 return null;
113 }
114
115 void set date(Date date) {
116 _checkMutable();
117 // Format "Date" header with date in Greenwich Mean Time (GMT).
118 String formatted = _HttpUtils.formatDate(date.toUtc());
119 _set("date", formatted);
120 }
121
122 Date get expires {
123 List<String> values = _headers["expires"];
124 if (values != null) {
125 try {
126 return _HttpUtils.parseDate(values[0]);
127 } on Exception catch (e) {
128 return null;
129 }
130 }
131 return null;
132 }
133
134 void set expires(Date expires) {
135 _checkMutable();
136 // Format "Expires" header with date in Greenwich Mean Time (GMT).
137 String formatted = _HttpUtils.formatDate(expires.toUtc());
138 _set("expires", formatted);
139 }
140
141 ContentType get contentType {
142 var values = _headers["content-type"];
143 if (values != null) {
144 return new ContentType.fromString(values[0]);
145 } else {
146 return new ContentType();
147 }
148 }
149
150 void set contentType(ContentType contentType) {
151 _checkMutable();
152 _set("content-type", contentType.toString());
153 }
154
155 void _add(String name, Object value) {
156 var lowerCaseName = name.toLowerCase();
157 // TODO(sgjesse): Add immutable state throw HttpException is immutable.
158 if (lowerCaseName == "date") {
159 if (value is Date) {
160 date = value;
161 } else if (value is String) {
162 _set("date", value);
163 } else {
164 throw new HttpException("Unexpected type for header named $name");
165 }
166 } else if (lowerCaseName == "expires") {
167 if (value is Date) {
168 expires = value;
169 } else if (value is String) {
170 _set("expires", value);
171 } else {
172 throw new HttpException("Unexpected type for header named $name");
173 }
174 } else if (lowerCaseName == "if-modified-since") {
175 if (value is Date) {
176 ifModifiedSince = value;
177 } else if (value is String) {
178 _set("if-modified-since", value);
179 } else {
180 throw new HttpException("Unexpected type for header named $name");
181 }
182 } else if (lowerCaseName == "host") {
183 int pos = value.indexOf(":");
184 if (pos == -1) {
185 _host = value;
186 _port = HttpClient.DEFAULT_HTTP_PORT;
187 } else {
188 if (pos > 0) {
189 _host = value.substring(0, pos);
190 } else {
191 _host = null;
192 }
193 if (pos + 1 == value.length) {
194 _port = HttpClient.DEFAULT_HTTP_PORT;
195 } else {
196 try {
197 _port = parseInt(value.substring(pos + 1));
198 } on FormatException catch (e) {
199 _port = null;
200 }
201 }
202 }
203 _set("host", value);
204 } else if (lowerCaseName == "content-type") {
205 _set("content-type", value);
206 } else {
207 name = lowerCaseName;
208 List<String> values = _headers[name];
209 if (values == null) {
210 values = new List<String>();
211 _headers[name] = values;
212 }
213 if (value is Date) {
214 values.add(_HttpUtils.formatDate(value));
215 } else {
216 values.add(value.toString());
217 }
218 }
219 }
220
221 void _set(String name, String value) {
222 name = name.toLowerCase();
223 List<String> values = new List<String>();
224 _headers[name] = values;
225 values.add(value);
226 }
227
228 _checkMutable() {
229 if (!_mutable) throw new HttpException("HTTP headers are not mutable");
230 }
231
232 _updateHostHeader() {
233 bool defaultPort = _port == null || _port == HttpClient.DEFAULT_HTTP_PORT;
234 String portPart = defaultPort ? "" : ":$_port";
235 _set("host", "$host$portPart");
236 }
237
238 _foldHeader(String name) {
239 if (name == "set-cookie" ||
240 (_noFoldingHeaders != null &&
241 _noFoldingHeaders.indexOf(name) != -1)) {
242 return false;
243 }
244 return true;
245 }
246
247 _write(_HttpConnectionBase connection) {
248 final COLONSP = const [_CharCode.COLON, _CharCode.SP];
249 final COMMASP = const [_CharCode.COMMA, _CharCode.SP];
250 final CRLF = const [_CharCode.CR, _CharCode.LF];
251
252 var bufferSize = 16 * 1024;
253 var buffer = new Uint8List(bufferSize);
254 var bufferPos = 0;
255
256 void writeBuffer() {
257 connection._writeFrom(buffer, 0, bufferPos);
258 bufferPos = 0;
259 }
260
261 // Format headers.
262 _headers.forEach((String name, List<String> values) {
263 bool fold = _foldHeader(name);
264 List<int> nameData;
265 nameData = name.charCodes;
266 int nameDataLen = nameData.length;
267 if (nameDataLen + 2 > bufferSize - bufferPos) writeBuffer();
268 buffer.setRange(bufferPos, nameDataLen, nameData);
269 bufferPos += nameDataLen;
270 buffer[bufferPos++] = _CharCode.COLON;
271 buffer[bufferPos++] = _CharCode.SP;
272 for (int i = 0; i < values.length; i++) {
273 List<int> data = values[i].charCodes;
274 int dataLen = data.length;
275 // Worst case here is writing the name, value and 6 additional bytes.
276 if (nameDataLen + dataLen + 6 > bufferSize - bufferPos) writeBuffer();
277 if (i > 0) {
278 if (fold) {
279 buffer[bufferPos++] = _CharCode.COMMA;
280 buffer[bufferPos++] = _CharCode.SP;
281 } else {
282 buffer[bufferPos++] = _CharCode.CR;
283 buffer[bufferPos++] = _CharCode.LF;
284 buffer.setRange(bufferPos, nameDataLen, nameData);
285 bufferPos += nameDataLen;
286 buffer[bufferPos++] = _CharCode.COLON;
287 buffer[bufferPos++] = _CharCode.SP;
288 }
289 }
290 buffer.setRange(bufferPos, dataLen, data);
291 bufferPos += dataLen;
292 }
293 buffer[bufferPos++] = _CharCode.CR;
294 buffer[bufferPos++] = _CharCode.LF;
295 });
296 writeBuffer();
297 }
298
299 String toString() {
300 StringBuffer sb = new StringBuffer();
301 _headers.forEach((String name, List<String> values) {
302 sb.add(name);
303 sb.add(": ");
304 bool fold = _foldHeader(name);
305 for (int i = 0; i < values.length; i++) {
306 if (i > 0) {
307 if (fold) {
308 sb.add(", ");
309 } else {
310 sb.add("\n");
311 sb.add(name);
312 sb.add(": ");
313 }
314 }
315 sb.add(values[i]);
316 }
317 sb.add("\n");
318 });
319 return sb.toString();
320 }
321
322 bool _mutable = true; // Are the headers currently mutable?
323 Map<String, List<String>> _headers;
324 List<String> _noFoldingHeaders;
325
326 String _host;
327 int _port;
328 }
329
330
331 class _HeaderValue implements HeaderValue {
332 _HeaderValue([String this.value = ""]);
333
334 _HeaderValue.fromString(String value, {this.parameterSeparator: ";"}) {
335 // Parse the string.
336 _parse(value);
337 }
338
339 Map<String, String> get parameters {
340 if (_parameters == null) _parameters = new Map<String, String>();
341 return _parameters;
342 }
343
344 String toString() {
345 StringBuffer sb = new StringBuffer();
346 sb.add(value);
347 if (parameters != null && parameters.length > 0) {
348 _parameters.forEach((String name, String value) {
349 sb.add("; ");
350 sb.add(name);
351 sb.add("=");
352 sb.add(value);
353 });
354 }
355 return sb.toString();
356 }
357
358 void _parse(String s) {
359 int index = 0;
360
361 bool done() => index == s.length;
362
363 void skipWS() {
364 while (!done()) {
365 if (s[index] != " " && s[index] != "\t") return;
366 index++;
367 }
368 }
369
370 String parseValue() {
371 int start = index;
372 while (!done()) {
373 if (s[index] == " " ||
374 s[index] == "\t" ||
375 s[index] == parameterSeparator) break;
376 index++;
377 }
378 return s.substring(start, index).toLowerCase();
379 }
380
381 void expect(String expected) {
382 if (done() || s[index] != expected) {
383 throw new HttpException("Failed to parse header value");
384 }
385 index++;
386 }
387
388 void maybeExpect(String expected) {
389 if (s[index] == expected) index++;
390 }
391
392 void parseParameters() {
393 _parameters = new Map<String, String>();
394
395 String parseParameterName() {
396 int start = index;
397 while (!done()) {
398 if (s[index] == " " || s[index] == "\t" || s[index] == "=") break;
399 index++;
400 }
401 return s.substring(start, index).toLowerCase();
402 }
403
404 String parseParameterValue() {
405 if (s[index] == "\"") {
406 // Parse quoted value.
407 StringBuffer sb = new StringBuffer();
408 index++;
409 while (!done()) {
410 if (s[index] == "\\") {
411 if (index + 1 == s.length) {
412 throw new HttpException("Failed to parse header value");
413 }
414 index++;
415 } else if (s[index] == "\"") {
416 index++;
417 break;
418 }
419 sb.add(s[index]);
420 index++;
421 }
422 return sb.toString();
423 } else {
424 // Parse non-quoted value.
425 return parseValue();
426 }
427 }
428
429 while (!done()) {
430 skipWS();
431 if (done()) return;
432 String name = parseParameterName();
433 skipWS();
434 expect("=");
435 skipWS();
436 String value = parseParameterValue();
437 _parameters[name] = value;
438 skipWS();
439 if (done()) return;
440 expect(parameterSeparator);
441 }
442 }
443
444 skipWS();
445 value = parseValue();
446 skipWS();
447 if (done()) return;
448 maybeExpect(parameterSeparator);
449 parseParameters();
450 }
451
452 String value;
453 String parameterSeparator;
454 Map<String, String> _parameters;
455 }
456
457
458 class _ContentType extends _HeaderValue implements ContentType {
459 _ContentType(String primaryType, String subType)
460 : _primaryType = primaryType, _subType = subType, super("");
461
462 _ContentType.fromString(String value) : super.fromString(value);
463
464 String get value => "$_primaryType/$_subType";
465
466 void set value(String s) {
467 int index = s.indexOf("/");
468 if (index == -1 || index == (s.length - 1)) {
469 primaryType = s.trim().toLowerCase();
470 subType = "";
471 } else {
472 primaryType = s.substring(0, index).trim().toLowerCase();
473 subType = s.substring(index + 1).trim().toLowerCase();
474 }
475 }
476
477 String get primaryType => _primaryType;
478
479 void set primaryType(String s) {
480 _primaryType = s;
481 }
482
483 String get subType => _subType;
484
485 void set subType(String s) {
486 _subType = s;
487 }
488
489 String get charset => parameters["charset"];
490
491 void set charset(String s) {
492 parameters["charset"] = s;
493 }
494
495 String _primaryType = "";
496 String _subType = "";
497 }
498
499
500 class _Cookie implements Cookie {
501 _Cookie([String this.name, String this.value]);
502
503 _Cookie.fromSetCookieValue(String value) {
504 // Parse the Set-Cookie header value.
505 _parseSetCookieValue(value);
506 }
507
508 // Parse a Set-Cookie header value according to the rules in RFC 6265.
509 void _parseSetCookieValue(String s) {
510 int index = 0;
511
512 bool done() => index == s.length;
513
514 String parseName() {
515 int start = index;
516 while (!done()) {
517 if (s[index] == "=") break;
518 index++;
519 }
520 return s.substring(start, index).trim().toLowerCase();
521 }
522
523 String parseValue() {
524 int start = index;
525 while (!done()) {
526 if (s[index] == ";") break;
527 index++;
528 }
529 return s.substring(start, index).trim().toLowerCase();
530 }
531
532 void expect(String expected) {
533 if (done()) throw new HttpException("Failed to parse header value [$s]");
534 if (s[index] != expected) {
535 throw new HttpException("Failed to parse header value [$s]");
536 }
537 index++;
538 }
539
540 void parseAttributes() {
541 String parseAttributeName() {
542 int start = index;
543 while (!done()) {
544 if (s[index] == "=" || s[index] == ";") break;
545 index++;
546 }
547 return s.substring(start, index).trim().toLowerCase();
548 }
549
550 String parseAttributeValue() {
551 int start = index;
552 while (!done()) {
553 if (s[index] == ";") break;
554 index++;
555 }
556 return s.substring(start, index).trim().toLowerCase();
557 }
558
559 while (!done()) {
560 String name = parseAttributeName();
561 String value = "";
562 if (!done() && s[index] == "=") {
563 index++; // Skip the = character.
564 value = parseAttributeValue();
565 }
566 if (name == "expires") {
567 expires = _HttpUtils.parseCookieDate(value);
568 } else if (name == "max-age") {
569 maxAge = parseInt(value);
570 } else if (name == "domain") {
571 domain = value;
572 } else if (name == "path") {
573 path = value;
574 } else if (name == "httponly") {
575 httpOnly = true;
576 } else if (name == "secure") {
577 secure = true;
578 }
579 if (!done()) index++; // Skip the ; character
580 }
581 }
582
583 name = parseName();
584 if (done() || name.length == 0) {
585 throw new HttpException("Failed to parse header value [$s]");
586 }
587 index++; // Skip the = character.
588 value = parseValue();
589 if (done()) return;
590 index++; // Skip the ; character.
591 parseAttributes();
592 }
593
594 String toString() {
595 StringBuffer sb = new StringBuffer();
596 sb.add(name);
597 sb.add("=");
598 sb.add(value);
599 if (expires != null) {
600 sb.add("; Expires=");
601 sb.add(_HttpUtils.formatDate(expires));
602 }
603 if (maxAge != null) {
604 sb.add("; Max-Age=");
605 sb.add(maxAge);
606 }
607 if (domain != null) {
608 sb.add("; Domain=");
609 sb.add(domain);
610 }
611 if (path != null) {
612 sb.add("; Path=");
613 sb.add(path);
614 }
615 if (secure) sb.add("; Secure");
616 if (httpOnly) sb.add("; HttpOnly");
617 return sb.toString();
618 }
619
620 String name;
621 String value;
622 Date expires;
623 int maxAge;
624 String domain;
625 String path;
626 bool httpOnly = false;
627 bool secure = false;
628 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698