{
    "file_diffs": [
        {
            "old_file_content": "from __future__ import absolute_import, division, print_function, with_statement\n\nimport traceback\n\nfrom tornado.concurrent import Future\nfrom tornado.httpclient import HTTPError, HTTPRequest\nfrom tornado.log import gen_log\nfrom tornado.testing import AsyncHTTPTestCase, gen_test, bind_unused_port, ExpectLog\nfrom tornado.test.util import unittest, skipOnTravis\nfrom tornado.web import Application, RequestHandler\n\ntry:\n    import tornado.websocket\nexcept ImportError:\n    # The unittest module presents misleading errors on ImportError\n    # (it acts as if websocket_test could not be found, hiding the underlying\n    # error).  If we get an ImportError here (which could happen due to\n    # TORNADO_EXTENSION=1), print some extra information before failing.\n    traceback.print_exc()\n    raise\n\nfrom tornado.websocket import WebSocketHandler, websocket_connect, WebSocketError, _websocket_mask_python\n\ntry:\n    from tornado import speedups\nexcept ImportError:\n    speedups = None\n\n\nclass TestWebSocketHandler(WebSocketHandler):\n    \"\"\"Base class for testing handlers that exposes the on_close event.\n\n    This allows for deterministic cleanup of the associated socket.\n    \"\"\"\n    def initialize(self, close_future):\n        self.close_future = close_future\n\n    def on_close(self):\n        self.close_future.set_result((self.close_code, self.close_reason))\n\n\nclass EchoHandler(TestWebSocketHandler):\n    def on_message(self, message):\n        self.write_message(message, isinstance(message, bytes))\n\n\nclass HeaderHandler(TestWebSocketHandler):\n    def open(self):\n        self.write_message(self.request.headers.get('X-Test', ''))\n\n\nclass NonWebSocketHandler(RequestHandler):\n    def get(self):\n        self.write('ok')\n\n\nclass CloseReasonHandler(TestWebSocketHandler):\n    def open(self):\n        self.close(1001, \"goodbye\")\n\n\nclass WebSocketTest(AsyncHTTPTestCase):\n    def get_app(self):\n        self.close_future = Future()\n        return Application([\n            ('/echo', EchoHandler, dict(close_future=self.close_future)),\n            ('/non_ws', NonWebSocketHandler),\n            ('/header', HeaderHandler, dict(close_future=self.close_future)),\n            ('/close_reason', CloseReasonHandler,\n             dict(close_future=self.close_future)),\n        ])\n\n    @gen_test\n    def test_websocket_gen(self):\n        ws = yield websocket_connect(\n            'ws://localhost:%d/echo' % self.get_http_port(),\n            io_loop=self.io_loop)\n        ws.write_message('hello')\n        response = yield ws.read_message()\n        self.assertEqual(response, 'hello')\n        ws.close()\n        yield self.close_future\n\n    def test_websocket_callbacks(self):\n        websocket_connect(\n            'ws://localhost:%d/echo' % self.get_http_port(),\n            io_loop=self.io_loop, callback=self.stop)\n        ws = self.wait().result()\n        ws.write_message('hello')\n        ws.read_message(self.stop)\n        response = self.wait().result()\n        self.assertEqual(response, 'hello')\n        self.close_future.add_done_callback(lambda f: self.stop())\n        ws.close()\n        self.wait()\n\n    @gen_test\n    def test_websocket_http_fail(self):\n        with self.assertRaises(HTTPError) as cm:\n            yield websocket_connect(\n                'ws://localhost:%d/notfound' % self.get_http_port(),\n                io_loop=self.io_loop)\n        self.assertEqual(cm.exception.code, 404)\n\n    @gen_test\n    def test_websocket_http_success(self):\n        with self.assertRaises(WebSocketError):\n            yield websocket_connect(\n                'ws://localhost:%d/non_ws' % self.get_http_port(),\n                io_loop=self.io_loop)\n\n    @skipOnTravis\n    @gen_test\n    def test_websocket_network_timeout(self):\n        sock, port = bind_unused_port()\n        sock.close()\n        with self.assertRaises(HTTPError) as cm:\n            with ExpectLog(gen_log, \".*\"):\n                yield websocket_connect(\n                    'ws://localhost:%d/' % port,\n                    io_loop=self.io_loop,\n                    connect_timeout=0.01)\n        self.assertEqual(cm.exception.code, 599)\n\n    @gen_test\n    def test_websocket_network_fail(self):\n        sock, port = bind_unused_port()\n        sock.close()\n        with self.assertRaises(HTTPError) as cm:\n            with ExpectLog(gen_log, \".*\"):\n                yield websocket_connect(\n                    'ws://localhost:%d/' % port,\n                    io_loop=self.io_loop,\n                    connect_timeout=3600)\n        self.assertEqual(cm.exception.code, 599)\n\n    @gen_test\n    def test_websocket_close_buffered_data(self):\n        ws = yield websocket_connect(\n            'ws://localhost:%d/echo' % self.get_http_port())\n        ws.write_message('hello')\n        ws.write_message('world')\n        ws.stream.close()\n        yield self.close_future\n\n    @gen_test\n    def test_websocket_headers(self):\n        # Ensure that arbitrary headers can be passed through websocket_connect.\n        ws = yield websocket_connect(\n            HTTPRequest('ws://localhost:%d/header' % self.get_http_port(),\n                        headers={'X-Test': 'hello'}))\n        response = yield ws.read_message()\n        self.assertEqual(response, 'hello')\n        ws.close()\n        yield self.close_future\n\n    @gen_test\n    def test_server_close_reason(self):\n        ws = yield websocket_connect(\n            'ws://localhost:%d/close_reason' % self.get_http_port())\n        msg = yield ws.read_message()\n        # A message of None means the other side closed the connection.\n        self.assertIs(msg, None)\n        self.assertEqual(ws.close_code, 1001)\n        self.assertEqual(ws.close_reason, \"goodbye\")\n\n    @gen_test\n    def test_client_close_reason(self):\n        ws = yield websocket_connect(\n            'ws://localhost:%d/echo' % self.get_http_port())\n        ws.close(1001, 'goodbye')\n        code, reason = yield self.close_future\n        self.assertEqual(code, 1001)\n        self.assertEqual(reason, 'goodbye')\n\n    @gen_test\n    def test_check_origin_valid(self):\n        port = self.get_http_port()\n\n        url = 'ws://localhost:%d/echo' % port\n        headers = {'Origin': 'http://localhost:%d' % port}\n\n        ws = yield websocket_connect(HTTPRequest(url, headers=headers),\n            io_loop=self.io_loop)\n        ws.write_message('hello')\n        response = yield ws.read_message()\n        self.assertEqual(response, 'hello')\n        ws.close()\n        yield self.close_future\n\n    @gen_test\n    def test_check_origin_invalid(self):\n        '''Currently a failing test'''\n        port = self.get_http_port()\n\n        url = 'ws://localhost:%d/echo' % port\n        headers = {'Origin': 'http://somewhereelse.com'}\n\n        ws = yield websocket_connect(HTTPRequest(url, headers=headers),\n            io_loop=self.io_loop)\n        ws.write_message('hello')\n\n        response = yield ws.read_message()\n\n        self.assertEqual(response, None)\n        ws.close()\n        yield self.close_future\n\n\nclass MaskFunctionMixin(object):\n    # Subclasses should define self.mask(mask, data)\n    def test_mask(self):\n        self.assertEqual(self.mask(b'abcd', b''), b'')\n        self.assertEqual(self.mask(b'abcd', b'b'), b'\\x03')\n        self.assertEqual(self.mask(b'abcd', b'54321'), b'TVPVP')\n        self.assertEqual(self.mask(b'ZXCV', b'98765432'), b'c`t`olpd')\n        # Include test cases with \\x00 bytes (to ensure that the C\n        # extension isn't depending on null-terminated strings) and\n        # bytes with the high bit set (to smoke out signedness issues).\n        self.assertEqual(self.mask(b'\\x00\\x01\\x02\\x03',\n                                   b'\\xff\\xfb\\xfd\\xfc\\xfe\\xfa'),\n                         b'\\xff\\xfa\\xff\\xff\\xfe\\xfb')\n        self.assertEqual(self.mask(b'\\xff\\xfb\\xfd\\xfc',\n                                   b'\\x00\\x01\\x02\\x03\\x04\\x05'),\n                         b'\\xff\\xfa\\xff\\xff\\xfb\\xfe')\n\n\nclass PythonMaskFunctionTest(MaskFunctionMixin, unittest.TestCase):\n    def mask(self, mask, data):\n        return _websocket_mask_python(mask, data)\n\n\n@unittest.skipIf(speedups is None, \"tornado.speedups module not present\")\nclass CythonMaskFunctionTest(MaskFunctionMixin, unittest.TestCase):\n    def mask(self, mask, data):\n        return speedups.websocket_mask(mask, data)\n",
            "new_file_content": "from __future__ import absolute_import, division, print_function, with_statement\n\nimport traceback\n\nfrom tornado.concurrent import Future\nfrom tornado.httpclient import HTTPError, HTTPRequest\nfrom tornado.log import gen_log\nfrom tornado.testing import AsyncHTTPTestCase, gen_test, bind_unused_port, ExpectLog\nfrom tornado.test.util import unittest, skipOnTravis\nfrom tornado.web import Application, RequestHandler\n\ntry:\n    import tornado.websocket\nexcept ImportError:\n    # The unittest module presents misleading errors on ImportError\n    # (it acts as if websocket_test could not be found, hiding the underlying\n    # error).  If we get an ImportError here (which could happen due to\n    # TORNADO_EXTENSION=1), print some extra information before failing.\n    traceback.print_exc()\n    raise\n\nfrom tornado.websocket import WebSocketHandler, websocket_connect, WebSocketError, _websocket_mask_python\n\ntry:\n    from tornado import speedups\nexcept ImportError:\n    speedups = None\n\n\nclass TestWebSocketHandler(WebSocketHandler):\n    \"\"\"Base class for testing handlers that exposes the on_close event.\n\n    This allows for deterministic cleanup of the associated socket.\n    \"\"\"\n    def initialize(self, close_future):\n        self.close_future = close_future\n\n    def on_close(self):\n        self.close_future.set_result((self.close_code, self.close_reason))\n\n\nclass EchoHandler(TestWebSocketHandler):\n    def on_message(self, message):\n        self.write_message(message, isinstance(message, bytes))\n\n\nclass HeaderHandler(TestWebSocketHandler):\n    def open(self):\n        self.write_message(self.request.headers.get('X-Test', ''))\n\n\nclass NonWebSocketHandler(RequestHandler):\n    def get(self):\n        self.write('ok')\n\n\nclass CloseReasonHandler(TestWebSocketHandler):\n    def open(self):\n        self.close(1001, \"goodbye\")\n\n\nclass WebSocketTest(AsyncHTTPTestCase):\n    def get_app(self):\n        self.close_future = Future()\n        return Application([\n            ('/echo', EchoHandler, dict(close_future=self.close_future)),\n            ('/non_ws', NonWebSocketHandler),\n            ('/header', HeaderHandler, dict(close_future=self.close_future)),\n            ('/close_reason', CloseReasonHandler,\n             dict(close_future=self.close_future)),\n        ])\n\n    @gen_test\n    def test_websocket_gen(self):\n        ws = yield websocket_connect(\n            'ws://localhost:%d/echo' % self.get_http_port(),\n            io_loop=self.io_loop)\n        ws.write_message('hello')\n        response = yield ws.read_message()\n        self.assertEqual(response, 'hello')\n        ws.close()\n        yield self.close_future\n\n    def test_websocket_callbacks(self):\n        websocket_connect(\n            'ws://localhost:%d/echo' % self.get_http_port(),\n            io_loop=self.io_loop, callback=self.stop)\n        ws = self.wait().result()\n        ws.write_message('hello')\n        ws.read_message(self.stop)\n        response = self.wait().result()\n        self.assertEqual(response, 'hello')\n        self.close_future.add_done_callback(lambda f: self.stop())\n        ws.close()\n        self.wait()\n\n    @gen_test\n    def test_websocket_http_fail(self):\n        with self.assertRaises(HTTPError) as cm:\n            yield websocket_connect(\n                'ws://localhost:%d/notfound' % self.get_http_port(),\n                io_loop=self.io_loop)\n        self.assertEqual(cm.exception.code, 404)\n\n    @gen_test\n    def test_websocket_http_success(self):\n        with self.assertRaises(WebSocketError):\n            yield websocket_connect(\n                'ws://localhost:%d/non_ws' % self.get_http_port(),\n                io_loop=self.io_loop)\n\n    @skipOnTravis\n    @gen_test\n    def test_websocket_network_timeout(self):\n        sock, port = bind_unused_port()\n        sock.close()\n        with self.assertRaises(HTTPError) as cm:\n            with ExpectLog(gen_log, \".*\"):\n                yield websocket_connect(\n                    'ws://localhost:%d/' % port,\n                    io_loop=self.io_loop,\n                    connect_timeout=0.01)\n        self.assertEqual(cm.exception.code, 599)\n\n    @gen_test\n    def test_websocket_network_fail(self):\n        sock, port = bind_unused_port()\n        sock.close()\n        with self.assertRaises(HTTPError) as cm:\n            with ExpectLog(gen_log, \".*\"):\n                yield websocket_connect(\n                    'ws://localhost:%d/' % port,\n                    io_loop=self.io_loop,\n                    connect_timeout=3600)\n        self.assertEqual(cm.exception.code, 599)\n\n    @gen_test\n    def test_websocket_close_buffered_data(self):\n        ws = yield websocket_connect(\n            'ws://localhost:%d/echo' % self.get_http_port())\n        ws.write_message('hello')\n        ws.write_message('world')\n        ws.stream.close()\n        yield self.close_future\n\n    @gen_test\n    def test_websocket_headers(self):\n        # Ensure that arbitrary headers can be passed through websocket_connect.\n        ws = yield websocket_connect(\n            HTTPRequest('ws://localhost:%d/header' % self.get_http_port(),\n                        headers={'X-Test': 'hello'}))\n        response = yield ws.read_message()\n        self.assertEqual(response, 'hello')\n        ws.close()\n        yield self.close_future\n\n    @gen_test\n    def test_server_close_reason(self):\n        ws = yield websocket_connect(\n            'ws://localhost:%d/close_reason' % self.get_http_port())\n        msg = yield ws.read_message()\n        # A message of None means the other side closed the connection.\n        self.assertIs(msg, None)\n        self.assertEqual(ws.close_code, 1001)\n        self.assertEqual(ws.close_reason, \"goodbye\")\n\n    @gen_test\n    def test_client_close_reason(self):\n        ws = yield websocket_connect(\n            'ws://localhost:%d/echo' % self.get_http_port())\n        ws.close(1001, 'goodbye')\n        code, reason = yield self.close_future\n        self.assertEqual(code, 1001)\n        self.assertEqual(reason, 'goodbye')\n\n    @gen_test\n    def test_check_origin_valid(self):\n        port = self.get_http_port()\n\n        url = 'ws://localhost:%d/echo' % port\n        headers = {'Origin': 'http://localhost:%d' % port}\n\n        ws = yield websocket_connect(HTTPRequest(url, headers=headers),\n            io_loop=self.io_loop)\n        ws.write_message('hello')\n        response = yield ws.read_message()\n        self.assertEqual(response, 'hello')\n        ws.close()\n        yield self.close_future\n\n    @gen_test\n    def test_check_origin_valid2(self):\n        port = self.get_http_port()\n\n        url = 'ws://localhost:%d/echo' % port\n        headers = {'Origin': 'localhost:%d' % port}\n\n        ws = yield websocket_connect(HTTPRequest(url, headers=headers),\n            io_loop=self.io_loop)\n        ws.write_message('hello')\n        response = yield ws.read_message()\n        self.assertEqual(response, 'hello')\n        ws.close()\n        yield self.close_future\n\n    @gen_test\n    def test_check_origin_invalid(self):\n        port = self.get_http_port()\n\n        url = 'ws://localhost:%d/echo' % port\n        # Host is localhost, which should not be accessible from some other\n        # domain\n        headers = {'Origin': 'http://somewhereelse.com'}\n\n        with self.assertRaises(HTTPError) as cm:\n            yield websocket_connect(HTTPRequest(url, headers=headers),\n                                    io_loop=self.io_loop)\n\n        self.assertEqual(cm.exception.code, 403)\n\n    @gen_test\n    def test_check_origin_invalid2(self):\n        port = self.get_http_port()\n\n        url = 'ws://localhost:%d/echo' % port\n        # subdomains should be invalid by default\n        headers = {'Origin': 'http://subtenant.somewhereelse.com',\n                   'Host': 'subtenant2.somewhereelse.com'}\n\n        with self.assertRaises(HTTPError) as cm:\n            yield websocket_connect(HTTPRequest(url, headers=headers),\n                                    io_loop=self.io_loop)\n\n        self.assertEqual(cm.exception.code, 403)\n\n\nclass MaskFunctionMixin(object):\n    # Subclasses should define self.mask(mask, data)\n    def test_mask(self):\n        self.assertEqual(self.mask(b'abcd', b''), b'')\n        self.assertEqual(self.mask(b'abcd', b'b'), b'\\x03')\n        self.assertEqual(self.mask(b'abcd', b'54321'), b'TVPVP')\n        self.assertEqual(self.mask(b'ZXCV', b'98765432'), b'c`t`olpd')\n        # Include test cases with \\x00 bytes (to ensure that the C\n        # extension isn't depending on null-terminated strings) and\n        # bytes with the high bit set (to smoke out signedness issues).\n        self.assertEqual(self.mask(b'\\x00\\x01\\x02\\x03',\n                                   b'\\xff\\xfb\\xfd\\xfc\\xfe\\xfa'),\n                         b'\\xff\\xfa\\xff\\xff\\xfe\\xfb')\n        self.assertEqual(self.mask(b'\\xff\\xfb\\xfd\\xfc',\n                                   b'\\x00\\x01\\x02\\x03\\x04\\x05'),\n                         b'\\xff\\xfa\\xff\\xff\\xfb\\xfe')\n\n\nclass PythonMaskFunctionTest(MaskFunctionMixin, unittest.TestCase):\n    def mask(self, mask, data):\n        return _websocket_mask_python(mask, data)\n\n\n@unittest.skipIf(speedups is None, \"tornado.speedups module not present\")\nclass CythonMaskFunctionTest(MaskFunctionMixin, unittest.TestCase):\n    def mask(self, mask, data):\n        return speedups.websocket_mask(mask, data)\n",
            "header": {
                "file": {
                    "path": "tornado/test/websocket_test.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "dae5d88b",
                "new_commit_hash": "1873af3f",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/tornado/test/websocket_test.py"
            },
            "plus_file": {
                "path": "b/tornado/test/websocket_test.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 189,
                            "length": 23
                        },
                        "new_range": {
                            "start": 189,
                            "length": 50
                        },
                        "section": "class WebSocketTest(AsyncHTTPTestCase):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "        yield self.close_future",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    @gen_test",
                                "type": "context"
                            },
                            {
                                "content": "    def test_check_origin_invalid(self):",
                                "type": "deleted"
                            },
                            {
                                "content": "        '''Currently a failing test'''",
                                "type": "deleted"
                            },
                            {
                                "content": "    def test_check_origin_valid2(self):",
                                "type": "added"
                            },
                            {
                                "content": "        port = self.get_http_port()",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "        url = 'ws://localhost:%d/echo' % port",
                                "type": "context"
                            },
                            {
                                "content": "        headers = {'Origin': 'http://somewhereelse.com'}",
                                "type": "deleted"
                            },
                            {
                                "content": "        headers = {'Origin': 'localhost:%d' % port}",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "        ws = yield websocket_connect(HTTPRequest(url, headers=headers),",
                                "type": "context"
                            },
                            {
                                "content": "            io_loop=self.io_loop)",
                                "type": "context"
                            },
                            {
                                "content": "        ws.write_message('hello')",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "deleted"
                            },
                            {
                                "content": "        response = yield ws.read_message()",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "deleted"
                            },
                            {
                                "content": "        self.assertEqual(response, None)",
                                "type": "deleted"
                            },
                            {
                                "content": "        self.assertEqual(response, 'hello')",
                                "type": "added"
                            },
                            {
                                "content": "        ws.close()",
                                "type": "context"
                            },
                            {
                                "content": "        yield self.close_future",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    @gen_test",
                                "type": "added"
                            },
                            {
                                "content": "    def test_check_origin_invalid(self):",
                                "type": "added"
                            },
                            {
                                "content": "        port = self.get_http_port()",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "        url = 'ws://localhost:%d/echo' % port",
                                "type": "added"
                            },
                            {
                                "content": "        # Host is localhost, which should not be accessible from some other",
                                "type": "added"
                            },
                            {
                                "content": "        # domain",
                                "type": "added"
                            },
                            {
                                "content": "        headers = {'Origin': 'http://somewhereelse.com'}",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "        with self.assertRaises(HTTPError) as cm:",
                                "type": "added"
                            },
                            {
                                "content": "            yield websocket_connect(HTTPRequest(url, headers=headers),",
                                "type": "added"
                            },
                            {
                                "content": "                                    io_loop=self.io_loop)",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "        self.assertEqual(cm.exception.code, 403)",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "    @gen_test",
                                "type": "added"
                            },
                            {
                                "content": "    def test_check_origin_invalid2(self):",
                                "type": "added"
                            },
                            {
                                "content": "        port = self.get_http_port()",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "        url = 'ws://localhost:%d/echo' % port",
                                "type": "added"
                            },
                            {
                                "content": "        # subdomains should be invalid by default",
                                "type": "added"
                            },
                            {
                                "content": "        headers = {'Origin': 'http://subtenant.somewhereelse.com',",
                                "type": "added"
                            },
                            {
                                "content": "                   'Host': 'subtenant2.somewhereelse.com'}",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "        with self.assertRaises(HTTPError) as cm:",
                                "type": "added"
                            },
                            {
                                "content": "            yield websocket_connect(HTTPRequest(url, headers=headers),",
                                "type": "added"
                            },
                            {
                                "content": "                                    io_loop=self.io_loop)",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "        self.assertEqual(cm.exception.code, 403)",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "class MaskFunctionMixin(object):",
                                "type": "context"
                            },
                            {
                                "content": "    # Subclasses should define self.mask(mask, data)",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "tornado/test/websocket_test.py",
                            "type": "method",
                            "name": "WebSocketTest.test_check_origin_invalid",
                            "content": "class WebSocketTest(AsyncHTTPTestCase):\n    def get_app(self):\n        self.close_future = Future()\n        return Application([\n            ('/echo', EchoHandler, dict(close_future=self.close_future)),\n            ('/non_ws', NonWebSocketHandler),\n            ('/header', HeaderHandler, dict(close_future=self.close_future)),\n            ('/close_reason', CloseReasonHandler,\n             dict(close_future=self.close_future)),\n        ])\n\n    @gen_test\n    def test_websocket_gen(self):\n        ws = yield websocket_connect(\n            'ws://localhost:%d/echo' % self.get_http_port(),\n            io_loop=self.io_loop)\n        ws.write_message('hello')\n        response = yield ws.read_message()\n        self.assertEqual(response, 'hello')\n        ws.close()\n        yield self.close_future\n\n    def test_websocket_callbacks(self):\n        websocket_connect(\n            'ws://localhost:%d/echo' % self.get_http_port(),\n            io_loop=self.io_loop, callback=self.stop)\n        ws = self.wait().result()\n        ws.write_message('hello')\n        ws.read_message(self.stop)\n        response = self.wait().result()\n        self.assertEqual(response, 'hello')\n        self.close_future.add_done_callback(lambda f: self.stop())\n        ws.close()\n        self.wait()\n\n    @gen_test\n    def test_websocket_http_fail(self):\n        with self.assertRaises(HTTPError) as cm:\n            yield websocket_connect(\n                'ws://localhost:%d/notfound' % self.get_http_port(),\n                io_loop=self.io_loop)\n        self.assertEqual(cm.exception.code, 404)\n\n    @gen_test\n    def test_websocket_http_success(self):\n        with self.assertRaises(WebSocketError):\n            yield websocket_connect(\n                'ws://localhost:%d/non_ws' % self.get_http_port(),\n                io_loop=self.io_loop)\n\n    @skipOnTravis\n    @gen_test\n    def test_websocket_network_timeout(self):\n        sock, port = bind_unused_port()\n        sock.close()\n        with self.assertRaises(HTTPError) as cm:\n            with ExpectLog(gen_log, \".*\"):\n                yield websocket_connect(\n                    'ws://localhost:%d/' % port,\n                    io_loop=self.io_loop,\n                    connect_timeout=0.01)\n        self.assertEqual(cm.exception.code, 599)\n\n    @gen_test\n    def test_websocket_network_fail(self):\n        sock, port = bind_unused_port()\n        sock.close()\n        with self.assertRaises(HTTPError) as cm:\n            with ExpectLog(gen_log, \".*\"):\n                yield websocket_connect(\n                    'ws://localhost:%d/' % port,\n                    io_loop=self.io_loop,\n                    connect_timeout=3600)\n        self.assertEqual(cm.exception.code, 599)\n\n    @gen_test\n    def test_websocket_close_buffered_data(self):\n        ws = yield websocket_connect(\n            'ws://localhost:%d/echo' % self.get_http_port())\n        ws.write_message('hello')\n        ws.write_message('world')\n        ws.stream.close()\n        yield self.close_future\n\n    @gen_test\n    def test_websocket_headers(self):\n        # Ensure that arbitrary headers can be passed through websocket_connect.\n        ws = yield websocket_connect(\n            HTTPRequest('ws://localhost:%d/header' % self.get_http_port(),\n                        headers={'X-Test': 'hello'}))\n        response = yield ws.read_message()\n        self.assertEqual(response, 'hello')\n        ws.close()\n        yield self.close_future\n\n    @gen_test\n    def test_server_close_reason(self):\n        ws = yield websocket_connect(\n            'ws://localhost:%d/close_reason' % self.get_http_port())\n        msg = yield ws.read_message()\n        # A message of None means the other side closed the connection.\n        self.assertIs(msg, None)\n        self.assertEqual(ws.close_code, 1001)\n        self.assertEqual(ws.close_reason, \"goodbye\")\n\n    @gen_test\n    def test_client_close_reason(self):\n        ws = yield websocket_connect(\n            'ws://localhost:%d/echo' % self.get_http_port())\n        ws.close(1001, 'goodbye')\n        code, reason = yield self.close_future\n        self.assertEqual(code, 1001)\n        self.assertEqual(reason, 'goodbye')\n\n    @gen_test\n    def test_check_origin_valid(self):\n        port = self.get_http_port()\n\n        url = 'ws://localhost:%d/echo' % port\n        headers = {'Origin': 'http://localhost:%d' % port}\n\n        ws = yield websocket_connect(HTTPRequest(url, headers=headers),\n            io_loop=self.io_loop)\n        ws.write_message('hello')\n        response = yield ws.read_message()\n        self.assertEqual(response, 'hello')\n        ws.close()\n        yield self.close_future\n\n    @gen_test\n    def test_check_origin_invalid(self):\n        '''Currently a failing test'''\n        port = self.get_http_port()\n\n        url = 'ws://localhost:%d/echo' % port\n        headers = {'Origin': 'http://somewhereelse.com'}\n\n        ws = yield websocket_connect(HTTPRequest(url, headers=headers),\n            io_loop=self.io_loop)\n        ws.write_message('hello')\n\n        response = yield ws.read_message()\n\n        self.assertEqual(response, None)\n        ws.close()\n        yield self.close_future",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 192,
                            "end_lineno": 207,
                            "parent": {
                                "file_name": "tornado/test/websocket_test.py",
                                "type": "class",
                                "name": "WebSocketTest",
                                "content": "class WebSocketTest(AsyncHTTPTestCase):\n    def get_app(self):\n        self.close_future = Future()\n        return Application([\n            ('/echo', EchoHandler, dict(close_future=self.close_future)),\n            ('/non_ws', NonWebSocketHandler),\n            ('/header', HeaderHandler, dict(close_future=self.close_future)),\n            ('/close_reason', CloseReasonHandler,\n             dict(close_future=self.close_future)),\n        ])\n\n    @gen_test\n    def test_websocket_gen(self):\n        ws = yield websocket_connect(\n            'ws://localhost:%d/echo' % self.get_http_port(),\n            io_loop=self.io_loop)\n        ws.write_message('hello')\n        response = yield ws.read_message()\n        self.assertEqual(response, 'hello')\n        ws.close()\n        yield self.close_future\n\n    def test_websocket_callbacks(self):\n        websocket_connect(\n            'ws://localhost:%d/echo' % self.get_http_port(),\n            io_loop=self.io_loop, callback=self.stop)\n        ws = self.wait().result()\n        ws.write_message('hello')\n        ws.read_message(self.stop)\n        response = self.wait().result()\n        self.assertEqual(response, 'hello')\n        self.close_future.add_done_callback(lambda f: self.stop())\n        ws.close()\n        self.wait()\n\n    @gen_test\n    def test_websocket_http_fail(self):\n        with self.assertRaises(HTTPError) as cm:\n            yield websocket_connect(\n                'ws://localhost:%d/notfound' % self.get_http_port(),\n                io_loop=self.io_loop)\n        self.assertEqual(cm.exception.code, 404)\n\n    @gen_test\n    def test_websocket_http_success(self):\n        with self.assertRaises(WebSocketError):\n            yield websocket_connect(\n                'ws://localhost:%d/non_ws' % self.get_http_port(),\n                io_loop=self.io_loop)\n\n    @skipOnTravis\n    @gen_test\n    def test_websocket_network_timeout(self):\n        sock, port = bind_unused_port()\n        sock.close()\n        with self.assertRaises(HTTPError) as cm:\n            with ExpectLog(gen_log, \".*\"):\n                yield websocket_connect(\n                    'ws://localhost:%d/' % port,\n                    io_loop=self.io_loop,\n                    connect_timeout=0.01)\n        self.assertEqual(cm.exception.code, 599)\n\n    @gen_test\n    def test_websocket_network_fail(self):\n        sock, port = bind_unused_port()\n        sock.close()\n        with self.assertRaises(HTTPError) as cm:\n            with ExpectLog(gen_log, \".*\"):\n                yield websocket_connect(\n                    'ws://localhost:%d/' % port,\n                    io_loop=self.io_loop,\n                    connect_timeout=3600)\n        self.assertEqual(cm.exception.code, 599)\n\n    @gen_test\n    def test_websocket_close_buffered_data(self):\n        ws = yield websocket_connect(\n            'ws://localhost:%d/echo' % self.get_http_port())\n        ws.write_message('hello')\n        ws.write_message('world')\n        ws.stream.close()\n        yield self.close_future\n\n    @gen_test\n    def test_websocket_headers(self):\n        # Ensure that arbitrary headers can be passed through websocket_connect.\n        ws = yield websocket_connect(\n            HTTPRequest('ws://localhost:%d/header' % self.get_http_port(),\n                        headers={'X-Test': 'hello'}))\n        response = yield ws.read_message()\n        self.assertEqual(response, 'hello')\n        ws.close()\n        yield self.close_future\n\n    @gen_test\n    def test_server_close_reason(self):\n        ws = yield websocket_connect(\n            'ws://localhost:%d/close_reason' % self.get_http_port())\n        msg = yield ws.read_message()\n        # A message of None means the other side closed the connection.\n        self.assertIs(msg, None)\n        self.assertEqual(ws.close_code, 1001)\n        self.assertEqual(ws.close_reason, \"goodbye\")\n\n    @gen_test\n    def test_client_close_reason(self):\n        ws = yield websocket_connect(\n            'ws://localhost:%d/echo' % self.get_http_port())\n        ws.close(1001, 'goodbye')\n        code, reason = yield self.close_future\n        self.assertEqual(code, 1001)\n        self.assertEqual(reason, 'goodbye')\n\n    @gen_test\n    def test_check_origin_valid(self):\n        port = self.get_http_port()\n\n        url = 'ws://localhost:%d/echo' % port\n        headers = {'Origin': 'http://localhost:%d' % port}\n\n        ws = yield websocket_connect(HTTPRequest(url, headers=headers),\n            io_loop=self.io_loop)\n        ws.write_message('hello')\n        response = yield ws.read_message()\n        self.assertEqual(response, 'hello')\n        ws.close()\n        yield self.close_future\n\n    @gen_test\n    def test_check_origin_invalid(self):\n        '''Currently a failing test'''\n        port = self.get_http_port()\n\n        url = 'ws://localhost:%d/echo' % port\n        headers = {'Origin': 'http://somewhereelse.com'}\n\n        ws = yield websocket_connect(HTTPRequest(url, headers=headers),\n            io_loop=self.io_loop)\n        ws.write_message('hello')\n\n        response = yield ws.read_message()\n\n        self.assertEqual(response, None)\n        ws.close()\n        yield self.close_future",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 62,
                                "end_lineno": 207,
                                "parent": null
                            }
                        },
                        {
                            "file_name": "tornado/test/websocket_test.py",
                            "type": "class",
                            "name": "WebSocketTest",
                            "content": "class WebSocketTest(AsyncHTTPTestCase):\n    def get_app(self):\n        self.close_future = Future()\n        return Application([\n            ('/echo', EchoHandler, dict(close_future=self.close_future)),\n            ('/non_ws', NonWebSocketHandler),\n            ('/header', HeaderHandler, dict(close_future=self.close_future)),\n            ('/close_reason', CloseReasonHandler,\n             dict(close_future=self.close_future)),\n        ])\n\n    @gen_test\n    def test_websocket_gen(self):\n        ws = yield websocket_connect(\n            'ws://localhost:%d/echo' % self.get_http_port(),\n            io_loop=self.io_loop)\n        ws.write_message('hello')\n        response = yield ws.read_message()\n        self.assertEqual(response, 'hello')\n        ws.close()\n        yield self.close_future\n\n    def test_websocket_callbacks(self):\n        websocket_connect(\n            'ws://localhost:%d/echo' % self.get_http_port(),\n            io_loop=self.io_loop, callback=self.stop)\n        ws = self.wait().result()\n        ws.write_message('hello')\n        ws.read_message(self.stop)\n        response = self.wait().result()\n        self.assertEqual(response, 'hello')\n        self.close_future.add_done_callback(lambda f: self.stop())\n        ws.close()\n        self.wait()\n\n    @gen_test\n    def test_websocket_http_fail(self):\n        with self.assertRaises(HTTPError) as cm:\n            yield websocket_connect(\n                'ws://localhost:%d/notfound' % self.get_http_port(),\n                io_loop=self.io_loop)\n        self.assertEqual(cm.exception.code, 404)\n\n    @gen_test\n    def test_websocket_http_success(self):\n        with self.assertRaises(WebSocketError):\n            yield websocket_connect(\n                'ws://localhost:%d/non_ws' % self.get_http_port(),\n                io_loop=self.io_loop)\n\n    @skipOnTravis\n    @gen_test\n    def test_websocket_network_timeout(self):\n        sock, port = bind_unused_port()\n        sock.close()\n        with self.assertRaises(HTTPError) as cm:\n            with ExpectLog(gen_log, \".*\"):\n                yield websocket_connect(\n                    'ws://localhost:%d/' % port,\n                    io_loop=self.io_loop,\n                    connect_timeout=0.01)\n        self.assertEqual(cm.exception.code, 599)\n\n    @gen_test\n    def test_websocket_network_fail(self):\n        sock, port = bind_unused_port()\n        sock.close()\n        with self.assertRaises(HTTPError) as cm:\n            with ExpectLog(gen_log, \".*\"):\n                yield websocket_connect(\n                    'ws://localhost:%d/' % port,\n                    io_loop=self.io_loop,\n                    connect_timeout=3600)\n        self.assertEqual(cm.exception.code, 599)\n\n    @gen_test\n    def test_websocket_close_buffered_data(self):\n        ws = yield websocket_connect(\n            'ws://localhost:%d/echo' % self.get_http_port())\n        ws.write_message('hello')\n        ws.write_message('world')\n        ws.stream.close()\n        yield self.close_future\n\n    @gen_test\n    def test_websocket_headers(self):\n        # Ensure that arbitrary headers can be passed through websocket_connect.\n        ws = yield websocket_connect(\n            HTTPRequest('ws://localhost:%d/header' % self.get_http_port(),\n                        headers={'X-Test': 'hello'}))\n        response = yield ws.read_message()\n        self.assertEqual(response, 'hello')\n        ws.close()\n        yield self.close_future\n\n    @gen_test\n    def test_server_close_reason(self):\n        ws = yield websocket_connect(\n            'ws://localhost:%d/close_reason' % self.get_http_port())\n        msg = yield ws.read_message()\n        # A message of None means the other side closed the connection.\n        self.assertIs(msg, None)\n        self.assertEqual(ws.close_code, 1001)\n        self.assertEqual(ws.close_reason, \"goodbye\")\n\n    @gen_test\n    def test_client_close_reason(self):\n        ws = yield websocket_connect(\n            'ws://localhost:%d/echo' % self.get_http_port())\n        ws.close(1001, 'goodbye')\n        code, reason = yield self.close_future\n        self.assertEqual(code, 1001)\n        self.assertEqual(reason, 'goodbye')\n\n    @gen_test\n    def test_check_origin_valid(self):\n        port = self.get_http_port()\n\n        url = 'ws://localhost:%d/echo' % port\n        headers = {'Origin': 'http://localhost:%d' % port}\n\n        ws = yield websocket_connect(HTTPRequest(url, headers=headers),\n            io_loop=self.io_loop)\n        ws.write_message('hello')\n        response = yield ws.read_message()\n        self.assertEqual(response, 'hello')\n        ws.close()\n        yield self.close_future\n\n    @gen_test\n    def test_check_origin_invalid(self):\n        '''Currently a failing test'''\n        port = self.get_http_port()\n\n        url = 'ws://localhost:%d/echo' % port\n        headers = {'Origin': 'http://somewhereelse.com'}\n\n        ws = yield websocket_connect(HTTPRequest(url, headers=headers),\n            io_loop=self.io_loop)\n        ws.write_message('hello')\n\n        response = yield ws.read_message()\n\n        self.assertEqual(response, None)\n        ws.close()\n        yield self.close_future",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 62,
                            "end_lineno": 207,
                            "parent": null
                        }
                    ],
                    "added_entities": [
                        {
                            "file_name": "tornado/test/websocket_test.py",
                            "type": "method",
                            "name": "WebSocketTest.test_check_origin_valid2",
                            "content": "class WebSocketTest(AsyncHTTPTestCase):\n    def get_app(self):\n        self.close_future = Future()\n        return Application([\n            ('/echo', EchoHandler, dict(close_future=self.close_future)),\n            ('/non_ws', NonWebSocketHandler),\n            ('/header', HeaderHandler, dict(close_future=self.close_future)),\n            ('/close_reason', CloseReasonHandler,\n             dict(close_future=self.close_future)),\n        ])\n\n    @gen_test\n    def test_websocket_gen(self):\n        ws = yield websocket_connect(\n            'ws://localhost:%d/echo' % self.get_http_port(),\n            io_loop=self.io_loop)\n        ws.write_message('hello')\n        response = yield ws.read_message()\n        self.assertEqual(response, 'hello')\n        ws.close()\n        yield self.close_future\n\n    def test_websocket_callbacks(self):\n        websocket_connect(\n            'ws://localhost:%d/echo' % self.get_http_port(),\n            io_loop=self.io_loop, callback=self.stop)\n        ws = self.wait().result()\n        ws.write_message('hello')\n        ws.read_message(self.stop)\n        response = self.wait().result()\n        self.assertEqual(response, 'hello')\n        self.close_future.add_done_callback(lambda f: self.stop())\n        ws.close()\n        self.wait()\n\n    @gen_test\n    def test_websocket_http_fail(self):\n        with self.assertRaises(HTTPError) as cm:\n            yield websocket_connect(\n                'ws://localhost:%d/notfound' % self.get_http_port(),\n                io_loop=self.io_loop)\n        self.assertEqual(cm.exception.code, 404)\n\n    @gen_test\n    def test_websocket_http_success(self):\n        with self.assertRaises(WebSocketError):\n            yield websocket_connect(\n                'ws://localhost:%d/non_ws' % self.get_http_port(),\n                io_loop=self.io_loop)\n\n    @skipOnTravis\n    @gen_test\n    def test_websocket_network_timeout(self):\n        sock, port = bind_unused_port()\n        sock.close()\n        with self.assertRaises(HTTPError) as cm:\n            with ExpectLog(gen_log, \".*\"):\n                yield websocket_connect(\n                    'ws://localhost:%d/' % port,\n                    io_loop=self.io_loop,\n                    connect_timeout=0.01)\n        self.assertEqual(cm.exception.code, 599)\n\n    @gen_test\n    def test_websocket_network_fail(self):\n        sock, port = bind_unused_port()\n        sock.close()\n        with self.assertRaises(HTTPError) as cm:\n            with ExpectLog(gen_log, \".*\"):\n                yield websocket_connect(\n                    'ws://localhost:%d/' % port,\n                    io_loop=self.io_loop,\n                    connect_timeout=3600)\n        self.assertEqual(cm.exception.code, 599)\n\n    @gen_test\n    def test_websocket_close_buffered_data(self):\n        ws = yield websocket_connect(\n            'ws://localhost:%d/echo' % self.get_http_port())\n        ws.write_message('hello')\n        ws.write_message('world')\n        ws.stream.close()\n        yield self.close_future\n\n    @gen_test\n    def test_websocket_headers(self):\n        # Ensure that arbitrary headers can be passed through websocket_connect.\n        ws = yield websocket_connect(\n            HTTPRequest('ws://localhost:%d/header' % self.get_http_port(),\n                        headers={'X-Test': 'hello'}))\n        response = yield ws.read_message()\n        self.assertEqual(response, 'hello')\n        ws.close()\n        yield self.close_future\n\n    @gen_test\n    def test_server_close_reason(self):\n        ws = yield websocket_connect(\n            'ws://localhost:%d/close_reason' % self.get_http_port())\n        msg = yield ws.read_message()\n        # A message of None means the other side closed the connection.\n        self.assertIs(msg, None)\n        self.assertEqual(ws.close_code, 1001)\n        self.assertEqual(ws.close_reason, \"goodbye\")\n\n    @gen_test\n    def test_client_close_reason(self):\n        ws = yield websocket_connect(\n            'ws://localhost:%d/echo' % self.get_http_port())\n        ws.close(1001, 'goodbye')\n        code, reason = yield self.close_future\n        self.assertEqual(code, 1001)\n        self.assertEqual(reason, 'goodbye')\n\n    @gen_test\n    def test_check_origin_valid(self):\n        port = self.get_http_port()\n\n        url = 'ws://localhost:%d/echo' % port\n        headers = {'Origin': 'http://localhost:%d' % port}\n\n        ws = yield websocket_connect(HTTPRequest(url, headers=headers),\n            io_loop=self.io_loop)\n        ws.write_message('hello')\n        response = yield ws.read_message()\n        self.assertEqual(response, 'hello')\n        ws.close()\n        yield self.close_future\n\n    @gen_test\n    def test_check_origin_valid2(self):\n        port = self.get_http_port()\n\n        url = 'ws://localhost:%d/echo' % port\n        headers = {'Origin': 'localhost:%d' % port}\n\n        ws = yield websocket_connect(HTTPRequest(url, headers=headers),\n            io_loop=self.io_loop)\n        ws.write_message('hello')\n        response = yield ws.read_message()\n        self.assertEqual(response, 'hello')\n        ws.close()\n        yield self.close_future\n\n    @gen_test\n    def test_check_origin_invalid(self):\n        port = self.get_http_port()\n\n        url = 'ws://localhost:%d/echo' % port\n        # Host is localhost, which should not be accessible from some other\n        # domain\n        headers = {'Origin': 'http://somewhereelse.com'}\n\n        with self.assertRaises(HTTPError) as cm:\n            yield websocket_connect(HTTPRequest(url, headers=headers),\n                                    io_loop=self.io_loop)\n\n        self.assertEqual(cm.exception.code, 403)\n\n    @gen_test\n    def test_check_origin_invalid2(self):\n        port = self.get_http_port()\n\n        url = 'ws://localhost:%d/echo' % port\n        # subdomains should be invalid by default\n        headers = {'Origin': 'http://subtenant.somewhereelse.com',\n                   'Host': 'subtenant2.somewhereelse.com'}\n\n        with self.assertRaises(HTTPError) as cm:\n            yield websocket_connect(HTTPRequest(url, headers=headers),\n                                    io_loop=self.io_loop)\n\n        self.assertEqual(cm.exception.code, 403)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 192,
                            "end_lineno": 204,
                            "parent": {
                                "file_name": "tornado/test/websocket_test.py",
                                "type": "class",
                                "name": "WebSocketTest",
                                "content": "class WebSocketTest(AsyncHTTPTestCase):\n    def get_app(self):\n        self.close_future = Future()\n        return Application([\n            ('/echo', EchoHandler, dict(close_future=self.close_future)),\n            ('/non_ws', NonWebSocketHandler),\n            ('/header', HeaderHandler, dict(close_future=self.close_future)),\n            ('/close_reason', CloseReasonHandler,\n             dict(close_future=self.close_future)),\n        ])\n\n    @gen_test\n    def test_websocket_gen(self):\n        ws = yield websocket_connect(\n            'ws://localhost:%d/echo' % self.get_http_port(),\n            io_loop=self.io_loop)\n        ws.write_message('hello')\n        response = yield ws.read_message()\n        self.assertEqual(response, 'hello')\n        ws.close()\n        yield self.close_future\n\n    def test_websocket_callbacks(self):\n        websocket_connect(\n            'ws://localhost:%d/echo' % self.get_http_port(),\n            io_loop=self.io_loop, callback=self.stop)\n        ws = self.wait().result()\n        ws.write_message('hello')\n        ws.read_message(self.stop)\n        response = self.wait().result()\n        self.assertEqual(response, 'hello')\n        self.close_future.add_done_callback(lambda f: self.stop())\n        ws.close()\n        self.wait()\n\n    @gen_test\n    def test_websocket_http_fail(self):\n        with self.assertRaises(HTTPError) as cm:\n            yield websocket_connect(\n                'ws://localhost:%d/notfound' % self.get_http_port(),\n                io_loop=self.io_loop)\n        self.assertEqual(cm.exception.code, 404)\n\n    @gen_test\n    def test_websocket_http_success(self):\n        with self.assertRaises(WebSocketError):\n            yield websocket_connect(\n                'ws://localhost:%d/non_ws' % self.get_http_port(),\n                io_loop=self.io_loop)\n\n    @skipOnTravis\n    @gen_test\n    def test_websocket_network_timeout(self):\n        sock, port = bind_unused_port()\n        sock.close()\n        with self.assertRaises(HTTPError) as cm:\n            with ExpectLog(gen_log, \".*\"):\n                yield websocket_connect(\n                    'ws://localhost:%d/' % port,\n                    io_loop=self.io_loop,\n                    connect_timeout=0.01)\n        self.assertEqual(cm.exception.code, 599)\n\n    @gen_test\n    def test_websocket_network_fail(self):\n        sock, port = bind_unused_port()\n        sock.close()\n        with self.assertRaises(HTTPError) as cm:\n            with ExpectLog(gen_log, \".*\"):\n                yield websocket_connect(\n                    'ws://localhost:%d/' % port,\n                    io_loop=self.io_loop,\n                    connect_timeout=3600)\n        self.assertEqual(cm.exception.code, 599)\n\n    @gen_test\n    def test_websocket_close_buffered_data(self):\n        ws = yield websocket_connect(\n            'ws://localhost:%d/echo' % self.get_http_port())\n        ws.write_message('hello')\n        ws.write_message('world')\n        ws.stream.close()\n        yield self.close_future\n\n    @gen_test\n    def test_websocket_headers(self):\n        # Ensure that arbitrary headers can be passed through websocket_connect.\n        ws = yield websocket_connect(\n            HTTPRequest('ws://localhost:%d/header' % self.get_http_port(),\n                        headers={'X-Test': 'hello'}))\n        response = yield ws.read_message()\n        self.assertEqual(response, 'hello')\n        ws.close()\n        yield self.close_future\n\n    @gen_test\n    def test_server_close_reason(self):\n        ws = yield websocket_connect(\n            'ws://localhost:%d/close_reason' % self.get_http_port())\n        msg = yield ws.read_message()\n        # A message of None means the other side closed the connection.\n        self.assertIs(msg, None)\n        self.assertEqual(ws.close_code, 1001)\n        self.assertEqual(ws.close_reason, \"goodbye\")\n\n    @gen_test\n    def test_client_close_reason(self):\n        ws = yield websocket_connect(\n            'ws://localhost:%d/echo' % self.get_http_port())\n        ws.close(1001, 'goodbye')\n        code, reason = yield self.close_future\n        self.assertEqual(code, 1001)\n        self.assertEqual(reason, 'goodbye')\n\n    @gen_test\n    def test_check_origin_valid(self):\n        port = self.get_http_port()\n\n        url = 'ws://localhost:%d/echo' % port\n        headers = {'Origin': 'http://localhost:%d' % port}\n\n        ws = yield websocket_connect(HTTPRequest(url, headers=headers),\n            io_loop=self.io_loop)\n        ws.write_message('hello')\n        response = yield ws.read_message()\n        self.assertEqual(response, 'hello')\n        ws.close()\n        yield self.close_future\n\n    @gen_test\n    def test_check_origin_valid2(self):\n        port = self.get_http_port()\n\n        url = 'ws://localhost:%d/echo' % port\n        headers = {'Origin': 'localhost:%d' % port}\n\n        ws = yield websocket_connect(HTTPRequest(url, headers=headers),\n            io_loop=self.io_loop)\n        ws.write_message('hello')\n        response = yield ws.read_message()\n        self.assertEqual(response, 'hello')\n        ws.close()\n        yield self.close_future\n\n    @gen_test\n    def test_check_origin_invalid(self):\n        port = self.get_http_port()\n\n        url = 'ws://localhost:%d/echo' % port\n        # Host is localhost, which should not be accessible from some other\n        # domain\n        headers = {'Origin': 'http://somewhereelse.com'}\n\n        with self.assertRaises(HTTPError) as cm:\n            yield websocket_connect(HTTPRequest(url, headers=headers),\n                                    io_loop=self.io_loop)\n\n        self.assertEqual(cm.exception.code, 403)\n\n    @gen_test\n    def test_check_origin_invalid2(self):\n        port = self.get_http_port()\n\n        url = 'ws://localhost:%d/echo' % port\n        # subdomains should be invalid by default\n        headers = {'Origin': 'http://subtenant.somewhereelse.com',\n                   'Host': 'subtenant2.somewhereelse.com'}\n\n        with self.assertRaises(HTTPError) as cm:\n            yield websocket_connect(HTTPRequest(url, headers=headers),\n                                    io_loop=self.io_loop)\n\n        self.assertEqual(cm.exception.code, 403)",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 62,
                                "end_lineno": 234,
                                "parent": null
                            }
                        },
                        {
                            "file_name": "tornado/test/websocket_test.py",
                            "type": "method",
                            "name": "WebSocketTest.test_check_origin_invalid2",
                            "content": "class WebSocketTest(AsyncHTTPTestCase):\n    def get_app(self):\n        self.close_future = Future()\n        return Application([\n            ('/echo', EchoHandler, dict(close_future=self.close_future)),\n            ('/non_ws', NonWebSocketHandler),\n            ('/header', HeaderHandler, dict(close_future=self.close_future)),\n            ('/close_reason', CloseReasonHandler,\n             dict(close_future=self.close_future)),\n        ])\n\n    @gen_test\n    def test_websocket_gen(self):\n        ws = yield websocket_connect(\n            'ws://localhost:%d/echo' % self.get_http_port(),\n            io_loop=self.io_loop)\n        ws.write_message('hello')\n        response = yield ws.read_message()\n        self.assertEqual(response, 'hello')\n        ws.close()\n        yield self.close_future\n\n    def test_websocket_callbacks(self):\n        websocket_connect(\n            'ws://localhost:%d/echo' % self.get_http_port(),\n            io_loop=self.io_loop, callback=self.stop)\n        ws = self.wait().result()\n        ws.write_message('hello')\n        ws.read_message(self.stop)\n        response = self.wait().result()\n        self.assertEqual(response, 'hello')\n        self.close_future.add_done_callback(lambda f: self.stop())\n        ws.close()\n        self.wait()\n\n    @gen_test\n    def test_websocket_http_fail(self):\n        with self.assertRaises(HTTPError) as cm:\n            yield websocket_connect(\n                'ws://localhost:%d/notfound' % self.get_http_port(),\n                io_loop=self.io_loop)\n        self.assertEqual(cm.exception.code, 404)\n\n    @gen_test\n    def test_websocket_http_success(self):\n        with self.assertRaises(WebSocketError):\n            yield websocket_connect(\n                'ws://localhost:%d/non_ws' % self.get_http_port(),\n                io_loop=self.io_loop)\n\n    @skipOnTravis\n    @gen_test\n    def test_websocket_network_timeout(self):\n        sock, port = bind_unused_port()\n        sock.close()\n        with self.assertRaises(HTTPError) as cm:\n            with ExpectLog(gen_log, \".*\"):\n                yield websocket_connect(\n                    'ws://localhost:%d/' % port,\n                    io_loop=self.io_loop,\n                    connect_timeout=0.01)\n        self.assertEqual(cm.exception.code, 599)\n\n    @gen_test\n    def test_websocket_network_fail(self):\n        sock, port = bind_unused_port()\n        sock.close()\n        with self.assertRaises(HTTPError) as cm:\n            with ExpectLog(gen_log, \".*\"):\n                yield websocket_connect(\n                    'ws://localhost:%d/' % port,\n                    io_loop=self.io_loop,\n                    connect_timeout=3600)\n        self.assertEqual(cm.exception.code, 599)\n\n    @gen_test\n    def test_websocket_close_buffered_data(self):\n        ws = yield websocket_connect(\n            'ws://localhost:%d/echo' % self.get_http_port())\n        ws.write_message('hello')\n        ws.write_message('world')\n        ws.stream.close()\n        yield self.close_future\n\n    @gen_test\n    def test_websocket_headers(self):\n        # Ensure that arbitrary headers can be passed through websocket_connect.\n        ws = yield websocket_connect(\n            HTTPRequest('ws://localhost:%d/header' % self.get_http_port(),\n                        headers={'X-Test': 'hello'}))\n        response = yield ws.read_message()\n        self.assertEqual(response, 'hello')\n        ws.close()\n        yield self.close_future\n\n    @gen_test\n    def test_server_close_reason(self):\n        ws = yield websocket_connect(\n            'ws://localhost:%d/close_reason' % self.get_http_port())\n        msg = yield ws.read_message()\n        # A message of None means the other side closed the connection.\n        self.assertIs(msg, None)\n        self.assertEqual(ws.close_code, 1001)\n        self.assertEqual(ws.close_reason, \"goodbye\")\n\n    @gen_test\n    def test_client_close_reason(self):\n        ws = yield websocket_connect(\n            'ws://localhost:%d/echo' % self.get_http_port())\n        ws.close(1001, 'goodbye')\n        code, reason = yield self.close_future\n        self.assertEqual(code, 1001)\n        self.assertEqual(reason, 'goodbye')\n\n    @gen_test\n    def test_check_origin_valid(self):\n        port = self.get_http_port()\n\n        url = 'ws://localhost:%d/echo' % port\n        headers = {'Origin': 'http://localhost:%d' % port}\n\n        ws = yield websocket_connect(HTTPRequest(url, headers=headers),\n            io_loop=self.io_loop)\n        ws.write_message('hello')\n        response = yield ws.read_message()\n        self.assertEqual(response, 'hello')\n        ws.close()\n        yield self.close_future\n\n    @gen_test\n    def test_check_origin_valid2(self):\n        port = self.get_http_port()\n\n        url = 'ws://localhost:%d/echo' % port\n        headers = {'Origin': 'localhost:%d' % port}\n\n        ws = yield websocket_connect(HTTPRequest(url, headers=headers),\n            io_loop=self.io_loop)\n        ws.write_message('hello')\n        response = yield ws.read_message()\n        self.assertEqual(response, 'hello')\n        ws.close()\n        yield self.close_future\n\n    @gen_test\n    def test_check_origin_invalid(self):\n        port = self.get_http_port()\n\n        url = 'ws://localhost:%d/echo' % port\n        # Host is localhost, which should not be accessible from some other\n        # domain\n        headers = {'Origin': 'http://somewhereelse.com'}\n\n        with self.assertRaises(HTTPError) as cm:\n            yield websocket_connect(HTTPRequest(url, headers=headers),\n                                    io_loop=self.io_loop)\n\n        self.assertEqual(cm.exception.code, 403)\n\n    @gen_test\n    def test_check_origin_invalid2(self):\n        port = self.get_http_port()\n\n        url = 'ws://localhost:%d/echo' % port\n        # subdomains should be invalid by default\n        headers = {'Origin': 'http://subtenant.somewhereelse.com',\n                   'Host': 'subtenant2.somewhereelse.com'}\n\n        with self.assertRaises(HTTPError) as cm:\n            yield websocket_connect(HTTPRequest(url, headers=headers),\n                                    io_loop=self.io_loop)\n\n        self.assertEqual(cm.exception.code, 403)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 222,
                            "end_lineno": 234,
                            "parent": {
                                "file_name": "tornado/test/websocket_test.py",
                                "type": "class",
                                "name": "WebSocketTest",
                                "content": "class WebSocketTest(AsyncHTTPTestCase):\n    def get_app(self):\n        self.close_future = Future()\n        return Application([\n            ('/echo', EchoHandler, dict(close_future=self.close_future)),\n            ('/non_ws', NonWebSocketHandler),\n            ('/header', HeaderHandler, dict(close_future=self.close_future)),\n            ('/close_reason', CloseReasonHandler,\n             dict(close_future=self.close_future)),\n        ])\n\n    @gen_test\n    def test_websocket_gen(self):\n        ws = yield websocket_connect(\n            'ws://localhost:%d/echo' % self.get_http_port(),\n            io_loop=self.io_loop)\n        ws.write_message('hello')\n        response = yield ws.read_message()\n        self.assertEqual(response, 'hello')\n        ws.close()\n        yield self.close_future\n\n    def test_websocket_callbacks(self):\n        websocket_connect(\n            'ws://localhost:%d/echo' % self.get_http_port(),\n            io_loop=self.io_loop, callback=self.stop)\n        ws = self.wait().result()\n        ws.write_message('hello')\n        ws.read_message(self.stop)\n        response = self.wait().result()\n        self.assertEqual(response, 'hello')\n        self.close_future.add_done_callback(lambda f: self.stop())\n        ws.close()\n        self.wait()\n\n    @gen_test\n    def test_websocket_http_fail(self):\n        with self.assertRaises(HTTPError) as cm:\n            yield websocket_connect(\n                'ws://localhost:%d/notfound' % self.get_http_port(),\n                io_loop=self.io_loop)\n        self.assertEqual(cm.exception.code, 404)\n\n    @gen_test\n    def test_websocket_http_success(self):\n        with self.assertRaises(WebSocketError):\n            yield websocket_connect(\n                'ws://localhost:%d/non_ws' % self.get_http_port(),\n                io_loop=self.io_loop)\n\n    @skipOnTravis\n    @gen_test\n    def test_websocket_network_timeout(self):\n        sock, port = bind_unused_port()\n        sock.close()\n        with self.assertRaises(HTTPError) as cm:\n            with ExpectLog(gen_log, \".*\"):\n                yield websocket_connect(\n                    'ws://localhost:%d/' % port,\n                    io_loop=self.io_loop,\n                    connect_timeout=0.01)\n        self.assertEqual(cm.exception.code, 599)\n\n    @gen_test\n    def test_websocket_network_fail(self):\n        sock, port = bind_unused_port()\n        sock.close()\n        with self.assertRaises(HTTPError) as cm:\n            with ExpectLog(gen_log, \".*\"):\n                yield websocket_connect(\n                    'ws://localhost:%d/' % port,\n                    io_loop=self.io_loop,\n                    connect_timeout=3600)\n        self.assertEqual(cm.exception.code, 599)\n\n    @gen_test\n    def test_websocket_close_buffered_data(self):\n        ws = yield websocket_connect(\n            'ws://localhost:%d/echo' % self.get_http_port())\n        ws.write_message('hello')\n        ws.write_message('world')\n        ws.stream.close()\n        yield self.close_future\n\n    @gen_test\n    def test_websocket_headers(self):\n        # Ensure that arbitrary headers can be passed through websocket_connect.\n        ws = yield websocket_connect(\n            HTTPRequest('ws://localhost:%d/header' % self.get_http_port(),\n                        headers={'X-Test': 'hello'}))\n        response = yield ws.read_message()\n        self.assertEqual(response, 'hello')\n        ws.close()\n        yield self.close_future\n\n    @gen_test\n    def test_server_close_reason(self):\n        ws = yield websocket_connect(\n            'ws://localhost:%d/close_reason' % self.get_http_port())\n        msg = yield ws.read_message()\n        # A message of None means the other side closed the connection.\n        self.assertIs(msg, None)\n        self.assertEqual(ws.close_code, 1001)\n        self.assertEqual(ws.close_reason, \"goodbye\")\n\n    @gen_test\n    def test_client_close_reason(self):\n        ws = yield websocket_connect(\n            'ws://localhost:%d/echo' % self.get_http_port())\n        ws.close(1001, 'goodbye')\n        code, reason = yield self.close_future\n        self.assertEqual(code, 1001)\n        self.assertEqual(reason, 'goodbye')\n\n    @gen_test\n    def test_check_origin_valid(self):\n        port = self.get_http_port()\n\n        url = 'ws://localhost:%d/echo' % port\n        headers = {'Origin': 'http://localhost:%d' % port}\n\n        ws = yield websocket_connect(HTTPRequest(url, headers=headers),\n            io_loop=self.io_loop)\n        ws.write_message('hello')\n        response = yield ws.read_message()\n        self.assertEqual(response, 'hello')\n        ws.close()\n        yield self.close_future\n\n    @gen_test\n    def test_check_origin_valid2(self):\n        port = self.get_http_port()\n\n        url = 'ws://localhost:%d/echo' % port\n        headers = {'Origin': 'localhost:%d' % port}\n\n        ws = yield websocket_connect(HTTPRequest(url, headers=headers),\n            io_loop=self.io_loop)\n        ws.write_message('hello')\n        response = yield ws.read_message()\n        self.assertEqual(response, 'hello')\n        ws.close()\n        yield self.close_future\n\n    @gen_test\n    def test_check_origin_invalid(self):\n        port = self.get_http_port()\n\n        url = 'ws://localhost:%d/echo' % port\n        # Host is localhost, which should not be accessible from some other\n        # domain\n        headers = {'Origin': 'http://somewhereelse.com'}\n\n        with self.assertRaises(HTTPError) as cm:\n            yield websocket_connect(HTTPRequest(url, headers=headers),\n                                    io_loop=self.io_loop)\n\n        self.assertEqual(cm.exception.code, 403)\n\n    @gen_test\n    def test_check_origin_invalid2(self):\n        port = self.get_http_port()\n\n        url = 'ws://localhost:%d/echo' % port\n        # subdomains should be invalid by default\n        headers = {'Origin': 'http://subtenant.somewhereelse.com',\n                   'Host': 'subtenant2.somewhereelse.com'}\n\n        with self.assertRaises(HTTPError) as cm:\n            yield websocket_connect(HTTPRequest(url, headers=headers),\n                                    io_loop=self.io_loop)\n\n        self.assertEqual(cm.exception.code, 403)",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 62,
                                "end_lineno": 234,
                                "parent": null
                            }
                        }
                    ],
                    "deleted_entities": []
                }
            ]
        },
        {
            "old_file_content": "\"\"\"Implementation of the WebSocket protocol.\n\n`WebSockets <http://dev.w3.org/html5/websockets/>`_ allow for bidirectional\ncommunication between the browser and server.\n\n.. warning::\n\n   The WebSocket protocol was recently finalized as `RFC 6455\n   <http://tools.ietf.org/html/rfc6455>`_ and is not yet supported in\n   all browsers.  Refer to http://caniuse.com/websockets for details\n   on compatibility.  In addition, during development the protocol\n   went through several incompatible versions, and some browsers only\n   support older versions.  By default this module only supports the\n   latest version of the protocol, but optional support for an older\n   version (known as \"draft 76\" or \"hixie-76\") can be enabled by\n   overriding `WebSocketHandler.allow_draft76` (see that method's\n   documentation for caveats).\n\"\"\"\n\nfrom __future__ import absolute_import, division, print_function, with_statement\n# Author: Jacob Kristhammar, 2010\n\nimport array\nimport base64\nimport collections\nimport functools\nimport hashlib\nimport os\nimport struct\nimport time\nimport tornado.escape\nimport tornado.web\n\nfrom tornado.concurrent import TracebackFuture\nfrom tornado.escape import utf8, native_str, to_unicode\nfrom tornado import httpclient, httputil\nfrom tornado.ioloop import IOLoop\nfrom tornado.iostream import StreamClosedError\nfrom tornado.log import gen_log, app_log\nfrom tornado.netutil import Resolver\nfrom tornado import simple_httpclient\nfrom tornado.util import bytes_type, unicode_type\n\ntry:\n    from urllib.parse import urlparse # py2\nexcept ImportError:\n    from urlparse import urlparse # py3\n\ntry:\n    xrange  # py2\nexcept NameError:\n    xrange = range  # py3\n\n\nclass WebSocketError(Exception):\n    pass\n\n\nclass WebSocketClosedError(WebSocketError):\n    \"\"\"Raised by operations on a closed connection.\n\n    .. versionadded:: 3.2\n    \"\"\"\n    pass\n\n\nclass WebSocketHandler(tornado.web.RequestHandler):\n    \"\"\"Subclass this class to create a basic WebSocket handler.\n\n    Override `on_message` to handle incoming messages, and use\n    `write_message` to send messages to the client. You can also\n    override `open` and `on_close` to handle opened and closed\n    connections.\n\n    See http://dev.w3.org/html5/websockets/ for details on the\n    JavaScript interface.  The protocol is specified at\n    http://tools.ietf.org/html/rfc6455.\n\n    Here is an example WebSocket handler that echos back all received messages\n    back to the client::\n\n      class EchoWebSocket(websocket.WebSocketHandler):\n          def open(self):\n              print \"WebSocket opened\"\n\n          def on_message(self, message):\n              self.write_message(u\"You said: \" + message)\n\n          def on_close(self):\n              print \"WebSocket closed\"\n\n    WebSockets are not standard HTTP connections. The \"handshake\" is\n    HTTP, but after the handshake, the protocol is\n    message-based. Consequently, most of the Tornado HTTP facilities\n    are not available in handlers of this type. The only communication\n    methods available to you are `write_message()`, `ping()`, and\n    `close()`. Likewise, your request handler class should implement\n    `open()` method rather than ``get()`` or ``post()``.\n\n    If you map the handler above to ``/websocket`` in your application, you can\n    invoke it in JavaScript with::\n\n      var ws = new WebSocket(\"ws://localhost:8888/websocket\");\n      ws.onopen = function() {\n         ws.send(\"Hello, world\");\n      };\n      ws.onmessage = function (evt) {\n         alert(evt.data);\n      };\n\n    This script pops up an alert box that says \"You said: Hello, world\".\n    \"\"\"\n    def __init__(self, application, request, **kwargs):\n        tornado.web.RequestHandler.__init__(self, application, request,\n                                            **kwargs)\n        self.ws_connection = None\n        self.close_code = None\n        self.close_reason = None\n\n    @tornado.web.asynchronous\n    def get(self, *args, **kwargs):\n        self.open_args = args\n        self.open_kwargs = kwargs\n\n        self.stream = self.request.connection.detach()\n\n        # Upgrade header should be present and should be equal to WebSocket\n        if self.request.headers.get(\"Upgrade\", \"\").lower() != 'websocket':\n            self.stream.write(tornado.escape.utf8(\n                \"HTTP/1.1 400 Bad Request\\r\\n\\r\\n\"\n                \"Can \\\"Upgrade\\\" only to \\\"WebSocket\\\".\"\n            ))\n            self.stream.close()\n            return\n\n        # Connection header should be upgrade. Some proxy servers/load balancers\n        # might mess with it.\n        headers = self.request.headers\n        connection = map(lambda s: s.strip().lower(), headers.get(\"Connection\", \"\").split(\",\"))\n        if 'upgrade' not in connection:\n            self.stream.write(tornado.escape.utf8(\n                \"HTTP/1.1 400 Bad Request\\r\\n\\r\\n\"\n                \"\\\"Connection\\\" must be \\\"Upgrade\\\".\"\n            ))\n            self.stream.close()\n            return\n\n        # The difference between version 8 and 13 is that in 8 the\n        # client sends a \"Sec-Websocket-Origin\" header and in 13 it's\n        # simply \"Origin\".\n        if self.request.headers.get(\"Sec-WebSocket-Version\") in (\"7\", \"8\", \"13\"):\n            self.ws_connection = WebSocketProtocol13(self)\n            self.ws_connection.accept_connection()\n        elif (self.allow_draft76() and\n              \"Sec-WebSocket-Version\" not in self.request.headers):\n            self.ws_connection = WebSocketProtocol76(self)\n            self.ws_connection.accept_connection()\n        else:\n            self.stream.write(tornado.escape.utf8(\n                \"HTTP/1.1 426 Upgrade Required\\r\\n\"\n                \"Sec-WebSocket-Version: 8\\r\\n\\r\\n\"))\n            self.stream.close()\n\n        if not self.check_origin():\n            self.stream.write(tornado.escape.utf8(\n                \"HTTP/1.1 403 Cross Origin Websockets Disabled\\r\\n\\r\\n\"\n            ))\n            self.stream.close()\n\n\n\n    def write_message(self, message, binary=False):\n        \"\"\"Sends the given message to the client of this Web Socket.\n\n        The message may be either a string or a dict (which will be\n        encoded as json).  If the ``binary`` argument is false, the\n        message will be sent as utf8; in binary mode any byte string\n        is allowed.\n\n        If the connection is already closed, raises `WebSocketClosedError`.\n\n        .. versionchanged:: 3.2\n           `WebSocketClosedError` was added (previously a closed connection\n           would raise an `AttributeError`)\n        \"\"\"\n        if self.ws_connection is None:\n            raise WebSocketClosedError()\n        if isinstance(message, dict):\n            message = tornado.escape.json_encode(message)\n        self.ws_connection.write_message(message, binary=binary)\n\n    def select_subprotocol(self, subprotocols):\n        \"\"\"Invoked when a new WebSocket requests specific subprotocols.\n\n        ``subprotocols`` is a list of strings identifying the\n        subprotocols proposed by the client.  This method may be\n        overridden to return one of those strings to select it, or\n        ``None`` to not select a subprotocol.  Failure to select a\n        subprotocol does not automatically abort the connection,\n        although clients may close the connection if none of their\n        proposed subprotocols was selected.\n        \"\"\"\n        return None\n\n    def open(self):\n        \"\"\"Invoked when a new WebSocket is opened.\n\n        The arguments to `open` are extracted from the `tornado.web.URLSpec`\n        regular expression, just like the arguments to\n        `tornado.web.RequestHandler.get`.\n        \"\"\"\n        pass\n\n    def on_message(self, message):\n        \"\"\"Handle incoming messages on the WebSocket\n\n        This method must be overridden.\n        \"\"\"\n        raise NotImplementedError\n\n    def ping(self, data):\n        \"\"\"Send ping frame to the remote end.\"\"\"\n        if self.ws_connection is None:\n            raise WebSocketClosedError()\n        self.ws_connection.write_ping(data)\n\n    def on_pong(self, data):\n        \"\"\"Invoked when the response to a ping frame is received.\"\"\"\n        pass\n\n    def on_close(self):\n        \"\"\"Invoked when the WebSocket is closed.\n\n        If the connection was closed cleanly and a status code or reason\n        phrase was supplied, these values will be available as the attributes\n        ``self.close_code`` and ``self.close_reason``.\n\n        .. versionchanged:: 3.3\n\n           Added ``close_code`` and ``close_reason`` attributes.\n        \"\"\"\n        pass\n\n    def close(self, code=None, reason=None):\n        \"\"\"Closes this Web Socket.\n\n        Once the close handshake is successful the socket will be closed.\n\n        ``code`` may be a numeric status code, taken from the values\n        defined in `RFC 6455 section 7.4.1\n        <https://tools.ietf.org/html/rfc6455#section-7.4.1>`_.\n        ``reason`` may be a textual message about why the connection is\n        closing.  These values are made available to the client, but are\n        not otherwise interpreted by the websocket protocol.\n\n        The ``code`` and ``reason`` arguments are ignored in the \"draft76\"\n        protocol version.\n\n        .. versionchanged:: 3.3\n\n           Added the ``code`` and ``reason`` arguments.\n        \"\"\"\n        if self.ws_connection:\n            self.ws_connection.close(code, reason)\n            self.ws_connection = None\n\n    def check_origin(self, allowed_origins=None):\n        \"\"\"Override to enable support for allowing alternate origins.\n        \n        By default, this checks to see that requests that provide both a host\n        origin have the same origin and host This is a security protection\n        against cross site scripting attacks on browsers,\n        since WebSockets don't have CORS headers.\n        \n        >>> self.check_origins(allowed_origins=['localhost'])\n        \n        \"\"\"\n        # Handle WebSocket Origin naming convention differences\n        # The difference between version 8 and 13 is that in 8 the\n        # client sends a \"Sec-Websocket-Origin\" header and in 13 it's\n        # simply \"Origin\".\n        if self.request.headers.get(\"Sec-WebSocket-Version\") in (\"7\", \"8\"):\n            origin_header = self.request.headers.get(\"Sec-Websocket-Origin\")\n        else:\n            origin_header = self.request.headers.get(\"Origin\")\n\n        host = self.request.headers.get(\"Host\")\n\n        # If no header is provided, assume request is not coming from a browser\n        if(origin_header is None or host is None):\n            return True\n\n        parsed_origin = urlparse(origin_header)\n        origin = parsed_origin.netloc\n\n        if allowed_origins and origin in allowed_origins:\n            return True\n\n        # Check to see that origin matches host directly, including ports\n        return origin == host\n\n    def allow_draft76(self):\n        \"\"\"Override to enable support for the older \"draft76\" protocol.\n\n        The draft76 version of the websocket protocol is disabled by\n        default due to security concerns, but it can be enabled by\n        overriding this method to return True.\n\n        Connections using the draft76 protocol do not support the\n        ``binary=True`` flag to `write_message`.\n\n        Support for the draft76 protocol is deprecated and will be\n        removed in a future version of Tornado.\n        \"\"\"\n        return False\n\n    def set_nodelay(self, value):\n        \"\"\"Set the no-delay flag for this stream.\n\n        By default, small messages may be delayed and/or combined to minimize\n        the number of packets sent.  This can sometimes cause 200-500ms delays\n        due to the interaction between Nagle's algorithm and TCP delayed\n        ACKs.  To reduce this delay (at the expense of possibly increasing\n        bandwidth usage), call ``self.set_nodelay(True)`` once the websocket\n        connection is established.\n\n        See `.BaseIOStream.set_nodelay` for additional details.\n\n        .. versionadded:: 3.1\n        \"\"\"\n        self.stream.set_nodelay(value)\n\n    def get_websocket_scheme(self):\n        \"\"\"Return the url scheme used for this request, either \"ws\" or \"wss\".\n\n        This is normally decided by HTTPServer, but applications\n        may wish to override this if they are using an SSL proxy\n        that does not provide the X-Scheme header as understood\n        by HTTPServer.\n\n        Note that this is only used by the draft76 protocol.\n        \"\"\"\n        return \"wss\" if self.request.protocol == \"https\" else \"ws\"\n\n    def async_callback(self, callback, *args, **kwargs):\n        \"\"\"Obsolete - catches exceptions from the wrapped function.\n\n        This function is normally unncecessary thanks to\n        `tornado.stack_context`.\n        \"\"\"\n        return self.ws_connection.async_callback(callback, *args, **kwargs)\n\n    def _not_supported(self, *args, **kwargs):\n        raise Exception(\"Method not supported for Web Sockets\")\n\n    def on_connection_close(self):\n        if self.ws_connection:\n            self.ws_connection.on_connection_close()\n            self.ws_connection = None\n            self.on_close()\n\n\nfor method in [\"write\", \"redirect\", \"set_header\", \"send_error\", \"set_cookie\",\n               \"set_status\", \"flush\", \"finish\"]:\n    setattr(WebSocketHandler, method, WebSocketHandler._not_supported)\n\n\nclass WebSocketProtocol(object):\n    \"\"\"Base class for WebSocket protocol versions.\n    \"\"\"\n    def __init__(self, handler):\n        self.handler = handler\n        self.request = handler.request\n        self.stream = handler.stream\n        self.client_terminated = False\n        self.server_terminated = False\n\n    def async_callback(self, callback, *args, **kwargs):\n        \"\"\"Wrap callbacks with this if they are used on asynchronous requests.\n\n        Catches exceptions properly and closes this WebSocket if an exception\n        is uncaught.\n        \"\"\"\n        if args or kwargs:\n            callback = functools.partial(callback, *args, **kwargs)\n\n        def wrapper(*args, **kwargs):\n            try:\n                return callback(*args, **kwargs)\n            except Exception:\n                app_log.error(\"Uncaught exception in %s\",\n                              self.request.path, exc_info=True)\n                self._abort()\n        return wrapper\n\n    def on_connection_close(self):\n        self._abort()\n\n    def _abort(self):\n        \"\"\"Instantly aborts the WebSocket connection by closing the socket\"\"\"\n        self.client_terminated = True\n        self.server_terminated = True\n        self.stream.close()  # forcibly tear down the connection\n        self.close()  # let the subclass cleanup\n\n\nclass WebSocketProtocol76(WebSocketProtocol):\n    \"\"\"Implementation of the WebSockets protocol, version hixie-76.\n\n    This class provides basic functionality to process WebSockets requests as\n    specified in\n    http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76\n    \"\"\"\n    def __init__(self, handler):\n        WebSocketProtocol.__init__(self, handler)\n        self.challenge = None\n        self._waiting = None\n\n    def accept_connection(self):\n        try:\n            self._handle_websocket_headers()\n        except ValueError:\n            gen_log.debug(\"Malformed WebSocket request received\")\n            self._abort()\n            return\n\n        scheme = self.handler.get_websocket_scheme()\n\n        # draft76 only allows a single subprotocol\n        subprotocol_header = ''\n        subprotocol = self.request.headers.get(\"Sec-WebSocket-Protocol\", None)\n        if subprotocol:\n            selected = self.handler.select_subprotocol([subprotocol])\n            if selected:\n                assert selected == subprotocol\n                subprotocol_header = \"Sec-WebSocket-Protocol: %s\\r\\n\" % selected\n\n        # Write the initial headers before attempting to read the challenge.\n        # This is necessary when using proxies (such as HAProxy), which\n        # need to see the Upgrade headers before passing through the\n        # non-HTTP traffic that follows.\n        self.stream.write(tornado.escape.utf8(\n            \"HTTP/1.1 101 WebSocket Protocol Handshake\\r\\n\"\n            \"Upgrade: WebSocket\\r\\n\"\n            \"Connection: Upgrade\\r\\n\"\n            \"Server: TornadoServer/%(version)s\\r\\n\"\n            \"Sec-WebSocket-Origin: %(origin)s\\r\\n\"\n            \"Sec-WebSocket-Location: %(scheme)s://%(host)s%(uri)s\\r\\n\"\n            \"%(subprotocol)s\"\n            \"\\r\\n\" % (dict(\n                version=tornado.version,\n                origin=self.request.headers[\"Origin\"],\n                scheme=scheme,\n                host=self.request.host,\n                uri=self.request.uri,\n                subprotocol=subprotocol_header))))\n        self.stream.read_bytes(8, self._handle_challenge)\n\n    def challenge_response(self, challenge):\n        \"\"\"Generates the challenge response that's needed in the handshake\n\n        The challenge parameter should be the raw bytes as sent from the\n        client.\n        \"\"\"\n        key_1 = self.request.headers.get(\"Sec-Websocket-Key1\")\n        key_2 = self.request.headers.get(\"Sec-Websocket-Key2\")\n        try:\n            part_1 = self._calculate_part(key_1)\n            part_2 = self._calculate_part(key_2)\n        except ValueError:\n            raise ValueError(\"Invalid Keys/Challenge\")\n        return self._generate_challenge_response(part_1, part_2, challenge)\n\n    def _handle_challenge(self, challenge):\n        try:\n            challenge_response = self.challenge_response(challenge)\n        except ValueError:\n            gen_log.debug(\"Malformed key data in WebSocket request\")\n            self._abort()\n            return\n        self._write_response(challenge_response)\n\n    def _write_response(self, challenge):\n        self.stream.write(challenge)\n        self.async_callback(self.handler.open)(*self.handler.open_args, **self.handler.open_kwargs)\n        self._receive_message()\n\n    def _handle_websocket_headers(self):\n        \"\"\"Verifies all invariant- and required headers\n\n        If a header is missing or have an incorrect value ValueError will be\n        raised\n        \"\"\"\n        fields = (\"Origin\", \"Host\", \"Sec-Websocket-Key1\",\n                  \"Sec-Websocket-Key2\")\n        if not all(map(lambda f: self.request.headers.get(f), fields)):\n            raise ValueError(\"Missing/Invalid WebSocket headers\")\n\n    def _calculate_part(self, key):\n        \"\"\"Processes the key headers and calculates their key value.\n\n        Raises ValueError when feed invalid key.\"\"\"\n        # pyflakes complains about variable reuse if both of these lines use 'c'\n        number = int(''.join(c for c in key if c.isdigit()))\n        spaces = len([c2 for c2 in key if c2.isspace()])\n        try:\n            key_number = number // spaces\n        except (ValueError, ZeroDivisionError):\n            raise ValueError\n        return struct.pack(\">I\", key_number)\n\n    def _generate_challenge_response(self, part_1, part_2, part_3):\n        m = hashlib.md5()\n        m.update(part_1)\n        m.update(part_2)\n        m.update(part_3)\n        return m.digest()\n\n    def _receive_message(self):\n        self.stream.read_bytes(1, self._on_frame_type)\n\n    def _on_frame_type(self, byte):\n        frame_type = ord(byte)\n        if frame_type == 0x00:\n            self.stream.read_until(b\"\\xff\", self._on_end_delimiter)\n        elif frame_type == 0xff:\n            self.stream.read_bytes(1, self._on_length_indicator)\n        else:\n            self._abort()\n\n    def _on_end_delimiter(self, frame):\n        if not self.client_terminated:\n            self.async_callback(self.handler.on_message)(\n                frame[:-1].decode(\"utf-8\", \"replace\"))\n        if not self.client_terminated:\n            self._receive_message()\n\n    def _on_length_indicator(self, byte):\n        if ord(byte) != 0x00:\n            self._abort()\n            return\n        self.client_terminated = True\n        self.close()\n\n    def write_message(self, message, binary=False):\n        \"\"\"Sends the given message to the client of this Web Socket.\"\"\"\n        if binary:\n            raise ValueError(\n                \"Binary messages not supported by this version of websockets\")\n        if isinstance(message, unicode_type):\n            message = message.encode(\"utf-8\")\n        assert isinstance(message, bytes_type)\n        self.stream.write(b\"\\x00\" + message + b\"\\xff\")\n\n    def write_ping(self, data):\n        \"\"\"Send ping frame.\"\"\"\n        raise ValueError(\"Ping messages not supported by this version of websockets\")\n\n    def close(self, code=None, reason=None):\n        \"\"\"Closes the WebSocket connection.\"\"\"\n        if not self.server_terminated:\n            if not self.stream.closed():\n                self.stream.write(\"\\xff\\x00\")\n            self.server_terminated = True\n        if self.client_terminated:\n            if self._waiting is not None:\n                self.stream.io_loop.remove_timeout(self._waiting)\n            self._waiting = None\n            self.stream.close()\n        elif self._waiting is None:\n            self._waiting = self.stream.io_loop.add_timeout(\n                time.time() + 5, self._abort)\n\n\nclass WebSocketProtocol13(WebSocketProtocol):\n    \"\"\"Implementation of the WebSocket protocol from RFC 6455.\n\n    This class supports versions 7 and 8 of the protocol in addition to the\n    final version 13.\n    \"\"\"\n    def __init__(self, handler, mask_outgoing=False):\n        WebSocketProtocol.__init__(self, handler)\n        self.mask_outgoing = mask_outgoing\n        self._final_frame = False\n        self._frame_opcode = None\n        self._masked_frame = None\n        self._frame_mask = None\n        self._frame_length = None\n        self._fragmented_message_buffer = None\n        self._fragmented_message_opcode = None\n        self._waiting = None\n\n    def accept_connection(self):\n        try:\n            self._handle_websocket_headers()\n            self._accept_connection()\n        except ValueError:\n            gen_log.debug(\"Malformed WebSocket request received\", exc_info=True)\n            self._abort()\n            return\n\n    def _handle_websocket_headers(self):\n        \"\"\"Verifies all invariant- and required headers\n\n        If a header is missing or have an incorrect value ValueError will be\n        raised\n        \"\"\"\n        fields = (\"Host\", \"Sec-Websocket-Key\", \"Sec-Websocket-Version\")\n        if not all(map(lambda f: self.request.headers.get(f), fields)):\n            raise ValueError(\"Missing/Invalid WebSocket headers\")\n\n    @staticmethod\n    def compute_accept_value(key):\n        \"\"\"Computes the value for the Sec-WebSocket-Accept header,\n        given the value for Sec-WebSocket-Key.\n        \"\"\"\n        sha1 = hashlib.sha1()\n        sha1.update(utf8(key))\n        sha1.update(b\"258EAFA5-E914-47DA-95CA-C5AB0DC85B11\")  # Magic value\n        return native_str(base64.b64encode(sha1.digest()))\n\n    def _challenge_response(self):\n        return WebSocketProtocol13.compute_accept_value(\n            self.request.headers.get(\"Sec-Websocket-Key\"))\n\n    def _accept_connection(self):\n        subprotocol_header = ''\n        subprotocols = self.request.headers.get(\"Sec-WebSocket-Protocol\", '')\n        subprotocols = [s.strip() for s in subprotocols.split(',')]\n        if subprotocols:\n            selected = self.handler.select_subprotocol(subprotocols)\n            if selected:\n                assert selected in subprotocols\n                subprotocol_header = \"Sec-WebSocket-Protocol: %s\\r\\n\" % selected\n\n        self.stream.write(tornado.escape.utf8(\n            \"HTTP/1.1 101 Switching Protocols\\r\\n\"\n            \"Upgrade: websocket\\r\\n\"\n            \"Connection: Upgrade\\r\\n\"\n            \"Sec-WebSocket-Accept: %s\\r\\n\"\n            \"%s\"\n            \"\\r\\n\" % (self._challenge_response(), subprotocol_header)))\n\n        self.async_callback(self.handler.open)(*self.handler.open_args, **self.handler.open_kwargs)\n        self._receive_frame()\n\n    def _write_frame(self, fin, opcode, data):\n        if fin:\n            finbit = 0x80\n        else:\n            finbit = 0\n        frame = struct.pack(\"B\", finbit | opcode)\n        l = len(data)\n        if self.mask_outgoing:\n            mask_bit = 0x80\n        else:\n            mask_bit = 0\n        if l < 126:\n            frame += struct.pack(\"B\", l | mask_bit)\n        elif l <= 0xFFFF:\n            frame += struct.pack(\"!BH\", 126 | mask_bit, l)\n        else:\n            frame += struct.pack(\"!BQ\", 127 | mask_bit, l)\n        if self.mask_outgoing:\n            mask = os.urandom(4)\n            data = mask + _websocket_mask(mask, data)\n        frame += data\n        self.stream.write(frame)\n\n    def write_message(self, message, binary=False):\n        \"\"\"Sends the given message to the client of this Web Socket.\"\"\"\n        if binary:\n            opcode = 0x2\n        else:\n            opcode = 0x1\n        message = tornado.escape.utf8(message)\n        assert isinstance(message, bytes_type)\n        try:\n            self._write_frame(True, opcode, message)\n        except StreamClosedError:\n            self._abort()\n\n    def write_ping(self, data):\n        \"\"\"Send ping frame.\"\"\"\n        assert isinstance(data, bytes_type)\n        self._write_frame(True, 0x9, data)\n\n    def _receive_frame(self):\n        try:\n            self.stream.read_bytes(2, self._on_frame_start)\n        except StreamClosedError:\n            self._abort()\n\n    def _on_frame_start(self, data):\n        header, payloadlen = struct.unpack(\"BB\", data)\n        self._final_frame = header & 0x80\n        reserved_bits = header & 0x70\n        self._frame_opcode = header & 0xf\n        self._frame_opcode_is_control = self._frame_opcode & 0x8\n        if reserved_bits:\n            # client is using as-yet-undefined extensions; abort\n            self._abort()\n            return\n        self._masked_frame = bool(payloadlen & 0x80)\n        payloadlen = payloadlen & 0x7f\n        if self._frame_opcode_is_control and payloadlen >= 126:\n            # control frames must have payload < 126\n            self._abort()\n            return\n        try:\n            if payloadlen < 126:\n                self._frame_length = payloadlen\n                if self._masked_frame:\n                    self.stream.read_bytes(4, self._on_masking_key)\n                else:\n                    self.stream.read_bytes(self._frame_length, self._on_frame_data)\n            elif payloadlen == 126:\n                self.stream.read_bytes(2, self._on_frame_length_16)\n            elif payloadlen == 127:\n                self.stream.read_bytes(8, self._on_frame_length_64)\n        except StreamClosedError:\n            self._abort()\n\n    def _on_frame_length_16(self, data):\n        self._frame_length = struct.unpack(\"!H\", data)[0]\n        try:\n            if self._masked_frame:\n                self.stream.read_bytes(4, self._on_masking_key)\n            else:\n                self.stream.read_bytes(self._frame_length, self._on_frame_data)\n        except StreamClosedError:\n            self._abort()\n\n    def _on_frame_length_64(self, data):\n        self._frame_length = struct.unpack(\"!Q\", data)[0]\n        try:\n            if self._masked_frame:\n                self.stream.read_bytes(4, self._on_masking_key)\n            else:\n                self.stream.read_bytes(self._frame_length, self._on_frame_data)\n        except StreamClosedError:\n            self._abort()\n\n    def _on_masking_key(self, data):\n        self._frame_mask = data\n        try:\n            self.stream.read_bytes(self._frame_length, self._on_masked_frame_data)\n        except StreamClosedError:\n            self._abort()\n\n    def _on_masked_frame_data(self, data):\n        self._on_frame_data(_websocket_mask(self._frame_mask, data))\n\n    def _on_frame_data(self, data):\n        if self._frame_opcode_is_control:\n            # control frames may be interleaved with a series of fragmented\n            # data frames, so control frames must not interact with\n            # self._fragmented_*\n            if not self._final_frame:\n                # control frames must not be fragmented\n                self._abort()\n                return\n            opcode = self._frame_opcode\n        elif self._frame_opcode == 0:  # continuation frame\n            if self._fragmented_message_buffer is None:\n                # nothing to continue\n                self._abort()\n                return\n            self._fragmented_message_buffer += data\n            if self._final_frame:\n                opcode = self._fragmented_message_opcode\n                data = self._fragmented_message_buffer\n                self._fragmented_message_buffer = None\n        else:  # start of new data message\n            if self._fragmented_message_buffer is not None:\n                # can't start new message until the old one is finished\n                self._abort()\n                return\n            if self._final_frame:\n                opcode = self._frame_opcode\n            else:\n                self._fragmented_message_opcode = self._frame_opcode\n                self._fragmented_message_buffer = data\n\n        if self._final_frame:\n            self._handle_message(opcode, data)\n\n        if not self.client_terminated:\n            self._receive_frame()\n\n    def _handle_message(self, opcode, data):\n        if self.client_terminated:\n            return\n\n        if opcode == 0x1:\n            # UTF-8 data\n            try:\n                decoded = data.decode(\"utf-8\")\n            except UnicodeDecodeError:\n                self._abort()\n                return\n            self.async_callback(self.handler.on_message)(decoded)\n        elif opcode == 0x2:\n            # Binary data\n            self.async_callback(self.handler.on_message)(data)\n        elif opcode == 0x8:\n            # Close\n            self.client_terminated = True\n            if len(data) >= 2:\n                self.handler.close_code = struct.unpack('>H', data[:2])[0]\n            if len(data) > 2:\n                self.handler.close_reason = to_unicode(data[2:])\n            self.close()\n        elif opcode == 0x9:\n            # Ping\n            self._write_frame(True, 0xA, data)\n        elif opcode == 0xA:\n            # Pong\n            self.async_callback(self.handler.on_pong)(data)\n        else:\n            self._abort()\n\n    def close(self, code=None, reason=None):\n        \"\"\"Closes the WebSocket connection.\"\"\"\n        if not self.server_terminated:\n            if not self.stream.closed():\n                if code is None and reason is not None:\n                    code = 1000  # \"normal closure\" status code\n                if code is None:\n                    close_data = b''\n                else:\n                    close_data = struct.pack('>H', code)\n                if reason is not None:\n                    close_data += utf8(reason)\n                self._write_frame(True, 0x8, close_data)\n            self.server_terminated = True\n        if self.client_terminated:\n            if self._waiting is not None:\n                self.stream.io_loop.remove_timeout(self._waiting)\n                self._waiting = None\n            self.stream.close()\n        elif self._waiting is None:\n            # Give the client a few seconds to complete a clean shutdown,\n            # otherwise just close the connection.\n            self._waiting = self.stream.io_loop.add_timeout(\n                self.stream.io_loop.time() + 5, self._abort)\n\n\nclass WebSocketClientConnection(simple_httpclient._HTTPConnection):\n    \"\"\"WebSocket client connection.\n\n    This class should not be instantiated directly; use the\n    `websocket_connect` function instead.\n    \"\"\"\n    def __init__(self, io_loop, request):\n        self.connect_future = TracebackFuture()\n        self.read_future = None\n        self.read_queue = collections.deque()\n        self.key = base64.b64encode(os.urandom(16))\n\n        scheme, sep, rest = request.url.partition(':')\n        scheme = {'ws': 'http', 'wss': 'https'}[scheme]\n        request.url = scheme + sep + rest\n        request.headers.update({\n            'Upgrade': 'websocket',\n            'Connection': 'Upgrade',\n            'Sec-WebSocket-Key': self.key,\n            'Sec-WebSocket-Version': '13',\n        })\n\n        self.resolver = Resolver(io_loop=io_loop)\n        super(WebSocketClientConnection, self).__init__(\n            io_loop, None, request, lambda: None, self._on_http_response,\n            104857600, self.resolver, 65536)\n\n    def close(self, code=None, reason=None):\n        \"\"\"Closes the websocket connection.\n\n        ``code`` and ``reason`` are documented under\n        `WebSocketHandler.close`.\n\n        .. versionadded:: 3.2\n\n        .. versionchanged:: 3.3\n\n           Added the ``code`` and ``reason`` arguments.\n        \"\"\"\n        if self.protocol is not None:\n            self.protocol.close(code, reason)\n            self.protocol = None\n\n    def _on_close(self):\n        self.on_message(None)\n        self.resolver.close()\n        super(WebSocketClientConnection, self)._on_close()\n\n    def _on_http_response(self, response):\n        if not self.connect_future.done():\n            if response.error:\n                self.connect_future.set_exception(response.error)\n            else:\n                self.connect_future.set_exception(WebSocketError(\n                    \"Non-websocket response\"))\n\n    def headers_received(self, start_line, headers):\n        if start_line.code != 101:\n            return super(WebSocketClientConnection, self).headers_received(\n                start_line, headers)\n\n        self.headers = headers\n        assert self.headers['Upgrade'].lower() == 'websocket'\n        assert self.headers['Connection'].lower() == 'upgrade'\n        accept = WebSocketProtocol13.compute_accept_value(self.key)\n        assert self.headers['Sec-Websocket-Accept'] == accept\n\n        self.protocol = WebSocketProtocol13(self, mask_outgoing=True)\n        self.protocol._receive_frame()\n\n        if self._timeout is not None:\n            self.io_loop.remove_timeout(self._timeout)\n            self._timeout = None\n\n        self.stream = self.connection.detach()\n        self.stream.set_close_callback(self._on_close)\n\n        self.connect_future.set_result(self)\n\n    def write_message(self, message, binary=False):\n        \"\"\"Sends a message to the WebSocket server.\"\"\"\n        self.protocol.write_message(message, binary)\n\n    def read_message(self, callback=None):\n        \"\"\"Reads a message from the WebSocket server.\n\n        Returns a future whose result is the message, or None\n        if the connection is closed.  If a callback argument\n        is given it will be called with the future when it is\n        ready.\n        \"\"\"\n        assert self.read_future is None\n        future = TracebackFuture()\n        if self.read_queue:\n            future.set_result(self.read_queue.popleft())\n        else:\n            self.read_future = future\n        if callback is not None:\n            self.io_loop.add_future(future, callback)\n        return future\n\n    def on_message(self, message):\n        if self.read_future is not None:\n            self.read_future.set_result(message)\n            self.read_future = None\n        else:\n            self.read_queue.append(message)\n\n    def on_pong(self, data):\n        pass\n\n\ndef websocket_connect(url, io_loop=None, callback=None, connect_timeout=None):\n    \"\"\"Client-side websocket support.\n\n    Takes a url and returns a Future whose result is a\n    `WebSocketClientConnection`.\n\n    .. versionchanged:: 3.2\n       Also accepts ``HTTPRequest`` objects in place of urls.\n    \"\"\"\n    if io_loop is None:\n        io_loop = IOLoop.current()\n    if isinstance(url, httpclient.HTTPRequest):\n        assert connect_timeout is None\n        request = url\n        # Copy and convert the headers dict/object (see comments in\n        # AsyncHTTPClient.fetch)\n        request.headers = httputil.HTTPHeaders(request.headers)\n    else:\n        request = httpclient.HTTPRequest(url, connect_timeout=connect_timeout)\n    request = httpclient._RequestProxy(\n        request, httpclient.HTTPRequest._DEFAULTS)\n    conn = WebSocketClientConnection(io_loop, request)\n    if callback is not None:\n        io_loop.add_future(conn.connect_future, callback)\n    return conn.connect_future\n\n\ndef _websocket_mask_python(mask, data):\n    \"\"\"Websocket masking function.\n\n    `mask` is a `bytes` object of length 4; `data` is a `bytes` object of any length.\n    Returns a `bytes` object of the same length as `data` with the mask applied\n    as specified in section 5.3 of RFC 6455.\n\n    This pure-python implementation may be replaced by an optimized version when available.\n    \"\"\"\n    mask = array.array(\"B\", mask)\n    unmasked = array.array(\"B\", data)\n    for i in xrange(len(data)):\n        unmasked[i] = unmasked[i] ^ mask[i % 4]\n    if hasattr(unmasked, 'tobytes'):\n        # tostring was deprecated in py32.  It hasn't been removed,\n        # but since we turn on deprecation warnings in our tests\n        # we need to use the right one.\n        return unmasked.tobytes()\n    else:\n        return unmasked.tostring()\n\nif (os.environ.get('TORNADO_NO_EXTENSION') or\n    os.environ.get('TORNADO_EXTENSION') == '0'):\n    # These environment variables exist to make it easier to do performance\n    # comparisons; they are not guaranteed to remain supported in the future.\n    _websocket_mask = _websocket_mask_python\nelse:\n    try:\n        from tornado.speedups import websocket_mask as _websocket_mask\n    except ImportError:\n        if os.environ.get('TORNADO_EXTENSION') == '1':\n            raise\n        _websocket_mask = _websocket_mask_python\n",
            "new_file_content": "\"\"\"Implementation of the WebSocket protocol.\n\n`WebSockets <http://dev.w3.org/html5/websockets/>`_ allow for bidirectional\ncommunication between the browser and server.\n\n.. warning::\n\n   The WebSocket protocol was recently finalized as `RFC 6455\n   <http://tools.ietf.org/html/rfc6455>`_ and is not yet supported in\n   all browsers.  Refer to http://caniuse.com/websockets for details\n   on compatibility.  In addition, during development the protocol\n   went through several incompatible versions, and some browsers only\n   support older versions.  By default this module only supports the\n   latest version of the protocol, but optional support for an older\n   version (known as \"draft 76\" or \"hixie-76\") can be enabled by\n   overriding `WebSocketHandler.allow_draft76` (see that method's\n   documentation for caveats).\n\"\"\"\n\nfrom __future__ import absolute_import, division, print_function, with_statement\n# Author: Jacob Kristhammar, 2010\n\nimport array\nimport base64\nimport collections\nimport functools\nimport hashlib\nimport os\nimport struct\nimport time\nimport tornado.escape\nimport tornado.web\n\nfrom tornado.concurrent import TracebackFuture\nfrom tornado.escape import utf8, native_str, to_unicode\nfrom tornado import httpclient, httputil\nfrom tornado.ioloop import IOLoop\nfrom tornado.iostream import StreamClosedError\nfrom tornado.log import gen_log, app_log\nfrom tornado.netutil import Resolver\nfrom tornado import simple_httpclient\nfrom tornado.util import bytes_type, unicode_type\n\ntry:\n    from urllib.parse import urlparse # py2\nexcept ImportError:\n    from urlparse import urlparse # py3\n\ntry:\n    xrange  # py2\nexcept NameError:\n    xrange = range  # py3\n\n\nclass WebSocketError(Exception):\n    pass\n\n\nclass WebSocketClosedError(WebSocketError):\n    \"\"\"Raised by operations on a closed connection.\n\n    .. versionadded:: 3.2\n    \"\"\"\n    pass\n\n\nclass WebSocketHandler(tornado.web.RequestHandler):\n    \"\"\"Subclass this class to create a basic WebSocket handler.\n\n    Override `on_message` to handle incoming messages, and use\n    `write_message` to send messages to the client. You can also\n    override `open` and `on_close` to handle opened and closed\n    connections.\n\n    See http://dev.w3.org/html5/websockets/ for details on the\n    JavaScript interface.  The protocol is specified at\n    http://tools.ietf.org/html/rfc6455.\n\n    Here is an example WebSocket handler that echos back all received messages\n    back to the client::\n\n      class EchoWebSocket(websocket.WebSocketHandler):\n          def open(self):\n              print \"WebSocket opened\"\n\n          def on_message(self, message):\n              self.write_message(u\"You said: \" + message)\n\n          def on_close(self):\n              print \"WebSocket closed\"\n\n    WebSockets are not standard HTTP connections. The \"handshake\" is\n    HTTP, but after the handshake, the protocol is\n    message-based. Consequently, most of the Tornado HTTP facilities\n    are not available in handlers of this type. The only communication\n    methods available to you are `write_message()`, `ping()`, and\n    `close()`. Likewise, your request handler class should implement\n    `open()` method rather than ``get()`` or ``post()``.\n\n    If you map the handler above to ``/websocket`` in your application, you can\n    invoke it in JavaScript with::\n\n      var ws = new WebSocket(\"ws://localhost:8888/websocket\");\n      ws.onopen = function() {\n         ws.send(\"Hello, world\");\n      };\n      ws.onmessage = function (evt) {\n         alert(evt.data);\n      };\n\n    This script pops up an alert box that says \"You said: Hello, world\".\n    \"\"\"\n    def __init__(self, application, request, **kwargs):\n        tornado.web.RequestHandler.__init__(self, application, request,\n                                            **kwargs)\n        self.ws_connection = None\n        self.close_code = None\n        self.close_reason = None\n\n    @tornado.web.asynchronous\n    def get(self, *args, **kwargs):\n        self.open_args = args\n        self.open_kwargs = kwargs\n\n        self.stream = self.request.connection.detach()\n\n        # Upgrade header should be present and should be equal to WebSocket\n        if self.request.headers.get(\"Upgrade\", \"\").lower() != 'websocket':\n            self.stream.write(tornado.escape.utf8(\n                \"HTTP/1.1 400 Bad Request\\r\\n\\r\\n\"\n                \"Can \\\"Upgrade\\\" only to \\\"WebSocket\\\".\"\n            ))\n            self.stream.close()\n            return\n\n        # Connection header should be upgrade. Some proxy servers/load balancers\n        # might mess with it.\n        headers = self.request.headers\n        connection = map(lambda s: s.strip().lower(), headers.get(\"Connection\", \"\").split(\",\"))\n        if 'upgrade' not in connection:\n            self.stream.write(tornado.escape.utf8(\n                \"HTTP/1.1 400 Bad Request\\r\\n\\r\\n\"\n                \"\\\"Connection\\\" must be \\\"Upgrade\\\".\"\n            ))\n            self.stream.close()\n            return\n\n        # Handle WebSocket Origin naming convention differences\n        # The difference between version 8 and 13 is that in 8 the\n        # client sends a \"Sec-Websocket-Origin\" header and in 13 it's\n        # simply \"Origin\".\n        if \"Origin\" in self.request.headers:\n            origin = self.request.headers.get(\"Origin\")\n        else:\n            origin = self.request.headers.get(\"Sec-Websocket-Origin\", None)\n\n        # If we have an origin, normalize\n        if(origin):\n            # Due to how stdlib's urlparse is implemented, urls without a //\n            # are interpreted to be paths (resulting in netloc being None)\n            if(\"//\" not in origin):\n                origin = \"//\" + origin\n            parsed_origin = urlparse(origin)\n            origin = parsed_origin.netloc\n            origin = origin.lower()\n\n        # If there was an origin header, check to make sure it matches\n        # according to check_origin\n        if not self.check_origin(origin):\n            self.stream.write(tornado.escape.utf8(\n                \"HTTP/1.1 403 Cross Origin Websockets Disabled\\r\\n\\r\\n\"\n            ))\n            self.stream.close()\n            return\n\n        if self.request.headers.get(\"Sec-WebSocket-Version\") in (\"7\", \"8\", \"13\"):\n            self.ws_connection = WebSocketProtocol13(self)\n            self.ws_connection.accept_connection()\n        elif (self.allow_draft76() and\n              \"Sec-WebSocket-Version\" not in self.request.headers):\n            self.ws_connection = WebSocketProtocol76(self)\n            self.ws_connection.accept_connection()\n        else:\n            self.stream.write(tornado.escape.utf8(\n                \"HTTP/1.1 426 Upgrade Required\\r\\n\"\n                \"Sec-WebSocket-Version: 8\\r\\n\\r\\n\"))\n            self.stream.close()\n\n\n    def write_message(self, message, binary=False):\n        \"\"\"Sends the given message to the client of this Web Socket.\n\n        The message may be either a string or a dict (which will be\n        encoded as json).  If the ``binary`` argument is false, the\n        message will be sent as utf8; in binary mode any byte string\n        is allowed.\n\n        If the connection is already closed, raises `WebSocketClosedError`.\n\n        .. versionchanged:: 3.2\n           `WebSocketClosedError` was added (previously a closed connection\n           would raise an `AttributeError`)\n        \"\"\"\n        if self.ws_connection is None:\n            raise WebSocketClosedError()\n        if isinstance(message, dict):\n            message = tornado.escape.json_encode(message)\n        self.ws_connection.write_message(message, binary=binary)\n\n    def select_subprotocol(self, subprotocols):\n        \"\"\"Invoked when a new WebSocket requests specific subprotocols.\n\n        ``subprotocols`` is a list of strings identifying the\n        subprotocols proposed by the client.  This method may be\n        overridden to return one of those strings to select it, or\n        ``None`` to not select a subprotocol.  Failure to select a\n        subprotocol does not automatically abort the connection,\n        although clients may close the connection if none of their\n        proposed subprotocols was selected.\n        \"\"\"\n        return None\n\n    def open(self):\n        \"\"\"Invoked when a new WebSocket is opened.\n\n        The arguments to `open` are extracted from the `tornado.web.URLSpec`\n        regular expression, just like the arguments to\n        `tornado.web.RequestHandler.get`.\n        \"\"\"\n        pass\n\n    def on_message(self, message):\n        \"\"\"Handle incoming messages on the WebSocket\n\n        This method must be overridden.\n        \"\"\"\n        raise NotImplementedError\n\n    def ping(self, data):\n        \"\"\"Send ping frame to the remote end.\"\"\"\n        if self.ws_connection is None:\n            raise WebSocketClosedError()\n        self.ws_connection.write_ping(data)\n\n    def on_pong(self, data):\n        \"\"\"Invoked when the response to a ping frame is received.\"\"\"\n        pass\n\n    def on_close(self):\n        \"\"\"Invoked when the WebSocket is closed.\n\n        If the connection was closed cleanly and a status code or reason\n        phrase was supplied, these values will be available as the attributes\n        ``self.close_code`` and ``self.close_reason``.\n\n        .. versionchanged:: 3.3\n\n           Added ``close_code`` and ``close_reason`` attributes.\n        \"\"\"\n        pass\n\n    def close(self, code=None, reason=None):\n        \"\"\"Closes this Web Socket.\n\n        Once the close handshake is successful the socket will be closed.\n\n        ``code`` may be a numeric status code, taken from the values\n        defined in `RFC 6455 section 7.4.1\n        <https://tools.ietf.org/html/rfc6455#section-7.4.1>`_.\n        ``reason`` may be a textual message about why the connection is\n        closing.  These values are made available to the client, but are\n        not otherwise interpreted by the websocket protocol.\n\n        The ``code`` and ``reason`` arguments are ignored in the \"draft76\"\n        protocol version.\n\n        .. versionchanged:: 3.3\n\n           Added the ``code`` and ``reason`` arguments.\n        \"\"\"\n        if self.ws_connection:\n            self.ws_connection.close(code, reason)\n            self.ws_connection = None\n\n    def check_origin(self, origin):\n        \"\"\"Override to enable support for allowing alternate origins.\n        \n        By default, this checks to see that the host matches the origin\n        provided.\n\n        This is a security protection against cross site scripting attacks on\n        browsers, since WebSockets don't have CORS headers.\n        \n        >>> self.check_origin(origin='localhost')\n        True\n        \n        \"\"\"\n        # When origin is None, assume it didn't come from a browser and we can\n        # pass it on\n        if origin is None:\n            return True\n\n        host = self.request.headers.get(\"Host\")\n\n        # Check to see that origin matches host directly, including ports\n        return origin == host\n\n    def allow_draft76(self):\n        \"\"\"Override to enable support for the older \"draft76\" protocol.\n\n        The draft76 version of the websocket protocol is disabled by\n        default due to security concerns, but it can be enabled by\n        overriding this method to return True.\n\n        Connections using the draft76 protocol do not support the\n        ``binary=True`` flag to `write_message`.\n\n        Support for the draft76 protocol is deprecated and will be\n        removed in a future version of Tornado.\n        \"\"\"\n        return False\n\n    def set_nodelay(self, value):\n        \"\"\"Set the no-delay flag for this stream.\n\n        By default, small messages may be delayed and/or combined to minimize\n        the number of packets sent.  This can sometimes cause 200-500ms delays\n        due to the interaction between Nagle's algorithm and TCP delayed\n        ACKs.  To reduce this delay (at the expense of possibly increasing\n        bandwidth usage), call ``self.set_nodelay(True)`` once the websocket\n        connection is established.\n\n        See `.BaseIOStream.set_nodelay` for additional details.\n\n        .. versionadded:: 3.1\n        \"\"\"\n        self.stream.set_nodelay(value)\n\n    def get_websocket_scheme(self):\n        \"\"\"Return the url scheme used for this request, either \"ws\" or \"wss\".\n\n        This is normally decided by HTTPServer, but applications\n        may wish to override this if they are using an SSL proxy\n        that does not provide the X-Scheme header as understood\n        by HTTPServer.\n\n        Note that this is only used by the draft76 protocol.\n        \"\"\"\n        return \"wss\" if self.request.protocol == \"https\" else \"ws\"\n\n    def async_callback(self, callback, *args, **kwargs):\n        \"\"\"Obsolete - catches exceptions from the wrapped function.\n\n        This function is normally unncecessary thanks to\n        `tornado.stack_context`.\n        \"\"\"\n        return self.ws_connection.async_callback(callback, *args, **kwargs)\n\n    def _not_supported(self, *args, **kwargs):\n        raise Exception(\"Method not supported for Web Sockets\")\n\n    def on_connection_close(self):\n        if self.ws_connection:\n            self.ws_connection.on_connection_close()\n            self.ws_connection = None\n            self.on_close()\n\n\nfor method in [\"write\", \"redirect\", \"set_header\", \"send_error\", \"set_cookie\",\n               \"set_status\", \"flush\", \"finish\"]:\n    setattr(WebSocketHandler, method, WebSocketHandler._not_supported)\n\n\nclass WebSocketProtocol(object):\n    \"\"\"Base class for WebSocket protocol versions.\n    \"\"\"\n    def __init__(self, handler):\n        self.handler = handler\n        self.request = handler.request\n        self.stream = handler.stream\n        self.client_terminated = False\n        self.server_terminated = False\n\n    def async_callback(self, callback, *args, **kwargs):\n        \"\"\"Wrap callbacks with this if they are used on asynchronous requests.\n\n        Catches exceptions properly and closes this WebSocket if an exception\n        is uncaught.\n        \"\"\"\n        if args or kwargs:\n            callback = functools.partial(callback, *args, **kwargs)\n\n        def wrapper(*args, **kwargs):\n            try:\n                return callback(*args, **kwargs)\n            except Exception:\n                app_log.error(\"Uncaught exception in %s\",\n                              self.request.path, exc_info=True)\n                self._abort()\n        return wrapper\n\n    def on_connection_close(self):\n        self._abort()\n\n    def _abort(self):\n        \"\"\"Instantly aborts the WebSocket connection by closing the socket\"\"\"\n        self.client_terminated = True\n        self.server_terminated = True\n        self.stream.close()  # forcibly tear down the connection\n        self.close()  # let the subclass cleanup\n\n\nclass WebSocketProtocol76(WebSocketProtocol):\n    \"\"\"Implementation of the WebSockets protocol, version hixie-76.\n\n    This class provides basic functionality to process WebSockets requests as\n    specified in\n    http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76\n    \"\"\"\n    def __init__(self, handler):\n        WebSocketProtocol.__init__(self, handler)\n        self.challenge = None\n        self._waiting = None\n\n    def accept_connection(self):\n        try:\n            self._handle_websocket_headers()\n        except ValueError:\n            gen_log.debug(\"Malformed WebSocket request received\")\n            self._abort()\n            return\n\n        scheme = self.handler.get_websocket_scheme()\n\n        # draft76 only allows a single subprotocol\n        subprotocol_header = ''\n        subprotocol = self.request.headers.get(\"Sec-WebSocket-Protocol\", None)\n        if subprotocol:\n            selected = self.handler.select_subprotocol([subprotocol])\n            if selected:\n                assert selected == subprotocol\n                subprotocol_header = \"Sec-WebSocket-Protocol: %s\\r\\n\" % selected\n\n        # Write the initial headers before attempting to read the challenge.\n        # This is necessary when using proxies (such as HAProxy), which\n        # need to see the Upgrade headers before passing through the\n        # non-HTTP traffic that follows.\n        self.stream.write(tornado.escape.utf8(\n            \"HTTP/1.1 101 WebSocket Protocol Handshake\\r\\n\"\n            \"Upgrade: WebSocket\\r\\n\"\n            \"Connection: Upgrade\\r\\n\"\n            \"Server: TornadoServer/%(version)s\\r\\n\"\n            \"Sec-WebSocket-Origin: %(origin)s\\r\\n\"\n            \"Sec-WebSocket-Location: %(scheme)s://%(host)s%(uri)s\\r\\n\"\n            \"%(subprotocol)s\"\n            \"\\r\\n\" % (dict(\n                version=tornado.version,\n                origin=self.request.headers[\"Origin\"],\n                scheme=scheme,\n                host=self.request.host,\n                uri=self.request.uri,\n                subprotocol=subprotocol_header))))\n        self.stream.read_bytes(8, self._handle_challenge)\n\n    def challenge_response(self, challenge):\n        \"\"\"Generates the challenge response that's needed in the handshake\n\n        The challenge parameter should be the raw bytes as sent from the\n        client.\n        \"\"\"\n        key_1 = self.request.headers.get(\"Sec-Websocket-Key1\")\n        key_2 = self.request.headers.get(\"Sec-Websocket-Key2\")\n        try:\n            part_1 = self._calculate_part(key_1)\n            part_2 = self._calculate_part(key_2)\n        except ValueError:\n            raise ValueError(\"Invalid Keys/Challenge\")\n        return self._generate_challenge_response(part_1, part_2, challenge)\n\n    def _handle_challenge(self, challenge):\n        try:\n            challenge_response = self.challenge_response(challenge)\n        except ValueError:\n            gen_log.debug(\"Malformed key data in WebSocket request\")\n            self._abort()\n            return\n        self._write_response(challenge_response)\n\n    def _write_response(self, challenge):\n        self.stream.write(challenge)\n        self.async_callback(self.handler.open)(*self.handler.open_args, **self.handler.open_kwargs)\n        self._receive_message()\n\n    def _handle_websocket_headers(self):\n        \"\"\"Verifies all invariant- and required headers\n\n        If a header is missing or have an incorrect value ValueError will be\n        raised\n        \"\"\"\n        fields = (\"Origin\", \"Host\", \"Sec-Websocket-Key1\",\n                  \"Sec-Websocket-Key2\")\n        if not all(map(lambda f: self.request.headers.get(f), fields)):\n            raise ValueError(\"Missing/Invalid WebSocket headers\")\n\n    def _calculate_part(self, key):\n        \"\"\"Processes the key headers and calculates their key value.\n\n        Raises ValueError when feed invalid key.\"\"\"\n        # pyflakes complains about variable reuse if both of these lines use 'c'\n        number = int(''.join(c for c in key if c.isdigit()))\n        spaces = len([c2 for c2 in key if c2.isspace()])\n        try:\n            key_number = number // spaces\n        except (ValueError, ZeroDivisionError):\n            raise ValueError\n        return struct.pack(\">I\", key_number)\n\n    def _generate_challenge_response(self, part_1, part_2, part_3):\n        m = hashlib.md5()\n        m.update(part_1)\n        m.update(part_2)\n        m.update(part_3)\n        return m.digest()\n\n    def _receive_message(self):\n        self.stream.read_bytes(1, self._on_frame_type)\n\n    def _on_frame_type(self, byte):\n        frame_type = ord(byte)\n        if frame_type == 0x00:\n            self.stream.read_until(b\"\\xff\", self._on_end_delimiter)\n        elif frame_type == 0xff:\n            self.stream.read_bytes(1, self._on_length_indicator)\n        else:\n            self._abort()\n\n    def _on_end_delimiter(self, frame):\n        if not self.client_terminated:\n            self.async_callback(self.handler.on_message)(\n                frame[:-1].decode(\"utf-8\", \"replace\"))\n        if not self.client_terminated:\n            self._receive_message()\n\n    def _on_length_indicator(self, byte):\n        if ord(byte) != 0x00:\n            self._abort()\n            return\n        self.client_terminated = True\n        self.close()\n\n    def write_message(self, message, binary=False):\n        \"\"\"Sends the given message to the client of this Web Socket.\"\"\"\n        if binary:\n            raise ValueError(\n                \"Binary messages not supported by this version of websockets\")\n        if isinstance(message, unicode_type):\n            message = message.encode(\"utf-8\")\n        assert isinstance(message, bytes_type)\n        self.stream.write(b\"\\x00\" + message + b\"\\xff\")\n\n    def write_ping(self, data):\n        \"\"\"Send ping frame.\"\"\"\n        raise ValueError(\"Ping messages not supported by this version of websockets\")\n\n    def close(self, code=None, reason=None):\n        \"\"\"Closes the WebSocket connection.\"\"\"\n        if not self.server_terminated:\n            if not self.stream.closed():\n                self.stream.write(\"\\xff\\x00\")\n            self.server_terminated = True\n        if self.client_terminated:\n            if self._waiting is not None:\n                self.stream.io_loop.remove_timeout(self._waiting)\n            self._waiting = None\n            self.stream.close()\n        elif self._waiting is None:\n            self._waiting = self.stream.io_loop.add_timeout(\n                time.time() + 5, self._abort)\n\n\nclass WebSocketProtocol13(WebSocketProtocol):\n    \"\"\"Implementation of the WebSocket protocol from RFC 6455.\n\n    This class supports versions 7 and 8 of the protocol in addition to the\n    final version 13.\n    \"\"\"\n    def __init__(self, handler, mask_outgoing=False):\n        WebSocketProtocol.__init__(self, handler)\n        self.mask_outgoing = mask_outgoing\n        self._final_frame = False\n        self._frame_opcode = None\n        self._masked_frame = None\n        self._frame_mask = None\n        self._frame_length = None\n        self._fragmented_message_buffer = None\n        self._fragmented_message_opcode = None\n        self._waiting = None\n\n    def accept_connection(self):\n        try:\n            self._handle_websocket_headers()\n            self._accept_connection()\n        except ValueError:\n            gen_log.debug(\"Malformed WebSocket request received\", exc_info=True)\n            self._abort()\n            return\n\n    def _handle_websocket_headers(self):\n        \"\"\"Verifies all invariant- and required headers\n\n        If a header is missing or have an incorrect value ValueError will be\n        raised\n        \"\"\"\n        fields = (\"Host\", \"Sec-Websocket-Key\", \"Sec-Websocket-Version\")\n        if not all(map(lambda f: self.request.headers.get(f), fields)):\n            raise ValueError(\"Missing/Invalid WebSocket headers\")\n\n    @staticmethod\n    def compute_accept_value(key):\n        \"\"\"Computes the value for the Sec-WebSocket-Accept header,\n        given the value for Sec-WebSocket-Key.\n        \"\"\"\n        sha1 = hashlib.sha1()\n        sha1.update(utf8(key))\n        sha1.update(b\"258EAFA5-E914-47DA-95CA-C5AB0DC85B11\")  # Magic value\n        return native_str(base64.b64encode(sha1.digest()))\n\n    def _challenge_response(self):\n        return WebSocketProtocol13.compute_accept_value(\n            self.request.headers.get(\"Sec-Websocket-Key\"))\n\n    def _accept_connection(self):\n        subprotocol_header = ''\n        subprotocols = self.request.headers.get(\"Sec-WebSocket-Protocol\", '')\n        subprotocols = [s.strip() for s in subprotocols.split(',')]\n        if subprotocols:\n            selected = self.handler.select_subprotocol(subprotocols)\n            if selected:\n                assert selected in subprotocols\n                subprotocol_header = \"Sec-WebSocket-Protocol: %s\\r\\n\" % selected\n\n        self.stream.write(tornado.escape.utf8(\n            \"HTTP/1.1 101 Switching Protocols\\r\\n\"\n            \"Upgrade: websocket\\r\\n\"\n            \"Connection: Upgrade\\r\\n\"\n            \"Sec-WebSocket-Accept: %s\\r\\n\"\n            \"%s\"\n            \"\\r\\n\" % (self._challenge_response(), subprotocol_header)))\n\n        self.async_callback(self.handler.open)(*self.handler.open_args, **self.handler.open_kwargs)\n        self._receive_frame()\n\n    def _write_frame(self, fin, opcode, data):\n        if fin:\n            finbit = 0x80\n        else:\n            finbit = 0\n        frame = struct.pack(\"B\", finbit | opcode)\n        l = len(data)\n        if self.mask_outgoing:\n            mask_bit = 0x80\n        else:\n            mask_bit = 0\n        if l < 126:\n            frame += struct.pack(\"B\", l | mask_bit)\n        elif l <= 0xFFFF:\n            frame += struct.pack(\"!BH\", 126 | mask_bit, l)\n        else:\n            frame += struct.pack(\"!BQ\", 127 | mask_bit, l)\n        if self.mask_outgoing:\n            mask = os.urandom(4)\n            data = mask + _websocket_mask(mask, data)\n        frame += data\n        self.stream.write(frame)\n\n    def write_message(self, message, binary=False):\n        \"\"\"Sends the given message to the client of this Web Socket.\"\"\"\n        if binary:\n            opcode = 0x2\n        else:\n            opcode = 0x1\n        message = tornado.escape.utf8(message)\n        assert isinstance(message, bytes_type)\n        try:\n            self._write_frame(True, opcode, message)\n        except StreamClosedError:\n            self._abort()\n\n    def write_ping(self, data):\n        \"\"\"Send ping frame.\"\"\"\n        assert isinstance(data, bytes_type)\n        self._write_frame(True, 0x9, data)\n\n    def _receive_frame(self):\n        try:\n            self.stream.read_bytes(2, self._on_frame_start)\n        except StreamClosedError:\n            self._abort()\n\n    def _on_frame_start(self, data):\n        header, payloadlen = struct.unpack(\"BB\", data)\n        self._final_frame = header & 0x80\n        reserved_bits = header & 0x70\n        self._frame_opcode = header & 0xf\n        self._frame_opcode_is_control = self._frame_opcode & 0x8\n        if reserved_bits:\n            # client is using as-yet-undefined extensions; abort\n            self._abort()\n            return\n        self._masked_frame = bool(payloadlen & 0x80)\n        payloadlen = payloadlen & 0x7f\n        if self._frame_opcode_is_control and payloadlen >= 126:\n            # control frames must have payload < 126\n            self._abort()\n            return\n        try:\n            if payloadlen < 126:\n                self._frame_length = payloadlen\n                if self._masked_frame:\n                    self.stream.read_bytes(4, self._on_masking_key)\n                else:\n                    self.stream.read_bytes(self._frame_length, self._on_frame_data)\n            elif payloadlen == 126:\n                self.stream.read_bytes(2, self._on_frame_length_16)\n            elif payloadlen == 127:\n                self.stream.read_bytes(8, self._on_frame_length_64)\n        except StreamClosedError:\n            self._abort()\n\n    def _on_frame_length_16(self, data):\n        self._frame_length = struct.unpack(\"!H\", data)[0]\n        try:\n            if self._masked_frame:\n                self.stream.read_bytes(4, self._on_masking_key)\n            else:\n                self.stream.read_bytes(self._frame_length, self._on_frame_data)\n        except StreamClosedError:\n            self._abort()\n\n    def _on_frame_length_64(self, data):\n        self._frame_length = struct.unpack(\"!Q\", data)[0]\n        try:\n            if self._masked_frame:\n                self.stream.read_bytes(4, self._on_masking_key)\n            else:\n                self.stream.read_bytes(self._frame_length, self._on_frame_data)\n        except StreamClosedError:\n            self._abort()\n\n    def _on_masking_key(self, data):\n        self._frame_mask = data\n        try:\n            self.stream.read_bytes(self._frame_length, self._on_masked_frame_data)\n        except StreamClosedError:\n            self._abort()\n\n    def _on_masked_frame_data(self, data):\n        self._on_frame_data(_websocket_mask(self._frame_mask, data))\n\n    def _on_frame_data(self, data):\n        if self._frame_opcode_is_control:\n            # control frames may be interleaved with a series of fragmented\n            # data frames, so control frames must not interact with\n            # self._fragmented_*\n            if not self._final_frame:\n                # control frames must not be fragmented\n                self._abort()\n                return\n            opcode = self._frame_opcode\n        elif self._frame_opcode == 0:  # continuation frame\n            if self._fragmented_message_buffer is None:\n                # nothing to continue\n                self._abort()\n                return\n            self._fragmented_message_buffer += data\n            if self._final_frame:\n                opcode = self._fragmented_message_opcode\n                data = self._fragmented_message_buffer\n                self._fragmented_message_buffer = None\n        else:  # start of new data message\n            if self._fragmented_message_buffer is not None:\n                # can't start new message until the old one is finished\n                self._abort()\n                return\n            if self._final_frame:\n                opcode = self._frame_opcode\n            else:\n                self._fragmented_message_opcode = self._frame_opcode\n                self._fragmented_message_buffer = data\n\n        if self._final_frame:\n            self._handle_message(opcode, data)\n\n        if not self.client_terminated:\n            self._receive_frame()\n\n    def _handle_message(self, opcode, data):\n        if self.client_terminated:\n            return\n\n        if opcode == 0x1:\n            # UTF-8 data\n            try:\n                decoded = data.decode(\"utf-8\")\n            except UnicodeDecodeError:\n                self._abort()\n                return\n            self.async_callback(self.handler.on_message)(decoded)\n        elif opcode == 0x2:\n            # Binary data\n            self.async_callback(self.handler.on_message)(data)\n        elif opcode == 0x8:\n            # Close\n            self.client_terminated = True\n            if len(data) >= 2:\n                self.handler.close_code = struct.unpack('>H', data[:2])[0]\n            if len(data) > 2:\n                self.handler.close_reason = to_unicode(data[2:])\n            self.close()\n        elif opcode == 0x9:\n            # Ping\n            self._write_frame(True, 0xA, data)\n        elif opcode == 0xA:\n            # Pong\n            self.async_callback(self.handler.on_pong)(data)\n        else:\n            self._abort()\n\n    def close(self, code=None, reason=None):\n        \"\"\"Closes the WebSocket connection.\"\"\"\n        if not self.server_terminated:\n            if not self.stream.closed():\n                if code is None and reason is not None:\n                    code = 1000  # \"normal closure\" status code\n                if code is None:\n                    close_data = b''\n                else:\n                    close_data = struct.pack('>H', code)\n                if reason is not None:\n                    close_data += utf8(reason)\n                self._write_frame(True, 0x8, close_data)\n            self.server_terminated = True\n        if self.client_terminated:\n            if self._waiting is not None:\n                self.stream.io_loop.remove_timeout(self._waiting)\n                self._waiting = None\n            self.stream.close()\n        elif self._waiting is None:\n            # Give the client a few seconds to complete a clean shutdown,\n            # otherwise just close the connection.\n            self._waiting = self.stream.io_loop.add_timeout(\n                self.stream.io_loop.time() + 5, self._abort)\n\n\nclass WebSocketClientConnection(simple_httpclient._HTTPConnection):\n    \"\"\"WebSocket client connection.\n\n    This class should not be instantiated directly; use the\n    `websocket_connect` function instead.\n    \"\"\"\n    def __init__(self, io_loop, request):\n        self.connect_future = TracebackFuture()\n        self.read_future = None\n        self.read_queue = collections.deque()\n        self.key = base64.b64encode(os.urandom(16))\n\n        scheme, sep, rest = request.url.partition(':')\n        scheme = {'ws': 'http', 'wss': 'https'}[scheme]\n        request.url = scheme + sep + rest\n        request.headers.update({\n            'Upgrade': 'websocket',\n            'Connection': 'Upgrade',\n            'Sec-WebSocket-Key': self.key,\n            'Sec-WebSocket-Version': '13',\n        })\n\n        self.resolver = Resolver(io_loop=io_loop)\n        super(WebSocketClientConnection, self).__init__(\n            io_loop, None, request, lambda: None, self._on_http_response,\n            104857600, self.resolver, 65536)\n\n    def close(self, code=None, reason=None):\n        \"\"\"Closes the websocket connection.\n\n        ``code`` and ``reason`` are documented under\n        `WebSocketHandler.close`.\n\n        .. versionadded:: 3.2\n\n        .. versionchanged:: 3.3\n\n           Added the ``code`` and ``reason`` arguments.\n        \"\"\"\n        if self.protocol is not None:\n            self.protocol.close(code, reason)\n            self.protocol = None\n\n    def _on_close(self):\n        self.on_message(None)\n        self.resolver.close()\n        super(WebSocketClientConnection, self)._on_close()\n\n    def _on_http_response(self, response):\n        if not self.connect_future.done():\n            if response.error:\n                self.connect_future.set_exception(response.error)\n            else:\n                self.connect_future.set_exception(WebSocketError(\n                    \"Non-websocket response\"))\n\n    def headers_received(self, start_line, headers):\n        if start_line.code != 101:\n            return super(WebSocketClientConnection, self).headers_received(\n                start_line, headers)\n\n        self.headers = headers\n        assert self.headers['Upgrade'].lower() == 'websocket'\n        assert self.headers['Connection'].lower() == 'upgrade'\n        accept = WebSocketProtocol13.compute_accept_value(self.key)\n        assert self.headers['Sec-Websocket-Accept'] == accept\n\n        self.protocol = WebSocketProtocol13(self, mask_outgoing=True)\n        self.protocol._receive_frame()\n\n        if self._timeout is not None:\n            self.io_loop.remove_timeout(self._timeout)\n            self._timeout = None\n\n        self.stream = self.connection.detach()\n        self.stream.set_close_callback(self._on_close)\n\n        self.connect_future.set_result(self)\n\n    def write_message(self, message, binary=False):\n        \"\"\"Sends a message to the WebSocket server.\"\"\"\n        self.protocol.write_message(message, binary)\n\n    def read_message(self, callback=None):\n        \"\"\"Reads a message from the WebSocket server.\n\n        Returns a future whose result is the message, or None\n        if the connection is closed.  If a callback argument\n        is given it will be called with the future when it is\n        ready.\n        \"\"\"\n        assert self.read_future is None\n        future = TracebackFuture()\n        if self.read_queue:\n            future.set_result(self.read_queue.popleft())\n        else:\n            self.read_future = future\n        if callback is not None:\n            self.io_loop.add_future(future, callback)\n        return future\n\n    def on_message(self, message):\n        if self.read_future is not None:\n            self.read_future.set_result(message)\n            self.read_future = None\n        else:\n            self.read_queue.append(message)\n\n    def on_pong(self, data):\n        pass\n\n\ndef websocket_connect(url, io_loop=None, callback=None, connect_timeout=None):\n    \"\"\"Client-side websocket support.\n\n    Takes a url and returns a Future whose result is a\n    `WebSocketClientConnection`.\n\n    .. versionchanged:: 3.2\n       Also accepts ``HTTPRequest`` objects in place of urls.\n    \"\"\"\n    if io_loop is None:\n        io_loop = IOLoop.current()\n    if isinstance(url, httpclient.HTTPRequest):\n        assert connect_timeout is None\n        request = url\n        # Copy and convert the headers dict/object (see comments in\n        # AsyncHTTPClient.fetch)\n        request.headers = httputil.HTTPHeaders(request.headers)\n    else:\n        request = httpclient.HTTPRequest(url, connect_timeout=connect_timeout)\n    request = httpclient._RequestProxy(\n        request, httpclient.HTTPRequest._DEFAULTS)\n    conn = WebSocketClientConnection(io_loop, request)\n    if callback is not None:\n        io_loop.add_future(conn.connect_future, callback)\n    return conn.connect_future\n\n\ndef _websocket_mask_python(mask, data):\n    \"\"\"Websocket masking function.\n\n    `mask` is a `bytes` object of length 4; `data` is a `bytes` object of any length.\n    Returns a `bytes` object of the same length as `data` with the mask applied\n    as specified in section 5.3 of RFC 6455.\n\n    This pure-python implementation may be replaced by an optimized version when available.\n    \"\"\"\n    mask = array.array(\"B\", mask)\n    unmasked = array.array(\"B\", data)\n    for i in xrange(len(data)):\n        unmasked[i] = unmasked[i] ^ mask[i % 4]\n    if hasattr(unmasked, 'tobytes'):\n        # tostring was deprecated in py32.  It hasn't been removed,\n        # but since we turn on deprecation warnings in our tests\n        # we need to use the right one.\n        return unmasked.tobytes()\n    else:\n        return unmasked.tostring()\n\nif (os.environ.get('TORNADO_NO_EXTENSION') or\n    os.environ.get('TORNADO_EXTENSION') == '0'):\n    # These environment variables exist to make it easier to do performance\n    # comparisons; they are not guaranteed to remain supported in the future.\n    _websocket_mask = _websocket_mask_python\nelse:\n    try:\n        from tornado.speedups import websocket_mask as _websocket_mask\n    except ImportError:\n        if os.environ.get('TORNADO_EXTENSION') == '1':\n            raise\n        _websocket_mask = _websocket_mask_python\n",
            "header": {
                "file": {
                    "path": "tornado/websocket.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "22369c87",
                "new_commit_hash": "1ba905b7",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/tornado/websocket.py"
            },
            "plus_file": {
                "path": "b/tornado/websocket.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 145,
                            "length": 9
                        },
                        "new_range": {
                            "start": 145,
                            "length": 34
                        },
                        "section": "class WebSocketHandler(tornado.web.RequestHandler):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "            self.stream.close()",
                                "type": "context"
                            },
                            {
                                "content": "            return",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "        # Handle WebSocket Origin naming convention differences",
                                "type": "added"
                            },
                            {
                                "content": "        # The difference between version 8 and 13 is that in 8 the",
                                "type": "context"
                            },
                            {
                                "content": "        # client sends a \"Sec-Websocket-Origin\" header and in 13 it's",
                                "type": "context"
                            },
                            {
                                "content": "        # simply \"Origin\".",
                                "type": "context"
                            },
                            {
                                "content": "        if \"Origin\" in self.request.headers:",
                                "type": "added"
                            },
                            {
                                "content": "            origin = self.request.headers.get(\"Origin\")",
                                "type": "added"
                            },
                            {
                                "content": "        else:",
                                "type": "added"
                            },
                            {
                                "content": "            origin = self.request.headers.get(\"Sec-Websocket-Origin\", None)",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "        # If we have an origin, normalize",
                                "type": "added"
                            },
                            {
                                "content": "        if(origin):",
                                "type": "added"
                            },
                            {
                                "content": "            # Due to how stdlib's urlparse is implemented, urls without a //",
                                "type": "added"
                            },
                            {
                                "content": "            # are interpreted to be paths (resulting in netloc being None)",
                                "type": "added"
                            },
                            {
                                "content": "            if(\"//\" not in origin):",
                                "type": "added"
                            },
                            {
                                "content": "                origin = \"//\" + origin",
                                "type": "added"
                            },
                            {
                                "content": "            parsed_origin = urlparse(origin)",
                                "type": "added"
                            },
                            {
                                "content": "            origin = parsed_origin.netloc",
                                "type": "added"
                            },
                            {
                                "content": "            origin = origin.lower()",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "        # If there was an origin header, check to make sure it matches",
                                "type": "added"
                            },
                            {
                                "content": "        # according to check_origin",
                                "type": "added"
                            },
                            {
                                "content": "        if not self.check_origin(origin):",
                                "type": "added"
                            },
                            {
                                "content": "            self.stream.write(tornado.escape.utf8(",
                                "type": "added"
                            },
                            {
                                "content": "                \"HTTP/1.1 403 Cross Origin Websockets Disabled\\r\\n\\r\\n\"",
                                "type": "added"
                            },
                            {
                                "content": "            ))",
                                "type": "added"
                            },
                            {
                                "content": "            self.stream.close()",
                                "type": "added"
                            },
                            {
                                "content": "            return",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "        if self.request.headers.get(\"Sec-WebSocket-Version\") in (\"7\", \"8\", \"13\"):",
                                "type": "context"
                            },
                            {
                                "content": "            self.ws_connection = WebSocketProtocol13(self)",
                                "type": "context"
                            },
                            {
                                "content": "            self.ws_connection.accept_connection()",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "tornado/websocket.py",
                            "type": "class",
                            "name": "WebSocketHandler",
                            "content": "class WebSocketHandler(tornado.web.RequestHandler):\n    \"\"\"Subclass this class to create a basic WebSocket handler.\n\n    Override `on_message` to handle incoming messages, and use\n    `write_message` to send messages to the client. You can also\n    override `open` and `on_close` to handle opened and closed\n    connections.\n\n    See http://dev.w3.org/html5/websockets/ for details on the\n    JavaScript interface.  The protocol is specified at\n    http://tools.ietf.org/html/rfc6455.\n\n    Here is an example WebSocket handler that echos back all received messages\n    back to the client::\n\n      class EchoWebSocket(websocket.WebSocketHandler):\n          def open(self):\n              print \"WebSocket opened\"\n\n          def on_message(self, message):\n              self.write_message(u\"You said: \" + message)\n\n          def on_close(self):\n              print \"WebSocket closed\"\n\n    WebSockets are not standard HTTP connections. The \"handshake\" is\n    HTTP, but after the handshake, the protocol is\n    message-based. Consequently, most of the Tornado HTTP facilities\n    are not available in handlers of this type. The only communication\n    methods available to you are `write_message()`, `ping()`, and\n    `close()`. Likewise, your request handler class should implement\n    `open()` method rather than ``get()`` or ``post()``.\n\n    If you map the handler above to ``/websocket`` in your application, you can\n    invoke it in JavaScript with::\n\n      var ws = new WebSocket(\"ws://localhost:8888/websocket\");\n      ws.onopen = function() {\n         ws.send(\"Hello, world\");\n      };\n      ws.onmessage = function (evt) {\n         alert(evt.data);\n      };\n\n    This script pops up an alert box that says \"You said: Hello, world\".\n    \"\"\"\n    def __init__(self, application, request, **kwargs):\n        tornado.web.RequestHandler.__init__(self, application, request,\n                                            **kwargs)\n        self.ws_connection = None\n        self.close_code = None\n        self.close_reason = None\n\n    @tornado.web.asynchronous\n    def get(self, *args, **kwargs):\n        self.open_args = args\n        self.open_kwargs = kwargs\n\n        self.stream = self.request.connection.detach()\n\n        # Upgrade header should be present and should be equal to WebSocket\n        if self.request.headers.get(\"Upgrade\", \"\").lower() != 'websocket':\n            self.stream.write(tornado.escape.utf8(\n                \"HTTP/1.1 400 Bad Request\\r\\n\\r\\n\"\n                \"Can \\\"Upgrade\\\" only to \\\"WebSocket\\\".\"\n            ))\n            self.stream.close()\n            return\n\n        # Connection header should be upgrade. Some proxy servers/load balancers\n        # might mess with it.\n        headers = self.request.headers\n        connection = map(lambda s: s.strip().lower(), headers.get(\"Connection\", \"\").split(\",\"))\n        if 'upgrade' not in connection:\n            self.stream.write(tornado.escape.utf8(\n                \"HTTP/1.1 400 Bad Request\\r\\n\\r\\n\"\n                \"\\\"Connection\\\" must be \\\"Upgrade\\\".\"\n            ))\n            self.stream.close()\n            return\n\n        # Handle WebSocket Origin naming convention differences\n        # The difference between version 8 and 13 is that in 8 the\n        # client sends a \"Sec-Websocket-Origin\" header and in 13 it's\n        # simply \"Origin\".\n        if \"Origin\" in self.request.headers:\n            origin = self.request.headers.get(\"Origin\")\n        else:\n            origin = self.request.headers.get(\"Sec-Websocket-Origin\", None)\n\n        # If we have an origin, normalize\n        if(origin):\n            # Due to how stdlib's urlparse is implemented, urls without a //\n            # are interpreted to be paths (resulting in netloc being None)\n            if(\"//\" not in origin):\n                origin = \"//\" + origin\n            parsed_origin = urlparse(origin)\n            origin = parsed_origin.netloc\n            origin = origin.lower()\n\n        # If there was an origin header, check to make sure it matches\n        # according to check_origin\n        if not self.check_origin(origin):\n            self.stream.write(tornado.escape.utf8(\n                \"HTTP/1.1 403 Cross Origin Websockets Disabled\\r\\n\\r\\n\"\n            ))\n            self.stream.close()\n            return\n\n        if self.request.headers.get(\"Sec-WebSocket-Version\") in (\"7\", \"8\", \"13\"):\n            self.ws_connection = WebSocketProtocol13(self)\n            self.ws_connection.accept_connection()\n        elif (self.allow_draft76() and\n              \"Sec-WebSocket-Version\" not in self.request.headers):\n            self.ws_connection = WebSocketProtocol76(self)\n            self.ws_connection.accept_connection()\n        else:\n            self.stream.write(tornado.escape.utf8(\n                \"HTTP/1.1 426 Upgrade Required\\r\\n\"\n                \"Sec-WebSocket-Version: 8\\r\\n\\r\\n\"))\n            self.stream.close()\n\n\n    def write_message(self, message, binary=False):\n        \"\"\"Sends the given message to the client of this Web Socket.\n\n        The message may be either a string or a dict (which will be\n        encoded as json).  If the ``binary`` argument is false, the\n        message will be sent as utf8; in binary mode any byte string\n        is allowed.\n\n        If the connection is already closed, raises `WebSocketClosedError`.\n\n        .. versionchanged:: 3.2\n           `WebSocketClosedError` was added (previously a closed connection\n           would raise an `AttributeError`)\n        \"\"\"\n        if self.ws_connection is None:\n            raise WebSocketClosedError()\n        if isinstance(message, dict):\n            message = tornado.escape.json_encode(message)\n        self.ws_connection.write_message(message, binary=binary)\n\n    def select_subprotocol(self, subprotocols):\n        \"\"\"Invoked when a new WebSocket requests specific subprotocols.\n\n        ``subprotocols`` is a list of strings identifying the\n        subprotocols proposed by the client.  This method may be\n        overridden to return one of those strings to select it, or\n        ``None`` to not select a subprotocol.  Failure to select a\n        subprotocol does not automatically abort the connection,\n        although clients may close the connection if none of their\n        proposed subprotocols was selected.\n        \"\"\"\n        return None\n\n    def open(self):\n        \"\"\"Invoked when a new WebSocket is opened.\n\n        The arguments to `open` are extracted from the `tornado.web.URLSpec`\n        regular expression, just like the arguments to\n        `tornado.web.RequestHandler.get`.\n        \"\"\"\n        pass\n\n    def on_message(self, message):\n        \"\"\"Handle incoming messages on the WebSocket\n\n        This method must be overridden.\n        \"\"\"\n        raise NotImplementedError\n\n    def ping(self, data):\n        \"\"\"Send ping frame to the remote end.\"\"\"\n        if self.ws_connection is None:\n            raise WebSocketClosedError()\n        self.ws_connection.write_ping(data)\n\n    def on_pong(self, data):\n        \"\"\"Invoked when the response to a ping frame is received.\"\"\"\n        pass\n\n    def on_close(self):\n        \"\"\"Invoked when the WebSocket is closed.\n\n        If the connection was closed cleanly and a status code or reason\n        phrase was supplied, these values will be available as the attributes\n        ``self.close_code`` and ``self.close_reason``.\n\n        .. versionchanged:: 3.3\n\n           Added ``close_code`` and ``close_reason`` attributes.\n        \"\"\"\n        pass\n\n    def close(self, code=None, reason=None):\n        \"\"\"Closes this Web Socket.\n\n        Once the close handshake is successful the socket will be closed.\n\n        ``code`` may be a numeric status code, taken from the values\n        defined in `RFC 6455 section 7.4.1\n        <https://tools.ietf.org/html/rfc6455#section-7.4.1>`_.\n        ``reason`` may be a textual message about why the connection is\n        closing.  These values are made available to the client, but are\n        not otherwise interpreted by the websocket protocol.\n\n        The ``code`` and ``reason`` arguments are ignored in the \"draft76\"\n        protocol version.\n\n        .. versionchanged:: 3.3\n\n           Added the ``code`` and ``reason`` arguments.\n        \"\"\"\n        if self.ws_connection:\n            self.ws_connection.close(code, reason)\n            self.ws_connection = None\n\n    def check_origin(self, origin):\n        \"\"\"Override to enable support for allowing alternate origins.\n        \n        By default, this checks to see that the host matches the origin\n        provided.\n\n        This is a security protection against cross site scripting attacks on\n        browsers, since WebSockets don't have CORS headers.\n        \n        >>> self.check_origin(origin='localhost')\n        True\n        \n        \"\"\"\n        # When origin is None, assume it didn't come from a browser and we can\n        # pass it on\n        if origin is None:\n            return True\n\n        host = self.request.headers.get(\"Host\")\n\n        # Check to see that origin matches host directly, including ports\n        return origin == host\n\n    def allow_draft76(self):\n        \"\"\"Override to enable support for the older \"draft76\" protocol.\n\n        The draft76 version of the websocket protocol is disabled by\n        default due to security concerns, but it can be enabled by\n        overriding this method to return True.\n\n        Connections using the draft76 protocol do not support the\n        ``binary=True`` flag to `write_message`.\n\n        Support for the draft76 protocol is deprecated and will be\n        removed in a future version of Tornado.\n        \"\"\"\n        return False\n\n    def set_nodelay(self, value):\n        \"\"\"Set the no-delay flag for this stream.\n\n        By default, small messages may be delayed and/or combined to minimize\n        the number of packets sent.  This can sometimes cause 200-500ms delays\n        due to the interaction between Nagle's algorithm and TCP delayed\n        ACKs.  To reduce this delay (at the expense of possibly increasing\n        bandwidth usage), call ``self.set_nodelay(True)`` once the websocket\n        connection is established.\n\n        See `.BaseIOStream.set_nodelay` for additional details.\n\n        .. versionadded:: 3.1\n        \"\"\"\n        self.stream.set_nodelay(value)\n\n    def get_websocket_scheme(self):\n        \"\"\"Return the url scheme used for this request, either \"ws\" or \"wss\".\n\n        This is normally decided by HTTPServer, but applications\n        may wish to override this if they are using an SSL proxy\n        that does not provide the X-Scheme header as understood\n        by HTTPServer.\n\n        Note that this is only used by the draft76 protocol.\n        \"\"\"\n        return \"wss\" if self.request.protocol == \"https\" else \"ws\"\n\n    def async_callback(self, callback, *args, **kwargs):\n        \"\"\"Obsolete - catches exceptions from the wrapped function.\n\n        This function is normally unncecessary thanks to\n        `tornado.stack_context`.\n        \"\"\"\n        return self.ws_connection.async_callback(callback, *args, **kwargs)\n\n    def _not_supported(self, *args, **kwargs):\n        raise Exception(\"Method not supported for Web Sockets\")\n\n    def on_connection_close(self):\n        if self.ws_connection:\n            self.ws_connection.on_connection_close()\n            self.ws_connection = None\n            self.on_close()",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 67,
                            "end_lineno": 366,
                            "parent": null
                        },
                        {
                            "file_name": "tornado/websocket.py",
                            "type": "method",
                            "name": "WebSocketHandler.get",
                            "content": "class WebSocketHandler(tornado.web.RequestHandler):\n    \"\"\"Subclass this class to create a basic WebSocket handler.\n\n    Override `on_message` to handle incoming messages, and use\n    `write_message` to send messages to the client. You can also\n    override `open` and `on_close` to handle opened and closed\n    connections.\n\n    See http://dev.w3.org/html5/websockets/ for details on the\n    JavaScript interface.  The protocol is specified at\n    http://tools.ietf.org/html/rfc6455.\n\n    Here is an example WebSocket handler that echos back all received messages\n    back to the client::\n\n      class EchoWebSocket(websocket.WebSocketHandler):\n          def open(self):\n              print \"WebSocket opened\"\n\n          def on_message(self, message):\n              self.write_message(u\"You said: \" + message)\n\n          def on_close(self):\n              print \"WebSocket closed\"\n\n    WebSockets are not standard HTTP connections. The \"handshake\" is\n    HTTP, but after the handshake, the protocol is\n    message-based. Consequently, most of the Tornado HTTP facilities\n    are not available in handlers of this type. The only communication\n    methods available to you are `write_message()`, `ping()`, and\n    `close()`. Likewise, your request handler class should implement\n    `open()` method rather than ``get()`` or ``post()``.\n\n    If you map the handler above to ``/websocket`` in your application, you can\n    invoke it in JavaScript with::\n\n      var ws = new WebSocket(\"ws://localhost:8888/websocket\");\n      ws.onopen = function() {\n         ws.send(\"Hello, world\");\n      };\n      ws.onmessage = function (evt) {\n         alert(evt.data);\n      };\n\n    This script pops up an alert box that says \"You said: Hello, world\".\n    \"\"\"\n    def __init__(self, application, request, **kwargs):\n        tornado.web.RequestHandler.__init__(self, application, request,\n                                            **kwargs)\n        self.ws_connection = None\n        self.close_code = None\n        self.close_reason = None\n\n    @tornado.web.asynchronous\n    def get(self, *args, **kwargs):\n        self.open_args = args\n        self.open_kwargs = kwargs\n\n        self.stream = self.request.connection.detach()\n\n        # Upgrade header should be present and should be equal to WebSocket\n        if self.request.headers.get(\"Upgrade\", \"\").lower() != 'websocket':\n            self.stream.write(tornado.escape.utf8(\n                \"HTTP/1.1 400 Bad Request\\r\\n\\r\\n\"\n                \"Can \\\"Upgrade\\\" only to \\\"WebSocket\\\".\"\n            ))\n            self.stream.close()\n            return\n\n        # Connection header should be upgrade. Some proxy servers/load balancers\n        # might mess with it.\n        headers = self.request.headers\n        connection = map(lambda s: s.strip().lower(), headers.get(\"Connection\", \"\").split(\",\"))\n        if 'upgrade' not in connection:\n            self.stream.write(tornado.escape.utf8(\n                \"HTTP/1.1 400 Bad Request\\r\\n\\r\\n\"\n                \"\\\"Connection\\\" must be \\\"Upgrade\\\".\"\n            ))\n            self.stream.close()\n            return\n\n        # Handle WebSocket Origin naming convention differences\n        # The difference between version 8 and 13 is that in 8 the\n        # client sends a \"Sec-Websocket-Origin\" header and in 13 it's\n        # simply \"Origin\".\n        if \"Origin\" in self.request.headers:\n            origin = self.request.headers.get(\"Origin\")\n        else:\n            origin = self.request.headers.get(\"Sec-Websocket-Origin\", None)\n\n        # If we have an origin, normalize\n        if(origin):\n            # Due to how stdlib's urlparse is implemented, urls without a //\n            # are interpreted to be paths (resulting in netloc being None)\n            if(\"//\" not in origin):\n                origin = \"//\" + origin\n            parsed_origin = urlparse(origin)\n            origin = parsed_origin.netloc\n            origin = origin.lower()\n\n        # If there was an origin header, check to make sure it matches\n        # according to check_origin\n        if not self.check_origin(origin):\n            self.stream.write(tornado.escape.utf8(\n                \"HTTP/1.1 403 Cross Origin Websockets Disabled\\r\\n\\r\\n\"\n            ))\n            self.stream.close()\n            return\n\n        if self.request.headers.get(\"Sec-WebSocket-Version\") in (\"7\", \"8\", \"13\"):\n            self.ws_connection = WebSocketProtocol13(self)\n            self.ws_connection.accept_connection()\n        elif (self.allow_draft76() and\n              \"Sec-WebSocket-Version\" not in self.request.headers):\n            self.ws_connection = WebSocketProtocol76(self)\n            self.ws_connection.accept_connection()\n        else:\n            self.stream.write(tornado.escape.utf8(\n                \"HTTP/1.1 426 Upgrade Required\\r\\n\"\n                \"Sec-WebSocket-Version: 8\\r\\n\\r\\n\"))\n            self.stream.close()\n\n\n    def write_message(self, message, binary=False):\n        \"\"\"Sends the given message to the client of this Web Socket.\n\n        The message may be either a string or a dict (which will be\n        encoded as json).  If the ``binary`` argument is false, the\n        message will be sent as utf8; in binary mode any byte string\n        is allowed.\n\n        If the connection is already closed, raises `WebSocketClosedError`.\n\n        .. versionchanged:: 3.2\n           `WebSocketClosedError` was added (previously a closed connection\n           would raise an `AttributeError`)\n        \"\"\"\n        if self.ws_connection is None:\n            raise WebSocketClosedError()\n        if isinstance(message, dict):\n            message = tornado.escape.json_encode(message)\n        self.ws_connection.write_message(message, binary=binary)\n\n    def select_subprotocol(self, subprotocols):\n        \"\"\"Invoked when a new WebSocket requests specific subprotocols.\n\n        ``subprotocols`` is a list of strings identifying the\n        subprotocols proposed by the client.  This method may be\n        overridden to return one of those strings to select it, or\n        ``None`` to not select a subprotocol.  Failure to select a\n        subprotocol does not automatically abort the connection,\n        although clients may close the connection if none of their\n        proposed subprotocols was selected.\n        \"\"\"\n        return None\n\n    def open(self):\n        \"\"\"Invoked when a new WebSocket is opened.\n\n        The arguments to `open` are extracted from the `tornado.web.URLSpec`\n        regular expression, just like the arguments to\n        `tornado.web.RequestHandler.get`.\n        \"\"\"\n        pass\n\n    def on_message(self, message):\n        \"\"\"Handle incoming messages on the WebSocket\n\n        This method must be overridden.\n        \"\"\"\n        raise NotImplementedError\n\n    def ping(self, data):\n        \"\"\"Send ping frame to the remote end.\"\"\"\n        if self.ws_connection is None:\n            raise WebSocketClosedError()\n        self.ws_connection.write_ping(data)\n\n    def on_pong(self, data):\n        \"\"\"Invoked when the response to a ping frame is received.\"\"\"\n        pass\n\n    def on_close(self):\n        \"\"\"Invoked when the WebSocket is closed.\n\n        If the connection was closed cleanly and a status code or reason\n        phrase was supplied, these values will be available as the attributes\n        ``self.close_code`` and ``self.close_reason``.\n\n        .. versionchanged:: 3.3\n\n           Added ``close_code`` and ``close_reason`` attributes.\n        \"\"\"\n        pass\n\n    def close(self, code=None, reason=None):\n        \"\"\"Closes this Web Socket.\n\n        Once the close handshake is successful the socket will be closed.\n\n        ``code`` may be a numeric status code, taken from the values\n        defined in `RFC 6455 section 7.4.1\n        <https://tools.ietf.org/html/rfc6455#section-7.4.1>`_.\n        ``reason`` may be a textual message about why the connection is\n        closing.  These values are made available to the client, but are\n        not otherwise interpreted by the websocket protocol.\n\n        The ``code`` and ``reason`` arguments are ignored in the \"draft76\"\n        protocol version.\n\n        .. versionchanged:: 3.3\n\n           Added the ``code`` and ``reason`` arguments.\n        \"\"\"\n        if self.ws_connection:\n            self.ws_connection.close(code, reason)\n            self.ws_connection = None\n\n    def check_origin(self, origin):\n        \"\"\"Override to enable support for allowing alternate origins.\n        \n        By default, this checks to see that the host matches the origin\n        provided.\n\n        This is a security protection against cross site scripting attacks on\n        browsers, since WebSockets don't have CORS headers.\n        \n        >>> self.check_origin(origin='localhost')\n        True\n        \n        \"\"\"\n        # When origin is None, assume it didn't come from a browser and we can\n        # pass it on\n        if origin is None:\n            return True\n\n        host = self.request.headers.get(\"Host\")\n\n        # Check to see that origin matches host directly, including ports\n        return origin == host\n\n    def allow_draft76(self):\n        \"\"\"Override to enable support for the older \"draft76\" protocol.\n\n        The draft76 version of the websocket protocol is disabled by\n        default due to security concerns, but it can be enabled by\n        overriding this method to return True.\n\n        Connections using the draft76 protocol do not support the\n        ``binary=True`` flag to `write_message`.\n\n        Support for the draft76 protocol is deprecated and will be\n        removed in a future version of Tornado.\n        \"\"\"\n        return False\n\n    def set_nodelay(self, value):\n        \"\"\"Set the no-delay flag for this stream.\n\n        By default, small messages may be delayed and/or combined to minimize\n        the number of packets sent.  This can sometimes cause 200-500ms delays\n        due to the interaction between Nagle's algorithm and TCP delayed\n        ACKs.  To reduce this delay (at the expense of possibly increasing\n        bandwidth usage), call ``self.set_nodelay(True)`` once the websocket\n        connection is established.\n\n        See `.BaseIOStream.set_nodelay` for additional details.\n\n        .. versionadded:: 3.1\n        \"\"\"\n        self.stream.set_nodelay(value)\n\n    def get_websocket_scheme(self):\n        \"\"\"Return the url scheme used for this request, either \"ws\" or \"wss\".\n\n        This is normally decided by HTTPServer, but applications\n        may wish to override this if they are using an SSL proxy\n        that does not provide the X-Scheme header as understood\n        by HTTPServer.\n\n        Note that this is only used by the draft76 protocol.\n        \"\"\"\n        return \"wss\" if self.request.protocol == \"https\" else \"ws\"\n\n    def async_callback(self, callback, *args, **kwargs):\n        \"\"\"Obsolete - catches exceptions from the wrapped function.\n\n        This function is normally unncecessary thanks to\n        `tornado.stack_context`.\n        \"\"\"\n        return self.ws_connection.async_callback(callback, *args, **kwargs)\n\n    def _not_supported(self, *args, **kwargs):\n        raise Exception(\"Method not supported for Web Sockets\")\n\n    def on_connection_close(self):\n        if self.ws_connection:\n            self.ws_connection.on_connection_close()\n            self.ws_connection = None\n            self.on_close()",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 121,
                            "end_lineno": 187,
                            "parent": {
                                "file_name": "tornado/websocket.py",
                                "type": "class",
                                "name": "WebSocketHandler",
                                "content": "class WebSocketHandler(tornado.web.RequestHandler):\n    \"\"\"Subclass this class to create a basic WebSocket handler.\n\n    Override `on_message` to handle incoming messages, and use\n    `write_message` to send messages to the client. You can also\n    override `open` and `on_close` to handle opened and closed\n    connections.\n\n    See http://dev.w3.org/html5/websockets/ for details on the\n    JavaScript interface.  The protocol is specified at\n    http://tools.ietf.org/html/rfc6455.\n\n    Here is an example WebSocket handler that echos back all received messages\n    back to the client::\n\n      class EchoWebSocket(websocket.WebSocketHandler):\n          def open(self):\n              print \"WebSocket opened\"\n\n          def on_message(self, message):\n              self.write_message(u\"You said: \" + message)\n\n          def on_close(self):\n              print \"WebSocket closed\"\n\n    WebSockets are not standard HTTP connections. The \"handshake\" is\n    HTTP, but after the handshake, the protocol is\n    message-based. Consequently, most of the Tornado HTTP facilities\n    are not available in handlers of this type. The only communication\n    methods available to you are `write_message()`, `ping()`, and\n    `close()`. Likewise, your request handler class should implement\n    `open()` method rather than ``get()`` or ``post()``.\n\n    If you map the handler above to ``/websocket`` in your application, you can\n    invoke it in JavaScript with::\n\n      var ws = new WebSocket(\"ws://localhost:8888/websocket\");\n      ws.onopen = function() {\n         ws.send(\"Hello, world\");\n      };\n      ws.onmessage = function (evt) {\n         alert(evt.data);\n      };\n\n    This script pops up an alert box that says \"You said: Hello, world\".\n    \"\"\"\n    def __init__(self, application, request, **kwargs):\n        tornado.web.RequestHandler.__init__(self, application, request,\n                                            **kwargs)\n        self.ws_connection = None\n        self.close_code = None\n        self.close_reason = None\n\n    @tornado.web.asynchronous\n    def get(self, *args, **kwargs):\n        self.open_args = args\n        self.open_kwargs = kwargs\n\n        self.stream = self.request.connection.detach()\n\n        # Upgrade header should be present and should be equal to WebSocket\n        if self.request.headers.get(\"Upgrade\", \"\").lower() != 'websocket':\n            self.stream.write(tornado.escape.utf8(\n                \"HTTP/1.1 400 Bad Request\\r\\n\\r\\n\"\n                \"Can \\\"Upgrade\\\" only to \\\"WebSocket\\\".\"\n            ))\n            self.stream.close()\n            return\n\n        # Connection header should be upgrade. Some proxy servers/load balancers\n        # might mess with it.\n        headers = self.request.headers\n        connection = map(lambda s: s.strip().lower(), headers.get(\"Connection\", \"\").split(\",\"))\n        if 'upgrade' not in connection:\n            self.stream.write(tornado.escape.utf8(\n                \"HTTP/1.1 400 Bad Request\\r\\n\\r\\n\"\n                \"\\\"Connection\\\" must be \\\"Upgrade\\\".\"\n            ))\n            self.stream.close()\n            return\n\n        # Handle WebSocket Origin naming convention differences\n        # The difference between version 8 and 13 is that in 8 the\n        # client sends a \"Sec-Websocket-Origin\" header and in 13 it's\n        # simply \"Origin\".\n        if \"Origin\" in self.request.headers:\n            origin = self.request.headers.get(\"Origin\")\n        else:\n            origin = self.request.headers.get(\"Sec-Websocket-Origin\", None)\n\n        # If we have an origin, normalize\n        if(origin):\n            # Due to how stdlib's urlparse is implemented, urls without a //\n            # are interpreted to be paths (resulting in netloc being None)\n            if(\"//\" not in origin):\n                origin = \"//\" + origin\n            parsed_origin = urlparse(origin)\n            origin = parsed_origin.netloc\n            origin = origin.lower()\n\n        # If there was an origin header, check to make sure it matches\n        # according to check_origin\n        if not self.check_origin(origin):\n            self.stream.write(tornado.escape.utf8(\n                \"HTTP/1.1 403 Cross Origin Websockets Disabled\\r\\n\\r\\n\"\n            ))\n            self.stream.close()\n            return\n\n        if self.request.headers.get(\"Sec-WebSocket-Version\") in (\"7\", \"8\", \"13\"):\n            self.ws_connection = WebSocketProtocol13(self)\n            self.ws_connection.accept_connection()\n        elif (self.allow_draft76() and\n              \"Sec-WebSocket-Version\" not in self.request.headers):\n            self.ws_connection = WebSocketProtocol76(self)\n            self.ws_connection.accept_connection()\n        else:\n            self.stream.write(tornado.escape.utf8(\n                \"HTTP/1.1 426 Upgrade Required\\r\\n\"\n                \"Sec-WebSocket-Version: 8\\r\\n\\r\\n\"))\n            self.stream.close()\n\n\n    def write_message(self, message, binary=False):\n        \"\"\"Sends the given message to the client of this Web Socket.\n\n        The message may be either a string or a dict (which will be\n        encoded as json).  If the ``binary`` argument is false, the\n        message will be sent as utf8; in binary mode any byte string\n        is allowed.\n\n        If the connection is already closed, raises `WebSocketClosedError`.\n\n        .. versionchanged:: 3.2\n           `WebSocketClosedError` was added (previously a closed connection\n           would raise an `AttributeError`)\n        \"\"\"\n        if self.ws_connection is None:\n            raise WebSocketClosedError()\n        if isinstance(message, dict):\n            message = tornado.escape.json_encode(message)\n        self.ws_connection.write_message(message, binary=binary)\n\n    def select_subprotocol(self, subprotocols):\n        \"\"\"Invoked when a new WebSocket requests specific subprotocols.\n\n        ``subprotocols`` is a list of strings identifying the\n        subprotocols proposed by the client.  This method may be\n        overridden to return one of those strings to select it, or\n        ``None`` to not select a subprotocol.  Failure to select a\n        subprotocol does not automatically abort the connection,\n        although clients may close the connection if none of their\n        proposed subprotocols was selected.\n        \"\"\"\n        return None\n\n    def open(self):\n        \"\"\"Invoked when a new WebSocket is opened.\n\n        The arguments to `open` are extracted from the `tornado.web.URLSpec`\n        regular expression, just like the arguments to\n        `tornado.web.RequestHandler.get`.\n        \"\"\"\n        pass\n\n    def on_message(self, message):\n        \"\"\"Handle incoming messages on the WebSocket\n\n        This method must be overridden.\n        \"\"\"\n        raise NotImplementedError\n\n    def ping(self, data):\n        \"\"\"Send ping frame to the remote end.\"\"\"\n        if self.ws_connection is None:\n            raise WebSocketClosedError()\n        self.ws_connection.write_ping(data)\n\n    def on_pong(self, data):\n        \"\"\"Invoked when the response to a ping frame is received.\"\"\"\n        pass\n\n    def on_close(self):\n        \"\"\"Invoked when the WebSocket is closed.\n\n        If the connection was closed cleanly and a status code or reason\n        phrase was supplied, these values will be available as the attributes\n        ``self.close_code`` and ``self.close_reason``.\n\n        .. versionchanged:: 3.3\n\n           Added ``close_code`` and ``close_reason`` attributes.\n        \"\"\"\n        pass\n\n    def close(self, code=None, reason=None):\n        \"\"\"Closes this Web Socket.\n\n        Once the close handshake is successful the socket will be closed.\n\n        ``code`` may be a numeric status code, taken from the values\n        defined in `RFC 6455 section 7.4.1\n        <https://tools.ietf.org/html/rfc6455#section-7.4.1>`_.\n        ``reason`` may be a textual message about why the connection is\n        closing.  These values are made available to the client, but are\n        not otherwise interpreted by the websocket protocol.\n\n        The ``code`` and ``reason`` arguments are ignored in the \"draft76\"\n        protocol version.\n\n        .. versionchanged:: 3.3\n\n           Added the ``code`` and ``reason`` arguments.\n        \"\"\"\n        if self.ws_connection:\n            self.ws_connection.close(code, reason)\n            self.ws_connection = None\n\n    def check_origin(self, origin):\n        \"\"\"Override to enable support for allowing alternate origins.\n        \n        By default, this checks to see that the host matches the origin\n        provided.\n\n        This is a security protection against cross site scripting attacks on\n        browsers, since WebSockets don't have CORS headers.\n        \n        >>> self.check_origin(origin='localhost')\n        True\n        \n        \"\"\"\n        # When origin is None, assume it didn't come from a browser and we can\n        # pass it on\n        if origin is None:\n            return True\n\n        host = self.request.headers.get(\"Host\")\n\n        # Check to see that origin matches host directly, including ports\n        return origin == host\n\n    def allow_draft76(self):\n        \"\"\"Override to enable support for the older \"draft76\" protocol.\n\n        The draft76 version of the websocket protocol is disabled by\n        default due to security concerns, but it can be enabled by\n        overriding this method to return True.\n\n        Connections using the draft76 protocol do not support the\n        ``binary=True`` flag to `write_message`.\n\n        Support for the draft76 protocol is deprecated and will be\n        removed in a future version of Tornado.\n        \"\"\"\n        return False\n\n    def set_nodelay(self, value):\n        \"\"\"Set the no-delay flag for this stream.\n\n        By default, small messages may be delayed and/or combined to minimize\n        the number of packets sent.  This can sometimes cause 200-500ms delays\n        due to the interaction between Nagle's algorithm and TCP delayed\n        ACKs.  To reduce this delay (at the expense of possibly increasing\n        bandwidth usage), call ``self.set_nodelay(True)`` once the websocket\n        connection is established.\n\n        See `.BaseIOStream.set_nodelay` for additional details.\n\n        .. versionadded:: 3.1\n        \"\"\"\n        self.stream.set_nodelay(value)\n\n    def get_websocket_scheme(self):\n        \"\"\"Return the url scheme used for this request, either \"ws\" or \"wss\".\n\n        This is normally decided by HTTPServer, but applications\n        may wish to override this if they are using an SSL proxy\n        that does not provide the X-Scheme header as understood\n        by HTTPServer.\n\n        Note that this is only used by the draft76 protocol.\n        \"\"\"\n        return \"wss\" if self.request.protocol == \"https\" else \"ws\"\n\n    def async_callback(self, callback, *args, **kwargs):\n        \"\"\"Obsolete - catches exceptions from the wrapped function.\n\n        This function is normally unncecessary thanks to\n        `tornado.stack_context`.\n        \"\"\"\n        return self.ws_connection.async_callback(callback, *args, **kwargs)\n\n    def _not_supported(self, *args, **kwargs):\n        raise Exception(\"Method not supported for Web Sockets\")\n\n    def on_connection_close(self):\n        if self.ws_connection:\n            self.ws_connection.on_connection_close()\n            self.ws_connection = None\n            self.on_close()",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 67,
                                "end_lineno": 366,
                                "parent": null
                            }
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 161,
                            "length": 13
                        },
                        "new_range": {
                            "start": 186,
                            "length": 6
                        },
                        "section": "class WebSocketHandler(tornado.web.RequestHandler):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "                \"Sec-WebSocket-Version: 8\\r\\n\\r\\n\"))",
                                "type": "context"
                            },
                            {
                                "content": "            self.stream.close()",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "        if not self.check_origin():",
                                "type": "deleted"
                            },
                            {
                                "content": "            self.stream.write(tornado.escape.utf8(",
                                "type": "deleted"
                            },
                            {
                                "content": "                \"HTTP/1.1 403 Cross Origin Websockets Disabled\\r\\n\\r\\n\"",
                                "type": "deleted"
                            },
                            {
                                "content": "            ))",
                                "type": "deleted"
                            },
                            {
                                "content": "            self.stream.close()",
                                "type": "deleted"
                            },
                            {
                                "content": "",
                                "type": "deleted"
                            },
                            {
                                "content": "",
                                "type": "deleted"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    def write_message(self, message, binary=False):",
                                "type": "context"
                            },
                            {
                                "content": "        \"\"\"Sends the given message to the client of this Web Socket.",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "tornado/websocket.py",
                            "type": "class",
                            "name": "WebSocketHandler",
                            "content": "class WebSocketHandler(tornado.web.RequestHandler):\n    \"\"\"Subclass this class to create a basic WebSocket handler.\n\n    Override `on_message` to handle incoming messages, and use\n    `write_message` to send messages to the client. You can also\n    override `open` and `on_close` to handle opened and closed\n    connections.\n\n    See http://dev.w3.org/html5/websockets/ for details on the\n    JavaScript interface.  The protocol is specified at\n    http://tools.ietf.org/html/rfc6455.\n\n    Here is an example WebSocket handler that echos back all received messages\n    back to the client::\n\n      class EchoWebSocket(websocket.WebSocketHandler):\n          def open(self):\n              print \"WebSocket opened\"\n\n          def on_message(self, message):\n              self.write_message(u\"You said: \" + message)\n\n          def on_close(self):\n              print \"WebSocket closed\"\n\n    WebSockets are not standard HTTP connections. The \"handshake\" is\n    HTTP, but after the handshake, the protocol is\n    message-based. Consequently, most of the Tornado HTTP facilities\n    are not available in handlers of this type. The only communication\n    methods available to you are `write_message()`, `ping()`, and\n    `close()`. Likewise, your request handler class should implement\n    `open()` method rather than ``get()`` or ``post()``.\n\n    If you map the handler above to ``/websocket`` in your application, you can\n    invoke it in JavaScript with::\n\n      var ws = new WebSocket(\"ws://localhost:8888/websocket\");\n      ws.onopen = function() {\n         ws.send(\"Hello, world\");\n      };\n      ws.onmessage = function (evt) {\n         alert(evt.data);\n      };\n\n    This script pops up an alert box that says \"You said: Hello, world\".\n    \"\"\"\n    def __init__(self, application, request, **kwargs):\n        tornado.web.RequestHandler.__init__(self, application, request,\n                                            **kwargs)\n        self.ws_connection = None\n        self.close_code = None\n        self.close_reason = None\n\n    @tornado.web.asynchronous\n    def get(self, *args, **kwargs):\n        self.open_args = args\n        self.open_kwargs = kwargs\n\n        self.stream = self.request.connection.detach()\n\n        # Upgrade header should be present and should be equal to WebSocket\n        if self.request.headers.get(\"Upgrade\", \"\").lower() != 'websocket':\n            self.stream.write(tornado.escape.utf8(\n                \"HTTP/1.1 400 Bad Request\\r\\n\\r\\n\"\n                \"Can \\\"Upgrade\\\" only to \\\"WebSocket\\\".\"\n            ))\n            self.stream.close()\n            return\n\n        # Connection header should be upgrade. Some proxy servers/load balancers\n        # might mess with it.\n        headers = self.request.headers\n        connection = map(lambda s: s.strip().lower(), headers.get(\"Connection\", \"\").split(\",\"))\n        if 'upgrade' not in connection:\n            self.stream.write(tornado.escape.utf8(\n                \"HTTP/1.1 400 Bad Request\\r\\n\\r\\n\"\n                \"\\\"Connection\\\" must be \\\"Upgrade\\\".\"\n            ))\n            self.stream.close()\n            return\n\n        # The difference between version 8 and 13 is that in 8 the\n        # client sends a \"Sec-Websocket-Origin\" header and in 13 it's\n        # simply \"Origin\".\n        if self.request.headers.get(\"Sec-WebSocket-Version\") in (\"7\", \"8\", \"13\"):\n            self.ws_connection = WebSocketProtocol13(self)\n            self.ws_connection.accept_connection()\n        elif (self.allow_draft76() and\n              \"Sec-WebSocket-Version\" not in self.request.headers):\n            self.ws_connection = WebSocketProtocol76(self)\n            self.ws_connection.accept_connection()\n        else:\n            self.stream.write(tornado.escape.utf8(\n                \"HTTP/1.1 426 Upgrade Required\\r\\n\"\n                \"Sec-WebSocket-Version: 8\\r\\n\\r\\n\"))\n            self.stream.close()\n\n        if not self.check_origin():\n            self.stream.write(tornado.escape.utf8(\n                \"HTTP/1.1 403 Cross Origin Websockets Disabled\\r\\n\\r\\n\"\n            ))\n            self.stream.close()\n\n\n\n    def write_message(self, message, binary=False):\n        \"\"\"Sends the given message to the client of this Web Socket.\n\n        The message may be either a string or a dict (which will be\n        encoded as json).  If the ``binary`` argument is false, the\n        message will be sent as utf8; in binary mode any byte string\n        is allowed.\n\n        If the connection is already closed, raises `WebSocketClosedError`.\n\n        .. versionchanged:: 3.2\n           `WebSocketClosedError` was added (previously a closed connection\n           would raise an `AttributeError`)\n        \"\"\"\n        if self.ws_connection is None:\n            raise WebSocketClosedError()\n        if isinstance(message, dict):\n            message = tornado.escape.json_encode(message)\n        self.ws_connection.write_message(message, binary=binary)\n\n    def select_subprotocol(self, subprotocols):\n        \"\"\"Invoked when a new WebSocket requests specific subprotocols.\n\n        ``subprotocols`` is a list of strings identifying the\n        subprotocols proposed by the client.  This method may be\n        overridden to return one of those strings to select it, or\n        ``None`` to not select a subprotocol.  Failure to select a\n        subprotocol does not automatically abort the connection,\n        although clients may close the connection if none of their\n        proposed subprotocols was selected.\n        \"\"\"\n        return None\n\n    def open(self):\n        \"\"\"Invoked when a new WebSocket is opened.\n\n        The arguments to `open` are extracted from the `tornado.web.URLSpec`\n        regular expression, just like the arguments to\n        `tornado.web.RequestHandler.get`.\n        \"\"\"\n        pass\n\n    def on_message(self, message):\n        \"\"\"Handle incoming messages on the WebSocket\n\n        This method must be overridden.\n        \"\"\"\n        raise NotImplementedError\n\n    def ping(self, data):\n        \"\"\"Send ping frame to the remote end.\"\"\"\n        if self.ws_connection is None:\n            raise WebSocketClosedError()\n        self.ws_connection.write_ping(data)\n\n    def on_pong(self, data):\n        \"\"\"Invoked when the response to a ping frame is received.\"\"\"\n        pass\n\n    def on_close(self):\n        \"\"\"Invoked when the WebSocket is closed.\n\n        If the connection was closed cleanly and a status code or reason\n        phrase was supplied, these values will be available as the attributes\n        ``self.close_code`` and ``self.close_reason``.\n\n        .. versionchanged:: 3.3\n\n           Added ``close_code`` and ``close_reason`` attributes.\n        \"\"\"\n        pass\n\n    def close(self, code=None, reason=None):\n        \"\"\"Closes this Web Socket.\n\n        Once the close handshake is successful the socket will be closed.\n\n        ``code`` may be a numeric status code, taken from the values\n        defined in `RFC 6455 section 7.4.1\n        <https://tools.ietf.org/html/rfc6455#section-7.4.1>`_.\n        ``reason`` may be a textual message about why the connection is\n        closing.  These values are made available to the client, but are\n        not otherwise interpreted by the websocket protocol.\n\n        The ``code`` and ``reason`` arguments are ignored in the \"draft76\"\n        protocol version.\n\n        .. versionchanged:: 3.3\n\n           Added the ``code`` and ``reason`` arguments.\n        \"\"\"\n        if self.ws_connection:\n            self.ws_connection.close(code, reason)\n            self.ws_connection = None\n\n    def check_origin(self, allowed_origins=None):\n        \"\"\"Override to enable support for allowing alternate origins.\n        \n        By default, this checks to see that requests that provide both a host\n        origin have the same origin and host This is a security protection\n        against cross site scripting attacks on browsers,\n        since WebSockets don't have CORS headers.\n        \n        >>> self.check_origins(allowed_origins=['localhost'])\n        \n        \"\"\"\n        # Handle WebSocket Origin naming convention differences\n        # The difference between version 8 and 13 is that in 8 the\n        # client sends a \"Sec-Websocket-Origin\" header and in 13 it's\n        # simply \"Origin\".\n        if self.request.headers.get(\"Sec-WebSocket-Version\") in (\"7\", \"8\"):\n            origin_header = self.request.headers.get(\"Sec-Websocket-Origin\")\n        else:\n            origin_header = self.request.headers.get(\"Origin\")\n\n        host = self.request.headers.get(\"Host\")\n\n        # If no header is provided, assume request is not coming from a browser\n        if(origin_header is None or host is None):\n            return True\n\n        parsed_origin = urlparse(origin_header)\n        origin = parsed_origin.netloc\n\n        if allowed_origins and origin in allowed_origins:\n            return True\n\n        # Check to see that origin matches host directly, including ports\n        return origin == host\n\n    def allow_draft76(self):\n        \"\"\"Override to enable support for the older \"draft76\" protocol.\n\n        The draft76 version of the websocket protocol is disabled by\n        default due to security concerns, but it can be enabled by\n        overriding this method to return True.\n\n        Connections using the draft76 protocol do not support the\n        ``binary=True`` flag to `write_message`.\n\n        Support for the draft76 protocol is deprecated and will be\n        removed in a future version of Tornado.\n        \"\"\"\n        return False\n\n    def set_nodelay(self, value):\n        \"\"\"Set the no-delay flag for this stream.\n\n        By default, small messages may be delayed and/or combined to minimize\n        the number of packets sent.  This can sometimes cause 200-500ms delays\n        due to the interaction between Nagle's algorithm and TCP delayed\n        ACKs.  To reduce this delay (at the expense of possibly increasing\n        bandwidth usage), call ``self.set_nodelay(True)`` once the websocket\n        connection is established.\n\n        See `.BaseIOStream.set_nodelay` for additional details.\n\n        .. versionadded:: 3.1\n        \"\"\"\n        self.stream.set_nodelay(value)\n\n    def get_websocket_scheme(self):\n        \"\"\"Return the url scheme used for this request, either \"ws\" or \"wss\".\n\n        This is normally decided by HTTPServer, but applications\n        may wish to override this if they are using an SSL proxy\n        that does not provide the X-Scheme header as understood\n        by HTTPServer.\n\n        Note that this is only used by the draft76 protocol.\n        \"\"\"\n        return \"wss\" if self.request.protocol == \"https\" else \"ws\"\n\n    def async_callback(self, callback, *args, **kwargs):\n        \"\"\"Obsolete - catches exceptions from the wrapped function.\n\n        This function is normally unncecessary thanks to\n        `tornado.stack_context`.\n        \"\"\"\n        return self.ws_connection.async_callback(callback, *args, **kwargs)\n\n    def _not_supported(self, *args, **kwargs):\n        raise Exception(\"Method not supported for Web Sockets\")\n\n    def on_connection_close(self):\n        if self.ws_connection:\n            self.ws_connection.on_connection_close()\n            self.ws_connection = None\n            self.on_close()",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 67,
                            "end_lineno": 360,
                            "parent": null
                        },
                        {
                            "file_name": "tornado/websocket.py",
                            "type": "method",
                            "name": "WebSocketHandler.get",
                            "content": "class WebSocketHandler(tornado.web.RequestHandler):\n    \"\"\"Subclass this class to create a basic WebSocket handler.\n\n    Override `on_message` to handle incoming messages, and use\n    `write_message` to send messages to the client. You can also\n    override `open` and `on_close` to handle opened and closed\n    connections.\n\n    See http://dev.w3.org/html5/websockets/ for details on the\n    JavaScript interface.  The protocol is specified at\n    http://tools.ietf.org/html/rfc6455.\n\n    Here is an example WebSocket handler that echos back all received messages\n    back to the client::\n\n      class EchoWebSocket(websocket.WebSocketHandler):\n          def open(self):\n              print \"WebSocket opened\"\n\n          def on_message(self, message):\n              self.write_message(u\"You said: \" + message)\n\n          def on_close(self):\n              print \"WebSocket closed\"\n\n    WebSockets are not standard HTTP connections. The \"handshake\" is\n    HTTP, but after the handshake, the protocol is\n    message-based. Consequently, most of the Tornado HTTP facilities\n    are not available in handlers of this type. The only communication\n    methods available to you are `write_message()`, `ping()`, and\n    `close()`. Likewise, your request handler class should implement\n    `open()` method rather than ``get()`` or ``post()``.\n\n    If you map the handler above to ``/websocket`` in your application, you can\n    invoke it in JavaScript with::\n\n      var ws = new WebSocket(\"ws://localhost:8888/websocket\");\n      ws.onopen = function() {\n         ws.send(\"Hello, world\");\n      };\n      ws.onmessage = function (evt) {\n         alert(evt.data);\n      };\n\n    This script pops up an alert box that says \"You said: Hello, world\".\n    \"\"\"\n    def __init__(self, application, request, **kwargs):\n        tornado.web.RequestHandler.__init__(self, application, request,\n                                            **kwargs)\n        self.ws_connection = None\n        self.close_code = None\n        self.close_reason = None\n\n    @tornado.web.asynchronous\n    def get(self, *args, **kwargs):\n        self.open_args = args\n        self.open_kwargs = kwargs\n\n        self.stream = self.request.connection.detach()\n\n        # Upgrade header should be present and should be equal to WebSocket\n        if self.request.headers.get(\"Upgrade\", \"\").lower() != 'websocket':\n            self.stream.write(tornado.escape.utf8(\n                \"HTTP/1.1 400 Bad Request\\r\\n\\r\\n\"\n                \"Can \\\"Upgrade\\\" only to \\\"WebSocket\\\".\"\n            ))\n            self.stream.close()\n            return\n\n        # Connection header should be upgrade. Some proxy servers/load balancers\n        # might mess with it.\n        headers = self.request.headers\n        connection = map(lambda s: s.strip().lower(), headers.get(\"Connection\", \"\").split(\",\"))\n        if 'upgrade' not in connection:\n            self.stream.write(tornado.escape.utf8(\n                \"HTTP/1.1 400 Bad Request\\r\\n\\r\\n\"\n                \"\\\"Connection\\\" must be \\\"Upgrade\\\".\"\n            ))\n            self.stream.close()\n            return\n\n        # The difference between version 8 and 13 is that in 8 the\n        # client sends a \"Sec-Websocket-Origin\" header and in 13 it's\n        # simply \"Origin\".\n        if self.request.headers.get(\"Sec-WebSocket-Version\") in (\"7\", \"8\", \"13\"):\n            self.ws_connection = WebSocketProtocol13(self)\n            self.ws_connection.accept_connection()\n        elif (self.allow_draft76() and\n              \"Sec-WebSocket-Version\" not in self.request.headers):\n            self.ws_connection = WebSocketProtocol76(self)\n            self.ws_connection.accept_connection()\n        else:\n            self.stream.write(tornado.escape.utf8(\n                \"HTTP/1.1 426 Upgrade Required\\r\\n\"\n                \"Sec-WebSocket-Version: 8\\r\\n\\r\\n\"))\n            self.stream.close()\n\n        if not self.check_origin():\n            self.stream.write(tornado.escape.utf8(\n                \"HTTP/1.1 403 Cross Origin Websockets Disabled\\r\\n\\r\\n\"\n            ))\n            self.stream.close()\n\n\n\n    def write_message(self, message, binary=False):\n        \"\"\"Sends the given message to the client of this Web Socket.\n\n        The message may be either a string or a dict (which will be\n        encoded as json).  If the ``binary`` argument is false, the\n        message will be sent as utf8; in binary mode any byte string\n        is allowed.\n\n        If the connection is already closed, raises `WebSocketClosedError`.\n\n        .. versionchanged:: 3.2\n           `WebSocketClosedError` was added (previously a closed connection\n           would raise an `AttributeError`)\n        \"\"\"\n        if self.ws_connection is None:\n            raise WebSocketClosedError()\n        if isinstance(message, dict):\n            message = tornado.escape.json_encode(message)\n        self.ws_connection.write_message(message, binary=binary)\n\n    def select_subprotocol(self, subprotocols):\n        \"\"\"Invoked when a new WebSocket requests specific subprotocols.\n\n        ``subprotocols`` is a list of strings identifying the\n        subprotocols proposed by the client.  This method may be\n        overridden to return one of those strings to select it, or\n        ``None`` to not select a subprotocol.  Failure to select a\n        subprotocol does not automatically abort the connection,\n        although clients may close the connection if none of their\n        proposed subprotocols was selected.\n        \"\"\"\n        return None\n\n    def open(self):\n        \"\"\"Invoked when a new WebSocket is opened.\n\n        The arguments to `open` are extracted from the `tornado.web.URLSpec`\n        regular expression, just like the arguments to\n        `tornado.web.RequestHandler.get`.\n        \"\"\"\n        pass\n\n    def on_message(self, message):\n        \"\"\"Handle incoming messages on the WebSocket\n\n        This method must be overridden.\n        \"\"\"\n        raise NotImplementedError\n\n    def ping(self, data):\n        \"\"\"Send ping frame to the remote end.\"\"\"\n        if self.ws_connection is None:\n            raise WebSocketClosedError()\n        self.ws_connection.write_ping(data)\n\n    def on_pong(self, data):\n        \"\"\"Invoked when the response to a ping frame is received.\"\"\"\n        pass\n\n    def on_close(self):\n        \"\"\"Invoked when the WebSocket is closed.\n\n        If the connection was closed cleanly and a status code or reason\n        phrase was supplied, these values will be available as the attributes\n        ``self.close_code`` and ``self.close_reason``.\n\n        .. versionchanged:: 3.3\n\n           Added ``close_code`` and ``close_reason`` attributes.\n        \"\"\"\n        pass\n\n    def close(self, code=None, reason=None):\n        \"\"\"Closes this Web Socket.\n\n        Once the close handshake is successful the socket will be closed.\n\n        ``code`` may be a numeric status code, taken from the values\n        defined in `RFC 6455 section 7.4.1\n        <https://tools.ietf.org/html/rfc6455#section-7.4.1>`_.\n        ``reason`` may be a textual message about why the connection is\n        closing.  These values are made available to the client, but are\n        not otherwise interpreted by the websocket protocol.\n\n        The ``code`` and ``reason`` arguments are ignored in the \"draft76\"\n        protocol version.\n\n        .. versionchanged:: 3.3\n\n           Added the ``code`` and ``reason`` arguments.\n        \"\"\"\n        if self.ws_connection:\n            self.ws_connection.close(code, reason)\n            self.ws_connection = None\n\n    def check_origin(self, allowed_origins=None):\n        \"\"\"Override to enable support for allowing alternate origins.\n        \n        By default, this checks to see that requests that provide both a host\n        origin have the same origin and host This is a security protection\n        against cross site scripting attacks on browsers,\n        since WebSockets don't have CORS headers.\n        \n        >>> self.check_origins(allowed_origins=['localhost'])\n        \n        \"\"\"\n        # Handle WebSocket Origin naming convention differences\n        # The difference between version 8 and 13 is that in 8 the\n        # client sends a \"Sec-Websocket-Origin\" header and in 13 it's\n        # simply \"Origin\".\n        if self.request.headers.get(\"Sec-WebSocket-Version\") in (\"7\", \"8\"):\n            origin_header = self.request.headers.get(\"Sec-Websocket-Origin\")\n        else:\n            origin_header = self.request.headers.get(\"Origin\")\n\n        host = self.request.headers.get(\"Host\")\n\n        # If no header is provided, assume request is not coming from a browser\n        if(origin_header is None or host is None):\n            return True\n\n        parsed_origin = urlparse(origin_header)\n        origin = parsed_origin.netloc\n\n        if allowed_origins and origin in allowed_origins:\n            return True\n\n        # Check to see that origin matches host directly, including ports\n        return origin == host\n\n    def allow_draft76(self):\n        \"\"\"Override to enable support for the older \"draft76\" protocol.\n\n        The draft76 version of the websocket protocol is disabled by\n        default due to security concerns, but it can be enabled by\n        overriding this method to return True.\n\n        Connections using the draft76 protocol do not support the\n        ``binary=True`` flag to `write_message`.\n\n        Support for the draft76 protocol is deprecated and will be\n        removed in a future version of Tornado.\n        \"\"\"\n        return False\n\n    def set_nodelay(self, value):\n        \"\"\"Set the no-delay flag for this stream.\n\n        By default, small messages may be delayed and/or combined to minimize\n        the number of packets sent.  This can sometimes cause 200-500ms delays\n        due to the interaction between Nagle's algorithm and TCP delayed\n        ACKs.  To reduce this delay (at the expense of possibly increasing\n        bandwidth usage), call ``self.set_nodelay(True)`` once the websocket\n        connection is established.\n\n        See `.BaseIOStream.set_nodelay` for additional details.\n\n        .. versionadded:: 3.1\n        \"\"\"\n        self.stream.set_nodelay(value)\n\n    def get_websocket_scheme(self):\n        \"\"\"Return the url scheme used for this request, either \"ws\" or \"wss\".\n\n        This is normally decided by HTTPServer, but applications\n        may wish to override this if they are using an SSL proxy\n        that does not provide the X-Scheme header as understood\n        by HTTPServer.\n\n        Note that this is only used by the draft76 protocol.\n        \"\"\"\n        return \"wss\" if self.request.protocol == \"https\" else \"ws\"\n\n    def async_callback(self, callback, *args, **kwargs):\n        \"\"\"Obsolete - catches exceptions from the wrapped function.\n\n        This function is normally unncecessary thanks to\n        `tornado.stack_context`.\n        \"\"\"\n        return self.ws_connection.async_callback(callback, *args, **kwargs)\n\n    def _not_supported(self, *args, **kwargs):\n        raise Exception(\"Method not supported for Web Sockets\")\n\n    def on_connection_close(self):\n        if self.ws_connection:\n            self.ws_connection.on_connection_close()\n            self.ws_connection = None\n            self.on_close()",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 121,
                            "end_lineno": 168,
                            "parent": {
                                "file_name": "tornado/websocket.py",
                                "type": "class",
                                "name": "WebSocketHandler",
                                "content": "class WebSocketHandler(tornado.web.RequestHandler):\n    \"\"\"Subclass this class to create a basic WebSocket handler.\n\n    Override `on_message` to handle incoming messages, and use\n    `write_message` to send messages to the client. You can also\n    override `open` and `on_close` to handle opened and closed\n    connections.\n\n    See http://dev.w3.org/html5/websockets/ for details on the\n    JavaScript interface.  The protocol is specified at\n    http://tools.ietf.org/html/rfc6455.\n\n    Here is an example WebSocket handler that echos back all received messages\n    back to the client::\n\n      class EchoWebSocket(websocket.WebSocketHandler):\n          def open(self):\n              print \"WebSocket opened\"\n\n          def on_message(self, message):\n              self.write_message(u\"You said: \" + message)\n\n          def on_close(self):\n              print \"WebSocket closed\"\n\n    WebSockets are not standard HTTP connections. The \"handshake\" is\n    HTTP, but after the handshake, the protocol is\n    message-based. Consequently, most of the Tornado HTTP facilities\n    are not available in handlers of this type. The only communication\n    methods available to you are `write_message()`, `ping()`, and\n    `close()`. Likewise, your request handler class should implement\n    `open()` method rather than ``get()`` or ``post()``.\n\n    If you map the handler above to ``/websocket`` in your application, you can\n    invoke it in JavaScript with::\n\n      var ws = new WebSocket(\"ws://localhost:8888/websocket\");\n      ws.onopen = function() {\n         ws.send(\"Hello, world\");\n      };\n      ws.onmessage = function (evt) {\n         alert(evt.data);\n      };\n\n    This script pops up an alert box that says \"You said: Hello, world\".\n    \"\"\"\n    def __init__(self, application, request, **kwargs):\n        tornado.web.RequestHandler.__init__(self, application, request,\n                                            **kwargs)\n        self.ws_connection = None\n        self.close_code = None\n        self.close_reason = None\n\n    @tornado.web.asynchronous\n    def get(self, *args, **kwargs):\n        self.open_args = args\n        self.open_kwargs = kwargs\n\n        self.stream = self.request.connection.detach()\n\n        # Upgrade header should be present and should be equal to WebSocket\n        if self.request.headers.get(\"Upgrade\", \"\").lower() != 'websocket':\n            self.stream.write(tornado.escape.utf8(\n                \"HTTP/1.1 400 Bad Request\\r\\n\\r\\n\"\n                \"Can \\\"Upgrade\\\" only to \\\"WebSocket\\\".\"\n            ))\n            self.stream.close()\n            return\n\n        # Connection header should be upgrade. Some proxy servers/load balancers\n        # might mess with it.\n        headers = self.request.headers\n        connection = map(lambda s: s.strip().lower(), headers.get(\"Connection\", \"\").split(\",\"))\n        if 'upgrade' not in connection:\n            self.stream.write(tornado.escape.utf8(\n                \"HTTP/1.1 400 Bad Request\\r\\n\\r\\n\"\n                \"\\\"Connection\\\" must be \\\"Upgrade\\\".\"\n            ))\n            self.stream.close()\n            return\n\n        # The difference between version 8 and 13 is that in 8 the\n        # client sends a \"Sec-Websocket-Origin\" header and in 13 it's\n        # simply \"Origin\".\n        if self.request.headers.get(\"Sec-WebSocket-Version\") in (\"7\", \"8\", \"13\"):\n            self.ws_connection = WebSocketProtocol13(self)\n            self.ws_connection.accept_connection()\n        elif (self.allow_draft76() and\n              \"Sec-WebSocket-Version\" not in self.request.headers):\n            self.ws_connection = WebSocketProtocol76(self)\n            self.ws_connection.accept_connection()\n        else:\n            self.stream.write(tornado.escape.utf8(\n                \"HTTP/1.1 426 Upgrade Required\\r\\n\"\n                \"Sec-WebSocket-Version: 8\\r\\n\\r\\n\"))\n            self.stream.close()\n\n        if not self.check_origin():\n            self.stream.write(tornado.escape.utf8(\n                \"HTTP/1.1 403 Cross Origin Websockets Disabled\\r\\n\\r\\n\"\n            ))\n            self.stream.close()\n\n\n\n    def write_message(self, message, binary=False):\n        \"\"\"Sends the given message to the client of this Web Socket.\n\n        The message may be either a string or a dict (which will be\n        encoded as json).  If the ``binary`` argument is false, the\n        message will be sent as utf8; in binary mode any byte string\n        is allowed.\n\n        If the connection is already closed, raises `WebSocketClosedError`.\n\n        .. versionchanged:: 3.2\n           `WebSocketClosedError` was added (previously a closed connection\n           would raise an `AttributeError`)\n        \"\"\"\n        if self.ws_connection is None:\n            raise WebSocketClosedError()\n        if isinstance(message, dict):\n            message = tornado.escape.json_encode(message)\n        self.ws_connection.write_message(message, binary=binary)\n\n    def select_subprotocol(self, subprotocols):\n        \"\"\"Invoked when a new WebSocket requests specific subprotocols.\n\n        ``subprotocols`` is a list of strings identifying the\n        subprotocols proposed by the client.  This method may be\n        overridden to return one of those strings to select it, or\n        ``None`` to not select a subprotocol.  Failure to select a\n        subprotocol does not automatically abort the connection,\n        although clients may close the connection if none of their\n        proposed subprotocols was selected.\n        \"\"\"\n        return None\n\n    def open(self):\n        \"\"\"Invoked when a new WebSocket is opened.\n\n        The arguments to `open` are extracted from the `tornado.web.URLSpec`\n        regular expression, just like the arguments to\n        `tornado.web.RequestHandler.get`.\n        \"\"\"\n        pass\n\n    def on_message(self, message):\n        \"\"\"Handle incoming messages on the WebSocket\n\n        This method must be overridden.\n        \"\"\"\n        raise NotImplementedError\n\n    def ping(self, data):\n        \"\"\"Send ping frame to the remote end.\"\"\"\n        if self.ws_connection is None:\n            raise WebSocketClosedError()\n        self.ws_connection.write_ping(data)\n\n    def on_pong(self, data):\n        \"\"\"Invoked when the response to a ping frame is received.\"\"\"\n        pass\n\n    def on_close(self):\n        \"\"\"Invoked when the WebSocket is closed.\n\n        If the connection was closed cleanly and a status code or reason\n        phrase was supplied, these values will be available as the attributes\n        ``self.close_code`` and ``self.close_reason``.\n\n        .. versionchanged:: 3.3\n\n           Added ``close_code`` and ``close_reason`` attributes.\n        \"\"\"\n        pass\n\n    def close(self, code=None, reason=None):\n        \"\"\"Closes this Web Socket.\n\n        Once the close handshake is successful the socket will be closed.\n\n        ``code`` may be a numeric status code, taken from the values\n        defined in `RFC 6455 section 7.4.1\n        <https://tools.ietf.org/html/rfc6455#section-7.4.1>`_.\n        ``reason`` may be a textual message about why the connection is\n        closing.  These values are made available to the client, but are\n        not otherwise interpreted by the websocket protocol.\n\n        The ``code`` and ``reason`` arguments are ignored in the \"draft76\"\n        protocol version.\n\n        .. versionchanged:: 3.3\n\n           Added the ``code`` and ``reason`` arguments.\n        \"\"\"\n        if self.ws_connection:\n            self.ws_connection.close(code, reason)\n            self.ws_connection = None\n\n    def check_origin(self, allowed_origins=None):\n        \"\"\"Override to enable support for allowing alternate origins.\n        \n        By default, this checks to see that requests that provide both a host\n        origin have the same origin and host This is a security protection\n        against cross site scripting attacks on browsers,\n        since WebSockets don't have CORS headers.\n        \n        >>> self.check_origins(allowed_origins=['localhost'])\n        \n        \"\"\"\n        # Handle WebSocket Origin naming convention differences\n        # The difference between version 8 and 13 is that in 8 the\n        # client sends a \"Sec-Websocket-Origin\" header and in 13 it's\n        # simply \"Origin\".\n        if self.request.headers.get(\"Sec-WebSocket-Version\") in (\"7\", \"8\"):\n            origin_header = self.request.headers.get(\"Sec-Websocket-Origin\")\n        else:\n            origin_header = self.request.headers.get(\"Origin\")\n\n        host = self.request.headers.get(\"Host\")\n\n        # If no header is provided, assume request is not coming from a browser\n        if(origin_header is None or host is None):\n            return True\n\n        parsed_origin = urlparse(origin_header)\n        origin = parsed_origin.netloc\n\n        if allowed_origins and origin in allowed_origins:\n            return True\n\n        # Check to see that origin matches host directly, including ports\n        return origin == host\n\n    def allow_draft76(self):\n        \"\"\"Override to enable support for the older \"draft76\" protocol.\n\n        The draft76 version of the websocket protocol is disabled by\n        default due to security concerns, but it can be enabled by\n        overriding this method to return True.\n\n        Connections using the draft76 protocol do not support the\n        ``binary=True`` flag to `write_message`.\n\n        Support for the draft76 protocol is deprecated and will be\n        removed in a future version of Tornado.\n        \"\"\"\n        return False\n\n    def set_nodelay(self, value):\n        \"\"\"Set the no-delay flag for this stream.\n\n        By default, small messages may be delayed and/or combined to minimize\n        the number of packets sent.  This can sometimes cause 200-500ms delays\n        due to the interaction between Nagle's algorithm and TCP delayed\n        ACKs.  To reduce this delay (at the expense of possibly increasing\n        bandwidth usage), call ``self.set_nodelay(True)`` once the websocket\n        connection is established.\n\n        See `.BaseIOStream.set_nodelay` for additional details.\n\n        .. versionadded:: 3.1\n        \"\"\"\n        self.stream.set_nodelay(value)\n\n    def get_websocket_scheme(self):\n        \"\"\"Return the url scheme used for this request, either \"ws\" or \"wss\".\n\n        This is normally decided by HTTPServer, but applications\n        may wish to override this if they are using an SSL proxy\n        that does not provide the X-Scheme header as understood\n        by HTTPServer.\n\n        Note that this is only used by the draft76 protocol.\n        \"\"\"\n        return \"wss\" if self.request.protocol == \"https\" else \"ws\"\n\n    def async_callback(self, callback, *args, **kwargs):\n        \"\"\"Obsolete - catches exceptions from the wrapped function.\n\n        This function is normally unncecessary thanks to\n        `tornado.stack_context`.\n        \"\"\"\n        return self.ws_connection.async_callback(callback, *args, **kwargs)\n\n    def _not_supported(self, *args, **kwargs):\n        raise Exception(\"Method not supported for Web Sockets\")\n\n    def on_connection_close(self):\n        if self.ws_connection:\n            self.ws_connection.on_connection_close()\n            self.ws_connection = None\n            self.on_close()",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 67,
                                "end_lineno": 360,
                                "parent": null
                            }
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 264,
                            "length": 37
                        },
                        "new_range": {
                            "start": 282,
                            "length": 25
                        },
                        "section": "class WebSocketHandler(tornado.web.RequestHandler):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "            self.ws_connection.close(code, reason)",
                                "type": "context"
                            },
                            {
                                "content": "            self.ws_connection = None",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    def check_origin(self, allowed_origins=None):",
                                "type": "deleted"
                            },
                            {
                                "content": "    def check_origin(self, origin):",
                                "type": "added"
                            },
                            {
                                "content": "        \"\"\"Override to enable support for allowing alternate origins.",
                                "type": "context"
                            },
                            {
                                "content": "        ",
                                "type": "context"
                            },
                            {
                                "content": "        By default, this checks to see that requests that provide both a host",
                                "type": "deleted"
                            },
                            {
                                "content": "        origin have the same origin and host This is a security protection",
                                "type": "deleted"
                            },
                            {
                                "content": "        against cross site scripting attacks on browsers,",
                                "type": "deleted"
                            },
                            {
                                "content": "        since WebSockets don't have CORS headers.",
                                "type": "deleted"
                            },
                            {
                                "content": "        By default, this checks to see that the host matches the origin",
                                "type": "added"
                            },
                            {
                                "content": "        provided.",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "        This is a security protection against cross site scripting attacks on",
                                "type": "added"
                            },
                            {
                                "content": "        browsers, since WebSockets don't have CORS headers.",
                                "type": "added"
                            },
                            {
                                "content": "        ",
                                "type": "context"
                            },
                            {
                                "content": "        >>> self.check_origins(allowed_origins=['localhost'])",
                                "type": "deleted"
                            },
                            {
                                "content": "        >>> self.check_origin(origin='localhost')",
                                "type": "added"
                            },
                            {
                                "content": "        True",
                                "type": "added"
                            },
                            {
                                "content": "        ",
                                "type": "context"
                            },
                            {
                                "content": "        \"\"\"",
                                "type": "context"
                            },
                            {
                                "content": "        # Handle WebSocket Origin naming convention differences",
                                "type": "deleted"
                            },
                            {
                                "content": "        # The difference between version 8 and 13 is that in 8 the",
                                "type": "deleted"
                            },
                            {
                                "content": "        # client sends a \"Sec-Websocket-Origin\" header and in 13 it's",
                                "type": "deleted"
                            },
                            {
                                "content": "        # simply \"Origin\".",
                                "type": "deleted"
                            },
                            {
                                "content": "        if self.request.headers.get(\"Sec-WebSocket-Version\") in (\"7\", \"8\"):",
                                "type": "deleted"
                            },
                            {
                                "content": "            origin_header = self.request.headers.get(\"Sec-Websocket-Origin\")",
                                "type": "deleted"
                            },
                            {
                                "content": "        else:",
                                "type": "deleted"
                            },
                            {
                                "content": "            origin_header = self.request.headers.get(\"Origin\")",
                                "type": "deleted"
                            },
                            {
                                "content": "",
                                "type": "deleted"
                            },
                            {
                                "content": "        host = self.request.headers.get(\"Host\")",
                                "type": "deleted"
                            },
                            {
                                "content": "",
                                "type": "deleted"
                            },
                            {
                                "content": "        # If no header is provided, assume request is not coming from a browser",
                                "type": "deleted"
                            },
                            {
                                "content": "        if(origin_header is None or host is None):",
                                "type": "deleted"
                            },
                            {
                                "content": "        # When origin is None, assume it didn't come from a browser and we can",
                                "type": "added"
                            },
                            {
                                "content": "        # pass it on",
                                "type": "added"
                            },
                            {
                                "content": "        if origin is None:",
                                "type": "added"
                            },
                            {
                                "content": "            return True",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "        parsed_origin = urlparse(origin_header)",
                                "type": "deleted"
                            },
                            {
                                "content": "        origin = parsed_origin.netloc",
                                "type": "deleted"
                            },
                            {
                                "content": "",
                                "type": "deleted"
                            },
                            {
                                "content": "        if allowed_origins and origin in allowed_origins:",
                                "type": "deleted"
                            },
                            {
                                "content": "            return True",
                                "type": "deleted"
                            },
                            {
                                "content": "        host = self.request.headers.get(\"Host\")",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "        # Check to see that origin matches host directly, including ports",
                                "type": "context"
                            },
                            {
                                "content": "        return origin == host",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "tornado/websocket.py",
                            "type": "method",
                            "name": "WebSocketHandler.check_origin",
                            "content": "class WebSocketHandler(tornado.web.RequestHandler):\n    \"\"\"Subclass this class to create a basic WebSocket handler.\n\n    Override `on_message` to handle incoming messages, and use\n    `write_message` to send messages to the client. You can also\n    override `open` and `on_close` to handle opened and closed\n    connections.\n\n    See http://dev.w3.org/html5/websockets/ for details on the\n    JavaScript interface.  The protocol is specified at\n    http://tools.ietf.org/html/rfc6455.\n\n    Here is an example WebSocket handler that echos back all received messages\n    back to the client::\n\n      class EchoWebSocket(websocket.WebSocketHandler):\n          def open(self):\n              print \"WebSocket opened\"\n\n          def on_message(self, message):\n              self.write_message(u\"You said: \" + message)\n\n          def on_close(self):\n              print \"WebSocket closed\"\n\n    WebSockets are not standard HTTP connections. The \"handshake\" is\n    HTTP, but after the handshake, the protocol is\n    message-based. Consequently, most of the Tornado HTTP facilities\n    are not available in handlers of this type. The only communication\n    methods available to you are `write_message()`, `ping()`, and\n    `close()`. Likewise, your request handler class should implement\n    `open()` method rather than ``get()`` or ``post()``.\n\n    If you map the handler above to ``/websocket`` in your application, you can\n    invoke it in JavaScript with::\n\n      var ws = new WebSocket(\"ws://localhost:8888/websocket\");\n      ws.onopen = function() {\n         ws.send(\"Hello, world\");\n      };\n      ws.onmessage = function (evt) {\n         alert(evt.data);\n      };\n\n    This script pops up an alert box that says \"You said: Hello, world\".\n    \"\"\"\n    def __init__(self, application, request, **kwargs):\n        tornado.web.RequestHandler.__init__(self, application, request,\n                                            **kwargs)\n        self.ws_connection = None\n        self.close_code = None\n        self.close_reason = None\n\n    @tornado.web.asynchronous\n    def get(self, *args, **kwargs):\n        self.open_args = args\n        self.open_kwargs = kwargs\n\n        self.stream = self.request.connection.detach()\n\n        # Upgrade header should be present and should be equal to WebSocket\n        if self.request.headers.get(\"Upgrade\", \"\").lower() != 'websocket':\n            self.stream.write(tornado.escape.utf8(\n                \"HTTP/1.1 400 Bad Request\\r\\n\\r\\n\"\n                \"Can \\\"Upgrade\\\" only to \\\"WebSocket\\\".\"\n            ))\n            self.stream.close()\n            return\n\n        # Connection header should be upgrade. Some proxy servers/load balancers\n        # might mess with it.\n        headers = self.request.headers\n        connection = map(lambda s: s.strip().lower(), headers.get(\"Connection\", \"\").split(\",\"))\n        if 'upgrade' not in connection:\n            self.stream.write(tornado.escape.utf8(\n                \"HTTP/1.1 400 Bad Request\\r\\n\\r\\n\"\n                \"\\\"Connection\\\" must be \\\"Upgrade\\\".\"\n            ))\n            self.stream.close()\n            return\n\n        # The difference between version 8 and 13 is that in 8 the\n        # client sends a \"Sec-Websocket-Origin\" header and in 13 it's\n        # simply \"Origin\".\n        if self.request.headers.get(\"Sec-WebSocket-Version\") in (\"7\", \"8\", \"13\"):\n            self.ws_connection = WebSocketProtocol13(self)\n            self.ws_connection.accept_connection()\n        elif (self.allow_draft76() and\n              \"Sec-WebSocket-Version\" not in self.request.headers):\n            self.ws_connection = WebSocketProtocol76(self)\n            self.ws_connection.accept_connection()\n        else:\n            self.stream.write(tornado.escape.utf8(\n                \"HTTP/1.1 426 Upgrade Required\\r\\n\"\n                \"Sec-WebSocket-Version: 8\\r\\n\\r\\n\"))\n            self.stream.close()\n\n        if not self.check_origin():\n            self.stream.write(tornado.escape.utf8(\n                \"HTTP/1.1 403 Cross Origin Websockets Disabled\\r\\n\\r\\n\"\n            ))\n            self.stream.close()\n\n\n\n    def write_message(self, message, binary=False):\n        \"\"\"Sends the given message to the client of this Web Socket.\n\n        The message may be either a string or a dict (which will be\n        encoded as json).  If the ``binary`` argument is false, the\n        message will be sent as utf8; in binary mode any byte string\n        is allowed.\n\n        If the connection is already closed, raises `WebSocketClosedError`.\n\n        .. versionchanged:: 3.2\n           `WebSocketClosedError` was added (previously a closed connection\n           would raise an `AttributeError`)\n        \"\"\"\n        if self.ws_connection is None:\n            raise WebSocketClosedError()\n        if isinstance(message, dict):\n            message = tornado.escape.json_encode(message)\n        self.ws_connection.write_message(message, binary=binary)\n\n    def select_subprotocol(self, subprotocols):\n        \"\"\"Invoked when a new WebSocket requests specific subprotocols.\n\n        ``subprotocols`` is a list of strings identifying the\n        subprotocols proposed by the client.  This method may be\n        overridden to return one of those strings to select it, or\n        ``None`` to not select a subprotocol.  Failure to select a\n        subprotocol does not automatically abort the connection,\n        although clients may close the connection if none of their\n        proposed subprotocols was selected.\n        \"\"\"\n        return None\n\n    def open(self):\n        \"\"\"Invoked when a new WebSocket is opened.\n\n        The arguments to `open` are extracted from the `tornado.web.URLSpec`\n        regular expression, just like the arguments to\n        `tornado.web.RequestHandler.get`.\n        \"\"\"\n        pass\n\n    def on_message(self, message):\n        \"\"\"Handle incoming messages on the WebSocket\n\n        This method must be overridden.\n        \"\"\"\n        raise NotImplementedError\n\n    def ping(self, data):\n        \"\"\"Send ping frame to the remote end.\"\"\"\n        if self.ws_connection is None:\n            raise WebSocketClosedError()\n        self.ws_connection.write_ping(data)\n\n    def on_pong(self, data):\n        \"\"\"Invoked when the response to a ping frame is received.\"\"\"\n        pass\n\n    def on_close(self):\n        \"\"\"Invoked when the WebSocket is closed.\n\n        If the connection was closed cleanly and a status code or reason\n        phrase was supplied, these values will be available as the attributes\n        ``self.close_code`` and ``self.close_reason``.\n\n        .. versionchanged:: 3.3\n\n           Added ``close_code`` and ``close_reason`` attributes.\n        \"\"\"\n        pass\n\n    def close(self, code=None, reason=None):\n        \"\"\"Closes this Web Socket.\n\n        Once the close handshake is successful the socket will be closed.\n\n        ``code`` may be a numeric status code, taken from the values\n        defined in `RFC 6455 section 7.4.1\n        <https://tools.ietf.org/html/rfc6455#section-7.4.1>`_.\n        ``reason`` may be a textual message about why the connection is\n        closing.  These values are made available to the client, but are\n        not otherwise interpreted by the websocket protocol.\n\n        The ``code`` and ``reason`` arguments are ignored in the \"draft76\"\n        protocol version.\n\n        .. versionchanged:: 3.3\n\n           Added the ``code`` and ``reason`` arguments.\n        \"\"\"\n        if self.ws_connection:\n            self.ws_connection.close(code, reason)\n            self.ws_connection = None\n\n    def check_origin(self, allowed_origins=None):\n        \"\"\"Override to enable support for allowing alternate origins.\n        \n        By default, this checks to see that requests that provide both a host\n        origin have the same origin and host This is a security protection\n        against cross site scripting attacks on browsers,\n        since WebSockets don't have CORS headers.\n        \n        >>> self.check_origins(allowed_origins=['localhost'])\n        \n        \"\"\"\n        # Handle WebSocket Origin naming convention differences\n        # The difference between version 8 and 13 is that in 8 the\n        # client sends a \"Sec-Websocket-Origin\" header and in 13 it's\n        # simply \"Origin\".\n        if self.request.headers.get(\"Sec-WebSocket-Version\") in (\"7\", \"8\"):\n            origin_header = self.request.headers.get(\"Sec-Websocket-Origin\")\n        else:\n            origin_header = self.request.headers.get(\"Origin\")\n\n        host = self.request.headers.get(\"Host\")\n\n        # If no header is provided, assume request is not coming from a browser\n        if(origin_header is None or host is None):\n            return True\n\n        parsed_origin = urlparse(origin_header)\n        origin = parsed_origin.netloc\n\n        if allowed_origins and origin in allowed_origins:\n            return True\n\n        # Check to see that origin matches host directly, including ports\n        return origin == host\n\n    def allow_draft76(self):\n        \"\"\"Override to enable support for the older \"draft76\" protocol.\n\n        The draft76 version of the websocket protocol is disabled by\n        default due to security concerns, but it can be enabled by\n        overriding this method to return True.\n\n        Connections using the draft76 protocol do not support the\n        ``binary=True`` flag to `write_message`.\n\n        Support for the draft76 protocol is deprecated and will be\n        removed in a future version of Tornado.\n        \"\"\"\n        return False\n\n    def set_nodelay(self, value):\n        \"\"\"Set the no-delay flag for this stream.\n\n        By default, small messages may be delayed and/or combined to minimize\n        the number of packets sent.  This can sometimes cause 200-500ms delays\n        due to the interaction between Nagle's algorithm and TCP delayed\n        ACKs.  To reduce this delay (at the expense of possibly increasing\n        bandwidth usage), call ``self.set_nodelay(True)`` once the websocket\n        connection is established.\n\n        See `.BaseIOStream.set_nodelay` for additional details.\n\n        .. versionadded:: 3.1\n        \"\"\"\n        self.stream.set_nodelay(value)\n\n    def get_websocket_scheme(self):\n        \"\"\"Return the url scheme used for this request, either \"ws\" or \"wss\".\n\n        This is normally decided by HTTPServer, but applications\n        may wish to override this if they are using an SSL proxy\n        that does not provide the X-Scheme header as understood\n        by HTTPServer.\n\n        Note that this is only used by the draft76 protocol.\n        \"\"\"\n        return \"wss\" if self.request.protocol == \"https\" else \"ws\"\n\n    def async_callback(self, callback, *args, **kwargs):\n        \"\"\"Obsolete - catches exceptions from the wrapped function.\n\n        This function is normally unncecessary thanks to\n        `tornado.stack_context`.\n        \"\"\"\n        return self.ws_connection.async_callback(callback, *args, **kwargs)\n\n    def _not_supported(self, *args, **kwargs):\n        raise Exception(\"Method not supported for Web Sockets\")\n\n    def on_connection_close(self):\n        if self.ws_connection:\n            self.ws_connection.on_connection_close()\n            self.ws_connection = None\n            self.on_close()",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 267,
                            "end_lineno": 300,
                            "parent": {
                                "file_name": "tornado/websocket.py",
                                "type": "class",
                                "name": "WebSocketHandler",
                                "content": "class WebSocketHandler(tornado.web.RequestHandler):\n    \"\"\"Subclass this class to create a basic WebSocket handler.\n\n    Override `on_message` to handle incoming messages, and use\n    `write_message` to send messages to the client. You can also\n    override `open` and `on_close` to handle opened and closed\n    connections.\n\n    See http://dev.w3.org/html5/websockets/ for details on the\n    JavaScript interface.  The protocol is specified at\n    http://tools.ietf.org/html/rfc6455.\n\n    Here is an example WebSocket handler that echos back all received messages\n    back to the client::\n\n      class EchoWebSocket(websocket.WebSocketHandler):\n          def open(self):\n              print \"WebSocket opened\"\n\n          def on_message(self, message):\n              self.write_message(u\"You said: \" + message)\n\n          def on_close(self):\n              print \"WebSocket closed\"\n\n    WebSockets are not standard HTTP connections. The \"handshake\" is\n    HTTP, but after the handshake, the protocol is\n    message-based. Consequently, most of the Tornado HTTP facilities\n    are not available in handlers of this type. The only communication\n    methods available to you are `write_message()`, `ping()`, and\n    `close()`. Likewise, your request handler class should implement\n    `open()` method rather than ``get()`` or ``post()``.\n\n    If you map the handler above to ``/websocket`` in your application, you can\n    invoke it in JavaScript with::\n\n      var ws = new WebSocket(\"ws://localhost:8888/websocket\");\n      ws.onopen = function() {\n         ws.send(\"Hello, world\");\n      };\n      ws.onmessage = function (evt) {\n         alert(evt.data);\n      };\n\n    This script pops up an alert box that says \"You said: Hello, world\".\n    \"\"\"\n    def __init__(self, application, request, **kwargs):\n        tornado.web.RequestHandler.__init__(self, application, request,\n                                            **kwargs)\n        self.ws_connection = None\n        self.close_code = None\n        self.close_reason = None\n\n    @tornado.web.asynchronous\n    def get(self, *args, **kwargs):\n        self.open_args = args\n        self.open_kwargs = kwargs\n\n        self.stream = self.request.connection.detach()\n\n        # Upgrade header should be present and should be equal to WebSocket\n        if self.request.headers.get(\"Upgrade\", \"\").lower() != 'websocket':\n            self.stream.write(tornado.escape.utf8(\n                \"HTTP/1.1 400 Bad Request\\r\\n\\r\\n\"\n                \"Can \\\"Upgrade\\\" only to \\\"WebSocket\\\".\"\n            ))\n            self.stream.close()\n            return\n\n        # Connection header should be upgrade. Some proxy servers/load balancers\n        # might mess with it.\n        headers = self.request.headers\n        connection = map(lambda s: s.strip().lower(), headers.get(\"Connection\", \"\").split(\",\"))\n        if 'upgrade' not in connection:\n            self.stream.write(tornado.escape.utf8(\n                \"HTTP/1.1 400 Bad Request\\r\\n\\r\\n\"\n                \"\\\"Connection\\\" must be \\\"Upgrade\\\".\"\n            ))\n            self.stream.close()\n            return\n\n        # The difference between version 8 and 13 is that in 8 the\n        # client sends a \"Sec-Websocket-Origin\" header and in 13 it's\n        # simply \"Origin\".\n        if self.request.headers.get(\"Sec-WebSocket-Version\") in (\"7\", \"8\", \"13\"):\n            self.ws_connection = WebSocketProtocol13(self)\n            self.ws_connection.accept_connection()\n        elif (self.allow_draft76() and\n              \"Sec-WebSocket-Version\" not in self.request.headers):\n            self.ws_connection = WebSocketProtocol76(self)\n            self.ws_connection.accept_connection()\n        else:\n            self.stream.write(tornado.escape.utf8(\n                \"HTTP/1.1 426 Upgrade Required\\r\\n\"\n                \"Sec-WebSocket-Version: 8\\r\\n\\r\\n\"))\n            self.stream.close()\n\n        if not self.check_origin():\n            self.stream.write(tornado.escape.utf8(\n                \"HTTP/1.1 403 Cross Origin Websockets Disabled\\r\\n\\r\\n\"\n            ))\n            self.stream.close()\n\n\n\n    def write_message(self, message, binary=False):\n        \"\"\"Sends the given message to the client of this Web Socket.\n\n        The message may be either a string or a dict (which will be\n        encoded as json).  If the ``binary`` argument is false, the\n        message will be sent as utf8; in binary mode any byte string\n        is allowed.\n\n        If the connection is already closed, raises `WebSocketClosedError`.\n\n        .. versionchanged:: 3.2\n           `WebSocketClosedError` was added (previously a closed connection\n           would raise an `AttributeError`)\n        \"\"\"\n        if self.ws_connection is None:\n            raise WebSocketClosedError()\n        if isinstance(message, dict):\n            message = tornado.escape.json_encode(message)\n        self.ws_connection.write_message(message, binary=binary)\n\n    def select_subprotocol(self, subprotocols):\n        \"\"\"Invoked when a new WebSocket requests specific subprotocols.\n\n        ``subprotocols`` is a list of strings identifying the\n        subprotocols proposed by the client.  This method may be\n        overridden to return one of those strings to select it, or\n        ``None`` to not select a subprotocol.  Failure to select a\n        subprotocol does not automatically abort the connection,\n        although clients may close the connection if none of their\n        proposed subprotocols was selected.\n        \"\"\"\n        return None\n\n    def open(self):\n        \"\"\"Invoked when a new WebSocket is opened.\n\n        The arguments to `open` are extracted from the `tornado.web.URLSpec`\n        regular expression, just like the arguments to\n        `tornado.web.RequestHandler.get`.\n        \"\"\"\n        pass\n\n    def on_message(self, message):\n        \"\"\"Handle incoming messages on the WebSocket\n\n        This method must be overridden.\n        \"\"\"\n        raise NotImplementedError\n\n    def ping(self, data):\n        \"\"\"Send ping frame to the remote end.\"\"\"\n        if self.ws_connection is None:\n            raise WebSocketClosedError()\n        self.ws_connection.write_ping(data)\n\n    def on_pong(self, data):\n        \"\"\"Invoked when the response to a ping frame is received.\"\"\"\n        pass\n\n    def on_close(self):\n        \"\"\"Invoked when the WebSocket is closed.\n\n        If the connection was closed cleanly and a status code or reason\n        phrase was supplied, these values will be available as the attributes\n        ``self.close_code`` and ``self.close_reason``.\n\n        .. versionchanged:: 3.3\n\n           Added ``close_code`` and ``close_reason`` attributes.\n        \"\"\"\n        pass\n\n    def close(self, code=None, reason=None):\n        \"\"\"Closes this Web Socket.\n\n        Once the close handshake is successful the socket will be closed.\n\n        ``code`` may be a numeric status code, taken from the values\n        defined in `RFC 6455 section 7.4.1\n        <https://tools.ietf.org/html/rfc6455#section-7.4.1>`_.\n        ``reason`` may be a textual message about why the connection is\n        closing.  These values are made available to the client, but are\n        not otherwise interpreted by the websocket protocol.\n\n        The ``code`` and ``reason`` arguments are ignored in the \"draft76\"\n        protocol version.\n\n        .. versionchanged:: 3.3\n\n           Added the ``code`` and ``reason`` arguments.\n        \"\"\"\n        if self.ws_connection:\n            self.ws_connection.close(code, reason)\n            self.ws_connection = None\n\n    def check_origin(self, allowed_origins=None):\n        \"\"\"Override to enable support for allowing alternate origins.\n        \n        By default, this checks to see that requests that provide both a host\n        origin have the same origin and host This is a security protection\n        against cross site scripting attacks on browsers,\n        since WebSockets don't have CORS headers.\n        \n        >>> self.check_origins(allowed_origins=['localhost'])\n        \n        \"\"\"\n        # Handle WebSocket Origin naming convention differences\n        # The difference between version 8 and 13 is that in 8 the\n        # client sends a \"Sec-Websocket-Origin\" header and in 13 it's\n        # simply \"Origin\".\n        if self.request.headers.get(\"Sec-WebSocket-Version\") in (\"7\", \"8\"):\n            origin_header = self.request.headers.get(\"Sec-Websocket-Origin\")\n        else:\n            origin_header = self.request.headers.get(\"Origin\")\n\n        host = self.request.headers.get(\"Host\")\n\n        # If no header is provided, assume request is not coming from a browser\n        if(origin_header is None or host is None):\n            return True\n\n        parsed_origin = urlparse(origin_header)\n        origin = parsed_origin.netloc\n\n        if allowed_origins and origin in allowed_origins:\n            return True\n\n        # Check to see that origin matches host directly, including ports\n        return origin == host\n\n    def allow_draft76(self):\n        \"\"\"Override to enable support for the older \"draft76\" protocol.\n\n        The draft76 version of the websocket protocol is disabled by\n        default due to security concerns, but it can be enabled by\n        overriding this method to return True.\n\n        Connections using the draft76 protocol do not support the\n        ``binary=True`` flag to `write_message`.\n\n        Support for the draft76 protocol is deprecated and will be\n        removed in a future version of Tornado.\n        \"\"\"\n        return False\n\n    def set_nodelay(self, value):\n        \"\"\"Set the no-delay flag for this stream.\n\n        By default, small messages may be delayed and/or combined to minimize\n        the number of packets sent.  This can sometimes cause 200-500ms delays\n        due to the interaction between Nagle's algorithm and TCP delayed\n        ACKs.  To reduce this delay (at the expense of possibly increasing\n        bandwidth usage), call ``self.set_nodelay(True)`` once the websocket\n        connection is established.\n\n        See `.BaseIOStream.set_nodelay` for additional details.\n\n        .. versionadded:: 3.1\n        \"\"\"\n        self.stream.set_nodelay(value)\n\n    def get_websocket_scheme(self):\n        \"\"\"Return the url scheme used for this request, either \"ws\" or \"wss\".\n\n        This is normally decided by HTTPServer, but applications\n        may wish to override this if they are using an SSL proxy\n        that does not provide the X-Scheme header as understood\n        by HTTPServer.\n\n        Note that this is only used by the draft76 protocol.\n        \"\"\"\n        return \"wss\" if self.request.protocol == \"https\" else \"ws\"\n\n    def async_callback(self, callback, *args, **kwargs):\n        \"\"\"Obsolete - catches exceptions from the wrapped function.\n\n        This function is normally unncecessary thanks to\n        `tornado.stack_context`.\n        \"\"\"\n        return self.ws_connection.async_callback(callback, *args, **kwargs)\n\n    def _not_supported(self, *args, **kwargs):\n        raise Exception(\"Method not supported for Web Sockets\")\n\n    def on_connection_close(self):\n        if self.ws_connection:\n            self.ws_connection.on_connection_close()\n            self.ws_connection = None\n            self.on_close()",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 67,
                                "end_lineno": 360,
                                "parent": null
                            }
                        },
                        {
                            "file_name": "tornado/websocket.py",
                            "type": "class",
                            "name": "WebSocketHandler",
                            "content": "class WebSocketHandler(tornado.web.RequestHandler):\n    \"\"\"Subclass this class to create a basic WebSocket handler.\n\n    Override `on_message` to handle incoming messages, and use\n    `write_message` to send messages to the client. You can also\n    override `open` and `on_close` to handle opened and closed\n    connections.\n\n    See http://dev.w3.org/html5/websockets/ for details on the\n    JavaScript interface.  The protocol is specified at\n    http://tools.ietf.org/html/rfc6455.\n\n    Here is an example WebSocket handler that echos back all received messages\n    back to the client::\n\n      class EchoWebSocket(websocket.WebSocketHandler):\n          def open(self):\n              print \"WebSocket opened\"\n\n          def on_message(self, message):\n              self.write_message(u\"You said: \" + message)\n\n          def on_close(self):\n              print \"WebSocket closed\"\n\n    WebSockets are not standard HTTP connections. The \"handshake\" is\n    HTTP, but after the handshake, the protocol is\n    message-based. Consequently, most of the Tornado HTTP facilities\n    are not available in handlers of this type. The only communication\n    methods available to you are `write_message()`, `ping()`, and\n    `close()`. Likewise, your request handler class should implement\n    `open()` method rather than ``get()`` or ``post()``.\n\n    If you map the handler above to ``/websocket`` in your application, you can\n    invoke it in JavaScript with::\n\n      var ws = new WebSocket(\"ws://localhost:8888/websocket\");\n      ws.onopen = function() {\n         ws.send(\"Hello, world\");\n      };\n      ws.onmessage = function (evt) {\n         alert(evt.data);\n      };\n\n    This script pops up an alert box that says \"You said: Hello, world\".\n    \"\"\"\n    def __init__(self, application, request, **kwargs):\n        tornado.web.RequestHandler.__init__(self, application, request,\n                                            **kwargs)\n        self.ws_connection = None\n        self.close_code = None\n        self.close_reason = None\n\n    @tornado.web.asynchronous\n    def get(self, *args, **kwargs):\n        self.open_args = args\n        self.open_kwargs = kwargs\n\n        self.stream = self.request.connection.detach()\n\n        # Upgrade header should be present and should be equal to WebSocket\n        if self.request.headers.get(\"Upgrade\", \"\").lower() != 'websocket':\n            self.stream.write(tornado.escape.utf8(\n                \"HTTP/1.1 400 Bad Request\\r\\n\\r\\n\"\n                \"Can \\\"Upgrade\\\" only to \\\"WebSocket\\\".\"\n            ))\n            self.stream.close()\n            return\n\n        # Connection header should be upgrade. Some proxy servers/load balancers\n        # might mess with it.\n        headers = self.request.headers\n        connection = map(lambda s: s.strip().lower(), headers.get(\"Connection\", \"\").split(\",\"))\n        if 'upgrade' not in connection:\n            self.stream.write(tornado.escape.utf8(\n                \"HTTP/1.1 400 Bad Request\\r\\n\\r\\n\"\n                \"\\\"Connection\\\" must be \\\"Upgrade\\\".\"\n            ))\n            self.stream.close()\n            return\n\n        # The difference between version 8 and 13 is that in 8 the\n        # client sends a \"Sec-Websocket-Origin\" header and in 13 it's\n        # simply \"Origin\".\n        if self.request.headers.get(\"Sec-WebSocket-Version\") in (\"7\", \"8\", \"13\"):\n            self.ws_connection = WebSocketProtocol13(self)\n            self.ws_connection.accept_connection()\n        elif (self.allow_draft76() and\n              \"Sec-WebSocket-Version\" not in self.request.headers):\n            self.ws_connection = WebSocketProtocol76(self)\n            self.ws_connection.accept_connection()\n        else:\n            self.stream.write(tornado.escape.utf8(\n                \"HTTP/1.1 426 Upgrade Required\\r\\n\"\n                \"Sec-WebSocket-Version: 8\\r\\n\\r\\n\"))\n            self.stream.close()\n\n        if not self.check_origin():\n            self.stream.write(tornado.escape.utf8(\n                \"HTTP/1.1 403 Cross Origin Websockets Disabled\\r\\n\\r\\n\"\n            ))\n            self.stream.close()\n\n\n\n    def write_message(self, message, binary=False):\n        \"\"\"Sends the given message to the client of this Web Socket.\n\n        The message may be either a string or a dict (which will be\n        encoded as json).  If the ``binary`` argument is false, the\n        message will be sent as utf8; in binary mode any byte string\n        is allowed.\n\n        If the connection is already closed, raises `WebSocketClosedError`.\n\n        .. versionchanged:: 3.2\n           `WebSocketClosedError` was added (previously a closed connection\n           would raise an `AttributeError`)\n        \"\"\"\n        if self.ws_connection is None:\n            raise WebSocketClosedError()\n        if isinstance(message, dict):\n            message = tornado.escape.json_encode(message)\n        self.ws_connection.write_message(message, binary=binary)\n\n    def select_subprotocol(self, subprotocols):\n        \"\"\"Invoked when a new WebSocket requests specific subprotocols.\n\n        ``subprotocols`` is a list of strings identifying the\n        subprotocols proposed by the client.  This method may be\n        overridden to return one of those strings to select it, or\n        ``None`` to not select a subprotocol.  Failure to select a\n        subprotocol does not automatically abort the connection,\n        although clients may close the connection if none of their\n        proposed subprotocols was selected.\n        \"\"\"\n        return None\n\n    def open(self):\n        \"\"\"Invoked when a new WebSocket is opened.\n\n        The arguments to `open` are extracted from the `tornado.web.URLSpec`\n        regular expression, just like the arguments to\n        `tornado.web.RequestHandler.get`.\n        \"\"\"\n        pass\n\n    def on_message(self, message):\n        \"\"\"Handle incoming messages on the WebSocket\n\n        This method must be overridden.\n        \"\"\"\n        raise NotImplementedError\n\n    def ping(self, data):\n        \"\"\"Send ping frame to the remote end.\"\"\"\n        if self.ws_connection is None:\n            raise WebSocketClosedError()\n        self.ws_connection.write_ping(data)\n\n    def on_pong(self, data):\n        \"\"\"Invoked when the response to a ping frame is received.\"\"\"\n        pass\n\n    def on_close(self):\n        \"\"\"Invoked when the WebSocket is closed.\n\n        If the connection was closed cleanly and a status code or reason\n        phrase was supplied, these values will be available as the attributes\n        ``self.close_code`` and ``self.close_reason``.\n\n        .. versionchanged:: 3.3\n\n           Added ``close_code`` and ``close_reason`` attributes.\n        \"\"\"\n        pass\n\n    def close(self, code=None, reason=None):\n        \"\"\"Closes this Web Socket.\n\n        Once the close handshake is successful the socket will be closed.\n\n        ``code`` may be a numeric status code, taken from the values\n        defined in `RFC 6455 section 7.4.1\n        <https://tools.ietf.org/html/rfc6455#section-7.4.1>`_.\n        ``reason`` may be a textual message about why the connection is\n        closing.  These values are made available to the client, but are\n        not otherwise interpreted by the websocket protocol.\n\n        The ``code`` and ``reason`` arguments are ignored in the \"draft76\"\n        protocol version.\n\n        .. versionchanged:: 3.3\n\n           Added the ``code`` and ``reason`` arguments.\n        \"\"\"\n        if self.ws_connection:\n            self.ws_connection.close(code, reason)\n            self.ws_connection = None\n\n    def check_origin(self, allowed_origins=None):\n        \"\"\"Override to enable support for allowing alternate origins.\n        \n        By default, this checks to see that requests that provide both a host\n        origin have the same origin and host This is a security protection\n        against cross site scripting attacks on browsers,\n        since WebSockets don't have CORS headers.\n        \n        >>> self.check_origins(allowed_origins=['localhost'])\n        \n        \"\"\"\n        # Handle WebSocket Origin naming convention differences\n        # The difference between version 8 and 13 is that in 8 the\n        # client sends a \"Sec-Websocket-Origin\" header and in 13 it's\n        # simply \"Origin\".\n        if self.request.headers.get(\"Sec-WebSocket-Version\") in (\"7\", \"8\"):\n            origin_header = self.request.headers.get(\"Sec-Websocket-Origin\")\n        else:\n            origin_header = self.request.headers.get(\"Origin\")\n\n        host = self.request.headers.get(\"Host\")\n\n        # If no header is provided, assume request is not coming from a browser\n        if(origin_header is None or host is None):\n            return True\n\n        parsed_origin = urlparse(origin_header)\n        origin = parsed_origin.netloc\n\n        if allowed_origins and origin in allowed_origins:\n            return True\n\n        # Check to see that origin matches host directly, including ports\n        return origin == host\n\n    def allow_draft76(self):\n        \"\"\"Override to enable support for the older \"draft76\" protocol.\n\n        The draft76 version of the websocket protocol is disabled by\n        default due to security concerns, but it can be enabled by\n        overriding this method to return True.\n\n        Connections using the draft76 protocol do not support the\n        ``binary=True`` flag to `write_message`.\n\n        Support for the draft76 protocol is deprecated and will be\n        removed in a future version of Tornado.\n        \"\"\"\n        return False\n\n    def set_nodelay(self, value):\n        \"\"\"Set the no-delay flag for this stream.\n\n        By default, small messages may be delayed and/or combined to minimize\n        the number of packets sent.  This can sometimes cause 200-500ms delays\n        due to the interaction between Nagle's algorithm and TCP delayed\n        ACKs.  To reduce this delay (at the expense of possibly increasing\n        bandwidth usage), call ``self.set_nodelay(True)`` once the websocket\n        connection is established.\n\n        See `.BaseIOStream.set_nodelay` for additional details.\n\n        .. versionadded:: 3.1\n        \"\"\"\n        self.stream.set_nodelay(value)\n\n    def get_websocket_scheme(self):\n        \"\"\"Return the url scheme used for this request, either \"ws\" or \"wss\".\n\n        This is normally decided by HTTPServer, but applications\n        may wish to override this if they are using an SSL proxy\n        that does not provide the X-Scheme header as understood\n        by HTTPServer.\n\n        Note that this is only used by the draft76 protocol.\n        \"\"\"\n        return \"wss\" if self.request.protocol == \"https\" else \"ws\"\n\n    def async_callback(self, callback, *args, **kwargs):\n        \"\"\"Obsolete - catches exceptions from the wrapped function.\n\n        This function is normally unncecessary thanks to\n        `tornado.stack_context`.\n        \"\"\"\n        return self.ws_connection.async_callback(callback, *args, **kwargs)\n\n    def _not_supported(self, *args, **kwargs):\n        raise Exception(\"Method not supported for Web Sockets\")\n\n    def on_connection_close(self):\n        if self.ws_connection:\n            self.ws_connection.on_connection_close()\n            self.ws_connection = None\n            self.on_close()",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 67,
                            "end_lineno": 360,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                }
            ]
        }
    ],
    "old_commit_hash": "9963e737aaa1ff158897ef9f92c361894005e669^",
    "new_commit_hash": "9963e737aaa1ff158897ef9f92c361894005e669",
    "commit_message": "Modify origin handling & normalization. Add tests.",
    "commit_date": "2014-05-08T13:42:21-05:00",
    "metadata": {}
}
{
    "repo_name": "tornado",
    "new_commit_hash": "9963e737aaa1ff158897ef9f92c361894005e669",
    "test_file_codes": [
        "from __future__ import absolute_import, division, print_function, with_statement\n\nimport traceback\n\nfrom tornado.concurrent import Future\nfrom tornado.httpclient import HTTPError, HTTPRequest\nfrom tornado.log import gen_log\nfrom tornado.testing import AsyncHTTPTestCase, gen_test, bind_unused_port, ExpectLog\nfrom tornado.test.util import unittest, skipOnTravis\nfrom tornado.web import Application, RequestHandler\n\ntry:\n    import tornado.websocket\nexcept ImportError:\n    # The unittest module presents misleading errors on ImportError\n    # (it acts as if websocket_test could not be found, hiding the underlying\n    # error).  If we get an ImportError here (which could happen due to\n    # TORNADO_EXTENSION=1), print some extra information before failing.\n    traceback.print_exc()\n    raise\n\nfrom tornado.websocket import WebSocketHandler, websocket_connect, WebSocketError, _websocket_mask_python\n\ntry:\n    from tornado import speedups\nexcept ImportError:\n    speedups = None\n\n\nclass TestWebSocketHandler(WebSocketHandler):\n    \"\"\"Base class for testing handlers that exposes the on_close event.\n\n    This allows for deterministic cleanup of the associated socket.\n    \"\"\"\n    def initialize(self, close_future):\n        self.close_future = close_future\n\n    def on_close(self):\n        self.close_future.set_result((self.close_code, self.close_reason))\n\n\nclass EchoHandler(TestWebSocketHandler):\n    def on_message(self, message):\n        self.write_message(message, isinstance(message, bytes))\n\n\nclass HeaderHandler(TestWebSocketHandler):\n    def open(self):\n        self.write_message(self.request.headers.get('X-Test', ''))\n\n\nclass NonWebSocketHandler(RequestHandler):\n    def get(self):\n        self.write('ok')\n\n\nclass CloseReasonHandler(TestWebSocketHandler):\n    def open(self):\n        self.close(1001, \"goodbye\")\n\n\nclass WebSocketTest(AsyncHTTPTestCase):\n    def get_app(self):\n        self.close_future = Future()\n        return Application([\n            ('/echo', EchoHandler, dict(close_future=self.close_future)),\n            ('/non_ws', NonWebSocketHandler),\n            ('/header', HeaderHandler, dict(close_future=self.close_future)),\n            ('/close_reason', CloseReasonHandler,\n             dict(close_future=self.close_future)),\n        ])\n\n    @gen_test\n    def test_websocket_gen(self):\n        ws = yield websocket_connect(\n            'ws://localhost:%d/echo' % self.get_http_port(),\n            io_loop=self.io_loop)\n        ws.write_message('hello')\n        response = yield ws.read_message()\n        self.assertEqual(response, 'hello')\n        ws.close()\n        yield self.close_future\n\n    def test_websocket_callbacks(self):\n        websocket_connect(\n            'ws://localhost:%d/echo' % self.get_http_port(),\n            io_loop=self.io_loop, callback=self.stop)\n        ws = self.wait().result()\n        ws.write_message('hello')\n        ws.read_message(self.stop)\n        response = self.wait().result()\n        self.assertEqual(response, 'hello')\n        self.close_future.add_done_callback(lambda f: self.stop())\n        ws.close()\n        self.wait()\n\n    @gen_test\n    def test_websocket_http_fail(self):\n        with self.assertRaises(HTTPError) as cm:\n            yield websocket_connect(\n                'ws://localhost:%d/notfound' % self.get_http_port(),\n                io_loop=self.io_loop)\n        self.assertEqual(cm.exception.code, 404)\n\n    @gen_test\n    def test_websocket_http_success(self):\n        with self.assertRaises(WebSocketError):\n            yield websocket_connect(\n                'ws://localhost:%d/non_ws' % self.get_http_port(),\n                io_loop=self.io_loop)\n\n    @skipOnTravis\n    @gen_test\n    def test_websocket_network_timeout(self):\n        sock, port = bind_unused_port()\n        sock.close()\n        with self.assertRaises(HTTPError) as cm:\n            with ExpectLog(gen_log, \".*\"):\n                yield websocket_connect(\n                    'ws://localhost:%d/' % port,\n                    io_loop=self.io_loop,\n                    connect_timeout=0.01)\n        self.assertEqual(cm.exception.code, 599)\n\n    @gen_test\n    def test_websocket_network_fail(self):\n        sock, port = bind_unused_port()\n        sock.close()\n        with self.assertRaises(HTTPError) as cm:\n            with ExpectLog(gen_log, \".*\"):\n                yield websocket_connect(\n                    'ws://localhost:%d/' % port,\n                    io_loop=self.io_loop,\n                    connect_timeout=3600)\n        self.assertEqual(cm.exception.code, 599)\n\n    @gen_test\n    def test_websocket_close_buffered_data(self):\n        ws = yield websocket_connect(\n            'ws://localhost:%d/echo' % self.get_http_port())\n        ws.write_message('hello')\n        ws.write_message('world')\n        ws.stream.close()\n        yield self.close_future\n\n    @gen_test\n    def test_websocket_headers(self):\n        # Ensure that arbitrary headers can be passed through websocket_connect.\n        ws = yield websocket_connect(\n            HTTPRequest('ws://localhost:%d/header' % self.get_http_port(),\n                        headers={'X-Test': 'hello'}))\n        response = yield ws.read_message()\n        self.assertEqual(response, 'hello')\n        ws.close()\n        yield self.close_future\n\n    @gen_test\n    def test_server_close_reason(self):\n        ws = yield websocket_connect(\n            'ws://localhost:%d/close_reason' % self.get_http_port())\n        msg = yield ws.read_message()\n        # A message of None means the other side closed the connection.\n        self.assertIs(msg, None)\n        self.assertEqual(ws.close_code, 1001)\n        self.assertEqual(ws.close_reason, \"goodbye\")\n\n    @gen_test\n    def test_client_close_reason(self):\n        ws = yield websocket_connect(\n            'ws://localhost:%d/echo' % self.get_http_port())\n        ws.close(1001, 'goodbye')\n        code, reason = yield self.close_future\n        self.assertEqual(code, 1001)\n        self.assertEqual(reason, 'goodbye')\n\n    @gen_test\n    def test_check_origin_valid(self):\n        port = self.get_http_port()\n\n        url = 'ws://localhost:%d/echo' % port\n        headers = {'Origin': 'http://localhost:%d' % port}\n\n        ws = yield websocket_connect(HTTPRequest(url, headers=headers),\n            io_loop=self.io_loop)\n        ws.write_message('hello')\n        response = yield ws.read_message()\n        self.assertEqual(response, 'hello')\n        ws.close()\n        yield self.close_future\n\n    @gen_test\n    def test_check_origin_valid2(self):\n        port = self.get_http_port()\n\n        url = 'ws://localhost:%d/echo' % port\n        headers = {'Origin': 'localhost:%d' % port}\n\n        ws = yield websocket_connect(HTTPRequest(url, headers=headers),\n            io_loop=self.io_loop)\n        ws.write_message('hello')\n        response = yield ws.read_message()\n        self.assertEqual(response, 'hello')\n        ws.close()\n        yield self.close_future\n\n    @gen_test\n    def test_check_origin_invalid(self):\n        port = self.get_http_port()\n\n        url = 'ws://localhost:%d/echo' % port\n        # Host is localhost, which should not be accessible from some other\n        # domain\n        headers = {'Origin': 'http://somewhereelse.com'}\n\n        with self.assertRaises(HTTPError) as cm:\n            yield websocket_connect(HTTPRequest(url, headers=headers),\n                                    io_loop=self.io_loop)\n\n        self.assertEqual(cm.exception.code, 403)\n\n    @gen_test\n    def test_check_origin_invalid2(self):\n        port = self.get_http_port()\n\n        url = 'ws://localhost:%d/echo' % port\n        # subdomains should be invalid by default\n        headers = {'Origin': 'http://subtenant.somewhereelse.com',\n                   'Host': 'subtenant2.somewhereelse.com'}\n\n        with self.assertRaises(HTTPError) as cm:\n            yield websocket_connect(HTTPRequest(url, headers=headers),\n                                    io_loop=self.io_loop)\n\n        self.assertEqual(cm.exception.code, 403)\n\n\nclass MaskFunctionMixin(object):\n    # Subclasses should define self.mask(mask, data)\n    def test_mask(self):\n        self.assertEqual(self.mask(b'abcd', b''), b'')\n        self.assertEqual(self.mask(b'abcd', b'b'), b'\\x03')\n        self.assertEqual(self.mask(b'abcd', b'54321'), b'TVPVP')\n        self.assertEqual(self.mask(b'ZXCV', b'98765432'), b'c`t`olpd')\n        # Include test cases with \\x00 bytes (to ensure that the C\n        # extension isn't depending on null-terminated strings) and\n        # bytes with the high bit set (to smoke out signedness issues).\n        self.assertEqual(self.mask(b'\\x00\\x01\\x02\\x03',\n                                   b'\\xff\\xfb\\xfd\\xfc\\xfe\\xfa'),\n                         b'\\xff\\xfa\\xff\\xff\\xfe\\xfb')\n        self.assertEqual(self.mask(b'\\xff\\xfb\\xfd\\xfc',\n                                   b'\\x00\\x01\\x02\\x03\\x04\\x05'),\n                         b'\\xff\\xfa\\xff\\xff\\xfb\\xfe')\n\n\nclass PythonMaskFunctionTest(MaskFunctionMixin, unittest.TestCase):\n    def mask(self, mask, data):\n        return _websocket_mask_python(mask, data)\n\n\n@unittest.skipIf(speedups is None, \"tornado.speedups module not present\")\nclass CythonMaskFunctionTest(MaskFunctionMixin, unittest.TestCase):\n    def mask(self, mask, data):\n        return speedups.websocket_mask(mask, data)\n",
        "#!/usr/bin/env python\nimport unittest\nimport sys\nimport time\nimport traceback\nimport platform\nimport os\n\n\nclass PytestLikeResult(unittest.TestResult):\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self.start_time = None\n        # Store (test, outcome, info) for each test:\n        #   outcome ∈ { \"passed\", \"failed\", \"error\", \"skipped\" }\n        #   info can hold the exception or skip reason, etc.\n        self.results = []\n\n    def startTestRun(self):\n        \"\"\"Called once before all tests.\"\"\"\n        self.start_time = time.time()\n        # Print a header similar to pytest\n        print(\"=\" * 29 + \" test session starts \" + \"=\" * 29)\n        # You can customize the platform/versions/paths as you like:\n        print(\n            f\"platform {platform.system().lower()} -- Python {platform.python_version()}\"\n        )\n        print(f\"rootdir: {os.path.abspath(os.curdir)}\")\n\n    def stopTestRun(self):\n        \"\"\"Called once after all tests are done.\"\"\"\n        elapsed = time.time() - self.start_time\n        print()  # blank line after final dot\n\n        # Summarize\n        ntests = len(self.results)\n        print(f\"collected {ntests} items\")\n\n        # Show details of failures/errors\n        failures = [r for r in self.results if r[1] == \"failed\"]\n        errors = [r for r in self.results if r[1] == \"error\"]\n\n        if failures:\n            print(\"\\n\" + \"=\" * 35 + \" FAILURES \" + \"=\" * 35)\n            for test, outcome, err_info in failures:\n                test = test.split(\"::\")\n                if len(test) == 3:\n                    test = f\"{test[1]}.{test[2]}\"\n                else:\n                    test = f\"{test[1]}\"\n                print(f\"__________ {test} __________\")\n                self._print_traceback(err_info)\n        if errors:\n            print(\"\\n\" + \"=\" * 35 + \" ERRORS \" + \"=\" * 37)\n            for test, outcome, err_info in errors:\n                test = test.split(\"::\")\n                if len(test) == 3:\n                    test = f\"{test[1]}.{test[2]}\"\n                else:\n                    test = f\"{test[1]}\"\n                print(f\"__________ {test} __________\")\n                self._print_traceback(err_info)\n\n        # Optional short summary lines for passes/fails/skips\n        print(\"\\n==================== short test summary info ====================\")\n        for test, outcome, info in self.results:\n            if outcome in (\"passed\", \"failed\", \"error\", \"skipped\"):\n                print(f\"{outcome.upper()} {test}\")\n\n        # Final one-line summary: “1 failed, 1 errors, 10 passed in 2.04s”\n        passed_count = sum(1 for r in self.results if r[1] == \"passed\")\n        failed_count = len(failures)\n        error_count = len(errors)\n        skipped_count = sum(1 for r in self.results if r[1] == \"skipped\")\n\n        summary_bits = []\n        if failed_count:\n            summary_bits.append(f\"{failed_count} failed\")\n        if error_count:\n            summary_bits.append(f\"{error_count} error{'s' if error_count != 1 else ''}\")\n        if passed_count:\n            summary_bits.append(f\"{passed_count} passed\")\n        if skipped_count:\n            summary_bits.append(f\"{skipped_count} skipped\")\n\n        summary_str = \", \".join(summary_bits) if summary_bits else \"no tests run\"\n        print(\n            f\"=================== {summary_str} in {elapsed:.2f}s ===================\"\n        )\n\n    def startTest(self, test):\n        \"\"\"Called right before each test method.\"\"\"\n        super().startTest(test)\n        # Print a dot or some indicator\n        print(\".\", end=\"\", flush=True)\n\n    def addSuccess(self, test):\n        super().addSuccess(test)\n        self.results.append((self._test_id(test), \"passed\", None))\n\n    def addFailure(self, test, err):\n        super().addFailure(test, err)\n        self.results.append((self._test_id(test), \"failed\", err))\n\n    def addError(self, test, err):\n        super().addError(test, err)\n        self.results.append((self._test_id(test), \"error\", err))\n\n    def addSkip(self, test, reason):\n        super().addSkip(test, reason)\n        self.results.append((self._test_id(test), \"skipped\", reason))\n\n    def _print_traceback(self, err_info):\n        \"\"\"Helper to print the traceback like pytest does.\"\"\"\n        if isinstance(err_info, tuple) and len(err_info) == 3:\n            exc_type, exc_value, tb = err_info\n            traceback.print_exception(exc_type, exc_value, tb, file=sys.stdout)\n        else:\n            print(str(err_info))\n\n    def _test_id(self, test):\n        try:\n            return f\"{test.__class__.__module__}::{test.__class__.__name__}::{test._testMethodName}\"\n        except AttributeError:\n            # Fallback for _ErrorHolder objects\n            return f\"{test.__class__.__module__}::{test.__class__.__name__}\"\n\n\nclass PytestLikeRunner(unittest.TextTestRunner):\n    \"\"\"A custom TextTestRunner that uses the PytestLikeResult.\"\"\"\n\n    resultclass = PytestLikeResult\n\n    def run(self, test):\n        result = self._makeResult()\n        # Overriding run to ensure we call startTestRun/stopTestRun\n        result.startTestRun()\n        test(result)\n        result.stopTestRun()\n        return result\n\n    def tearDown(self):\n        # Reset signal handlers\n        from twisted.internet import reactor\n\n        reactor.removeAll()\n        reactor.stop()\n        super().tearDown()\n\n\ndef main():\n    loader = unittest.TestLoader()\n    suite = loader.discover(\".\", pattern=\"test_*.py\")  # discover tests in r2e_tests/\n    runner = PytestLikeRunner(verbosity=0)\n    result = runner.run(suite)\n    # Exit with code 0 if all tests passed/skipped, 1 if there were fails/errors\n    sys.exit(not result.wasSuccessful())\n\n\nif __name__ == \"__main__\":\n    main()\n"
    ],
    "test_file_names": [
        "test_1.py",
        "tornado_unittest_runner.py"
    ],
    "setup_res_code": 0,
    "setup_res_stdout": "",
    "setup_res_stderr": "Using CPython 3.9.21\nCreating virtual environment at: .venv\nActivate with: source .venv/bin/activate\nResolved 2 packages in 787ms\nPrepared 1 package in 1.11s\nInstalled 2 packages in 2ms\n + certifi==2024.12.14\n + tornado==3.3.dev1 (from file:///home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_9963e737aaa1ff158897ef9f92c361894005e669)\nResolved 29 packages in 17ms\nInstalled 29 packages in 217ms\n + attrs==24.3.0\n + automat==24.8.1\n + cachetools==5.5.0\n + cffi==1.17.1\n + chardet==5.2.0\n + colorama==0.4.6\n + constantly==23.10.4\n + distlib==0.3.9\n + exceptiongroup==1.2.2\n + filelock==3.16.1\n + hyperlink==21.0.0\n + idna==3.10\n + incremental==24.7.2\n + iniconfig==2.0.0\n + packaging==24.2\n + platformdirs==4.3.6\n + pluggy==1.5.0\n + pycares==4.5.0\n + pycparser==2.22\n + pycurl==7.45.4\n + pyproject-api==1.8.0\n + pytest==8.3.4\n + setuptools==75.6.0\n + tomli==2.2.1\n + tox==4.23.2\n + twisted==24.11.0\n + typing-extensions==4.12.2\n + virtualenv==20.28.0\n + zope-interface==7.2\n",
    "new_commit_res_code": 0,
    "new_commit_res_stdout": "============================= test session starts =============================\nplatform linux -- Python 3.9.21\nrootdir: /home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_9963e737aaa1ff158897ef9f92c361894005e669\n................\ncollected 16 items\n\n==================== short test summary info ====================\nPASSED r2e_tests.test_1::CythonMaskFunctionTest::test_mask\nPASSED r2e_tests.test_1::PythonMaskFunctionTest::test_mask\nPASSED r2e_tests.test_1::WebSocketTest::test_check_origin_invalid\nPASSED r2e_tests.test_1::WebSocketTest::test_check_origin_invalid2\nPASSED r2e_tests.test_1::WebSocketTest::test_check_origin_valid\nPASSED r2e_tests.test_1::WebSocketTest::test_check_origin_valid2\nPASSED r2e_tests.test_1::WebSocketTest::test_client_close_reason\nPASSED r2e_tests.test_1::WebSocketTest::test_server_close_reason\nPASSED r2e_tests.test_1::WebSocketTest::test_websocket_callbacks\nPASSED r2e_tests.test_1::WebSocketTest::test_websocket_close_buffered_data\nPASSED r2e_tests.test_1::WebSocketTest::test_websocket_gen\nPASSED r2e_tests.test_1::WebSocketTest::test_websocket_headers\nPASSED r2e_tests.test_1::WebSocketTest::test_websocket_http_fail\nPASSED r2e_tests.test_1::WebSocketTest::test_websocket_http_success\nPASSED r2e_tests.test_1::WebSocketTest::test_websocket_network_fail\nPASSED r2e_tests.test_1::WebSocketTest::test_websocket_network_timeout\n=================== 16 passed in 0.03s ===================\n",
    "new_commit_res_stderr": "WARNING:tornado.access:404 GET /notfound (127.0.0.1) 0.24ms\n",
    "old_commit_res_code": 1,
    "old_commit_res_stdout": "============================= test session starts =============================\nplatform linux -- Python 3.9.21\nrootdir: /home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_9963e737aaa1ff158897ef9f92c361894005e669\n................\ncollected 16 items\n\n=================================== FAILURES ===================================\n__________ WebSocketTest.test_check_origin_invalid __________\nTraceback (most recent call last):\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 59, in testPartExecutor\n    yield\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 592, in run\n    self._callTestMethod(testMethod)\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 550, in _callTestMethod\n    method()\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_9963e737aaa1ff158897ef9f92c361894005e669/tornado/testing.py\", line 118, in __call__\n    result = self.orig_method()\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_9963e737aaa1ff158897ef9f92c361894005e669/tornado/testing.py\", line 487, in post_coroutine\n    return self.io_loop.run_sync(\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_9963e737aaa1ff158897ef9f92c361894005e669/tornado/ioloop.py\", line 418, in run_sync\n    return future_cell[0].result()\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_9963e737aaa1ff158897ef9f92c361894005e669/tornado/concurrent.py\", line 109, in result\n    raise_exc_info(self._exc_info)\n  File \"<string>\", line 3, in raise_exc_info\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_9963e737aaa1ff158897ef9f92c361894005e669/tornado/gen.py\", line 587, in run\n    yielded = self.gen.send(value)\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_9963e737aaa1ff158897ef9f92c361894005e669/r2e_tests/test_1.py\", line 216, in test_check_origin_invalid\n    yield websocket_connect(HTTPRequest(url, headers=headers),\nAssertionError: HTTPError not raised\n__________ WebSocketTest.test_check_origin_invalid2 __________\nTraceback (most recent call last):\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 59, in testPartExecutor\n    yield\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 592, in run\n    self._callTestMethod(testMethod)\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 550, in _callTestMethod\n    method()\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_9963e737aaa1ff158897ef9f92c361894005e669/tornado/testing.py\", line 118, in __call__\n    result = self.orig_method()\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_9963e737aaa1ff158897ef9f92c361894005e669/tornado/testing.py\", line 487, in post_coroutine\n    return self.io_loop.run_sync(\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_9963e737aaa1ff158897ef9f92c361894005e669/tornado/ioloop.py\", line 418, in run_sync\n    return future_cell[0].result()\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_9963e737aaa1ff158897ef9f92c361894005e669/tornado/concurrent.py\", line 109, in result\n    raise_exc_info(self._exc_info)\n  File \"<string>\", line 3, in raise_exc_info\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_9963e737aaa1ff158897ef9f92c361894005e669/tornado/gen.py\", line 587, in run\n    yielded = self.gen.send(value)\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_9963e737aaa1ff158897ef9f92c361894005e669/r2e_tests/test_1.py\", line 231, in test_check_origin_invalid2\n    yield websocket_connect(HTTPRequest(url, headers=headers),\nAssertionError: HTTPError not raised\n__________ WebSocketTest.test_check_origin_valid2 __________\nTraceback (most recent call last):\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 59, in testPartExecutor\n    yield\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 592, in run\n    self._callTestMethod(testMethod)\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 550, in _callTestMethod\n    method()\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_9963e737aaa1ff158897ef9f92c361894005e669/tornado/testing.py\", line 118, in __call__\n    result = self.orig_method()\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_9963e737aaa1ff158897ef9f92c361894005e669/tornado/testing.py\", line 487, in post_coroutine\n    return self.io_loop.run_sync(\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_9963e737aaa1ff158897ef9f92c361894005e669/tornado/ioloop.py\", line 418, in run_sync\n    return future_cell[0].result()\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_9963e737aaa1ff158897ef9f92c361894005e669/tornado/concurrent.py\", line 109, in result\n    raise_exc_info(self._exc_info)\n  File \"<string>\", line 3, in raise_exc_info\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_9963e737aaa1ff158897ef9f92c361894005e669/tornado/gen.py\", line 587, in run\n    yielded = self.gen.send(value)\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_9963e737aaa1ff158897ef9f92c361894005e669/r2e_tests/test_1.py\", line 202, in test_check_origin_valid2\n    self.assertEqual(response, 'hello')\nAssertionError: None != 'hello'\n\n==================== short test summary info ====================\nPASSED r2e_tests.test_1::CythonMaskFunctionTest::test_mask\nPASSED r2e_tests.test_1::PythonMaskFunctionTest::test_mask\nFAILED r2e_tests.test_1::WebSocketTest::test_check_origin_invalid\nFAILED r2e_tests.test_1::WebSocketTest::test_check_origin_invalid2\nPASSED r2e_tests.test_1::WebSocketTest::test_check_origin_valid\nFAILED r2e_tests.test_1::WebSocketTest::test_check_origin_valid2\nPASSED r2e_tests.test_1::WebSocketTest::test_client_close_reason\nPASSED r2e_tests.test_1::WebSocketTest::test_server_close_reason\nPASSED r2e_tests.test_1::WebSocketTest::test_websocket_callbacks\nPASSED r2e_tests.test_1::WebSocketTest::test_websocket_close_buffered_data\nPASSED r2e_tests.test_1::WebSocketTest::test_websocket_gen\nPASSED r2e_tests.test_1::WebSocketTest::test_websocket_headers\nPASSED r2e_tests.test_1::WebSocketTest::test_websocket_http_fail\nPASSED r2e_tests.test_1::WebSocketTest::test_websocket_http_success\nPASSED r2e_tests.test_1::WebSocketTest::test_websocket_network_fail\nPASSED r2e_tests.test_1::WebSocketTest::test_websocket_network_timeout\n=================== 3 failed, 13 passed in 0.02s ===================\n",
    "old_commit_res_stderr": "WARNING:tornado.access:404 GET /notfound (127.0.0.1) 0.16ms\n"
}
tornado/test/websocket_test.py tornado/websocket.py
We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[ISSUE]
**Title:** WebSocketHandler Does Not Reject Connections with Invalid Origin Headers

**Description:**
When initiating a WebSocket connection with an invalid Origin header, the server is expected to reject the connection to prevent unauthorized cross-origin access. Currently, connections with invalid Origin headers are not properly rejected, allowing potential security vulnerabilities.

**Example:**
Attempting to connect with an Origin header set to `'http://somewhereelse.com'`:

```python
url = 'ws://localhost:port/echo'
headers = {'Origin': 'http://somewhereelse.com'}
ws = websocket_connect(HTTPRequest(url, headers=headers), io_loop=self.io_loop)
```

**Expected Behavior:**
The server should respond with a **403 Forbidden** error, rejecting the WebSocket connection due to the invalid Origin.

**Actual Behavior:**
No error is raised, and the connection is unexpectedly accepted, allowing cross-origin WebSocket access.
[/ISSUE]
--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.

--- BEGIN FILE ---
```
### tornado/websocket.py
"""Implementation of the WebSocket protocol.

`WebSockets <http://dev.w3.org/html5/websockets/>`_ allow for bidirectional
communication between the browser and server.

.. warning::

   The WebSocket protocol was recently finalized as `RFC 6455
   <http://tools.ietf.org/html/rfc6455>`_ and is not yet supported in
   all browsers.  Refer to http://caniuse.com/websockets for details
   on compatibility.  In addition, during development the protocol
   went through several incompatible versions, and some browsers only
   support older versions.  By default this module only supports the
   latest version of the protocol, but optional support for an older
   version (known as "draft 76" or "hixie-76") can be enabled by
   overriding `WebSocketHandler.allow_draft76` (see that method's
   documentation for caveats).
"""

from __future__ import absolute_import, division, print_function, with_statement
# Author: Jacob Kristhammar, 2010

import array
import base64
import collections
import functools
import hashlib
import os
import struct
import time
import tornado.escape
import tornado.web

from tornado.concurrent import TracebackFuture
from tornado.escape import utf8, native_str, to_unicode
from tornado import httpclient, httputil
from tornado.ioloop import IOLoop
from tornado.iostream import StreamClosedError
from tornado.log import gen_log, app_log
from tornado.netutil import Resolver
from tornado import simple_httpclient
from tornado.util import bytes_type, unicode_type

try:
    from urllib.parse import urlparse # py2
except ImportError:
    from urlparse import urlparse # py3

try:
    xrange  # py2
except NameError:
    xrange = range  # py3


class WebSocketError(Exception):
    pass


class WebSocketClosedError(WebSocketError):
    """Raised by operations on a closed connection.

    .. versionadded:: 3.2
    """
    pass


class WebSocketHandler(tornado.web.RequestHandler):
    """Subclass this class to create a basic WebSocket handler.

    Override `on_message` to handle incoming messages, and use
    `write_message` to send messages to the client. You can also
    override `open` and `on_close` to handle opened and closed
    connections.

    See http://dev.w3.org/html5/websockets/ for details on the
    JavaScript interface.  The protocol is specified at
    http://tools.ietf.org/html/rfc6455.

    Here is an example WebSocket handler that echos back all received messages
    back to the client::

      class EchoWebSocket(websocket.WebSocketHandler):
          def open(self):
              print "WebSocket opened"

          def on_message(self, message):
              self.write_message(u"You said: " + message)

          def on_close(self):
              print "WebSocket closed"

    WebSockets are not standard HTTP connections. The "handshake" is
    HTTP, but after the handshake, the protocol is
    message-based. Consequently, most of the Tornado HTTP facilities
    are not available in handlers of this type. The only communication
    methods available to you are `write_message()`, `ping()`, and
    `close()`. Likewise, your request handler class should implement
    `open()` method rather than ``get()`` or ``post()``.

    If you map the handler above to ``/websocket`` in your application, you can
    invoke it in JavaScript with::

      var ws = new WebSocket("ws://localhost:8888/websocket");
      ws.onopen = function() {
         ws.send("Hello, world");
      };
      ws.onmessage = function (evt) {
         alert(evt.data);
      };

    This script pops up an alert box that says "You said: Hello, world".
    """
    def __init__(self, application, request, **kwargs):
        tornado.web.RequestHandler.__init__(self, application, request,
                                            **kwargs)
        self.ws_connection = None
        self.close_code = None
        self.close_reason = None

    @tornado.web.asynchronous
    def get(self, *args, **kwargs):
        self.open_args = args
        self.open_kwargs = kwargs

        self.stream = self.request.connection.detach()

        # Upgrade header should be present and should be equal to WebSocket
        if self.request.headers.get("Upgrade", "").lower() != 'websocket':
            self.stream.write(tornado.escape.utf8(
                "HTTP/1.1 400 Bad Request\r\n\r\n"
                "Can \"Upgrade\" only to \"WebSocket\"."
            ))
            self.stream.close()
            return

        # Connection header should be upgrade. Some proxy servers/load balancers
        # might mess with it.
        headers = self.request.headers
        connection = map(lambda s: s.strip().lower(), headers.get("Connection", "").split(","))
        if 'upgrade' not in connection:
            self.stream.write(tornado.escape.utf8(
                "HTTP/1.1 400 Bad Request\r\n\r\n"
                "\"Connection\" must be \"Upgrade\"."
            ))
            self.stream.close()
            return

        # The difference between version 8 and 13 is that in 8 the
        # client sends a "Sec-Websocket-Origin" header and in 13 it's
        # simply "Origin".
        if self.request.headers.get("Sec-WebSocket-Version") in ("7", "8", "13"):
            self.ws_connection = WebSocketProtocol13(self)
            self.ws_connection.accept_connection()
        elif (self.allow_draft76() and
              "Sec-WebSocket-Version" not in self.request.headers):
            self.ws_connection = WebSocketProtocol76(self)
            self.ws_connection.accept_connection()
        else:
            self.stream.write(tornado.escape.utf8(
                "HTTP/1.1 426 Upgrade Required\r\n"
                "Sec-WebSocket-Version: 8\r\n\r\n"))
            self.stream.close()

        if not self.check_origin():
            self.stream.write(tornado.escape.utf8(
                "HTTP/1.1 403 Cross Origin Websockets Disabled\r\n\r\n"
            ))
            self.stream.close()



    def write_message(self, message, binary=False):
        """Sends the given message to the client of this Web Socket.

        The message may be either a string or a dict (which will be
        encoded as json).  If the ``binary`` argument is false, the
        message will be sent as utf8; in binary mode any byte string
        is allowed.

        If the connection is already closed, raises `WebSocketClosedError`.

        .. versionchanged:: 3.2
           `WebSocketClosedError` was added (previously a closed connection
           would raise an `AttributeError`)
        """
        if self.ws_connection is None:
            raise WebSocketClosedError()
        if isinstance(message, dict):
            message = tornado.escape.json_encode(message)
        self.ws_connection.write_message(message, binary=binary)

    def select_subprotocol(self, subprotocols):
        """Invoked when a new WebSocket requests specific subprotocols.

        ``subprotocols`` is a list of strings identifying the
        subprotocols proposed by the client.  This method may be
        overridden to return one of those strings to select it, or
        ``None`` to not select a subprotocol.  Failure to select a
        subprotocol does not automatically abort the connection,
        although clients may close the connection if none of their
        proposed subprotocols was selected.
        """
        return None

    def open(self):
        """Invoked when a new WebSocket is opened.

        The arguments to `open` are extracted from the `tornado.web.URLSpec`
        regular expression, just like the arguments to
        `tornado.web.RequestHandler.get`.
        """
        pass

    def on_message(self, message):
        """Handle incoming messages on the WebSocket

        This method must be overridden.
        """
        raise NotImplementedError

    def ping(self, data):
        """Send ping frame to the remote end."""
        if self.ws_connection is None:
            raise WebSocketClosedError()
        self.ws_connection.write_ping(data)

    def on_pong(self, data):
        """Invoked when the response to a ping frame is received."""
        pass

    def on_close(self):
        """Invoked when the WebSocket is closed.

        If the connection was closed cleanly and a status code or reason
        phrase was supplied, these values will be available as the attributes
        ``self.close_code`` and ``self.close_reason``.

        .. versionchanged:: 3.3

           Added ``close_code`` and ``close_reason`` attributes.
        """
        pass

    def close(self, code=None, reason=None):
        """Closes this Web Socket.

        Once the close handshake is successful the socket will be closed.

        ``code`` may be a numeric status code, taken from the values
        defined in `RFC 6455 section 7.4.1
        <https://tools.ietf.org/html/rfc6455#section-7.4.1>`_.
        ``reason`` may be a textual message about why the connection is
        closing.  These values are made available to the client, but are
        not otherwise interpreted by the websocket protocol.

        The ``code`` and ``reason`` arguments are ignored in the "draft76"
        protocol version.

        .. versionchanged:: 3.3

           Added the ``code`` and ``reason`` arguments.
        """
        if self.ws_connection:
            self.ws_connection.close(code, reason)
            self.ws_connection = None

    def check_origin(self, allowed_origins=None):
        """Override to enable support for allowing alternate origins.
        
        By default, this checks to see that requests that provide both a host
        origin have the same origin and host This is a security protection
        against cross site scripting attacks on browsers,
        since WebSockets don't have CORS headers.
        
        >>> self.check_origins(allowed_origins=['localhost'])
        
        """
        # Handle WebSocket Origin naming convention differences
        # The difference between version 8 and 13 is that in 8 the
        # client sends a "Sec-Websocket-Origin" header and in 13 it's
        # simply "Origin".
        if self.request.headers.get("Sec-WebSocket-Version") in ("7", "8"):
            origin_header = self.request.headers.get("Sec-Websocket-Origin")
        else:
            origin_header = self.request.headers.get("Origin")

        host = self.request.headers.get("Host")

        # If no header is provided, assume request is not coming from a browser
        if(origin_header is None or host is None):
            return True

        parsed_origin = urlparse(origin_header)
        origin = parsed_origin.netloc

        if allowed_origins and origin in allowed_origins:
            return True

        # Check to see that origin matches host directly, including ports
        return origin == host

    def allow_draft76(self):
        """Override to enable support for the older "draft76" protocol.

        The draft76 version of the websocket protocol is disabled by
        default due to security concerns, but it can be enabled by
        overriding this method to return True.

        Connections using the draft76 protocol do not support the
        ``binary=True`` flag to `write_message`.

        Support for the draft76 protocol is deprecated and will be
        removed in a future version of Tornado.
        """
        return False

    def set_nodelay(self, value):
        """Set the no-delay flag for this stream.

        By default, small messages may be delayed and/or combined to minimize
        the number of packets sent.  This can sometimes cause 200-500ms delays
        due to the interaction between Nagle's algorithm and TCP delayed
        ACKs.  To reduce this delay (at the expense of possibly increasing
        bandwidth usage), call ``self.set_nodelay(True)`` once the websocket
        connection is established.

        See `.BaseIOStream.set_nodelay` for additional details.

        .. versionadded:: 3.1
        """
        self.stream.set_nodelay(value)

    def get_websocket_scheme(self):
        """Return the url scheme used for this request, either "ws" or "wss".

        This is normally decided by HTTPServer, but applications
        may wish to override this if they are using an SSL proxy
        that does not provide the X-Scheme header as understood
        by HTTPServer.

        Note that this is only used by the draft76 protocol.
        """
        return "wss" if self.request.protocol == "https" else "ws"

    def async_callback(self, callback, *args, **kwargs):
        """Obsolete - catches exceptions from the wrapped function.

        This function is normally unncecessary thanks to
        `tornado.stack_context`.
        """
        return self.ws_connection.async_callback(callback, *args, **kwargs)

    def _not_supported(self, *args, **kwargs):
        raise Exception("Method not supported for Web Sockets")

    def on_connection_close(self):
        if self.ws_connection:
            self.ws_connection.on_connection_close()
            self.ws_connection = None
            self.on_close()


for method in ["write", "redirect", "set_header", "send_error", "set_cookie",
               "set_status", "flush", "finish"]:
    setattr(WebSocketHandler, method, WebSocketHandler._not_supported)


class WebSocketProtocol(object):
    """Base class for WebSocket protocol versions.
    """
    def __init__(self, handler):
        self.handler = handler
        self.request = handler.request
        self.stream = handler.stream
        self.client_terminated = False
        self.server_terminated = False

    def async_callback(self, callback, *args, **kwargs):
        """Wrap callbacks with this if they are used on asynchronous requests.

        Catches exceptions properly and closes this WebSocket if an exception
        is uncaught.
        """
        if args or kwargs:
            callback = functools.partial(callback, *args, **kwargs)

        def wrapper(*args, **kwargs):
            try:
                return callback(*args, **kwargs)
            except Exception:
                app_log.error("Uncaught exception in %s",
                              self.request.path, exc_info=True)
                self._abort()
        return wrapper

    def on_connection_close(self):
        self._abort()

    def _abort(self):
        """Instantly aborts the WebSocket connection by closing the socket"""
        self.client_terminated = True
        self.server_terminated = True
        self.stream.close()  # forcibly tear down the connection
        self.close()  # let the subclass cleanup


class WebSocketProtocol76(WebSocketProtocol):
    """Implementation of the WebSockets protocol, version hixie-76.

    This class provides basic functionality to process WebSockets requests as
    specified in
    http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76
    """
    def __init__(self, handler):
        WebSocketProtocol.__init__(self, handler)
        self.challenge = None
        self._waiting = None

    def accept_connection(self):
        try:
            self._handle_websocket_headers()
        except ValueError:
            gen_log.debug("Malformed WebSocket request received")
            self._abort()
            return

        scheme = self.handler.get_websocket_scheme()

        # draft76 only allows a single subprotocol
        subprotocol_header = ''
        subprotocol = self.request.headers.get("Sec-WebSocket-Protocol", None)
        if subprotocol:
            selected = self.handler.select_subprotocol([subprotocol])
            if selected:
                assert selected == subprotocol
                subprotocol_header = "Sec-WebSocket-Protocol: %s\r\n" % selected

        # Write the initial headers before attempting to read the challenge.
        # This is necessary when using proxies (such as HAProxy), which
        # need to see the Upgrade headers before passing through the
        # non-HTTP traffic that follows.
        self.stream.write(tornado.escape.utf8(
            "HTTP/1.1 101 WebSocket Protocol Handshake\r\n"
            "Upgrade: WebSocket\r\n"
            "Connection: Upgrade\r\n"
            "Server: TornadoServer/%(version)s\r\n"
            "Sec-WebSocket-Origin: %(origin)s\r\n"
            "Sec-WebSocket-Location: %(scheme)s://%(host)s%(uri)s\r\n"
            "%(subprotocol)s"
            "\r\n" % (dict(
                version=tornado.version,
                origin=self.request.headers["Origin"],
                scheme=scheme,
                host=self.request.host,
                uri=self.request.uri,
                subprotocol=subprotocol_header))))
        self.stream.read_bytes(8, self._handle_challenge)

    def challenge_response(self, challenge):
        """Generates the challenge response that's needed in the handshake

        The challenge parameter should be the raw bytes as sent from the
        client.
        """
        key_1 = self.request.headers.get("Sec-Websocket-Key1")
        key_2 = self.request.headers.get("Sec-Websocket-Key2")
        try:
            part_1 = self._calculate_part(key_1)
            part_2 = self._calculate_part(key_2)
        except ValueError:
            raise ValueError("Invalid Keys/Challenge")
        return self._generate_challenge_response(part_1, part_2, challenge)

    def _handle_challenge(self, challenge):
        try:
            challenge_response = self.challenge_response(challenge)
        except ValueError:
            gen_log.debug("Malformed key data in WebSocket request")
            self._abort()
            return
        self._write_response(challenge_response)

    def _write_response(self, challenge):
        self.stream.write(challenge)
        self.async_callback(self.handler.open)(*self.handler.open_args, **self.handler.open_kwargs)
        self._receive_message()

    def _handle_websocket_headers(self):
        """Verifies all invariant- and required headers

        If a header is missing or have an incorrect value ValueError will be
        raised
        """
        fields = ("Origin", "Host", "Sec-Websocket-Key1",
                  "Sec-Websocket-Key2")
        if not all(map(lambda f: self.request.headers.get(f), fields)):
            raise ValueError("Missing/Invalid WebSocket headers")

    def _calculate_part(self, key):
        """Processes the key headers and calculates their key value.

        Raises ValueError when feed invalid key."""
        # pyflakes complains about variable reuse if both of these lines use 'c'
        number = int(''.join(c for c in key if c.isdigit()))
        spaces = len([c2 for c2 in key if c2.isspace()])
        try:
            key_number = number // spaces
        except (ValueError, ZeroDivisionError):
            raise ValueError
        return struct.pack(">I", key_number)

    def _generate_challenge_response(self, part_1, part_2, part_3):
        m = hashlib.md5()
        m.update(part_1)
        m.update(part_2)
        m.update(part_3)
        return m.digest()

    def _receive_message(self):
        self.stream.read_bytes(1, self._on_frame_type)

    def _on_frame_type(self, byte):
        frame_type = ord(byte)
        if frame_type == 0x00:
            self.stream.read_until(b"\xff", self._on_end_delimiter)
        elif frame_type == 0xff:
            self.stream.read_bytes(1, self._on_length_indicator)
        else:
            self._abort()

    def _on_end_delimiter(self, frame):
        if not self.client_terminated:
            self.async_callback(self.handler.on_message)(
                frame[:-1].decode("utf-8", "replace"))
        if not self.client_terminated:
            self._receive_message()

    def _on_length_indicator(self, byte):
        if ord(byte) != 0x00:
            self._abort()
            return
        self.client_terminated = True
        self.close()

    def write_message(self, message, binary=False):
        """Sends the given message to the client of this Web Socket."""
        if binary:
            raise ValueError(
                "Binary messages not supported by this version of websockets")
        if isinstance(message, unicode_type):
            message = message.encode("utf-8")
        assert isinstance(message, bytes_type)
        self.stream.write(b"\x00" + message + b"\xff")

    def write_ping(self, data):
        """Send ping frame."""
        raise ValueError("Ping messages not supported by this version of websockets")

    def close(self, code=None, reason=None):
        """Closes the WebSocket connection."""
        if not self.server_terminated:
            if not self.stream.closed():
                self.stream.write("\xff\x00")
            self.server_terminated = True
        if self.client_terminated:
            if self._waiting is not None:
                self.stream.io_loop.remove_timeout(self._waiting)
            self._waiting = None
            self.stream.close()
        elif self._waiting is None:
            self._waiting = self.stream.io_loop.add_timeout(
                time.time() + 5, self._abort)


class WebSocketProtocol13(WebSocketProtocol):
    """Implementation of the WebSocket protocol from RFC 6455.

    This class supports versions 7 and 8 of the protocol in addition to the
    final version 13.
    """
    def __init__(self, handler, mask_outgoing=False):
        WebSocketProtocol.__init__(self, handler)
        self.mask_outgoing = mask_outgoing
        self._final_frame = False
        self._frame_opcode = None
        self._masked_frame = None
        self._frame_mask = None
        self._frame_length = None
        self._fragmented_message_buffer = None
        self._fragmented_message_opcode = None
        self._waiting = None

    def accept_connection(self):
        try:
            self._handle_websocket_headers()
            self._accept_connection()
        except ValueError:
            gen_log.debug("Malformed WebSocket request received", exc_info=True)
            self._abort()
            return

    def _handle_websocket_headers(self):
        """Verifies all invariant- and required headers

        If a header is missing or have an incorrect value ValueError will be
        raised
        """
        fields = ("Host", "Sec-Websocket-Key", "Sec-Websocket-Version")
        if not all(map(lambda f: self.request.headers.get(f), fields)):
            raise ValueError("Missing/Invalid WebSocket headers")

    @staticmethod
    def compute_accept_value(key):
        """Computes the value for the Sec-WebSocket-Accept header,
        given the value for Sec-WebSocket-Key.
        """
        sha1 = hashlib.sha1()
        sha1.update(utf8(key))
        sha1.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11")  # Magic value
        return native_str(base64.b64encode(sha1.digest()))

    def _challenge_response(self):
        return WebSocketProtocol13.compute_accept_value(
            self.request.headers.get("Sec-Websocket-Key"))

    def _accept_connection(self):
        subprotocol_header = ''
        subprotocols = self.request.headers.get("Sec-WebSocket-Protocol", '')
        subprotocols = [s.strip() for s in subprotocols.split(',')]
        if subprotocols:
            selected = self.handler.select_subprotocol(subprotocols)
            if selected:
                assert selected in subprotocols
                subprotocol_header = "Sec-WebSocket-Protocol: %s\r\n" % selected

        self.stream.write(tornado.escape.utf8(
            "HTTP/1.1 101 Switching Protocols\r\n"
            "Upgrade: websocket\r\n"
            "Connection: Upgrade\r\n"
            "Sec-WebSocket-Accept: %s\r\n"
            "%s"
            "\r\n" % (self._challenge_response(), subprotocol_header)))

        self.async_callback(self.handler.open)(*self.handler.open_args, **self.handler.open_kwargs)
        self._receive_frame()

    def _write_frame(self, fin, opcode, data):
        if fin:
            finbit = 0x80
        else:
            finbit = 0
        frame = struct.pack("B", finbit | opcode)
        l = len(data)
        if self.mask_outgoing:
            mask_bit = 0x80
        else:
            mask_bit = 0
        if l < 126:
            frame += struct.pack("B", l | mask_bit)
        elif l <= 0xFFFF:
            frame += struct.pack("!BH", 126 | mask_bit, l)
        else:
            frame += struct.pack("!BQ", 127 | mask_bit, l)
        if self.mask_outgoing:
            mask = os.urandom(4)
            data = mask + _websocket_mask(mask, data)
        frame += data
        self.stream.write(frame)

    def write_message(self, message, binary=False):
        """Sends the given message to the client of this Web Socket."""
        if binary:
            opcode = 0x2
        else:
            opcode = 0x1
        message = tornado.escape.utf8(message)
        assert isinstance(message, bytes_type)
        try:
            self._write_frame(True, opcode, message)
        except StreamClosedError:
            self._abort()

    def write_ping(self, data):
        """Send ping frame."""
        assert isinstance(data, bytes_type)
        self._write_frame(True, 0x9, data)

    def _receive_frame(self):
        try:
            self.stream.read_bytes(2, self._on_frame_start)
        except StreamClosedError:
            self._abort()

    def _on_frame_start(self, data):
        header, payloadlen = struct.unpack("BB", data)
        self._final_frame = header & 0x80
        reserved_bits = header & 0x70
        self._frame_opcode = header & 0xf
        self._frame_opcode_is_control = self._frame_opcode & 0x8
        if reserved_bits:
            # client is using as-yet-undefined extensions; abort
            self._abort()
            return
        self._masked_frame = bool(payloadlen & 0x80)
        payloadlen = payloadlen & 0x7f
        if self._frame_opcode_is_control and payloadlen >= 126:
            # control frames must have payload < 126
            self._abort()
            return
        try:
            if payloadlen < 126:
                self._frame_length = payloadlen
                if self._masked_frame:
                    self.stream.read_bytes(4, self._on_masking_key)
                else:
                    self.stream.read_bytes(self._frame_length, self._on_frame_data)
            elif payloadlen == 126:
                self.stream.read_bytes(2, self._on_frame_length_16)
            elif payloadlen == 127:
                self.stream.read_bytes(8, self._on_frame_length_64)
        except StreamClosedError:
            self._abort()

    def _on_frame_length_16(self, data):
        self._frame_length = struct.unpack("!H", data)[0]
        try:
            if self._masked_frame:
                self.stream.read_bytes(4, self._on_masking_key)
            else:
                self.stream.read_bytes(self._frame_length, self._on_frame_data)
        except StreamClosedError:
            self._abort()

    def _on_frame_length_64(self, data):
        self._frame_length = struct.unpack("!Q", data)[0]
        try:
            if self._masked_frame:
                self.stream.read_bytes(4, self._on_masking_key)
            else:
                self.stream.read_bytes(self._frame_length, self._on_frame_data)
        except StreamClosedError:
            self._abort()

    def _on_masking_key(self, data):
        self._frame_mask = data
        try:
            self.stream.read_bytes(self._frame_length, self._on_masked_frame_data)
        except StreamClosedError:
            self._abort()

    def _on_masked_frame_data(self, data):
        self._on_frame_data(_websocket_mask(self._frame_mask, data))

    def _on_frame_data(self, data):
        if self._frame_opcode_is_control:
            # control frames may be interleaved with a series of fragmented
            # data frames, so control frames must not interact with
            # self._fragmented_*
            if not self._final_frame:
                # control frames must not be fragmented
                self._abort()
                return
            opcode = self._frame_opcode
        elif self._frame_opcode == 0:  # continuation frame
            if self._fragmented_message_buffer is None:
                # nothing to continue
                self._abort()
                return
            self._fragmented_message_buffer += data
            if self._final_frame:
                opcode = self._fragmented_message_opcode
                data = self._fragmented_message_buffer
                self._fragmented_message_buffer = None
        else:  # start of new data message
            if self._fragmented_message_buffer is not None:
                # can't start new message until the old one is finished
                self._abort()
                return
            if self._final_frame:
                opcode = self._frame_opcode
            else:
                self._fragmented_message_opcode = self._frame_opcode
                self._fragmented_message_buffer = data

        if self._final_frame:
            self._handle_message(opcode, data)

        if not self.client_terminated:
            self._receive_frame()

    def _handle_message(self, opcode, data):
        if self.client_terminated:
            return

        if opcode == 0x1:
            # UTF-8 data
            try:
                decoded = data.decode("utf-8")
            except UnicodeDecodeError:
                self._abort()
                return
            self.async_callback(self.handler.on_message)(decoded)
        elif opcode == 0x2:
            # Binary data
            self.async_callback(self.handler.on_message)(data)
        elif opcode == 0x8:
            # Close
            self.client_terminated = True
            if len(data) >= 2:
                self.handler.close_code = struct.unpack('>H', data[:2])[0]
            if len(data) > 2:
                self.handler.close_reason = to_unicode(data[2:])
            self.close()
        elif opcode == 0x9:
            # Ping
            self._write_frame(True, 0xA, data)
        elif opcode == 0xA:
            # Pong
            self.async_callback(self.handler.on_pong)(data)
        else:
            self._abort()

    def close(self, code=None, reason=None):
        """Closes the WebSocket connection."""
        if not self.server_terminated:
            if not self.stream.closed():
                if code is None and reason is not None:
                    code = 1000  # "normal closure" status code
                if code is None:
                    close_data = b''
                else:
                    close_data = struct.pack('>H', code)
                if reason is not None:
                    close_data += utf8(reason)
                self._write_frame(True, 0x8, close_data)
            self.server_terminated = True
        if self.client_terminated:
            if self._waiting is not None:
                self.stream.io_loop.remove_timeout(self._waiting)
                self._waiting = None
            self.stream.close()
        elif self._waiting is None:
            # Give the client a few seconds to complete a clean shutdown,
            # otherwise just close the connection.
            self._waiting = self.stream.io_loop.add_timeout(
                self.stream.io_loop.time() + 5, self._abort)


class WebSocketClientConnection(simple_httpclient._HTTPConnection):
    """WebSocket client connection.

    This class should not be instantiated directly; use the
    `websocket_connect` function instead.
    """
    def __init__(self, io_loop, request):
        self.connect_future = TracebackFuture()
        self.read_future = None
        self.read_queue = collections.deque()
        self.key = base64.b64encode(os.urandom(16))

        scheme, sep, rest = request.url.partition(':')
        scheme = {'ws': 'http', 'wss': 'https'}[scheme]
        request.url = scheme + sep + rest
        request.headers.update({
            'Upgrade': 'websocket',
            'Connection': 'Upgrade',
            'Sec-WebSocket-Key': self.key,
            'Sec-WebSocket-Version': '13',
        })

        self.resolver = Resolver(io_loop=io_loop)
        super(WebSocketClientConnection, self).__init__(
            io_loop, None, request, lambda: None, self._on_http_response,
            104857600, self.resolver, 65536)

    def close(self, code=None, reason=None):
        """Closes the websocket connection.

        ``code`` and ``reason`` are documented under
        `WebSocketHandler.close`.

        .. versionadded:: 3.2

        .. versionchanged:: 3.3

           Added the ``code`` and ``reason`` arguments.
        """
        if self.protocol is not None:
            self.protocol.close(code, reason)
            self.protocol = None

    def _on_close(self):
        self.on_message(None)
        self.resolver.close()
        super(WebSocketClientConnection, self)._on_close()

    def _on_http_response(self, response):
        if not self.connect_future.done():
            if response.error:
                self.connect_future.set_exception(response.error)
            else:
                self.connect_future.set_exception(WebSocketError(
                    "Non-websocket response"))

    def headers_received(self, start_line, headers):
        if start_line.code != 101:
            return super(WebSocketClientConnection, self).headers_received(
                start_line, headers)

        self.headers = headers
        assert self.headers['Upgrade'].lower() == 'websocket'
        assert self.headers['Connection'].lower() == 'upgrade'
        accept = WebSocketProtocol13.compute_accept_value(self.key)
        assert self.headers['Sec-Websocket-Accept'] == accept

        self.protocol = WebSocketProtocol13(self, mask_outgoing=True)
        self.protocol._receive_frame()

        if self._timeout is not None:
            self.io_loop.remove_timeout(self._timeout)
            self._timeout = None

        self.stream = self.connection.detach()
        self.stream.set_close_callback(self._on_close)

        self.connect_future.set_result(self)

    def write_message(self, message, binary=False):
        """Sends a message to the WebSocket server."""
        self.protocol.write_message(message, binary)

    def read_message(self, callback=None):
        """Reads a message from the WebSocket server.

        Returns a future whose result is the message, or None
        if the connection is closed.  If a callback argument
        is given it will be called with the future when it is
        ready.
        """
        assert self.read_future is None
        future = TracebackFuture()
        if self.read_queue:
            future.set_result(self.read_queue.popleft())
        else:
            self.read_future = future
        if callback is not None:
            self.io_loop.add_future(future, callback)
        return future

    def on_message(self, message):
        if self.read_future is not None:
            self.read_future.set_result(message)
            self.read_future = None
        else:
            self.read_queue.append(message)

    def on_pong(self, data):
        pass


def websocket_connect(url, io_loop=None, callback=None, connect_timeout=None):
    """Client-side websocket support.

    Takes a url and returns a Future whose result is a
    `WebSocketClientConnection`.

    .. versionchanged:: 3.2
       Also accepts ``HTTPRequest`` objects in place of urls.
    """
    if io_loop is None:
        io_loop = IOLoop.current()
    if isinstance(url, httpclient.HTTPRequest):
        assert connect_timeout is None
        request = url
        # Copy and convert the headers dict/object (see comments in
        # AsyncHTTPClient.fetch)
        request.headers = httputil.HTTPHeaders(request.headers)
    else:
        request = httpclient.HTTPRequest(url, connect_timeout=connect_timeout)
    request = httpclient._RequestProxy(
        request, httpclient.HTTPRequest._DEFAULTS)
    conn = WebSocketClientConnection(io_loop, request)
    if callback is not None:
        io_loop.add_future(conn.connect_future, callback)
    return conn.connect_future


def _websocket_mask_python(mask, data):
    """Websocket masking function.

    `mask` is a `bytes` object of length 4; `data` is a `bytes` object of any length.
    Returns a `bytes` object of the same length as `data` with the mask applied
    as specified in section 5.3 of RFC 6455.

    This pure-python implementation may be replaced by an optimized version when available.
    """
    mask = array.array("B", mask)
    unmasked = array.array("B", data)
    for i in xrange(len(data)):
        unmasked[i] = unmasked[i] ^ mask[i % 4]
    if hasattr(unmasked, 'tobytes'):
        # tostring was deprecated in py32.  It hasn't been removed,
        # but since we turn on deprecation warnings in our tests
        # we need to use the right one.
        return unmasked.tobytes()
    else:
        return unmasked.tostring()

if (os.environ.get('TORNADO_NO_EXTENSION') or
    os.environ.get('TORNADO_EXTENSION') == '0'):
    # These environment variables exist to make it easier to do performance
    # comparisons; they are not guaranteed to remain supported in the future.
    _websocket_mask = _websocket_mask_python
else:
    try:
        from tornado.speedups import websocket_mask as _websocket_mask
    except ImportError:
        if os.environ.get('TORNADO_EXTENSION') == '1':
            raise
        _websocket_mask = _websocket_mask_python

```
--- END FILE ---

Please first localize the bug based on the issue statement, and then generate *SEARCH/REPLACE* edits to fix the issue.

Every *SEARCH/REPLACE* edit must use this format:
1. The file path
2. The start of search block: <<<<<<< SEARCH
3. A contiguous chunk of lines to search for in the existing source code
4. The dividing line: =======
5. The lines to replace into the source code
6. The end of the replace block: >>>>>>> REPLACE

Here is an example:

```python
### mathweb/flask/app.py
<<<<<<< SEARCH
from flask import Flask
=======
import math
from flask import Flask
>>>>>>> REPLACE
```
</solution>

Please note that the *SEARCH/REPLACE* edit REQUIRES PROPER INDENTATION. If you would like to add the line '        print(x)', you must fully write that out, with all those spaces before the code!
Wrap each *SEARCH/REPLACE* edit in a code block as shown in the example above. If you have multiple *SEARCH/REPLACE* edits, use a separate code block for each one.
[ISSUE]
**Title:** WebSocketHandler Does Not Reject Connections with Invalid Origin Headers

**Description:**
When initiating a WebSocket connection with an invalid Origin header, the server is expected to reject the connection to prevent unauthorized cross-origin access. Currently, connections with invalid Origin headers are not properly rejected, allowing potential security vulnerabilities.

**Example:**
Attempting to connect with an Origin header set to `'http://somewhereelse.com'`:

```python
url = 'ws://localhost:port/echo'
headers = {'Origin': 'http://somewhereelse.com'}
ws = websocket_connect(HTTPRequest(url, headers=headers), io_loop=self.io_loop)
```

**Expected Behavior:**
The server should respond with a **403 Forbidden** error, rejecting the WebSocket connection due to the invalid Origin.

**Actual Behavior:**
No error is raised, and the connection is unexpectedly accepted, allowing cross-origin WebSocket access.
[/ISSUE]
{
    "CythonMaskFunctionTest.test_mask": "PASSED",
    "PythonMaskFunctionTest.test_mask": "PASSED",
    "WebSocketTest.test_check_origin_invalid": "PASSED",
    "WebSocketTest.test_check_origin_invalid2": "PASSED",
    "WebSocketTest.test_check_origin_valid": "PASSED",
    "WebSocketTest.test_check_origin_valid2": "PASSED",
    "WebSocketTest.test_client_close_reason": "PASSED",
    "WebSocketTest.test_server_close_reason": "PASSED",
    "WebSocketTest.test_websocket_callbacks": "PASSED",
    "WebSocketTest.test_websocket_close_buffered_data": "PASSED",
    "WebSocketTest.test_websocket_gen": "PASSED",
    "WebSocketTest.test_websocket_headers": "PASSED",
    "WebSocketTest.test_websocket_http_fail": "PASSED",
    "WebSocketTest.test_websocket_http_success": "PASSED",
    "WebSocketTest.test_websocket_network_fail": "PASSED",
    "WebSocketTest.test_websocket_network_timeout": "PASSED"
}
diff --git a/tornado/websocket.py b/tornado/websocket.py
index 22369c87..1ba905b7 100644
--- a/tornado/websocket.py
+++ b/tornado/websocket.py
@@ -145,9 +145,34 @@ class WebSocketHandler(tornado.web.RequestHandler):
             self.stream.close()
             return
 
+        # Handle WebSocket Origin naming convention differences
         # The difference between version 8 and 13 is that in 8 the
         # client sends a "Sec-Websocket-Origin" header and in 13 it's
         # simply "Origin".
+        if "Origin" in self.request.headers:
+            origin = self.request.headers.get("Origin")
+        else:
+            origin = self.request.headers.get("Sec-Websocket-Origin", None)
+
+        # If we have an origin, normalize
+        if(origin):
+            # Due to how stdlib's urlparse is implemented, urls without a //
+            # are interpreted to be paths (resulting in netloc being None)
+            if("//" not in origin):
+                origin = "//" + origin
+            parsed_origin = urlparse(origin)
+            origin = parsed_origin.netloc
+            origin = origin.lower()
+
+        # If there was an origin header, check to make sure it matches
+        # according to check_origin
+        if not self.check_origin(origin):
+            self.stream.write(tornado.escape.utf8(
+                "HTTP/1.1 403 Cross Origin Websockets Disabled\r\n\r\n"
+            ))
+            self.stream.close()
+            return
+
         if self.request.headers.get("Sec-WebSocket-Version") in ("7", "8", "13"):
             self.ws_connection = WebSocketProtocol13(self)
             self.ws_connection.accept_connection()
@@ -161,13 +186,6 @@ class WebSocketHandler(tornado.web.RequestHandler):
                 "Sec-WebSocket-Version: 8\r\n\r\n"))
             self.stream.close()
 
-        if not self.check_origin():
-            self.stream.write(tornado.escape.utf8(
-                "HTTP/1.1 403 Cross Origin Websockets Disabled\r\n\r\n"
-            ))
-            self.stream.close()
-
-
 
     def write_message(self, message, binary=False):
         """Sends the given message to the client of this Web Socket.
@@ -264,37 +282,25 @@ class WebSocketHandler(tornado.web.RequestHandler):
             self.ws_connection.close(code, reason)
             self.ws_connection = None
 
-    def check_origin(self, allowed_origins=None):
+    def check_origin(self, origin):
         """Override to enable support for allowing alternate origins.
         
-        By default, this checks to see that requests that provide both a host
-        origin have the same origin and host This is a security protection
-        against cross site scripting attacks on browsers,
-        since WebSockets don't have CORS headers.
+        By default, this checks to see that the host matches the origin
+        provided.
+
+        This is a security protection against cross site scripting attacks on
+        browsers, since WebSockets don't have CORS headers.
         
-        >>> self.check_origins(allowed_origins=['localhost'])
+        >>> self.check_origin(origin='localhost')
+        True
         
         """
-        # Handle WebSocket Origin naming convention differences
-        # The difference between version 8 and 13 is that in 8 the
-        # client sends a "Sec-Websocket-Origin" header and in 13 it's
-        # simply "Origin".
-        if self.request.headers.get("Sec-WebSocket-Version") in ("7", "8"):
-            origin_header = self.request.headers.get("Sec-Websocket-Origin")
-        else:
-            origin_header = self.request.headers.get("Origin")
-
-        host = self.request.headers.get("Host")
-
-        # If no header is provided, assume request is not coming from a browser
-        if(origin_header is None or host is None):
+        # When origin is None, assume it didn't come from a browser and we can
+        # pass it on
+        if origin is None:
             return True
 
-        parsed_origin = urlparse(origin_header)
-        origin = parsed_origin.netloc
-
-        if allowed_origins and origin in allowed_origins:
-            return True
+        host = self.request.headers.get("Host")
 
         # Check to see that origin matches host directly, including ports
         return origin == host
 

{"tornado/websocket.py": "\"\"\"Implementation of the WebSocket protocol.\n\n`WebSockets <http://dev.w3.org/html5/websockets/>`_ allow for bidirectional\ncommunication between the browser and server.\n\n.. warning::\n\n   The WebSocket protocol was recently finalized as `RFC 6455\n   <http://tools.ietf.org/html/rfc6455>`_ and is not yet supported in\n   all browsers.  Refer to http://caniuse.com/websockets for details\n   on compatibility.  In addition, during development the protocol\n   went through several incompatible versions, and some browsers only\n   support older versions.  By default this module only supports the\n   latest version of the protocol, but optional support for an older\n   version (known as \"draft 76\" or \"hixie-76\") can be enabled by\n   overriding `WebSocketHandler.allow_draft76` (see that method's\n   documentation for caveats).\n\"\"\"\n\nfrom __future__ import absolute_import, division, print_function, with_statement\n# Author: Jacob Kristhammar, 2010\n\nimport array\nimport base64\nimport collections\nimport functools\nimport hashlib\nimport os\nimport struct\nimport time\nimport tornado.escape\nimport tornado.web\n\nfrom tornado.concurrent import TracebackFuture\nfrom tornado.escape import utf8, native_str, to_unicode\nfrom tornado import httpclient, httputil\nfrom tornado.ioloop import IOLoop\nfrom tornado.iostream import StreamClosedError\nfrom tornado.log import gen_log, app_log\nfrom tornado.netutil import Resolver\nfrom tornado import simple_httpclient\nfrom tornado.util import bytes_type, unicode_type\n\ntry:\n    from urllib.parse import urlparse # py2\nexcept ImportError:\n    from urlparse import urlparse # py3\n\ntry:\n    xrange  # py2\nexcept NameError:\n    xrange = range  # py3\n\n\nclass WebSocketError(Exception):\n    pass\n\n\nclass WebSocketClosedError(WebSocketError):\n    \"\"\"Raised by operations on a closed connection.\n\n    .. versionadded:: 3.2\n    \"\"\"\n    pass\n\n\nclass WebSocketHandler(tornado.web.RequestHandler):\n    \"\"\"Subclass this class to create a basic WebSocket handler.\n\n    Override `on_message` to handle incoming messages, and use\n    `write_message` to send messages to the client. You can also\n    override `open` and `on_close` to handle opened and closed\n    connections.\n\n    See http://dev.w3.org/html5/websockets/ for details on the\n    JavaScript interface.  The protocol is specified at\n    http://tools.ietf.org/html/rfc6455.\n\n    Here is an example WebSocket handler that echos back all received messages\n    back to the client::\n\n      class EchoWebSocket(websocket.WebSocketHandler):\n          def open(self):\n              print \"WebSocket opened\"\n\n          def on_message(self, message):\n              self.write_message(u\"You said: \" + message)\n\n          def on_close(self):\n              print \"WebSocket closed\"\n\n    WebSockets are not standard HTTP connections. The \"handshake\" is\n    HTTP, but after the handshake, the protocol is\n    message-based. Consequently, most of the Tornado HTTP facilities\n    are not available in handlers of this type. The only communication\n    methods available to you are `write_message()`, `ping()`, and\n    `close()`. Likewise, your request handler class should implement\n    `open()` method rather than ``get()`` or ``post()``.\n\n    If you map the handler above to ``/websocket`` in your application, you can\n    invoke it in JavaScript with::\n\n      var ws = new WebSocket(\"ws://localhost:8888/websocket\");\n      ws.onopen = function() {\n         ws.send(\"Hello, world\");\n      };\n      ws.onmessage = function (evt) {\n         alert(evt.data);\n      };\n\n    This script pops up an alert box that says \"You said: Hello, world\".\n    \"\"\"\n    def __init__(self, application, request, **kwargs):\n        tornado.web.RequestHandler.__init__(self, application, request,\n                                            **kwargs)\n        self.ws_connection = None\n        self.close_code = None\n        self.close_reason = None\n\n    @tornado.web.asynchronous\n    def get(self, *args, **kwargs):\n        self.open_args = args\n        self.open_kwargs = kwargs\n\n        self.stream = self.request.connection.detach()\n\n        # Upgrade header should be present and should be equal to WebSocket\n        if self.request.headers.get(\"Upgrade\", \"\").lower() != 'websocket':\n            self.stream.write(tornado.escape.utf8(\n                \"HTTP/1.1 400 Bad Request\\r\\n\\r\\n\"\n                \"Can \\\"Upgrade\\\" only to \\\"WebSocket\\\".\"\n            ))\n            self.stream.close()\n            return\n\n        # Connection header should be upgrade. Some proxy servers/load balancers\n        # might mess with it.\n        headers = self.request.headers\n        connection = map(lambda s: s.strip().lower(), headers.get(\"Connection\", \"\").split(\",\"))\n        if 'upgrade' not in connection:\n            self.stream.write(tornado.escape.utf8(\n                \"HTTP/1.1 400 Bad Request\\r\\n\\r\\n\"\n                \"\\\"Connection\\\" must be \\\"Upgrade\\\".\"\n            ))\n            self.stream.close()\n            return\n\n        # The difference between version 8 and 13 is that in 8 the\n        # client sends a \"Sec-Websocket-Origin\" header and in 13 it's\n        # simply \"Origin\".\n        if self.request.headers.get(\"Sec-WebSocket-Version\") in (\"7\", \"8\", \"13\"):\n            self.ws_connection = WebSocketProtocol13(self)\n            self.ws_connection.accept_connection()\n        elif (self.allow_draft76() and\n              \"Sec-WebSocket-Version\" not in self.request.headers):\n            self.ws_connection = WebSocketProtocol76(self)\n            self.ws_connection.accept_connection()\n        else:\n            self.stream.write(tornado.escape.utf8(\n                \"HTTP/1.1 426 Upgrade Required\\r\\n\"\n                \"Sec-WebSocket-Version: 8\\r\\n\\r\\n\"))\n            self.stream.close()\n\n        if not self.check_origin():\n            self.stream.write(tornado.escape.utf8(\n                \"HTTP/1.1 403 Cross Origin Websockets Disabled\\r\\n\\r\\n\"\n            ))\n            self.stream.close()\n\n\n\n    def write_message(self, message, binary=False):\n        \"\"\"Sends the given message to the client of this Web Socket.\n\n        The message may be either a string or a dict (which will be\n        encoded as json).  If the ``binary`` argument is false, the\n        message will be sent as utf8; in binary mode any byte string\n        is allowed.\n\n        If the connection is already closed, raises `WebSocketClosedError`.\n\n        .. versionchanged:: 3.2\n           `WebSocketClosedError` was added (previously a closed connection\n           would raise an `AttributeError`)\n        \"\"\"\n        if self.ws_connection is None:\n            raise WebSocketClosedError()\n        if isinstance(message, dict):\n            message = tornado.escape.json_encode(message)\n        self.ws_connection.write_message(message, binary=binary)\n\n    def select_subprotocol(self, subprotocols):\n        \"\"\"Invoked when a new WebSocket requests specific subprotocols.\n\n        ``subprotocols`` is a list of strings identifying the\n        subprotocols proposed by the client.  This method may be\n        overridden to return one of those strings to select it, or\n        ``None`` to not select a subprotocol.  Failure to select a\n        subprotocol does not automatically abort the connection,\n        although clients may close the connection if none of their\n        proposed subprotocols was selected.\n        \"\"\"\n        return None\n\n    def open(self):\n        \"\"\"Invoked when a new WebSocket is opened.\n\n        The arguments to `open` are extracted from the `tornado.web.URLSpec`\n        regular expression, just like the arguments to\n        `tornado.web.RequestHandler.get`.\n        \"\"\"\n        pass\n\n    def on_message(self, message):\n        \"\"\"Handle incoming messages on the WebSocket\n\n        This method must be overridden.\n        \"\"\"\n        raise NotImplementedError\n\n    def ping(self, data):\n        \"\"\"Send ping frame to the remote end.\"\"\"\n        if self.ws_connection is None:\n            raise WebSocketClosedError()\n        self.ws_connection.write_ping(data)\n\n    def on_pong(self, data):\n        \"\"\"Invoked when the response to a ping frame is received.\"\"\"\n        pass\n\n    def on_close(self):\n        \"\"\"Invoked when the WebSocket is closed.\n\n        If the connection was closed cleanly and a status code or reason\n        phrase was supplied, these values will be available as the attributes\n        ``self.close_code`` and ``self.close_reason``.\n\n        .. versionchanged:: 3.3\n\n           Added ``close_code`` and ``close_reason`` attributes.\n        \"\"\"\n        pass\n\n    def close(self, code=None, reason=None):\n        \"\"\"Closes this Web Socket.\n\n        Once the close handshake is successful the socket will be closed.\n\n        ``code`` may be a numeric status code, taken from the values\n        defined in `RFC 6455 section 7.4.1\n        <https://tools.ietf.org/html/rfc6455#section-7.4.1>`_.\n        ``reason`` may be a textual message about why the connection is\n        closing.  These values are made available to the client, but are\n        not otherwise interpreted by the websocket protocol.\n\n        The ``code`` and ``reason`` arguments are ignored in the \"draft76\"\n        protocol version.\n\n        .. versionchanged:: 3.3\n\n           Added the ``code`` and ``reason`` arguments.\n        \"\"\"\n        if self.ws_connection:\n            self.ws_connection.close(code, reason)\n            self.ws_connection = None\n\n    def check_origin(self, allowed_origins=None):\n        \"\"\"Override to enable support for allowing alternate origins.\n        \n        By default, this checks to see that requests that provide both a host\n        origin have the same origin and host This is a security protection\n        against cross site scripting attacks on browsers,\n        since WebSockets don't have CORS headers.\n        \n        >>> self.check_origins(allowed_origins=['localhost'])\n        \n        \"\"\"\n        # Handle WebSocket Origin naming convention differences\n        # The difference between version 8 and 13 is that in 8 the\n        # client sends a \"Sec-Websocket-Origin\" header and in 13 it's\n        # simply \"Origin\".\n        if self.request.headers.get(\"Sec-WebSocket-Version\") in (\"7\", \"8\"):\n            origin_header = self.request.headers.get(\"Sec-Websocket-Origin\")\n        else:\n            origin_header = self.request.headers.get(\"Origin\")\n\n        host = self.request.headers.get(\"Host\")\n\n        # If no header is provided, assume request is not coming from a browser\n        if(origin_header is None or host is None):\n            return True\n\n        parsed_origin = urlparse(origin_header)\n        origin = parsed_origin.netloc\n\n        if allowed_origins and origin in allowed_origins:\n            return True\n\n        # Check to see that origin matches host directly, including ports\n        return origin == host\n\n    def allow_draft76(self):\n        \"\"\"Override to enable support for the older \"draft76\" protocol.\n\n        The draft76 version of the websocket protocol is disabled by\n        default due to security concerns, but it can be enabled by\n        overriding this method to return True.\n\n        Connections using the draft76 protocol do not support the\n        ``binary=True`` flag to `write_message`.\n\n        Support for the draft76 protocol is deprecated and will be\n        removed in a future version of Tornado.\n        \"\"\"\n        return False\n\n    def set_nodelay(self, value):\n        \"\"\"Set the no-delay flag for this stream.\n\n        By default, small messages may be delayed and/or combined to minimize\n        the number of packets sent.  This can sometimes cause 200-500ms delays\n        due to the interaction between Nagle's algorithm and TCP delayed\n        ACKs.  To reduce this delay (at the expense of possibly increasing\n        bandwidth usage), call ``self.set_nodelay(True)`` once the websocket\n        connection is established.\n\n        See `.BaseIOStream.set_nodelay` for additional details.\n\n        .. versionadded:: 3.1\n        \"\"\"\n        self.stream.set_nodelay(value)\n\n    def get_websocket_scheme(self):\n        \"\"\"Return the url scheme used for this request, either \"ws\" or \"wss\".\n\n        This is normally decided by HTTPServer, but applications\n        may wish to override this if they are using an SSL proxy\n        that does not provide the X-Scheme header as understood\n        by HTTPServer.\n\n        Note that this is only used by the draft76 protocol.\n        \"\"\"\n        return \"wss\" if self.request.protocol == \"https\" else \"ws\"\n\n    def async_callback(self, callback, *args, **kwargs):\n        \"\"\"Obsolete - catches exceptions from the wrapped function.\n\n        This function is normally unncecessary thanks to\n        `tornado.stack_context`.\n        \"\"\"\n        return self.ws_connection.async_callback(callback, *args, **kwargs)\n\n    def _not_supported(self, *args, **kwargs):\n        raise Exception(\"Method not supported for Web Sockets\")\n\n    def on_connection_close(self):\n        if self.ws_connection:\n            self.ws_connection.on_connection_close()\n            self.ws_connection = None\n            self.on_close()\n\n\nfor method in [\"write\", \"redirect\", \"set_header\", \"send_error\", \"set_cookie\",\n               \"set_status\", \"flush\", \"finish\"]:\n    setattr(WebSocketHandler, method, WebSocketHandler._not_supported)\n\n\nclass WebSocketProtocol(object):\n    \"\"\"Base class for WebSocket protocol versions.\n    \"\"\"\n    def __init__(self, handler):\n        self.handler = handler\n        self.request = handler.request\n        self.stream = handler.stream\n        self.client_terminated = False\n        self.server_terminated = False\n\n    def async_callback(self, callback, *args, **kwargs):\n        \"\"\"Wrap callbacks with this if they are used on asynchronous requests.\n\n        Catches exceptions properly and closes this WebSocket if an exception\n        is uncaught.\n        \"\"\"\n        if args or kwargs:\n            callback = functools.partial(callback, *args, **kwargs)\n\n        def wrapper(*args, **kwargs):\n            try:\n                return callback(*args, **kwargs)\n            except Exception:\n                app_log.error(\"Uncaught exception in %s\",\n                              self.request.path, exc_info=True)\n                self._abort()\n        return wrapper\n\n    def on_connection_close(self):\n        self._abort()\n\n    def _abort(self):\n        \"\"\"Instantly aborts the WebSocket connection by closing the socket\"\"\"\n        self.client_terminated = True\n        self.server_terminated = True\n        self.stream.close()  # forcibly tear down the connection\n        self.close()  # let the subclass cleanup\n\n\nclass WebSocketProtocol76(WebSocketProtocol):\n    \"\"\"Implementation of the WebSockets protocol, version hixie-76.\n\n    This class provides basic functionality to process WebSockets requests as\n    specified in\n    http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76\n    \"\"\"\n    def __init__(self, handler):\n        WebSocketProtocol.__init__(self, handler)\n        self.challenge = None\n        self._waiting = None\n\n    def accept_connection(self):\n        try:\n            self._handle_websocket_headers()\n        except ValueError:\n            gen_log.debug(\"Malformed WebSocket request received\")\n            self._abort()\n            return\n\n        scheme = self.handler.get_websocket_scheme()\n\n        # draft76 only allows a single subprotocol\n        subprotocol_header = ''\n        subprotocol = self.request.headers.get(\"Sec-WebSocket-Protocol\", None)\n        if subprotocol:\n            selected = self.handler.select_subprotocol([subprotocol])\n            if selected:\n                assert selected == subprotocol\n                subprotocol_header = \"Sec-WebSocket-Protocol: %s\\r\\n\" % selected\n\n        # Write the initial headers before attempting to read the challenge.\n        # This is necessary when using proxies (such as HAProxy), which\n        # need to see the Upgrade headers before passing through the\n        # non-HTTP traffic that follows.\n        self.stream.write(tornado.escape.utf8(\n            \"HTTP/1.1 101 WebSocket Protocol Handshake\\r\\n\"\n            \"Upgrade: WebSocket\\r\\n\"\n            \"Connection: Upgrade\\r\\n\"\n            \"Server: TornadoServer/%(version)s\\r\\n\"\n            \"Sec-WebSocket-Origin: %(origin)s\\r\\n\"\n            \"Sec-WebSocket-Location: %(scheme)s://%(host)s%(uri)s\\r\\n\"\n            \"%(subprotocol)s\"\n            \"\\r\\n\" % (dict(\n                version=tornado.version,\n                origin=self.request.headers[\"Origin\"],\n                scheme=scheme,\n                host=self.request.host,\n                uri=self.request.uri,\n                subprotocol=subprotocol_header))))\n        self.stream.read_bytes(8, self._handle_challenge)\n\n    def challenge_response(self, challenge):\n        \"\"\"Generates the challenge response that's needed in the handshake\n\n        The challenge parameter should be the raw bytes as sent from the\n        client.\n        \"\"\"\n        key_1 = self.request.headers.get(\"Sec-Websocket-Key1\")\n        key_2 = self.request.headers.get(\"Sec-Websocket-Key2\")\n        try:\n            part_1 = self._calculate_part(key_1)\n            part_2 = self._calculate_part(key_2)\n        except ValueError:\n            raise ValueError(\"Invalid Keys/Challenge\")\n        return self._generate_challenge_response(part_1, part_2, challenge)\n\n    def _handle_challenge(self, challenge):\n        try:\n            challenge_response = self.challenge_response(challenge)\n        except ValueError:\n            gen_log.debug(\"Malformed key data in WebSocket request\")\n            self._abort()\n            return\n        self._write_response(challenge_response)\n\n    def _write_response(self, challenge):\n        self.stream.write(challenge)\n        self.async_callback(self.handler.open)(*self.handler.open_args, **self.handler.open_kwargs)\n        self._receive_message()\n\n    def _handle_websocket_headers(self):\n        \"\"\"Verifies all invariant- and required headers\n\n        If a header is missing or have an incorrect value ValueError will be\n        raised\n        \"\"\"\n        fields = (\"Origin\", \"Host\", \"Sec-Websocket-Key1\",\n                  \"Sec-Websocket-Key2\")\n        if not all(map(lambda f: self.request.headers.get(f), fields)):\n            raise ValueError(\"Missing/Invalid WebSocket headers\")\n\n    def _calculate_part(self, key):\n        \"\"\"Processes the key headers and calculates their key value.\n\n        Raises ValueError when feed invalid key.\"\"\"\n        # pyflakes complains about variable reuse if both of these lines use 'c'\n        number = int(''.join(c for c in key if c.isdigit()))\n        spaces = len([c2 for c2 in key if c2.isspace()])\n        try:\n            key_number = number // spaces\n        except (ValueError, ZeroDivisionError):\n            raise ValueError\n        return struct.pack(\">I\", key_number)\n\n    def _generate_challenge_response(self, part_1, part_2, part_3):\n        m = hashlib.md5()\n        m.update(part_1)\n        m.update(part_2)\n        m.update(part_3)\n        return m.digest()\n\n    def _receive_message(self):\n        self.stream.read_bytes(1, self._on_frame_type)\n\n    def _on_frame_type(self, byte):\n        frame_type = ord(byte)\n        if frame_type == 0x00:\n            self.stream.read_until(b\"\\xff\", self._on_end_delimiter)\n        elif frame_type == 0xff:\n            self.stream.read_bytes(1, self._on_length_indicator)\n        else:\n            self._abort()\n\n    def _on_end_delimiter(self, frame):\n        if not self.client_terminated:\n            self.async_callback(self.handler.on_message)(\n                frame[:-1].decode(\"utf-8\", \"replace\"))\n        if not self.client_terminated:\n            self._receive_message()\n\n    def _on_length_indicator(self, byte):\n        if ord(byte) != 0x00:\n            self._abort()\n            return\n        self.client_terminated = True\n        self.close()\n\n    def write_message(self, message, binary=False):\n        \"\"\"Sends the given message to the client of this Web Socket.\"\"\"\n        if binary:\n            raise ValueError(\n                \"Binary messages not supported by this version of websockets\")\n        if isinstance(message, unicode_type):\n            message = message.encode(\"utf-8\")\n        assert isinstance(message, bytes_type)\n        self.stream.write(b\"\\x00\" + message + b\"\\xff\")\n\n    def write_ping(self, data):\n        \"\"\"Send ping frame.\"\"\"\n        raise ValueError(\"Ping messages not supported by this version of websockets\")\n\n    def close(self, code=None, reason=None):\n        \"\"\"Closes the WebSocket connection.\"\"\"\n        if not self.server_terminated:\n            if not self.stream.closed():\n                self.stream.write(\"\\xff\\x00\")\n            self.server_terminated = True\n        if self.client_terminated:\n            if self._waiting is not None:\n                self.stream.io_loop.remove_timeout(self._waiting)\n            self._waiting = None\n            self.stream.close()\n        elif self._waiting is None:\n            self._waiting = self.stream.io_loop.add_timeout(\n                time.time() + 5, self._abort)\n\n\nclass WebSocketProtocol13(WebSocketProtocol):\n    \"\"\"Implementation of the WebSocket protocol from RFC 6455.\n\n    This class supports versions 7 and 8 of the protocol in addition to the\n    final version 13.\n    \"\"\"\n    def __init__(self, handler, mask_outgoing=False):\n        WebSocketProtocol.__init__(self, handler)\n        self.mask_outgoing = mask_outgoing\n        self._final_frame = False\n        self._frame_opcode = None\n        self._masked_frame = None\n        self._frame_mask = None\n        self._frame_length = None\n        self._fragmented_message_buffer = None\n        self._fragmented_message_opcode = None\n        self._waiting = None\n\n    def accept_connection(self):\n        try:\n            self._handle_websocket_headers()\n            self._accept_connection()\n        except ValueError:\n            gen_log.debug(\"Malformed WebSocket request received\", exc_info=True)\n            self._abort()\n            return\n\n    def _handle_websocket_headers(self):\n        \"\"\"Verifies all invariant- and required headers\n\n        If a header is missing or have an incorrect value ValueError will be\n        raised\n        \"\"\"\n        fields = (\"Host\", \"Sec-Websocket-Key\", \"Sec-Websocket-Version\")\n        if not all(map(lambda f: self.request.headers.get(f), fields)):\n            raise ValueError(\"Missing/Invalid WebSocket headers\")\n\n    @staticmethod\n    def compute_accept_value(key):\n        \"\"\"Computes the value for the Sec-WebSocket-Accept header,\n        given the value for Sec-WebSocket-Key.\n        \"\"\"\n        sha1 = hashlib.sha1()\n        sha1.update(utf8(key))\n        sha1.update(b\"258EAFA5-E914-47DA-95CA-C5AB0DC85B11\")  # Magic value\n        return native_str(base64.b64encode(sha1.digest()))\n\n    def _challenge_response(self):\n        return WebSocketProtocol13.compute_accept_value(\n            self.request.headers.get(\"Sec-Websocket-Key\"))\n\n    def _accept_connection(self):\n        subprotocol_header = ''\n        subprotocols = self.request.headers.get(\"Sec-WebSocket-Protocol\", '')\n        subprotocols = [s.strip() for s in subprotocols.split(',')]\n        if subprotocols:\n            selected = self.handler.select_subprotocol(subprotocols)\n            if selected:\n                assert selected in subprotocols\n                subprotocol_header = \"Sec-WebSocket-Protocol: %s\\r\\n\" % selected\n\n        self.stream.write(tornado.escape.utf8(\n            \"HTTP/1.1 101 Switching Protocols\\r\\n\"\n            \"Upgrade: websocket\\r\\n\"\n            \"Connection: Upgrade\\r\\n\"\n            \"Sec-WebSocket-Accept: %s\\r\\n\"\n            \"%s\"\n            \"\\r\\n\" % (self._challenge_response(), subprotocol_header)))\n\n        self.async_callback(self.handler.open)(*self.handler.open_args, **self.handler.open_kwargs)\n        self._receive_frame()\n\n    def _write_frame(self, fin, opcode, data):\n        if fin:\n            finbit = 0x80\n        else:\n            finbit = 0\n        frame = struct.pack(\"B\", finbit | opcode)\n        l = len(data)\n        if self.mask_outgoing:\n            mask_bit = 0x80\n        else:\n            mask_bit = 0\n        if l < 126:\n            frame += struct.pack(\"B\", l | mask_bit)\n        elif l <= 0xFFFF:\n            frame += struct.pack(\"!BH\", 126 | mask_bit, l)\n        else:\n            frame += struct.pack(\"!BQ\", 127 | mask_bit, l)\n        if self.mask_outgoing:\n            mask = os.urandom(4)\n            data = mask + _websocket_mask(mask, data)\n        frame += data\n        self.stream.write(frame)\n\n    def write_message(self, message, binary=False):\n        \"\"\"Sends the given message to the client of this Web Socket.\"\"\"\n        if binary:\n            opcode = 0x2\n        else:\n            opcode = 0x1\n        message = tornado.escape.utf8(message)\n        assert isinstance(message, bytes_type)\n        try:\n            self._write_frame(True, opcode, message)\n        except StreamClosedError:\n            self._abort()\n\n    def write_ping(self, data):\n        \"\"\"Send ping frame.\"\"\"\n        assert isinstance(data, bytes_type)\n        self._write_frame(True, 0x9, data)\n\n    def _receive_frame(self):\n        try:\n            self.stream.read_bytes(2, self._on_frame_start)\n        except StreamClosedError:\n            self._abort()\n\n    def _on_frame_start(self, data):\n        header, payloadlen = struct.unpack(\"BB\", data)\n        self._final_frame = header & 0x80\n        reserved_bits = header & 0x70\n        self._frame_opcode = header & 0xf\n        self._frame_opcode_is_control = self._frame_opcode & 0x8\n        if reserved_bits:\n            # client is using as-yet-undefined extensions; abort\n            self._abort()\n            return\n        self._masked_frame = bool(payloadlen & 0x80)\n        payloadlen = payloadlen & 0x7f\n        if self._frame_opcode_is_control and payloadlen >= 126:\n            # control frames must have payload < 126\n            self._abort()\n            return\n        try:\n            if payloadlen < 126:\n                self._frame_length = payloadlen\n                if self._masked_frame:\n                    self.stream.read_bytes(4, self._on_masking_key)\n                else:\n                    self.stream.read_bytes(self._frame_length, self._on_frame_data)\n            elif payloadlen == 126:\n                self.stream.read_bytes(2, self._on_frame_length_16)\n            elif payloadlen == 127:\n                self.stream.read_bytes(8, self._on_frame_length_64)\n        except StreamClosedError:\n            self._abort()\n\n    def _on_frame_length_16(self, data):\n        self._frame_length = struct.unpack(\"!H\", data)[0]\n        try:\n            if self._masked_frame:\n                self.stream.read_bytes(4, self._on_masking_key)\n            else:\n                self.stream.read_bytes(self._frame_length, self._on_frame_data)\n        except StreamClosedError:\n            self._abort()\n\n    def _on_frame_length_64(self, data):\n        self._frame_length = struct.unpack(\"!Q\", data)[0]\n        try:\n            if self._masked_frame:\n                self.stream.read_bytes(4, self._on_masking_key)\n            else:\n                self.stream.read_bytes(self._frame_length, self._on_frame_data)\n        except StreamClosedError:\n            self._abort()\n\n    def _on_masking_key(self, data):\n        self._frame_mask = data\n        try:\n            self.stream.read_bytes(self._frame_length, self._on_masked_frame_data)\n        except StreamClosedError:\n            self._abort()\n\n    def _on_masked_frame_data(self, data):\n        self._on_frame_data(_websocket_mask(self._frame_mask, data))\n\n    def _on_frame_data(self, data):\n        if self._frame_opcode_is_control:\n            # control frames may be interleaved with a series of fragmented\n            # data frames, so control frames must not interact with\n            # self._fragmented_*\n            if not self._final_frame:\n                # control frames must not be fragmented\n                self._abort()\n                return\n            opcode = self._frame_opcode\n        elif self._frame_opcode == 0:  # continuation frame\n            if self._fragmented_message_buffer is None:\n                # nothing to continue\n                self._abort()\n                return\n            self._fragmented_message_buffer += data\n            if self._final_frame:\n                opcode = self._fragmented_message_opcode\n                data = self._fragmented_message_buffer\n                self._fragmented_message_buffer = None\n        else:  # start of new data message\n            if self._fragmented_message_buffer is not None:\n                # can't start new message until the old one is finished\n                self._abort()\n                return\n            if self._final_frame:\n                opcode = self._frame_opcode\n            else:\n                self._fragmented_message_opcode = self._frame_opcode\n                self._fragmented_message_buffer = data\n\n        if self._final_frame:\n            self._handle_message(opcode, data)\n\n        if not self.client_terminated:\n            self._receive_frame()\n\n    def _handle_message(self, opcode, data):\n        if self.client_terminated:\n            return\n\n        if opcode == 0x1:\n            # UTF-8 data\n            try:\n                decoded = data.decode(\"utf-8\")\n            except UnicodeDecodeError:\n                self._abort()\n                return\n            self.async_callback(self.handler.on_message)(decoded)\n        elif opcode == 0x2:\n            # Binary data\n            self.async_callback(self.handler.on_message)(data)\n        elif opcode == 0x8:\n            # Close\n            self.client_terminated = True\n            if len(data) >= 2:\n                self.handler.close_code = struct.unpack('>H', data[:2])[0]\n            if len(data) > 2:\n                self.handler.close_reason = to_unicode(data[2:])\n            self.close()\n        elif opcode == 0x9:\n            # Ping\n            self._write_frame(True, 0xA, data)\n        elif opcode == 0xA:\n            # Pong\n            self.async_callback(self.handler.on_pong)(data)\n        else:\n            self._abort()\n\n    def close(self, code=None, reason=None):\n        \"\"\"Closes the WebSocket connection.\"\"\"\n        if not self.server_terminated:\n            if not self.stream.closed():\n                if code is None and reason is not None:\n                    code = 1000  # \"normal closure\" status code\n                if code is None:\n                    close_data = b''\n                else:\n                    close_data = struct.pack('>H', code)\n                if reason is not None:\n                    close_data += utf8(reason)\n                self._write_frame(True, 0x8, close_data)\n            self.server_terminated = True\n        if self.client_terminated:\n            if self._waiting is not None:\n                self.stream.io_loop.remove_timeout(self._waiting)\n                self._waiting = None\n            self.stream.close()\n        elif self._waiting is None:\n            # Give the client a few seconds to complete a clean shutdown,\n            # otherwise just close the connection.\n            self._waiting = self.stream.io_loop.add_timeout(\n                self.stream.io_loop.time() + 5, self._abort)\n\n\nclass WebSocketClientConnection(simple_httpclient._HTTPConnection):\n    \"\"\"WebSocket client connection.\n\n    This class should not be instantiated directly; use the\n    `websocket_connect` function instead.\n    \"\"\"\n    def __init__(self, io_loop, request):\n        self.connect_future = TracebackFuture()\n        self.read_future = None\n        self.read_queue = collections.deque()\n        self.key = base64.b64encode(os.urandom(16))\n\n        scheme, sep, rest = request.url.partition(':')\n        scheme = {'ws': 'http', 'wss': 'https'}[scheme]\n        request.url = scheme + sep + rest\n        request.headers.update({\n            'Upgrade': 'websocket',\n            'Connection': 'Upgrade',\n            'Sec-WebSocket-Key': self.key,\n            'Sec-WebSocket-Version': '13',\n        })\n\n        self.resolver = Resolver(io_loop=io_loop)\n        super(WebSocketClientConnection, self).__init__(\n            io_loop, None, request, lambda: None, self._on_http_response,\n            104857600, self.resolver, 65536)\n\n    def close(self, code=None, reason=None):\n        \"\"\"Closes the websocket connection.\n\n        ``code`` and ``reason`` are documented under\n        `WebSocketHandler.close`.\n\n        .. versionadded:: 3.2\n\n        .. versionchanged:: 3.3\n\n           Added the ``code`` and ``reason`` arguments.\n        \"\"\"\n        if self.protocol is not None:\n            self.protocol.close(code, reason)\n            self.protocol = None\n\n    def _on_close(self):\n        self.on_message(None)\n        self.resolver.close()\n        super(WebSocketClientConnection, self)._on_close()\n\n    def _on_http_response(self, response):\n        if not self.connect_future.done():\n            if response.error:\n                self.connect_future.set_exception(response.error)\n            else:\n                self.connect_future.set_exception(WebSocketError(\n                    \"Non-websocket response\"))\n\n    def headers_received(self, start_line, headers):\n        if start_line.code != 101:\n            return super(WebSocketClientConnection, self).headers_received(\n                start_line, headers)\n\n        self.headers = headers\n        assert self.headers['Upgrade'].lower() == 'websocket'\n        assert self.headers['Connection'].lower() == 'upgrade'\n        accept = WebSocketProtocol13.compute_accept_value(self.key)\n        assert self.headers['Sec-Websocket-Accept'] == accept\n\n        self.protocol = WebSocketProtocol13(self, mask_outgoing=True)\n        self.protocol._receive_frame()\n\n        if self._timeout is not None:\n            self.io_loop.remove_timeout(self._timeout)\n            self._timeout = None\n\n        self.stream = self.connection.detach()\n        self.stream.set_close_callback(self._on_close)\n\n        self.connect_future.set_result(self)\n\n    def write_message(self, message, binary=False):\n        \"\"\"Sends a message to the WebSocket server.\"\"\"\n        self.protocol.write_message(message, binary)\n\n    def read_message(self, callback=None):\n        \"\"\"Reads a message from the WebSocket server.\n\n        Returns a future whose result is the message, or None\n        if the connection is closed.  If a callback argument\n        is given it will be called with the future when it is\n        ready.\n        \"\"\"\n        assert self.read_future is None\n        future = TracebackFuture()\n        if self.read_queue:\n            future.set_result(self.read_queue.popleft())\n        else:\n            self.read_future = future\n        if callback is not None:\n            self.io_loop.add_future(future, callback)\n        return future\n\n    def on_message(self, message):\n        if self.read_future is not None:\n            self.read_future.set_result(message)\n            self.read_future = None\n        else:\n            self.read_queue.append(message)\n\n    def on_pong(self, data):\n        pass\n\n\ndef websocket_connect(url, io_loop=None, callback=None, connect_timeout=None):\n    \"\"\"Client-side websocket support.\n\n    Takes a url and returns a Future whose result is a\n    `WebSocketClientConnection`.\n\n    .. versionchanged:: 3.2\n       Also accepts ``HTTPRequest`` objects in place of urls.\n    \"\"\"\n    if io_loop is None:\n        io_loop = IOLoop.current()\n    if isinstance(url, httpclient.HTTPRequest):\n        assert connect_timeout is None\n        request = url\n        # Copy and convert the headers dict/object (see comments in\n        # AsyncHTTPClient.fetch)\n        request.headers = httputil.HTTPHeaders(request.headers)\n    else:\n        request = httpclient.HTTPRequest(url, connect_timeout=connect_timeout)\n    request = httpclient._RequestProxy(\n        request, httpclient.HTTPRequest._DEFAULTS)\n    conn = WebSocketClientConnection(io_loop, request)\n    if callback is not None:\n        io_loop.add_future(conn.connect_future, callback)\n    return conn.connect_future\n\n\ndef _websocket_mask_python(mask, data):\n    \"\"\"Websocket masking function.\n\n    `mask` is a `bytes` object of length 4; `data` is a `bytes` object of any length.\n    Returns a `bytes` object of the same length as `data` with the mask applied\n    as specified in section 5.3 of RFC 6455.\n\n    This pure-python implementation may be replaced by an optimized version when available.\n    \"\"\"\n    mask = array.array(\"B\", mask)\n    unmasked = array.array(\"B\", data)\n    for i in xrange(len(data)):\n        unmasked[i] = unmasked[i] ^ mask[i % 4]\n    if hasattr(unmasked, 'tobytes'):\n        # tostring was deprecated in py32.  It hasn't been removed,\n        # but since we turn on deprecation warnings in our tests\n        # we need to use the right one.\n        return unmasked.tobytes()\n    else:\n        return unmasked.tostring()\n\nif (os.environ.get('TORNADO_NO_EXTENSION') or\n    os.environ.get('TORNADO_EXTENSION') == '0'):\n    # These environment variables exist to make it easier to do performance\n    # comparisons; they are not guaranteed to remain supported in the future.\n    _websocket_mask = _websocket_mask_python\nelse:\n    try:\n        from tornado.speedups import websocket_mask as _websocket_mask\n    except ImportError:\n        if os.environ.get('TORNADO_EXTENSION') == '1':\n            raise\n        _websocket_mask = _websocket_mask_python\n"}
A user will ask you to solve a task. You should first draft your thinking process (inner monologue). Then, generate the solution.

Your response format must follow the template below:
<think>
Your thoughts or/and draft, like working through an exercise on scratch paper. Be as casual and as long as you want until you are confident to generate a correct solution.
</think>
<solution>
Final solution presented to the user.
</solution>
system
We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[ISSUE]
**Title:** WebSocketHandler Does Not Reject Connections with Invalid Origin Headers

**Description:**
When initiating a WebSocket connection with an invalid Origin header, the server is expected to reject the connection to prevent unauthorized cross-origin access. Currently, connections with invalid Origin headers are not properly rejected, allowing potential security vulnerabilities.

**Example:**
Attempting to connect with an Origin header set to `'http://somewhereelse.com'`:

```python
url = 'ws://localhost:port/echo'
headers = {'Origin': 'http://somewhereelse.com'}
ws = websocket_connect(HTTPRequest(url, headers=headers), io_loop=self.io_loop)
```

**Expected Behavior:**
The server should respond with a **403 Forbidden** error, rejecting the WebSocket connection due to the invalid Origin.

**Actual Behavior:**
No error is raised, and the connection is unexpectedly accepted, allowing cross-origin WebSocket access.
[/ISSUE]
--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.

--- BEGIN FILE ---
```
### tornado/websocket.py
"""Implementation of the WebSocket protocol.

`WebSockets <http://dev.w3.org/html5/websockets/>`_ allow for bidirectional
communication between the browser and server.

.. warning::

   The WebSocket protocol was recently finalized as `RFC 6455
   <http://tools.ietf.org/html/rfc6455>`_ and is not yet supported in
   all browsers.  Refer to http://caniuse.com/websockets for details
   on compatibility.  In addition, during development the protocol
   went through several incompatible versions, and some browsers only
   support older versions.  By default this module only supports the
   latest version of the protocol, but optional support for an older
   version (known as "draft 76" or "hixie-76") can be enabled by
   overriding `WebSocketHandler.allow_draft76` (see that method's
   documentation for caveats).
"""

from __future__ import absolute_import, division, print_function, with_statement
# Author: Jacob Kristhammar, 2010

import array
import base64
import collections
import functools
import hashlib
import os
import struct
import time
import tornado.escape
import tornado.web

from tornado.concurrent import TracebackFuture
from tornado.escape import utf8, native_str, to_unicode
from tornado import httpclient, httputil
from tornado.ioloop import IOLoop
from tornado.iostream import StreamClosedError
from tornado.log import gen_log, app_log
from tornado.netutil import Resolver
from tornado import simple_httpclient
from tornado.util import bytes_type, unicode_type

try:
    from urllib.parse import urlparse # py2
except ImportError:
    from urlparse import urlparse # py3

try:
    xrange  # py2
except NameError:
    xrange = range  # py3


class WebSocketError(Exception):
    pass


class WebSocketClosedError(WebSocketError):
    """Raised by operations on a closed connection.

    .. versionadded:: 3.2
    """
    pass


class WebSocketHandler(tornado.web.RequestHandler):
    """Subclass this class to create a basic WebSocket handler.

    Override `on_message` to handle incoming messages, and use
    `write_message` to send messages to the client. You can also
    override `open` and `on_close` to handle opened and closed
    connections.

    See http://dev.w3.org/html5/websockets/ for details on the
    JavaScript interface.  The protocol is specified at
    http://tools.ietf.org/html/rfc6455.

    Here is an example WebSocket handler that echos back all received messages
    back to the client::

      class EchoWebSocket(websocket.WebSocketHandler):
          def open(self):
              print "WebSocket opened"

          def on_message(self, message):
              self.write_message(u"You said: " + message)

          def on_close(self):
              print "WebSocket closed"

    WebSockets are not standard HTTP connections. The "handshake" is
    HTTP, but after the handshake, the protocol is
    message-based. Consequently, most of the Tornado HTTP facilities
    are not available in handlers of this type. The only communication
    methods available to you are `write_message()`, `ping()`, and
    `close()`. Likewise, your request handler class should implement
    `open()` method rather than ``get()`` or ``post()``.

    If you map the handler above to ``/websocket`` in your application, you can
    invoke it in JavaScript with::

      var ws = new WebSocket("ws://localhost:8888/websocket");
      ws.onopen = function() {
         ws.send("Hello, world");
      };
      ws.onmessage = function (evt) {
         alert(evt.data);
      };

    This script pops up an alert box that says "You said: Hello, world".
    """
    def __init__(self, application, request, **kwargs):
        tornado.web.RequestHandler.__init__(self, application, request,
                                            **kwargs)
        self.ws_connection = None
        self.close_code = None
        self.close_reason = None

    @tornado.web.asynchronous
    def get(self, *args, **kwargs):
        self.open_args = args
        self.open_kwargs = kwargs

        self.stream = self.request.connection.detach()

        # Upgrade header should be present and should be equal to WebSocket
        if self.request.headers.get("Upgrade", "").lower() != 'websocket':
            self.stream.write(tornado.escape.utf8(
                "HTTP/1.1 400 Bad Request\r\n\r\n"
                "Can \"Upgrade\" only to \"WebSocket\"."
            ))
            self.stream.close()
            return

        # Connection header should be upgrade. Some proxy servers/load balancers
        # might mess with it.
        headers = self.request.headers
        connection = map(lambda s: s.strip().lower(), headers.get("Connection", "").split(","))
        if 'upgrade' not in connection:
            self.stream.write(tornado.escape.utf8(
                "HTTP/1.1 400 Bad Request\r\n\r\n"
                "\"Connection\" must be \"Upgrade\"."
            ))
            self.stream.close()
            return

        # The difference between version 8 and 13 is that in 8 the
        # client sends a "Sec-Websocket-Origin" header and in 13 it's
        # simply "Origin".
        if self.request.headers.get("Sec-WebSocket-Version") in ("7", "8", "13"):
            self.ws_connection = WebSocketProtocol13(self)
            self.ws_connection.accept_connection()
        elif (self.allow_draft76() and
              "Sec-WebSocket-Version" not in self.request.headers):
            self.ws_connection = WebSocketProtocol76(self)
            self.ws_connection.accept_connection()
        else:
            self.stream.write(tornado.escape.utf8(
                "HTTP/1.1 426 Upgrade Required\r\n"
                "Sec-WebSocket-Version: 8\r\n\r\n"))
            self.stream.close()

        if not self.check_origin():
            self.stream.write(tornado.escape.utf8(
                "HTTP/1.1 403 Cross Origin Websockets Disabled\r\n\r\n"
            ))
            self.stream.close()



    def write_message(self, message, binary=False):
        """Sends the given message to the client of this Web Socket.

        The message may be either a string or a dict (which will be
        encoded as json).  If the ``binary`` argument is false, the
        message will be sent as utf8; in binary mode any byte string
        is allowed.

        If the connection is already closed, raises `WebSocketClosedError`.

        .. versionchanged:: 3.2
           `WebSocketClosedError` was added (previously a closed connection
           would raise an `AttributeError`)
        """
        if self.ws_connection is None:
            raise WebSocketClosedError()
        if isinstance(message, dict):
            message = tornado.escape.json_encode(message)
        self.ws_connection.write_message(message, binary=binary)

    def select_subprotocol(self, subprotocols):
        """Invoked when a new WebSocket requests specific subprotocols.

        ``subprotocols`` is a list of strings identifying the
        subprotocols proposed by the client.  This method may be
        overridden to return one of those strings to select it, or
        ``None`` to not select a subprotocol.  Failure to select a
        subprotocol does not automatically abort the connection,
        although clients may close the connection if none of their
        proposed subprotocols was selected.
        """
        return None

    def open(self):
        """Invoked when a new WebSocket is opened.

        The arguments to `open` are extracted from the `tornado.web.URLSpec`
        regular expression, just like the arguments to
        `tornado.web.RequestHandler.get`.
        """
        pass

    def on_message(self, message):
        """Handle incoming messages on the WebSocket

        This method must be overridden.
        """
        raise NotImplementedError

    def ping(self, data):
        """Send ping frame to the remote end."""
        if self.ws_connection is None:
            raise WebSocketClosedError()
        self.ws_connection.write_ping(data)

    def on_pong(self, data):
        """Invoked when the response to a ping frame is received."""
        pass

    def on_close(self):
        """Invoked when the WebSocket is closed.

        If the connection was closed cleanly and a status code or reason
        phrase was supplied, these values will be available as the attributes
        ``self.close_code`` and ``self.close_reason``.

        .. versionchanged:: 3.3

           Added ``close_code`` and ``close_reason`` attributes.
        """
        pass

    def close(self, code=None, reason=None):
        """Closes this Web Socket.

        Once the close handshake is successful the socket will be closed.

        ``code`` may be a numeric status code, taken from the values
        defined in `RFC 6455 section 7.4.1
        <https://tools.ietf.org/html/rfc6455#section-7.4.1>`_.
        ``reason`` may be a textual message about why the connection is
        closing.  These values are made available to the client, but are
        not otherwise interpreted by the websocket protocol.

        The ``code`` and ``reason`` arguments are ignored in the "draft76"
        protocol version.

        .. versionchanged:: 3.3

           Added the ``code`` and ``reason`` arguments.
        """
        if self.ws_connection:
            self.ws_connection.close(code, reason)
            self.ws_connection = None

    def check_origin(self, allowed_origins=None):
        """Override to enable support for allowing alternate origins.
        
        By default, this checks to see that requests that provide both a host
        origin have the same origin and host This is a security protection
        against cross site scripting attacks on browsers,
        since WebSockets don't have CORS headers.
        
        >>> self.check_origins(allowed_origins=['localhost'])
        
        """
        # Handle WebSocket Origin naming convention differences
        # The difference between version 8 and 13 is that in 8 the
        # client sends a "Sec-Websocket-Origin" header and in 13 it's
        # simply "Origin".
        if self.request.headers.get("Sec-WebSocket-Version") in ("7", "8"):
            origin_header = self.request.headers.get("Sec-Websocket-Origin")
        else:
            origin_header = self.request.headers.get("Origin")

        host = self.request.headers.get("Host")

        # If no header is provided, assume request is not coming from a browser
        if(origin_header is None or host is None):
            return True

        parsed_origin = urlparse(origin_header)
        origin = parsed_origin.netloc

        if allowed_origins and origin in allowed_origins:
            return True

        # Check to see that origin matches host directly, including ports
        return origin == host

    def allow_draft76(self):
        """Override to enable support for the older "draft76" protocol.

        The draft76 version of the websocket protocol is disabled by
        default due to security concerns, but it can be enabled by
        overriding this method to return True.

        Connections using the draft76 protocol do not support the
        ``binary=True`` flag to `write_message`.

        Support for the draft76 protocol is deprecated and will be
        removed in a future version of Tornado.
        """
        return False

    def set_nodelay(self, value):
        """Set the no-delay flag for this stream.

        By default, small messages may be delayed and/or combined to minimize
        the number of packets sent.  This can sometimes cause 200-500ms delays
        due to the interaction between Nagle's algorithm and TCP delayed
        ACKs.  To reduce this delay (at the expense of possibly increasing
        bandwidth usage), call ``self.set_nodelay(True)`` once the websocket
        connection is established.

        See `.BaseIOStream.set_nodelay` for additional details.

        .. versionadded:: 3.1
        """
        self.stream.set_nodelay(value)

    def get_websocket_scheme(self):
        """Return the url scheme used for this request, either "ws" or "wss".

        This is normally decided by HTTPServer, but applications
        may wish to override this if they are using an SSL proxy
        that does not provide the X-Scheme header as understood
        by HTTPServer.

        Note that this is only used by the draft76 protocol.
        """
        return "wss" if self.request.protocol == "https" else "ws"

    def async_callback(self, callback, *args, **kwargs):
        """Obsolete - catches exceptions from the wrapped function.

        This function is normally unncecessary thanks to
        `tornado.stack_context`.
        """
        return self.ws_connection.async_callback(callback, *args, **kwargs)

    def _not_supported(self, *args, **kwargs):
        raise Exception("Method not supported for Web Sockets")

    def on_connection_close(self):
        if self.ws_connection:
            self.ws_connection.on_connection_close()
            self.ws_connection = None
            self.on_close()


for method in ["write", "redirect", "set_header", "send_error", "set_cookie",
               "set_status", "flush", "finish"]:
    setattr(WebSocketHandler, method, WebSocketHandler._not_supported)


class WebSocketProtocol(object):
    """Base class for WebSocket protocol versions.
    """
    def __init__(self, handler):
        self.handler = handler
        self.request = handler.request
        self.stream = handler.stream
        self.client_terminated = False
        self.server_terminated = False

    def async_callback(self, callback, *args, **kwargs):
        """Wrap callbacks with this if they are used on asynchronous requests.

        Catches exceptions properly and closes this WebSocket if an exception
        is uncaught.
        """
        if args or kwargs:
            callback = functools.partial(callback, *args, **kwargs)

        def wrapper(*args, **kwargs):
            try:
                return callback(*args, **kwargs)
            except Exception:
                app_log.error("Uncaught exception in %s",
                              self.request.path, exc_info=True)
                self._abort()
        return wrapper

    def on_connection_close(self):
        self._abort()

    def _abort(self):
        """Instantly aborts the WebSocket connection by closing the socket"""
        self.client_terminated = True
        self.server_terminated = True
        self.stream.close()  # forcibly tear down the connection
        self.close()  # let the subclass cleanup


class WebSocketProtocol76(WebSocketProtocol):
    """Implementation of the WebSockets protocol, version hixie-76.

    This class provides basic functionality to process WebSockets requests as
    specified in
    http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76
    """
    def __init__(self, handler):
        WebSocketProtocol.__init__(self, handler)
        self.challenge = None
        self._waiting = None

    def accept_connection(self):
        try:
            self._handle_websocket_headers()
        except ValueError:
            gen_log.debug("Malformed WebSocket request received")
            self._abort()
            return

        scheme = self.handler.get_websocket_scheme()

        # draft76 only allows a single subprotocol
        subprotocol_header = ''
        subprotocol = self.request.headers.get("Sec-WebSocket-Protocol", None)
        if subprotocol:
            selected = self.handler.select_subprotocol([subprotocol])
            if selected:
                assert selected == subprotocol
                subprotocol_header = "Sec-WebSocket-Protocol: %s\r\n" % selected

        # Write the initial headers before attempting to read the challenge.
        # This is necessary when using proxies (such as HAProxy), which
        # need to see the Upgrade headers before passing through the
        # non-HTTP traffic that follows.
        self.stream.write(tornado.escape.utf8(
            "HTTP/1.1 101 WebSocket Protocol Handshake\r\n"
            "Upgrade: WebSocket\r\n"
            "Connection: Upgrade\r\n"
            "Server: TornadoServer/%(version)s\r\n"
            "Sec-WebSocket-Origin: %(origin)s\r\n"
            "Sec-WebSocket-Location: %(scheme)s://%(host)s%(uri)s\r\n"
            "%(subprotocol)s"
            "\r\n" % (dict(
                version=tornado.version,
                origin=self.request.headers["Origin"],
                scheme=scheme,
                host=self.request.host,
                uri=self.request.uri,
                subprotocol=subprotocol_header))))
        self.stream.read_bytes(8, self._handle_challenge)

    def challenge_response(self, challenge):
        """Generates the challenge response that's needed in the handshake

        The challenge parameter should be the raw bytes as sent from the
        client.
        """
        key_1 = self.request.headers.get("Sec-Websocket-Key1")
        key_2 = self.request.headers.get("Sec-Websocket-Key2")
        try:
            part_1 = self._calculate_part(key_1)
            part_2 = self._calculate_part(key_2)
        except ValueError:
            raise ValueError("Invalid Keys/Challenge")
        return self._generate_challenge_response(part_1, part_2, challenge)

    def _handle_challenge(self, challenge):
        try:
            challenge_response = self.challenge_response(challenge)
        except ValueError:
            gen_log.debug("Malformed key data in WebSocket request")
            self._abort()
            return
        self._write_response(challenge_response)

    def _write_response(self, challenge):
        self.stream.write(challenge)
        self.async_callback(self.handler.open)(*self.handler.open_args, **self.handler.open_kwargs)
        self._receive_message()

    def _handle_websocket_headers(self):
        """Verifies all invariant- and required headers

        If a header is missing or have an incorrect value ValueError will be
        raised
        """
        fields = ("Origin", "Host", "Sec-Websocket-Key1",
                  "Sec-Websocket-Key2")
        if not all(map(lambda f: self.request.headers.get(f), fields)):
            raise ValueError("Missing/Invalid WebSocket headers")

    def _calculate_part(self, key):
        """Processes the key headers and calculates their key value.

        Raises ValueError when feed invalid key."""
        # pyflakes complains about variable reuse if both of these lines use 'c'
        number = int(''.join(c for c in key if c.isdigit()))
        spaces = len([c2 for c2 in key if c2.isspace()])
        try:
            key_number = number // spaces
        except (ValueError, ZeroDivisionError):
            raise ValueError
        return struct.pack(">I", key_number)

    def _generate_challenge_response(self, part_1, part_2, part_3):
        m = hashlib.md5()
        m.update(part_1)
        m.update(part_2)
        m.update(part_3)
        return m.digest()

    def _receive_message(self):
        self.stream.read_bytes(1, self._on_frame_type)

    def _on_frame_type(self, byte):
        frame_type = ord(byte)
        if frame_type == 0x00:
            self.stream.read_until(b"\xff", self._on_end_delimiter)
        elif frame_type == 0xff:
            self.stream.read_bytes(1, self._on_length_indicator)
        else:
            self._abort()

    def _on_end_delimiter(self, frame):
        if not self.client_terminated:
            self.async_callback(self.handler.on_message)(
                frame[:-1].decode("utf-8", "replace"))
        if not self.client_terminated:
            self._receive_message()

    def _on_length_indicator(self, byte):
        if ord(byte) != 0x00:
            self._abort()
            return
        self.client_terminated = True
        self.close()

    def write_message(self, message, binary=False):
        """Sends the given message to the client of this Web Socket."""
        if binary:
            raise ValueError(
                "Binary messages not supported by this version of websockets")
        if isinstance(message, unicode_type):
            message = message.encode("utf-8")
        assert isinstance(message, bytes_type)
        self.stream.write(b"\x00" + message + b"\xff")

    def write_ping(self, data):
        """Send ping frame."""
        raise ValueError("Ping messages not supported by this version of websockets")

    def close(self, code=None, reason=None):
        """Closes the WebSocket connection."""
        if not self.server_terminated:
            if not self.stream.closed():
                self.stream.write("\xff\x00")
            self.server_terminated = True
        if self.client_terminated:
            if self._waiting is not None:
                self.stream.io_loop.remove_timeout(self._waiting)
            self._waiting = None
            self.stream.close()
        elif self._waiting is None:
            self._waiting = self.stream.io_loop.add_timeout(
                time.time() + 5, self._abort)


class WebSocketProtocol13(WebSocketProtocol):
    """Implementation of the WebSocket protocol from RFC 6455.

    This class supports versions 7 and 8 of the protocol in addition to the
    final version 13.
    """
    def __init__(self, handler, mask_outgoing=False):
        WebSocketProtocol.__init__(self, handler)
        self.mask_outgoing = mask_outgoing
        self._final_frame = False
        self._frame_opcode = None
        self._masked_frame = None
        self._frame_mask = None
        self._frame_length = None
        self._fragmented_message_buffer = None
        self._fragmented_message_opcode = None
        self._waiting = None

    def accept_connection(self):
        try:
            self._handle_websocket_headers()
            self._accept_connection()
        except ValueError:
            gen_log.debug("Malformed WebSocket request received", exc_info=True)
            self._abort()
            return

    def _handle_websocket_headers(self):
        """Verifies all invariant- and required headers

        If a header is missing or have an incorrect value ValueError will be
        raised
        """
        fields = ("Host", "Sec-Websocket-Key", "Sec-Websocket-Version")
        if not all(map(lambda f: self.request.headers.get(f), fields)):
            raise ValueError("Missing/Invalid WebSocket headers")

    @staticmethod
    def compute_accept_value(key):
        """Computes the value for the Sec-WebSocket-Accept header,
        given the value for Sec-WebSocket-Key.
        """
        sha1 = hashlib.sha1()
        sha1.update(utf8(key))
        sha1.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11")  # Magic value
        return native_str(base64.b64encode(sha1.digest()))

    def _challenge_response(self):
        return WebSocketProtocol13.compute_accept_value(
            self.request.headers.get("Sec-Websocket-Key"))

    def _accept_connection(self):
        subprotocol_header = ''
        subprotocols = self.request.headers.get("Sec-WebSocket-Protocol", '')
        subprotocols = [s.strip() for s in subprotocols.split(',')]
        if subprotocols:
            selected = self.handler.select_subprotocol(subprotocols)
            if selected:
                assert selected in subprotocols
                subprotocol_header = "Sec-WebSocket-Protocol: %s\r\n" % selected

        self.stream.write(tornado.escape.utf8(
            "HTTP/1.1 101 Switching Protocols\r\n"
            "Upgrade: websocket\r\n"
            "Connection: Upgrade\r\n"
            "Sec-WebSocket-Accept: %s\r\n"
            "%s"
            "\r\n" % (self._challenge_response(), subprotocol_header)))

        self.async_callback(self.handler.open)(*self.handler.open_args, **self.handler.open_kwargs)
        self._receive_frame()

    def _write_frame(self, fin, opcode, data):
        if fin:
            finbit = 0x80
        else:
            finbit = 0
        frame = struct.pack("B", finbit | opcode)
        l = len(data)
        if self.mask_outgoing:
            mask_bit = 0x80
        else:
            mask_bit = 0
        if l < 126:
            frame += struct.pack("B", l | mask_bit)
        elif l <= 0xFFFF:
            frame += struct.pack("!BH", 126 | mask_bit, l)
        else:
            frame += struct.pack("!BQ", 127 | mask_bit, l)
        if self.mask_outgoing:
            mask = os.urandom(4)
            data = mask + _websocket_mask(mask, data)
        frame += data
        self.stream.write(frame)

    def write_message(self, message, binary=False):
        """Sends the given message to the client of this Web Socket."""
        if binary:
            opcode = 0x2
        else:
            opcode = 0x1
        message = tornado.escape.utf8(message)
        assert isinstance(message, bytes_type)
        try:
            self._write_frame(True, opcode, message)
        except StreamClosedError:
            self._abort()

    def write_ping(self, data):
        """Send ping frame."""
        assert isinstance(data, bytes_type)
        self._write_frame(True, 0x9, data)

    def _receive_frame(self):
        try:
            self.stream.read_bytes(2, self._on_frame_start)
        except StreamClosedError:
            self._abort()

    def _on_frame_start(self, data):
        header, payloadlen = struct.unpack("BB", data)
        self._final_frame = header & 0x80
        reserved_bits = header & 0x70
        self._frame_opcode = header & 0xf
        self._frame_opcode_is_control = self._frame_opcode & 0x8
        if reserved_bits:
            # client is using as-yet-undefined extensions; abort
            self._abort()
            return
        self._masked_frame = bool(payloadlen & 0x80)
        payloadlen = payloadlen & 0x7f
        if self._frame_opcode_is_control and payloadlen >= 126:
            # control frames must have payload < 126
            self._abort()
            return
        try:
            if payloadlen < 126:
                self._frame_length = payloadlen
                if self._masked_frame:
                    self.stream.read_bytes(4, self._on_masking_key)
                else:
                    self.stream.read_bytes(self._frame_length, self._on_frame_data)
            elif payloadlen == 126:
                self.stream.read_bytes(2, self._on_frame_length_16)
            elif payloadlen == 127:
                self.stream.read_bytes(8, self._on_frame_length_64)
        except StreamClosedError:
            self._abort()

    def _on_frame_length_16(self, data):
        self._frame_length = struct.unpack("!H", data)[0]
        try:
            if self._masked_frame:
                self.stream.read_bytes(4, self._on_masking_key)
            else:
                self.stream.read_bytes(self._frame_length, self._on_frame_data)
        except StreamClosedError:
            self._abort()

    def _on_frame_length_64(self, data):
        self._frame_length = struct.unpack("!Q", data)[0]
        try:
            if self._masked_frame:
                self.stream.read_bytes(4, self._on_masking_key)
            else:
                self.stream.read_bytes(self._frame_length, self._on_frame_data)
        except StreamClosedError:
            self._abort()

    def _on_masking_key(self, data):
        self._frame_mask = data
        try:
            self.stream.read_bytes(self._frame_length, self._on_masked_frame_data)
        except StreamClosedError:
            self._abort()

    def _on_masked_frame_data(self, data):
        self._on_frame_data(_websocket_mask(self._frame_mask, data))

    def _on_frame_data(self, data):
        if self._frame_opcode_is_control:
            # control frames may be interleaved with a series of fragmented
            # data frames, so control frames must not interact with
            # self._fragmented_*
            if not self._final_frame:
                # control frames must not be fragmented
                self._abort()
                return
            opcode = self._frame_opcode
        elif self._frame_opcode == 0:  # continuation frame
            if self._fragmented_message_buffer is None:
                # nothing to continue
                self._abort()
                return
            self._fragmented_message_buffer += data
            if self._final_frame:
                opcode = self._fragmented_message_opcode
                data = self._fragmented_message_buffer
                self._fragmented_message_buffer = None
        else:  # start of new data message
            if self._fragmented_message_buffer is not None:
                # can't start new message until the old one is finished
                self._abort()
                return
            if self._final_frame:
                opcode = self._frame_opcode
            else:
                self._fragmented_message_opcode = self._frame_opcode
                self._fragmented_message_buffer = data

        if self._final_frame:
            self._handle_message(opcode, data)

        if not self.client_terminated:
            self._receive_frame()

    def _handle_message(self, opcode, data):
        if self.client_terminated:
            return

        if opcode == 0x1:
            # UTF-8 data
            try:
                decoded = data.decode("utf-8")
            except UnicodeDecodeError:
                self._abort()
                return
            self.async_callback(self.handler.on_message)(decoded)
        elif opcode == 0x2:
            # Binary data
            self.async_callback(self.handler.on_message)(data)
        elif opcode == 0x8:
            # Close
            self.client_terminated = True
            if len(data) >= 2:
                self.handler.close_code = struct.unpack('>H', data[:2])[0]
            if len(data) > 2:
                self.handler.close_reason = to_unicode(data[2:])
            self.close()
        elif opcode == 0x9:
            # Ping
            self._write_frame(True, 0xA, data)
        elif opcode == 0xA:
            # Pong
            self.async_callback(self.handler.on_pong)(data)
        else:
            self._abort()

    def close(self, code=None, reason=None):
        """Closes the WebSocket connection."""
        if not self.server_terminated:
            if not self.stream.closed():
                if code is None and reason is not None:
                    code = 1000  # "normal closure" status code
                if code is None:
                    close_data = b''
                else:
                    close_data = struct.pack('>H', code)
                if reason is not None:
                    close_data += utf8(reason)
                self._write_frame(True, 0x8, close_data)
            self.server_terminated = True
        if self.client_terminated:
            if self._waiting is not None:
                self.stream.io_loop.remove_timeout(self._waiting)
                self._waiting = None
            self.stream.close()
        elif self._waiting is None:
            # Give the client a few seconds to complete a clean shutdown,
            # otherwise just close the connection.
            self._waiting = self.stream.io_loop.add_timeout(
                self.stream.io_loop.time() + 5, self._abort)


class WebSocketClientConnection(simple_httpclient._HTTPConnection):
    """WebSocket client connection.

    This class should not be instantiated directly; use the
    `websocket_connect` function instead.
    """
    def __init__(self, io_loop, request):
        self.connect_future = TracebackFuture()
        self.read_future = None
        self.read_queue = collections.deque()
        self.key = base64.b64encode(os.urandom(16))

        scheme, sep, rest = request.url.partition(':')
        scheme = {'ws': 'http', 'wss': 'https'}[scheme]
        request.url = scheme + sep + rest
        request.headers.update({
            'Upgrade': 'websocket',
            'Connection': 'Upgrade',
            'Sec-WebSocket-Key': self.key,
            'Sec-WebSocket-Version': '13',
        })

        self.resolver = Resolver(io_loop=io_loop)
        super(WebSocketClientConnection, self).__init__(
            io_loop, None, request, lambda: None, self._on_http_response,
            104857600, self.resolver, 65536)

    def close(self, code=None, reason=None):
        """Closes the websocket connection.

        ``code`` and ``reason`` are documented under
        `WebSocketHandler.close`.

        .. versionadded:: 3.2

        .. versionchanged:: 3.3

           Added the ``code`` and ``reason`` arguments.
        """
        if self.protocol is not None:
            self.protocol.close(code, reason)
            self.protocol = None

    def _on_close(self):
        self.on_message(None)
        self.resolver.close()
        super(WebSocketClientConnection, self)._on_close()

    def _on_http_response(self, response):
        if not self.connect_future.done():
            if response.error:
                self.connect_future.set_exception(response.error)
            else:
                self.connect_future.set_exception(WebSocketError(
                    "Non-websocket response"))

    def headers_received(self, start_line, headers):
        if start_line.code != 101:
            return super(WebSocketClientConnection, self).headers_received(
                start_line, headers)

        self.headers = headers
        assert self.headers['Upgrade'].lower() == 'websocket'
        assert self.headers['Connection'].lower() == 'upgrade'
        accept = WebSocketProtocol13.compute_accept_value(self.key)
        assert self.headers['Sec-Websocket-Accept'] == accept

        self.protocol = WebSocketProtocol13(self, mask_outgoing=True)
        self.protocol._receive_frame()

        if self._timeout is not None:
            self.io_loop.remove_timeout(self._timeout)
            self._timeout = None

        self.stream = self.connection.detach()
        self.stream.set_close_callback(self._on_close)

        self.connect_future.set_result(self)

    def write_message(self, message, binary=False):
        """Sends a message to the WebSocket server."""
        self.protocol.write_message(message, binary)

    def read_message(self, callback=None):
        """Reads a message from the WebSocket server.

        Returns a future whose result is the message, or None
        if the connection is closed.  If a callback argument
        is given it will be called with the future when it is
        ready.
        """
        assert self.read_future is None
        future = TracebackFuture()
        if self.read_queue:
            future.set_result(self.read_queue.popleft())
        else:
            self.read_future = future
        if callback is not None:
            self.io_loop.add_future(future, callback)
        return future

    def on_message(self, message):
        if self.read_future is not None:
            self.read_future.set_result(message)
            self.read_future = None
        else:
            self.read_queue.append(message)

    def on_pong(self, data):
        pass


def websocket_connect(url, io_loop=None, callback=None, connect_timeout=None):
    """Client-side websocket support.

    Takes a url and returns a Future whose result is a
    `WebSocketClientConnection`.

    .. versionchanged:: 3.2
       Also accepts ``HTTPRequest`` objects in place of urls.
    """
    if io_loop is None:
        io_loop = IOLoop.current()
    if isinstance(url, httpclient.HTTPRequest):
        assert connect_timeout is None
        request = url
        # Copy and convert the headers dict/object (see comments in
        # AsyncHTTPClient.fetch)
        request.headers = httputil.HTTPHeaders(request.headers)
    else:
        request = httpclient.HTTPRequest(url, connect_timeout=connect_timeout)
    request = httpclient._RequestProxy(
        request, httpclient.HTTPRequest._DEFAULTS)
    conn = WebSocketClientConnection(io_loop, request)
    if callback is not None:
        io_loop.add_future(conn.connect_future, callback)
    return conn.connect_future


def _websocket_mask_python(mask, data):
    """Websocket masking function.

    `mask` is a `bytes` object of length 4; `data` is a `bytes` object of any length.
    Returns a `bytes` object of the same length as `data` with the mask applied
    as specified in section 5.3 of RFC 6455.

    This pure-python implementation may be replaced by an optimized version when available.
    """
    mask = array.array("B", mask)
    unmasked = array.array("B", data)
    for i in xrange(len(data)):
        unmasked[i] = unmasked[i] ^ mask[i % 4]
    if hasattr(unmasked, 'tobytes'):
        # tostring was deprecated in py32.  It hasn't been removed,
        # but since we turn on deprecation warnings in our tests
        # we need to use the right one.
        return unmasked.tobytes()
    else:
        return unmasked.tostring()

if (os.environ.get('TORNADO_NO_EXTENSION') or
    os.environ.get('TORNADO_EXTENSION') == '0'):
    # These environment variables exist to make it easier to do performance
    # comparisons; they are not guaranteed to remain supported in the future.
    _websocket_mask = _websocket_mask_python
else:
    try:
        from tornado.speedups import websocket_mask as _websocket_mask
    except ImportError:
        if os.environ.get('TORNADO_EXTENSION') == '1':
            raise
        _websocket_mask = _websocket_mask_python

```
--- END FILE ---

Please first localize the bug based on the issue statement, and then generate *SEARCH/REPLACE* edits to fix the issue.

Every *SEARCH/REPLACE* edit must use this format:
1. The file path
2. The start of search block: <<<<<<< SEARCH
3. A contiguous chunk of lines to search for in the existing source code
4. The dividing line: =======
5. The lines to replace into the source code
6. The end of the replace block: >>>>>>> REPLACE

Here is an example:

```python
### mathweb/flask/app.py
<<<<<<< SEARCH
from flask import Flask
=======
import math
from flask import Flask
>>>>>>> REPLACE
```
</solution>

Please note that the *SEARCH/REPLACE* edit REQUIRES PROPER INDENTATION. If you would like to add the line '        print(x)', you must fully write that out, with all those spaces before the code!
Wrap each *SEARCH/REPLACE* edit in a code block as shown in the example above. If you have multiple *SEARCH/REPLACE* edits, use a separate code block for each one.
user