{
    "file_diffs": [
        {
            "old_file_content": "\"\"\"WebSocket protocol versions 13 and 8.\"\"\"\n\n__all__ = ['WebSocketParser', 'WebSocketWriter', 'do_handshake',\n           'Message', 'WebSocketError',\n           'MSG_TEXT', 'MSG_BINARY', 'MSG_CLOSE', 'MSG_PING', 'MSG_PONG']\n\nimport base64\nimport binascii\nimport collections\nimport hashlib\nimport struct\nfrom aiohttp import errors\n\n# Frame opcodes defined in the spec.\nOPCODE_CONTINUATION = 0x0\nMSG_TEXT = OPCODE_TEXT = 0x1\nMSG_BINARY = OPCODE_BINARY = 0x2\nMSG_CLOSE = OPCODE_CLOSE = 0x8\nMSG_PING = OPCODE_PING = 0x9\nMSG_PONG = OPCODE_PONG = 0xa\n\nWS_KEY = b'258EAFA5-E914-47DA-95CA-C5AB0DC85B11'\nWS_HDRS = ('UPGRADE', 'CONNECTION',\n           'SEC-WEBSOCKET-VERSION', 'SEC-WEBSOCKET-KEY', 'SEC-WEBSOCKET-PROTOCOL')\n\nMessage = collections.namedtuple('Message', ['tp', 'data', 'extra'])\n\n\nclass WebSocketError(Exception):\n    \"\"\"WebSocket protocol parser error.\"\"\"\n\n\ndef WebSocketParser(out, buf):\n    while True:\n        message = yield from parse_message(buf)\n        out.feed_data(message)\n\n        if message.tp == MSG_CLOSE:\n            out.feed_eof()\n            break\n\n\ndef parse_frame(buf):\n    \"\"\"Return the next frame from the socket.\"\"\"\n    # read header\n    data = yield from buf.read(2)\n    first_byte, second_byte = struct.unpack('!BB', data)\n\n    fin = (first_byte >> 7) & 1\n    rsv1 = (first_byte >> 6) & 1\n    rsv2 = (first_byte >> 5) & 1\n    rsv3 = (first_byte >> 4) & 1\n    opcode = first_byte & 0xf\n\n    # frame-fin = %x0 ; more frames of this message follow\n    #           / %x1 ; final frame of this message\n    # frame-rsv1 = %x0 ; 1 bit, MUST be 0 unless negotiated otherwise\n    # frame-rsv2 = %x0 ; 1 bit, MUST be 0 unless negotiated otherwise\n    # frame-rsv3 = %x0 ; 1 bit, MUST be 0 unless negotiated otherwise\n    if rsv1 or rsv2 or rsv3:\n        raise WebSocketError('Received frame with non-zero reserved bits')\n\n    if opcode > 0x7 and fin == 0:\n        raise WebSocketError('Received fragmented control frame')\n\n    if fin == 0 and opcode == OPCODE_CONTINUATION:\n        raise WebSocketError(\n            'Received new fragment frame with non-zero opcode')\n\n    has_mask = (second_byte >> 7) & 1\n    length = (second_byte) & 0x7f\n\n    # Control frames MUST have a payload length of 125 bytes or less\n    if opcode > 0x7 and length > 125:\n        raise WebSocketError(\n            \"Control frame payload cannot be larger than 125 bytes\")\n\n    # read payload\n    if length == 126:\n        data = yield from buf.read(2)\n        length = struct.unpack_from('!H', data)[0]\n    elif length > 126:\n        data = yield from buf.read(8)\n        length = struct.unpack_from('!Q', data)[0]\n\n    if has_mask:\n        mask = yield from buf.read(4)\n\n    if length:\n        payload = yield from buf.read(length)\n    else:\n        payload = b''\n\n    if has_mask:\n        payload = bytes(b ^ mask[i % 4] for i, b in enumerate(payload))\n\n    return fin, opcode, payload\n\n\ndef parse_message(buf):\n    fin, opcode, payload = yield from parse_frame(buf)\n\n    if opcode == OPCODE_CLOSE:\n        if len(payload) >= 2:\n            close_code = struct.unpack('!H', payload[:2])[0]\n            close_message = payload[2:]\n            return Message(OPCODE_CLOSE, close_code, close_message)\n        elif payload:\n            raise WebSocketError(\n                'Invalid close frame: {} {} {!r}'.format(fin, opcode, payload))\n        return Message(OPCODE_CLOSE, '', '')\n\n    elif opcode == OPCODE_PING:\n        return Message(OPCODE_PING, '', '')\n\n    elif opcode == OPCODE_PONG:\n        return Message(OPCODE_PONG, '', '')\n\n    elif opcode not in (OPCODE_TEXT, OPCODE_BINARY):\n        raise WebSocketError(\"Unexpected opcode={!r}\".format(opcode))\n\n    # load text/binary\n    data = [payload]\n\n    while not fin:\n        fin, _opcode, payload = yield from parse_frame(buf)\n        if _opcode != OPCODE_CONTINUATION:\n            raise WebSocketError(\n                'The opcode in non-fin frame is expected '\n                'to be zero, got {!r}'.format(opcode))\n        else:\n            data.append(payload)\n\n    if opcode == OPCODE_TEXT:\n        return Message(OPCODE_TEXT, b''.join(data).decode('utf-8'), '')\n    else:\n        return Message(OPCODE_BINARY, b''.join(data), '')\n\n\nclass WebSocketWriter:\n\n    def __init__(self, writer):\n        self.writer = writer\n\n    def _send_frame(self, message, opcode):\n        \"\"\"Send a frame over the websocket with message as its payload.\"\"\"\n        header = bytes([0x80 | opcode])\n        msg_length = len(message)\n\n        if msg_length < 126:\n            header += bytes([msg_length])\n        elif msg_length < (1 << 16):\n            header += bytes([126]) + struct.pack('!H', msg_length)\n        else:\n            header += bytes([127]) + struct.pack('!Q', msg_length)\n\n        self.writer.write(header + message)\n\n    def pong(self):\n        \"\"\"Send pong message.\"\"\"\n        self._send_frame(b'', OPCODE_PONG)\n\n    def ping(self):\n        \"\"\"Send pong message.\"\"\"\n        self._send_frame(b'', OPCODE_PING)\n\n    def send(self, message, binary=False):\n        \"\"\"Send a frame over the websocket with message as its payload.\"\"\"\n        if isinstance(message, str):\n            message = message.encode('utf-8')\n        if binary:\n            self._send_frame(message, OPCODE_BINARY)\n        else:\n            self._send_frame(message, OPCODE_TEXT)\n\n    def close(self, code=1000, message=b''):\n        \"\"\"Close the websocket, sending the specified code and message.\"\"\"\n        if isinstance(message, str):\n            message = message.encode('utf-8')\n        self._send_frame(\n            struct.pack('!H%ds' % len(message), code, message),\n            opcode=OPCODE_CLOSE)\n\n\ndef do_handshake(method, headers, transport, protocols=()):\n    \"\"\"Prepare WebSocket handshake. It return http response code,\n    response headers, websocket parser, websocket writer. It does not\n    perform any IO.\n\n    `protocols` is a sequence of known protocols. On successful handshake,\n    the returned response headers contain the first protocol in this list\n    which the server also knows.\"\"\"\n\n    # WebSocket accepts only GET\n    if method.upper() != 'GET':\n        raise errors.HttpErrorException(405, headers=(('Allow', 'GET'),))\n\n    if 'websocket' != headers.get('UPGRADE', '').lower().strip():\n        raise errors.HttpBadRequest(\n            'No WebSocket UPGRADE hdr: {}\\n'\n            'Can \"Upgrade\" only to \"WebSocket\".'.format(\n                headers.get('UPGRADE')))\n\n    if 'upgrade' not in headers.get('CONNECTION', '').lower():\n        raise errors.HttpBadRequest(\n            'No CONNECTION upgrade hdr: {}'.format(\n                headers.get('CONNECTION')))\n    \n    # find common sub-protocol between client and server\n    protocol = None\n    if 'SEC-WEBSOCKET-PROTOCOL' in headers:\n        req_protocols = {str(proto.strip()) for proto in\n            headers['SEC-WEBSOCKET-PROTOCOL'].split(',')}\n        \n        for proto in protocols:\n            if proto in req_protocols:\n                protocol = proto\n                break\n        else:\n            raise errors.HttpBadRequest(\n                'Client protocols {} don’t overlap server-known ones {}'\n                .format(protocols, req_protocols))\n\n    # check supported version\n    version = headers.get('SEC-WEBSOCKET-VERSION')\n    if version not in ('13', '8', '7'):\n        raise errors.HttpBadRequest(\n            'Unsupported version: {}'.format(version))\n\n    # check client handshake for validity\n    key = headers.get('SEC-WEBSOCKET-KEY')\n    try:\n        if not key or len(base64.b64decode(key)) != 16:\n            raise errors.HttpBadRequest(\n                'Handshake error: {!r}'.format(key))\n    except binascii.Error:\n        raise errors.HttpBadRequest(\n            'Handshake error: {!r}'.format(key)) from None\n\n    response_headers = [('UPGRADE', 'websocket'),\n             ('CONNECTION', 'upgrade'),\n             ('TRANSFER-ENCODING', 'chunked'),\n             ('SEC-WEBSOCKET-ACCEPT', base64.b64encode(\n                 hashlib.sha1(key.encode() + WS_KEY).digest()).decode())]\n    \n    if protocol:\n        response_headers.append(('SEC-WEBSOCKET-PROTOCOL', protocol))\n\n    # response code, headers, parser, writer\n    return (101,\n            response_headers,\n            WebSocketParser,\n            WebSocketWriter(transport))\n",
            "new_file_content": "\"\"\"WebSocket protocol versions 13 and 8.\"\"\"\n\n__all__ = ['WebSocketParser', 'WebSocketWriter', 'do_handshake',\n           'Message', 'WebSocketError',\n           'MSG_TEXT', 'MSG_BINARY', 'MSG_CLOSE', 'MSG_PING', 'MSG_PONG']\n\nimport base64\nimport binascii\nimport collections\nimport hashlib\nimport struct\nfrom aiohttp import errors\n\n# Frame opcodes defined in the spec.\nOPCODE_CONTINUATION = 0x0\nMSG_TEXT = OPCODE_TEXT = 0x1\nMSG_BINARY = OPCODE_BINARY = 0x2\nMSG_CLOSE = OPCODE_CLOSE = 0x8\nMSG_PING = OPCODE_PING = 0x9\nMSG_PONG = OPCODE_PONG = 0xa\n\nWS_KEY = b'258EAFA5-E914-47DA-95CA-C5AB0DC85B11'\nWS_HDRS = ('UPGRADE', 'CONNECTION',\n           'SEC-WEBSOCKET-VERSION', 'SEC-WEBSOCKET-KEY', 'SEC-WEBSOCKET-PROTOCOL')\n\nMessage = collections.namedtuple('Message', ['tp', 'data', 'extra'])\n\n\nclass WebSocketError(Exception):\n    \"\"\"WebSocket protocol parser error.\"\"\"\n\n\ndef WebSocketParser(out, buf):\n    while True:\n        message = yield from parse_message(buf)\n        out.feed_data(message)\n\n        if message.tp == MSG_CLOSE:\n            out.feed_eof()\n            break\n\n\ndef parse_frame(buf):\n    \"\"\"Return the next frame from the socket.\"\"\"\n    # read header\n    data = yield from buf.read(2)\n    first_byte, second_byte = struct.unpack('!BB', data)\n\n    fin = (first_byte >> 7) & 1\n    rsv1 = (first_byte >> 6) & 1\n    rsv2 = (first_byte >> 5) & 1\n    rsv3 = (first_byte >> 4) & 1\n    opcode = first_byte & 0xf\n\n    # frame-fin = %x0 ; more frames of this message follow\n    #           / %x1 ; final frame of this message\n    # frame-rsv1 = %x0 ; 1 bit, MUST be 0 unless negotiated otherwise\n    # frame-rsv2 = %x0 ; 1 bit, MUST be 0 unless negotiated otherwise\n    # frame-rsv3 = %x0 ; 1 bit, MUST be 0 unless negotiated otherwise\n    if rsv1 or rsv2 or rsv3:\n        raise WebSocketError('Received frame with non-zero reserved bits')\n\n    if opcode > 0x7 and fin == 0:\n        raise WebSocketError('Received fragmented control frame')\n\n    if fin == 0 and opcode == OPCODE_CONTINUATION:\n        raise WebSocketError(\n            'Received new fragment frame with non-zero opcode')\n\n    has_mask = (second_byte >> 7) & 1\n    length = (second_byte) & 0x7f\n\n    # Control frames MUST have a payload length of 125 bytes or less\n    if opcode > 0x7 and length > 125:\n        raise WebSocketError(\n            \"Control frame payload cannot be larger than 125 bytes\")\n\n    # read payload\n    if length == 126:\n        data = yield from buf.read(2)\n        length = struct.unpack_from('!H', data)[0]\n    elif length > 126:\n        data = yield from buf.read(8)\n        length = struct.unpack_from('!Q', data)[0]\n\n    if has_mask:\n        mask = yield from buf.read(4)\n\n    if length:\n        payload = yield from buf.read(length)\n    else:\n        payload = b''\n\n    if has_mask:\n        payload = bytes(b ^ mask[i % 4] for i, b in enumerate(payload))\n\n    return fin, opcode, payload\n\n\ndef parse_message(buf):\n    fin, opcode, payload = yield from parse_frame(buf)\n\n    if opcode == OPCODE_CLOSE:\n        if len(payload) >= 2:\n            close_code = struct.unpack('!H', payload[:2])[0]\n            close_message = payload[2:]\n            return Message(OPCODE_CLOSE, close_code, close_message)\n        elif payload:\n            raise WebSocketError(\n                'Invalid close frame: {} {} {!r}'.format(fin, opcode, payload))\n        return Message(OPCODE_CLOSE, '', '')\n\n    elif opcode == OPCODE_PING:\n        return Message(OPCODE_PING, '', '')\n\n    elif opcode == OPCODE_PONG:\n        return Message(OPCODE_PONG, '', '')\n\n    elif opcode not in (OPCODE_TEXT, OPCODE_BINARY):\n        raise WebSocketError(\"Unexpected opcode={!r}\".format(opcode))\n\n    # load text/binary\n    data = [payload]\n\n    while not fin:\n        fin, _opcode, payload = yield from parse_frame(buf)\n        if _opcode != OPCODE_CONTINUATION:\n            raise WebSocketError(\n                'The opcode in non-fin frame is expected '\n                'to be zero, got {!r}'.format(opcode))\n        else:\n            data.append(payload)\n\n    if opcode == OPCODE_TEXT:\n        return Message(OPCODE_TEXT, b''.join(data).decode('utf-8'), '')\n    else:\n        return Message(OPCODE_BINARY, b''.join(data), '')\n\n\nclass WebSocketWriter:\n\n    def __init__(self, writer):\n        self.writer = writer\n\n    def _send_frame(self, message, opcode):\n        \"\"\"Send a frame over the websocket with message as its payload.\"\"\"\n        header = bytes([0x80 | opcode])\n        msg_length = len(message)\n\n        if msg_length < 126:\n            header += bytes([msg_length])\n        elif msg_length < (1 << 16):\n            header += bytes([126]) + struct.pack('!H', msg_length)\n        else:\n            header += bytes([127]) + struct.pack('!Q', msg_length)\n\n        self.writer.write(header + message)\n\n    def pong(self):\n        \"\"\"Send pong message.\"\"\"\n        self._send_frame(b'', OPCODE_PONG)\n\n    def ping(self):\n        \"\"\"Send pong message.\"\"\"\n        self._send_frame(b'', OPCODE_PING)\n\n    def send(self, message, binary=False):\n        \"\"\"Send a frame over the websocket with message as its payload.\"\"\"\n        if isinstance(message, str):\n            message = message.encode('utf-8')\n        if binary:\n            self._send_frame(message, OPCODE_BINARY)\n        else:\n            self._send_frame(message, OPCODE_TEXT)\n\n    def close(self, code=1000, message=b''):\n        \"\"\"Close the websocket, sending the specified code and message.\"\"\"\n        if isinstance(message, str):\n            message = message.encode('utf-8')\n        self._send_frame(\n            struct.pack('!H%ds' % len(message), code, message),\n            opcode=OPCODE_CLOSE)\n\n\ndef do_handshake(method, headers, transport, protocols=()):\n    \"\"\"Prepare WebSocket handshake. It return http response code,\n    response headers, websocket parser, websocket writer. It does not\n    perform any IO.\n\n    `protocols` is a sequence of known protocols. On successful handshake,\n    the returned response headers contain the first protocol in this list\n    which the server also knows.\"\"\"\n\n    # WebSocket accepts only GET\n    if method.upper() != 'GET':\n        raise errors.HttpErrorException(405, headers=(('Allow', 'GET'),))\n\n    if 'websocket' != headers.get('UPGRADE', '').lower().strip():\n        raise errors.HttpBadRequest(\n            'No WebSocket UPGRADE hdr: {}\\n'\n            'Can \"Upgrade\" only to \"WebSocket\".'.format(\n                headers.get('UPGRADE')))\n\n    if 'upgrade' not in headers.get('CONNECTION', '').lower():\n        raise errors.HttpBadRequest(\n            'No CONNECTION upgrade hdr: {}'.format(\n                headers.get('CONNECTION')))\n    \n    # find common sub-protocol between client and server\n    protocol = None\n    if 'SEC-WEBSOCKET-PROTOCOL' in headers:\n        req_protocols = {str(proto.strip()) for proto in\n            headers['SEC-WEBSOCKET-PROTOCOL'].split(',')}\n        \n        for proto in protocols:\n            if proto in req_protocols:\n                protocol = proto\n                break\n        else:\n            raise errors.HttpBadRequest(\n                'Client protocols {!r} don’t overlap server-known ones {!r}'\n                .format(protocols, req_protocols))\n\n    # check supported version\n    version = headers.get('SEC-WEBSOCKET-VERSION')\n    if version not in ('13', '8', '7'):\n        raise errors.HttpBadRequest(\n            'Unsupported version: {}'.format(version))\n\n    # check client handshake for validity\n    key = headers.get('SEC-WEBSOCKET-KEY')\n    try:\n        if not key or len(base64.b64decode(key)) != 16:\n            raise errors.HttpBadRequest(\n                'Handshake error: {!r}'.format(key))\n    except binascii.Error:\n        raise errors.HttpBadRequest(\n            'Handshake error: {!r}'.format(key)) from None\n\n    response_headers = [('UPGRADE', 'websocket'),\n             ('CONNECTION', 'upgrade'),\n             ('TRANSFER-ENCODING', 'chunked'),\n             ('SEC-WEBSOCKET-ACCEPT', base64.b64encode(\n                 hashlib.sha1(key.encode() + WS_KEY).digest()).decode())]\n    \n    if protocol:\n        response_headers.append(('SEC-WEBSOCKET-PROTOCOL', protocol))\n\n    # response code, headers, parser, writer, protocol\n    return (101,\n            response_headers,\n            WebSocketParser,\n            WebSocketWriter(transport),\n            protocol)\n",
            "header": {
                "file": {
                    "path": "aiohttp/websocket.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "9996fe56",
                "new_commit_hash": "b1018bb1",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/aiohttp/websocket.py"
            },
            "plus_file": {
                "path": "b/aiohttp/websocket.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 218,
                            "length": 7
                        },
                        "new_range": {
                            "start": 218,
                            "length": 7
                        },
                        "section": "def do_handshake(method, headers, transport, protocols=()):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "                break",
                                "type": "context"
                            },
                            {
                                "content": "        else:",
                                "type": "context"
                            },
                            {
                                "content": "            raise errors.HttpBadRequest(",
                                "type": "context"
                            },
                            {
                                "content": "                'Client protocols {} don’t overlap server-known ones {}'",
                                "type": "deleted"
                            },
                            {
                                "content": "                'Client protocols {!r} don’t overlap server-known ones {!r}'",
                                "type": "added"
                            },
                            {
                                "content": "                .format(protocols, req_protocols))",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    # check supported version",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "aiohttp/websocket.py",
                            "type": "function",
                            "name": "do_handshake",
                            "content": "def do_handshake(method, headers, transport, protocols=()):\n    \"\"\"Prepare WebSocket handshake. It return http response code,\n    response headers, websocket parser, websocket writer. It does not\n    perform any IO.\n\n    `protocols` is a sequence of known protocols. On successful handshake,\n    the returned response headers contain the first protocol in this list\n    which the server also knows.\"\"\"\n\n    # WebSocket accepts only GET\n    if method.upper() != 'GET':\n        raise errors.HttpErrorException(405, headers=(('Allow', 'GET'),))\n\n    if 'websocket' != headers.get('UPGRADE', '').lower().strip():\n        raise errors.HttpBadRequest(\n            'No WebSocket UPGRADE hdr: {}\\n'\n            'Can \"Upgrade\" only to \"WebSocket\".'.format(\n                headers.get('UPGRADE')))\n\n    if 'upgrade' not in headers.get('CONNECTION', '').lower():\n        raise errors.HttpBadRequest(\n            'No CONNECTION upgrade hdr: {}'.format(\n                headers.get('CONNECTION')))\n    \n    # find common sub-protocol between client and server\n    protocol = None\n    if 'SEC-WEBSOCKET-PROTOCOL' in headers:\n        req_protocols = {str(proto.strip()) for proto in\n            headers['SEC-WEBSOCKET-PROTOCOL'].split(',')}\n        \n        for proto in protocols:\n            if proto in req_protocols:\n                protocol = proto\n                break\n        else:\n            raise errors.HttpBadRequest(\n                'Client protocols {} don’t overlap server-known ones {}'\n                .format(protocols, req_protocols))\n\n    # check supported version\n    version = headers.get('SEC-WEBSOCKET-VERSION')\n    if version not in ('13', '8', '7'):\n        raise errors.HttpBadRequest(\n            'Unsupported version: {}'.format(version))\n\n    # check client handshake for validity\n    key = headers.get('SEC-WEBSOCKET-KEY')\n    try:\n        if not key or len(base64.b64decode(key)) != 16:\n            raise errors.HttpBadRequest(\n                'Handshake error: {!r}'.format(key))\n    except binascii.Error:\n        raise errors.HttpBadRequest(\n            'Handshake error: {!r}'.format(key)) from None\n\n    response_headers = [('UPGRADE', 'websocket'),\n             ('CONNECTION', 'upgrade'),\n             ('TRANSFER-ENCODING', 'chunked'),\n             ('SEC-WEBSOCKET-ACCEPT', base64.b64encode(\n                 hashlib.sha1(key.encode() + WS_KEY).digest()).decode())]\n    \n    if protocol:\n        response_headers.append(('SEC-WEBSOCKET-PROTOCOL', protocol))\n\n    # response code, headers, parser, writer\n    return (101,\n            response_headers,\n            WebSocketParser,\n            WebSocketWriter(transport))",
                            "ast_type_str": "FunctionDef",
                            "start_lineno": 185,
                            "end_lineno": 253,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 246,
                            "length": 8
                        },
                        "new_range": {
                            "start": 246,
                            "length": 9
                        },
                        "section": "def do_handshake(method, headers, transport, protocols=()):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "    if protocol:",
                                "type": "context"
                            },
                            {
                                "content": "        response_headers.append(('SEC-WEBSOCKET-PROTOCOL', protocol))",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    # response code, headers, parser, writer",
                                "type": "deleted"
                            },
                            {
                                "content": "    # response code, headers, parser, writer, protocol",
                                "type": "added"
                            },
                            {
                                "content": "    return (101,",
                                "type": "context"
                            },
                            {
                                "content": "            response_headers,",
                                "type": "context"
                            },
                            {
                                "content": "            WebSocketParser,",
                                "type": "context"
                            },
                            {
                                "content": "            WebSocketWriter(transport))",
                                "type": "deleted"
                            },
                            {
                                "content": "            WebSocketWriter(transport),",
                                "type": "added"
                            },
                            {
                                "content": "            protocol)",
                                "type": "added"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "aiohttp/websocket.py",
                            "type": "function",
                            "name": "do_handshake",
                            "content": "def do_handshake(method, headers, transport, protocols=()):\n    \"\"\"Prepare WebSocket handshake. It return http response code,\n    response headers, websocket parser, websocket writer. It does not\n    perform any IO.\n\n    `protocols` is a sequence of known protocols. On successful handshake,\n    the returned response headers contain the first protocol in this list\n    which the server also knows.\"\"\"\n\n    # WebSocket accepts only GET\n    if method.upper() != 'GET':\n        raise errors.HttpErrorException(405, headers=(('Allow', 'GET'),))\n\n    if 'websocket' != headers.get('UPGRADE', '').lower().strip():\n        raise errors.HttpBadRequest(\n            'No WebSocket UPGRADE hdr: {}\\n'\n            'Can \"Upgrade\" only to \"WebSocket\".'.format(\n                headers.get('UPGRADE')))\n\n    if 'upgrade' not in headers.get('CONNECTION', '').lower():\n        raise errors.HttpBadRequest(\n            'No CONNECTION upgrade hdr: {}'.format(\n                headers.get('CONNECTION')))\n    \n    # find common sub-protocol between client and server\n    protocol = None\n    if 'SEC-WEBSOCKET-PROTOCOL' in headers:\n        req_protocols = {str(proto.strip()) for proto in\n            headers['SEC-WEBSOCKET-PROTOCOL'].split(',')}\n        \n        for proto in protocols:\n            if proto in req_protocols:\n                protocol = proto\n                break\n        else:\n            raise errors.HttpBadRequest(\n                'Client protocols {} don’t overlap server-known ones {}'\n                .format(protocols, req_protocols))\n\n    # check supported version\n    version = headers.get('SEC-WEBSOCKET-VERSION')\n    if version not in ('13', '8', '7'):\n        raise errors.HttpBadRequest(\n            'Unsupported version: {}'.format(version))\n\n    # check client handshake for validity\n    key = headers.get('SEC-WEBSOCKET-KEY')\n    try:\n        if not key or len(base64.b64decode(key)) != 16:\n            raise errors.HttpBadRequest(\n                'Handshake error: {!r}'.format(key))\n    except binascii.Error:\n        raise errors.HttpBadRequest(\n            'Handshake error: {!r}'.format(key)) from None\n\n    response_headers = [('UPGRADE', 'websocket'),\n             ('CONNECTION', 'upgrade'),\n             ('TRANSFER-ENCODING', 'chunked'),\n             ('SEC-WEBSOCKET-ACCEPT', base64.b64encode(\n                 hashlib.sha1(key.encode() + WS_KEY).digest()).decode())]\n    \n    if protocol:\n        response_headers.append(('SEC-WEBSOCKET-PROTOCOL', protocol))\n\n    # response code, headers, parser, writer\n    return (101,\n            response_headers,\n            WebSocketParser,\n            WebSocketWriter(transport))",
                            "ast_type_str": "FunctionDef",
                            "start_lineno": 185,
                            "end_lineno": 253,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                }
            ]
        },
        {
            "old_file_content": "\"\"\"Tests for http/websocket.py\"\"\"\n\nimport base64\nimport hashlib\nimport os\nimport struct\nimport unittest\nimport unittest.mock\n\nimport aiohttp\nfrom aiohttp import websocket, multidict, protocol, errors\n\n\nclass WebsocketParserTests(unittest.TestCase):\n\n    def test_parse_frame(self):\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_frame(buf)\n        next(p)\n        p.send(struct.pack('!BB', 0b00000001, 0b00000001))\n        try:\n            p.send(b'1')\n        except StopIteration as exc:\n            fin, opcode, payload = exc.value\n\n        self.assertEqual((0, 1, b'1'), (fin, opcode, payload))\n\n    def test_parse_frame_length0(self):\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_frame(buf)\n        next(p)\n        try:\n            p.send(struct.pack('!BB', 0b00000001, 0b00000000))\n        except StopIteration as exc:\n            fin, opcode, payload = exc.value\n\n        self.assertEqual((0, 1, b''), (fin, opcode, payload))\n\n    def test_parse_frame_length2(self):\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_frame(buf)\n        next(p)\n        p.send(struct.pack('!BB', 0b00000001, 126))\n        p.send(struct.pack('!H', 4))\n        try:\n            p.send(b'1234')\n        except StopIteration as exc:\n            fin, opcode, payload = exc.value\n\n        self.assertEqual((0, 1, b'1234'), (fin, opcode, payload))\n\n    def test_parse_frame_length4(self):\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_frame(buf)\n        next(p)\n        p.send(struct.pack('!BB', 0b00000001, 127))\n        p.send(struct.pack('!Q', 4))\n        try:\n            p.send(b'1234')\n        except StopIteration as exc:\n            fin, opcode, payload = exc.value\n\n        self.assertEqual((0, 1, b'1234'), (fin, opcode, payload))\n\n    def test_parse_frame_mask(self):\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_frame(buf)\n        next(p)\n        p.send(struct.pack('!BB', 0b00000001, 0b10000001))\n        p.send(b'0001')\n        try:\n            p.send(b'1')\n        except StopIteration as exc:\n            fin, opcode, payload = exc.value\n\n        self.assertEqual((0, 1, b'\\x01'), (fin, opcode, payload))\n\n    def test_parse_frame_header_reversed_bits(self):\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_frame(buf)\n        next(p)\n        self.assertRaises(\n            websocket.WebSocketError,\n            p.send, struct.pack('!BB', 0b01100000, 0b00000000))\n\n    def test_parse_frame_header_control_frame(self):\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_frame(buf)\n        next(p)\n        self.assertRaises(\n            websocket.WebSocketError,\n            p.send, struct.pack('!BB', 0b00001000, 0b00000000))\n\n    def test_parse_frame_header_continuation(self):\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_frame(buf)\n        next(p)\n        self.assertRaises(\n            websocket.WebSocketError,\n            p.send, struct.pack('!BB', 0b00000000, 0b00000000))\n\n    def test_parse_frame_header_new_data_err(self):\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_frame(buf)\n        next(p)\n        self.assertRaises(\n            websocket.WebSocketError,\n            p.send, struct.pack('!BB', 0b000000000, 0b00000000))\n\n    def test_parse_frame_header_payload_size(self):\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_frame(buf)\n        next(p)\n        self.assertRaises(\n            websocket.WebSocketError,\n            p.send, struct.pack('!BB', 0b10001000, 0b01111110))\n\n    @unittest.mock.patch('aiohttp.websocket.parse_frame')\n    def test_ping_frame(self, m_parse_frame):\n        def parse_frame(buf):\n            yield\n            return (1, websocket.OPCODE_PING, b'')\n        m_parse_frame.side_effect = parse_frame\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_message(buf)\n        next(p)\n        try:\n            p.send(b'')\n        except StopIteration as exc:\n            res = exc.value\n        self.assertEqual(res, (websocket.OPCODE_PING, '', ''))\n\n    @unittest.mock.patch('aiohttp.websocket.parse_frame')\n    def test_pong_frame(self, m_parse_frame):\n        def parse_frame(buf):\n            yield\n            return (1, websocket.OPCODE_PONG, b'')\n        m_parse_frame.side_effect = parse_frame\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_message(buf)\n        next(p)\n        try:\n            p.send(b'')\n        except StopIteration as exc:\n            res = exc.value\n        self.assertEqual(res, (websocket.OPCODE_PONG, '', ''))\n\n    @unittest.mock.patch('aiohttp.websocket.parse_frame')\n    def test_close_frame(self, m_parse_frame):\n        def parse_frame(buf):\n            yield\n            return (1, websocket.OPCODE_CLOSE, b'')\n        m_parse_frame.side_effect = parse_frame\n        p = websocket.parse_message(aiohttp.ParserBuffer())\n        next(p)\n        try:\n            p.send(b'')\n        except StopIteration as exc:\n            res = exc.value\n        self.assertEqual(res, (websocket.OPCODE_CLOSE, '', ''))\n\n    @unittest.mock.patch('aiohttp.websocket.parse_frame')\n    def test_close_frame_info(self, m_parse_frame):\n        def parse_frame(buf):\n            yield\n            return (1, websocket.OPCODE_CLOSE, b'0112345')\n        m_parse_frame.side_effect = parse_frame\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_message(buf)\n        next(p)\n        try:\n            p.send(b'')\n        except StopIteration as exc:\n            res = exc.value\n        self.assertEqual(res, (websocket.OPCODE_CLOSE, 12337, b'12345'))\n\n    @unittest.mock.patch('aiohttp.websocket.parse_frame')\n    def test_close_frame_invalid(self, m_parse_frame):\n        def parse_frame(buf):\n            yield\n            return (1, websocket.OPCODE_CLOSE, b'1')\n        m_parse_frame.side_effect = parse_frame\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_message(buf)\n        next(p)\n        self.assertRaises(websocket.WebSocketError, p.send, b'')\n\n    @unittest.mock.patch('aiohttp.websocket.parse_frame')\n    def test_unknown_frame(self, m_parse_frame):\n        def parse_frame(buf):\n            yield\n            return (1, websocket.OPCODE_CONTINUATION, b'')\n        m_parse_frame.side_effect = parse_frame\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_message(buf)\n        next(p)\n        self.assertRaises(websocket.WebSocketError, p.send, b'')\n\n    @unittest.mock.patch('aiohttp.websocket.parse_frame')\n    def test_simple_text(self, m_parse_frame):\n        def parse_frame(buf):\n            yield\n            return (1, websocket.OPCODE_TEXT, b'text')\n        m_parse_frame.side_effect = parse_frame\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_message(buf)\n        next(p)\n        try:\n            p.send(b'')\n        except StopIteration as exc:\n            res = exc.value\n        self.assertEqual(res, (websocket.OPCODE_TEXT, 'text', ''))\n\n    @unittest.mock.patch('aiohttp.websocket.parse_frame')\n    def test_simple_binary(self, m_parse_frame):\n        def parse_frame(buf):\n            yield\n            return (1, websocket.OPCODE_BINARY, b'binary')\n        m_parse_frame.side_effect = parse_frame\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_message(buf)\n        next(p)\n        try:\n            p.send(b'')\n        except StopIteration as exc:\n            res = exc.value\n        self.assertEqual(res, (websocket.OPCODE_BINARY, b'binary', ''))\n\n    @unittest.mock.patch('aiohttp.websocket.parse_frame')\n    def test_continuation(self, m_parse_frame):\n        cur = 0\n\n        def parse_frame(buf):\n            nonlocal cur\n            yield\n            if cur == 0:\n                cur = 1\n                return (0, websocket.OPCODE_TEXT, b'line1')\n            else:\n                return (1, websocket.OPCODE_CONTINUATION, b'line2')\n\n        m_parse_frame.side_effect = parse_frame\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_message(buf)\n        next(p)\n        p.send(b'')\n        try:\n            p.send(b'')\n        except StopIteration as exc:\n            res = exc.value\n        self.assertEqual(res, (websocket.OPCODE_TEXT, 'line1line2', ''))\n\n    @unittest.mock.patch('aiohttp.websocket.parse_frame')\n    def test_continuation_err(self, m_parse_frame):\n        cur = 0\n\n        def parse_frame(buf):\n            nonlocal cur\n            yield\n            if cur == 0:\n                cur = 1\n                return (0, websocket.OPCODE_TEXT, b'line1')\n            else:\n                return (1, websocket.OPCODE_TEXT, b'line2')\n\n        m_parse_frame.side_effect = parse_frame\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_message(buf)\n        next(p)\n        p.send(b'')\n        self.assertRaises(websocket.WebSocketError, p.send, b'')\n\n    @unittest.mock.patch('aiohttp.websocket.parse_message')\n    def test_parser(self, m_parse_message):\n        cur = 0\n\n        def parse_message(buf):\n            nonlocal cur\n            yield\n            if cur == 0:\n                cur = 1\n                return websocket.Message(websocket.OPCODE_TEXT, b'line1', b'')\n            else:\n                return websocket.Message(websocket.OPCODE_CLOSE, b'', b'')\n\n        m_parse_message.side_effect = parse_message\n        out = aiohttp.FlowControlDataQueue(unittest.mock.Mock())\n        buf = aiohttp.ParserBuffer()\n        p = websocket.WebSocketParser(out, buf)\n        next(p)\n        p.send(b'')\n        self.assertRaises(StopIteration, p.send, b'')\n\n        self.assertEqual(\n            (websocket.OPCODE_TEXT, b'line1', b''), out._buffer[0])\n        self.assertEqual(\n            (websocket.OPCODE_CLOSE, b'', b''), out._buffer[1])\n        self.assertTrue(out._eof)\n\n    def test_parser_eof(self):\n        out = aiohttp.FlowControlDataQueue(unittest.mock.Mock())\n        buf = aiohttp.ParserBuffer()\n        p = websocket.WebSocketParser(out, buf)\n        next(p)\n        self.assertRaises(aiohttp.EofStream, p.throw, aiohttp.EofStream)\n        self.assertEqual([], list(out._buffer))\n\n\nclass WebsocketWriterTests(unittest.TestCase):\n\n    def setUp(self):\n        self.transport = unittest.mock.Mock()\n        self.writer = websocket.WebSocketWriter(self.transport)\n\n    def test_pong(self):\n        self.writer.pong()\n        self.transport.write.assert_called_with(b'\\x8a\\x00')\n\n    def test_ping(self):\n        self.writer.ping()\n        self.transport.write.assert_called_with(b'\\x89\\x00')\n\n    def test_send_text(self):\n        self.writer.send(b'text')\n        self.transport.write.assert_called_with(b'\\x81\\x04text')\n\n    def test_send_binary(self):\n        self.writer.send('binary', True)\n        self.transport.write.assert_called_with(b'\\x82\\x06binary')\n\n    def test_send_binary_long(self):\n        self.writer.send(b'b'*127, True)\n        self.assertTrue(\n            self.transport.write.call_args[0][0].startswith(b'\\x82~\\x00\\x7fb'))\n\n    def test_send_binary_very_long(self):\n        self.writer.send(b'b'*65537, True)\n        self.assertTrue(\n            self.transport.write.call_args[0][0].startswith(\n                b'\\x82\\x7f\\x00\\x00\\x00\\x00\\x00\\x01\\x00\\x01b'))\n\n    def test_close(self):\n        self.writer.close(1001, 'msg')\n        self.transport.write.assert_called_with(b'\\x88\\x05\\x03\\xe9msg')\n\n        self.writer.close(1001, b'msg')\n        self.transport.write.assert_called_with(b'\\x88\\x05\\x03\\xe9msg')\n\n\nclass WebSocketHandshakeTests(unittest.TestCase):\n\n    def setUp(self):\n        self.transport = unittest.mock.Mock()\n        self.headers = multidict.MutableMultiDict()\n        self.message = protocol.RawRequestMessage(\n            'GET', '/path', (1, 0), self.headers, True, None)\n\n    def test_not_get(self):\n        self.assertRaises(\n            errors.HttpErrorException,\n            websocket.do_handshake,\n            'POST', self.message.headers, self.transport)\n\n    def test_no_upgrade(self):\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n    def test_no_connection(self):\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'keep-alive')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n    def test_protocol_version(self):\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '1')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n    def test_protocol_key(self):\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '13')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '13'),\n                             ('SEC-WEBSOCKET-KEY', '123')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n        sec_key = base64.b64encode(os.urandom(2))\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '13'),\n                             ('SEC-WEBSOCKET-KEY', sec_key.decode())])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n    def test_handshake(self):\n        sec_key = base64.b64encode(os.urandom(16)).decode()\n\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '13'),\n                             ('SEC-WEBSOCKET-KEY', sec_key)])\n        status, headers, parser, writer = websocket.do_handshake(\n            self.message.method, self.message.headers, self.transport)\n        self.assertEqual(status, 101)\n\n        key = base64.b64encode(\n            hashlib.sha1(sec_key.encode() + websocket.WS_KEY).digest())\n        headers = dict(headers)\n        self.assertEqual(headers['SEC-WEBSOCKET-ACCEPT'], key.decode())\n",
            "new_file_content": "\"\"\"Tests for http/websocket.py\"\"\"\n\nimport base64\nimport hashlib\nimport os\nimport struct\nimport unittest\nimport unittest.mock\n\nimport aiohttp\nfrom aiohttp import websocket, multidict, protocol, errors\n\n\nclass WebsocketParserTests(unittest.TestCase):\n\n    def test_parse_frame(self):\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_frame(buf)\n        next(p)\n        p.send(struct.pack('!BB', 0b00000001, 0b00000001))\n        try:\n            p.send(b'1')\n        except StopIteration as exc:\n            fin, opcode, payload = exc.value\n\n        self.assertEqual((0, 1, b'1'), (fin, opcode, payload))\n\n    def test_parse_frame_length0(self):\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_frame(buf)\n        next(p)\n        try:\n            p.send(struct.pack('!BB', 0b00000001, 0b00000000))\n        except StopIteration as exc:\n            fin, opcode, payload = exc.value\n\n        self.assertEqual((0, 1, b''), (fin, opcode, payload))\n\n    def test_parse_frame_length2(self):\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_frame(buf)\n        next(p)\n        p.send(struct.pack('!BB', 0b00000001, 126))\n        p.send(struct.pack('!H', 4))\n        try:\n            p.send(b'1234')\n        except StopIteration as exc:\n            fin, opcode, payload = exc.value\n\n        self.assertEqual((0, 1, b'1234'), (fin, opcode, payload))\n\n    def test_parse_frame_length4(self):\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_frame(buf)\n        next(p)\n        p.send(struct.pack('!BB', 0b00000001, 127))\n        p.send(struct.pack('!Q', 4))\n        try:\n            p.send(b'1234')\n        except StopIteration as exc:\n            fin, opcode, payload = exc.value\n\n        self.assertEqual((0, 1, b'1234'), (fin, opcode, payload))\n\n    def test_parse_frame_mask(self):\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_frame(buf)\n        next(p)\n        p.send(struct.pack('!BB', 0b00000001, 0b10000001))\n        p.send(b'0001')\n        try:\n            p.send(b'1')\n        except StopIteration as exc:\n            fin, opcode, payload = exc.value\n\n        self.assertEqual((0, 1, b'\\x01'), (fin, opcode, payload))\n\n    def test_parse_frame_header_reversed_bits(self):\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_frame(buf)\n        next(p)\n        self.assertRaises(\n            websocket.WebSocketError,\n            p.send, struct.pack('!BB', 0b01100000, 0b00000000))\n\n    def test_parse_frame_header_control_frame(self):\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_frame(buf)\n        next(p)\n        self.assertRaises(\n            websocket.WebSocketError,\n            p.send, struct.pack('!BB', 0b00001000, 0b00000000))\n\n    def test_parse_frame_header_continuation(self):\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_frame(buf)\n        next(p)\n        self.assertRaises(\n            websocket.WebSocketError,\n            p.send, struct.pack('!BB', 0b00000000, 0b00000000))\n\n    def test_parse_frame_header_new_data_err(self):\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_frame(buf)\n        next(p)\n        self.assertRaises(\n            websocket.WebSocketError,\n            p.send, struct.pack('!BB', 0b000000000, 0b00000000))\n\n    def test_parse_frame_header_payload_size(self):\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_frame(buf)\n        next(p)\n        self.assertRaises(\n            websocket.WebSocketError,\n            p.send, struct.pack('!BB', 0b10001000, 0b01111110))\n\n    @unittest.mock.patch('aiohttp.websocket.parse_frame')\n    def test_ping_frame(self, m_parse_frame):\n        def parse_frame(buf):\n            yield\n            return (1, websocket.OPCODE_PING, b'')\n        m_parse_frame.side_effect = parse_frame\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_message(buf)\n        next(p)\n        try:\n            p.send(b'')\n        except StopIteration as exc:\n            res = exc.value\n        self.assertEqual(res, (websocket.OPCODE_PING, '', ''))\n\n    @unittest.mock.patch('aiohttp.websocket.parse_frame')\n    def test_pong_frame(self, m_parse_frame):\n        def parse_frame(buf):\n            yield\n            return (1, websocket.OPCODE_PONG, b'')\n        m_parse_frame.side_effect = parse_frame\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_message(buf)\n        next(p)\n        try:\n            p.send(b'')\n        except StopIteration as exc:\n            res = exc.value\n        self.assertEqual(res, (websocket.OPCODE_PONG, '', ''))\n\n    @unittest.mock.patch('aiohttp.websocket.parse_frame')\n    def test_close_frame(self, m_parse_frame):\n        def parse_frame(buf):\n            yield\n            return (1, websocket.OPCODE_CLOSE, b'')\n        m_parse_frame.side_effect = parse_frame\n        p = websocket.parse_message(aiohttp.ParserBuffer())\n        next(p)\n        try:\n            p.send(b'')\n        except StopIteration as exc:\n            res = exc.value\n        self.assertEqual(res, (websocket.OPCODE_CLOSE, '', ''))\n\n    @unittest.mock.patch('aiohttp.websocket.parse_frame')\n    def test_close_frame_info(self, m_parse_frame):\n        def parse_frame(buf):\n            yield\n            return (1, websocket.OPCODE_CLOSE, b'0112345')\n        m_parse_frame.side_effect = parse_frame\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_message(buf)\n        next(p)\n        try:\n            p.send(b'')\n        except StopIteration as exc:\n            res = exc.value\n        self.assertEqual(res, (websocket.OPCODE_CLOSE, 12337, b'12345'))\n\n    @unittest.mock.patch('aiohttp.websocket.parse_frame')\n    def test_close_frame_invalid(self, m_parse_frame):\n        def parse_frame(buf):\n            yield\n            return (1, websocket.OPCODE_CLOSE, b'1')\n        m_parse_frame.side_effect = parse_frame\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_message(buf)\n        next(p)\n        self.assertRaises(websocket.WebSocketError, p.send, b'')\n\n    @unittest.mock.patch('aiohttp.websocket.parse_frame')\n    def test_unknown_frame(self, m_parse_frame):\n        def parse_frame(buf):\n            yield\n            return (1, websocket.OPCODE_CONTINUATION, b'')\n        m_parse_frame.side_effect = parse_frame\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_message(buf)\n        next(p)\n        self.assertRaises(websocket.WebSocketError, p.send, b'')\n\n    @unittest.mock.patch('aiohttp.websocket.parse_frame')\n    def test_simple_text(self, m_parse_frame):\n        def parse_frame(buf):\n            yield\n            return (1, websocket.OPCODE_TEXT, b'text')\n        m_parse_frame.side_effect = parse_frame\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_message(buf)\n        next(p)\n        try:\n            p.send(b'')\n        except StopIteration as exc:\n            res = exc.value\n        self.assertEqual(res, (websocket.OPCODE_TEXT, 'text', ''))\n\n    @unittest.mock.patch('aiohttp.websocket.parse_frame')\n    def test_simple_binary(self, m_parse_frame):\n        def parse_frame(buf):\n            yield\n            return (1, websocket.OPCODE_BINARY, b'binary')\n        m_parse_frame.side_effect = parse_frame\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_message(buf)\n        next(p)\n        try:\n            p.send(b'')\n        except StopIteration as exc:\n            res = exc.value\n        self.assertEqual(res, (websocket.OPCODE_BINARY, b'binary', ''))\n\n    @unittest.mock.patch('aiohttp.websocket.parse_frame')\n    def test_continuation(self, m_parse_frame):\n        cur = 0\n\n        def parse_frame(buf):\n            nonlocal cur\n            yield\n            if cur == 0:\n                cur = 1\n                return (0, websocket.OPCODE_TEXT, b'line1')\n            else:\n                return (1, websocket.OPCODE_CONTINUATION, b'line2')\n\n        m_parse_frame.side_effect = parse_frame\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_message(buf)\n        next(p)\n        p.send(b'')\n        try:\n            p.send(b'')\n        except StopIteration as exc:\n            res = exc.value\n        self.assertEqual(res, (websocket.OPCODE_TEXT, 'line1line2', ''))\n\n    @unittest.mock.patch('aiohttp.websocket.parse_frame')\n    def test_continuation_err(self, m_parse_frame):\n        cur = 0\n\n        def parse_frame(buf):\n            nonlocal cur\n            yield\n            if cur == 0:\n                cur = 1\n                return (0, websocket.OPCODE_TEXT, b'line1')\n            else:\n                return (1, websocket.OPCODE_TEXT, b'line2')\n\n        m_parse_frame.side_effect = parse_frame\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_message(buf)\n        next(p)\n        p.send(b'')\n        self.assertRaises(websocket.WebSocketError, p.send, b'')\n\n    @unittest.mock.patch('aiohttp.websocket.parse_message')\n    def test_parser(self, m_parse_message):\n        cur = 0\n\n        def parse_message(buf):\n            nonlocal cur\n            yield\n            if cur == 0:\n                cur = 1\n                return websocket.Message(websocket.OPCODE_TEXT, b'line1', b'')\n            else:\n                return websocket.Message(websocket.OPCODE_CLOSE, b'', b'')\n\n        m_parse_message.side_effect = parse_message\n        out = aiohttp.FlowControlDataQueue(unittest.mock.Mock())\n        buf = aiohttp.ParserBuffer()\n        p = websocket.WebSocketParser(out, buf)\n        next(p)\n        p.send(b'')\n        self.assertRaises(StopIteration, p.send, b'')\n\n        self.assertEqual(\n            (websocket.OPCODE_TEXT, b'line1', b''), out._buffer[0])\n        self.assertEqual(\n            (websocket.OPCODE_CLOSE, b'', b''), out._buffer[1])\n        self.assertTrue(out._eof)\n\n    def test_parser_eof(self):\n        out = aiohttp.FlowControlDataQueue(unittest.mock.Mock())\n        buf = aiohttp.ParserBuffer()\n        p = websocket.WebSocketParser(out, buf)\n        next(p)\n        self.assertRaises(aiohttp.EofStream, p.throw, aiohttp.EofStream)\n        self.assertEqual([], list(out._buffer))\n\n\nclass WebsocketWriterTests(unittest.TestCase):\n\n    def setUp(self):\n        self.transport = unittest.mock.Mock()\n        self.writer = websocket.WebSocketWriter(self.transport)\n\n    def test_pong(self):\n        self.writer.pong()\n        self.transport.write.assert_called_with(b'\\x8a\\x00')\n\n    def test_ping(self):\n        self.writer.ping()\n        self.transport.write.assert_called_with(b'\\x89\\x00')\n\n    def test_send_text(self):\n        self.writer.send(b'text')\n        self.transport.write.assert_called_with(b'\\x81\\x04text')\n\n    def test_send_binary(self):\n        self.writer.send('binary', True)\n        self.transport.write.assert_called_with(b'\\x82\\x06binary')\n\n    def test_send_binary_long(self):\n        self.writer.send(b'b'*127, True)\n        self.assertTrue(\n            self.transport.write.call_args[0][0].startswith(b'\\x82~\\x00\\x7fb'))\n\n    def test_send_binary_very_long(self):\n        self.writer.send(b'b'*65537, True)\n        self.assertTrue(\n            self.transport.write.call_args[0][0].startswith(\n                b'\\x82\\x7f\\x00\\x00\\x00\\x00\\x00\\x01\\x00\\x01b'))\n\n    def test_close(self):\n        self.writer.close(1001, 'msg')\n        self.transport.write.assert_called_with(b'\\x88\\x05\\x03\\xe9msg')\n\n        self.writer.close(1001, b'msg')\n        self.transport.write.assert_called_with(b'\\x88\\x05\\x03\\xe9msg')\n\n\nclass WebSocketHandshakeTests(unittest.TestCase):\n\n    def setUp(self):\n        self.transport = unittest.mock.Mock()\n        self.headers = multidict.MutableMultiDict()\n        self.message = protocol.RawRequestMessage(\n            'GET', '/path', (1, 0), self.headers, True, None)\n\n    def test_not_get(self):\n        self.assertRaises(\n            errors.HttpErrorException,\n            websocket.do_handshake,\n            'POST', self.message.headers, self.transport)\n\n    def test_no_upgrade(self):\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n    def test_no_connection(self):\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'keep-alive')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n    def test_protocol_version(self):\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '1')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n    def test_protocol_key(self):\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '13')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '13'),\n                             ('SEC-WEBSOCKET-KEY', '123')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n        sec_key = base64.b64encode(os.urandom(2))\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '13'),\n                             ('SEC-WEBSOCKET-KEY', sec_key.decode())])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n    def gen_ws_headers(self, protocols=''):\n        key = base64.b64encode(os.urandom(16)).decode()\n        hdrs = [('UPGRADE', 'websocket'),\n                ('CONNECTION', 'upgrade'),\n                ('SEC-WEBSOCKET-VERSION', '13'),\n                ('SEC-WEBSOCKET-KEY', key)]\n        if protocols:\n            hdrs += [('SEC-WEBSOCKET-PROTOCOL', protocols)]\n        return hdrs, key\n\n    def test_handshake(self):\n        hdrs, sec_key = self.gen_ws_headers()\n\n        self.headers.extend(hdrs)\n        status, headers, parser, writer, protocol = websocket.do_handshake(\n            self.message.method, self.message.headers, self.transport)\n        self.assertEqual(status, 101)\n        self.assertIsNone(protocol)\n\n        key = base64.b64encode(\n            hashlib.sha1(sec_key.encode() + websocket.WS_KEY).digest())\n        headers = dict(headers)\n        self.assertEqual(headers['SEC-WEBSOCKET-ACCEPT'], key.decode())\n\n    def test_handshake_protocol(self):\n        '''Tests if one protocol is returned by do_handshake'''\n        proto = 'chat'\n\n        self.headers.extend(self.gen_ws_headers(proto)[0])\n        _, resp_headers, _, _, protocol = websocket.do_handshake(\n            self.message.method, self.message.headers, self.transport,\n            protocols=[proto])\n\n        self.assertEqual(protocol, proto)\n\n        #also test if we reply with the protocol\n        resp_headers = dict(resp_headers)\n        self.assertEqual(resp_headers['SEC-WEBSOCKET-PROTOCOL'], proto)\n\n    def test_handshake_protocol_agreement(self):\n        '''Tests if the right protocol is selected given multiple'''\n        best_proto = 'chat'\n        wanted_protos = ['best', 'chat', 'worse_proto']\n        server_protos = 'worse_proto,chat'\n\n        self.headers.extend(self.gen_ws_headers(server_protos)[0])\n        _, resp_headers, _, _, protocol = websocket.do_handshake(\n            self.message.method, self.message.headers, self.transport,\n            protocols=wanted_protos)\n\n        self.assertEqual(protocol, best_proto)\n",
            "header": {
                "file": {
                    "path": "tests/test_websocket.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "bb101456",
                "new_commit_hash": "08d4ee80",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/tests/test_websocket.py"
            },
            "plus_file": {
                "path": "b/tests/test_websocket.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 419,
                            "length": 18
                        },
                        "new_range": {
                            "start": 419,
                            "length": 54
                        },
                        "section": "class WebSocketHandshakeTests(unittest.TestCase):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "            websocket.do_handshake,",
                                "type": "context"
                            },
                            {
                                "content": "            self.message.method, self.message.headers, self.transport)",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    def gen_ws_headers(self, protocols=''):",
                                "type": "added"
                            },
                            {
                                "content": "        key = base64.b64encode(os.urandom(16)).decode()",
                                "type": "added"
                            },
                            {
                                "content": "        hdrs = [('UPGRADE', 'websocket'),",
                                "type": "added"
                            },
                            {
                                "content": "                ('CONNECTION', 'upgrade'),",
                                "type": "added"
                            },
                            {
                                "content": "                ('SEC-WEBSOCKET-VERSION', '13'),",
                                "type": "added"
                            },
                            {
                                "content": "                ('SEC-WEBSOCKET-KEY', key)]",
                                "type": "added"
                            },
                            {
                                "content": "        if protocols:",
                                "type": "added"
                            },
                            {
                                "content": "            hdrs += [('SEC-WEBSOCKET-PROTOCOL', protocols)]",
                                "type": "added"
                            },
                            {
                                "content": "        return hdrs, key",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "    def test_handshake(self):",
                                "type": "context"
                            },
                            {
                                "content": "        sec_key = base64.b64encode(os.urandom(16)).decode()",
                                "type": "deleted"
                            },
                            {
                                "content": "        hdrs, sec_key = self.gen_ws_headers()",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "        self.headers.extend([('UPGRADE', 'websocket'),",
                                "type": "deleted"
                            },
                            {
                                "content": "                             ('CONNECTION', 'upgrade'),",
                                "type": "deleted"
                            },
                            {
                                "content": "                             ('SEC-WEBSOCKET-VERSION', '13'),",
                                "type": "deleted"
                            },
                            {
                                "content": "                             ('SEC-WEBSOCKET-KEY', sec_key)])",
                                "type": "deleted"
                            },
                            {
                                "content": "        status, headers, parser, writer = websocket.do_handshake(",
                                "type": "deleted"
                            },
                            {
                                "content": "        self.headers.extend(hdrs)",
                                "type": "added"
                            },
                            {
                                "content": "        status, headers, parser, writer, protocol = websocket.do_handshake(",
                                "type": "added"
                            },
                            {
                                "content": "            self.message.method, self.message.headers, self.transport)",
                                "type": "context"
                            },
                            {
                                "content": "        self.assertEqual(status, 101)",
                                "type": "context"
                            },
                            {
                                "content": "        self.assertIsNone(protocol)",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "        key = base64.b64encode(",
                                "type": "context"
                            },
                            {
                                "content": "            hashlib.sha1(sec_key.encode() + websocket.WS_KEY).digest())",
                                "type": "context"
                            },
                            {
                                "content": "        headers = dict(headers)",
                                "type": "context"
                            },
                            {
                                "content": "        self.assertEqual(headers['SEC-WEBSOCKET-ACCEPT'], key.decode())",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "    def test_handshake_protocol(self):",
                                "type": "added"
                            },
                            {
                                "content": "        '''Tests if one protocol is returned by do_handshake'''",
                                "type": "added"
                            },
                            {
                                "content": "        proto = 'chat'",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "        self.headers.extend(self.gen_ws_headers(proto)[0])",
                                "type": "added"
                            },
                            {
                                "content": "        _, resp_headers, _, _, protocol = websocket.do_handshake(",
                                "type": "added"
                            },
                            {
                                "content": "            self.message.method, self.message.headers, self.transport,",
                                "type": "added"
                            },
                            {
                                "content": "            protocols=[proto])",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "        self.assertEqual(protocol, proto)",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "        #also test if we reply with the protocol",
                                "type": "added"
                            },
                            {
                                "content": "        resp_headers = dict(resp_headers)",
                                "type": "added"
                            },
                            {
                                "content": "        self.assertEqual(resp_headers['SEC-WEBSOCKET-PROTOCOL'], proto)",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "    def test_handshake_protocol_agreement(self):",
                                "type": "added"
                            },
                            {
                                "content": "        '''Tests if the right protocol is selected given multiple'''",
                                "type": "added"
                            },
                            {
                                "content": "        best_proto = 'chat'",
                                "type": "added"
                            },
                            {
                                "content": "        wanted_protos = ['best', 'chat', 'worse_proto']",
                                "type": "added"
                            },
                            {
                                "content": "        server_protos = 'worse_proto,chat'",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "        self.headers.extend(self.gen_ws_headers(server_protos)[0])",
                                "type": "added"
                            },
                            {
                                "content": "        _, resp_headers, _, _, protocol = websocket.do_handshake(",
                                "type": "added"
                            },
                            {
                                "content": "            self.message.method, self.message.headers, self.transport,",
                                "type": "added"
                            },
                            {
                                "content": "            protocols=wanted_protos)",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "        self.assertEqual(protocol, best_proto)",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "tests/test_websocket.py",
                            "type": "class",
                            "name": "WebSocketHandshakeTests",
                            "content": "class WebSocketHandshakeTests(unittest.TestCase):\n\n    def setUp(self):\n        self.transport = unittest.mock.Mock()\n        self.headers = multidict.MutableMultiDict()\n        self.message = protocol.RawRequestMessage(\n            'GET', '/path', (1, 0), self.headers, True, None)\n\n    def test_not_get(self):\n        self.assertRaises(\n            errors.HttpErrorException,\n            websocket.do_handshake,\n            'POST', self.message.headers, self.transport)\n\n    def test_no_upgrade(self):\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n    def test_no_connection(self):\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'keep-alive')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n    def test_protocol_version(self):\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '1')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n    def test_protocol_key(self):\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '13')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '13'),\n                             ('SEC-WEBSOCKET-KEY', '123')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n        sec_key = base64.b64encode(os.urandom(2))\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '13'),\n                             ('SEC-WEBSOCKET-KEY', sec_key.decode())])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n    def test_handshake(self):\n        sec_key = base64.b64encode(os.urandom(16)).decode()\n\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '13'),\n                             ('SEC-WEBSOCKET-KEY', sec_key)])\n        status, headers, parser, writer = websocket.do_handshake(\n            self.message.method, self.message.headers, self.transport)\n        self.assertEqual(status, 101)\n\n        key = base64.b64encode(\n            hashlib.sha1(sec_key.encode() + websocket.WS_KEY).digest())\n        headers = dict(headers)\n        self.assertEqual(headers['SEC-WEBSOCKET-ACCEPT'], key.decode())",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 350,
                            "end_lineno": 436,
                            "parent": null
                        },
                        {
                            "file_name": "tests/test_websocket.py",
                            "type": "method",
                            "name": "WebSocketHandshakeTests.test_handshake",
                            "content": "class WebSocketHandshakeTests(unittest.TestCase):\n\n    def setUp(self):\n        self.transport = unittest.mock.Mock()\n        self.headers = multidict.MutableMultiDict()\n        self.message = protocol.RawRequestMessage(\n            'GET', '/path', (1, 0), self.headers, True, None)\n\n    def test_not_get(self):\n        self.assertRaises(\n            errors.HttpErrorException,\n            websocket.do_handshake,\n            'POST', self.message.headers, self.transport)\n\n    def test_no_upgrade(self):\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n    def test_no_connection(self):\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'keep-alive')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n    def test_protocol_version(self):\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '1')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n    def test_protocol_key(self):\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '13')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '13'),\n                             ('SEC-WEBSOCKET-KEY', '123')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n        sec_key = base64.b64encode(os.urandom(2))\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '13'),\n                             ('SEC-WEBSOCKET-KEY', sec_key.decode())])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n    def test_handshake(self):\n        sec_key = base64.b64encode(os.urandom(16)).decode()\n\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '13'),\n                             ('SEC-WEBSOCKET-KEY', sec_key)])\n        status, headers, parser, writer = websocket.do_handshake(\n            self.message.method, self.message.headers, self.transport)\n        self.assertEqual(status, 101)\n\n        key = base64.b64encode(\n            hashlib.sha1(sec_key.encode() + websocket.WS_KEY).digest())\n        headers = dict(headers)\n        self.assertEqual(headers['SEC-WEBSOCKET-ACCEPT'], key.decode())",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 422,
                            "end_lineno": 436,
                            "parent": {
                                "file_name": "tests/test_websocket.py",
                                "type": "class",
                                "name": "WebSocketHandshakeTests",
                                "content": "class WebSocketHandshakeTests(unittest.TestCase):\n\n    def setUp(self):\n        self.transport = unittest.mock.Mock()\n        self.headers = multidict.MutableMultiDict()\n        self.message = protocol.RawRequestMessage(\n            'GET', '/path', (1, 0), self.headers, True, None)\n\n    def test_not_get(self):\n        self.assertRaises(\n            errors.HttpErrorException,\n            websocket.do_handshake,\n            'POST', self.message.headers, self.transport)\n\n    def test_no_upgrade(self):\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n    def test_no_connection(self):\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'keep-alive')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n    def test_protocol_version(self):\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '1')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n    def test_protocol_key(self):\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '13')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '13'),\n                             ('SEC-WEBSOCKET-KEY', '123')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n        sec_key = base64.b64encode(os.urandom(2))\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '13'),\n                             ('SEC-WEBSOCKET-KEY', sec_key.decode())])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n    def test_handshake(self):\n        sec_key = base64.b64encode(os.urandom(16)).decode()\n\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '13'),\n                             ('SEC-WEBSOCKET-KEY', sec_key)])\n        status, headers, parser, writer = websocket.do_handshake(\n            self.message.method, self.message.headers, self.transport)\n        self.assertEqual(status, 101)\n\n        key = base64.b64encode(\n            hashlib.sha1(sec_key.encode() + websocket.WS_KEY).digest())\n        headers = dict(headers)\n        self.assertEqual(headers['SEC-WEBSOCKET-ACCEPT'], key.decode())",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 350,
                                "end_lineno": 436,
                                "parent": null
                            }
                        }
                    ],
                    "added_entities": [
                        {
                            "file_name": "tests/test_websocket.py",
                            "type": "method",
                            "name": "WebSocketHandshakeTests.test_handshake_protocol",
                            "content": "class WebSocketHandshakeTests(unittest.TestCase):\n\n    def setUp(self):\n        self.transport = unittest.mock.Mock()\n        self.headers = multidict.MutableMultiDict()\n        self.message = protocol.RawRequestMessage(\n            'GET', '/path', (1, 0), self.headers, True, None)\n\n    def test_not_get(self):\n        self.assertRaises(\n            errors.HttpErrorException,\n            websocket.do_handshake,\n            'POST', self.message.headers, self.transport)\n\n    def test_no_upgrade(self):\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n    def test_no_connection(self):\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'keep-alive')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n    def test_protocol_version(self):\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '1')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n    def test_protocol_key(self):\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '13')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '13'),\n                             ('SEC-WEBSOCKET-KEY', '123')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n        sec_key = base64.b64encode(os.urandom(2))\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '13'),\n                             ('SEC-WEBSOCKET-KEY', sec_key.decode())])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n    def gen_ws_headers(self, protocols=''):\n        key = base64.b64encode(os.urandom(16)).decode()\n        hdrs = [('UPGRADE', 'websocket'),\n                ('CONNECTION', 'upgrade'),\n                ('SEC-WEBSOCKET-VERSION', '13'),\n                ('SEC-WEBSOCKET-KEY', key)]\n        if protocols:\n            hdrs += [('SEC-WEBSOCKET-PROTOCOL', protocols)]\n        return hdrs, key\n\n    def test_handshake(self):\n        hdrs, sec_key = self.gen_ws_headers()\n\n        self.headers.extend(hdrs)\n        status, headers, parser, writer, protocol = websocket.do_handshake(\n            self.message.method, self.message.headers, self.transport)\n        self.assertEqual(status, 101)\n        self.assertIsNone(protocol)\n\n        key = base64.b64encode(\n            hashlib.sha1(sec_key.encode() + websocket.WS_KEY).digest())\n        headers = dict(headers)\n        self.assertEqual(headers['SEC-WEBSOCKET-ACCEPT'], key.decode())\n\n    def test_handshake_protocol(self):\n        '''Tests if one protocol is returned by do_handshake'''\n        proto = 'chat'\n\n        self.headers.extend(self.gen_ws_headers(proto)[0])\n        _, resp_headers, _, _, protocol = websocket.do_handshake(\n            self.message.method, self.message.headers, self.transport,\n            protocols=[proto])\n\n        self.assertEqual(protocol, proto)\n\n        #also test if we reply with the protocol\n        resp_headers = dict(resp_headers)\n        self.assertEqual(resp_headers['SEC-WEBSOCKET-PROTOCOL'], proto)\n\n    def test_handshake_protocol_agreement(self):\n        '''Tests if the right protocol is selected given multiple'''\n        best_proto = 'chat'\n        wanted_protos = ['best', 'chat', 'worse_proto']\n        server_protos = 'worse_proto,chat'\n\n        self.headers.extend(self.gen_ws_headers(server_protos)[0])\n        _, resp_headers, _, _, protocol = websocket.do_handshake(\n            self.message.method, self.message.headers, self.transport,\n            protocols=wanted_protos)\n\n        self.assertEqual(protocol, best_proto)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 446,
                            "end_lineno": 459,
                            "parent": {
                                "file_name": "tests/test_websocket.py",
                                "type": "class",
                                "name": "WebSocketHandshakeTests",
                                "content": "class WebSocketHandshakeTests(unittest.TestCase):\n\n    def setUp(self):\n        self.transport = unittest.mock.Mock()\n        self.headers = multidict.MutableMultiDict()\n        self.message = protocol.RawRequestMessage(\n            'GET', '/path', (1, 0), self.headers, True, None)\n\n    def test_not_get(self):\n        self.assertRaises(\n            errors.HttpErrorException,\n            websocket.do_handshake,\n            'POST', self.message.headers, self.transport)\n\n    def test_no_upgrade(self):\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n    def test_no_connection(self):\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'keep-alive')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n    def test_protocol_version(self):\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '1')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n    def test_protocol_key(self):\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '13')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '13'),\n                             ('SEC-WEBSOCKET-KEY', '123')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n        sec_key = base64.b64encode(os.urandom(2))\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '13'),\n                             ('SEC-WEBSOCKET-KEY', sec_key.decode())])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n    def gen_ws_headers(self, protocols=''):\n        key = base64.b64encode(os.urandom(16)).decode()\n        hdrs = [('UPGRADE', 'websocket'),\n                ('CONNECTION', 'upgrade'),\n                ('SEC-WEBSOCKET-VERSION', '13'),\n                ('SEC-WEBSOCKET-KEY', key)]\n        if protocols:\n            hdrs += [('SEC-WEBSOCKET-PROTOCOL', protocols)]\n        return hdrs, key\n\n    def test_handshake(self):\n        hdrs, sec_key = self.gen_ws_headers()\n\n        self.headers.extend(hdrs)\n        status, headers, parser, writer, protocol = websocket.do_handshake(\n            self.message.method, self.message.headers, self.transport)\n        self.assertEqual(status, 101)\n        self.assertIsNone(protocol)\n\n        key = base64.b64encode(\n            hashlib.sha1(sec_key.encode() + websocket.WS_KEY).digest())\n        headers = dict(headers)\n        self.assertEqual(headers['SEC-WEBSOCKET-ACCEPT'], key.decode())\n\n    def test_handshake_protocol(self):\n        '''Tests if one protocol is returned by do_handshake'''\n        proto = 'chat'\n\n        self.headers.extend(self.gen_ws_headers(proto)[0])\n        _, resp_headers, _, _, protocol = websocket.do_handshake(\n            self.message.method, self.message.headers, self.transport,\n            protocols=[proto])\n\n        self.assertEqual(protocol, proto)\n\n        #also test if we reply with the protocol\n        resp_headers = dict(resp_headers)\n        self.assertEqual(resp_headers['SEC-WEBSOCKET-PROTOCOL'], proto)\n\n    def test_handshake_protocol_agreement(self):\n        '''Tests if the right protocol is selected given multiple'''\n        best_proto = 'chat'\n        wanted_protos = ['best', 'chat', 'worse_proto']\n        server_protos = 'worse_proto,chat'\n\n        self.headers.extend(self.gen_ws_headers(server_protos)[0])\n        _, resp_headers, _, _, protocol = websocket.do_handshake(\n            self.message.method, self.message.headers, self.transport,\n            protocols=wanted_protos)\n\n        self.assertEqual(protocol, best_proto)",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 350,
                                "end_lineno": 472,
                                "parent": null
                            }
                        },
                        {
                            "file_name": "tests/test_websocket.py",
                            "type": "method",
                            "name": "WebSocketHandshakeTests.test_handshake_protocol_agreement",
                            "content": "class WebSocketHandshakeTests(unittest.TestCase):\n\n    def setUp(self):\n        self.transport = unittest.mock.Mock()\n        self.headers = multidict.MutableMultiDict()\n        self.message = protocol.RawRequestMessage(\n            'GET', '/path', (1, 0), self.headers, True, None)\n\n    def test_not_get(self):\n        self.assertRaises(\n            errors.HttpErrorException,\n            websocket.do_handshake,\n            'POST', self.message.headers, self.transport)\n\n    def test_no_upgrade(self):\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n    def test_no_connection(self):\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'keep-alive')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n    def test_protocol_version(self):\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '1')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n    def test_protocol_key(self):\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '13')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '13'),\n                             ('SEC-WEBSOCKET-KEY', '123')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n        sec_key = base64.b64encode(os.urandom(2))\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '13'),\n                             ('SEC-WEBSOCKET-KEY', sec_key.decode())])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n    def gen_ws_headers(self, protocols=''):\n        key = base64.b64encode(os.urandom(16)).decode()\n        hdrs = [('UPGRADE', 'websocket'),\n                ('CONNECTION', 'upgrade'),\n                ('SEC-WEBSOCKET-VERSION', '13'),\n                ('SEC-WEBSOCKET-KEY', key)]\n        if protocols:\n            hdrs += [('SEC-WEBSOCKET-PROTOCOL', protocols)]\n        return hdrs, key\n\n    def test_handshake(self):\n        hdrs, sec_key = self.gen_ws_headers()\n\n        self.headers.extend(hdrs)\n        status, headers, parser, writer, protocol = websocket.do_handshake(\n            self.message.method, self.message.headers, self.transport)\n        self.assertEqual(status, 101)\n        self.assertIsNone(protocol)\n\n        key = base64.b64encode(\n            hashlib.sha1(sec_key.encode() + websocket.WS_KEY).digest())\n        headers = dict(headers)\n        self.assertEqual(headers['SEC-WEBSOCKET-ACCEPT'], key.decode())\n\n    def test_handshake_protocol(self):\n        '''Tests if one protocol is returned by do_handshake'''\n        proto = 'chat'\n\n        self.headers.extend(self.gen_ws_headers(proto)[0])\n        _, resp_headers, _, _, protocol = websocket.do_handshake(\n            self.message.method, self.message.headers, self.transport,\n            protocols=[proto])\n\n        self.assertEqual(protocol, proto)\n\n        #also test if we reply with the protocol\n        resp_headers = dict(resp_headers)\n        self.assertEqual(resp_headers['SEC-WEBSOCKET-PROTOCOL'], proto)\n\n    def test_handshake_protocol_agreement(self):\n        '''Tests if the right protocol is selected given multiple'''\n        best_proto = 'chat'\n        wanted_protos = ['best', 'chat', 'worse_proto']\n        server_protos = 'worse_proto,chat'\n\n        self.headers.extend(self.gen_ws_headers(server_protos)[0])\n        _, resp_headers, _, _, protocol = websocket.do_handshake(\n            self.message.method, self.message.headers, self.transport,\n            protocols=wanted_protos)\n\n        self.assertEqual(protocol, best_proto)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 461,
                            "end_lineno": 472,
                            "parent": {
                                "file_name": "tests/test_websocket.py",
                                "type": "class",
                                "name": "WebSocketHandshakeTests",
                                "content": "class WebSocketHandshakeTests(unittest.TestCase):\n\n    def setUp(self):\n        self.transport = unittest.mock.Mock()\n        self.headers = multidict.MutableMultiDict()\n        self.message = protocol.RawRequestMessage(\n            'GET', '/path', (1, 0), self.headers, True, None)\n\n    def test_not_get(self):\n        self.assertRaises(\n            errors.HttpErrorException,\n            websocket.do_handshake,\n            'POST', self.message.headers, self.transport)\n\n    def test_no_upgrade(self):\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n    def test_no_connection(self):\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'keep-alive')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n    def test_protocol_version(self):\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '1')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n    def test_protocol_key(self):\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '13')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '13'),\n                             ('SEC-WEBSOCKET-KEY', '123')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n        sec_key = base64.b64encode(os.urandom(2))\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '13'),\n                             ('SEC-WEBSOCKET-KEY', sec_key.decode())])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n    def gen_ws_headers(self, protocols=''):\n        key = base64.b64encode(os.urandom(16)).decode()\n        hdrs = [('UPGRADE', 'websocket'),\n                ('CONNECTION', 'upgrade'),\n                ('SEC-WEBSOCKET-VERSION', '13'),\n                ('SEC-WEBSOCKET-KEY', key)]\n        if protocols:\n            hdrs += [('SEC-WEBSOCKET-PROTOCOL', protocols)]\n        return hdrs, key\n\n    def test_handshake(self):\n        hdrs, sec_key = self.gen_ws_headers()\n\n        self.headers.extend(hdrs)\n        status, headers, parser, writer, protocol = websocket.do_handshake(\n            self.message.method, self.message.headers, self.transport)\n        self.assertEqual(status, 101)\n        self.assertIsNone(protocol)\n\n        key = base64.b64encode(\n            hashlib.sha1(sec_key.encode() + websocket.WS_KEY).digest())\n        headers = dict(headers)\n        self.assertEqual(headers['SEC-WEBSOCKET-ACCEPT'], key.decode())\n\n    def test_handshake_protocol(self):\n        '''Tests if one protocol is returned by do_handshake'''\n        proto = 'chat'\n\n        self.headers.extend(self.gen_ws_headers(proto)[0])\n        _, resp_headers, _, _, protocol = websocket.do_handshake(\n            self.message.method, self.message.headers, self.transport,\n            protocols=[proto])\n\n        self.assertEqual(protocol, proto)\n\n        #also test if we reply with the protocol\n        resp_headers = dict(resp_headers)\n        self.assertEqual(resp_headers['SEC-WEBSOCKET-PROTOCOL'], proto)\n\n    def test_handshake_protocol_agreement(self):\n        '''Tests if the right protocol is selected given multiple'''\n        best_proto = 'chat'\n        wanted_protos = ['best', 'chat', 'worse_proto']\n        server_protos = 'worse_proto,chat'\n\n        self.headers.extend(self.gen_ws_headers(server_protos)[0])\n        _, resp_headers, _, _, protocol = websocket.do_handshake(\n            self.message.method, self.message.headers, self.transport,\n            protocols=wanted_protos)\n\n        self.assertEqual(protocol, best_proto)",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 350,
                                "end_lineno": 472,
                                "parent": null
                            }
                        },
                        {
                            "file_name": "tests/test_websocket.py",
                            "type": "method",
                            "name": "WebSocketHandshakeTests.gen_ws_headers",
                            "content": "class WebSocketHandshakeTests(unittest.TestCase):\n\n    def setUp(self):\n        self.transport = unittest.mock.Mock()\n        self.headers = multidict.MutableMultiDict()\n        self.message = protocol.RawRequestMessage(\n            'GET', '/path', (1, 0), self.headers, True, None)\n\n    def test_not_get(self):\n        self.assertRaises(\n            errors.HttpErrorException,\n            websocket.do_handshake,\n            'POST', self.message.headers, self.transport)\n\n    def test_no_upgrade(self):\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n    def test_no_connection(self):\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'keep-alive')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n    def test_protocol_version(self):\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '1')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n    def test_protocol_key(self):\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '13')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '13'),\n                             ('SEC-WEBSOCKET-KEY', '123')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n        sec_key = base64.b64encode(os.urandom(2))\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '13'),\n                             ('SEC-WEBSOCKET-KEY', sec_key.decode())])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n    def gen_ws_headers(self, protocols=''):\n        key = base64.b64encode(os.urandom(16)).decode()\n        hdrs = [('UPGRADE', 'websocket'),\n                ('CONNECTION', 'upgrade'),\n                ('SEC-WEBSOCKET-VERSION', '13'),\n                ('SEC-WEBSOCKET-KEY', key)]\n        if protocols:\n            hdrs += [('SEC-WEBSOCKET-PROTOCOL', protocols)]\n        return hdrs, key\n\n    def test_handshake(self):\n        hdrs, sec_key = self.gen_ws_headers()\n\n        self.headers.extend(hdrs)\n        status, headers, parser, writer, protocol = websocket.do_handshake(\n            self.message.method, self.message.headers, self.transport)\n        self.assertEqual(status, 101)\n        self.assertIsNone(protocol)\n\n        key = base64.b64encode(\n            hashlib.sha1(sec_key.encode() + websocket.WS_KEY).digest())\n        headers = dict(headers)\n        self.assertEqual(headers['SEC-WEBSOCKET-ACCEPT'], key.decode())\n\n    def test_handshake_protocol(self):\n        '''Tests if one protocol is returned by do_handshake'''\n        proto = 'chat'\n\n        self.headers.extend(self.gen_ws_headers(proto)[0])\n        _, resp_headers, _, _, protocol = websocket.do_handshake(\n            self.message.method, self.message.headers, self.transport,\n            protocols=[proto])\n\n        self.assertEqual(protocol, proto)\n\n        #also test if we reply with the protocol\n        resp_headers = dict(resp_headers)\n        self.assertEqual(resp_headers['SEC-WEBSOCKET-PROTOCOL'], proto)\n\n    def test_handshake_protocol_agreement(self):\n        '''Tests if the right protocol is selected given multiple'''\n        best_proto = 'chat'\n        wanted_protos = ['best', 'chat', 'worse_proto']\n        server_protos = 'worse_proto,chat'\n\n        self.headers.extend(self.gen_ws_headers(server_protos)[0])\n        _, resp_headers, _, _, protocol = websocket.do_handshake(\n            self.message.method, self.message.headers, self.transport,\n            protocols=wanted_protos)\n\n        self.assertEqual(protocol, best_proto)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 422,
                            "end_lineno": 430,
                            "parent": {
                                "file_name": "tests/test_websocket.py",
                                "type": "class",
                                "name": "WebSocketHandshakeTests",
                                "content": "class WebSocketHandshakeTests(unittest.TestCase):\n\n    def setUp(self):\n        self.transport = unittest.mock.Mock()\n        self.headers = multidict.MutableMultiDict()\n        self.message = protocol.RawRequestMessage(\n            'GET', '/path', (1, 0), self.headers, True, None)\n\n    def test_not_get(self):\n        self.assertRaises(\n            errors.HttpErrorException,\n            websocket.do_handshake,\n            'POST', self.message.headers, self.transport)\n\n    def test_no_upgrade(self):\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n    def test_no_connection(self):\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'keep-alive')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n    def test_protocol_version(self):\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '1')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n    def test_protocol_key(self):\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '13')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '13'),\n                             ('SEC-WEBSOCKET-KEY', '123')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n        sec_key = base64.b64encode(os.urandom(2))\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '13'),\n                             ('SEC-WEBSOCKET-KEY', sec_key.decode())])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n    def gen_ws_headers(self, protocols=''):\n        key = base64.b64encode(os.urandom(16)).decode()\n        hdrs = [('UPGRADE', 'websocket'),\n                ('CONNECTION', 'upgrade'),\n                ('SEC-WEBSOCKET-VERSION', '13'),\n                ('SEC-WEBSOCKET-KEY', key)]\n        if protocols:\n            hdrs += [('SEC-WEBSOCKET-PROTOCOL', protocols)]\n        return hdrs, key\n\n    def test_handshake(self):\n        hdrs, sec_key = self.gen_ws_headers()\n\n        self.headers.extend(hdrs)\n        status, headers, parser, writer, protocol = websocket.do_handshake(\n            self.message.method, self.message.headers, self.transport)\n        self.assertEqual(status, 101)\n        self.assertIsNone(protocol)\n\n        key = base64.b64encode(\n            hashlib.sha1(sec_key.encode() + websocket.WS_KEY).digest())\n        headers = dict(headers)\n        self.assertEqual(headers['SEC-WEBSOCKET-ACCEPT'], key.decode())\n\n    def test_handshake_protocol(self):\n        '''Tests if one protocol is returned by do_handshake'''\n        proto = 'chat'\n\n        self.headers.extend(self.gen_ws_headers(proto)[0])\n        _, resp_headers, _, _, protocol = websocket.do_handshake(\n            self.message.method, self.message.headers, self.transport,\n            protocols=[proto])\n\n        self.assertEqual(protocol, proto)\n\n        #also test if we reply with the protocol\n        resp_headers = dict(resp_headers)\n        self.assertEqual(resp_headers['SEC-WEBSOCKET-PROTOCOL'], proto)\n\n    def test_handshake_protocol_agreement(self):\n        '''Tests if the right protocol is selected given multiple'''\n        best_proto = 'chat'\n        wanted_protos = ['best', 'chat', 'worse_proto']\n        server_protos = 'worse_proto,chat'\n\n        self.headers.extend(self.gen_ws_headers(server_protos)[0])\n        _, resp_headers, _, _, protocol = websocket.do_handshake(\n            self.message.method, self.message.headers, self.transport,\n            protocols=wanted_protos)\n\n        self.assertEqual(protocol, best_proto)",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 350,
                                "end_lineno": 472,
                                "parent": null
                            }
                        }
                    ],
                    "deleted_entities": []
                }
            ]
        }
    ],
    "old_commit_hash": "92ce18b0a7d677c4fbdfc835198725a24052179c^",
    "new_commit_hash": "92ce18b0a7d677c4fbdfc835198725a24052179c",
    "commit_message": "broke websocket API and added tests",
    "commit_date": "2014-09-12T15:29:09+02:00",
    "metadata": {}
}
{
    "repo_name": "aiohttp",
    "new_commit_hash": "92ce18b0a7d677c4fbdfc835198725a24052179c",
    "test_file_codes": [
        "\"\"\"Tests for http/websocket.py\"\"\"\n\nimport base64\nimport hashlib\nimport os\nimport struct\nimport unittest\nimport unittest.mock\n\nimport aiohttp\nfrom aiohttp import websocket, multidict, protocol, errors\n\n\nclass WebsocketParserTests(unittest.TestCase):\n\n    def test_parse_frame(self):\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_frame(buf)\n        next(p)\n        p.send(struct.pack('!BB', 0b00000001, 0b00000001))\n        try:\n            p.send(b'1')\n        except StopIteration as exc:\n            fin, opcode, payload = exc.value\n\n        self.assertEqual((0, 1, b'1'), (fin, opcode, payload))\n\n    def test_parse_frame_length0(self):\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_frame(buf)\n        next(p)\n        try:\n            p.send(struct.pack('!BB', 0b00000001, 0b00000000))\n        except StopIteration as exc:\n            fin, opcode, payload = exc.value\n\n        self.assertEqual((0, 1, b''), (fin, opcode, payload))\n\n    def test_parse_frame_length2(self):\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_frame(buf)\n        next(p)\n        p.send(struct.pack('!BB', 0b00000001, 126))\n        p.send(struct.pack('!H', 4))\n        try:\n            p.send(b'1234')\n        except StopIteration as exc:\n            fin, opcode, payload = exc.value\n\n        self.assertEqual((0, 1, b'1234'), (fin, opcode, payload))\n\n    def test_parse_frame_length4(self):\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_frame(buf)\n        next(p)\n        p.send(struct.pack('!BB', 0b00000001, 127))\n        p.send(struct.pack('!Q', 4))\n        try:\n            p.send(b'1234')\n        except StopIteration as exc:\n            fin, opcode, payload = exc.value\n\n        self.assertEqual((0, 1, b'1234'), (fin, opcode, payload))\n\n    def test_parse_frame_mask(self):\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_frame(buf)\n        next(p)\n        p.send(struct.pack('!BB', 0b00000001, 0b10000001))\n        p.send(b'0001')\n        try:\n            p.send(b'1')\n        except StopIteration as exc:\n            fin, opcode, payload = exc.value\n\n        self.assertEqual((0, 1, b'\\x01'), (fin, opcode, payload))\n\n    def test_parse_frame_header_reversed_bits(self):\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_frame(buf)\n        next(p)\n        self.assertRaises(\n            websocket.WebSocketError,\n            p.send, struct.pack('!BB', 0b01100000, 0b00000000))\n\n    def test_parse_frame_header_control_frame(self):\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_frame(buf)\n        next(p)\n        self.assertRaises(\n            websocket.WebSocketError,\n            p.send, struct.pack('!BB', 0b00001000, 0b00000000))\n\n    def test_parse_frame_header_continuation(self):\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_frame(buf)\n        next(p)\n        self.assertRaises(\n            websocket.WebSocketError,\n            p.send, struct.pack('!BB', 0b00000000, 0b00000000))\n\n    def test_parse_frame_header_new_data_err(self):\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_frame(buf)\n        next(p)\n        self.assertRaises(\n            websocket.WebSocketError,\n            p.send, struct.pack('!BB', 0b000000000, 0b00000000))\n\n    def test_parse_frame_header_payload_size(self):\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_frame(buf)\n        next(p)\n        self.assertRaises(\n            websocket.WebSocketError,\n            p.send, struct.pack('!BB', 0b10001000, 0b01111110))\n\n    @unittest.mock.patch('aiohttp.websocket.parse_frame')\n    def test_ping_frame(self, m_parse_frame):\n        def parse_frame(buf):\n            yield\n            return (1, websocket.OPCODE_PING, b'')\n        m_parse_frame.side_effect = parse_frame\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_message(buf)\n        next(p)\n        try:\n            p.send(b'')\n        except StopIteration as exc:\n            res = exc.value\n        self.assertEqual(res, (websocket.OPCODE_PING, '', ''))\n\n    @unittest.mock.patch('aiohttp.websocket.parse_frame')\n    def test_pong_frame(self, m_parse_frame):\n        def parse_frame(buf):\n            yield\n            return (1, websocket.OPCODE_PONG, b'')\n        m_parse_frame.side_effect = parse_frame\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_message(buf)\n        next(p)\n        try:\n            p.send(b'')\n        except StopIteration as exc:\n            res = exc.value\n        self.assertEqual(res, (websocket.OPCODE_PONG, '', ''))\n\n    @unittest.mock.patch('aiohttp.websocket.parse_frame')\n    def test_close_frame(self, m_parse_frame):\n        def parse_frame(buf):\n            yield\n            return (1, websocket.OPCODE_CLOSE, b'')\n        m_parse_frame.side_effect = parse_frame\n        p = websocket.parse_message(aiohttp.ParserBuffer())\n        next(p)\n        try:\n            p.send(b'')\n        except StopIteration as exc:\n            res = exc.value\n        self.assertEqual(res, (websocket.OPCODE_CLOSE, '', ''))\n\n    @unittest.mock.patch('aiohttp.websocket.parse_frame')\n    def test_close_frame_info(self, m_parse_frame):\n        def parse_frame(buf):\n            yield\n            return (1, websocket.OPCODE_CLOSE, b'0112345')\n        m_parse_frame.side_effect = parse_frame\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_message(buf)\n        next(p)\n        try:\n            p.send(b'')\n        except StopIteration as exc:\n            res = exc.value\n        self.assertEqual(res, (websocket.OPCODE_CLOSE, 12337, b'12345'))\n\n    @unittest.mock.patch('aiohttp.websocket.parse_frame')\n    def test_close_frame_invalid(self, m_parse_frame):\n        def parse_frame(buf):\n            yield\n            return (1, websocket.OPCODE_CLOSE, b'1')\n        m_parse_frame.side_effect = parse_frame\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_message(buf)\n        next(p)\n        self.assertRaises(websocket.WebSocketError, p.send, b'')\n\n    @unittest.mock.patch('aiohttp.websocket.parse_frame')\n    def test_unknown_frame(self, m_parse_frame):\n        def parse_frame(buf):\n            yield\n            return (1, websocket.OPCODE_CONTINUATION, b'')\n        m_parse_frame.side_effect = parse_frame\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_message(buf)\n        next(p)\n        self.assertRaises(websocket.WebSocketError, p.send, b'')\n\n    @unittest.mock.patch('aiohttp.websocket.parse_frame')\n    def test_simple_text(self, m_parse_frame):\n        def parse_frame(buf):\n            yield\n            return (1, websocket.OPCODE_TEXT, b'text')\n        m_parse_frame.side_effect = parse_frame\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_message(buf)\n        next(p)\n        try:\n            p.send(b'')\n        except StopIteration as exc:\n            res = exc.value\n        self.assertEqual(res, (websocket.OPCODE_TEXT, 'text', ''))\n\n    @unittest.mock.patch('aiohttp.websocket.parse_frame')\n    def test_simple_binary(self, m_parse_frame):\n        def parse_frame(buf):\n            yield\n            return (1, websocket.OPCODE_BINARY, b'binary')\n        m_parse_frame.side_effect = parse_frame\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_message(buf)\n        next(p)\n        try:\n            p.send(b'')\n        except StopIteration as exc:\n            res = exc.value\n        self.assertEqual(res, (websocket.OPCODE_BINARY, b'binary', ''))\n\n    @unittest.mock.patch('aiohttp.websocket.parse_frame')\n    def test_continuation(self, m_parse_frame):\n        cur = 0\n\n        def parse_frame(buf):\n            nonlocal cur\n            yield\n            if cur == 0:\n                cur = 1\n                return (0, websocket.OPCODE_TEXT, b'line1')\n            else:\n                return (1, websocket.OPCODE_CONTINUATION, b'line2')\n\n        m_parse_frame.side_effect = parse_frame\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_message(buf)\n        next(p)\n        p.send(b'')\n        try:\n            p.send(b'')\n        except StopIteration as exc:\n            res = exc.value\n        self.assertEqual(res, (websocket.OPCODE_TEXT, 'line1line2', ''))\n\n    @unittest.mock.patch('aiohttp.websocket.parse_frame')\n    def test_continuation_err(self, m_parse_frame):\n        cur = 0\n\n        def parse_frame(buf):\n            nonlocal cur\n            yield\n            if cur == 0:\n                cur = 1\n                return (0, websocket.OPCODE_TEXT, b'line1')\n            else:\n                return (1, websocket.OPCODE_TEXT, b'line2')\n\n        m_parse_frame.side_effect = parse_frame\n        buf = aiohttp.ParserBuffer()\n        p = websocket.parse_message(buf)\n        next(p)\n        p.send(b'')\n        self.assertRaises(websocket.WebSocketError, p.send, b'')\n\n    @unittest.mock.patch('aiohttp.websocket.parse_message')\n    def test_parser(self, m_parse_message):\n        cur = 0\n\n        def parse_message(buf):\n            nonlocal cur\n            yield\n            if cur == 0:\n                cur = 1\n                return websocket.Message(websocket.OPCODE_TEXT, b'line1', b'')\n            else:\n                return websocket.Message(websocket.OPCODE_CLOSE, b'', b'')\n\n        m_parse_message.side_effect = parse_message\n        out = aiohttp.FlowControlDataQueue(unittest.mock.Mock())\n        buf = aiohttp.ParserBuffer()\n        p = websocket.WebSocketParser(out, buf)\n        next(p)\n        p.send(b'')\n        self.assertRaises(StopIteration, p.send, b'')\n\n        self.assertEqual(\n            (websocket.OPCODE_TEXT, b'line1', b''), out._buffer[0])\n        self.assertEqual(\n            (websocket.OPCODE_CLOSE, b'', b''), out._buffer[1])\n        self.assertTrue(out._eof)\n\n    def test_parser_eof(self):\n        out = aiohttp.FlowControlDataQueue(unittest.mock.Mock())\n        buf = aiohttp.ParserBuffer()\n        p = websocket.WebSocketParser(out, buf)\n        next(p)\n        self.assertRaises(aiohttp.EofStream, p.throw, aiohttp.EofStream)\n        self.assertEqual([], list(out._buffer))\n\n\nclass WebsocketWriterTests(unittest.TestCase):\n\n    def setUp(self):\n        self.transport = unittest.mock.Mock()\n        self.writer = websocket.WebSocketWriter(self.transport)\n\n    def test_pong(self):\n        self.writer.pong()\n        self.transport.write.assert_called_with(b'\\x8a\\x00')\n\n    def test_ping(self):\n        self.writer.ping()\n        self.transport.write.assert_called_with(b'\\x89\\x00')\n\n    def test_send_text(self):\n        self.writer.send(b'text')\n        self.transport.write.assert_called_with(b'\\x81\\x04text')\n\n    def test_send_binary(self):\n        self.writer.send('binary', True)\n        self.transport.write.assert_called_with(b'\\x82\\x06binary')\n\n    def test_send_binary_long(self):\n        self.writer.send(b'b'*127, True)\n        self.assertTrue(\n            self.transport.write.call_args[0][0].startswith(b'\\x82~\\x00\\x7fb'))\n\n    def test_send_binary_very_long(self):\n        self.writer.send(b'b'*65537, True)\n        self.assertTrue(\n            self.transport.write.call_args[0][0].startswith(\n                b'\\x82\\x7f\\x00\\x00\\x00\\x00\\x00\\x01\\x00\\x01b'))\n\n    def test_close(self):\n        self.writer.close(1001, 'msg')\n        self.transport.write.assert_called_with(b'\\x88\\x05\\x03\\xe9msg')\n\n        self.writer.close(1001, b'msg')\n        self.transport.write.assert_called_with(b'\\x88\\x05\\x03\\xe9msg')\n\n\nclass WebSocketHandshakeTests(unittest.TestCase):\n\n    def setUp(self):\n        self.transport = unittest.mock.Mock()\n        self.headers = multidict.MutableMultiDict()\n        self.message = protocol.RawRequestMessage(\n            'GET', '/path', (1, 0), self.headers, True, None)\n\n    def test_not_get(self):\n        self.assertRaises(\n            errors.HttpErrorException,\n            websocket.do_handshake,\n            'POST', self.message.headers, self.transport)\n\n    def test_no_upgrade(self):\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n    def test_no_connection(self):\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'keep-alive')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n    def test_protocol_version(self):\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '1')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n    def test_protocol_key(self):\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '13')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '13'),\n                             ('SEC-WEBSOCKET-KEY', '123')])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n        sec_key = base64.b64encode(os.urandom(2))\n        self.headers.extend([('UPGRADE', 'websocket'),\n                             ('CONNECTION', 'upgrade'),\n                             ('SEC-WEBSOCKET-VERSION', '13'),\n                             ('SEC-WEBSOCKET-KEY', sec_key.decode())])\n        self.assertRaises(\n            errors.HttpBadRequest,\n            websocket.do_handshake,\n            self.message.method, self.message.headers, self.transport)\n\n    def gen_ws_headers(self, protocols=''):\n        key = base64.b64encode(os.urandom(16)).decode()\n        hdrs = [('UPGRADE', 'websocket'),\n                ('CONNECTION', 'upgrade'),\n                ('SEC-WEBSOCKET-VERSION', '13'),\n                ('SEC-WEBSOCKET-KEY', key)]\n        if protocols:\n            hdrs += [('SEC-WEBSOCKET-PROTOCOL', protocols)]\n        return hdrs, key\n\n    def test_handshake(self):\n        hdrs, sec_key = self.gen_ws_headers()\n\n        self.headers.extend(hdrs)\n        status, headers, parser, writer, protocol = websocket.do_handshake(\n            self.message.method, self.message.headers, self.transport)\n        self.assertEqual(status, 101)\n        self.assertIsNone(protocol)\n\n        key = base64.b64encode(\n            hashlib.sha1(sec_key.encode() + websocket.WS_KEY).digest())\n        headers = dict(headers)\n        self.assertEqual(headers['SEC-WEBSOCKET-ACCEPT'], key.decode())\n\n    def test_handshake_protocol(self):\n        '''Tests if one protocol is returned by do_handshake'''\n        proto = 'chat'\n\n        self.headers.extend(self.gen_ws_headers(proto)[0])\n        _, resp_headers, _, _, protocol = websocket.do_handshake(\n            self.message.method, self.message.headers, self.transport,\n            protocols=[proto])\n\n        self.assertEqual(protocol, proto)\n\n        #also test if we reply with the protocol\n        resp_headers = dict(resp_headers)\n        self.assertEqual(resp_headers['SEC-WEBSOCKET-PROTOCOL'], proto)\n\n    def test_handshake_protocol_agreement(self):\n        '''Tests if the right protocol is selected given multiple'''\n        best_proto = 'chat'\n        wanted_protos = ['best', 'chat', 'worse_proto']\n        server_protos = 'worse_proto,chat'\n\n        self.headers.extend(self.gen_ws_headers(server_protos)[0])\n        _, resp_headers, _, _, protocol = websocket.do_handshake(\n            self.message.method, self.message.headers, self.transport,\n            protocols=wanted_protos)\n\n        self.assertEqual(protocol, best_proto)\n"
    ],
    "test_file_names": [
        "test_1.py"
    ],
    "setup_res_code": 0,
    "setup_res_stdout": "Transforming aiohttp/worker.py\nTransforming aiohttp/server.py\nTransforming aiohttp/client.py\n",
    "setup_res_stderr": "Using CPython 3.9.21\nCreating virtual environment at: .venv\nActivate with: source .venv/bin/activate\nmake: *** No rule to make target '.develop'.  Stop.\nResolved 26 packages in 26ms\nInstalled 26 packages in 49ms\n + async-generator==1.10\n + async-timeout==5.0.1\n + brotlipy==0.7.0\n + cffi==1.17.1\n + chardet==5.2.0\n + coverage==7.6.10\n + cryptography==44.0.0\n + cython==3.0.11\n + exceptiongroup==1.2.2\n + gunicorn==23.0.0\n + idna==3.10\n + iniconfig==2.0.0\n + multdict==0.0.5\n + multidict==6.1.0\n + packaging==24.2\n + pluggy==1.5.0\n + propcache==0.2.1\n + pycparser==2.22\n + pytest==8.3.4\n + pytest-asyncio==0.25.0\n + pytest-cov==6.0.0\n + pytest-mock==3.14.0\n + tomli==2.2.1\n + trustme==1.2.1\n + typing-extensions==4.12.2\n + yarl==1.18.3\n",
    "new_commit_res_code": 0,
    "new_commit_res_stdout": "============================= test session starts ==============================\nplatform linux -- Python 3.9.21, pytest-8.3.4, pluggy-1.5.0\nrootdir: /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_92ce18b0a7d677c4fbdfc835198725a24052179c\nplugins: asyncio-0.25.0, mock-3.14.0, cov-6.0.0\nasyncio: mode=strict, asyncio_default_fixture_loop_scope=None\ncollected 37 items\n\nr2e_tests/test_1.py .....................................                [100%]\n\n==================================== PASSES ====================================\n=========================== short test summary info ============================\nPASSED r2e_tests/test_1.py::WebsocketParserTests::test_close_frame\nPASSED r2e_tests/test_1.py::WebsocketParserTests::test_close_frame_info\nPASSED r2e_tests/test_1.py::WebsocketParserTests::test_close_frame_invalid\nPASSED r2e_tests/test_1.py::WebsocketParserTests::test_continuation\nPASSED r2e_tests/test_1.py::WebsocketParserTests::test_continuation_err\nPASSED r2e_tests/test_1.py::WebsocketParserTests::test_parse_frame\nPASSED r2e_tests/test_1.py::WebsocketParserTests::test_parse_frame_header_continuation\nPASSED r2e_tests/test_1.py::WebsocketParserTests::test_parse_frame_header_control_frame\nPASSED r2e_tests/test_1.py::WebsocketParserTests::test_parse_frame_header_new_data_err\nPASSED r2e_tests/test_1.py::WebsocketParserTests::test_parse_frame_header_payload_size\nPASSED r2e_tests/test_1.py::WebsocketParserTests::test_parse_frame_header_reversed_bits\nPASSED r2e_tests/test_1.py::WebsocketParserTests::test_parse_frame_length0\nPASSED r2e_tests/test_1.py::WebsocketParserTests::test_parse_frame_length2\nPASSED r2e_tests/test_1.py::WebsocketParserTests::test_parse_frame_length4\nPASSED r2e_tests/test_1.py::WebsocketParserTests::test_parse_frame_mask\nPASSED r2e_tests/test_1.py::WebsocketParserTests::test_parser\nPASSED r2e_tests/test_1.py::WebsocketParserTests::test_parser_eof\nPASSED r2e_tests/test_1.py::WebsocketParserTests::test_ping_frame\nPASSED r2e_tests/test_1.py::WebsocketParserTests::test_pong_frame\nPASSED r2e_tests/test_1.py::WebsocketParserTests::test_simple_binary\nPASSED r2e_tests/test_1.py::WebsocketParserTests::test_simple_text\nPASSED r2e_tests/test_1.py::WebsocketParserTests::test_unknown_frame\nPASSED r2e_tests/test_1.py::WebsocketWriterTests::test_close\nPASSED r2e_tests/test_1.py::WebsocketWriterTests::test_ping\nPASSED r2e_tests/test_1.py::WebsocketWriterTests::test_pong\nPASSED r2e_tests/test_1.py::WebsocketWriterTests::test_send_binary\nPASSED r2e_tests/test_1.py::WebsocketWriterTests::test_send_binary_long\nPASSED r2e_tests/test_1.py::WebsocketWriterTests::test_send_binary_very_long\nPASSED r2e_tests/test_1.py::WebsocketWriterTests::test_send_text\nPASSED r2e_tests/test_1.py::WebSocketHandshakeTests::test_handshake\nPASSED r2e_tests/test_1.py::WebSocketHandshakeTests::test_handshake_protocol\nPASSED r2e_tests/test_1.py::WebSocketHandshakeTests::test_handshake_protocol_agreement\nPASSED r2e_tests/test_1.py::WebSocketHandshakeTests::test_no_connection\nPASSED r2e_tests/test_1.py::WebSocketHandshakeTests::test_no_upgrade\nPASSED r2e_tests/test_1.py::WebSocketHandshakeTests::test_not_get\nPASSED r2e_tests/test_1.py::WebSocketHandshakeTests::test_protocol_key\nPASSED r2e_tests/test_1.py::WebSocketHandshakeTests::test_protocol_version\n============================== 37 passed in 0.46s ==============================\n",
    "new_commit_res_stderr": "/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_92ce18b0a7d677c4fbdfc835198725a24052179c/.venv/lib/python3.9/site-packages/pytest_asyncio/plugin.py:207: PytestDeprecationWarning: The configuration option \"asyncio_default_fixture_loop_scope\" is unset.\nThe event loop scope for asynchronous fixtures will default to the fixture caching scope. Future versions of pytest-asyncio will default the loop scope for asynchronous fixtures to function scope. Set the default fixture loop scope explicitly in order to avoid unexpected behavior in the future. Valid fixture loop scopes are: \"function\", \"class\", \"module\", \"package\", \"session\"\n\n  warnings.warn(PytestDeprecationWarning(_DEFAULT_FIXTURE_LOOP_SCOPE_UNSET))\n",
    "old_commit_res_code": 1,
    "old_commit_res_stdout": "============================= test session starts ==============================\nplatform linux -- Python 3.9.21, pytest-8.3.4, pluggy-1.5.0\nrootdir: /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_92ce18b0a7d677c4fbdfc835198725a24052179c\nplugins: asyncio-0.25.0, mock-3.14.0, cov-6.0.0\nasyncio: mode=strict, asyncio_default_fixture_loop_scope=None\ncollected 37 items\n\nr2e_tests/test_1.py .............................FFF.....                [100%]\n\n=================================== FAILURES ===================================\n____________________ WebSocketHandshakeTests.test_handshake ____________________\n\nself = <r2e_tests.test_1.WebSocketHandshakeTests testMethod=test_handshake>\n\n    def test_handshake(self):\n        hdrs, sec_key = self.gen_ws_headers()\n    \n        self.headers.extend(hdrs)\n>       status, headers, parser, writer, protocol = websocket.do_handshake(\n            self.message.method, self.message.headers, self.transport)\nE       ValueError: not enough values to unpack (expected 5, got 4)\n\nr2e_tests/test_1.py:436: ValueError\n_______________ WebSocketHandshakeTests.test_handshake_protocol ________________\n\nself = <r2e_tests.test_1.WebSocketHandshakeTests testMethod=test_handshake_protocol>\n\n    def test_handshake_protocol(self):\n        '''Tests if one protocol is returned by do_handshake'''\n        proto = 'chat'\n    \n        self.headers.extend(self.gen_ws_headers(proto)[0])\n>       _, resp_headers, _, _, protocol = websocket.do_handshake(\n            self.message.method, self.message.headers, self.transport,\n            protocols=[proto])\nE       ValueError: not enough values to unpack (expected 5, got 4)\n\nr2e_tests/test_1.py:451: ValueError\n__________ WebSocketHandshakeTests.test_handshake_protocol_agreement ___________\n\nself = <r2e_tests.test_1.WebSocketHandshakeTests testMethod=test_handshake_protocol_agreement>\n\n    def test_handshake_protocol_agreement(self):\n        '''Tests if the right protocol is selected given multiple'''\n        best_proto = 'chat'\n        wanted_protos = ['best', 'chat', 'worse_proto']\n        server_protos = 'worse_proto,chat'\n    \n        self.headers.extend(self.gen_ws_headers(server_protos)[0])\n>       _, resp_headers, _, _, protocol = websocket.do_handshake(\n            self.message.method, self.message.headers, self.transport,\n            protocols=wanted_protos)\nE       ValueError: not enough values to unpack (expected 5, got 4)\n\nr2e_tests/test_1.py:468: ValueError\n==================================== PASSES ====================================\n=========================== short test summary info ============================\nPASSED r2e_tests/test_1.py::WebsocketParserTests::test_close_frame\nPASSED r2e_tests/test_1.py::WebsocketParserTests::test_close_frame_info\nPASSED r2e_tests/test_1.py::WebsocketParserTests::test_close_frame_invalid\nPASSED r2e_tests/test_1.py::WebsocketParserTests::test_continuation\nPASSED r2e_tests/test_1.py::WebsocketParserTests::test_continuation_err\nPASSED r2e_tests/test_1.py::WebsocketParserTests::test_parse_frame\nPASSED r2e_tests/test_1.py::WebsocketParserTests::test_parse_frame_header_continuation\nPASSED r2e_tests/test_1.py::WebsocketParserTests::test_parse_frame_header_control_frame\nPASSED r2e_tests/test_1.py::WebsocketParserTests::test_parse_frame_header_new_data_err\nPASSED r2e_tests/test_1.py::WebsocketParserTests::test_parse_frame_header_payload_size\nPASSED r2e_tests/test_1.py::WebsocketParserTests::test_parse_frame_header_reversed_bits\nPASSED r2e_tests/test_1.py::WebsocketParserTests::test_parse_frame_length0\nPASSED r2e_tests/test_1.py::WebsocketParserTests::test_parse_frame_length2\nPASSED r2e_tests/test_1.py::WebsocketParserTests::test_parse_frame_length4\nPASSED r2e_tests/test_1.py::WebsocketParserTests::test_parse_frame_mask\nPASSED r2e_tests/test_1.py::WebsocketParserTests::test_parser\nPASSED r2e_tests/test_1.py::WebsocketParserTests::test_parser_eof\nPASSED r2e_tests/test_1.py::WebsocketParserTests::test_ping_frame\nPASSED r2e_tests/test_1.py::WebsocketParserTests::test_pong_frame\nPASSED r2e_tests/test_1.py::WebsocketParserTests::test_simple_binary\nPASSED r2e_tests/test_1.py::WebsocketParserTests::test_simple_text\nPASSED r2e_tests/test_1.py::WebsocketParserTests::test_unknown_frame\nPASSED r2e_tests/test_1.py::WebsocketWriterTests::test_close\nPASSED r2e_tests/test_1.py::WebsocketWriterTests::test_ping\nPASSED r2e_tests/test_1.py::WebsocketWriterTests::test_pong\nPASSED r2e_tests/test_1.py::WebsocketWriterTests::test_send_binary\nPASSED r2e_tests/test_1.py::WebsocketWriterTests::test_send_binary_long\nPASSED r2e_tests/test_1.py::WebsocketWriterTests::test_send_binary_very_long\nPASSED r2e_tests/test_1.py::WebsocketWriterTests::test_send_text\nPASSED r2e_tests/test_1.py::WebSocketHandshakeTests::test_no_connection\nPASSED r2e_tests/test_1.py::WebSocketHandshakeTests::test_no_upgrade\nPASSED r2e_tests/test_1.py::WebSocketHandshakeTests::test_not_get\nPASSED r2e_tests/test_1.py::WebSocketHandshakeTests::test_protocol_key\nPASSED r2e_tests/test_1.py::WebSocketHandshakeTests::test_protocol_version\nFAILED r2e_tests/test_1.py::WebSocketHandshakeTests::test_handshake - ValueEr...\nFAILED r2e_tests/test_1.py::WebSocketHandshakeTests::test_handshake_protocol\nFAILED r2e_tests/test_1.py::WebSocketHandshakeTests::test_handshake_protocol_agreement\n========================= 3 failed, 34 passed in 0.23s =========================\n",
    "old_commit_res_stderr": "/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_92ce18b0a7d677c4fbdfc835198725a24052179c/.venv/lib/python3.9/site-packages/pytest_asyncio/plugin.py:207: PytestDeprecationWarning: The configuration option \"asyncio_default_fixture_loop_scope\" is unset.\nThe event loop scope for asynchronous fixtures will default to the fixture caching scope. Future versions of pytest-asyncio will default the loop scope for asynchronous fixtures to function scope. Set the default fixture loop scope explicitly in order to avoid unexpected behavior in the future. Valid fixture loop scopes are: \"function\", \"class\", \"module\", \"package\", \"session\"\n\n  warnings.warn(PytestDeprecationWarning(_DEFAULT_FIXTURE_LOOP_SCOPE_UNSET))\n"
}
aiohttp/websocket.py tests/test_websocket.py
We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[ISSUE]
**Title:** WebSocket handshake fails due to incorrect number of return values from `do_handshake`

