about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2025-05-02 17:17:40 +0200
committerbptato <nincsnevem662@gmail.com>2025-05-02 17:45:19 +0200
commite512ff078d6afda9a8712dfad793182dd19df53a (patch)
tree8220e6e7fece8d3abf763cf1cf2c1adfd3640671
parenta3ef823e8224b908a14690aa3fb2a460246e2ca8 (diff)
downloadchawan-e512ff078d6afda9a8712dfad793182dd19df53a.tar.gz
container: support Refresh header
-rw-r--r--src/local/container.nim27
-rw-r--r--src/server/buffer.nim40
-rw-r--r--src/server/headers.nim43
3 files changed, 63 insertions, 47 deletions
diff --git a/src/local/container.nim b/src/local/container.nim
index c4f20523..1b621d87 100644
--- a/src/local/container.nim
+++ b/src/local/container.nim
@@ -188,6 +188,7 @@ type
     cachedImages*: seq[CachedImage]
     luctx: LUContext
     redraw*: bool
+    refreshHeader: string
 
 jsDestructor(Highlight)
 jsDestructor(Container)
@@ -1521,14 +1522,23 @@ proc onload(container: Container; res: int) =
               container.onReadLine(res.focus)
         )
     if container.config.metaRefresh != mrNever:
-      container.iface.checkRefresh().then(proc(res: CheckRefreshResult) =
-        if res.n >= 0:
-          container.triggerEvent(ContainerEvent(
-            t: cetMetaRefresh,
-            refreshIn: res.n,
-            refreshURL: if res.url != nil: res.url else: container.url
-          ))
-      )
+      let res = parseRefresh(container.refreshHeader, container.url)
+      container.refreshHeader = ""
+      if res.n != -1:
+        container.triggerEvent(ContainerEvent(
+          t: cetMetaRefresh,
+          refreshIn: res.n,
+          refreshURL: if res.url != nil: res.url else: container.url
+        ))
+      else:
+        container.iface.checkRefresh().then(proc(res: CheckRefreshResult) =
+          if res.n >= 0:
+            container.triggerEvent(ContainerEvent(
+              t: cetMetaRefresh,
+              refreshIn: res.n,
+              refreshURL: if res.url != nil: res.url else: container.url
+            ))
+        )
   else:
     container.setLoadInfo(convertSize(res) & " loaded")
     discard container.iface.load().then(proc(res: int) =
@@ -1575,6 +1585,7 @@ proc applyResponse*(container: Container; response: Response;
     if container.charsetStack.len == 0:
       container.charsetStack.add(DefaultCharset)
   container.charset = container.charsetStack[^1]
+  container.refreshHeader = response.headers.getOrDefault("Refresh")
 
 proc remoteCancel*(container: Container) =
   if container.iface != nil:
diff --git a/src/server/buffer.nim b/src/server/buffer.nim
index c36caecf..e898ee86 100644
--- a/src/server/buffer.nim
+++ b/src/server/buffer.nim
@@ -690,12 +690,6 @@ proc gotoAnchor*(buffer: Buffer; anchor: string; autofocus, target: bool):
   let y = max(offset.y div buffer.attrs.ppl, 0).toInt
   return GotoAnchorResult(found: true, x: x, y: y, focus: focus)
 
-type CheckRefreshResult* = object
-  # n is timeout in millis. -1 => not found
-  n*: int
-  # url == nil => self
-  url*: URL
-
 proc checkRefresh*(buffer: Buffer): CheckRefreshResult {.proxy.} =
   if buffer.navigateUrl != nil:
     let url = buffer.navigateUrl
@@ -706,39 +700,7 @@ proc checkRefresh*(buffer: Buffer): CheckRefreshResult {.proxy.} =
   let element = buffer.document.findMetaRefresh()
   if element == nil:
     return CheckRefreshResult(n: -1)
-  let s = element.attr(satContent)
-  var i = s.skipBlanks(0)
-  let s0 = s.until(AllChars - AsciiDigit, i)
-  let x = parseUInt32(s0, allowSign = false)
-  if s0 != "":
-    if x.isNone and (i >= s.len or s[i] != '.'):
-      return CheckRefreshResult(n: -1)
-  var n = int(x.get(0) * 1000)
-  i = s.skipBlanks(i + s0.len)
-  if i < s.len and s[i] == '.':
-    inc i
-    let s1 = s.until(AllChars - AsciiDigit, i)
-    if s1 != "":
-      n += int(parseUInt32(s1, allowSign = false).get(0))
-      i = s.skipBlanks(i + s1.len)
-  if i >= s.len: # just reload this page
-    return CheckRefreshResult(n: n)
-  if s[i] notin {',', ';'}:
-    return CheckRefreshResult(n: -1)
-  i = s.skipBlanks(i + 1)
-  if s.toOpenArray(i, s.high).startsWithIgnoreCase("url="):
-    i = s.skipBlanks(i + "url=".len)
-  var q = false
-  if i < s.len and s[i] in {'"', '\''}:
-    q = true
-    inc i
-  var s2 = s.substr(i)
-  if q and s2.len > 0 and s[^1] in {'"', '\''}:
-    s2.setLen(s2.high)
-  let url = buffer.document.parseURL(s2)
-  if url.isNone:
-    return CheckRefreshResult(n: -1)
-  return CheckRefreshResult(n: n, url: url.get)
+  return parseRefresh(element.attr(satContent), buffer.url)
 
 proc hasTask(buffer: Buffer; cmd: BufferCommand): bool =
   return buffer.tasks[cmd] != 0
diff --git a/src/server/headers.nim b/src/server/headers.nim
index 48959e07..c6fa0566 100644
--- a/src/server/headers.nim
+++ b/src/server/headers.nim
@@ -7,6 +7,7 @@ import monoucha/jserror
 import monoucha/quickjs
 import monoucha/tojs
 import types/opt
+import types/url
 import utils/twtstr
 
 type
@@ -302,5 +303,47 @@ func getAllNoComma*(headers: Headers; k: string): seq[string] =
     return p[]
   return @[]
 
+type CheckRefreshResult* = object
+  # n is timeout in millis. -1 => not found
+  n*: int
+  # url == nil => self
+  url*: URL
+
+func parseRefresh*(s: string; baseURL: URL): CheckRefreshResult =
+  var i = s.skipBlanks(0)
+  let s0 = s.until(AllChars - AsciiDigit, i)
+  let x = parseUInt32(s0, allowSign = false)
+  if s0 != "":
+    if x.isNone and (i >= s.len or s[i] != '.'):
+      return CheckRefreshResult(n: -1)
+  var n = int(x.get(0) * 1000)
+  i = s.skipBlanks(i + s0.len)
+  if i < s.len and s[i] == '.':
+    inc i
+    let s1 = s.until(AllChars - AsciiDigit, i)
+    if s1 != "":
+      n += int(parseUInt32(s1, allowSign = false).get(0))
+      i = s.skipBlanks(i + s1.len)
+  elif s0 == "": # empty string or blanks
+    return CheckRefreshResult(n: -1)
+  if i >= s.len: # just reload this page
+    return CheckRefreshResult(n: n)
+  if s[i] notin {',', ';'}:
+    return CheckRefreshResult(n: -1)
+  i = s.skipBlanks(i + 1)
+  if s.toOpenArray(i, s.high).startsWithIgnoreCase("url="):
+    i = s.skipBlanks(i + "url=".len)
+  var q = false
+  if i < s.len and s[i] in {'"', '\''}:
+    q = true
+    inc i
+  var s2 = s.substr(i)
+  if q and s2.len > 0 and s[^1] in {'"', '\''}:
+    s2.setLen(s2.high)
+  let url = parseURL(s2, some(baseURL))
+  if url.isNone:
+    return CheckRefreshResult(n: -1)
+  return CheckRefreshResult(n: n, url: url.get)
+
 proc addHeadersModule*(ctx: JSContext) =
   ctx.registerType(Headers)