django的web server的源代码流程

 1 class WSGIServer(simple_server.WSGIServer):
 2     """BaseHTTPServer that implements the Python WSGI protocol"""
 3 
 4     request_queue_size = 10
 5 
 6     def __init__(self, *args, ipv6=False, allow_reuse_address=True, **kwargs):
 7         if ipv6:
 8             self.address_family = socket.AF_INET6
 9         self.allow_reuse_address = allow_reuse_address
10         super().__init__(*args, **kwargs)
11 
12     def handle_error(self, request, client_address):
13         if is_broken_pipe_error():
14             logger.info("- Broken pipe from %s\n", client_address)
15         else:
16             super().handle_error(request, client_address)
17 
18 class WSGIRequestHandler(simple_server.WSGIRequestHandler):
19     protocol_version = 'HTTP/1.1'
20 
21     def address_string(self):
22         # Short-circuit parent method to not call socket.getfqdn
23         return self.client_address[0]
24 
25     def log_message(self, format, *args):
26         extra = {
27             'request': self.request,
28             'server_time': self.log_date_time_string(),
29         }
30         if args[1][0] == '4':
31             # 0x16 = Handshake, 0x03 = SSL 3.0 or TLS 1.x
32             if args[0].startswith('\x16\x03'):
33                 extra['status_code'] = 500
34                 logger.error(
35                     "You're accessing the development server over HTTPS, but "
36                     "it only supports HTTP.\n", extra=extra,
37                 )
38                 return
39 
40         if args[1].isdigit() and len(args[1]) == 3:
41             status_code = int(args[1])
42             extra['status_code'] = status_code
43 
44             if status_code >= 500:
45                 level = logger.error
46             elif status_code >= 400:
47                 level = logger.warning
48             else:
49                 level = logger.info
50         else:
51             level = logger.info
52 
53         level(format, *args, extra=extra)
54 
55     def get_environ(self):
56         # Strip all headers with underscores in the name before constructing
57         # the WSGI environ. This prevents header-spoofing based on ambiguity
58         # between underscores and dashes both normalized to underscores in WSGI
59         # env vars. Nginx and Apache 2.4+ both do this as well.
60         for k in self.headers:
61             if '_' in k:
62                 del self.headers[k]
63 
64         return super().get_environ()
65 
66     def handle(self):
67         self.close_connection = True
68         self.handle_one_request()
69         while not self.close_connection:
70             self.handle_one_request()
71         try:
72             self.connection.shutdown(socket.SHUT_WR)
73         except (socket.error, AttributeError):
74             pass
75 
76     def handle_one_request(self):
77         """Copy of WSGIRequestHandler.handle() but with different ServerHandler"""
78         self.raw_requestline = self.rfile.readline(65537)
79         if len(self.raw_requestline) > 65536:
80             self.requestline = ''
81             self.request_version = ''
82             self.command = ''
83             self.send_error(414)
84             return
85 
86         if not self.parse_request():  # An error code has been sent, just exit
87             return
88 
89         handler = ServerHandler(
90             self.rfile, self.wfile, self.get_stderr(), self.get_environ()
91         )
92         handler.request_handler = self      # backpointer for logging & connection closing
93         handler.run(self.server.get_app())
WSGIServer的父类是wsgiref.simple_server.WSGIServer, wsgiref.simple_server.WSGIServer的父类是http.server.HTTPServer,http.server.HTTPServer的父类是socketserver.TCPServer;
WSGIRequestHandler的父类是wsgiref.simple_server.WSGIRequestHandler,wsgiref.simple_server.WSGIRequestHandler的父类是http.server.BaseHTTPRequestHandler,
http.server.BaseHTTPRequestHandler的父类是socketserver.StreamRequestHandler,socketserver.StreamRequestHandler的父类是socketserver.BaseRequestHandler
def run(addr, port, wsgi_handler, ipv6=False, threading=False, server_cls=WSGIServer):
    server_address = (addr, port)
    if threading:
        httpd_cls = type('WSGIServer', (socketserver.ThreadingMixIn, server_cls), {})
    else:
        httpd_cls = server_cls
    httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6)  实例化WSGIserver
    if threading:
        # ThreadingMixIn.daemon_threads indicates how threads will behave on an
        # abrupt shutdown; like quitting the server by the user or restarting
        # by the auto-reloader. True means the server will not wait for thread
        # termination before it quits. This will make auto-reloader faster
        # and will prevent the need to kill the server manually if a thread
        # isn't terminating correctly.
        httpd.daemon_threads = True
    httpd.set_app(wsgi_handler)
    httpd.serve_forever()  #这里调用TCPserver的父类BaseServer的serve_forever方法