**Description:**
When performing a WebSocket handshake, the `do_handshake` function is expected to return five values: `status`, `headers`, `parser`, `writer`, and `protocol`. Currently, it only returns four values, leading to unpacking errors in tests.

**Example Buggy Code:**
```python
def test_handshake(self):
    hdrs, sec_key = self.gen_ws_headers()
    self.headers.extend(hdrs)
    status, headers, parser, writer, protocol = websocket.do_handshake(
        self.message.method, self.message.headers, self.transport)
    # Further assertions
```

**Error Message:**
```
ValueError: not enough values to unpack (expected 5, got 4)
```

**Expected Behavior:**
The `do_handshake` function should return five values, including the `protocol`, to allow proper unpacking and handling of the WebSocket protocol negotiation.

**Actual Behavior:**
The `do_handshake` function returns only four values, resulting in a `ValueError` when the calling code attempts to unpack five values.

[/ISSUE]
--- END ISSUE ---

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

--- BEGIN FILE ---
```
### aiohttp/websocket.py
"""WebSocket protocol versions 13 and 8."""

__all__ = ['WebSocketParser', 'WebSocketWriter', 'do_handshake',
           'Message', 'WebSocketError',
           'MSG_TEXT', 'MSG_BINARY', 'MSG_CLOSE', 'MSG_PING', 'MSG_PONG']

import base64
import binascii
import collections
import hashlib
import struct
from aiohttp import errors

# Frame opcodes defined in the spec.
OPCODE_CONTINUATION = 0x0
MSG_TEXT = OPCODE_TEXT = 0x1
MSG_BINARY = OPCODE_BINARY = 0x2
MSG_CLOSE = OPCODE_CLOSE = 0x8
MSG_PING = OPCODE_PING = 0x9
MSG_PONG = OPCODE_PONG = 0xa

WS_KEY = b'258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
WS_HDRS = ('UPGRADE', 'CONNECTION',
           'SEC-WEBSOCKET-VERSION', 'SEC-WEBSOCKET-KEY', 'SEC-WEBSOCKET-PROTOCOL')

Message = collections.namedtuple('Message', ['tp', 'data', 'extra'])


class WebSocketError(Exception):
    """WebSocket protocol parser error."""


def WebSocketParser(out, buf):
    while True:
        message = yield from parse_message(buf)
        out.feed_data(message)

        if message.tp == MSG_CLOSE:
            out.feed_eof()
            break


def parse_frame(buf):
    """Return the next frame from the socket."""
    # read header
    data = yield from buf.read(2)
    first_byte, second_byte = struct.unpack('!BB', data)

    fin = (first_byte >> 7) & 1
    rsv1 = (first_byte >> 6) & 1
    rsv2 = (first_byte >> 5) & 1
    rsv3 = (first_byte >> 4) & 1
    opcode = first_byte & 0xf

    # frame-fin = %x0 ; more frames of this message follow
    #           / %x1 ; final frame of this message
    # frame-rsv1 = %x0 ; 1 bit, MUST be 0 unless negotiated otherwise
    # frame-rsv2 = %x0 ; 1 bit, MUST be 0 unless negotiated otherwise
    # frame-rsv3 = %x0 ; 1 bit, MUST be 0 unless negotiated otherwise
    if rsv1 or rsv2 or rsv3:
        raise WebSocketError('Received frame with non-zero reserved bits')

    if opcode > 0x7 and fin == 0:
        raise WebSocketError('Received fragmented control frame')

    if fin == 0 and opcode == OPCODE_CONTINUATION:
        raise WebSocketError(
            'Received new fragment frame with non-zero opcode')

    has_mask = (second_byte >> 7) & 1
    length = (second_byte) & 0x7f

    # Control frames MUST have a payload length of 125 bytes or less
    if opcode > 0x7 and length > 125:
        raise WebSocketError(
            "Control frame payload cannot be larger than 125 bytes")

    # read payload
    if length == 126:
        data = yield from buf.read(2)
        length = struct.unpack_from('!H', data)[0]
    elif length > 126:
        data = yield from buf.read(8)
        length = struct.unpack_from('!Q', data)[0]

    if has_mask:
        mask = yield from buf.read(4)

    if length:
        payload = yield from buf.read(length)
    else:
        payload = b''

    if has_mask:
        payload = bytes(b ^ mask[i % 4] for i, b in enumerate(payload))

    return fin, opcode, payload


def parse_message(buf):
    fin, opcode, payload = yield from parse_frame(buf)

    if opcode == OPCODE_CLOSE:
        if len(payload) >= 2:
            close_code = struct.unpack('!H', payload[:2])[0]
            close_message = payload[2:]
            return Message(OPCODE_CLOSE, close_code, close_message)
        elif payload:
            raise WebSocketError(
                'Invalid close frame: {} {} {!r}'.format(fin, opcode, payload))
        return Message(OPCODE_CLOSE, '', '')

    elif opcode == OPCODE_PING:
        return Message(OPCODE_PING, '', '')

    elif opcode == OPCODE_PONG:
        return Message(OPCODE_PONG, '', '')

    elif opcode not in (OPCODE_TEXT, OPCODE_BINARY):
        raise WebSocketError("Unexpected opcode={!r}".format(opcode))

    # load text/binary
    data = [payload]

    while not fin:
        fin, _opcode, payload = yield from parse_frame(buf)
        if _opcode != OPCODE_CONTINUATION:
            raise WebSocketError(
                'The opcode in non-fin frame is expected '
                'to be zero, got {!r}'.format(opcode))
        else:
            data.append(payload)

    if opcode == OPCODE_TEXT:
        return Message(OPCODE_TEXT, b''.join(data).decode('utf-8'), '')
    else:
        return Message(OPCODE_BINARY, b''.join(data), '')


class WebSocketWriter:

    def __init__(self, writer):
        self.writer = writer

    def _send_frame(self, message, opcode):
        """Send a frame over the websocket with message as its payload."""
        header = bytes([0x80 | opcode])
        msg_length = len(message)

        if msg_length < 126:
            header += bytes([msg_length])
        elif msg_length < (1 << 16):
            header += bytes([126]) + struct.pack('!H', msg_length)
        else:
            header += bytes([127]) + struct.pack('!Q', msg_length)

        self.writer.write(header + message)

    def pong(self):
        """Send pong message."""
        self._send_frame(b'', OPCODE_PONG)

    def ping(self):
        """Send pong message."""
        self._send_frame(b'', OPCODE_PING)

    def send(self, message, binary=False):
        """Send a frame over the websocket with message as its payload."""
        if isinstance(message, str):
            message = message.encode('utf-8')
        if binary:
            self._send_frame(message, OPCODE_BINARY)
        else:
            self._send_frame(message, OPCODE_TEXT)

    def close(self, code=1000, message=b''):
        """Close the websocket, sending the specified code and message."""
        if isinstance(message, str):
            message = message.encode('utf-8')
        self._send_frame(
            struct.pack('!H%ds' % len(message), code, message),
            opcode=OPCODE_CLOSE)


def do_handshake(method, headers, transport, protocols=()):
    """Prepare WebSocket handshake. It return http response code,
    response headers, websocket parser, websocket writer. It does not
    perform any IO.

    `protocols` is a sequence of known protocols. On successful handshake,
    the returned response headers contain the first protocol in this list
    which the server also knows."""

    # WebSocket accepts only GET
    if method.upper() != 'GET':
        raise errors.HttpErrorException(405, headers=(('Allow', 'GET'),))

    if 'websocket' != headers.get('UPGRADE', '').lower().strip():
        raise errors.HttpBadRequest(
            'No WebSocket UPGRADE hdr: {}\n'
            'Can "Upgrade" only to "WebSocket".'.format(
                headers.get('UPGRADE')))

    if 'upgrade' not in headers.get('CONNECTION', '').lower():
        raise errors.HttpBadRequest(
            'No CONNECTION upgrade hdr: {}'.format(
                headers.get('CONNECTION')))
    
    # find common sub-protocol between client and server
    protocol = None
    if 'SEC-WEBSOCKET-PROTOCOL' in headers:
        req_protocols = {str(proto.strip()) for proto in
            headers['SEC-WEBSOCKET-PROTOCOL'].split(',')}
        
        for proto in protocols:
            if proto in req_protocols:
                protocol = proto
                break
        else:
            raise errors.HttpBadRequest(
                'Client protocols {} don’t overlap server-known ones {}'
                .format(protocols, req_protocols))

    # check supported version
    version = headers.get('SEC-WEBSOCKET-VERSION')
    if version not in ('13', '8', '7'):
        raise errors.HttpBadRequest(
            'Unsupported version: {}'.format(version))

    # check client handshake for validity
    key = headers.get('SEC-WEBSOCKET-KEY')
    try:
        if not key or len(base64.b64decode(key)) != 16:
            raise errors.HttpBadRequest(
                'Handshake error: {!r}'.format(key))
    except binascii.Error:
        raise errors.HttpBadRequest(
            'Handshake error: {!r}'.format(key)) from None

    response_headers = [('UPGRADE', 'websocket'),
             ('CONNECTION', 'upgrade'),
             ('TRANSFER-ENCODING', 'chunked'),
             ('SEC-WEBSOCKET-ACCEPT', base64.b64encode(
                 hashlib.sha1(key.encode() + WS_KEY).digest()).decode())]
    
    if protocol:
        response_headers.append(('SEC-WEBSOCKET-PROTOCOL', protocol))

    # response code, headers, parser, writer
    return (101,
            response_headers,
            WebSocketParser,
            WebSocketWriter(transport))

```
--- 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:** WebSocket handshake fails due to incorrect number of return values from `do_handshake`

