summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_cgi.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/test/test_cgi.py')
-rw-r--r--Lib/test/test_cgi.py371
1 files changed, 125 insertions, 246 deletions
diff --git a/Lib/test/test_cgi.py b/Lib/test/test_cgi.py
index ab86771..743c2af 100644
--- a/Lib/test/test_cgi.py
+++ b/Lib/test/test_cgi.py
@@ -1,11 +1,12 @@
+from io import BytesIO
+from test.test_support import run_unittest, check_warnings
import cgi
import os
import sys
import tempfile
import unittest
+
from collections import namedtuple
-from io import StringIO, BytesIO
-from test import support
class HackedSysModule:
# The regression test will have real values in sys.argv, which
@@ -15,6 +16,11 @@ class HackedSysModule:
cgi.sys = HackedSysModule()
+try:
+ from cStringIO import StringIO
+except ImportError:
+ from StringIO import StringIO
+
class ComparableException:
def __init__(self, err):
self.err = err
@@ -22,11 +28,13 @@ class ComparableException:
def __str__(self):
return str(self.err)
- def __eq__(self, anExc):
+ def __cmp__(self, anExc):
if not isinstance(anExc, Exception):
- return NotImplemented
- return (self.err.__class__ == anExc.__class__ and
- self.err.args == anExc.args)
+ return -1
+ x = cmp(self.err.__class__, anExc.__class__)
+ if x != 0:
+ return x
+ return cmp(self.err.args, anExc.args)
def __getattr__(self, attr):
return getattr(self.err, attr)
@@ -38,15 +46,15 @@ def do_test(buf, method):
env['REQUEST_METHOD'] = 'GET'
env['QUERY_STRING'] = buf
elif method == "POST":
- fp = BytesIO(buf.encode('latin-1')) # FieldStorage expects bytes
+ fp = StringIO(buf)
env['REQUEST_METHOD'] = 'POST'
env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded'
env['CONTENT_LENGTH'] = str(len(buf))
else:
- raise ValueError("unknown method: %s" % method)
+ raise ValueError, "unknown method: %s" % method
try:
return cgi.parse(fp, env, strict_parsing=1)
- except Exception as err:
+ except StandardError, err:
return ComparableException(err)
parse_strict_test_cases = [
@@ -96,20 +104,16 @@ parse_strict_test_cases = [
})
]
-def norm(seq):
- return sorted(seq, key=repr)
-
def first_elts(list):
- return [p[0] for p in list]
+ return map(lambda x:x[0], list)
def first_second_elts(list):
- return [(p[0], p[1][0]) for p in list]
+ return map(lambda p:(p[0], p[1][0]), list)
def gen_result(data, environ):
- encoding = 'latin-1'
- fake_stdin = BytesIO(data.encode(encoding))
+ fake_stdin = StringIO(data)
fake_stdin.seek(0)
- form = cgi.FieldStorage(fp=fake_stdin, environ=environ, encoding=encoding)
+ form = cgi.FieldStorage(fp=fake_stdin, environ=environ)
result = {}
for k, v in dict(form).items():
@@ -119,73 +123,70 @@ def gen_result(data, environ):
class CgiTests(unittest.TestCase):
- def test_parse_multipart(self):
- fp = BytesIO(POSTDATA.encode('latin1'))
- env = {'boundary': BOUNDARY.encode('latin1'),
- 'CONTENT-LENGTH': '558'}
- result = cgi.parse_multipart(fp, env)
- expected = {'submit': [' Add '], 'id': ['1234'],
- 'file': [b'Testing 123.\n'], 'title': ['']}
- self.assertEqual(result, expected)
-
- def test_parse_multipart_invalid_encoding(self):
- BOUNDARY = "JfISa01"
- POSTDATA = """--JfISa01
-Content-Disposition: form-data; name="submit-name"
-Content-Length: 3
-
-\u2603
---JfISa01"""
- fp = BytesIO(POSTDATA.encode('utf8'))
- env = {'boundary': BOUNDARY.encode('latin1'),
- 'CONTENT-LENGTH': str(len(POSTDATA.encode('utf8')))}
- result = cgi.parse_multipart(fp, env, encoding="ascii",
- errors="surrogateescape")
- expected = {'submit-name': ["\udce2\udc98\udc83"]}
- self.assertEqual(result, expected)
- self.assertEqual("\u2603".encode('utf8'),
- result["submit-name"][0].encode('utf8', 'surrogateescape'))
-
- def test_fieldstorage_properties(self):
- fs = cgi.FieldStorage()
- self.assertFalse(fs)
- self.assertIn("FieldStorage", repr(fs))
- self.assertEqual(list(fs), list(fs.keys()))
- fs.list.append(namedtuple('MockFieldStorage', 'name')('fieldvalue'))
- self.assertTrue(fs)
-
- def test_fieldstorage_invalid(self):
- self.assertRaises(TypeError, cgi.FieldStorage, "not-a-file-obj",
- environ={"REQUEST_METHOD":"PUT"})
- self.assertRaises(TypeError, cgi.FieldStorage, "foo", "bar")
- fs = cgi.FieldStorage(headers={'content-type':'text/plain'})
- self.assertRaises(TypeError, bool, fs)
+ def test_escape(self):
+ self.assertEqual("test & string", cgi.escape("test & string"))
+ self.assertEqual("&lt;test string&gt;", cgi.escape("<test string>"))
+ self.assertEqual("&quot;test string&quot;", cgi.escape('"test string"', True))
def test_strict(self):
for orig, expect in parse_strict_test_cases:
# Test basic parsing
d = do_test(orig, "GET")
- self.assertEqual(d, expect, "Error parsing %s method GET" % repr(orig))
+ self.assertEqual(d, expect, "Error parsing %s" % repr(orig))
d = do_test(orig, "POST")
- self.assertEqual(d, expect, "Error parsing %s method POST" % repr(orig))
+ self.assertEqual(d, expect, "Error parsing %s" % repr(orig))
env = {'QUERY_STRING': orig}
+ fcd = cgi.FormContentDict(env)
+ sd = cgi.SvFormContentDict(env)
fs = cgi.FieldStorage(environ=env)
if isinstance(expect, dict):
# test dict interface
- self.assertEqual(len(expect), len(fs))
- self.assertCountEqual(expect.keys(), fs.keys())
- ##self.assertEqual(norm(expect.values()), norm(fs.values()))
- ##self.assertEqual(norm(expect.items()), norm(fs.items()))
+ self.assertEqual(len(expect), len(fcd))
+ self.assertItemsEqual(expect.keys(), fcd.keys())
+ self.assertItemsEqual(expect.values(), fcd.values())
+ self.assertItemsEqual(expect.items(), fcd.items())
+ self.assertEqual(fcd.get("nonexistent field", "default"), "default")
+ self.assertEqual(len(sd), len(fs))
+ self.assertItemsEqual(sd.keys(), fs.keys())
self.assertEqual(fs.getvalue("nonexistent field", "default"), "default")
# test individual fields
for key in expect.keys():
expect_val = expect[key]
- self.assertIn(key, fs)
+ self.assertTrue(fcd.has_key(key))
+ self.assertItemsEqual(fcd[key], expect[key])
+ self.assertEqual(fcd.get(key, "default"), fcd[key])
+ self.assertTrue(fs.has_key(key))
if len(expect_val) > 1:
+ single_value = 0
+ else:
+ single_value = 1
+ try:
+ val = sd[key]
+ except IndexError:
+ self.assertFalse(single_value)
self.assertEqual(fs.getvalue(key), expect_val)
else:
+ self.assertTrue(single_value)
+ self.assertEqual(val, expect_val[0])
self.assertEqual(fs.getvalue(key), expect_val[0])
+ self.assertItemsEqual(sd.getlist(key), expect_val)
+ if single_value:
+ self.assertItemsEqual(sd.values(),
+ first_elts(expect.values()))
+ self.assertItemsEqual(sd.items(),
+ first_second_elts(expect.items()))
+
+ def test_weird_formcontentdict(self):
+ # Test the weird FormContentDict classes
+ env = {'QUERY_STRING': "x=1&y=2.0&z=2-3.%2b0&1=1abc"}
+ expect = {'x': 1, 'y': 2.0, 'z': '2-3.+0', '1': '1abc'}
+ d = cgi.InterpFormContentDict(env)
+ for k, v in expect.items():
+ self.assertEqual(d[k], v)
+ for k, v in d.items():
+ self.assertEqual(expect[k], v)
+ self.assertItemsEqual(expect.values(), d.values())
def test_log(self):
cgi.log("Testing")
@@ -194,11 +195,10 @@ Content-Length: 3
cgi.initlog("%s", "Testing initlog 1")
cgi.log("%s", "Testing log 2")
self.assertEqual(cgi.logfp.getvalue(), "Testing initlog 1\nTesting log 2\n")
- if os.path.exists(os.devnull):
+ if os.path.exists("/dev/null"):
cgi.logfp = None
- cgi.logfile = os.devnull
+ cgi.logfile = "/dev/null"
cgi.initlog("%s", "Testing log 3")
- self.addCleanup(cgi.closelog)
cgi.log("Testing log 4")
def test_fieldstorage_readline(self):
@@ -225,77 +225,65 @@ Content-Length: 3
setattr(self, name, a)
return a
- f = TestReadlineFile(tempfile.TemporaryFile("wb+"))
- self.addCleanup(f.close)
- f.write(b'x' * 256 * 1024)
+ f = TestReadlineFile(tempfile.TemporaryFile())
+ f.write('x' * 256 * 1024)
f.seek(0)
env = {'REQUEST_METHOD':'PUT'}
fs = cgi.FieldStorage(fp=f, environ=env)
- self.addCleanup(fs.file.close)
# if we're not chunking properly, readline is only called twice
# (by read_binary); if we are chunking properly, it will be called 5 times
# as long as the chunksize is 1 << 16.
self.assertGreater(f.numcalls, 2)
- f.close()
+
+ def test_fieldstorage_invalid(self):
+ fs = cgi.FieldStorage()
+ self.assertFalse(fs)
+ self.assertRaises(TypeError, bool(fs))
+ self.assertEqual(list(fs), list(fs.keys()))
+ fs.list.append(namedtuple('MockFieldStorage', 'name')('fieldvalue'))
+ self.assertTrue(fs)
def test_fieldstorage_multipart(self):
#Test basic FieldStorage multipart parsing
- env = {
- 'REQUEST_METHOD': 'POST',
- 'CONTENT_TYPE': 'multipart/form-data; boundary={}'.format(BOUNDARY),
- 'CONTENT_LENGTH': '558'}
- fp = BytesIO(POSTDATA.encode('latin-1'))
- fs = cgi.FieldStorage(fp, environ=env, encoding="latin-1")
- self.assertEqual(len(fs.list), 4)
- expect = [{'name':'id', 'filename':None, 'value':'1234'},
- {'name':'title', 'filename':None, 'value':''},
- {'name':'file', 'filename':'test.txt', 'value':b'Testing 123.\n'},
- {'name':'submit', 'filename':None, 'value':' Add '}]
- for x in range(len(fs.list)):
- for k, exp in expect[x].items():
- got = getattr(fs.list[x], k)
- self.assertEqual(got, exp)
+ env = {'REQUEST_METHOD':'POST', 'CONTENT_TYPE':'multipart/form-data; boundary=---------------------------721837373350705526688164684', 'CONTENT_LENGTH':'558'}
+ postdata = """-----------------------------721837373350705526688164684
+Content-Disposition: form-data; name="id"
- def test_fieldstorage_multipart_leading_whitespace(self):
- env = {
- 'REQUEST_METHOD': 'POST',
- 'CONTENT_TYPE': 'multipart/form-data; boundary={}'.format(BOUNDARY),
- 'CONTENT_LENGTH': '560'}
- # Add some leading whitespace to our post data that will cause the
- # first line to not be the innerboundary.
- fp = BytesIO(b"\r\n" + POSTDATA.encode('latin-1'))
- fs = cgi.FieldStorage(fp, environ=env, encoding="latin-1")
+1234
+-----------------------------721837373350705526688164684
+Content-Disposition: form-data; name="title"
+
+
+-----------------------------721837373350705526688164684
+Content-Disposition: form-data; name="file"; filename="test.txt"
+Content-Type: text/plain
+
+Testing 123.
+
+-----------------------------721837373350705526688164684
+Content-Disposition: form-data; name="submit"
+
+ Add\x20
+-----------------------------721837373350705526688164684--
+"""
+ fs = cgi.FieldStorage(fp=StringIO(postdata), environ=env)
self.assertEqual(len(fs.list), 4)
expect = [{'name':'id', 'filename':None, 'value':'1234'},
{'name':'title', 'filename':None, 'value':''},
- {'name':'file', 'filename':'test.txt', 'value':b'Testing 123.\n'},
+ {'name':'file', 'filename':'test.txt','value':'Testing 123.\n'},
{'name':'submit', 'filename':None, 'value':' Add '}]
for x in range(len(fs.list)):
for k, exp in expect[x].items():
got = getattr(fs.list[x], k)
self.assertEqual(got, exp)
- def test_fieldstorage_multipart_non_ascii(self):
- #Test basic FieldStorage multipart parsing
- env = {'REQUEST_METHOD':'POST',
- 'CONTENT_TYPE': 'multipart/form-data; boundary={}'.format(BOUNDARY),
- 'CONTENT_LENGTH':'558'}
- for encoding in ['iso-8859-1','utf-8']:
- fp = BytesIO(POSTDATA_NON_ASCII.encode(encoding))
- fs = cgi.FieldStorage(fp, environ=env,encoding=encoding)
- self.assertEqual(len(fs.list), 1)
- expect = [{'name':'id', 'filename':None, 'value':'\xe7\xf1\x80'}]
- for x in range(len(fs.list)):
- for k, exp in expect[x].items():
- got = getattr(fs.list[x], k)
- self.assertEqual(got, exp)
-
def test_fieldstorage_multipart_maxline(self):
# Issue #18167
maxline = 1 << 16
self.maxDiff = None
def check(content):
- data = """---123
+ data = """
+---123
Content-Disposition: form-data; name="upload"; filename="fake.txt"
Content-Type: text/plain
@@ -307,79 +295,11 @@ Content-Type: text/plain
'CONTENT_TYPE': 'multipart/form-data; boundary=-123',
'REQUEST_METHOD': 'POST',
}
- self.assertEqual(gen_result(data, environ),
- {'upload': content.encode('latin1')})
+ self.assertEqual(gen_result(data, environ), {'upload': content})
check('x' * (maxline - 1))
check('x' * (maxline - 1) + '\r')
check('x' * (maxline - 1) + '\r' + 'y' * (maxline - 1))
- def test_fieldstorage_multipart_w3c(self):
- # Test basic FieldStorage multipart parsing (W3C sample)
- env = {
- 'REQUEST_METHOD': 'POST',
- 'CONTENT_TYPE': 'multipart/form-data; boundary={}'.format(BOUNDARY_W3),
- 'CONTENT_LENGTH': str(len(POSTDATA_W3))}
- fp = BytesIO(POSTDATA_W3.encode('latin-1'))
- fs = cgi.FieldStorage(fp, environ=env, encoding="latin-1")
- self.assertEqual(len(fs.list), 2)
- self.assertEqual(fs.list[0].name, 'submit-name')
- self.assertEqual(fs.list[0].value, 'Larry')
- self.assertEqual(fs.list[1].name, 'files')
- files = fs.list[1].value
- self.assertEqual(len(files), 2)
- expect = [{'name': None, 'filename': 'file1.txt', 'value': b'... contents of file1.txt ...'},
- {'name': None, 'filename': 'file2.gif', 'value': b'...contents of file2.gif...'}]
- for x in range(len(files)):
- for k, exp in expect[x].items():
- got = getattr(files[x], k)
- self.assertEqual(got, exp)
-
- def test_fieldstorage_part_content_length(self):
- BOUNDARY = "JfISa01"
- POSTDATA = """--JfISa01
-Content-Disposition: form-data; name="submit-name"
-Content-Length: 5
-
-Larry
---JfISa01"""
- env = {
- 'REQUEST_METHOD': 'POST',
- 'CONTENT_TYPE': 'multipart/form-data; boundary={}'.format(BOUNDARY),
- 'CONTENT_LENGTH': str(len(POSTDATA))}
- fp = BytesIO(POSTDATA.encode('latin-1'))
- fs = cgi.FieldStorage(fp, environ=env, encoding="latin-1")
- self.assertEqual(len(fs.list), 1)
- self.assertEqual(fs.list[0].name, 'submit-name')
- self.assertEqual(fs.list[0].value, 'Larry')
-
- def test_field_storage_multipart_no_content_length(self):
- fp = BytesIO(b"""--MyBoundary
-Content-Disposition: form-data; name="my-arg"; filename="foo"
-
-Test
-
---MyBoundary--
-""")
- env = {
- "REQUEST_METHOD": "POST",
- "CONTENT_TYPE": "multipart/form-data; boundary=MyBoundary",
- "wsgi.input": fp,
- }
- fields = cgi.FieldStorage(fp, environ=env)
-
- self.assertEqual(len(fields["my-arg"].file.read()), 5)
-
- def test_fieldstorage_as_context_manager(self):
- fp = BytesIO(b'x' * 10)
- env = {'REQUEST_METHOD': 'PUT'}
- with cgi.FieldStorage(fp=fp, environ=env) as fs:
- content = fs.file.read()
- self.assertFalse(fs.file.closed)
- self.assertTrue(fs.file.closed)
- self.assertEqual(content, 'x' * 10)
- with self.assertRaisesRegex(ValueError, 'I/O operation on closed file'):
- fs.file.read()
-
_qs_result = {
'key1': 'value1',
'key2': ['value2x', 'value2y'],
@@ -452,7 +372,8 @@ a=5
)
def testQSAndFormData(self):
- data = """---123
+ data = """
+---123
Content-Disposition: form-data; name="key2"
value2y
@@ -476,7 +397,8 @@ value4
self.assertEqual(self._qs_result, v)
def testQSAndFormDataFile(self):
- data = """---123
+ data = """
+---123
Content-Disposition: form-data; name="key2"
value2y
@@ -504,11 +426,25 @@ this is the content of the fake file
}
result = self._qs_result.copy()
result.update({
- 'upload': b'this is the content of the fake file\n'
+ 'upload': 'this is the content of the fake file\n'
})
v = gen_result(data, environ)
self.assertEqual(result, v)
+ def test_deprecated_parse_qs(self):
+ # this func is moved to urlparse, this is just a sanity check
+ with check_warnings(('cgi.parse_qs is deprecated, use urlparse.'
+ 'parse_qs instead', PendingDeprecationWarning)):
+ self.assertEqual({'a': ['A1'], 'B': ['B3'], 'b': ['B2']},
+ cgi.parse_qs('a=A1&b=B2&B=B3'))
+
+ def test_deprecated_parse_qsl(self):
+ # this func is moved to urlparse, this is just a sanity check
+ with check_warnings(('cgi.parse_qsl is deprecated, use urlparse.'
+ 'parse_qsl instead', PendingDeprecationWarning)):
+ self.assertEqual([('a', 'A1'), ('b', 'B2'), ('B', 'B3')],
+ cgi.parse_qsl('a=A1&b=B2&B=B3'))
+
def test_parse_header(self):
self.assertEqual(
cgi.parse_header("text/plain"),
@@ -538,66 +474,9 @@ this is the content of the fake file
cgi.parse_header('form-data; name="files"; filename="fo\\"o;bar"'),
("form-data", {"name": "files", "filename": 'fo"o;bar'}))
- def test_all(self):
- blacklist = {"logfile", "logfp", "initlog", "dolog", "nolog",
- "closelog", "log", "maxlen", "valid_boundary"}
- support.check__all__(self, cgi, blacklist=blacklist)
-
-
-BOUNDARY = "---------------------------721837373350705526688164684"
-
-POSTDATA = """-----------------------------721837373350705526688164684
-Content-Disposition: form-data; name="id"
-
-1234
------------------------------721837373350705526688164684
-Content-Disposition: form-data; name="title"
-
------------------------------721837373350705526688164684
-Content-Disposition: form-data; name="file"; filename="test.txt"
-Content-Type: text/plain
-
-Testing 123.
-
------------------------------721837373350705526688164684
-Content-Disposition: form-data; name="submit"
-
- Add\x20
------------------------------721837373350705526688164684--
-"""
-
-POSTDATA_NON_ASCII = """-----------------------------721837373350705526688164684
-Content-Disposition: form-data; name="id"
-
-\xe7\xf1\x80
------------------------------721837373350705526688164684
-"""
-
-# http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4
-BOUNDARY_W3 = "AaB03x"
-POSTDATA_W3 = """--AaB03x
-Content-Disposition: form-data; name="submit-name"
-
-Larry
---AaB03x
-Content-Disposition: form-data; name="files"
-Content-Type: multipart/mixed; boundary=BbC04y
-
---BbC04y
-Content-Disposition: file; filename="file1.txt"
-Content-Type: text/plain
-
-... contents of file1.txt ...
---BbC04y
-Content-Disposition: file; filename="file2.gif"
-Content-Type: image/gif
-Content-Transfer-Encoding: binary
-
-...contents of file2.gif...
---BbC04y--
---AaB03x--
-"""
+def test_main():
+ run_unittest(CgiTests)
if __name__ == '__main__':
- unittest.main()
+ test_main()