Changeset 823
- Timestamp:
- 11/14/05 02:29:11
- Files:
-
- trunk/cherrypy/_cphttptools.py (modified) (1 diff)
- trunk/cherrypy/_cputil.py (modified) (2 diffs)
- trunk/cherrypy/test/test_config.py (modified) (1 diff)
- trunk/cherrypy/test/test_core.py (modified) (6 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/cherrypy/_cphttptools.py
r819 r823 63 63 # right away. 64 64 self.processRequestLine(requestLine) 65 66 # handles "OPTIONS * HTTP/1.1" requests67 # we could avoid testing for the method value here but68 # we still do it to avoid an useless call to getSpecialAttribute69 # OPTIONS request should be very rare compare to regular requests70 # let's not add too much overhead71 if cherrypy.request.method == 'OPTIONS':72 if _cputil.getSpecialAttribute("_cpGlobalInformation")() == True:73 # if we had such a request we don't have to keep processing74 return75 65 76 66 try: trunk/cherrypy/_cputil.py
r816 r823 31 31 else: 32 32 nameList = objectpath.split('/') 33 33 34 if nameList == ['global']: 34 nameList = ['global_'] 35 # Special-case a Request-URI of * to allow for our default handler. 36 root = getattr(cherrypy, 'root', None) 37 if root is None: 38 return [('root', None), ('global_', None), ('index', None)] 39 gh = getattr(root, 'global_', _cpGlobalHandler) 40 return [('root', cherrypy.root), ('global_', gh), ('index', None)] 41 35 42 nameList = ['root'] + nameList + ['index'] 36 43 … … 71 78 raise cherrypy.HTTPError(500, msg) 72 79 73 def _cpGlobalInformation(): 74 """Handles OPTIONS * HTTP/1.1 requests""" 80 def _cpGlobalHandler(): 81 """Default handler for a Request-URI of '*'.""" 82 response = cherrypy.response 83 response.headerMap['Content-Type'] = 'text/plain' 84 85 # OPTIONS is defined in HTTP 1.1 and greater 75 86 request = cherrypy.request 76 if request.method == 'OPTIONS': 77 # this normally should be * but processRequestLine 78 # switched it to 'global' for the configuration handling 79 if request.path == 'global': 80 # OPTIONS is defined in HTTP 1.1 81 if request.version >= '1.1': 82 response = cherrypy.response 83 response.body = [] 84 response.status = '200 OK' 85 response.headerMap['Allow'] = 'HEAD, GET, POST, PUT, OPTIONS' 86 response.headerMap['Content-Length'] = 0 87 response.headerMap['Content-Type'] = 'text/plain' 88 response.finalize() 89 getSpecialAttribute("_cpLogAccess")() 90 return True 91 return False 87 if request.method == 'OPTIONS' and request.version >= 1.1: 88 response.headerMap['Allow'] = 'HEAD, GET, POST, PUT, OPTIONS' 89 else: 90 response.headerMap['Allow'] = 'HEAD, GET, POST' 91 return "" 92 _cpGlobalHandler.exposed = True 92 93 93 94 def logtime(): trunk/cherrypy/test/test_config.py
r778 r823 32 32 'server.environment': 'production', 33 33 'server.showTracebacks': True, 34 'server.protocolVersion': "HTTP/1.1",35 34 }, 36 35 '/': { trunk/cherrypy/test/test_core.py
r819 r823 326 326 'server.environment': 'production', 327 327 'server.showTracebacks': True, 328 'server.protocolVersion': "HTTP/1.1",329 328 }, 330 329 '/flatten': { … … 547 546 # HTTPRedirect on error 548 547 self.getPage("/redirect/error/") 549 self.assertStatus( '303 See Other')548 self.assertStatus(('302 Found', '303 See Other')) 550 549 self.assertInBody('/errpage') 551 550 … … 553 552 self.getPage("/redirect/stringify") 554 553 self.assertStatus('200 OK') 555 self.assertBody("(['http://127.0.0.1:8000/'], 303)") 554 protocol = cherrypy.config.get('server.protocolVersion') 555 if protocol == "HTTP/1.1": 556 self.assertBody("(['http://127.0.0.1:8000/'], 303)") 557 else: 558 self.assertBody("(['http://127.0.0.1:8000/'], 302)") 556 559 557 560 def testCPFilterList(self): … … 616 619 617 620 def testRanges(self): 618 self.getPage("/ranges/get_ranges", [('Range', 'bytes=3-6')]) 619 self.assertBody("[(3, 7)]") 620 621 # Test multiple ranges and a suffix-byte-range-spec, for good measure. 622 self.getPage("/ranges/get_ranges", [('Range', 'bytes=2-4,-1')]) 623 self.assertBody("[(2, 5), (7, 8)]") 624 625 # Get a partial file. 626 self.getPage("/ranges/slice_file", [('Range', 'bytes=2-5')]) 627 self.assertStatus("206 Partial Content") 628 self.assertHeader("Content-Type", "text/html") 629 self.assertHeader("Content-Range", "bytes 2-5/14") 630 self.assertBody("llo,") 631 632 # What happens with overlapping ranges (and out of order, too)? 633 self.getPage("/ranges/slice_file", [('Range', 'bytes=4-6,2-5')]) 634 self.assertStatus("206 Partial Content") 635 ct = "" 636 for k, v in self.headers: 637 if k.lower() == "content-type": 638 ct = v 639 break 640 expected_type = "multipart/byteranges; boundary=" 641 self.assert_(ct.startswith(expected_type)) 642 boundary = ct[len(expected_type):] 643 expected_body = """--%s 621 protocol = cherrypy.config.get('server.protocolVersion') 622 if protocol == "HTTP/1.1": 623 self.getPage("/ranges/get_ranges", [('Range', 'bytes=3-6')]) 624 self.assertBody("[(3, 7)]") 625 626 # Test multiple ranges and a suffix-byte-range-spec, for good measure. 627 self.getPage("/ranges/get_ranges", [('Range', 'bytes=2-4,-1')]) 628 self.assertBody("[(2, 5), (7, 8)]") 629 630 # Get a partial file. 631 self.getPage("/ranges/slice_file", [('Range', 'bytes=2-5')]) 632 self.assertStatus("206 Partial Content") 633 self.assertHeader("Content-Type", "text/html") 634 self.assertHeader("Content-Range", "bytes 2-5/14") 635 self.assertBody("llo,") 636 637 # What happens with overlapping ranges (and out of order, too)? 638 self.getPage("/ranges/slice_file", [('Range', 'bytes=4-6,2-5')]) 639 self.assertStatus("206 Partial Content") 640 ct = "" 641 for k, v in self.headers: 642 if k.lower() == "content-type": 643 ct = v 644 break 645 expected_type = "multipart/byteranges; boundary=" 646 self.assert_(ct.startswith(expected_type)) 647 boundary = ct[len(expected_type):] 648 expected_body = """--%s 644 649 Content-type: text/html 645 650 Content-range: bytes 4-6/14 … … 652 657 llo, 653 658 --%s""" % (boundary, boundary, boundary) 654 self.assertBody(expected_body) 655 self.assertHeader("Content-Length") 656 657 # Test "416 Requested Range Not Satisfiable" 658 self.getPage("/ranges/slice_file", [('Range', 'bytes=2300-2900')]) 659 self.assertStatus("416 Requested Range Not Satisfiable") 660 self.assertHeader("Content-Range", "bytes */14") 659 self.assertBody(expected_body) 660 self.assertHeader("Content-Length") 661 662 # Test "416 Requested Range Not Satisfiable" 663 self.getPage("/ranges/slice_file", [('Range', 'bytes=2300-2900')]) 664 self.assertStatus("416 Requested Range Not Satisfiable") 665 self.assertHeader("Content-Range", "bytes */14") 666 else: 667 self.getPage("/ranges/slice_file", [('Range', 'bytes=2-5')]) 668 self.assertStatus("200 OK") 669 self.assertBody("Hello, world\r\n") 661 670 662 671 def testExpect(self): … … 764 773 self.assertHeader("Content-Length", "0") 765 774 775 # Now be really dastardly and delete our custom global_ handler, 776 # to see if the default one works. 777 del Root.global_ 778 self.getPage("*", method="OPTIONS") 779 self.assertStatus("200 OK") 780 self.assertHeader("Allow", 'HEAD, GET, POST, PUT, OPTIONS') 781 766 782 # For method dispatchers: make sure that an HTTP method doesn't 767 783 # collide with a virtual path atom. If you build HTTP-method

