00001
00002
00003
00004 from __future__ import absolute_import, division, with_statement
00005 from tornado.httputil import url_concat, parse_multipart_form_data, HTTPHeaders
00006 from tornado.escape import utf8
00007 from tornado.testing import LogTrapTestCase
00008 from tornado.util import b
00009 import logging
00010 import unittest
00011
00012
00013 class TestUrlConcat(unittest.TestCase):
00014
00015 def test_url_concat_no_query_params(self):
00016 url = url_concat(
00017 "https://localhost/path",
00018 [('y', 'y'), ('z', 'z')],
00019 )
00020 self.assertEqual(url, "https://localhost/path?y=y&z=z")
00021
00022 def test_url_concat_encode_args(self):
00023 url = url_concat(
00024 "https://localhost/path",
00025 [('y', '/y'), ('z', 'z')],
00026 )
00027 self.assertEqual(url, "https://localhost/path?y=%2Fy&z=z")
00028
00029 def test_url_concat_trailing_q(self):
00030 url = url_concat(
00031 "https://localhost/path?",
00032 [('y', 'y'), ('z', 'z')],
00033 )
00034 self.assertEqual(url, "https://localhost/path?y=y&z=z")
00035
00036 def test_url_concat_q_with_no_trailing_amp(self):
00037 url = url_concat(
00038 "https://localhost/path?x",
00039 [('y', 'y'), ('z', 'z')],
00040 )
00041 self.assertEqual(url, "https://localhost/path?x&y=y&z=z")
00042
00043 def test_url_concat_trailing_amp(self):
00044 url = url_concat(
00045 "https://localhost/path?x&",
00046 [('y', 'y'), ('z', 'z')],
00047 )
00048 self.assertEqual(url, "https://localhost/path?x&y=y&z=z")
00049
00050 def test_url_concat_mult_params(self):
00051 url = url_concat(
00052 "https://localhost/path?a=1&b=2",
00053 [('y', 'y'), ('z', 'z')],
00054 )
00055 self.assertEqual(url, "https://localhost/path?a=1&b=2&y=y&z=z")
00056
00057 def test_url_concat_no_params(self):
00058 url = url_concat(
00059 "https://localhost/path?r=1&t=2",
00060 [],
00061 )
00062 self.assertEqual(url, "https://localhost/path?r=1&t=2")
00063
00064
00065 class MultipartFormDataTest(LogTrapTestCase):
00066 def test_file_upload(self):
00067 data = b("""\
00068 --1234
00069 Content-Disposition: form-data; name="files"; filename="ab.txt"
00070
00071 Foo
00072 --1234--""").replace(b("\n"), b("\r\n"))
00073 args = {}
00074 files = {}
00075 parse_multipart_form_data(b("1234"), data, args, files)
00076 file = files["files"][0]
00077 self.assertEqual(file["filename"], "ab.txt")
00078 self.assertEqual(file["body"], b("Foo"))
00079
00080 def test_unquoted_names(self):
00081
00082 data = b("""\
00083 --1234
00084 Content-Disposition: form-data; name=files; filename=ab.txt
00085
00086 Foo
00087 --1234--""").replace(b("\n"), b("\r\n"))
00088 args = {}
00089 files = {}
00090 parse_multipart_form_data(b("1234"), data, args, files)
00091 file = files["files"][0]
00092 self.assertEqual(file["filename"], "ab.txt")
00093 self.assertEqual(file["body"], b("Foo"))
00094
00095 def test_special_filenames(self):
00096 filenames = ['a;b.txt',
00097 'a"b.txt',
00098 'a";b.txt',
00099 'a;"b.txt',
00100 'a";";.txt',
00101 'a\\"b.txt',
00102 'a\\b.txt',
00103 ]
00104 for filename in filenames:
00105 logging.info("trying filename %r", filename)
00106 data = """\
00107 --1234
00108 Content-Disposition: form-data; name="files"; filename="%s"
00109
00110 Foo
00111 --1234--""" % filename.replace('\\', '\\\\').replace('"', '\\"')
00112 data = utf8(data.replace("\n", "\r\n"))
00113 args = {}
00114 files = {}
00115 parse_multipart_form_data(b("1234"), data, args, files)
00116 file = files["files"][0]
00117 self.assertEqual(file["filename"], filename)
00118 self.assertEqual(file["body"], b("Foo"))
00119
00120 def test_boundary_starts_and_ends_with_quotes(self):
00121 data = b('''\
00122 --1234
00123 Content-Disposition: form-data; name="files"; filename="ab.txt"
00124
00125 Foo
00126 --1234--''').replace(b("\n"), b("\r\n"))
00127 args = {}
00128 files = {}
00129 parse_multipart_form_data(b('"1234"'), data, args, files)
00130 file = files["files"][0]
00131 self.assertEqual(file["filename"], "ab.txt")
00132 self.assertEqual(file["body"], b("Foo"))
00133
00134 def test_missing_headers(self):
00135 data = b('''\
00136 --1234
00137
00138 Foo
00139 --1234--''').replace(b("\n"), b("\r\n"))
00140 args = {}
00141 files = {}
00142 parse_multipart_form_data(b("1234"), data, args, files)
00143 self.assertEqual(files, {})
00144
00145 def test_invalid_content_disposition(self):
00146 data = b('''\
00147 --1234
00148 Content-Disposition: invalid; name="files"; filename="ab.txt"
00149
00150 Foo
00151 --1234--''').replace(b("\n"), b("\r\n"))
00152 args = {}
00153 files = {}
00154 parse_multipart_form_data(b("1234"), data, args, files)
00155 self.assertEqual(files, {})
00156
00157 def test_line_does_not_end_with_correct_line_break(self):
00158 data = b('''\
00159 --1234
00160 Content-Disposition: form-data; name="files"; filename="ab.txt"
00161
00162 Foo--1234--''').replace(b("\n"), b("\r\n"))
00163 args = {}
00164 files = {}
00165 parse_multipart_form_data(b("1234"), data, args, files)
00166 self.assertEqual(files, {})
00167
00168 def test_content_disposition_header_without_name_parameter(self):
00169 data = b("""\
00170 --1234
00171 Content-Disposition: form-data; filename="ab.txt"
00172
00173 Foo
00174 --1234--""").replace(b("\n"), b("\r\n"))
00175 args = {}
00176 files = {}
00177 parse_multipart_form_data(b("1234"), data, args, files)
00178 self.assertEqual(files, {})
00179
00180 def test_data_after_final_boundary(self):
00181
00182
00183
00184 data = b("""\
00185 --1234
00186 Content-Disposition: form-data; name="files"; filename="ab.txt"
00187
00188 Foo
00189 --1234--
00190 """).replace(b("\n"), b("\r\n"))
00191 args = {}
00192 files = {}
00193 parse_multipart_form_data(b("1234"), data, args, files)
00194 file = files["files"][0]
00195 self.assertEqual(file["filename"], "ab.txt")
00196 self.assertEqual(file["body"], b("Foo"))
00197
00198
00199 class HTTPHeadersTest(unittest.TestCase):
00200 def test_multi_line(self):
00201
00202
00203
00204
00205 data = """\
00206 Foo: bar
00207 baz
00208 Asdf: qwer
00209 \tzxcv
00210 Foo: even
00211 more
00212 lines
00213 """.replace("\n", "\r\n")
00214 headers = HTTPHeaders.parse(data)
00215 self.assertEqual(headers["asdf"], "qwer zxcv")
00216 self.assertEqual(headers.get_list("asdf"), ["qwer zxcv"])
00217 self.assertEqual(headers["Foo"], "bar baz,even more lines")
00218 self.assertEqual(headers.get_list("foo"), ["bar baz", "even more lines"])
00219 self.assertEqual(sorted(list(headers.get_all())),
00220 [("Asdf", "qwer zxcv"),
00221 ("Foo", "bar baz"),
00222 ("Foo", "even more lines")])