| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | |
| 2 // for details. All rights reserved. Use of this source code is governed by a | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 import "dart:io"; | |
| 6 import "dart:isolate"; | |
| 7 import "dart:math"; | |
| 8 | |
| 9 class ExpectedDataOutputStream implements OutputStream { | |
| 10 ExpectedDataOutputStream(List<int> this._data, | |
| 11 int this._cutoff, | |
| 12 bool this._closeAsError, | |
| 13 SocketMock this._socket); | |
| 14 | |
| 15 void set onNoPendingWrites(void callback()) { | |
| 16 _onNoPendingWrites = callback; | |
| 17 } | |
| 18 | |
| 19 void set onClosed(void callback()) { | |
| 20 // Not used in test. | |
| 21 } | |
| 22 | |
| 23 void set onError(void callback(e)) { | |
| 24 _onError = callback; | |
| 25 } | |
| 26 | |
| 27 bool write(List data, [bool copyBuffer = true]) { | |
| 28 _onData(data); | |
| 29 return true; | |
| 30 } | |
| 31 | |
| 32 bool writeFrom(List data, [int offset = 0, int len]) { | |
| 33 if (len == null) len = data.length - offset; | |
| 34 _onData(data.getRange(offset, len)); | |
| 35 return true; | |
| 36 } | |
| 37 | |
| 38 void close() { | |
| 39 _socket.close(true); | |
| 40 } | |
| 41 | |
| 42 void _onData(List<int> data) { | |
| 43 // TODO(ajohnsen): To be removed, since the socket should not be written to | |
| 44 // after close. | |
| 45 if (_socket._closed) return; | |
| 46 Expect.isFalse(_written > _cutoff); | |
| 47 Expect.listEquals(data, _data.getRange(0, data.length)); | |
| 48 _data = _data.getRange(data.length, _data.length - data.length); | |
| 49 _written += data.length; | |
| 50 if (_written >= _cutoff) { | |
| 51 // Tell HttpServer that the socket have closed. | |
| 52 _socket._closeInternal(_closeAsError); | |
| 53 } | |
| 54 } | |
| 55 | |
| 56 Function _onNoPendingWrites; | |
| 57 Function _onError; | |
| 58 List<int> _data; | |
| 59 int _written = 0; | |
| 60 int _cutoff; | |
| 61 bool _closeAsError; | |
| 62 SocketMock _socket; | |
| 63 } | |
| 64 | |
| 65 class SocketMock implements Socket { | |
| 66 SocketMock(List<int> this._data, | |
| 67 List<int> expected, | |
| 68 int cutoff, | |
| 69 bool closeAsError) : | |
| 70 _hashCode = new Random().nextInt(1<< 32), | |
| 71 _read = [] { | |
| 72 _outputStream = | |
| 73 new ExpectedDataOutputStream(expected, cutoff, closeAsError, this); | |
| 74 } | |
| 75 | |
| 76 int available() { | |
| 77 return _data.length; | |
| 78 } | |
| 79 | |
| 80 void _closeInternal([bool asError = false]) { | |
| 81 Expect.isFalse(_closed); | |
| 82 _closed = true; | |
| 83 _onClosedInternal(); | |
| 84 if (asError) { | |
| 85 _onError(new Exception("Socket closed unexpected")); | |
| 86 } else { | |
| 87 _onClosed(); | |
| 88 } | |
| 89 } | |
| 90 | |
| 91 List<int> read([int len]) { | |
| 92 var result; | |
| 93 if (len == null) { | |
| 94 result = _data; | |
| 95 _data = []; | |
| 96 } else { | |
| 97 result = new Uint8List(len); | |
| 98 readList(result, 0, len); | |
| 99 } | |
| 100 return result; | |
| 101 } | |
| 102 | |
| 103 int readList(List<int> buffer, int offset, int count) { | |
| 104 int max = min(count, _data.length); | |
| 105 buffer.setRange(offset, max, _data); | |
| 106 _data = _data.getRange(max, _data.length - max); | |
| 107 return max; | |
| 108 } | |
| 109 | |
| 110 void close([bool halfClose = false]) { | |
| 111 if (!halfClose && !_closed) _closeInternal(); | |
| 112 } | |
| 113 | |
| 114 void set onData(void callback()) { | |
| 115 _onData = callback; | |
| 116 } | |
| 117 | |
| 118 void set onClosed(void callback()) { | |
| 119 _onClosed = callback; | |
| 120 } | |
| 121 | |
| 122 void set onError(void callback(e)) { | |
| 123 _onError = callback; | |
| 124 } | |
| 125 | |
| 126 OutputStream get outputStream => _outputStream; | |
| 127 | |
| 128 int get hashCode => _hashCode; | |
| 129 | |
| 130 List<int> _read; | |
| 131 bool _closed = false; | |
| 132 int _hashCode; | |
| 133 Function _onData; | |
| 134 Function _onClosed; | |
| 135 Function _onError; | |
| 136 Function _onClosedInternal; | |
| 137 List<int> _data; | |
| 138 ExpectedDataOutputStream _outputStream; | |
| 139 } | |
| 140 | |
| 141 class ServerSocketMock implements ServerSocket { | |
| 142 ServerSocketMock(String addr, int this._port, int backlog) : | |
| 143 _sockets = new Set<Socket>(); | |
| 144 | |
| 145 void spawnSocket(var data, String response, int cutOff, bool closeAsError) { | |
| 146 if (data is String) data = data.charCodes; | |
| 147 SocketMock socket = new SocketMock(data, | |
| 148 response.charCodes, | |
| 149 cutOff, | |
| 150 closeAsError); | |
| 151 _sockets.add(socket); | |
| 152 ReceivePort port = new ReceivePort(); | |
| 153 socket._onClosedInternal = () { | |
| 154 // The server should always close the connection. | |
| 155 _sockets.remove(socket); | |
| 156 port.close(); | |
| 157 }; | |
| 158 // Tell HttpServer that a connection have come to life. | |
| 159 _onConnection(socket); | |
| 160 // Start 'sending' data. | |
| 161 socket._onData(); | |
| 162 } | |
| 163 | |
| 164 void close() { | |
| 165 Expect.fail("Don't close the connection, we attach to this socket"); | |
| 166 } | |
| 167 | |
| 168 void set onConnection(void callback(Socket connection)) { | |
| 169 _onConnection = callback; | |
| 170 } | |
| 171 | |
| 172 void set onError(void callback(e)) { | |
| 173 _onError = callback; | |
| 174 } | |
| 175 | |
| 176 int get port => _port; | |
| 177 | |
| 178 int _port; | |
| 179 Function _onConnection; | |
| 180 Function _onError; | |
| 181 Set<Socket> _sockets; | |
| 182 } | |
| 183 | |
| 184 void testSocketClose() { | |
| 185 ServerSocketMock serverSocket = new ServerSocketMock("0.0.0.0", 5432, 5); | |
| 186 | |
| 187 HttpServer server = new HttpServer(); | |
| 188 server.listenOn(serverSocket); | |
| 189 void testContent(String requestString, | |
| 190 String responseString, | |
| 191 [int okayFrom = 0, | |
| 192 bool expectError = true]) { | |
| 193 // Inner callback to actually run a given setting. | |
| 194 void runSettings(int cutoff, | |
| 195 bool closeAsError, | |
| 196 bool expectError) { | |
| 197 server.defaultRequestHandler = | |
| 198 (HttpRequest request, HttpResponse response) { | |
| 199 request.inputStream.onData = () { | |
| 200 }; | |
| 201 request.inputStream.onClosed = () { | |
| 202 response.outputStream.close(); | |
| 203 }; | |
| 204 }; | |
| 205 | |
| 206 if (expectError) { | |
| 207 ReceivePort port = new ReceivePort(); | |
| 208 server.onError = (var error) { | |
| 209 port.close(); | |
| 210 }; | |
| 211 } else { | |
| 212 server.onError = (var error) { | |
| 213 Expect.fail("An error was not expected: $error"); | |
| 214 }; | |
| 215 } | |
| 216 | |
| 217 serverSocket.spawnSocket(requestString, responseString, | |
| 218 cutoff, closeAsError); | |
| 219 // TODO(ajohnsen): Validate HttpServers number of connections. | |
| 220 } | |
| 221 for (int i = 1; i < responseString.length; i++) { | |
| 222 bool _expectError = expectError && i < responseString.length - okayFrom; | |
| 223 runSettings(i, false, _expectError); | |
| 224 runSettings(i, true, _expectError); | |
| 225 } | |
| 226 } | |
| 227 testContent( | |
| 228 "GET / HTTP/1.1\r\nKeep-Alive: False\r\n\r\n", | |
| 229 "HTTP/1.1 200 OK\r\ntransfer-encoding: chunked\r\nconnection: close" | |
| 230 "\r\n\r\n0\r\n\r\n"); | |
| 231 | |
| 232 server.close(); | |
| 233 } | |
| 234 | |
| 235 void main() { | |
| 236 testSocketClose(); | |
| 237 } | |
| OLD | NEW |