**Description:**
When performing a WebSocket handshake, the `do_handshake` function is expected to return five values: `status`, `headers`, `parser`, `writer`, and `protocol`. Currently, it only returns four values, leading to unpacking errors in tests.

**Example Buggy Code:**
```python
def test_handshake(self):
    hdrs, sec_key = self.gen_ws_headers()
    self.headers.extend(hdrs)
    status, headers, parser, writer, protocol = websocket.do_handshake(
        self.message.method, self.message.headers, self.transport)
    # Further assertions
```

**Error Message:**
```
ValueError: not enough values to unpack (expected 5, got 4)
```

**Expected Behavior:**
The `do_handshake` function should return five values, including the `protocol`, to allow proper unpacking and handling of the WebSocket protocol negotiation.

**Actual Behavior:**
The `do_handshake` function returns only four values, resulting in a `ValueError` when the calling code attempts to unpack five values.

[/ISSUE]
{
    "WebsocketParserTests.test_close_frame": "PASSED",
    "WebsocketParserTests.test_close_frame_info": "PASSED",
    "WebsocketParserTests.test_close_frame_invalid": "PASSED",
    "WebsocketParserTests.test_continuation": "PASSED",
    "WebsocketParserTests.test_continuation_err": "PASSED",
    "WebsocketParserTests.test_parse_frame": "PASSED",
    "WebsocketParserTests.test_parse_frame_header_continuation": "PASSED",
    "WebsocketParserTests.test_parse_frame_header_control_frame": "PASSED",
    "WebsocketParserTests.test_parse_frame_header_new_data_err": "PASSED",
    "WebsocketParserTests.test_parse_frame_header_payload_size": "PASSED",
    "WebsocketParserTests.test_parse_frame_header_reversed_bits": "PASSED",
    "WebsocketParserTests.test_parse_frame_length0": "PASSED",
    "WebsocketParserTests.test_parse_frame_length2": "PASSED",
    "WebsocketParserTests.test_parse_frame_length4": "PASSED",
    "WebsocketParserTests.test_parse_frame_mask": "PASSED",
    "WebsocketParserTests.test_parser": "PASSED",
    "WebsocketParserTests.test_parser_eof": "PASSED",
    "WebsocketParserTests.test_ping_frame": "PASSED",
    "WebsocketParserTests.test_pong_frame": "PASSED",
    "WebsocketParserTests.test_simple_binary": "PASSED",
    "WebsocketParserTests.test_simple_text": "PASSED",
    "WebsocketParserTests.test_unknown_frame": "PASSED",
    "WebsocketWriterTests.test_close": "PASSED",
    "WebsocketWriterTests.test_ping": "PASSED",
    "WebsocketWriterTests.test_pong": "PASSED",
    "WebsocketWriterTests.test_send_binary": "PASSED",
    "WebsocketWriterTests.test_send_binary_long": "PASSED",
    "WebsocketWriterTests.test_send_binary_very_long": "PASSED",
    "WebsocketWriterTests.test_send_text": "PASSED",
    "WebSocketHandshakeTests.test_handshake": "PASSED",
    "WebSocketHandshakeTests.test_handshake_protocol": "PASSED",
    "WebSocketHandshakeTests.test_handshake_protocol_agreement": "PASSED",
    "WebSocketHandshakeTests.test_no_connection": "PASSED",
    "WebSocketHandshakeTests.test_no_upgrade": "PASSED",
    "WebSocketHandshakeTests.test_not_get": "PASSED",
    "WebSocketHandshakeTests.test_protocol_key": "PASSED",
    "WebSocketHandshakeTests.test_protocol_version": "PASSED"
}
diff --git a/aiohttp/websocket.py b/aiohttp/websocket.py
index 9996fe56..b1018bb1 100644
--- a/aiohttp/websocket.py
+++ b/aiohttp/websocket.py
@@ -218,7 +218,7 @@ def do_handshake(method, headers, transport, protocols=()):
                 break
         else:
             raise errors.HttpBadRequest(
-                'Client protocols {} don’t overlap server-known ones {}'
+                'Client protocols {!r} don’t overlap server-known ones {!r}'
                 .format(protocols, req_protocols))
 
     # check supported version
