Package trac :: Package web :: Package tests :: Module main

Source Code for Module trac.web.tests.main

  1  # -*- coding: utf-8 -*- 
  2  # 
  3  # Copyright (C) 2010-2020 Edgewall Software 
  4  # All rights reserved. 
  5  # 
  6  # This software is licensed as described in the file COPYING, which 
  7  # you should have received as part of this distribution. The terms 
  8  # are also available at https://trac.edgewall.org/wiki/TracLicense. 
  9  # 
 10  # This software consists of voluntary contributions made by many 
 11  # individuals. For the exact contribution history, see the revision 
 12  # history and logs, available at https://trac.edgewall.org/log/. 
 13   
 14  import os.path 
 15  import re 
 16  import sys 
 17  import tempfile 
 18  import textwrap 
 19  import unittest 
 20  from subprocess import PIPE, Popen 
 21   
 22   
 23  import trac.tests.compat 
 24  from trac.config import ConfigurationError 
 25  from trac.core import Component, ComponentManager, TracError, implements 
 26  from trac.db.api import DatabaseManager 
 27  from trac.perm import PermissionError 
 28  from trac.resource import ResourceNotFound 
 29  from trac.test import EnvironmentStub, MockRequest 
 30  from trac.util import create_file 
 31  from trac.util.compat import close_fds 
 32  from trac.web.api import (HTTPForbidden, HTTPInternalError, HTTPNotFound, 
 33      IRequestFilter, IRequestHandler, RequestDone) 
 34  from trac.web.auth import IAuthenticator 
 35  from trac.web.main import FakeSession, RequestDispatcher, Session, \ 
 36                            get_environments 
 37   
 38   
