You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
145 lines
4.6 KiB
145 lines
4.6 KiB
4 years ago
|
diff --git a/Lib/DocXMLRPCServer.py b/Lib/DocXMLRPCServer.py
|
||
|
index 4064ec2..90b037d 100644
|
||
|
--- a/Lib/DocXMLRPCServer.py
|
||
|
+++ b/Lib/DocXMLRPCServer.py
|
||
|
@@ -20,6 +20,16 @@ from SimpleXMLRPCServer import (SimpleXMLRPCServer,
|
||
|
CGIXMLRPCRequestHandler,
|
||
|
resolve_dotted_attribute)
|
||
|
|
||
|
+
|
||
|
+def _html_escape_quote(s):
|
||
|
+ s = s.replace("&", "&") # Must be done first!
|
||
|
+ s = s.replace("<", "<")
|
||
|
+ s = s.replace(">", ">")
|
||
|
+ s = s.replace('"', """)
|
||
|
+ s = s.replace('\'', "'")
|
||
|
+ return s
|
||
|
+
|
||
|
+
|
||
|
class ServerHTMLDoc(pydoc.HTMLDoc):
|
||
|
"""Class used to generate pydoc HTML document for a server"""
|
||
|
|
||
|
@@ -210,7 +220,8 @@ class XMLRPCDocGenerator:
|
||
|
methods
|
||
|
)
|
||
|
|
||
|
- return documenter.page(self.server_title, documentation)
|
||
|
+ title = _html_escape_quote(self.server_title)
|
||
|
+ return documenter.page(title, documentation)
|
||
|
|
||
|
class DocXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||
|
"""XML-RPC and documentation request handler class.
|
||
|
diff --git a/Lib/test/test_docxmlrpc.py b/Lib/test/test_docxmlrpc.py
|
||
|
index 80d1803..d464ef8 100644
|
||
|
--- a/Lib/test/test_docxmlrpc.py
|
||
|
+++ b/Lib/test/test_docxmlrpc.py
|
||
|
@@ -1,13 +1,11 @@
|
||
|
from DocXMLRPCServer import DocXMLRPCServer
|
||
|
import httplib
|
||
|
+import re
|
||
|
import sys
|
||
|
from test import test_support
|
||
|
threading = test_support.import_module('threading')
|
||
|
-import time
|
||
|
-import socket
|
||
|
import unittest
|
||
|
|
||
|
-PORT = None
|
||
|
|
||
|
def make_request_and_skipIf(condition, reason):
|
||
|
# If we skip the test, we have to make a request because the
|
||
|
@@ -23,13 +21,10 @@ def make_request_and_skipIf(condition, reason):
|
||
|
return decorator
|
||
|
|
||
|
|
||
|
-def server(evt, numrequests):
|
||
|
+def make_server():
|
||
|
serv = DocXMLRPCServer(("localhost", 0), logRequests=False)
|
||
|
|
||
|
try:
|
||
|
- global PORT
|
||
|
- PORT = serv.socket.getsockname()[1]
|
||
|
-
|
||
|
# Add some documentation
|
||
|
serv.set_server_title("DocXMLRPCServer Test Documentation")
|
||
|
serv.set_server_name("DocXMLRPCServer Test Docs")
|
||
|
@@ -56,42 +51,31 @@ def server(evt, numrequests):
|
||
|
|
||
|
serv.register_function(add)
|
||
|
serv.register_function(lambda x, y: x-y)
|
||
|
-
|
||
|
- while numrequests > 0:
|
||
|
- serv.handle_request()
|
||
|
- numrequests -= 1
|
||
|
- except socket.timeout:
|
||
|
- pass
|
||
|
- finally:
|
||
|
+ return serv
|
||
|
+ except:
|
||
|
serv.server_close()
|
||
|
- PORT = None
|
||
|
- evt.set()
|
||
|
+ raise
|
||
|
|
||
|
class DocXMLRPCHTTPGETServer(unittest.TestCase):
|
||
|
def setUp(self):
|
||
|
- self._threads = test_support.threading_setup()
|
||
|
# Enable server feedback
|
||
|
DocXMLRPCServer._send_traceback_header = True
|
||
|
|
||
|
- self.evt = threading.Event()
|
||
|
- threading.Thread(target=server, args=(self.evt, 1)).start()
|
||
|
-
|
||
|
- # wait for port to be assigned
|
||
|
- n = 1000
|
||
|
- while n > 0 and PORT is None:
|
||
|
- time.sleep(0.001)
|
||
|
- n -= 1
|
||
|
+ self.serv = make_server()
|
||
|
+ self.thread = threading.Thread(target=self.serv.serve_forever)
|
||
|
+ self.thread.start()
|
||
|
|
||
|
+ PORT = self.serv.server_address[1]
|
||
|
self.client = httplib.HTTPConnection("localhost:%d" % PORT)
|
||
|
|
||
|
def tearDown(self):
|
||
|
self.client.close()
|
||
|
|
||
|
- self.evt.wait()
|
||
|
-
|
||
|
# Disable server feedback
|
||
|
DocXMLRPCServer._send_traceback_header = False
|
||
|
- test_support.threading_cleanup(*self._threads)
|
||
|
+ self.serv.shutdown()
|
||
|
+ self.thread.join()
|
||
|
+ self.serv.server_close()
|
||
|
|
||
|
def test_valid_get_response(self):
|
||
|
self.client.request("GET", "/")
|
||
|
@@ -194,6 +178,25 @@ class DocXMLRPCHTTPGETServer(unittest.TestCase):
|
||
|
self.assertIn("""Try self.<strong>add</strong>, too.""",
|
||
|
response.read())
|
||
|
|
||
|
+ def test_server_title_escape(self):
|
||
|
+ """Test that the server title and documentation
|
||
|
+ are escaped for HTML.
|
||
|
+ """
|
||
|
+ self.serv.set_server_title('test_title<script>')
|
||
|
+ self.serv.set_server_documentation('test_documentation<script>')
|
||
|
+ self.assertEqual('test_title<script>', self.serv.server_title)
|
||
|
+ self.assertEqual('test_documentation<script>',
|
||
|
+ self.serv.server_documentation)
|
||
|
+
|
||
|
+ generated = self.serv.generate_html_documentation()
|
||
|
+ title = re.search(r'<title>(.+?)</title>', generated).group()
|
||
|
+ documentation = re.search(r'<p><tt>(.+?)</tt></p>', generated).group()
|
||
|
+ self.assertEqual('<title>Python: test_title<script></title>',
|
||
|
+ title)
|
||
|
+ self.assertEqual('<p><tt>test_documentation<script></tt></p>',
|
||
|
+ documentation)
|
||
|
+
|
||
|
+
|
||
|
def test_main():
|
||
|
test_support.run_unittest(DocXMLRPCHTTPGETServer)
|
||
|
|