@@ -246,8 +246,9 @@ def do_handshake(method, headers, transport, protocols=()):
     if protocol:
         response_headers.append(('SEC-WEBSOCKET-PROTOCOL', protocol))
 
-    # response code, headers, parser, writer
+    # response code, headers, parser, writer, protocol
     return (101,
             response_headers,
             WebSocketParser,
-            WebSocketWriter(transport))
+            WebSocketWriter(transport),
+            protocol)

{"aiohttp/websocket.py": "\"\"\"WebSocket protocol versions 13 and 8.\"\"\"\n\n__all__ = ['WebSocketParser', 'WebSocketWriter', 'do_handshake',\n           'Message', 'WebSocketError',\n           'MSG_TEXT', 'MSG_BINARY', 'MSG_CLOSE', 'MSG_PING', 'MSG_PONG']\n\nimport base64\nimport binascii\nimport collections\nimport hashlib\nimport struct\nfrom aiohttp import errors\n\n# Frame opcodes defined in the spec.\nOPCODE_CONTINUATION = 0x0\nMSG_TEXT = OPCODE_TEXT = 0x1\nMSG_BINARY = OPCODE_BINARY = 0x2\nMSG_CLOSE = OPCODE_CLOSE = 0x8\nMSG_PING = OPCODE_PING = 0x9\nMSG_PONG = OPCODE_PONG = 0xa\n\nWS_KEY = b'258EAFA5-E914-47DA-95CA-C5AB0DC85B11'\nWS_HDRS = ('UPGRADE', 'CONNECTION',\n           'SEC-WEBSOCKET-VERSION', 'SEC-WEBSOCKET-KEY', 'SEC-WEBSOCKET-PROTOCOL')\n\nMessage = collections.namedtuple('Message', ['tp', 'data', 'extra'])\n\n\nclass WebSocketError(Exception):\n    \"\"\"WebSocket protocol parser error.\"\"\"\n\n\ndef WebSocketParser(out, buf):\n    while True:\n        message = yield from parse_message(buf)\n        out.feed_data(message)\n\n        if message.tp == MSG_CLOSE:\n            out.feed_eof()\n            break\n\n\ndef parse_frame(buf):\n    \"\"\"Return the next frame from the socket.\"\"\"\n    # read header\n    data = yield from buf.read(2)\n    first_byte, second_byte = struct.unpack('!BB', data)\n\n    fin = (first_byte >> 7) & 1\n    rsv1 = (first_byte >> 6) & 1\n    rsv2 = (first_byte >> 5) & 1\n    rsv3 = (first_byte >> 4) & 1\n    opcode = first_byte & 0xf\n\n    # frame-fin = %x0 ; more frames of this message follow\n    #           / %x1 ; final frame of this message\n    # frame-rsv1 = %x0 ; 1 bit, MUST be 0 unless negotiated otherwise\n    # frame-rsv2 = %x0 ; 1 bit, MUST be 0 unless negotiated otherwise\n    # frame-rsv3 = %x0 ; 1 bit, MUST be 0 unless negotiated otherwise\n    if rsv1 or rsv2 or rsv3:\n        raise WebSocketError('Received frame with non-zero reserved bits')\n\n    if opcode > 0x7 and fin == 0:\n        raise WebSocketError('Received fragmented control frame')\n\n    if fin == 0 and opcode == OPCODE_CONTINUATION:\n        raise WebSocketError(\n            'Received new fragment frame with non-zero opcode')\n\n    has_mask = (second_byte >> 7) & 1\n    length = (second_byte) & 0x7f\n\n    # Control frames MUST have a payload length of 125 bytes or less\n    if opcode > 0x7 and length > 125:\n        raise WebSocketError(\n            \"Control frame payload cannot be larger than 125 bytes\")\n\n    # read payload\n    if length == 126:\n        data = yield from buf.read(2)\n        length = struct.unpack_from('!H', data)[0]\n    elif length > 126:\n        data = yield from buf.read(8)\n        length = struct.unpack_from('!Q', data)[0]\n\n    if has_mask:\n        mask = yield from buf.read(4)\n\n    if length:\n        payload = yield from buf.read(length)\n    else:\n        payload = b''\n\n    if has_mask:\n        payload = bytes(b ^ mask[i % 4] for i, b in enumerate(payload))\n\n    return fin, opcode, payload\n\n\ndef parse_message(buf):\n    fin, opcode, payload = yield from parse_frame(buf)\n\n    if opcode == OPCODE_CLOSE:\n        if len(payload) >= 2:\n            close_code = struct.unpack('!H', payload[:2])[0]\n            close_message = payload[2:]\n            return Message(OPCODE_CLOSE, close_code, close_message)\n        elif payload:\n            raise WebSocketError(\n                'Invalid close frame: {} {} {!r}'.format(fin, opcode, payload))\n        return Message(OPCODE_CLOSE, '', '')\n\n    elif opcode == OPCODE_PING:\n        return Message(OPCODE_PING, '', '')\n\n    elif opcode == OPCODE_PONG:\n        return Message(OPCODE_PONG, '', '')\n\n    elif opcode not in (OPCODE_TEXT, OPCODE_BINARY):\n        raise WebSocketError(\"Unexpected opcode={!r}\".format(opcode))\n\n    # load text/binary\n    data = [payload]\n\n    while not fin:\n        fin, _opcode, payload = yield from parse_frame(buf)\n        if _opcode != OPCODE_CONTINUATION:\n            raise WebSocketError(\n                'The opcode in non-fin frame is expected '\n                'to be zero, got {!r}'.format(opcode))\n        else:\n            data.append(payload)\n\n    if opcode == OPCODE_TEXT:\n        return Message(OPCODE_TEXT, b''.join(data).decode('utf-8'), '')\n    else:\n        return Message(OPCODE_BINARY, b''.join(data), '')\n\n\nclass WebSocketWriter:\n\n    def __init__(self, writer):\n        self.writer = writer\n\n    def _send_frame(self, message, opcode):\n        \"\"\"Send a frame over the websocket with message as its payload.\"\"\"\n        header = bytes([0x80 | opcode])\n        msg_length = len(message)\n\n        if msg_length < 126:\n            header += bytes([msg_length])\n        elif msg_length < (1 << 16):\n            header += bytes([126]) + struct.pack('!H', msg_length)\n        else:\n            header += bytes([127]) + struct.pack('!Q', msg_length)\n\n        self.writer.write(header + message)\n\n    def pong(self):\n        \"\"\"Send pong message.\"\"\"\n        self._send_frame(b'', OPCODE_PONG)\n\n    def ping(self):\n        \"\"\"Send pong message.\"\"\"\n        self._send_frame(b'', OPCODE_PING)\n\n    def send(self, message, binary=False):\n        \"\"\"Send a frame over the websocket with message as its payload.\"\"\"\n        if isinstance(message, str):\n            message = message.encode('utf-8')\n        if binary:\n            self._send_frame(message, OPCODE_BINARY)\n        else:\n            self._send_frame(message, OPCODE_TEXT)\n\n    def close(self, code=1000, message=b''):\n        \"\"\"Close the websocket, sending the specified code and message.\"\"\"\n        if isinstance(message, str):\n            message = message.encode('utf-8')\n        self._send_frame(\n            struct.pack('!H%ds' % len(message), code, message),\n            opcode=OPCODE_CLOSE)\n\n\ndef do_handshake(method, headers, transport, protocols=()):\n    \"\"\"Prepare WebSocket handshake. It return http response code,\n    response headers, websocket parser, websocket writer. It does not\n    perform any IO.\n\n    `protocols` is a sequence of known protocols. On successful handshake,\n    the returned response headers contain the first protocol in this list\n    which the server also knows.\"\"\"\n\n    # WebSocket accepts only GET\n    if method.upper() != 'GET':\n        raise errors.HttpErrorException(405, headers=(('Allow', 'GET'),))\n\n    if 'websocket' != headers.get('UPGRADE', '').lower().strip():\n        raise errors.HttpBadRequest(\n            'No WebSocket UPGRADE hdr: {}\\n'\n            'Can \"Upgrade\" only to \"WebSocket\".'.format(\n                headers.get('UPGRADE')))\n\n    if 'upgrade' not in headers.get('CONNECTION', '').lower():\n        raise errors.HttpBadRequest(\n            'No CONNECTION upgrade hdr: {}'.format(\n                headers.get('CONNECTION')))\n    \n    # find common sub-protocol between client and server\n    protocol = None\n    if 'SEC-WEBSOCKET-PROTOCOL' in headers:\n        req_protocols = {str(proto.strip()) for proto in\n            headers['SEC-WEBSOCKET-PROTOCOL'].split(',')}\n        \n        for proto in protocols:\n            if proto in req_protocols:\n                protocol = proto\n                break\n        else:\n            raise errors.HttpBadRequest(\n                'Client protocols {} don\u2019t overlap server-known ones {}'\n                .format(protocols, req_protocols))\n\n    # check supported version\n    version = headers.get('SEC-WEBSOCKET-VERSION')\n    if version not in ('13', '8', '7'):\n        raise errors.HttpBadRequest(\n            'Unsupported version: {}'.format(version))\n\n    # check client handshake for validity\n    key = headers.get('SEC-WEBSOCKET-KEY')\n    try:\n        if not key or len(base64.b64decode(key)) != 16:\n            raise errors.HttpBadRequest(\n                'Handshake error: {!r}'.format(key))\n    except binascii.Error:\n        raise errors.HttpBadRequest(\n            'Handshake error: {!r}'.format(key)) from None\n\n    response_headers = [('UPGRADE', 'websocket'),\n             ('CONNECTION', 'upgrade'),\n             ('TRANSFER-ENCODING', 'chunked'),\n             ('SEC-WEBSOCKET-ACCEPT', base64.b64encode(\n                 hashlib.sha1(key.encode() + WS_KEY).digest()).decode())]\n    \n    if protocol:\n        response_headers.append(('SEC-WEBSOCKET-PROTOCOL', protocol))\n\n    # response code, headers, parser, writer\n    return (101,\n            response_headers,\n            WebSocketParser,\n            WebSocketWriter(transport))\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:** WebSocket handshake fails due to incorrect number of return values from `do_handshake`

**Description:**
When performing a WebSocket handshake, the `do_handshake` function is expected to return five values: `status`, `headers`, `parser`, `writer`, and `protocol`. Currently, it only returns four values, leading to unpacking errors in tests.

**Example Buggy Code:**
```python
def test_handshake(self):
    hdrs, sec_key = self.gen_ws_headers()
    self.headers.extend(hdrs)
    status, headers, parser, writer, protocol = websocket.do_handshake(
        self.message.method, self.message.headers, self.transport)
    # Further assertions
```

**Error Message:**
```
ValueError: not enough values to unpack (expected 5, got 4)
```

**Expected Behavior:**
The `do_handshake` function should return five values, including the `protocol`, to allow proper unpacking and handling of the WebSocket protocol negotiation.

**Actual Behavior:**
The `do_handshake` function returns only four values, resulting in a `ValueError` when the calling code attempts to unpack five values.

[/ISSUE]
--- END ISSUE ---

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

--- BEGIN FILE ---
```
### aiohttp/websocket.py
"""WebSocket protocol versions 13 and 8."""

__all__ = ['WebSocketParser', 'WebSocketWriter', 'do_handshake',
           'Message', 'WebSocketError',
           'MSG_TEXT', 'MSG_BINARY', 'MSG_CLOSE', 'MSG_PING', 'MSG_PONG']

import base64
import binascii
import collections
import hashlib
import struct
from aiohttp import errors

# Frame opcodes defined in the spec.
OPCODE_CONTINUATION = 0x0
MSG_TEXT = OPCODE_TEXT = 0x1
MSG_BINARY = OPCODE_BINARY = 0x2
MSG_CLOSE = OPCODE_CLOSE = 0x8
MSG_PING = OPCODE_PING = 0x9
MSG_PONG = OPCODE_PONG = 0xa

WS_KEY = b'258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
WS_HDRS = ('UPGRADE', 'CONNECTION',
           'SEC-WEBSOCKET-VERSION', 'SEC-WEBSOCKET-KEY', 'SEC-WEBSOCKET-PROTOCOL')

Message = collections.namedtuple('Message', ['tp', 'data', 'extra'])


class WebSocketError(Exception):
    """WebSocket protocol parser error."""


def WebSocketParser(out, buf):
    while True:
        message = yield from parse_message(buf)
        out.feed_data(message)

        if message.tp == MSG_CLOSE:
            out.feed_eof()
            break


def parse_frame(buf):
    """Return the next frame from the socket."""
    # read header
    data = yield from buf.read(2)
    first_byte, second_byte = struct.unpack('!BB', data)

    fin = (first_byte >> 7) & 1
    rsv1 = (first_byte >> 6) & 1
    rsv2 = (first_byte >> 5) & 1
    rsv3 = (first_byte >> 4) & 1
    opcode = first_byte & 0xf

    # frame-fin = %x0 ; more frames of this message follow
    #           / %x1 ; final frame of this message
    # frame-rsv1 = %x0 ; 1 bit, MUST be 0 unless negotiated otherwise
    # frame-rsv2 = %x0 ; 1 bit, MUST be 0 unless negotiated otherwise
    # frame-rsv3 = %x0 ; 1 bit, MUST be 0 unless negotiated otherwise
    if rsv1 or rsv2 or rsv3:
        raise WebSocketError('Received frame with non-zero reserved bits')

    if opcode > 0x7 and fin == 0:
        raise WebSocketError('Received fragmented control frame')

    if fin == 0 and opcode == OPCODE_CONTINUATION:
        raise WebSocketError(
            'Received new fragment frame with non-zero opcode')

    has_mask = (second_byte >> 7) & 1
    length = (second_byte) & 0x7f

    # Control frames MUST have a payload length of 125 bytes or less
    if opcode > 0x7 and length > 125:
        raise WebSocketError(
            "Control frame payload cannot be larger than 125 bytes")

    # read payload
    if length == 126:
        data = yield from buf.read(2)
        length = struct.unpack_from('!H', data)[0]
    elif length > 126:
        data = yield from buf.read(8)
        length = struct.unpack_from('!Q', data)[0]

    if has_mask:
        mask = yield from buf.read(4)

    if length:
        payload = yield from buf.read(length)
    else:
        payload = b''

    if has_mask:
        payload = bytes(b ^ mask[i % 4] for i, b in enumerate(payload))

    return fin, opcode, payload


def parse_message(buf):
    fin, opcode, payload = yield from parse_frame(buf)

    if opcode == OPCODE_CLOSE:
        if len(payload) >= 2:
            close_code = struct.unpack('!H', payload[:2])[0]
            close_message = payload[2:]
            return Message(OPCODE_CLOSE, close_code, close_message)
        elif payload:
            raise WebSocketError(
                'Invalid close frame: {} {} {!r}'.format(fin, opcode, payload))
        return Message(OPCODE_CLOSE, '', '')

    elif opcode == OPCODE_PING:
        return Message(OPCODE_PING, '', '')

    elif opcode == OPCODE_PONG:
        return Message(OPCODE_PONG, '', '')

    elif opcode not in (OPCODE_TEXT, OPCODE_BINARY):
        raise WebSocketError("Unexpected opcode={!r}".format(opcode))

    # load text/binary
    data = [payload]

    while not fin:
        fin, _opcode, payload = yield from parse_frame(buf)
        if _opcode != OPCODE_CONTINUATION:
            raise WebSocketError(
                'The opcode in non-fin frame is expected '
                'to be zero, got {!r}'.format(opcode))
        else:
            data.append(payload)

    if opcode == OPCODE_TEXT:
        return Message(OPCODE_TEXT, b''.join(data).decode('utf-8'), '')
    else:
        return Message(OPCODE_BINARY, b''.join(data), '')


class WebSocketWriter:

    def __init__(self, writer):
        self.writer = writer

    def _send_frame(self, message, opcode):
        """Send a frame over the websocket with message as its payload."""
        header = bytes([0x80 | opcode])
        msg_length = len(message)

        if msg_length < 126:
            header += bytes([msg_length])
        elif msg_length < (1 << 16):
            header += bytes([126]) + struct.pack('!H', msg_length)
        else:
            header += bytes([127]) + struct.pack('!Q', msg_length)

        self.writer.write(header + message)

    def pong(self):
        """Send pong message."""
        self._send_frame(b'', OPCODE_PONG)

    def ping(self):
        """Send pong message."""
        self._send_frame(b'', OPCODE_PING)

    def send(self, message, binary=False):
        """Send a frame over the websocket with message as its payload."""
        if isinstance(message, str):
            message = message.encode('utf-8')
        if binary:
            self._send_frame(message, OPCODE_BINARY)
        else:
            self._send_frame(message, OPCODE_TEXT)

    def close(self, code=1000, message=b''):
        """Close the websocket, sending the specified code and message."""
        if isinstance(message, str):
            message = message.encode('utf-8')
        self._send_frame(
            struct.pack('!H%ds' % len(message), code, message),
            opcode=OPCODE_CLOSE)


def do_handshake(method, headers, transport, protocols=()):
    """Prepare WebSocket handshake. It return http response code,
    response headers, websocket parser, websocket writer. It does not
    perform any IO.

    `protocols` is a sequence of known protocols. On successful handshake,
    the returned response headers contain the first protocol in this list
    which the server also knows."""

    # WebSocket accepts only GET
    if method.upper() != 'GET':
        raise errors.HttpErrorException(405, headers=(('Allow', 'GET'),))

    if 'websocket' != headers.get('UPGRADE', '').lower().strip():
        raise errors.HttpBadRequest(
            'No WebSocket UPGRADE hdr: {}\n'
            'Can "Upgrade" only to "WebSocket".'.format(
                headers.get('UPGRADE')))

    if 'upgrade' not in headers.get('CONNECTION', '').lower():
        raise errors.HttpBadRequest(
            'No CONNECTION upgrade hdr: {}'.format(
                headers.get('CONNECTION')))
    
    # find common sub-protocol between client and server
    protocol = None
    if 'SEC-WEBSOCKET-PROTOCOL' in headers:
        req_protocols = {str(proto.strip()) for proto in
            headers['SEC-WEBSOCKET-PROTOCOL'].split(',')}
        
        for proto in protocols:
            if proto in req_protocols:
                protocol = proto
                break
        else:
            raise errors.HttpBadRequest(
                'Client protocols {} don’t overlap server-known ones {}'
                .format(protocols, req_protocols))

    # check supported version
    version = headers.get('SEC-WEBSOCKET-VERSION')
    if version not in ('13', '8', '7'):
        raise errors.HttpBadRequest(
            'Unsupported version: {}'.format(version))

    # check client handshake for validity
    key = headers.get('SEC-WEBSOCKET-KEY')
    try:
        if not key or len(base64.b64decode(key)) != 16:
            raise errors.HttpBadRequest(
                'Handshake error: {!r}'.format(key))
    except binascii.Error:
        raise errors.HttpBadRequest(
            'Handshake error: {!r}'.format(key)) from None

    response_headers = [('UPGRADE', 'websocket'),
             ('CONNECTION', 'upgrade'),
             ('TRANSFER-ENCODING', 'chunked'),
             ('SEC-WEBSOCKET-ACCEPT', base64.b64encode(
                 hashlib.sha1(key.encode() + WS_KEY).digest()).decode())]
    
    if protocol:
        response_headers.append(('SEC-WEBSOCKET-PROTOCOL', protocol))

    # response code, headers, parser, writer
    return (101,
            response_headers,
            WebSocketParser,
            WebSocketWriter(transport))

```
--- 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