# -*- coding: utf-8 -*- import collections import sys import warnings from io import ( BytesIO, StringIO, ) import pytest from webob.compat import ( bytes_, native_, text_type, text_, ) py2only = pytest.mark.skipif("sys.version_info >= (3, 0)") py3only = pytest.mark.skipif("sys.version_info < (3, 0)") class TestRequestCommon(object): # unit tests of non-bytes-vs-text-specific methods of request object def _getTargetClass(self): from webob.request import Request return Request def _makeOne(self, *arg, **kw): cls = self._getTargetClass() return cls(*arg, **kw) def _blankOne(self, *arg, **kw): cls = self._getTargetClass() return cls.blank(*arg, **kw) def test_ctor_environ_getter_raises_WTF(self): with pytest.raises(TypeError): self._makeOne({}, environ_getter=object()) def test_ctor_wo_environ_raises_WTF(self): with pytest.raises(TypeError): self._makeOne(None) def test_ctor_w_environ(self): environ = {} req = self._makeOne(environ) assert req.environ == environ def test_ctor_w_non_utf8_charset(self): environ = {} with pytest.raises(DeprecationWarning): self._makeOne(environ, charset='latin-1') def test_scheme(self): environ = {'wsgi.url_scheme': 'something:'} req = self._makeOne(environ) assert req.scheme == 'something:' def test_body_file_getter(self): body = b'input' INPUT = BytesIO(body) environ = { 'wsgi.input': INPUT, 'CONTENT_LENGTH': len(body), 'REQUEST_METHOD': 'POST', } req = self._makeOne(environ) assert req.body_file is not INPUT def test_body_file_getter_seekable(self): body = b'input' INPUT = BytesIO(body) environ = { 'wsgi.input': INPUT, 'CONTENT_LENGTH': len(body), 'REQUEST_METHOD': 'POST', 'webob.is_body_seekable': True, } req = self._makeOne(environ) assert req.body_file is INPUT def test_body_file_getter_cache(self): body = b'input' INPUT = BytesIO(body) environ = { 'wsgi.input': INPUT, 'CONTENT_LENGTH': len(body), 'REQUEST_METHOD': 'POST', } req = self._makeOne(environ) assert req.body_file is req.body_file def test_body_file_getter_unreadable(self): body = b'input' INPUT = BytesIO(body) environ = {'wsgi.input': INPUT, 'REQUEST_METHOD': 'FOO'} req = self._makeOne(environ) assert req.body_file_raw is INPUT assert req.body_file is not INPUT assert req.body_file.read() == b'' def test_body_file_setter_w_bytes(self): req = self._blankOne('/') with pytest.raises(ValueError): setattr(req, 'body_file', b'foo') def test_body_file_setter_non_bytes(self): BEFORE = BytesIO(b'before') AFTER = BytesIO(b'after') environ = { 'wsgi.input': BEFORE, 'CONTENT_LENGTH': len('before'), 'REQUEST_METHOD': 'POST' } req = self._makeOne(environ) req.body_file = AFTER assert req.body_file is AFTER assert req.content_length == None def test_body_file_deleter(self): body = b'input' INPUT = BytesIO(body) environ = { 'wsgi.input': INPUT, 'CONTENT_LENGTH': len(body), 'REQUEST_METHOD': 'POST', } req = self._makeOne(environ) del req.body_file assert req.body_file.getvalue() == b'' assert req.content_length == 0 def test_body_file_raw(self): INPUT = BytesIO(b'input') environ = { 'wsgi.input': INPUT, 'CONTENT_LENGTH': len('input'), 'REQUEST_METHOD': 'POST', } req = self._makeOne(environ) assert req.body_file_raw is INPUT def test_body_file_seekable_input_not_seekable(self): data = b'input' INPUT = BytesIO(data) INPUT.seek(1, 0) # consume environ = { 'wsgi.input': INPUT, 'webob.is_body_seekable': False, 'CONTENT_LENGTH': len(data) - 1, 'REQUEST_METHOD': 'POST', } req = self._makeOne(environ) seekable = req.body_file_seekable assert seekable is not INPUT assert seekable.getvalue() == b'nput' def test_body_file_seekable_input_is_seekable(self): INPUT = BytesIO(b'input') INPUT.seek(1, 0) # consume environ = {'wsgi.input': INPUT, 'webob.is_body_seekable': True, 'CONTENT_LENGTH': len('input')-1, 'REQUEST_METHOD': 'POST', } req = self._makeOne(environ) seekable = req.body_file_seekable assert seekable is INPUT def test_urlvars_getter_w_paste_key(self): environ = {'paste.urlvars': {'foo': 'bar'}, } req = self._makeOne(environ) assert req.urlvars == {'foo': 'bar'} def test_urlvars_getter_w_wsgiorg_key(self): environ = {'wsgiorg.routing_args': ((), {'foo': 'bar'}), } req = self._makeOne(environ) assert req.urlvars == {'foo': 'bar'} def test_urlvars_getter_wo_keys(self): environ = {} req = self._makeOne(environ) assert req.urlvars == {} assert environ['wsgiorg.routing_args'] == ((), {}) def test_urlvars_setter_w_paste_key(self): environ = {'paste.urlvars': {'foo': 'bar'}, } req = self._makeOne(environ) req.urlvars = {'baz': 'bam'} assert req.urlvars == {'baz': 'bam'} assert environ['paste.urlvars'] == {'baz': 'bam'} assert 'wsgiorg.routing_args' not in environ def test_urlvars_setter_w_wsgiorg_key(self): environ = {'wsgiorg.routing_args': ((), {'foo': 'bar'}), 'paste.urlvars': {'qux': 'spam'}, } req = self._makeOne(environ) req.urlvars = {'baz': 'bam'} assert req.urlvars == {'baz': 'bam'} assert environ['wsgiorg.routing_args'] == ((), {'baz': 'bam'}) assert 'paste.urlvars' not in environ def test_urlvars_setter_wo_keys(self): environ = {} req = self._makeOne(environ) req.urlvars = {'baz': 'bam'} assert req.urlvars == {'baz': 'bam'} assert environ['wsgiorg.routing_args'] == ((), {'baz': 'bam'}) assert 'paste.urlvars' not in environ def test_urlvars_deleter_w_paste_key(self): environ = {'paste.urlvars': {'foo': 'bar'}, } req = self._makeOne(environ) del req.urlvars assert req.urlvars == {} assert 'paste.urlvars' not in environ assert environ['wsgiorg.routing_args'] == ((), {}) def test_urlvars_deleter_w_wsgiorg_key_non_empty_tuple(self): environ = {'wsgiorg.routing_args': (('a', 'b'), {'foo': 'bar'}), 'paste.urlvars': {'qux': 'spam'}, } req = self._makeOne(environ) del req.urlvars assert req.urlvars == {} assert environ['wsgiorg.routing_args'] == (('a', 'b'), {}) assert 'paste.urlvars' not in environ def test_urlvars_deleter_w_wsgiorg_key_empty_tuple(self): environ = {'wsgiorg.routing_args': ((), {'foo': 'bar'}), 'paste.urlvars': {'qux': 'spam'}, } req = self._makeOne(environ) del req.urlvars assert req.urlvars == {} assert environ['wsgiorg.routing_args'] == ((), {}) assert 'paste.urlvars' not in environ def test_urlvars_deleter_wo_keys(self): environ = {} req = self._makeOne(environ) del req.urlvars assert req.urlvars == {} assert environ['wsgiorg.routing_args'] == ((), {}) assert 'paste.urlvars' not in environ def test_urlargs_getter_w_paste_key(self): environ = {'paste.urlvars': {'foo': 'bar'}, } req = self._makeOne(environ) assert req.urlargs == () def test_urlargs_getter_w_wsgiorg_key(self): environ = {'wsgiorg.routing_args': (('a', 'b'), {'foo': 'bar'}), } req = self._makeOne(environ) assert req.urlargs, ('a' == 'b') def test_urlargs_getter_wo_keys(self): environ = {} req = self._makeOne(environ) assert req.urlargs == () assert 'wsgiorg.routing_args' not in environ def test_urlargs_setter_w_paste_key(self): environ = {'paste.urlvars': {'foo': 'bar'}, } req = self._makeOne(environ) req.urlargs = ('a', 'b') assert req.urlargs == ('a', 'b') assert environ['wsgiorg.routing_args'] == (('a', 'b'), {'foo': 'bar'}) assert 'paste.urlvars' not in environ def test_urlargs_setter_w_wsgiorg_key(self): environ = {'wsgiorg.routing_args': ((), {'foo': 'bar'}), } req = self._makeOne(environ) req.urlargs = ('a', 'b') assert req.urlargs == ('a', 'b') assert environ['wsgiorg.routing_args'] == (('a', 'b'), {'foo': 'bar'}) def test_urlargs_setter_wo_keys(self): environ = {} req = self._makeOne(environ) req.urlargs = ('a', 'b') assert req.urlargs == ('a', 'b') assert environ['wsgiorg.routing_args'] == (('a', 'b'), {}) assert 'paste.urlvars' not in environ def test_urlargs_deleter_w_wsgiorg_key(self): environ = {'wsgiorg.routing_args': (('a', 'b'), {'foo': 'bar'}), } req = self._makeOne(environ) del req.urlargs assert req.urlargs == () assert environ['wsgiorg.routing_args'] == ((), {'foo': 'bar'}) def test_urlargs_deleter_w_wsgiorg_key_empty(self): environ = {'wsgiorg.routing_args': ((), {}), } req = self._makeOne(environ) del req.urlargs assert req.urlargs == () assert 'paste.urlvars' not in environ assert 'wsgiorg.routing_args' not in environ def test_urlargs_deleter_wo_keys(self): environ = {} req = self._makeOne(environ) del req.urlargs assert req.urlargs == () assert 'paste.urlvars' not in environ assert 'wsgiorg.routing_args' not in environ def test_cookies_empty_environ(self): req = self._makeOne({}) assert req.cookies == {} def test_cookies_is_mutable(self): req = self._makeOne({}) cookies = req.cookies cookies['a'] = '1' assert req.cookies['a'] == '1' def test_cookies_w_webob_parsed_cookies_matching_source(self): environ = { 'HTTP_COOKIE': 'a=b', 'webob._parsed_cookies': ('a=b', {'a': 'b'}), } req = self._makeOne(environ) assert req.cookies == {'a': 'b'} def test_cookies_w_webob_parsed_cookies_mismatched_source(self): environ = { 'HTTP_COOKIE': 'a=b', 'webob._parsed_cookies': ('a=b;c=d', {'a': 'b', 'c': 'd'}), } req = self._makeOne(environ) assert req.cookies == {'a': 'b'} def test_set_cookies(self): environ = { 'HTTP_COOKIE': 'a=b', } req = self._makeOne(environ) req.cookies = {'a':'1', 'b': '2'} assert req.cookies == {'a': '1', 'b':'2'} rcookies = [x.strip() for x in environ['HTTP_COOKIE'].split(';')] assert sorted(rcookies) == ['a=1', 'b=2'] # body def test_body_getter(self): INPUT = BytesIO(b'input') environ = {'wsgi.input': INPUT, 'webob.is_body_seekable': True, 'CONTENT_LENGTH': len('input'), 'REQUEST_METHOD': 'POST' } req = self._makeOne(environ) assert req.body == b'input' assert req.content_length == len(b'input') def test_body_setter_None(self): INPUT = BytesIO(b'input') environ = {'wsgi.input': INPUT, 'webob.is_body_seekable': True, 'CONTENT_LENGTH': len(b'input'), 'REQUEST_METHOD': 'POST' } req = self._makeOne(environ) req.body = None assert req.body == b'' assert req.content_length == 0 assert req.is_body_seekable def test_body_setter_non_string_raises(self): req = self._makeOne({}) def _test(): req.body = object() with pytest.raises(TypeError): _test() def test_body_setter_value(self): BEFORE = BytesIO(b'before') environ = {'wsgi.input': BEFORE, 'webob.is_body_seekable': True, 'CONTENT_LENGTH': len('before'), 'REQUEST_METHOD': 'POST' } req = self._makeOne(environ) req.body = b'after' assert req.body == b'after' assert req.content_length == len(b'after') assert req.is_body_seekable def test_body_deleter_None(self): data = b'input' INPUT = BytesIO(data) environ = {'wsgi.input': INPUT, 'webob.is_body_seekable': True, 'CONTENT_LENGTH': len(data), 'REQUEST_METHOD': 'POST', } req = self._makeOne(environ) del req.body assert req.body == b'' assert req.content_length == 0 assert req.is_body_seekable # JSON def test_json_body(self): body = b'{"a":1}' INPUT = BytesIO(body) environ = {'wsgi.input': INPUT, 'CONTENT_LENGTH': str(len(body))} req = self._makeOne(environ) assert req.json == {"a": 1} assert req.json_body == {"a": 1} req.json = {"b": 2} assert req.body == b'{"b":2}' del req.json assert req.body == b'' def test_json_body_array(self): body = b'[{"a":1}, {"b":2}]' INPUT = BytesIO(body) environ = {'wsgi.input': INPUT, 'CONTENT_LENGTH': str(len(body))} req = self._makeOne(environ) assert req.json, [{"a": 1} == {"b": 2}] assert req.json_body == [{"a": 1}, {"b": 2}] req.json = [{"b": 2}] assert req.body == b'[{"b":2}]' del req.json assert req.body == b'' # .text def test_text_body(self): body = b'test' INPUT = BytesIO(body) environ = {'wsgi.input': INPUT, 'CONTENT_LENGTH': str(len(body))} req = self._makeOne(environ) assert req.body == b'test' assert req.text == 'test' req.text = text_('\u1000') assert req.body == '\u1000'.encode(req.charset) del req.text assert req.body == b'' def set_bad_text(): req.text = 1 with pytest.raises(TypeError): set_bad_text() def test__text_get_without_charset(self): body = b'test' INPUT = BytesIO(body) environ = {'wsgi.input': INPUT, 'CONTENT_LENGTH': str(len(body))} req = self._makeOne(environ) req._charset = '' with pytest.raises(AttributeError): getattr(req, 'text') def test__text_set_without_charset(self): body = b'test' INPUT = BytesIO(body) environ = {'wsgi.input': INPUT, 'CONTENT_LENGTH': str(len(body))} req = self._makeOne(environ) req._charset = '' with pytest.raises(AttributeError): setattr(req, 'text', 'abc') # POST def test_POST_not_POST_or_PUT(self): from webob.multidict import NoVars environ = {'REQUEST_METHOD': 'GET', } req = self._makeOne(environ) result = req.POST assert isinstance(result, NoVars) assert result.reason.startswith('Not a form request') def test_POST_existing_cache_hit(self): data = b'input' INPUT = BytesIO(data) environ = {'wsgi.input': INPUT, 'REQUEST_METHOD': 'POST', 'webob._parsed_post_vars': ({'foo': 'bar'}, INPUT), } req = self._makeOne(environ) result = req.POST assert result == {'foo': 'bar'} def test_PUT_missing_content_type(self): from webob.multidict import NoVars data = b'input' INPUT = BytesIO(data) environ = {'wsgi.input': INPUT, 'REQUEST_METHOD': 'PUT', } req = self._makeOne(environ) result = req.POST assert isinstance(result, NoVars) assert result.reason.startswith('Not an HTML form submission') def test_PATCH_missing_content_type(self): from webob.multidict import NoVars data = b'input' INPUT = BytesIO(data) environ = {'wsgi.input': INPUT, 'REQUEST_METHOD': 'PATCH', } req = self._makeOne(environ) result = req.POST assert isinstance(result, NoVars) assert result.reason.startswith('Not an HTML form submission') def test_POST_missing_content_type(self): data = b'var1=value1&var2=value2&rep=1&rep=2' INPUT = BytesIO(data) environ = {'wsgi.input': INPUT, 'REQUEST_METHOD': 'POST', 'CONTENT_LENGTH':len(data), 'webob.is_body_seekable': True, } req = self._makeOne(environ) result = req.POST assert result['var1'] == 'value1' def test_POST_json_no_content_type(self): data = b'{"password": "last centurion", "email": "rory@wiggy.net"}' INPUT = BytesIO(data) environ = {'wsgi.input': INPUT, 'REQUEST_METHOD': 'POST', 'CONTENT_LENGTH':len(data), 'webob.is_body_seekable': True, } req = self._makeOne(environ) r_1 = req.body r_2 = req.POST r_3 = req.body assert r_1 == b'{"password": "last centurion", "email": "rory@wiggy.net"}' assert r_3 == b'{"password": "last centurion", "email": "rory@wiggy.net"}' def test_PUT_bad_content_type(self): from webob.multidict import NoVars data = b'input' INPUT = BytesIO(data) environ = {'wsgi.input': INPUT, 'REQUEST_METHOD': 'PUT', 'CONTENT_TYPE': 'text/plain', } req = self._makeOne(environ) result = req.POST assert isinstance(result, NoVars) assert result.reason.startswith( 'Not an HTML form submission') def test_POST_multipart(self): BODY_TEXT = ( b'------------------------------deb95b63e42a\n' b'Content-Disposition: form-data; name="foo"\n' b'\n' b'foo\n' b'------------------------------deb95b63e42a\n' b'Content-Disposition: form-data; name="bar"; filename="bar.txt"\n' b'Content-type: application/octet-stream\n' b'\n' b'these are the contents of the file "bar.txt"\n' b'\n' b'------------------------------deb95b63e42a--\n') INPUT = BytesIO(BODY_TEXT) environ = {'wsgi.input': INPUT, 'webob.is_body_seekable': True, 'REQUEST_METHOD': 'POST', 'CONTENT_TYPE': 'multipart/form-data; ' 'boundary=----------------------------deb95b63e42a', 'CONTENT_LENGTH': len(BODY_TEXT), } req = self._makeOne(environ) result = req.POST assert result['foo'] == 'foo' bar = result['bar'] assert bar.name == 'bar' assert bar.filename == 'bar.txt' assert bar.file.read() == b'these are the contents of the file "bar.txt"\n' # GET def test_GET_reflects_query_string(self): environ = { 'QUERY_STRING': 'foo=123', } req = self._makeOne(environ) result = req.GET assert result == {'foo': '123'} req.query_string = 'foo=456' result = req.GET assert result == {'foo': '456'} req.query_string = '' result = req.GET assert result == {} def test_GET_updates_query_string(self): req = self._makeOne({}) result = req.query_string assert result == '' req.GET['foo'] = '123' result = req.query_string assert result == 'foo=123' del req.GET['foo'] result = req.query_string assert result == '' # cookies def test_cookies_wo_webob_parsed_cookies(self): environ = { 'HTTP_COOKIE': 'a=b', } req = self._blankOne('/', environ) assert req.cookies == {'a': 'b'} # copy def test_copy_get(self): environ = { 'HTTP_COOKIE': 'a=b', } req = self._blankOne('/', environ) clone = req.copy_get() for k, v in req.environ.items(): if k in ('CONTENT_LENGTH', 'webob.is_body_seekable'): assert k not in clone.environ elif k == 'wsgi.input': assert clone.environ[k] is not v else: assert clone.environ[k] == v def test_remove_conditional_headers_accept_encoding(self): req = self._blankOne('/') req.accept_encoding='gzip,deflate' req.remove_conditional_headers() assert bool(req.accept_encoding) == False def test_remove_conditional_headers_if_modified_since(self): from webob.datetime_utils import UTC from datetime import datetime req = self._blankOne('/') req.if_modified_since = datetime(2006, 1, 1, 12, 0, tzinfo=UTC) req.remove_conditional_headers() assert req.if_modified_since == None def test_remove_conditional_headers_if_none_match(self): req = self._blankOne('/') req.if_none_match = 'foo' assert req.if_none_match req.remove_conditional_headers() assert not req.if_none_match def test_remove_conditional_headers_if_range(self): req = self._blankOne('/') req.if_range = 'foo, bar' req.remove_conditional_headers() assert bool(req.if_range) == False def test_remove_conditional_headers_range(self): req = self._blankOne('/') req.range = 'bytes=0-100' req.remove_conditional_headers() assert req.range == None def test_is_body_readable_POST(self): req = self._blankOne('/', environ={'REQUEST_METHOD': 'POST', 'CONTENT_LENGTH': '100'}) assert req.is_body_readable def test_is_body_readable_PATCH(self): req = self._blankOne('/', environ={'REQUEST_METHOD': 'PATCH', 'CONTENT_LENGTH': '100'}) assert req.is_body_readable def test_is_body_readable_GET(self): req = self._blankOne('/', environ={'REQUEST_METHOD': 'GET', 'CONTENT_LENGTH': '100'}) assert req.is_body_readable def test_is_body_readable_unknown_method_and_content_length(self): req = self._blankOne('/', environ={'REQUEST_METHOD': 'WTF', 'CONTENT_LENGTH': '100'}) assert req.is_body_readable def test_is_body_readable_special_flag(self): req = self._blankOne('/', environ={'REQUEST_METHOD': 'WTF', 'webob.is_body_readable': True}) assert req.is_body_readable # is_body_seekable # make_body_seekable # copy_body # make_tempfile # remove_conditional_headers # accept # accept_charset # accept_encoding # accept_language # authorization # cache_control def test_cache_control_reflects_environ(self): environ = { 'HTTP_CACHE_CONTROL': 'max-age=5', } req = self._makeOne(environ) result = req.cache_control assert result.properties == {'max-age': 5} req.environ.update(HTTP_CACHE_CONTROL='max-age=10') result = req.cache_control assert result.properties == {'max-age': 10} req.environ.update(HTTP_CACHE_CONTROL='') result = req.cache_control assert result.properties == {} def test_cache_control_updates_environ(self): environ = {} req = self._makeOne(environ) req.cache_control.max_age = 5 result = req.environ['HTTP_CACHE_CONTROL'] assert result == 'max-age=5' req.cache_control.max_age = 10 result = req.environ['HTTP_CACHE_CONTROL'] assert result == 'max-age=10' req.cache_control = None result = req.environ['HTTP_CACHE_CONTROL'] assert result == '' del req.cache_control assert 'HTTP_CACHE_CONTROL' not in req.environ def test_cache_control_set_dict(self): environ = {} req = self._makeOne(environ) req.cache_control = {'max-age': 5} result = req.cache_control assert result.max_age == 5 def test_cache_control_set_object(self): from webob.cachecontrol import CacheControl environ = {} req = self._makeOne(environ) req.cache_control = CacheControl({'max-age': 5}, type='request') result = req.cache_control assert result.max_age == 5 def test_cache_control_gets_cached(self): environ = {} req = self._makeOne(environ) assert req.cache_control is req.cache_control #if_match #if_none_match #date #if_modified_since #if_unmodified_since #if_range #max_forwards #pragma #range #referer #referrer #user_agent #__repr__ #__str__ #from_file #call_application def test_call_application_calls_application(self): environ = {} req = self._makeOne(environ) def application(environ, start_response): start_response('200 OK', [('content-type', 'text/plain')]) return ['...\n'] status, headers, output = req.call_application(application) assert status == '200 OK' assert headers == [('content-type', 'text/plain')] assert ''.join(output) == '...\n' def test_call_application_provides_write(self): environ = {} req = self._makeOne(environ) def application(environ, start_response): write = start_response('200 OK', [('content-type', 'text/plain')]) write('...\n') return [] status, headers, output = req.call_application(application) assert status == '200 OK' assert headers == [('content-type', 'text/plain')] assert ''.join(output) == '...\n' def test_call_application_closes_iterable_when_mixed_w_write_calls(self): environ = { 'test._call_application_called_close': False } req = self._makeOne(environ) def application(environ, start_response): write = start_response('200 OK', [('content-type', 'text/plain')]) class AppIter(object): def __iter__(self): yield '...\n' def close(self): environ['test._call_application_called_close'] = True write('...\n') return AppIter() status, headers, output = req.call_application(application) assert ''.join(output) == '...\n...\n' assert environ['test._call_application_called_close'] == True def test_call_application_raises_exc_info(self): environ = {} req = self._makeOne(environ) def application(environ, start_response): try: raise RuntimeError('OH NOES') except: exc_info = sys.exc_info() start_response('200 OK', [('content-type', 'text/plain')], exc_info) return ['...\n'] with pytest.raises(RuntimeError): req.call_application(application) def test_call_application_returns_exc_info(self): environ = {} req = self._makeOne(environ) def application(environ, start_response): try: raise RuntimeError('OH NOES') except: exc_info = sys.exc_info() start_response('200 OK', [('content-type', 'text/plain')], exc_info) return ['...\n'] status, headers, output, exc_info = req.call_application( application, True) assert status == '200 OK' assert headers == [('content-type', 'text/plain')] assert ''.join(output) == '...\n' assert exc_info[0] == RuntimeError #get_response def test_blank__method_subtitution(self): request = self._blankOne('/', environ={'REQUEST_METHOD': 'PUT'}) assert request.method == 'PUT' request = self._blankOne( '/', environ={'REQUEST_METHOD': 'PUT'}, POST={}) assert request.method == 'PUT' request = self._blankOne( '/', environ={'REQUEST_METHOD': 'HEAD'}, POST={}) assert request.method == 'POST' def test_blank__ctype_in_env(self): request = self._blankOne( '/', environ={'CONTENT_TYPE': 'application/json'}) assert request.content_type == 'application/json' assert request.method == 'GET' request = self._blankOne( '/', environ={'CONTENT_TYPE': 'application/json'}, POST='') assert request.content_type == 'application/json' assert request.method == 'POST' def test_blank__ctype_in_headers(self): request = self._blankOne( '/', headers={'Content-type': 'application/json'}) assert request.content_type == 'application/json' assert request.method == 'GET' request = self._blankOne( '/', headers={'Content-Type': 'application/json'}, POST='') assert request.content_type == 'application/json' assert request.method == 'POST' def test_blank__ctype_as_kw(self): request = self._blankOne('/', content_type='application/json') assert request.content_type == 'application/json' assert request.method == 'GET' request = self._blankOne('/', content_type='application/json', POST='') assert request.content_type == 'application/json' assert request.method == 'POST' def test_blank__str_post_data_for_unsupported_ctype(self): with pytest.raises(ValueError): self._blankOne('/', content_type='application/json', POST={}) def test_blank__post_urlencoded(self): from webob.multidict import MultiDict POST = MultiDict() POST["first"] = 1 POST["second"] = 2 request = self._blankOne('/', POST=POST) assert request.method == 'POST' assert request.content_type == 'application/x-www-form-urlencoded' assert request.body == b'first=1&second=2' assert request.content_length == 16 def test_blank__post_multipart(self): from webob.multidict import MultiDict POST = MultiDict() POST["first"] = "1" POST["second"] = "2" request = self._blankOne('/', POST=POST, content_type='multipart/form-data; ' 'boundary=boundary') assert request.method == 'POST' assert request.content_type == 'multipart/form-data' expected = ( b'--boundary\r\n' b'Content-Disposition: form-data; name="first"\r\n\r\n' b'1\r\n' b'--boundary\r\n' b'Content-Disposition: form-data; name="second"\r\n\r\n' b'2\r\n' b'--boundary--') assert request.body == expected assert request.content_length == 139 def test_blank__post_files(self): import cgi from webob.request import _get_multipart_boundary from webob.multidict import MultiDict POST = MultiDict() POST["first"] = ('filename1', BytesIO(b'1')) POST["second"] = ('filename2', '2') POST["third"] = "3" request = self._blankOne('/', POST=POST) assert request.method == 'POST' assert request.content_type == 'multipart/form-data' boundary = bytes_( _get_multipart_boundary(request.headers['content-type'])) body_norm = request.body.replace(boundary, b'boundary') expected = ( b'--boundary\r\n' b'Content-Disposition: form-data; name="first"; ' b'filename="filename1"\r\n\r\n' b'1\r\n' b'--boundary\r\n' b'Content-Disposition: form-data; name="second"; ' b'filename="filename2"\r\n\r\n' b'2\r\n' b'--boundary\r\n' b'Content-Disposition: form-data; name="third"\r\n\r\n' b'3\r\n' b'--boundary--' ) assert body_norm == expected assert request.content_length == 294 assert isinstance(request.POST['first'], cgi.FieldStorage) assert isinstance(request.POST['second'], cgi.FieldStorage) assert request.POST['first'].value == b'1' assert request.POST['second'].value == b'2' assert request.POST['third'] == '3' def test_blank__post_file_w_wrong_ctype(self): with pytest.raises(ValueError): self._blankOne( '/', POST={'first': ('filename1', '1')}, content_type='application/x-www-form-urlencoded') #from_bytes def test_from_bytes_extra_data(self): _test_req_copy = _test_req.replace( b'Content-Type', b'Content-Length: 337\r\nContent-Type') cls = self._getTargetClass() with pytest.raises(ValueError): cls.from_bytes(_test_req_copy+b'EXTRA!') #as_bytes def test_as_bytes_skip_body(self): cls = self._getTargetClass() req = cls.from_bytes(_test_req) body = req.as_bytes(skip_body=True) assert body.count(b'\r\n\r\n') == 0 assert req.as_bytes(skip_body=337) == req.as_bytes() body = req.as_bytes(337-1).split(b'\r\n\r\n', 1)[1] assert body == b'
' class TestBaseRequest(object): # tests of methods of a base request which are encoding-specific def _getTargetClass(self): from webob.request import BaseRequest return BaseRequest def _makeOne(self, *arg, **kw): cls = self._getTargetClass() return cls(*arg, **kw) def _blankOne(self, *arg, **kw): cls = self._getTargetClass() return cls.blank(*arg, **kw) def test_method(self): environ = {'REQUEST_METHOD': 'OPTIONS', } req = self._makeOne(environ) result = req.method assert result.__class__ == str assert result == 'OPTIONS' def test_http_version(self): environ = {'SERVER_PROTOCOL': '1.1', } req = self._makeOne(environ) result = req.http_version assert result == '1.1' def test_script_name(self): environ = {'SCRIPT_NAME': '/script', } req = self._makeOne(environ) assert req.script_name == '/script' def test_path_info(self): environ = {'PATH_INFO': '/path/info', } req = self._makeOne(environ) assert req.path_info == '/path/info' def test_content_length_getter(self): environ = {'CONTENT_LENGTH': '1234', } req = self._makeOne(environ) assert req.content_length == 1234 def test_content_length_setter_w_str(self): environ = {'CONTENT_LENGTH': '1234', } req = self._makeOne(environ) req.content_length = '3456' assert req.content_length == 3456 def test_remote_user(self): environ = {'REMOTE_USER': 'phred', } req = self._makeOne(environ) assert req.remote_user == 'phred' def test_remote_addr(self): environ = {'REMOTE_ADDR': '1.2.3.4', } req = self._makeOne(environ) assert req.remote_addr == '1.2.3.4' def test_query_string(self): environ = {'QUERY_STRING': 'foo=bar&baz=bam', } req = self._makeOne(environ) assert req.query_string == 'foo=bar&baz=bam' def test_server_name(self): environ = {'SERVER_NAME': 'somehost.tld', } req = self._makeOne(environ) assert req.server_name == 'somehost.tld' def test_server_port_getter(self): environ = {'SERVER_PORT': '6666', } req = self._makeOne(environ) assert req.server_port == 6666 def test_server_port_setter_with_string(self): environ = {'SERVER_PORT': '6666', } req = self._makeOne(environ) req.server_port = '6667' assert req.server_port == 6667 def test_uscript_name(self): environ = {'SCRIPT_NAME': '/script', } req = self._makeOne(environ) assert isinstance(req.uscript_name, text_type) assert req.uscript_name == '/script' def test_upath_info(self): environ = {'PATH_INFO': '/path/info', } req = self._makeOne(environ) assert isinstance(req.upath_info, text_type) assert req.upath_info == '/path/info' def test_upath_info_set_unicode(self): environ = {'PATH_INFO': '/path/info', } req = self._makeOne(environ) req.upath_info = text_('/another') assert isinstance(req.upath_info, text_type) assert req.upath_info == '/another' def test_content_type_getter_no_parameters(self): environ = {'CONTENT_TYPE': 'application/xml+foobar', } req = self._makeOne(environ) assert req.content_type == 'application/xml+foobar' def test_content_type_getter_w_parameters(self): environ = {'CONTENT_TYPE': 'application/xml+foobar;charset="utf8"', } req = self._makeOne(environ) assert req.content_type == 'application/xml+foobar' def test_content_type_setter_w_None(self): environ = {'CONTENT_TYPE': 'application/xml+foobar;charset="utf8"', } req = self._makeOne(environ) req.content_type = None assert req.content_type == '' assert 'CONTENT_TYPE' not in environ def test_content_type_setter_existing_paramter_no_new_paramter(self): environ = {'CONTENT_TYPE': 'application/xml+foobar;charset="utf8"', } req = self._makeOne(environ) req.content_type = 'text/xml' assert req.content_type == 'text/xml' assert environ['CONTENT_TYPE'] == 'text/xml;charset="utf8"' def test_content_type_deleter_clears_environ_value(self): environ = {'CONTENT_TYPE': 'application/xml+foobar;charset="utf8"', } req = self._makeOne(environ) del req.content_type assert req.content_type == '' assert 'CONTENT_TYPE' not in environ def test_content_type_deleter_no_environ_value(self): environ = {} req = self._makeOne(environ) del req.content_type assert req.content_type == '' assert 'CONTENT_TYPE' not in environ def test_headers_getter(self): CONTENT_TYPE = 'application/xml+foobar;charset="utf8"' environ = {'CONTENT_TYPE': CONTENT_TYPE, 'CONTENT_LENGTH': '123', } req = self._makeOne(environ) headers = req.headers assert headers == {'Content-Type': CONTENT_TYPE, 'Content-Length': '123'} def test_headers_setter(self): CONTENT_TYPE = 'application/xml+foobar;charset="utf8"' environ = {'CONTENT_TYPE': CONTENT_TYPE, 'CONTENT_LENGTH': '123', } req = self._makeOne(environ) req.headers = {'Qux': 'Spam'} assert req.headers == {'Qux': 'Spam'} assert environ == {'HTTP_QUX': 'Spam'} def test_no_headers_deleter(self): CONTENT_TYPE = 'application/xml+foobar;charset="utf8"' environ = {'CONTENT_TYPE': CONTENT_TYPE, 'CONTENT_LENGTH': '123', } req = self._makeOne(environ) def _test(): del req.headers with pytest.raises(AttributeError): _test() def test_client_addr_xff_singleval(self): environ = { 'HTTP_X_FORWARDED_FOR': '192.168.1.1', } req = self._makeOne(environ) assert req.client_addr == '192.168.1.1' def test_client_addr_xff_multival(self): environ = { 'HTTP_X_FORWARDED_FOR': '192.168.1.1, 192.168.1.2', } req = self._makeOne(environ) assert req.client_addr == '192.168.1.1' def test_client_addr_prefers_xff(self): environ = {'REMOTE_ADDR': '192.168.1.2', 'HTTP_X_FORWARDED_FOR': '192.168.1.1', } req = self._makeOne(environ) assert req.client_addr == '192.168.1.1' def test_client_addr_no_xff(self): environ = {'REMOTE_ADDR': '192.168.1.2', } req = self._makeOne(environ) assert req.client_addr == '192.168.1.2' def test_client_addr_no_xff_no_remote_addr(self): environ = {} req = self._makeOne(environ) assert req.client_addr == None def test_host_port_w_http_host_and_no_port(self): environ = {'wsgi.url_scheme': 'http', 'HTTP_HOST': 'example.com', } req = self._makeOne(environ) assert req.host_port == '80' def test_host_port_w_http_host_and_standard_port(self): environ = {'wsgi.url_scheme': 'http', 'HTTP_HOST': 'example.com:80', } req = self._makeOne(environ) assert req.host_port == '80' def test_host_port_w_http_host_and_oddball_port(self): environ = {'wsgi.url_scheme': 'http', 'HTTP_HOST': 'example.com:8888', } req = self._makeOne(environ) assert req.host_port == '8888' def test_host_port_w_http_host_https_and_no_port(self): environ = {'wsgi.url_scheme': 'https', 'HTTP_HOST': 'example.com', } req = self._makeOne(environ) assert req.host_port == '443' def test_host_port_w_http_host_https_and_standard_port(self): environ = {'wsgi.url_scheme': 'https', 'HTTP_HOST': 'example.com:443', } req = self._makeOne(environ) assert req.host_port == '443' def test_host_port_w_http_host_https_and_oddball_port(self): environ = {'wsgi.url_scheme': 'https', 'HTTP_HOST': 'example.com:8888', } req = self._makeOne(environ) assert req.host_port == '8888' def test_host_port_wo_http_host(self): environ = {'wsgi.url_scheme': 'https', 'SERVER_PORT': '4333', } req = self._makeOne(environ) assert req.host_port == '4333' def test_host_url_w_http_host_and_no_port(self): environ = {'wsgi.url_scheme': 'http', 'HTTP_HOST': 'example.com', } req = self._makeOne(environ) assert req.host_url == 'http://example.com' def test_host_url_w_http_host_and_standard_port(self): environ = {'wsgi.url_scheme': 'http', 'HTTP_HOST': 'example.com:80', } req = self._makeOne(environ) assert req.host_url == 'http://example.com' def test_host_url_w_http_host_and_oddball_port(self): environ = {'wsgi.url_scheme': 'http', 'HTTP_HOST': 'example.com:8888', } req = self._makeOne(environ) assert req.host_url == 'http://example.com:8888' def test_host_url_w_http_host_https_and_no_port(self): environ = {'wsgi.url_scheme': 'https', 'HTTP_HOST': 'example.com', } req = self._makeOne(environ) assert req.host_url == 'https://example.com' def test_host_url_w_http_host_https_and_standard_port(self): environ = {'wsgi.url_scheme': 'https', 'HTTP_HOST': 'example.com:443', } req = self._makeOne(environ) assert req.host_url == 'https://example.com' def test_host_url_w_http_host_https_and_oddball_port(self): environ = {'wsgi.url_scheme': 'https', 'HTTP_HOST': 'example.com:4333', } req = self._makeOne(environ) assert req.host_url == 'https://example.com:4333' def test_host_url_wo_http_host(self): environ = {'wsgi.url_scheme': 'https', 'SERVER_NAME': 'example.com', 'SERVER_PORT': '4333', } req = self._makeOne(environ) assert req.host_url == 'https://example.com:4333' def test_application_url(self): inst = self._blankOne('/%C3%AB') inst.script_name = text_(b'/\xc3\xab', 'utf-8') app_url = inst.application_url assert app_url.__class__ == str assert app_url == 'http://localhost/%C3%AB' def test_path_url(self): inst = self._blankOne('/%C3%AB') inst.script_name = text_(b'/\xc3\xab', 'utf-8') app_url = inst.path_url assert app_url.__class__ == str assert app_url == 'http://localhost/%C3%AB/%C3%AB' def test_path(self): inst = self._blankOne('/%C3%AB') inst.script_name = text_(b'/\xc3\xab', 'utf-8') app_url = inst.path assert app_url.__class__ == str assert app_url == '/%C3%AB/%C3%AB' def test_path_qs_no_qs(self): environ = {'wsgi.url_scheme': 'http', 'SERVER_NAME': 'example.com', 'SERVER_PORT': '80', 'SCRIPT_NAME': '/script', 'PATH_INFO': '/path/info', } req = self._makeOne(environ) assert req.path_qs == '/script/path/info' def test_path_qs_w_qs(self): environ = {'wsgi.url_scheme': 'http', 'SERVER_NAME': 'example.com', 'SERVER_PORT': '80', 'SCRIPT_NAME': '/script', 'PATH_INFO': '/path/info', 'QUERY_STRING': 'foo=bar&baz=bam' } req = self._makeOne(environ) assert req.path_qs == '/script/path/info?foo=bar&baz=bam' def test_url_no_qs(self): environ = {'wsgi.url_scheme': 'http', 'SERVER_NAME': 'example.com', 'SERVER_PORT': '80', 'SCRIPT_NAME': '/script', 'PATH_INFO': '/path/info', } req = self._makeOne(environ) assert req.url == 'http://example.com/script/path/info' def test_url_w_qs(self): environ = {'wsgi.url_scheme': 'http', 'SERVER_NAME': 'example.com', 'SERVER_PORT': '80', 'SCRIPT_NAME': '/script', 'PATH_INFO': '/path/info', 'QUERY_STRING': 'foo=bar&baz=bam' } req = self._makeOne(environ) assert req.url == 'http://example.com/script/path/info?foo=bar&baz=bam' def test_relative_url_to_app_true_wo_leading_slash(self): environ = {'wsgi.url_scheme': 'http', 'SERVER_NAME': 'example.com', 'SERVER_PORT': '80', 'SCRIPT_NAME': '/script', 'PATH_INFO': '/path/info', 'QUERY_STRING': 'foo=bar&baz=bam' } req = self._makeOne(environ) assert req.relative_url('other/page', True) == 'http://example.com/script/other/page' def test_relative_url_to_app_true_w_leading_slash(self): environ = {'wsgi.url_scheme': 'http', 'SERVER_NAME': 'example.com', 'SERVER_PORT': '80', 'SCRIPT_NAME': '/script', 'PATH_INFO': '/path/info', 'QUERY_STRING': 'foo=bar&baz=bam' } req = self._makeOne(environ) assert req.relative_url('/other/page', True) == 'http://example.com/other/page' def test_relative_url_to_app_false_other_w_leading_slash(self): environ = {'wsgi.url_scheme': 'http', 'SERVER_NAME': 'example.com', 'SERVER_PORT': '80', 'SCRIPT_NAME': '/script', 'PATH_INFO': '/path/info', 'QUERY_STRING': 'foo=bar&baz=bam' } req = self._makeOne(environ) assert req.relative_url('/other/page', False) == 'http://example.com/other/page' def test_relative_url_to_app_false_other_wo_leading_slash(self): environ = {'wsgi.url_scheme': 'http', 'SERVER_NAME': 'example.com', 'SERVER_PORT': '80', 'SCRIPT_NAME': '/script', 'PATH_INFO': '/path/info', 'QUERY_STRING': 'foo=bar&baz=bam' } req = self._makeOne(environ) assert req.relative_url('other/page', False) == 'http://example.com/script/path/other/page' def test_path_info_pop_empty(self): environ = {'wsgi.url_scheme': 'http', 'SERVER_NAME': 'example.com', 'SERVER_PORT': '80', 'SCRIPT_NAME': '/script', 'PATH_INFO': '', } req = self._makeOne(environ) popped = req.path_info_pop() assert popped == None assert environ['SCRIPT_NAME'] == '/script' def test_path_info_pop_just_leading_slash(self): environ = {'wsgi.url_scheme': 'http', 'SERVER_NAME': 'example.com', 'SERVER_PORT': '80', 'SCRIPT_NAME': '/script', 'PATH_INFO': '/', } req = self._makeOne(environ) popped = req.path_info_pop() assert popped == '' assert environ['SCRIPT_NAME'] == '/script/' assert environ['PATH_INFO'] == '' def test_path_info_pop_non_empty_no_pattern(self): environ = {'wsgi.url_scheme': 'http', 'SERVER_NAME': 'example.com', 'SERVER_PORT': '80', 'SCRIPT_NAME': '/script', 'PATH_INFO': '/path/info', } req = self._makeOne(environ) popped = req.path_info_pop() assert popped == 'path' assert environ['SCRIPT_NAME'] == '/script/path' assert environ['PATH_INFO'] == '/info' def test_path_info_pop_non_empty_w_pattern_miss(self): import re PATTERN = re.compile('miss') environ = {'wsgi.url_scheme': 'http', 'SERVER_NAME': 'example.com', 'SERVER_PORT': '80', 'SCRIPT_NAME': '/script', 'PATH_INFO': '/path/info', } req = self._makeOne(environ) popped = req.path_info_pop(PATTERN) assert popped == None assert environ['SCRIPT_NAME'] == '/script' assert environ['PATH_INFO'] == '/path/info' def test_path_info_pop_non_empty_w_pattern_hit(self): import re PATTERN = re.compile('path') environ = {'wsgi.url_scheme': 'http', 'SERVER_NAME': 'example.com', 'SERVER_PORT': '80', 'SCRIPT_NAME': '/script', 'PATH_INFO': '/path/info', } req = self._makeOne(environ) popped = req.path_info_pop(PATTERN) assert popped == 'path' assert environ['SCRIPT_NAME'] == '/script/path' assert environ['PATH_INFO'] == '/info' def test_path_info_pop_skips_empty_elements(self): environ = {'wsgi.url_scheme': 'http', 'SERVER_NAME': 'example.com', 'SERVER_PORT': '80', 'SCRIPT_NAME': '/script', 'PATH_INFO': '//path/info', } req = self._makeOne(environ) popped = req.path_info_pop() assert popped == 'path' assert environ['SCRIPT_NAME'] == '/script//path' assert environ['PATH_INFO'] == '/info' def test_path_info_peek_empty(self): environ = {'wsgi.url_scheme': 'http', 'SERVER_NAME': 'example.com', 'SERVER_PORT': '80', 'SCRIPT_NAME': '/script', 'PATH_INFO': '', } req = self._makeOne(environ) peeked = req.path_info_peek() assert peeked == None assert environ['SCRIPT_NAME'] == '/script' assert environ['PATH_INFO'] == '' def test_path_info_peek_just_leading_slash(self): environ = {'wsgi.url_scheme': 'http', 'SERVER_NAME': 'example.com', 'SERVER_PORT': '80', 'SCRIPT_NAME': '/script', 'PATH_INFO': '/', } req = self._makeOne(environ) peeked = req.path_info_peek() assert peeked == '' assert environ['SCRIPT_NAME'] == '/script' assert environ['PATH_INFO'] == '/' def test_path_info_peek_non_empty(self): environ = {'wsgi.url_scheme': 'http', 'SERVER_NAME': 'example.com', 'SERVER_PORT': '80', 'SCRIPT_NAME': '/script', 'PATH_INFO': '/path', } req = self._makeOne(environ) peeked = req.path_info_peek() assert peeked == 'path' assert environ['SCRIPT_NAME'] == '/script' assert environ['PATH_INFO'] == '/path' def test_is_xhr_no_header(self): req = self._makeOne({}) assert not req.is_xhr def test_is_xhr_header_miss(self): environ = {'HTTP_X_REQUESTED_WITH': 'notAnXMLHTTPRequest'} req = self._makeOne(environ) assert not req.is_xhr def test_is_xhr_header_hit(self): environ = {'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'} req = self._makeOne(environ) assert req.is_xhr # host def test_host_getter_w_HTTP_HOST(self): environ = {'HTTP_HOST': 'example.com:8888'} req = self._makeOne(environ) assert req.host == 'example.com:8888' def test_host_getter_wo_HTTP_HOST(self): environ = {'SERVER_NAME': 'example.com', 'SERVER_PORT': '8888'} req = self._makeOne(environ) assert req.host == 'example.com:8888' def test_host_setter(self): environ = {} req = self._makeOne(environ) req.host = 'example.com:8888' assert environ['HTTP_HOST'] == 'example.com:8888' def test_host_deleter_hit(self): environ = {'HTTP_HOST': 'example.com:8888'} req = self._makeOne(environ) del req.host assert 'HTTP_HOST' not in environ def test_host_deleter_miss(self): environ = {} req = self._makeOne(environ) del req.host # doesn't raise def test_domain_nocolon(self): environ = {'HTTP_HOST':'example.com'} req = self._makeOne(environ) assert req.domain == 'example.com' def test_domain_withcolon(self): environ = {'HTTP_HOST':'example.com:8888'} req = self._makeOne(environ) assert req.domain == 'example.com' def test_encget_raises_without_default(self): inst = self._makeOne({}) with pytest.raises(KeyError): inst.encget('a') def test_encget_doesnt_raises_with_default(self): inst = self._makeOne({}) assert inst.encget('a', None) == None def test_encget_with_encattr(self): val = native_(b'\xc3\xab', 'latin-1') inst = self._makeOne({'a': val}) assert inst.encget('a', encattr='url_encoding') == text_(b'\xc3\xab', 'utf-8') def test_encget_with_encattr_latin_1(self): val = native_(b'\xc3\xab', 'latin-1') inst = self._makeOne({'a': val}) inst.my_encoding = 'latin-1' assert inst.encget('a', encattr='my_encoding') == text_(b'\xc3\xab', 'latin-1') def test_encget_no_encattr(self): val = native_(b'\xc3\xab', 'latin-1') inst = self._makeOne({'a': val}) assert inst.encget('a') == val def test_relative_url(self): inst = self._blankOne('/%C3%AB/c') result = inst.relative_url('a') assert result.__class__ == str assert result == 'http://localhost/%C3%AB/a' def test_header_getter(self): val = native_(b'abc', 'latin-1') inst = self._makeOne({'HTTP_FLUB': val}) result = inst.headers['Flub'] assert result.__class__ == str assert result == 'abc' def test_json_body(self): inst = self._makeOne({}) inst.body = b'{"a":"1"}' assert inst.json_body == {'a':'1'} inst.json_body = {'a': '2'} assert inst.body == b'{"a":"2"}' def test_host_get(self): inst = self._makeOne({'HTTP_HOST':'example.com'}) result = inst.host assert result.__class__ == str assert result == 'example.com' def test_host_get_w_no_http_host(self): inst = self._makeOne({'SERVER_NAME':'example.com', 'SERVER_PORT':'80'}) result = inst.host assert result.__class__ == str assert result == 'example.com:80' class TestLegacyRequest(object): # tests of methods of a bytesrequest which deal with http environment vars def _getTargetClass(self): from webob.request import LegacyRequest return LegacyRequest def _makeOne(self, *arg, **kw): cls = self._getTargetClass() return cls(*arg, **kw) def _blankOne(self, *arg, **kw): cls = self._getTargetClass() return cls.blank(*arg, **kw) def test_method(self): environ = {'REQUEST_METHOD': 'OPTIONS', } req = self._makeOne(environ) assert req.method == 'OPTIONS' def test_http_version(self): environ = {'SERVER_PROTOCOL': '1.1', } req = self._makeOne(environ) assert req.http_version == '1.1' def test_script_name(self): environ = {'SCRIPT_NAME': '/script', } req = self._makeOne(environ) assert req.script_name == '/script' def test_path_info(self): environ = {'PATH_INFO': '/path/info', } req = self._makeOne(environ) assert req.path_info == '/path/info' def test_content_length_getter(self): environ = {'CONTENT_LENGTH': '1234', } req = self._makeOne(environ) assert req.content_length == 1234 def test_content_length_setter_w_str(self): environ = {'CONTENT_LENGTH': '1234', } req = self._makeOne(environ) req.content_length = '3456' assert req.content_length == 3456 def test_remote_user(self): environ = {'REMOTE_USER': 'phred', } req = self._makeOne(environ) assert req.remote_user == 'phred' def test_remote_addr(self): environ = {'REMOTE_ADDR': '1.2.3.4', } req = self._makeOne(environ) assert req.remote_addr == '1.2.3.4' def test_query_string(self): environ = {'QUERY_STRING': 'foo=bar&baz=bam', } req = self._makeOne(environ) assert req.query_string == 'foo=bar&baz=bam' def test_server_name(self): environ = {'SERVER_NAME': 'somehost.tld', } req = self._makeOne(environ) assert req.server_name == 'somehost.tld' def test_server_port_getter(self): environ = {'SERVER_PORT': '6666', } req = self._makeOne(environ) assert req.server_port == 6666 def test_server_port_setter_with_string(self): environ = {'SERVER_PORT': '6666', } req = self._makeOne(environ) req.server_port = '6667' assert req.server_port == 6667 def test_uscript_name(self): environ = {'SCRIPT_NAME': '/script', } req = self._makeOne(environ) assert isinstance(req.uscript_name, text_type) result = req.uscript_name assert result.__class__ == text_type assert result == '/script' def test_upath_info(self): environ = {'PATH_INFO': '/path/info', } req = self._makeOne(environ) result = req.upath_info assert isinstance(result, text_type) assert result == '/path/info' def test_upath_info_set_unicode(self): environ = {'PATH_INFO': '/path/info', } req = self._makeOne(environ) req.upath_info = text_('/another') result = req.upath_info assert isinstance(result, text_type) assert result == '/another' def test_content_type_getter_no_parameters(self): environ = {'CONTENT_TYPE': 'application/xml+foobar', } req = self._makeOne(environ) assert req.content_type == 'application/xml+foobar' def test_content_type_getter_w_parameters(self): environ = {'CONTENT_TYPE': 'application/xml+foobar;charset="utf8"', } req = self._makeOne(environ) assert req.content_type == 'application/xml+foobar' def test_content_type_setter_w_None(self): environ = {'CONTENT_TYPE': 'application/xml+foobar;charset="utf8"', } req = self._makeOne(environ) req.content_type = None assert req.content_type == '' assert 'CONTENT_TYPE' not in environ def test_content_type_setter_existing_paramter_no_new_paramter(self): environ = {'CONTENT_TYPE': 'application/xml+foobar;charset="utf8"', } req = self._makeOne(environ) req.content_type = 'text/xml' assert req.content_type == 'text/xml' assert environ['CONTENT_TYPE'] == 'text/xml;charset="utf8"' def test_content_type_deleter_clears_environ_value(self): environ = {'CONTENT_TYPE': 'application/xml+foobar;charset="utf8"', } req = self._makeOne(environ) del req.content_type assert req.content_type == '' assert 'CONTENT_TYPE' not in environ def test_content_type_deleter_no_environ_value(self): environ = {} req = self._makeOne(environ) del req.content_type assert req.content_type == '' assert 'CONTENT_TYPE' not in environ def test_headers_getter(self): CONTENT_TYPE = 'application/xml+foobar;charset="utf8"' environ = {'CONTENT_TYPE': CONTENT_TYPE, 'CONTENT_LENGTH': '123', } req = self._makeOne(environ) headers = req.headers assert headers == {'Content-Type':CONTENT_TYPE, 'Content-Length': '123'} def test_headers_setter(self): CONTENT_TYPE = 'application/xml+foobar;charset="utf8"' environ = {'CONTENT_TYPE': CONTENT_TYPE, 'CONTENT_LENGTH': '123', } req = self._makeOne(environ) req.headers = {'Qux': 'Spam'} assert req.headers == {'Qux': 'Spam'} assert environ['HTTP_QUX'] == native_('Spam') assert environ == {'HTTP_QUX': 'Spam'} def test_no_headers_deleter(self): CONTENT_TYPE = 'application/xml+foobar;charset="utf8"' environ = {'CONTENT_TYPE': CONTENT_TYPE, 'CONTENT_LENGTH': '123', } req = self._makeOne(environ) def _test(): del req.headers with pytest.raises(AttributeError): _test() def test_client_addr_xff_singleval(self): environ = { 'HTTP_X_FORWARDED_FOR': '192.168.1.1', } req = self._makeOne(environ) assert req.client_addr == '192.168.1.1' def test_client_addr_xff_multival(self): environ = { 'HTTP_X_FORWARDED_FOR': '192.168.1.1, 192.168.1.2', } req = self._makeOne(environ) assert req.client_addr == '192.168.1.1' def test_client_addr_prefers_xff(self): environ = {'REMOTE_ADDR': '192.168.1.2', 'HTTP_X_FORWARDED_FOR': '192.168.1.1', } req = self._makeOne(environ) assert req.client_addr == '192.168.1.1' def test_client_addr_no_xff(self): environ = {'REMOTE_ADDR': '192.168.1.2', } req = self._makeOne(environ) assert req.client_addr == '192.168.1.2' def test_client_addr_no_xff_no_remote_addr(self): environ = {} req = self._makeOne(environ) assert req.client_addr == None def test_host_port_w_http_host_and_no_port(self): environ = {'wsgi.url_scheme': 'http', 'HTTP_HOST': 'example.com', } req = self._makeOne(environ) assert req.host_port == '80' def test_host_port_w_http_host_and_standard_port(self): environ = {'wsgi.url_scheme': 'http', 'HTTP_HOST': 'example.com:80', } req = self._makeOne(environ) assert req.host_port == '80' def test_host_port_w_http_host_and_oddball_port(self): environ = {'wsgi.url_scheme': 'http', 'HTTP_HOST': 'example.com:8888', } req = self._makeOne(environ) assert req.host_port == '8888' def test_host_port_w_http_host_https_and_no_port(self): environ = {'wsgi.url_scheme': 'https', 'HTTP_HOST': 'example.com', } req = self._makeOne(environ) assert req.host_port == '443' def test_host_port_w_http_host_https_and_standard_port(self): environ = {'wsgi.url_scheme': 'https', 'HTTP_HOST': 'example.com:443', } req = self._makeOne(environ) assert req.host_port == '443' def test_host_port_w_http_host_https_and_oddball_port(self): environ = {'wsgi.url_scheme': 'https', 'HTTP_HOST': 'example.com:8888', } req = self._makeOne(environ) assert req.host_port == '8888' def test_host_port_wo_http_host(self): environ = {'wsgi.url_scheme': 'https', 'SERVER_PORT': '4333', } req = self._makeOne(environ) assert req.host_port == '4333' def test_host_url_w_http_host_and_no_port(self): environ = {'wsgi.url_scheme': 'http', 'HTTP_HOST': 'example.com', } req = self._makeOne(environ) assert req.host_url == 'http://example.com' def test_host_url_w_http_host_and_standard_port(self): environ = {'wsgi.url_scheme': 'http', 'HTTP_HOST': 'example.com:80', } req = self._makeOne(environ) assert req.host_url == 'http://example.com' def test_host_url_w_http_host_and_oddball_port(self): environ = {'wsgi.url_scheme': 'http', 'HTTP_HOST': 'example.com:8888', } req = self._makeOne(environ) assert req.host_url == 'http://example.com:8888' def test_host_url_w_http_host_https_and_no_port(self): environ = {'wsgi.url_scheme': 'https', 'HTTP_HOST': 'example.com', } req = self._makeOne(environ) assert req.host_url == 'https://example.com' def test_host_url_w_http_host_https_and_standard_port(self): environ = {'wsgi.url_scheme': 'https', 'HTTP_HOST': 'example.com:443', } req = self._makeOne(environ) assert req.host_url == 'https://example.com' def test_host_url_w_http_host_https_and_oddball_port(self): environ = {'wsgi.url_scheme': 'https', 'HTTP_HOST': 'example.com:4333', } req = self._makeOne(environ) assert req.host_url == 'https://example.com:4333' def test_host_url_wo_http_host(self): environ = {'wsgi.url_scheme': 'https', 'SERVER_NAME': 'example.com', 'SERVER_PORT': '4333', } req = self._makeOne(environ) assert req.host_url == 'https://example.com:4333' @py2only def test_application_url_py2(self): inst = self._blankOne('/%C3%AB') inst.script_name = b'/\xc3\xab' app_url = inst.application_url assert app_url == 'http://localhost/%C3%AB' @py3only def test_application_url(self): inst = self._blankOne('/%C3%AB') inst.script_name = b'/\xc3\xab' app_url = inst.application_url assert app_url == 'http://localhost/%C3%83%C2%AB' @py2only def test_path_url_py2(self): inst = self._blankOne('/%C3%AB') inst.script_name = b'/\xc3\xab' result = inst.path_url assert result == 'http://localhost/%C3%AB/%C3%AB' @py3only def test_path_url(self): inst = self._blankOne('/%C3%AB') inst.script_name = b'/\xc3\xab' result = inst.path_url assert result == 'http://localhost/%C3%83%C2%AB/%C3%83%C2%AB' @py2only def test_path_py2(self): inst = self._blankOne('/%C3%AB') inst.script_name = b'/\xc3\xab' result = inst.path assert result == '/%C3%AB/%C3%AB' @py3only def test_path(self): inst = self._blankOne('/%C3%AB') inst.script_name = b'/\xc3\xab' result = inst.path assert result == '/%C3%83%C2%AB/%C3%83%C2%AB' def test_path_qs_no_qs(self): environ = {'wsgi.url_scheme': 'http', 'SERVER_NAME': 'example.com', 'SERVER_PORT': '80', 'SCRIPT_NAME': '/script', 'PATH_INFO': '/path/info', } req = self._makeOne(environ) assert req.path_qs == '/script/path/info' def test_path_qs_w_qs(self): environ = {'wsgi.url_scheme': 'http', 'SERVER_NAME': 'example.com', 'SERVER_PORT': '80', 'SCRIPT_NAME': '/script', 'PATH_INFO': '/path/info', 'QUERY_STRING': 'foo=bar&baz=bam' } req = self._makeOne(environ) assert req.path_qs == '/script/path/info?foo=bar&baz=bam' def test_url_no_qs(self): environ = {'wsgi.url_scheme': 'http', 'SERVER_NAME': 'example.com', 'SERVER_PORT': '80', 'SCRIPT_NAME': '/script', 'PATH_INFO': '/path/info', } req = self._makeOne(environ) assert req.url == 'http://example.com/script/path/info' def test_url_w_qs(self): environ = {'wsgi.url_scheme': 'http', 'SERVER_NAME': 'example.com', 'SERVER_PORT': '80', 'SCRIPT_NAME': '/script', 'PATH_INFO': '/path/info', 'QUERY_STRING': 'foo=bar&baz=bam' } req = self._makeOne(environ) assert req.url == 'http://example.com/script/path/info?foo=bar&baz=bam' def test_relative_url_to_app_true_wo_leading_slash(self): environ = {'wsgi.url_scheme': 'http', 'SERVER_NAME': 'example.com', 'SERVER_PORT': '80', 'SCRIPT_NAME': '/script', 'PATH_INFO': '/path/info', 'QUERY_STRING': 'foo=bar&baz=bam' } req = self._makeOne(environ) assert req.relative_url('other/page' == True, 'http://example.com/script/other/page') def test_relative_url_to_app_true_w_leading_slash(self): environ = {'wsgi.url_scheme': 'http', 'SERVER_NAME': 'example.com', 'SERVER_PORT': '80', 'SCRIPT_NAME': '/script', 'PATH_INFO': '/path/info', 'QUERY_STRING': 'foo=bar&baz=bam' } req = self._makeOne(environ) assert req.relative_url('/other/page' == True, 'http://example.com/other/page') def test_relative_url_to_app_false_other_w_leading_slash(self): environ = {'wsgi.url_scheme': 'http', 'SERVER_NAME': 'example.com', 'SERVER_PORT': '80', 'SCRIPT_NAME': '/script', 'PATH_INFO': '/path/info', 'QUERY_STRING': 'foo=bar&baz=bam' } req = self._makeOne(environ) assert req.relative_url('/other/page', False) == 'http://example.com/other/page' def test_relative_url_to_app_false_other_wo_leading_slash(self): environ = {'wsgi.url_scheme': 'http', 'SERVER_NAME': 'example.com', 'SERVER_PORT': '80', 'SCRIPT_NAME': '/script', 'PATH_INFO': '/path/info', 'QUERY_STRING': 'foo=bar&baz=bam' } req = self._makeOne(environ) assert req.relative_url('other/page', False) == 'http://example.com/script/path/other/page' def test_path_info_pop_empty(self): environ = {'wsgi.url_scheme': 'http', 'SERVER_NAME': 'example.com', 'SERVER_PORT': '80', 'SCRIPT_NAME': '/script', 'PATH_INFO': '', } req = self._makeOne(environ) popped = req.path_info_pop() assert popped == None assert environ['SCRIPT_NAME'] == '/script' def test_path_info_pop_just_leading_slash(self): environ = {'wsgi.url_scheme': 'http', 'SERVER_NAME': 'example.com', 'SERVER_PORT': '80', 'SCRIPT_NAME': '/script', 'PATH_INFO': '/', } req = self._makeOne(environ) popped = req.path_info_pop() assert popped == '' assert environ['SCRIPT_NAME'] == '/script/' assert environ['PATH_INFO'] == '' def test_path_info_pop_non_empty_no_pattern(self): environ = {'wsgi.url_scheme': 'http', 'SERVER_NAME': 'example.com', 'SERVER_PORT': '80', 'SCRIPT_NAME': '/script', 'PATH_INFO': '/path/info', } req = self._makeOne(environ) popped = req.path_info_pop() assert popped == 'path' assert environ['SCRIPT_NAME'] == '/script/path' assert environ['PATH_INFO'] == '/info' def test_path_info_pop_non_empty_w_pattern_miss(self): import re PATTERN = re.compile('miss') environ = {'wsgi.url_scheme': 'http', 'SERVER_NAME': 'example.com', 'SERVER_PORT': '80', 'SCRIPT_NAME': '/script', 'PATH_INFO': '/path/info', } req = self._makeOne(environ) popped = req.path_info_pop(PATTERN) assert popped == None assert environ['SCRIPT_NAME'] == '/script' assert environ['PATH_INFO'] == '/path/info' def test_path_info_pop_non_empty_w_pattern_hit(self): import re PATTERN = re.compile('path') environ = {'wsgi.url_scheme': 'http', 'SERVER_NAME': 'example.com', 'SERVER_PORT': '80', 'SCRIPT_NAME': '/script', 'PATH_INFO': '/path/info', } req = self._makeOne(environ) popped = req.path_info_pop(PATTERN) assert popped == 'path' assert environ['SCRIPT_NAME'] == '/script/path' assert environ['PATH_INFO'] == '/info' def test_path_info_pop_skips_empty_elements(self): environ = {'wsgi.url_scheme': 'http', 'SERVER_NAME': 'example.com', 'SERVER_PORT': '80', 'SCRIPT_NAME': '/script', 'PATH_INFO': '//path/info', } req = self._makeOne(environ) popped = req.path_info_pop() assert popped == 'path' assert environ['SCRIPT_NAME'] == '/script//path' assert environ['PATH_INFO'] == '/info' def test_path_info_peek_empty(self): environ = {'wsgi.url_scheme': 'http', 'SERVER_NAME': 'example.com', 'SERVER_PORT': '80', 'SCRIPT_NAME': '/script', 'PATH_INFO': '', } req = self._makeOne(environ) peeked = req.path_info_peek() assert peeked == None assert environ['SCRIPT_NAME'] == '/script' assert environ['PATH_INFO'] == '' def test_path_info_peek_just_leading_slash(self): environ = {'wsgi.url_scheme': 'http', 'SERVER_NAME': 'example.com', 'SERVER_PORT': '80', 'SCRIPT_NAME': '/script', 'PATH_INFO': '/', } req = self._makeOne(environ) peeked = req.path_info_peek() assert peeked == '' assert environ['SCRIPT_NAME'] == '/script' assert environ['PATH_INFO'] == '/' def test_path_info_peek_non_empty(self): environ = {'wsgi.url_scheme': 'http', 'SERVER_NAME': 'example.com', 'SERVER_PORT': '80', 'SCRIPT_NAME': '/script', 'PATH_INFO': '/path', } req = self._makeOne(environ) peeked = req.path_info_peek() assert peeked == 'path' assert environ['SCRIPT_NAME'] == '/script' assert environ['PATH_INFO'] == '/path' def test_is_xhr_no_header(self): req = self._makeOne({}) assert not req.is_xhr def test_is_xhr_header_miss(self): environ = {'HTTP_X_REQUESTED_WITH': 'notAnXMLHTTPRequest'} req = self._makeOne(environ) assert not req.is_xhr def test_is_xhr_header_hit(self): environ = {'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'} req = self._makeOne(environ) assert req.is_xhr # host def test_host_getter_w_HTTP_HOST(self): environ = {'HTTP_HOST': 'example.com:8888'} req = self._makeOne(environ) assert req.host == 'example.com:8888' def test_host_getter_wo_HTTP_HOST(self): environ = {'SERVER_NAME': 'example.com', 'SERVER_PORT': '8888'} req = self._makeOne(environ) assert req.host == 'example.com:8888' def test_host_setter(self): environ = {} req = self._makeOne(environ) req.host = 'example.com:8888' assert environ['HTTP_HOST'] == 'example.com:8888' def test_host_deleter_hit(self): environ = {'HTTP_HOST': 'example.com:8888'} req = self._makeOne(environ) del req.host assert 'HTTP_HOST' not in environ def test_host_deleter_miss(self): environ = {} req = self._makeOne(environ) del req.host # doesn't raise def test_encget_raises_without_default(self): inst = self._makeOne({}) with pytest.raises(KeyError): inst.encget('a') def test_encget_doesnt_raises_with_default(self): inst = self._makeOne({}) assert inst.encget('a', None) == None def test_encget_with_encattr(self): val = native_(b'\xc3\xab', 'latin-1') inst = self._makeOne({'a':val}) assert inst.encget('a', encattr='url_encoding') == native_(b'\xc3\xab', 'latin-1') def test_encget_no_encattr(self): val = native_(b'\xc3\xab', 'latin-1') inst = self._makeOne({'a': val}) assert inst.encget('a'), native_(b'\xc3\xab' == 'latin-1') @py2only def test_relative_url_py2(self): inst = self._blankOne('/%C3%AB/c') result = inst.relative_url('a') assert result == 'http://localhost/%C3%AB/a' @py3only def test_relative_url(self): inst = self._blankOne('/%C3%AB/c') result = inst.relative_url('a') assert result == 'http://localhost/%C3%83%C2%AB/a' def test_header_getter(self): val = native_(b'abc', 'latin-1') inst = self._makeOne({'HTTP_FLUB':val}) result = inst.headers['Flub'] assert result == 'abc' def test_json_body(self): inst = self._makeOne({}) inst.body = b'{"a":"1"}' assert inst.json_body == {'a':'1'} def test_host_get_w_http_host(self): inst = self._makeOne({'HTTP_HOST':'example.com'}) result = inst.host assert result == 'example.com' def test_host_get_w_no_http_host(self): inst = self._makeOne({'SERVER_NAME':'example.com', 'SERVER_PORT':'80'}) result = inst.host assert result == 'example.com:80' class TestRequestConstructorWarnings(object): def _getTargetClass(self): from webob.request import Request return Request def _makeOne(self, *arg, **kw): cls = self._getTargetClass() return cls(*arg, **kw) def test_ctor_w_unicode_errors(self): with warnings.catch_warnings(record=True) as w: # still emit if warning was printed previously warnings.simplefilter('always') self._makeOne({}, unicode_errors=True) assert len(w) == 1 def test_ctor_w_decode_param_names(self): with warnings.catch_warnings(record=True) as w: # still emit if warning was printed previously warnings.simplefilter('always') self._makeOne({}, decode_param_names=True) assert len(w) == 1 class TestRequestWithAdhocAttr(object): def _blankOne(self, *arg, **kw): from webob.request import Request return Request.blank(*arg, **kw) def test_adhoc_attrs_set(self): req = self._blankOne('/') req.foo = 1 assert req.environ['webob.adhoc_attrs'] == {'foo': 1} def test_adhoc_attrs_set_nonadhoc(self): req = self._blankOne('/', environ={'webob.adhoc_attrs':{}}) req.request_body_tempfile_limit = 1 assert req.environ['webob.adhoc_attrs'] == {} def test_adhoc_attrs_get(self): req = self._blankOne('/', environ={'webob.adhoc_attrs': {'foo': 1}}) assert req.foo == 1 def test_adhoc_attrs_get_missing(self): req = self._blankOne('/') with pytest.raises(AttributeError): getattr(req, 'some_attr') def test_adhoc_attrs_del(self): req = self._blankOne('/', environ={'webob.adhoc_attrs': {'foo': 1}}) del req.foo assert req.environ['webob.adhoc_attrs'] == {} def test_adhoc_attrs_del_missing(self): req = self._blankOne('/') with pytest.raises(AttributeError): delattr(req, 'some_attr') class TestRequest_functional(object): # functional tests of request def _getTargetClass(self): from webob.request import Request return Request def _makeOne(self, *arg, **kw): cls = self._getTargetClass() return cls(*arg, **kw) def _blankOne(self, *arg, **kw): cls = self._getTargetClass() return cls.blank(*arg, **kw) def test_gets(self): request = self._blankOne('/') status, headerlist, app_iter = request.call_application(simpleapp) assert status == '200 OK' res = b''.join(app_iter) assert b'Hello' in res assert b"MultiDict([])" in res assert b"post is