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.

_gaiohttp.py 5.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  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. import asyncio
  6. import datetime
  7. import functools
  8. import logging
  9. import os
  10. try:
  11. import ssl
  12. except ImportError:
  13. ssl = None
  14. import gunicorn.workers.base as base
  15. from aiohttp.wsgi import WSGIServerHttpProtocol as OldWSGIServerHttpProtocol
  16. class WSGIServerHttpProtocol(OldWSGIServerHttpProtocol):
  17. def log_access(self, request, environ, response, time):
  18. self.logger.access(response, request, environ, datetime.timedelta(0, 0, time))
  19. class AiohttpWorker(base.Worker):
  20. def __init__(self, *args, **kw): # pragma: no cover
  21. super().__init__(*args, **kw)
  22. cfg = self.cfg
  23. if cfg.is_ssl:
  24. self.ssl_context = self._create_ssl_context(cfg)
  25. else:
  26. self.ssl_context = None
  27. self.servers = []
  28. self.connections = {}
  29. def init_process(self):
  30. # create new event_loop after fork
  31. asyncio.get_event_loop().close()
  32. self.loop = asyncio.new_event_loop()
  33. asyncio.set_event_loop(self.loop)
  34. super().init_process()
  35. def run(self):
  36. self._runner = asyncio.async(self._run(), loop=self.loop)
  37. try:
  38. self.loop.run_until_complete(self._runner)
  39. finally:
  40. self.loop.close()
  41. def wrap_protocol(self, proto):
  42. proto.connection_made = _wrp(
  43. proto, proto.connection_made, self.connections)
  44. proto.connection_lost = _wrp(
  45. proto, proto.connection_lost, self.connections, False)
  46. return proto
  47. def factory(self, wsgi, addr):
  48. # are we in debug level
  49. is_debug = self.log.loglevel == logging.DEBUG
  50. proto = WSGIServerHttpProtocol(
  51. wsgi, readpayload=True,
  52. loop=self.loop,
  53. log=self.log,
  54. debug=is_debug,
  55. keep_alive=self.cfg.keepalive,
  56. access_log=self.log.access_log,
  57. access_log_format=self.cfg.access_log_format)
  58. return self.wrap_protocol(proto)
  59. def get_factory(self, sock, addr):
  60. return functools.partial(self.factory, self.wsgi, addr)
  61. @asyncio.coroutine
  62. def close(self):
  63. try:
  64. if hasattr(self.wsgi, 'close'):
  65. yield from self.wsgi.close()
  66. except:
  67. self.log.exception('Process shutdown exception')
  68. @asyncio.coroutine
  69. def _run(self):
  70. for sock in self.sockets:
  71. factory = self.get_factory(sock.sock, sock.cfg_addr)
  72. self.servers.append(
  73. (yield from self._create_server(factory, sock)))
  74. # If our parent changed then we shut down.
  75. pid = os.getpid()
  76. try:
  77. while self.alive or self.connections:
  78. self.notify()
  79. if (self.alive and
  80. pid == os.getpid() and self.ppid != os.getppid()):
  81. self.log.info("Parent changed, shutting down: %s", self)
  82. self.alive = False
  83. # stop accepting requests
  84. if not self.alive:
  85. if self.servers:
  86. self.log.info(
  87. "Stopping server: %s, connections: %s",
  88. pid, len(self.connections))
  89. for server in self.servers:
  90. server.close()
  91. self.servers.clear()
  92. # prepare connections for closing
  93. for conn in self.connections.values():
  94. if hasattr(conn, 'closing'):
  95. conn.closing()
  96. yield from asyncio.sleep(1.0, loop=self.loop)
  97. except KeyboardInterrupt:
  98. pass
  99. if self.servers:
  100. for server in self.servers:
  101. server.close()
  102. yield from self.close()
  103. @asyncio.coroutine
  104. def _create_server(self, factory, sock):
  105. return self.loop.create_server(factory, sock=sock.sock,
  106. ssl=self.ssl_context)
  107. @staticmethod
  108. def _create_ssl_context(cfg):
  109. """ Creates SSLContext instance for usage in asyncio.create_server.
  110. See ssl.SSLSocket.__init__ for more details.
  111. """
  112. ctx = ssl.SSLContext(cfg.ssl_version)
  113. ctx.load_cert_chain(cfg.certfile, cfg.keyfile)
  114. ctx.verify_mode = cfg.cert_reqs
  115. if cfg.ca_certs:
  116. ctx.load_verify_locations(cfg.ca_certs)
  117. if cfg.ciphers:
  118. ctx.set_ciphers(cfg.ciphers)
  119. return ctx
  120. class _wrp:
  121. def __init__(self, proto, meth, tracking, add=True):
  122. self._proto = proto
  123. self._id = id(proto)
  124. self._meth = meth
  125. self._tracking = tracking
  126. self._add = add
  127. def __call__(self, *args):
  128. if self._add:
  129. self._tracking[self._id] = self._proto
  130. elif self._id in self._tracking:
  131. del self._tracking[self._id]
  132. conn = self._meth(*args)
  133. return conn