Profile Report Profile Time on Sat Jun 20 06:59:14 2009
Reported Time on Tue Jun 23 02:22:32 2009

Total Time : 12.5950 CPU second
Total Func Call: 1285 function calls

Top 20 functions data
ncalls tottime percall cumtime percall filename:lineno(function)
9 7.4059 0.8229 7.4060 0.8229 /usr/lib/python2.6/socket.py : 194 (accept)
13 5.0035 0.3849 5.0041 0.3849 /usr/lib/python2.6/threading.py : 228 (wait)
1 0.1006 0.1006 0.1155 0.1155 /var/lib/python-support/python2.6/web/wsgiserver/__init__.py : 1283 (start)
1 0.0254 0.0254 0.0316 0.0316 /usr/lib/python2.6/mimetypes.py : 199 (readfp)
23 0.0090 0.0004 0.0092 0.0004 /usr/lib/python2.6/threading.py : 179 (__init__)
610 0.0079 0.0000 0.0079 0.0000 /usr/lib/python2.6/mimetypes.py : 71 (add_type)
1 0.0061 0.0061 0.0068 0.0068 /var/lib/python-support/python2.6/OpenSSL/tsafe.py : 9 (Connection)
1 0.0058 0.0058 0.0060 0.0060 /var/lib/python-support/python2.6/web/wsgiserver/__init__.py : 1366 (SSLConnection)
1 0.0037 0.0037 0.0238 0.0238 /var/lib/python-support/python2.6/web/wsgiserver/__init__.py : 77 (<module>)
1 0.0032 0.0032 0.0102 0.0102 /var/lib/python-support/python2.6/OpenSSL/__init__.py : 10 (<module>)
1 0.0025 0.0025 12.5948 12.5948 /var/lib/python-support/python2.6/web/httpserver.py : 130 (runsimple)
1 0.0025 0.0025 0.0404 0.0404 /usr/lib/python2.6/SimpleHTTPServer.py : 6 (<module>)
77 0.0013 0.0000 0.0013 0.0000 <string> : 1 (<module>)
10 0.0011 0.0001 0.0039 0.0004 /usr/lib/python2.6/threading.py : 461 (start)
1 0.0010 0.0010 0.0017 0.0017 /usr/lib/python2.6/BaseHTTPServer.py : 18 (<module>)
1 0.0010 0.0010 0.0027 0.0027 /usr/lib/python2.6/mimetypes.py : 57 (__init__)
1 0.0009 0.0009 0.0018 0.0018 /usr/lib/python2.6/Queue.py : 1 (<module>)
1 0.0008 0.0008 0.0008 0.0008 /usr/lib/python2.6/heapq.py : 31 (<module>)
1 0.0008 0.0008 0.0008 0.0008 /usr/lib/python2.6/shutil.py : 5 (<module>)
10 0.0006 0.0001 0.0106 0.0011 /usr/lib/python2.6/threading.py : 424 (__init__)
/usr/lib/python2.6/BaseHTTPServer.py
     time      num code
1
"""HTTP server base class.
2
3
Note: the class in this module doesn't implement any HTTP request; see
4
SimpleHTTPServer for simple implementations of GET, HEAD and POST
5
(including CGI scripts).  It does, however, optionally implement HTTP/1.1
6
persistent connections, as of version 0.3.
7
8
Contents:
9
10
- BaseHTTPRequestHandler: HTTP request handler base class
11
- test: test function
12
13
XXX To do:
14
15
- log requests even later (to capture byte count)
16
- log user-agent header and other interesting goodies
17
- send error log to separate file
0.000895 sec 18
"""
19
20
21
# See also:
22
#
23
# HTTP Working Group                                        T. Berners-Lee
24
# INTERNET-DRAFT                                            R. T. Fielding
25
# <draft-ietf-http-v10-spec-00.txt>                     H. Frystyk Nielsen
26
# Expires September 8, 1995                                  March 8, 1995
27
#
28
# URL: http://www.ics.uci.edu/pub/ietf/http/draft-ietf-http-v10-spec-00.txt
29
#
30
# and
31
#
32
# Network Working Group                                      R. Fielding
33
# Request for Comments: 2616                                       et al
34
# Obsoletes: 2068                                              June 1999
35
# Category: Standards Track
36
#
37
# URL: http://www.faqs.org/rfcs/rfc2616.html
38
39
# Log files
40
# ---------
41
#
42
# Here's a quote from the NCSA httpd docs about log file format.
43
#
44
# | The logfile format is as follows. Each line consists of:
45
# |
46
# | host rfc931 authuser [DD/Mon/YYYY:hh:mm:ss] "request" ddd bbbb
47
# |
48
# |        host: Either the DNS name or the IP number of the remote client
49
# |        rfc931: Any information returned by identd for this person,
50
# |                - otherwise.
51
# |        authuser: If user sent a userid for authentication, the user name,
52
# |                  - otherwise.
53
# |        DD: Day
54
# |        Mon: Month (calendar name)
55
# |        YYYY: Year
56
# |        hh: hour (24-hour format, the machine's timezone)
57
# |        mm: minutes
58
# |        ss: seconds
59
# |        request: The first line of the HTTP request as sent by the client.
60
# |        ddd: the status code returned by the server, - if not available.
61
# |        bbbb: the total number of bytes sent,
62
# |              *not including the HTTP/1.0 header*, - if not available
63
# |
64
# | You can determine the name of the file accessed through request.
65
#
66
# (Actually, the latter is only true if you know the server configuration
67
# at the time the request was made!)
68
2e-06 sec 69
__version__ = "0.3"
70
3e-06 sec 71
__all__ = ["HTTPServer", "BaseHTTPRequestHandler"]
72
3e-06 sec 73
import sys
9e-06 sec 74
import time
5e-06 sec 75
import socket # For gethostbyaddr()
5e-06 sec 76
from warnings import filterwarnings, catch_warnings
1.3e-05 sec 77
with catch_warnings():
3e-06 sec 78
    if sys.py3kwarning:
79
        filterwarnings("ignore", ".*mimetools has been removed",
80
                        DeprecationWarning)
3e-06 sec 81
    import mimetools
6e-06 sec 82
import SocketServer
83
84
# Default error message template
85
DEFAULT_ERROR_MESSAGE = """\
86
<head>
87
<title>Error response</title>
88
</head>
89
<body>
90
<h1>Error response</h1>
91
<p>Error code %(code)d.
92
<p>Message: %(message)s.
93
<p>Error code explanation: %(code)s = %(explain)s.
94
</body>
2.1e-05 sec 95
"""
96
3e-06 sec 97
DEFAULT_ERROR_CONTENT_TYPE = "text/html"
98
2e-06 sec 99
def _quote_html(html):
100
    return html.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")
