| # -*- 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() |