Download Install Tutorial Docs FAQ Tools WikiLicense Team IRC Planet Involvement Shop Book

root/trunk/cherrypy/wsgiserver/__init__.py

Revision 2564 (checked in by fumanchu, 4 months ago)

Reinstating SERVER_SOFTWARE wsgi environ entry.

  • Property svn:eol-style set to native
Line 
1 """A high-speed, production ready, thread pooled, generic HTTP server.
2
3 Simplest 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     
18 The CherryPy WSGI server can serve as many WSGI applications
19 as 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     
24 Want SSL support? Just set server.ssl_adapter to an SSLAdapter instance.
25
26 This won't call the CherryPy engine (application side) at all, only the
27 HTTP server, which is independent from the rest of CherryPy. Don't
28 let the name "CherryPyWSGIServer" throw you; the name merely reflects
29 its origin, not its coupling.
30
31 For those of you wanting to understand internals of this module, here's the
32 basic call flow. The server's listening thread runs a very tight loop,
33 sticking incoming connections onto a Queue:
34
35     server = CherryPyWSGIServer(...)
36     server.start()
37     while True:
38         tick()
39         # This blocks until a request comes in:
40         child = socket.accept()
41         conn = HTTPConnection(child, ...)
42         server.requests.put(conn)
43
44 Worker threads are kept in a pool and poll the Queue, popping off and then
45 handling each connection in turn. Each connection can consist of an arbitrary
46 number of requests and their responses, so we run a nested loop:
47
48     while True:
49         conn = server.requests.get()
50         conn.communicate()
51         ->  while True:
52                 req = HTTPRequest(...)
53                 req.parse_request()
54                 ->  # Read the Request-Line, e.g. "GET /page HTTP/1.1"
55                     req.rfile.readline()
56                     read_headers(req.rfile, req.inheaders)
57                 req.respond()
58                 ->  response = app(...)
59                     try:
60                         for chunk in response:
61                             if chunk:
62                                 req.write(chunk)
63                     finally:
64                         if hasattr(response, "close"):
65                             response.close()
66                 if req.close_connection:
67                     return
68 """
69
70 CRLF = '\r\n'
71 import os
72 import Queue
73 import re
74 quoted_slash = re.compile("(?i)%2F")
75 import rfc822
76 import socket
77 import sys
78 if 'win' in sys.platform and not hasattr(socket, 'IPPROTO_IPV6'):
79     socket.IPPROTO_IPV6 = 41
80 try:
81     import cStringIO as StringIO
82 except ImportError:
83     import StringIO
84
85 _fileobject_uses_str_type = isinstance(socket._fileobject(None)._rbuf, basestring)
86
87 import threading
88 import time
89 import traceback
90 from urllib import unquote
91 from urlparse import urlparse
92 import warnings
93
94 import errno
95
96 def plat_specific_errors(*errnames):
97     """Return error numbers for all errors in errnames on this platform.
98     
99     The 'errno' module contains different global constants depending on
100     the specific platform (OS). This function will return the list of
101     numeric values for a given list of potential names.
102     """
103     errno_names = dir(errno)
104     nums = [getattr(errno, k) for k in errnames if k in errno_names]
105     # de-dupe the list
106     return dict.fromkeys(nums).keys()
107
108 socket_error_eintr = plat_specific_errors("EINTR", "WSAEINTR")
109
110 socket_errors_to_ignore = plat_specific_errors(
111     "EPIPE",
112     "EBADF", "WSAEBADF",
113     "ENOTSOCK", "WSAENOTSOCK",
114     "ETIMEDOUT", "WSAETIMEDOUT",
115     "ECONNREFUSED", "WSAECONNREFUSED",
116     "ECONNRESET", "WSAECONNRESET",
117     "ECONNABORTED", "WSAECONNABORTED",
118     "ENETRESET", "WSAENETRESET",
119     "EHOSTDOWN", "EHOSTUNREACH",
120     )
121 socket_errors_to_ignore.append("timed out")
122 socket_errors_to_ignore.append("The read operation timed out")
123
124 socket_errors_nonblocking = plat_specific_errors(
125     'EAGAIN', 'EWOULDBLOCK', 'WSAEWOULDBLOCK')
126
127 comma_separated_headers = ['Accept', 'Accept-Charset', 'Accept-Encoding',
128     'Accept-Language', 'Accept-Ranges', 'Allow', 'Cache-Control',
129     'Connection', 'Content-Encoding', 'Content-Language', 'Expect',
130     'If-Match', 'If-None-Match', 'Pragma', 'Proxy-Authenticate', 'TE',
131     'Trailer', 'Transfer-Encoding', 'Upgrade', 'Vary', 'Via', 'Warning',
132     'WWW-Authenticate']
133
134
135 def read_headers(rfile, hdict=None):
136     """Read headers from the given stream into the given header dict.
137     
138     If hdict is None, a new header dict is created. Returns the populated
139     header dict.
140     
141     Headers which are repeated are folded together using a comma if their
142     specification so dictates.
143     
144     This function raises ValueError when the read bytes violate the HTTP spec.
145     You should probably return "400 Bad Request" if this happens.
146     """
147     if hdict is None:
148         hdict = {}
149    
150     while True:
151         line = rfile.readline()
152         if not line:
153             # No more data--illegal end of headers
154             raise ValueError("Illegal end of headers.")
155        
156         if line == CRLF:
157             # Normal end of headers
158             break
159         if not line.endswith(CRLF):
160             raise ValueError("HTTP requires CRLF terminators")
161        
162         if line[0] in ' \t':
163             # It's a continuation line.
164             v = line.strip()
165         else:
166             try:
167                 k, v = line.split(":", 1)
168             except ValueError:
169                 raise ValueError("Illegal header line.")
170             # TODO: what about TE and WWW-Authenticate?
171             k = k.strip().title()
172             v = v.strip()
173             hname = k
174        
175         if k in comma_separated_headers:
176             existing = hdict.get(hname)
177             if existing:
178                 v = ", ".join((existing, v))
179         hdict[hname] = v
180    
181     return hdict
182
183
184 class MaxSizeExceeded(Exception):
185     pass
186
187 class SizeCheckWrapper(object):
188     """Wraps a file-like object, raising MaxSizeExceeded if too large."""
189    
190     def __init__(self, rfile, maxlen):
191         self.rfile = rfile
192         self.maxlen = maxlen
193         self.bytes_read = 0
194    
195     def _check_length(self):
196         if self.maxlen and self.bytes_read > self.maxlen:
197             raise MaxSizeExceeded()
198    
199     def read(self, size=None):
200         data = self.rfile.read(size)
201         self.bytes_read += len(data)
202         self._check_length()
203         return data
204    
205     def readline(self, size=None):
206         if size is not None:
207             data = self.rfile.readline(size)
208             self.bytes_read += len(data)
209             self._check_length()
210             return data
211        
212         # User didn't specify a size ...
213         # We read the line in chunks to make sure it's not a 100MB line !
214         res = []
215         while True:
216             data = self.rfile.readline(256)
217             self.bytes_read += len(data)
218             self._check_length()
219             res.append(data)
220             # See http://www.cherrypy.org/ticket/421
221             if len(data) < 256 or data[-1:] == "\n":
222                 return ''.join(res)
223    
224     def readlines(self, sizehint=0):
225         # Shamelessly stolen from StringIO
226         total = 0
227         lines = []
228         line = self.readline()
229         while line:
230             lines.append(line)
231             total += len(line)
232             if 0 < sizehint <= total:
233                 break
234             line = self.readline()
235         return lines
236    
237     def close(self):
238         self.rfile.close()
239    
240     def __iter__(self):
241         return self
242    
243     def next(self):
244         data = self.rfile.next()
245         self.bytes_read += len(data)
246         self._check_length()
247         return data
248
249
250 class KnownLengthRFile(object):
251     """Wraps a file-like object, returning an empty string when exhausted."""
252    
253     def __init__(self, rfile, content_length):
254         self.rfile = rfile
255         self.remaining = content_length
256    
257     def read(self, size=None):
258         if self.remaining == 0:
259             return ''
260         if size is None:
261             size = self.remaining
262         else:
263             size = min(size, self.remaining)
264        
265         data = self.rfile.read(size)
266         self.remaining -= len(data)
267         return data
268    
269     def readline(self, size=None):
270         if self.remaining == 0:
271             return ''
272         if size is None:
273             size = self.remaining
274         else:
275             size = min(size, self.remaining)
276        
277         data = self.rfile.readline(size)
278         self.remaining -= len(data)
279         return data
280    
281     def readlines(self, sizehint=0):
282         # Shamelessly stolen from StringIO
283         total = 0
284         lines = []
285         line = self.readline(sizehint)
286         while line:
287             lines.append(line)
288             total += len(line)
289             if 0 < sizehint <= total:
290                 break
291             line = self.readline(sizehint)
292         return lines
293    
294     def close(self):
295         self.rfile.close()
296    
297     def __iter__(self):
298         return self
299    
300     def __next__(self):
301         data = next(self.rfile)
302         self.remaining -= len(data)
303         return data
304
305
306 class MaxSizeExceeded(Exception):
307     pass
308
309
310 class ChunkedRFile(object):
311     """Wraps a file-like object, returning an empty string when exhausted.
312     
313     This class is intended to provide a conforming wsgi.input value for
314     request entities that have been encoded with the 'chunked' transfer
315     encoding.
316     """
317    
318     def __init__(self, rfile, maxlen, bufsize=8192):
319         self.rfile = rfile
320         self.maxlen = maxlen
321         self.bytes_read = 0
322         self.buffer = ''
323         self.bufsize = bufsize
324         self.closed = False
325    
326     def _fetch(self):
327         if self.closed:
328             return
329        
330         line = self.rfile.readline()
331         self.bytes_read += len(line)
332        
333         if self.maxlen and self.bytes_read > self.maxlen:
334             raise MaxSizeExceeded("Request Entity Too Large", self.maxlen)
335        
336         line = line.strip().split(";", 1)
337        
338         try:
339             chunk_size = line.pop(0)
340             chunk_size = int(chunk_size, 16)
341         except ValueError:
342             raise ValueError("Bad chunked transfer size: " + repr(chunk_size))
343        
344         if chunk_size <= 0:
345             self.closed = True
346             return
347        
348 ##            if line: chunk_extension = line[0]
349        
350         if self.maxlen and self.bytes_read + chunk_size > self.maxlen:
351             raise IOError("Request Entity Too Large")
352        
353         chunk = self.rfile.read(chunk_size)
354         self.bytes_read += len(chunk)
355         self.buffer += chunk
356        
357         crlf = self.rfile.read(2)
358         if crlf != CRLF:
359             raise ValueError(
360                  "Bad chunked transfer coding (expected '\\r\\n', "
361                  "got " + repr(crlf) + ")")
362    
363     def read(self, size=None):
364         data = ''
365         while True:
366             if size and len(data) >= size:
367                 return data
368            
369             if not self.buffer:
370                 self._fetch()
371                 if not self.buffer:
372                     # EOF
373                     return data
374            
375             if size:
376                 remaining = size - len(data)
377                 data += self.buffer[:remaining]
378                 self.buffer = self.buffer[remaining:]
379             else:
380                 data += self.buffer
381    
382     def readline(self, size=None):
383         data = ''
384         while True:
385             if size and len(data) >= size:
386                 return data
387            
388             if not self.buffer:
389                 self._fetch()
390                 if not self.buffer:
391                     # EOF
392                     return data
393            
394             newline_pos = self.buffer.find('\n')
395             if size:
396                 if newline_pos == -1:
397                     remaining = size - len(data)
398                     data += self.buffer[:remaining]
399                     self.buffer = self.buffer[remaining:]
400                 else:
401                     remaining = min(size - len(data), newline_pos)
402                     data += self.buffer[:remaining]
403                     self.buffer = self.buffer[remaining:]
404             else:
405                 if newline_pos == -1:
406                     data += self.buffer
407                 else:
408                     data += self.buffer[:newline_pos]
409                     self.buffer = self.buffer[newline_pos:]
410    
411     def readlines(self, sizehint=0):
412         # Shamelessly stolen from StringIO
413         total = 0
414         lines = []
415         line = self.readline(sizehint)
416         while line:
417             lines.append(line)
418             total += len(line)
419             if 0 < sizehint <= total:
420                 break
421             line = self.readline(sizehint)
422         return lines
423    
424     def read_trailer_lines(self):
425         if not self.closed:
426             raise ValueError(
427                 "Cannot read trailers until the request body has been read.")
428        
429         while True:
430             line = self.rfile.readline()
431             if not line:
432                 # No more data--illegal end of headers
433                 raise ValueError("Illegal end of headers.")
434            
435             self.bytes_read += len(line)
436             if self.maxlen and self.bytes_read > self.maxlen:
437                 raise IOError("Request Entity Too Large")
438            
439             if line == CRLF:
440                 # Normal end of headers
441                 break
442             if not line.endswith(CRLF):
443                 raise ValueError("HTTP requires CRLF terminators")
444            
445             yield line
446    
447     def close(self):
448         self.rfile.close()
449    
450     def __iter__(self):
451         # Shamelessly stolen from StringIO
452         total = 0
453         line = self.readline(sizehint)
454         while line:
455             yield line
456             total += len(line)
457             if 0 < sizehint <= total:
458                 break
459             line = self.readline(sizehint)
460
461
462 class HTTPRequest(object):
463     """An HTTP Request (and response).
464     
465     A single HTTP connection may consist of multiple request/response pairs.
466     
467     server: the Server object which is receiving this request.
468     conn: the HTTPConnection object on which this request connected.
469     
470     inheaders: a dict of request headers.
471     outheaders: a list of header tuples to write in the response.
472     ready: when True, the request has been parsed and is ready to begin
473         generating the response. When False, signals the calling Connection
474         that the response should not be generated and the connection should
475         close.
476     close_connection: signals the calling Connection that the request
477         should close. This does not imply an error! The client and/or
478         server may each request that the connection be closed.
479     chunked_write: if True, output will be encoded with the "chunked"
480         transfer-coding. This value is set automatically inside
481         send_headers.
482     """
483    
484     def __init__(self, server, conn):
485         self.server= server
486         self.conn = conn
487        
488         self.ready = False
489         self.started_request = False
490         self.scheme = "http"
491         if self.server.ssl_adapter is not None:
492             self.scheme = "https"
493         self.inheaders = {}
494        
495         self.status = ""
496         self.outheaders = []
497         self.sent_headers = False
498         self.close_connection = False
499         self.chunked_write = False
500    
501     def parse_request(self):
502         """Parse the next HTTP request start-line and message-headers."""
503         self.rfile = SizeCheckWrapper(self.conn.rfile,
504                                       self.server.max_request_header_size)
505         try:
506             self._parse_request()
507         except MaxSizeExceeded:
508             self.simple_response("413 Request Entity Too Large")
509             return
510    
511     def _parse_request(self):
512         # HTTP/1.1 connections are persistent by default. If a client
513         # requests a page, then idles (leaves the connection open),
514         # then rfile.readline() will raise socket.error("timed out").
515         # Note that it does this based on the value given to settimeout(),
516         # and doesn't need the client to request or acknowledge the close
517         # (although your TCP stack might suffer for it: cf Apache's history
518         # with FIN_WAIT_2).
519         request_line = self.rfile.readline()
520        
521         # Set started_request to True so communicate() knows to send 408
522         # from here on out.
523         self.started_request = True
524         if not request_line:
525             # Force self.ready = False so the connection will close.
526             self.ready = False
527             return
528        
529         if request_line == CRLF:
530             # RFC 2616 sec 4.1: "...if the server is reading the protocol
531             # stream at the beginning of a message and receives a CRLF
532             # first, it should ignore the CRLF."
533             # But only ignore one leading line! else we enable a DoS.
534             request_line = self.rfile.readline()
535             if not request_line:
536                 self.ready = False
537                 return
538        
539         if not request_line.endswith(CRLF):
540             self.simple_response(400, "HTTP requires CRLF terminators")
541             return
542        
543         try:
544             method, uri, req_protocol = request_line.strip().split(" ", 2)
545         except ValueError:
546             self.simple_response(400, "Malformed Request-Line")
547             return
548        
549         self.uri = uri
550         self.method = method
551        
552         # uri may be an abs_path (including "http://host.domain.tld");
553         scheme, authority, path = self.parse_request_uri(uri)
554         if '#' in path:
555             self.simple_response("400 Bad Request",
556                                  "Illegal #fragment in Request-URI.")
557             return
558        
559         if scheme:
560             self.scheme = scheme
561        
562         qs = ''
563         if '?' in path:
564             path, qs = path.split('?', 1)
565        
566         # Unquote the path+params (e.g. "/this%20path" -> "/this path").
567         # http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.2
568         #
569         # But note that "...a URI must be separated into its components
570         # before the escaped characters within those components can be
571         # safely decoded." http://www.ietf.org/rfc/rfc2396.txt, sec 2.4.2
572         # Therefore, "/this%2Fpath" becomes "/this%2Fpath", not "/this/path".
573         try:
574             atoms = [unquote(x) for x in quoted_slash.split(path)]
575         except ValueError, ex:
576             self.simple_response("400 Bad Request", ex.args[0])
577             return
578         path = "%2F".join(atoms)
579         self.path = path
580        
581         # Note that, like wsgiref and most other HTTP servers,
582         # we "% HEX HEX"-unquote the path but not the query string.
583         self.qs = qs
584        
585         # Compare request and server HTTP protocol versions, in case our
586         # server does not support the requested protocol. Limit our output
587         # to min(req, server). We want the following output:
588         #     request    server     actual written   supported response
589         #     protocol   protocol  response protocol    feature set
590         # a     1.0        1.0           1.0                1.0
591         # b     1.0        1.1           1.1                1.0
592         # c     1.1        1.0           1.0                1.0
593         # d     1.1        1.1           1.1                1.1
594         # Notice that, in (b), the response will be "HTTP/1.1" even though
595         # the client only understands 1.0. RFC 2616 10.5.6 says we should
596         # only return 505 if the _major_ version is different.
597         rp = int(req_protocol[5]), int(req_protocol[7])
598         sp = int(self.server.protocol[5]), int(self.server.protocol[7])
599        
600         if sp[0] != rp[0]:
601             self.simple_response("505 HTTP Version Not Supported")
602             return
603         self.request_protocol = req_protocol
604         self.response_protocol = "HTTP/%s.%s" % min(rp, sp)
605        
606         # then all the http headers
607         try:
608             read_headers(self.rfile, self.inheaders)
609         except ValueError, ex:
610             self.simple_response("400 Bad Request", ex.args[0])
611             return
612        
613         mrbs = self.server.max_request_body_size
614         if mrbs and int(self.inheaders.get("Content-Length", 0)) > mrbs:
615             self.simple_response("413 Request Entity Too Large")
616             return
617        
618         # Persistent connection support
619         if self.response_protocol == "HTTP/1.1":
620             # Both server and client are HTTP/1.1
621             if self.inheaders.get("Connection", "") == "close":
622                 self.close_connection = True
623         else:
624             # Either the server or client (or both) are HTTP/1.0
625             if self.inheaders.get("Connection", "") != "Keep-Alive":
626                 self.close_connection = True
627        
628         # Transfer-Encoding support
629         te = None
630         if self.response_protocol == "HTTP/1.1":
631             te = self.inheaders.get("Transfer-Encoding")
632             if te:
633                 te = [x.strip().lower() for x in te.split(",") if x.strip()]
634        
635         self.chunked_read = False
636        
637         if te:
638             for enc in te:
639                 if enc == "chunked":
640                     self.chunked_read = True
641                 else:
642                     # Note that, even if we see "chunked", we must reject
643                     # if there is an extension we don't recognize.
644                     self.simple_response("501 Unimplemented")
645                     self.close_connection = True
646                     return
647        
648         # From PEP 333:
649         # "Servers and gateways that implement HTTP 1.1 must provide
650         # transparent support for HTTP 1.1's "expect/continue" mechanism.
651         # This may be done in any of several ways:
652         #   1. Respond to requests containing an Expect: 100-continue request
653         #      with an immediate "100 Continue" response, and proceed normally.
654         #   2. Proceed with the request normally, but provide the application
655         #      with a wsgi.input stream that will send the "100 Continue"
656         #      response if/when the application first attempts to read from
657         #      the input stream. The read request must then remain blocked
658         #      until the client responds.
659         #   3. Wait until the client decides that the server does not support
660         #      expect/continue, and sends the request body on its own.
661         #      (This is suboptimal, and is not recommended.)
662         #
663         # We used to do 3, but are now doing 1. Maybe we'll do 2 someday,
664         # but it seems like it would be a big slowdown for such a rare case.
665         if self.inheaders.get("Expect", "") == "100-continue":
666             # Don't use simple_response here, because it emits headers
667             # we don't want. See http://www.cherrypy.org/ticket/951
668             msg = self.server.protocol + " 100 Continue\r\n\r\n"
669             try:
670                 self.conn.wfile.sendall(msg)
671             except socket.error, x:
672                 if x.args[0] not in socket_errors_to_ignore:
673                     raise
674        
675         self.ready = True
676    
677     def parse_request_uri(self, uri):
678         """Parse a Request-URI into (scheme, authority, path).
679         
680         Note that Request-URI's must be one of:
681             
682             Request-URI    = "*" | absoluteURI | abs_path | authority
683         
684         Therefore, a Request-URI which starts with a double forward-slash
685         cannot be a "net_path":
686         
687             net_path      = "//" authority [ abs_path ]
688         
689         Instead, it must be interpreted as an "abs_path" with an empty first
690         path segment:
691         
692             abs_path      = "/"  path_segments
693             path_segments = segment *( "/" segment )
694             segment       = *pchar *( ";" param )
695             param         = *pchar
696         """
697         if uri == "*":
698             return None, None, uri
699        
700         i = uri.find('://')
701         if i > 0 and '?' not in uri[:i]:
702             # An absoluteURI.
703             # If there's a scheme (and it must be http or https), then:
704             # http_URL = "http:" "//" host [ ":" port ] [ abs_path [ "?" query ]]
705             scheme, remainder = uri[:i].lower(), uri[i + 3:]
706             authority, path = remainder.split("/", 1)
707             return scheme, authority, path
708        
709         if uri.startswith('/'):
710             # An abs_path.
711             return None, None, uri
712         else:
713             # An authority.
714             return None, uri, None
715    
716     def respond(self):
717         """Call the gateway and write its iterable output."""
718         mrbs = self.server.max_request_body_size
719         if self.chunked_read:
720             self.rfile = ChunkedRFile(self.conn.rfile, mrbs)
721         else:
722             cl = int(self.inheaders.get("Content-Length", 0))
723             if mrbs and mrbs < cl:
724                 if not self.sent_headers:
725                     self.simple_response("413 Request Entity Too Large")
726                 return
727             self.rfile = KnownLengthRFile(self.conn.rfile, cl)
728        
729         self.server.gateway(self).respond()
730        
731         if (self.ready and not self.sent_headers):
732             self.sent_headers = True
733             self.send_headers()
734         if self.chunked_write:
735             self.conn.wfile.sendall("0\r\n\r\n")
736    
737     def simple_response(self, status, msg=""):
738         """Write a simple response back to the client."""
739         status = str(status)
740         buf = [self.server.protocol + " " +
741                status + CRLF,
742                "Content-Length: %s\r\n" % len(msg),
743                "Content-Type: text/plain\r\n"]
744        
745         if status[:3] == "413" and self.response_protocol == 'HTTP/1.1':
746             # Request Entity Too Large
747             self.close_connection = True
748             buf.append("Connection: close\r\n")
749        
750         buf.append(CRLF)
751         if msg:
752             if isinstance(msg, unicode):
753                 msg = msg.encode("ISO-8859-1")
754             buf.append(msg)
755        
756         try:
757             self.conn.wfile.sendall("".join(buf))
758         except socket.error, x:
759             if x.args[0] not in socket_errors_to_ignore:
760                 raise
761    
762     def write(self, chunk):
763         """Write unbuffered data to the client."""
764         if self.chunked_write and chunk:
765             buf = [hex(len(chunk))[2:], CRLF, chunk, CRLF]
766             self.conn.wfile.sendall("".join(buf))
767         else:
768             self.conn.wfile.sendall(chunk)
769    
770     def send_headers(self):
771         """Assert, process, and send the HTTP response message-headers.
772         
773         You must set self.status, and self.outheaders before calling this.
774         """
775         hkeys = [key.lower() for key, value in self.outheaders]
776         status = int(self.status[:3])
777        
778         if status == 413:
779             # Request Entity Too Large. Close conn to avoid garbage.
780             self.close_connection = True
781         elif "content-length" not in hkeys:
782             # "All 1xx (informational), 204 (no content),
783             # and 304 (not modified) responses MUST NOT
784             # include a message-body." So no point chunking.
785             if status < 200 or status in (204, 205, 304):
786                 pass
787             else:
788                 if (self.response_protocol == 'HTTP/1.1'
789                     and self.method != 'HEAD'):
790                     # Use the chunked transfer-coding
791                     self.chunked_write = True
792                     self.outheaders.append(("Transfer-Encoding", "chunked"))
793                 else:
794                     # Closing the conn is the only way to determine len.
795                     self.close_connection = True
796        
797         if "connection" not in hkeys:
798             if self.response_protocol == 'HTTP/1.1':
799                 # Both server and client are HTTP/1.1 or better
800                 if self.close_connection:
801                     self.outheaders.append(("Connection", "close"))
802             else:
803                 # Server and/or client are HTTP/1.0
804                 if not self.close_connection:
805                     self.outheaders.append(("Connection", "Keep-Alive"))
806        
807         if (not self.close_connection) and (not self.chunked_read):
808             # Read any remaining request body data on the socket.
809             # "If an origin server receives a request that does not include an
810             # Expect request-header field with the "100-continue" expectation,
811             # the request includes a request body, and the server responds
812             # with a final status code before reading the entire request body
813             # from the transport connection, then the server SHOULD NOT close
814             # the transport connection until it has read the entire request,
815             # or until the client closes the connection. Otherwise, the client
816             # might not reliably receive the response message. However, this
817             # requirement is not be construed as preventing a server from
818             # defending itself against denial-of-service attacks, or from
819             # badly broken client implementations."
820             remaining = getattr(self.rfile, 'remaining', 0)
821             if remaining > 0:
822                 self.rfile.read(remaining)
823        
824         if "date" not in hkeys:
825             self.outheaders.append(("Date", rfc822.formatdate()))
826        
827         if "server" not in hkeys:
828             self.outheaders.append(("Server", self.server.server_name))
829        
830         buf = [self.server.protocol + " " + self.status + CRLF]
831         for k, v in self.outheaders:
832             buf.append(k + ": " + v + CRLF)
833         buf.append(CRLF)
834         self.conn.wfile.sendall("".join(buf))
835
836
837 class NoSSLError(Exception):
838     """Exception raised when a client speaks HTTP to an HTTPS socket."""
839     pass
840
841
842 class FatalSSLAlert(Exception):
843     """Exception raised when the SSL implementation signals a fatal alert."""
844     pass
845
846
847 if not _fileobject_uses_str_type:
848     class CP_fileobject(socket._fileobject):
849         """Faux file object attached to a socket object."""
850
851         def sendall(self, data):
852             """Sendall for non-blocking sockets."""
853             while data:
854                 try:
855                     bytes_sent = self.send(data)
856                     data = data[bytes_sent:]
857                 except socket.error, e:
858                     if e.args[0] not in socket_errors_nonblocking:
859                         raise
860
861         def send(self, data):
862             return self._sock.send(data)
863
864         def flush(self):
865             if self._wbuf:
866                 buffer = "".join(self._wbuf)
867                 self._wbuf = []
868                 self.sendall(buffer)
869
870         def recv(self, size):
871             while True:
872                 try:
873                     return self._sock.recv(size)
874                 except socket.error, e:
875                     if (e.args[0] not in socket_errors_nonblocking
876                         and e.args[0] not in socket_error_eintr):
877                         raise
878
879         def read(self, size=-1):
880             # Use max, disallow tiny reads in a loop as they are very inefficient.
881             # We never leave read() with any leftover data from a new recv() call
882             # in our internal buffer.
883             rbufsize = max(self._rbufsize, self.default_bufsize)
884             # Our use of StringIO rather than lists of string objects returned by
885             # recv() minimizes memory usage and fragmentation that occurs when
886             # rbufsize is large compared to the typical return value of recv().
887             buf = self._rbuf
888             buf.seek(0, 2)  # seek end
889             if size < 0:
890                 # Read until EOF
891                 self._rbuf = StringIO.StringIO()  # reset _rbuf.  we consume it via buf.
892                 while True:
893                     data = self.recv(rbufsize)
894                     if not data:
895                         break
896                     buf.write(data)
897                 return buf.getvalue()
898             else:
899                 # Read until size bytes or EOF seen, whichever comes first
900                 buf_len = buf.tell()
901                 if buf_len >= size:
902                     # Already have size bytes in our buffer?  Extract and return.
903                     buf.seek(0)
904                     rv = buf.read(size)
905                     self._rbuf = StringIO.StringIO()
906                     self._rbuf.write(buf.read())
907                     return rv
908
909                 self._rbuf = StringIO.StringIO()  # reset _rbuf.  we consume it via buf.
910                 while True:
911                     left = size - buf_len
912                     # recv() will malloc the amount of memory given as its
913                     # parameter even though it often returns much less data
914                     # than that.  The returned data string is short lived
915                     # as we copy it into a StringIO and free it.  This avoids
916                     # fragmentation issues on many platforms.
917                     data = self.recv(left)
918                     if not data:
919                         break
920                     n = len(data)
921                     if n == size and not buf_len:
922                         # Shortcut.  Avoid buffer data copies when:
923                         # - We have no data in our buffer.
924                         # AND
925                         # - Our call to recv returned exactly the
926                         #   number of bytes we were asked to read.
927                         return data
928                     if n == left:
929                         buf.write(data)
930                         del data  # explicit free
931                         break
932                     assert n <= left, "recv(%d) returned %d bytes" % (left, n)
933                     buf.write(data)
934                     buf_len += n
935                     del data  # explicit free
936                     #assert buf_len == buf.tell()
937                 return buf.getvalue()
938
939         def readline(self, size=-1):
940             buf = self._rbuf
941             buf.seek(0, 2)  # seek end
942             if buf.tell() > 0:
943                 # check if we already have it in our buffer
944                 buf.seek(0)
945                 bline = buf.readline(size)
946                 if bline.endswith('\n') or len(bline) == size:
947                     self._rbuf = StringIO.StringIO()
948                     self._rbuf.write(buf.read())
949                     return bline
950                 del bline
951             if size < 0:
952                 # Read until \n or EOF, whichever comes first
953                 if self._rbufsize <= 1:
954                     # Speed up unbuffered case
955                     buf.seek(0)
956                     buffers = [buf.read()]
957                     self._rbuf = StringIO.StringIO()  # reset _rbuf.  we consume it via buf.
958                     data = None
959                     recv = self.recv
960                     while data != "\n":
961                         data = recv(1)
962                         if not data:
963                             break
964                         buffers.append(data)
965                     return "".join(buffers)
966
967                 buf.seek(0, 2)  # seek end
968                 self._rbuf = StringIO.StringIO()  # reset _rbuf.  we consume it via buf.
969                 while True:
970                     data = self.recv(self._rbufsize)
971                     if not data:
972                         break
973                     nl = data.find('\n')
974                     if nl >= 0:
975                         nl += 1
976                         buf.write(data[:nl])
977                         self._rbuf.write(data[nl:])
978                         del data
979                         break
980                     buf.write(data)
981                 return buf.getvalue()
982             else:
983                 # Read until size bytes or \n or EOF seen, whichever comes first
984                 buf.seek(0, 2)  # seek end
985                 buf_len = buf.tell()
986                 if buf_len >= size:
987                     buf.seek(0)
988                     rv = buf.read(size)
989                     self._rbuf = StringIO.StringIO()
990                     self._rbuf.write(buf.read())
991                     return rv
992                 self._rbuf = StringIO.StringIO()  # reset _rbuf.  we consume it via buf.
993                 while True:
994                     data = self.recv(self._rbufsize)
995                     if not data:
996                         break
997                     left = size - buf_len
998                     # did we just receive a newline?
999                     nl = data.find('\n', 0, left)
1000                     if nl >= 0:
1001                         nl += 1
1002                         # save the excess data to _rbuf
1003                         self._rbuf.write(data[nl:])
1004                         if buf_len:
1005                             buf.write(data[:nl])
1006                             break
1007                         else:
1008                             # Shortcut.  Avoid data copy through buf when returning
1009                             # a substring of our first recv().
1010                             return data[:nl]
1011                     n = len(data)
1012                     if n == size and not buf_len:
1013                         # Shortcut.  Avoid data copy through buf when
1014                         # returning exactly all of our first recv().
1015                         return data
1016                     if n >= left:
1017                         buf.write(data[:left])
1018                         self._rbuf.write(data[left:])
1019                         break
1020                     buf.write(data)
1021                     buf_len += n
1022                     #assert buf_len == buf.tell()
1023                 return buf.getvalue()
1024
1025 else:
1026     class CP_fileobject(socket._fileobject):
1027         """Faux file object attached to a socket object."""
1028
1029         def sendall(self, data):
1030             """Sendall for non-blocking sockets."""
1031             while data:
1032                 try:
1033                     bytes_sent = self.send(data)
1034                     data = data[bytes_sent:]
1035                 except socket.error, e:
1036                     if e.args[0] not in socket_errors_nonblocking:
1037                         raise
1038
1039         def send(self, data):
1040             return self._sock.send(data)
1041
1042         def flush(self):
1043             if self._wbuf:
1044                 buffer = "".join(self._wbuf)
1045                 self._wbuf = []
1046                 self.sendall(buffer)
1047
1048         def recv(self, size):
1049             while True:
1050                 try:
1051                     return self._sock.recv(size)
1052                 except socket.error, e:
1053                     if (e.args[0] not in socket_errors_nonblocking
1054                         and e.args[0] not in socket_error_eintr):
1055                         raise
1056
1057         def read(self, size=-1):
1058             if size < 0:
1059                 # Read until EOF
1060                 buffers = [self._rbuf]
1061                 self._rbuf = ""
1062                 if self._rbufsize <= 1:
1063                     recv_size = self.default_bufsize
1064                 else:
1065                     recv_size = self._rbufsize
1066
1067                 while True:
1068                     data = self.recv(recv_size)
1069                     if not data:
1070                         break
1071                     buffers.append(data)
1072                 return "".join(buffers)
1073             else:
1074                 # Read until size bytes or EOF seen, whichever comes first
1075                 data = self._rbuf
1076                 buf_len = len(data)
1077                 if buf_len >= size:
1078                     self._rbuf = data[size:]
1079                     return data[:size]
1080                 buffers = []
1081                 if data:
1082                     buffers.append(data)
1083                 self._rbuf = ""
1084                 while True:
1085                     left = size - buf_len
1086                     recv_size = max(self._rbufsize, left)
1087                     data = self.recv(recv_size)
1088                     if not data:
1089                         break
1090                     buffers.append(data)
1091                     n = len(data)
1092                     if n >= left:
1093                         self._rbuf = data[left:]
1094                         buffers[-1] = data[:left]
1095                         break
1096                     buf_len += n
1097                 return "".join(buffers)
1098
1099         def readline(self, size=-1):
1100             data = self._rbuf
1101             if size < 0:
1102                 # Read until \n or EOF, whichever comes first
1103                 if self._rbufsize <= 1:
1104                     # Speed up unbuffered case
1105                     assert data == ""
1106                     buffers = []
1107                     while data != "\n":
1108                         data = self.recv(1)
1109                         if not data:
1110                             break
1111                         buffers.append(data)
1112                     return "".join(buffers)
1113                 nl = data.find('\n')
1114                 if nl >= 0:
1115                     nl += 1
1116                     self._rbuf = data[nl:]
1117                     return data[:nl]
1118                 buffers = []
1119                 if data:
1120                     buffers.append(data)
1121                 self._rbuf = ""
1122                 while True:
1123                     data = self.recv(self._rbufsize)
1124                     if not data:
1125                         break
1126                     buffers.append(data)
1127                     nl = data.find('\n')
1128                     if nl >= 0:
1129                         nl += 1
1130                         self._rbuf = data[nl:]
1131                         buffers[-1] = data[:nl]
1132                         break
1133                 return "".join(buffers)
1134             else:
1135                 # Read until size bytes or \n or EOF seen, whichever comes first
1136                 nl = data.find('\n', 0, size)
1137                 if nl >= 0:
1138                     nl += 1
1139                     self._rbuf = data[nl:]
1140                     return data[:nl]
1141                 buf_len = len(data)
1142                 if buf_len >= size:
1143                     self._rbuf = data[size:]
1144                     return data[:size]
1145                 buffers = []
1146                 if data:
1147                     buffers.append(data)
1148                 self._rbuf = ""
1149                 while True:
1150                     data = self.recv(self._rbufsize)
1151                     if not data:
1152                         break
1153                     buffers.append(data)
1154                     left = size - buf_len
1155                     nl = data.find('\n', 0, left)
1156                     if nl >= 0:
1157                         nl += 1
1158                         self._rbuf = data[nl:]
1159                         buffers[-1] = data[:nl]
1160                         break
1161                     n = len(data)
1162                     if n >= left:
1163                         self._rbuf = data[left:]
1164                         buffers[-1] = data[:left]
1165                         break
1166                     buf_len += n
1167                 return "".join(buffers)
1168
1169
1170 class HTTPConnection(object):
1171     """An HTTP connection (active socket).
1172     
1173     server: the Server object which received this connection.
1174     socket: the raw socket object (usually TCP) for this connection.
1175     makefile: a fileobject class for reading from the socket.
1176     """
1177    
1178     remote_addr = None
1179     remote_port = None
1180     ssl_env = None
1181     rbufsize = -1
1182     RequestHandlerClass = HTTPRequest
1183    
1184     def __init__(self, server, sock, makefile=CP_fileobject):
1185         self.server = server
1186         self.socket = sock
1187         self.rfile = makefile(sock, "rb", self.rbufsize)
1188         self.wfile = makefile(sock, "wb", -1)
1189    
1190     def communicate(self):
1191         """Read each request and respond appropriately."""
1192         request_seen = False
1193         try:
1194             while True:
1195                 # (re)set req to None so that if something goes wrong in
1196                 # the RequestHandlerClass constructor, the error doesn't
1197                 # get written to the previous request.
1198                 req = None
1199                 req = self.RequestHandlerClass(self.server, self)
1200                
1201                 # This order of operations should guarantee correct pipelining.
1202                 req.parse_request()
1203                 if not req.ready:
1204                     # Something went wrong in the parsing (and the server has
1205                     # probably already made a simple_response). Return and
1206                     # let the conn close.
1207                     return
1208                
1209                 request_seen = True
1210                 req.respond()
1211                 if req.close_connection:
1212                     return
1213         except socket.error, e:
1214             errnum = e.args[0]
1215             if errnum == 'timed out':
1216                 # Don't error if we're between requests; only error
1217                 # if 1) no request has been started at all, or 2) we're
1218                 # in the middle of a request.
1219                 # See http://www.cherrypy.org/ticket/853
1220                 if (not request_seen) or (req and req.started_request):
1221                     # Don't bother writing the 408 if the response
1222                     # has already started being written.
1223                     if req and not req.sent_headers:
1224                         try:
1225                             req.simple_response("408 Request Timeout")
1226                         except FatalSSLAlert:
1227                             # Close the connection.
1228                             return
1229             elif errnum not in socket_errors_to_ignore:
1230                 if req and not req.sent_headers:
1231                     try:
1232                         req.simple_response("500 Internal Server Error",
1233                                             format_exc())
1234                     except FatalSSLAlert:
1235                         # Close the connection.
1236                         return
1237             return
1238         except (KeyboardInterrupt, SystemExit):
1239             raise
1240         except FatalSSLAlert:
1241             # Close the connection.
1242             return
1243         except NoSSLError:
1244             if req and not req.sent_headers:
1245                 # Unwrap our wfile
1246                 self.wfile = CP_fileobject(self.socket._sock, "wb", -1)
1247                 req.simple_response("400 Bad Request",
1248                     "The client sent a plain HTTP request, but "
1249                     "this server only speaks HTTPS on this port.")
1250                 self.linger = True
1251         except Exception:
1252             if req and not req.sent_headers:
1253                 try:
1254                     req.simple_response("500 Internal Server Error", format_exc())
1255                 except FatalSSLAlert:
1256                     # Close the connection.
1257                     return
1258    
1259     linger = False
1260    
1261     def close(self):
1262         """Close the socket underlying this connection."""
1263         self.rfile.close()
1264        
1265         if not self.linger:
1266             # Python's socket module does NOT call close on the kernel socket
1267             # when you call socket.close(). We do so manually here because we
1268             # want this server to send a FIN TCP segment immediately. Note this
1269             # must be called *before* calling socket.close(), because the latter
1270             # drops its reference to the kernel socket.
1271             if hasattr(self.socket, '_sock'):
1272                 self.socket._sock.close()
1273             self.socket.close()
1274         else:
1275             # On the other hand, sometimes we want to hang around for a bit
1276             # to make sure the client has a chance to read our entire
1277             # response. Skipping the close() calls here delays the FIN
1278             # packet until the socket object is garbage-collected later.
1279             # Someday, perhaps, we'll do the full lingering_close that
1280             # Apache does, but not today.
1281             pass
1282
1283
1284 def format_exc(limit=None):
1285     """Like print_exc() but return a string. Backport for Python 2.3."""
1286     try:
1287         etype, value, tb = sys.exc_info()
1288         return ''.join(traceback.format_exception(etype, value, tb, limit))
1289     finally:
1290         etype = value = tb = None
1291
1292
1293 _SHUTDOWNREQUEST = None
1294
1295 class WorkerThread(threading.Thread):
1296     """Thread which continuously polls a Queue for Connection objects.
1297     
1298     server: the HTTP Server which spawned this thread, and which owns the
1299         Queue and is placing active connections into it.
1300     ready: a simple flag for the calling server to know when this thread
1301         has begun polling the Queue.
1302     
1303     Due to the timing issues of polling a Queue, a WorkerThread does not
1304     check its own 'ready' flag after it has started. To stop the thread,
1305     it is necessary to stick a _SHUTDOWNREQUEST object onto the Queue
1306     (one for each running WorkerThread).
1307     """
1308    
1309     conn = None
1310    
1311     def __init__(self, server):
1312         self.ready = False
1313         self.server = server
1314         threading.Thread.__init__(self)
1315    
1316     def run(self):
1317         try:
1318             self.ready = True
1319             while True:
1320                 conn = self.server.requests.get()
1321                 if conn is _SHUTDOWNREQUEST:
1322                     return
1323                
1324                 self.conn = conn
1325                 try:
1326                     conn.communicate()
1327                 finally:
1328                     conn.close()
1329                     self.conn = None
1330         except (KeyboardInterrupt, SystemExit), exc:
1331             self.server.interrupt = exc
1332
1333
1334 class ThreadPool(object):
1335     """A Request Queue for the CherryPyWSGIServer which pools threads.
1336     
1337     ThreadPool objects must provide min, get(), put(obj), start()
1338     and stop(timeout) attributes.
1339     """
1340    
1341     def __init__(self, server, min=10, max=-1):
1342         self.server = server
1343         self.min = min
1344         self.max = max
1345         self._threads = []
1346         self._queue = Queue.Queue()
1347         self.get = self._queue.get
1348    
1349     def start(self):
1350         """Start the pool of threads."""
1351         for i in range(self.min):
1352             self._threads.append(WorkerThread(self.server))
1353         for worker in self._threads:
1354             worker.setName("CP Server " + worker.getName())
1355             worker.start()
1356         for worker in self._threads:
1357             while not worker.ready:
1358                 time.sleep(.1)
1359    
1360     def _get_idle(self):
1361         """Number of worker threads which are idle. Read-only."""
1362         return len([t for t in self._threads if t.conn is None])
1363     idle = property(_get_idle, doc=_get_idle.__doc__)
1364    
1365     def put(self, obj):
1366         self._queue.put(obj)
1367         if obj is _SHUTDOWNREQUEST:
1368             return
1369    
1370     def grow(self, amount):
1371         """Spawn new worker threads (not above self.max)."""
1372         for i in range(amount):
1373             if self.max > 0 and len(self._threads) >= self.max:
1374                 break
1375             worker = WorkerThread(self.server)
1376             worker.setName("CP Server " + worker.getName())
1377             self._threads.append(worker)
1378             worker.start()
1379    
1380     def shrink(self, amount):
1381         """Kill off worker threads (not below self.min)."""
1382         # Grow/shrink the pool if necessary.
1383         # Remove any dead threads from our list
1384         for t in self._threads:
1385             if not t.isAlive():
1386                 self._threads.remove(t)
1387                 amount -= 1
1388        
1389         if amount > 0:
1390             for i in range(min(amount, len(self._threads) - self.min)):
1391                 # Put a number of shutdown requests on the queue equal
1392                 # to 'amount'. Once each of those is processed by a worker,
1393                 # that worker will terminate and be culled from our list
1394                 # in self.put.
1395                 self._queue.put(_SHUTDOWNREQUEST)
1396    
1397     def stop(self, timeout=5):
1398         # Must shut down threads here so the code that calls
1399         # this method can know when all threads are stopped.
1400         for worker in self._threads:
1401             self._queue.put(_SHUTDOWNREQUEST)
1402        
1403         # Don't join currentThread (when stop is called inside a request).
1404         current = threading.currentThread()
1405         if timeout and timeout >= 0:
1406             endtime = time.time() + timeout
1407         while self._threads:
1408             worker = self._threads.pop()
1409             if worker is not current and worker.isAlive():
1410                 try:
1411                     if timeout is None or timeout < 0:
1412                         worker.join()
1413                     else:
1414                         remaining_time = endtime - time.time()
1415                         if remaining_time > 0:
1416                             worker.join(remaining_time)
1417                         if worker.isAlive():
1418                             # We exhausted the timeout.
1419                             # Forcibly shut down the socket.
1420                             c = worker.conn
1421                             if c and not c.rfile.closed:
1422                                 try:
1423                                     c.socket.shutdown(socket.SHUT_RD)
1424                                 except TypeError:
1425                                     # pyOpenSSL sockets don't take an arg
1426                                     c.socket.shutdown()
1427                             worker.join()
1428                 except (AssertionError,
1429                         # Ignore repeated Ctrl-C.
1430                         # See http://www.cherrypy.org/ticket/691.
1431                         KeyboardInterrupt), exc1:
1432                     pass
1433
1434
1435
1436 try:
1437     import fcntl
1438 except ImportError:
1439     try:
1440         from ctypes import windll, WinError
1441     except ImportError:
1442         def prevent_socket_inheritance(sock):
1443             """Dummy function, since neither fcntl nor ctypes are available."""
1444             pass
1445     else:
1446         def prevent_socket_inheritance(sock):
1447             """Mark the given socket fd as non-inheritable (Windows)."""
1448             if not windll.kernel32.SetHandleInformation(sock.fileno(), 1, 0):
1449                 raise WinError()
1450 else:
1451     def prevent_socket_inheritance(sock):
1452         """Mark the given socket fd as non-inheritable (POSIX)."""
1453         fd = sock.fileno()
1454         old_flags = fcntl.fcntl(fd, fcntl.F_GETFD)
1455         fcntl.fcntl(fd, fcntl.F_SETFD, old_flags | fcntl.FD_CLOEXEC)
1456
1457
1458 class SSLAdapter(object):
1459    
1460     def __init__(self, certificate, private_key, certificate_chain=None):
1461         self.certificate = certificate
1462         self.private_key = private_key
1463         self.certificate_chain = certificate_chain
1464    
1465     def wrap(self, sock):
1466         raise NotImplemented
1467    
1468     def makefile(self, sock, mode='r', bufsize=-1):
1469         raise NotImplemented
1470
1471
1472 class HTTPServer(object):
1473     """An HTTP server.
1474     
1475     bind_addr: The interface on which to listen for connections.
1476         For TCP sockets, a (host, port) tuple. Host values may be any IPv4
1477         or IPv6 address, or any valid hostname. The string 'localhost' is a
1478         synonym for '127.0.0.1' (or '::1', if your hosts file prefers IPv6).
1479         The string '0.0.0.0' is a special IPv4 entry meaning "any active
1480         interface" (INADDR_ANY), and '::' is the similar IN6ADDR_ANY for
1481         IPv6. The empty string or None are not allowed.
1482         
1483         For UNIX sockets, supply the filename as a string.
1484     gateway: a Gateway instance.
1485     minthreads: the minimum number of worker threads to create (default 10).
1486     maxthreads: the maximum number of worker threads to create (default -1 = no limit).
1487     server_name: defaults to socket.gethostname().
1488     
1489     request_queue_size: the 'backlog' argument to socket.listen();
1490         specifies the maximum number of queued connections (default 5).
1491     timeout: the timeout in seconds for accepted connections (default 10).
1492     nodelay: if True (the default since 3.1), sets the TCP_NODELAY socket
1493         option.
1494     protocol: the version string to write in the Status-Line of all
1495         HTTP responses. For example, "HTTP/1.1" (the default). This
1496         also limits the supported features used in the response.
1497     
1498     
1499     SSL/HTTPS
1500     ---------
1501     You must have an ssl library installed and set self.ssl_adapter to an
1502     instance of SSLAdapter (or a subclass) which provides the methods:
1503         wrap(sock) -> wrapped socket, ssl environ dict
1504         makefile(sock, mode='r', bufsize=-1) -> socket file object
1505     """
1506    
1507     protocol = "HTTP/1.1"
1508     _bind_addr = "127.0.0.1"
1509     version = "CherryPy/3.2.0rc1"
1510     response_header = None
1511     ready = False
1512     _interrupt = None
1513     max_request_header_size = 0
1514     max_request_body_size = 0
1515     nodelay = True
1516    
1517     ConnectionClass = HTTPConnection
1518    
1519     ssl_adapter = None
1520    
1521     def __init__(self, bind_addr, gateway, minthreads=10, maxthreads=-1,
1522                  server_name=None):
1523         self.bind_addr = bind_addr
1524         self.gateway = gateway
1525        
1526         self.requests = ThreadPool(self, min=minthreads or 1, max=maxthreads)
1527        
1528         if not server_name:
1529             server_name = socket.gethostname()
1530         self.server_name = server_name
1531    
1532     def __str__(self):
1533         return "%s.%s(%r)" % (self.__module__, self.__class__.__name__,
1534                               self.bind_addr)
1535    
1536     def _get_bind_addr(self):
1537         return self._bind_addr
1538     def _set_bind_addr(self, value):
1539         if isinstance(value, tuple) and value[0] in ('', None):
1540             # Despite the socket module docs, using '' does not
1541             # allow AI_PASSIVE to work. Passing None instead
1542             # returns '0.0.0.0' like we want. In other words:
1543             #     host    AI_PASSIVE     result
1544             #      ''         Y         192.168.x.y
1545             #      ''         N         192.168.x.y
1546             #     None        Y         0.0.0.0
1547             #     None        N         127.0.0.1
1548             # But since you can get the same effect with an explicit
1549             # '0.0.0.0', we deny both the empty string and None as values.
1550             raise ValueError("Host values of '' or None are not allowed. "
1551                              "Use '0.0.0.0' (IPv4) or '::' (IPv6) instead "
1552                              "to listen on all active interfaces.")
1553         self._bind_addr = value
1554     bind_addr = property(_get_bind_addr, _set_bind_addr,
1555         doc="""The interface on which to listen for connections.
1556         
1557         For TCP sockets, a (host, port) tuple. Host values may be any IPv4
1558         or IPv6 address, or any valid hostname. The string 'localhost' is a
1559         synonym for '127.0.0.1' (or '::1', if your hosts file prefers IPv6).
1560         The string '0.0.0.0' is a special IPv4 entry meaning "any active
1561         interface" (INADDR_ANY), and '::' is the similar IN6ADDR_ANY for
1562         IPv6. The empty string or None are not allowed.
1563         
1564         For UNIX sockets, supply the filename as a string.""")
1565    
1566     def start(self):
1567         """Run the server forever."""
1568         # We don't have to trap KeyboardInterrupt or SystemExit here,
1569         # because cherrpy.server already does so, calling self.stop() for us.
1570         # If you're using this server with another framework, you should
1571         # trap those exceptions in whatever code block calls start().
1572         self._interrupt = None
1573        
1574         # SSL backward compatibility
1575         if (self.ssl_adapter is None and
1576             getattr(self, 'ssl_certificate', None) and
1577             getattr(self, 'ssl_private_key', None)):
1578             warnings.warn(
1579                     "SSL attributes are deprecated in CherryPy 3.2, and will "
1580                     "be removed in CherryPy 3.3. Use an ssl_adapter attribute "
1581                     "instead.",
1582                     DeprecationWarning
1583                 )
1584             try:
1585                 from cherrypy.wsgiserver.ssl_pyopenssl import pyOpenSSLAdapter
1586             except ImportError:
1587                 pass
1588             else:
1589                 self.ssl_adapter = pyOpenSSLAdapter(
1590                     self.ssl_certificate, self.ssl_private_key,
1591                     getattr(self, 'ssl_certificate_chain', None))
1592        
1593         # Select the appropriate socket
1594         if isinstance(self.bind_addr, basestring):
1595             # AF_UNIX socket
1596            
1597             # So we can reuse the socket...
1598             try: os.unlink(self.bind_addr)
1599             except: pass
1600            
1601             # So everyone can access the socket...
1602             try: os.chmod(self.bind_addr, 0777)
1603             except: pass
1604            
1605             info = [(socket.AF_UNIX, socket.SOCK_STREAM, 0, "", self.bind_addr)]
1606         else:
1607             # AF_INET or AF_INET6 socket
1608             # Get the correct address family for our host (allows IPv6 addresses)
1609             host, port = self.bind_addr
1610             try:
1611                 info = socket.getaddrinfo(host, port, socket.AF_UNSPEC,
1612                                           socket.SOCK_STREAM, 0, socket.AI_PASSIVE)
1613             except socket.gaierror:
1614                 if ':' in self.bind_addr[0]:
1615                     info = [(socket.AF_INET6, socket.SOCK_STREAM,
1616                              0, "", self.bind_addr + (0, 0))]
1617                 else:
1618                     info = [(socket.AF_INET, socket.SOCK_STREAM,
1619                              0, "", self.bind_addr)]
1620        
1621         self.socket = None
1622         msg = "No socket could be created"
1623         for res in info:
1624             af, socktype, proto, canonname, sa = res
1625             try:
1626                 self.bind(af, socktype, proto)
1627             except socket.error, msg:
1628                 if self.socket:
1629                     self.socket.close()
1630                 self.socket = None
1631                 continue
1632             break
1633         if not self.socket:
1634             raise socket.error(msg)
1635        
1636         # Timeout so KeyboardInterrupt can be caught on Win32
1637         self.socket.settimeout(1)
1638         self.socket.listen(self.request_queue_size)
1639        
1640         # Create worker threads
1641         self.requests.start()
1642        
1643         self.ready = True
1644         while self.ready:
1645             self.tick()
1646             if self.interrupt:
1647                 while self.interrupt is True:
1648                     # Wait for self.stop() to complete. See _set_interrupt.
1649                     time.sleep(0.1)
1650                 if self.interrupt:
1651                     raise self.interrupt
1652    
1653     def bind(self, family, type, proto=0):
1654         """Create (or recreate) the actual socket object."""
1655         self.socket = socket.socket(family, type, proto)
1656         prevent_socket_inheritance(self.socket)
1657         self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
1658         if self.nodelay and not isinstance(self.bind_addr, str):
1659             self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
1660        
1661         if self.ssl_adapter is not None:
1662             self.socket = self.ssl_adapter.bind(self.socket)
1663        
1664         # If listening on the IPV6 any address ('::' = IN6ADDR_ANY),
1665         # activate dual-stack. See http://www.cherrypy.org/ticket/871.
1666         if (family == socket.AF_INET6
1667             and self.bind_addr[0] in ('::', '::0', '::0.0.0.0')):
1668             try:
1669                 self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0)
1670             except (AttributeError, socket.error):
1671                 # Apparently, the socket option is not available in
1672                 # this machine's TCP stack
1673                 pass
1674        
1675         self.socket.bind(self.bind_addr)
1676    
1677     def tick(self):
1678         """Accept a new connection and put it on the Queue."""
1679         try:
1680             s, addr = self.socket.accept()
1681             if not self.ready:
1682                 return
1683            
1684             prevent_socket_inheritance(s)
1685             if hasattr(s, 'settimeout'):
1686                 s.settimeout(self.timeout)
1687            
1688             if self.response_header is None:
1689                 self.response_header = "%s Server" % self.version
1690            
1691             makefile = CP_fileobject
1692             ssl_env = {}
1693             # if ssl cert and key are set, we try to be a secure HTTP server
1694             if self.ssl_adapter is not None:
1695                 try:
1696                     s, ssl_env = self.ssl_adapter.wrap(s)
1697                 except NoSSLError:
1698                     msg = ("The client sent a plain HTTP request, but "
1699                            "this server only speaks HTTPS on this port.")
1700                     buf = ["%s 400 Bad Request\r\n" % self.protocol,
1701                            "Content-Length: %s\r\n" % len(msg),
1702                            "Content-Type: text/plain\r\n\r\n",
1703                            msg]
1704                    
1705                     wfile = CP_fileobject(s, "wb", -1)
1706                     try:
1707                         wfile.sendall("".join(buf))
1708                     except socket.error, x:
1709                         if x.args[0] not in socket_errors_to_ignore:
1710                             raise
1711                     return
1712                 if not s:
1713                     return
1714                 makefile = self.ssl_adapter.makefile
1715            
1716             conn = self.ConnectionClass(self, s, makefile)
1717            
1718             if not isinstance(self.bind_addr, basestring):
1719                 # optional values
1720                 # Until we do DNS lookups, omit REMOTE_HOST
1721                 if addr is None: # sometimes this can happen
1722                     # figure out if AF_INET or AF_INET6.
1723                     if len(s.getsockname()) == 2:
1724                         # AF_INET
1725                         addr = ('0.0.0.0', 0)
1726                     else:
1727                         # AF_INET6
1728                         addr = ('::', 0)
1729                 conn.remote_addr = addr[0]
1730                 conn.remote_port = addr[1]
1731            
1732             conn.ssl_env = ssl_env
1733            
1734             self.requests.put(conn)
1735         except socket.timeout:
1736             # The only reason for the timeout in start() is so we can
1737             # notice keyboard interrupts on Win32, which don't interrupt
1738             # accept() by default
1739             return
1740         except socket.error, x:
1741             if x.args[0] in socket_error_eintr:
1742                 # I *think* this is right. EINTR should occur when a signal
1743                 # is received during the accept() call; all docs say retry
1744                 # the call, and I *think* I'm reading it right that Python
1745                 # will then go ahead and poll for and handle the signal
1746                 # elsewhere. See http://www.cherrypy.org/ticket/707.
1747                 return
1748             if x.args[0] in socket_errors_nonblocking:
1749                 # Just try again. See http://www.cherrypy.org/ticket/479.
1750                 return
1751             if x.args[0] in socket_errors_to_ignore:
1752                 # Our socket was closed.
1753                 # See http://www.cherrypy.org/ticket/686.
1754                 return
1755             raise
1756    
1757     def _get_interrupt(self):
1758         return self._interrupt
1759     def _set_interrupt(self, interrupt):
1760         self._interrupt = True
1761         self.stop()
1762         self._interrupt = interrupt
1763     interrupt = property(_get_interrupt, _set_interrupt,
1764                          doc="Set this to an Exception instance to "
1765                              "interrupt the server.")
1766    
1767     def stop(self):
1768         """Gracefully shutdown a server that is serving forever."""
1769         self.ready = False
1770        
1771         sock = getattr(self, "socket", None)
1772         if sock:
1773             if not isinstance(self.bind_addr, basestring):
1774                 # Touch our own socket to make accept() return immediately.
1775                 try:
1776                     host, port = sock.getsockname()[:2]
1777                 except socket.error, x:
1778                     if x.args[0] not in socket_errors_to_ignore:
1779                         # Changed to use error code and not message
1780                         # See http://www.cherrypy.org/ticket/860.
1781                         raise
1782                 else:
1783                     # Note that we're explicitly NOT using AI_PASSIVE,
1784                     # here, because we want an actual IP to touch.
1785                     # localhost won't work if we've bound to a public IP,
1786                     # but it will if we bound to '0.0.0.0' (INADDR_ANY).
1787                     for res in socket.getaddrinfo(host, port, socket.AF_UNSPEC,
1788                                                   socket.SOCK_STREAM):
1789                         af, socktype, proto, canonname, sa = res
1790                         s = None
1791                         try:
1792                             s = socket.socket(af, socktype, proto)
1793                             # See http://groups.google.com/group/cherrypy-users/
1794                             #        browse_frm/thread/bbfe5eb39c904fe0
1795                             s.settimeout(1.0)
1796                             s.connect((host, port))
1797                             s.close()
1798                         except socket.error:
1799                             if s:
1800                                 s.close()
1801             if hasattr(sock, "close"):
1802                 sock.close()
1803             self.socket = None
1804        
1805         self.requests.stop(self.shutdown_timeout)
1806
1807
1808 class Gateway(object):
1809    
1810     def __init__(self, req):
1811         self.req = req
1812    
1813     def respond(self):
1814         raise NotImplemented
1815
1816
1817 # These may either be wsgiserver.SSLAdapter subclasses or the string names
1818 # of such classes (in which case they will be lazily loaded).
1819 ssl_adapters = {
1820     'builtin': 'cherrypy.wsgiserver.ssl_builtin.BuiltinSSLAdapter',
1821     'pyopenssl': 'cherrypy.wsgiserver.ssl_pyopenssl.pyOpenSSLAdapter',
1822     }
1823
1824 def get_ssl_adapter_class(name='pyopenssl'):
1825     adapter = ssl_adapters[name.lower()]
1826     if isinstance(adapter, basestring):
1827         last_dot = adapter.rfind(".")
1828         attr_name = adapter[last_dot + 1:]
1829         mod_path = adapter[:last_dot]
1830        
1831         try:
1832             mod = sys.modules[mod_path]
1833             if mod is None:
1834                 raise KeyError()
1835         except KeyError:
1836             # The last [''] is important.
1837             mod = __import__(mod_path, globals(), locals(), [''])
1838        
1839         # Let an AttributeError propagate outward.
1840         try:
1841             adapter = getattr(mod, attr_name)
1842         except AttributeError:
1843             raise AttributeError("'%s' object has no attribute '%s'"
1844                                  % (mod_path, attr_name))
1845    
1846     return adapter
1847
1848 # -------------------------------- WSGI Stuff -------------------------------- #
1849
1850
1851 class CherryPyWSGIServer(HTTPServer):
1852    
1853     wsgi_version = (1, 1)
1854    
1855     def __init__(self, bind_addr, wsgi_app, numthreads=10, server_name=None,
1856                  max=-1, request_queue_size=5, timeout=10, shutdown_timeout=5):
1857         self.requests = ThreadPool(self, min=numthreads or 1, max=max)
1858         self.wsgi_app = wsgi_app
1859         self.gateway = wsgi_gateways[self.wsgi_version]
1860        
1861         self.bind_addr = bind_addr
1862         if not server_name:
1863             server_name = socket.gethostname()
1864         self.server_name = server_name
1865         self.request_queue_size = request_queue_size
1866        
1867         self.timeout = timeout
1868         self.shutdown_timeout = shutdown_timeout
1869    
1870     def _get_numthreads(self):
1871         return self.requests.min
1872     def _set_numthreads(self, value):
1873         self.requests.min = value
1874     numthreads = property(_get_numthreads, _set_numthreads)
1875
1876
1877 class WSGIGateway(Gateway):
1878    
1879     def __init__(self, req):
1880         self.req = req
1881         self.started_response = False
1882         self.env = self.get_environ()
1883    
1884     def get_environ(self):
1885         """Return a new environ dict targeting the given wsgi.version"""
1886         raise NotImplemented
1887    
1888     def respond(self):
1889         response = self.req.server.wsgi_app(self.env, self.start_response)
1890         try:
1891             for chunk in response:
1892                 # "The start_response callable must not actually transmit
1893                 # the response headers. Instead, it must store them for the
1894                 # server or gateway to transmit only after the first
1895                 # iteration of the application return value that yields
1896                 # a NON-EMPTY string, or upon the application's first
1897                 # invocation of the write() callable." (PEP 333)
1898                 if chunk:
1899                     if isinstance(chunk, unicode):
1900                         chunk = chunk.encode('ISO-8859-1')
1901                     self.write(chunk)
1902         finally:
1903             if hasattr(response, "close"):
1904                 response.close()
1905    
1906     def start_response(self, status, headers, exc_info = None):
1907         """WSGI callable to begin the HTTP response."""
1908         # "The application may call start_response more than once,
1909         # if and only if the exc_info argument is provided."
1910         if self.started_response and not exc_info:
1911             raise AssertionError("WSGI start_response called a second "
1912                                  "time with no exc_info.")
1913         self.started_response = True
1914        
1915         # "if exc_info is provided, and the HTTP headers have already been
1916         # sent, start_response must raise an error, and should raise the
1917         # exc_info tuple."
1918         if self.req.sent_headers:
1919             try:
1920                 raise exc_info[0], exc_info[1], exc_info[2]
1921             finally:
1922                 exc_info = None
1923        
1924         self.req.status = status
1925         for k, v in headers:
1926             if not isinstance(k, str):
1927                 raise TypeError("WSGI response header key %r is not a byte string." % k)
1928             if not isinstance(v, str):
1929                 raise TypeError("WSGI response header value %r is not a byte string." % v)
1930         self.req.outheaders.extend(headers)
1931        
1932         return self.write
1933    
1934     def write(self, chunk):
1935         """WSGI callable to write unbuffered data to the client.
1936         
1937         This method is also used internally by start_response (to write
1938         data from the iterable returned by the WSGI application).
1939         """
1940         if not self.started_response:
1941             raise AssertionError("WSGI write called before start_response.")
1942        
1943         if not self.req.sent_headers:
1944             self.req.sent_headers = True
1945             self.req.send_headers()
1946        
1947         self.req.write(chunk)
1948
1949
1950 class WSGIGateway_10(WSGIGateway):
1951    
1952     def get_environ(self):
1953         """Return a new environ dict targeting the given wsgi.version"""
1954         req = self.req
1955         env = {
1956             # set a non-standard environ entry so the WSGI app can know what
1957             # the *real* server protocol is (and what features to support).
1958             # See http://www.faqs.org/rfcs/rfc2145.html.
1959             'ACTUAL_SERVER_PROTOCOL': req.server.protocol,
1960             'PATH_INFO': req.path,
1961             'QUERY_STRING': req.qs,
1962             'REMOTE_ADDR': req.conn.remote_addr or '',
1963             'REMOTE_PORT': str(req.conn.remote_port or ''),
1964             'REQUEST_METHOD': req.method,
1965             'REQUEST_URI': req.uri,
1966             'SCRIPT_NAME': '',
1967             'SERVER_NAME': req.server.server_name,
1968             # Bah. "SERVER_PROTOCOL" is actually the REQUEST protocol.
1969             'SERVER_PROTOCOL': req.request_protocol,
1970             'SERVER_SOFTWARE': "%s WSGI Server" % req.server.version,
1971             'wsgi.errors': sys.stderr,
1972             'wsgi.input': req.rfile,
1973             'wsgi.multiprocess': False,
1974             'wsgi.multithread': True,
1975             'wsgi.run_once': False,
1976             'wsgi.url_scheme': req.scheme,
1977             'wsgi.version': (1, 0),
1978             }
1979        
1980         if isinstance(req.server.bind_addr, basestring):
1981             # AF_UNIX. This isn't really allowed by WSGI, which doesn't
1982             # address unix domain sockets. But it's better than nothing.
1983             env["SERVER_PORT"] = ""
1984         else:
1985             env["SERVER_PORT"] = str(req.server.bind_addr[1])
1986        
1987         # CONTENT_TYPE/CONTENT_LENGTH
1988         for k, v in req.inheaders.iteritems():
1989             env["HTTP_" + k.upper().replace("-", "_")] = v
1990         ct = env.pop("HTTP_CONTENT_TYPE", None)
1991         if ct is not None:
1992             env["CONTENT_TYPE"] = ct
1993         cl = env.pop("HTTP_CONTENT_LENGTH", None)
1994         if cl is not None:
1995             env["CONTENT_LENGTH"] = cl
1996        
1997         if req.conn.ssl_env:
1998             env.update(req.conn.ssl_env)
1999        
2000         return env
2001
2002
2003 class WSGIGateway_11(WSGIGateway_10):
2004    
2005     def get_environ(self):
2006         env = WSGIGateway_10.get_environ(self)
2007         env['wsgi.version'] = (1, 1)
2008         return env
2009
2010
2011 class WSGIGateway_u0(WSGIGateway_10):
2012    
2013     def get_environ(self):
2014         """Return a new environ dict targeting the given wsgi.version"""
2015         req = self.req
2016         env_10 = WSGIGateway_10.get_environ(self)
2017         env = dict([(k.decode('ISO-8859-1'), v) for k, v in env_10.iteritems()])
2018         env[u'wsgi.version'] = ('u', 0)
2019        
2020         # Request-URI
2021         env.setdefault(u'wsgi.url_encoding', u'utf-8')
2022         try:
2023             for key in [u"PATH_INFO", u"SCRIPT_NAME", u"QUERY_STRING"]:
2024                 env[key] = env_10[str(key)].decode(env[u'wsgi.url_encoding'])
2025         except UnicodeDecodeError:
2026             # Fall back to latin 1 so apps can transcode if needed.
2027             env[u'wsgi.url_encoding'] = u'ISO-8859-1'
2028             for key in [u"PATH_INFO", u"SCRIPT_NAME", u"QUERY_STRING"]:
2029                 env[key] = env_10[str(key)].decode(env[u'wsgi.url_encoding'])
2030        
2031         for k, v in sorted(env.items()):
2032             if isinstance(v, str) and k not in ('REQUEST_URI', 'wsgi.input'):
2033                 env[k] = v.decode('ISO-8859-1')
2034        
2035         return env
2036
2037 wsgi_gateways = {
2038     (1, 0): WSGIGateway_10,
2039     (1, 1): WSGIGateway_11,
2040     ('u', 0): WSGIGateway_u0,
2041 }
2042
2043 class WSGIPathInfoDispatcher(object):
2044     """A WSGI dispatcher for dispatch based on the PATH_INFO.
2045     
2046     apps: a dict or list of (path_prefix, app) pairs.
2047     """
2048    
2049     def __init__(self, apps):
2050         try:
2051             apps = apps.items()
2052         except AttributeError:
2053             pass
2054        
2055         # Sort the apps by len(path), descending
2056         apps.sort(cmp=lambda x,y: cmp(len(x[0]), len(y[0])))
2057         apps.reverse()
2058        
2059         # The path_prefix strings must start, but not end, with a slash.
2060         # Use "" instead of "/".
2061         self.apps = [(p.rstrip("/"), a) for p, a in apps]
2062    
2063     def __call__(self, environ, start_response):
2064         path = environ["PATH_INFO"] or "/"
2065         for p, app in self.apps:
2066             # The apps list should be sorted by length, descending.
2067             if path.startswith(p + "/") or path == p:
2068                 environ = environ.copy()
2069                 environ["SCRIPT_NAME"] = environ["SCRIPT_NAME"] + p
2070                 environ["PATH_INFO"] = path[len(p):]
2071                 return app(environ, start_response)
2072        
2073         start_response('404 Not Found', [('Content-Type', 'text/plain'),
2074                                          ('Content-Length', '0')])
2075         return ['']
Note: See TracBrowser for help on using the browser.

Hosted by WebFaction

Log in as guest/cpguest to create tickets