This file is indexed.

/usr/lib/python3/dist-packages/websockets/handshake.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
"""
The :mod:`websockets.handshake` module deals with the WebSocket opening
handshake according to `section 4 of RFC 6455`_.

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

It provides functions to implement the handshake with any existing HTTP
library. You must pass to these functions:

- A ``set_header`` function accepting a header name and a header value,
- A ``get_header`` function accepting a header name and returning the header
  value.

The inputs and outputs of ``get_header`` and ``set_header`` are :class:`str`
objects containing only ASCII characters.

Some checks cannot be performed because they depend too much on the
context; instead, they're documented below.

To accept a connection, a server must:

- Read the request, check that the method is GET, and check the headers with
  :func:`check_request`,
- Send a 101 response to the client with the headers created by
  :func:`build_response` if the request is valid; otherwise, send an
  appropriate HTTP error code.

To open a connection, a client must:

- Send a GET request to the server with the headers created by
  :func:`build_request`,
- Read the response, check that the status code is 101, and check the headers
  with :func:`check_response`.

"""

__all__ = [
    'build_request', 'check_request',
    'build_response', 'check_response',
]

import base64
import hashlib
import random

from .exceptions import InvalidHandshake


GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"


def build_request(set_header):
    """
    Build a handshake request to send to the server.

    Return the ``key`` which must be passed to :func:`check_response`.

    """
    rand = bytes(random.getrandbits(8) for _ in range(16))
    key = base64.b64encode(rand).decode()
    set_header('Upgrade', 'WebSocket')
    set_header('Connection', 'Upgrade')
    set_header('Sec-WebSocket-Key', key)
    set_header('Sec-WebSocket-Version', '13')
    return key


def check_request(get_header):
    """
    Check a handshake request received from the client.

    If the handshake is valid, this function returns the ``key`` which must be
    passed to :func:`build_response`.

    Otherwise it raises an :exc:`~websockets.exceptions.InvalidHandshake`
    exception and the server must return an error like 400 Bad Request.

    This function doesn't verify that the request is an HTTP/1.1 or higher GET
    request and doesn't perform Host and Origin checks. These controls are
    usually performed earlier in the HTTP request handling code. They're the
    responsibility of the caller.

    """
    try:
        assert get_header('Upgrade').lower() == 'websocket'
        assert any(
            token.strip() == 'upgrade'
            for token in get_header('Connection').lower().split(','))
        key = get_header('Sec-WebSocket-Key')
        assert len(base64.b64decode(key.encode(), validate=True)) == 16
        assert get_header('Sec-WebSocket-Version') == '13'
    except Exception as exc:
        raise InvalidHandshake("Invalid request") from exc
    else:
        return key


def build_response(set_header, key):
    """
    Build a handshake response to send to the client.

    ``key`` comes from :func:`check_request`.

    """
    set_header('Upgrade', 'WebSocket')
    set_header('Connection', 'Upgrade')
    set_header('Sec-WebSocket-Accept', accept(key))


def check_response(get_header, key):
    """
    Check a handshake response received from the server.

    ``key`` comes from :func:`build_request`.

    If the handshake is valid, this function returns ``None``.

    Otherwise it raises an :exc:`~websockets.exceptions.InvalidHandshake`
    exception.

    This function doesn't verify that the response is an HTTP/1.1 or higher
    response with a 101 status code. These controls are the responsibility of
    the caller.

    """
    try:
        assert get_header('Upgrade').lower() == 'websocket'
        assert any(
            token.strip() == 'upgrade'
            for token in get_header('Connection').lower().split(','))
        assert get_header('Sec-WebSocket-Accept') == accept(key)
    except Exception as exc:
        raise InvalidHandshake("Invalid response") from exc


def accept(key):
    sha1 = hashlib.sha1((key + GUID).encode()).digest()
    return base64.b64encode(sha1).decode()