| 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 { | |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 } |
| OLD | NEW |