在socketserver.BaseServer.serve_forever中

 1     def serve_forever(self, poll_interval=0.5):
 2         """Handle one request at a time until shutdown.
 3 
 4         Polls for shutdown every poll_interval seconds. Ignores
 5         self.timeout. If you need to do periodic tasks, do them in
 6         another thread.
 7         """
 8         self.__is_shut_down.clear()
 9         try:
10             # XXX: Consider using another file descriptor or connecting to the
11             # socket to wake this up instead of polling. Polling reduces our
12             # responsiveness to a shutdown request and wastes cpu at all other
13             # times.
14             with _ServerSelector() as selector:
15                 selector.register(self, selectors.EVENT_READ)
16 
17                 while not self.__shutdown_request:
18                     ready = selector.select(poll_interval)
19                     # bpo-35017: shutdown() called during select(), exit immediately.
20                     if self.__shutdown_request:
21                         break
22                     if ready:
23                         self._handle_request_noblock()  在这里调用process_request方法
24 
25                     self.service_actions()
26         finally:
27             self.__shutdown_request = False
28             self.__is_shut_down.set()

在process_request方法中调用finish_request方法去实例化WSGIRequestHandler

1     def process_request(self, request, client_address):
2         """Call finish_request.
3 
4         Overridden by ForkingMixIn and ThreadingMixIn.
5 
6         """
7         self.finish_request(request, client_address)
8         self.shutdown_request(request)

在finish_request中实例化WSGIRequestHandler

    def finish_request(self, request, client_address):
        """Finish one request by instantiating RequestHandlerClass."""
        self.RequestHandlerClass(request, client_address, self)  #这个self是WSGIserver实例化的对象
class BaseRequestHandler:  #实例化WSGIRequestHandler必须先初始化BaseRequestHandler类

    """Base class for request handler classes.

    This class is instantiated for each request to be handled.  The
    constructor sets the instance variables request, client_address
    and server, and then calls the handle() method.  To implement a
    specific service, all you need to do is to derive a class which
    defines a handle() method.

    The handle() method can find the request as self.request, the
    client address as self.client_address, and the server (in case it
    needs access to per-server information) as self.server.  Since a
    separate instance is created for each request, the handle() method
    can define other arbitrary instance variables.

    """

    def __init__(self, request, client_address, server):
        self.request = request
        self.client_address = client_address
        self.server = server
        self.setup()
        try:
            self.handle()  #这个类没有实现handle方法,所以需要我们自己去实现
        finally:
            self.finish()

    def setup(self):
        pass

    def handle(self):
        pass

    def finish(self):
        pass

class StreamRequestHandler(BaseRequestHandler):

    """Define self.rfile and self.wfile for stream sockets."""

    # Default buffer sizes for rfile, wfile.
    # We default rfile to buffered because otherwise it could be
    # really slow for large data (a getc() call per byte); we make
    # wfile unbuffered because (a) often after a write() we want to
    # read and we need to flush the line; (b) big writes to unbuffered
    # files are typically optimized by stdio even when big reads
    # aren't.
    rbufsize = -1
    wbufsize = 0

    # A timeout to apply to the request socket, if not None.
    timeout = None

    # Disable nagle algorithm for this socket, if True.
    # Use only when wbufsize != 0, to avoid small packets.
    disable_nagle_algorithm = False

    def setup(self):
        self.connection = self.request
        if self.timeout is not None:
            self.connection.settimeout(self.timeout)
        if self.disable_nagle_algorithm:
            self.connection.setsockopt(socket.IPPROTO_TCP,
                                       socket.TCP_NODELAY, True)
        self.rfile = self.connection.makefile('rb', self.rbufsize)
        if self.wbufsize == 0:
            self.wfile = _SocketWriter(self.connection)
        else:
            self.wfile = self.connection.makefile('wb', self.wbufsize)

    def finish(self):
        if not self.wfile.closed:
            try:
                self.wfile.flush()
            except socket.error:
                # A final socket error may have occurred here, such as
                # the local error ECONNABORTED.
                pass
        self.wfile.close()
        self.rfile.close()

