123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143 |
- # -*- coding: utf-8 -
- #
- # This file is part of gunicorn released under the MIT license.
- # See the NOTICE for more information.
-
- from datetime import datetime
- import errno
- import socket
- import ssl
- import sys
-
- import gunicorn.http as http
- import gunicorn.http.wsgi as wsgi
- import gunicorn.util as util
- import gunicorn.workers.base as base
- from gunicorn import six
-
- ALREADY_HANDLED = object()
-
-
- class AsyncWorker(base.Worker):
-
- def __init__(self, *args, **kwargs):
- super(AsyncWorker, self).__init__(*args, **kwargs)
- self.worker_connections = self.cfg.worker_connections
-
- def timeout_ctx(self):
- raise NotImplementedError()
-
- def handle(self, listener, client, addr):
- req = None
- try:
- parser = http.RequestParser(self.cfg, client)
- try:
- listener_name = listener.getsockname()
- if not self.cfg.keepalive:
- req = six.next(parser)
- self.handle_request(listener_name, req, client, addr)
- else:
- # keepalive loop
- proxy_protocol_info = {}
- while True:
- req = None
- with self.timeout_ctx():
- req = six.next(parser)
- if not req:
- break
- if req.proxy_protocol_info:
- proxy_protocol_info = req.proxy_protocol_info
- else:
- req.proxy_protocol_info = proxy_protocol_info
- self.handle_request(listener_name, req, client, addr)
- except http.errors.NoMoreData as e:
- self.log.debug("Ignored premature client disconnection. %s", e)
- except StopIteration as e:
- self.log.debug("Closing connection. %s", e)
- except ssl.SSLError:
- # pass to next try-except level
- six.reraise(*sys.exc_info())
- except EnvironmentError:
- # pass to next try-except level
- six.reraise(*sys.exc_info())
- except Exception as e:
- self.handle_error(req, client, addr, e)
- except ssl.SSLError as e:
- if e.args[0] == ssl.SSL_ERROR_EOF:
- self.log.debug("ssl connection closed")
- client.close()
- else:
- self.log.debug("Error processing SSL request.")
- self.handle_error(req, client, addr, e)
- except EnvironmentError as e:
- if e.errno not in (errno.EPIPE, errno.ECONNRESET):
- self.log.exception("Socket error processing request.")
- else:
- if e.errno == errno.ECONNRESET:
- self.log.debug("Ignoring connection reset")
- else:
- self.log.debug("Ignoring EPIPE")
- except Exception as e:
- self.handle_error(req, client, addr, e)
- finally:
- util.close(client)
-
- def handle_request(self, listener_name, req, sock, addr):
- request_start = datetime.now()
- environ = {}
- resp = None
- try:
- self.cfg.pre_request(self, req)
- resp, environ = wsgi.create(req, sock, addr,
- listener_name, self.cfg)
- environ["wsgi.multithread"] = True
- self.nr += 1
- if self.alive and self.nr >= self.max_requests:
- self.log.info("Autorestarting worker after current request.")
- resp.force_close()
- self.alive = False
-
- if not self.cfg.keepalive:
- resp.force_close()
-
- respiter = self.wsgi(environ, resp.start_response)
- if respiter == ALREADY_HANDLED:
- return False
- try:
- if isinstance(respiter, environ['wsgi.file_wrapper']):
- resp.write_file(respiter)
- else:
- for item in respiter:
- resp.write(item)
- resp.close()
- request_time = datetime.now() - request_start
- self.log.access(resp, req, environ, request_time)
- finally:
- if hasattr(respiter, "close"):
- respiter.close()
- if resp.should_close():
- raise StopIteration()
- except StopIteration:
- raise
- except EnvironmentError:
- # If the original exception was a socket.error we delegate
- # handling it to the caller (where handle() might ignore it)
- six.reraise(*sys.exc_info())
- except Exception:
- if resp and resp.headers_sent:
- # If the requests have already been sent, we should close the
- # connection to indicate the error.
- self.log.exception("Error handling request")
- try:
- sock.shutdown(socket.SHUT_RDWR)
- sock.close()
- except EnvironmentError:
- pass
- raise StopIteration()
- raise
- finally:
- try:
- self.cfg.post_request(self, req, environ, resp)
- except Exception:
- self.log.exception("Exception in post_request hook")
- return True
|