Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b533e26

Browse files
committed
Merged revisions 63412,63445-63447,63449-63450,63452,63454,63459,63463,63465,63470,63483-63484,63496-63497,63499-63501,63530-63531,63540,63614 via svnmerge from
svn+ssh://[email protected]/python/trunk ........ r63412 | georg.brandl | 2008-05-17 19:57:01 +0200 (Sat, 17 May 2008) | 2 lines #961805: fix Edit.text_modified(). ........ r63445 | georg.brandl | 2008-05-18 10:52:59 +0200 (Sun, 18 May 2008) | 2 lines GHOP #180 by Michael Schneider: add examples to the socketserver documentation. ........ r63446 | georg.brandl | 2008-05-18 11:12:20 +0200 (Sun, 18 May 2008) | 2 lines GHOP #134, #171, #137: unit tests for the three HTTPServer modules. ........ r63447 | georg.brandl | 2008-05-18 12:39:26 +0200 (Sun, 18 May 2008) | 3 lines Take namedtuple item names only from ascii_letters (this blew up on OSX), and make sure there are no duplicate names. ........ r63449 | georg.brandl | 2008-05-18 13:46:51 +0200 (Sun, 18 May 2008) | 2 lines GHOP #217: add support for compiling Python with coverage checking enabled. ........ r63450 | georg.brandl | 2008-05-18 13:52:36 +0200 (Sun, 18 May 2008) | 2 lines GHOP #257: test distutils' build_ext command, written by Josip Dzolonga. ........ r63452 | georg.brandl | 2008-05-18 15:34:06 +0200 (Sun, 18 May 2008) | 2 lines Add GHOP students. ........ r63454 | georg.brandl | 2008-05-18 18:32:48 +0200 (Sun, 18 May 2008) | 2 lines GHOP #121: improve test_pydoc, by Benjamin Peterson. ........ r63459 | benjamin.peterson | 2008-05-18 22:48:07 +0200 (Sun, 18 May 2008) | 2 lines bring test_pydoc up to my high standards (now that I have them) ........ r63463 | georg.brandl | 2008-05-18 23:10:19 +0200 (Sun, 18 May 2008) | 2 lines Fix test_pyclbr after another platform-dependent function was added to urllib. ........ r63465 | benjamin.peterson | 2008-05-19 01:07:07 +0200 (Mon, 19 May 2008) | 2 lines change some imports in tests so they will not be skipped in 3.0 ........ r63470 | georg.brandl | 2008-05-19 18:47:25 +0200 (Mon, 19 May 2008) | 2 lines test_httpservers has unpredictable refcount behavior. ........ r63483 | georg.brandl | 2008-05-20 08:15:36 +0200 (Tue, 20 May 2008) | 2 lines Activate two more test cases in test_httpservers. ........ r63484 | georg.brandl | 2008-05-20 08:47:31 +0200 (Tue, 20 May 2008) | 2 lines Argh, this is the *actual* test that works under Windows. ........ r63496 | georg.brandl | 2008-05-20 10:07:36 +0200 (Tue, 20 May 2008) | 2 lines Improve diffing logic and output for test_pydoc. ........ r63497 | georg.brandl | 2008-05-20 10:10:03 +0200 (Tue, 20 May 2008) | 2 lines Use inspect.getabsfile() to get the documented module's filename. ........ r63499 | georg.brandl | 2008-05-20 10:25:48 +0200 (Tue, 20 May 2008) | 3 lines Patch #1775025: allow opening zipfile members via ZipInfo instances. Patch by Graham Horler. ........ r63500 | georg.brandl | 2008-05-20 10:40:43 +0200 (Tue, 20 May 2008) | 2 lines #2592: delegate nb_index and the floor/truediv slots in weakref.proxy. ........ r63501 | georg.brandl | 2008-05-20 10:48:34 +0200 (Tue, 20 May 2008) | 2 lines #615772: raise a more explicit error from Tkinter.Misc.__contains__. ........ r63530 | benjamin.peterson | 2008-05-22 02:57:02 +0200 (Thu, 22 May 2008) | 2 lines use more specific asserts in test_opcode ........ r63531 | benjamin.peterson | 2008-05-22 03:02:23 +0200 (Thu, 22 May 2008) | 2 lines remove redundant invocation of json doctests ........ r63540 | benjamin.peterson | 2008-05-23 01:09:26 +0200 (Fri, 23 May 2008) | 3 lines fix test_pydoc so it works on make installed Python installations Also let it pass when invoked directly ........ r63614 | georg.brandl | 2008-05-25 10:07:37 +0200 (Sun, 25 May 2008) | 2 lines #2959: allow multiple close() calls for GzipFile. ........
1 parent cea7774 commit b533e26

23 files changed

Lines changed: 1135 additions & 97 deletions

Doc/library/socketserver.rst

