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

Side by Side Diff: pkg/shelf/lib/src/media_type.dart

Issue 219283008: pkg/shelf (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: cl nits Created 6 years, 8 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 | « pkg/shelf/lib/src/handlers/logger.dart ('k') | pkg/shelf/lib/src/message.dart » ('j') | 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) 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.media_type;
6
7 import 'package:collection/collection.dart';
8
9 import 'string_scanner.dart';
10
11 // All of the following regular expressions come from section 2.2 of the HTTP
12 // spec: http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html
13 final _lws = new RegExp(r"(?:\r\n)?[ \t]+");
14 final _token = new RegExp(r'[^()<>@,;:"\\/[\]?={} \t\x00-\x1F\x7F]+');
15 final _quotedString = new RegExp(r'"(?:[^"\x00-\x1F\x7F]|\\.)*"');
16 final _quotedPair = new RegExp(r'\\(.)');
17
18 /// A regular expression matching any number of [_lws] productions in a row.
19 final _whitespace = new RegExp("(?:${_lws.pattern})*");
20
21 /// A regular expression matching a character that is not a valid HTTP token.
22 final _nonToken = new RegExp(r'[()<>@,;:"\\/\[\]?={} \t\x00-\x1F\x7F]');
23
24 /// A regular expression matching a character that needs to be backslash-escaped
25 /// in a quoted string.
26 final _escapedChar = new RegExp(r'["\x00-\x1F\x7F]');
27
28 /// A class representing an HTTP media type, as used in Accept and Content-Type
29 /// headers.
30 class MediaType {
31 /// The primary identifier of the MIME type.
32 final String type;
33
34 /// The secondary identifier of the MIME type.
35 final String subtype;
36
37 /// The parameters to the media type.
38 ///
39 /// This map is immutable.
40 final Map<String, String> parameters;
41
42 /// The media type's MIME type.
43 String get mimeType => "$type/$subtype";
44
45 /// Parses a media type.
46 ///
47 /// This will throw a FormatError if the media type is invalid.
48 factory MediaType.parse(String mediaType) {
49 // This parsing is based on sections 3.6 and 3.7 of the HTTP spec:
50 // http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html.
51 var errorMessage = 'Invalid media type "$mediaType".';
52 var scanner = new StringScanner(mediaType);
53 scanner.scan(_whitespace);
54 scanner.expect(_token, errorMessage);
55 var type = scanner.lastMatch[0];
56 scanner.expect('/', errorMessage);
57 scanner.expect(_token, errorMessage);
58 var subtype = scanner.lastMatch[0];
59 scanner.scan(_whitespace);
60
61 var parameters = {};
62 while (scanner.scan(';')) {
63 scanner.scan(_whitespace);
64 scanner.expect(_token, errorMessage);
65 var attribute = scanner.lastMatch[0];
66 scanner.expect('=', errorMessage);
67
68 var value;
69 if (scanner.scan(_token)) {
70 value = scanner.lastMatch[0];
71 } else {
72 scanner.expect(_quotedString, errorMessage);
73 var quotedString = scanner.lastMatch[0];
74 value = quotedString.substring(1, quotedString.length - 1).
75 replaceAllMapped(_quotedPair, (match) => match[1]);
76 }
77
78 scanner.scan(_whitespace);
79 parameters[attribute] = value;
80 }
81
82 if (!scanner.isDone) throw new FormatException(errorMessage);
83
84 return new MediaType(type, subtype, parameters);
85 }
86
87 MediaType(this.type, this.subtype, [Map<String, String> parameters])
88 : this.parameters = new UnmodifiableMapView(
89 parameters == null ? {} : new Map.from(parameters));
90
91 /// Returns a copy of this [MediaType] with some fields altered.
92 ///
93 /// [type] and [subtype] alter the corresponding fields. [mimeType] is parsed
94 /// and alters both the [type] and [subtype] fields; it cannot be passed along
95 /// with [type] or [subtype].
96 ///
97 /// [parameters] overwrites and adds to the corresponding field. If
98 /// [clearParameters] is passed, it replaces the corresponding field entirely
99 /// instead.
100 MediaType change({String type, String subtype, String mimeType,
101 Map<String, String> parameters, bool clearParameters: false}) {
102 if (mimeType != null) {
103 if (type != null) {
104 throw new ArgumentError("You may not pass both [type] and [mimeType].");
105 } else if (subtype != null) {
106 throw new ArgumentError("You may not pass both [subtype] and "
107 "[mimeType].");
108 }
109
110 var segments = mimeType.split('/');
111 if (segments.length != 2) {
112 throw new FormatException('Invalid mime type "$mimeType".');
113 }
114
115 type = segments[0];
116 subtype = segments[1];
117 }
118
119 if (type == null) type = this.type;
120 if (subtype == null) subtype = this.subtype;
121 if (parameters == null) parameters = {};
122
123 if (!clearParameters) {
124 var newParameters = parameters;
125 parameters = new Map.from(this.parameters);
126 parameters.addAll(newParameters);
127 }
128
129 return new MediaType(type, subtype, parameters);
130 }
131
132 /// Converts the media type to a string.
133 ///
134 /// This will produce a valid HTTP media type.
135 String toString() {
136 var buffer = new StringBuffer()
137 ..write(type)
138 ..write("/")
139 ..write(subtype);
140
141 parameters.forEach((attribute, value) {
142 buffer.write("; $attribute=");
143 if (_nonToken.hasMatch(value)) {
144 buffer
145 ..write('"')
146 ..write(value.replaceAllMapped(
147 _escapedChar, (match) => "\\" + match[0]))
148 ..write('"');
149 } else {
150 buffer.write(value);
151 }
152 });
153
154 return buffer.toString();
155 }
156 }
OLDNEW
« no previous file with comments | « pkg/shelf/lib/src/handlers/logger.dart ('k') | pkg/shelf/lib/src/message.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698