Extract httputils.serve_folder

This commit is contained in:
Unrud 2022-01-18 18:20:16 +01:00
parent 555e4ccc51
commit 33fcda7c32
2 changed files with 60 additions and 54 deletions

View File

@ -23,10 +23,12 @@ Helper functions for HTTP.
"""
import contextlib
import os
import time
from http import client
from typing import List, cast
from typing import List, Mapping, cast
from radicale import config, types
from radicale import config, pathutils, types
from radicale.log import logger
NOT_ALLOWED: types.WSGIResponse = (
@ -67,6 +69,22 @@ INTERNAL_SERVER_ERROR: types.WSGIResponse = (
DAV_HEADERS: str = "1, 2, 3, calendar-access, addressbook, extended-mkcol"
MIMETYPES: Mapping[str, str] = {
".css": "text/css",
".eot": "application/vnd.ms-fontobject",
".gif": "image/gif",
".html": "text/html",
".js": "application/javascript",
".manifest": "text/cache-manifest",
".png": "image/png",
".svg": "image/svg+xml",
".ttf": "application/font-sfnt",
".txt": "text/plain",
".woff": "application/font-woff",
".woff2": "font/woff2",
".xml": "text/xml"}
FALLBACK_MIMETYPE: str = "application/octet-stream"
def decode_request(configuration: "config.Configuration",
environ: types.WSGIEnviron, text: bytes) -> str:
@ -120,3 +138,38 @@ def redirect(location: str, status: int = client.FOUND) -> types.WSGIResponse:
return (status,
{"Location": location, "Content-Type": "text/plain"},
"Redirected to %s" % location)
def serve_folder(folder: str, base_prefix: str, path: str,
path_prefix: str = "/.web", index_file: str = "index.html",
mimetypes: Mapping[str, str] = MIMETYPES,
fallback_mimetype: str = FALLBACK_MIMETYPE,
) -> types.WSGIResponse:
if path != path_prefix and not path.startswith(path_prefix):
raise ValueError("path must start with path_prefix: %r --> %r" %
(path_prefix, path))
assert pathutils.sanitize_path(path) == path
try:
filesystem_path = pathutils.path_to_filesystem(
folder, path[len(path_prefix):].strip("/"))
except ValueError as e:
logger.debug("Web content with unsafe path %r requested: %s",
path, e, exc_info=True)
return NOT_FOUND
if os.path.isdir(filesystem_path) and not path.endswith("/"):
return redirect(base_prefix + path + "/")
if os.path.isdir(filesystem_path) and index_file:
filesystem_path = os.path.join(filesystem_path, index_file)
if not os.path.isfile(filesystem_path):
return NOT_FOUND
content_type = MIMETYPES.get(
os.path.splitext(filesystem_path)[1].lower(), FALLBACK_MIMETYPE)
with open(filesystem_path, "rb") as f:
answer = f.read()
last_modified = time.strftime(
"%a, %d %b %Y %H:%M:%S GMT",
time.gmtime(os.fstat(f.fileno()).st_mtime))
headers = {
"Content-Type": content_type,
"Last-Modified": last_modified}
return client.OK, headers, answer

View File

@ -25,32 +25,10 @@ Features:
"""
import os
import time
from http import client
from typing import Mapping
import pkg_resources
from radicale import config, httputils, pathutils, types, web
from radicale.log import logger
MIMETYPES: Mapping[str, str] = {
".css": "text/css",
".eot": "application/vnd.ms-fontobject",
".gif": "image/gif",
".html": "text/html",
".js": "application/javascript",
".manifest": "text/cache-manifest",
".png": "image/png",
".svg": "image/svg+xml",
".ttf": "application/font-sfnt",
".txt": "text/plain",
".woff": "application/font-woff",
".woff2": "font/woff2",
".xml": "text/xml"}
FALLBACK_MIMETYPE: str = "application/octet-stream"
from radicale import config, httputils, types, web
from radicale.httputils import FALLBACK_MIMETYPE, MIMETYPES # noqa:F401
class Web(web.BaseWeb):
@ -59,34 +37,9 @@ class Web(web.BaseWeb):
def __init__(self, configuration: config.Configuration) -> None:
super().__init__(configuration)
self.folder = pkg_resources.resource_filename(__name__,
"internal_data")
self.folder = pkg_resources.resource_filename(
__name__, "internal_data")
def get(self, environ: types.WSGIEnviron, base_prefix: str, path: str,
user: str) -> types.WSGIResponse:
assert path == "/.web" or path.startswith("/.web/")
assert pathutils.sanitize_path(path) == path
try:
filesystem_path = pathutils.path_to_filesystem(
self.folder, path[len("/.web"):].strip("/"))
except ValueError as e:
logger.debug("Web content with unsafe path %r requested: %s",
path, e, exc_info=True)
return httputils.NOT_FOUND
if os.path.isdir(filesystem_path) and not path.endswith("/"):
return httputils.redirect(base_prefix + path + "/")
if os.path.isdir(filesystem_path):
filesystem_path = os.path.join(filesystem_path, "index.html")
if not os.path.isfile(filesystem_path):
return httputils.NOT_FOUND
content_type = MIMETYPES.get(
os.path.splitext(filesystem_path)[1].lower(), FALLBACK_MIMETYPE)
with open(filesystem_path, "rb") as f:
answer = f.read()
last_modified = time.strftime(
"%a, %d %b %Y %H:%M:%S GMT",
time.gmtime(os.fstat(f.fileno()).st_mtime))
headers = {
"Content-Type": content_type,
"Last-Modified": last_modified}
return client.OK, headers, answer
return httputils.serve_folder(self.folder, base_prefix, path)