Lines changed: 233 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -236,8 +236,8 @@ users of the server object.
236236

237237
.. function:: handle_timeout()
238238

239-
This function is called when the :attr:`timeout` attribute has been set to a
240-
value other than :const:`None` and the timeout period has passed with no
239+
This function is called when the :attr:`timeout` attribute has been set to a
240+
value other than :const:`None` and the timeout period has passed with no
241241
requests being received. The default action for forking servers is
242242
to collect the status of any child processes that have exited, while
243243
in threading servers this method does nothing.
@@ -284,31 +284,246 @@ request.
284284

285285
.. function:: finish()
286286

287-
Called after the :meth:`handle` method to perform any clean-up actions required.
288-
The default implementation does nothing. If :meth:`setup` or :meth:`handle`
289-
raise an exception, this function will not be called.
287+
Called after the :meth:`handle` method to perform any clean-up actions
288+
required. The default implementation does nothing. If :meth:`setup` or
289+
:meth:`handle` raise an exception, this function will not be called.
290290

291291

292292
.. function:: handle()
293293

294-
This function must do all the work required to service a request. The default
295-
implementation does nothing. Several instance attributes are available to it;
296-
the request is available as :attr:`self.request`; the client address as
297-
:attr:`self.client_address`; and the server instance as :attr:`self.server`, in
298-
case it needs access to per-server information.
294+
This function must do all the work required to service a request. The
295+
default implementation does nothing. Several instance attributes are
296+
available to it; the request is available as :attr:`self.request`; the client
297+
address as :attr:`self.client_address`; and the server instance as
298+
:attr:`self.server`, in case it needs access to per-server information.
299299

300-
The type of :attr:`self.request` is different for datagram or stream services.
301-
For stream services, :attr:`self.request` is a socket object; for datagram
302-
services, :attr:`self.request` is a string. However, this can be hidden by using
303-
the request handler subclasses :class:`StreamRequestHandler` or
304-
:class:`DatagramRequestHandler`, which override the :meth:`setup` and
305-
:meth:`finish` methods, and provide :attr:`self.rfile` and :attr:`self.wfile`
306-
attributes. :attr:`self.rfile` and :attr:`self.wfile` can be read or written,
307-
respectively, to get the request data or return data to the client.
300+
The type of :attr:`self.request` is different for datagram or stream
301+
services. For stream services, :attr:`self.request` is a socket object; for
302+
datagram services, :attr:`self.request` is a pair of string and socket.
303+
However, this can be hidden by using the request handler subclasses
304+
:class:`StreamRequestHandler` or :class:`DatagramRequestHandler`, which
305+
override the :meth:`setup` and :meth:`finish` methods, and provide
306+
:attr:`self.rfile` and :attr:`self.wfile` attributes. :attr:`self.rfile` and
307+
:attr:`self.wfile` can be read or written, respectively, to get the request
308+
data or return data to the client.
308309

309310

310311
.. function:: setup()
311312

312313
Called before the :meth:`handle` method to perform any initialization actions
313314
required. The default implementation does nothing.
314315

