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

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

Issue 11415027: Refactor the HTTP parser to collect headers (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Addessed review comments 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 | sdk/lib/io/http_parser.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) 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 {
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 _set("host", value);
203 }
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 }
629
630
631 // The close queue handles graceful closing of HTTP connections. When 5 // The close queue handles graceful closing of HTTP connections. When
632 // a connection is added to the queue it will enter a wait state 6 // a connection is added to the queue it will enter a wait state
633 // waiting for all data written and possibly socket shutdown from 7 // waiting for all data written and possibly socket shutdown from
634 // peer. 8 // peer.
635 class _CloseQueue { 9 class _CloseQueue {
636 _CloseQueue() : _q = new Set<_HttpConnectionBase>(); 10 _CloseQueue() : _q = new Set<_HttpConnectionBase>();
637 11
638 void add(_HttpConnectionBase connection) { 12 void add(_HttpConnectionBase connection) {
639 void closeIfDone() { 13 void closeIfDone() {
640 // We only check for write closed here. This means that we are 14 // We only check for write closed here. This means that we are
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
694 _q.forEach((_HttpConnectionBase connection) { 68 _q.forEach((_HttpConnectionBase connection) {
695 connection._socket.close(); 69 connection._socket.close();
696 }); 70 });
697 } 71 }
698 72
699 final Set<_HttpConnectionBase> _q; 73 final Set<_HttpConnectionBase> _q;
700 } 74 }
701 75
702 76
703 class _HttpRequestResponseBase { 77 class _HttpRequestResponseBase {
704 final int START = 0; 78 static const int START = 0;
705 final int HEADER_SENT = 1; 79 static const int HEADER_SENT = 1;
706 final int DONE = 2; 80 static const int DONE = 2;
707 final int UPGRADED = 3; 81 static const int UPGRADED = 3;
708 82
709 _HttpRequestResponseBase(_HttpConnectionBase this._httpConnection) 83 _HttpRequestResponseBase(_HttpConnectionBase this._httpConnection)
710 : _headers = new _HttpHeaders() { 84 : _state = START, _headResponse = false;
711 _state = START;
712 _headResponse = false;
713 }
714 85
715 int get contentLength => _contentLength; 86 int get contentLength => _contentLength;
716 HttpHeaders get headers => _headers; 87 HttpHeaders get headers => _headers;
717 88
718 bool get persistentConnection { 89 bool get persistentConnection {
719 List<String> connection = headers[HttpHeaders.CONNECTION]; 90 List<String> connection = headers[HttpHeaders.CONNECTION];
720 if (_protocolVersion == "1.1") { 91 if (_protocolVersion == "1.1") {
721 if (connection == null) return true; 92 if (connection == null) return true;
722 return !headers[HttpHeaders.CONNECTION].some( 93 return !headers[HttpHeaders.CONNECTION].some(
723 (value) => value.toLowerCase() == "close"); 94 (value) => value.toLowerCase() == "close");
(...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after
951 HttpSession session([init(HttpSession session)]) { 322 HttpSession session([init(HttpSession session)]) {
952 if (_session != null) { 323 if (_session != null) {
953 // It's already mapped, use it. 324 // It's already mapped, use it.
954 return _session; 325 return _session;
955 } 326 }
956 // Create session, store it in connection, and return. 327 // Create session, store it in connection, and return.
957 var sessionManager = _httpConnection._server._sessionManager; 328 var sessionManager = _httpConnection._server._sessionManager;
958 return _session = sessionManager.createSession(init); 329 return _session = sessionManager.createSession(init);
959 } 330 }
960 331
961 void _onRequestStart(String method, String uri, String version) { 332 void _onRequestReceived(String method,
333 String uri,
334 String version,
335 _HttpHeaders headers) {
962 _method = method; 336 _method = method;
963 _uri = uri; 337 _uri = uri;
964 _parseRequestUri(uri); 338 _parseRequestUri(uri);
965 } 339 _headers = headers;
966
967 void _onHeaderReceived(String name, String value) {
968 _headers.add(name, value);
969 }
970
971 void _onHeadersComplete() {
972 if (_httpConnection._server._sessionManagerInstance != null) { 340 if (_httpConnection._server._sessionManagerInstance != null) {
973 // Map to session if exists. 341 // Map to session if exists.
974 var sessionId = cookies.reduce(null, (last, cookie) { 342 var sessionId = cookies.reduce(null, (last, cookie) {
975 if (last != null) return last; 343 if (last != null) return last;
976 return cookie.name.toUpperCase() == _DART_SESSION_ID ? 344 return cookie.name.toUpperCase() == _DART_SESSION_ID ?
977 cookie.value : null; 345 cookie.value : null;
978 }); 346 });
979 if (sessionId != null) { 347 if (sessionId != null) {
980 var sessionManager = _httpConnection._server._sessionManager; 348 var sessionManager = _httpConnection._server._sessionManager;
981 _session = sessionManager.getSession(sessionId); 349 _session = sessionManager.getSession(sessionId);
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
1048 _BufferList _buffer; 416 _BufferList _buffer;
1049 Function _streamErrorHandler; 417 Function _streamErrorHandler;
1050 _HttpSession _session; 418 _HttpSession _session;
1051 } 419 }
1052 420
1053 421
1054 // HTTP response object for sending a HTTP response. 422 // HTTP response object for sending a HTTP response.
1055 class _HttpResponse extends _HttpRequestResponseBase implements HttpResponse { 423 class _HttpResponse extends _HttpRequestResponseBase implements HttpResponse {
1056 _HttpResponse(_HttpConnection httpConnection) 424 _HttpResponse(_HttpConnection httpConnection)
1057 : super(httpConnection), 425 : super(httpConnection),
1058 _statusCode = HttpStatus.OK; 426 _statusCode = HttpStatus.OK {
427 _headers = new _HttpHeaders();
428 }
1059 429
1060 void set contentLength(int contentLength) { 430 void set contentLength(int contentLength) {
1061 if (_state >= HEADER_SENT) throw new HttpException("Header already sent"); 431 if (_state >= _HttpRequestResponseBase.HEADER_SENT) {
432 throw new HttpException("Header already sent");
433 }
1062 _contentLength = contentLength; 434 _contentLength = contentLength;
1063 } 435 }
1064 436
1065 int get statusCode => _statusCode; 437 int get statusCode => _statusCode;
1066 void set statusCode(int statusCode) { 438 void set statusCode(int statusCode) {
1067 if (_outputStream != null) throw new HttpException("Header already sent"); 439 if (_outputStream != null) throw new HttpException("Header already sent");
1068 _statusCode = statusCode; 440 _statusCode = statusCode;
1069 } 441 }
1070 442
1071 String get reasonPhrase => _findReasonPhrase(_statusCode); 443 String get reasonPhrase => _findReasonPhrase(_statusCode);
1072 void set reasonPhrase(String reasonPhrase) { 444 void set reasonPhrase(String reasonPhrase) {
1073 if (_outputStream != null) throw new HttpException("Header already sent"); 445 if (_outputStream != null) throw new HttpException("Header already sent");
1074 _reasonPhrase = reasonPhrase; 446 _reasonPhrase = reasonPhrase;
1075 } 447 }
1076 448
1077 List<Cookie> get cookies { 449 List<Cookie> get cookies {
1078 if (_cookies == null) _cookies = new List<Cookie>(); 450 if (_cookies == null) _cookies = new List<Cookie>();
1079 return _cookies; 451 return _cookies;
1080 } 452 }
1081 453
1082 OutputStream get outputStream { 454 OutputStream get outputStream {
1083 if (_state >= DONE) throw new HttpException("Response closed"); 455 if (_state >= _HttpRequestResponseBase.DONE) {
456 throw new HttpException("Response closed");
457 }
1084 if (_outputStream == null) { 458 if (_outputStream == null) {
1085 _outputStream = new _HttpOutputStream(this); 459 _outputStream = new _HttpOutputStream(this);
1086 } 460 }
1087 return _outputStream; 461 return _outputStream;
1088 } 462 }
1089 463
1090 DetachedSocket detachSocket() { 464 DetachedSocket detachSocket() {
1091 if (_state >= DONE) throw new HttpException("Response closed"); 465 if (_state >= _HttpRequestResponseBase.DONE) {
466 throw new HttpException("Response closed");
467 }
1092 // Ensure that headers are written. 468 // Ensure that headers are written.
1093 if (_state == START) { 469 if (_state == _HttpRequestResponseBase.START) {
1094 _writeHeader(); 470 _writeHeader();
1095 } 471 }
1096 _state = UPGRADED; 472 _state = _HttpRequestResponseBase.UPGRADED;
1097 // Ensure that any trailing data is written. 473 // Ensure that any trailing data is written.
1098 _writeDone(); 474 _writeDone();
1099 // Indicate to the connection that the response handling is done. 475 // Indicate to the connection that the response handling is done.
1100 return _httpConnection._detachSocket(); 476 return _httpConnection._detachSocket();
1101 } 477 }
1102 478
1103 // Delegate functions for the HttpOutputStream implementation. 479 // Delegate functions for the HttpOutputStream implementation.
1104 bool _streamWrite(List<int> buffer, bool copyBuffer) { 480 bool _streamWrite(List<int> buffer, bool copyBuffer) {
1105 if (_done) throw new HttpException("Response closed"); 481 if (_done) throw new HttpException("Response closed");
1106 return _write(buffer, copyBuffer); 482 return _write(buffer, copyBuffer);
1107 } 483 }
1108 484
1109 bool _streamWriteFrom(List<int> buffer, int offset, int len) { 485 bool _streamWriteFrom(List<int> buffer, int offset, int len) {
1110 if (_done) throw new HttpException("Response closed"); 486 if (_done) throw new HttpException("Response closed");
1111 return _writeList(buffer, offset, len); 487 return _writeList(buffer, offset, len);
1112 } 488 }
1113 489
1114 void _streamFlush() { 490 void _streamFlush() {
1115 _httpConnection._flush(); 491 _httpConnection._flush();
1116 } 492 }
1117 493
1118 void _streamClose() { 494 void _streamClose() {
1119 _ensureHeadersSent(); 495 _ensureHeadersSent();
1120 _state = DONE; 496 _state = _HttpRequestResponseBase.DONE;
1121 // Stop tracking no pending write events. 497 // Stop tracking no pending write events.
1122 _httpConnection._onNoPendingWrites = null; 498 _httpConnection._onNoPendingWrites = null;
1123 // Ensure that any trailing data is written. 499 // Ensure that any trailing data is written.
1124 _writeDone(); 500 _writeDone();
1125 // Indicate to the connection that the response handling is done. 501 // Indicate to the connection that the response handling is done.
1126 _httpConnection._responseClosed(); 502 _httpConnection._responseClosed();
1127 } 503 }
1128 504
1129 void _streamSetNoPendingWriteHandler(callback()) { 505 void _streamSetNoPendingWriteHandler(callback()) {
1130 if (_state != DONE) { 506 if (_state != _HttpRequestResponseBase.DONE) {
1131 _httpConnection._onNoPendingWrites = callback; 507 _httpConnection._onNoPendingWrites = callback;
1132 } 508 }
1133 } 509 }
1134 510
1135 void _streamSetCloseHandler(callback()) { 511 void _streamSetCloseHandler(callback()) {
1136 // TODO(sgjesse): Handle this. 512 // TODO(sgjesse): Handle this.
1137 } 513 }
1138 514
1139 void _streamSetErrorHandler(callback(e)) { 515 void _streamSetErrorHandler(callback(e)) {
1140 _streamErrorHandler = callback; 516 _streamErrorHandler = callback;
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
1239 } 615 }
1240 // Add all the cookies set to the headers. 616 // Add all the cookies set to the headers.
1241 if (_cookies != null) { 617 if (_cookies != null) {
1242 _cookies.forEach((cookie) { 618 _cookies.forEach((cookie) {
1243 _headers.add("set-cookie", cookie); 619 _headers.add("set-cookie", cookie);
1244 }); 620 });
1245 } 621 }
1246 622
1247 // Write headers. 623 // Write headers.
1248 bool allWritten = _writeHeaders(); 624 bool allWritten = _writeHeaders();
1249 _state = HEADER_SENT; 625 _state = _HttpRequestResponseBase.HEADER_SENT;
1250 return allWritten; 626 return allWritten;
1251 } 627 }
1252 628
1253 int _statusCode; // Response status code. 629 int _statusCode; // Response status code.
1254 String _reasonPhrase; // Response reason phrase. 630 String _reasonPhrase; // Response reason phrase.
1255 _HttpOutputStream _outputStream; 631 _HttpOutputStream _outputStream;
1256 Function _streamErrorHandler; 632 Function _streamErrorHandler;
1257 } 633 }
1258 634
1259 635
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after
1437 final int hashCode; 813 final int hashCode;
1438 static int _nextHashCode = 0; 814 static int _nextHashCode = 0;
1439 } 815 }
1440 816
1441 817
1442 // HTTP server connection over a socket. 818 // HTTP server connection over a socket.
1443 class _HttpConnection extends _HttpConnectionBase { 819 class _HttpConnection extends _HttpConnectionBase {
1444 _HttpConnection(HttpServer this._server) { 820 _HttpConnection(HttpServer this._server) {
1445 _httpParser = new _HttpParser.requestParser(); 821 _httpParser = new _HttpParser.requestParser();
1446 // Register HTTP parser callbacks. 822 // Register HTTP parser callbacks.
1447 _httpParser.requestStart = _onRequestStart; 823 _httpParser.requestStart = _onRequestReceived;
1448 _httpParser.headerReceived = _onHeaderReceived;
1449 _httpParser.headersComplete = _onHeadersComplete;
1450 _httpParser.dataReceived = _onDataReceived; 824 _httpParser.dataReceived = _onDataReceived;
1451 _httpParser.dataEnd = _onDataEnd; 825 _httpParser.dataEnd = _onDataEnd;
1452 _httpParser.error = _onError; 826 _httpParser.error = _onError;
1453 _httpParser.closed = _onClosed; 827 _httpParser.closed = _onClosed;
1454 _httpParser.responseStart = (statusCode, reasonPhrase, version) { 828 _httpParser.responseStart = (statusCode, reasonPhrase, version) {
1455 assert(false); 829 assert(false);
1456 }; 830 };
1457 } 831 }
1458 832
1459 void _onClosed() { 833 void _onClosed() {
1460 _state |= _HttpConnectionBase.READ_CLOSED; 834 _state |= _HttpConnectionBase.READ_CLOSED;
1461 } 835 }
1462 836
1463 void _onError(e) { 837 void _onError(e) {
1464 onError(e); 838 onError(e);
1465 // Propagate the error to the streams. 839 // Propagate the error to the streams.
1466 if (_request != null && _request._streamErrorHandler != null) { 840 if (_request != null && _request._streamErrorHandler != null) {
1467 _request._streamErrorHandler(e); 841 _request._streamErrorHandler(e);
1468 } 842 }
1469 if (_response != null && _response._streamErrorHandler != null) { 843 if (_response != null && _response._streamErrorHandler != null) {
1470 _response._streamErrorHandler(e); 844 _response._streamErrorHandler(e);
1471 } 845 }
1472 if (_socket != null) _socket.close(); 846 if (_socket != null) _socket.close();
1473 } 847 }
1474 848
1475 void _onRequestStart(String method, String uri, String version) { 849 void _onRequestReceived(String method,
850 String uri,
851 String version,
852 _HttpHeaders headers) {
1476 _state = _HttpConnectionBase.ACTIVE; 853 _state = _HttpConnectionBase.ACTIVE;
1477 // Create new request and response objects for this request. 854 // Create new request and response objects for this request.
1478 _request = new _HttpRequest(this); 855 _request = new _HttpRequest(this);
1479 _response = new _HttpResponse(this); 856 _response = new _HttpResponse(this);
1480 _request._onRequestStart(method, uri, version); 857 _request._onRequestReceived(method, uri, version, headers);
1481 _request._protocolVersion = version; 858 _request._protocolVersion = version;
1482 _response._protocolVersion = version; 859 _response._protocolVersion = version;
1483 _response._headResponse = method == "HEAD"; 860 _response._headResponse = method == "HEAD";
1484 }
1485
1486 void _onHeaderReceived(String name, String value) {
1487 _request._onHeaderReceived(name, value);
1488 }
1489
1490 void _onHeadersComplete() {
1491 _request._onHeadersComplete();
1492 _response.persistentConnection = _httpParser.persistentConnection; 861 _response.persistentConnection = _httpParser.persistentConnection;
1493 if (onRequestReceived != null) { 862 if (onRequestReceived != null) {
1494 onRequestReceived(_request, _response); 863 onRequestReceived(_request, _response);
1495 } 864 }
1496 } 865 }
1497 866
1498 void _onDataReceived(List<int> data) { 867 void _onDataReceived(List<int> data) {
1499 _request._onDataReceived(data); 868 _request._onDataReceived(data);
1500 } 869 }
1501 870
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after
1666 _HttpSessionManager _sessionManagerInstance; 1035 _HttpSessionManager _sessionManagerInstance;
1667 } 1036 }
1668 1037
1669 1038
1670 class _HttpClientRequest 1039 class _HttpClientRequest
1671 extends _HttpRequestResponseBase implements HttpClientRequest { 1040 extends _HttpRequestResponseBase implements HttpClientRequest {
1672 _HttpClientRequest(String this._method, 1041 _HttpClientRequest(String this._method,
1673 Uri this._uri, 1042 Uri this._uri,
1674 _HttpClientConnection connection) 1043 _HttpClientConnection connection)
1675 : super(connection) { 1044 : super(connection) {
1045 _headers = new _HttpHeaders();
1676 _connection = connection; 1046 _connection = connection;
1677 // Default GET and HEAD requests to have no content. 1047 // Default GET and HEAD requests to have no content.
1678 if (_method == "GET" || _method == "HEAD") { 1048 if (_method == "GET" || _method == "HEAD") {
1679 _contentLength = 0; 1049 _contentLength = 0;
1680 } 1050 }
1681 } 1051 }
1682 1052
1683 void set contentLength(int contentLength) { 1053 void set contentLength(int contentLength) {
1684 if (_state >= HEADER_SENT) throw new HttpException("Header already sent"); 1054 if (_state >= _HttpRequestResponseBase.HEADER_SENT) {
1055 throw new HttpException("Header already sent");
1056 }
1685 _contentLength = contentLength; 1057 _contentLength = contentLength;
1686 } 1058 }
1687 1059
1688 List<Cookie> get cookies { 1060 List<Cookie> get cookies {
1689 if (_cookies == null) _cookies = new List<Cookie>(); 1061 if (_cookies == null) _cookies = new List<Cookie>();
1690 return _cookies; 1062 return _cookies;
1691 } 1063 }
1692 1064
1693 OutputStream get outputStream { 1065 OutputStream get outputStream {
1694 if (_done) throw new HttpException("Request closed"); 1066 if (_done) throw new HttpException("Request closed");
(...skipping 13 matching lines...) Expand all
1708 if (_done) throw new HttpException("Request closed"); 1080 if (_done) throw new HttpException("Request closed");
1709 return _writeList(buffer, offset, len); 1081 return _writeList(buffer, offset, len);
1710 } 1082 }
1711 1083
1712 void _streamFlush() { 1084 void _streamFlush() {
1713 _httpConnection._flush(); 1085 _httpConnection._flush();
1714 } 1086 }
1715 1087
1716 void _streamClose() { 1088 void _streamClose() {
1717 _ensureHeadersSent(); 1089 _ensureHeadersSent();
1718 _state = DONE; 1090 _state = _HttpRequestResponseBase.DONE;
1719 // Stop tracking no pending write events. 1091 // Stop tracking no pending write events.
1720 _httpConnection._onNoPendingWrites = null; 1092 _httpConnection._onNoPendingWrites = null;
1721 // Ensure that any trailing data is written. 1093 // Ensure that any trailing data is written.
1722 _writeDone(); 1094 _writeDone();
1723 _connection._requestClosed(); 1095 _connection._requestClosed();
1724 } 1096 }
1725 1097
1726 void _streamSetNoPendingWriteHandler(callback()) { 1098 void _streamSetNoPendingWriteHandler(callback()) {
1727 if (_state != DONE) { 1099 if (_state != _HttpRequestResponseBase.DONE) {
1728 _httpConnection._onNoPendingWrites = callback; 1100 _httpConnection._onNoPendingWrites = callback;
1729 } 1101 }
1730 } 1102 }
1731 1103
1732 void _streamSetCloseHandler(callback()) { 1104 void _streamSetCloseHandler(callback()) {
1733 // TODO(sgjesse): Handle this. 1105 // TODO(sgjesse): Handle this.
1734 } 1106 }
1735 1107
1736 void _streamSetErrorHandler(callback(e)) { 1108 void _streamSetErrorHandler(callback(e)) {
1737 _streamErrorHandler = callback; 1109 _streamErrorHandler = callback;
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
1781 if (i > 0) sb.add("; "); 1153 if (i > 0) sb.add("; ");
1782 sb.add(_cookies[i].name); 1154 sb.add(_cookies[i].name);
1783 sb.add("="); 1155 sb.add("=");
1784 sb.add(_cookies[i].value); 1156 sb.add(_cookies[i].value);
1785 } 1157 }
1786 _headers.add("cookie", sb.toString()); 1158 _headers.add("cookie", sb.toString());
1787 } 1159 }
1788 1160
1789 // Write headers. 1161 // Write headers.
1790 _writeHeaders(); 1162 _writeHeaders();
1791 _state = HEADER_SENT; 1163 _state = _HttpRequestResponseBase.HEADER_SENT;
1792 } 1164 }
1793 1165
1794 String _method; 1166 String _method;
1795 Uri _uri; 1167 Uri _uri;
1796 _HttpClientConnection _connection; 1168 _HttpClientConnection _connection;
1797 _HttpOutputStream _outputStream; 1169 _HttpOutputStream _outputStream;
1798 Function _streamErrorHandler; 1170 Function _streamErrorHandler;
1799 } 1171 }
1800 1172
1801 1173
(...skipping 26 matching lines...) Expand all
1828 return _cookies; 1200 return _cookies;
1829 } 1201 }
1830 1202
1831 InputStream get inputStream { 1203 InputStream get inputStream {
1832 if (_inputStream == null) { 1204 if (_inputStream == null) {
1833 _inputStream = new _HttpInputStream(this); 1205 _inputStream = new _HttpInputStream(this);
1834 } 1206 }
1835 return _inputStream; 1207 return _inputStream;
1836 } 1208 }
1837 1209
1838 void _onResponseStart(int statusCode, String reasonPhrase, String version) { 1210 void _onResponseReceived(int statusCode,
1211 String reasonPhrase,
1212 String version,
1213 _HttpHeaders headers) {
1839 _statusCode = statusCode; 1214 _statusCode = statusCode;
1840 _reasonPhrase = reasonPhrase; 1215 _reasonPhrase = reasonPhrase;
1841 } 1216 _headers = headers;
1217 // Get parsed content length.
1218 _contentLength = _httpConnection._httpParser.contentLength;
1842 1219
1843 void _onHeaderReceived(String name, String value) { 1220 // Prepare for receiving data.
1844 _headers.add(name, value); 1221 _headers._mutable = false;
1222 _buffer = new _BufferList();
1223
1224 if (isRedirect && _connection.followRedirects) {
1225 if (_connection._redirects == null ||
1226 _connection._redirects.length < _connection.maxRedirects) {
1227 // Check the location header.
1228 List<String> location = headers[HttpHeaders.LOCATION];
1229 if (location == null || location.length > 1) {
1230 throw new RedirectException("Invalid redirect",
1231 _connection._redirects);
1232 }
1233 // Check for redirect loop
1234 if (_connection._redirects != null) {
1235 Uri redirectUrl = new Uri.fromString(location[0]);
1236 for (int i = 0; i < _connection._redirects.length; i++) {
1237 if (_connection._redirects[i].location.toString() ==
1238 redirectUrl.toString()) {
1239 throw new RedirectLoopException(_connection._redirects);
1240 }
1241 }
1242 }
1243 // Drain body and redirect.
1244 inputStream.onData = inputStream.read;
1245 _connection.redirect();
1246 } else {
1247 throw new RedirectLimitExceededException(_connection._redirects);
1248 }
1249 } else if (statusCode == HttpStatus.UNAUTHORIZED) {
1250 _handleUnauthorized();
1251 } else if (_connection._onResponse != null) {
1252 _connection._onResponse(this);
1253 }
1845 } 1254 }
1846 1255
1847 void _handleUnauthorized() { 1256 void _handleUnauthorized() {
1848 1257
1849 void retryRequest(_Credentials cr) { 1258 void retryRequest(_Credentials cr) {
1850 if (cr != null) { 1259 if (cr != null) {
1851 // Drain body and retry. 1260 // Drain body and retry.
1852 // TODO(sgjesse): Support digest. 1261 // TODO(sgjesse): Support digest.
1853 if (cr.scheme == _AuthenticationScheme.BASIC) { 1262 if (cr.scheme == _AuthenticationScheme.BASIC) {
1854 inputStream.onData = inputStream.read; 1263 inputStream.onData = inputStream.read;
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
1910 } 1319 }
1911 } 1320 }
1912 1321
1913 // Fall through to here to perform normal response handling if 1322 // Fall through to here to perform normal response handling if
1914 // there is no sensible authorization handling. 1323 // there is no sensible authorization handling.
1915 if (_connection._onResponse != null) { 1324 if (_connection._onResponse != null) {
1916 _connection._onResponse(this); 1325 _connection._onResponse(this);
1917 } 1326 }
1918 } 1327 }
1919 1328
1920 void _onHeadersComplete() {
1921 // Get parsed content length.
1922 _contentLength = _httpConnection._httpParser.contentLength;
1923
1924 // Prepare for receiving data.
1925 _headers._mutable = false;
1926 _buffer = new _BufferList();
1927
1928 if (isRedirect && _connection.followRedirects) {
1929 if (_connection._redirects == null ||
1930 _connection._redirects.length < _connection.maxRedirects) {
1931 // Check the location header.
1932 List<String> location = headers[HttpHeaders.LOCATION];
1933 if (location == null || location.length > 1) {
1934 throw new RedirectException("Invalid redirect",
1935 _connection._redirects);
1936 }
1937 // Check for redirect loop
1938 if (_connection._redirects != null) {
1939 Uri redirectUrl = new Uri.fromString(location[0]);
1940 for (int i = 0; i < _connection._redirects.length; i++) {
1941 if (_connection._redirects[i].location.toString() ==
1942 redirectUrl.toString()) {
1943 throw new RedirectLoopException(_connection._redirects);
1944 }
1945 }
1946 }
1947 // Drain body and redirect.
1948 inputStream.onData = inputStream.read;
1949 _connection.redirect();
1950 } else {
1951 throw new RedirectLimitExceededException(_connection._redirects);
1952 }
1953 } else if (statusCode == HttpStatus.UNAUTHORIZED) {
1954 _handleUnauthorized();
1955 } else if (_connection._onResponse != null) {
1956 _connection._onResponse(this);
1957 }
1958 }
1959
1960 void _onDataReceived(List<int> data) { 1329 void _onDataReceived(List<int> data) {
1961 _buffer.add(data); 1330 _buffer.add(data);
1962 if (_inputStream != null) _inputStream._dataReceived(); 1331 if (_inputStream != null) _inputStream._dataReceived();
1963 } 1332 }
1964 1333
1965 void _onDataEnd() { 1334 void _onDataEnd() {
1966 if (_inputStream != null) { 1335 if (_inputStream != null) {
1967 _inputStream._closeReceived(); 1336 _inputStream._closeReceived();
1968 } else { 1337 } else {
1969 inputStream._streamMarkedClosed = true; 1338 inputStream._streamMarkedClosed = true;
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
2004 extends _HttpConnectionBase implements HttpClientConnection { 1373 extends _HttpConnectionBase implements HttpClientConnection {
2005 1374
2006 _HttpClientConnection(_HttpClient this._client) { 1375 _HttpClientConnection(_HttpClient this._client) {
2007 _httpParser = new _HttpParser.responseParser(); 1376 _httpParser = new _HttpParser.responseParser();
2008 } 1377 }
2009 1378
2010 void _connectionEstablished(_SocketConnection socketConn) { 1379 void _connectionEstablished(_SocketConnection socketConn) {
2011 super._connectionEstablished(socketConn._socket); 1380 super._connectionEstablished(socketConn._socket);
2012 _socketConn = socketConn; 1381 _socketConn = socketConn;
2013 // Register HTTP parser callbacks. 1382 // Register HTTP parser callbacks.
2014 _httpParser.responseStart = _onResponseStart; 1383 _httpParser.responseStart = _onResponseReceived;
2015 _httpParser.headerReceived = _onHeaderReceived;
2016 _httpParser.headersComplete = _onHeadersComplete;
2017 _httpParser.dataReceived = _onDataReceived; 1384 _httpParser.dataReceived = _onDataReceived;
2018 _httpParser.dataEnd = _onDataEnd; 1385 _httpParser.dataEnd = _onDataEnd;
2019 _httpParser.error = _onError; 1386 _httpParser.error = _onError;
2020 _httpParser.closed = _onClosed; 1387 _httpParser.closed = _onClosed;
2021 _httpParser.requestStart = (method, uri, version) { assert(false); }; 1388 _httpParser.requestStart = (method, uri, version) { assert(false); };
2022 _state = _HttpConnectionBase.ACTIVE; 1389 _state = _HttpConnectionBase.ACTIVE;
2023 } 1390 }
2024 1391
2025 void _checkSocketDone() { 1392 void _checkSocketDone() {
2026 if (_isAllDone) { 1393 if (_isAllDone) {
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
2079 } 1446 }
2080 // Propagate the error to the streams. 1447 // Propagate the error to the streams.
2081 if (_response != null && _response._streamErrorHandler != null) { 1448 if (_response != null && _response._streamErrorHandler != null) {
2082 _response._streamErrorHandler(e); 1449 _response._streamErrorHandler(e);
2083 } 1450 }
2084 if (_socketConn != null) { 1451 if (_socketConn != null) {
2085 _client._closeSocketConnection(_socketConn); 1452 _client._closeSocketConnection(_socketConn);
2086 } 1453 }
2087 } 1454 }
2088 1455
2089 void _onResponseStart(int statusCode, String reasonPhrase, String version) { 1456 void _onResponseReceived(int statusCode,
2090 _response._onResponseStart(statusCode, reasonPhrase, version); 1457 String reasonPhrase,
2091 } 1458 String version,
2092 1459 _HttpHeaders headers) {
2093 void _onHeaderReceived(String name, String value) { 1460 _response._onResponseReceived(statusCode, reasonPhrase, version, headers);
2094 _response._onHeaderReceived(name, value);
2095 }
2096
2097 void _onHeadersComplete() {
2098 _response._onHeadersComplete();
2099 } 1461 }
2100 1462
2101 void _onDataReceived(List<int> data) { 1463 void _onDataReceived(List<int> data) {
2102 _response._onDataReceived(data); 1464 _response._onDataReceived(data);
2103 } 1465 }
2104 1466
2105 void _onDataEnd(bool close) { 1467 void _onDataEnd(bool close) {
2106 _response._onDataEnd(); 1468 _response._onDataEnd();
2107 _state |= _HttpConnectionBase.RESPONSE_DONE; 1469 _state |= _HttpConnectionBase.RESPONSE_DONE;
2108 _checkSocketDone(); 1470 _checkSocketDone();
(...skipping 602 matching lines...) Expand 10 before | Expand all | Expand 10 after
2711 2073
2712 2074
2713 class _RedirectInfo implements RedirectInfo { 2075 class _RedirectInfo implements RedirectInfo {
2714 const _RedirectInfo(int this.statusCode, 2076 const _RedirectInfo(int this.statusCode,
2715 String this.method, 2077 String this.method,
2716 Uri this.location); 2078 Uri this.location);
2717 final int statusCode; 2079 final int statusCode;
2718 final String method; 2080 final String method;
2719 final Uri location; 2081 final Uri location;
2720 } 2082 }
OLDNEW
« no previous file with comments | « no previous file | sdk/lib/io/http_parser.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698