_internal.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  1. # -*- coding: utf-8 -*-
  2. """
  3. werkzeug._internal
  4. ~~~~~~~~~~~~~~~~~~
  5. This module provides internally used helpers and constants.
  6. :copyright: 2007 Pallets
  7. :license: BSD-3-Clause
  8. """
  9. import inspect
  10. import logging
  11. import re
  12. import string
  13. from datetime import date
  14. from datetime import datetime
  15. from itertools import chain
  16. from weakref import WeakKeyDictionary
  17. from ._compat import int_to_byte
  18. from ._compat import integer_types
  19. from ._compat import iter_bytes
  20. from ._compat import range_type
  21. from ._compat import text_type
  22. _logger = None
  23. _signature_cache = WeakKeyDictionary()
  24. _epoch_ord = date(1970, 1, 1).toordinal()
  25. _legal_cookie_chars = (
  26. string.ascii_letters + string.digits + u"/=!#$%&'*+-.^_`|~:"
  27. ).encode("ascii")
  28. _cookie_quoting_map = {b",": b"\\054", b";": b"\\073", b'"': b'\\"', b"\\": b"\\\\"}
  29. for _i in chain(range_type(32), range_type(127, 256)):
  30. _cookie_quoting_map[int_to_byte(_i)] = ("\\%03o" % _i).encode("latin1")
  31. _octal_re = re.compile(br"\\[0-3][0-7][0-7]")
  32. _quote_re = re.compile(br"[\\].")
  33. _legal_cookie_chars_re = br"[\w\d!#%&\'~_`><@,:/\$\*\+\-\.\^\|\)\(\?\}\{\=]"
  34. _cookie_re = re.compile(
  35. br"""
  36. (?P<key>[^=;]+)
  37. (?:\s*=\s*
  38. (?P<val>
  39. "(?:[^\\"]|\\.)*" |
  40. (?:.*?)
  41. )
  42. )?
  43. \s*;
  44. """,
  45. flags=re.VERBOSE,
  46. )
  47. class _Missing(object):
  48. def __repr__(self):
  49. return "no value"
  50. def __reduce__(self):
  51. return "_missing"
  52. _missing = _Missing()
  53. def _get_environ(obj):
  54. env = getattr(obj, "environ", obj)
  55. assert isinstance(env, dict), (
  56. "%r is not a WSGI environment (has to be a dict)" % type(obj).__name__
  57. )
  58. return env
  59. def _has_level_handler(logger):
  60. """Check if there is a handler in the logging chain that will handle
  61. the given logger's effective level.
  62. """
  63. level = logger.getEffectiveLevel()
  64. current = logger
  65. while current:
  66. if any(handler.level <= level for handler in current.handlers):
  67. return True
  68. if not current.propagate:
  69. break
  70. current = current.parent
  71. return False
  72. def _log(type, message, *args, **kwargs):
  73. """Log a message to the 'werkzeug' logger.
  74. The logger is created the first time it is needed. If there is no
  75. level set, it is set to :data:`logging.INFO`. If there is no handler
  76. for the logger's effective level, a :class:`logging.StreamHandler`
  77. is added.
  78. """
  79. global _logger
  80. if _logger is None:
  81. _logger = logging.getLogger("werkzeug")
  82. if _logger.level == logging.NOTSET:
  83. _logger.setLevel(logging.INFO)
  84. if not _has_level_handler(_logger):
  85. _logger.addHandler(logging.StreamHandler())
  86. getattr(_logger, type)(message.rstrip(), *args, **kwargs)
  87. def _parse_signature(func):
  88. """Return a signature object for the function."""
  89. if hasattr(func, "im_func"):
  90. func = func.im_func
  91. # if we have a cached validator for this function, return it
  92. parse = _signature_cache.get(func)
  93. if parse is not None:
  94. return parse
  95. # inspect the function signature and collect all the information
  96. if hasattr(inspect, "getfullargspec"):
  97. tup = inspect.getfullargspec(func)
  98. else:
  99. tup = inspect.getargspec(func)
  100. positional, vararg_var, kwarg_var, defaults = tup[:4]
  101. defaults = defaults or ()
  102. arg_count = len(positional)
  103. arguments = []
  104. for idx, name in enumerate(positional):
  105. if isinstance(name, list):
  106. raise TypeError(
  107. "cannot parse functions that unpack tuples in the function signature"
  108. )
  109. try:
  110. default = defaults[idx - arg_count]
  111. except IndexError:
  112. param = (name, False, None)
  113. else:
  114. param = (name, True, default)
  115. arguments.append(param)
  116. arguments = tuple(arguments)
  117. def parse(args, kwargs):
  118. new_args = []
  119. missing = []
  120. extra = {}
  121. # consume as many arguments as positional as possible
  122. for idx, (name, has_default, default) in enumerate(arguments):
  123. try:
  124. new_args.append(args[idx])
  125. except IndexError:
  126. try:
  127. new_args.append(kwargs.pop(name))
  128. except KeyError:
  129. if has_default:
  130. new_args.append(default)
  131. else:
  132. missing.append(name)
  133. else:
  134. if name in kwargs:
  135. extra[name] = kwargs.pop(name)
  136. # handle extra arguments
  137. extra_positional = args[arg_count:]
  138. if vararg_var is not None:
  139. new_args.extend(extra_positional)
  140. extra_positional = ()
  141. if kwargs and kwarg_var is None:
  142. extra.update(kwargs)
  143. kwargs = {}
  144. return (
  145. new_args,
  146. kwargs,
  147. missing,
  148. extra,
  149. extra_positional,
  150. arguments,
  151. vararg_var,
  152. kwarg_var,
  153. )
  154. _signature_cache[func] = parse
  155. return parse
  156. def _date_to_unix(arg):
  157. """Converts a timetuple, integer or datetime object into the seconds from
  158. epoch in utc.
  159. """
  160. if isinstance(arg, datetime):
  161. arg = arg.utctimetuple()
  162. elif isinstance(arg, integer_types + (float,)):
  163. return int(arg)
  164. year, month, day, hour, minute, second = arg[:6]
  165. days = date(year, month, 1).toordinal() - _epoch_ord + day - 1
  166. hours = days * 24 + hour
  167. minutes = hours * 60 + minute
  168. seconds = minutes * 60 + second
  169. return seconds
  170. class _DictAccessorProperty(object):
  171. """Baseclass for `environ_property` and `header_property`."""
  172. read_only = False
  173. def __init__(
  174. self,
  175. name,
  176. default=None,
  177. load_func=None,
  178. dump_func=None,
  179. read_only=None,
  180. doc=None,
  181. ):
  182. self.name = name
  183. self.default = default
  184. self.load_func = load_func
  185. self.dump_func = dump_func
  186. if read_only is not None:
  187. self.read_only = read_only
  188. self.__doc__ = doc
  189. def __get__(self, obj, type=None):
  190. if obj is None:
  191. return self
  192. storage = self.lookup(obj)
  193. if self.name not in storage:
  194. return self.default
  195. rv = storage[self.name]
  196. if self.load_func is not None:
  197. try:
  198. rv = self.load_func(rv)
  199. except (ValueError, TypeError):
  200. rv = self.default
  201. return rv
  202. def __set__(self, obj, value):
  203. if self.read_only:
  204. raise AttributeError("read only property")
  205. if self.dump_func is not None:
  206. value = self.dump_func(value)
  207. self.lookup(obj)[self.name] = value
  208. def __delete__(self, obj):
  209. if self.read_only:
  210. raise AttributeError("read only property")
  211. self.lookup(obj).pop(self.name, None)
  212. def __repr__(self):
  213. return "<%s %s>" % (self.__class__.__name__, self.name)
  214. def _cookie_quote(b):
  215. buf = bytearray()
  216. all_legal = True
  217. _lookup = _cookie_quoting_map.get
  218. _push = buf.extend
  219. for char in iter_bytes(b):
  220. if char not in _legal_cookie_chars:
  221. all_legal = False
  222. char = _lookup(char, char)
  223. _push(char)
  224. if all_legal:
  225. return bytes(buf)
  226. return bytes(b'"' + buf + b'"')
  227. def _cookie_unquote(b):
  228. if len(b) < 2:
  229. return b
  230. if b[:1] != b'"' or b[-1:] != b'"':
  231. return b
  232. b = b[1:-1]
  233. i = 0
  234. n = len(b)
  235. rv = bytearray()
  236. _push = rv.extend
  237. while 0 <= i < n:
  238. o_match = _octal_re.search(b, i)
  239. q_match = _quote_re.search(b, i)
  240. if not o_match and not q_match:
  241. rv.extend(b[i:])
  242. break
  243. j = k = -1
  244. if o_match:
  245. j = o_match.start(0)
  246. if q_match:
  247. k = q_match.start(0)
  248. if q_match and (not o_match or k < j):
  249. _push(b[i:k])
  250. _push(b[k + 1 : k + 2])
  251. i = k + 2
  252. else:
  253. _push(b[i:j])
  254. rv.append(int(b[j + 1 : j + 4], 8))
  255. i = j + 4
  256. return bytes(rv)
  257. def _cookie_parse_impl(b):
  258. """Lowlevel cookie parsing facility that operates on bytes."""
  259. i = 0
  260. n = len(b)
  261. while i < n:
  262. match = _cookie_re.search(b + b";", i)
  263. if not match:
  264. break
  265. key = match.group("key").strip()
  266. value = match.group("val") or b""
  267. i = match.end(0)
  268. yield _cookie_unquote(key), _cookie_unquote(value)
  269. def _encode_idna(domain):
  270. # If we're given bytes, make sure they fit into ASCII
  271. if not isinstance(domain, text_type):
  272. domain.decode("ascii")
  273. return domain
  274. # Otherwise check if it's already ascii, then return
  275. try:
  276. return domain.encode("ascii")
  277. except UnicodeError:
  278. pass
  279. # Otherwise encode each part separately
  280. parts = domain.split(".")
  281. for idx, part in enumerate(parts):
  282. parts[idx] = part.encode("idna")
  283. return b".".join(parts)
  284. def _decode_idna(domain):
  285. # If the input is a string try to encode it to ascii to
  286. # do the idna decoding. if that fails because of an
  287. # unicode error, then we already have a decoded idna domain
  288. if isinstance(domain, text_type):
  289. try:
  290. domain = domain.encode("ascii")
  291. except UnicodeError:
  292. return domain
  293. # Decode each part separately. If a part fails, try to
  294. # decode it with ascii and silently ignore errors. This makes
  295. # most sense because the idna codec does not have error handling
  296. parts = domain.split(b".")
  297. for idx, part in enumerate(parts):
  298. try:
  299. parts[idx] = part.decode("idna")
  300. except UnicodeError:
  301. parts[idx] = part.decode("ascii", "ignore")
  302. return ".".join(parts)
  303. def _make_cookie_domain(domain):
  304. if domain is None:
  305. return None
  306. domain = _encode_idna(domain)
  307. if b":" in domain:
  308. domain = domain.split(b":", 1)[0]
  309. if b"." in domain:
  310. return domain
  311. raise ValueError(
  312. "Setting 'domain' for a cookie on a server running locally (ex: "
  313. "localhost) is not supported by complying browsers. You should "
  314. "have something like: '127.0.0.1 localhost dev.localhost' on "
  315. "your hosts file and then point your server to run on "
  316. "'dev.localhost' and also set 'domain' for 'dev.localhost'"
  317. )
  318. def _easteregg(app=None):
  319. """Like the name says. But who knows how it works?"""
  320. def bzzzzzzz(gyver):
  321. import base64
  322. import zlib
  323. return zlib.decompress(base64.b64decode(gyver)).decode("ascii")
  324. gyver = u"\n".join(
  325. [
  326. x + (77 - len(x)) * u" "
  327. for x in bzzzzzzz(
  328. b"""
  329. eJyFlzuOJDkMRP06xRjymKgDJCDQStBYT8BCgK4gTwfQ2fcFs2a2FzvZk+hvlcRvRJD148efHt9m
  330. 9Xz94dRY5hGt1nrYcXx7us9qlcP9HHNh28rz8dZj+q4rynVFFPdlY4zH873NKCexrDM6zxxRymzz
  331. 4QIxzK4bth1PV7+uHn6WXZ5C4ka/+prFzx3zWLMHAVZb8RRUxtFXI5DTQ2n3Hi2sNI+HK43AOWSY
  332. jmEzE4naFp58PdzhPMdslLVWHTGUVpSxImw+pS/D+JhzLfdS1j7PzUMxij+mc2U0I9zcbZ/HcZxc
  333. q1QjvvcThMYFnp93agEx392ZdLJWXbi/Ca4Oivl4h/Y1ErEqP+lrg7Xa4qnUKu5UE9UUA4xeqLJ5
  334. jWlPKJvR2yhRI7xFPdzPuc6adXu6ovwXwRPXXnZHxlPtkSkqWHilsOrGrvcVWXgGP3daXomCj317
  335. 8P2UOw/NnA0OOikZyFf3zZ76eN9QXNwYdD8f8/LdBRFg0BO3bB+Pe/+G8er8tDJv83XTkj7WeMBJ
  336. v/rnAfdO51d6sFglfi8U7zbnr0u9tyJHhFZNXYfH8Iafv2Oa+DT6l8u9UYlajV/hcEgk1x8E8L/r
  337. XJXl2SK+GJCxtnyhVKv6GFCEB1OO3f9YWAIEbwcRWv/6RPpsEzOkXURMN37J0PoCSYeBnJQd9Giu
  338. LxYQJNlYPSo/iTQwgaihbART7Fcyem2tTSCcwNCs85MOOpJtXhXDe0E7zgZJkcxWTar/zEjdIVCk
  339. iXy87FW6j5aGZhttDBoAZ3vnmlkx4q4mMmCdLtnHkBXFMCReqthSGkQ+MDXLLCpXwBs0t+sIhsDI
  340. tjBB8MwqYQpLygZ56rRHHpw+OAVyGgaGRHWy2QfXez+ZQQTTBkmRXdV/A9LwH6XGZpEAZU8rs4pE
  341. 1R4FQ3Uwt8RKEtRc0/CrANUoes3EzM6WYcFyskGZ6UTHJWenBDS7h163Eo2bpzqxNE9aVgEM2CqI
  342. GAJe9Yra4P5qKmta27VjzYdR04Vc7KHeY4vs61C0nbywFmcSXYjzBHdiEjraS7PGG2jHHTpJUMxN
  343. Jlxr3pUuFvlBWLJGE3GcA1/1xxLcHmlO+LAXbhrXah1tD6Ze+uqFGdZa5FM+3eHcKNaEarutAQ0A
  344. QMAZHV+ve6LxAwWnXbbSXEG2DmCX5ijeLCKj5lhVFBrMm+ryOttCAeFpUdZyQLAQkA06RLs56rzG
  345. 8MID55vqr/g64Qr/wqwlE0TVxgoiZhHrbY2h1iuuyUVg1nlkpDrQ7Vm1xIkI5XRKLedN9EjzVchu
  346. jQhXcVkjVdgP2O99QShpdvXWoSwkp5uMwyjt3jiWCqWGSiaaPAzohjPanXVLbM3x0dNskJsaCEyz
  347. DTKIs+7WKJD4ZcJGfMhLFBf6hlbnNkLEePF8Cx2o2kwmYF4+MzAxa6i+6xIQkswOqGO+3x9NaZX8
  348. MrZRaFZpLeVTYI9F/djY6DDVVs340nZGmwrDqTCiiqD5luj3OzwpmQCiQhdRYowUYEA3i1WWGwL4
  349. GCtSoO4XbIPFeKGU13XPkDf5IdimLpAvi2kVDVQbzOOa4KAXMFlpi/hV8F6IDe0Y2reg3PuNKT3i
  350. RYhZqtkQZqSB2Qm0SGtjAw7RDwaM1roESC8HWiPxkoOy0lLTRFG39kvbLZbU9gFKFRvixDZBJmpi
  351. Xyq3RE5lW00EJjaqwp/v3EByMSpVZYsEIJ4APaHmVtpGSieV5CALOtNUAzTBiw81GLgC0quyzf6c
  352. NlWknzJeCsJ5fup2R4d8CYGN77mu5vnO1UqbfElZ9E6cR6zbHjgsr9ly18fXjZoPeDjPuzlWbFwS
  353. pdvPkhntFvkc13qb9094LL5NrA3NIq3r9eNnop9DizWOqCEbyRBFJTHn6Tt3CG1o8a4HevYh0XiJ
  354. sR0AVVHuGuMOIfbuQ/OKBkGRC6NJ4u7sbPX8bG/n5sNIOQ6/Y/BX3IwRlTSabtZpYLB85lYtkkgm
  355. p1qXK3Du2mnr5INXmT/78KI12n11EFBkJHHp0wJyLe9MvPNUGYsf+170maayRoy2lURGHAIapSpQ
  356. krEDuNoJCHNlZYhKpvw4mspVWxqo415n8cD62N9+EfHrAvqQnINStetek7RY2Urv8nxsnGaZfRr/
  357. nhXbJ6m/yl1LzYqscDZA9QHLNbdaSTTr+kFg3bC0iYbX/eQy0Bv3h4B50/SGYzKAXkCeOLI3bcAt
  358. mj2Z/FM1vQWgDynsRwNvrWnJHlespkrp8+vO1jNaibm+PhqXPPv30YwDZ6jApe3wUjFQobghvW9p
  359. 7f2zLkGNv8b191cD/3vs9Q833z8t"""
  360. ).splitlines()
  361. ]
  362. )
  363. def easteregged(environ, start_response):
  364. def injecting_start_response(status, headers, exc_info=None):
  365. headers.append(("X-Powered-By", "Werkzeug"))
  366. return start_response(status, headers, exc_info)
  367. if app is not None and environ.get("QUERY_STRING") != "macgybarchakku":
  368. return app(environ, injecting_start_response)
  369. injecting_start_response("200 OK", [("Content-Type", "text/html")])
  370. return [
  371. (
  372. u"""
  373. <!DOCTYPE html>
  374. <html>
  375. <head>
  376. <title>About Werkzeug</title>
  377. <style type="text/css">
  378. body { font: 15px Georgia, serif; text-align: center; }
  379. a { color: #333; text-decoration: none; }
  380. h1 { font-size: 30px; margin: 20px 0 10px 0; }
  381. p { margin: 0 0 30px 0; }
  382. pre { font: 11px 'Consolas', 'Monaco', monospace; line-height: 0.95; }
  383. </style>
  384. </head>
  385. <body>
  386. <h1><a href="http://werkzeug.pocoo.org/">Werkzeug</a></h1>
  387. <p>the Swiss Army knife of Python web development.</p>
  388. <pre>%s\n\n\n</pre>
  389. </body>
  390. </html>"""
  391. % gyver
  392. ).encode("latin1")
  393. ]
  394. return easteregged