diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b0c1a5..207baa0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Jetforce Changelog +### v0.3.2 + +#### Bugfixes + +- The static file server will now URL-encode spaces (%20) and other reserved + characters in filenames. +- The ``Request`` class will now apply URL decoding to the following components + of the request, in addition to the query params: + - ``request.path`` + - ``request.params`` + - ``request.fragment`` + ### v0.3.1 #### Bugfixes diff --git a/jetforce/app/base.py b/jetforce/app/base.py index 1b25fed..a1bac69 100644 --- a/jetforce/app/base.py +++ b/jetforce/app/base.py @@ -2,7 +2,7 @@ import argparse import dataclasses import re import typing -import urllib.parse +from urllib.parse import unquote, urlparse from twisted.internet.defer import Deferred @@ -51,7 +51,7 @@ class Request: self.environ = environ self.url = environ["GEMINI_URL"] - url_parts = urllib.parse.urlparse(self.url) + url_parts = urlparse(self.url) if not url_parts.hostname: raise ValueError("URL must contain a `hostname` part") @@ -63,10 +63,11 @@ class Request: self.hostname = url_parts.hostname self.port = url_parts.port - self.path = url_parts.path - self.params = url_parts.params - self.query = urllib.parse.unquote(url_parts.query) - self.fragment = url_parts.fragment + + self.path = unquote(url_parts.path) + self.params = unquote(url_parts.params) + self.query = unquote(url_parts.query) + self.fragment = unquote(url_parts.fragment) @dataclasses.dataclass diff --git a/jetforce/app/static.py b/jetforce/app/static.py index 891c4a8..a704ddf 100644 --- a/jetforce/app/static.py +++ b/jetforce/app/static.py @@ -174,10 +174,12 @@ class StaticDirectoryApplication(JetforceApplication): if file.name.startswith("."): # Skip hidden directories/files that may contain sensitive info continue - elif file.is_dir(): - yield f"=>/{url_path / file.name}/\t{file.name}/\r\n".encode() + + encoded_path = urllib.parse.quote(str(url_path / file.name)) + if file.is_dir(): + yield f"=>/{encoded_path}/\t{file.name}/\r\n".encode() else: - yield f"=>/{url_path / file.name}\t{file.name}\r\n".encode() + yield f"=>/{encoded_path}\t{file.name}\r\n".encode() def guess_mimetype(self, filename: str) -> str: """