在handle方法中

 1 class WSGIRequestHandler(BaseHTTPRequestHandler):
 2 
 3     server_version = "WSGIServer/" + __version__
 4 
 5     def get_environ(self):
 6         env = self.server.base_environ.copy()
 7         env['SERVER_PROTOCOL'] = self.request_version
 8         env['SERVER_SOFTWARE'] = self.server_version
 9         env['REQUEST_METHOD'] = self.command
10         if '?' in self.path:
11             path,query = self.path.split('?',1)
12         else:
13             path,query = self.path,''
14 
15         env['PATH_INFO'] = urllib.parse.unquote(path, 'iso-8859-1')
16         env['QUERY_STRING'] = query
17 
18         host = self.address_string()
19         if host != self.client_address[0]:
20             env['REMOTE_HOST'] = host
21         env['REMOTE_ADDR'] = self.client_address[0]
22 
23         if self.headers.get('content-type') is None:
24             env['CONTENT_TYPE'] = self.headers.get_content_type()
25         else:
26             env['CONTENT_TYPE'] = self.headers['content-type']
27 
28         length = self.headers.get('content-length')
29         if length:
30             env['CONTENT_LENGTH'] = length
31 
32         for k, v in self.headers.items():
33             k=k.replace('-','_').upper(); v=v.strip()
34             if k in env:
35                 continue                    # skip content length, type,etc.
36             if 'HTTP_'+k in env:
37                 env['HTTP_'+k] += ','+v     # comma-separate multiple headers
38             else:
39                 env['HTTP_'+k] = v
40         return env
41 
42     def get_stderr(self):
43         return sys.stderr
44 
45     def handle(self):
46         """Handle a single HTTP request"""
47 
48         self.raw_requestline = self.rfile.readline(65537)  #读取游览器发来的请求包文起始
49         if len(self.raw_requestline) > 65536:  #判断数据长度是否大于65536
50             self.requestline = ''
51             self.request_version = ''
52             self.command = ''
53             self.send_error(414)   #发送414错误
54             return
55 
56         if not self.parse_request(): # An error code has been sent, just exit
57             return
58 
59         handler = ServerHandler(
60             self.rfile, self.wfile, self.get_stderr(), self.get_environ()
61         )  #rfile相当于socket中的recv,wfile相当于socket中的send,   get_atderr是系统的标准错误输出句柄, get_environ是先将下划线开头的头部字段删除,再调用父类的get_envrion方法将请求的头部字段加上HTTP_,再添加一些公共字段
62         handler.request_handler = self      # backpointer for logging
63         handler.run(self.server.get_app())

在run中

 1     def run(self, application):
 2         """Invoke the application"""
 3         # Note to self: don't move the close()!  Asynchronous servers shouldn't
 4         # call close() from finish_response(), so if you close() anywhere but
 5         # the double-error branch here, you'll break asynchronous servers by
 6         # prematurely closing.  Async servers must return from 'run()' without
 7         # closing if there might still be output to iterate over.
 8         try:
 9             self.setup_environ()  #设置环境,将系统环境拷贝,然后将传入的环境变量扩展进该环境内同时增加一些WSGI通用环境
10             self.result = application(self.environ, self.start_response)#设置完环境后开始执行我们传入的handler对象
11             self.finish_response()
12         except:
13             try:
14                 self.handle_error()
15             except:
16                 # If we get an error handling an error, just give up already!
17                 self.close()
18                 raise   # ...and let the actual server figure it out.

也就是执行以下代码

 1 class WSGIHandler(base.BaseHandler):
 2     request_class = WSGIRequest
 3 
 4     def __init__(self, *args, **kwargs):
 5         super(WSGIHandler, self).__init__(*args, **kwargs)
 6         self.load_middleware()
 7 
 8     def __call__(self, environ, start_response):
 9         set_script_prefix(get_script_name(environ))
10         signals.request_started.send(sender=self.__class__, environ=environ)
11         request = self.request_class(environ)
12         response = self.get_response(request)
13         response._handler_class = self.__class__
14 
15         status = '%d %s' % (response.status_code, response.reason_phrase)
16         response_headers = [(str(k), str(v)) for k, v in response.items()]
17         for c in response.cookies.values():
18             response_headers.append((str('Set-Cookie'), str(c.output(header=''))))
19         start_response(force_str(status), response_headers)
20         if getattr(response, 'file_to_stream', None) is not None and environ.get('wsgi.file_wrapper'):
21             response = environ['wsgi.file_wrapper'](response.file_to_stream)
22         return response


猜你喜欢

转载自www.cnblogs.com/arrow-kejin/p/10361341.html