about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2023-07-04 12:25:40 +0200
committerbptato <nincsnevem662@gmail.com>2023-07-04 12:25:56 +0200
commitb96d8cc51a7f469eaa5804c24a8b45cc4d5b3756 (patch)
tree0d1deb5281e233d6627a4cfde91732c34adbbc05
parente961b086d263022c3486a4742d1ab29331212c62 (diff)
downloadchawan-b96d8cc51a7f469eaa5804c24a8b45cc4d5b3756.tar.gz
Add proxy support
-rw-r--r--doc/config.md13
-rw-r--r--src/config/config.nim24
-rw-r--r--src/display/client.nim6
-rw-r--r--src/display/pager.nim41
-rw-r--r--src/io/loader.nim6
-rw-r--r--src/ips/forkserver.nim12
-rw-r--r--todo1
7 files changed, 77 insertions, 26 deletions
diff --git a/doc/config.md b/doc/config.md
index 2316ff6e..6662d1be 100644
--- a/doc/config.md
+++ b/doc/config.md
@@ -184,6 +184,13 @@ Network options are to be placed in the `[network]` section.
 https (e.g. wikipedia.org as https://wikipedia.org.)</td>
 </tr>
 
+<tr>
+<td>proxy</td>
+<td>URL</td>
+<td>Specify a proxy for all network requests Chawan makes. All proxies
+supported by cURL may be used. Can be overridden by siteconf.</td>
+</tr>
+
 </table>
 
 ## Display
@@ -433,6 +440,12 @@ siteconfs) are not overridden. (In other words, they will be concatenated
 with this stylesheet to get the final user stylesheet.)</td>
 </tr>
 
+<tr>
+<td>proxy</td>
+<td>URL</td>
+<td>Specify a proxy for network requests fetching contents of this buffer.</td>
+</tr>
+
 
 </table>
 
diff --git a/src/config/config.nim b/src/config/config.nim
index 1bfacd28..b546ce3c 100644
--- a/src/config/config.nim
+++ b/src/config/config.nim
@@ -37,6 +37,7 @@ type
     document_charset: seq[Charset]
     images: Opt[bool]
     stylesheet: Opt[string]
+    proxy: Opt[string]
 
   StaticOmniRule = object
     match: string
@@ -54,6 +55,7 @@ type
     document_charset*: seq[Charset]
     images*: Opt[bool]
     stylesheet*: Opt[string]
+    proxy*: Opt[URL]
 
   OmniRule* = object
     match*: Regex
@@ -81,6 +83,7 @@ type
   NetworkConfig = object
     max_redirect*: int32
     prepend_https*: bool
+    proxy*: Opt[string]
 
   DisplayConfig = object
     color_mode*: Opt[ColorMode]
@@ -120,6 +123,7 @@ type
     scripting*: bool
     charsets*: seq[Charset]
     images*: bool
+    proxy*: URL
 
   ForkServerConfig* = object
     tmpdir*: string
@@ -141,9 +145,19 @@ func getForkServerConfig*(config: Config): ForkServerConfig =
     ambiguous_double: config.display.double_width_ambiguous
   )
 
