diff --git a/browser.py b/browser.py index 99a8a4c..bc30069 100644 --- a/browser.py +++ b/browser.py @@ -8,6 +8,7 @@ SUPPORTED_SCHEMES = [ "http", "https", "file", + "data" ] DEFAULT_FILE = "default.html" @@ -22,6 +23,9 @@ class URL: self.query: str = "" self.fragment: str = "" self.default_port = False + self.media_type = "" + self.media_encoding = "" + self.data = "" if url_string is not None: parse_url(url_string, self) @@ -75,10 +79,13 @@ class Request: self.request_string += "\r\n" def send_request(self, *args, **kwargs): - if self.url.scheme in ["http", "https"]: - return self.http_request(*args, **kwargs) - elif self.url.scheme == "file": - return self.file_request() + if hasattr(self, f"{self.url.scheme.lower()}_request"): + request = getattr(self, f"{self.url.scheme.lower()}_request") + return request(*args, **kwargs) + raise ValueError(f"scheme '{self.url.scheme}' is not supported.") + + def https_request(self, *args, **kwargs): + return self.http_request(*args, **kwargs) def http_request(self, method: str = "GET", headers: dict = None) -> str: if headers is not None: @@ -121,6 +128,9 @@ class Request: with open(self.url.path) as f: return f.read() + def data_request(self): + return self.url.data + def parse_url(url_string: str, url: URL | None = None) -> tuple[URL, bool]: has_authority = False @@ -164,26 +174,29 @@ def parse_url(url_string: str, url: URL | None = None) -> tuple[URL, bool]: if url_string.startswith("#"): url.fragment = url_string[1:] - if url.scheme == "http": - url.port = 80 - url.default_port = True - elif url.scheme == "https": - url.port = 443 - url.default_port = False + match url.scheme: + case "http": + url.port = 80 + url.default_port = True + case "https": + url.port = 443 + url.default_port = False + case "file": + if sys.platform == "win32" and url.path.startswith("/") and ":" in url.path: + url.path = url.path[1:] + if url.path == "" or url.path == "/": + return url, False + case "data": + if url.host != "": + return url, False + url.media_type, url.data = url.path.split(",", 1) + if ";" in url.media_type: + url.media_type, url.media_encoding = url.media_type.split(";", 1) + if url.scheme in ["http", "https"]: if url.path == "" or url.path is None: url.path = "/" - if url.scheme == "file": - print(f"{url.scheme=}") - print(f"{url.host=}") - print(f"{url.port=}") - print(f"{url.path=}") - print(f"{url.query=}") - print(f"{url.fragment=}") - if sys.platform == "win32" and url.path.startswith("/") and ":" in url.path: - url.path = url.path[1:] - if url.path == "" or url.path == "/": - return url, False + if ":" in url.host: url.host, port = url.host.split(":", 1) diff --git a/tests/url_test.py b/tests/url_test.py index dd7a508..0117454 100644 --- a/tests/url_test.py +++ b/tests/url_test.py @@ -147,6 +147,16 @@ from browser import Request "", True, ), + ( + "data:text,This is some text", + "data", + "", + -1, + "text,This is some text", + "", + "", + True, + ), ], ) def test_url_parsing(url_string, scheme, host, port, path, query, fragment, parse_success): @@ -160,6 +170,40 @@ def test_url_parsing(url_string, scheme, host, port, path, query, fragment, pars assert success == parse_success +@pytest.mark.parametrize( + "url_string,media_type,media_encoding,data,parse_success", + [ + ( + "data:text,This is some text", + "text", + "", + "This is some text", + True, + ), + ( + "data:text/plain,This is some text", + "text/plain", + "", + "This is some text", + True, + ), + ( + "data:text/plain;base64,This is some text", + "text/plain", + "base64", + "This is some text", + True, + ), + ], +) +def test_data_url_parsing(url_string, media_type, media_encoding, data, parse_success): + url, success = parse_url(url_string) + assert url.media_type == media_type + assert url.media_encoding == media_encoding + assert url.data == data + assert success == parse_success + + @pytest.mark.parametrize( "http_server,url_string", [