101
1e-05 sec 102
class HTTPServer(SocketServer.TCPServer):
103
3e-06 sec 104
    allow_reuse_address = 1    # Seems to make sense in testing environment
105
1e-06 sec 106
    def server_bind(self):
107
        """Override server_bind to store the server name."""
108
        SocketServer.TCPServer.server_bind(self)
109
        host, port = self.socket.getsockname()[:2]
110
        self.server_name = socket.getfqdn(host)
111
        self.server_port = port
112
113
1.1e-05 sec 114
class BaseHTTPRequestHandler(SocketServer.StreamRequestHandler):
115
116
    """HTTP request handler base class.
117
118
    The following explanation of HTTP serves to guide you through the
119
    code as well as to expose any misunderstandings I may have about
120
    HTTP (so you don't need to read the code to figure out I'm wrong
121
    :-).
122
123
    HTTP (HyperText Transfer Protocol) is an extensible protocol on
124
    top of a reliable stream transport (e.g. TCP/IP).  The protocol
125
    recognizes three parts to a request:
126
127
    1. One line identifying the request type and path
128
    2. An optional set of RFC-822-style headers
129
    3. An optional data part
130
131
    The headers and data are separated by a blank line.
132
133
    The first line of the request has the form
134
135
    <command> <path> <version>
136
137
    where <command> is a (case-sensitive) keyword such as GET or POST,
138
    <path> is a string containing path information for the request,
139
    and <version> should be the string "HTTP/1.0" or "HTTP/1.1".
140
    <path> is encoded using the URL encoding scheme (using %xx to signify
141
    the ASCII character with hex code xx).
142
143
    The specification specifies that lines are separated by CRLF but
144
    for compatibility with the widest range of clients recommends
145
    servers also handle LF.  Similarly, whitespace in the request line
146
    is treated sensibly (allowing multiple spaces between components
147
    and allowing trailing whitespace).
148
149
    Similarly, for output, lines ought to be separated by CRLF pairs
150
    but most clients grok LF characters just fine.
151
152
    If the first line of the request has the form
153
154
    <command> <path>
155
156
    (i.e. <version> is left out) then this is assumed to be an HTTP
157
    0.9 request; this form has no optional headers and data part and
158
    the reply consists of just the data.
159
160
    The reply form of the HTTP 1.x protocol again has three parts:
161
162
    1. One line giving the response code
163
    2. An optional set of RFC-822-style headers
164
    3. The data
165
166
    Again, the headers and data are separated by a blank line.
167
168
    The response code line has the form
169
170
    <version> <responsecode> <responsestring>
171
172
    where <version> is the protocol version ("HTTP/1.0" or "HTTP/1.1"),
173
    <responsecode> is a 3-digit response code indicating success or
174
    failure of the request, and <responsestring> is an optional
175
    human-readable string explaining what the response code means.
176
177
    This server parses the request and the headers, and then calls a
178
    function specific to the request type (<command>).  Specifically,
179
    a request SPAM will be handled by a method do_SPAM().  If no
180
    such method exists the server sends an error response to the
181
    client.  If it exists, it is called with no arguments:
182
183
    do_SPAM()
184
185
    Note that the request name is case sensitive (i.e. SPAM and spam
186
    are different requests).
187
188
    The various request details are stored in instance variables:
189
190
    - client_address is the client IP address in the form (host,
191
    port);
192
193
    - command, path and version are the broken-down request line;
194
195
    - headers is an instance of mimetools.Message (or a derived
196
    class) containing the header information;
197
198
    - rfile is a file object open for reading positioned at the
199
    start of the optional input data part;
200
201
    - wfile is a file object open for writing.
202
203
    IT IS IMPORTANT TO ADHERE TO THE PROTOCOL FOR WRITING!
204
205
    The first thing to be written must be the response line.  Then
206
    follow 0 or more header lines, then a blank line, and then the
207
    actual data (if any).  The meaning of the header lines depends on
208
    the command executed by the server; in most cases, when data is
209
    returned, there should be at least one header line of the form
210
211
    Content-type: <type>/<subtype>
212
213
    where <type> and <subtype> should be registered MIME types,
214
    e.g. "text/html" or "text/plain".
215
2e-06 sec 216
    """
217
218
    # The Python system version, truncated to its first component.
2e-06 sec 219
    sys_version = "Python/" + sys.version.split()[0]
220
221
    # The server software version.  You may want to override this.
222
    # The format is multiple whitespace-separated strings,
223
    # where each string is of the form name[/version].
1.5e-05 sec 224
    server_version = "BaseHTTP/" + __version__
225
226
    # The default request version.  This only affects responses up until
227
    # the point where the request line is parsed, so it mainly decides what
228
    # the client gets back when sending a malformed request line.
229
    # Most web servers default to HTTP 0.9, i.e. don't send a status line.
2e-06 sec 230
    default_request_version = "HTTP/0.9"
231
3e-06 sec 232
    def parse_request(self):
233
        """Parse a request (internal).
234
235
        The request should be stored in self.raw_requestline; the results
236
        are in self.command, self.path, self.request_version and
237
        self.headers.
238
239
        Return True for success, False for failure; on failure, an
240
        error is sent back.
241
242
        """
243
        self.command = None  # set in case of error on the first line
244
        self.request_version = version = self.default_request_version
245
        self.close_connection = 1
246
        requestline = self.raw_requestline
247
        if requestline[-2:] == '\r\n':
248
            requestline = requestline[:-2]
249
        elif requestline[-1:] == '\n':
250
            requestline = requestline[:-1]
251
        self.requestline = requestline
252
        words = requestline.split()
253
        if len(words) == 3:
254
            [command, path, version] = words
255
            if version[:5] != 'HTTP/':
256
                self.send_error(400, "Bad request version (%r)" % version)
257
                return False
258
            try:
259
                base_version_number = version.split('/', 1)[1]
260
                version_number = base_version_number.split(".")
261
                # RFC 2145 section 3.1 says there can be only one "." and
262
                #   - major and minor numbers MUST be treated as
263
                #      separate integers;
264
                #   - HTTP/2.4 is a lower version than HTTP/2.13, which in
265
                #      turn is lower than HTTP/12.3;
266
                #   - Leading zeros MUST be ignored by recipients.
267
                if len(version_number) != 2:
268
                    raise ValueError
269
                version_number = int(version_number[0]), int(version_number[1])
270
            except (ValueError, IndexError):
271
                self.send_error(400, "Bad request version (%r)" % version)
272
                return False
273
            if version_number >= (1, 1) and self.protocol_version >= "HTTP/1.1":
274
                self.close_connection = 0
275
            if version_number >= (2, 0):
276
                self.send_error(505,
277
                          "Invalid HTTP Version (%s)" % base_version_number)