+func getProxy*(config: Config): URL =
+  if config.network.proxy.isSome:
+    let s = config.network.proxy.get
+    let x = parseURL(s)
+    if x.isSome:
+      return x.get
+    else:
+      raise newException(Defect, "Invalid proxy URL: " & s)
+  return nil
+
 proc getBufferConfig*(config: Config, location: URL, cookiejar: CookieJar,
     headers: Headers, referer_from, scripting: bool, charsets: seq[Charset],
-    images: bool, userstyle: string): BufferConfig =
+    images: bool, userstyle: string, proxy: URL): BufferConfig =
   result = BufferConfig(
     userstyle: userstyle,
     filter: newURLFilter(scheme = some(location.scheme), default = true),
@@ -152,7 +166,8 @@ proc getBufferConfig*(config: Config, location: URL, cookiejar: CookieJar,
     referer_from: referer_from,
     scripting: scripting,
     charsets: charsets,
-    images: images
+    images: images,
+    proxy: proxy
   )
   new(result.headers)
   result.headers[] = DefaultHeaders
@@ -177,6 +192,11 @@ proc getSiteConfig*(config: Config, jsctx: JSContext): seq[SiteConfig] =
       let fun = jsctx.eval(sc.rewrite_url.get, "<siteconf>",
         JS_EVAL_TYPE_GLOBAL)
       conf.rewrite_url = getJSFunction[URL, URL](jsctx, fun)
+    if sc.proxy.isSome:
+      let x = parseURL(sc.proxy.get)
+      if x.isNone:
+        raise newException(Defect, "invalid URL: " & sc.proxy.get)
+      conf.proxy = opt(x.get)
     result.add(conf)
 
 proc getOmniRules*(config: Config, jsctx: JSContext): seq[OmniRule] =
diff --git a/src/display/client.nim b/src/display/client.nim
index 5134f130..f7e89b78 100644
--- a/src/display/client.nim
+++ b/src/display/client.nim
@@ -566,7 +566,11 @@ proc newClient*(config: Config, dispatcher: Dispatcher): Client =
   result.config = config
   result.dispatcher = dispatcher
   result.attrs = getWindowAttributes(stdout)
-  result.loader = dispatcher.forkserver.newFileLoader()
+  let forkserver = dispatcher.forkserver
+  result.loader = forkserver.newFileLoader(
+    proxy = config.getProxy(),
+    acceptProxy = true
+  )
   result.jsrt = newJSRuntime()
   result.jsrt.setInterruptHandler(interruptHandler, cast[pointer](result))
   JS_SetModuleLoaderFunc(result.jsrt, normalizeModuleName, clientLoadJSModule,
diff --git a/src/display/pager.nim b/src/display/pager.nim
index c8d0b83e..2698550c 100644
--- a/src/display/pager.nim
+++ b/src/display/pager.nim
@@ -39,34 +39,35 @@ type
     SEARCH_B, ISEARCH_F, ISEARCH_B, GOTO_LINE
 
   Pager* = ref object
+    alerton: bool
+    alerts: seq[string]
+    askcursor: int
     askpromise*: Promise[bool]
     askprompt: string
-    askcursor: int
-    numload*: int
-    alerts: seq[string]
-    alerton: bool
     commandMode* {.jsget.}: bool
+    config: Config
     container*: Container
+    cookiejars: Table[string, CookieJar]
     dispatcher*: Dispatcher
+    display: FixedGrid
+    iregex: Result[Regex, string]
     lineedit*: Option[LineEdit]
+    linehist: array[LineMode, LineHistory]
     linemode*: LineMode
-    username: string
-    scommand*: string
-    config: Config
+    numload*: int
+    omnirules: seq[OmniRule]
+    procmap*: Table[Pid, Container]
+    proxy: URL
+    redraw*: bool
     regex: Opt[Regex]
-    iregex: Result[Regex, string]
     reverseSearch: bool
+    scommand*: string
+    siteconf: seq[SiteConfig]
     statusgrid*: FixedGrid
+    term*: Terminal
     tty: File
-    procmap*: Table[Pid, Container]
     unreg*: seq[(Pid, SocketStream)]
-    display: FixedGrid
-    redraw*: bool
-    term*: Terminal
-    linehist: array[LineMode, LineHistory]
-    siteconf: seq[SiteConfig]
-    omnirules: seq[OmniRule]
-    cookiejars: Table[string, CookieJar]
+    username: string
 
 jsDestructor(Pager)
 
@@ -181,7 +182,8 @@ proc newPager*(config: Config, attrs: WindowAttributes,
     statusgrid: newFixedGrid(attrs.width),
     term: newTerminal(stdout, config, attrs),
     siteconf: config.getSiteConfig(ctx),
-    omnirules: config.getOmniRules(ctx)
+    omnirules: config.getOmniRules(ctx),
+    proxy: config.getProxy()
   )
   return pager
 
@@ -576,6 +578,7 @@ proc applySiteconf(pager: Pager, url: var URL): BufferConfig =
   var images: bool
   var charsets = pager.config.encoding.document_charset
   var userstyle = pager.config.css.stylesheet
+  var proxy = pager.proxy
   for sc in pager.siteconf:
     if sc.url.isSome and not sc.url.get.match($url):
       continue
@@ -606,8 +609,10 @@ proc applySiteconf(pager: Pager, url: var URL): BufferConfig =
     if sc.stylesheet.isSome:
       userstyle &= "\n"
       userstyle &= sc.stylesheet.get
+    if sc.proxy.isSome:
+      proxy = sc.proxy.get
   return pager.config.getBufferConfig(url, cookiejar, headers,
-    referer_from, scripting, charsets, images, userstyle)
+    referer_from, scripting, charsets, images, userstyle, proxy)
 
 # Load request in a new buffer.
 proc gotoURL(pager: Pager, request: Request, prevurl = none(URL),
diff --git a/src/io/loader.nim b/src/io/loader.nim
index 6583ce2c..46f694e6 100644
--- a/src/io/loader.nim
+++ b/src/io/loader.nim
@@ -84,6 +84,10 @@ type
     filter*: URLFilter
     cookiejar*: CookieJar
     referrerpolicy*: ReferrerPolicy
+    proxy*: URL
+    # When set to false, requests with a proxy URL are overridden by the
+    # loader proxy.
+    acceptProxy*: bool
 
   FetchPromise* = Promise[Result[Response, JSError]]
 
@@ -132,6 +136,8 @@ proc onLoad(ctx: LoaderContext, stream: Stream) =
       let r = getReferer(request.referer, request.url, ctx.config.referrerpolicy)
       if r != "":
         request.headers["Referer"] = r
+    if request.proxy == nil or not ctx.config.acceptProxy:
+      request.proxy = ctx.config.proxy
     ctx.loadResource(request, stream)
 
 proc acceptConnection(ctx: LoaderContext) =
diff --git a/src/ips/forkserver.nim b/src/ips/forkserver.nim
index e2e825c1..62d41198 100644
--- a/src/ips/forkserver.nim
+++ b/src/ips/forkserver.nim
@@ -15,6 +15,7 @@ import ips/serialize
 import ips/serversocket
 import types/buffersource
 import types/cookie
+import types/url
 import utils/twtstr
 
 type
@@ -33,8 +34,8 @@ type
     children: seq[(Pid, Pid)]
 
 proc newFileLoader*(forkserver: ForkServer, defaultHeaders: Headers = nil,
-    filter = newURLFilter(default = true),
-    cookiejar: CookieJar = nil): FileLoader =
+    filter = newURLFilter(default = true), cookiejar: CookieJar = nil,
+    proxy: URL = nil, acceptProxy = false): FileLoader =
   new(result)
   forkserver.ostream.swrite(FORK_LOADER)
   var defaultHeaders = defaultHeaders
@@ -44,7 +45,9 @@ proc newFileLoader*(forkserver: ForkServer, defaultHeaders: Headers = nil,
   let config = LoaderConfig(
     defaultHeaders: defaultHeaders,
     filter: filter,
-    cookiejar: cookiejar
+    cookiejar: cookiejar,
+    proxy: proxy,
+    acceptProxy: acceptProxy
   )
   forkserver.ostream.swrite(config)
   forkserver.ostream.flush()
@@ -113,7 +116,8 @@ proc forkBuffer(ctx: var ForkServerContext): Pid =
       defaultHeaders: config.headers,
       filter: config.filter,
       cookiejar: config.cookiejar,
-      referrerpolicy: config.referrerpolicy
+      referrerpolicy: config.referrerpolicy,
+      proxy: config.proxy
     )
   )
   let pid = fork()
diff --git a/todo b/todo
index f7644770..c23e689c 100644
--- a/todo
+++ b/todo
@@ -50,7 +50,6 @@ network:
 - gopher
 - gemini? (not a fan, but quite a bit of interesting content is on gemini)
 - uBO integration? (or at least implement filter lists)
-- socks/http proxies (just settings needed...)
 - websockets (curl supports ws)
 - integrate curl-impersonate (LD_PRELOAD works, but still...)
 external: