| OLD | NEW | 
|     1 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file |     1 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file | 
|     2 // for details. All rights reserved. Use of this source code is governed by a |     2 // for details. All rights reserved. Use of this source code is governed by a | 
|     3 // BSD-style license that can be found in the LICENSE file. |     3 // BSD-style license that can be found in the LICENSE file. | 
|     4  |     4  | 
|     5 class _HttpHeaders implements HttpHeaders { |     5 class _HttpHeaders implements HttpHeaders { | 
|     6   _HttpHeaders() : _headers = new Map<String, List<String>>(); |     6   _HttpHeaders() : _headers = new Map<String, List<String>>(); | 
|     7  |     7  | 
|     8   List<String> operator[](String name) { |     8   List<String> operator[](String name) { | 
|     9     name = name.toLowerCase(); |     9     name = name.toLowerCase(); | 
|    10     return _headers[name]; |    10     return _headers[name]; | 
| (...skipping 587 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   598   String value; |   598   String value; | 
|   599   Date expires; |   599   Date expires; | 
|   600   int maxAge; |   600   int maxAge; | 
|   601   String domain; |   601   String domain; | 
|   602   String path; |   602   String path; | 
|   603   bool httpOnly = false; |   603   bool httpOnly = false; | 
|   604   bool secure = false; |   604   bool secure = false; | 
|   605 } |   605 } | 
|   606  |   606  | 
|   607  |   607  | 
 |   608 // The close queue handles graceful closing of HTTP connections. When | 
 |   609 // a connection is added to the queue it will enter a wait state | 
 |   610 // waiting for all data written and possibly socket shutdown from | 
 |   611 // peer. | 
 |   612 class _CloseQueue { | 
 |   613   _CloseQueue() : _q = new Set<_HttpConnectionBase>(); | 
 |   614  | 
 |   615   void add(_HttpConnectionBase connection) { | 
 |   616     void closeIfDone() { | 
 |   617       // We only check for write closed here. This means that we are | 
 |   618       // not waiting for the client to half-close the socket before | 
 |   619       // fully closing the socket. | 
 |   620       if (!connection._isWriteClosed) return; | 
 |   621       _q.remove(connection); | 
 |   622       connection._socket.close(); | 
 |   623       if (connection.onClosed != null) connection.onClosed(); | 
 |   624     } | 
 |   625  | 
 |   626     // If the connection is already fully closed don't insert it into the queue. | 
 |   627     if (connection._isFullyClosed) { | 
 |   628       connection._socket.close(); | 
 |   629       if (connection.onClosed != null) connection.onClosed(); | 
 |   630       return; | 
 |   631     } | 
 |   632  | 
 |   633     _q.add(connection); | 
 |   634  | 
 |   635     // If output stream is not closed for writing close it now and | 
 |   636     // wait for callback when closed. | 
 |   637     if (!connection._isWriteClosed) { | 
 |   638       connection._socket.outputStream.close(); | 
 |   639       connection._socket.outputStream.onClosed = () { | 
 |   640         connection._state |= _HttpConnectionBase.WRITE_CLOSED; | 
 |   641         closeIfDone(); | 
 |   642       }; | 
 |   643     } else { | 
 |   644       connection._socket.outputStream.onClosed = () { assert(false); }; | 
 |   645     } | 
 |   646  | 
 |   647     // If socket is not closed for reading wait for callback. | 
 |   648     if (!connection._isReadClosed) { | 
 |   649       connection._socket.onClosed = () { | 
 |   650         connection._state |= _HttpConnectionBase.READ_CLOSED; | 
 |   651         // This is a nop, as we are not using the read closed | 
 |   652         // information for anything. For both server and client | 
 |   653         // connections the inbound message have been read to | 
 |   654         // completion when the socket enters the close queue. | 
 |   655       }; | 
 |   656     } else { | 
 |   657       connection._socket.onClosed = () { assert(false); }; | 
 |   658     } | 
 |   659  | 
 |   660     // Ignore any data on a socket in the close queue. | 
 |   661     connection._socket.onData = connection._socket.read; | 
 |   662  | 
 |   663     // If an error occurs immediately close the socket. | 
 |   664     connection._socket.onError = (e) { | 
 |   665       connection._state |= _HttpConnectionBase.WRITE_CLOSED; | 
 |   666       closeIfDone(); | 
 |   667     }; | 
 |   668   } | 
 |   669  | 
 |   670   void shutdown() { | 
 |   671     _q.forEach((_HttpConnectionBase connection) { | 
 |   672       connection._socket.close(); | 
 |   673     }); | 
 |   674   } | 
 |   675  | 
 |   676   final Set<_HttpConnectionBase> _q; | 
 |   677 } | 
 |   678  | 
 |   679  | 
|   608 class _HttpRequestResponseBase { |   680 class _HttpRequestResponseBase { | 
|   609   final int START = 0; |   681   final int START = 0; | 
|   610   final int HEADER_SENT = 1; |   682   final int HEADER_SENT = 1; | 
|   611   final int DONE = 2; |   683   final int DONE = 2; | 
|   612   final int UPGRADED = 3; |   684   final int UPGRADED = 3; | 
|   613  |   685  | 
|   614   _HttpRequestResponseBase(_HttpConnectionBase this._httpConnection) |   686   _HttpRequestResponseBase(_HttpConnectionBase this._httpConnection) | 
|   615       : _headers = new _HttpHeaders() { |   687       : _headers = new _HttpHeaders() { | 
|   616     _state = START; |   688     _state = START; | 
|   617     _headResponse = false; |   689     _headResponse = false; | 
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   689     bool allWritten = true; |   761     bool allWritten = true; | 
|   690     if (_contentLength < 0) { |   762     if (_contentLength < 0) { | 
|   691       // Terminate the content if transfer encoding is chunked. |   763       // Terminate the content if transfer encoding is chunked. | 
|   692       allWritten = _httpConnection._write(_Const.END_CHUNKED); |   764       allWritten = _httpConnection._write(_Const.END_CHUNKED); | 
|   693     } else { |   765     } else { | 
|   694       if (!_headResponse && _bodyBytesWritten < _contentLength) { |   766       if (!_headResponse && _bodyBytesWritten < _contentLength) { | 
|   695         throw new HttpException("Sending less than specified content length"); |   767         throw new HttpException("Sending less than specified content length"); | 
|   696       } |   768       } | 
|   697       assert(_headResponse || _bodyBytesWritten == _contentLength); |   769       assert(_headResponse || _bodyBytesWritten == _contentLength); | 
|   698     } |   770     } | 
|   699     // If we are done writing the response, and either the client has |  | 
|   700     // closed or the connection is not persistent, we can close. Also |  | 
|   701     // if using HTTP 1.0 and the content length was not known we must |  | 
|   702     // close to indicate end of body. |  | 
|   703     if (!persistentConnection || _httpConnection._closing || |  | 
|   704         (_protocolVersion == "1.0" && _contentLength < 0)) { |  | 
|   705       _httpConnection._close(); |  | 
|   706     } |  | 
|   707     return allWritten; |   771     return allWritten; | 
|   708   } |   772   } | 
|   709  |   773  | 
|   710   bool _writeHeaders() { |   774   bool _writeHeaders() { | 
|   711     _headers._mutable = false; |   775     _headers._mutable = false; | 
|   712     _headers._write(_httpConnection); |   776     _headers._write(_httpConnection); | 
|   713     // Terminate header. |   777     // Terminate header. | 
|   714     return _writeCRLF(); |   778     return _writeCRLF(); | 
|   715   } |   779   } | 
|   716  |   780  | 
| (...skipping 289 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  1006     if (_state == START) { |  1070     if (_state == START) { | 
|  1007       _writeHeader(); |  1071       _writeHeader(); | 
|  1008     } |  1072     } | 
|  1009     _state = UPGRADED; |  1073     _state = UPGRADED; | 
|  1010     // Ensure that any trailing data is written. |  1074     // Ensure that any trailing data is written. | 
|  1011     _writeDone(); |  1075     _writeDone(); | 
|  1012     // Indicate to the connection that the response handling is done. |  1076     // Indicate to the connection that the response handling is done. | 
|  1013     return _httpConnection._detachSocket(); |  1077     return _httpConnection._detachSocket(); | 
|  1014   } |  1078   } | 
|  1015  |  1079  | 
|  1016   void _responseEnd() { |  | 
|  1017     _ensureHeadersSent(); |  | 
|  1018     _state = DONE; |  | 
|  1019     // Stop tracking no pending write events. |  | 
|  1020     _httpConnection._onNoPendingWrites = null; |  | 
|  1021     // Ensure that any trailing data is written. |  | 
|  1022     _writeDone(); |  | 
|  1023     // Indicate to the connection that the response handling is done. |  | 
|  1024     _httpConnection._responseDone(); |  | 
|  1025   } |  | 
|  1026  |  | 
|  1027   // Delegate functions for the HttpOutputStream implementation. |  1080   // Delegate functions for the HttpOutputStream implementation. | 
|  1028   bool _streamWrite(List<int> buffer, bool copyBuffer) { |  1081   bool _streamWrite(List<int> buffer, bool copyBuffer) { | 
|  1029     if (_done) throw new HttpException("Response closed"); |  1082     if (_done) throw new HttpException("Response closed"); | 
|  1030     return _write(buffer, copyBuffer); |  1083     return _write(buffer, copyBuffer); | 
|  1031   } |  1084   } | 
|  1032  |  1085  | 
|  1033   bool _streamWriteFrom(List<int> buffer, int offset, int len) { |  1086   bool _streamWriteFrom(List<int> buffer, int offset, int len) { | 
|  1034     if (_done) throw new HttpException("Response closed"); |  1087     if (_done) throw new HttpException("Response closed"); | 
|  1035     return _writeList(buffer, offset, len); |  1088     return _writeList(buffer, offset, len); | 
|  1036   } |  1089   } | 
|  1037  |  1090  | 
|  1038   void _streamFlush() { |  1091   void _streamFlush() { | 
|  1039     _httpConnection._flush(); |  1092     _httpConnection._flush(); | 
|  1040   } |  1093   } | 
|  1041  |  1094  | 
|  1042   void _streamClose() { |  1095   void _streamClose() { | 
|  1043     _responseEnd(); |  1096     _ensureHeadersSent(); | 
 |  1097     _state = DONE; | 
 |  1098     // Stop tracking no pending write events. | 
 |  1099     _httpConnection._onNoPendingWrites = null; | 
 |  1100     // Ensure that any trailing data is written. | 
 |  1101     _writeDone(); | 
 |  1102     // Indicate to the connection that the response handling is done. | 
 |  1103     _httpConnection._responseClosed(); | 
|  1044   } |  1104   } | 
|  1045  |  1105  | 
|  1046   void _streamSetNoPendingWriteHandler(callback()) { |  1106   void _streamSetNoPendingWriteHandler(callback()) { | 
|  1047     if (_state != DONE) { |  1107     if (_state != DONE) { | 
|  1048       _httpConnection._onNoPendingWrites = callback; |  1108       _httpConnection._onNoPendingWrites = callback; | 
|  1049     } |  1109     } | 
|  1050   } |  1110   } | 
|  1051  |  1111  | 
|  1052   void _streamSetCloseHandler(callback()) { |  1112   void _streamSetCloseHandler(callback()) { | 
|  1053     // TODO(sgjesse): Handle this. |  1113     // TODO(sgjesse): Handle this. | 
| (...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  1250  |  1310  | 
|  1251   void set onError(void callback(e)) { |  1311   void set onError(void callback(e)) { | 
|  1252     _requestOrResponse._streamSetErrorHandler(callback); |  1312     _requestOrResponse._streamSetErrorHandler(callback); | 
|  1253   } |  1313   } | 
|  1254  |  1314  | 
|  1255   _HttpRequestResponseBase _requestOrResponse; |  1315   _HttpRequestResponseBase _requestOrResponse; | 
|  1256 } |  1316 } | 
|  1257  |  1317  | 
|  1258  |  1318  | 
|  1259 abstract class _HttpConnectionBase { |  1319 abstract class _HttpConnectionBase { | 
|  1260   _HttpConnectionBase() : _httpParser = new _HttpParser(), |  1320   static const int IDLE = 0; | 
|  1261                           hashCode = _nextHashCode { |  1321   static const int ACTIVE = 1; | 
 |  1322   static const int REQUEST_DONE = 2; | 
 |  1323   static const int RESPONSE_DONE = 4; | 
 |  1324   static const int ALL_DONE = REQUEST_DONE | RESPONSE_DONE; | 
 |  1325   static const int READ_CLOSED = 8; | 
 |  1326   static const int WRITE_CLOSED = 16; | 
 |  1327   static const int FULLY_CLOSED = READ_CLOSED | WRITE_CLOSED; | 
 |  1328  | 
 |  1329   _HttpConnectionBase() : hashCode = _nextHashCode { | 
|  1262     _nextHashCode = (_nextHashCode + 1) & 0xFFFFFFF; |  1330     _nextHashCode = (_nextHashCode + 1) & 0xFFFFFFF; | 
|  1263   } |  1331   } | 
|  1264  |  1332  | 
 |  1333   bool get _isRequestDone => (_state & REQUEST_DONE) == REQUEST_DONE; | 
 |  1334   bool get _isResponseDone => (_state & RESPONSE_DONE) == RESPONSE_DONE; | 
 |  1335   bool get _isAllDone => (_state & ALL_DONE) == ALL_DONE; | 
 |  1336   bool get _isReadClosed => (_state & READ_CLOSED) == READ_CLOSED; | 
 |  1337   bool get _isWriteClosed => (_state & WRITE_CLOSED) == WRITE_CLOSED; | 
 |  1338   bool get _isFullyClosed => (_state & FULLY_CLOSED) == FULLY_CLOSED; | 
 |  1339  | 
|  1265   void _connectionEstablished(Socket socket) { |  1340   void _connectionEstablished(Socket socket) { | 
|  1266     _socket = socket; |  1341     _socket = socket; | 
|  1267     // Register handler for socket events. |  1342     // Register handlers for socket events. All socket events are | 
|  1268     _socket.onData = _onData; |  1343     // passed to the HTTP parser. | 
|  1269     _socket.onClosed = _onClosed; |  1344     _socket.onData = () { | 
|  1270     _socket.onError = _onError; |  1345       List<int> buffer = _socket.read(); | 
 |  1346       if (buffer != null) { | 
 |  1347         _httpParser.streamData(buffer); | 
 |  1348       } | 
 |  1349     }; | 
 |  1350     _socket.onClosed = _httpParser.streamDone; | 
 |  1351     _socket.onError = _httpParser.streamError; | 
|  1271     // Ignore errors in the socket output stream as this is getting |  1352     // Ignore errors in the socket output stream as this is getting | 
|  1272     // the same errors as the socket itself. |  1353     // the same errors as the socket itself. | 
|  1273     _socket.outputStream.onError = (e) => null; |  1354     _socket.outputStream.onError = (e) => null; | 
|  1274   } |  1355   } | 
|  1275  |  1356  | 
|  1276   bool _write(List<int> data, [bool copyBuffer = false]) { |  1357   bool _write(List<int> data, [bool copyBuffer = false]) { | 
|  1277     if (!_error && !_closing) { |  1358     return _socket.outputStream.write(data, copyBuffer); | 
|  1278       return _socket.outputStream.write(data, copyBuffer); |  | 
|  1279     } |  | 
|  1280   } |  1359   } | 
|  1281  |  1360  | 
|  1282   bool _writeFrom(List<int> buffer, [int offset, int len]) { |  1361   bool _writeFrom(List<int> buffer, [int offset, int len]) { | 
|  1283     if (!_error && !_closing) { |  1362     return _socket.outputStream.writeFrom(buffer, offset, len); | 
|  1284       return _socket.outputStream.writeFrom(buffer, offset, len); |  | 
|  1285     } |  | 
|  1286   } |  1363   } | 
|  1287  |  1364  | 
|  1288   bool _flush() { |  1365   bool _flush() { | 
|  1289     _socket.outputStream.flush(); |  1366     _socket.outputStream.flush(); | 
|  1290   } |  1367   } | 
|  1291  |  1368  | 
|  1292   bool _close() { |  1369   bool _close() { | 
|  1293     _closing = true; |  | 
|  1294     _socket.outputStream.close(); |  1370     _socket.outputStream.close(); | 
|  1295   } |  1371   } | 
|  1296  |  1372  | 
|  1297   bool _destroy() { |  1373   bool _destroy() { | 
|  1298     _closing = true; |  | 
|  1299     _socket.close(); |  1374     _socket.close(); | 
|  1300   } |  1375   } | 
|  1301  |  1376  | 
|  1302   void _onData() { |  | 
|  1303     List<int> buffer = _socket.read(); |  | 
|  1304     if (buffer != null) { |  | 
|  1305       _httpParser.writeList(buffer, 0, buffer.length); |  | 
|  1306     } |  | 
|  1307   } |  | 
|  1308  |  | 
|  1309   void _onClosed() { |  | 
|  1310     _closing = true; |  | 
|  1311     _onConnectionClosed(null); |  | 
|  1312   } |  | 
|  1313  |  | 
|  1314   void _onError(e) { |  | 
|  1315     // If an error occurs, make sure to close the socket if one is associated. |  | 
|  1316     _error = true; |  | 
|  1317     if (_socket != null) { |  | 
|  1318       _socket.close(); |  | 
|  1319     } |  | 
|  1320     _onConnectionClosed(e); |  | 
|  1321   } |  | 
|  1322  |  | 
|  1323   DetachedSocket _detachSocket() { |  1377   DetachedSocket _detachSocket() { | 
|  1324     _socket.onData = null; |  1378     _socket.onData = null; | 
|  1325     _socket.onClosed = null; |  1379     _socket.onClosed = null; | 
|  1326     _socket.onError = null; |  1380     _socket.onError = null; | 
|  1327     _socket.outputStream.onNoPendingWrites = null; |  1381     _socket.outputStream.onNoPendingWrites = null; | 
|  1328     Socket socket = _socket; |  1382     Socket socket = _socket; | 
|  1329     _socket = null; |  1383     _socket = null; | 
|  1330     if (onDetach != null) onDetach(); |  1384     if (onDetach != null) onDetach(); | 
|  1331     return new _DetachedSocket(socket, _httpParser.readUnparsedData()); |  1385     return new _DetachedSocket(socket, _httpParser.readUnparsedData()); | 
|  1332   } |  1386   } | 
|  1333  |  1387  | 
|  1334   HttpConnectionInfo get connectionInfo { |  1388   HttpConnectionInfo get connectionInfo { | 
|  1335     if (_socket == null || _closing || _error) return null; |  1389     if (_socket == null) return null; | 
|  1336     try { |  1390     try { | 
|  1337       _HttpConnectionInfo info = new _HttpConnectionInfo(); |  1391       _HttpConnectionInfo info = new _HttpConnectionInfo(); | 
|  1338       info.remoteHost = _socket.remoteHost; |  1392       info.remoteHost = _socket.remoteHost; | 
|  1339       info.remotePort = _socket.remotePort; |  1393       info.remotePort = _socket.remotePort; | 
|  1340       info.localPort = _socket.port; |  1394       info.localPort = _socket.port; | 
|  1341       return info; |  1395       return info; | 
|  1342     } catch (e) { } |  1396     } catch (e) { } | 
|  1343     return null; |  1397     return null; | 
|  1344   } |  1398   } | 
|  1345  |  1399  | 
|  1346   void _onConnectionClosed(e); |  | 
|  1347   void _responseDone(); |  | 
|  1348  |  | 
|  1349   void set _onNoPendingWrites(void callback()) { |  1400   void set _onNoPendingWrites(void callback()) { | 
|  1350     if (!_error) { |  1401     _socket.outputStream.onNoPendingWrites = callback; | 
|  1351       _socket.outputStream.onNoPendingWrites = callback; |  | 
|  1352     } |  | 
|  1353   } |  1402   } | 
|  1354  |  1403  | 
 |  1404   int _state = IDLE; | 
 |  1405  | 
|  1355   Socket _socket; |  1406   Socket _socket; | 
|  1356   bool _closing = false;  // Is the socket closed by the client? |  | 
|  1357   bool _error = false;  // Is the socket closed due to an error? |  | 
|  1358   _HttpParser _httpParser; |  1407   _HttpParser _httpParser; | 
|  1359  |  1408  | 
 |  1409   // Callbacks. | 
|  1360   Function onDetach; |  1410   Function onDetach; | 
 |  1411   Function onClosed; | 
|  1361  |  1412  | 
|  1362   // Hash code for HTTP connection. Currently this is just a counter. |  1413   // Hash code for HTTP connection. Currently this is just a counter. | 
|  1363   final int hashCode; |  1414   final int hashCode; | 
|  1364   static int _nextHashCode = 0; |  1415   static int _nextHashCode = 0; | 
|  1365 } |  1416 } | 
|  1366  |  1417  | 
|  1367  |  1418  | 
|  1368 // HTTP server connection over a socket. |  1419 // HTTP server connection over a socket. | 
|  1369 class _HttpConnection extends _HttpConnectionBase { |  1420 class _HttpConnection extends _HttpConnectionBase { | 
|  1370   _HttpConnection(HttpServer this._server) { |  1421   _HttpConnection(HttpServer this._server) { | 
 |  1422     _httpParser = new _HttpParser.requestParser(); | 
|  1371     // Register HTTP parser callbacks. |  1423     // Register HTTP parser callbacks. | 
|  1372     _httpParser.requestStart = |  1424     _httpParser.requestStart = _onRequestStart; | 
|  1373       (method, uri, version) => _onRequestStart(method, uri, version); |  1425     _httpParser.headerReceived = _onHeaderReceived; | 
|  1374     _httpParser.responseStart = |  1426     _httpParser.headersComplete = _onHeadersComplete; | 
|  1375       (statusCode, reasonPhrase, version) => |  1427     _httpParser.dataReceived = _onDataReceived; | 
|  1376       _onResponseStart(statusCode, reasonPhrase, version); |  1428     _httpParser.dataEnd = _onDataEnd; | 
|  1377     _httpParser.headerReceived = |  1429     _httpParser.error = _onError; | 
|  1378         (name, value) => _onHeaderReceived(name, value); |  1430     _httpParser.closed = _onClosed; | 
|  1379     _httpParser.headersComplete = () => _onHeadersComplete(); |  1431     _httpParser.responseStart = (statusCode, reasonPhrase, version) { | 
|  1380     _httpParser.dataReceived = (data) => _onDataReceived(data); |  1432       assert(false); | 
|  1381     _httpParser.dataEnd = (close) => _onDataEnd(close); |  1433     }; | 
|  1382     _httpParser.error = (e) => _onError(e); |  | 
|  1383   } |  1434   } | 
|  1384  |  1435  | 
|  1385   void _onConnectionClosed(e) { |  1436   void _onClosed() { | 
|  1386     // Don't report errors when HTTP parser is in idle state. Clients |  1437     _state |= _HttpConnectionBase.READ_CLOSED; | 
|  1387     // can close the connection and cause a connection reset by peer |  1438   } | 
|  1388     // error which is OK. |  1439  | 
|  1389     if (e != null && !_httpParser.isIdle) { |  1440   void _onError(e) { | 
|  1390       onError(e); |  1441     onError(e); | 
|  1391       // Propagate the error to the streams. |  1442     // Propagate the error to the streams. | 
|  1392       if (_request != null && _request._streamErrorHandler != null) { |  1443     if (_request != null && _request._streamErrorHandler != null) { | 
|  1393         _request._streamErrorHandler(e); |  1444       _request._streamErrorHandler(e); | 
|  1394       } |  | 
|  1395       if (_response != null && _response._streamErrorHandler != null) { |  | 
|  1396         _response._streamErrorHandler(e); |  | 
|  1397       } |  | 
|  1398     } |  1445     } | 
|  1399  |  1446     if (_response != null && _response._streamErrorHandler != null) { | 
|  1400     // If currently not processing any request close the socket when |  1447       _response._streamErrorHandler(e); | 
|  1401     // we are done writing the response. |  | 
|  1402     if (_httpParser.isIdle) { |  | 
|  1403       // If the httpParser is idle and we get an error from the |  | 
|  1404       // connection we deal with that as a closed connection and not |  | 
|  1405       // as an error. When the client disappears we get a connection |  | 
|  1406       // reset by peer and that is OK. |  | 
|  1407       if (e != null) { |  | 
|  1408         onClosed(); |  | 
|  1409       } else { |  | 
|  1410         _socket.outputStream.onClosed = () { |  | 
|  1411           _destroy(); |  | 
|  1412           onClosed(); |  | 
|  1413         }; |  | 
|  1414         // If the client closes and we are done writing the response |  | 
|  1415         // the connection should be closed. |  | 
|  1416         if (_response == null) _close(); |  | 
|  1417       } |  | 
|  1418     } else { |  | 
|  1419       // Processing a request. |  | 
|  1420       if (e == null) { |  | 
|  1421         // Indicate connection close to the HTTP parser. |  | 
|  1422         _httpParser.connectionClosed(); |  | 
|  1423       } |  | 
|  1424     } |  1448     } | 
 |  1449     if (_socket != null) _socket.close(); | 
|  1425   } |  1450   } | 
|  1426  |  1451  | 
|  1427   void _onRequestStart(String method, String uri, String version) { |  1452   void _onRequestStart(String method, String uri, String version) { | 
 |  1453     _state = _HttpConnectionBase.ACTIVE; | 
|  1428     // Create new request and response objects for this request. |  1454     // Create new request and response objects for this request. | 
|  1429     _request = new _HttpRequest(this); |  1455     _request = new _HttpRequest(this); | 
|  1430     _response = new _HttpResponse(this); |  1456     _response = new _HttpResponse(this); | 
|  1431     _request._onRequestStart(method, uri, version); |  1457     _request._onRequestStart(method, uri, version); | 
|  1432     _request._protocolVersion = version; |  1458     _request._protocolVersion = version; | 
|  1433     _response._protocolVersion = version; |  1459     _response._protocolVersion = version; | 
|  1434     _response._headResponse = method == "HEAD"; |  1460     _response._headResponse = method == "HEAD"; | 
|  1435   } |  1461   } | 
|  1436  |  1462  | 
|  1437   void _onResponseStart(int statusCode, String reasonPhrase, String version) { |  | 
|  1438     // TODO(sgjesse): Error handling. |  | 
|  1439   } |  | 
|  1440  |  | 
|  1441   void _onHeaderReceived(String name, String value) { |  1463   void _onHeaderReceived(String name, String value) { | 
|  1442     _request._onHeaderReceived(name, value); |  1464     _request._onHeaderReceived(name, value); | 
|  1443   } |  1465   } | 
|  1444  |  1466  | 
|  1445   void _onHeadersComplete() { |  1467   void _onHeadersComplete() { | 
|  1446     _request._onHeadersComplete(); |  1468     _request._onHeadersComplete(); | 
|  1447     _response.persistentConnection = _httpParser.persistentConnection; |  1469     _response.persistentConnection = _httpParser.persistentConnection; | 
|  1448     if (onRequestReceived != null) { |  1470     if (onRequestReceived != null) { | 
|  1449       onRequestReceived(_request, _response); |  1471       onRequestReceived(_request, _response); | 
|  1450     } |  1472     } | 
|  1451   } |  1473   } | 
|  1452  |  1474  | 
|  1453   void _onDataReceived(List<int> data) { |  1475   void _onDataReceived(List<int> data) { | 
|  1454     _request._onDataReceived(data); |  1476     _request._onDataReceived(data); | 
|  1455   } |  1477   } | 
|  1456  |  1478  | 
 |  1479   void _checkDone() { | 
 |  1480     if (_isAllDone) { | 
 |  1481       // If we are done writing the response, and either the client | 
 |  1482       // has closed or the connection is not persistent, we must | 
 |  1483       // close. Also if using HTTP 1.0 and the content length was not | 
 |  1484       // known we must close to indicate end of body. | 
 |  1485       bool close = | 
 |  1486           !_response.persistentConnection || | 
 |  1487           (_response._protocolVersion == "1.0" && _response._contentLength < 0); | 
 |  1488       _request = null; | 
 |  1489       _response = null; | 
 |  1490       if (_isReadClosed || close) { | 
 |  1491         _server._closeQueue.add(this); | 
 |  1492       } else { | 
 |  1493         _state = _HttpConnectionBase.IDLE; | 
 |  1494       } | 
 |  1495     } | 
 |  1496   } | 
 |  1497  | 
|  1457   void _onDataEnd(bool close) { |  1498   void _onDataEnd(bool close) { | 
|  1458     _request._onDataEnd(); |  1499     _request._onDataEnd(); | 
 |  1500     _state |= _HttpConnectionBase.REQUEST_DONE; | 
 |  1501     _checkDone(); | 
|  1459   } |  1502   } | 
|  1460  |  1503  | 
|  1461   void _responseDone() { |  1504   void _responseClosed() { | 
|  1462     // If the connection is closing then close the output stream to |  1505     _state |= _HttpConnectionBase.RESPONSE_DONE; | 
|  1463     // fully close the socket. |  1506     _checkDone(); | 
|  1464     if (_closing) { |  | 
|  1465       _socket.outputStream.onClosed = () { |  | 
|  1466         _socket.close(); |  | 
|  1467         onClosed(); |  | 
|  1468       }; |  | 
|  1469     } |  | 
|  1470     _response = null; |  | 
|  1471   } |  1507   } | 
|  1472  |  1508  | 
|  1473   HttpServer _server; |  1509   HttpServer _server; | 
|  1474   HttpRequest _request; |  1510   HttpRequest _request; | 
|  1475   HttpResponse _response; |  1511   HttpResponse _response; | 
|  1476  |  1512  | 
|  1477   // Callbacks. |  1513   // Callbacks. | 
|  1478   Function onRequestReceived; |  1514   Function onRequestReceived; | 
|  1479   Function onClosed; |  | 
|  1480   Function onError; |  1515   Function onError; | 
|  1481 } |  1516 } | 
|  1482  |  1517  | 
|  1483  |  1518  | 
|  1484 class _RequestHandlerRegistration { |  1519 class _RequestHandlerRegistration { | 
|  1485   _RequestHandlerRegistration(Function this._matcher, Function this._handler); |  1520   _RequestHandlerRegistration(Function this._matcher, Function this._handler); | 
|  1486   Function _matcher; |  1521   Function _matcher; | 
|  1487   Function _handler; |  1522   Function _handler; | 
|  1488 } |  1523 } | 
|  1489  |  1524  | 
|  1490 // HTTP server waiting for socket connections. The connections are |  1525 // HTTP server waiting for socket connections. The connections are | 
|  1491 // managed by the server and as requests are received the request. |  1526 // managed by the server and as requests are received the request. | 
|  1492 class _HttpServer implements HttpServer { |  1527 class _HttpServer implements HttpServer { | 
|  1493   _HttpServer() : _connections = new Set<_HttpConnection>(), |  1528   _HttpServer() : _connections = new Set<_HttpConnection>(), | 
|  1494                   _handlers = new List<_RequestHandlerRegistration>(); |  1529                   _handlers = new List<_RequestHandlerRegistration>(), | 
 |  1530                   _closeQueue = new _CloseQueue(); | 
|  1495  |  1531  | 
|  1496   void listen(String host, int port, {int backlog: 128}) { |  1532   void listen(String host, int port, {int backlog: 128}) { | 
|  1497     listenOn(new ServerSocket(host, port, backlog)); |  1533     listenOn(new ServerSocket(host, port, backlog)); | 
|  1498     _closeServer = true; |  1534     _closeServer = true; | 
|  1499   } |  1535   } | 
|  1500  |  1536  | 
|  1501   void listenOn(ServerSocket serverSocket) { |  1537   void listenOn(ServerSocket serverSocket) { | 
|  1502     void onConnection(Socket socket) { |  1538     void onConnection(Socket socket) { | 
|  1503       // Accept the client connection. |  1539       // Accept the client connection. | 
|  1504       _HttpConnection connection = new _HttpConnection(this); |  1540       _HttpConnection connection = new _HttpConnection(this); | 
| (...skipping 20 matching lines...) Expand all  Loading... | 
|  1525                     void handler(HttpRequest request, HttpResponse response)) { |  1561                     void handler(HttpRequest request, HttpResponse response)) { | 
|  1526     _handlers.add(new _RequestHandlerRegistration(matcher, handler)); |  1562     _handlers.add(new _RequestHandlerRegistration(matcher, handler)); | 
|  1527   } |  1563   } | 
|  1528  |  1564  | 
|  1529   void set defaultRequestHandler( |  1565   void set defaultRequestHandler( | 
|  1530       void handler(HttpRequest request, HttpResponse response)) { |  1566       void handler(HttpRequest request, HttpResponse response)) { | 
|  1531     _defaultHandler = handler; |  1567     _defaultHandler = handler; | 
|  1532   } |  1568   } | 
|  1533  |  1569  | 
|  1534   void close() { |  1570   void close() { | 
 |  1571     _closeQueue.shutdown(); | 
|  1535     if (_sessionManagerInstance != null) { |  1572     if (_sessionManagerInstance != null) { | 
|  1536       _sessionManagerInstance.close(); |  1573       _sessionManagerInstance.close(); | 
|  1537       _sessionManagerInstance = null; |  1574       _sessionManagerInstance = null; | 
|  1538     } |  1575     } | 
|  1539     if (_server != null && _closeServer) { |  1576     if (_server != null && _closeServer) { | 
|  1540       _server.close(); |  1577       _server.close(); | 
|  1541     } |  1578     } | 
|  1542     _server = null; |  1579     _server = null; | 
|  1543     for (_HttpConnection connection in _connections) { |  1580     for (_HttpConnection connection in _connections) { | 
|  1544       connection._destroy(); |  1581       connection._destroy(); | 
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  1595     return _sessionManagerInstance; |  1632     return _sessionManagerInstance; | 
|  1596   } |  1633   } | 
|  1597  |  1634  | 
|  1598  |  1635  | 
|  1599   ServerSocket _server;  // The server listen socket. |  1636   ServerSocket _server;  // The server listen socket. | 
|  1600   bool _closeServer = false; |  1637   bool _closeServer = false; | 
|  1601   Set<_HttpConnection> _connections;  // Set of currently connected clients. |  1638   Set<_HttpConnection> _connections;  // Set of currently connected clients. | 
|  1602   List<_RequestHandlerRegistration> _handlers; |  1639   List<_RequestHandlerRegistration> _handlers; | 
|  1603   Object _defaultHandler; |  1640   Object _defaultHandler; | 
|  1604   Function _onError; |  1641   Function _onError; | 
 |  1642   _CloseQueue _closeQueue; | 
|  1605   _HttpSessionManager _sessionManagerInstance; |  1643   _HttpSessionManager _sessionManagerInstance; | 
|  1606 } |  1644 } | 
|  1607  |  1645  | 
|  1608  |  1646  | 
|  1609 class _HttpClientRequest |  1647 class _HttpClientRequest | 
|  1610     extends _HttpRequestResponseBase implements HttpClientRequest { |  1648     extends _HttpRequestResponseBase implements HttpClientRequest { | 
|  1611   _HttpClientRequest(String this._method, |  1649   _HttpClientRequest(String this._method, | 
|  1612                      Uri this._uri, |  1650                      Uri this._uri, | 
|  1613                      _HttpClientConnection connection) |  1651                      _HttpClientConnection connection) | 
|  1614       : super(connection) { |  1652       : super(connection) { | 
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  1652     _httpConnection._flush(); |  1690     _httpConnection._flush(); | 
|  1653   } |  1691   } | 
|  1654  |  1692  | 
|  1655   void _streamClose() { |  1693   void _streamClose() { | 
|  1656     _ensureHeadersSent(); |  1694     _ensureHeadersSent(); | 
|  1657     _state = DONE; |  1695     _state = DONE; | 
|  1658     // Stop tracking no pending write events. |  1696     // Stop tracking no pending write events. | 
|  1659     _httpConnection._onNoPendingWrites = null; |  1697     _httpConnection._onNoPendingWrites = null; | 
|  1660     // Ensure that any trailing data is written. |  1698     // Ensure that any trailing data is written. | 
|  1661     _writeDone(); |  1699     _writeDone(); | 
|  1662     _connection._requestDone(); |  1700     _connection._requestClosed(); | 
|  1663   } |  1701   } | 
|  1664  |  1702  | 
|  1665   void _streamSetNoPendingWriteHandler(callback()) { |  1703   void _streamSetNoPendingWriteHandler(callback()) { | 
|  1666     if (_state != DONE) { |  1704     if (_state != DONE) { | 
|  1667       _httpConnection._onNoPendingWrites = callback; |  1705       _httpConnection._onNoPendingWrites = callback; | 
|  1668     } |  1706     } | 
|  1669   } |  1707   } | 
|  1670  |  1708  | 
|  1671   void _streamSetCloseHandler(callback()) { |  1709   void _streamSetCloseHandler(callback()) { | 
|  1672     // TODO(sgjesse): Handle this. |  1710     // TODO(sgjesse): Handle this. | 
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  1767     return _cookies; |  1805     return _cookies; | 
|  1768   } |  1806   } | 
|  1769  |  1807  | 
|  1770   InputStream get inputStream { |  1808   InputStream get inputStream { | 
|  1771     if (_inputStream == null) { |  1809     if (_inputStream == null) { | 
|  1772       _inputStream = new _HttpInputStream(this); |  1810       _inputStream = new _HttpInputStream(this); | 
|  1773     } |  1811     } | 
|  1774     return _inputStream; |  1812     return _inputStream; | 
|  1775   } |  1813   } | 
|  1776  |  1814  | 
|  1777   void _onRequestStart(String method, String uri, String version) { |  | 
|  1778     // TODO(sgjesse): Error handling |  | 
|  1779   } |  | 
|  1780  |  | 
|  1781   void _onResponseStart(int statusCode, String reasonPhrase, String version) { |  1815   void _onResponseStart(int statusCode, String reasonPhrase, String version) { | 
|  1782     _statusCode = statusCode; |  1816     _statusCode = statusCode; | 
|  1783     _reasonPhrase = reasonPhrase; |  1817     _reasonPhrase = reasonPhrase; | 
|  1784   } |  1818   } | 
|  1785  |  1819  | 
|  1786   void _onHeaderReceived(String name, String value) { |  1820   void _onHeaderReceived(String name, String value) { | 
|  1787     _headers.add(name, value); |  1821     _headers.add(name, value); | 
|  1788   } |  1822   } | 
|  1789  |  1823  | 
|  1790   void _handleUnauthorized() { |  1824   void _handleUnauthorized() { | 
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  1899       _connection._onResponse(this); |  1933       _connection._onResponse(this); | 
|  1900     } |  1934     } | 
|  1901   } |  1935   } | 
|  1902  |  1936  | 
|  1903   void _onDataReceived(List<int> data) { |  1937   void _onDataReceived(List<int> data) { | 
|  1904     _buffer.add(data); |  1938     _buffer.add(data); | 
|  1905     if (_inputStream != null) _inputStream._dataReceived(); |  1939     if (_inputStream != null) _inputStream._dataReceived(); | 
|  1906   } |  1940   } | 
|  1907  |  1941  | 
|  1908   void _onDataEnd() { |  1942   void _onDataEnd() { | 
|  1909     _connection._responseDone(); |  | 
|  1910     if (_inputStream != null) { |  1943     if (_inputStream != null) { | 
|  1911       _inputStream._closeReceived(); |  1944       _inputStream._closeReceived(); | 
|  1912     } else { |  1945     } else { | 
|  1913       inputStream._streamMarkedClosed = true; |  1946       inputStream._streamMarkedClosed = true; | 
|  1914     } |  1947     } | 
|  1915   } |  1948   } | 
|  1916  |  1949  | 
|  1917   // Delegate functions for the HttpInputStream implementation. |  1950   // Delegate functions for the HttpInputStream implementation. | 
|  1918   int _streamAvailable() { |  1951   int _streamAvailable() { | 
|  1919     return _buffer.length; |  1952     return _buffer.length; | 
| (...skipping 19 matching lines...) Expand all  Loading... | 
|  1939   _HttpClientConnection _connection; |  1972   _HttpClientConnection _connection; | 
|  1940   _HttpInputStream _inputStream; |  1973   _HttpInputStream _inputStream; | 
|  1941   _BufferList _buffer; |  1974   _BufferList _buffer; | 
|  1942  |  1975  | 
|  1943   Function _streamErrorHandler; |  1976   Function _streamErrorHandler; | 
|  1944 } |  1977 } | 
|  1945  |  1978  | 
|  1946  |  1979  | 
|  1947 class _HttpClientConnection |  1980 class _HttpClientConnection | 
|  1948     extends _HttpConnectionBase implements HttpClientConnection { |  1981     extends _HttpConnectionBase implements HttpClientConnection { | 
|  1949   static const int NONE = 0; |  | 
|  1950   static const int REQUEST_DONE = 1; |  | 
|  1951   static const int RESPONSE_DONE = 2; |  | 
|  1952   static const int ALL_DONE = REQUEST_DONE | RESPONSE_DONE; |  | 
|  1953  |  1982  | 
|  1954   _HttpClientConnection(_HttpClient this._client); |  1983   _HttpClientConnection(_HttpClient this._client) { | 
 |  1984     _httpParser = new _HttpParser.responseParser(); | 
 |  1985   } | 
|  1955  |  1986  | 
|  1956   void _connectionEstablished(_SocketConnection socketConn) { |  1987   void _connectionEstablished(_SocketConnection socketConn) { | 
|  1957     super._connectionEstablished(socketConn._socket); |  1988     super._connectionEstablished(socketConn._socket); | 
|  1958     _socketConn = socketConn; |  1989     _socketConn = socketConn; | 
|  1959     // Register HTTP parser callbacks. |  1990     // Register HTTP parser callbacks. | 
|  1960     _httpParser.requestStart = |  1991     _httpParser.responseStart = _onResponseStart; | 
|  1961       (method, uri, version) => _onRequestStart(method, uri, version); |  1992     _httpParser.headerReceived = _onHeaderReceived; | 
|  1962     _httpParser.responseStart = |  1993     _httpParser.headersComplete = _onHeadersComplete; | 
|  1963       (statusCode, reasonPhrase, version) => |  1994     _httpParser.dataReceived = _onDataReceived; | 
|  1964       _onResponseStart(statusCode, reasonPhrase, version); |  1995     _httpParser.dataEnd = _onDataEnd; | 
|  1965     _httpParser.headerReceived = |  1996     _httpParser.error = _onError; | 
|  1966         (name, value) => _onHeaderReceived(name, value); |  1997     _httpParser.closed = _onClosed; | 
|  1967     _httpParser.headersComplete = () => _onHeadersComplete(); |  1998     _httpParser.requestStart = (method, uri, version) { assert(false); }; | 
|  1968     _httpParser.dataReceived = (data) => _onDataReceived(data); |  1999     _state = _HttpConnectionBase.ACTIVE; | 
|  1969     _httpParser.dataEnd = (closed) => _onDataEnd(closed); |  | 
|  1970     _httpParser.error = (e) => _onError(e); |  | 
|  1971   } |  2000   } | 
|  1972  |  2001  | 
|  1973   bool get _isRequestDone => (_state & REQUEST_DONE) == REQUEST_DONE; |  | 
|  1974   bool get _isResponseDone => (_state & RESPONSE_DONE) == RESPONSE_DONE; |  | 
|  1975   bool get _isAllDone => (_state & ALL_DONE) == ALL_DONE; |  | 
|  1976  |  | 
|  1977   void _checkSocketDone() { |  2002   void _checkSocketDone() { | 
|  1978     if (_isAllDone) { |  2003     if (_isAllDone) { | 
|  1979       if (!_closing) { |  2004       // If we are done writing the response, and either the server | 
 |  2005       // has closed or the connection is not persistent, we must | 
 |  2006       // close. | 
 |  2007       if (_isReadClosed || !_response.persistentConnection) { | 
 |  2008         this.onClosed = () { | 
 |  2009           _client._closedSocketConnection(_socketConn); | 
 |  2010         }; | 
 |  2011         _client._closeQueue.add(this); | 
 |  2012       } else { | 
|  1980         _client._returnSocketConnection(_socketConn); |  2013         _client._returnSocketConnection(_socketConn); | 
|  1981       } |  2014         _socket = null; | 
|  1982       _socket = null; |  2015         _socketConn = null; | 
|  1983       _socketConn = null; |  2016         assert(_pendingRedirect == null || _pendingRetry == null); | 
|  1984       assert(_pendingRedirect == null || _pendingRetry == null); |  2017         if (_pendingRedirect != null) { | 
|  1985       if (_pendingRedirect != null) { |  2018           _doRedirect(_pendingRedirect); | 
|  1986         _doRedirect(_pendingRedirect); |  2019           _pendingRedirect = null; | 
|  1987         _pendingRedirect = null; |  2020         } else if (_pendingRetry != null) { | 
|  1988       } else if (_pendingRetry != null) { |  2021           _doRetry(_pendingRetry); | 
|  1989         _doRetry(_pendingRetry); |  2022           _pendingRetry = null; | 
|  1990         _pendingRetry = null; |  2023         } | 
|  1991       } |  2024       } | 
|  1992     } |  2025     } | 
|  1993   } |  2026   } | 
|  1994  |  2027  | 
|  1995   void _requestDone() { |  2028   void _requestClosed() { | 
|  1996     _state |= REQUEST_DONE; |  2029     _state |= _HttpConnectionBase.REQUEST_DONE; | 
|  1997     _checkSocketDone(); |  2030     _checkSocketDone(); | 
|  1998   } |  2031   } | 
|  1999  |  2032  | 
|  2000   void _responseDone() { |  | 
|  2001     if (_closing) { |  | 
|  2002       if (_socket != null) { |  | 
|  2003         _socket.close(); |  | 
|  2004       } |  | 
|  2005     } |  | 
|  2006     _state |= RESPONSE_DONE; |  | 
|  2007     _checkSocketDone(); |  | 
|  2008   } |  | 
|  2009  |  | 
|  2010   HttpClientRequest open(String method, Uri uri) { |  2033   HttpClientRequest open(String method, Uri uri) { | 
|  2011     _method = method; |  2034     _method = method; | 
|  2012     // Tell the HTTP parser the method it is expecting a response to. |  2035     // Tell the HTTP parser the method it is expecting a response to. | 
|  2013     _httpParser.responseToMethod = method; |  2036     _httpParser.responseToMethod = method; | 
|  2014     _request = new _HttpClientRequest(method, uri, this); |  2037     _request = new _HttpClientRequest(method, uri, this); | 
|  2015     _response = new _HttpClientResponse(this); |  2038     _response = new _HttpClientResponse(this); | 
|  2016     return _request; |  2039     return _request; | 
|  2017   } |  2040   } | 
|  2018  |  2041  | 
|  2019   DetachedSocket detachSocket() { |  2042   DetachedSocket detachSocket() { | 
|  2020     return _detachSocket(); |  2043     return _detachSocket(); | 
|  2021   } |  2044   } | 
|  2022  |  2045  | 
|  2023   void _onConnectionClosed(e) { |  2046   void _onClosed() { | 
 |  2047     _state |= _HttpConnectionBase.READ_CLOSED; | 
 |  2048   } | 
 |  2049  | 
 |  2050   void _onError(e) { | 
|  2024     // Socket is closed either due to an error or due to normal socket close. |  2051     // Socket is closed either due to an error or due to normal socket close. | 
|  2025     if (e != null) { |  2052     if (_onErrorCallback != null) { | 
|  2026       if (_onErrorCallback != null) { |  2053       _onErrorCallback(e); | 
|  2027         _onErrorCallback(e); |  2054     } else { | 
|  2028       } else { |  2055       throw e; | 
|  2029         throw e; |  | 
|  2030       } |  | 
|  2031     } |  2056     } | 
|  2032     _closing = true; |  2057     // Propagate the error to the streams. | 
|  2033     if (e != null) { |  2058     if (_response != null && _response._streamErrorHandler != null) { | 
|  2034       // Propagate the error to the streams. |  2059        _response._streamErrorHandler(e); | 
|  2035       if (_response != null && _response._streamErrorHandler != null) { |  2060     } | 
|  2036         _response._streamErrorHandler(e); |  2061     if (_socketConn != null) { | 
|  2037       } |  2062       _client._closeSocketConnection(_socketConn); | 
|  2038       _responseDone(); |  | 
|  2039     } else { |  | 
|  2040       // If there was no socket error the socket was closed |  | 
|  2041       // normally. Indicate closing to the HTTP Parser as there might |  | 
|  2042       // still be an HTTP error. |  | 
|  2043       _httpParser.connectionClosed(); |  | 
|  2044     } |  2063     } | 
|  2045   } |  2064   } | 
|  2046  |  2065  | 
|  2047   void _onRequestStart(String method, String uri, String version) { |  | 
|  2048     // TODO(sgjesse): Error handling. |  | 
|  2049   } |  | 
|  2050  |  | 
|  2051   void _onResponseStart(int statusCode, String reasonPhrase, String version) { |  2066   void _onResponseStart(int statusCode, String reasonPhrase, String version) { | 
|  2052     _response._onResponseStart(statusCode, reasonPhrase, version); |  2067     _response._onResponseStart(statusCode, reasonPhrase, version); | 
|  2053   } |  2068   } | 
|  2054  |  2069  | 
|  2055   void _onHeaderReceived(String name, String value) { |  2070   void _onHeaderReceived(String name, String value) { | 
|  2056     _response._onHeaderReceived(name, value); |  2071     _response._onHeaderReceived(name, value); | 
|  2057   } |  2072   } | 
|  2058  |  2073  | 
|  2059   void _onHeadersComplete() { |  2074   void _onHeadersComplete() { | 
|  2060     _response._onHeadersComplete(); |  2075     _response._onHeadersComplete(); | 
|  2061   } |  2076   } | 
|  2062  |  2077  | 
|  2063   void _onDataReceived(List<int> data) { |  2078   void _onDataReceived(List<int> data) { | 
|  2064     _response._onDataReceived(data); |  2079     _response._onDataReceived(data); | 
|  2065   } |  2080   } | 
|  2066  |  2081  | 
|  2067   void _onDataEnd(bool close) { |  2082   void _onDataEnd(bool close) { | 
|  2068     if (close) _closing = true; |  | 
|  2069     _response._onDataEnd(); |  2083     _response._onDataEnd(); | 
 |  2084     _state |= _HttpConnectionBase.RESPONSE_DONE; | 
 |  2085     _checkSocketDone(); | 
|  2070   } |  2086   } | 
|  2071  |  2087  | 
|  2072   void set onRequest(void handler(HttpClientRequest request)) { |  2088   void set onRequest(void handler(HttpClientRequest request)) { | 
|  2073     _onRequest = handler; |  2089     _onRequest = handler; | 
|  2074   } |  2090   } | 
|  2075  |  2091  | 
|  2076   void set onResponse(void handler(HttpClientResponse response)) { |  2092   void set onResponse(void handler(HttpClientResponse response)) { | 
|  2077     _onResponse = handler; |  2093     _onResponse = handler; | 
|  2078   } |  2094   } | 
|  2079  |  2095  | 
|  2080   void set onError(void callback(e)) { |  2096   void set onError(void callback(e)) { | 
|  2081     _onErrorCallback = callback; |  2097     _onErrorCallback = callback; | 
|  2082   } |  2098   } | 
|  2083  |  2099  | 
|  2084   void _doRetry(_RedirectInfo retry) { |  2100   void _doRetry(_RedirectInfo retry) { | 
|  2085     assert(_socketConn == null); |  2101     assert(_socketConn == null); | 
|  2086     _request = null; |  2102     _request = null; | 
|  2087     _response = null; |  2103     _response = null; | 
|  2088  |  2104  | 
|  2089     // Retry the URL using the same connection instance. |  2105     // Retry the URL using the same connection instance. | 
|  2090     _state = NONE; |  2106     _state = _HttpConnectionBase.IDLE; | 
|  2091     _client._openUrl(retry.method, retry.location, this); |  2107     _client._openUrl(retry.method, retry.location, this); | 
|  2092   } |  2108   } | 
|  2093  |  2109  | 
|  2094   void _retry() { |  2110   void _retry() { | 
|  2095     var retry = new _RedirectInfo(_response.statusCode, _method, _request._uri); |  2111     var retry = new _RedirectInfo(_response.statusCode, _method, _request._uri); | 
|  2096     // The actual retry is postponed until both response and request |  2112     // The actual retry is postponed until both response and request | 
|  2097     // are done. |  2113     // are done. | 
|  2098     if (_isAllDone) { |  2114     if (_isAllDone) { | 
|  2099       _doRetry(retry); |  2115       _doRetry(retry); | 
|  2100     } else { |  2116     } else { | 
| (...skipping 23 matching lines...) Expand all  Loading... | 
|  2124     // request are done. |  2140     // request are done. | 
|  2125     if (_isAllDone) { |  2141     if (_isAllDone) { | 
|  2126       _doRedirect(redirect); |  2142       _doRedirect(redirect); | 
|  2127     } else { |  2143     } else { | 
|  2128       // Prepare for redirect. |  2144       // Prepare for redirect. | 
|  2129       assert(_pendingRetry == null); |  2145       assert(_pendingRetry == null); | 
|  2130       _pendingRedirect = redirect; |  2146       _pendingRedirect = redirect; | 
|  2131     } |  2147     } | 
|  2132   } |  2148   } | 
|  2133  |  2149  | 
|  2134   int _state = NONE; |  | 
|  2135  |  | 
|  2136   List<RedirectInfo> get redirects => _redirects; |  2150   List<RedirectInfo> get redirects => _redirects; | 
|  2137  |  2151  | 
|  2138   Function _onRequest; |  2152   Function _onRequest; | 
|  2139   Function _onResponse; |  2153   Function _onResponse; | 
|  2140   Function _onErrorCallback; |  2154   Function _onErrorCallback; | 
|  2141  |  2155  | 
|  2142   _HttpClient _client; |  2156   _HttpClient _client; | 
|  2143   _SocketConnection _socketConn; |  2157   _SocketConnection _socketConn; | 
|  2144   HttpClientRequest _request; |  2158   HttpClientRequest _request; | 
|  2145   HttpClientResponse _response; |  2159   HttpClientResponse _response; | 
| (...skipping 19 matching lines...) Expand all  Loading... | 
|  2165                     int this._port, |  2179                     int this._port, | 
|  2166                     Socket this._socket); |  2180                     Socket this._socket); | 
|  2167  |  2181  | 
|  2168   void _markReturned() { |  2182   void _markReturned() { | 
|  2169     _socket.onData = null; |  2183     _socket.onData = null; | 
|  2170     _socket.onClosed = null; |  2184     _socket.onClosed = null; | 
|  2171     _socket.onError = null; |  2185     _socket.onError = null; | 
|  2172     _returnTime = new Date.now(); |  2186     _returnTime = new Date.now(); | 
|  2173   } |  2187   } | 
|  2174  |  2188  | 
 |  2189   void _close() { | 
 |  2190     _socket.onData = null; | 
 |  2191     _socket.onClosed = null; | 
 |  2192     _socket.onError = null; | 
 |  2193     _socket.close(); | 
 |  2194   } | 
 |  2195  | 
|  2175   Duration _idleTime(Date now) => now.difference(_returnTime); |  2196   Duration _idleTime(Date now) => now.difference(_returnTime); | 
|  2176  |  2197  | 
|  2177   int get hashCode => _socket.hashCode; |  2198   int get hashCode => _socket.hashCode; | 
|  2178  |  2199  | 
|  2179   String _host; |  2200   String _host; | 
|  2180   int _port; |  2201   int _port; | 
|  2181   Socket _socket; |  2202   Socket _socket; | 
|  2182   Date _returnTime; |  2203   Date _returnTime; | 
|  2183 } |  2204 } | 
|  2184  |  2205  | 
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  2234   final String host; |  2255   final String host; | 
|  2235   final int port; |  2256   final int port; | 
|  2236   final bool isDirect; |  2257   final bool isDirect; | 
|  2237 } |  2258 } | 
|  2238  |  2259  | 
|  2239 class _HttpClient implements HttpClient { |  2260 class _HttpClient implements HttpClient { | 
|  2240   static const int DEFAULT_EVICTION_TIMEOUT = 60000; |  2261   static const int DEFAULT_EVICTION_TIMEOUT = 60000; | 
|  2241  |  2262  | 
|  2242   _HttpClient() : _openSockets = new Map(), |  2263   _HttpClient() : _openSockets = new Map(), | 
|  2243                   _activeSockets = new Set(), |  2264                   _activeSockets = new Set(), | 
 |  2265                   _closeQueue = new _CloseQueue(), | 
|  2244                   credentials = new List<_Credentials>(), |  2266                   credentials = new List<_Credentials>(), | 
|  2245                   _shutdown = false; |  2267                   _shutdown = false; | 
|  2246  |  2268  | 
|  2247   HttpClientConnection open( |  2269   HttpClientConnection open( | 
|  2248       String method, String host, int port, String path) { |  2270       String method, String host, int port, String path) { | 
|  2249     // TODO(sgjesse): The path set here can contain both query and |  2271     // TODO(sgjesse): The path set here can contain both query and | 
|  2250     // fragment. They should be cracked and set correctly. |  2272     // fragment. They should be cracked and set correctly. | 
|  2251     return _open(method, new Uri.fromComponents( |  2273     return _open(method, new Uri.fromComponents( | 
|  2252         scheme: "http", domain: host, port: port, path: path)); |  2274         scheme: "http", domain: host, port: port, path: path)); | 
|  2253   } |  2275   } | 
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  2292   } |  2314   } | 
|  2293  |  2315  | 
|  2294   void addCredentials( |  2316   void addCredentials( | 
|  2295       Uri url, String realm, HttpClientCredentials cr) { |  2317       Uri url, String realm, HttpClientCredentials cr) { | 
|  2296     credentials.add(new _Credentials(url, realm, cr)); |  2318     credentials.add(new _Credentials(url, realm, cr)); | 
|  2297   } |  2319   } | 
|  2298  |  2320  | 
|  2299   set findProxy(String f(Uri uri)) => _findProxy = f; |  2321   set findProxy(String f(Uri uri)) => _findProxy = f; | 
|  2300  |  2322  | 
|  2301   void shutdown() { |  2323   void shutdown() { | 
|  2302      _openSockets.forEach((String key, Queue<_SocketConnection> connections) { |  2324     _closeQueue.shutdown(); | 
|  2303        while (!connections.isEmpty) { |  2325     _openSockets.forEach((String key, Queue<_SocketConnection> connections) { | 
|  2304          _SocketConnection socketConn = connections.removeFirst(); |  2326       while (!connections.isEmpty) { | 
|  2305          socketConn._socket.close(); |  2327         _SocketConnection socketConn = connections.removeFirst(); | 
|  2306        } |  2328         socketConn._socket.close(); | 
|  2307      }); |  2329       } | 
|  2308      _activeSockets.forEach((_SocketConnection socketConn) { |  2330     }); | 
|  2309        socketConn._socket.close(); |  2331     _activeSockets.forEach((_SocketConnection socketConn) { | 
|  2310      }); |  2332       socketConn._socket.close(); | 
 |  2333     }); | 
|  2311     if (_evictionTimer != null) _cancelEvictionTimer(); |  2334     if (_evictionTimer != null) _cancelEvictionTimer(); | 
|  2312      _shutdown = true; |  2335      _shutdown = true; | 
|  2313   } |  2336   } | 
|  2314  |  2337  | 
|  2315   void _cancelEvictionTimer() { |  2338   void _cancelEvictionTimer() { | 
|  2316     _evictionTimer.cancel(); |  2339     _evictionTimer.cancel(); | 
|  2317     _evictionTimer = null; |  2340     _evictionTimer = null; | 
|  2318   } |  2341   } | 
|  2319  |  2342  | 
|  2320   String _connectionKey(String host, int port) { |  2343   String _connectionKey(String host, int port) { | 
| (...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  2496         if (_openSockets.isEmpty) _cancelEvictionTimer(); |  2519         if (_openSockets.isEmpty) _cancelEvictionTimer(); | 
|  2497       } |  2520       } | 
|  2498       _evictionTimer = new Timer.repeating(10000, _handleEviction); |  2521       _evictionTimer = new Timer.repeating(10000, _handleEviction); | 
|  2499     } |  2522     } | 
|  2500  |  2523  | 
|  2501     // Return connection. |  2524     // Return connection. | 
|  2502     _activeSockets.remove(socketConn); |  2525     _activeSockets.remove(socketConn); | 
|  2503     sockets.addFirst(socketConn); |  2526     sockets.addFirst(socketConn); | 
|  2504   } |  2527   } | 
|  2505  |  2528  | 
 |  2529   void _closeSocketConnection(_SocketConnection socketConn) { | 
 |  2530     socketConn._close(); | 
 |  2531     _activeSockets.remove(socketConn); | 
 |  2532   } | 
 |  2533  | 
 |  2534   void _closedSocketConnection(_SocketConnection socketConn) { | 
 |  2535     _activeSockets.remove(socketConn); | 
 |  2536   } | 
 |  2537  | 
|  2506   _Credentials _findCredentials(Uri url, [_AuthenticationScheme scheme]) { |  2538   _Credentials _findCredentials(Uri url, [_AuthenticationScheme scheme]) { | 
|  2507     // Look for credentials. |  2539     // Look for credentials. | 
|  2508     _Credentials cr = |  2540     _Credentials cr = | 
|  2509         credentials.reduce(null, (_Credentials prev, _Credentials value) { |  2541         credentials.reduce(null, (_Credentials prev, _Credentials value) { | 
|  2510           if (value.applies(url, scheme)) { |  2542           if (value.applies(url, scheme)) { | 
|  2511             if (prev == null) return value; |  2543             if (prev == null) return value; | 
|  2512             return value.uri.path.length > prev.uri.path.length ? value : prev; |  2544             return value.uri.path.length > prev.uri.path.length ? value : prev; | 
|  2513           } else { |  2545           } else { | 
|  2514             return prev; |  2546             return prev; | 
|  2515           } |  2547           } | 
|  2516         }); |  2548         }); | 
|  2517     return cr; |  2549     return cr; | 
|  2518   } |  2550   } | 
|  2519  |  2551  | 
|  2520   void _removeCredentials(_Credentials cr) { |  2552   void _removeCredentials(_Credentials cr) { | 
|  2521     int index = credentials.indexOf(cr); |  2553     int index = credentials.indexOf(cr); | 
|  2522     if (index != -1) { |  2554     if (index != -1) { | 
|  2523       credentials.removeAt(index); |  2555       credentials.removeAt(index); | 
|  2524     } |  2556     } | 
|  2525   } |  2557   } | 
|  2526  |  2558  | 
|  2527   Function _onOpen; |  2559   Function _onOpen; | 
|  2528   Map<String, Queue<_SocketConnection>> _openSockets; |  2560   Map<String, Queue<_SocketConnection>> _openSockets; | 
|  2529   Set<_SocketConnection> _activeSockets; |  2561   Set<_SocketConnection> _activeSockets; | 
 |  2562   _CloseQueue _closeQueue; | 
|  2530   List<_Credentials> credentials; |  2563   List<_Credentials> credentials; | 
|  2531   Timer _evictionTimer; |  2564   Timer _evictionTimer; | 
|  2532   Function _findProxy; |  2565   Function _findProxy; | 
|  2533   Function _authenticate; |  2566   Function _authenticate; | 
|  2534   bool _shutdown;  // Has this HTTP client been shutdown? |  2567   bool _shutdown;  // Has this HTTP client been shutdown? | 
|  2535 } |  2568 } | 
|  2536  |  2569  | 
|  2537  |  2570  | 
|  2538 class _HttpConnectionInfo implements HttpConnectionInfo { |  2571 class _HttpConnectionInfo implements HttpConnectionInfo { | 
|  2539   String remoteHost; |  2572   String remoteHost; | 
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  2655  |  2688  | 
|  2656  |  2689  | 
|  2657 class _RedirectInfo implements RedirectInfo { |  2690 class _RedirectInfo implements RedirectInfo { | 
|  2658   const _RedirectInfo(int this.statusCode, |  2691   const _RedirectInfo(int this.statusCode, | 
|  2659                       String this.method, |  2692                       String this.method, | 
|  2660                       Uri this.location); |  2693                       Uri this.location); | 
|  2661   final int statusCode; |  2694   final int statusCode; | 
|  2662   final String method; |  2695   final String method; | 
|  2663   final Uri location; |  2696   final Uri location; | 
|  2664 } |  2697 } | 
| OLD | NEW |