def tearDown(self):
# wait on the server thread to terminate
-- self.evt.wait(4.0)
- # XXX this code does not work, and in fact stop_serving doesn't exist.
-- if not self.evt.is_set():
-- self.evt.set()
-- stop_serving()
-- raise RuntimeError("timeout reached, test has failed")
++ self.evt.wait()
# disable traceback reporting
xmlrpc.server.SimpleXMLRPCServer._send_traceback_header = False
# This avoids waiting for the socket timeout.
self.test_simple1()
+ def test_unicode_host(self):
+ server = xmlrpclib.ServerProxy("http://%s:%d/RPC2" % (ADDR, PORT))
+ self.assertEqual(server.add("a", "\xe9"), "a\xe9")
+
++ def test_partial_post(self):
++ # Check that a partial POST doesn't make the server loop: issue #14001.
++ conn = http.client.HTTPConnection(ADDR, PORT)
++ conn.request('POST', '/RPC2 HTTP/1.0\r\nContent-Length: 100\r\n\r\nbye')
++ conn.close()
++
++
+class MultiPathServerTestCase(BaseServerTestCase):
+ threadFunc = staticmethod(http_multi_server)
+ request_count = 2
+ def test_path1(self):
+ p = xmlrpclib.ServerProxy(URL+"/foo")
+ self.assertEqual(p.pow(6,8), 6**8)
+ self.assertRaises(xmlrpclib.Fault, p.add, 6, 8)
+
+ def test_path2(self):
+ p = xmlrpclib.ServerProxy(URL+"/foo/bar")
+ self.assertEqual(p.add(6,8), 6+8)
+ self.assertRaises(xmlrpclib.Fault, p.pow, 6, 8)
+
+ def test_path3(self):
+ p = xmlrpclib.ServerProxy(URL+"/is/broken")
+ self.assertRaises(xmlrpclib.Fault, p.add, 6, 8)
+
+#A test case that verifies that a server using the HTTP/1.1 keep-alive mechanism
+#does indeed serve subsequent requests on the same connection
+class BaseKeepaliveServerTestCase(BaseServerTestCase):
+ #a request handler that supports keep-alive and logs requests into a
+ #class variable
+ class RequestHandler(xmlrpc.server.SimpleXMLRPCRequestHandler):
+ parentClass = xmlrpc.server.SimpleXMLRPCRequestHandler
+ protocol_version = 'HTTP/1.1'
+ myRequests = []
+ def handle(self):
+ self.myRequests.append([])
+ self.reqidx = len(self.myRequests)-1
+ return self.parentClass.handle(self)
+ def handle_one_request(self):
+ result = self.parentClass.handle_one_request(self)
+ self.myRequests[self.reqidx].append(self.raw_requestline)
+ return result
+
+ requestHandler = RequestHandler
+ def setUp(self):
+ #clear request log
+ self.RequestHandler.myRequests = []
+ return BaseServerTestCase.setUp(self)
+
+#A test case that verifies that a server using the HTTP/1.1 keep-alive mechanism
+#does indeed serve subsequent requests on the same connection
+class KeepaliveServerTestCase1(BaseKeepaliveServerTestCase):
+ def test_two(self):
+ p = xmlrpclib.ServerProxy(URL)
+ #do three requests.
+ self.assertEqual(p.pow(6,8), 6**8)
+ self.assertEqual(p.pow(6,8), 6**8)
+ self.assertEqual(p.pow(6,8), 6**8)
+ p("close")()
+
+ #they should have all been handled by a single request handler
+ self.assertEqual(len(self.RequestHandler.myRequests), 1)
+
+ #check that we did at least two (the third may be pending append
+ #due to thread scheduling)
+ self.assertGreaterEqual(len(self.RequestHandler.myRequests[-1]), 2)
+
+
+#test special attribute access on the serverproxy, through the __call__
+#function.
+class KeepaliveServerTestCase2(BaseKeepaliveServerTestCase):
+ #ask for two keepalive requests to be handled.
+ request_count=2
+
+ def test_close(self):
+ p = xmlrpclib.ServerProxy(URL)
+ #do some requests with close.
+ self.assertEqual(p.pow(6,8), 6**8)
+ self.assertEqual(p.pow(6,8), 6**8)
+ self.assertEqual(p.pow(6,8), 6**8)
+ p("close")() #this should trigger a new keep-alive request
+ self.assertEqual(p.pow(6,8), 6**8)
+ self.assertEqual(p.pow(6,8), 6**8)
+ self.assertEqual(p.pow(6,8), 6**8)
+ p("close")()
+
+ #they should have all been two request handlers, each having logged at least
+ #two complete requests
+ self.assertEqual(len(self.RequestHandler.myRequests), 2)
+ self.assertGreaterEqual(len(self.RequestHandler.myRequests[-1]), 2)
+ self.assertGreaterEqual(len(self.RequestHandler.myRequests[-2]), 2)
+
+
+ def test_transport(self):
+ p = xmlrpclib.ServerProxy(URL)
+ #do some requests with close.
+ self.assertEqual(p.pow(6,8), 6**8)
+ p("transport").close() #same as above, really.
+ self.assertEqual(p.pow(6,8), 6**8)
+ p("close")()
+ self.assertEqual(len(self.RequestHandler.myRequests), 2)
+
+#A test case that verifies that gzip encoding works in both directions
+#(for a request and the response)
+class GzipServerTestCase(BaseServerTestCase):
+ #a request handler that supports keep-alive and logs requests into a
+ #class variable
+ class RequestHandler(xmlrpc.server.SimpleXMLRPCRequestHandler):
+ parentClass = xmlrpc.server.SimpleXMLRPCRequestHandler
+ protocol_version = 'HTTP/1.1'
+
+ def do_POST(self):
+ #store content of last request in class
+ self.__class__.content_length = int(self.headers["content-length"])
+ return self.parentClass.do_POST(self)
+ requestHandler = RequestHandler
+
+ class Transport(xmlrpclib.Transport):
+ #custom transport, stores the response length for our perusal
+ fake_gzip = False
+ def parse_response(self, response):
+ self.response_length=int(response.getheader("content-length", 0))
+ return xmlrpclib.Transport.parse_response(self, response)
+
+ def send_content(self, connection, body):
+ if self.fake_gzip:
+ #add a lone gzip header to induce decode error remotely
+ connection.putheader("Content-Encoding", "gzip")
+ return xmlrpclib.Transport.send_content(self, connection, body)
+
+ def setUp(self):
+ BaseServerTestCase.setUp(self)
+
+ def test_gzip_request(self):
+ t = self.Transport()
+ t.encode_threshold = None
+ p = xmlrpclib.ServerProxy(URL, transport=t)
+ self.assertEqual(p.pow(6,8), 6**8)
+ a = self.RequestHandler.content_length
+ t.encode_threshold = 0 #turn on request encoding
+ self.assertEqual(p.pow(6,8), 6**8)
+ b = self.RequestHandler.content_length
+ self.assertTrue(a>b)
+ p("close")()
+
+ def test_bad_gzip_request(self):
+ t = self.Transport()
+ t.encode_threshold = None
+ t.fake_gzip = True
+ p = xmlrpclib.ServerProxy(URL, transport=t)
+ cm = self.assertRaisesRegex(xmlrpclib.ProtocolError,
+ re.compile(r"\b400\b"))
+ with cm:
+ p.pow(6, 8)
+ p("close")()
+
+ def test_gsip_response(self):
+ t = self.Transport()
+ p = xmlrpclib.ServerProxy(URL, transport=t)
+ old = self.requestHandler.encode_threshold
+ self.requestHandler.encode_threshold = None #no encoding
+ self.assertEqual(p.pow(6,8), 6**8)
+ a = t.response_length
+ self.requestHandler.encode_threshold = 0 #always encode
+ self.assertEqual(p.pow(6,8), 6**8)
+ p("close")()
+ b = t.response_length
+ self.requestHandler.encode_threshold = old
+ self.assertTrue(a>b)
+
+#Test special attributes of the ServerProxy object
+class ServerProxyTestCase(unittest.TestCase):
+ def setUp(self):
+ unittest.TestCase.setUp(self)
+ if threading:
+ self.url = URL
+ else:
+ # Without threading, http_server() and http_multi_server() will not
+ # be executed and URL is still equal to None. 'http://' is a just
+ # enough to choose the scheme (HTTP)
+ self.url = 'http://'
+
+ def test_close(self):
+ p = xmlrpclib.ServerProxy(self.url)
+ self.assertEqual(p('close')(), None)
+
+ def test_transport(self):
+ t = xmlrpclib.Transport()
+ p = xmlrpclib.ServerProxy(self.url, transport=t)
+ self.assertEqual(p('transport'), t)
+
# This is a contrived way to make a failure occur on the server side
# in order to test the _send_traceback_header flag on the server
class FailingMessageClass(http.client.HTTPMessage):
Library
-------
+ - Issue #14001: CVE-2012-0845: xmlrpc: Fix an endless loop in
+ SimpleXMLRPCServer upon malformed POST request.
+
+- Issue #2489: pty.spawn could consume 100% cpu when it encountered an EOF.
+
+- Issue #13014: Fix a possible reference leak in SSLSocket.getpeercert().
+
+- Issue #13015: Fix a possible reference leak in defaultdict.__repr__.
+ Patch by Suman Saha.
+
+- Issue #1326113: distutils' build_ext command --libraries option now
+ correctly parses multiple values separated by whitespace or commas.
+
+- Issue #10287: nntplib now queries the server's CAPABILITIES first before
+ sending MODE READER, and only sends it if not already in READER mode.
+ Patch by Hynek Schlawack.
+
+- Issue #13979: A bug in ctypes.util.find_library that caused
+ the wrong library name to be returned has been fixed.
+
+- Issue #13993: HTMLParser is now able to handle broken end tags when
+ strict=False.
+
+- Issue #9750: Fix sqlite3.Connection.iterdump on tables and fields
+ with a name that is a keyword or contains quotes. Patch by Marko
+ Kohtala.
+
+- Issue #10287: nntplib now queries the server's CAPABILITIES again after
+ authenticating (since the result may change, according to RFC 4643).
+ Patch by Hynek Schlawack.
+
+- Issue #13989: Document that GzipFile does not support text mode, and give a
+ more helpful error message when opened with an invalid mode string.
+
+- Issue #13590: On OS X 10.7 and 10.6 with Xcode 4.2, building
+ Distutils-based packages with C extension modules may fail because
+ Apple has removed gcc-4.2, the version used to build python.org
+ 64-bit/32-bit Pythons. If the user does not explicitly override
+ the default C compiler by setting the CC environment variable,
+ Distutils will now attempt to compile extension modules with clang
+ if gcc-4.2 is required but not found. Also as a convenience, if
+ the user does explicitly set CC, substitute its value as the default
+ compiler in the Distutils LDSHARED configuration variable for OS X.
+ (Note, the python.org 32-bit-only Pythons use gcc-4.0 and the 10.4u
+ SDK, neither of which are available in Xcode 4. This change does not
+ attempt to override settings to support their use with Xcode 4.)
+
+- Issue #13960: HTMLParser is now able to handle broken comments when
+ strict=False.
+
+- Issue #9021: Add an introduction to the copy module documentation.
+
+- Issue #6005: Examples in the socket library documentation use sendall, where
+ relevant, instead send method.
+
+- Issue #10811: Fix recursive usage of cursors. Instead of crashing,
+ raise a ProgrammingError now.
+
+- Issue #10881: Fix test_site failure with OS X framework builds.
+
+- Issue #964437: Make IDLE help window non-modal.
+ Patch by Guilherme Polo and Roger Serwy.
+
+- Issue #2945: Make the distutils upload command aware of bdist_rpm products.
+
+- Issue #13933: IDLE auto-complete did not work with some imported
+ module, like hashlib. (Patch by Roger Serwy)
+
+- Issue #13901: Prevent test_distutils failures on OS X with --enable-shared.
+
+- Issue #13676: Handle strings with embedded zeros correctly in sqlite3.
+
+- Issue #13506: Add '' to path for IDLE Shell when started and restarted with Restart Shell.
+ Original patches by Marco Scataglini and Roger Serwy.
+
+- Issue #13848: open() and the FileIO constructor now check for NUL
+ characters in the file name. Patch by Hynek Schlawack.
+
+- Issue #13806: The size check in audioop decompression functions was too
+ strict and could reject valid compressed data. Patch by Oleg Plakhotnyuk.
+
+- Issue #13812: When a multiprocessing Process child raises an exception,
+ flush stderr after printing the exception traceback.
+
- Issue #13885: CVE-2011-3389: the _ssl module would always disable the CBC
IV attack countermeasure.