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

Side by Side Diff: runtime/bin/http_impl.dart

Issue 10082003: Start refactoring of the HTTP header handling (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
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 void add(String name, value) {
14 // TODO(sgjesse): Add immutable state throw HttpException is immutable.
15 if (name.toLowerCase() == "expires") {
16 if (value is Date) {
17 expires = value;
18 } else if (value is String) {
19 expires = _HttpUtils.parseDate(value);
20 } else {
21 throw new HttpException("Unexpected type for header named $name");
22 }
23 } else if (name.toLowerCase() == "host") {
24 int pos = value.indexOf(":");
25 if (pos == -1) {
26 _host = value;
27 _port = HttpClient.DEFAULT_HTTP_PORT;
28 } else {
29 _host = value.substring(0, pos);
30 if (pos + 1 == value.length) {
31 _port = HttpClient.DEFAULT_HTTP_PORT;
32 } else {
33 _port = Math.parseInt(value.substring(pos + 1));
34 }
35 }
36 _updateHostHeader();
37 } else {
38 _add(name, value.toString());
39 }
40 }
41
42 void set(String name, value) {
43 removeAll(name);
44 add(name, value);
45 }
46
47 void remove(String name, value) {
48 name = name.toLowerCase();
49 List<String> values = _headers[name];
50 if (values != null) {
51 int index = values.indexOf(value);
52 if (index != -1) {
53 values.removeRange(index, 1);
54 }
55 }
56 }
57
58 void removeAll(String name) {
59 name = name.toLowerCase();
60 _headers.remove(name);
61 }
62
63 String get host() => _host;
64 void set host(String host) {
65 _host = host;
66 _updateHostHeader();
67 }
68
69 int get port() => _port;
70 void set port(int port) {
71 _port = port;
72 _updateHostHeader();
73 }
74
75 Date get expires() {
Anders Johnsen 2012/04/13 11:47:53 expires is not defined in interface. Should it? Sa
Søren Gjesse 2012/04/16 11:37:16 The interface has Date expires; String host; int
Anders Johnsen 2012/04/16 11:50:46 Ahh, I see.
76 if (_expires == null) {
77 List<String> values = _headers["expires"];
78 if (values != null) {
79 _expires = _HttpUtils.parseDate(values[0]);
80 }
81 }
82 return _expires;
83 }
84
85 void set expires(Date expires) {
86 _expires = expires;
87 // Format "Expires" header with date in Greenwich Mean Time (GMT).
88 String formatted =
89 _HttpUtils.formatDate(_expires.changeTimeZone(new TimeZone.utc()));
90 _set("expires", formatted);
91 }
92
93 void _add(String name, String value) {
94 name = name.toLowerCase();
95 List<String> values = _headers[name];
96 if (values == null) {
97 values = new List<String>();
98 _headers[name] = values;
99 }
100 values.add(value);
101 }
102
103 void _set(String name, String value) {
104 name = name.toLowerCase();
105 List<String> values = new List<String>();
106 _headers[name] = values;
107 values.add(value);
108 }
109
110 _updateHostHeader() {
111 String portPart = _port == HttpClient.DEFAULT_HTTP_PORT ? "" : ":$_port";
112 _set("host", "$host$portPart");
113 }
114
115 Map<String, List<String>> _headers;
116
117 String _host;
118 int _port;
119 Date _expires;
Anders Johnsen 2012/04/13 11:47:53 Can we do with keeping a String in _headers, and n
Søren Gjesse 2012/04/16 11:37:16 We could, but I am not sure it would be less compl
Anders Johnsen 2012/04/16 11:50:46 Okay, let's keep as is then.
120 }
121
122
5 class _HttpRequestResponseBase { 123 class _HttpRequestResponseBase {
6 _HttpRequestResponseBase(_HttpConnectionBase this._httpConnection) 124 _HttpRequestResponseBase(_HttpConnectionBase this._httpConnection)
7 : _contentLength = -1, 125 : _contentLength = -1,
8 _headers = new Map(); 126 _headers = new _HttpHeaders();
9 127
10 int get contentLength() => _contentLength; 128 int get contentLength() => _contentLength;
11 Map get headers() => _headers; 129 HttpHeaders get headers() => _headers;
12
13 void _setHeader(String name, String value) {
14 _headers[name.toLowerCase()] = value;
15 }
16 130
17 bool _write(List<int> data, bool copyBuffer) { 131 bool _write(List<int> data, bool copyBuffer) {
18 bool allWritten = true; 132 bool allWritten = true;
19 if (data.length > 0) { 133 if (data.length > 0) {
20 if (_contentLength < 0) { 134 if (_contentLength < 0) {
21 // Write chunk size if transfer encoding is chunked. 135 // Write chunk size if transfer encoding is chunked.
22 _writeHexString(data.length); 136 _writeHexString(data.length);
23 _writeCRLF(); 137 _writeCRLF();
24 _httpConnection._write(data, copyBuffer); 138 _httpConnection._write(data, copyBuffer);
25 allWritten = _writeCRLF(); 139 allWritten = _writeCRLF();
(...skipping 26 matching lines...) Expand all
52 // Terminate the content if transfer encoding is chunked. 166 // Terminate the content if transfer encoding is chunked.
53 allWritten = _httpConnection._write(_Const.END_CHUNKED); 167 allWritten = _httpConnection._write(_Const.END_CHUNKED);
54 } 168 }
55 return allWritten; 169 return allWritten;
56 } 170 }
57 171
58 bool _writeHeaders() { 172 bool _writeHeaders() {
59 List<int> data; 173 List<int> data;
60 174
61 // Format headers. 175 // Format headers.
62 _headers.forEach((String name, String value) { 176 _headers._headers.forEach((String name, List<String> values) {
63 data = name.charCodes(); 177 data = name.charCodes();
64 _httpConnection._write(data); 178 _httpConnection._write(data);
65 data = ": ".charCodes(); 179 data = ": ".charCodes();
66 _httpConnection._write(data); 180 _httpConnection._write(data);
67 data = value.charCodes(); 181 for (int i = 0; i < values.length; i++) {
Anders Johnsen 2012/04/13 11:47:53 We could move this to the _HttpHeader class, with
Søren Gjesse 2012/04/16 11:37:16 Added a _write method which takes a _HttpConnectio
Anders Johnsen 2012/04/16 11:50:46 Thank you!
68 _httpConnection._write(data); 182 if (i > 0) {
183 data = ", ".charCodes();
184 _httpConnection._write(data);
185 }
186 data = values[i].charCodes();
187 _httpConnection._write(data);
188 }
69 _writeCRLF(); 189 _writeCRLF();
70 }); 190 });
71 // Terminate header. 191 // Terminate header.
72 return _writeCRLF(); 192 return _writeCRLF();
73 } 193 }
74 194
75 bool _writeHexString(int x) { 195 bool _writeHexString(int x) {
76 final List<int> hexDigits = [0x30, 0x31, 0x32, 0x33, 0x34, 196 final List<int> hexDigits = [0x30, 0x31, 0x32, 0x33, 0x34,
77 0x35, 0x36, 0x37, 0x38, 0x39, 197 0x35, 0x36, 0x37, 0x38, 0x39,
78 0x41, 0x42, 0x43, 0x44, 0x45, 0x46]; 198 0x41, 0x42, 0x43, 0x44, 0x45, 0x46];
(...skipping 11 matching lines...) Expand all
90 final CRLF = const [_CharCode.CR, _CharCode.LF]; 210 final CRLF = const [_CharCode.CR, _CharCode.LF];
91 return _httpConnection._write(CRLF); 211 return _httpConnection._write(CRLF);
92 } 212 }
93 213
94 bool _writeSP() { 214 bool _writeSP() {
95 final SP = const [_CharCode.SP]; 215 final SP = const [_CharCode.SP];
96 return _httpConnection._write(SP); 216 return _httpConnection._write(SP);
97 } 217 }
98 218
99 _HttpConnectionBase _httpConnection; 219 _HttpConnectionBase _httpConnection;
100 Map<String, String> _headers; 220 _HttpHeaders _headers;
101 221
102 // Length of the content body. If this is set to -1 (default value) 222 // Length of the content body. If this is set to -1 (default value)
103 // when starting to send data chunked transfer encoding will be 223 // when starting to send data chunked transfer encoding will be
104 // used. 224 // used.
105 int _contentLength; 225 int _contentLength;
106 } 226 }
107 227
108 228
109 // Parsed HTTP request providing information on the HTTP headers. 229 // Parsed HTTP request providing information on the HTTP headers.
110 class _HttpRequest extends _HttpRequestResponseBase implements HttpRequest { 230 class _HttpRequest extends _HttpRequestResponseBase implements HttpRequest {
(...skipping 12 matching lines...) Expand all
123 return _inputStream; 243 return _inputStream;
124 } 244 }
125 245
126 void _onRequestStart(String method, String uri, String version) { 246 void _onRequestStart(String method, String uri, String version) {
127 _method = method; 247 _method = method;
128 _uri = uri; 248 _uri = uri;
129 _parseRequestUri(uri); 249 _parseRequestUri(uri);
130 } 250 }
131 251
132 void _onHeaderReceived(String name, String value) { 252 void _onHeaderReceived(String name, String value) {
133 _setHeader(name, value); 253 _headers.add(name, value);
134 } 254 }
135 255
136 void _onHeadersComplete() { 256 void _onHeadersComplete() {
137 // Prepare for receiving data. 257 // Prepare for receiving data.
138 _buffer = new _BufferList(); 258 _buffer = new _BufferList();
139 } 259 }
140 260
141 void _onDataReceived(List<int> data) { 261 void _onDataReceived(List<int> data) {
142 _buffer.add(data); 262 _buffer.add(data);
143 if (_inputStream != null) _inputStream._dataReceived(); 263 if (_inputStream != null) _inputStream._dataReceived();
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
212 if (_outputStream != null) throw new HttpException("Header already sent"); 332 if (_outputStream != null) throw new HttpException("Header already sent");
213 _statusCode = statusCode; 333 _statusCode = statusCode;
214 } 334 }
215 335
216 String get reasonPhrase() => _findReasonPhrase(_statusCode); 336 String get reasonPhrase() => _findReasonPhrase(_statusCode);
217 void set reasonPhrase(String reasonPhrase) { 337 void set reasonPhrase(String reasonPhrase) {
218 if (_outputStream != null) throw new HttpException("Header already sent"); 338 if (_outputStream != null) throw new HttpException("Header already sent");
219 _reasonPhrase = reasonPhrase; 339 _reasonPhrase = reasonPhrase;
220 } 340 }
221 341
222 Date get expires() => _expires;
223 void set expires(Date expires) {
224 if (_outputStream != null) throw new HttpException("Header already sent");
225 _expires = expires;
226 // Format "Expires" header with date in Greenwich Mean Time (GMT).
227 String formatted =
228 _HttpUtils.formatDate(_expires.changeTimeZone(new TimeZone.utc()));
229 _setHeader("Expires", formatted);
230 }
231
232 // Set a header on the response. NOTE: If the same header is set
233 // more than once only the last one will be part of the response.
234 void setHeader(String name, String value) {
235 if (_outputStream != null) return new HttpException("Header already sent");
236 if (name.toLowerCase() == "expires") {
237 expires = _HttpUtils.parseDate(value);
238 } else {
239 _setHeader(name, value);
240 }
241 }
242
243 OutputStream get outputStream() { 342 OutputStream get outputStream() {
244 if (_state == DONE) throw new HttpException("Response closed"); 343 if (_state == DONE) throw new HttpException("Response closed");
245 if (_outputStream == null) { 344 if (_outputStream == null) {
246 // Ensure that headers are written. 345 // Ensure that headers are written.
247 if (_state == START) { 346 if (_state == START) {
248 _writeHeader(); 347 _writeHeader();
249 } 348 }
250 _outputStream = new _HttpOutputStream(this); 349 _outputStream = new _HttpOutputStream(this);
251 } 350 }
252 return _outputStream; 351 return _outputStream;
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
356 _writeSP(); 455 _writeSP();
357 data = _statusCode.toString().charCodes(); 456 data = _statusCode.toString().charCodes();
358 _httpConnection._write(data); 457 _httpConnection._write(data);
359 _writeSP(); 458 _writeSP();
360 data = reasonPhrase.charCodes(); 459 data = reasonPhrase.charCodes();
361 _httpConnection._write(data); 460 _httpConnection._write(data);
362 _writeCRLF(); 461 _writeCRLF();
363 462
364 // Determine the value of the "Connection" header. 463 // Determine the value of the "Connection" header.
365 if (_protocolVersion == "1.1" && !_persistentConnection) { 464 if (_protocolVersion == "1.1" && !_persistentConnection) {
366 setHeader("Connection", "close"); 465 _headers.set("Connection", "close");
367 } else if (_protocolVersion == "1.0" && _persistentConnection) { 466 } else if (_protocolVersion == "1.0" && _persistentConnection) {
368 setHeader("Connection", "keep-alive"); 467 _headers.set("Connection", "keep-alive");
369 } 468 }
370 // Determine the value of the "Transfer-Encoding" header based on 469 // Determine the value of the "Transfer-Encoding" header based on
371 // whether the content length is known. 470 // whether the content length is known.
372 if (_contentLength >= 0) { 471 if (_contentLength >= 0) {
373 setHeader("Content-Length", _contentLength.toString()); 472 _headers.set("Content-Length", _contentLength.toString());
374 } else { 473 } else {
375 setHeader("Transfer-Encoding", "chunked"); 474 _headers.set("Transfer-Encoding", "chunked");
376 } 475 }
377 476
378 // Write headers. 477 // Write headers.
379 bool allWritten = _writeHeaders(); 478 bool allWritten = _writeHeaders();
380 _state = HEADERS_SENT; 479 _state = HEADERS_SENT;
381 return allWritten; 480 return allWritten;
382 } 481 }
383 482
384 // Response status code. 483 // Response status code.
385 int _statusCode; 484 int _statusCode;
386 String _reasonPhrase; 485 String _reasonPhrase;
387 String _protocolVersion; 486 String _protocolVersion;
388 Date _expires;
389 bool _persistentConnection; 487 bool _persistentConnection;
390 _HttpOutputStream _outputStream; 488 _HttpOutputStream _outputStream;
391 int _state; 489 int _state;
392 Function _streamErrorHandler; 490 Function _streamErrorHandler;
393 } 491 }
394 492
395 493
396 class _HttpInputStream extends _BaseDataInputStream implements InputStream { 494 class _HttpInputStream extends _BaseDataInputStream implements InputStream {
397 _HttpInputStream(_HttpRequestResponseBase this._requestOrResponse) { 495 _HttpInputStream(_HttpRequestResponseBase this._requestOrResponse) {
398 _checkScheduleCallbacks(); 496 _checkScheduleCallbacks();
(...skipping 327 matching lines...) Expand 10 before | Expand all | Expand 10 after
726 _state = START { 824 _state = START {
727 _connection = connection; 825 _connection = connection;
728 // Default GET requests to have no content. 826 // Default GET requests to have no content.
729 if (_method == "GET") { 827 if (_method == "GET") {
730 _contentLength = 0; 828 _contentLength = 0;
731 } 829 }
732 } 830 }
733 831
734 void set contentLength(int contentLength) => _contentLength = contentLength; 832 void set contentLength(int contentLength) => _contentLength = contentLength;
735 833
736 String get host() => _host;
737 void set host(String host) {
738 _host = host;
739 _updateHostHeader();
740 }
741
742 int get port() => _port;
743 void set port(int port) {
744 _port = port;
745 _updateHostHeader();
746 }
747
748 void setHeader(String name, String value) {
749 if (_state != START) throw new HttpException("Header already sent");
750 if (name.toLowerCase() == "host") {
751 int pos = value.indexOf(":");
752 if (pos == -1) {
753 _host = value;
754 _port = HttpClient.DEFAULT_HTTP_PORT;
755 } else {
756 _host = value.substring(0, pos);
757 if (pos + 1 == value.length) {
758 _port = HttpClient.DEFAULT_HTTP_PORT;
759 } else {
760 _port = Math.parseInt(value.substring(pos + 1));
761 }
762 }
763 _updateHostHeader();
764 return;
765 }
766 _setHeader(name, value);
767 }
768
769 OutputStream get outputStream() { 834 OutputStream get outputStream() {
770 if (_state == DONE) throw new HttpException("Request closed"); 835 if (_state == DONE) throw new HttpException("Request closed");
771 if (_outputStream == null) { 836 if (_outputStream == null) {
772 // Ensure that headers are written. 837 // Ensure that headers are written.
773 if (_state == START) { 838 if (_state == START) {
774 _writeHeader(); 839 _writeHeader();
775 } 840 }
776 _outputStream = new _HttpOutputStream(this); 841 _outputStream = new _HttpOutputStream(this);
777 } 842 }
778 return _outputStream; 843 return _outputStream;
779 } 844 }
780 845
781 _updateHostHeader() {
782 String portPart = _port == HttpClient.DEFAULT_HTTP_PORT ? "" : ":$_port";
783 _setHeader("Host", "$host$portPart");
784 }
785
786 // Delegate functions for the HttpOutputStream implementation. 846 // Delegate functions for the HttpOutputStream implementation.
787 bool _streamWrite(List<int> buffer, bool copyBuffer) { 847 bool _streamWrite(List<int> buffer, bool copyBuffer) {
788 return _write(buffer, copyBuffer); 848 return _write(buffer, copyBuffer);
789 } 849 }
790 850
791 bool _streamWriteFrom(List<int> buffer, int offset, int len) { 851 bool _streamWriteFrom(List<int> buffer, int offset, int len) {
792 return _writeList(buffer, offset, len); 852 return _writeList(buffer, offset, len);
793 } 853 }
794 854
795 void _streamClose() { 855 void _streamClose() {
(...skipping 27 matching lines...) Expand all
823 _writeSP(); 883 _writeSP();
824 data = _uri.toString().charCodes(); 884 data = _uri.toString().charCodes();
825 _httpConnection._write(data); 885 _httpConnection._write(data);
826 _writeSP(); 886 _writeSP();
827 _httpConnection._write(_Const.HTTP11); 887 _httpConnection._write(_Const.HTTP11);
828 _writeCRLF(); 888 _writeCRLF();
829 889
830 // Determine the value of the "Transfer-Encoding" header based on 890 // Determine the value of the "Transfer-Encoding" header based on
831 // whether the content length is known. 891 // whether the content length is known.
832 if (_contentLength >= 0) { 892 if (_contentLength >= 0) {
833 setHeader("Content-Length", _contentLength.toString()); 893 _headers.set("Content-Length", _contentLength.toString());
834 } else { 894 } else {
835 setHeader("Transfer-Encoding", "chunked"); 895 _headers.set("Transfer-Encoding", "chunked");
836 } 896 }
837 897
838 // Write headers. 898 // Write headers.
839 _writeHeaders(); 899 _writeHeaders();
840 _state = HEADERS_SENT; 900 _state = HEADERS_SENT;
841 } 901 }
842 902
843 String _method; 903 String _method;
844 String _uri; 904 String _uri;
845 String _host;
846 int _port;
847 _HttpClientConnection _connection; 905 _HttpClientConnection _connection;
848 _HttpOutputStream _outputStream; 906 _HttpOutputStream _outputStream;
849 int _state; 907 int _state;
850 Function _streamErrorHandler; 908 Function _streamErrorHandler;
851 } 909 }
852 910
853 911
854 class _HttpClientResponse 912 class _HttpClientResponse
855 extends _HttpRequestResponseBase implements HttpClientResponse { 913 extends _HttpRequestResponseBase implements HttpClientResponse {
856 _HttpClientResponse(_HttpClientConnection connection) 914 _HttpClientResponse(_HttpClientConnection connection)
857 : super(connection) { 915 : super(connection) {
858 _connection = connection; 916 _connection = connection;
859 } 917 }
860 918
861 int get statusCode() => _statusCode; 919 int get statusCode() => _statusCode;
862 String get reasonPhrase() => _reasonPhrase; 920 String get reasonPhrase() => _reasonPhrase;
863 921
864 Date get expires() {
865 String str = _headers["expires"];
866 if (str == null) return null;
867 return _HttpUtils.parseDate(str);
868 }
869
870 Map get headers() => _headers;
871
872 InputStream get inputStream() { 922 InputStream get inputStream() {
873 if (_inputStream == null) { 923 if (_inputStream == null) {
874 _inputStream = new _HttpInputStream(this); 924 _inputStream = new _HttpInputStream(this);
875 } 925 }
876 return _inputStream; 926 return _inputStream;
877 } 927 }
878 928
879 void _onRequestStart(String method, String uri, String version) { 929 void _onRequestStart(String method, String uri, String version) {
880 // TODO(sgjesse): Error handling 930 // TODO(sgjesse): Error handling
881 } 931 }
882 932
883 void _onResponseStart(int statusCode, String reasonPhrase, String version) { 933 void _onResponseStart(int statusCode, String reasonPhrase, String version) {
884 _statusCode = statusCode; 934 _statusCode = statusCode;
885 _reasonPhrase = reasonPhrase; 935 _reasonPhrase = reasonPhrase;
886 } 936 }
887 937
888 void _onHeaderReceived(String name, String value) { 938 void _onHeaderReceived(String name, String value) {
889 _setHeader(name, value); 939 _headers.add(name, value);
890 } 940 }
891 941
892 void _onHeadersComplete() { 942 void _onHeadersComplete() {
893 _buffer = new _BufferList(); 943 _buffer = new _BufferList();
894 if (_connection._onResponse != null) { 944 if (_connection._onResponse != null) {
895 _connection._onResponse(this); 945 _connection._onResponse(this);
896 } 946 }
897 } 947 }
898 948
899 void _onDataReceived(List<int> data) { 949 void _onDataReceived(List<int> data) {
(...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after
1142 return "$host:$port"; 1192 return "$host:$port";
1143 } 1193 }
1144 1194
1145 HttpClientConnection _prepareHttpClientConnection( 1195 HttpClientConnection _prepareHttpClientConnection(
1146 String host, int port, String method, String path) { 1196 String host, int port, String method, String path) {
1147 1197
1148 void _connectionOpened(_SocketConnection socketConn, 1198 void _connectionOpened(_SocketConnection socketConn,
1149 _HttpClientConnection connection) { 1199 _HttpClientConnection connection) {
1150 connection._connectionEstablished(socketConn); 1200 connection._connectionEstablished(socketConn);
1151 HttpClientRequest request = connection.open(method, path); 1201 HttpClientRequest request = connection.open(method, path);
1152 request.host = host; 1202 request.headers.host = host;
1153 request.port = port; 1203 request.headers.port = port;
1154 if (connection._onRequest != null) { 1204 if (connection._onRequest != null) {
1155 connection._onRequest(request); 1205 connection._onRequest(request);
1156 } else { 1206 } else {
1157 request.outputStream.close(); 1207 request.outputStream.close();
1158 } 1208 }
1159 } 1209 }
1160 1210
1161 _HttpClientConnection connection = new _HttpClientConnection(this); 1211 _HttpClientConnection connection = new _HttpClientConnection(this);
1162 1212
1163 // If there are active connections for this key get the first one 1213 // If there are active connections for this key get the first one
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
1243 sockets.addFirst(socketConn); 1293 sockets.addFirst(socketConn);
1244 socketConn._markReturned(); 1294 socketConn._markReturned();
1245 } 1295 }
1246 1296
1247 Function _onOpen; 1297 Function _onOpen;
1248 Map<String, Queue<_SocketConnection>> _openSockets; 1298 Map<String, Queue<_SocketConnection>> _openSockets;
1249 Set<_SocketConnection> _activeSockets; 1299 Set<_SocketConnection> _activeSockets;
1250 Timer _evictionTimer; 1300 Timer _evictionTimer;
1251 bool _shutdown; // Has this HTTP client been shutdown? 1301 bool _shutdown; // Has this HTTP client been shutdown?
1252 } 1302 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698