/circuits/web/dispatchers/static.py

https://bitbucket.org/prologic/circuits/ · Python · 145 lines · 105 code · 26 blank · 14 comment · 33 complexity · 37783e36f49e8bf9b8aab1e6f5c9a565 MD5 · raw file

  1. # Module: static
  2. # Date: 13th September 2007
  3. # Author: James Mills, prologic at shortcircuit dot net dot au
  4. """Static
  5. This modStatic implements a Static dispatcher used to serve up static
  6. resources and an optional apache-style directory listing.
  7. """
  8. import os
  9. from string import Template
  10. try:
  11. from urllib import quote, unquote
  12. except ImportError:
  13. from urllib.parse import quote, unquote # NOQA
  14. from circuits import handler, BaseComponent
  15. from circuits.web.tools import serve_file
  16. DEFAULT_DIRECTORY_INDEX_TEMPLATE = """
  17. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  18. "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  19. <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  20. <head>
  21. <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
  22. <meta http-equiv="Content-Language" content="en-us" />
  23. <meta name="robots" content="NONE,NOARCHIVE" />
  24. <title>Index of $directory</title>
  25. </head>
  26. <body>
  27. <h1>Index of $directory</h1>
  28. <ul>
  29. $url_up
  30. $listing
  31. </ul>
  32. </body>
  33. </html>
  34. """
  35. _dirlisting_template = Template(DEFAULT_DIRECTORY_INDEX_TEMPLATE)
  36. class Static(BaseComponent):
  37. channel = "web"
  38. def __init__(self, path=None, docroot=None,
  39. defaults=("index.html", "index.xhtml",), dirlisting=False):
  40. super(Static, self).__init__()
  41. self.path = path
  42. self.docroot = os.path.abspath(docroot) if docroot is not None else os.path.abspath(os.getcwd())
  43. self.defaults = defaults
  44. self.dirlisting = dirlisting
  45. @handler("request", priority=0.9)
  46. def _on_request(self, event, request, response):
  47. if self.path is not None and not request.path.startswith(self.path):
  48. return
  49. path = request.path
  50. if self.path is not None:
  51. path = path[len(self.path):]
  52. path = unquote(path.strip("/"))
  53. if path:
  54. location = os.path.abspath(os.path.join(self.docroot, path))
  55. else:
  56. location = os.path.abspath(os.path.join(self.docroot, "."))
  57. if not os.path.exists(location):
  58. return
  59. if not location.startswith(os.path.dirname(self.docroot)):
  60. return # hacking attemp e.g. /foo/../../../../../etc/shadow
  61. # Is it a file we can serve directly?
  62. if os.path.isfile(location):
  63. # Don't set cookies for static content
  64. response.cookie.clear()
  65. try:
  66. return serve_file(request, response, location)
  67. finally:
  68. event.stop()
  69. # Is it a directory?
  70. elif os.path.isdir(location):
  71. # Try to serve one of default files first..
  72. for default in self.defaults:
  73. location = os.path.abspath(
  74. os.path.join(self.docroot, path, default)
  75. )
  76. if os.path.exists(location):
  77. # Don't set cookies for static content
  78. response.cookie.clear()
  79. try:
  80. return serve_file(request, response, location)
  81. finally:
  82. event.stop()
  83. # .. serve a directory listing if allowed to.
  84. if self.dirlisting:
  85. directory = os.path.abspath(os.path.join(self.docroot, path))
  86. cur_dir = os.path.join(self.path, path) if self.path else ""
  87. if not path:
  88. url_up = ""
  89. else:
  90. if self.path is None:
  91. url_up = os.path.join("/", os.path.split(path)[0])
  92. else:
  93. url_up = os.path.join(cur_dir, "..")
  94. url_up = '<li><a href="%s">%s</a></li>' % (url_up, "..")
  95. listing = []
  96. for item in os.listdir(directory):
  97. if not item.startswith("."):
  98. url = os.path.join("/", path, cur_dir, item)
  99. location = os.path.abspath(
  100. os.path.join(self.docroot, path, item)
  101. )
  102. if os.path.isdir(location):
  103. li = '<li><a href="%s/">%s/</a></li>' % (
  104. quote(url), item
  105. )
  106. else:
  107. li = '<li><a href="%s">%s</a></li>' % (
  108. quote(url), item
  109. )
  110. listing.append(li)
  111. ctx = {}
  112. ctx["directory"] = cur_dir or os.path.join("/", cur_dir, path)
  113. ctx["url_up"] = url_up
  114. ctx["listing"] = "\n".join(listing)
  115. try:
  116. return _dirlisting_template.safe_substitute(ctx)
  117. finally:
  118. event.stop()