278
                return False
279
        elif len(words) == 2:
280
            [command, path] = words
281
            self.close_connection = 1
282
            if command != 'GET':
283
                self.send_error(400,
284
                                "Bad HTTP/0.9 request type (%r)" % command)
285
                return False
286
        elif not words:
287
            return False
288
        else:
289
            self.send_error(400, "Bad request syntax (%r)" % requestline)
290
            return False
291
        self.command, self.path, self.request_version = command, path, version
292
293
        # Examine the headers and look for a Connection directive
294
        self.headers = self.MessageClass(self.rfile, 0)
295
296
        conntype = self.headers.get('Connection', "")
297
        if conntype.lower() == 'close':
298
            self.close_connection = 1
299
        elif (conntype.lower() == 'keep-alive' and
300
              self.protocol_version >= "HTTP/1.1"):
301
            self.close_connection = 0
302
        return True
303
3e-06 sec 304
    def handle_one_request(self):
305
        """Handle a single HTTP request.
306
307
        You normally don't need to override this method; see the class
308
        __doc__ string for information on how to handle specific HTTP
309
        commands such as GET and POST.
310
311
        """
312
        self.raw_requestline = self.rfile.readline()
313
        if not self.raw_requestline:
314
            self.close_connection = 1
315
            return
316
        if not self.parse_request(): # An error code has been sent, just exit
317
            return
318
        mname = 'do_' + self.command
319
        if not hasattr(self, mname):
320
            self.send_error(501, "Unsupported method (%r)" % self.command)
321
            return
322
        method = getattr(self, mname)
323
        method()
324
3e-06 sec 325
    def handle(self):
326
        """Handle multiple requests if necessary."""
327
        self.close_connection = 1
328
329
        self.handle_one_request()
330
        while not self.close_connection:
331
            self.handle_one_request()
332
2e-06 sec 333
    def send_error(self, code, message=None):
334
        """Send and log an error reply.
335
336
        Arguments are the error code, and a detailed message.
337
        The detailed message defaults to the short entry matching the
338
        response code.
339
340
        This sends an error response (so it must be called before any
341
        output has been generated), logs the error, and finally sends
342
        a piece of HTML explaining the error to the user.
343
344
        """
345
346
        try:
347
            short, long = self.responses[code]
348
        except KeyError:
349
            short, long = '???', '???'
350
        if message is None:
351
            message = short
352
        explain = long
353
        self.log_error("code %d, message %s", code, message)
354
        # using _quote_html to prevent Cross Site Scripting attacks (see bug #1100201)
355
        content = (self.error_message_format %
356
                   {'code': code, 'message': _quote_html(message), 'explain': explain})
357
        self.send_response(code, message)
358
        self.send_header("Content-Type", self.error_content_type)
359
        self.send_header('Connection', 'close')
360
        self.end_headers()
361
        if self.command != 'HEAD' and code >= 200 and code not in (204, 304):
362
            self.wfile.write(content)
363
3e-06 sec 364
    error_message_format = DEFAULT_ERROR_MESSAGE
2e-06 sec 365
    error_content_type = DEFAULT_ERROR_CONTENT_TYPE
366
3e-06 sec 367
    def send_response(self, code, message=None):
368
        """Send the response header and log the response code.
369
370
        Also send two standard headers with the server software
371
        version and the current date.
372
373
        """
374
        self.log_request(code)
375
        if message is None:
376
            if code in self.responses:
377
                message = self.responses[code][0]
378
            else:
379
                message = ''
380
        if self.request_version != 'HTTP/0.9':
381
            self.wfile.write("%s %d %s\r\n" %
382
                             (self.protocol_version, code, message))
383
            # print (self.protocol_version, code, message)
384
        self.send_header('Server', self.version_string())
385
        self.send_header('Date', self.date_time_string())
386
2e-06 sec 387
    def send_header(self, keyword, value):
388
        """Send a MIME header."""
389
        if self.request_version != 'HTTP/0.9':
390
            self.wfile.write("%s: %s\r\n" % (keyword, value))
391
392
        if keyword.lower() == 'connection':
393
            if value.lower() == 'close':
394
                self.close_connection = 1
395
            elif value.lower() == 'keep-alive':
396
                self.close_connection = 0
397
2e-06 sec 398
    def end_headers(self):
399
        """Send the blank line ending the MIME headers."""
400
        if self.request_version != 'HTTP/0.9':
401
            self.wfile.write("\r\n")
402
3e-06 sec 403
    def log_request(self, code='-', size='-'):
404
        """Log an accepted request.
405
406
        This is called by send_response().
407
408
        """
409
410
        self.log_message('"%s" %s %s',
411
                         self.requestline, str(code), str(size))
412
3e-06 sec 413
    def log_error(self, format, *args):
414
        """Log an error.
415
416
        This is called when a request cannot be fulfilled.  By
417
        default it passes the message on to log_message().
418
419
        Arguments are the same as for log_message().
420
421
        XXX This should go to the separate error log.
422
423
        """
424
425
        self.log_message(format, *args)
426
2e-06 sec 427
    def log_message(self, format, *args):
428
        """Log an arbitrary message.
429
430
        This is used by all other logging functions.  Override
431
        it if you have specific logging wishes.
432
433
        The first argument, FORMAT, is a format string for the
434
        message to be logged.  If the format string contains
435
        any % escapes requiring parameters, they should be
436
        specified as subsequent arguments (it's just like
437
        printf!).
438
439
        The client host and current date/time are prefixed to
440
        every message.
441
442
        """
443
444
        sys.stderr.write("%s - - [%s] %s\n" %
445
                         (self.address_string(),
446
                          self.log_date_time_string(),
447
                          format%args))
448
2e-06 sec 449
    def version_string(self):
450
        """Return the server software version string."""
451
        return self.server_version + ' ' + self.sys_version
452
3e-06 sec 453
    def date_time_string(self, timestamp=None):
454
        """Return the current date and time formatted for a message header."""
455
        if timestamp is None:
456
            timestamp = time.time()
457
        year, month, day, hh, mm, ss, wd, y, z = time.gmtime(timestamp)
458
        s = "%s, %02d %3s %4d %02d:%02d:%02d GMT" % (
459
                self.weekdayname[wd],
460
                day, self.monthname[month], year,
461
                hh, mm, ss)
462
        return s
463
2e-06 sec 464
    def log_date_time_string(self):
465
        """Return the current time formatted for logging."""
466
        now = time.time()
467
        year, month, day, hh, mm, ss, x, y, z = time.localtime(now)
468
        s = "%02d/%3s/%04d %02d:%02d:%02d" % (
469
                day, self.monthname[month], year, hh, mm, ss)
470
        return s
471
3e-06 sec 472
    weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
