This file is indexed.

/usr/lib/python3/dist-packages/websockets/framing.py is in python3-websockets 3.0-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
"""
The :mod:`websockets.framing` module implements data framing as specified in
`section 5 of RFC 6455`_.

It deals with a single frame at a time. Anything that depends on the sequence
of frames is implemented in :mod:`websockets.protocol`.

.. _section 5 of RFC 6455: http://tools.ietf.org/html/rfc6455#section-5

"""

import asyncio
import collections
import io
import random
import struct

from .exceptions import PayloadTooBig, WebSocketProtocolError


__all__ = [
    'OP_CONT', 'OP_TEXT', 'OP_BINARY', 'OP_CLOSE', 'OP_PING', 'OP_PONG',
    'Frame', 'read_frame', 'write_frame', 'parse_close', 'serialize_close'
]

OP_CONT, OP_TEXT, OP_BINARY = range(0x00, 0x03)
OP_CLOSE, OP_PING, OP_PONG = range(0x08, 0x0b)

CLOSE_CODES = {
    1000: "OK",
    1001: "going away",
    1002: "protocol error",
    1003: "unsupported type",
    # 1004: - (reserved)
    # 1005: no status code (internal)
    # 1006: connection closed abnormally (internal)
    1007: "invalid data",
    1008: "policy violation",
    1009: "message too big",
    1010: "extension required",
    1011: "unexpected error",
    # 1015: TLS failure (internal)
}


Frame = collections.namedtuple('Frame', ('fin', 'opcode', 'data'))
Frame.__doc__ = """WebSocket frame.

* ``fin`` is the FIN bit
* ``opcode`` is the opcode
* ``data`` is the payload data

Only these three fields are needed by higher level code. The MASK bit, payload
length and masking-key are handled on the fly by :func:`read_frame` and
:func:`write_frame`.

"""


@asyncio.coroutine
def read_frame(reader, mask, *, max_size=None):
    """
    Read a WebSocket frame and return a :class:`Frame` object.

    ``reader`` is a coroutine taking an integer argument and reading exactly
    this number of bytes, unless the end of file is reached.

    ``mask`` is a :class:`bool` telling whether the frame should be masked
    i.e. whether the read happens on the server side.

    If ``max_size`` is set and the payload exceeds this size in bytes,
    :exc:`~websockets.exceptions.PayloadTooBig` is raised.

    This function validates the frame before returning it and raises
    :exc:`~websockets.exceptions.WebSocketProtocolError` if it contains
    incorrect values.

    """
    # Read the header
    data = yield from reader(2)
    head1, head2 = struct.unpack('!BB', data)
    fin = bool(head1 & 0b10000000)
    if head1 & 0b01110000:
        raise WebSocketProtocolError("Reserved bits must be 0")
    opcode = head1 & 0b00001111
    if bool(head2 & 0b10000000) != mask:
        raise WebSocketProtocolError("Incorrect masking")
    length = head2 & 0b01111111
    if length == 126:
        data = yield from reader(2)
        length, = struct.unpack('!H', data)
    elif length == 127:
        data = yield from reader(8)
        length, = struct.unpack('!Q', data)
    if max_size is not None and length > max_size:
        raise PayloadTooBig("Payload exceeds limit "
                            "({} > {} bytes)".format(length, max_size))
    if mask:
        mask_bits = yield from reader(4)

    # Read the data
    data = yield from reader(length)
    if mask:
        data = bytes(b ^ mask_bits[i % 4] for i, b in enumerate(data))

    frame = Frame(fin, opcode, data)
    check_frame(frame)
    return frame


def write_frame(frame, writer, mask):
    """
    Write a WebSocket frame.

    ``frame`` is the :class:`Frame` object to write.

    ``writer`` is a function accepting bytes.

    ``mask`` is a :class:`bool` telling whether the frame should be masked
    i.e. whether the write happens on the client side.

    This function validates the frame before sending it and raises
    :exc:`~websockets.exceptions.WebSocketProtocolError` if it contains
    incorrect values.

    """
    check_frame(frame)
    output = io.BytesIO()

    # Prepare the header
    head1 = 0b10000000 if frame.fin else 0
    head1 |= frame.opcode
    head2 = 0b10000000 if mask else 0
    length = len(frame.data)
    if length < 0x7e:
        output.write(struct.pack('!BB', head1, head2 | length))
    elif length < 0x10000:
        output.write(struct.pack('!BBH', head1, head2 | 126, length))
    else:
        output.write(struct.pack('!BBQ', head1, head2 | 127, length))
    if mask:
        mask_bits = struct.pack('!I', random.getrandbits(32))
        output.write(mask_bits)

    # Prepare the data
    if mask:
        data = bytes(b ^ mask_bits[i % 4] for i, b in enumerate(frame.data))
    else:
        data = frame.data
    output.write(data)

    # Send the frame
    writer(output.getvalue())


def check_frame(frame):
    """
    Raise :exc:`~websockets.exceptions.WebSocketProtocolError` if the frame
    contains incorrect values.

    """
    if frame.opcode in (OP_CONT, OP_TEXT, OP_BINARY):
        return
    elif frame.opcode in (OP_CLOSE, OP_PING, OP_PONG):
        if len(frame.data) > 125:
            raise WebSocketProtocolError("Control frame too long")
        if not frame.fin:
            raise WebSocketProtocolError("Fragmented control frame")
    else:
        raise WebSocketProtocolError("Invalid opcode")


def parse_close(data):
    """
    Parse the data in a close frame.

    Return ``(code, reason)`` when ``code`` is an :class:`int` and ``reason``
    a :class:`str`.

    Raise :exc:`~websockets.exceptions.WebSocketProtocolError` or
    :exc:`UnicodeDecodeError` if the data is invalid.

    """
    length = len(data)
    if length == 0:
        return 1005, ''
    elif length == 1:
        raise WebSocketProtocolError("Close frame too short")
    else:
        code, = struct.unpack('!H', data[:2])
        if not (code in CLOSE_CODES or 3000 <= code < 5000):
            raise WebSocketProtocolError("Invalid status code")
        reason = data[2:].decode('utf-8')
        return code, reason


def serialize_close(code, reason):
    """
    Serialize the data for a close frame.

    This is the reverse of :func:`parse_close`.

    """
    return struct.pack('!H', code) + reason.encode('utf-8')