# -*- coding: utf-8 -*- import StringIO import webapp2 import test_base def _norm_req(s): return '\r\n'.join(s.strip().replace('\r','').split('\n')) _test_req = """ POST /webob/ HTTP/1.0 Accept: */* Cache-Control: max-age=0 Content-Type: multipart/form-data; boundary=----------------------------deb95b63e42a Host: pythonpaste.org User-Agent: UserAgent/1.0 (identifier-version) library/7.0 otherlibrary/0.8 ------------------------------deb95b63e42a Content-Disposition: form-data; name="foo" foo ------------------------------deb95b63e42a Content-Disposition: form-data; name="bar"; filename="bar.txt" Content-type: application/octet-stream these are the contents of the file 'bar.txt' ------------------------------deb95b63e42a-- """ _test_req2 = """ POST / HTTP/1.0 Content-Length: 0 """ _test_req = _norm_req(_test_req) _test_req2 = _norm_req(_test_req2) + '\r\n' class TestRequest(test_base.BaseTestCase): def test_charset(self): req = webapp2.Request.blank('/', environ={ 'CONTENT_TYPE': 'text/html; charset=ISO-8859-4', }) self.assertEqual(req.content_type, 'text/html') self.assertEqual(req.charset, 'iso-8859-4') req = webapp2.Request.blank('/', environ={ 'CONTENT_TYPE': 'application/json; charset="ISO-8859-1"', }) self.assertEqual(req.content_type, 'application/json') self.assertEqual(req.charset, 'iso-8859-1') req = webapp2.Request.blank('/', environ={ 'CONTENT_TYPE': 'application/json', }) self.assertEqual(req.content_type, 'application/json') self.assertEqual(req.charset.lower(), 'utf-8') match = webapp2._charset_re.search('text/html') if match: charset = match.group(1).lower().strip().strip('"').strip() else: charset = 'utf-8' self.assertEqual(charset, 'utf-8') match = webapp2._charset_re.search('text/html; charset=ISO-8859-4') if match: charset = match.group(1).lower().strip().strip('"').strip() else: charset = 'utf-8' self.assertEqual(charset, 'iso-8859-4') match = webapp2._charset_re.search('text/html; charset="ISO-8859-4"') if match: charset = match.group(1).lower().strip().strip('"').strip() else: charset = 'utf-8' self.assertEqual(charset, 'iso-8859-4') match = webapp2._charset_re.search('text/html; charset= " ISO-8859-4 " ') if match: charset = match.group(1).lower().strip().strip('"').strip() else: charset = 'utf-8' self.assertEqual(charset, 'iso-8859-4') def test_unicode(self): req = webapp2.Request.blank('/?1=2', POST='3=4') res = req.GET.get('1') self.assertEqual(res, '2') self.assertTrue(isinstance(res, unicode)) res = req.str_GET.get('1') self.assertEqual(res, '2') self.assertTrue(isinstance(res, str)) res = req.POST.get('3') self.assertEqual(res, '4') self.assertTrue(isinstance(res, unicode)) res = req.str_POST.get('3') self.assertEqual(res, '4') self.assertTrue(isinstance(res, str)) def test_cookie_unicode(self): import urllib import base64 # With base64 --------------------------------------------------------- value = base64.b64encode(u'á'.encode('utf-8')) rsp = webapp2.Response() rsp.set_cookie('foo', value) cookie = rsp.headers.get('Set-Cookie') req = webapp2.Request.blank('/', headers=[('Cookie', cookie)]) self.assertEqual(req.cookies.get('foo'), value) self.assertEqual(base64.b64decode(req.cookies.get('foo')).decode('utf-8'), u'á') # Without quote ------------------------------------------------------- # Most recent WebOb versions take care of quoting. # (not the version available on App Engine though) value = u'föö=bär; föo, bär, bäz=dïng;' rsp = webapp2.Response() rsp.set_cookie('foo', value) cookie = rsp.headers.get('Set-Cookie') req = webapp2.Request.blank('/', headers=[('Cookie', cookie)]) self.assertEqual(req.cookies.get('foo'), value) # With quote, hard way ------------------------------------------------ # Here is our test value. x = u'föö' # We must store cookies quoted. To quote unicode, we need to encode it. y = urllib.quote(x.encode('utf8')) # The encoded, quoted string looks ugly. self.assertEqual(y, 'f%C3%B6%C3%B6') # But it is easy to get it back to our initial value. z = urllib.unquote(y).decode('utf8') # And it is indeed the same value. self.assertEqual(z, x) # Set a cookie using the encoded/quoted value. rsp = webapp2.Response() rsp.set_cookie('foo', y) cookie = rsp.headers.get('Set-Cookie') self.assertEqual(cookie, 'foo=f%C3%B6%C3%B6; Path=/') # Get the cookie back. req = webapp2.Request.blank('/', headers=[('Cookie', cookie)]) self.assertEqual(req.cookies.get('foo'), y) # Here is our original value, again. Problem: the value is decoded # before we had a chance to unquote it. w = urllib.unquote(req.cookies.get('foo').encode('utf8')).decode('utf8') # And it is indeed the same value. self.assertEqual(w, x) # With quote, easy way ------------------------------------------------ value = u'föö=bär; föo, bär, bäz=dïng;' quoted_value = urllib.quote(value.encode('utf8')) rsp = webapp2.Response() rsp.set_cookie('foo', quoted_value) cookie = rsp.headers.get('Set-Cookie') req = webapp2.Request.blank('/', headers=[('Cookie', cookie)]) cookie_value = req.str_cookies.get('foo') unquoted_cookie_value = urllib.unquote(cookie_value).decode('utf-8') self.assertEqual(cookie_value, quoted_value) self.assertEqual(unquoted_cookie_value, value) def test_get(self): req = webapp2.Request.blank('/?1=2&1=3&3=4', POST='5=6&7=8') res = req.get('1') self.assertEqual(res, '2') res = req.get('1', allow_multiple=True) self.assertEqual(res, ['2', '3']) res = req.get('8') self.assertEqual(res, '') res = req.get('8', allow_multiple=True) self.assertEqual(res, []) res = req.get('8', default_value='9') self.assertEqual(res, '9') def test_get_with_POST(self): req = webapp2.Request.blank('/?1=2&1=3&3=4', POST={5: 6, 7: 8}, unicode_errors='ignore') res = req.get('1') self.assertEqual(res, '2') res = req.get('1', allow_multiple=True) self.assertEqual(res, ['2', '3']) res = req.get('8') self.assertEqual(res, '') res = req.get('8', allow_multiple=True) self.assertEqual(res, []) res = req.get('8', default_value='9') self.assertEqual(res, '9') def test_arguments(self): req = webapp2.Request.blank('/?1=2&3=4', POST='5=6&7=8') res = req.arguments() self.assertEqual(res, ['1', '3', '5', '7']) def test_get_range(self): req = webapp2.Request.blank('/') res = req.get_range('1', min_value=None, max_value=None, default=None) self.assertEqual(res, None) req = webapp2.Request.blank('/?1=2') res = req.get_range('1', min_value=None, max_value=None, default=0) self.assertEqual(res, 2) req = webapp2.Request.blank('/?1=foo') res = req.get_range('1', min_value=1, max_value=99, default=100) self.assertEqual(res, 99) def test_issue_3426(self): """When the content-type is 'application/x-www-form-urlencoded' and POST data is empty the content-type is dropped by Google appengine. """ req = webapp2.Request.blank('/', environ={ 'REQUEST_METHOD': 'GET', 'CONTENT_TYPE': 'application/x-www-form-urlencoded', }) self.assertEqual(req.method, 'GET') self.assertEqual(req.content_type, 'application/x-www-form-urlencoded') # XXX: These tests fail when request charset is set to utf-8 by default. # Otherwise they pass. ''' def test_get_with_FieldStorage(self): if not test_base.check_webob_version(1.0): return # A valid request without a Content-Length header should still read # the full body. # Also test parity between as_string and from_string / from_file. import cgi req = webapp2.Request.from_string(_test_req) self.assertTrue(isinstance(req, webapp2.Request)) self.assertTrue(not repr(req).endswith('(invalid WSGI environ)>')) self.assertTrue('\n' not in req.http_version or '\r' in req.http_version) self.assertTrue(',' not in req.host) self.assertTrue(req.content_length is not None) self.assertEqual(req.content_length, 337) self.assertTrue('foo' in req.body) bar_contents = "these are the contents of the file 'bar.txt'\r\n" self.assertTrue(bar_contents in req.body) self.assertEqual(req.params['foo'], 'foo') bar = req.params['bar'] self.assertTrue(isinstance(bar, cgi.FieldStorage)) self.assertEqual(bar.type, 'application/octet-stream') bar.file.seek(0) self.assertEqual(bar.file.read(), bar_contents) bar = req.get_all('bar') self.assertEqual(bar[0], bar_contents) # out should equal contents, except for the Content-Length header, # so insert that. _test_req_copy = _test_req.replace('Content-Type', 'Content-Length: 337\r\nContent-Type') self.assertEqual(str(req), _test_req_copy) req2 = webapp2.Request.from_string(_test_req2) self.assertTrue('host' not in req2.headers) self.assertEqual(str(req2), _test_req2.rstrip()) self.assertRaises(ValueError, webapp2.Request.from_string, _test_req2 + 'xx') def test_issue_5118(self): """Unable to read POST variables ONCE self.request.body is read.""" if not test_base.check_webob_version(1.0): return import cgi req = webapp2.Request.from_string(_test_req) fieldStorage = req.POST.get('bar') self.assertTrue(isinstance(fieldStorage, cgi.FieldStorage)) self.assertEqual(fieldStorage.type, 'application/octet-stream') # Double read. fieldStorage = req.POST.get('bar') self.assertTrue(isinstance(fieldStorage, cgi.FieldStorage)) self.assertEqual(fieldStorage.type, 'application/octet-stream') # Now read the body. x = req.body fieldStorage = req.POST.get('bar') self.assertTrue(isinstance(fieldStorage, cgi.FieldStorage)) self.assertEqual(fieldStorage.type, 'application/octet-stream') ''' if __name__ == '__main__': test_base.main()