No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.

155 líneas
4.5KB

  1. import asyncio
  2. import sys
  3. from urllib.parse import urlsplit
  4. try:
  5. import tornado.web
  6. import tornado.websocket
  7. except ImportError: # pragma: no cover
  8. pass
  9. import six
  10. def get_tornado_handler(engineio_server):
  11. class Handler(tornado.websocket.WebSocketHandler): # pragma: no cover
  12. def __init__(self, *args, **kwargs):
  13. super().__init__(*args, **kwargs)
  14. self.receive_queue = asyncio.Queue()
  15. async def get(self):
  16. if self.request.headers.get('Upgrade', '').lower() == 'websocket':
  17. super().get()
  18. await engineio_server.handle_request(self)
  19. async def post(self):
  20. await engineio_server.handle_request(self)
  21. async def options(self):
  22. await engineio_server.handle_request(self)
  23. async def on_message(self, message):
  24. await self.receive_queue.put(message)
  25. async def get_next_message(self):
  26. return await self.receive_queue.get()
  27. def on_close(self):
  28. self.receive_queue.put_nowait(None)
  29. return Handler
  30. def translate_request(handler):
  31. """This function takes the arguments passed to the request handler and
  32. uses them to generate a WSGI compatible environ dictionary.
  33. """
  34. class AwaitablePayload(object):
  35. def __init__(self, payload):
  36. self.payload = payload or b''
  37. async def read(self, length=None):
  38. if length is None:
  39. r = self.payload
  40. self.payload = b''
  41. else:
  42. r = self.payload[:length]
  43. self.payload = self.payload[length:]
  44. return r
  45. payload = handler.request.body
  46. uri_parts = urlsplit(handler.request.path)
  47. full_uri = handler.request.path
  48. if handler.request.query: # pragma: no cover
  49. full_uri += '?' + handler.request.query
  50. environ = {
  51. 'wsgi.input': AwaitablePayload(payload),
  52. 'wsgi.errors': sys.stderr,
  53. 'wsgi.version': (1, 0),
  54. 'wsgi.async': True,
  55. 'wsgi.multithread': False,
  56. 'wsgi.multiprocess': False,
  57. 'wsgi.run_once': False,
  58. 'SERVER_SOFTWARE': 'aiohttp',
  59. 'REQUEST_METHOD': handler.request.method,
  60. 'QUERY_STRING': handler.request.query or '',
  61. 'RAW_URI': full_uri,
  62. 'SERVER_PROTOCOL': 'HTTP/%s' % handler.request.version,
  63. 'REMOTE_ADDR': '127.0.0.1',
  64. 'REMOTE_PORT': '0',
  65. 'SERVER_NAME': 'aiohttp',
  66. 'SERVER_PORT': '0',
  67. 'tornado.handler': handler
  68. }
  69. for hdr_name, hdr_value in handler.request.headers.items():
  70. hdr_name = hdr_name.upper()
  71. if hdr_name == 'CONTENT-TYPE':
  72. environ['CONTENT_TYPE'] = hdr_value
  73. continue
  74. elif hdr_name == 'CONTENT-LENGTH':
  75. environ['CONTENT_LENGTH'] = hdr_value
  76. continue
  77. key = 'HTTP_%s' % hdr_name.replace('-', '_')
  78. environ[key] = hdr_value
  79. environ['wsgi.url_scheme'] = environ.get('HTTP_X_FORWARDED_PROTO', 'http')
  80. path_info = uri_parts.path
  81. environ['PATH_INFO'] = path_info
  82. environ['SCRIPT_NAME'] = ''
  83. return environ
  84. def make_response(status, headers, payload, environ):
  85. """This function generates an appropriate response object for this async
  86. mode.
  87. """
  88. tornado_handler = environ['tornado.handler']
  89. tornado_handler.set_status(int(status.split()[0]))
  90. for header, value in headers:
  91. tornado_handler.set_header(header, value)
  92. tornado_handler.write(payload)
  93. tornado_handler.finish()
  94. class WebSocket(object): # pragma: no cover
  95. """
  96. This wrapper class provides a tornado WebSocket interface that is
  97. somewhat compatible with eventlet's implementation.
  98. """
  99. def __init__(self, handler):
  100. self.handler = handler
  101. self.tornado_handler = None
  102. async def __call__(self, environ):
  103. self.tornado_handler = environ['tornado.handler']
  104. self.environ = environ
  105. await self.handler(self)
  106. async def close(self):
  107. self.tornado_handler.close()
  108. async def send(self, message):
  109. self.tornado_handler.write_message(
  110. message, binary=isinstance(message, bytes))
  111. async def wait(self):
  112. msg = await self.tornado_handler.get_next_message()
  113. if not isinstance(msg, six.binary_type) and \
  114. not isinstance(msg, six.text_type):
  115. raise IOError()
  116. return msg
  117. _async = {
  118. 'asyncio': True,
  119. 'translate_request': translate_request,
  120. 'make_response': make_response,
  121. 'websocket': sys.modules[__name__],
  122. 'websocket_class': 'WebSocket'
  123. }