navigation: abandon assume_absolute URL madness

This commit is contained in:
dece 2021-05-15 19:06:44 +02:00
parent 2b684d7afc
commit 2b072bcc76
4 changed files with 27 additions and 46 deletions

View file

@ -150,7 +150,9 @@ class Browser:
) )
if start_url: if start_url:
self.open_url(start_url, assume_absolute=True) self.open_url(start_url)
else:
self.open_home()
while self.running: while self.running:
try: try:
@ -309,7 +311,7 @@ class Browser:
self.running = False self.running = False
return return
if command in ("o", "open"): if command in ("o", "open"):
self.open_url(words[1], assume_absolute=True) self.open_url(words[1])
elif command == "forget-certificate": elif command == "forget-certificate":
from bebop.browser.gemini import forget_certificate from bebop.browser.gemini import forget_certificate
forget_certificate(self, words[1]) forget_certificate(self, words[1])
@ -323,8 +325,8 @@ class Browser:
result = result.strip() result = result.strip()
return result return result
def open_url(self, url, base_url=None, redirects=0, assume_absolute=False, def open_url(self, url, base_url=None, redirects=0, history=True,
history=True, use_cache=False): use_cache=False):
"""Try to open an URL. """Try to open an URL.
This function assumes that the URL can be from an user and thus tries a This function assumes that the URL can be from an user and thus tries a
@ -338,7 +340,6 @@ class Browser:
- url: an URL string, may not be completely compliant. - url: an URL string, may not be completely compliant.
- base_url: an URL string to use as base in case `url` is relative. - base_url: an URL string to use as base in case `url` is relative.
- redirections: number of redirections we did yet for the same request. - redirections: number of redirections we did yet for the same request.
- assume_absolute: assume we intended to use an absolute URL if True.
- history: whether the URL should be pushed to history on success. - history: whether the URL should be pushed to history on success.
- use_cache: whether we should look for an already cached document. - use_cache: whether we should look for an already cached document.
""" """
@ -347,10 +348,7 @@ class Browser:
return return
current_scheme = self.current_scheme or "gemini" current_scheme = self.current_scheme or "gemini"
if assume_absolute or not self.current_url: parts = parse_url(url, default_scheme=current_scheme)
parts = parse_url(url, absolute=True, default_scheme=current_scheme)
else:
parts = parse_url(url, default_scheme=current_scheme)
# If there is a no netloc part, try to join the URL. # If there is a no netloc part, try to join the URL.
if ( if (
@ -358,10 +356,20 @@ class Browser:
and parts["scheme"] == current_scheme and parts["scheme"] == current_scheme
and parts["scheme"] not in NO_NETLOC_SCHEMES and parts["scheme"] not in NO_NETLOC_SCHEMES
): ):
base_url = base_url or self.current_url url_is_usable = False
# Join from either a given base URL, e.g. redirections or following
# a relative link. If there is no such reference URL, try to guess
# what the user meant to do.
if base_url: if base_url:
parts = parse_url(join_url(base_url, url)) parts = parse_url(join_url(base_url, url))
else: url_is_usable = True
elif parts["scheme"] and parts["path"]:
guessed_url = parts["scheme"] + "://" + parts["path"]
if self.prompt(f"Did you mean '{guessed_url}'?", "yn") == "y":
parts = parse_url(guessed_url)
url_is_usable = True
# If nothing could be done, just give up.
if not url_is_usable:
self.set_status_error(f"Can't open '{url}'.") self.set_status_error(f"Can't open '{url}'.")
return return
@ -429,7 +437,7 @@ class Browser:
if not link_id in links: if not link_id in links:
self.set_status_error(f"Unknown link ID {link_id}.") self.set_status_error(f"Unknown link ID {link_id}.")
return return
self.open_url(links[link_id]) self.open_url(links[link_id], base_url=self.current_url)
def handle_mouse(self, mouse_id: int, x: int, y: int, z: int, bstate: int): def handle_mouse(self, mouse_id: int, x: int, y: int, z: int, bstate: int):
"""Handle mouse events. """Handle mouse events.
@ -608,7 +616,8 @@ class Browser:
def prompt(self, text, keys): def prompt(self, text, keys):
"""Display the text and allow it to type one of the given keys.""" """Display the text and allow it to type one of the given keys."""
self.set_status(text) choice = "/".join(keys)
self.set_status(f"{text} [{choice}]")
return self.command_line.prompt_key(keys) return self.command_line.prompt_key(keys)
def open_history(self): def open_history(self):

