test_static.py (9535B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\lib\cherrypy\test\test_static.py 2 from cherrypy._cpcompat import HTTPConnection, HTTPSConnection, ntob 3 from cherrypy._cpcompat import BytesIO 4 import os 5 curdir = os.path.join(os.getcwd(), os.path.dirname(__file__)) 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 = 1048576 9 import threading 10 import cherrypy 11 from cherrypy.lib import static 12 from cherrypy.test import helper 13 14 class StaticTest(helper.CPWebCase): 15 16 def setup_server(): 17 if not os.path.exists(has_space_filepath): 18 open(has_space_filepath, 'wb').write(ntob('Hello, world\r\n')) 19 if not os.path.exists(bigfile_filepath): 20 open(bigfile_filepath, 'wb').write(ntob('x' * BIGFILE_SIZE)) 21 22 class Root: 23 24 def bigfile(self): 25 from cherrypy.lib import static 26 self.f = static.serve_file(bigfile_filepath) 27 return self.f 28 29 bigfile.exposed = True 30 bigfile._cp_config = {'response.stream': True} 31 32 def tell(self): 33 if self.f.input.closed: 34 return '' 35 return repr(self.f.input.tell()).rstrip('L') 36 37 tell.exposed = True 38 39 def fileobj(self): 40 f = open(os.path.join(curdir, 'style.css'), 'rb') 41 return static.serve_fileobj(f, content_type='text/css') 42 43 fileobj.exposed = True 44 45 def bytesio(self): 46 f = BytesIO(ntob('Fee\nfie\nfo\nfum')) 47 return static.serve_fileobj(f, content_type='text/plain') 48 49 bytesio.exposed = True 50 51 class Static: 52 53 def index(self): 54 return 'You want the Baron? You can have the Baron!' 55 56 index.exposed = True 57 58 def dynamic(self): 59 return 'This is a DYNAMIC page' 60 61 dynamic.exposed = True 62 63 root = Root() 64 root.static = Static() 65 rootconf = {'/static': {'tools.staticdir.on': True, 66 'tools.staticdir.dir': 'static', 67 'tools.staticdir.root': curdir}, 68 '/style.css': {'tools.staticfile.on': True, 69 'tools.staticfile.filename': os.path.join(curdir, 'style.css')}, 70 '/docroot': {'tools.staticdir.on': True, 71 'tools.staticdir.root': curdir, 72 'tools.staticdir.dir': 'static', 73 'tools.staticdir.index': 'index.html'}, 74 '/error': {'tools.staticdir.on': True, 75 'request.show_tracebacks': True}} 76 rootApp = cherrypy.Application(root) 77 rootApp.merge(rootconf) 78 test_app_conf = {'/test': {'tools.staticdir.index': 'index.html', 79 'tools.staticdir.on': True, 80 'tools.staticdir.root': curdir, 81 'tools.staticdir.dir': 'static'}} 82 testApp = cherrypy.Application(Static()) 83 testApp.merge(test_app_conf) 84 vhost = cherrypy._cpwsgi.VirtualHost(rootApp, {'virt.net': testApp}) 85 cherrypy.tree.graft(vhost) 86 87 setup_server = staticmethod(setup_server) 88 89 def teardown_server(): 90 for f in (has_space_filepath, bigfile_filepath): 91 if os.path.exists(f): 92 try: 93 os.unlink(f) 94 except: 95 pass 96 97 teardown_server = staticmethod(teardown_server) 98 99 def testStatic(self): 100 self.getPage('/static/index.html') 101 self.assertStatus('200 OK') 102 self.assertHeader('Content-Type', 'text/html') 103 self.assertBody('Hello, world\r\n') 104 self.getPage('/docroot/index.html') 105 self.assertStatus('200 OK') 106 self.assertHeader('Content-Type', 'text/html') 107 self.assertBody('Hello, world\r\n') 108 self.getPage('/static/has%20space.html') 109 self.assertStatus('200 OK') 110 self.assertHeader('Content-Type', 'text/html') 111 self.assertBody('Hello, world\r\n') 112 self.getPage('/style.css') 113 self.assertStatus('200 OK') 114 self.assertHeader('Content-Type', 'text/css') 115 self.assertMatchesBody('^Dummy stylesheet') 116 117 def test_fallthrough(self): 118 self.getPage('/static/dynamic') 119 self.assertBody('This is a DYNAMIC page') 120 self.getPage('/static/') 121 self.assertStatus('200 OK') 122 self.assertHeader('Content-Type', 'text/html;charset=utf-8') 123 self.assertBody('You want the Baron? You can have the Baron!') 124 125 def test_index(self): 126 self.getPage('/docroot/') 127 self.assertStatus('200 OK') 128 self.assertHeader('Content-Type', 'text/html') 129 self.assertBody('Hello, world\r\n') 130 self.getPage('/docroot') 131 self.assertStatus(301) 132 self.assertHeader('Location', '%s/docroot/' % self.base()) 133 self.assertMatchesBody("This resource .* <a href='%s/docroot/'>%s/docroot/</a>." % (self.base(), self.base())) 134 135 def test_config_errors(self): 136 self.getPage('/error/thing.html') 137 self.assertErrorPage(500) 138 self.assertMatchesBody(ntob('TypeError: staticdir\\(\\) takes at least 2 (positional )?arguments \\(0 given\\)')) 139 140 def test_security(self): 141 self.getPage('/static/../../test/style.css') 142 self.assertStatus((400, 403)) 143 144 def test_modif(self): 145 self.getPage('/static/dirback.jpg') 146 self.assertStatus('200 OK') 147 lastmod = '' 148 for k, v in self.headers: 149 if k == 'Last-Modified': 150 lastmod = v 151 152 ims = ('If-Modified-Since', lastmod) 153 self.getPage('/static/dirback.jpg', headers=[ims]) 154 self.assertStatus(304) 155 self.assertNoHeader('Content-Type') 156 self.assertNoHeader('Content-Length') 157 self.assertNoHeader('Content-Disposition') 158 self.assertBody('') 159 160 def test_755_vhost(self): 161 self.getPage('/test/', [('Host', 'virt.net')]) 162 self.assertStatus(200) 163 self.getPage('/test', [('Host', 'virt.net')]) 164 self.assertStatus(301) 165 self.assertHeader('Location', self.scheme + '://virt.net/test/') 166 167 def test_serve_fileobj(self): 168 self.getPage('/fileobj') 169 self.assertStatus('200 OK') 170 self.assertHeader('Content-Type', 'text/css;charset=utf-8') 171 self.assertMatchesBody('^Dummy stylesheet') 172 173 def test_serve_bytesio(self): 174 self.getPage('/bytesio') 175 self.assertStatus('200 OK') 176 self.assertHeader('Content-Type', 'text/plain;charset=utf-8') 177 self.assertHeader('Content-Length', 14) 178 self.assertMatchesBody('Fee\nfie\nfo\nfum') 179 180 def test_file_stream(self): 181 if cherrypy.server.protocol_version != 'HTTP/1.1': 182 return self.skip() 183 self.PROTOCOL = 'HTTP/1.1' 184 self.persistent = True 185 conn = self.HTTP_CONN 186 conn.putrequest('GET', '/bigfile', skip_host=True) 187 conn.putheader('Host', self.HOST) 188 conn.endheaders() 189 response = conn.response_class(conn.sock, method='GET') 190 response.begin() 191 self.assertEqual(response.status, 200) 192 body = ntob('') 193 remaining = BIGFILE_SIZE 194 while remaining > 0: 195 data = response.fp.read(65536) 196 if not data: 197 break 198 body += data 199 remaining -= len(data) 200 if self.scheme == 'https': 201 newconn = HTTPSConnection 202 else: 203 newconn = HTTPConnection 204 s, h, b = helper.webtest.openURL(ntob('/tell'), headers=[], host=self.HOST, port=self.PORT, http_conn=newconn) 205 if not b: 206 tell_position = BIGFILE_SIZE 207 else: 208 tell_position = int(b) 209 expected = len(body) 210 if tell_position >= BIGFILE_SIZE: 211 if expected < BIGFILE_SIZE / 2: 212 self.fail('The file should have advanced to position %r, but has already advanced to the end of the file. It may not be streamed as intended, or at the wrong chunk size (64k)' % expected) 213 elif tell_position < expected: 214 self.fail('The file should have advanced to position %r, but has only advanced to position %r. It may not be streamed as intended, or at the wrong chunk size (65536)' % (expected, tell_position)) 215 216 if body != ntob('x' * BIGFILE_SIZE): 217 self.fail("Body != 'x' * %d. Got %r instead (%d bytes)." % (BIGFILE_SIZE, body[:50], len(body))) 218 conn.close() 219 220 def test_file_stream_deadlock(self): 221 if cherrypy.server.protocol_version != 'HTTP/1.1': 222 return self.skip() 223 self.PROTOCOL = 'HTTP/1.1' 224 self.persistent = True 225 conn = self.HTTP_CONN 226 conn.putrequest('GET', '/bigfile', skip_host=True) 227 conn.putheader('Host', self.HOST) 228 conn.endheaders() 229 response = conn.response_class(conn.sock, method='GET') 230 response.begin() 231 self.assertEqual(response.status, 200) 232 body = response.fp.read(65536) 233 if body != ntob('x' * len(body)): 234 self.fail("Body != 'x' * %d. Got %r instead (%d bytes)." % (65536, body[:50], len(body))) 235 response.close() 236 conn.close() 237 self.persistent = False 238 self.getPage('/bigfile') 239 if self.body != ntob('x' * BIGFILE_SIZE): 240 self.fail("Body != 'x' * %d. Got %r instead (%d bytes)." % (BIGFILE_SIZE, self.body[:50], len(body)))