aboutsummaryrefslogtreecommitdiff
path: root/tests/compat_ws.c
diff options
context:
space:
mode:
authorGarrett D'Amore <garrett@damore.org>2018-05-22 10:27:47 -0700
committerGarrett D'Amore <garrett@damore.org>2018-05-22 10:29:06 -0700
commit959eabe2675a3b8be9bc2b2459cc899a5a64b283 (patch)
tree373fba9ab3c7cf4c769efb1c42f896694bf16d25 /tests/compat_ws.c
parent67f5ed6e5c0dd7bdd9002bbb519ab34f35fef8dd (diff)
downloadnng-959eabe2675a3b8be9bc2b2459cc899a5a64b283.tar.gz
nng-959eabe2675a3b8be9bc2b2459cc899a5a64b283.tar.bz2
nng-959eabe2675a3b8be9bc2b2459cc899a5a64b283.zip
fixes #474 websocket listen on ws://*:<x> fails
fixes #464 Support NN_WS_MSG_TYPE option (compat) fixes #415 websocket does not honor recv maxsize This fixes a significant (and security) issue in websocket, where the code does not honor a maximum receive size. We've exposed new API (internal) to set the limit on the frame size, and we've changed the default to *unlimited* for that internal API. (But the default for SP sockets, which are the only consumers at present, is still 1MB just like all other SP transports.)
Diffstat (limited to 'tests/compat_ws.c')
-rw-r--r--tests/compat_ws.c281
1 files changed, 281 insertions, 0 deletions
diff --git a/tests/compat_ws.c b/tests/compat_ws.c
new file mode 100644
index 00000000..6d019364
--- /dev/null
+++ b/tests/compat_ws.c
@@ -0,0 +1,281 @@
+/*
+ Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+ Copyright 2018 Capitar IT Group BV <info@capitar.com>
+ Copyright (c) 2012 250bpm s.r.o. All rights reserved.
+ Copyright (c) 2014-2016 Jack R. Dunaway. All rights reserved.
+ Copyright 2016 Franklin "Snaipe" Mathieu <franklinmathieu@gmail.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom
+ the Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+*/
+
+// This file began life in nanomsg, but we have made some significant changes
+// to it. Specifically, NNG has no support for text frames, requires that
+// maximum receive frame sizes be set before connections are established,
+// has support for IPv6, and does not support local interface binding.
+// We have improved the maximum receive size test, and verified that option
+// setting for the frame type conforms to NNG constraints.
+
+#include <nanomsg/nn.h>
+#include <nanomsg/pair.h>
+#include <nanomsg/ws.h>
+
+#include "compat_testutil.h"
+
+static char socket_address[128];
+
+/* Basic tests for WebSocket transport. */
+
+#if 0 // NNG has no support for text frames.
+/* test_text() verifies that we drop messages properly when sending invalid
+ UTF-8, but not when we send valid data. */
+void test_text ()
+{
+ int sb;
+ int sc;
+ int opt;
+ uint8_t bad[20];
+
+ /* Negative testing... bad UTF-8 data for text. */
+ sb = test_socket (AF_SP, NN_PAIR);
+ sc = test_socket (AF_SP, NN_PAIR);
+
+ opt = NN_WS_MSG_TYPE_TEXT;
+ test_setsockopt (sb, NN_WS, NN_WS_MSG_TYPE, &opt, sizeof (opt));
+
+ opt = NN_WS_MSG_TYPE_TEXT;
+ test_setsockopt (sc, NN_WS, NN_WS_MSG_TYPE, &opt, sizeof (opt));
+ opt = 500;
+ test_setsockopt (sb, NN_SOL_SOCKET, NN_RCVTIMEO, &opt, sizeof (opt));
+
+ test_bind (sb, socket_address);
+ test_connect (sc, socket_address);
+
+ test_send (sc, "GOOD");
+ test_recv (sb, "GOOD");
+
+ /* and the bad ... */
+ strcpy ((char *)bad, "BAD.");
+ bad[2] = (char)0xDD;
+ test_send (sc, (char *)bad);
+
+ /* Make sure we dropped the frame. */
+ test_drop (sb, ETIMEDOUT);
+
+ test_close (sb);
+ test_close (sc);
+
+ return;
+}
+#endif
+
+int main (int argc, const char *argv[])
+{
+ int rc;
+ int sb;
+ int sc;
+ int sb2;
+ int opt;
+ size_t sz;
+ int i;
+ char any_address[128];
+
+ test_addr_from (socket_address, "ws", "127.0.0.1",
+ get_test_port (argc, argv));
+
+ test_addr_from (any_address, "ws", "*",
+ get_test_port (argc, argv));
+
+ /* Try closing bound but unconnected socket. */
+ sb = test_socket (AF_SP, NN_PAIR);
+ test_bind (sb, any_address);
+ test_close (sb);
+
+ /* Try closing a TCP socket while it not connected. At the same time
+ test specifying the local address for the connection. */
+ sc = test_socket (AF_SP, NN_PAIR);
+ test_connect (sc, socket_address);
+ test_close (sc);
+
+ /* Open the socket anew. */
+ sc = test_socket (AF_SP, NN_PAIR);
+
+ /* Check socket options. */
+ sz = sizeof (opt);
+ rc = nn_getsockopt (sc, NN_WS, NN_WS_MSG_TYPE, &opt, &sz);
+ errno_assert (rc == 0);
+ nn_assert (sz == sizeof (opt));
+ nn_assert (opt == NN_WS_MSG_TYPE_BINARY);
+
+ /* Default port 80 should be assumed if not explicitly declared. */
+ rc = nn_connect (sc, "ws://127.0.0.1");
+ errno_assert (rc >= 0);
+
+ /* Try using invalid address strings. */
+ rc = nn_connect (sc, "ws://*:");
+ nn_assert (rc < 0);
+ errno_assert (nn_errno () == EINVAL);
+ rc = nn_connect (sc, "ws://*:1000000");
+ nn_assert (rc < 0);
+ errno_assert (nn_errno () == EINVAL);
+ rc = nn_connect (sc, "ws://*:some_port");
+ nn_assert (rc < 0);
+#if 0 // NNG doesn't support device binding
+ rc = nn_connect (sc, "ws://eth10000;127.0.0.1:5555");
+ nn_assert (rc < 0);
+ errno_assert (nn_errno () == ENODEV);
+#endif
+
+ rc = nn_bind (sc, "ws://127.0.0.1:");
+ nn_assert (rc < 0);
+ errno_assert (nn_errno () == EINVAL);
+ rc = nn_bind (sc, "ws://127.0.0.1:1000000");
+ nn_assert (rc < 0);
+ errno_assert (nn_errno () == EINVAL);
+#if 0 // NNG doesn't support device binding
+ rc = nn_bind (sc, "ws://eth10000:5555");
+ nn_assert (rc < 0);
+ errno_assert (nn_errno () == ENODEV);
+#endif
+
+ rc = nn_connect (sc, "ws://:5555");
+ nn_assert (rc < 0);
+ errno_assert (nn_errno () == EINVAL);
+ rc = nn_connect (sc, "ws://-hostname:5555");
+ nn_assert (rc < 0);
+ errno_assert (nn_errno () == EINVAL);
+ rc = nn_connect (sc, "ws://abc.123.---.#:5555");
+ nn_assert (rc < 0);
+ errno_assert (nn_errno () == EINVAL);
+#if 0 // Nothing wrong with this under NNG. Valid IPv6 URL
+ rc = nn_connect (sc, "ws://[::1]:5555");
+ nn_assert (rc < 0);
+#endif
+ errno_assert (nn_errno () == EINVAL);
+ rc = nn_connect (sc, "ws://abc...123:5555");
+ nn_assert (rc < 0);
+ errno_assert (nn_errno () == EINVAL);
+ rc = nn_connect (sc, "ws://.123:5555");
+ nn_assert (rc < 0);
+ errno_assert (nn_errno () == EINVAL);
+
+ test_close (sc);
+
+ sb = test_socket (AF_SP, NN_PAIR);
+ test_bind (sb, socket_address);
+ sc = test_socket (AF_SP, NN_PAIR);
+ test_connect (sc, socket_address);
+
+ nn_sleep(100);
+ /* Ping-pong test. */
+ for (i = 0; i != 100; ++i) {
+
+ test_send (sc, "ABC");
+ test_recv (sb, "ABC");
+
+ test_send (sb, "DEF");
+ test_recv (sc, "DEF");
+ }
+
+ /* Batch transfer test. */
+ for (i = 0; i != 100; ++i) {
+ test_send (sc, "0123456789012345678901234567890123456789");
+ }
+ for (i = 0; i != 100; ++i) {
+ test_recv (sb, "0123456789012345678901234567890123456789");
+ }
+
+ test_close (sc);
+ test_close (sb);
+
+ /* Test two sockets binding to the same address. */
+ sb = test_socket (AF_SP, NN_PAIR);
+ test_bind (sb, socket_address);
+ sb2 = test_socket (AF_SP, NN_PAIR);
+
+ rc = nn_bind (sb2, socket_address);
+ nn_assert (rc < 0);
+ errno_assert (nn_errno () == EADDRINUSE);
+ test_close(sb);
+ test_close(sb2);
+
+ /* Test that NN_RCVMAXSIZE can be -1, but not lower */
+ sb = test_socket (AF_SP, NN_PAIR);
+ opt = -1;
+ rc = nn_setsockopt (sb, NN_SOL_SOCKET, NN_RCVMAXSIZE, &opt, sizeof (opt));
+ nn_assert (rc >= 0);
+ opt = -2;
+ rc = nn_setsockopt (sb, NN_SOL_SOCKET, NN_RCVMAXSIZE, &opt, sizeof (opt));
+ nn_assert (rc < 0);
+ errno_assert (nn_errno () == EINVAL);
+ test_close (sb);
+
+ /* Test NN_RCVMAXSIZE limit */
+ sb = test_socket (AF_SP, NN_PAIR);
+ opt = 4;
+ test_setsockopt (sb, NN_SOL_SOCKET, NN_RCVMAXSIZE, &opt, sizeof (opt));
+ test_bind (sb, socket_address);
+ sc = test_socket (AF_SP, NN_PAIR);
+ test_connect (sc, socket_address);
+ opt = 1000;
+ test_setsockopt (sc, NN_SOL_SOCKET, NN_SNDTIMEO, &opt, sizeof (opt));
+ nn_assert (opt == 1000);
+ opt = 1000;
+ test_setsockopt (sb, NN_SOL_SOCKET, NN_RCVTIMEO, &opt, sizeof (opt));
+ nn_assert (opt == 1000);
+ test_send (sc, "ABC");
+ test_recv (sb, "ABC");
+ test_send (sc, "ABCD");
+ test_recv (sb, "ABCD");
+ test_send (sc, "ABCDE");
+ test_drop (sb, ETIMEDOUT);
+ test_close (sc);
+
+ /* Increase the size limit, reconnect, then try sending again. */
+ opt = 5;
+ test_setsockopt (sb, NN_SOL_SOCKET, NN_RCVMAXSIZE, &opt, sizeof (opt));
+
+ sc = test_socket (AF_SP, NN_PAIR);
+ test_connect (sc, socket_address);
+ nn_sleep(200);
+
+ test_send (sc, "ABCDE");
+ test_recv (sb, "ABCDE");
+ test_close (sb);
+ test_close (sc);
+
+#if 0 // NNG doesn't support text frames.
+ test_text ();
+#else
+ opt = NN_WS_MSG_TYPE_TEXT;
+ rc = nn_setsockopt (sc, NN_WS, NN_WS_MSG_TYPE, &opt, sizeof (opt));
+ nn_assert (rc < 0);
+ errno_assert (nn_errno () == EINVAL);
+
+ opt = NN_WS_MSG_TYPE_BINARY;
+ test_setsockopt (sb, NN_WS, NN_WS_MSG_TYPE, &opt, sizeof (opt));
+#endif
+
+ /* Test closing a socket that is waiting to connect. */
+ sc = test_socket (AF_SP, NN_PAIR);
+ test_connect (sc, socket_address);
+ nn_sleep (100);
+ test_close (sc);
+
+ return 0;
+}