473
3e-06 sec 474
    monthname = [None,
2e-06 sec 475
                 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
2e-06 sec 476
                 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
477
6e-06 sec 478
    def address_string(self):
479
        """Return the client address formatted for logging.
480
481
        This version looks up the full hostname using gethostbyaddr(),
482
        and tries to find a name that contains at least one dot.
483
484
        """
485
486
        host, port = self.client_address[:2]
487
        return socket.getfqdn(host)
488
489
    # Essentially static class variables
490
491
    # The version of the HTTP protocol we support.
492
    # Set this to HTTP/1.1 to enable automatic keepalive
3e-06 sec 493
    protocol_version = "HTTP/1.0"
494
495
    # The Message-like class used to parse headers
3e-06 sec 496
    MessageClass = mimetools.Message
497
498
    # Table mapping response codes to messages; entries have the
499
    # form {code: (shortmessage, longmessage)}.
500
    # See RFC 2616.
4e-06 sec 501
    responses = {
3e-06 sec 502
        100: ('Continue', 'Request received, please continue'),
503
        101: ('Switching Protocols',
4e-06 sec 504
              'Switching to new protocol; obey Upgrade header'),
505
2e-06 sec 506
        200: ('OK', 'Request fulfilled, document follows'),
2e-06 sec 507
        201: ('Created', 'Document created, URL follows'),
508
        202: ('Accepted',
2e-06 sec 509
              'Request accepted, processing continues off-line'),
2e-06 sec 510
        203: ('Non-Authoritative Information', 'Request fulfilled from cache'),
2e-06 sec 511
        204: ('No Content', 'Request fulfilled, nothing follows'),
2e-06 sec 512
        205: ('Reset Content', 'Clear input form for further input.'),
2e-06 sec 513
        206: ('Partial Content', 'Partial content follows.'),
514
515
        300: ('Multiple Choices',
2e-06 sec 516
              'Object has several resources -- see URI list'),
2e-06 sec 517
        301: ('Moved Permanently', 'Object moved permanently -- see URI list'),
2e-06 sec 518
        302: ('Found', 'Object moved temporarily -- see URI list'),
3e-06 sec 519
        303: ('See Other', 'Object moved -- see Method and URL list'),
520
        304: ('Not Modified',
2e-06 sec 521
              'Document has not changed since given time'),
522
        305: ('Use Proxy',
2e-06 sec 523
              'You must use proxy specified in Location to access this '
524
              'resource.'),
525
        307: ('Temporary Redirect',
2e-06 sec 526
              'Object moved temporarily -- see URI list'),
527
528
        400: ('Bad Request',
2e-06 sec 529
              'Bad request syntax or unsupported method'),
530
        401: ('Unauthorized',
2e-06 sec 531
              'No permission -- see authorization schemes'),
532
        402: ('Payment Required',
3e-06 sec 533
              'No payment -- see charging schemes'),
534
        403: ('Forbidden',
1e-06 sec 535
              'Request forbidden -- authorization will not help'),
3e-06 sec 536
        404: ('Not Found', 'Nothing matches the given URI'),
537
        405: ('Method Not Allowed',
2e-06 sec 538
              'Specified method is invalid for this server.'),
2e-06 sec 539
        406: ('Not Acceptable', 'URI not available in preferred format.'),
3e-06 sec 540
        407: ('Proxy Authentication Required', 'You must authenticate with '
541
              'this proxy before proceeding.'),
3e-06 sec 542
        408: ('Request Timeout', 'Request timed out; try again later.'),
2e-06 sec 543
        409: ('Conflict', 'Request conflict.'),
544
        410: ('Gone',
2e-06 sec 545
              'URI no longer exists and has been permanently removed.'),
3e-06 sec 546
        411: ('Length Required', 'Client must specify Content-Length.'),
2e-06 sec 547
        412: ('Precondition Failed', 'Precondition in headers is false.'),
2e-06 sec 548
        413: ('Request Entity Too Large', 'Entity is too large.'),
2e-06 sec 549
        414: ('Request-URI Too Long', 'URI is too long.'),
3e-06 sec 550
        415: ('Unsupported Media Type', 'Entity body in unsupported format.'),
551
        416: ('Requested Range Not Satisfiable',
2e-06 sec 552
              'Cannot satisfy request range.'),
553
        417: ('Expectation Failed',
2e-06 sec 554
              'Expect condition could not be satisfied.'),
555
3e-06 sec 556
        500: ('Internal Server Error', 'Server got itself in trouble'),
557
        501: ('Not Implemented',
2e-06 sec 558
              'Server does not support this operation'),
2e-06 sec 559
        502: ('Bad Gateway', 'Invalid responses from another server/proxy.'),
560
        503: ('Service Unavailable',
3e-06 sec 561
              'The server cannot process the request due to a high load'),
562
        504: ('Gateway Timeout',
2e-06 sec 563
              'The gateway server did not receive a timely response'),
2e-06 sec 564
        505: ('HTTP Version Not Supported', 'Cannot fulfill request.'),
565
        }
566
567
9e-06 sec 568
def test(HandlerClass = BaseHTTPRequestHandler,
2e-06 sec 569
         ServerClass = HTTPServer, protocol="HTTP/1.0"):
570
    """Test the HTTP request handler class.
571
572
    This runs an HTTP server on port 8000 (or the first command line
573
    argument).
574
575
    """
576
577
    if sys.argv[1:]:
578
        port = int(sys.argv[1])
579
    else:
580
        port = 8000
581
    server_address = ('', port)
582
583
    HandlerClass.protocol_version = protocol
584
    httpd = ServerClass(server_address, HandlerClass)
585
586
    sa = httpd.socket.getsockname()
587
    print "Serving HTTP on", sa[0], "port", sa[1], "..."
588
    httpd.serve_forever()
589
590
3e-06 sec 591
if __name__ == '__main__':
592
    test()
/usr/lib/python2.6/Queue.py
     time      num code
0.000698 sec 1
"""A multi-producer, multi-consumer queue."""
2
2e-06 sec 3
from time import time as _time
1.9e-05 sec 4
from collections import deque
1e-05 sec 5
import heapq
6
2.5e-05 sec 7
__all__ = ['Empty', 'Full', 'Queue', 'PriorityQueue', 'LifoQueue']
8
1.3e-05 sec 9
class Empty(Exception):
2e-06 sec 10
    "Exception raised by Queue.get(block=0)/get_nowait()."
2e-06 sec 11
    pass
12
0.00012 sec 13
class Full(Exception):
2e-06 sec 14
    "Exception raised by Queue.put(block=0)/put_nowait()."
2e-06 sec 15
    pass
16
7.4e-05 sec 17
class Queue:
18
    """Create a queue object with a given maximum size.
19
20
    If maxsize is <= 0, the queue size is infinite.
1e-06 sec 21
    """
1.3e-05 sec 22
    def __init__(self, maxsize=0):
1e-06 sec 23
        try:
2e-06 sec 24
            import threading
25
        except ImportError:
26
            import dummy_threading as threading
8e-06 sec 27
        self.maxsize = maxsize
3e-06 sec 28
        self._init(maxsize)
29
        # mutex must be held whenever the queue is mutating.  All methods
30
        # that acquire mutex must release it before returning.  mutex
31
        # is shared between the three conditions, so acquiring and
32
        # releasing the conditions also acquires and releases mutex.
2e-06 sec 33
        self.mutex = threading.Lock()
34
        # Notify not_empty whenever an item is added to the queue; a
35
        # thread waiting to get is notified then.
6e-06 sec 36
        self.not_empty = threading.Condition(self.mutex)
37
        # Notify not_full whenever an item is removed from the queue;
38
        # a thread waiting to put is notified then.
3e-06 sec 39
        self.not_full = threading.Condition(self.mutex)
40
        # Notify all_tasks_done whenever the number of unfinished tasks
41
        # drops to zero; thread waiting to join() is notified to resume
2e-06 sec 42
        self.all_tasks_done = threading.Condition(self.mutex)
4e-06 sec 43
        self.unfinished_tasks = 0
44
3e-06 sec 45
    def task_done(self):
46
        """Indicate that a formerly enqueued task is complete.
47
48
        Used by Queue consumer threads.  For each get() used to fetch a task,
49
        a subsequent call to task_done() tells the queue that the processing
50
        on the task is complete.
51
52
        If a join() is currently blocking, it will resume when all items
53
        have been processed (meaning that a task_done() call was received
54
        for every item that had been put() into the queue).
55
56
        Raises a ValueError if called more times than there were items
57
        placed in the queue.
58
        """
59
        self.all_tasks_done.acquire()
60
        try:
61
            unfinished = self.unfinished_tasks - 1
62
            if unfinished <= 0:
63
                if unfinished < 0:
64
                    raise ValueError('task_done() called too many times')
65
                self.all_tasks_done.notify_all()
66
            self.unfinished_tasks = unfinished
67
        finally:
68
            self.all_tasks_done.release()
69
2e-06 sec 70
    def join(self):
71
        """Blocks until all items in the Queue have been gotten and processed.
72
73
        The count of unfinished tasks goes up whenever an item is added to the
74
        queue. The count goes down whenever a consumer thread calls task_done()
75
        to indicate the item was retrieved and all work on it is complete.
76
77
        When the count of unfinished tasks drops to zero, join() unblocks.
78
        """
79
        self.all_tasks_done.acquire()
80
        try:
81
            while self.unfinished_tasks:
82
                self.all_tasks_done.wait()
83
        finally:
84
            self.all_tasks_done.release()
85
2e-06 sec 86
    def qsize(self):
87
        """Return the approximate size of the queue (not reliable!)."""
88
        self.mutex.acquire()
89
        n = self._qsize()
90
        self.mutex.release()
91
        return n
92
4e-06 sec 93
    def empty(self):
94
        """Return True if the queue is empty, False otherwise (not reliable!)."""
95
        self.mutex.acquire()
96
        n = not self._qsize()
97
        self.mutex.release()
98
        return n
99
3e-06 sec 100
    def full(self):
101
        """Return True if the queue is full, False otherwise (not reliable!)."""
102
        self.mutex.acquire()
103
        n = 0 < self.maxsize == self._qsize()
104
        self.mutex.release()
105
        return n
106
8.6e-05 sec 107
    def put(self, item, block=True, timeout=None):
108
        """Put an item into the queue.
109
110
        If optional args 'block' is true and 'timeout' is None (the default),
111
        block if necessary until a free slot is available. If 'timeout' is
112
        a positive number, it blocks at most 'timeout' seconds and raises
113
        the Full exception if no free slot was available within that time.
114
        Otherwise ('block' is false), put an item on the queue if a free slot
115
        is immediately available, else raise the Full exception ('timeout'
116
        is ignored in that case).
117
        """
1.8e-05 sec 118
        self.not_full.acquire()
4.5e-05 sec 119
        try:
2e-05 sec 120
            if self.maxsize > 0:
121
                if not block:
122
                    if self._qsize() == self.maxsize:
123
                        raise Full
124
                elif timeout is None:
125
                    while self._qsize() == self.maxsize:
126
                        self.not_full.wait()
127
                elif timeout < 0:
128
                    raise ValueError("'timeout' must be a positive number")
129
                else:
130
                    endtime = _time() + timeout
131
                    while self._qsize() == self.maxsize:
132
                        remaining = endtime - _time()
133
                        if remaining <= 0.0:
134
                            raise Full
135
                        self.not_full.wait(remaining)
3e-05 sec 136
            self._put(item)
2.2e-05 sec 137
            self.unfinished_tasks += 1
3.5e-05 sec 138
            self.not_empty.notify()
139
        finally:
2.7e-05 sec 140
            self.not_full.release()
141
3e-06 sec 142
    def put_nowait(self, item):
143
        """Put an item into the queue without blocking.
144
145
        Only enqueue the item if a free slot is immediately available.
146
        Otherwise raise the Full exception.
147
        """
148
        return self.put(item, False)
149
2e-06 sec 150
    def get(self, block=True, timeout=None):
151
        """Remove and return an item from the queue.
152
153
        If optional args 'block' is true and 'timeout' is None (the default),
154
        block if necessary until an item is available. If 'timeout' is
155
        a positive number, it blocks at most 'timeout' seconds and raises
156
        the Empty exception if no item was available within that time.
157
        Otherwise ('block' is false), return an item if one is immediately
158
        available, else raise the Empty exception ('timeout' is ignored
159
        in that case).
160
        """
161
        self.not_empty.acquire()
162
        try:
163
            if not block:
164
                if not self._qsize():
165
                    raise Empty
166
            elif timeout is None:
167
                while not self._qsize():
168
                    self.not_empty.wait()
169
            elif timeout < 0:
170
                raise ValueError("'timeout' must be a positive number")
171
            else:
172
                endtime = _time() + timeout
173
                while not self._qsize():
174
                    remaining = endtime - _time()
175
                    if remaining <= 0.0:
176
                        raise Empty
177
                    self.not_empty.wait(remaining)
178
            item = self._get()
179
            self.not_full.notify()
180
            return item
181
        finally:
182
            self.not_empty.release()
183
3e-06 sec 184
    def get_nowait(self):
185
        """Remove and return an item from the queue without blocking.
186
187
        Only get an item if one is immediately available. Otherwise
188
        raise the Empty exception.
189
        """
190
        return self.get(False)
191
192
    # Override these methods to implement other queue organizations
193
    # (e.g. stack or priority queue).
194
    # These will only be called with appropriate locks held
195
196
    # Initialize the queue representation
1.7e-05 sec 197
    def _init(self, maxsize):
2e-06 sec 198
        self.queue = deque()
199
3e-06 sec 200
    def _qsize(self, len=len):
201
        return len(self.queue)
202
203
    # Put a new item in the queue
7.8e-05 sec 204
    def _put(self, item):
2.1e-05 sec 205
        self.queue.append(item)
206
207
    # Get an item from the queue
2e-06 sec 208
    def _get(self):
209
        return self.queue.popleft()
210
211
1.2e-05 sec 212
class PriorityQueue(Queue):
213
    '''Variant of Queue that retrieves open entries in priority order (lowest first).
214
215
    Entries are typically tuples of the form:  (priority number, data).
2e-06 sec 216
    '''
217
1e-06 sec 218
    def _init(self, maxsize):
219
        self.queue = []
220
3e-06 sec 221
    def _qsize(self, len=len):
222
        return len(self.queue)
223
2e-06 sec 224
    def _put(self, item, heappush=heapq.heappush):
225
        heappush(self.queue, item)
226
3e-06 sec 227
    def _get(self, heappop=heapq.heappop):
228
        return heappop(self.queue)
229
230
1e-05 sec 231
class LifoQueue(Queue):
2e-06 sec 232
    '''Variant of Queue that retrieves most recently added entries first.'''
233
3e-06 sec 234
    def _init(self, maxsize):
235
        self.queue = []
236
2e-06 sec 237
    def _qsize(self, len=len):
238
        return len(self.queue)
239
3e-06 sec 240
    def _put(self, item):
241
        self.queue.append(item)
242
2e-06 sec 243
    def _get(self):
244
        return self.queue.pop()
/usr/lib/python2.6/SimpleHTTPServer.py
     time      num code
1
"""Simple HTTP Server.
2
3
This module builds on BaseHTTPServer by implementing the standard GET
4
and HEAD requests in a fairly straightforward manner.
5
0.000705 sec 6
"""
7
8
2e-06 sec 9
__version__ = "0.6"
10
4e-06 sec 11
__all__ = ["SimpleHTTPRequestHandler"]
12
2e-06 sec 13
import os
9e-06 sec 14
import posixpath
5e-06 sec 15
import BaseHTTPServer
2e-05 sec 16
import urllib
6e-06 sec 17
import cgi
6e-06 sec 18
import shutil
2e-05 sec 19
import mimetypes
1.6e-05 sec 20
try:
2e-06 sec 21
    from cStringIO import StringIO
22
except ImportError:
23
    from StringIO import StringIO
24
25
1.7e-05 sec 26
class SimpleHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
27
28
    """Simple HTTP request handler with GET and HEAD commands.
29
30
    This serves files from the current directory and any of its
31
    subdirectories.  The MIME type for files is determined by
32
    calling the .guess_type() method.
33
34
    The GET and HEAD requests are identical except that the HEAD
35
    request omits the actual contents of the file.
36
2e-06 sec 37
    """
38
2e-06 sec 39
    server_version = "SimpleHTTP/" + __version__
40
5e-06 sec 41
    def do_GET(self):
42
        """Serve a GET request."""
43
        f = self.send_head()
44
        if f:
45
            self.copyfile(f, self.wfile)
46
            f.close()
47
2e-06 sec 48
    def do_HEAD(self):
49
        """Serve a HEAD request."""
50
        f = self.send_head()
51
        if f:
52
            f.close()
53
3e-06 sec 54
    def send_head(self):
55
        """Common code for GET and HEAD commands.
56
57
        This sends the response code and MIME headers.
58
59
        Return value is either a file object (which has to be copied
60
        to the outputfile by the caller unless the command was HEAD,
61
        and must be closed by the caller under all circumstances), or
62
        None, in which case the caller has nothing further to do.
63
64
        """
65
        path = self.translate_path(self.path)
66
        f = None
67
        if os.path.isdir(path):
68
            if not self.path.endswith('/'):
69
                # redirect browser - doing basically what apache does
70
                self.send_response(301)
71
                self.send_header("Location", self.path + "/")
72
                self.end_headers()
73
                return None
74
            for index in "index.html", "index.htm":
75
                index = os.path.join(path, index)
76
                if os.path.exists(index):
77
                    path = index
78
                    break
79
            else:
80
                return self.list_directory(path)
81
        ctype = self.guess_type(path)
82
        try:
83
            # Always read in binary mode. Opening files in text mode may cause
84
            # newline translations, making the actual size of the content
85
            # transmitted *less* than the content-length!
86
            f = open(path, 'rb')
87
        except IOError:
88
            self.send_error(404, "File not found")
89
            return None
90
        self.send_response(200)
91
        self.send_header("Content-type", ctype)
92
        fs = os.fstat(f.fileno())
93
        self.send_header("Content-Length", str(fs[6]))
94
        self.send_header("Last-Modified", self.date_time_string(fs.st_mtime))
95
        self.end_headers()
96
        return f
97
3e-06 sec 98
    def list_directory(self, path):
99
        """Helper to produce a directory listing (absent index.html).
100
101
        Return value is either a file object, or None (indicating an
102
        error).  In either case, the headers are sent, making the
103
        interface the same as for send_head().
104
105
        """
106
        try:
107
            list = os.listdir(path)
108
        except os.error:
109
            self.send_error(404, "No permission to list directory")
110
            return None
111
        list.sort(key=lambda a: a.lower())
112
        f = StringIO()
113
        displaypath = cgi.escape(urllib.unquote(self.path))
114
        f.write('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">')
115
        f.write("<html>\n<title>Directory listing for %s</title>\n" % displaypath)
116
        f.write("<body>\n<h2>Directory listing for %s</h2>\n" % displaypath)
117
        f.write("<hr>\n<ul>\n")
118
        for name in list:
119
            fullname = os.path.join(path, name)
120
            displayname = linkname = name
121
            # Append / for directories or @ for symbolic links
122
            if os.path.isdir(fullname):
123
                displayname = name + "/"
124
                linkname = name + "/"
125
            if os.path.islink(fullname):
126
                displayname = name + "@"
127
                # Note: a link to a directory displays with @ and links with /
128
            f.write('<li><a href="%s">%s</a>\n'
129
                    % (urllib.quote(linkname), cgi.escape(displayname)))
130
        f.write("</ul>\n<hr>\n</body>\n</html>\n")
131
        length = f.tell()
132
        f.seek(0)
133
        self.send_response(200)
134
        self.send_header("Content-type", "text/html")
135
        self.send_header("Content-Length", str(length))
136
        self.end_headers()
137
        return f
138
2e-06 sec 139
    def translate_path(self, path):
140
        """Translate a /-separated PATH to the local filename syntax.
141
142
        Components that mean special things to the local file system
143
        (e.g. drive or directory names) are ignored.  (XXX They should
144
        probably be diagnosed.)
145
146
        """
147
        # abandon query parameters
148
        path = path.split('?',1)[0]
149
        path = path.split('#',1)[0]
150
        path = posixpath.normpath(urllib.unquote(path))
151
        words = path.split('/')
152
        words = filter(None, words)
153
        path = os.getcwd()
154
        for word in words:
155
            drive, word = os.path.splitdrive(word)
156
            head, word = os.path.split(word)
157
            if word in (os.curdir, os.pardir): continue
158
            path = os.path.join(path, word)
159
        return path
160
3e-06 sec 161
    def copyfile(self, source, outputfile):
162
        """Copy all data between two file objects.
163
164
        The SOURCE argument is a file object open for reading
165
        (or anything with a read() method) and the DESTINATION
166
        argument is a file object open for writing (or
167
        anything with a write() method).
168
169
        The only reason for overriding this would be to change
170
        the block size or perhaps to replace newlines by CRLF
171
        -- note however that this the default server uses this
172
        to copy binary data as well.
173
174
        """
175
        shutil.copyfileobj(source, outputfile)
176
2e-06 sec 177
    def guess_type(self, path):
178
        """Guess the type of a file.
179
180
        Argument is a PATH (a filename).
181
182
        Return value is a string of the form type/subtype,
183
        usable for a MIME Content-type header.
184
185
        The default implementation looks the file's extension
186
        up in the table self.extensions_map, using application/octet-stream
187
        as a default; however it would be permissible (if
188
        slow) to look inside the data to make a better guess.
189
190
        """
191
192
        base, ext = posixpath.splitext(path)
193
        if ext in self.extensions_map:
194
            return self.extensions_map[ext]
195
        ext = ext.lower()
196
        if ext in self.extensions_map:
197
            return self.extensions_map[ext]
198
        else:
199
            return self.extensions_map['']
200
2e-06 sec 201
    if not mimetypes.inited:
3e-06 sec 202
        mimetypes.init() # try to read system mime.types
4e-06 sec 203
    extensions_map = mimetypes.types_map.copy()
9.5e-05 sec 204
    extensions_map.update({
4e-06 sec 205
        '': 'application/octet-stream', # Default
2e-06 sec 206
        '.py': 'text/plain',
2e-06 sec 207
        '.c': 'text/plain',
3e-06 sec 208
        '.h': 'text/plain',
209
        })
210
211
2.1e-05 sec 212
def test(HandlerClass = SimpleHTTPRequestHandler,
2e-06 sec 213
         ServerClass = BaseHTTPServer.HTTPServer):
214
    BaseHTTPServer.test(HandlerClass, ServerClass)
215
216
6e-06 sec 217
if __name__ == '__main__':
218
    test()
/usr/lib/python2.6/SocketServer.py
     time      num code
1
"""Generic socket server classes.
2
3
This module tries to capture the various aspects of defining a server:
4
5
For socket-based servers:
6
7
- address family:
8
        - AF_INET{,6}: IP (Internet Protocol) sockets (default)
9
        - AF_UNIX: Unix domain sockets
10
        - others, e.g. AF_DECNET are conceivable (see <socket.h>
11
- socket type:
12
        - SOCK_STREAM (reliable stream, e.g. TCP)
13
        - SOCK_DGRAM (datagrams, e.g. UDP)
14
15
For request-based servers (including socket-based):
16
17
- client address verification before further looking at the request
18
        (This is actually a hook for any processing that needs to look
19
         at the request before anything else, e.g. logging)
20
- how to handle multiple requests:
21
        - synchronous (one request is handled at a time)
22
        - forking (each request is handled by a new process)
23
        - threading (each request is handled by a new thread)
24
25
The classes in this module favor the server type that is simplest to
26
write: a synchronous TCP/IP server.  This is bad class design, but
27
save some typing.  (There's also the issue that a deep class hierarchy
28
slows down method lookups.)
29
30
There are five classes in an inheritance diagram, four of which represent
31
synchronous servers of four types:
32
33
        +------------+
34
        | BaseServer |
35
        +------------+
36
              |
37
              v
38
        +-----------+        +------------------+
39
        | TCPServer |------->| UnixStreamServer |
40
        +-----------+        +------------------+
41
              |
42
              v
43
        +-----------+        +--------------------+
44
        | UDPServer |------->| UnixDatagramServer |
45
        +-----------+        +--------------------+
46
47
Note that UnixDatagramServer derives from UDPServer, not from
48
UnixStreamServer -- the only difference between an IP and a Unix
49
stream server is the address family, which is simply repeated in both
50
unix server classes.
51
52
Forking and threading versions of each type of server can be created
53
using the ForkingMixIn and ThreadingMixIn mix-in classes.  For
54
instance, a threading UDP server class is created as follows:
55
56
        class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass
57
58
The Mix-in class must come first, since it overrides a method defined
59
in UDPServer! Setting the various member variables also changes
60
the behavior of the underlying server mechanism.
61
62
To implement a service, you must derive a class from
63
BaseRequestHandler and redefine its handle() method.  You can then run
64
various versions of the service by combining one of the server classes
65
with your request handler class.
66
67
The request handler class must be different for datagram or stream
68
services.  This can be hidden by using the request handler
69
subclasses StreamRequestHandler or DatagramRequestHandler.
70
71
Of course, you still have to use your head!
72
73
For instance, it makes no sense to use a forking server if the service
74
contains state in memory that can be modified by requests (since the
75
modifications in the child process would never reach the initial state
76
kept in the parent process and passed to each child).  In this case,
77
you can use a threading server, but you will probably have to use
78
locks to avoid two requests that come in nearly simultaneous to apply
79
conflicting changes to the server state.
80
81
On the other hand, if you are building e.g. an HTTP server, where all
82
data is stored externally (e.g. in the file system), a synchronous
83
class will essentially render the service "deaf" while one request is
84
being handled -- which may be for a very long time if a client is slow
85
to reqd all the data it has requested.  Here a threading or forking
86
server is appropriate.
87
88
In some cases, it may be appropriate to process part of a request
89
synchronously, but to finish processing in a forked child depending on
90
the request data.  This can be implemented by using a synchronous
91
server and doing an explicit fork in the request handler class
92
handle() method.
93
94
Another approach to handling multiple simultaneous requests in an
95
environment that supports neither threads nor fork (or where these are
96
too expensive or inappropriate for the service) is to maintain an
97
explicit table of partially finished requests and to use select() to
98
decide which request to work on next (or whether to handle a new
99
incoming request).  This is particularly important for stream services
100
where each client can potentially be connected for a long time (if
101
threads or subprocesses cannot be used).
102
103
Future work:
104
- Standard classes for Sun RPC (which uses either UDP or TCP)
105
- Standard mix-in classes to implement various authentication
106
  and encryption schemes
107
- Standard framework for select-based multiplexing
108
109
XXX Open problems:
110
- What to do with out-of-band data?
111
112
BaseServer:
113
- split generic "request" functionality out into BaseServer class.
114
  Copyright (C) 2000  Luke Kenneth Casson Leighton <lkcl@samba.org>
115
116
  example: read entries from a SQL database (requires overriding
117
  get_request() to return a table entry from the database).
118
  entry is processed by a RequestHandlerClass.
119
0.000876 sec 120
"""
121
122
# Author of the BaseServer patch: Luke Kenneth Casson Leighton
123
124
# XXX Warning!
125
# There is a test suite for this module, but it cannot be run by the
126
# standard regression test.
127
# To run it manually, run Lib/test/test_socketserver.py.
128
2e-06 sec 129
__version__ = "0.4"
130
131
3e-06 sec 132
import socket
8e-06 sec 133
import select
4e-06 sec 134
import sys
5e-06 sec 135
import os
4e-06 sec 136
try:
2e-06 sec 137
    import threading
138
except ImportError:
139
    import dummy_threading as threading
140
5e-06 sec 141
__all__ = ["TCPServer","UDPServer","ForkingUDPServer","ForkingTCPServer",
2e-06 sec 142
           "ThreadingUDPServer","ThreadingTCPServer","BaseRequestHandler",
2e-06 sec 143
           "StreamRequestHandler","DatagramRequestHandler",
2e-06 sec 144
           "ThreadingMixIn", "ForkingMixIn"]
3e-06 sec 145
if hasattr(socket, "AF_UNIX"):
7e-06 sec 146
    __all__.extend(["UnixStreamServer","UnixDatagramServer",
3e-06 sec 147
                    "ThreadingUnixStreamServer",
2e-06 sec 148
                    "ThreadingUnixDatagramServer"])
149
1.1e-05 sec 150
class BaseServer:
151
152
    """Base class for server classes.
153
154
    Methods for the caller:
155
156
    - __init__(server_address, RequestHandlerClass)
157
    - serve_forever(poll_interval=0.5)
158
    - shutdown()
159
    - handle_request()  # if you do not use serve_forever()
160
    - fileno() -> int   # for select()
161
162
    Methods that may be overridden:
163
164
    - server_bind()
165
    - server_activate()
166
    - get_request() -> request, client_address
167
    - handle_timeout()
168
    - verify_request(request, client_address)
169
    - server_close()
170
    - process_request(request, client_address)
171
    - close_request(request)
172
    - handle_error()
173
174
    Methods for derived classes:
175
176
    - finish_request(request, client_address)
177
178
    Class variables that may be overridden by derived classes or
179
    instances:
180
181
    - timeout
182
    - address_family
183
    - socket_type
184
    - allow_reuse_address
185
186
    Instance variables:
187
188
    - RequestHandlerClass
189
    - socket
190
2e-06 sec 191
    """
192
1e-06 sec 193
    timeout = None
194
2e-06 sec 195
    def __init__(self, server_address, RequestHandlerClass):
196
        """Constructor.  May be extended, do not override."""
197
        self.server_address = server_address
198
        self.RequestHandlerClass = RequestHandlerClass
199
        self.__is_shut_down = threading.Event()
200
        self.__serving = False
201
2e-06 sec 202
    def server_activate(self):
203
        """Called by constructor to activate the server.
204
205
        May be overridden.
206
207
        """
208
        pass
209
2e-06 sec 210
    def serve_forever(self, poll_interval=0.5):
211
        """Handle one request at a time until shutdown.
212
213
        Polls for shutdown every poll_interval seconds. Ignores
214
        self.timeout. If you need to do periodic tasks, do them in
215
        another thread.
216
        """
217
        self.__serving = True
218
        self.__is_shut_down.clear()
219
        while self.__serving:
220
            # XXX: Consider using another file descriptor or
221
            # connecting to the socket to wake this up instead of
222
            # polling. Polling reduces our responsiveness to a
223
            # shutdown request and wastes cpu at all other times.
224
            r, w, e = select.select([self], [], [], poll_interval)
225
            if r:
226
                self._handle_request_noblock()
227
        self.__is_shut_down.set()
228
4e-06 sec 229
    def shutdown(self):
230
        """Stops the serve_forever loop.
231
232
        Blocks until the loop has finished. This must be called while
233
        serve_forever() is running in another thread, or it will
234
        deadlock.
235
        """
236
        self.__serving = False
237
        self.__is_shut_down.wait()
238
239
    # The distinction between handling, getting, processing and
240
    # finishing a request is fairly arbitrary.  Remember:
241
    #
242
    # - handle_request() is the top-level call.  It calls
243
    #   select, get_request(), verify_request() and process_request()
244
    # - get_request() is different for stream or datagram sockets
245
    # - process_request() is the place that may fork a new process
246
    #   or create a new thread to finish the request
247
    # - finish_request() instantiates the request handler class;
248
    #   this constructor will handle the request all by itself
249
2e-06 sec 250
    def handle_request(self):
251
        """Handle one request, possibly blocking.
252
253
        Respects self.timeout.
254
        """
255
        # Support people who used socket.settimeout() to escape
256
        # handle_request before self.timeout was available.
257
        timeout = self.socket.gettimeout()
258
        if timeout is None:
259
            timeout = self.timeout
260
        elif self.timeout is not None:
261
            timeout = min(timeout, self.timeout)
262
        fd_sets = select.select([self], [], [], timeout)
263
        if not fd_sets[0]:
264
            self.handle_timeout()
265
            return
266
        self._handle_request_noblock()
267
3e-06 sec 268
    def _handle_request_noblock(self):
269
        """Handle one request, without blocking.
270
271
        I assume that select.select has returned that the socket is
272
        readable before this function was called, so there should be
273
        no risk of blocking in get_request().
274
        """
275
        try:
276
            request, client_address = self.get_request()
277
        except socket.error:
278
            return
279
        if self.verify_request(request, client_address):
280
            try:
281
                self.process_request(request, client_address)
282
            except:
283
                self.handle_error(request, client_address)
284
                self.close_request(request)
285
2e-06 sec 286
    def handle_timeout(self):
287
        """Called if no new request arrives within self.timeout.
288
289
        Overridden by ForkingMixIn.
290
        """
291
        pass
292
2e-06 sec 293
    def verify_request(self, request, client_address):
294
        """Verify the request.  May be overridden.
295
296