1# -*- coding: utf-8 -*- 2import StringIO 3 4import webapp2 5 6import test_base 7 8 9def _norm_req(s): 10 return '\r\n'.join(s.strip().replace('\r','').split('\n')) 11 12_test_req = """ 13POST /webob/ HTTP/1.0 14Accept: */* 15Cache-Control: max-age=0 16Content-Type: multipart/form-data; boundary=----------------------------deb95b63e42a 17Host: pythonpaste.org 18User-Agent: UserAgent/1.0 (identifier-version) library/7.0 otherlibrary/0.8 19 20------------------------------deb95b63e42a 21Content-Disposition: form-data; name="foo" 22 23foo 24------------------------------deb95b63e42a 25Content-Disposition: form-data; name="bar"; filename="bar.txt" 26Content-type: application/octet-stream 27 28these are the contents of the file 'bar.txt' 29 30------------------------------deb95b63e42a-- 31""" 32 33_test_req2 = """ 34POST / HTTP/1.0 35Content-Length: 0 36 37""" 38 39_test_req = _norm_req(_test_req) 40_test_req2 = _norm_req(_test_req2) + '\r\n' 41 42 43class TestRequest(test_base.BaseTestCase): 44 def test_charset(self): 45 req = webapp2.Request.blank('/', environ={ 46 'CONTENT_TYPE': 'text/html; charset=ISO-8859-4', 47 }) 48 self.assertEqual(req.content_type, 'text/html') 49 self.assertEqual(req.charset, 'iso-8859-4') 50 51 req = webapp2.Request.blank('/', environ={ 52 'CONTENT_TYPE': 'application/json; charset="ISO-8859-1"', 53 }) 54 self.assertEqual(req.content_type, 'application/json') 55 self.assertEqual(req.charset, 'iso-8859-1') 56 57 req = webapp2.Request.blank('/', environ={ 58 'CONTENT_TYPE': 'application/json', 59 }) 60 self.assertEqual(req.content_type, 'application/json') 61 self.assertEqual(req.charset.lower(), 'utf-8') 62 63 match = webapp2._charset_re.search('text/html') 64 if match: 65 charset = match.group(1).lower().strip().strip('"').strip() 66 else: 67 charset = 'utf-8' 68 self.assertEqual(charset, 'utf-8') 69 70 match = webapp2._charset_re.search('text/html; charset=ISO-8859-4') 71 if match: 72 charset = match.group(1).lower().strip().strip('"').strip() 73 else: 74 charset = 'utf-8' 75 self.assertEqual(charset, 'iso-8859-4') 76 77 match = webapp2._charset_re.search('text/html; charset="ISO-8859-4"') 78 if match: 79 charset = match.group(1).lower().strip().strip('"').strip() 80 else: 81 charset = 'utf-8' 82 self.assertEqual(charset, 'iso-8859-4') 83 84 match = webapp2._charset_re.search('text/html; charset= " ISO-8859-4 " ') 85 if match: 86 charset = match.group(1).lower().strip().strip('"').strip() 87 else: 88 charset = 'utf-8' 89 self.assertEqual(charset, 'iso-8859-4') 90 91 def test_unicode(self): 92 req = webapp2.Request.blank('/?1=2', POST='3=4') 93 94 res = req.GET.get('1') 95 self.assertEqual(res, '2') 96 self.assertTrue(isinstance(res, unicode)) 97 98 res = req.str_GET.get('1') 99 self.assertEqual(res, '2') 100 self.assertTrue(isinstance(res, str)) 101 102 res = req.POST.get('3') 103 self.assertEqual(res, '4') 104 self.assertTrue(isinstance(res, unicode)) 105 106 res = req.str_POST.get('3') 107 self.assertEqual(res, '4') 108 self.assertTrue(isinstance(res, str)) 109 110 def test_cookie_unicode(self): 111 import urllib 112 import base64 113 114 # With base64 --------------------------------------------------------- 115 116 value = base64.b64encode(u'á'.encode('utf-8')) 117 rsp = webapp2.Response() 118 rsp.set_cookie('foo', value) 119 120 cookie = rsp.headers.get('Set-Cookie') 121 req = webapp2.Request.blank('/', headers=[('Cookie', cookie)]) 122 123 self.assertEqual(req.cookies.get('foo'), value) 124 self.assertEqual(base64.b64decode(req.cookies.get('foo')).decode('utf-8'), u'á') 125 126 # Without quote ------------------------------------------------------- 127 128 # Most recent WebOb versions take care of quoting. 129 # (not the version available on App Engine though) 130 131 value = u'föö=bär; föo, bär, bäz=dïng;' 132 rsp = webapp2.Response() 133 rsp.set_cookie('foo', value) 134 135 cookie = rsp.headers.get('Set-Cookie') 136 req = webapp2.Request.blank('/', headers=[('Cookie', cookie)]) 137 138 self.assertEqual(req.cookies.get('foo'), value) 139 140 # With quote, hard way ------------------------------------------------ 141 142 # Here is our test value. 143 x = u'föö' 144 # We must store cookies quoted. To quote unicode, we need to encode it. 145 y = urllib.quote(x.encode('utf8')) 146 # The encoded, quoted string looks ugly. 147 self.assertEqual(y, 'f%C3%B6%C3%B6') 148 # But it is easy to get it back to our initial value. 149 z = urllib.unquote(y).decode('utf8') 150 # And it is indeed the same value. 151 self.assertEqual(z, x) 152 153 # Set a cookie using the encoded/quoted value. 154 rsp = webapp2.Response() 155 rsp.set_cookie('foo', y) 156 cookie = rsp.headers.get('Set-Cookie') 157 self.assertEqual(cookie, 'foo=f%C3%B6%C3%B6; Path=/') 158 159 # Get the cookie back. 160 req = webapp2.Request.blank('/', headers=[('Cookie', cookie)]) 161 self.assertEqual(req.cookies.get('foo'), y) 162 # Here is our original value, again. Problem: the value is decoded 163 # before we had a chance to unquote it. 164 w = urllib.unquote(req.cookies.get('foo').encode('utf8')).decode('utf8') 165 # And it is indeed the same value. 166 self.assertEqual(w, x) 167 168 # With quote, easy way ------------------------------------------------ 169 170 value = u'föö=bär; föo, bär, bäz=dïng;' 171 quoted_value = urllib.quote(value.encode('utf8')) 172 rsp = webapp2.Response() 173 rsp.set_cookie('foo', quoted_value) 174 175 cookie = rsp.headers.get('Set-Cookie') 176 req = webapp2.Request.blank('/', headers=[('Cookie', cookie)]) 177 178 cookie_value = req.str_cookies.get('foo') 179 unquoted_cookie_value = urllib.unquote(cookie_value).decode('utf-8') 180 self.assertEqual(cookie_value, quoted_value) 181 self.assertEqual(unquoted_cookie_value, value) 182 183 def test_get(self): 184 req = webapp2.Request.blank('/?1=2&1=3&3=4', POST='5=6&7=8') 185 186 res = req.get('1') 187 self.assertEqual(res, '2') 188 189 res = req.get('1', allow_multiple=True) 190 self.assertEqual(res, ['2', '3']) 191 192 res = req.get('8') 193 self.assertEqual(res, '') 194 195 res = req.get('8', allow_multiple=True) 196 self.assertEqual(res, []) 197 198 res = req.get('8', default_value='9') 199 self.assertEqual(res, '9') 200 201 def test_get_with_POST(self): 202 req = webapp2.Request.blank('/?1=2&1=3&3=4', POST={5: 6, 7: 8}, 203 unicode_errors='ignore') 204 205 res = req.get('1') 206 self.assertEqual(res, '2') 207 208 res = req.get('1', allow_multiple=True) 209 self.assertEqual(res, ['2', '3']) 210 211 res = req.get('8') 212 self.assertEqual(res, '') 213 214 res = req.get('8', allow_multiple=True) 215 self.assertEqual(res, []) 216 217 res = req.get('8', default_value='9') 218 self.assertEqual(res, '9') 219 220 def test_arguments(self): 221 req = webapp2.Request.blank('/?1=2&3=4', POST='5=6&7=8') 222 223 res = req.arguments() 224 self.assertEqual(res, ['1', '3', '5', '7']) 225 226 def test_get_range(self): 227 req = webapp2.Request.blank('/') 228 res = req.get_range('1', min_value=None, max_value=None, default=None) 229 self.assertEqual(res, None) 230 231 req = webapp2.Request.blank('/?1=2') 232 res = req.get_range('1', min_value=None, max_value=None, default=0) 233 self.assertEqual(res, 2) 234 235 req = webapp2.Request.blank('/?1=foo') 236 res = req.get_range('1', min_value=1, max_value=99, default=100) 237 self.assertEqual(res, 99) 238 239 def test_issue_3426(self): 240 """When the content-type is 'application/x-www-form-urlencoded' and 241 POST data is empty the content-type is dropped by Google appengine. 242 """ 243 req = webapp2.Request.blank('/', environ={ 244 'REQUEST_METHOD': 'GET', 245 'CONTENT_TYPE': 'application/x-www-form-urlencoded', 246 }) 247 self.assertEqual(req.method, 'GET') 248 self.assertEqual(req.content_type, 'application/x-www-form-urlencoded') 249 250 # XXX: These tests fail when request charset is set to utf-8 by default. 251 # Otherwise they pass. 252 ''' 253 def test_get_with_FieldStorage(self): 254 if not test_base.check_webob_version(1.0): 255 return 256 # A valid request without a Content-Length header should still read 257 # the full body. 258 # Also test parity between as_string and from_string / from_file. 259 import cgi 260 req = webapp2.Request.from_string(_test_req) 261 self.assertTrue(isinstance(req, webapp2.Request)) 262 self.assertTrue(not repr(req).endswith('(invalid WSGI environ)>')) 263 self.assertTrue('\n' not in req.http_version or '\r' in req.http_version) 264 self.assertTrue(',' not in req.host) 265 self.assertTrue(req.content_length is not None) 266 self.assertEqual(req.content_length, 337) 267 self.assertTrue('foo' in req.body) 268 bar_contents = "these are the contents of the file 'bar.txt'\r\n" 269 self.assertTrue(bar_contents in req.body) 270 self.assertEqual(req.params['foo'], 'foo') 271 bar = req.params['bar'] 272 self.assertTrue(isinstance(bar, cgi.FieldStorage)) 273 self.assertEqual(bar.type, 'application/octet-stream') 274 bar.file.seek(0) 275 self.assertEqual(bar.file.read(), bar_contents) 276 277 bar = req.get_all('bar') 278 self.assertEqual(bar[0], bar_contents) 279 280 # out should equal contents, except for the Content-Length header, 281 # so insert that. 282 _test_req_copy = _test_req.replace('Content-Type', 283 'Content-Length: 337\r\nContent-Type') 284 self.assertEqual(str(req), _test_req_copy) 285 286 req2 = webapp2.Request.from_string(_test_req2) 287 self.assertTrue('host' not in req2.headers) 288 self.assertEqual(str(req2), _test_req2.rstrip()) 289 self.assertRaises(ValueError, 290 webapp2.Request.from_string, _test_req2 + 'xx') 291 292 def test_issue_5118(self): 293 """Unable to read POST variables ONCE self.request.body is read.""" 294 if not test_base.check_webob_version(1.0): 295 return 296 import cgi 297 req = webapp2.Request.from_string(_test_req) 298 fieldStorage = req.POST.get('bar') 299 self.assertTrue(isinstance(fieldStorage, cgi.FieldStorage)) 300 self.assertEqual(fieldStorage.type, 'application/octet-stream') 301 # Double read. 302 fieldStorage = req.POST.get('bar') 303 self.assertTrue(isinstance(fieldStorage, cgi.FieldStorage)) 304 self.assertEqual(fieldStorage.type, 'application/octet-stream') 305 # Now read the body. 306 x = req.body 307 fieldStorage = req.POST.get('bar') 308 self.assertTrue(isinstance(fieldStorage, cgi.FieldStorage)) 309 self.assertEqual(fieldStorage.type, 'application/octet-stream') 310 ''' 311 312if __name__ == '__main__': 313 test_base.main() 314