| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 part of dart.io; | 5 part of dart.io; |
| 6 | 6 |
| 7 class _HttpIncoming extends Stream<List<int>> { | 7 class _HttpIncoming extends Stream<List<int>> { |
| 8 final int _transferLength; | 8 final int _transferLength; |
| 9 final Completer _dataCompleter = new Completer(); | 9 final Completer _dataCompleter = new Completer(); |
| 10 Stream<List<int>> _stream; | 10 Stream<List<int>> _stream; |
| (...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 325 bool _headersWritten = false; | 325 bool _headersWritten = false; |
| 326 bool _chunked = false; | 326 bool _chunked = false; |
| 327 | 327 |
| 328 final IOSink _ioSink; | 328 final IOSink _ioSink; |
| 329 final _HttpOutgoing _outgoing; | 329 final _HttpOutgoing _outgoing; |
| 330 | 330 |
| 331 final _HttpHeaders headers; | 331 final _HttpHeaders headers; |
| 332 | 332 |
| 333 _HttpOutboundMessage(String protocolVersion, _HttpOutgoing outgoing) | 333 _HttpOutboundMessage(String protocolVersion, _HttpOutgoing outgoing) |
| 334 : _outgoing = outgoing, | 334 : _outgoing = outgoing, |
| 335 _ioSink = new IOSink(outgoing), | 335 _ioSink = new IOSink(outgoing, encoding: Encoding.ASCII), |
| 336 headers = new _HttpHeaders(protocolVersion); | 336 headers = new _HttpHeaders(protocolVersion); |
| 337 | 337 |
| 338 int get contentLength => headers.contentLength; | 338 int get contentLength => headers.contentLength; |
| 339 void set contentLength(int contentLength) { | 339 void set contentLength(int contentLength) { |
| 340 headers.contentLength = contentLength; | 340 headers.contentLength = contentLength; |
| 341 } | 341 } |
| 342 | 342 |
| 343 bool get persistentConnection => headers.persistentConnection; | 343 bool get persistentConnection => headers.persistentConnection; |
| 344 void set persistentConnection(bool p) { | 344 void set persistentConnection(bool p) { |
| 345 headers.persistentConnection = p; | 345 headers.persistentConnection = p; |
| 346 } | 346 } |
| 347 | 347 |
| 348 Encoding get encoding { |
| 349 var charset; |
| 350 if (headers.contentType != null && headers.contentType.charset != null) { |
| 351 charset = headers.contentType.charset; |
| 352 } else { |
| 353 charset = "iso-8859-1"; |
| 354 } |
| 355 return Encoding.fromName(charset); |
| 356 } |
| 357 |
| 358 void set encoding(Encoding value) { |
| 359 throw new StateError("IOSink encoding is not mutable"); |
| 360 } |
| 361 |
| 362 void write(Object obj) { |
| 363 _writeHeaders(); |
| 364 if (_ignoreBody) return; |
| 365 // This comment is copied from runtime/lib/string_buffer_patch.dart. |
| 366 // TODO(srdjan): The following four lines could be replaced by |
| 367 // '$obj', but apparently this is too slow on the Dart VM. |
| 368 String string; |
| 369 if (obj is String) { |
| 370 string = obj; |
| 371 } else { |
| 372 string = obj.toString(); |
| 373 if (string is! String) { |
| 374 throw new ArgumentError('toString() did not return a string'); |
| 375 } |
| 376 } |
| 377 if (string.isEmpty) return; |
| 378 if (_chunked) { |
| 379 _ChunkedTransformer._addChunk(_encodeString(string, encoding), |
| 380 _ioSink.writeBytes); |
| 381 } else { |
| 382 _ioSink.write(string); |
| 383 } |
| 384 } |
| 385 |
| 386 void writeAll(Iterable objects) { |
| 387 for (Object obj in objects) write(obj); |
| 388 } |
| 389 |
| 390 void writeln(Object obj) { |
| 391 write(obj); |
| 392 write("\n"); |
| 393 } |
| 394 |
| 395 void writeCharCode(int charCode) { |
| 396 write(new String.fromCharCode(charCode)); |
| 397 } |
| 398 |
| 399 void writeBytes(List<int> data) { |
| 400 _writeHeaders(); |
| 401 if (_ignoreBody || data.length == 0) return; |
| 402 if (_chunked) { |
| 403 _ChunkedTransformer._addChunk(data, _ioSink.writeBytes); |
| 404 } else { |
| 405 _ioSink.writeBytes(data); |
| 406 } |
| 407 } |
| 408 |
| 348 Future<T> consume(Stream<List<int>> stream) { | 409 Future<T> consume(Stream<List<int>> stream) { |
| 349 _writeHeaders(); | 410 _writeHeaders(); |
| 350 if (_ignoreBody) return new Future.immediate(this); | 411 if (_ignoreBody) return new Future.immediate(this); |
| 351 if (_chunked) { | 412 if (_chunked) { |
| 352 // Transform when chunked. | 413 // Transform when chunked. |
| 353 stream = stream.transform(new _ChunkedTransformer()); | 414 stream = stream.transform(new _ChunkedTransformer()); |
| 354 } | 415 } |
| 355 return _ioSink.consume(stream).then((_) => this); | 416 return _ioSink.consume(stream).then((_) => this); |
| 356 } | 417 } |
| 357 | 418 |
| 358 void add(List<int> data) { | 419 Future<T> writeStream(Stream<List<int>> stream) { |
| 359 _writeHeaders(); | |
| 360 if (_ignoreBody || data.length == 0) return; | |
| 361 if (_chunked) { | |
| 362 _ChunkedTransformer._addChunk(data, _ioSink.add); | |
| 363 } else { | |
| 364 _ioSink.add(data); | |
| 365 } | |
| 366 } | |
| 367 | |
| 368 void addString(String string, [Encoding encoding = Encoding.UTF_8]) { | |
| 369 add(_encodeString(string, encoding)); | |
| 370 } | |
| 371 | |
| 372 Future<T> addStream(Stream<List<int>> stream) { | |
| 373 _writeHeaders(); | 420 _writeHeaders(); |
| 374 if (_ignoreBody) return new Future.immediate(this); | 421 if (_ignoreBody) return new Future.immediate(this); |
| 375 if (_chunked) { | 422 if (_chunked) { |
| 376 // Transform when chunked. | 423 // Transform when chunked. |
| 377 stream = stream.transform(new _ChunkedTransformer(writeEnd: false)); | 424 stream = stream.transform(new _ChunkedTransformer(writeEnd: false)); |
| 378 } | 425 } |
| 379 return _ioSink.addStream(stream).then((_) => this); | 426 return _ioSink.writeStream(stream).then((_) => this); |
| 380 } | 427 } |
| 381 | 428 |
| 382 void close() { | 429 void close() { |
| 383 if (!_headersWritten && !_ignoreBody && headers.chunkedTransferEncoding) { | 430 if (!_headersWritten && !_ignoreBody && headers.chunkedTransferEncoding) { |
| 384 // If no body was written, _ignoreBody is false (it's not a HEAD | 431 // If no body was written, _ignoreBody is false (it's not a HEAD |
| 385 // request) and the content-length is unspecified, set contentLength to 0. | 432 // request) and the content-length is unspecified, set contentLength to 0. |
| 386 headers.contentLength = 0; | 433 headers.contentLength = 0; |
| 387 } | 434 } |
| 388 _writeHeaders(); | 435 _writeHeaders(); |
| 389 if (!_ignoreBody) { | 436 if (!_ignoreBody) { |
| 390 if (_chunked) { | 437 if (_chunked) { |
| 391 _ChunkedTransformer._addChunk([], _ioSink.add); | 438 _ChunkedTransformer._addChunk([], _ioSink.writeBytes); |
| 392 } | 439 } |
| 393 } | 440 } |
| 394 _ioSink.close(); | 441 _ioSink.close(); |
| 395 } | 442 } |
| 396 | 443 |
| 397 Future<T> get done => _ioSink.done.then((_) => this); | 444 Future<T> get done => _ioSink.done.then((_) => this); |
| 398 | 445 |
| 399 void _writeHeaders() { | 446 void _writeHeaders() { |
| 400 if (_headersWritten) return; | 447 if (_headersWritten) return; |
| 401 _headersWritten = true; | 448 _headersWritten = true; |
| 449 _ioSink.encoding = Encoding.ASCII; |
| 402 _writeHeader(); | 450 _writeHeader(); |
| 451 _ioSink.encoding = encoding; |
| 403 if (_ignoreBody) { | 452 if (_ignoreBody) { |
| 404 _ioSink.close(); | 453 _ioSink.close(); |
| 405 return; | 454 return; |
| 406 } | 455 } |
| 407 _chunked = headers.chunkedTransferEncoding; | 456 _chunked = headers.chunkedTransferEncoding; |
| 408 if (headers.contentLength >= 0) { | 457 if (headers.contentLength >= 0) { |
| 409 _outgoing.setTransferLength(headers.contentLength); | 458 _outgoing.setTransferLength(headers.contentLength); |
| 410 } | 459 } |
| 411 } | 460 } |
| 412 | 461 |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 445 done.catchError((_) { | 494 done.catchError((_) { |
| 446 // Catch any error on done, as they automatically will be propegated to | 495 // Catch any error on done, as they automatically will be propegated to |
| 447 // the websocket. | 496 // the websocket. |
| 448 }); | 497 }); |
| 449 return future; | 498 return future; |
| 450 } | 499 } |
| 451 | 500 |
| 452 HttpConnectionInfo get connectionInfo => _httpRequest.connectionInfo; | 501 HttpConnectionInfo get connectionInfo => _httpRequest.connectionInfo; |
| 453 | 502 |
| 454 void _writeHeader() { | 503 void _writeHeader() { |
| 455 writeSP() => _ioSink.add([_CharCode.SP]); | 504 writeSP() => _ioSink.writeBytes([_CharCode.SP]); |
| 456 writeCRLF() => _ioSink.add([_CharCode.CR, _CharCode.LF]); | 505 writeCRLF() => _ioSink.writeBytes([_CharCode.CR, _CharCode.LF]); |
| 457 | 506 |
| 458 // Write status line. | 507 // Write status line. |
| 459 if (headers.protocolVersion == "1.1") { | 508 if (headers.protocolVersion == "1.1") { |
| 460 _ioSink.add(_Const.HTTP11); | 509 _ioSink.writeBytes(_Const.HTTP11); |
| 461 } else { | 510 } else { |
| 462 _ioSink.add(_Const.HTTP10); | 511 _ioSink.writeBytes(_Const.HTTP10); |
| 463 } | 512 } |
| 464 writeSP(); | 513 writeSP(); |
| 465 _ioSink.addString(statusCode.toString()); | 514 _ioSink.write(statusCode.toString()); |
| 466 writeSP(); | 515 writeSP(); |
| 467 _ioSink.addString(reasonPhrase); | 516 _ioSink.write(reasonPhrase); |
| 468 writeCRLF(); | 517 writeCRLF(); |
| 469 | 518 |
| 470 var session = _httpRequest._session; | 519 var session = _httpRequest._session; |
| 471 if (session != null && !session._destroyed) { | 520 if (session != null && !session._destroyed) { |
| 472 // Mark as not new. | 521 // Mark as not new. |
| 473 session._isNew = false; | 522 session._isNew = false; |
| 474 // Make sure we only send the current session id. | 523 // Make sure we only send the current session id. |
| 475 bool found = false; | 524 bool found = false; |
| 476 for (int i = 0; i < cookies.length; i++) { | 525 for (int i = 0; i < cookies.length; i++) { |
| 477 if (cookies[i].name.toUpperCase() == _DART_SESSION_ID) { | 526 if (cookies[i].name.toUpperCase() == _DART_SESSION_ID) { |
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 638 onError: (e) { | 687 onError: (e) { |
| 639 _responseCompleter.completeError(e); | 688 _responseCompleter.completeError(e); |
| 640 }); | 689 }); |
| 641 } | 690 } |
| 642 | 691 |
| 643 void _onError(AsyncError error) { | 692 void _onError(AsyncError error) { |
| 644 _responseCompleter.completeError(error); | 693 _responseCompleter.completeError(error); |
| 645 } | 694 } |
| 646 | 695 |
| 647 void _writeHeader() { | 696 void _writeHeader() { |
| 648 writeSP() => _ioSink.add([_CharCode.SP]); | 697 writeSP() => _ioSink.writeBytes([_CharCode.SP]); |
| 649 writeCRLF() => _ioSink.add([_CharCode.CR, _CharCode.LF]); | 698 writeCRLF() => _ioSink.writeBytes([_CharCode.CR, _CharCode.LF]); |
| 650 | 699 |
| 651 _ioSink.addString(method); | 700 _ioSink.write(method); |
| 652 writeSP(); | 701 writeSP(); |
| 653 // Send the path for direct connections and the whole URL for | 702 // Send the path for direct connections and the whole URL for |
| 654 // proxy connections. | 703 // proxy connections. |
| 655 if (!_usingProxy) { | 704 if (!_usingProxy) { |
| 656 String path = uri.path; | 705 String path = uri.path; |
| 657 if (path.length == 0) path = "/"; | 706 if (path.length == 0) path = "/"; |
| 658 if (uri.query != "") { | 707 if (uri.query != "") { |
| 659 if (uri.fragment != "") { | 708 if (uri.fragment != "") { |
| 660 path = "${path}?${uri.query}#${uri.fragment}"; | 709 path = "${path}?${uri.query}#${uri.fragment}"; |
| 661 } else { | 710 } else { |
| 662 path = "${path}?${uri.query}"; | 711 path = "${path}?${uri.query}"; |
| 663 } | 712 } |
| 664 } | 713 } |
| 665 _ioSink.addString(path); | 714 _ioSink.write(path); |
| 666 } else { | 715 } else { |
| 667 _ioSink.addString(uri.toString()); | 716 _ioSink.write(uri.toString()); |
| 668 } | 717 } |
| 669 writeSP(); | 718 writeSP(); |
| 670 _ioSink.add(_Const.HTTP11); | 719 _ioSink.writeBytes(_Const.HTTP11); |
| 671 writeCRLF(); | 720 writeCRLF(); |
| 672 | 721 |
| 673 // Add the cookies to the headers. | 722 // Add the cookies to the headers. |
| 674 if (!cookies.isEmpty) { | 723 if (!cookies.isEmpty) { |
| 675 StringBuffer sb = new StringBuffer(); | 724 StringBuffer sb = new StringBuffer(); |
| 676 for (int i = 0; i < cookies.length; i++) { | 725 for (int i = 0; i < cookies.length; i++) { |
| 677 if (i > 0) sb.write("; "); | 726 if (i > 0) sb.write("; "); |
| 678 sb.write(cookies[i].name); | 727 sb.write(cookies[i].name); |
| 679 sb.write("="); | 728 sb.write("="); |
| 680 sb.write(cookies[i].value); | 729 sb.write(cookies[i].value); |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 768 var subscription; | 817 var subscription; |
| 769 subscription = stream.listen( | 818 subscription = stream.listen( |
| 770 (data) { | 819 (data) { |
| 771 if (expectedTransferLength != null) { | 820 if (expectedTransferLength != null) { |
| 772 _bytesWritten += data.length; | 821 _bytesWritten += data.length; |
| 773 if (_bytesWritten > expectedTransferLength) { | 822 if (_bytesWritten > expectedTransferLength) { |
| 774 subscription.cancel(); | 823 subscription.cancel(); |
| 775 _controller.signalError(new HttpException( | 824 _controller.signalError(new HttpException( |
| 776 "Content size exceeds specified contentLength. " | 825 "Content size exceeds specified contentLength. " |
| 777 "$_bytesWritten bytes written while expected " | 826 "$_bytesWritten bytes written while expected " |
| 778 "$expectedTransferLength.")); | 827 "$expectedTransferLength. " |
| 828 "[${new String.fromCharCodes(data)}]")); |
| 779 _controller.close(); | 829 _controller.close(); |
| 780 return; | 830 return; |
| 781 } | 831 } |
| 782 } | 832 } |
| 783 _controller.add(data); | 833 _controller.add(data); |
| 784 }, | 834 }, |
| 785 onError: (error) { | 835 onError: (error) { |
| 786 _controller.signalError(error); | 836 _controller.signalError(error); |
| 787 _controller.close(); | 837 _controller.close(); |
| 788 }, | 838 }, |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 894 cr.authorize(request); | 944 cr.authorize(request); |
| 895 } | 945 } |
| 896 } | 946 } |
| 897 // Start sending the request (lazy, delayed until the user provides | 947 // Start sending the request (lazy, delayed until the user provides |
| 898 // data). | 948 // data). |
| 899 _httpParser.responseToMethod = method; | 949 _httpParser.responseToMethod = method; |
| 900 _streamFuture = outgoing.onStream((stream) { | 950 _streamFuture = outgoing.onStream((stream) { |
| 901 // Sending request, set up response completer. | 951 // Sending request, set up response completer. |
| 902 _nextResponseCompleter = new Completer(); | 952 _nextResponseCompleter = new Completer(); |
| 903 | 953 |
| 904 var requestFuture = _socket.addStream(stream) | 954 var requestFuture = _socket.writeStream(stream) |
| 905 .catchError((e) { | 955 .catchError((e) { |
| 906 destroy(); | 956 destroy(); |
| 907 throw e; | 957 throw e; |
| 908 }); | 958 }); |
| 909 | 959 |
| 910 // Listen for response. | 960 // Listen for response. |
| 911 _nextResponseCompleter.future | 961 _nextResponseCompleter.future |
| 912 .then((incoming) { | 962 .then((incoming) { |
| 913 incoming.dataDone.then((_) { | 963 incoming.dataDone.then((_) { |
| 914 if (incoming.headers.persistentConnection && | 964 if (incoming.headers.persistentConnection && |
| (...skipping 306 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1221 (incoming) { | 1271 (incoming) { |
| 1222 // Only handle one incoming request at the time. Keep the | 1272 // Only handle one incoming request at the time. Keep the |
| 1223 // stream paused until the request has been send. | 1273 // stream paused until the request has been send. |
| 1224 _subscription.pause(); | 1274 _subscription.pause(); |
| 1225 _state = _ACTIVE; | 1275 _state = _ACTIVE; |
| 1226 var outgoing = new _HttpOutgoing(); | 1276 var outgoing = new _HttpOutgoing(); |
| 1227 var response = new _HttpResponse(incoming.headers.protocolVersion, | 1277 var response = new _HttpResponse(incoming.headers.protocolVersion, |
| 1228 outgoing); | 1278 outgoing); |
| 1229 var request = new _HttpRequest(response, incoming, _httpServer, this); | 1279 var request = new _HttpRequest(response, incoming, _httpServer, this); |
| 1230 outgoing.onStream((stream) { | 1280 outgoing.onStream((stream) { |
| 1231 return _streamFuture = _socket.addStream(stream) | 1281 return _streamFuture = _socket.writeStream(stream) |
| 1232 .then((_) { | 1282 .then((_) { |
| 1233 if (_state == _DETACHED) return; | 1283 if (_state == _DETACHED) return; |
| 1234 if (response.persistentConnection && | 1284 if (response.persistentConnection && |
| 1235 request.persistentConnection && | 1285 request.persistentConnection && |
| 1236 incoming.fullBodyRead) { | 1286 incoming.fullBodyRead) { |
| 1237 _state = _IDLE; | 1287 _state = _IDLE; |
| 1238 // Resume the subscription for incoming requests as the | 1288 // Resume the subscription for incoming requests as the |
| 1239 // request is now processed. | 1289 // request is now processed. |
| 1240 _subscription.resume(); | 1290 _subscription.resume(); |
| 1241 } else { | 1291 } else { |
| (...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1502 StreamSubscription<List<int>> listen(void onData(List<int> event), | 1552 StreamSubscription<List<int>> listen(void onData(List<int> event), |
| 1503 {void onError(AsyncError error), | 1553 {void onError(AsyncError error), |
| 1504 void onDone(), | 1554 void onDone(), |
| 1505 bool unsubscribeOnError}) { | 1555 bool unsubscribeOnError}) { |
| 1506 return _incoming.listen(onData, | 1556 return _incoming.listen(onData, |
| 1507 onError: onError, | 1557 onError: onError, |
| 1508 onDone: onDone, | 1558 onDone: onDone, |
| 1509 unsubscribeOnError: unsubscribeOnError); | 1559 unsubscribeOnError: unsubscribeOnError); |
| 1510 } | 1560 } |
| 1511 | 1561 |
| 1562 Encoding get encoding => _socket.encoding; |
| 1563 |
| 1564 void set encoding(Encoding value) { |
| 1565 _socket.encoding = value; |
| 1566 } |
| 1567 |
| 1568 void write(Object obj) => _socket.write(obj); |
| 1569 |
| 1570 void writeln(Object obj) => _socket.writeln(obj); |
| 1571 |
| 1572 void writeCharCode(int charCode) => _socket.writeCharCode(charCode); |
| 1573 |
| 1574 void writeAll(Iterable objects) => _socket.writeAll(objects); |
| 1575 |
| 1576 void writeBytes(List<int> bytes) => _socket.writeBytes(bytes); |
| 1577 |
| 1512 Future<Socket> consume(Stream<List<int>> stream) { | 1578 Future<Socket> consume(Stream<List<int>> stream) { |
| 1513 return _socket.consume(stream); | 1579 return _socket.consume(stream); |
| 1514 } | 1580 } |
| 1515 | 1581 |
| 1516 Future<Socket> addStream(Stream<List<int>> stream) { | 1582 Future<Socket> writeStream(Stream<List<int>> stream) { |
| 1517 return _socket.addStream(stream); | 1583 return _socket.writeStream(stream); |
| 1518 } | |
| 1519 | |
| 1520 void addString(String string, [Encoding encoding = Encoding.UTF_8]) { | |
| 1521 return _socket.addString(string, encoding); | |
| 1522 } | 1584 } |
| 1523 | 1585 |
| 1524 void destroy() => _socket.destroy(); | 1586 void destroy() => _socket.destroy(); |
| 1525 void add(List<int> data) => _socket.add(data); | 1587 |
| 1526 void close() => _socket.close(); | 1588 void close() => _socket.close(); |
| 1589 |
| 1527 Future<Socket> get done => _socket.done; | 1590 Future<Socket> get done => _socket.done; |
| 1591 |
| 1528 int get port => _socket.port; | 1592 int get port => _socket.port; |
| 1593 |
| 1529 String get remoteHost => _socket.remoteHost; | 1594 String get remoteHost => _socket.remoteHost; |
| 1595 |
| 1530 int get remotePort => _socket.remotePort; | 1596 int get remotePort => _socket.remotePort; |
| 1531 } | 1597 } |
| 1532 | 1598 |
| 1533 | 1599 |
| 1534 class _AuthenticationScheme { | 1600 class _AuthenticationScheme { |
| 1535 static const UNKNOWN = const _AuthenticationScheme(-1); | 1601 static const UNKNOWN = const _AuthenticationScheme(-1); |
| 1536 static const BASIC = const _AuthenticationScheme(0); | 1602 static const BASIC = const _AuthenticationScheme(0); |
| 1537 static const DIGEST = const _AuthenticationScheme(1); | 1603 static const DIGEST = const _AuthenticationScheme(1); |
| 1538 | 1604 |
| 1539 const _AuthenticationScheme(this._scheme); | 1605 const _AuthenticationScheme(this._scheme); |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1636 | 1702 |
| 1637 | 1703 |
| 1638 class _RedirectInfo implements RedirectInfo { | 1704 class _RedirectInfo implements RedirectInfo { |
| 1639 const _RedirectInfo(int this.statusCode, | 1705 const _RedirectInfo(int this.statusCode, |
| 1640 String this.method, | 1706 String this.method, |
| 1641 Uri this.location); | 1707 Uri this.location); |
| 1642 final int statusCode; | 1708 final int statusCode; |
| 1643 final String method; | 1709 final String method; |
| 1644 final Uri location; | 1710 final Uri location; |
| 1645 } | 1711 } |
| OLD | NEW |