httputil.py (9473B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\lib\cherrypy\lib\httputil.py 2 from binascii import b2a_base64 3 from cherrypy._cpcompat import BaseHTTPRequestHandler, HTTPDate, ntob, ntou, reversed, sorted 4 from cherrypy._cpcompat import basestring, iteritems, unicodestr, unquote_qs 5 response_codes = BaseHTTPRequestHandler.responses.copy() 6 response_codes[500] = ('Internal Server Error', 'The server encountered an unexpected condition which prevented it from fulfilling the request.') 7 response_codes[503] = ('Service Unavailable', 'The server is currently unable to handle the request due to a temporary overloading or maintenance of the server.') 8 import re 9 import urllib 10 11 def urljoin(*atoms): 12 url = '/'.join([ x for x in atoms if x ]) 13 while '//' in url: 14 url = url.replace('//', '/') 15 16 return url or '/' 17 18 19 def protocol_from_http(protocol_str): 20 return (int(protocol_str[5]), int(protocol_str[7])) 21 22 23 def get_ranges(headervalue, content_length): 24 if not headervalue: 25 return None 26 result = [] 27 bytesunit, byteranges = headervalue.split('=', 1) 28 for brange in byteranges.split(','): 29 start, stop = [ x.strip() for x in brange.split('-', 1) ] 30 if start: 31 if not stop: 32 stop = content_length - 1 33 start, stop = int(start), int(stop) 34 if start >= content_length: 35 continue 36 if stop < start: 37 return None 38 result.append((start, stop + 1)) 39 else: 40 if not stop: 41 return None 42 result.append((content_length - int(stop), content_length)) 43 44 return result 45 46 47 class HeaderElement(object): 48 49 def __init__(self, value, params = None): 50 self.value = value 51 if params is None: 52 params = {} 53 self.params = params 54 55 def __cmp__(self, other): 56 return cmp(self.value, other.value) 57 58 def __str__(self): 59 p = [ ';%s=%s' % (k, v) for k, v in iteritems(self.params) ] 60 return '%s%s' % (self.value, ''.join(p)) 61 62 def __unicode__(self): 63 return ntou(self.__str__()) 64 65 def parse(elementstr): 66 atoms = [ x.strip() for x in elementstr.split(';') if x.strip() ] 67 if not atoms: 68 initial_value = '' 69 else: 70 initial_value = atoms.pop(0).strip() 71 params = {} 72 for atom in atoms: 73 atom = [ x.strip() for x in atom.split('=', 1) if x.strip() ] 74 key = atom.pop(0) 75 if atom: 76 val = atom[0] 77 else: 78 val = '' 79 params[key] = val 80 81 return (initial_value, params) 82 83 parse = staticmethod(parse) 84 85 def from_str(cls, elementstr): 86 ival, params = cls.parse(elementstr) 87 return cls(ival, params) 88 89 from_str = classmethod(from_str) 90 91 92 q_separator = re.compile('; *q *=') 93 94 class AcceptElement(HeaderElement): 95 96 def from_str(cls, elementstr): 97 qvalue = None 98 atoms = q_separator.split(elementstr, 1) 99 media_range = atoms.pop(0).strip() 100 if atoms: 101 qvalue = HeaderElement.from_str(atoms[0].strip()) 102 media_type, params = cls.parse(media_range) 103 if qvalue is not None: 104 params['q'] = qvalue 105 return cls(media_type, params) 106 107 from_str = classmethod(from_str) 108 109 def qvalue(self): 110 val = self.params.get('q', '1') 111 if isinstance(val, HeaderElement): 112 val = val.value 113 return float(val) 114 115 qvalue = property(qvalue, doc='The qvalue, or priority, of this value.') 116 117 def __cmp__(self, other): 118 diff = cmp(self.qvalue, other.qvalue) 119 if diff == 0: 120 diff = cmp(str(self), str(other)) 121 return diff 122 123 124 def header_elements(fieldname, fieldvalue): 125 if not fieldvalue: 126 return [] 127 result = [] 128 for element in fieldvalue.split(','): 129 if fieldname.startswith('Accept') or fieldname == 'TE': 130 hv = AcceptElement.from_str(element) 131 else: 132 hv = HeaderElement.from_str(element) 133 result.append(hv) 134 135 return list(reversed(sorted(result))) 136 137 138 def decode_TEXT(value): 139 from email.Header import decode_header 140 atoms = decode_header(value) 141 decodedvalue = '' 142 for atom, charset in atoms: 143 if charset is not None: 144 atom = atom.decode(charset) 145 decodedvalue += atom 146 147 return decodedvalue 148 149 150 def valid_status(status): 151 if not status: 152 status = 200 153 status = str(status) 154 parts = status.split(' ', 1) 155 if len(parts) == 1: 156 code, = parts 157 reason = None 158 else: 159 code, reason = parts 160 reason = reason.strip() 161 try: 162 code = int(code) 163 except ValueError: 164 raise ValueError('Illegal response status from server (%s is non-numeric).' % repr(code)) 165 166 if code < 100 or code > 599: 167 raise ValueError('Illegal response status from server (%s is out of range).' % repr(code)) 168 if code not in response_codes: 169 default_reason, message = ('', '') 170 else: 171 default_reason, message = response_codes[code] 172 if reason is None: 173 reason = default_reason 174 return (code, reason, message) 175 176 177 def _parse_qs(qs, keep_blank_values = 0, strict_parsing = 0, encoding = 'utf-8'): 178 pairs = [ s2 for s1 in qs.split('&') for s2 in s1.split(';') ] 179 d = {} 180 for name_value in pairs: 181 if not name_value and not strict_parsing: 182 continue 183 nv = name_value.split('=', 1) 184 if len(nv) != 2: 185 if strict_parsing: 186 raise ValueError('bad query field: %r' % (name_value,)) 187 if keep_blank_values: 188 nv.append('') 189 else: 190 continue 191 if len(nv[1]) or keep_blank_values: 192 name = unquote_qs(nv[0], encoding) 193 value = unquote_qs(nv[1], encoding) 194 if name in d: 195 if not isinstance(d[name], list): 196 d[name] = [d[name]] 197 d[name].append(value) 198 else: 199 d[name] = value 200 201 return d 202 203 204 image_map_pattern = re.compile('[0-9]+,[0-9]+') 205 206 def parse_query_string(query_string, keep_blank_values = True, encoding = 'utf-8'): 207 if image_map_pattern.match(query_string): 208 pm = query_string.split(',') 209 pm = {'x': int(pm[0]), 210 'y': int(pm[1])} 211 else: 212 pm = _parse_qs(query_string, keep_blank_values, encoding=encoding) 213 return pm 214 215 216 class CaseInsensitiveDict(dict): 217 218 def __getitem__(self, key): 219 return dict.__getitem__(self, str(key).title()) 220 221 def __setitem__(self, key, value): 222 dict.__setitem__(self, str(key).title(), value) 223 224 def __delitem__(self, key): 225 dict.__delitem__(self, str(key).title()) 226 227 def __contains__(self, key): 228 return dict.__contains__(self, str(key).title()) 229 230 def get(self, key, default = None): 231 return dict.get(self, str(key).title(), default) 232 233 def has_key(self, key): 234 return dict.has_key(self, str(key).title()) 235 236 def update(self, E): 237 for k in E.keys(): 238 self[str(k).title()] = E[k] 239 240 def fromkeys(cls, seq, value = None): 241 newdict = cls() 242 for k in seq: 243 newdict[str(k).title()] = value 244 245 return newdict 246 247 fromkeys = classmethod(fromkeys) 248 249 def setdefault(self, key, x = None): 250 key = str(key).title() 251 try: 252 return self[key] 253 except KeyError: 254 self[key] = x 255 return x 256 257 def pop(self, key, default): 258 return dict.pop(self, str(key).title(), default) 259 260 261 header_translate_table = ''.join([ chr(i) for i in xrange(256) ]) 262 header_translate_deletechars = ''.join([ chr(i) for i in xrange(32) ]) + chr(127) 263 264 class HeaderMap(CaseInsensitiveDict): 265 protocol = (1, 1) 266 encodings = ['ISO-8859-1'] 267 use_rfc_2047 = True 268 269 def elements(self, key): 270 key = str(key).title() 271 value = self.get(key) 272 return header_elements(key, value) 273 274 def values(self, key): 275 return [ e.value for e in self.elements(key) ] 276 277 def output(self): 278 header_list = [] 279 for k, v in self.items(): 280 if isinstance(k, unicodestr): 281 k = self.encode(k) 282 if not isinstance(v, basestring): 283 v = str(v) 284 if isinstance(v, unicodestr): 285 v = self.encode(v) 286 k = k.translate(header_translate_table, header_translate_deletechars) 287 v = v.translate(header_translate_table, header_translate_deletechars) 288 header_list.append((k, v)) 289 290 return header_list 291 292 def encode(self, v): 293 for enc in self.encodings: 294 try: 295 return v.encode(enc) 296 except UnicodeEncodeError: 297 continue 298 299 if self.protocol == (1, 1) and self.use_rfc_2047: 300 v = b2a_base64(v.encode('utf-8')) 301 return ntob('=?utf-8?b?') + v.strip(ntob('\n')) + ntob('?=') 302 raise ValueError('Could not encode header part %r using any of the encodings %r.' % (v, self.encodings)) 303 304 305 class Host(object): 306 ip = '0.0.0.0' 307 port = 80 308 name = 'unknown.tld' 309 310 def __init__(self, ip, port, name = None): 311 self.ip = ip 312 self.port = port 313 if name is None: 314 name = ip 315 self.name = name 316 317 def __repr__(self): 318 return 'httputil.Host(%r, %r, %r)' % (self.ip, self.port, self.name)