navigation: abandon assume_absolute URL madness
This commit is contained in:
parent
2b684d7afc
commit
2b072bcc76
|
@ -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):
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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")
|
||||||
|
|
Reference in a new issue