Changeset 1137
- Timestamp:
- 06/12/06 00:34:44
- Files:
-
- trunk/cherrypy/_cperror.py (modified) (1 diff)
- trunk/cherrypy/_cprequest.py (modified) (2 diffs)
- trunk/cherrypy/lib/httptools.py (modified) (4 diffs)
- trunk/cherrypy/lib/static.py (modified) (1 diff)
- trunk/cherrypy/lib/wsgiapp.py (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/cherrypy/_cperror.py
r1134 r1137 77 77 # http://ppewww.ph.gla.ac.uk/~flavell/www/post-redirect.html 78 78 if status is None: 79 if cherrypy.response.version >= "1.1":79 if cherrypy.response.version >= (1, 1): 80 80 status = 303 81 81 else: trunk/cherrypy/_cprequest.py
r1136 r1137 220 220 221 221 # cherrypy.request.version == request.protocol in a Version instance. 222 self.version = httptools. Version.from_http(self.protocol)222 self.version = httptools.version_from_http(self.protocol) 223 223 224 224 # cherrypy.response.version should be used to determine whether or 225 225 # not to include a given HTTP/1.1 feature in the response content. 226 226 server_v = cherrypy.config.get('server.protocol_version', 'HTTP/1.0') 227 server_v = httptools. Version.from_http(server_v)227 server_v = httptools.version_from_http(server_v) 228 228 cherrypy.response.version = min(self.version, server_v) 229 229 … … 244 244 self.simple_cookie.load(value) 245 245 246 if self.version >= "1.1": 246 host = self.headers.get('Host') 247 if host is None: 247 248 # All Internet-based HTTP/1.1 servers MUST respond with a 400 248 249 # (Bad Request) status code to any HTTP/1.1 request message 249 250 # which lacks a Host header field. 250 if not self.headers.has_key("Host"):251 if self.version >= (1, 1): 251 252 msg = "HTTP/1.1 requires a 'Host' request header." 252 253 raise cherrypy.HTTPError(400, msg) 253 254 host = self.headers.get('Host', '')255 254 if not host: 256 255 host = cherrypy.config.get('server.socket_host', '') trunk/cherrypy/lib/httptools.py
r1125 r1137 1 """HTTP library functions and tools."""2 3 # This module contains functions and toolsfor building an HTTP application1 """HTTP library functions.""" 2 3 # This module contains functions for building an HTTP application 4 4 # framework: any one, not just one whose name starts with "Ch". ;) If you 5 5 # reference any modules from some popular framework inside *this* module, … … 23 23 import re 24 24 import time 25 import urllib 25 from urllib import unquote 26 26 from urlparse import urlparse 27 27 … … 63 63 64 64 65 class Version(object): 66 67 """A version, such as "2.1 beta 3", which can be compared atom-by-atom. 68 69 If a string is provided to the constructor, it will be split on word 70 boundaries; that is, "1.4.13 beta 9" -> ["1", "4", "13", "beta", "9"]. 71 72 Comparisons are performed atom-by-atom, numerically if both atoms are 73 numeric. Therefore, "2.12" is greater than "2.4", and "3.0 beta" is 74 greater than "3.0 alpha" (only because "b" > "a"). If an atom is 75 provided in one Version and not another, the longer Version is 76 greater than the shorter, that is: "4.8 alpha" > "4.8". 77 """ 78 79 def __init__(self, atoms): 80 """A Version object. 81 82 atoms: if a str, it will be split on word boundaries; 83 if a float or int, it will be split at the decimal point. 84 """ 85 if isinstance(atoms, (int, float)): 86 atoms = str(atoms) 87 if isinstance(atoms, basestring): 88 self.atoms = re.split(r'\W', atoms) 89 else: 90 self.atoms = [str(x) for x in atoms] 91 92 def from_http(cls, version_str): 93 """Return a Version object from the given 'HTTP/x.y' string.""" 94 return cls(version_str[5:]) 95 from_http = classmethod(from_http) 96 97 def to_http(self): 98 """Return a 'HTTP/x.y' string for this Version object.""" 99 return "HTTP/%s.%s" % tuple(self.atoms[:2]) 100 101 def __str__(self): 102 return ".".join([str(x) for x in self.atoms]) 103 104 def __cmp__(self, other): 105 cls = self.__class__ 106 if not isinstance(other, cls): 107 # Try to coerce other to a Version instance. 108 other = cls(other) 109 110 index = 0 111 while index < len(self.atoms) and index < len(other.atoms): 112 mine, theirs = self.atoms[index], other.atoms[index] 113 if mine.isdigit() and theirs.isdigit(): 114 mine, theirs = int(mine), int(theirs) 115 if mine < theirs: 116 return -1 117 if mine > theirs: 118 return 1 119 index += 1 120 if index < len(other.atoms): 121 return -1 122 if index < len(self.atoms): 123 return 1 124 return 0 125 65 def version_from_http(version_str): 66 """Return a Version tuple from the given 'HTTP/x.y' string.""" 67 return int(version_str[5]), int(version_str[7]) 126 68 127 69 def getRanges(headervalue, content_length): … … 318 260 # [Therefore, this assumes all hosts are valid for this server. 319 261 # Note that we are also violating the RFC which says: if the host 320 # given i nan abs_path, it must override any Host header.]262 # given is an abs_path, it must override any Host header.] 321 263 scheme, location, path, params, qs, frag = urlparse(path) 322 if path == "*": 323 # "...the request does not apply to a particular resource, 324 # but to the server itself". See 325 # http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.2 326 pass 327 else: 328 if params: 329 params = ";" + params 330 path = path + params 331 332 # Unquote the path (e.g. "/this%20path" -> "this path"). 333 # http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.2 334 # 335 # But note that "...a URI must be separated into its components 336 # before the escaped characters within those components can be 337 # safely decoded." http://www.ietf.org/rfc/rfc2396.txt, sec 2.4.2 338 # 339 # Note also that cgi.parse_qs will decode the querystring for us. 340 atoms = [urllib.unquote(x) for x in re.split("(?i)%2F", path)] 341 path = "%2F".join(atoms) 264 265 if params: 266 path = path + ";" + params 267 268 # Unquote the path (e.g. "/this%20path" -> "this path"). 269 # http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.2 270 # 271 # But note that "...a URI must be separated into its components 272 # before the escaped characters within those components can be 273 # safely decoded." http://www.ietf.org/rfc/rfc2396.txt, sec 2.4.2 274 # 275 # Note also that cgi.parse_qs will decode the querystring for us. 276 atoms = [unquote(x) for x in re.split("(?i)%2F", path)] 277 path = "%2F".join(atoms) 342 278 343 279 return method, path, qs, protocol trunk/cherrypy/lib/static.py
r1117 r1137 75 75 76 76 # HTTP/1.0 didn't have Range/Accept-Ranges headers, or the 206 code 77 if cherrypy.response.version >= "1.1":77 if cherrypy.response.version >= (1, 1): 78 78 response.headers["Accept-Ranges"] = "bytes" 79 79 r = httptools.getRanges(cherrypy.request.headers.get('Range'), c_len) trunk/cherrypy/lib/wsgiapp.py
r1114 r1137 31 31 environ["PATH_INFO"] = cherrypy.request.path_info 32 32 environ["QUERY_STRING"] = cherrypy.request.query_string 33 environ["SERVER_PROTOCOL"] = cherrypy.request. version33 environ["SERVER_PROTOCOL"] = cherrypy.request.protocol 34 34 server_name = getattr(cherrypy.server.httpserver, 'server_name', "None") 35 35 environ["SERVER_NAME"] = server_name