316+
317+
Examples
318+
--------
319+
320+
:class:`socketserver.TCPServer` Example
321+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
322+
323+
This is the server side::
324+
325+
import socketserver
326+
327+
class MyTCPHandler(socketserver.BaseRequestHandler):
328+
"""
329+
The RequestHandler class for our server.
330+
331+
It is instantiated once per connection to the server, and must
332+
override the handle() method to implement communication to the
333+
client.
334+
"""
335+
336+
def handle(self):
337+
# self.request is the TCP socket connected to the client
338+
self.data = self.request.recv(1024).strip()
339+
print "%s wrote:" % self.client_address[0]
340+
print self.data
341+
# just send back the same data, but upper-cased
342+
self.request.send(self.data.upper())
343+
344+
if __name__ == "__main__":
345+
HOST, PORT = "localhost", 9999
346+
347+
# Create the server, binding to localhost on port 9999
348+
server = socketserver.TCPServer((HOST, PORT), MyTCPHandler)
349+
350+
# Activate the server; this will keep running until you
351+
# interrupt the program with Ctrl-C
352+
server.serve_forever()
353+
354+
An alternative request handler class that makes use of streams (file-like
355+
objects that simplify communication by providing the standard file interface)::
356+
357+
class MyTCPHandler(socketserver.StreamRequestHandler):
358+
359+
def handle(self):
360+
# self.rfile is a file-like object created by the handler;
361+
# we can now use e.g. readline() instead of raw recv() calls
362+
self.data = self.rfile.readline().strip()
363+
print "%s wrote:" % self.client_address[0]
364+
print self.data
365+
# Likewise, self.wfile is a file-like object used to write back
366+
# to the client
367+
self.wfile.write(self.data.upper())
368+
369+
The difference is that the ``readline()`` call in the second handler will call
370+
``recv()`` multiple times until it encounters a newline character, while the
371+
single ``recv()`` call in the first handler will just return what has been sent
372+
from the client in one ``send()`` call.
373+
374+
375+
This is the client side::
376+
377+
import socket
378+
import sys
379+
380+
HOST, PORT = "localhost", 9999
381+
data = " ".join(sys.argv[1:])
382+
383+
# Create a socket (SOCK_STREAM means a TCP socket)
384+
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
385+
386+
# Connect to server and send data
387+
sock.connect((HOST, PORT))
388+
sock.send(data + "\n")
389+
390+
# Receive data from the server and shut down
391+
received = sock.recv(1024)
392+
sock.close()
393+
394+
print "Sent: %s" % data
395+
print "Received: %s" % received
396+
397+
398+
The output of the example should look something like this:
399+
400+
Server::
401+
402+
$ python TCPServer.py
403+
127.0.0.1 wrote:
404+
hello world with TCP
405+
127.0.0.1 wrote:
406+
python is nice
407+
408+
Client::
409+
410+
$ python TCPClient.py hello world with TCP
411+
Sent: hello world with TCP
412+
Received: HELLO WORLD WITH TCP
413+
$ python TCPClient.py python is nice
414+
Sent: python is nice
415+
Received: PYTHON IS NICE
416+
417+
418+
:class:`socketserver.UDPServer` Example
419+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
420+
421+
This is the server side::
422+
423+
import socketserver
424+
425+
class MyUDPHandler(socketserver.BaseRequestHandler):
426+
"""
427+
This class works similar to the TCP handler class, except that
428+
self.request consists of a pair of data and client socket, and since
429+
there is no connection the client address must be given explicitly
430+
when sending data back via sendto().
431+
"""
432+
433+
def handle(self):
434+
data = self.request[0].strip()
435+
socket = self.request[1]
436+
print "%s wrote:" % self.client_address[0]
437+
print data
438+
socket.sendto(data.upper(), self.client_address)
439+
440+
if __name__ == "__main__":
441+
HOST, PORT = "localhost", 9999
442+
server = socketserver.UDPServer((HOST, PORT), BaseUDPRequestHandler)
443+
server.serve_forever()
444+
445+
This is the client side::
446+
447+
import socket
448+
import sys
449+
450+
HOST, PORT = "localhost"
451+
data = " ".join(sys.argv[1:])
452+
453+
# SOCK_DGRAM is the socket type to use for UDP sockets
454+
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
455+
456+
# As you can see, there is no connect() call; UDP has no connections.
457+
# Instead, data is directly sent to the recipient via sendto().
458+
sock.sendto(data + "\n", (HOST, PORT))
459+
received = sock.recv(1024)
460+
461+
print "Sent: %s" % data
462+
print "Received: %s" % received
463+
464+
The output of the example should look exactly like for the TCP server example.
465+
466+
467+
Asynchronous Mixins
468+
~~~~~~~~~~~~~~~~~~~
469+
470+
To build asynchronous handlers, use the :class:`ThreadingMixIn` and
471+
:class:`ForkingMixIn` classes.
472+
473+
An example for the :class:`ThreadingMixIn` class::
474+
475+
import socket
476+
import threading
477+
import socketserver
478+
479+
class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
480+
481+
def handle(self):
482+
data = self.request.recv(1024)
483+
cur_thread = threading.currentThread()
484+
response = "%s: %s" % (cur_thread.getName(), data)
485+
self.request.send(response)
486+
487+
class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
488+
pass
489+
490+
def client(ip, port, message):
491+
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
492+
sock.connect((ip, port))
493+
sock.send(message)
494+
response = sock.recv(1024)
495+
print "Received: %s" % response
496+
sock.close()
497+
498+
if __name__ == "__main__":
499+
# Port 0 means to select an arbitrary unused port
500+
HOST, PORT = "localhost", 0
501+
502+
server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
503+
ip, port = server.server_address
504+
505+
# Start a thread with the server -- that thread will then start one
506+
# more thread for each request
507+
server_thread = threading.Thread(target=server.serve_forever)
508+
# Exit the server thread when the main thread terminates
509+
server_thread.setDaemon(True)
510+
server_thread.start()
511+
print "Server loop running in thread:", t.getName()
512+
513+
client(ip, port, "Hello World 1")
514+
client(ip, port, "Hello World 2")
515+
client(ip, port, "Hello World 3")
516+
517+
server.shutdown()
518+
519+
The output of the example should look something like this::
520+
521+
$ python ThreadedTCPServer.py
522+
Server loop running in thread: Thread-1
523+
Received: Thread-2: Hello World 1
524+
Received: Thread-3: Hello World 2
525+
Received: Thread-4: Hello World 3
526+
527+
528+
The :class:`ForkingMixIn` class is used in the same way, except that the server
529+
will spawn a new process for each request.

