internal.py 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. # This file is part of Radicale Server - Calendar Server
  2. # Copyright © 2017-2018 Unrud <unrud@outlook.com>
  3. #
  4. # This library is free software: you can redistribute it and/or modify
  5. # it under the terms of the GNU General Public License as published by
  6. # the Free Software Foundation, either version 3 of the License, or
  7. # (at your option) any later version.
  8. #
  9. # This library is distributed in the hope that it will be useful,
  10. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. # GNU General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU General Public License
  15. # along with Radicale. If not, see <http://www.gnu.org/licenses/>.
  16. import os
  17. import posixpath
  18. import time
  19. from http import client
  20. import pkg_resources
  21. from radicale import httputils, pathutils, web
  22. from radicale.log import logger
  23. MIMETYPES = {
  24. ".css": "text/css",
  25. ".eot": "application/vnd.ms-fontobject",
  26. ".gif": "image/gif",
  27. ".html": "text/html",
  28. ".js": "application/javascript",
  29. ".manifest": "text/cache-manifest",
  30. ".png": "image/png",
  31. ".svg": "image/svg+xml",
  32. ".ttf": "application/font-sfnt",
  33. ".txt": "text/plain",
  34. ".woff": "application/font-woff",
  35. ".woff2": "font/woff2",
  36. ".xml": "text/xml"}
  37. FALLBACK_MIMETYPE = "application/octet-stream"
  38. class Web(web.BaseWeb):
  39. def __init__(self, configuration):
  40. super().__init__(configuration)
  41. self.folder = pkg_resources.resource_filename(__name__,
  42. "internal_data")
  43. def get(self, environ, base_prefix, path, user):
  44. try:
  45. filesystem_path = pathutils.path_to_filesystem(
  46. self.folder, path[len("/.web"):])
  47. except ValueError as e:
  48. logger.debug("Web content with unsafe path %r requested: %s",
  49. path, e, exc_info=True)
  50. return httputils.NOT_FOUND
  51. if os.path.isdir(filesystem_path) and not path.endswith("/"):
  52. location = posixpath.basename(path) + "/"
  53. return (client.FOUND,
  54. {"Location": location, "Content-Type": "text/plain"},
  55. "Redirected to %s" % location)
  56. if os.path.isdir(filesystem_path):
  57. filesystem_path = os.path.join(filesystem_path, "index.html")
  58. if not os.path.isfile(filesystem_path):
  59. return httputils.NOT_FOUND
  60. content_type = MIMETYPES.get(
  61. os.path.splitext(filesystem_path)[1].lower(), FALLBACK_MIMETYPE)
  62. with open(filesystem_path, "rb") as f:
  63. answer = f.read()
  64. last_modified = time.strftime(
  65. "%a, %d %b %Y %H:%M:%S GMT",
  66. time.gmtime(os.fstat(f.fileno()).st_mtime))
  67. headers = {
  68. "Content-Type": content_type,
  69. "Last-Modified": last_modified}
  70. return client.OK, headers, answer