OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 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 | 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 class _HttpHeaders implements HttpHeaders { | 5 class _HttpHeaders implements HttpHeaders { |
6 _HttpHeaders() : _headers = new Map<String, List<String>>(); | 6 _HttpHeaders() : _headers = new Map<String, List<String>>(); |
7 | 7 |
8 List<String> operator[](String name) { | 8 List<String> operator[](String name) { |
9 name = name.toLowerCase(); | 9 name = name.toLowerCase(); |
10 return _headers[name]; | 10 return _headers[name]; |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
70 void set contentLength(int contentLength) { | 70 void set contentLength(int contentLength) { |
71 _checkMutable(); | 71 _checkMutable(); |
72 _contentLength = contentLength; | 72 _contentLength = contentLength; |
73 if (_contentLength >= 0) { | 73 if (_contentLength >= 0) { |
74 _set("content-length", contentLength.toString()); | 74 _set("content-length", contentLength.toString()); |
75 } else { | 75 } else { |
76 removeAll("content-length"); | 76 removeAll("content-length"); |
77 } | 77 } |
78 } | 78 } |
79 | 79 |
| 80 bool get chunkedTransferEncoding => _chunkedTransferEncoding; |
| 81 |
| 82 void set chunkedTransferEncoding(bool chunkedTransferEncoding) { |
| 83 _checkMutable(); |
| 84 _chunkedTransferEncoding = chunkedTransferEncoding; |
| 85 List<String> values = _headers["transfer-encoding"]; |
| 86 if (values == null || values[values.length - 1] != "chunked") { |
| 87 // Headers does not specify chunked encoding - add it if set. |
| 88 if (chunkedTransferEncoding) _addValue("transfer-encoding", "chunked"); |
| 89 } else { |
| 90 // Headers does specify chunked encoding - remove it if not set. |
| 91 if (!chunkedTransferEncoding) remove("transfer-encoding", "chunked"); |
| 92 } |
| 93 } |
| 94 |
80 String get host => _host; | 95 String get host => _host; |
81 | 96 |
82 void set host(String host) { | 97 void set host(String host) { |
83 _checkMutable(); | 98 _checkMutable(); |
84 _host = host; | 99 _host = host; |
85 _updateHostHeader(); | 100 _updateHostHeader(); |
86 } | 101 } |
87 | 102 |
88 int get port => _port; | 103 int get port => _port; |
89 | 104 |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
168 var lowerCaseName = name.toLowerCase(); | 183 var lowerCaseName = name.toLowerCase(); |
169 // TODO(sgjesse): Add immutable state throw HttpException is immutable. | 184 // TODO(sgjesse): Add immutable state throw HttpException is immutable. |
170 if (lowerCaseName == "content-length") { | 185 if (lowerCaseName == "content-length") { |
171 if (value is int) { | 186 if (value is int) { |
172 contentLength = value; | 187 contentLength = value; |
173 } else if (value is String) { | 188 } else if (value is String) { |
174 contentLength = parseInt(value); | 189 contentLength = parseInt(value); |
175 } else { | 190 } else { |
176 throw new HttpException("Unexpected type for header named $name"); | 191 throw new HttpException("Unexpected type for header named $name"); |
177 } | 192 } |
| 193 } else if (lowerCaseName == "transfer-encoding") { |
| 194 if (value == "chunked") { |
| 195 chunkedTransferEncoding = true; |
| 196 } else { |
| 197 _addValue(lowerCaseName, value); |
| 198 } |
178 } else if (lowerCaseName == "date") { | 199 } else if (lowerCaseName == "date") { |
179 if (value is Date) { | 200 if (value is Date) { |
180 date = value; | 201 date = value; |
181 } else if (value is String) { | 202 } else if (value is String) { |
182 _set("date", value); | 203 _set("date", value); |
183 } else { | 204 } else { |
184 throw new HttpException("Unexpected type for header named $name"); | 205 throw new HttpException("Unexpected type for header named $name"); |
185 } | 206 } |
186 } else if (lowerCaseName == "expires") { | 207 } else if (lowerCaseName == "expires") { |
187 if (value is Date) { | 208 if (value is Date) { |
(...skipping 29 matching lines...) Expand all Loading... |
217 _port = parseInt(value.substring(pos + 1)); | 238 _port = parseInt(value.substring(pos + 1)); |
218 } on FormatException catch (e) { | 239 } on FormatException catch (e) { |
219 _port = null; | 240 _port = null; |
220 } | 241 } |
221 } | 242 } |
222 } | 243 } |
223 _set("host", value); | 244 _set("host", value); |
224 } else if (lowerCaseName == "content-type") { | 245 } else if (lowerCaseName == "content-type") { |
225 _set("content-type", value); | 246 _set("content-type", value); |
226 } else { | 247 } else { |
227 name = lowerCaseName; | 248 _addValue(lowerCaseName, value); |
228 List<String> values = _headers[name]; | |
229 if (values == null) { | |
230 values = new List<String>(); | |
231 _headers[name] = values; | |
232 } | |
233 if (value is Date) { | |
234 values.add(_HttpUtils.formatDate(value)); | |
235 } else { | |
236 values.add(value.toString()); | |
237 } | |
238 } | 249 } |
239 } | 250 } |
240 | 251 |
| 252 void _addValue(String name, Object value) { |
| 253 List<String> values = _headers[name]; |
| 254 if (values == null) { |
| 255 values = new List<String>(); |
| 256 _headers[name] = values; |
| 257 } |
| 258 if (value is Date) { |
| 259 values.add(_HttpUtils.formatDate(value)); |
| 260 } else { |
| 261 values.add(value.toString()); |
| 262 } |
| 263 } |
| 264 |
241 void _set(String name, String value) { | 265 void _set(String name, String value) { |
242 name = name.toLowerCase(); | 266 name = name.toLowerCase(); |
243 List<String> values = new List<String>(); | 267 List<String> values = new List<String>(); |
244 _headers[name] = values; | 268 _headers[name] = values; |
245 values.add(value); | 269 values.add(value); |
246 } | 270 } |
247 | 271 |
248 _checkMutable() { | 272 _checkMutable() { |
249 if (!_mutable) throw new HttpException("HTTP headers are not mutable"); | 273 if (!_mutable) throw new HttpException("HTTP headers are not mutable"); |
250 } | 274 } |
251 | 275 |
252 _updateHostHeader() { | 276 _updateHostHeader() { |
253 bool defaultPort = _port == null || _port == HttpClient.DEFAULT_HTTP_PORT; | 277 bool defaultPort = _port == null || _port == HttpClient.DEFAULT_HTTP_PORT; |
254 String portPart = defaultPort ? "" : ":$_port"; | 278 String portPart = defaultPort ? "" : ":$_port"; |
255 _set("host", "$host$portPart"); | 279 _set("host", "$host$portPart"); |
256 } | 280 } |
257 | 281 |
258 _foldHeader(String name) { | 282 _foldHeader(String name) { |
259 if (name == "set-cookie" || | 283 if (name == "set-cookie" || |
260 (_noFoldingHeaders != null && | 284 (_noFoldingHeaders != null && |
261 _noFoldingHeaders.indexOf(name) != -1)) { | 285 _noFoldingHeaders.indexOf(name) != -1)) { |
262 return false; | 286 return false; |
263 } | 287 } |
264 return true; | 288 return true; |
265 } | 289 } |
266 | 290 |
| 291 void _finalize(String protocolVersion) { |
| 292 // If the content length is not known make sure chunked transfer |
| 293 // encoding is used for HTTP 1.1. |
| 294 if (contentLength < 0 && protocolVersion == "1.1") { |
| 295 chunkedTransferEncoding = true; |
| 296 } |
| 297 // If a Transfer-Encoding header field is present the |
| 298 // Content-Length header MUST NOT be sent (RFC 2616 section 4.4). |
| 299 if (chunkedTransferEncoding && |
| 300 contentLength >= 0 && |
| 301 protocolVersion == "1.1") { |
| 302 contentLength = -1; |
| 303 } |
| 304 _mutable = false; |
| 305 } |
| 306 |
267 _write(_HttpConnectionBase connection) { | 307 _write(_HttpConnectionBase connection) { |
268 final COLONSP = const [_CharCode.COLON, _CharCode.SP]; | 308 final COLONSP = const [_CharCode.COLON, _CharCode.SP]; |
269 final COMMASP = const [_CharCode.COMMA, _CharCode.SP]; | 309 final COMMASP = const [_CharCode.COMMA, _CharCode.SP]; |
270 final CRLF = const [_CharCode.CR, _CharCode.LF]; | 310 final CRLF = const [_CharCode.CR, _CharCode.LF]; |
271 | 311 |
272 var bufferSize = 16 * 1024; | 312 var bufferSize = 16 * 1024; |
273 var buffer = new Uint8List(bufferSize); | 313 var buffer = new Uint8List(bufferSize); |
274 var bufferPos = 0; | 314 var bufferPos = 0; |
275 | 315 |
276 void writeBuffer() { | 316 void writeBuffer() { |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
337 sb.add("\n"); | 377 sb.add("\n"); |
338 }); | 378 }); |
339 return sb.toString(); | 379 return sb.toString(); |
340 } | 380 } |
341 | 381 |
342 bool _mutable = true; // Are the headers currently mutable? | 382 bool _mutable = true; // Are the headers currently mutable? |
343 Map<String, List<String>> _headers; | 383 Map<String, List<String>> _headers; |
344 List<String> _noFoldingHeaders; | 384 List<String> _noFoldingHeaders; |
345 | 385 |
346 int _contentLength = -1; | 386 int _contentLength = -1; |
| 387 bool _chunkedTransferEncoding = false; |
347 String _host; | 388 String _host; |
348 int _port; | 389 int _port; |
349 } | 390 } |
350 | 391 |
351 | 392 |
352 class _HeaderValue implements HeaderValue { | 393 class _HeaderValue implements HeaderValue { |
353 _HeaderValue([String this.value = ""]); | 394 _HeaderValue([String this.value = ""]); |
354 | 395 |
355 _HeaderValue.fromString(String value, {this.parameterSeparator: ";"}) { | 396 _HeaderValue.fromString(String value, {this.parameterSeparator: ";"}) { |
356 // Parse the string. | 397 // Parse the string. |
(...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
640 | 681 |
641 String name; | 682 String name; |
642 String value; | 683 String value; |
643 Date expires; | 684 Date expires; |
644 int maxAge; | 685 int maxAge; |
645 String domain; | 686 String domain; |
646 String path; | 687 String path; |
647 bool httpOnly = false; | 688 bool httpOnly = false; |
648 bool secure = false; | 689 bool secure = false; |
649 } | 690 } |
OLD | NEW |