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 // The close queue handles graceful closing of HTTP connections. When | 5 // The close queue handles graceful closing of HTTP connections. When |
6 // a connection is added to the queue it will enter a wait state | 6 // a connection is added to the queue it will enter a wait state |
7 // waiting for all data written and possibly socket shutdown from | 7 // waiting for all data written and possibly socket shutdown from |
8 // peer. | 8 // peer. |
9 class _CloseQueue { | 9 class _CloseQueue { |
10 _CloseQueue() : _q = new Set<_HttpConnectionBase>(); | 10 _CloseQueue() : _q = new Set<_HttpConnectionBase>(); |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
93 if (connection == null) return true; | 93 if (connection == null) return true; |
94 return !headers[HttpHeaders.CONNECTION].some( | 94 return !headers[HttpHeaders.CONNECTION].some( |
95 (value) => value.toLowerCase() == "close"); | 95 (value) => value.toLowerCase() == "close"); |
96 } else { | 96 } else { |
97 if (connection == null) return false; | 97 if (connection == null) return false; |
98 return headers[HttpHeaders.CONNECTION].some( | 98 return headers[HttpHeaders.CONNECTION].some( |
99 (value) => value.toLowerCase() == "keep-alive"); | 99 (value) => value.toLowerCase() == "keep-alive"); |
100 } | 100 } |
101 } | 101 } |
102 | 102 |
| 103 X509Certificate get certificate { |
| 104 var socket = _httpConnection._socket as SecureSocket; |
| 105 return socket == null ? socket : socket.peerCertificate; |
| 106 } |
| 107 |
103 void set persistentConnection(bool persistentConnection) { | 108 void set persistentConnection(bool persistentConnection) { |
104 if (_outputStream != null) throw new HttpException("Header already sent"); | 109 if (_outputStream != null) throw new HttpException("Header already sent"); |
105 | 110 |
106 // Determine the value of the "Connection" header. | 111 // Determine the value of the "Connection" header. |
107 headers.remove(HttpHeaders.CONNECTION, "close"); | 112 headers.remove(HttpHeaders.CONNECTION, "close"); |
108 headers.remove(HttpHeaders.CONNECTION, "keep-alive"); | 113 headers.remove(HttpHeaders.CONNECTION, "keep-alive"); |
109 if (_protocolVersion == "1.1" && !persistentConnection) { | 114 if (_protocolVersion == "1.1" && !persistentConnection) { |
110 headers.add(HttpHeaders.CONNECTION, "close"); | 115 headers.add(HttpHeaders.CONNECTION, "close"); |
111 } else if (_protocolVersion == "1.0" && persistentConnection) { | 116 } else if (_protocolVersion == "1.0" && persistentConnection) { |
112 headers.add(HttpHeaders.CONNECTION, "keep-alive"); | 117 headers.add(HttpHeaders.CONNECTION, "keep-alive"); |
(...skipping 880 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
993 | 998 |
994 _HttpServer._internal({ bool isSecure: false }) | 999 _HttpServer._internal({ bool isSecure: false }) |
995 : _secure = isSecure, | 1000 : _secure = isSecure, |
996 _connections = new Set<_HttpConnection>(), | 1001 _connections = new Set<_HttpConnection>(), |
997 _handlers = new List<_RequestHandlerRegistration>(), | 1002 _handlers = new List<_RequestHandlerRegistration>(), |
998 _closeQueue = new _CloseQueue(); | 1003 _closeQueue = new _CloseQueue(); |
999 | 1004 |
1000 void listen(String host, | 1005 void listen(String host, |
1001 int port, | 1006 int port, |
1002 {int backlog: 128, | 1007 {int backlog: 128, |
1003 String certificate_name}) { | 1008 String certificate_name, |
| 1009 bool requestClientCertificate: false}) { |
1004 if (_secure) { | 1010 if (_secure) { |
1005 listenOn(new SecureServerSocket(host, port, backlog, certificate_name)); | 1011 listenOn(new SecureServerSocket( |
| 1012 host, |
| 1013 port, |
| 1014 backlog, |
| 1015 certificate_name, |
| 1016 requestClientCertificate: requestClientCertificate)); |
1006 } else { | 1017 } else { |
1007 listenOn(new ServerSocket(host, port, backlog)); | 1018 listenOn(new ServerSocket(host, port, backlog)); |
1008 } | 1019 } |
1009 _closeServer = true; | 1020 _closeServer = true; |
1010 } | 1021 } |
1011 | 1022 |
1012 void listenOn(ServerSocket serverSocket) { | 1023 void listenOn(ServerSocket serverSocket) { |
1013 if (_secure && serverSocket is! SecureServerSocket) { | 1024 if (_secure && serverSocket is! SecureServerSocket) { |
1014 throw new HttpException( | 1025 throw new HttpException( |
1015 'HttpsServer.listenOn was called with non-secure server socket'); | 1026 'HttpsServer.listenOn was called with non-secure server socket'); |
(...skipping 727 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1743 void _markReturned() { | 1754 void _markReturned() { |
1744 // Any activity on the socket while waiting in the pool will | 1755 // Any activity on the socket while waiting in the pool will |
1745 // invalidate the connection os that it is not reused. | 1756 // invalidate the connection os that it is not reused. |
1746 _socket.onData = _invalidate; | 1757 _socket.onData = _invalidate; |
1747 _socket.onClosed = _invalidate; | 1758 _socket.onClosed = _invalidate; |
1748 _socket.onError = (_) => _invalidate(); | 1759 _socket.onError = (_) => _invalidate(); |
1749 _returnTime = new Date.now(); | 1760 _returnTime = new Date.now(); |
1750 _httpClientConnection = null; | 1761 _httpClientConnection = null; |
1751 } | 1762 } |
1752 | 1763 |
1753 void _markRetreived() { | 1764 void _markRetrieved() { |
1754 _socket.onData = null; | 1765 _socket.onData = null; |
1755 _socket.onClosed = null; | 1766 _socket.onClosed = null; |
1756 _socket.onError = null; | 1767 _socket.onError = null; |
1757 _httpClientConnection = null; | 1768 _httpClientConnection = null; |
1758 } | 1769 } |
1759 | 1770 |
1760 void _close() { | 1771 void _close() { |
1761 _socket.onData = null; | 1772 _socket.onData = null; |
1762 _socket.onClosed = null; | 1773 _socket.onClosed = null; |
1763 _socket.onError = null; | 1774 _socket.onError = null; |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1892 | 1903 |
1893 set authenticate(Future<bool> f(Uri url, String scheme, String realm)) { | 1904 set authenticate(Future<bool> f(Uri url, String scheme, String realm)) { |
1894 _authenticate = f; | 1905 _authenticate = f; |
1895 } | 1906 } |
1896 | 1907 |
1897 void addCredentials( | 1908 void addCredentials( |
1898 Uri url, String realm, HttpClientCredentials cr) { | 1909 Uri url, String realm, HttpClientCredentials cr) { |
1899 credentials.add(new _Credentials(url, realm, cr)); | 1910 credentials.add(new _Credentials(url, realm, cr)); |
1900 } | 1911 } |
1901 | 1912 |
| 1913 set sendClientCertificate(bool send) => _sendClientCertificate = send; |
| 1914 |
| 1915 set clientCertificate(String nickname) => _clientCertificate = nickname; |
| 1916 |
1902 set findProxy(String f(Uri uri)) => _findProxy = f; | 1917 set findProxy(String f(Uri uri)) => _findProxy = f; |
1903 | 1918 |
1904 void shutdown({bool force: false}) { | 1919 void shutdown({bool force: false}) { |
1905 if (force) _closeQueue.shutdown(); | 1920 if (force) _closeQueue.shutdown(); |
1906 _openSockets.forEach((String key, Queue<_SocketConnection> connections) { | 1921 _openSockets.forEach((String key, Queue<_SocketConnection> connections) { |
1907 while (!connections.isEmpty) { | 1922 while (!connections.isEmpty) { |
1908 _SocketConnection socketConn = connections.removeFirst(); | 1923 _SocketConnection socketConn = connections.removeFirst(); |
1909 socketConn._socket.close(); | 1924 socketConn._socket.close(); |
1910 } | 1925 } |
1911 }); | 1926 }); |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1985 connectHost = proxy.host; | 2000 connectHost = proxy.host; |
1986 connectPort = proxy.port; | 2001 connectPort = proxy.port; |
1987 } | 2002 } |
1988 | 2003 |
1989 // If there are active connections for this key get the first one | 2004 // If there are active connections for this key get the first one |
1990 // otherwise create a new one. | 2005 // otherwise create a new one. |
1991 String key = _connectionKey(connectHost, connectPort); | 2006 String key = _connectionKey(connectHost, connectPort); |
1992 Queue socketConnections = _openSockets[key]; | 2007 Queue socketConnections = _openSockets[key]; |
1993 // Remove active connections that are not valid any more or of | 2008 // Remove active connections that are not valid any more or of |
1994 // the wrong type (HTTP or HTTPS). | 2009 // the wrong type (HTTP or HTTPS). |
1995 while (socketConnections != null && | 2010 if (socketConnections != null) { |
1996 !socketConnections.isEmpty && | 2011 while (!socketConnections.isEmpty) { |
1997 (!socketConnections.first._valid || | 2012 if (socketConnections.first._valid) { |
1998 secure != (socketConnections.first._socket is SecureSocket))) { | 2013 // If socket has the same properties, exit loop with found socket. |
1999 socketConnections.removeFirst()._close(); | 2014 var socket = socketConnections.first._socket; |
| 2015 if (!secure && socket is! SecureSocket) break; |
| 2016 if (secure && socket is SecureSocket && |
| 2017 _sendClientCertificate == socket.sendClientCertificate && |
| 2018 _clientCertificate == socket.certificateName) break; |
| 2019 } |
| 2020 socketConnections.removeFirst()._close(); |
| 2021 } |
2000 } | 2022 } |
2001 if (socketConnections == null || socketConnections.isEmpty) { | 2023 if (socketConnections == null || socketConnections.isEmpty) { |
2002 Socket socket = secure ? new SecureSocket(connectHost, connectPort) : | 2024 Socket socket = secure ? |
2003 new Socket(connectHost, connectPort); | 2025 new SecureSocket(connectHost, |
| 2026 connectPort, |
| 2027 sendClientCertificate: _sendClientCertificate, |
| 2028 certificateName: _clientCertificate) : |
| 2029 new Socket(connectHost, connectPort); |
2004 // Until the connection is established handle connection errors | 2030 // Until the connection is established handle connection errors |
2005 // here as the HttpClientConnection object is not yet associated | 2031 // here as the HttpClientConnection object is not yet associated |
2006 // with the socket. | 2032 // with the socket. |
2007 socket.onError = (e) { | 2033 socket.onError = (e) { |
2008 proxyIndex++; | 2034 proxyIndex++; |
2009 if (proxyIndex < proxyConfiguration.proxies.length) { | 2035 if (proxyIndex < proxyConfiguration.proxies.length) { |
2010 // Try the next proxy in the list. | 2036 // Try the next proxy in the list. |
2011 _establishConnection( | 2037 _establishConnection( |
2012 host, port, proxyConfiguration, proxyIndex, false, secure); | 2038 host, port, proxyConfiguration, proxyIndex, false, secure); |
2013 } else { | 2039 } else { |
2014 // Report the error through the HttpClientConnection object to | 2040 // Report the error through the HttpClientConnection object to |
2015 // the client. | 2041 // the client. |
2016 connection._onError(e); | 2042 connection._onError(e); |
2017 } | 2043 } |
2018 }; | 2044 }; |
2019 socket.onConnect = () { | 2045 socket.onConnect = () { |
2020 // When the connection is established, clear the error | 2046 // When the connection is established, clear the error |
2021 // callback as it will now be handled by the | 2047 // callback as it will now be handled by the |
2022 // HttpClientConnection object which will be associated with | 2048 // HttpClientConnection object which will be associated with |
2023 // the connected socket. | 2049 // the connected socket. |
2024 socket.onError = null; | 2050 socket.onError = null; |
2025 _SocketConnection socketConn = | 2051 _SocketConnection socketConn = |
2026 new _SocketConnection(connectHost, connectPort, socket); | 2052 new _SocketConnection(connectHost, connectPort, socket); |
2027 _activeSockets.add(socketConn); | 2053 _activeSockets.add(socketConn); |
2028 _connectionOpened(socketConn, connection, !proxy.isDirect); | 2054 _connectionOpened(socketConn, connection, !proxy.isDirect); |
2029 }; | 2055 }; |
2030 } else { | 2056 } else { |
2031 _SocketConnection socketConn = socketConnections.removeFirst(); | 2057 _SocketConnection socketConn = socketConnections.removeFirst(); |
2032 socketConn._markRetreived(); | 2058 socketConn._markRetrieved(); |
2033 _activeSockets.add(socketConn); | 2059 _activeSockets.add(socketConn); |
2034 new Timer(0, (ignored) => | 2060 new Timer(0, (ignored) => |
2035 _connectionOpened(socketConn, connection, !proxy.isDirect)); | 2061 _connectionOpened(socketConn, connection, !proxy.isDirect)); |
2036 | 2062 |
2037 // Get rid of eviction timer if there are no more active connections. | 2063 // Get rid of eviction timer if there are no more active connections. |
2038 if (socketConnections.isEmpty) _openSockets.remove(key); | 2064 if (socketConnections.isEmpty) _openSockets.remove(key); |
2039 if (_openSockets.isEmpty) _cancelEvictionTimer(); | 2065 if (_openSockets.isEmpty) _cancelEvictionTimer(); |
2040 } | 2066 } |
2041 } | 2067 } |
2042 | 2068 |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2165 } | 2191 } |
2166 | 2192 |
2167 Function _onOpen; | 2193 Function _onOpen; |
2168 Map<String, Queue<_SocketConnection>> _openSockets; | 2194 Map<String, Queue<_SocketConnection>> _openSockets; |
2169 Set<_SocketConnection> _activeSockets; | 2195 Set<_SocketConnection> _activeSockets; |
2170 _CloseQueue _closeQueue; | 2196 _CloseQueue _closeQueue; |
2171 List<_Credentials> credentials; | 2197 List<_Credentials> credentials; |
2172 Timer _evictionTimer; | 2198 Timer _evictionTimer; |
2173 Function _findProxy; | 2199 Function _findProxy; |
2174 Function _authenticate; | 2200 Function _authenticate; |
| 2201 bool _sendClientCertificate = false; |
| 2202 String _clientCertificate; |
2175 bool _shutdown; // Has this HTTP client been shutdown? | 2203 bool _shutdown; // Has this HTTP client been shutdown? |
2176 } | 2204 } |
2177 | 2205 |
2178 | 2206 |
2179 class _HttpConnectionInfo implements HttpConnectionInfo { | 2207 class _HttpConnectionInfo implements HttpConnectionInfo { |
2180 String remoteHost; | 2208 String remoteHost; |
2181 int remotePort; | 2209 int remotePort; |
2182 int localPort; | 2210 int localPort; |
2183 } | 2211 } |
2184 | 2212 |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2296 | 2324 |
2297 | 2325 |
2298 class _RedirectInfo implements RedirectInfo { | 2326 class _RedirectInfo implements RedirectInfo { |
2299 const _RedirectInfo(int this.statusCode, | 2327 const _RedirectInfo(int this.statusCode, |
2300 String this.method, | 2328 String this.method, |
2301 Uri this.location); | 2329 Uri this.location); |
2302 final int statusCode; | 2330 final int statusCode; |
2303 final String method; | 2331 final String method; |
2304 final Uri location; | 2332 final Uri location; |
2305 } | 2333 } |
OLD | NEW |