summaryrefslogtreecommitdiffstats
path: root/google_appengine/lib/webob/tests/test_response.txt
blob: 270e139a0235bd5f301c0f37f8bc2f6f7f003032 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
This demonstrates how the Response object works, and tests it at the
same time.

    >>> from dtopt import ELLIPSIS
    >>> from webob import Response, UTC
    >>> from datetime import datetime
    >>> res = Response('Test', status='200 OK')

This is a minimal response object.  We can do things like get and set
the body:

    >>> res.body
    'Test'
    >>> res.body = 'Another test'
    >>> res.body
    'Another test'
    >>> res.body = 'Another'
    >>> res.write(' test')
    >>> res.app_iter
    ['Another test']
    >>> res.content_length
    12
    >>> res.headers['content-length']
    '12'
    
Content-Length is only applied when setting the body to a string; you
have to set it manually otherwise.  There are also getters and setters
for the various pieces:

    >>> res.app_iter = ['test']
    >>> print res.content_length
    None
    >>> res.content_length = 4
    >>> res.status
    '200 OK'
    >>> res.status_int
    200
    >>> res.headers
    HeaderDict([('content-type', 'text/html; charset=utf8'), ('Content-Length', '4')])
    >>> res.headerlist
    [('content-type', 'text/html; charset=utf8'), ('Content-Length', '4')]

Content-type and charset are handled separately as properties, though
they are both in the ``res.headers['content-type']`` header:

    >>> res.content_type
    'text/html'
    >>> res.content_type = 'text/html'
    >>> res.content_type
    'text/html'
    >>> res.charset
    'utf8'
    >>> res.charset = 'iso-8859-1'
    >>> res.charset
    'iso-8859-1'
    >>> res.content_type
    'text/html'
    >>> res.headers['content-type']
    'text/html; charset=iso-8859-1'

Cookie handling is done through methods:

    >>> res.set_cookie('test', 'value')
    >>> res.headers['set-cookie']
    'test=value; Path=/'
    >>> res.set_cookie('test2', 'value2', max_age=10000)
    >>> res.headers['set-cookie'] # We only see the last header
    'test2=value2; Max-Age=10000; Path=/'
    >>> res.headers.getall('set-cookie')
    ['test=value; Path=/', 'test2=value2; Max-Age=10000; Path=/']
    >>> res.unset_cookie('test')
    >>> res.headers.getall('set-cookie')
    ['test2=value2; Max-Age=10000; Path=/']

Most headers are available in a parsed getter/setter form through
properties:

    >>> res.age = 10
    >>> res.age, res.headers['age']
    (10, '10')
    >>> res.allow = ['GET', 'PUT']
    >>> res.allow, res.headers['allow']
    (['GET', 'PUT'], 'GET, PUT')
    >>> res.cache_control
    <CacheControl ''>
    >>> print res.cache_control.max_age
    None
    >>> res.cache_control.properties['max-age'] = None
    >>> print res.cache_control.max_age
    -1
    >>> res.cache_control.max_age = 10
    >>> res.cache_control
    <CacheControl 'max-age=10'>
    >>> res.headers['cache-control']
    'max-age=10'
    >>> res.cache_control.max_stale = 10
    Traceback (most recent call last):
        ...
    AttributeError: The property max-stale only applies to request Cache-Control
    >>> res.cache_control = {}
    >>> res.cache_control
    <CacheControl ''>
    >>> res.content_encoding = 'gzip'
    >>> (res.content_encoding, res.headers['content-encoding'])
    ('gzip', 'gzip')
    >>> res.content_language = 'en'
    >>> (res.content_language, res.headers['content-language'])
    (['en'], 'en')
    >>> res.content_location = 'http://localhost:8080'
    >>> res.headers['content-location']
    'http://localhost:8080'
    >>> res.content_range = (0, 100, 1000)
    >>> (res.content_range, res.headers['content-range'])
    (<ContentRange bytes 0-101/1000>, 'bytes 0-101/1000')
    >>> res.date = datetime(2005, 1, 1, 12, 0, tzinfo=UTC)
    >>> (res.date, res.headers['date'])
    (datetime.datetime(2005, 1, 1, 12, 0, tzinfo=UTC), 'Sat, 01 Jan 2005 12:00:00 GMT')
    >>> print res.etag
    None
    >>> res.etag = 'foo'
    >>> (res.etag, res.headers['etag'])
    ('foo', 'foo')
    >>> res.expires = res.date
    >>> res.retry_after = 120 # two minutes
    >>> res.retry_after
    datetime.datetime(...)
    >>> res.server = 'Python/foo'
    >>> res.headers['server']
    'Python/foo'
    >>> res.vary = ['Cookie']
    >>> (res.vary, res.headers['vary'])
    (['Cookie'], 'Cookie')

