Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

145 строки
4.2KB

  1. import sys
  2. from urllib.parse import urlsplit
  3. from sanic.response import HTTPResponse
  4. try:
  5. from sanic.websocket import WebSocketProtocol
  6. except ImportError:
  7. # the installed version of sanic does not have websocket support
  8. WebSocketProtocol = None
  9. import six
  10. def create_route(app, engineio_server, engineio_endpoint):
  11. """This function sets up the engine.io endpoint as a route for the
  12. application.
  13. Note that both GET and POST requests must be hooked up on the engine.io
  14. endpoint.
  15. """
  16. app.add_route(engineio_server.handle_request, engineio_endpoint,
  17. methods=['GET', 'POST', 'OPTIONS'])
  18. try:
  19. app.enable_websocket()
  20. except AttributeError:
  21. # ignore, this version does not support websocket
  22. pass
  23. def translate_request(request):
  24. """This function takes the arguments passed to the request handler and
  25. uses them to generate a WSGI compatible environ dictionary.
  26. """
  27. class AwaitablePayload(object):
  28. def __init__(self, payload):
  29. self.payload = payload or b''
  30. async def read(self, length=None):
  31. if length is None:
  32. r = self.payload
  33. self.payload = b''
  34. else:
  35. r = self.payload[:length]
  36. self.payload = self.payload[length:]
  37. return r
  38. uri_parts = urlsplit(request.url)
  39. environ = {
  40. 'wsgi.input': AwaitablePayload(request.body),
  41. 'wsgi.errors': sys.stderr,
  42. 'wsgi.version': (1, 0),
  43. 'wsgi.async': True,
  44. 'wsgi.multithread': False,
  45. 'wsgi.multiprocess': False,
  46. 'wsgi.run_once': False,
  47. 'SERVER_SOFTWARE': 'sanic',
  48. 'REQUEST_METHOD': request.method,
  49. 'QUERY_STRING': uri_parts.query or '',
  50. 'RAW_URI': request.url,
  51. 'SERVER_PROTOCOL': 'HTTP/' + request.version,
  52. 'REMOTE_ADDR': '127.0.0.1',
  53. 'REMOTE_PORT': '0',
  54. 'SERVER_NAME': 'sanic',
  55. 'SERVER_PORT': '0',
  56. 'sanic.request': request
  57. }
  58. for hdr_name, hdr_value in request.headers.items():
  59. hdr_name = hdr_name.upper()
  60. if hdr_name == 'CONTENT-TYPE':
  61. environ['CONTENT_TYPE'] = hdr_value
  62. continue
  63. elif hdr_name == 'CONTENT-LENGTH':
  64. environ['CONTENT_LENGTH'] = hdr_value
  65. continue
  66. key = 'HTTP_%s' % hdr_name.replace('-', '_')
  67. if key in environ:
  68. hdr_value = '%s,%s' % (environ[key], hdr_value)
  69. environ[key] = hdr_value
  70. environ['wsgi.url_scheme'] = environ.get('HTTP_X_FORWARDED_PROTO', 'http')
  71. path_info = uri_parts.path
  72. environ['PATH_INFO'] = path_info
  73. environ['SCRIPT_NAME'] = ''
  74. return environ
  75. def make_response(status, headers, payload, environ):
  76. """This function generates an appropriate response object for this async
  77. mode.
  78. """
  79. headers_dict = {}
  80. content_type = None
  81. for h in headers:
  82. if h[0].lower() == 'content-type':
  83. content_type = h[1]
  84. else:
  85. headers_dict[h[0]] = h[1]
  86. return HTTPResponse(body_bytes=payload, content_type=content_type,
  87. status=int(status.split()[0]), headers=headers_dict)
  88. class WebSocket(object): # pragma: no cover
  89. """
  90. This wrapper class provides a sanic WebSocket interface that is
  91. somewhat compatible with eventlet's implementation.
  92. """
  93. def __init__(self, handler):
  94. self.handler = handler
  95. self._sock = None
  96. async def __call__(self, environ):
  97. request = environ['sanic.request']
  98. protocol = request.transport.get_protocol()
  99. self._sock = await protocol.websocket_handshake(request)
  100. self.environ = environ
  101. await self.handler(self)
  102. async def close(self):
  103. await self._sock.close()
  104. async def send(self, message):
  105. await self._sock.send(message)
  106. async def wait(self):
  107. data = await self._sock.recv()
  108. if not isinstance(data, six.binary_type) and \
  109. not isinstance(data, six.text_type):
  110. raise IOError()
  111. return data
  112. _async = {
  113. 'asyncio': True,
  114. 'create_route': create_route,
  115. 'translate_request': translate_request,
  116. 'make_response': make_response,
  117. 'websocket': WebSocket if WebSocketProtocol else None,
  118. }