Development of an internal social media platform with personalised dashboards for students
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

async.py 5.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. # -*- coding: utf-8 -
  2. #
  3. # This file is part of gunicorn released under the MIT license.
  4. # See the NOTICE for more information.
  5. from datetime import datetime
  6. import errno
  7. import socket
  8. import ssl
  9. import sys
  10. import gunicorn.http as http
  11. import gunicorn.http.wsgi as wsgi
  12. import gunicorn.util as util
  13. import gunicorn.workers.base as base
  14. from gunicorn import six
  15. ALREADY_HANDLED = object()
  16. class AsyncWorker(base.Worker):
  17. def __init__(self, *args, **kwargs):
  18. super(AsyncWorker, self).__init__(*args, **kwargs)
  19. self.worker_connections = self.cfg.worker_connections
  20. def timeout_ctx(self):
  21. raise NotImplementedError()
  22. def handle(self, listener, client, addr):
  23. req = None
  24. try:
  25. parser = http.RequestParser(self.cfg, client)
  26. try:
  27. listener_name = listener.getsockname()
  28. if not self.cfg.keepalive:
  29. req = six.next(parser)
  30. self.handle_request(listener_name, req, client, addr)
  31. else:
  32. # keepalive loop
  33. proxy_protocol_info = {}
  34. while True:
  35. req = None
  36. with self.timeout_ctx():
  37. req = six.next(parser)
  38. if not req:
  39. break
  40. if req.proxy_protocol_info:
  41. proxy_protocol_info = req.proxy_protocol_info
  42. else:
  43. req.proxy_protocol_info = proxy_protocol_info
  44. self.handle_request(listener_name, req, client, addr)
  45. except http.errors.NoMoreData as e:
  46. self.log.debug("Ignored premature client disconnection. %s", e)
  47. except StopIteration as e:
  48. self.log.debug("Closing connection. %s", e)
  49. except ssl.SSLError:
  50. # pass to next try-except level
  51. six.reraise(*sys.exc_info())
  52. except EnvironmentError:
  53. # pass to next try-except level
  54. six.reraise(*sys.exc_info())
  55. except Exception as e:
  56. self.handle_error(req, client, addr, e)
  57. except ssl.SSLError as e:
  58. if e.args[0] == ssl.SSL_ERROR_EOF:
  59. self.log.debug("ssl connection closed")
  60. client.close()
  61. else:
  62. self.log.debug("Error processing SSL request.")
  63. self.handle_error(req, client, addr, e)
  64. except EnvironmentError as e:
  65. if e.errno not in (errno.EPIPE, errno.ECONNRESET):
  66. self.log.exception("Socket error processing request.")
  67. else:
  68. if e.errno == errno.ECONNRESET:
  69. self.log.debug("Ignoring connection reset")
  70. else:
  71. self.log.debug("Ignoring EPIPE")
  72. except Exception as e:
  73. self.handle_error(req, client, addr, e)
  74. finally:
  75. util.close(client)
  76. def handle_request(self, listener_name, req, sock, addr):
  77. request_start = datetime.now()
  78. environ = {}
  79. resp = None
  80. try:
  81. self.cfg.pre_request(self, req)
  82. resp, environ = wsgi.create(req, sock, addr,
  83. listener_name, self.cfg)
  84. environ["wsgi.multithread"] = True
  85. self.nr += 1
  86. if self.alive and self.nr >= self.max_requests:
  87. self.log.info("Autorestarting worker after current request.")
  88. resp.force_close()
  89. self.alive = False
  90. if not self.cfg.keepalive:
  91. resp.force_close()
  92. respiter = self.wsgi(environ, resp.start_response)
  93. if respiter == ALREADY_HANDLED:
  94. return False
  95. try:
  96. if isinstance(respiter, environ['wsgi.file_wrapper']):
  97. resp.write_file(respiter)
  98. else:
  99. for item in respiter:
  100. resp.write(item)
  101. resp.close()
  102. request_time = datetime.now() - request_start
  103. self.log.access(resp, req, environ, request_time)
  104. finally:
  105. if hasattr(respiter, "close"):
  106. respiter.close()
  107. if resp.should_close():
  108. raise StopIteration()
  109. except StopIteration:
  110. raise
  111. except EnvironmentError:
  112. # If the original exception was a socket.error we delegate
  113. # handling it to the caller (where handle() might ignore it)
  114. six.reraise(*sys.exc_info())
  115. except Exception:
  116. if resp and resp.headers_sent:
  117. # If the requests have already been sent, we should close the
  118. # connection to indicate the error.
  119. self.log.exception("Error handling request")
  120. try:
  121. sock.shutdown(socket.SHUT_RDWR)
  122. sock.close()
  123. except EnvironmentError:
  124. pass
  125. raise StopIteration()
  126. raise
  127. finally:
  128. try:
  129. self.cfg.post_request(self, req, environ, resp)
  130. except Exception:
  131. self.log.exception("Exception in post_request hook")
  132. return True