The location header will try to absolutify itself if you have a
request object attached.

    >>> res.location = '/test.html'
    >>> from webob import Request
    >>> res.request = Request.blank('/')
    >>> res.location
    'http://localhost/test.html'
    >>> res.request = None
    >>> res.location
    '/test.html'
    >>> res.request = Request.blank('/')
    >>> res.location = '/test2.html'
    >>> res.request = None
    >>> res.location
    'http://localhost/test2.html'

There's some conditional response handling too (you have to turn on
conditioanl_response)::

    >>> res = Response(conditional_response=True)
    >>> req = Request.blank('/')
    >>> res.etag = 'tag'
    >>> req.if_none_match = 'tag'
    >>> req.get_response(res)
    <Response ... 304 Not Modified>
    >>> res.etag = 'other-tag'
    >>> req.get_response(res)
    <Response ... 200 OK>
    >>> del req.if_none_match
    >>> req.if_modified_since = datetime(2005, 1, 1, 12, 1, tzinfo=UTC)
    >>> res.last_modified = datetime(2005, 1, 1, 12, 1, tzinfo=UTC)
    >>> req.get_response(res)
    <Response ... 304 Not Modified>
    >>> res.last_modified = datetime(2006, 1, 1, 12, 1, tzinfo=UTC)
    >>> req.get_response(res)
    <Response ... 200 OK>
    >>> res.last_modified = None
    >>> req.get_response(res)
    <Response ... 200 OK>

Also range response::

    >>> res = Response(conditional_response=True)
    >>> req = Request.blank('/')
    >>> res.body = '0123456789'
    >>> req.range = (1, 5)
    >>> result = req.get_response(res)
    >>> result.body
    '1234'
    >>> result.content_range
    <ContentRange bytes 1-6/10>
    >>> tuple(result.content_range)
    (1, 5, 10)
    >>> # Now an invalid range:
    >>> req.range = (0, 20)
    >>> str(req.range)
    'bytes=0-21'
    >>> result = req.get_response(res)
    >>> result.body
    '0123456789'
    >>> print result.content_range
    None

That was easier; we'll try it with a iterator for the body::

    >>> res = Response(conditional_response=True)
    >>> res.app_iter = ['01234', '567', '89']
    >>> req = Request.blank('/')
    >>> req.range = (1, 5)
    >>> result = req.get_response(res)
    >>> # Because we don't know the length of the app_iter, this
    >>> # doesn't work:
    >>> result.body
    '0123456789'
    >>> print result.content_range
    None
    >>> req.range = (5, None)
    >>> result = req.get_response(res)
    >>> result.body
    '56789'
    >>> result.content_range
    <ContentRange bytes 5-*/10>
    >>> # If we set Content-Length then we can use it with an app_iter
    >>> res.content_length = 10
    >>> req.range = (1, 5)
    >>> result = req.get_response(res)
    >>> result.body
    '1234'
    >>> result.content_range
    <ContentRange bytes 1-6/10>
    >>> # And trying If-modified-since
    >>> res.etag = 'foobar'
    >>> req.if_range = 'foobar'
    >>> req.if_range
    <IfRange etag=foobar, date=*>
    >>> result = req.get_response(res)
    >>> result.content_range
    <ContentRange bytes 1-6/10>
    >>> req.if_range = 'blah'
    >>> result = req.get_response(res)
    >>> result.content_range
    >>> req.if_range = datetime(2005, 1, 1, 12, 0, tzinfo=UTC)
    >>> res.last_modified = datetime(2005, 1, 1, 12, 0, tzinfo=UTC)
    >>> result = req.get_response(res)
    >>> result.content_range
    <ContentRange bytes 1-6/10>
    >>> res.last_modified = datetime(2006, 1, 1, 12, 0, tzinfo=UTC)
    >>> result = req.get_response(res)
    >>> result.content_range

Some tests of exceptions::

    >>> from webob import exc
    >>> res = exc.HTTPNotFound('Not found!')
    >>> res.exception.content_type = 'text/plain'
    >>> res.content_type
    'text/plain'
    >>> res = exc.HTTPNotModified()
    >>> res.headers
    HeaderDict([])