diff options
-rw-r--r-- | src/library.js | 4 | ||||
-rw-r--r-- | src/library_sockfs.js | 38 | ||||
-rw-r--r-- | src/settings.js | 13 | ||||
-rw-r--r-- | tests/test_sockets.py | 53 |
4 files changed, 94 insertions, 14 deletions
diff --git a/src/library.js b/src/library.js index e711ee98..8aac2bb2 100644 --- a/src/library.js +++ b/src/library.js @@ -8176,7 +8176,9 @@ LibraryManager.library = { }, setsockopt: function(d, level, optname, optval, optlen) { +#if SOCKET_DEBUG console.log('ignoring setsockopt command'); +#endif return 0; }, @@ -8665,7 +8667,9 @@ LibraryManager.library = { }, setsockopt: function(fd, level, optname, optval, optlen) { +#if SOCKET_DEBUG console.log('ignoring setsockopt command'); +#endif return 0; }, diff --git a/src/library_sockfs.js b/src/library_sockfs.js index 22fd8761..23641464 100644 --- a/src/library_sockfs.js +++ b/src/library_sockfs.js @@ -133,12 +133,42 @@ mergeInto(LibraryManager.library, { } else { // create the actual websocket object and connect try { - var url = 'ws://' + addr + ':' + port; + // runtimeConfig gets set to true if WebSocket runtime configuration is available. + var runtimeConfig = (Module['websocket'] && ('object' === typeof Module['websocket'])); + + // The default value is 'ws://' the replace is needed because the compiler replaces "//" comments with '#' + // comments without checking context, so we'd end up with ws:#, the replace swaps the "#" for "//" again. + var url = '{{{ WEBSOCKET_URL }}}'.replace('#', '//'); + + if (runtimeConfig) { + if ('string' === typeof Module['websocket']['url']) { + url = Module['websocket']['url']; // Fetch runtime WebSocket URL config. + } + } + + if (url === 'ws://' || url === 'wss://') { // Is the supplied URL config just a prefix, if so complete it. + url = url + addr + ':' + port; + } + + // Make the WebSocket subprotocol (Sec-WebSocket-Protocol) default to binary if no configuration is set. + var subProtocols = '{{{ WEBSOCKET_SUBPROTOCOL }}}'; // The default value is 'binary' + + if (runtimeConfig) { + if ('string' === typeof Module['websocket']['subprotocol']) { + subProtocols = Module['websocket']['subprotocol']; // Fetch runtime WebSocket subprotocol config. + } + } + + // The regex trims the string (removes spaces at the beginning and end, then splits the string by + // <any space>,<any space> into an Array. Whitespace removal is important for Websockify and ws. + subProtocols = subProtocols.replace(/^ +| +$/g,"").split(/ *, */); + + // The node ws library API for specifying optional subprotocol is slightly different than the browser's. + var opts = ENVIRONMENT_IS_NODE ? {'protocol': subProtocols.toString()} : subProtocols; + #if SOCKET_DEBUG - console.log('connect: ' + url); + Module.print('connect: ' + url + ', ' + subProtocols.toString()); #endif - // the node ws library API is slightly different than the browser's - var opts = ENVIRONMENT_IS_NODE ? {headers: {'websocket-protocol': ['binary']}} : ['binary']; // If node we use the ws library. var WebSocket = ENVIRONMENT_IS_NODE ? require('ws') : window['WebSocket']; ws = new WebSocket(url, opts); diff --git a/src/settings.js b/src/settings.js index 1c41676d..6e644a54 100644 --- a/src/settings.js +++ b/src/settings.js @@ -225,6 +225,19 @@ var LIBRARY_DEBUG = 0; // Print out when we enter a library call (library*.js). var SOCKET_DEBUG = 0; // Log out socket/network data transfer. var SOCKET_WEBRTC = 0; // Select socket backend, either webrtc or websockets. +// As well as being configurable at compile time via the "-s" option the WEBSOCKET_URL and WEBSOCKET_SUBPROTOCOL +// settings may configured at run time via the Module object e.g. +// Module['websocket'] = {subprotocol: 'base64, binary, text'}; +// Module['websocket'] = {url: 'wss://', subprotocol: 'base64'}; +// Run time configuration may be useful as it lets an application select multiple different services. +var WEBSOCKET_URL = 'ws://'; // A string containing either a WebSocket URL prefix (ws:// or wss://) or a complete + // RFC 6455 URL - "ws[s]:" "//" host [ ":" port ] path [ "?" query ]. + // In the (default) case of only a prefix being specified the URL will be constructed from + // prefix + addr + ':' + port + // where addr and port are derived from the socket connect/bind/accept calls. +var WEBSOCKET_SUBPROTOCOL = 'binary'; // A string containing a comma separated list of WebSocket subprotocols + // as would be present in the Sec-WebSocket-Protocol header. + var OPENAL_DEBUG = 0; // Print out debugging information from our OpenAL implementation. var GL_ASSERTIONS = 0; // Adds extra checks for error situations in the GL library. Can impact performance. diff --git a/tests/test_sockets.py b/tests/test_sockets.py index 3a5555ed..f1bdc320 100644 --- a/tests/test_sockets.py +++ b/tests/test_sockets.py @@ -414,21 +414,54 @@ class sockets(BrowserCore): sockets_include = '-I'+path_from_root('tests', 'sockets') - # Websockify-proxied servers can't run dgram tests harnesses = [ - # Websockify doesn't seem to like ws.WebSocket clients TODO check if this is a ws issue or Websockify issue - #(WebsockifyServerHarness(os.path.join('sockets', 'test_sockets_echo_server.c'), [sockets_include], 49160), 0), - (CompiledServerHarness(os.path.join('sockets', 'test_sockets_echo_server.c'), [sockets_include, '-DTEST_DGRAM=0'], 49161), 0), - (CompiledServerHarness(os.path.join('sockets', 'test_sockets_echo_server.c'), [sockets_include, '-DTEST_DGRAM=1'], 49162), 1) + (WebsockifyServerHarness(os.path.join('sockets', 'test_sockets_echo_server.c'), [sockets_include], 59160), 0), + (CompiledServerHarness(os.path.join('sockets', 'test_sockets_echo_server.c'), [sockets_include, '-DTEST_DGRAM=0'], 59162), 0), + (CompiledServerHarness(os.path.join('sockets', 'test_sockets_echo_server.c'), [sockets_include, '-DTEST_DGRAM=1'], 59164), 1) ] + # Basic test of node client against both a Websockified and compiled echo server. for harness, datagram in harnesses: with harness: - Popen([PYTHON, EMCC, path_from_root('tests', 'sockets', 'test_sockets_echo_client.c'), '-o', path_from_root('tests', 'sockets', 'client.js'), '-DSOCKK=%d' % harness.listen_port, '-DREPORT_RESULT=int dummy'], stdout=PIPE, stderr=PIPE).communicate() + Popen([PYTHON, EMCC, path_from_root('tests', 'sockets', 'test_sockets_echo_client.c'), '-o', 'client.js', '-DSOCKK=%d' % harness.listen_port, '-DTEST_DGRAM=%d' % datagram, '-DREPORT_RESULT=int dummy'], stdout=PIPE, stderr=PIPE).communicate() + + out = run_js('client.js', engine=NODE_JS, full_output=True) + self.assertContained('do_msg_read: read 14 bytes', out) + + # Test against a Websockified server with compile time configured WebSocket subprotocol. We use a Websockified + # server because as long as the subprotocol list contains binary it will configure itself to accept binary + # This test also checks that the connect url contains the correct subprotocols. + print "\nTesting compile time WebSocket configuration.\n" + for harness in [ + WebsockifyServerHarness(os.path.join('sockets', 'test_sockets_echo_server.c'), [sockets_include], 59166) + ]: + with harness: + Popen([PYTHON, EMCC, path_from_root('tests', 'sockets', 'test_sockets_echo_client.c'), '-o', 'client.js', '-s', 'SOCKET_DEBUG=1', '-s', 'WEBSOCKET_SUBPROTOCOL="base64, binary"', '-DSOCKK=59166', '-DREPORT_RESULT=int dummy'], stdout=PIPE, stderr=PIPE).communicate() + + out = run_js('client.js', engine=NODE_JS, full_output=True) + self.assertContained('do_msg_read: read 14 bytes', out) + self.assertContained('connect: ws://127.0.0.1:59166, base64,binary', out) + + # Test against a Websockified server with runtime WebSocket configuration. We specify both url and subprotocol. + # In this test we have *deliberately* used the wrong port '-DSOCKK=12345' to configure the echo_client.c, so + # the connection would fail without us specifying a valid WebSocket URL in the configuration. + print "\nTesting runtime WebSocket configuration.\n" + for harness in [ + WebsockifyServerHarness(os.path.join('sockets', 'test_sockets_echo_server.c'), [sockets_include], 59168) + ]: + with harness: + open(os.path.join(self.get_dir(), 'websocket_pre.js'), 'w').write(''' + var Module = { + websocket: { + url: 'ws://localhost:59168/testA/testB', + subprotocol: 'text, base64, binary', + } + }; + ''') - self.assertContained('do_msg_read: read 14 bytes', run_js(path_from_root('tests', 'sockets', 'client.js'), engine=NODE_JS)) + Popen([PYTHON, EMCC, path_from_root('tests', 'sockets', 'test_sockets_echo_client.c'), '-o', 'client.js', '--pre-js', 'websocket_pre.js', '-s', 'SOCKET_DEBUG=1', '-DSOCKK=12345', '-DREPORT_RESULT=int dummy'], stdout=PIPE, stderr=PIPE).communicate() - # Tidy up files that might have been created by this test. - try_delete(path_from_root('tests', 'sockets', 'client.js')) - try_delete(path_from_root('tests', 'sockets', 'client.js.map')) + out = run_js('client.js', engine=NODE_JS, full_output=True) + self.assertContained('do_msg_read: read 14 bytes', out) + self.assertContained('connect: ws://localhost:59168/testA/testB, text,base64,binary', out) |