39 -class TestStubRequestHandler(Component):
40 41 implements(IRequestHandler) 42 43 filename = 'test_stub.html' 44 45 template = textwrap.dedent("""\ 46 <!DOCTYPE html 47 PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 48 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 49 <html xmlns="http://www.w3.org/1999/xhtml" 50 xmlns:py="http://genshi.edgewall.org/"> 51 <body> 52 <h1>${greeting}</h1> 53 </body> 54 </html> 55 """) 56
57 - def match_request(self, req):
58 return req.path_info == '/test-stub'
59
60 - def process_request(self, req):
61 return self.filename, {'greeting': 'Hello World'}, None
62 63
64 -class AuthenticateTestCase(unittest.TestCase):
65
66 - def setUp(self):
67 self.env = EnvironmentStub(disable=['trac.web.auth.LoginModule']) 68 self.request_dispatcher = RequestDispatcher(self.env) 69 self.req = MockRequest(self.env) 70 self.env.clear_component_registry()
71
72 - def tearDown(self):
74
76 class SuccessfulAuthenticator1(Component): 77 implements(IAuthenticator) 78 def authenticate(self, req): 79 return 'user1'
80 class SuccessfulAuthenticator2(Component): 81 implements(IAuthenticator) 82 def authenticate(self, req): 83 return 'user2' 84 self.assertEqual(2, len(self.request_dispatcher.authenticators)) 85 self.assertIsInstance(self.request_dispatcher.authenticators[0], 86 SuccessfulAuthenticator1) 87 self.assertIsInstance(self.request_dispatcher.authenticators[1], 88 SuccessfulAuthenticator2) 89 self.assertEqual('user1', 90 self.request_dispatcher.authenticate(self.req)) 91
92 - def test_authenticate_skips_unsuccessful(self):
93 class UnsuccessfulAuthenticator(Component): 94 implements(IAuthenticator) 95 def authenticate(self, req): 96 return None
97 class SuccessfulAuthenticator(Component): 98 implements(IAuthenticator) 99 def authenticate(self, req): 100 return 'user' 101 self.assertEqual(2, len(self.request_dispatcher.authenticators)) 102 self.assertIsInstance(self.request_dispatcher.authenticators[0], 103 UnsuccessfulAuthenticator) 104 self.assertIsInstance(self.request_dispatcher.authenticators[1], 105 SuccessfulAuthenticator) 106 self.assertEqual('user', 107 self.request_dispatcher.authenticate(self.req)) 108
109 - def test_authenticate_raises(self):
110 class RaisingAuthenticator(Component): 111 implements(IAuthenticator) 112 def authenticate(self, req): 113 raise TracError("Bad attempt")
114 class SuccessfulAuthenticator(Component): 115 implements(IAuthenticator) 116 def authenticate(self, req): 117 return 'user' 118 self.assertEqual(2, len(self.request_dispatcher.authenticators)) 119 self.assertIsInstance(self.request_dispatcher.authenticators[0], 120 RaisingAuthenticator) 121 self.assertIsInstance(self.request_dispatcher.authenticators[1], 122 SuccessfulAuthenticator) 123 self.assertEqual('anonymous', 124 self.request_dispatcher.authenticate(self.req)) 125 self.assertEqual(1, len(self.req.chrome['warnings'])) 126
127 - def test_authenticate_once(self):
128 class Authenticator(Component): 129 implements(IAuthenticator) 130 def authenticate(self, req): 131 authenticated[0] += 1 132 return 'admin'
133 class AuthenticateRequestHandler(Component): 134 implements(IRequestHandler) 135 def match_request(self, req): 136 return bool(req.perm) 137 def process_request(self, req): 138 req.authname 139 req.send('') 140 141 self.env.config.set('trac', 'default_handler', 142 'AuthenticateRequestHandler') 143 authenticated = [0] 144 req = MockRequest(self.env) 145 self.request_dispatcher.set_default_callbacks(req) 146 147 self.assertEqual(1, len(self.request_dispatcher.authenticators)) 148 self.assertIsInstance(self.request_dispatcher.authenticators[0], 149 Authenticator) 150 self.assertRaises(RequestDone, self.request_dispatcher.dispatch, req) 151 self.assertEqual(1, authenticated[0]) 152 153
154 -class DispatchRequestTestCase(unittest.TestCase):
155
157 """EnvironmentError exception is raised when dispatching request 158 with optimizations enabled. 159 """ 160 proc = Popen((sys.executable, '-O', '-c', 161 'from trac.web.main import dispatch_request; ' 162 'dispatch_request({}, None)'), stdin=PIPE, 163 stdout=PIPE, stderr=PIPE, close_fds=close_fds) 164 165 stdout, stderr = proc.communicate() 166 for f in (proc.stdin, proc.stdout, proc.stderr): 167 f.close() 168 self.assertEqual(1, proc.returncode) 169 self.assertIn("EnvironmentError: Python with optimizations is not " 170 "supported.", stderr)
171 172
173 -class EnvironmentsTestCase(unittest.TestCase):
174 175 dirs = ('mydir1', 'mydir2', '.hidden_dir') 176 files = ('myfile1', 'myfile2', '.dot_file') 177
178 - def setUp(self):
179 self.parent_dir = tempfile.mkdtemp(prefix='trac-') 180 self.tracignore = os.path.join(self.parent_dir, '.tracignore') 181 for dname in self.dirs: 182 os.mkdir(os.path.join(self.parent_dir, dname)) 183 for fname in self.files: 184 create_file(os.path.join(self.parent_dir, fname)) 185 self.environ = { 186 'trac.env_paths': [], 187 'trac.env_parent_dir': self.parent_dir, 188 }
189
190 - def tearDown(self):
191 for fname in self.files: 192 os.unlink(os.path.join(self.parent_dir, fname)) 193 for dname in self.dirs: 194 os.rmdir(os.path.join(self.parent_dir, dname)) 195 if os.path.exists(self.tracignore): 196 os.unlink(self.tracignore) 197 os.rmdir(self.parent_dir)
198
199 - def env_paths(self, projects):
200 return dict((project, os.path.normpath(os.path.join(self.parent_dir, 201 project))) 202 for project in projects)
203
204 - def test_default_tracignore(self):
205 self.assertEqual(self.env_paths(['mydir1', 'mydir2']), 206 get_environments(self.environ))
207
208 - def test_empty_tracignore(self):
209 create_file(self.tracignore) 210 self.assertEqual(self.env_paths(['mydir1', 'mydir2', '.hidden_dir']), 211 get_environments(self.environ))
212
214 create_file(self.tracignore, 'mydir?') 215 self.assertEqual(self.env_paths(['.hidden_dir']), 216 get_environments(self.environ))
217
219 create_file(self.tracignore, 'my*\n.hidden_dir') 220 self.assertEqual({}, get_environments(self.environ))
221
222 - def test_combined_tracignore(self):
223 create_file(self.tracignore, 'my*i?1\n\n#mydir2') 224 self.assertEqual(self.env_paths(['mydir2', '.hidden_dir']), 225 get_environments(self.environ))
226 227
228 -class PreProcessRequestTestCase(unittest.TestCase):
229
230 - def setUp(self):
231 self.env = EnvironmentStub() 232 self.env.config.set('trac', 'default_handler', 'DefaultHandler') 233 self.env.clear_component_registry() 234 class DefaultHandler(Component): 235 implements(IRequestHandler) 236 def match_request(self, req): 237 return True
238 def process_request(self, req): 239 pass
240
241 - def tearDown(self):
242 self.env.restore_component_registry()
243
244 - def test_trac_error_raises_http_internal_error(self):
245 """TracError in pre_process_request is trapped and an 246 HTTPInternalError is raised. 247 """ 248 class RequestFilter(Component): 249 implements(IRequestFilter) 250 def pre_process_request(self, req, handler): 251 raise TracError("Raised in pre_process_request")
252 def post_process_request(self, req, template, data, content_type): 253 return template, data, content_type 254 req = MockRequest(self.env) 255 256 try: 257 RequestDispatcher(self.env).dispatch(req) 258 except HTTPInternalError as e: 259 self.assertEqual("500 Trac Error (Raised in pre_process_request)", 260 unicode(e)) 261 else: 262 self.fail("HTTPInternalError not raised") 263 264
265 -class ProcessRequestTestCase(unittest.TestCase):
266
267 - def setUp(self):
268 self.env = EnvironmentStub() 269 self.env.config.set('trac', 'default_handler', 'DefaultHandler') 270 self.env.clear_component_registry() 271 class DefaultHandler(Component): 272 implements(IRequestHandler) 273 def match_request(self, req): 274 return True
275 def process_request(self, req): 276 raise req.exc_class("Raised in process_request")
277
278 - def tearDown(self):
279 self.env.restore_component_registry()
280
281 - def test_permission_error_raises_http_forbidden(self):
282 """TracError in process_request is trapped and an HTTPForbidden 283 error is raised. 284 """ 285 req = MockRequest(self.env) 286 req.exc_class = PermissionError 287 288 try: 289 RequestDispatcher(self.env).dispatch(req) 290 except HTTPForbidden as e: 291 self.assertEqual( 292 "403 Forbidden (Raised in process_request " 293 "privileges are required to perform this operation. You " 294 "don't have the required permissions.)", unicode(e)) 295 else: 296 self.fail("HTTPForbidden not raised")
297
298 - def test_resource_not_found_raises_http_not_found(self):
299 """ResourceNotFound error in process_request is trapped and an 300 HTTPNotFound error is raised. 301 """ 302 req = MockRequest(self.env) 303 req.exc_class = ResourceNotFound 304 305 try: 306 RequestDispatcher(self.env).dispatch(req) 307 except HTTPNotFound as e: 308 self.assertEqual("404 Trac Error (Raised in process_request)", 309 unicode(e)) 310 else: 311 self.fail("HTTPNotFound not raised")
312
313 - def test_trac_error_raises_http_internal_error(self):
314 """TracError in process_request is trapped and an 315 HTTPInternalError is raised. 316 """ 317 req = MockRequest(self.env) 318 req.exc_class = TracError 319 320 try: 321 RequestDispatcher(self.env).dispatch(req) 322 except HTTPInternalError as e: 323 self.assertEqual("500 Trac Error (Raised in process_request)", 324 unicode(e)) 325 else: 326 self.fail("HTTPInternalError not raised")
327
328 - def test_not_implemented_error_raises_http_internal_server_error(self):
329 """NotImplementedError in process_request is trapped and an 330 HTTPInternalError is raised. 331 """ 332 req = MockRequest(self.env) 333 req.exc_class = NotImplementedError 334 335 try: 336 RequestDispatcher(self.env).dispatch(req) 337 except HTTPInternalError as e: 338 self.assertEqual("500 Not Implemented Error (Raised in " 339 "process_request)", unicode(e)) 340 else: 341 self.fail("HTTPInternalError not raised")
342 343
344 -class PostProcessRequestTestCase(unittest.TestCase):
345 """Test cases for handling of the optional `method` argument in 346 RequestDispatcher._post_process_request.""" 347
348 - def setUp(self):
349 self.env = EnvironmentStub() 350 self.req = MockRequest(self.env) 351 self.request_dispatcher = RequestDispatcher(self.env) 352 self.compmgr = ComponentManager() 353 self.env.clear_component_registry()
354
355 - def tearDown(self):
357
359 """IRequestHandler doesn't return `method` and no IRequestFilters 360 are registered. The `method` is set to `None`. 361 """ 362 args = ('template.html', {}, 'text/html') 363 resp = self.request_dispatcher._post_process_request(self.req, *args) 364 self.assertEqual(0, len(self.request_dispatcher.filters)) 365 self.assertEqual(4, len(resp)) 366 self.assertEqual(args + (None,), resp)
367
369 """IRequestHandler returns `method` and no IRequestFilters 370 are registered. The `method` is forwarded. 371 """ 372 args = ('template.html', {}, 'text/html', 'xhtml') 373 resp = self.request_dispatcher._post_process_request(self.req, *args) 374 self.assertEqual(0, len(self.request_dispatcher.filters)) 375 self.assertEqual(4, len(resp)) 376 self.assertEqual(args, resp)
377
378 - def test_4arg_post_process_request_request_handler_returns_method_false(self):
379 """IRequestHandler doesn't return `method` and IRequestFilter doesn't 380 accept `method` as an argument. The `method` is set to `None`. 381 """ 382 class RequestFilter(Component): 383 implements(IRequestFilter) 384 def pre_process_request(self, req, handler): 385 return handler
386 def post_process_request(self, req, template, data, content_type): 387 return template, data, content_type
388 args = ('template.html', {}, 'text/html') 389 resp = self.request_dispatcher._post_process_request(self.req, *args) 390 self.assertEqual(1, len(self.request_dispatcher.filters)) 391 self.assertEqual(4, len(resp)) 392 self.assertEqual(args + (None,), resp) 393
394 - def test_4arg_post_process_request_request_handler_returns_method_true(self):
395 """IRequestHandler returns `method` and IRequestFilter doesn't accept 396 the argument. The `method` argument is forwarded over IRequestFilter 397 implementations that don't accept the argument. 398 """ 399 class RequestFilter(Component): 400 implements(IRequestFilter) 401 def pre_process_request(self, req, handler): 402 return handler
403 def post_process_request(self, req, template, data, content_type): 404 return template, data, content_type 405 args = ('template.html', {}, 'text/html', 'xhtml') 406 resp = self.request_dispatcher._post_process_request(self.req, *args) 407 self.assertEqual(1, len(self.request_dispatcher.filters)) 408 self.assertEqual(4, len(resp)) 409 self.assertEqual(args, resp) 410
411 - def test_5arg_post_process_request_request_handler_returns_method_false(self):
412 """IRequestHandler doesn't return `method` and IRequestFilter accepts 413 `method` as an argument. The `method` is set to `None`. 414 """ 415 class RequestFilter(Component): 416 implements(IRequestFilter) 417 def pre_process_request(self, req, handler): 418 return handler
419 def post_process_request(self, req, template, data, 420 content_type, method=None): 421 return template, data, content_type, method 422 args = ('template.html', {}, 'text/html') 423 resp = self.request_dispatcher._post_process_request(self.req, *args) 424 self.assertEqual(1, len(self.request_dispatcher.filters)) 425 self.assertEqual(4, len(resp)) 426 self.assertEqual(args[:3] + (None,), resp) 427
428 - def test_5arg_post_process_request_request_handler_returns_method_true(self):
429 """IRequestHandler returns `method` and IRequestFilter accepts 430 the argument. The `method` argument is passed through IRequestFilter 431 implementations. 432 """ 433 class RequestFilter(Component): 434 implements(IRequestFilter) 435 def pre_process_request(self, req, handler): 436 return handler
437 def post_process_request(self, req, template, data, 438 content_type, method=None): 439 return template, data, content_type, method 440 args = ('template.html', {}, 'text/html', 'xhtml') 441 resp = self.request_dispatcher._post_process_request(self.req, *args) 442 self.assertEqual(1, len(self.request_dispatcher.filters)) 443 self.assertEqual(4, len(resp)) 444 self.assertEqual(args, resp) 445
446 - def test_5arg_post_process_request_request_handler_adds_method(self):
447 """IRequestFilter adds `method` not returned by IRequestHandler. 448 """ 449 class RequestFilter(Component): 450 implements(IRequestFilter) 451 def pre_process_request(self, req, handler): 452 return handler
453 def post_process_request(self, req, template, data, 454 content_type, method=None): 455 return template, data, content_type, 'xml' 456 args = ('template.html', {}, 'text/html') 457 resp = self.request_dispatcher._post_process_request(self.req, *args) 458 self.assertEqual(1, len(self.request_dispatcher.filters)) 459 self.assertEqual(4, len(resp)) 460 self.assertEqual(args[:3] + ('xml',), resp) 461
462 - def test_5arg_post_process_request_request_handler_modifies_method(self):
463 """IRequestFilter modifies `method` returned by IRequestHandler. 464 """ 465 class RequestFilter(Component): 466 implements(IRequestFilter) 467 def pre_process_request(self, req, handler): 468 return handler
469 def post_process_request(self, req, template, data, 470 content_type, method=None): 471 return template, data, content_type, 'xml' 472 args = ('template.html', {}, 'text/html', 'xhtml') 473 resp = self.request_dispatcher._post_process_request(self.req, *args) 474 self.assertEqual(1, len(self.request_dispatcher.filters)) 475 self.assertEqual(4, len(resp)) 476 self.assertEqual(args[:3] + ('xml',), resp) 477
478 - def test_redirect_on_permission_error(self):
479 """The post_process_request method can redirect during exception 480 handling from an exception raised in process_request. 481 """ 482 class RedirectOnPermissionErrorStub(Component): 483 implements(IRequestHandler, IRequestFilter) 484 485 def match_request(self, req): 486 return re.match(r'/perm-error', req.path_info)
487 488 def process_request(self, req): 489 req.entered_process_request = True 490 raise PermissionError("No permission to view") 491 492 def pre_process_request(self, req, handler): 493 return handler 494 495 def post_process_request(self, req, template, data, content_type): 496 if (template, data, content_type) == (None, None, None): 497 req.entered_post_process_request = True 498 req.redirect(req.href('/redirect-target')) 499 return template, data, content_type 500 501 dispatcher = RequestDispatcher(self.env) 502 req = MockRequest(self.env, method='GET', path_info='/perm-error') 503 req.entered_process_request = False 504 req.entered_post_process_request = False 505 506 try: 507 dispatcher.dispatch(req) 508 except RequestDone: 509 pass 510 else: 511 self.fail("RequestDone not raised") 512 513 self.assertTrue(req.entered_process_request) 514 self.assertTrue(req.entered_post_process_request) 515 516
517 -class RequestDispatcherTestCase(unittest.TestCase):
518
519 - def setUp(self):
520 self.env = EnvironmentStub( 521 path=tempfile.mkdtemp(prefix='trac-tempenv-')) 522 os.mkdir(self.env.templates_dir) 523 filepath = os.path.join(self.env.templates_dir, 524 TestStubRequestHandler.filename) 525 create_file(filepath, TestStubRequestHandler.template) 526 self.filename = os.path.join(self.env.path, 'test.txt') 527 self.data = 'contents\n' 528 create_file(self.filename, self.data, 'wb')
529
530 - def tearDown(self):
532
533 - def _insert_session(self):
534 sid = '1234567890abcdef' 535 name = 'First Last' 536 email = '[email protected]' 537 self.env.insert_users([(sid, name, email, 0)]) 538 return sid, name, email
539
540 - def _content(self):
541 yield 'line1,' 542 yield 'line2,' 543 yield 'line3\n'
544
546 self.env.config.set('trac', 'default_date_format', u'ĭšo8601') 547 548 self.assertEqual(u'ĭšo8601', 549 self.env.config.get('trac', 'default_date_format')) 550 self.assertRaises(ConfigurationError, getattr, 551 RequestDispatcher(self.env), 'default_date_format')
552
554 """Session is returned when database is reachable.""" 555 sid, name, email = self._insert_session() 556 req = MockRequest(self.env, path_info='/test-stub', 557 cookie='trac_session=%s;' % sid) 558 request_dispatcher = RequestDispatcher(self.env) 559 request_dispatcher.set_default_callbacks(req) 560 561 self.assertRaises(RequestDone, request_dispatcher.dispatch, req) 562 563 self.assertIsInstance(req.session, Session) 564 self.assertEqual(sid, req.session.sid) 565 self.assertEqual(name, req.session['name']) 566 self.assertEqual(email, req.session['email']) 567 self.assertFalse(req.session.authenticated) 568 self.assertEqual('200 Ok', req.status_sent[0]) 569 self.assertIn('<h1>Hello World</h1>', req.response_sent.getvalue())
570
572 """Fake session is returned when database is not reachable.""" 573 sid = self._insert_session()[0] 574 request_dispatcher = RequestDispatcher(self.env) 575 576 def get_session(req): 577 """Simulates an unreachable database.""" 578 _get_connector = DatabaseManager.get_connector 579 580 def get_connector(self): 581 raise TracError("Database not reachable")
582 583 DatabaseManager.get_connector = get_connector 584 DatabaseManager(self.env).shutdown() 585 session = request_dispatcher._get_session(req) 586 DatabaseManager.get_connector = _get_connector 587 return session
588 589 req = MockRequest(self.env, path_info='/test-stub', 590 cookie='trac_session=%s;' % sid) 591 req.callbacks['session'] = get_session 592 593 self.assertRaises(RequestDone, request_dispatcher.dispatch, req) 594 595 self.assertIsInstance(req.session, FakeSession) 596 self.assertIsNone(req.session.sid) 597 self.assertNotIn('name', req.session) 598 self.assertNotIn('email', req.session) 599 self.assertFalse(req.session.authenticated) 600 self.assertEqual('200 Ok', req.status_sent[0]) 601 self.assertIn('<h1>Hello World</h1>', req.response_sent.getvalue()) 602
603 - def test_invalid_session_id_returns_fake_session(self):
604 """Fake session is returned when session id is invalid.""" 605 sid = 'a' * 23 + '$' # last char invalid, sid must be alphanumeric. 606 req = MockRequest(self.env, path_info='/test-stub', 607 cookie='trac_session=%s;' % sid) 608 request_dispatcher = RequestDispatcher(self.env) 609 request_dispatcher.set_default_callbacks(req) 610 611 self.assertRaises(RequestDone, request_dispatcher.dispatch, req) 612 613 self.assertIsInstance(req.session, FakeSession) 614 self.assertIsNone(req.session.sid) 615 self.assertEqual('200 Ok', req.status_sent[0]) 616 self.assertIn('<h1>Hello World</h1>', req.response_sent.getvalue())
617
618 - def test_set_valid_xsendfile_header(self):
619 """Send file using xsendfile header.""" 620 self.env.config.set('trac', 'use_xsendfile', True) 621 self.env.config.set('trac', 'xsendfile_header', 'X-Accel-Redirect') 622 623 req = MockRequest(self.env) 624 request_dispatcher = RequestDispatcher(self.env) 625 request_dispatcher.set_default_callbacks(req) 626 627 # File is sent using xsendfile. 628 self.assertRaises(RequestDone, req.send_file, self.filename) 629 self.assertEqual(['200 Ok'], req.status_sent) 630 self.assertEqual('text/plain', req.headers_sent['Content-Type']) 631 self.assertEqual(self.filename, req.headers_sent['X-Accel-Redirect']) 632 self.assertNotIn('X-Sendfile', req.headers_sent) 633 self.assertEqual(None, req._response) 634 self.assertEqual('', req.response_sent.getvalue())
635
636 - def _test_file_not_sent_using_xsendfile_header(self, xsendfile_header):
637 req = MockRequest(self.env) 638 request_dispatcher = RequestDispatcher(self.env) 639 request_dispatcher.set_default_callbacks(req) 640 641 # File is not sent using xsendfile. 642 self.assertRaises(RequestDone, req.send_file, self.filename) 643 self.assertEqual(['200 Ok'], req.status_sent) 644 self.assertEqual('text/plain', req.headers_sent['Content-Type']) 645 self.assertNotIn(xsendfile_header, req.headers_sent) 646 self.assertEqual('_FileWrapper', type(req._response).__name__) 647 self.assertEqual('', req.response_sent.getvalue())
648
649 - def test_set_invalid_xsendfile_header(self):
650 """Not sent by xsendfile header because header is invalid.""" 651 xsendfile_header = '(X-SendFile)' 652 self.env.config.set('trac', 'use_xsendfile', True) 653 self.env.config.set('trac', 'xsendfile_header', xsendfile_header) 654 655 self._test_file_not_sent_using_xsendfile_header(xsendfile_header)
656
657 - def test_xsendfile_is_disabled(self):
658 """Not sent by xsendfile header because xsendfile is disabled.""" 659 xsendfile_header = 'X-SendFile' 660 self.env.config.set('trac', 'use_xsendfile', False) 661 self.env.config.set('trac', 'xsendfile_header', xsendfile_header) 662 663 self._test_file_not_sent_using_xsendfile_header(xsendfile_header)
664
665 - def _test_configurable_headers(self, method):
666 # Reserved headers not allowed. 667 content_type = 'not-allowed' 668 self.env.config.set('http-headers', 'Content-Type', content_type) 669 # Control code not allowed. 670 custom1 = '\x00custom1' 671 self.env.config.set('http-headers', 'X-Custom-1', custom1) 672 # Many special characters allowed in header name. 673 custom2 = 'Custom2-!#$%&\'*+.^_`|~' 674 self.env.config.set('http-headers', custom2, 'custom2') 675 # Some special characters not allowed in header name. 676 self.env.config.set('http-headers', 'X-Custom-(3)', 'custom3') 677 678 req = MockRequest(self.env, method='POST') 679 request_dispatcher = RequestDispatcher(self.env) 680 request_dispatcher.set_default_callbacks(req) 681 self.assertRaises(RequestDone, getattr(req, method), self._content()) 682 683 self.assertNotEqual('not-allowed', req.headers_sent.get('Content-Type')) 684 self.assertNotIn('x-custom-1', req.headers_sent) 685 self.assertIn(custom2.lower(), req.headers_sent) 686 self.assertNotIn('x-custom-(3)', req.headers_sent)
687
688 - def test_send_configurable_headers(self):
689 self._test_configurable_headers('send')
690
691 - def test_send_error_configurable_headers(self):
692 self._test_configurable_headers('send_error')
693
694 - def test_send_configurable_headers_no_override(self):
695 """Headers in request not overridden by configurable headers.""" 696 self.env.config.set('http-headers', 'X-XSS-Protection', '1; mode=block') 697 request_dispatcher = RequestDispatcher(self.env) 698 req1 = MockRequest(self.env) 699 request_dispatcher.set_default_callbacks(req1) 700 701 self.assertRaises(RequestDone, req1.send, self._content()) 702 703 self.assertNotIn('X-XSS-protection', req1.headers_sent) 704 self.assertIn('x-xss-protection', req1.headers_sent) 705 self.assertEqual('1; mode=block', req1.headers_sent['x-xss-protection']) 706 707 req2 = MockRequest(self.env, method='POST') 708 request_dispatcher.set_default_callbacks(req2) 709 710 self.assertRaises(RequestDone, req2.send, self._content()) 711 712 self.assertNotIn('x-xss-protection', req2.headers_sent) 713 self.assertIn('X-XSS-Protection', req2.headers_sent) 714 self.assertEqual('0', req2.headers_sent['X-XSS-Protection'])
715 716
717 -class HdfdumpTestCase(unittest.TestCase):
718
719 - def setUp(self):
720 self.env = EnvironmentStub() 721 self.req = MockRequest(self.env, args={'hdfdump': '1'}) 722 self.env.clear_component_registry() 723 self.request_dispatcher = RequestDispatcher(self.env) 724 perm = self.req.perm 725 self.request_dispatcher._get_perm = lambda req: perm
726
727 - def tearDown(self):
729
730 - def test_hdfdump(self):
731 class HdfdumpRequestHandler(Component): 732 implements(IRequestHandler) 733 def match_request(self, req): 734 return True
735 def process_request(self, req): 736 data = {'name': 'value'} 737 return 'error.html', data, None
738 739 self.env.config.set('trac', 'default_handler', 'HdfdumpRequestHandler') 740 self.assertRaises(RequestDone, self.request_dispatcher.dispatch, 741 self.req) 742 self.assertIn("{'name': 'value'}\n", 743 self.req.response_sent.getvalue()) 744 self.assertEqual('text/plain;charset=utf-8', 745 self.req.headers_sent['Content-Type']) 746 747
748 -def test_suite():
749 suite = unittest.TestSuite() 750 suite.addTest(unittest.makeSuite(AuthenticateTestCase)) 751 suite.addTest(unittest.makeSuite(DispatchRequestTestCase)) 752 suite.addTest(unittest.makeSuite(EnvironmentsTestCase)) 753 suite.addTest(unittest.makeSuite(PreProcessRequestTestCase)) 754 suite.addTest(unittest.makeSuite(ProcessRequestTestCase)) 755 suite.addTest(unittest.makeSuite(PostProcessRequestTestCase)) 756 suite.addTest(unittest.makeSuite(RequestDispatcherTestCase)) 757 suite.addTest(unittest.makeSuite(HdfdumpTestCase)) 758 return suite
759 760 761 if __name__ == '__main__': 762 unittest.main(defaultTest='test_suite') 763