View file

@ -330,7 +330,7 @@ def create_identity(browser: Browser, url: str):
Returns: Returns:
The created identity on success (already registered in identities The created identity on success (already registered in identities
""" """
key = browser.prompt("Create client certificate? [y/n]", "yn") key = browser.prompt("Create client certificate?", "yn")
if key != "y": if key != "y":
browser.reset_status() browser.reset_status()
return None return None
@ -357,7 +357,7 @@ def create_identity(browser: Browser, url: str):
def forget_certificate(browser: Browser, hostname: str): def forget_certificate(browser: Browser, hostname: str):
"""Remove the fingerprint associated to this hostname for the cert stash.""" """Remove the fingerprint associated to this hostname for the cert stash."""
key = browser.prompt(f"Remove fingerprint for {hostname}? [y/n]", "yn") key = browser.prompt(f"Remove fingerprint for {hostname}?", "yn")
if key != "y": if key != "y":
browser.reset_status() browser.reset_status()
return return

View file

@ -31,11 +31,7 @@ class InvalidUrlException(Exception):
self.url = url self.url = url
def parse_url( def parse_url(url: str, default_scheme: Optional[str] =None) -> Dict[str, Any]:
url: str,
absolute: bool =False,
default_scheme: Optional[str] =None
) -> Dict[str, Any]:
"""Return URL parts from this URL. """Return URL parts from this URL.
Use the RFC regex to get parts from URL. This function can be used on Use the RFC regex to get parts from URL. This function can be used on
@ -44,15 +40,8 @@ def parse_url(
Arguments: Arguments:
- url: URL to parse. - url: URL to parse.
- absolute: assume the URL is absolute, e.g. in the case we are trying to
parse an URL an user has written, which is most of the time an absolute
URL even if not perfectly so. This only has an effect if, after the
initial parsing, there is no netloc available and if there is no scheme
that is known to not have a netloc (i.e. the dummy "bebop" scheme).
- default_scheme: specify the scheme to use if the URL either does not - default_scheme: specify the scheme to use if the URL either does not
specify it and we need it (e.g. there is a location), or `absolute` is specify it and we need it (e.g. there is a location).
true; if absolute is true but `default_scheme` is not specified, a netloc
marker ("//") is prefixed without scheme.
Returns: Returns:
URL parts, as a dictionary with the following keys: "scheme", "netloc", URL parts, as a dictionary with the following keys: "scheme", "netloc",
@ -72,18 +61,7 @@ def parse_url(
for k in ("scheme", "netloc", "path", "query", "fragment") for k in ("scheme", "netloc", "path", "query", "fragment")
} }
# Smol hack: if we assume it's an absolute URL and no netloc has been found, # Smol hack: if there is no scheme, use `default_scheme` as default.
# just prefix default scheme (if any) and "//".
if (
absolute
and not parts["netloc"]
and parts["scheme"] not in NO_NETLOC_SCHEMES
):
scheme = parts["scheme"] or default_scheme
prefix = scheme + "://" if scheme else "//"
return parse_url(prefix + url)
# Another smol hack: if there is no scheme, use `default_scheme` as default.
if default_scheme and parts["scheme"] is None: if default_scheme and parts["scheme"] is None:
parts["scheme"] = default_scheme parts["scheme"] = default_scheme

View file

@ -33,12 +33,6 @@ class TestNavigation(unittest.TestCase):
self.assertIsNone(res["netloc"]) self.assertIsNone(res["netloc"])
self.assertEqual(res["path"], "dece.space/parse-me.gmi") self.assertEqual(res["path"], "dece.space/parse-me.gmi")
# No scheme nor netloc but we should pretend having an absolute URL.
res = parse_url("dece.space/parse-me.gmi", absolute=True)
self.assertIsNone(res["scheme"])
self.assertEqual(res["netloc"], "dece.space")
self.assertEqual(res["path"], "/parse-me.gmi")
# HTTPS scheme. # HTTPS scheme.
res = parse_url("https://dece.space/index.html") res = parse_url("https://dece.space/index.html")
self.assertEqual(res["scheme"], "https") self.assertEqual(res["scheme"], "https")