Doc/library/zipfile.rst

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -150,11 +150,11 @@ ZipFile Objects
150150
.. method:: ZipFile.open(name[, mode[, pwd]])
151151

152152
Extract a member from the archive as a file-like object (ZipExtFile). *name* is
153-
the name of the file in the archive. The *mode* parameter, if included, must be
154-
one of the following: ``'r'`` (the default), ``'U'``, or ``'rU'``. Choosing
155-
``'U'`` or ``'rU'`` will enable universal newline support in the read-only
156-
object. *pwd* is the password used for encrypted files. Calling :meth:`open`
157-
on a closed ZipFile will raise a :exc:`RuntimeError`.
153+
the name of the file in the archive, or a :class:`ZipInfo` object. The *mode*
154+
parameter, if included, must be one of the following: ``'r'`` (the default),
155+
``'U'``, or ``'rU'``. Choosing ``'U'`` or ``'rU'`` will enable universal newline
156+
support in the read-only object. *pwd* is the password used for encrypted files.
157+
Calling :meth:`open` on a closed ZipFile will raise a :exc:`RuntimeError`.
158158

159159
.. note::
160160

@@ -173,14 +173,20 @@ ZipFile Objects
173173
create a new file object that will be held by the ZipExtFile, allowing it to
174174
operate independently of the ZipFile.
175175

176+
.. note::
177+
178+
The :meth:`open`, :meth:`read` and :meth:`extract` methods can take a filename
179+
or a :class:`ZipInfo` object. You will appreciate this when trying to read a
180+
ZIP file that contains members with duplicate names.
181+
176182

177183
.. method:: ZipFile.extract(member[, path[, pwd]])
178184

179-
Extract a member from the archive to the current working directory, using its
180-
full name. Its file information is extracted as accurately as possible.
181-
*path* specifies a different directory to extract to. *member* can be a
182-
filename or a :class:`ZipInfo` object. *pwd* is the password used for
183-
encrypted files.
185+
Extract a member from the archive to the current working directory; *member*
186+
must be its full name or a :class:`ZipInfo` object). Its file information is
187+
extracted as accurately as possible. *path* specifies a different directory
188+
to extract to. *member* can be a filename or a :class:`ZipInfo` object.
189+
*pwd* is the password used for encrypted files.
184190

185191

186192
.. method:: ZipFile.extractall([path[, members[, pwd]]])
@@ -203,9 +209,10 @@ ZipFile Objects
203209

204210
.. method:: ZipFile.read(name[, pwd])
205211

206-
Return the bytes of the file in the archive. The archive must be open for read
207-
or append. *pwd* is the password used for encrypted files and, if specified, it
208-
will override the default password set with :meth:`setpassword`. Calling
212+
Return the bytes of the file *name* in the archive. *name* is the name of the
213+
file in the archive, or a :class:`ZipInfo` object. The archive must be open for
214+
read or append. *pwd* is the password used for encrypted files and, if specified,
215+
it will override the default password set with :meth:`setpassword`. Calling
209216
:meth:`read` on a closed ZipFile will raise a :exc:`RuntimeError`.
210217

211218

Lib/BaseHTTPServer.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,12 @@ class BaseHTTPRequestHandler(socketserver.StreamRequestHandler):
222222
error_message_format = DEFAULT_ERROR_MESSAGE
223223
error_content_type = DEFAULT_ERROR_CONTENT_TYPE
224224

225+
# The default request version. This only affects responses up until
226+
# the point where the request line is parsed, so it mainly decides what
227+
# the client gets back when sending a malformed request line.
228+
# Most web servers default to HTTP 0.9, i.e. don't send a status line.
229+
default_request_version = "HTTP/0.9"
230+
225231
def parse_request(self):
226232
"""Parse a request (internal).
227233
@@ -234,7 +240,7 @@ def parse_request(self):
234240
235241
"""
236242
self.command = None # set in case of error on the first line
237-
self.request_version = version = "HTTP/0.9" # Default
243+
self.request_version = version = self.default_request_version
238244
self.close_connection = 1
239245
requestline = str(self.raw_requestline, 'iso-8859-1')
240246
if requestline[-2:] == '\r\n':

Lib/CGIHTTPServer.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,8 +182,10 @@ def run_cgi(self):
182182
env['AUTH_TYPE'] = authorization[0]
183183
if authorization[0].lower() == "basic":
184184
try:
185-
authorization = base64.decodestring(authorization[1])
186-
except binascii.Error:
185+
authorization = authorization[1].encode('ascii')
186+
authorization = base64.decodestring(authorization).\
187+
decode('ascii')
188+
except (binascii.Error, UnicodeError):
187189
pass
188190
else:
189191
authorization = authorization.split(':')

0 commit comments

Comments
 (0)