root/galaxy-central/eggs/PasteScript-1.7.3-py2.6.egg/paste/script/wsgiserver/__init__.py

リビジョン 3, 69.2 KB (コミッタ: kohda, 14 年 前)

Install Unix tools  http://hannonlab.cshl.edu/galaxy_unix_tools/galaxy.html

行番号 
1"""A high-speed, production ready, thread pooled, generic WSGI server.
2
3Simplest example on how to use this module directly
4(without using CherryPy's application machinery):
5
6    from cherrypy import wsgiserver
7   
8    def my_crazy_app(environ, start_response):
9        status = '200 OK'
10        response_headers = [('Content-type','text/plain')]
11        start_response(status, response_headers)
12        return ['Hello world!\n']
13   
14    server = wsgiserver.CherryPyWSGIServer(
15                ('0.0.0.0', 8070), my_crazy_app,
16                server_name='www.cherrypy.example')
17   
18The CherryPy WSGI server can serve as many WSGI applications
19as you want in one instance by using a WSGIPathInfoDispatcher:
20   
21    d = WSGIPathInfoDispatcher({'/': my_crazy_app, '/blog': my_blog_app})
22    server = wsgiserver.CherryPyWSGIServer(('0.0.0.0', 80), d)
23   
24Want SSL support? Just set these attributes:
25   
26    server.ssl_certificate = <filename>
27    server.ssl_private_key = <filename>
28   
29    if __name__ == '__main__':
30        try:
31            server.start()
32        except KeyboardInterrupt:
33            server.stop()
34
35This won't call the CherryPy engine (application side) at all, only the
36WSGI server, which is independant from the rest of CherryPy. Don't
37let the name "CherryPyWSGIServer" throw you; the name merely reflects
38its origin, not its coupling.
39
40For those of you wanting to understand internals of this module, here's the
41basic call flow. The server's listening thread runs a very tight loop,
42sticking incoming connections onto a Queue:
43
44    server = CherryPyWSGIServer(...)
45    server.start()
46    while True:
47        tick()
48        # This blocks until a request comes in:
49        child = socket.accept()
50        conn = HTTPConnection(child, ...)
51        server.requests.put(conn)
52
53Worker threads are kept in a pool and poll the Queue, popping off and then
54handling each connection in turn. Each connection can consist of an arbitrary
55number of requests and their responses, so we run a nested loop:
56
57    while True:
58        conn = server.requests.get()
59        conn.communicate()
60        ->  while True:
61                req = HTTPRequest(...)
62                req.parse_request()
63                ->  # Read the Request-Line, e.g. "GET /page HTTP/1.1"
64                    req.rfile.readline()
65                    req.read_headers()
66                req.respond()
67                ->  response = wsgi_app(...)
68                    try:
69                        for chunk in response:
70                            if chunk:
71                                req.write(chunk)
72                    finally:
73                        if hasattr(response, "close"):
74                            response.close()
75                if req.close_connection:
76                    return
77"""
78
79
80import base64
81import os
82import Queue
83import re
84quoted_slash = re.compile("(?i)%2F")
85import rfc822
86import socket
87try:
88    import cStringIO as StringIO
89except ImportError:
90    import StringIO
91
92_fileobject_uses_str_type = isinstance(socket._fileobject(None)._rbuf, basestring)
93
94import sys
95import threading
96import time
97import traceback
98from urllib import unquote
99from urlparse import urlparse
100import warnings
101
102try:
103    from OpenSSL import SSL
104    from OpenSSL import crypto
105except ImportError:
106    SSL = None
107
108import errno
109
110def plat_specific_errors(*errnames):
111    """Return error numbers for all errors in errnames on this platform.
112   
113    The 'errno' module contains different global constants depending on
114    the specific platform (OS). This function will return the list of
115    numeric values for a given list of potential names.
116    """
117    errno_names = dir(errno)
118    nums = [getattr(errno, k) for k in errnames if k in errno_names]
119    # de-dupe the list
120    return dict.fromkeys(nums).keys()
121
122socket_error_eintr = plat_specific_errors("EINTR", "WSAEINTR")
123
124socket_errors_to_ignore = plat_specific_errors(
125    "EPIPE",
126    "EBADF", "WSAEBADF",
127    "ENOTSOCK", "WSAENOTSOCK",
128    "ETIMEDOUT", "WSAETIMEDOUT",
129    "ECONNREFUSED", "WSAECONNREFUSED",
130    "ECONNRESET", "WSAECONNRESET",
131    "ECONNABORTED", "WSAECONNABORTED",
132    "ENETRESET", "WSAENETRESET",
133    "EHOSTDOWN", "EHOSTUNREACH",
134    )
135socket_errors_to_ignore.append("timed out")
136
137socket_errors_nonblocking = plat_specific_errors(
138    'EAGAIN', 'EWOULDBLOCK', 'WSAEWOULDBLOCK')
139
140comma_separated_headers = ['ACCEPT', 'ACCEPT-CHARSET', 'ACCEPT-ENCODING',
141    'ACCEPT-LANGUAGE', 'ACCEPT-RANGES', 'ALLOW', 'CACHE-CONTROL',
142    'CONNECTION', 'CONTENT-ENCODING', 'CONTENT-LANGUAGE', 'EXPECT',
143    'IF-MATCH', 'IF-NONE-MATCH', 'PRAGMA', 'PROXY-AUTHENTICATE', 'TE',
144    'TRAILER', 'TRANSFER-ENCODING', 'UPGRADE', 'VARY', 'VIA', 'WARNING',
145    'WWW-AUTHENTICATE']
146
147
148class WSGIPathInfoDispatcher(object):
149    """A WSGI dispatcher for dispatch based on the PATH_INFO.
150   
151    apps: a dict or list of (path_prefix, app) pairs.
152    """
153   
154    def __init__(self, apps):
155        try:
156            apps = apps.items()
157        except AttributeError:
158            pass
159       
160        # Sort the apps by len(path), descending
161        apps.sort()
162        apps.reverse()
163       
164        # The path_prefix strings must start, but not end, with a slash.
165        # Use "" instead of "/".
166        self.apps = [(p.rstrip("/"), a) for p, a in apps]
167   
168    def __call__(self, environ, start_response):
169        path = environ["PATH_INFO"] or "/"
170        for p, app in self.apps:
171            # The apps list should be sorted by length, descending.
172            if path.startswith(p + "/") or path == p:
173                environ = environ.copy()
174                environ["SCRIPT_NAME"] = environ["SCRIPT_NAME"] + p
175                environ["PATH_INFO"] = path[len(p):]
176                return app(environ, start_response)
177       
178        start_response('404 Not Found', [('Content-Type', 'text/plain'),
179                                         ('Content-Length', '0')])
180        return ['']
181
182
183class MaxSizeExceeded(Exception):
184    pass
185
186class SizeCheckWrapper(object):
187    """Wraps a file-like object, raising MaxSizeExceeded if too large."""
188   
189    def __init__(self, rfile, maxlen):
190        self.rfile = rfile
191        self.maxlen = maxlen
192        self.bytes_read = 0
193   
194    def _check_length(self):
195        if self.maxlen and self.bytes_read > self.maxlen:
196            raise MaxSizeExceeded()
197   
198    def read(self, size=None):
199        data = self.rfile.read(size)
200        self.bytes_read += len(data)
201        self._check_length()
202        return data
203   
204    def readline(self, size=None):
205        if size is not None:
206            data = self.rfile.readline(size)
207            self.bytes_read += len(data)
208            self._check_length()
209            return data
210       
211        # User didn't specify a size ...
212        # We read the line in chunks to make sure it's not a 100MB line !
213        res = []
214        while True:
215            data = self.rfile.readline(256)
216            self.bytes_read += len(data)
217            self._check_length()
218            res.append(data)
219            # See http://www.cherrypy.org/ticket/421
220            if len(data) < 256 or data[-1:] == "\n":
221                return ''.join(res)
222   
223    def readlines(self, sizehint=0):
224        # Shamelessly stolen from StringIO
225        total = 0
226        lines = []
227        line = self.readline()
228        while line:
229            lines.append(line)
230            total += len(line)
231            if 0 < sizehint <= total:
232                break
233            line = self.readline()
234        return lines
235   
236    def close(self):
237        self.rfile.close()
238   
239    def __iter__(self):
240        return self
241   
242    def next(self):
243        data = self.rfile.next()
244        self.bytes_read += len(data)
245        self._check_length()
246        return data
247
248
249class HTTPRequest(object):
250    """An HTTP Request (and response).
251   
252    A single HTTP connection may consist of multiple request/response pairs.
253   
254    send: the 'send' method from the connection's socket object.
255    wsgi_app: the WSGI application to call.
256    environ: a partial WSGI environ (server and connection entries).
257        The caller MUST set the following entries:
258        * All wsgi.* entries, including .input
259        * SERVER_NAME and SERVER_PORT
260        * Any SSL_* entries
261        * Any custom entries like REMOTE_ADDR and REMOTE_PORT
262        * SERVER_SOFTWARE: the value to write in the "Server" response header.
263        * ACTUAL_SERVER_PROTOCOL: the value to write in the Status-Line of
264            the response. From RFC 2145: "An HTTP server SHOULD send a
265            response version equal to the highest version for which the
266            server is at least conditionally compliant, and whose major
267            version is less than or equal to the one received in the
268            request.  An HTTP server MUST NOT send a version for which
269            it is not at least conditionally compliant."
270   
271    outheaders: a list of header tuples to write in the response.
272    ready: when True, the request has been parsed and is ready to begin
273        generating the response. When False, signals the calling Connection
274        that the response should not be generated and the connection should
275        close.
276    close_connection: signals the calling Connection that the request
277        should close. This does not imply an error! The client and/or
278        server may each request that the connection be closed.
279    chunked_write: if True, output will be encoded with the "chunked"
280        transfer-coding. This value is set automatically inside
281        send_headers.
282    """
283   
284    max_request_header_size = 0
285    max_request_body_size = 0
286   
287    def __init__(self, wfile, environ, wsgi_app):
288        self.rfile = environ['wsgi.input']
289        self.wfile = wfile
290        self.environ = environ.copy()
291        self.wsgi_app = wsgi_app
292       
293        self.ready = False
294        self.started_response = False
295        self.status = ""
296        self.outheaders = []
297        self.sent_headers = False
298        self.close_connection = False
299        self.chunked_write = False
300   
301    def parse_request(self):
302        """Parse the next HTTP request start-line and message-headers."""
303        self.rfile.maxlen = self.max_request_header_size
304        self.rfile.bytes_read = 0
305       
306        try:
307            self._parse_request()
308        except MaxSizeExceeded:
309            self.simple_response("413 Request Entity Too Large")
310            return
311   
312    def _parse_request(self):
313        # HTTP/1.1 connections are persistent by default. If a client
314        # requests a page, then idles (leaves the connection open),
315        # then rfile.readline() will raise socket.error("timed out").
316        # Note that it does this based on the value given to settimeout(),
317        # and doesn't need the client to request or acknowledge the close
318        # (although your TCP stack might suffer for it: cf Apache's history
319        # with FIN_WAIT_2).
320        request_line = self.rfile.readline()
321        if not request_line:
322            # Force self.ready = False so the connection will close.
323            self.ready = False
324            return
325       
326        if request_line == "\r\n":
327            # RFC 2616 sec 4.1: "...if the server is reading the protocol
328            # stream at the beginning of a message and receives a CRLF
329            # first, it should ignore the CRLF."
330            # But only ignore one leading line! else we enable a DoS.
331            request_line = self.rfile.readline()
332            if not request_line:
333                self.ready = False
334                return
335       
336        environ = self.environ
337       
338        try:
339            method, path, req_protocol = request_line.strip().split(" ", 2)
340        except ValueError:
341            self.simple_response(400, "Malformed Request-Line")
342            return
343       
344        environ["REQUEST_METHOD"] = method
345       
346        # path may be an abs_path (including "http://host.domain.tld");
347        scheme, location, path, params, qs, frag = urlparse(path)
348       
349        if frag:
350            self.simple_response("400 Bad Request",
351                                 "Illegal #fragment in Request-URI.")
352            return
353       
354        if scheme:
355            environ["wsgi.url_scheme"] = scheme
356        if params:
357            path = path + ";" + params
358       
359        environ["SCRIPT_NAME"] = ""
360       
361        # Unquote the path+params (e.g. "/this%20path" -> "this path").
362        # http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.2
363        #
364        # But note that "...a URI must be separated into its components
365        # before the escaped characters within those components can be
366        # safely decoded." http://www.ietf.org/rfc/rfc2396.txt, sec 2.4.2
367        atoms = [unquote(x) for x in quoted_slash.split(path)]
368        path = "%2F".join(atoms)
369        environ["PATH_INFO"] = path
370       
371        # Note that, like wsgiref and most other WSGI servers,
372        # we unquote the path but not the query string.
373        environ["QUERY_STRING"] = qs
374       
375        # Compare request and server HTTP protocol versions, in case our
376        # server does not support the requested protocol. Limit our output
377        # to min(req, server). We want the following output:
378        #     request    server     actual written   supported response
379        #     protocol   protocol  response protocol    feature set
380        # a     1.0        1.0           1.0                1.0
381        # b     1.0        1.1           1.1                1.0
382        # c     1.1        1.0           1.0                1.0
383        # d     1.1        1.1           1.1                1.1
384        # Notice that, in (b), the response will be "HTTP/1.1" even though
385        # the client only understands 1.0. RFC 2616 10.5.6 says we should
386        # only return 505 if the _major_ version is different.
387        rp = int(req_protocol[5]), int(req_protocol[7])
388        server_protocol = environ["ACTUAL_SERVER_PROTOCOL"]
389        sp = int(server_protocol[5]), int(server_protocol[7])
390        if sp[0] != rp[0]:
391            self.simple_response("505 HTTP Version Not Supported")
392            return
393        # Bah. "SERVER_PROTOCOL" is actually the REQUEST protocol.
394        environ["SERVER_PROTOCOL"] = req_protocol
395        self.response_protocol = "HTTP/%s.%s" % min(rp, sp)
396       
397        # If the Request-URI was an absoluteURI, use its location atom.
398        if location:
399            environ["SERVER_NAME"] = location
400       
401        # then all the http headers
402        try:
403            self.read_headers()
404        except ValueError, ex:
405            self.simple_response("400 Bad Request", repr(ex.args))
406            return
407       
408        mrbs = self.max_request_body_size
409        if mrbs and int(environ.get("CONTENT_LENGTH", 0)) > mrbs:
410            self.simple_response("413 Request Entity Too Large")
411            return
412       
413        # Persistent connection support
414        if self.response_protocol == "HTTP/1.1":
415            # Both server and client are HTTP/1.1
416            if environ.get("HTTP_CONNECTION", "") == "close":
417                self.close_connection = True
418        else:
419            # Either the server or client (or both) are HTTP/1.0
420            if environ.get("HTTP_CONNECTION", "") != "Keep-Alive":
421                self.close_connection = True
422       
423        # Transfer-Encoding support
424        te = None
425        if self.response_protocol == "HTTP/1.1":
426            te = environ.get("HTTP_TRANSFER_ENCODING")
427            if te:
428                te = [x.strip().lower() for x in te.split(",") if x.strip()]
429       
430        self.chunked_read = False
431       
432        if te:
433            for enc in te:
434                if enc == "chunked":
435                    self.chunked_read = True
436                else:
437                    # Note that, even if we see "chunked", we must reject
438                    # if there is an extension we don't recognize.
439                    self.simple_response("501 Unimplemented")
440                    self.close_connection = True
441                    return
442       
443        # From PEP 333:
444        # "Servers and gateways that implement HTTP 1.1 must provide
445        # transparent support for HTTP 1.1's "expect/continue" mechanism.
446        # This may be done in any of several ways:
447        #   1. Respond to requests containing an Expect: 100-continue request
448        #      with an immediate "100 Continue" response, and proceed normally.
449        #   2. Proceed with the request normally, but provide the application
450        #      with a wsgi.input stream that will send the "100 Continue"
451        #      response if/when the application first attempts to read from
452        #      the input stream. The read request must then remain blocked
453        #      until the client responds.
454        #   3. Wait until the client decides that the server does not support
455        #      expect/continue, and sends the request body on its own.
456        #      (This is suboptimal, and is not recommended.)
457        #
458        # We used to do 3, but are now doing 1. Maybe we'll do 2 someday,
459        # but it seems like it would be a big slowdown for such a rare case.
460        if environ.get("HTTP_EXPECT", "") == "100-continue":
461            self.simple_response(100)
462       
463        self.ready = True
464   
465    def read_headers(self):
466        """Read header lines from the incoming stream."""
467        environ = self.environ
468       
469        while True:
470            line = self.rfile.readline()
471            if not line:
472                # No more data--illegal end of headers
473                raise ValueError("Illegal end of headers.")
474           
475            if line == '\r\n':
476                # Normal end of headers
477                break
478           
479            if line[0] in ' \t':
480                # It's a continuation line.
481                v = line.strip()
482            else:
483                k, v = line.split(":", 1)
484                k, v = k.strip().upper(), v.strip()
485                envname = "HTTP_" + k.replace("-", "_")
486           
487            if k in comma_separated_headers:
488                existing = environ.get(envname)
489                if existing:
490                    v = ", ".join((existing, v))
491            environ[envname] = v
492       
493        ct = environ.pop("HTTP_CONTENT_TYPE", None)
494        if ct is not None:
495            environ["CONTENT_TYPE"] = ct
496        cl = environ.pop("HTTP_CONTENT_LENGTH", None)
497        if cl is not None:
498            environ["CONTENT_LENGTH"] = cl
499   
500    def decode_chunked(self):
501        """Decode the 'chunked' transfer coding."""
502        cl = 0
503        data = StringIO.StringIO()
504        while True:
505            line = self.rfile.readline().strip().split(";", 1)
506            chunk_size = int(line.pop(0), 16)
507            if chunk_size <= 0:
508                break
509##            if line: chunk_extension = line[0]
510            cl += chunk_size
511            data.write(self.rfile.read(chunk_size))
512            crlf = self.rfile.read(2)
513            if crlf != "\r\n":
514                self.simple_response("400 Bad Request",
515                                     "Bad chunked transfer coding "
516                                     "(expected '\\r\\n', got %r)" % crlf)
517                return
518       
519        # Grab any trailer headers
520        self.read_headers()
521       
522        data.seek(0)
523        self.environ["wsgi.input"] = data
524        self.environ["CONTENT_LENGTH"] = str(cl) or ""
525        return True
526   
527    def respond(self):
528        """Call the appropriate WSGI app and write its iterable output."""
529        # Set rfile.maxlen to ensure we don't read past Content-Length.
530        # This will also be used to read the entire request body if errors
531        # are raised before the app can read the body.
532        if self.chunked_read:
533            # If chunked, Content-Length will be 0.
534            self.rfile.maxlen = self.max_request_body_size
535        else:
536            cl = int(self.environ.get("CONTENT_LENGTH", 0))
537            if self.max_request_body_size:
538                self.rfile.maxlen = min(cl, self.max_request_body_size)
539            else:
540                self.rfile.maxlen = cl
541        self.rfile.bytes_read = 0
542       
543        try:
544            self._respond()
545        except MaxSizeExceeded:
546            if not self.sent_headers:
547                self.simple_response("413 Request Entity Too Large")
548            return
549   
550    def _respond(self):
551        if self.chunked_read:
552            if not self.decode_chunked():
553                self.close_connection = True
554                return
555       
556        response = self.wsgi_app(self.environ, self.start_response)
557        try:
558            for chunk in response:
559                # "The start_response callable must not actually transmit
560                # the response headers. Instead, it must store them for the
561                # server or gateway to transmit only after the first
562                # iteration of the application return value that yields
563                # a NON-EMPTY string, or upon the application's first
564                # invocation of the write() callable." (PEP 333)
565                if chunk:
566                    self.write(chunk)
567        finally:
568            if hasattr(response, "close"):
569                response.close()
570       
571        if (self.ready and not self.sent_headers):
572            self.sent_headers = True
573            self.send_headers()
574        if self.chunked_write:
575            self.wfile.sendall("0\r\n\r\n")
576   
577    def simple_response(self, status, msg=""):
578        """Write a simple response back to the client."""
579        status = str(status)
580        buf = ["%s %s\r\n" % (self.environ['ACTUAL_SERVER_PROTOCOL'], status),
581               "Content-Length: %s\r\n" % len(msg),
582               "Content-Type: text/plain\r\n"]
583       
584        if status[:3] == "413" and self.response_protocol == 'HTTP/1.1':
585            # Request Entity Too Large
586            self.close_connection = True
587            buf.append("Connection: close\r\n")
588       
589        buf.append("\r\n")
590        if msg:
591            buf.append(msg)
592       
593        try:
594            self.wfile.sendall("".join(buf))
595        except socket.error, x:
596            if x.args[0] not in socket_errors_to_ignore:
597                raise
598   
599    def start_response(self, status, headers, exc_info = None):
600        """WSGI callable to begin the HTTP response."""
601        # "The application may call start_response more than once,
602        # if and only if the exc_info argument is provided."
603        if self.started_response and not exc_info:
604            raise AssertionError("WSGI start_response called a second "
605                                 "time with no exc_info.")
606       
607        # "if exc_info is provided, and the HTTP headers have already been
608        # sent, start_response must raise an error, and should raise the
609        # exc_info tuple."
610        if self.sent_headers:
611            try:
612                raise exc_info[0], exc_info[1], exc_info[2]
613            finally:
614                exc_info = None
615       
616        self.started_response = True
617        self.status = status
618        self.outheaders.extend(headers)
619        return self.write
620   
621    def write(self, chunk):
622        """WSGI callable to write unbuffered data to the client.
623       
624        This method is also used internally by start_response (to write
625        data from the iterable returned by the WSGI application).
626        """
627        if not self.started_response:
628            raise AssertionError("WSGI write called before start_response.")
629       
630        if not self.sent_headers:
631            self.sent_headers = True
632            self.send_headers()
633       
634        if self.chunked_write and chunk:
635            buf = [hex(len(chunk))[2:], "\r\n", chunk, "\r\n"]
636            self.wfile.sendall("".join(buf))
637        else:
638            self.wfile.sendall(chunk)
639   
640    def send_headers(self):
641        """Assert, process, and send the HTTP response message-headers."""
642        hkeys = [key.lower() for key, value in self.outheaders]
643        status = int(self.status[:3])
644       
645        if status == 413:
646            # Request Entity Too Large. Close conn to avoid garbage.
647            self.close_connection = True
648        elif "content-length" not in hkeys:
649            # "All 1xx (informational), 204 (no content),
650            # and 304 (not modified) responses MUST NOT
651            # include a message-body." So no point chunking.
652            if status < 200 or status in (204, 205, 304):
653                pass
654            else:
655                if (self.response_protocol == 'HTTP/1.1'
656                    and self.environ["REQUEST_METHOD"] != 'HEAD'):
657                    # Use the chunked transfer-coding
658                    self.chunked_write = True
659                    self.outheaders.append(("Transfer-Encoding", "chunked"))
660                else:
661                    # Closing the conn is the only way to determine len.
662                    self.close_connection = True
663       
664        if "connection" not in hkeys:
665            if self.response_protocol == 'HTTP/1.1':
666                # Both server and client are HTTP/1.1 or better
667                if self.close_connection:
668                    self.outheaders.append(("Connection", "close"))
669            else:
670                # Server and/or client are HTTP/1.0
671                if not self.close_connection:
672                    self.outheaders.append(("Connection", "Keep-Alive"))
673       
674        if (not self.close_connection) and (not self.chunked_read):
675            # Read any remaining request body data on the socket.
676            # "If an origin server receives a request that does not include an
677            # Expect request-header field with the "100-continue" expectation,
678            # the request includes a request body, and the server responds
679            # with a final status code before reading the entire request body
680            # from the transport connection, then the server SHOULD NOT close
681            # the transport connection until it has read the entire request,
682            # or until the client closes the connection. Otherwise, the client
683            # might not reliably receive the response message. However, this
684            # requirement is not be construed as preventing a server from
685            # defending itself against denial-of-service attacks, or from
686            # badly broken client implementations."
687            size = self.rfile.maxlen - self.rfile.bytes_read
688            if size > 0:
689                self.rfile.read(size)
690       
691        if "date" not in hkeys:
692            self.outheaders.append(("Date", rfc822.formatdate()))
693       
694        if "server" not in hkeys:
695            self.outheaders.append(("Server", self.environ['SERVER_SOFTWARE']))
696       
697        buf = [self.environ['ACTUAL_SERVER_PROTOCOL'], " ", self.status, "\r\n"]
698        try:
699            buf += [k + ": " + v + "\r\n" for k, v in self.outheaders]
700        except TypeError:
701            if not isinstance(k, str):
702                raise TypeError("WSGI response header key %r is not a string.")
703            if not isinstance(v, str):
704                raise TypeError("WSGI response header value %r is not a string.")
705            else:
706                raise
707        buf.append("\r\n")
708        self.wfile.sendall("".join(buf))
709
710
711class NoSSLError(Exception):
712    """Exception raised when a client speaks HTTP to an HTTPS socket."""
713    pass
714
715
716class FatalSSLAlert(Exception):
717    """Exception raised when the SSL implementation signals a fatal alert."""
718    pass
719
720
721if not _fileobject_uses_str_type:
722    class CP_fileobject(socket._fileobject):
723        """Faux file object attached to a socket object."""
724
725        def sendall(self, data):
726            """Sendall for non-blocking sockets."""
727            while data:
728                try:
729                    bytes_sent = self.send(data)
730                    data = data[bytes_sent:]
731                except socket.error, e:
732                    if e.args[0] not in socket_errors_nonblocking:
733                        raise
734
735        def send(self, data):
736            return self._sock.send(data)
737
738        def flush(self):
739            if self._wbuf:
740                buffer = "".join(self._wbuf)
741                self._wbuf = []
742                self.sendall(buffer)
743
744        def recv(self, size):
745            while True:
746                try:
747                    return self._sock.recv(size)
748                except socket.error, e:
749                    if (e.args[0] not in socket_errors_nonblocking
750                        and e.args[0] not in socket_error_eintr):
751                        raise
752
753        def read(self, size=-1):
754            # Use max, disallow tiny reads in a loop as they are very inefficient.
755            # We never leave read() with any leftover data from a new recv() call
756            # in our internal buffer.
757            rbufsize = max(self._rbufsize, self.default_bufsize)
758            # Our use of StringIO rather than lists of string objects returned by
759            # recv() minimizes memory usage and fragmentation that occurs when
760            # rbufsize is large compared to the typical return value of recv().
761            buf = self._rbuf
762            buf.seek(0, 2)  # seek end
763            if size < 0:
764                # Read until EOF
765                self._rbuf = StringIO.StringIO()  # reset _rbuf.  we consume it via buf.
766                while True:
767                    data = self.recv(rbufsize)
768                    if not data:
769                        break
770                    buf.write(data)
771                return buf.getvalue()
772            else:
773                # Read until size bytes or EOF seen, whichever comes first
774                buf_len = buf.tell()
775                if buf_len >= size:
776                    # Already have size bytes in our buffer?  Extract and return.
777                    buf.seek(0)
778                    rv = buf.read(size)
779                    self._rbuf = StringIO.StringIO()
780                    self._rbuf.write(buf.read())
781                    return rv
782
783                self._rbuf = StringIO.StringIO()  # reset _rbuf.  we consume it via buf.
784                while True:
785                    left = size - buf_len
786                    # recv() will malloc the amount of memory given as its
787                    # parameter even though it often returns much less data
788                    # than that.  The returned data string is short lived
789                    # as we copy it into a StringIO and free it.  This avoids
790                    # fragmentation issues on many platforms.
791                    data = self.recv(left)
792                    if not data:
793                        break
794                    n = len(data)
795                    if n == size and not buf_len:
796                        # Shortcut.  Avoid buffer data copies when:
797                        # - We have no data in our buffer.
798                        # AND
799                        # - Our call to recv returned exactly the
800                        #   number of bytes we were asked to read.
801                        return data
802                    if n == left:
803                        buf.write(data)
804                        del data  # explicit free
805                        break
806                    assert n <= left, "recv(%d) returned %d bytes" % (left, n)
807                    buf.write(data)
808                    buf_len += n
809                    del data  # explicit free
810                    #assert buf_len == buf.tell()
811                return buf.getvalue()
812
813        def readline(self, size=-1):
814            buf = self._rbuf
815            buf.seek(0, 2)  # seek end
816            if buf.tell() > 0:
817                # check if we already have it in our buffer
818                buf.seek(0)
819                bline = buf.readline(size)
820                if bline.endswith('\n') or len(bline) == size:
821                    self._rbuf = StringIO.StringIO()
822                    self._rbuf.write(buf.read())
823                    return bline
824                del bline
825            if size < 0:
826                # Read until \n or EOF, whichever comes first
827                if self._rbufsize <= 1:
828                    # Speed up unbuffered case
829                    buf.seek(0)
830                    buffers = [buf.read()]
831                    self._rbuf = StringIO.StringIO()  # reset _rbuf.  we consume it via buf.
832                    data = None
833                    recv = self.recv
834                    while data != "\n":
835                        data = recv(1)
836                        if not data:
837                            break
838                        buffers.append(data)
839                    return "".join(buffers)
840
841                buf.seek(0, 2)  # seek end
842                self._rbuf = StringIO.StringIO()  # reset _rbuf.  we consume it via buf.
843                while True:
844                    data = self.recv(self._rbufsize)
845                    if not data:
846                        break
847                    nl = data.find('\n')
848                    if nl >= 0:
849                        nl += 1
850                        buf.write(data[:nl])
851                        self._rbuf.write(data[nl:])
852                        del data
853                        break
854                    buf.write(data)
855                return buf.getvalue()
856            else:
857                # Read until size bytes or \n or EOF seen, whichever comes first
858                buf.seek(0, 2)  # seek end
859                buf_len = buf.tell()
860                if buf_len >= size:
861                    buf.seek(0)
862                    rv = buf.read(size)
863                    self._rbuf = StringIO.StringIO()
864                    self._rbuf.write(buf.read())
865                    return rv
866                self._rbuf = StringIO.StringIO()  # reset _rbuf.  we consume it via buf.
867                while True:
868                    data = self.recv(self._rbufsize)
869                    if not data:
870                        break
871                    left = size - buf_len
872                    # did we just receive a newline?
873                    nl = data.find('\n', 0, left)
874                    if nl >= 0:
875                        nl += 1
876                        # save the excess data to _rbuf
877                        self._rbuf.write(data[nl:])
878                        if buf_len:
879                            buf.write(data[:nl])
880                            break
881                        else:
882                            # Shortcut.  Avoid data copy through buf when returning
883                            # a substring of our first recv().
884                            return data[:nl]
885                    n = len(data)
886                    if n == size and not buf_len:
887                        # Shortcut.  Avoid data copy through buf when
888                        # returning exactly all of our first recv().
889                        return data
890                    if n >= left:
891                        buf.write(data[:left])
892                        self._rbuf.write(data[left:])
893                        break
894                    buf.write(data)
895                    buf_len += n
896                    #assert buf_len == buf.tell()
897                return buf.getvalue()
898
899else:
900    class CP_fileobject(socket._fileobject):
901        """Faux file object attached to a socket object."""
902
903        def sendall(self, data):
904            """Sendall for non-blocking sockets."""
905            while data:
906                try:
907                    bytes_sent = self.send(data)
908                    data = data[bytes_sent:]
909                except socket.error, e:
910                    if e.args[0] not in socket_errors_nonblocking:
911                        raise
912
913        def send(self, data):
914            return self._sock.send(data)
915
916        def flush(self):
917            if self._wbuf:
918                buffer = "".join(self._wbuf)
919                self._wbuf = []
920                self.sendall(buffer)
921
922        def recv(self, size):
923            while True:
924                try:
925                    return self._sock.recv(size)
926                except socket.error, e:
927                    if (e.args[0] not in socket_errors_nonblocking
928                        and e.args[0] not in socket_error_eintr):
929                        raise
930
931        def read(self, size=-1):
932            if size < 0:
933                # Read until EOF
934                buffers = [self._rbuf]
935                self._rbuf = ""
936                if self._rbufsize <= 1:
937                    recv_size = self.default_bufsize
938                else:
939                    recv_size = self._rbufsize
940
941                while True:
942                    data = self.recv(recv_size)
943                    if not data:
944                        break
945                    buffers.append(data)
946                return "".join(buffers)
947            else:
948                # Read until size bytes or EOF seen, whichever comes first
949                data = self._rbuf
950                buf_len = len(data)
951                if buf_len >= size:
952                    self._rbuf = data[size:]
953                    return data[:size]
954                buffers = []
955                if data:
956                    buffers.append(data)
957                self._rbuf = ""
958                while True:
959                    left = size - buf_len
960                    recv_size = max(self._rbufsize, left)
961                    data = self.recv(recv_size)
962                    if not data:
963                        break
964                    buffers.append(data)
965                    n = len(data)
966                    if n >= left:
967                        self._rbuf = data[left:]
968                        buffers[-1] = data[:left]
969                        break
970                    buf_len += n
971                return "".join(buffers)
972
973        def readline(self, size=-1):
974            data = self._rbuf
975            if size < 0:
976                # Read until \n or EOF, whichever comes first
977                if self._rbufsize <= 1:
978                    # Speed up unbuffered case
979                    assert data == ""
980                    buffers = []
981                    while data != "\n":
982                        data = self.recv(1)
983                        if not data:
984                            break
985                        buffers.append(data)
986                    return "".join(buffers)
987                nl = data.find('\n')
988                if nl >= 0:
989                    nl += 1
990                    self._rbuf = data[nl:]
991                    return data[:nl]
992                buffers = []
993                if data:
994                    buffers.append(data)
995                self._rbuf = ""
996                while True:
997                    data = self.recv(self._rbufsize)
998                    if not data:
999                        break
1000                    buffers.append(data)
1001                    nl = data.find('\n')
1002                    if nl >= 0:
1003                        nl += 1
1004                        self._rbuf = data[nl:]
1005                        buffers[-1] = data[:nl]
1006                        break
1007                return "".join(buffers)
1008            else:
1009                # Read until size bytes or \n or EOF seen, whichever comes first
1010                nl = data.find('\n', 0, size)
1011                if nl >= 0:
1012                    nl += 1
1013                    self._rbuf = data[nl:]
1014                    return data[:nl]
1015                buf_len = len(data)
1016                if buf_len >= size:
1017                    self._rbuf = data[size:]
1018                    return data[:size]
1019                buffers = []
1020                if data:
1021                    buffers.append(data)
1022                self._rbuf = ""
1023                while True:
1024                    data = self.recv(self._rbufsize)
1025                    if not data:
1026                        break
1027                    buffers.append(data)
1028                    left = size - buf_len
1029                    nl = data.find('\n', 0, left)
1030                    if nl >= 0:
1031                        nl += 1
1032                        self._rbuf = data[nl:]
1033                        buffers[-1] = data[:nl]
1034                        break
1035                    n = len(data)
1036                    if n >= left:
1037                        self._rbuf = data[left:]
1038                        buffers[-1] = data[:left]
1039                        break
1040                    buf_len += n
1041                return "".join(buffers)
1042   
1043
1044class SSL_fileobject(CP_fileobject):
1045    """SSL file object attached to a socket object."""
1046   
1047    ssl_timeout = 3
1048    ssl_retry = .01
1049   
1050    def _safe_call(self, is_reader, call, *args, **kwargs):
1051        """Wrap the given call with SSL error-trapping.
1052       
1053        is_reader: if False EOF errors will be raised. If True, EOF errors
1054            will return "" (to emulate normal sockets).
1055        """
1056        start = time.time()
1057        while True:
1058            try:
1059                return call(*args, **kwargs)
1060            except SSL.WantReadError:
1061                # Sleep and try again. This is dangerous, because it means
1062                # the rest of the stack has no way of differentiating
1063                # between a "new handshake" error and "client dropped".
1064                # Note this isn't an endless loop: there's a timeout below.
1065                time.sleep(self.ssl_retry)
1066            except SSL.WantWriteError:
1067                time.sleep(self.ssl_retry)
1068            except SSL.SysCallError, e:
1069                if is_reader and e.args == (-1, 'Unexpected EOF'):
1070                    return ""
1071               
1072                errnum = e.args[0]
1073                if is_reader and errnum in socket_errors_to_ignore:
1074                    return ""
1075                raise socket.error(errnum)
1076            except SSL.Error, e:
1077                if is_reader and e.args == (-1, 'Unexpected EOF'):
1078                    return ""
1079               
1080                thirdarg = None
1081                try:
1082                    thirdarg = e.args[0][0][2]
1083                except IndexError:
1084                    pass
1085               
1086                if thirdarg == 'http request':
1087                    # The client is talking HTTP to an HTTPS server.
1088                    raise NoSSLError()
1089                raise FatalSSLAlert(*e.args)
1090            except:
1091                raise
1092           
1093            if time.time() - start > self.ssl_timeout:
1094                raise socket.timeout("timed out")
1095
1096    def recv(self, *args, **kwargs):
1097        buf = []
1098        r = super(SSL_fileobject, self).recv
1099        while True:
1100            data = self._safe_call(True, r, *args, **kwargs)
1101            buf.append(data)
1102            p = self._sock.pending()
1103            if not p:
1104                return "".join(buf)
1105   
1106    def sendall(self, *args, **kwargs):
1107        return self._safe_call(False, super(SSL_fileobject, self).sendall, *args, **kwargs)
1108
1109    def send(self, *args, **kwargs):
1110        return self._safe_call(False, super(SSL_fileobject, self).send, *args, **kwargs)
1111
1112
1113class HTTPConnection(object):
1114    """An HTTP connection (active socket).
1115   
1116    socket: the raw socket object (usually TCP) for this connection.
1117    wsgi_app: the WSGI application for this server/connection.
1118    environ: a WSGI environ template. This will be copied for each request.
1119   
1120    rfile: a fileobject for reading from the socket.
1121    send: a function for writing (+ flush) to the socket.
1122    """
1123   
1124    rbufsize = -1
1125    RequestHandlerClass = HTTPRequest
1126    environ = {"wsgi.version": (1, 0),
1127               "wsgi.url_scheme": "http",
1128               "wsgi.multithread": True,
1129               "wsgi.multiprocess": False,
1130               "wsgi.run_once": False,
1131               "wsgi.errors": sys.stderr,
1132               }
1133   
1134    def __init__(self, sock, wsgi_app, environ):
1135        self.socket = sock
1136        self.wsgi_app = wsgi_app
1137       
1138        # Copy the class environ into self.
1139        self.environ = self.environ.copy()
1140        self.environ.update(environ)
1141       
1142        if SSL and isinstance(sock, SSL.ConnectionType):
1143            timeout = sock.gettimeout()
1144            self.rfile = SSL_fileobject(sock, "rb", self.rbufsize)
1145            self.rfile.ssl_timeout = timeout
1146            self.wfile = SSL_fileobject(sock, "wb", -1)
1147            self.wfile.ssl_timeout = timeout
1148        else:
1149            self.rfile = CP_fileobject(sock, "rb", self.rbufsize)
1150            self.wfile = CP_fileobject(sock, "wb", -1)
1151       
1152        # Wrap wsgi.input but not HTTPConnection.rfile itself.
1153        # We're also not setting maxlen yet; we'll do that separately
1154        # for headers and body for each iteration of self.communicate
1155        # (if maxlen is 0 the wrapper doesn't check length).
1156        self.environ["wsgi.input"] = SizeCheckWrapper(self.rfile, 0)
1157   
1158    def communicate(self):
1159        """Read each request and respond appropriately."""
1160        try:
1161            while True:
1162                # (re)set req to None so that if something goes wrong in
1163                # the RequestHandlerClass constructor, the error doesn't
1164                # get written to the previous request.
1165                req = None
1166                req = self.RequestHandlerClass(self.wfile, self.environ,
1167                                               self.wsgi_app)
1168               
1169                # This order of operations should guarantee correct pipelining.
1170                req.parse_request()
1171                if not req.ready:
1172                    return
1173               
1174                req.respond()
1175                if req.close_connection:
1176                    return
1177       
1178        except socket.error, e:
1179            errnum = e.args[0]
1180            if errnum == 'timed out':
1181                if req and not req.sent_headers:
1182                    req.simple_response("408 Request Timeout")
1183            elif errnum not in socket_errors_to_ignore:
1184                if req and not req.sent_headers:
1185                    req.simple_response("500 Internal Server Error",
1186                                        format_exc())
1187            return
1188        except (KeyboardInterrupt, SystemExit):
1189            raise
1190        except FatalSSLAlert, e:
1191            # Close the connection.
1192            return
1193        except NoSSLError:
1194            # Unwrap our wfile
1195            req.wfile = CP_fileobject(self.socket, "wb", -1)
1196            if req and not req.sent_headers:
1197                req.simple_response("400 Bad Request",
1198                    "The client sent a plain HTTP request, but "
1199                    "this server only speaks HTTPS on this port.")
1200        except Exception, e:
1201            if req and not req.sent_headers:
1202                req.simple_response("500 Internal Server Error", format_exc())
1203   
1204    def close(self):
1205        """Close the socket underlying this connection."""
1206        self.rfile.close()
1207       
1208        # Python's socket module does NOT call close on the kernel socket
1209        # when you call socket.close(). We do so manually here because we
1210        # want this server to send a FIN TCP segment immediately. Note this
1211        # must be called *before* calling socket.close(), because the latter
1212        # drops its reference to the kernel socket.
1213        self.socket._sock.close()
1214       
1215        self.socket.close()
1216
1217
1218def format_exc(limit=None):
1219    """Like print_exc() but return a string. Backport for Python 2.3."""
1220    try:
1221        etype, value, tb = sys.exc_info()
1222        return ''.join(traceback.format_exception(etype, value, tb, limit))
1223    finally:
1224        etype = value = tb = None
1225
1226
1227_SHUTDOWNREQUEST = None
1228
1229class WorkerThread(threading.Thread):
1230    """Thread which continuously polls a Queue for Connection objects.
1231   
1232    server: the HTTP Server which spawned this thread, and which owns the
1233        Queue and is placing active connections into it.
1234    ready: a simple flag for the calling server to know when this thread
1235        has begun polling the Queue.
1236   
1237    Due to the timing issues of polling a Queue, a WorkerThread does not
1238    check its own 'ready' flag after it has started. To stop the thread,
1239    it is necessary to stick a _SHUTDOWNREQUEST object onto the Queue
1240    (one for each running WorkerThread).
1241    """
1242   
1243    conn = None
1244   
1245    def __init__(self, server):
1246        self.ready = False
1247        self.server = server
1248        threading.Thread.__init__(self)
1249   
1250    def run(self):
1251        try:
1252            self.ready = True
1253            while True:
1254                conn = self.server.requests.get()
1255                if conn is _SHUTDOWNREQUEST:
1256                    return
1257               
1258                self.conn = conn
1259                try:
1260                    conn.communicate()
1261                finally:
1262                    conn.close()
1263                    self.conn = None
1264        except (KeyboardInterrupt, SystemExit), exc:
1265            self.server.interrupt = exc
1266
1267
1268class ThreadPool(object):
1269    """A Request Queue for the CherryPyWSGIServer which pools threads.
1270   
1271    ThreadPool objects must provide min, get(), put(obj), start()
1272    and stop(timeout) attributes.
1273    """
1274   
1275    def __init__(self, server, min=10, max=-1):
1276        self.server = server
1277        self.min = min
1278        self.max = max
1279        self._threads = []
1280        self._queue = Queue.Queue()
1281        self.get = self._queue.get
1282   
1283    def start(self):
1284        """Start the pool of threads."""
1285        for i in xrange(self.min):
1286            self._threads.append(WorkerThread(self.server))
1287        for worker in self._threads:
1288            worker.setName("CP WSGIServer " + worker.getName())
1289            worker.start()
1290        for worker in self._threads:
1291            while not worker.ready:
1292                time.sleep(.1)
1293   
1294    def _get_idle(self):
1295        """Number of worker threads which are idle. Read-only."""
1296        return len([t for t in self._threads if t.conn is None])
1297    idle = property(_get_idle, doc=_get_idle.__doc__)
1298   
1299    def put(self, obj):
1300        self._queue.put(obj)
1301        if obj is _SHUTDOWNREQUEST:
1302            return
1303   
1304    def grow(self, amount):
1305        """Spawn new worker threads (not above self.max)."""
1306        for i in xrange(amount):
1307            if self.max > 0 and len(self._threads) >= self.max:
1308                break
1309            worker = WorkerThread(self.server)
1310            worker.setName("CP WSGIServer " + worker.getName())
1311            self._threads.append(worker)
1312            worker.start()
1313   
1314    def shrink(self, amount):
1315        """Kill off worker threads (not below self.min)."""
1316        # Grow/shrink the pool if necessary.
1317        # Remove any dead threads from our list
1318        for t in self._threads:
1319            if not t.isAlive():
1320                self._threads.remove(t)
1321                amount -= 1
1322       
1323        if amount > 0:
1324            for i in xrange(min(amount, len(self._threads) - self.min)):
1325                # Put a number of shutdown requests on the queue equal
1326                # to 'amount'. Once each of those is processed by a worker,
1327                # that worker will terminate and be culled from our list
1328                # in self.put.
1329                self._queue.put(_SHUTDOWNREQUEST)
1330   
1331    def stop(self, timeout=5):
1332        # Must shut down threads here so the code that calls
1333        # this method can know when all threads are stopped.
1334        for worker in self._threads:
1335            self._queue.put(_SHUTDOWNREQUEST)
1336       
1337        # Don't join currentThread (when stop is called inside a request).
1338        current = threading.currentThread()
1339        while self._threads:
1340            worker = self._threads.pop()
1341            if worker is not current and worker.isAlive():
1342                try:
1343                    if timeout is None or timeout < 0:
1344                        worker.join()
1345                    else:
1346                        worker.join(timeout)
1347                        if worker.isAlive():
1348                            # We exhausted the timeout.
1349                            # Forcibly shut down the socket.
1350                            c = worker.conn
1351                            if c and not c.rfile.closed:
1352                                if SSL and isinstance(c.socket, SSL.ConnectionType):
1353                                    # pyOpenSSL.socket.shutdown takes no args
1354                                    c.socket.shutdown()
1355                                else:
1356                                    c.socket.shutdown(socket.SHUT_RD)
1357                            worker.join()
1358                except (AssertionError,
1359                        # Ignore repeated Ctrl-C.
1360                        # See http://www.cherrypy.org/ticket/691.
1361                        KeyboardInterrupt), exc1:
1362                    pass
1363
1364
1365
1366class SSLConnection:
1367    """A thread-safe wrapper for an SSL.Connection.
1368   
1369    *args: the arguments to create the wrapped SSL.Connection(*args).
1370    """
1371   
1372    def __init__(self, *args):
1373        self._ssl_conn = SSL.Connection(*args)
1374        self._lock = threading.RLock()
1375   
1376    for f in ('get_context', 'pending', 'send', 'write', 'recv', 'read',
1377              'renegotiate', 'bind', 'listen', 'connect', 'accept',
1378              'setblocking', 'fileno', 'shutdown', 'close', 'get_cipher_list',
1379              'getpeername', 'getsockname', 'getsockopt', 'setsockopt',
1380              'makefile', 'get_app_data', 'set_app_data', 'state_string',
1381              'sock_shutdown', 'get_peer_certificate', 'want_read',
1382              'want_write', 'set_connect_state', 'set_accept_state',
1383              'connect_ex', 'sendall', 'settimeout'):
1384        exec """def %s(self, *args):
1385        self._lock.acquire()
1386        try:
1387            return self._ssl_conn.%s(*args)
1388        finally:
1389            self._lock.release()
1390""" % (f, f)
1391
1392
1393try:
1394    import fcntl
1395except ImportError:
1396    try:
1397        from ctypes import windll, WinError
1398    except ImportError:
1399        def prevent_socket_inheritance(sock):
1400            """Dummy function, since neither fcntl nor ctypes are available."""
1401            pass
1402    else:
1403        def prevent_socket_inheritance(sock):
1404            """Mark the given socket fd as non-inheritable (Windows)."""
1405            if not windll.kernel32.SetHandleInformation(sock.fileno(), 1, 0):
1406                raise WinError()
1407else:
1408    def prevent_socket_inheritance(sock):
1409        """Mark the given socket fd as non-inheritable (POSIX)."""
1410        fd = sock.fileno()
1411        old_flags = fcntl.fcntl(fd, fcntl.F_GETFD)
1412        fcntl.fcntl(fd, fcntl.F_SETFD, old_flags | fcntl.FD_CLOEXEC)
1413
1414
1415class CherryPyWSGIServer(object):
1416    """An HTTP server for WSGI.
1417   
1418    bind_addr: The interface on which to listen for connections.
1419        For TCP sockets, a (host, port) tuple. Host values may be any IPv4
1420        or IPv6 address, or any valid hostname. The string 'localhost' is a
1421        synonym for '127.0.0.1' (or '::1', if your hosts file prefers IPv6).
1422        The string '0.0.0.0' is a special IPv4 entry meaning "any active
1423        interface" (INADDR_ANY), and '::' is the similar IN6ADDR_ANY for
1424        IPv6. The empty string or None are not allowed.
1425       
1426        For UNIX sockets, supply the filename as a string.
1427    wsgi_app: the WSGI 'application callable'; multiple WSGI applications
1428        may be passed as (path_prefix, app) pairs.
1429    numthreads: the number of worker threads to create (default 10).
1430    server_name: the string to set for WSGI's SERVER_NAME environ entry.
1431        Defaults to socket.gethostname().
1432    max: the maximum number of queued requests (defaults to -1 = no limit).
1433    request_queue_size: the 'backlog' argument to socket.listen();
1434        specifies the maximum number of queued connections (default 5).
1435    timeout: the timeout in seconds for accepted connections (default 10).
1436   
1437    nodelay: if True (the default since 3.1), sets the TCP_NODELAY socket
1438        option.
1439   
1440    protocol: the version string to write in the Status-Line of all
1441        HTTP responses. For example, "HTTP/1.1" (the default). This
1442        also limits the supported features used in the response.
1443   
1444   
1445    SSL/HTTPS
1446    ---------
1447    The OpenSSL module must be importable for SSL functionality.
1448    You can obtain it from http://pyopenssl.sourceforge.net/
1449   
1450    ssl_certificate: the filename of the server SSL certificate.
1451    ssl_privatekey: the filename of the server's private key file.
1452   
1453    If either of these is None (both are None by default), this server
1454    will not use SSL. If both are given and are valid, they will be read
1455    on server start and used in the SSL context for the listening socket.
1456    """
1457   
1458    protocol = "HTTP/1.1"
1459    _bind_addr = "127.0.0.1"
1460    version = "CherryPy/3.1.1"
1461    ready = False
1462    _interrupt = None
1463   
1464    nodelay = True
1465   
1466    ConnectionClass = HTTPConnection
1467    environ = {}
1468   
1469    # Paths to certificate and private key files
1470    ssl_certificate = None
1471    ssl_private_key = None
1472   
1473    def __init__(self, bind_addr, wsgi_app, numthreads=10, server_name=None,
1474                 max=-1, request_queue_size=5, timeout=10, shutdown_timeout=5):
1475        self.requests = ThreadPool(self, min=numthreads or 1, max=max)
1476       
1477        if callable(wsgi_app):
1478            # We've been handed a single wsgi_app, in CP-2.1 style.
1479            # Assume it's mounted at "".
1480            self.wsgi_app = wsgi_app
1481        else:
1482            # We've been handed a list of (path_prefix, wsgi_app) tuples,
1483            # so that the server can call different wsgi_apps, and also
1484            # correctly set SCRIPT_NAME.
1485            warnings.warn("The ability to pass multiple apps is deprecated "
1486                          "and will be removed in 3.2. You should explicitly "
1487                          "include a WSGIPathInfoDispatcher instead.",
1488                          DeprecationWarning)
1489            self.wsgi_app = WSGIPathInfoDispatcher(wsgi_app)
1490       
1491        self.bind_addr = bind_addr
1492        if not server_name:
1493            server_name = socket.gethostname()
1494        self.server_name = server_name
1495        self.request_queue_size = request_queue_size
1496       
1497        self.timeout = timeout
1498        self.shutdown_timeout = shutdown_timeout
1499   
1500    def _get_numthreads(self):
1501        return self.requests.min
1502    def _set_numthreads(self, value):
1503        self.requests.min = value
1504    numthreads = property(_get_numthreads, _set_numthreads)
1505   
1506    def __str__(self):
1507        return "%s.%s(%r)" % (self.__module__, self.__class__.__name__,
1508                              self.bind_addr)
1509   
1510    def _get_bind_addr(self):
1511        return self._bind_addr
1512    def _set_bind_addr(self, value):
1513        if isinstance(value, tuple) and value[0] in ('', None):
1514            # Despite the socket module docs, using '' does not
1515            # allow AI_PASSIVE to work. Passing None instead
1516            # returns '0.0.0.0' like we want. In other words:
1517            #     host    AI_PASSIVE     result
1518            #      ''         Y         192.168.x.y
1519            #      ''         N         192.168.x.y
1520            #     None        Y         0.0.0.0
1521            #     None        N         127.0.0.1
1522            # But since you can get the same effect with an explicit
1523            # '0.0.0.0', we deny both the empty string and None as values.
1524            raise ValueError("Host values of '' or None are not allowed. "
1525                             "Use '0.0.0.0' (IPv4) or '::' (IPv6) instead "
1526                             "to listen on all active interfaces.")
1527        self._bind_addr = value
1528    bind_addr = property(_get_bind_addr, _set_bind_addr,
1529        doc="""The interface on which to listen for connections.
1530       
1531        For TCP sockets, a (host, port) tuple. Host values may be any IPv4
1532        or IPv6 address, or any valid hostname. The string 'localhost' is a
1533        synonym for '127.0.0.1' (or '::1', if your hosts file prefers IPv6).
1534        The string '0.0.0.0' is a special IPv4 entry meaning "any active
1535        interface" (INADDR_ANY), and '::' is the similar IN6ADDR_ANY for
1536        IPv6. The empty string or None are not allowed.
1537       
1538        For UNIX sockets, supply the filename as a string.""")
1539   
1540    def start(self):
1541        """Run the server forever."""
1542        # We don't have to trap KeyboardInterrupt or SystemExit here,
1543        # because cherrpy.server already does so, calling self.stop() for us.
1544        # If you're using this server with another framework, you should
1545        # trap those exceptions in whatever code block calls start().
1546        self._interrupt = None
1547       
1548        # Select the appropriate socket
1549        if isinstance(self.bind_addr, basestring):
1550            # AF_UNIX socket
1551           
1552            # So we can reuse the socket...
1553            try: os.unlink(self.bind_addr)
1554            except: pass
1555           
1556            # So everyone can access the socket...
1557            try: os.chmod(self.bind_addr, 0777)
1558            except: pass
1559           
1560            info = [(socket.AF_UNIX, socket.SOCK_STREAM, 0, "", self.bind_addr)]
1561        else:
1562            # AF_INET or AF_INET6 socket
1563            # Get the correct address family for our host (allows IPv6 addresses)
1564            host, port = self.bind_addr
1565            try:
1566                info = socket.getaddrinfo(host, port, socket.AF_UNSPEC,
1567                                          socket.SOCK_STREAM, 0, socket.AI_PASSIVE)
1568            except socket.gaierror:
1569                # Probably a DNS issue. Assume IPv4.
1570                info = [(socket.AF_INET, socket.SOCK_STREAM, 0, "", self.bind_addr)]
1571       
1572        self.socket = None
1573        msg = "No socket could be created"
1574        for res in info:
1575            af, socktype, proto, canonname, sa = res
1576            try:
1577                self.bind(af, socktype, proto)
1578            except socket.error, msg:
1579                if self.socket:
1580                    self.socket.close()
1581                self.socket = None
1582                continue
1583            break
1584        if not self.socket:
1585            raise socket.error, msg
1586       
1587        # Timeout so KeyboardInterrupt can be caught on Win32
1588        self.socket.settimeout(1)
1589        self.socket.listen(self.request_queue_size)
1590       
1591        # Create worker threads
1592        self.requests.start()
1593       
1594        self.ready = True
1595        while self.ready:
1596            self.tick()
1597            if self.interrupt:
1598                while self.interrupt is True:
1599                    # Wait for self.stop() to complete. See _set_interrupt.
1600                    time.sleep(0.1)
1601                if self.interrupt:
1602                    raise self.interrupt
1603   
1604    def bind(self, family, type, proto=0):
1605        """Create (or recreate) the actual socket object."""
1606        self.socket = socket.socket(family, type, proto)
1607        prevent_socket_inheritance(self.socket)
1608        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
1609        if self.nodelay:
1610            self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
1611        if self.ssl_certificate and self.ssl_private_key:
1612            if SSL is None:
1613                raise ImportError("You must install pyOpenSSL to use HTTPS.")
1614           
1615            # See http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/442473
1616            ctx = SSL.Context(SSL.SSLv23_METHOD)
1617            ctx.use_privatekey_file(self.ssl_private_key)
1618            ctx.use_certificate_file(self.ssl_certificate)
1619            self.socket = SSLConnection(ctx, self.socket)
1620            self.populate_ssl_environ()
1621           
1622            # If listening on the IPV6 any address ('::' = IN6ADDR_ANY),
1623            # activate dual-stack. See http://www.cherrypy.org/ticket/871.
1624            if (not isinstance(self.bind_addr, basestring)
1625                and self.bind_addr[0] == '::' and family == socket.AF_INET6):
1626                try:
1627                    self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0)
1628                except (AttributeError, socket.error):
1629                    # Apparently, the socket option is not available in
1630                    # this machine's TCP stack
1631                    pass
1632       
1633        self.socket.bind(self.bind_addr)
1634   
1635    def tick(self):
1636        """Accept a new connection and put it on the Queue."""
1637        try:
1638            s, addr = self.socket.accept()
1639            prevent_socket_inheritance(s)
1640            if not self.ready:
1641                return
1642            if hasattr(s, 'settimeout'):
1643                s.settimeout(self.timeout)
1644           
1645            environ = self.environ.copy()
1646            # SERVER_SOFTWARE is common for IIS. It's also helpful for
1647            # us to pass a default value for the "Server" response header.
1648            if environ.get("SERVER_SOFTWARE") is None:
1649                environ["SERVER_SOFTWARE"] = "%s WSGI Server" % self.version
1650            # set a non-standard environ entry so the WSGI app can know what
1651            # the *real* server protocol is (and what features to support).
1652            # See http://www.faqs.org/rfcs/rfc2145.html.
1653            environ["ACTUAL_SERVER_PROTOCOL"] = self.protocol
1654            environ["SERVER_NAME"] = self.server_name
1655           
1656            if isinstance(self.bind_addr, basestring):
1657                # AF_UNIX. This isn't really allowed by WSGI, which doesn't
1658                # address unix domain sockets. But it's better than nothing.
1659                environ["SERVER_PORT"] = ""
1660            else:
1661                environ["SERVER_PORT"] = str(self.bind_addr[1])
1662                # optional values
1663                # Until we do DNS lookups, omit REMOTE_HOST
1664                environ["REMOTE_ADDR"] = addr[0]
1665                environ["REMOTE_PORT"] = str(addr[1])
1666           
1667            conn = self.ConnectionClass(s, self.wsgi_app, environ)
1668            self.requests.put(conn)
1669        except socket.timeout:
1670            # The only reason for the timeout in start() is so we can
1671            # notice keyboard interrupts on Win32, which don't interrupt
1672            # accept() by default
1673            return
1674        except socket.error, x:
1675            if x.args[0] in socket_error_eintr:
1676                # I *think* this is right. EINTR should occur when a signal
1677                # is received during the accept() call; all docs say retry
1678                # the call, and I *think* I'm reading it right that Python
1679                # will then go ahead and poll for and handle the signal
1680                # elsewhere. See http://www.cherrypy.org/ticket/707.
1681                return
1682            if x.args[0] in socket_errors_nonblocking:
1683                # Just try again. See http://www.cherrypy.org/ticket/479.
1684                return
1685            if x.args[0] in socket_errors_to_ignore:
1686                # Our socket was closed.
1687                # See http://www.cherrypy.org/ticket/686.
1688                return
1689            raise
1690   
1691    def _get_interrupt(self):
1692        return self._interrupt
1693    def _set_interrupt(self, interrupt):
1694        self._interrupt = True
1695        self.stop()
1696        self._interrupt = interrupt
1697    interrupt = property(_get_interrupt, _set_interrupt,
1698                         doc="Set this to an Exception instance to "
1699                             "interrupt the server.")
1700   
1701    def stop(self):
1702        """Gracefully shutdown a server that is serving forever."""
1703        self.ready = False
1704       
1705        sock = getattr(self, "socket", None)
1706        if sock:
1707            if not isinstance(self.bind_addr, basestring):
1708                # Touch our own socket to make accept() return immediately.
1709                try:
1710                    host, port = sock.getsockname()[:2]
1711                except socket.error, x:
1712                    if x.args[1] != "Bad file descriptor":
1713                        raise
1714                else:
1715                    # Note that we're explicitly NOT using AI_PASSIVE,
1716                    # here, because we want an actual IP to touch.
1717                    # localhost won't work if we've bound to a public IP,
1718                    # but it will if we bound to '0.0.0.0' (INADDR_ANY).
1719                    for res in socket.getaddrinfo(host, port, socket.AF_UNSPEC,
1720                                                  socket.SOCK_STREAM):
1721                        af, socktype, proto, canonname, sa = res
1722                        s = None
1723                        try:
1724                            s = socket.socket(af, socktype, proto)
1725                            # See http://groups.google.com/group/cherrypy-users/
1726                            #        browse_frm/thread/bbfe5eb39c904fe0
1727                            s.settimeout(1.0)
1728                            s.connect((host, port))
1729                            s.close()
1730                        except socket.error:
1731                            if s:
1732                                s.close()
1733            if hasattr(sock, "close"):
1734                sock.close()
1735            self.socket = None
1736       
1737        self.requests.stop(self.shutdown_timeout)
1738   
1739    def populate_ssl_environ(self):
1740        """Create WSGI environ entries to be merged into each request."""
1741        cert = open(self.ssl_certificate, 'rb').read()
1742        cert = crypto.load_certificate(crypto.FILETYPE_PEM, cert)
1743        ssl_environ = {
1744            "wsgi.url_scheme": "https",
1745            "HTTPS": "on",
1746            # pyOpenSSL doesn't provide access to any of these AFAICT
1747##            'SSL_PROTOCOL': 'SSLv2',
1748##            SSL_CIPHER        string  The cipher specification name
1749##            SSL_VERSION_INTERFACE     string  The mod_ssl program version
1750##            SSL_VERSION_LIBRARY       string  The OpenSSL program version
1751            }
1752       
1753        # Server certificate attributes
1754        ssl_environ.update({
1755            'SSL_SERVER_M_VERSION': cert.get_version(),
1756            'SSL_SERVER_M_SERIAL': cert.get_serial_number(),
1757##            'SSL_SERVER_V_START': Validity of server's certificate (start time),
1758##            'SSL_SERVER_V_END': Validity of server's certificate (end time),
1759            })
1760       
1761        for prefix, dn in [("I", cert.get_issuer()),
1762                           ("S", cert.get_subject())]:
1763            # X509Name objects don't seem to have a way to get the
1764            # complete DN string. Use str() and slice it instead,
1765            # because str(dn) == "<X509Name object '/C=US/ST=...'>"
1766            dnstr = str(dn)[18:-2]
1767           
1768            wsgikey = 'SSL_SERVER_%s_DN' % prefix
1769            ssl_environ[wsgikey] = dnstr
1770           
1771            # The DN should be of the form: /k1=v1/k2=v2, but we must allow
1772            # for any value to contain slashes itself (in a URL).
1773            while dnstr:
1774                pos = dnstr.rfind("=")
1775                dnstr, value = dnstr[:pos], dnstr[pos + 1:]
1776                pos = dnstr.rfind("/")
1777                dnstr, key = dnstr[:pos], dnstr[pos + 1:]
1778                if key and value:
1779                    wsgikey = 'SSL_SERVER_%s_DN_%s' % (prefix, key)
1780                    ssl_environ[wsgikey] = value
1781       
1782        self.environ.update(ssl_environ)
1783
Note: リポジトリブラウザについてのヘルプは TracBrowser を参照してください。