1. """Generic socket server classes.
  2.  
  3. This module tries to capture the various aspects of defining a server:
  4.  
  5. For socket-based servers:
  6.  
  7. - address family:
  8. - AF_INET{,6}: IP (Internet Protocol) sockets (default)
  9. - AF_UNIX: Unix domain sockets
  10. - others, e.g. AF_DECNET are conceivable (see <socket.h>
  11. - socket type:
  12. - SOCK_STREAM (reliable stream, e.g. TCP)
  13. - SOCK_DGRAM (datagrams, e.g. UDP)
  14.  
  15. For request-based servers (including socket-based):
  16.  
  17. - client address verification before further looking at the request
  18. (This is actually a hook for any processing that needs to look
  19. at the request before anything else, e.g. logging)
  20. - how to handle multiple requests:
  21. - synchronous (one request is handled at a time)
  22. - forking (each request is handled by a new process)
  23. - threading (each request is handled by a new thread)
  24.  
  25. The classes in this module favor the server type that is simplest to
  26. write: a synchronous TCP/IP server. This is bad class design, but
  27. save some typing. (There's also the issue that a deep class hierarchy
  28. slows down method lookups.)
  29.  
  30. There are five classes in an inheritance diagram, four of which represent
  31. synchronous servers of four types:
  32.  
  33. +------------+
  34. | BaseServer |
  35. +------------+
  36. |
  37. v
  38. +-----------+ +------------------+
  39. | TCPServer |------->| UnixStreamServer |
  40. +-----------+ +------------------+
  41. |
  42. v
  43. +-----------+ +--------------------+
  44. | UDPServer |------->| UnixDatagramServer |
  45. +-----------+ +--------------------+
  46.  
  47. Note that UnixDatagramServer derives from UDPServer, not from
  48. UnixStreamServer -- the only difference between an IP and a Unix
  49. stream server is the address family, which is simply repeated in both
  50. unix server classes.
  51.  
  52. Forking and threading versions of each type of server can be created
  53. using the ForkingMixIn and ThreadingMixIn mix-in classes. For
  54. instance, a threading UDP server class is created as follows:
  55.  
  56. class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass
  57.  
  58. The Mix-in class must come first, since it overrides a method defined
  59. in UDPServer! Setting the various member variables also changes
  60. the behavior of the underlying server mechanism.
  61.  
  62. To implement a service, you must derive a class from
  63. BaseRequestHandler and redefine its handle() method. You can then run
  64. various versions of the service by combining one of the server classes
  65. with your request handler class.
  66.  
  67. The request handler class must be different for datagram or stream
  68. services. This can be hidden by using the request handler
  69. subclasses StreamRequestHandler or DatagramRequestHandler.
  70.  
  71. Of course, you still have to use your head!
  72.  
  73. For instance, it makes no sense to use a forking server if the service
  74. contains state in memory that can be modified by requests (since the
  75. modifications in the child process would never reach the initial state
  76. kept in the parent process and passed to each child). In this case,
  77. you can use a threading server, but you will probably have to use
  78. locks to avoid two requests that come in nearly simultaneous to apply
  79. conflicting changes to the server state.
  80.  
  81. On the other hand, if you are building e.g. an HTTP server, where all
  82. data is stored externally (e.g. in the file system), a synchronous
  83. class will essentially render the service "deaf" while one request is
  84. being handled -- which may be for a very long time if a client is slow
  85. to read all the data it has requested. Here a threading or forking
  86. server is appropriate.
  87.  
  88. In some cases, it may be appropriate to process part of a request
  89. synchronously, but to finish processing in a forked child depending on
  90. the request data. This can be implemented by using a synchronous
  91. server and doing an explicit fork in the request handler class
  92. handle() method.
  93.  
  94. Another approach to handling multiple simultaneous requests in an
  95. environment that supports neither threads nor fork (or where these are
  96. too expensive or inappropriate for the service) is to maintain an
  97. explicit table of partially finished requests and to use select() to
  98. decide which request to work on next (or whether to handle a new
  99. incoming request). This is particularly important for stream services
  100. where each client can potentially be connected for a long time (if
  101. threads or subprocesses cannot be used).
  102.  
  103. Future work:
  104. - Standard classes for Sun RPC (which uses either UDP or TCP)
  105. - Standard mix-in classes to implement various authentication
  106. and encryption schemes
  107. - Standard framework for select-based multiplexing
  108.  
  109. XXX Open problems:
  110. - What to do with out-of-band data?
  111.  
  112. BaseServer:
  113. - split generic "request" functionality out into BaseServer class.
  114. Copyright (C) 2000 Luke Kenneth Casson Leighton <lkcl@samba.org>
  115.  
  116. example: read entries from a SQL database (requires overriding
  117. get_request() to return a table entry from the database).
  118. entry is processed by a RequestHandlerClass.
  119.  
  120. """
  121.  
  122. # Author of the BaseServer patch: Luke Kenneth Casson Leighton
  123.  
  124. # XXX Warning!
  125. # There is a test suite for this module, but it cannot be run by the
  126. # standard regression test.
  127. # To run it manually, run Lib/test/test_socketserver.py.
  128.  
  129. __version__ = "0.4"
  130.  
  131. import socket
  132. import select
  133. import sys
  134. import os
  135. import errno
  136. try:
  137. import threading
  138. except ImportError:
  139. import dummy_threading as threading
  140.  
  141. __all__ = ["TCPServer","UDPServer","ForkingUDPServer","ForkingTCPServer",
  142. "ThreadingUDPServer","ThreadingTCPServer","BaseRequestHandler",
  143. "StreamRequestHandler","DatagramRequestHandler",
  144. "ThreadingMixIn", "ForkingMixIn"]
  145. if hasattr(socket, "AF_UNIX"):
  146. __all__.extend(["UnixStreamServer","UnixDatagramServer",
  147. "ThreadingUnixStreamServer",
  148. "ThreadingUnixDatagramServer"])
  149.  
  150. def _eintr_retry(func, *args):
  151. """restart a system call interrupted by EINTR"""
  152. while True:
  153. try:
  154. return func(*args)
  155. except (OSError, select.error) as e:
  156. if e.args[0] != errno.EINTR:
  157. raise
  158.  
  159. class BaseServer:
  160.  
  161. """Base class for server classes.
  162.  
  163. Methods for the caller:
  164.  
  165. - __init__(server_address, RequestHandlerClass)
  166. - serve_forever(poll_interval=0.5)
  167. - shutdown()
  168. - handle_request() # if you do not use serve_forever()
  169. - fileno() -> int # for select()
  170.  
  171. Methods that may be overridden:
  172.  
  173. - server_bind()
  174. - server_activate()
  175. - get_request() -> request, client_address
  176. - handle_timeout()
  177. - verify_request(request, client_address)
  178. - server_close()
  179. - process_request(request, client_address)
  180. - shutdown_request(request)
  181. - close_request(request)
  182. - handle_error()
  183.  
  184. Methods for derived classes:
  185.  
  186. - finish_request(request, client_address)
  187.  
  188. Class variables that may be overridden by derived classes or
  189. instances:
  190.  
  191. - timeout
  192. - address_family
  193. - socket_type
  194. - allow_reuse_address
  195.  
  196. Instance variables:
  197.  
  198. - RequestHandlerClass
  199. - socket
  200.  
  201. """
  202.  
  203. timeout = None
  204.  
  205. def __init__(self, server_address, RequestHandlerClass):
  206. """Constructor. May be extended, do not override."""
  207. self.server_address = server_address
  208. self.RequestHandlerClass = RequestHandlerClass
  209. self.__is_shut_down = threading.Event()
  210. self.__shutdown_request = False
  211.  
  212. def server_activate(self):
  213. """Called by constructor to activate the server.
  214.  
  215. May be overridden.
  216.  
  217. """
  218. pass
  219.  
  220. def serve_forever(self, poll_interval=0.5):
  221. """Handle one request at a time until shutdown.
  222.  
  223. Polls for shutdown every poll_interval seconds. Ignores
  224. self.timeout. If you need to do periodic tasks, do them in
  225. another thread.
  226. """
  227. self.__is_shut_down.clear()
  228. try:
  229. while not self.__shutdown_request:
  230. # XXX: Consider using another file descriptor or
  231. # connecting to the socket to wake this up instead of
  232. # polling. Polling reduces our responsiveness to a
  233. # shutdown request and wastes cpu at all other times.
  234. r, w, e = _eintr_retry(select.select, [self], [], [],
  235. poll_interval)
  236. if self in r:
  237. self._handle_request_noblock()
  238. finally:
  239. self.__shutdown_request = False
  240. self.__is_shut_down.set()
  241.  
  242. def shutdown(self):
  243. """Stops the serve_forever loop.
  244.  
  245. Blocks until the loop has finished. This must be called while
  246. serve_forever() is running in another thread, or it will
  247. deadlock.
  248. """
  249. self.__shutdown_request = True
  250. self.__is_shut_down.wait()
  251.  
  252. # The distinction between handling, getting, processing and
  253. # finishing a request is fairly arbitrary. Remember:
  254. #
  255. # - handle_request() is the top-level call. It calls
  256. # select, get_request(), verify_request() and process_request()
  257. # - get_request() is different for stream or datagram sockets
  258. # - process_request() is the place that may fork a new process
  259. # or create a new thread to finish the request
  260. # - finish_request() instantiates the request handler class;
  261. # this constructor will handle the request all by itself
  262.  
  263. def handle_request(self):
  264. """Handle one request, possibly blocking.
  265.  
  266. Respects self.timeout.
  267. """
  268. # Support people who used socket.settimeout() to escape
  269. # handle_request before self.timeout was available.
  270. timeout = self.socket.gettimeout()
  271. if timeout is None:
  272. timeout = self.timeout
  273. elif self.timeout is not None:
  274. timeout = min(timeout, self.timeout)
  275. fd_sets = _eintr_retry(select.select, [self], [], [], timeout)
  276. if not fd_sets[0]:
  277. self.handle_timeout()
  278. return
  279. self._handle_request_noblock()
  280.  
  281. def _handle_request_noblock(self):
  282. """Handle one request, without blocking.
  283.  
  284. I assume that select.select has returned that the socket is
  285. readable before this function was called, so there should be
  286. no risk of blocking in get_request().
  287. """
  288. try:
  289. request, client_address = self.get_request()
  290. except socket.error:
  291. return
  292. if self.verify_request(request, client_address):
  293. try:
  294. self.process_request(request, client_address)
  295. except:
  296. self.handle_error(request, client_address)
  297. self.shutdown_request(request)
  298.  
  299. def handle_timeout(self):
  300. """Called if no new request arrives within self.timeout.
  301.  
  302. Overridden by ForkingMixIn.
  303. """
  304. pass
  305.  
  306. def verify_request(self, request, client_address):
  307. """Verify the request. May be overridden.
  308.  
  309. Return True if we should proceed with this request.
  310.  
  311. """
  312. return True
  313.  
  314. def process_request(self, request, client_address):
  315. """Call finish_request.
  316.  
  317. Overridden by ForkingMixIn and ThreadingMixIn.
  318.  
  319. """
  320. self.finish_request(request, client_address)
  321. self.shutdown_request(request)
  322.  
  323. def server_close(self):
  324. """Called to clean-up the server.
  325.  
  326. May be overridden.
  327.  
  328. """
  329. pass
  330.  
  331. def finish_request(self, request, client_address):
  332. """Finish one request by instantiating RequestHandlerClass."""
  333. self.RequestHandlerClass(request, client_address, self)
  334.  
  335. def shutdown_request(self, request):
  336. """Called to shutdown and close an individual request."""
  337. self.close_request(request)
  338.  
  339. def close_request(self, request):
  340. """Called to clean up an individual request."""
  341. pass
  342.  
  343. def handle_error(self, request, client_address):
  344. """Handle an error gracefully. May be overridden.
  345.  
  346. The default is to print a traceback and continue.
  347.  
  348. """
  349. print '-'*40
  350. print 'Exception happened during processing of request from',
  351. print client_address
  352. import traceback
  353. traceback.print_exc() # XXX But this goes to stderr!
  354. print '-'*40
  355.  
  356. class TCPServer(BaseServer):
  357.  
  358. """Base class for various socket-based server classes.
  359.  
  360. Defaults to synchronous IP stream (i.e., TCP).
  361.  
  362. Methods for the caller:
  363.  
  364. - __init__(server_address, RequestHandlerClass, bind_and_activate=True)
  365. - serve_forever(poll_interval=0.5)
  366. - shutdown()
  367. - handle_request() # if you don't use serve_forever()
  368. - fileno() -> int # for select()
  369.  
  370. Methods that may be overridden:
  371.  
  372. - server_bind()
  373. - server_activate()
  374. - get_request() -> request, client_address
  375. - handle_timeout()
  376. - verify_request(request, client_address)
  377. - process_request(request, client_address)
  378. - shutdown_request(request)
  379. - close_request(request)
  380. - handle_error()
  381.  
  382. Methods for derived classes:
  383.  
  384. - finish_request(request, client_address)
  385.  
  386. Class variables that may be overridden by derived classes or
  387. instances:
  388.  
  389. - timeout
  390. - address_family
  391. - socket_type
  392. - request_queue_size (only for stream sockets)
  393. - allow_reuse_address
  394.  
  395. Instance variables:
  396.  
  397. - server_address
  398. - RequestHandlerClass
  399. - socket
  400.  
  401. """
  402.  
  403. address_family = socket.AF_INET
  404.  
  405. socket_type = socket.SOCK_STREAM
  406.  
  407. request_queue_size = 5
  408.  
  409. allow_reuse_address = False
  410.  
  411. def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True):
  412. """Constructor. May be extended, do not override."""
  413. BaseServer.__init__(self, server_address, RequestHandlerClass)
  414. self.socket = socket.socket(self.address_family,
  415. self.socket_type)
  416. if bind_and_activate:
  417. try:
  418. self.server_bind()
  419. self.server_activate()
  420. except:
  421. self.server_close()
  422. raise
  423.  
  424. def server_bind(self):
  425. """Called by constructor to bind the socket.
  426.  
  427. May be overridden.
  428.  
  429. """
  430. if self.allow_reuse_address:
  431. self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  432. self.socket.bind(self.server_address)
  433. self.server_address = self.socket.getsockname()
  434.  
  435. def server_activate(self):
  436. """Called by constructor to activate the server.
  437.  
  438. May be overridden.
  439.  
  440. """
  441. self.socket.listen(self.request_queue_size)
  442.  
  443. def server_close(self):
  444. """Called to clean-up the server.
  445.  
  446. May be overridden.
  447.  
  448. """
  449. self.socket.close()
  450.  
  451. def fileno(self):
  452. """Return socket file number.
  453.  
  454. Interface required by select().
  455.  
  456. """
  457. return self.socket.fileno()
  458.  
  459. def get_request(self):
  460. """Get the request and client address from the socket.
  461.  
  462. May be overridden.
  463.  
  464. """
  465. return self.socket.accept()
  466.  
  467. def shutdown_request(self, request):
  468. """Called to shutdown and close an individual request."""
  469. try:
  470. #explicitly shutdown. socket.close() merely releases
  471. #the socket and waits for GC to perform the actual close.
  472. request.shutdown(socket.SHUT_WR)
  473. except socket.error:
  474. pass #some platforms may raise ENOTCONN here
  475. self.close_request(request)
  476.  
  477. def close_request(self, request):
  478. """Called to clean up an individual request."""
  479. request.close()
  480. __version__ = "0.3"
  481.  
  482. __all__ = ["HTTPServer", "BaseHTTPRequestHandler"]
  483.  
  484. import sys
  485. import time
  486. import socket # For gethostbyaddr()
  487. from warnings import filterwarnings, catch_warnings
  488. with catch_warnings():
  489. if sys.py3kwarning:
  490. filterwarnings("ignore", ".*mimetools has been removed",
  491. DeprecationWarning)
  492. import mimetools
  493. import SocketServer
  494.  
  495. # Default error message template
  496. DEFAULT_ERROR_MESSAGE = """\
  497. <head>
  498. <title>Error response</title>
  499. </head>
  500. <body>
  501. <h1>Error response</h1>
  502. <p>Error code %(code)d.
  503. <p>Message: %(message)s.
  504. <p>Error code explanation: %(code)s = %(explain)s.
  505. </body>
  506. """
  507.  
  508. DEFAULT_ERROR_CONTENT_TYPE = "text/html"
  509.  
  510. def _quote_html(html):
  511. return html.replace("&", "&").replace("<", "<").replace(">", ">")
  512.  
  513. class HTTPServer(SocketServer.TCPServer):
  514.  
  515. allow_reuse_address = 1 # Seems to make sense in testing environment
  516.  
  517. def server_bind(self):
  518. """Override server_bind to store the server name."""
  519. SocketServer.TCPServer.server_bind(self)
  520. host, port = self.socket.getsockname()[:2]
  521. self.server_name = socket.getfqdn(host)
  522. self.server_port = port
  523.  
  524. SocketServer.StreamRequestHandler
  525. class BaseRequestHandler:
  526.  
  527. """Base class for request handler classes.
  528.  
  529. This class is instantiated for each request to be handled. The
  530. constructor sets the instance variables request, client_address
  531. and server, and then calls the handle() method. To implement a
  532. specific service, all you need to do is to derive a class which
  533. defines a handle() method.
  534.  
  535. The handle() method can find the request as self.request, the
  536. client address as self.client_address, and the server (in case it
  537. needs access to per-server information) as self.server. Since a
  538. separate instance is created for each request, the handle() method
  539. can define arbitrary other instance variariables.
  540.  
  541. """
  542.  
  543. def __init__(self, request, client_address, server):
  544. self.request = request
  545. self.client_address = client_address
  546. self.server = server
  547. self.setup()
  548. try:
  549. self.handle()
  550. finally:
  551. self.finish()
  552.  
  553. def setup(self):
  554. pass
  555.  
  556. def handle(self):
  557. pass
  558.  
  559. def finish(self):
  560. pass
  561.  
  562. # The following two classes make it possible to use the same service
  563. # class for stream or datagram servers.
  564. # Each class sets up these instance variables:
  565. # - rfile: a file object from which receives the request is read
  566. # - wfile: a file object to which the reply is written
  567. # When the handle() method returns, wfile is flushed properly
  568.  
  569. class StreamRequestHandler(BaseRequestHandler):
  570.  
  571. """Define self.rfile and self.wfile for stream sockets."""
  572.  
  573. # Default buffer sizes for rfile, wfile.
  574. # We default rfile to buffered because otherwise it could be
  575. # really slow for large data (a getc() call per byte); we make
  576. # wfile unbuffered because (a) often after a write() we want to
  577. # read and we need to flush the line; (b) big writes to unbuffered
  578. # files are typically optimized by stdio even when big reads
  579. # aren't.
  580. rbufsize = -1
  581. wbufsize = 0
  582.  
  583. # A timeout to apply to the request socket, if not None.
  584. timeout = None
  585.  
  586. # Disable nagle algorithm for this socket, if True.
  587. # Use only when wbufsize != 0, to avoid small packets.
  588. disable_nagle_algorithm = False
  589.  
  590. def setup(self):
  591. self.connection = self.request#是一个socket对象
  592. if self.timeout is not None:
  593. self.connection.settimeout(self.timeout)
  594. if self.disable_nagle_algorithm:
  595. self.connection.setsockopt(socket.IPPROTO_TCP,
  596. socket.TCP_NODELAY, True)
  597. self.rfile = self.connection.makefile('rb', self.rbufsize) #makefile([mode, [bufsize]]) -- return a file object for the socket [*]
  598. self.wfile = self.connection.makefile('wb', self.wbufsize)
  599.  
  600. def finish(self):
  601. if not self.wfile.closed:
  602. try:
  603. self.wfile.flush()
  604. except socket.error:
  605. # An final socket error may have occurred here, such as
  606. # the local error ECONNABORTED.
  607. pass
  608. self.wfile.close()
  609. self.rfile.close()
  610.  
  611. class BaseHTTPRequestHandler(SocketServer.StreamRequestHandler):
  612.  
  613. """HTTP request handler base class.
  614.  
  615. The following explanation of HTTP serves to guide you through the
  616. code as well as to expose any misunderstandings I may have about
  617. HTTP (so you don't need to read the code to figure out I'm wrong
  618. :-).
  619.  
  620. HTTP (HyperText Transfer Protocol) is an extensible protocol on
  621. top of a reliable stream transport (e.g. TCP/IP). The protocol
  622. recognizes three parts to a request:
  623.  
  624. 1. One line identifying the request type and path
  625. 2. An optional set of RFC-822-style headers
  626. 3. An optional data part
  627.  
  628. The headers and data are separated by a blank line.
  629.  
  630. The first line of the request has the form
  631.  
  632. <command> <path> <version>
  633.  
  634. where <command> is a (case-sensitive) keyword such as GET or POST,
  635. <path> is a string containing path information for the request,
  636. and <version> should be the string "HTTP/1.0" or "HTTP/1.1".
  637. <path> is encoded using the URL encoding scheme (using %xx to signify
  638. the ASCII character with hex code xx).
  639.  
  640. The specification specifies that lines are separated by CRLF but
  641. for compatibility with the widest range of clients recommends
  642. servers also handle LF. Similarly, whitespace in the request line
  643. is treated sensibly (allowing multiple spaces between components
  644. and allowing trailing whitespace).
  645.  
  646. Similarly, for output, lines ought to be separated by CRLF pairs
  647. but most clients grok LF characters just fine.
  648.  
  649. If the first line of the request has the form
  650.  
  651. <command> <path>
  652.  
  653. (i.e. <version> is left out) then this is assumed to be an HTTP
  654. 0.9 request; this form has no optional headers and data part and
  655. the reply consists of just the data.
  656.  
  657. The reply form of the HTTP 1.x protocol again has three parts:
  658.  
  659. 1. One line giving the response code
  660. 2. An optional set of RFC-822-style headers
  661. 3. The data
  662.  
  663. Again, the headers and data are separated by a blank line.
  664.  
  665. The response code line has the form
  666.  
  667. <version> <responsecode> <responsestring>
  668.  
  669. where <version> is the protocol version ("HTTP/1.0" or "HTTP/1.1"),
  670. <responsecode> is a 3-digit response code indicating success or
  671. failure of the request, and <responsestring> is an optional
  672. human-readable string explaining what the response code means.
  673.  
  674. This server parses the request and the headers, and then calls a
  675. function specific to the request type (<command>). Specifically,
  676. a request SPAM will be handled by a method do_SPAM(). If no
  677. such method exists the server sends an error response to the
  678. client. If it exists, it is called with no arguments:
  679.  
  680. do_SPAM()
  681.  
  682. Note that the request name is case sensitive (i.e. SPAM and spam
  683. are different requests).
  684.  
  685. The various request details are stored in instance variables:
  686.  
  687. - client_address is the client IP address in the form (host,
  688. port);
  689.  
  690. - command, path and version are the broken-down request line;
  691.  
  692. - headers is an instance of mimetools.Message (or a derived
  693. class) containing the header information;
  694.  
  695. - rfile is a file object open for reading positioned at the
  696. start of the optional input data part;
  697.  
  698. - wfile is a file object open for writing.
  699.  
  700. IT IS IMPORTANT TO ADHERE TO THE PROTOCOL FOR WRITING!
  701.  
  702. The first thing to be written must be the response line. Then
  703. follow 0 or more header lines, then a blank line, and then the
  704. actual data (if any). The meaning of the header lines depends on
  705. the command executed by the server; in most cases, when data is
  706. returned, there should be at least one header line of the form
  707.  
  708. Content-type: <type>/<subtype>
  709.  
  710. where <type> and <subtype> should be registered MIME types,
  711. e.g. "text/html" or "text/plain".
  712.  
  713. """
  714.  
  715. # The Python system version, truncated to its first component.
  716. sys_version = "Python/" + sys.version.split()[0]
  717.  
  718. # The server software version. You may want to override this.
  719. # The format is multiple whitespace-separated strings,
  720. # where each string is of the form name[/version].
  721. server_version = "BaseHTTP/" + __version__
  722.  
  723. # The default request version. This only affects responses up until
  724. # the point where the request line is parsed, so it mainly decides what
  725. # the client gets back when sending a malformed request line.
  726. # Most web servers default to HTTP 0.9, i.e. don't send a status line.
  727. default_request_version = "HTTP/0.9"
  728.  
  729. def parse_request(self):
  730. """Parse a request (internal).
  731.  
  732. The request should be stored in self.raw_requestline; the results
  733. are in self.command, self.path, self.request_version and
  734. self.headers.
  735.  
  736. Return True for success, False for failure; on failure, an
  737. error is sent back.
  738.  
  739. """
  740. self.command = None # set in case of error on the first line
  741. self.request_version = version = self.default_request_version
  742. self.close_connection = 1
  743. requestline = self.raw_requestline
  744. requestline = requestline.rstrip('\r\n')
  745. self.requestline = requestline
  746. words = requestline.split()
  747. if len(words) == 3:
  748. command, path, version = words
  749. if version[:5] != 'HTTP/':
  750. self.send_error(400, "Bad request version (%r)" % version)
  751. return False
  752. try:
  753. base_version_number = version.split('/', 1)[1]
  754. version_number = base_version_number.split(".")
  755. # RFC 2145 section 3.1 says there can be only one "." and
  756. # - major and minor numbers MUST be treated as
  757. # separate integers;
  758. # - HTTP/2.4 is a lower version than HTTP/2.13, which in
  759. # turn is lower than HTTP/12.3;
  760. # - Leading zeros MUST be ignored by recipients.
  761. if len(version_number) != 2:
  762. raise ValueError
  763. version_number = int(version_number[0]), int(version_number[1])
  764. except (ValueError, IndexError):
  765. self.send_error(400, "Bad request version (%r)" % version)
  766. return False
  767. if version_number >= (1, 1) and self.protocol_version >= "HTTP/1.1":
  768. self.close_connection = 0
  769. if version_number >= (2, 0):
  770. self.send_error(505,
  771. "Invalid HTTP Version (%s)" % base_version_number)
  772. return False
  773. elif len(words) == 2:
  774. command, path = words
  775. self.close_connection = 1
  776. if command != 'GET':
  777. self.send_error(400,
  778. "Bad HTTP/0.9 request type (%r)" % command)
  779. return False
  780. elif not words:
  781. return False
  782. else:
  783. self.send_error(400, "Bad request syntax (%r)" % requestline)
  784. return False
  785. self.command, self.path, self.request_version = command, path, version
  786.  
  787. # Examine the headers and look for a Connection directive
  788. self.headers = self.MessageClass(self.rfile, 0)
  789.  
  790. conntype = self.headers.get('Connection', "")
  791. if conntype.lower() == 'close':
  792. self.close_connection = 1
  793. elif (conntype.lower() == 'keep-alive' and
  794. self.protocol_version >= "HTTP/1.1"):
  795. self.close_connection = 0
  796. return True
  797.  
  798. def handle_one_request(self):
  799. """Handle a single HTTP request.
  800.  
  801. You normally don't need to override this method; see the class
  802. __doc__ string for information on how to handle specific HTTP
  803. commands such as GET and POST.
  804.  
  805. """
  806. try:
  807. self.raw_requestline = self.rfile.readline(65537)#读取一行,这行最多为65537B
  808. if len(self.raw_requestline) > 65536:#溢出处理
  809. self.requestline = ''
  810. self.request_version = ''
  811. self.command = ''
  812. self.send_error(414)
  813. return
  814. if not self.raw_requestline:#读取数据为空,关闭连接
  815. self.close_connection = 1
  816. return
  817. if not self.parse_request():#分析请求,出错则返回
  818. # An error code has been sent, just exit
  819. return
  820. mname = 'do_' + self.command#生成动作,例如do_post
  821. if not hasattr(self, mname):
  822. self.send_error(501, "Unsupported method (%r)" % self.command)
  823. return
  824. method = getattr(self, mname)
  825. method()
  826. self.wfile.flush() #actually send the response if not already done.
  827. except socket.timeout, e:
  828. #a read or a write timed out. Discard this connection
  829. self.log_error("Request timed out: %r", e)
  830. self.close_connection = 1
  831. return
  832.  
  833. def handle(self):
  834. """Handle multiple requests if necessary."""
  835. self.close_connection = 1
  836.  
  837. self.handle_one_request()
  838. while not self.close_connection:
  839. self.handle_one_request()
  840.  
  841. def send_error(self, code, message=None):
  842. """Send and log an error reply.
  843.  
  844. Arguments are the error code, and a detailed message.
  845. The detailed message defaults to the short entry matching the
  846. response code.
  847.  
  848. This sends an error response (so it must be called before any
  849. output has been generated), logs the error, and finally sends
  850. a piece of HTML explaining the error to the user.
  851.  
  852. """
  853.  
  854. try:
  855. short, long = self.responses[code]
  856. except KeyError:
  857. short, long = '???', '???'
  858. if message is None:
  859. message = short
  860. explain = long
  861. self.log_error("code %d, message %s", code, message)
  862. # using _quote_html to prevent Cross Site Scripting attacks (see bug #1100201)
  863. content = (self.error_message_format %
  864. {'code': code, 'message': _quote_html(message), 'explain': explain})
  865. self.send_response(code, message)
  866. self.send_header("Content-Type", self.error_content_type)
  867. self.send_header('Connection', 'close')
  868. self.end_headers()
  869. if self.command != 'HEAD' and code >= 200 and code not in (204, 304):
  870. self.wfile.write(content)
  871.  
  872. error_message_format = DEFAULT_ERROR_MESSAGE
  873. error_content_type = DEFAULT_ERROR_CONTENT_TYPE
  874.  
  875. def send_response(self, code, message=None):
  876. """Send the response header and log the response code.
  877.  
  878. Also send two standard headers with the server software
  879. version and the current date.
  880.  
  881. """
  882. self.log_request(code)
  883. if message is None:
  884. if code in self.responses:
  885. message = self.responses[code][0]
  886. else:
  887. message = ''
  888. if self.request_version != 'HTTP/0.9':
  889. self.wfile.write("%s %d %s\r\n" %
  890. (self.protocol_version, code, message))
  891. # print (self.protocol_version, code, message)
  892. self.send_header('Server', self.version_string())
  893. self.send_header('Date', self.date_time_string())
  894.  
  895. def send_header(self, keyword, value):
  896. """Send a MIME header."""
  897. if self.request_version != 'HTTP/0.9':
  898. self.wfile.write("%s: %s\r\n" % (keyword, value))
  899.  
  900. if keyword.lower() == 'connection':
  901. if value.lower() == 'close':
  902. self.close_connection = 1
  903. elif value.lower() == 'keep-alive':
  904. self.close_connection = 0
  905.  
  906. def end_headers(self):
  907. """Send the blank line ending the MIME headers."""
  908. if self.request_version != 'HTTP/0.9':
  909. self.wfile.write("\r\n")
  910.  
  911. def log_request(self, code='-', size='-'):
  912. """Log an accepted request.
  913.  
  914. This is called by send_response().
  915.  
  916. """
  917.  
  918. self.log_message('"%s" %s %s',
  919. self.requestline, str(code), str(size))
  920.  
  921. def log_error(self, format, *args):
  922. """Log an error.
  923.  
  924. This is called when a request cannot be fulfilled. By
  925. default it passes the message on to log_message().
  926.  
  927. Arguments are the same as for log_message().
  928.  
  929. XXX This should go to the separate error log.
  930.  
  931. """
  932.  
  933. self.log_message(format, *args)
  934.  
  935. def log_message(self, format, *args):
  936. """Log an arbitrary message.
  937.  
  938. This is used by all other logging functions. Override
  939. it if you have specific logging wishes.
  940.  
  941. The first argument, FORMAT, is a format string for the
  942. message to be logged. If the format string contains
  943. any % escapes requiring parameters, they should be
  944. specified as subsequent arguments (it's just like
  945. printf!).
  946.  
  947. The client ip address and current date/time are prefixed to every
  948. message.
  949.  
  950. """
  951.  
  952. sys.stderr.write("%s - - [%s] %s\n" %
  953. (self.client_address[0],
  954. self.log_date_time_string(),
  955. format%args))
  956.  
  957. def version_string(self):
  958. """Return the server software version string."""
  959. return self.server_version + ' ' + self.sys_version
  960.  
  961. def date_time_string(self, timestamp=None):
  962. """Return the current date and time formatted for a message header."""
  963. if timestamp is None:
  964. timestamp = time.time()
  965. year, month, day, hh, mm, ss, wd, y, z = time.gmtime(timestamp)
  966. s = "%s, %02d %3s %4d %02d:%02d:%02d GMT" % (
  967. self.weekdayname[wd],
  968. day, self.monthname[month], year,
  969. hh, mm, ss)
  970. return s
  971.  
  972. def log_date_time_string(self):
  973. """Return the current time formatted for logging."""
  974. now = time.time()
  975. year, month, day, hh, mm, ss, x, y, z = time.localtime(now)
  976. s = "%02d/%3s/%04d %02d:%02d:%02d" % (
  977. day, self.monthname[month], year, hh, mm, ss)
  978. return s
  979.  
  980. weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
  981.  
  982. monthname = [None,
  983. 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
  984. 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
  985.  
  986. def address_string(self):
  987. """Return the client address formatted for logging.
  988.  
  989. This version looks up the full hostname using gethostbyaddr(),
  990. and tries to find a name that contains at least one dot.
  991.  
  992. """
  993.  
  994. host, port = self.client_address[:2]
  995. return socket.getfqdn(host)
  996.  
  997. # Essentially static class variables
  998.  
  999. # The version of the HTTP protocol we support.
  1000. # Set this to HTTP/1.1 to enable automatic keepalive
  1001. protocol_version = "HTTP/1.0"
  1002.  
  1003. # The Message-like class used to parse headers
  1004. MessageClass = mimetools.Message
  1005.  
  1006. # Table mapping response codes to messages; entries have the
  1007. # form {code: (shortmessage, longmessage)}.
  1008. # See RFC 2616.
  1009. responses = {
  1010. 100: ('Continue', 'Request received, please continue'),
  1011. 101: ('Switching Protocols',
  1012. 'Switching to new protocol; obey Upgrade header'),
  1013.  
  1014. 200: ('OK', 'Request fulfilled, document follows'),
  1015. 201: ('Created', 'Document created, URL follows'),
  1016. 202: ('Accepted',
  1017. 'Request accepted, processing continues off-line'),
  1018. 203: ('Non-Authoritative Information', 'Request fulfilled from cache'),
  1019. 204: ('No Content', 'Request fulfilled, nothing follows'),
  1020. 205: ('Reset Content', 'Clear input form for further input.'),
  1021. 206: ('Partial Content', 'Partial content follows.'),
  1022.  
  1023. 300: ('Multiple Choices',
  1024. 'Object has several resources -- see URI list'),
  1025. 301: ('Moved Permanently', 'Object moved permanently -- see URI list'),
  1026. 302: ('Found', 'Object moved temporarily -- see URI list'),
  1027. 303: ('See Other', 'Object moved -- see Method and URL list'),
  1028. 304: ('Not Modified',
  1029. 'Document has not changed since given time'),
  1030. 305: ('Use Proxy',
  1031. 'You must use proxy specified in Location to access this '
  1032. 'resource.'),
  1033. 307: ('Temporary Redirect',
  1034. 'Object moved temporarily -- see URI list'),
  1035.  
  1036. 400: ('Bad Request',
  1037. 'Bad request syntax or unsupported method'),
  1038. 401: ('Unauthorized',
  1039. 'No permission -- see authorization schemes'),
  1040. 402: ('Payment Required',
  1041. 'No payment -- see charging schemes'),
  1042. 403: ('Forbidden',
  1043. 'Request forbidden -- authorization will not help'),
  1044. 404: ('Not Found', 'Nothing matches the given URI'),
  1045. 405: ('Method Not Allowed',
  1046. 'Specified method is invalid for this resource.'),
  1047. 406: ('Not Acceptable', 'URI not available in preferred format.'),
  1048. 407: ('Proxy Authentication Required', 'You must authenticate with '
  1049. 'this proxy before proceeding.'),
  1050. 408: ('Request Timeout', 'Request timed out; try again later.'),
  1051. 409: ('Conflict', 'Request conflict.'),
  1052. 410: ('Gone',
  1053. 'URI no longer exists and has been permanently removed.'),
  1054. 411: ('Length Required', 'Client must specify Content-Length.'),
  1055. 412: ('Precondition Failed', 'Precondition in headers is false.'),
  1056. 413: ('Request Entity Too Large', 'Entity is too large.'),
  1057. 414: ('Request-URI Too Long', 'URI is too long.'),
  1058. 415: ('Unsupported Media Type', 'Entity body in unsupported format.'),
  1059. 416: ('Requested Range Not Satisfiable',
  1060. 'Cannot satisfy request range.'),
  1061. 417: ('Expectation Failed',
  1062. 'Expect condition could not be satisfied.'),
  1063.  
  1064. 500: ('Internal Server Error', 'Server got itself in trouble'),
  1065. 501: ('Not Implemented',
  1066. 'Server does not support this operation'),
  1067. 502: ('Bad Gateway', 'Invalid responses from another server/proxy.'),
  1068. 503: ('Service Unavailable',
  1069. 'The server cannot process the request due to a high load'),
  1070. 504: ('Gateway Timeout',
  1071. 'The gateway server did not receive a timely response'),
  1072. 505: ('HTTP Version Not Supported', 'Cannot fulfill request.'),
  1073. }
  1074. class BaseHandler:
  1075. """Manage the invocation of a WSGI application"""
  1076.  
  1077. # Configuration parameters; can override per-subclass or per-instance
  1078. wsgi_version = (1,0)
  1079. wsgi_multithread = True
  1080. wsgi_multiprocess = True
  1081. wsgi_run_once = False
  1082.  
  1083. origin_server = True # We are transmitting direct to client
  1084. http_version = "1.0" # Version that should be used for response
  1085. server_software = None # String name of server software, if any
  1086.  
  1087. # os_environ is used to supply configuration from the OS environment:
  1088. # by default it's a copy of 'os.environ' as of import time, but you can
  1089. # override this in e.g. your __init__ method.
  1090. os_environ = dict(os.environ.items())
  1091.  
  1092. # Collaborator classes
  1093. wsgi_file_wrapper = FileWrapper # set to None to disable
  1094. headers_class = Headers # must be a Headers-like class
  1095.  
  1096. # Error handling (also per-subclass or per-instance)
  1097. traceback_limit = None # Print entire traceback to self.get_stderr()
  1098. error_status = "500 Internal Server Error"
  1099. error_headers = [('Content-Type','text/plain')]
  1100. error_body = "A server error occurred. Please contact the administrator."
  1101.  
  1102. # State variables (don't mess with these)
  1103. status = result = None
  1104. headers_sent = False
  1105. headers = None
  1106. bytes_sent = 0
  1107.  
  1108. def run(self, application):
  1109. """Invoke the application"""
  1110. # Note to self: don't move the close()! Asynchronous servers shouldn't
  1111. # call close() from finish_response(), so if you close() anywhere but
  1112. # the double-error branch here, you'll break asynchronous servers by
  1113. # prematurely closing. Async servers must return from 'run()' without
  1114. # closing if there might still be output to iterate over.
  1115. try:
  1116. self.setup_environ()
  1117. self.result = application(self.environ, self.start_response)
  1118. self.finish_response()
  1119. except:
  1120. try:
  1121. self.handle_error()
  1122. except:
  1123. # If we get an error handling an error, just give up already!
  1124. self.close()
  1125. raise # ...and let the actual server figure it out.
  1126.  
  1127. def setup_environ(self):
  1128. """Set up the environment for one request"""
  1129.  
  1130. env = self.environ = self.os_environ.copy()
  1131. self.add_cgi_vars()
  1132.  
  1133. env['wsgi.input'] = self.get_stdin()
  1134. env['wsgi.errors'] = self.get_stderr()
  1135. env['wsgi.version'] = self.wsgi_version
  1136. env['wsgi.run_once'] = self.wsgi_run_once
  1137. env['wsgi.url_scheme'] = self.get_scheme()
  1138. env['wsgi.multithread'] = self.wsgi_multithread
  1139. env['wsgi.multiprocess'] = self.wsgi_multiprocess
  1140.  
  1141. if self.wsgi_file_wrapper is not None:
  1142. env['wsgi.file_wrapper'] = self.wsgi_file_wrapper
  1143.  
  1144. if self.origin_server and self.server_software:
  1145. env.setdefault('SERVER_SOFTWARE',self.server_software)
  1146.  
  1147. def finish_response(self):
  1148. """Send any iterable data, then close self and the iterable
  1149.  
  1150. Subclasses intended for use in asynchronous servers will
  1151. want to redefine this method, such that it sets up callbacks
  1152. in the event loop to iterate over the data, and to call
  1153. 'self.close()' once the response is finished.
  1154. """
  1155. try:
  1156. if not self.result_is_file() or not self.sendfile():
  1157. for data in self.result:
  1158. self.write(data)
  1159. self.finish_content()
  1160. finally:
  1161. self.close()
  1162.  
  1163. def get_scheme(self):
  1164. """Return the URL scheme being used"""
  1165. return guess_scheme(self.environ)
  1166.  
  1167. def set_content_length(self):
  1168. """Compute Content-Length or switch to chunked encoding if possible"""
  1169. try:
  1170. blocks = len(self.result)
  1171. except (TypeError,AttributeError,NotImplementedError):
  1172. pass
  1173. else:
  1174. if blocks==1:
  1175. self.headers['Content-Length'] = str(self.bytes_sent)
  1176. return
  1177. # XXX Try for chunked encoding if origin server and client is 1.1
  1178.  
  1179. def cleanup_headers(self):
  1180. """Make any necessary header changes or defaults
  1181.  
  1182. Subclasses can extend this to add other defaults.
  1183. """
  1184. if 'Content-Length' not in self.headers:
  1185. self.set_content_length()
  1186.  
  1187. def start_response(self, status, headers,exc_info=None):
  1188. """'start_response()' callable as specified by PEP 333"""
  1189.  
  1190. if exc_info:
  1191. try:
  1192. if self.headers_sent:
  1193. # Re-raise original exception if headers sent
  1194. raise exc_info[0], exc_info[1], exc_info[2]
  1195. finally:
  1196. exc_info = None # avoid dangling circular ref
  1197. elif self.headers is not None:
  1198. raise AssertionError("Headers already set!")
  1199.  
  1200. assert type(status) is StringType,"Status must be a string"
  1201. assert len(status)>=4,"Status must be at least 4 characters"
  1202. assert int(status[:3]),"Status message must begin w/3-digit code"
  1203. assert status[3]==" ", "Status message must have a space after code"
  1204. if __debug__:
  1205. for name,val in headers:
  1206. assert type(name) is StringType,"Header names must be strings"
  1207. assert type(val) is StringType,"Header values must be strings"
  1208. assert not is_hop_by_hop(name),"Hop-by-hop headers not allowed"
  1209. self.status = status
  1210. self.headers = self.headers_class(headers)
  1211. return self.write
  1212.  
  1213. def send_preamble(self):
  1214. """Transmit version/status/date/server, via self._write()"""
  1215. if self.origin_server:
  1216. if self.client_is_modern():
  1217. self._write('HTTP/%s %s\r\n' % (self.http_version,self.status))
  1218. if 'Date' not in self.headers:
  1219. self._write(
  1220. 'Date: %s\r\n' % format_date_time(time.time())
  1221. )
  1222. if self.server_software and 'Server' not in self.headers:
  1223. self._write('Server: %s\r\n' % self.server_software)
  1224. else:
  1225. self._write('Status: %s\r\n' % self.status)
  1226.  
  1227. def write(self, data):
  1228. """'write()' callable as specified by PEP 333"""
  1229.  
  1230. assert type(data) is StringType,"write() argument must be string"
  1231.  
  1232. if not self.status:
  1233. raise AssertionError("write() before start_response()")
  1234.  
  1235. elif not self.headers_sent:
  1236. # Before the first output, send the stored headers
  1237. self.bytes_sent = len(data) # make sure we know content-length
  1238. self.send_headers()
  1239. else:
  1240. self.bytes_sent += len(data)
  1241.  
  1242. # XXX check Content-Length and truncate if too many bytes written?
  1243. self._write(data)
  1244. self._flush()
  1245.  
  1246. def sendfile(self):
  1247. """Platform-specific file transmission
  1248.  
  1249. Override this method in subclasses to support platform-specific
  1250. file transmission. It is only called if the application's
  1251. return iterable ('self.result') is an instance of
  1252. 'self.wsgi_file_wrapper'.
  1253.  
  1254. This method should return a true value if it was able to actually
  1255. transmit the wrapped file-like object using a platform-specific
  1256. approach. It should return a false value if normal iteration
  1257. should be used instead. An exception can be raised to indicate
  1258. that transmission was attempted, but failed.
  1259.  
  1260. NOTE: this method should call 'self.send_headers()' if
  1261. 'self.headers_sent' is false and it is going to attempt direct
  1262. transmission of the file.
  1263. """
  1264. return False # No platform-specific transmission by default
  1265.  
  1266. def finish_content(self):
  1267. """Ensure headers and content have both been sent"""
  1268. if not self.headers_sent:
  1269. # Only zero Content-Length if not set by the application (so
  1270. # that HEAD requests can be satisfied properly, see #3839)
  1271. self.headers.setdefault('Content-Length', "")
  1272. self.send_headers()
  1273. else:
  1274. pass # XXX check if content-length was too short?
  1275.  
  1276. def close(self):
  1277. """Close the iterable (if needed) and reset all instance vars
  1278.  
  1279. Subclasses may want to also drop the client connection.
  1280. """
  1281. try:
  1282. if hasattr(self.result,'close'):
  1283. self.result.close()
  1284. finally:
  1285. self.result = self.headers = self.status = self.environ = None
  1286. self.bytes_sent = 0; self.headers_sent = False
  1287.  
  1288. def send_headers(self):
  1289. """Transmit headers to the client, via self._write()"""
  1290. self.cleanup_headers()
  1291. self.headers_sent = True
  1292. if not self.origin_server or self.client_is_modern():
  1293. self.send_preamble()
  1294. self._write(str(self.headers))
  1295.  
  1296. def result_is_file(self):
  1297. """True if 'self.result' is an instance of 'self.wsgi_file_wrapper'"""
  1298. wrapper = self.wsgi_file_wrapper
  1299. return wrapper is not None and isinstance(self.result,wrapper)
  1300.  
  1301. def client_is_modern(self):
  1302. """True if client can accept status and headers"""
  1303. return self.environ['SERVER_PROTOCOL'].upper() != 'HTTP/0.9'
  1304.  
  1305. def log_exception(self,exc_info):
  1306. """Log the 'exc_info' tuple in the server log
  1307.  
  1308. Subclasses may override to retarget the output or change its format.
  1309. """
  1310. try:
  1311. from traceback import print_exception
  1312. stderr = self.get_stderr()
  1313. print_exception(
  1314. exc_info[0], exc_info[1], exc_info[2],
  1315. self.traceback_limit, stderr
  1316. )
  1317. stderr.flush()
  1318. finally:
  1319. exc_info = None
  1320.  
  1321. def handle_error(self):
  1322. """Log current error, and send error output to client if possible"""
  1323. self.log_exception(sys.exc_info())
  1324. if not self.headers_sent:
  1325. self.result = self.error_output(self.environ, self.start_response)
  1326. self.finish_response()
  1327. # XXX else: attempt advanced recovery techniques for HTML or text?
  1328.  
  1329. def error_output(self, environ, start_response):
  1330. """WSGI mini-app to create error output
  1331.  
  1332. By default, this just uses the 'error_status', 'error_headers',
  1333. and 'error_body' attributes to generate an output page. It can
  1334. be overridden in a subclass to dynamically generate diagnostics,
  1335. choose an appropriate message for the user's preferred language, etc.
  1336.  
  1337. Note, however, that it's not recommended from a security perspective to
  1338. spit out diagnostics to any old user; ideally, you should have to do
  1339. something special to enable diagnostic output, which is why we don't
  1340. include any here!
  1341. """
  1342. start_response(self.error_status,self.error_headers[:],sys.exc_info())
  1343. return [self.error_body]
  1344.  
  1345. # Pure abstract methods; *must* be overridden in subclasses
  1346.  
  1347. def _write(self,data):
  1348. """Override in subclass to buffer data for send to client
  1349.  
  1350. It's okay if this method actually transmits the data; BaseHandler
  1351. just separates write and flush operations for greater efficiency
  1352. when the underlying system actually has such a distinction.
  1353. """
  1354. raise NotImplementedError
  1355.  
  1356. def _flush(self):
  1357. """Override in subclass to force sending of recent '_write()' calls
  1358.  
  1359. It's okay if this method is a no-op (i.e., if '_write()' actually
  1360. sends the data.
  1361. """
  1362. raise NotImplementedError
  1363.  
  1364. def get_stdin(self):
  1365. """Override in subclass to return suitable 'wsgi.input'"""
  1366. raise NotImplementedError
  1367.  
  1368. def get_stderr(self):
  1369. """Override in subclass to return suitable 'wsgi.errors'"""
  1370. raise NotImplementedError
  1371.  
  1372. def add_cgi_vars(self):
  1373. """Override in subclass to insert CGI variables in 'self.environ'"""
  1374. raise NotImplementedError
  1375.  
  1376. class SimpleHandler(BaseHandler):
  1377. """Handler that's just initialized with streams, environment, etc.
  1378.  
  1379. This handler subclass is intended for synchronous HTTP/1.0 origin servers,
  1380. and handles sending the entire response output, given the correct inputs.
  1381.  
  1382. Usage::
  1383.  
  1384. handler = SimpleHandler(
  1385. inp,out,err,env, multithread=False, multiprocess=True
  1386. )
  1387. handler.run(app)"""
  1388.  
  1389. def __init__(self,stdin,stdout,stderr,environ,
  1390. multithread=True, multiprocess=False
  1391. ):
  1392. self.stdin = stdin
  1393. self.stdout = stdout
  1394. self.stderr = stderr
  1395. self.base_env = environ
  1396. self.wsgi_multithread = multithread
  1397. self.wsgi_multiprocess = multiprocess
  1398.  
  1399. def get_stdin(self):
  1400. return self.stdin
  1401.  
  1402. def get_stderr(self):
  1403. return self.stderr
  1404.  
  1405. def add_cgi_vars(self):
  1406. self.environ.update(self.base_env)
  1407.  
  1408. def _write(self,data):
  1409. self.stdout.write(data)
  1410. self._write = self.stdout.write
  1411.  
  1412. def _flush(self):
  1413. self.stdout.flush()
  1414. self._flush = self.stdout.flush
  1415.  
  1416. class BaseCGIHandler(SimpleHandler):
  1417.  
  1418. """CGI-like systems using input/output/error streams and environ mapping
  1419.  
  1420. Usage::
  1421.  
  1422. handler = BaseCGIHandler(inp,out,err,env)
  1423. handler.run(app)
  1424.  
  1425. This handler class is useful for gateway protocols like ReadyExec and
  1426. FastCGI, that have usable input/output/error streams and an environment
  1427. mapping. It's also the base class for CGIHandler, which just uses
  1428. sys.stdin, os.environ, and so on.
  1429.  
  1430. The constructor also takes keyword arguments 'multithread' and
  1431. 'multiprocess' (defaulting to 'True' and 'False' respectively) to control
  1432. the configuration sent to the application. It sets 'origin_server' to
  1433. False (to enable CGI-like output), and assumes that 'wsgi.run_once' is
  1434. False.
  1435. """
  1436.  
  1437. origin_server = False
  1438.  
  1439. """BaseHTTPServer that implements the Python WSGI protocol (PEP 333, rev 1.21)
  1440.  
  1441. This is both an example of how WSGI can be implemented, and a basis for running
  1442. simple web applications on a local machine, such as might be done when testing
  1443. or debugging an application. It has not been reviewed for security issues,
  1444. however, and we strongly recommend that you use a "real" web server for
  1445. production use.
  1446.  
  1447. For example usage, see the 'if __name__=="__main__"' block at the end of the
  1448. module. See also the BaseHTTPServer module docs for other API information.
  1449. """
  1450.  
  1451. from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
  1452. import urllib, sys
  1453. from wsgiref.handlers import SimpleHandler
  1454.  
  1455. __version__ = "0.1"
  1456. __all__ = ['WSGIServer', 'WSGIRequestHandler', 'demo_app', 'make_server']
  1457.  
  1458. server_version = "WSGIServer/" + __version__
  1459. sys_version = "Python/" + sys.version.split()[0]
  1460. software_version = server_version + ' ' + sys_version
  1461.  
  1462. class ServerHandler(SimpleHandler):
  1463.  
  1464. server_software = software_version
  1465.  
  1466. def close(self):
  1467. try:
  1468. self.request_handler.log_request(
  1469. self.status.split(' ',1)[0], self.bytes_sent
  1470. )
  1471. finally:
  1472. SimpleHandler.close(self)
  1473.  
  1474. class WSGIServer(HTTPServer):
  1475.  
  1476. """BaseHTTPServer that implements the Python WSGI protocol"""
  1477.  
  1478. application = None
  1479.  
  1480. def server_bind(self):
  1481. """Override server_bind to store the server name."""
  1482. HTTPServer.server_bind(self)
  1483. self.setup_environ()
  1484.  
  1485. def setup_environ(self):
  1486. # Set up base environment
  1487. env = self.base_environ = {}
  1488. env['SERVER_NAME'] = self.server_name
  1489. env['GATEWAY_INTERFACE'] = 'CGI/1.1'
  1490. env['SERVER_PORT'] = str(self.server_port)
  1491. env['REMOTE_HOST']=''
  1492. env['CONTENT_LENGTH']=''
  1493. env['SCRIPT_NAME'] = ''
  1494.  
  1495. def get_app(self):
  1496. return self.application
  1497.  
  1498. def set_app(self,application):
  1499. self.application = application
  1500.  
  1501. class WSGIRequestHandler(BaseHTTPRequestHandler):
  1502.  
  1503. server_version = "WSGIServer/" + __version__
  1504.  
  1505. def get_environ(self):
  1506. env = self.server.base_environ.copy()
  1507. env['SERVER_PROTOCOL'] = self.request_version
  1508. env['REQUEST_METHOD'] = self.command
  1509. if '?' in self.path:
  1510. path,query = self.path.split('?',1)
  1511. else:
  1512. path,query = self.path,''
  1513.  
  1514. env['PATH_INFO'] = urllib.unquote(path)
  1515. env['QUERY_STRING'] = query
  1516.  
  1517. host = self.address_string()
  1518. if host != self.client_address[0]:
  1519. env['REMOTE_HOST'] = host
  1520. env['REMOTE_ADDR'] = self.client_address[0]
  1521.  
  1522. if self.headers.typeheader is None:
  1523. env['CONTENT_TYPE'] = self.headers.type
  1524. else:
  1525. env['CONTENT_TYPE'] = self.headers.typeheader
  1526.  
  1527. length = self.headers.getheader('content-length')
  1528. if length:
  1529. env['CONTENT_LENGTH'] = length
  1530.  
  1531. for h in self.headers.headers:
  1532. k,v = h.split(':',1)
  1533. k=k.replace('-','_').upper(); v=v.strip()
  1534. if k in env:
  1535. continue # skip content length, type,etc.
  1536. if 'HTTP_'+k in env:
  1537. env['HTTP_'+k] += ','+v # comma-separate multiple headers
  1538. else:
  1539. env['HTTP_'+k] = v
  1540. return env
  1541.  
  1542. def get_stderr(self):
  1543. return sys.stderr
  1544.  
  1545. def handle(self):#处理一个request,构造server时,要传入一个requesthandler
  1546. """Handle a single HTTP request"""
  1547.  
  1548. self.raw_requestline = self.rfile.readline(65537)
  1549. if len(self.raw_requestline) > 65536:
  1550. self.requestline = ''
  1551. self.request_version = ''
  1552. self.command = ''
  1553. self.send_error(414)
  1554. return
  1555.  
  1556. if not self.parse_request(): # An error code has been sent, just exit
  1557. return
  1558.  
  1559. handler = ServerHandler(
  1560. self.rfile, self.wfile, self.get_stderr(), self.get_environ()
  1561. )
  1562. handler.request_handler = self # backpointer for logging
  1563. handler.run(self.server.get_app())
  1564.  
  1565. def demo_app(environ,start_response):#相当于django框架,处理request时会调用它
  1566. from StringIO import StringIO
  1567. stdout = StringIO()
  1568. print >>stdout, "Hello world!"
  1569. print >>stdout
  1570. h = environ.items(); h.sort()
  1571. for k,v in h:
  1572. print >>stdout, k,'=', repr(v)
  1573. start_response("200 OK", [('Content-Type','text/plain')])
  1574. return [stdout.getvalue()]
  1575.  
  1576. def make_server(
  1577. host, port, app, server_class=WSGIServer, handler_class=WSGIRequestHandler
  1578. ):
  1579. """Create a new WSGI server listening on `host` and `port` for `app`"""
  1580. server = server_class((host, port), handler_class)
  1581. server.set_app(app)
  1582. return server
  1583.  
  1584. if __name__ == '__main__':
  1585. httpd = make_server('', 8000, demo_app)
  1586. sa = httpd.socket.getsockname()
  1587. print "Serving HTTP on", sa[0], "port", sa[1], "..."
  1588. import webbrowser
  1589. webbrowser.open('http://localhost:8000/xyz?abc')
  1590. httpd.handle_request() # serve one request, then exit
  1591. httpd.server_close()
  1592.  
  1593. server执行监听,acceptserver对象有个成员为requesthandler,服务器在serv_forever时,会通过select函数来判断有无客户连接,有就调用_handle_request _noblock ->get_request ->process_request ->finish_request ->RequestHandlerClass生成一个RequestHandler对象,该对象又会调用自己的handle()->handle_one_request->parse_request->找到相应的处理方法,然后调用方法,完成一个请求。在wsgirequesthandler中重载了handle函数,它构造了serverhandler对象,serverhandler调用run来完成请求,run又调用到app对象,由app干活,返回response

wsgiref分析的更多相关文章

  1. python 从SocketServer到 WSGIServer 源码分析、

    python 下有个wsgi的封装库.wsgiref. WSGI 指的是 Web服务器网关接口(Python Web Server Gateway Interface) django的runserve ...

  2. nova创建虚拟机源码分析系列之四 nova代码模拟

    在前面的三篇博文中,介绍了restful和SWGI的实现.结合restful和WSGI配置就能够简单的实现nova服务模型的最简单的操作. 如下的内容是借鉴网上博文,因为写的很巧妙,将nova管理虚拟 ...

  3. nova创建虚拟机源码分析系列之三 PasteDeploy

    上一篇博文介绍WSGI在nova创建虚拟机过程的作用是解析URL,是以一个最简单的例子去给读者有一个印象.在openstack中URL复杂程度也大大超过上一个例子.所以openstack使用了Past ...

  4. 一个Flask运行分析

    当我们安装好Flask环境之后,创建好项目,就会自动生成下面这段代码: from flask import Flask app = Flask(__name__) @app.route('/') de ...

  5. wsgiref源码解析

    wsgiref是PEP 333定义的wsgi规范的范例实现,里面的功能包括了: wsgi的环境变量 应答头部的处理 实现简单的HTTP服务器 简单的对程序端和服务器端校验函数 我们先看一个简单的代码实 ...

  6. django源码分析

    原文网址 https://www.jianshu.com/p/17d78b52c732?utm_campaign=maleskine&utm_content=note&utm_medi ...

  7. [深度分析] Python Web 开发框架 Bottle

    [深度分析] Python Web 开发框架 Bottle(这个真的他妈的经典!!!) 作者:lhf2009913 Bottle 是一个非常精致的WSGI框架,它提供了 Python Web开发中需要 ...

  8. openstack XXX-api分析

    一.概述 RESTful API: 表征状态迁移,也就是说client端使用http的基本操作(主要四种:get, post, put, delete 对应增删改查)使服务端的资源状态转化: WSGI ...

  9. linux性能评估与分析工具

    linux是一个开源系统,其内核负责管理系统的进程,内存,设备驱动程序,文件和网络系统, 决定着系统的性能和稳定性.由于内核源码很容易获取,任何人都可以将自己认为优秀的代码 加入到其中.linux默认 ...

随机推荐

  1. [蓝桥杯]ALGO-51.算法训练_Torry的困惑(基本型)

    题目描述: 问题描述 Torry从小喜爱数学.一天,老师告诉他,像2...……这样的数叫做质数.Torry突然想到一个问题,前10...……个质数的乘积是多少呢?他把这个问题告诉老师.老师愣住了,一时 ...

  2. 【windows】之查看端口占用

    打开cmd界面 netstat -aon|findstr "80" 查看80端口占用PIDtasklist|findstr "2448" 找到占用程序直接杀死( ...

  3. 【转】hive中UDF、UDAF和UDTF使用

    原博文出自于: http://blog.csdn.net/liuj2511981/article/details/8523084 感谢! Hive进行UDF开发十分简单,此处所说UDF为Tempora ...

  4. 阿里云服务器 ECS Linux操作系统加固

    1. 账号和口令 1.1 禁用或删除无用账号 减少系统无用账号,降低安全风险. 操作步骤 使用命令 userdel <用户名> 删除不必要的账号. 使用命令 passwd -l <用 ...

  5. 信息安全-加密:DES 加密

    ylbtech-信息安全-加密:DES 加密 DES全称为Data Encryption Standard,即数据加密标准,是一种使用密钥加密的块算法,1977年被美国联邦政府的国家标准局确定为联邦资 ...

  6. [转]Android 代码自动提示功能

    源地址http://blog.sina.com.cn/s/blog_7dbac12501019mbh.html 或者http://blog.csdn.net/longvslove/article/de ...

  7. redis集群服务启动

    1 启动redis服务器 redis-server.exe redis.windows.conf 需要配置config节点的bind ip 2 启动redis集群 开启redis.xx.conf 服务 ...

  8. 数据库的ds命令

    Mysqi      数据库: 理一下数据库的格式: mysqi 关系型数据库,(表的概念) node.js 非关系性数据库  (json) 结构:数据库存放多张表,每个表可以存放多个字段,每个字段可 ...

  9. MFC (如何通过点击botton打开一个文件夹/文件)

    1.建一个MFC的工程,类型为基于对话框.在工具箱里拖进去一个button按键,如下图. 2.双击button1按键就可以进入到点击button1后要执行操作的代码,编写如下代码实现网页/文件夹或者文 ...

  10. [UE4]Set Skeletal Mesh,在蓝图中设置骨骼模型