Repos / mcross / 550f985403
commit 550f9854030fb21ed706c53a4081b0629f96edee
Author: Bùi Thành Nhân <hi@imnhan.com>
Date:   Wed Jun 17 21:33:58 2020 +0700

    parse and correctly use mimetype+charset from meta

diff --git a/src/mcross/gui/controller.py b/src/mcross/gui/controller.py
index f65ec4a..0749068 100644
--- a/src/mcross/gui/controller.py
+++ b/src/mcross/gui/controller.py
@@ -160,9 +160,27 @@ async def load_page(self, url: GeminiUrl):
             f"{resp.status} {resp.meta} (took {request_time:.2f}s)",
         )
 
+        # Support whatever encoding that python supports
+        try:
+            body_string = resp.body.decode(resp.charset)
+        except LookupError:
+            await self.put_gui_op(
+                self.model.update_content,
+                "\n".join(
+                    [
+                        "Error:",
+                        f"{resp.status} {resp.meta}",
+                        f"Unsupported charset: {resp.charset}",
+                    ]
+                ),
+                "text/plain",
+            )
+            return resp
+
+        # Sucessfully decoded body string!
         if resp.status.startswith("2"):
             await self.put_gui_op(
-                self.model.update_content, resp.body.decode(), resp.meta
+                self.model.update_content, body_string, resp.mime_type
             )
         else:
             await self.put_gui_op(
@@ -171,7 +189,7 @@ async def load_page(self, url: GeminiUrl):
                     [
                         "Error:",
                         f"{resp.status} {resp.meta}",
-                        resp.body.decode() if resp.body else "",
+                        body_string if resp.body else "",
                     ]
                 ),
                 "text/plain",
diff --git a/src/mcross/gui/view.py b/src/mcross/gui/view.py
index f61f14a..06fdd1f 100644
--- a/src/mcross/gui/view.py
+++ b/src/mcross/gui/view.py
@@ -250,7 +250,7 @@ def render_page(self):
 
     def render_viewport(self):
         self.text.delete("1.0", "end")
-        if self.model.mime_type == "text/gemini":
+        if self.model.mime_type.startswith("text/gemini"):
             for node in self.model.gemini_nodes:
                 render_node(node, self.text)
             # delete final trailing newline:
diff --git a/src/mcross/transport.py b/src/mcross/transport.py
index 68dcaef..3eb448d 100644
--- a/src/mcross/transport.py
+++ b/src/mcross/transport.py
@@ -11,16 +11,20 @@
 
 
 class Response:
-    __slots__ = ("status", "meta", "body", "url")
+    __slots__ = ("status", "meta", "body", "url", "mime_type", "charset")
 
-    def __init__(self, status: str, meta: str, url, body: bytes = None):
+    def __init__(
+        self, status: str, meta: str, url, mime_type, charset, body: bytes = None
+    ):
         self.status = status
         self.meta = meta
         self.body = body
         self.url = url
+        self.mime_type = mime_type
+        self.charset = charset
 
     def __repr__(self):
-        return f"Response(status={repr(self.status)}, meta={repr(self.meta)})"
+        return f"Response(status={repr(self.status)}, mime_type={repr(self.mime_type)}, charset={repr(self.charset)})"
 
 
 def _parse_resp_header(header, pattern=re.compile(r"^(\d\d)\s+(.{,1024})\r\n$")):
@@ -133,7 +137,27 @@ async def raw_get(url: GeminiUrl):
                 break
 
         status, meta = _parse_resp_header(header.decode())
-        resp = Response(status=status, meta=meta, url=url)
+
+        # If success, extract mime type & charset from meta
+        mime_type = None
+        charset = None
+        if status.startswith("2"):
+            if not meta:
+                mime_type = "text/gemini"
+                charset = "utf-8"
+            else:
+                meta_parts = meta.split(";")
+                mime_type = meta_parts[0].strip() or "text/gemini"
+                charset = ""
+                if len(meta_parts) == 2:
+                    charset_part = meta_parts[1].strip()
+                    if charset_part.startswith("charset="):
+                        charset = charset_part[len("charset=") :]
+                charset = charset or "utf-8"
+
+        resp = Response(
+            status=status, meta=meta, url=url, mime_type=mime_type, charset=charset
+        )
 
         if status.startswith("2"):
             body = remainder