Repos / mcross / a6bca3328c
commit a6bca3328c4d18cb7d42ee7b1f9a9f152d0ff8e8
Author: Bùi Thành Nhân <hi@imnhan.com>
Date: Sat May 16 15:59:33 2020 +0700
follow redirects, max 3 times
diff --git a/README.md b/README.md
index 07fd1c3..b50a3ff 100644
--- a/README.md
+++ b/README.md
@@ -48,7 +48,7 @@ # to publish, first bump version in pyproject.toml then
# Feature checklist
- [x] back-forward buttons
-- [ ] handle redirects
+- [x] handle redirects
- [ ] separate I/O thread to avoid blocking GUI
- [ ] more visual indicators - maybe a status bar at the bottom
- [x] parse gemini's advanced line types
@@ -61,7 +61,7 @@ # Feature checklist
## Easy for end users to install
-If the word `rustup` exists in the installation guide for your G U I
+If the words `cargo build` exists in the installation guide for your G U I
application then I'm sorry it's not software made for people to _use_.
## What-you-see-is-what-you-write
diff --git a/pyproject.toml b/pyproject.toml
index 9efa363..2d80b51 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[tool.poetry]
name = "mcross"
-version = "0.4.1"
+version = "0.4.2"
description = "Do you remember www?"
authors = ["nhanb <hi@imnhan.com>"]
license = "MIT"
diff --git a/src/mcross/gui/controller.py b/src/mcross/gui/controller.py
index 672e8fd..6bcaefb 100644
--- a/src/mcross/gui/controller.py
+++ b/src/mcross/gui/controller.py
@@ -53,8 +53,8 @@ def link_click_callback(self, raw_url):
)
def visit_link(self, url: GeminiUrl):
- self.load_page(url)
- self.model.history.visit(url)
+ resp = self.load_page(url)
+ self.model.history.visit(resp.url)
self.view.render_page()
def back_callback(self):
@@ -84,3 +84,4 @@ def load_page(self, url: GeminiUrl):
]
)
)
+ return resp
diff --git a/src/mcross/transport.py b/src/mcross/transport.py
index 10e4ff0..0a74c05 100644
--- a/src/mcross/transport.py
+++ b/src/mcross/transport.py
@@ -5,6 +5,7 @@
MAX_RESP_HEADER_BYTES = 2 + 1 + 1024 + 2 # <STATUS><whitespace><META><CR><LF>
MAX_RESP_BODY_BYTES = 1024 * 1024 * 5
+MAX_REDIRECTS = 3
# Wanted to use a dataclass here but ofc it doesn't allow a slotted class to
@@ -12,12 +13,13 @@
# https://stackoverflow.com/questions/50180735/how-can-dataclasses-be-made-to-work-better-with-slots
# Maaaaybe I should just use attrs and call it a day.
class Response:
- __slots__ = ("status", "meta", "body")
+ __slots__ = ("status", "meta", "body", "url")
- def __init__(self, status: str, meta: str, body: bytes = None):
+ def __init__(self, status: str, meta: str, url, body: bytes = None):
self.status = status
self.meta = meta
self.body = body
+ self.url = url
def __repr__(self):
return f"Response(status={repr(self.status)}, meta={repr(self.meta)})"
@@ -106,16 +108,26 @@ def parse_absolute_url(text):
return GeminiUrl(parsed.hostname, parsed.port or 1965, parsed.path)
-def get(url: GeminiUrl):
+def raw_get(url: GeminiUrl):
context = ssl.create_default_context()
with socket.create_connection((url.host, url.port)) as sock:
with context.wrap_socket(sock, server_hostname=url.host) as ssock:
ssock.send(f"gemini://{url.host}{url.path}\r\n".encode())
header = ssock.recv(MAX_RESP_HEADER_BYTES).decode()
status, meta = _parse_resp_header(header)
- resp = Response(status=status, meta=meta)
+ resp = Response(status=status, meta=meta, url=url)
if status.startswith("2"):
resp.body = ssock.recv(MAX_RESP_BODY_BYTES)
return resp
+
+
+def get(url: GeminiUrl, redirect_count=0):
+ resp = raw_get(url)
+ if resp.status.startswith("3") and redirect_count < MAX_REDIRECTS:
+ redirect_count += 1
+ new_url = GeminiUrl.parse_absolute_url(resp.meta)
+ print(f"Redirecting to {new_url}, count={redirect_count}")
+ return get(new_url, redirect_count)
+ return resp