thirdparty/google_appengine/lib/webob/tests/test_request.txt
changeset 109 620f9b141567
equal deleted inserted replaced
108:261778de26ff 109:620f9b141567
       
     1 This demonstrates how the Request object works, and tests it.
       
     2 
       
     3 You can instantiate a request using ``Request.blank()``, to create a
       
     4 fresh environment dictionary with all the basic keys such a dictionary
       
     5 should have.
       
     6 
       
     7     >>> from dtopt import ELLIPSIS
       
     8     >>> from webob import Request, UTC
       
     9     >>> req = Request.blank('/')
       
    10     >>> req # doctest: +ELLIPSIS
       
    11     <Request at ... GET http://localhost/>
       
    12     >>> print repr(str(req))
       
    13     'GET /\r\nHost: localhost:80\r\n\r\n'
       
    14     >>> req.environ # doctest: +ELLIPSIS
       
    15     {...}
       
    16     >>> req.body_file # doctest: +ELLIPSIS
       
    17     <cStringIO.StringI object at ...>
       
    18     >>> req.scheme
       
    19     'http'
       
    20     >>> req.method
       
    21     'GET'
       
    22     >>> req.script_name
       
    23     ''
       
    24     >>> req.path_info
       
    25     '/'
       
    26     >>> req.content_type
       
    27     ''
       
    28     >>> print req.remote_user
       
    29     None
       
    30     >>> req.host_url
       
    31     'http://localhost'
       
    32     >>> req.script_name = '/foo'
       
    33     >>> req.path_info = '/bar/'
       
    34     >>> req.environ['QUERY_STRING'] = 'a=b'
       
    35     >>> req.application_url
       
    36     'http://localhost/foo'
       
    37     >>> req.path_url
       
    38     'http://localhost/foo/bar/'
       
    39     >>> req.url
       
    40     'http://localhost/foo/bar/?a=b'
       
    41     >>> req.relative_url('baz')
       
    42     'http://localhost/foo/bar/baz'
       
    43     >>> req.relative_url('baz', to_application=True)
       
    44     'http://localhost/foo/baz'
       
    45     >>> req.relative_url('http://example.org')
       
    46     'http://example.org'
       
    47     >>> req.path_info_peek()
       
    48     'bar'
       
    49     >>> req.path_info_pop()
       
    50     'bar'
       
    51     >>> req.script_name, req.path_info
       
    52     ('/foo/bar', '/')
       
    53     >>> print req.environ.get('wsgiorg.routing_args')
       
    54     None
       
    55     >>> req.urlvars
       
    56     {}
       
    57     >>> req.environ['wsgiorg.routing_args']
       
    58     ((), {})
       
    59     >>> req.urlvars = dict(x='y')
       
    60     >>> req.environ['wsgiorg.routing_args']
       
    61     ((), {'x': 'y'})
       
    62     >>> req.urlargs
       
    63     ()
       
    64     >>> req.urlargs = (1, 2, 3)
       
    65     >>> req.environ['wsgiorg.routing_args']
       
    66     ((1, 2, 3), {'x': 'y'})
       
    67     >>> del req.urlvars
       
    68     >>> req.environ['wsgiorg.routing_args']
       
    69     ((1, 2, 3), {})
       
    70     >>> req.urlvars = {'test': 'value'}
       
    71     >>> del req.urlargs
       
    72     >>> req.environ['wsgiorg.routing_args']
       
    73     ((), {'test': 'value'})
       
    74     >>> req.is_xhr
       
    75     False
       
    76     >>> req.environ['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'
       
    77     >>> req.is_xhr
       
    78     True
       
    79     >>> req.host
       
    80     'localhost:80'
       
    81 
       
    82 There are also variables to access the variables and body:
       
    83 
       
    84     >>> from cStringIO import StringIO
       
    85     >>> body = 'var1=value1&var2=value2&rep=1&rep=2'
       
    86     >>> req = Request.blank('/')
       
    87     >>> req.method = 'POST'
       
    88     >>> req.body_file = StringIO(body)
       
    89     >>> req.environ['CONTENT_LENGTH'] = str(len(body))
       
    90     >>> vars = req.str_POST
       
    91     >>> vars
       
    92     MultiDict([('var1', 'value1'), ('var2', 'value2'), ('rep', '1'), ('rep', '2')])
       
    93     >>> vars is req.str_POST
       
    94     True
       
    95     >>> req.POST
       
    96     MultiDict([('var1', 'value1'), ('var2', 'value2'), ('rep', '1'), ('rep', '2')])
       
    97     >>> req.charset = 'utf8'
       
    98     >>> req.POST
       
    99     UnicodeMultiDict([(u'var1', u'value1'), (u'var2', u'value2'), (u'rep', u'1'), (u'rep', u'2')])
       
   100 
       
   101 Note that the variables are there for GET requests and non-form POST
       
   102 requests, but they are empty and read-only:
       
   103 
       
   104     >>> req = Request.blank('/')
       
   105     >>> req.str_POST
       
   106     <NoVars: Not a POST request>
       
   107     >>> req.str_POST.items()
       
   108     []
       
   109     >>> req.str_POST['x'] = 'y'
       
   110     Traceback (most recent call last):
       
   111         ...
       
   112     KeyError: 'Cannot add variables: Not a POST request'
       
   113     >>> req.method = 'POST'
       
   114     >>> req.str_POST
       
   115     MultiDict([])
       
   116     >>> req.content_type = 'text/xml'
       
   117     >>> req.body_file = StringIO('<xml></xml>')
       
   118     >>> req.str_POST
       
   119     <NoVars: Not an HTML form submission (Content-Type: text/xml)>
       
   120     >>> req.body
       
   121     '<xml></xml>'
       
   122 
       
   123 You can also get access to the query string variables, of course:
       
   124 
       
   125     >>> req = Request.blank('/?a=b&d=e&d=f')
       
   126     >>> req.GET
       
   127     MultiDict([('a', 'b'), ('d', 'e'), ('d', 'f')])
       
   128     >>> req.GET['d']
       
   129     'f'
       
   130     >>> req.GET.getall('d')
       
   131     ['e', 'f']
       
   132     >>> req.method = 'POST'
       
   133     >>> req.body = 'x=y&d=g'
       
   134     >>> req.body_file # doctest: +ELLIPSIS
       
   135     <cStringIO.StringI object at ...>
       
   136     >>> req.environ['CONTENT_LENGTH']
       
   137     '7'
       
   138     >>> req.params
       
   139     NestedMultiDict([('a', 'b'), ('d', 'e'), ('d', 'f'), ('x', 'y'), ('d', 'g')])
       
   140     >>> req.params['d']
       
   141     'f'
       
   142     >>> req.params.getall('d')
       
   143     ['e', 'f', 'g']
       
   144 
       
   145 Cookie are viewed as a dictionary (*view only*):
       
   146 
       
   147     >>> req = Request.blank('/')
       
   148     >>> req.environ['HTTP_COOKIE'] = 'var1=value1; var2=value2'
       
   149     >>> req.str_cookies
       
   150     {'var1': 'value1', 'var2': 'value2'}
       
   151     >>> req.cookies
       
   152     {'var1': 'value1', 'var2': 'value2'}
       
   153     >>> req.charset = 'utf8'
       
   154     >>> req.cookies
       
   155     UnicodeMultiDict([(u'var1', u'value1'), (u'var2', u'value2')])
       
   156 
       
   157 Sometimes conditional headers are problematic.  You can remove them:
       
   158 
       
   159     >>> from datetime import datetime
       
   160     >>> req = Request.blank('/')
       
   161     >>> req.if_match = 'some-etag'
       
   162     >>> req.if_modified_since = datetime(2005, 1, 1, 12, 0)
       
   163     >>> req.environ['HTTP_ACCEPT_ENCODING'] = 'gzip'
       
   164     >>> print req.headers
       
   165     {'Host': 'localhost:80', 'If-Match': 'some-etag', 'Accept-Encoding': 'gzip', 'If-Modified-Since': 'Sat, 01 Jan 2005 12:00:00 GMT'}
       
   166     >>> req.remove_conditional_headers()
       
   167     >>> print req.headers
       
   168     {'Host': 'localhost:80'}
       
   169 
       
   170 Some headers are handled specifically (more should be added):
       
   171 
       
   172     >>> req = Request.blank('/')
       
   173     >>> req.if_none_match = 'xxx'
       
   174     >>> 'xxx' in req.if_none_match
       
   175     True
       
   176     >>> 'yyy' in req.if_none_match
       
   177     False
       
   178     >>> req.if_modified_since = datetime(2005, 1, 1, 12, 0)
       
   179     >>> req.if_modified_since < datetime(2006, 1, 1, 12, 0, tzinfo=UTC)
       
   180     True
       
   181     >>> req.user_agent
       
   182     ''
       
   183     >>> req.user_agent = 'MSIE-Win'
       
   184     >>> req.user_agent
       
   185     'MSIE-Win'
       
   186 
       
   187 Accept-* headers are parsed into read-only objects that support
       
   188 containment tests, and some useful methods.  Note that parameters on
       
   189 mime types are not supported.
       
   190 
       
   191     >>> req = Request.blank('/')
       
   192     >>> req.environ['HTTP_ACCEPT'] = "text/*;q=0.3, text/html;q=0.7, text/html;level=1, text/html;level=2;q=0.4, */*;q=0.5"
       
   193     >>> req.accept # doctest: +ELLIPSIS
       
   194     <MIMEAccept at ... Accept: text/*;q=0.3, text/html;q=0.7, text/html, text/html;q=0.4, */*;q=0.5>
       
   195     >>> for item, quality in req.accept._parsed:
       
   196     ...     print '%s: %0.1f' % (item, quality)
       
   197     text/*: 0.3
       
   198     text/html: 0.7
       
   199     text/html: 1.0
       
   200     text/html: 0.4
       
   201     */*: 0.5
       
   202     >>> '%0.1f' % req.accept.quality('text/html')
       
   203     '0.3'
       
   204     >>> req.accept.first_match(['text/plain', 'text/html', 'image/png'])
       
   205     'text/plain'
       
   206     >>> 'image/png' in req.accept
       
   207     True
       
   208     >>> req.environ['HTTP_ACCEPT'] = "text/html, application/xml; q=0.7, text/*; q=0.5, */*; q=0.1"
       
   209     >>> req.accept # doctest: +ELLIPSIS
       
   210     <MIMEAccept at ... Accept: text/html, application/xml;q=0.7, text/*;q=0.5, */*;q=0.1>
       
   211     >>> req.accept.best_match(['text/plain', 'application/xml'])
       
   212     'application/xml'
       
   213     >>> req.accept.first_match(['application/xml', 'text/html'])
       
   214     'application/xml'
       
   215     >>> req.accept = "text/html, application/xml, text/*; q=0.5"
       
   216     >>> 'image/png' in req.accept
       
   217     False
       
   218     >>> 'text/plain' in req.accept
       
   219     True
       
   220     >>> req.accept_charset = 'utf8'
       
   221     >>> 'UTF8' in req.accept_charset
       
   222     True
       
   223     >>> 'gzip' in req.accept_encoding
       
   224     False
       
   225     >>> req.accept_encoding = 'gzip'
       
   226     >>> 'GZIP' in req.accept_encoding
       
   227     True
       
   228     >>> req.accept_language = {'en-US': 0.5, 'es': 0.7}
       
   229     >>> str(req.accept_language)
       
   230     'es;q=0.7, en-US;q=0.5'
       
   231     >>> req.headers['Accept-Language']
       
   232     'es;q=0.7, en-US;q=0.5'
       
   233     >>> req.accept_language.best_matches('en-GB')
       
   234     ['es', 'en-US', 'en-GB']
       
   235     >>> req.accept_language.best_matches('es')
       
   236     ['es']
       
   237     >>> req.accept_language.best_matches('ES')
       
   238     ['es']
       
   239 
       
   240 The If-Range header is a combination of a possible conditional date or
       
   241 etag match::
       
   242 
       
   243     >>> req = Request.blank('/')
       
   244     >>> req.if_range = 'asdf'
       
   245     >>> req.if_range
       
   246     <IfRange etag=asdf, date=*>
       
   247     >>> from webob import Response
       
   248     >>> res = Response()
       
   249     >>> res.etag = 'asdf'
       
   250     >>> req.if_range.match_response(res)
       
   251     True
       
   252     >>> res.etag = None
       
   253     >>> req.if_range.match_response(res)
       
   254     False
       
   255     >>> res.last_modified = datetime(2005, 1, 1, 12, 0, tzinfo=UTC)
       
   256     >>> req.if_range = datetime(2006, 1, 1, 12, 0, tzinfo=UTC)
       
   257     >>> req.if_range
       
   258     <IfRange etag=*, date=Sun, 01 Jan 2006 12:00:00 GMT>
       
   259     >>> req.if_range.match_response(res)
       
   260     True
       
   261     >>> res.last_modified = datetime(2007, 1, 1, 12, 0, tzinfo=UTC)
       
   262     >>> req.if_range.match_response(res)
       
   263     False
       
   264     >>> req = Request.blank('/')
       
   265     >>> req.if_range
       
   266     <Empty If-Range>
       
   267     >>> req.if_range.match_response(res)
       
   268     True
       
   269 
       
   270 Ranges work like so::
       
   271 
       
   272     >>> req = Request.blank('/')
       
   273     >>> req.range = (0, 100)
       
   274     >>> req.range
       
   275     <Range ranges=(0, 100)>
       
   276     >>> str(req.range)
       
   277     'bytes=0-101'
       
   278 
       
   279 You can use them with responses::
       
   280 
       
   281     >>> res = Response()
       
   282     >>> res.content_range = req.range.content_range(1000)
       
   283     >>> res.content_range
       
   284     <ContentRange bytes 0-101/1000>
       
   285     >>> str(res.content_range)
       
   286     'bytes 0-101/1000'
       
   287     >>> start, end, length = res.content_range
       
   288     >>> start, end, length
       
   289     (0, 100, 1000)
       
   290 
       
   291 A quick test of caching the request body:
       
   292 
       
   293     >>> from cStringIO import StringIO
       
   294     >>> length = Request.request_body_tempfile_limit+10
       
   295     >>> data = StringIO('x'*length)
       
   296     >>> req = Request.blank('/')
       
   297     >>> req.content_length = length
       
   298     >>> req.body_file = data
       
   299     >>> req.body_file
       
   300     <cStringIO.StringI object at ...>
       
   301     >>> len(req.body)
       
   302     10250
       
   303     >>> req.body_file
       
   304     <open file '<fdopen>', mode 'w+b' at ...>
       
   305 
       
   306 Some query tests:
       
   307 
       
   308     >>> req = Request.blank('/')
       
   309     >>> req.GET.get('unknown')
       
   310     >>> req.GET.get('unknown', '?')
       
   311     '?'
       
   312     >>> req.POST.get('unknown')
       
   313     >>> req.POST.get('unknown', '?')
       
   314     '?'
       
   315     >>> req.params.get('unknown')
       
   316     >>> req.params.get('unknown', '?')
       
   317     '?'