1
from cherrypy.test import test
2
test.prefer_parent_path()
1
from cherrypy._cpcompat import HTTPConnection, HTTPSConnection, ntob
2
from cherrypy._cpcompat import BytesIO
5
5
curdir = os.path.join(os.getcwd(), os.path.dirname(__file__))
6
6
has_space_filepath = os.path.join(curdir, 'static', 'has space.html')
7
bigfile_filepath = os.path.join(curdir, "static", "bigfile.log")
8
BIGFILE_SIZE = 1024 * 1024
12
if not os.path.exists(has_space_filepath):
13
file(has_space_filepath, 'wb').write('Hello, world\r\n')
21
return 'You want the Baron? You can have the Baron!'
25
return "This is a DYNAMIC page"
26
dynamic.exposed = True
29
cherrypy.config.update({'environment': 'test_suite'})
32
root.static = Static()
36
'tools.staticdir.on': True,
37
'tools.staticdir.dir': 'static',
38
'tools.staticdir.root': curdir,
41
'tools.staticfile.on': True,
42
'tools.staticfile.filename': os.path.join(curdir, 'style.css'),
45
'tools.staticdir.on': True,
46
'tools.staticdir.root': curdir,
47
'tools.staticdir.dir': 'static',
48
'tools.staticdir.index': 'index.html',
51
'tools.staticdir.on': True,
52
'request.show_tracebacks': True,
55
rootApp = cherrypy.Application(root)
56
rootApp.merge(rootconf)
60
'tools.staticdir.index': 'index.html',
61
'tools.staticdir.on': True,
62
'tools.staticdir.root': curdir,
63
'tools.staticdir.dir': 'static',
66
testApp = cherrypy.Application(Static())
67
testApp.merge(test_app_conf)
69
vhost = cherrypy._cpwsgi.VirtualHost(rootApp, {'virt.net': testApp})
70
cherrypy.tree.graft(vhost)
73
def teardown_server():
74
if os.path.exists(has_space_filepath):
76
os.unlink(has_space_filepath)
12
from cherrypy.lib import static
80
13
from cherrypy.test import helper
82
16
class StaticTest(helper.CPWebCase):
19
if not os.path.exists(has_space_filepath):
20
open(has_space_filepath, 'wb').write(ntob('Hello, world\r\n'))
21
if not os.path.exists(bigfile_filepath):
22
open(bigfile_filepath, 'wb').write(ntob("x" * BIGFILE_SIZE))
27
from cherrypy.lib import static
28
self.f = static.serve_file(bigfile_filepath)
30
bigfile.exposed = True
31
bigfile._cp_config = {'response.stream': True}
34
if self.f.input.closed:
36
return repr(self.f.input.tell()).rstrip('L')
40
f = open(os.path.join(curdir, 'style.css'), 'rb')
41
return static.serve_fileobj(f, content_type='text/css')
42
fileobj.exposed = True
45
f = BytesIO(ntob('Fee\nfie\nfo\nfum'))
46
return static.serve_fileobj(f, content_type='text/plain')
47
bytesio.exposed = True
52
return 'You want the Baron? You can have the Baron!'
56
return "This is a DYNAMIC page"
57
dynamic.exposed = True
61
root.static = Static()
65
'tools.staticdir.on': True,
66
'tools.staticdir.dir': 'static',
67
'tools.staticdir.root': curdir,
70
'tools.staticfile.on': True,
71
'tools.staticfile.filename': os.path.join(curdir, 'style.css'),
74
'tools.staticdir.on': True,
75
'tools.staticdir.root': curdir,
76
'tools.staticdir.dir': 'static',
77
'tools.staticdir.index': 'index.html',
80
'tools.staticdir.on': True,
81
'request.show_tracebacks': True,
84
rootApp = cherrypy.Application(root)
85
rootApp.merge(rootconf)
89
'tools.staticdir.index': 'index.html',
90
'tools.staticdir.on': True,
91
'tools.staticdir.root': curdir,
92
'tools.staticdir.dir': 'static',
95
testApp = cherrypy.Application(Static())
96
testApp.merge(test_app_conf)
98
vhost = cherrypy._cpwsgi.VirtualHost(rootApp, {'virt.net': testApp})
99
cherrypy.tree.graft(vhost)
100
setup_server = staticmethod(setup_server)
103
def teardown_server():
104
for f in (has_space_filepath, bigfile_filepath):
105
if os.path.exists(f):
110
teardown_server = staticmethod(teardown_server)
84
113
def testStatic(self):
85
114
self.getPage("/static/index.html")
127
156
self.assertBody('Hello, world\r\n')
128
157
# The same page should be returned even if redirected.
129
158
self.getPage("/docroot")
130
self.assertStatus((302, 303))
159
self.assertStatus(301)
131
160
self.assertHeader('Location', '%s/docroot/' % self.base())
132
self.assertMatchesBody("This resource .* at <a href='%s/docroot/'>"
161
self.assertMatchesBody("This resource .* <a href='%s/docroot/'>"
133
162
"%s/docroot/</a>." % (self.base(), self.base()))
135
164
def test_config_errors(self):
136
165
# Check that we get an error if no .file or .dir
137
166
self.getPage("/error/thing.html")
138
167
self.assertErrorPage(500)
139
self.assertInBody("TypeError: staticdir() takes at least 2 "
140
"arguments (0 given)")
168
self.assertMatchesBody(ntob("TypeError: staticdir\(\) takes at least 2 "
169
"(positional )?arguments \(0 given\)"))
142
171
def test_security(self):
143
172
# Test up-level security
164
193
self.getPage("/test/", [('Host', 'virt.net')])
165
194
self.assertStatus(200)
166
195
self.getPage("/test", [('Host', 'virt.net')])
167
self.assertStatus((302, 303))
196
self.assertStatus(301)
168
197
self.assertHeader('Location', self.scheme + '://virt.net/test/')
171
if __name__ == "__main__":
199
def test_serve_fileobj(self):
200
self.getPage("/fileobj")
201
self.assertStatus('200 OK')
202
self.assertHeader('Content-Type', 'text/css;charset=utf-8')
203
self.assertMatchesBody('^Dummy stylesheet')
205
def test_serve_bytesio(self):
206
self.getPage("/bytesio")
207
self.assertStatus('200 OK')
208
self.assertHeader('Content-Type', 'text/plain;charset=utf-8')
209
self.assertHeader('Content-Length', 14)
210
self.assertMatchesBody('Fee\nfie\nfo\nfum')
212
def test_file_stream(self):
213
if cherrypy.server.protocol_version != "HTTP/1.1":
216
self.PROTOCOL = "HTTP/1.1"
218
# Make an initial request
219
self.persistent = True
220
conn = self.HTTP_CONN
221
conn.putrequest("GET", "/bigfile", skip_host=True)
222
conn.putheader("Host", self.HOST)
224
response = conn.response_class(conn.sock, method="GET")
226
self.assertEqual(response.status, 200)
229
remaining = BIGFILE_SIZE
231
data = response.fp.read(65536)
235
remaining -= len(data)
237
if self.scheme == "https":
238
newconn = HTTPSConnection
240
newconn = HTTPConnection
241
s, h, b = helper.webtest.openURL(
242
ntob("/tell"), headers=[], host=self.HOST, port=self.PORT,
245
# The file was closed on the server.
246
tell_position = BIGFILE_SIZE
248
tell_position = int(b)
251
if tell_position >= BIGFILE_SIZE:
252
# We can't exactly control how much content the server asks for.
253
# Fudge it by only checking the first half of the reads.
254
if expected < (BIGFILE_SIZE / 2):
256
"The file should have advanced to position %r, but has "
257
"already advanced to the end of the file. It may not be "
258
"streamed as intended, or at the wrong chunk size (64k)" %
260
elif tell_position < expected:
262
"The file should have advanced to position %r, but has "
263
"only advanced to position %r. It may not be streamed "
264
"as intended, or at the wrong chunk size (65536)" %
265
(expected, tell_position))
267
if body != ntob("x" * BIGFILE_SIZE):
268
self.fail("Body != 'x' * %d. Got %r instead (%d bytes)." %
269
(BIGFILE_SIZE, body[:50], len(body)))
272
def test_file_stream_deadlock(self):
273
if cherrypy.server.protocol_version != "HTTP/1.1":
276
self.PROTOCOL = "HTTP/1.1"
278
# Make an initial request but abort early.
279
self.persistent = True
280
conn = self.HTTP_CONN
281
conn.putrequest("GET", "/bigfile", skip_host=True)
282
conn.putheader("Host", self.HOST)
284
response = conn.response_class(conn.sock, method="GET")
286
self.assertEqual(response.status, 200)
287
body = response.fp.read(65536)
288
if body != ntob("x" * len(body)):
289
self.fail("Body != 'x' * %d. Got %r instead (%d bytes)." %
290
(65536, body[:50], len(body)))
294
# Make a second request, which should fetch the whole file.
295
self.persistent = False
296
self.getPage("/bigfile")
297
if self.body != ntob("x" * BIGFILE_SIZE):
298
self.fail("Body != 'x' * %d. Got %r instead (%d bytes)." %
299
(BIGFILE_SIZE, self.body[:50], len(body)))