File: async_aiohttp.py

package info (click to toggle)
python-engineio 3.0.0%2Bdfsg-1
  • links: PTS
  • area: main
  • in suites: buster
  • size: 468 kB
  • sloc: python: 4,688; makefile: 15
file content (129 lines) | stat: -rw-r--r-- 3,824 bytes parent folder | download
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
import asyncio
import sys
from urllib.parse import urlsplit

from aiohttp.web import Response, WebSocketResponse
import six


def create_route(app, engineio_server, engineio_endpoint):
    """This function sets up the engine.io endpoint as a route for the
    application.

    Note that both GET and POST requests must be hooked up on the engine.io
    endpoint.
    """
    app.router.add_get(engineio_endpoint, engineio_server.handle_request)
    app.router.add_post(engineio_endpoint, engineio_server.handle_request)
    app.router.add_route('OPTIONS', engineio_endpoint,
                         engineio_server.handle_request)


def translate_request(request):
    """This function takes the arguments passed to the request handler and
    uses them to generate a WSGI compatible environ dictionary.
    """
    message = request._message
    payload = request._payload

    uri_parts = urlsplit(message.path)
    environ = {
        'wsgi.input': payload,
        'wsgi.errors': sys.stderr,
        'wsgi.version': (1, 0),
        'wsgi.async': True,
        'wsgi.multithread': False,
        'wsgi.multiprocess': False,
        'wsgi.run_once': False,
        'SERVER_SOFTWARE': 'aiohttp',
        'REQUEST_METHOD': message.method,
        'QUERY_STRING': uri_parts.query or '',
        'RAW_URI': message.path,
        'SERVER_PROTOCOL': 'HTTP/%s.%s' % message.version,
        'REMOTE_ADDR': '127.0.0.1',
        'REMOTE_PORT': '0',
        'SERVER_NAME': 'aiohttp',
        'SERVER_PORT': '0',
        'aiohttp.request': request
    }

    for hdr_name, hdr_value in message.headers.items():
        hdr_name = hdr_name.upper()
        if hdr_name == 'CONTENT-TYPE':
            environ['CONTENT_TYPE'] = hdr_value
            continue
        elif hdr_name == 'CONTENT-LENGTH':
            environ['CONTENT_LENGTH'] = hdr_value
            continue

        key = 'HTTP_%s' % hdr_name.replace('-', '_')
        if key in environ:
            hdr_value = '%s,%s' % (environ[key], hdr_value)

        environ[key] = hdr_value

    environ['wsgi.url_scheme'] = environ.get('HTTP_X_FORWARDED_PROTO', 'http')

    path_info = uri_parts.path

    environ['PATH_INFO'] = path_info
    environ['SCRIPT_NAME'] = ''

    return environ


def make_response(status, headers, payload, environ):
    """This function generates an appropriate response object for this async
    mode.
    """
    return Response(body=payload, status=int(status.split()[0]),
                    headers=headers)


class WebSocket(object):  # pragma: no cover
    """
    This wrapper class provides a aiohttp WebSocket interface that is
    somewhat compatible with eventlet's implementation.
    """
    def __init__(self, handler):
        self.handler = handler
        self._sock = None

    async def __call__(self, environ):
        request = environ['aiohttp.request']
        self._sock = WebSocketResponse()
        await self._sock.prepare(request)

        self.environ = environ
        await self.handler(self)
        return self._sock

    async def close(self):
        await self._sock.close()

    async def send(self, message):
        if isinstance(message, bytes):
            f = self._sock.send_bytes
        else:
            f = self._sock.send_str
        if asyncio.iscoroutinefunction(f):
            await f(message)
        else:
            f(message)

    async def wait(self):
        msg = await self._sock.receive()
        if not isinstance(msg.data, six.binary_type) and \
                not isinstance(msg.data, six.text_type):
            raise IOError()
        return msg.data


_async = {
    'asyncio': True,
    'create_route': create_route,
    'translate_request': translate_request,
    'make_response': make_response,
    'websocket': sys.modules[__name__],
    'websocket_class': 'WebSocket'
}