1import warnings 2 3from webob.compat import ( 4 escape, 5 string_types, 6 text_, 7 text_type, 8 ) 9 10from webob.headers import _trans_key 11 12def html_escape(s): 13 """HTML-escape a string or object 14 15 This converts any non-string objects passed into it to strings 16 (actually, using ``unicode()``). All values returned are 17 non-unicode strings (using ``&#num;`` entities for all non-ASCII 18 characters). 19 20 None is treated specially, and returns the empty string. 21 """ 22 if s is None: 23 return '' 24 __html__ = getattr(s, '__html__', None) 25 if __html__ is not None and callable(__html__): 26 return s.__html__() 27 if not isinstance(s, string_types): 28 __unicode__ = getattr(s, '__unicode__', None) 29 if __unicode__ is not None and callable(__unicode__): 30 s = s.__unicode__() 31 else: 32 s = str(s) 33 s = escape(s, True) 34 if isinstance(s, text_type): 35 s = s.encode('ascii', 'xmlcharrefreplace') 36 return text_(s) 37 38def header_docstring(header, rfc_section): 39 if header.isupper(): 40 header = _trans_key(header) 41 major_section = rfc_section.split('.')[0] 42 link = 'http://www.w3.org/Protocols/rfc2616/rfc2616-sec%s.html#sec%s' % ( 43 major_section, rfc_section) 44 return "Gets and sets the ``%s`` header (`HTTP spec section %s <%s>`_)." % ( 45 header, rfc_section, link) 46 47 48def warn_deprecation(text, version, stacklevel): 49 # version specifies when to start raising exceptions instead of warnings 50 if version in ('1.2', '1.3', '1.4'): 51 raise DeprecationWarning(text) 52 else: 53 cls = DeprecationWarning 54 warnings.warn(text, cls, stacklevel=stacklevel+1) 55 56status_reasons = { 57 # Status Codes 58 # Informational 59 100: 'Continue', 60 101: 'Switching Protocols', 61 102: 'Processing', 62 63 # Successful 64 200: 'OK', 65 201: 'Created', 66 202: 'Accepted', 67 203: 'Non-Authoritative Information', 68 204: 'No Content', 69 205: 'Reset Content', 70 206: 'Partial Content', 71 207: 'Multi Status', 72 226: 'IM Used', 73 74 # Redirection 75 300: 'Multiple Choices', 76 301: 'Moved Permanently', 77 302: 'Found', 78 303: 'See Other', 79 304: 'Not Modified', 80 305: 'Use Proxy', 81 307: 'Temporary Redirect', 82 83 # Client Error 84 400: 'Bad Request', 85 401: 'Unauthorized', 86 402: 'Payment Required', 87 403: 'Forbidden', 88 404: 'Not Found', 89 405: 'Method Not Allowed', 90 406: 'Not Acceptable', 91 407: 'Proxy Authentication Required', 92 408: 'Request Timeout', 93 409: 'Conflict', 94 410: 'Gone', 95 411: 'Length Required', 96 412: 'Precondition Failed', 97 413: 'Request Entity Too Large', 98 414: 'Request URI Too Long', 99 415: 'Unsupported Media Type', 100 416: 'Requested Range Not Satisfiable', 101 417: 'Expectation Failed', 102 418: "I'm a teapot", 103 422: 'Unprocessable Entity', 104 423: 'Locked', 105 424: 'Failed Dependency', 106 426: 'Upgrade Required', 107 428: 'Precondition Required', 108 429: 'Too Many Requests', 109 451: 'Unavailable for Legal Reasons', 110 431: 'Request Header Fields Too Large', 111 112 # Server Error 113 500: 'Internal Server Error', 114 501: 'Not Implemented', 115 502: 'Bad Gateway', 116 503: 'Service Unavailable', 117 504: 'Gateway Timeout', 118 505: 'HTTP Version Not Supported', 119 507: 'Insufficient Storage', 120 510: 'Not Extended', 121 511: 'Network Authentication Required', 122} 123 124# generic class responses as per RFC2616 125status_generic_reasons = { 126 1: 'Continue', 127 2: 'Success', 128 3: 'Multiple Choices', 129 4: 'Unknown Client Error', 130 5: 'Unknown Server Error', 131} 132 133try: 134 # py3.3+ have native comparison support 135 from hmac import compare_digest 136except ImportError: # pragma: nocover (Python 2.7.7 backported this) 137 compare_digest = None 138 139def strings_differ(string1, string2, compare_digest=compare_digest): 140 """Check whether two strings differ while avoiding timing attacks. 141 142 This function returns True if the given strings differ and False 143 if they are equal. It's careful not to leak information about *where* 144 they differ as a result of its running time, which can be very important 145 to avoid certain timing-related crypto attacks: 146 147 http://seb.dbzteam.org/crypto/python-oauth-timing-hmac.pdf 148 149 .. versionchanged:: 1.5 150 Support :func:`hmac.compare_digest` if it is available (Python 2.7.7+ 151 and Python 3.3+). 152 153 """ 154 len_eq = len(string1) == len(string2) 155 if len_eq: 156 invalid_bits = 0 157 left = string1 158 else: 159 invalid_bits = 1 160 left = string2 161 right = string2 162 163 if compare_digest is not None: 164 invalid_bits += not compare_digest(left, right) 165 else: 166 for a, b in zip(left, right): 167 invalid_bits += a != b 168 return invalid_bits != 0 169 170