10 Commits

Author SHA1 Message Date
Antoni Sawicki
9b53a6e757 update modules 2026-06-05 03:06:50 -07:00
Antoni Sawicki
42bba02a73 mod update 2026-04-23 11:43:06 -07:00
Antoni Sawicki
892758140d fix go vet 2026-04-23 11:42:01 -07:00
Antoni Sawicki
bd0c2d974c auto detect browser 2026-04-23 11:40:57 -07:00
Antoni Sawicki
7b9ffea57f support downloads in proxy mode 2026-04-21 21:43:22 -07:00
Antoni Sawicki
ef1c4c0760 update dependencies 2026-04-21 21:24:53 -07:00
Antoni Sawicki
78efc3210d add download support 2026-04-21 21:24:22 -07:00
Antoni Sawicki
6b372aca23 update readme 2026-03-18 01:44:32 -07:00
Antoni Sawicki
9d21aa5ce1 update readme 2026-03-18 01:38:35 -07:00
Antoni Sawicki
365a786a42 move screenshot 2026-03-18 01:27:20 -07:00
7 changed files with 325 additions and 47 deletions

View File

@@ -2,23 +2,25 @@
A browser-in-browser proxy server that allows to use historical / vintage web browsers on the modern web.
![Internet Explorer 1.5 doing Gmail](wrp.png)
## Modes of operation
### Access
### Access Types
- Browser in browser, navigate to the address of WRP and use built-in web form to naviate.
- HTTP proxy mode which offers more seamless, but also limited use.
- Browser-in-browser, navigate to the address of WRP and use the built-in web form to browse web.
- HTTP proxy mode which offers more seamless, but also limited use. Semi compatible with https://.
### Rende modes
- ISMAP "graphical" mode, renders web page in to a GIF/PNG/JPG image with clickable imagemap.
- Simple HTML mode converts pages into simplified HTML for old browsers.
![Internet Explorer 1.5 doing Gmail](wrp.png)
Different modes have different uses. ISMAP mode will be better for flashy modern web. Simple HTML mode will be better for reading articles or documentation.
## Usage Instructions
* [Download a WRP binary](https://github.com/tenox7/wrp/releases/) run it on a machine that will become your WRP gateway/server. This should be modern hardware and OS. Google Chrome / Chromium Browser is required to be preinstalled. Do not try to run WRP on an old machine like Windows XP or 98.
* [Download a WRP binary](https://github.com/tenox7/wrp/releases/) run it on a machine that will become your WRP gateway/server. This should be modern hardware and OS. Google Chrome / Chromium / Brave Browser is required to be preinstalled. Do not run WRP on an old machine like Windows XP or 98.
* Make sure you have disabled firewall or open port WRP is listening on (by default 8080).
* Point your legacy browser to `http://address:port` of the WRP server or set your proxy address there.
* Type a search string or a full http/https URL and click **Go**.
@@ -26,9 +28,9 @@ A browser-in-browser proxy server that allows to use historical / vintage web br
### Proxy mode
- Try to use http:// addresses only, the proxy will automatically rewrite them to https as needed.
- https:// addresses are limited in functionality (no /suffix or path).
- You can use `/proxy.pac` automatic configuration mode.
- Stick to `http://` addresses only, the proxy will automatically rewrite them to `https://` as needed.
- `https://` addresses are limited in functionality (no /suffix or paths).
- Proxy mode doesn't have a customizable web interface with html forms. All configuration is done via flags.
### Image Map Mode
@@ -40,9 +42,9 @@ A browser-in-browser proxy server that allows to use historical / vintage web br
* You can re-capture screenshot without reloading page by using **St** (Stop). This is useful if page didn't render fully before screenshot is taken.
* You can also reload page and re-capture screenshot with **Re** (Reload).
* To send keystrokes, fill **K** input box and press **Go**. There also are buttons for backspace, enter and arrow keys.
* The default image type GIP is a ultra fast, optimized, parallel encoded GIF type.
* If your browser supports it, prefer PNG over GIF/JPG. PNG is much faster, whereas GIF/JPG requires a lot of additional processing on both client and server to encode/decode.
* GIF images are by default encoded with 216 colors, "web safe" palette. This uses an ultra fast but not very accurate color mapping algorithm. If you want better color representation switch to 256 color mode.
* The default image type is `GIP` - an ultra fast, optimized, parallel encoded GIF type.
* If your browser supports it, prefer PNG over GIF/JPG. PNG is much faster, whereas GIF/JPG requires a lot of additional processing on both client and server to compress/uncompress.
* GIF images are by default encoded with 216 colors, "web safe" palette. This uses an ultra fast encoding algorithm optimized mostly for text. Images have rather wonky color colors. If you want better color representation switch to 256 color mode.
### Simple HTML mode
@@ -183,8 +185,7 @@ Click `st` to re-capture screenshot. You may want to increase the page delay usi
### Websites are blocking headless browsers
This is a well known issue. WRP has some provisions to work around it, but it's a cat and mouse game. By default WRP tries to obtain some current valid User Agent
from https://github.com/jnrbsn/user-agents rather than using the internal "HeadlessChrome". You can override this to your own, for example:
This is a well known issue. WRP has some provisions to work around it, but it's a cat and mouse game. By default WRP tries to obtain some current valid User Agent from https://github.com/jnrbsn/user-agents rather than using the internal "HeadlessChrome". You can override this to your own, for example:
```shell
$ wrp -ua="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36"
@@ -229,6 +230,7 @@ You may also be interested in:
* [VncFox](https://github.com/tenox7/vncfox)
* [webone](https://github.com/atauenis/webone)
* [Pici Server](https://github.com/picidae-project/pici-server)
* [Browservice](https://github.com/ttalvitie/browservice)
* [Browsh](https://github.com/browsh-org/browsh)

167
download.go Normal file
View File

@@ -0,0 +1,167 @@
package main
import (
"fmt"
"log"
"net/http"
"os"
"path/filepath"
"strconv"
"strings"
"sync"
"time"
"github.com/chromedp/cdproto/browser"
"github.com/chromedp/chromedp"
"github.com/lithammer/shortuuid/v4"
)
var (
dlDir string
dlNotify = make(chan struct{}, 1)
)
type dlEvent struct {
guid string
filename string
done chan struct{}
}
var dlTrack struct {
sync.Mutex
ev *dlEvent
}
type dlFile struct {
name string
data []byte
}
var dlCache struct {
sync.Mutex
files map[string]dlFile
}
func setupDownloads() {
if dlDir == "" {
var err error
dlDir, err = os.MkdirTemp("", "wrp-dl-")
if err != nil {
log.Fatalf("Failed to create download dir: %v", err)
}
dlCache.files = make(map[string]dlFile)
}
chromedp.ListenTarget(ctx, func(ev interface{}) {
switch e := ev.(type) {
case *browser.EventDownloadWillBegin:
log.Printf("Download started: %s (%s)", e.SuggestedFilename, e.GUID)
dlTrack.Lock()
dlTrack.ev = &dlEvent{
guid: e.GUID,
filename: e.SuggestedFilename,
done: make(chan struct{}),
}
dlTrack.Unlock()
select {
case dlNotify <- struct{}{}:
default:
}
case *browser.EventDownloadProgress:
dlTrack.Lock()
ev := dlTrack.ev
dlTrack.Unlock()
if ev == nil || ev.guid != e.GUID {
return
}
if e.State == browser.DownloadProgressStateCompleted || e.State == browser.DownloadProgressStateCanceled {
log.Printf("Download %s: %s", e.State, e.GUID)
close(ev.done)
}
}
})
err := chromedp.Run(ctx,
browser.SetDownloadBehavior(browser.SetDownloadBehaviorBehaviorAllowAndName).
WithDownloadPath(dlDir).
WithEventsEnabled(true),
)
if err != nil {
log.Printf("Warning: failed to set download behavior: %v", err)
}
}
func resetDownloadState() {
dlTrack.Lock()
dlTrack.ev = nil
dlTrack.Unlock()
select {
case <-dlNotify:
default:
}
}
func waitForDownload() *dlFile {
select {
case <-dlNotify:
case <-time.After(500 * time.Millisecond):
return nil
}
dlTrack.Lock()
ev := dlTrack.ev
dlTrack.Unlock()
if ev == nil {
return nil
}
log.Printf("Waiting for download: %s", ev.filename)
select {
case <-ev.done:
case <-time.After(60 * time.Second):
log.Printf("Download timed out: %s", ev.guid)
dlTrack.Lock()
dlTrack.ev = nil
dlTrack.Unlock()
return nil
}
fpath := filepath.Join(dlDir, ev.guid)
data, err := os.ReadFile(fpath)
dlTrack.Lock()
dlTrack.ev = nil
dlTrack.Unlock()
if err != nil {
log.Printf("Failed to read download %s: %v", fpath, err)
return nil
}
os.Remove(fpath)
return &dlFile{name: ev.filename, data: data}
}
func cacheDownload(f *dlFile) string {
id := shortuuid.New()
dlCache.Lock()
dlCache.files[id] = *f
dlCache.Unlock()
log.Printf("Download cached: /dl/%s (%s, %d bytes)", id, f.name, len(f.data))
return "/dl/" + id
}
func writeDownload(w http.ResponseWriter, f *dlFile) {
w.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, f.name))
w.Header().Set("Content-Type", http.DetectContentType(f.data))
w.Header().Set("Content-Length", strconv.Itoa(len(f.data)))
w.Write(f.data)
w.(http.Flusher).Flush()
log.Printf("Download served inline: %s (%d bytes)", f.name, len(f.data))
}
func dlServer(w http.ResponseWriter, r *http.Request) {
id := strings.TrimPrefix(r.URL.Path, "/dl/")
log.Printf("%s Download request for %s", r.RemoteAddr, id)
dlCache.Lock()
f, ok := dlCache.files[id]
delete(dlCache.files, id)
dlCache.Unlock()
if !ok {
http.NotFound(w, r)
return
}
writeDownload(w, &f)
}

22
go.mod
View File

@@ -4,28 +4,28 @@ go 1.26
require (
github.com/MaxHalford/halfgone v0.0.0-20171017091812-482157b86ccb
github.com/PuerkitoBio/goquery v1.11.0
github.com/breml/rootcerts v0.3.4
github.com/chromedp/cdproto v0.0.0-20250803210736-d308e07a266d
github.com/chromedp/chromedp v0.14.2
github.com/PuerkitoBio/goquery v1.12.0
github.com/breml/rootcerts v0.3.5
github.com/chromedp/cdproto v0.0.0-20260427013145-5737772c319b
github.com/chromedp/chromedp v0.15.1
github.com/ericpauley/go-quantize v0.0.0-20200331213906-ae555eb2afa4
github.com/lithammer/shortuuid/v4 v4.2.0
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef
github.com/tenox7/gip v1.0.1
golang.org/x/image v0.36.0
golang.org/x/net v0.51.0
github.com/tenox7/gip v1.0.2
golang.org/x/image v0.41.0
golang.org/x/net v0.55.0
)
require (
github.com/andybalholm/cascadia v1.3.3 // indirect
github.com/andybalholm/cascadia v1.3.4 // indirect
github.com/chromedp/sysutil v1.1.0 // indirect
github.com/go-json-experiment/json v0.0.0-20260214004413-d219187c3433 // indirect
github.com/go-json-experiment/json v0.0.0-20260601182631-00ed12fed2a6 // indirect
github.com/gobwas/httphead v0.1.0 // indirect
github.com/gobwas/pool v0.2.1 // indirect
github.com/gobwas/ws v1.4.0 // indirect
github.com/google/uuid v1.6.0 // indirect
golang.org/x/sys v0.42.0 // indirect
golang.org/x/text v0.34.0 // indirect
golang.org/x/sys v0.45.0 // indirect
golang.org/x/text v0.37.0 // indirect
)

50
go.sum
View File

@@ -1,21 +1,27 @@
github.com/MaxHalford/halfgone v0.0.0-20171017091812-482157b86ccb h1:YQ+d0g0P0F/06oDoeEgDHeZCIrnKgLxXcqYOpe8sTuU=
github.com/MaxHalford/halfgone v0.0.0-20171017091812-482157b86ccb/go.mod h1:J86XzS1wgzJPjpQmpriJ+SetP17JSQUd9l+HWQK86jA=
github.com/PuerkitoBio/goquery v1.11.0 h1:jZ7pwMQXIITcUXNH83LLk+txlaEy6NVOfTuP43xxfqw=
github.com/PuerkitoBio/goquery v1.11.0/go.mod h1:wQHgxUOU3JGuj3oD/QFfxUdlzW6xPHfqyHre6VMY4DQ=
github.com/PuerkitoBio/goquery v1.12.0 h1:pAcL4g3WRXekcB9AU/y1mbKez2dbY2AajVhtkO8RIBo=
github.com/PuerkitoBio/goquery v1.12.0/go.mod h1:802ej+gV2y7bbIhOIoPY5sT183ZW0YFofScC4q/hIpQ=
github.com/andybalholm/cascadia v1.3.3 h1:AG2YHrzJIm4BZ19iwJ/DAua6Btl3IwJX+VI4kktS1LM=
github.com/andybalholm/cascadia v1.3.3/go.mod h1:xNd9bqTn98Ln4DwST8/nG+H0yuB8Hmgu1YHNnWw0GeA=
github.com/breml/rootcerts v0.3.4 h1:9i7WNl/ctd9OEAOaTfLy//Wrlfxq/tRQ7v4okYFN9Ys=
github.com/breml/rootcerts v0.3.4/go.mod h1:S/PKh+4d1HUn4HQovEB8hPJZO6pUZYrIhmXBhsegfXw=
github.com/chromedp/cdproto v0.0.0-20250803210736-d308e07a266d h1:ZtA1sedVbEW7EW80Iz2GR3Ye6PwbJAJXjv7D74xG6HU=
github.com/chromedp/cdproto v0.0.0-20250803210736-d308e07a266d/go.mod h1:NItd7aLkcfOA/dcMXvl8p1u+lQqioRMq/SqDp71Pb/k=
github.com/chromedp/chromedp v0.14.2 h1:r3b/WtwM50RsBZHMUm9fsNhhzRStTHrKdr2zmwbZSzM=
github.com/chromedp/chromedp v0.14.2/go.mod h1:rHzAv60xDE7VNy/MYtTUrYreSc0ujt2O1/C3bzctYBo=
github.com/andybalholm/cascadia v1.3.4 h1:vM2lgh0Vru9Vwyfm4cQqWP2HHMW0u0+2PAW7Q38Qufg=
github.com/andybalholm/cascadia v1.3.4/go.mod h1:BLRmbRjpEtNKieZOCCvYj4RqN+KRA41GBe/5O+G93kM=
github.com/breml/rootcerts v0.3.5 h1:oi7YiZ25HH52+mrKyjrMkcAFfnRDUf6HO8aUDr7RlJI=
github.com/breml/rootcerts v0.3.5/go.mod h1:S/PKh+4d1HUn4HQovEB8hPJZO6pUZYrIhmXBhsegfXw=
github.com/chromedp/cdproto v0.0.0-20260405000525-47a8ff65b46a h1:Kk4P1W58eAf+OUGtx51cM7CcJokJuBEmOxxwPdHFH4Q=
github.com/chromedp/cdproto v0.0.0-20260405000525-47a8ff65b46a/go.mod h1:cbyjALe67vDvlvdiG9369P8w5U2w6IshwtyD2f2Tvag=
github.com/chromedp/cdproto v0.0.0-20260427013145-5737772c319b h1:fpvdcCAe2z3H8OvVY00iKOp3Wapbs/Gy375Fn6l/XM4=
github.com/chromedp/cdproto v0.0.0-20260427013145-5737772c319b/go.mod h1:cbyjALe67vDvlvdiG9369P8w5U2w6IshwtyD2f2Tvag=
github.com/chromedp/chromedp v0.15.1 h1:EJWiPm7BNqDqjYy6U0lTSL5wNH+iNt9GjC3a4gfjNyQ=
github.com/chromedp/chromedp v0.15.1/go.mod h1:CdTHtUqD/dqaFw/cvFWtTydoEQS44wLBuwbMR9EkOY4=
github.com/chromedp/sysutil v1.1.0 h1:PUFNv5EcprjqXZD9nJb9b/c9ibAbxiYo4exNWZyipwM=
github.com/chromedp/sysutil v1.1.0/go.mod h1:WiThHUdltqCNKGc4gaU50XgYjwjYIhKWoHGPTUfWTJ8=
github.com/ericpauley/go-quantize v0.0.0-20200331213906-ae555eb2afa4 h1:BBade+JlV/f7JstZ4pitd4tHhpN+w+6I+LyOS7B4fyU=
github.com/ericpauley/go-quantize v0.0.0-20200331213906-ae555eb2afa4/go.mod h1:H7chHJglrhPPzetLdzBleF8d22WYOv7UM/lEKYiwlKM=
github.com/go-json-experiment/json v0.0.0-20260214004413-d219187c3433 h1:vymEbVwYFP/L05h5TKQxvkXoKxNvTpjxYKdF1Nlwuao=
github.com/go-json-experiment/json v0.0.0-20260214004413-d219187c3433/go.mod h1:tphK2c80bpPhMOI4v6bIc2xWywPfbqi1Z06+RcrMkDg=
github.com/go-json-experiment/json v0.0.0-20260601182631-00ed12fed2a6 h1:nxP4pPoyqOAgX8lYDFCfl3DyKeXErCvSvhcyzwGV9CE=
github.com/go-json-experiment/json v0.0.0-20260601182631-00ed12fed2a6/go.mod h1:tphK2c80bpPhMOI4v6bIc2xWywPfbqi1Z06+RcrMkDg=
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
@@ -37,8 +43,8 @@ github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c h1:km8GpoQut05eY3GiY
github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c/go.mod h1:cNQ3dwVJtS5Hmnjxy6AgTPd0Inb3pW05ftPSX7NZO7Q=
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef h1:Ch6Q+AZUxDBCVqdkI8FSpFyZDtCVBc2VmejdNrm5rRQ=
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef/go.mod h1:nXTWP6+gD5+LUJ8krVhhoeHjvHTutPxMYl5SvkcnJNE=
github.com/tenox7/gip v1.0.1 h1:yRcHROzwBjV2BhCjnh1y19wIg5Ei5CTMaZ+lx9nMl3Q=
github.com/tenox7/gip v1.0.1/go.mod h1:MR/eaUKjLGkYIguDcAUrWyxG58ipjjCrzM92jwGqDno=
github.com/tenox7/gip v1.0.2 h1:VQcaQub/bKu87pQZ1PxeSJPcRWpPRcpIGwP70w6ovQ8=
github.com/tenox7/gip v1.0.2/go.mod h1:MR/eaUKjLGkYIguDcAUrWyxG58ipjjCrzM92jwGqDno=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
@@ -46,8 +52,10 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/image v0.36.0 h1:Iknbfm1afbgtwPTmHnS2gTM/6PPZfH+z2EFuOkSbqwc=
golang.org/x/image v0.36.0/go.mod h1:YsWD2TyyGKiIX1kZlu9QfKIsQ4nAAK9bdgdrIsE7xy4=
golang.org/x/image v0.39.0 h1:skVYidAEVKgn8lZ602XO75asgXBgLj9G/FE3RbuPFww=
golang.org/x/image v0.39.0/go.mod h1:sIbmppfU+xFLPIG0FoVUTvyBMmgng1/XAMhQ2ft0hpA=
golang.org/x/image v0.41.0 h1:8wS72eGJMJaBxK6okTzd4WaXumUlTVlb753MlsSvTCo=
golang.org/x/image v0.41.0/go.mod h1:uIc348UZMSvS5Z65CVZ7iDPaNobNFEPeJ4kbqTOszmA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
@@ -62,8 +70,10 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo=
golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y=
golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA=
golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs=
golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8=
golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -83,8 +93,10 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY=
golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -103,8 +115,10 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=
golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg=
golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164=
golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=

View File

@@ -94,8 +94,14 @@ func chromedpStart() (context.CancelFunc, context.CancelFunc) {
if *userAgent != "" {
opts = append(opts, chromedp.UserAgent(*userAgent))
}
if *browserPath == "" {
*browserPath = findBrowser()
}
if *browserPath != "" {
log.Printf("Using browser: %s", *browserPath)
opts = append(opts, chromedp.ExecPath(*browserPath))
} else {
log.Printf("No browser detected, falling back to chromedp default lookup")
}
if *userDataDir != "" {
opts = append(opts, chromedp.UserDataDir(*userDataDir))
@@ -152,9 +158,11 @@ func (rq *wrpReq) action() chromedp.Action {
return chromedp.Navigate(rq.url)
}
// Navigate to the desired URL.
func (rq *wrpReq) navigate() {
// Navigate to the desired URL, returns the downloaded file if one was triggered.
func (rq *wrpReq) navigate() *dlFile {
resetDownloadState()
ctxErr(chromedp.Run(ctx, rq.action()), rq.w)
return waitForDownload()
}
// Handle context errors
@@ -170,6 +178,7 @@ func ctxErr(err error, w io.Writer) {
return
}
ctx, cncl = chromedp.NewContext(actx)
setupDownloads()
log.Printf("Created new context, try again")
fmt.Fprintln(w, "Created new context, try again")
}
@@ -382,7 +391,14 @@ func mapServer(w http.ResponseWriter, r *http.Request) {
rq.printUI(uiParams{})
return
}
rq.navigate() // TODO: if error from navigate do not capture
if dl := rq.navigate(); dl != nil {
if rq.proxy {
writeDownload(w, dl)
} else {
http.Redirect(w, r, cacheDownload(dl), http.StatusFound)
}
return
}
if rq.proxy {
chromedp.Run(ctx, waitForRender())
var loc string

70
util.go
View File

@@ -8,6 +8,10 @@ import (
"log"
"net"
"net/http"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"time"
@@ -72,6 +76,72 @@ func asciify(s []byte) []byte {
return a
}
func findBrowser() string {
var paths []string
switch runtime.GOOS {
case "darwin":
paths = []string{
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
"/Applications/Chromium.app/Contents/MacOS/Chromium",
"/Applications/Brave Browser.app/Contents/MacOS/Brave Browser",
"/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge",
"/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary",
"/Applications/Brave Browser Beta.app/Contents/MacOS/Brave Browser Beta",
"/Applications/Brave Browser Nightly.app/Contents/MacOS/Brave Browser Nightly",
"/Applications/Vivaldi.app/Contents/MacOS/Vivaldi",
"/Applications/Arc.app/Contents/MacOS/Arc",
}
case "windows":
pf := os.Getenv("ProgramFiles")
pfx86 := os.Getenv("ProgramFiles(x86)")
lad := os.Getenv("LOCALAPPDATA")
paths = []string{
filepath.Join(pf, `Google\Chrome\Application\chrome.exe`),
filepath.Join(pfx86, `Google\Chrome\Application\chrome.exe`),
filepath.Join(lad, `Google\Chrome\Application\chrome.exe`),
filepath.Join(pf, `BraveSoftware\Brave-Browser\Application\brave.exe`),
filepath.Join(pfx86, `BraveSoftware\Brave-Browser\Application\brave.exe`),
filepath.Join(lad, `BraveSoftware\Brave-Browser\Application\brave.exe`),
filepath.Join(pf, `Chromium\Application\chrome.exe`),
filepath.Join(lad, `Chromium\Application\chrome.exe`),
filepath.Join(pf, `Microsoft\Edge\Application\msedge.exe`),
filepath.Join(pfx86, `Microsoft\Edge\Application\msedge.exe`),
filepath.Join(pf, `Vivaldi\Application\vivaldi.exe`),
}
default:
paths = []string{
"/usr/bin/google-chrome",
"/usr/bin/google-chrome-stable",
"/usr/bin/chromium",
"/usr/bin/chromium-browser",
"/usr/bin/brave-browser",
"/usr/bin/brave-browser-stable",
"/usr/bin/brave",
"/usr/bin/microsoft-edge",
"/usr/bin/vivaldi",
"/snap/bin/chromium",
"/snap/bin/brave",
"/opt/brave.com/brave/brave",
"/opt/google/chrome/chrome",
"/opt/vivaldi/vivaldi",
"/usr/local/bin/chrome",
"/usr/local/bin/chromium",
"/usr/local/bin/brave",
}
}
for _, p := range paths {
if _, err := os.Stat(p); err == nil {
return p
}
}
for _, n := range []string{"google-chrome", "google-chrome-stable", "chromium", "chromium-browser", "brave-browser", "brave", "microsoft-edge", "vivaldi", "chrome"} {
if p, err := exec.LookPath(n); err == nil {
return p
}
}
return ""
}
func fetchJnrbsnUserAgent() string {
client := &http.Client{Timeout: 5 * time.Second}
resp, err := client.Get("https://jnrbsn.github.io/user-agents/user-agents.json")

15
wrp.go
View File

@@ -239,7 +239,10 @@ func proxyServer(w http.ResponseWriter, r *http.Request) {
chromedp.Run(ctx, chromedp.Location(&currentURL))
currentURL = strings.Replace(currentURL, "https://", "http://", 1)
if currentURL != strings.Replace(rq.url, "https://", "http://", 1) {
rq.navigate()
if dl := rq.navigate(); dl != nil {
writeDownload(w, dl)
return
}
}
rq.url = strings.Replace(rq.url, "https://", "http://", 1)
if r.Method == "CONNECT" {
@@ -273,7 +276,10 @@ func pageServer(w http.ResponseWriter, r *http.Request) {
rq.printUI(uiParams{})
return
}
rq.navigate() // TODO: if error from navigate do not capture
if dl := rq.navigate(); dl != nil {
http.Redirect(w, r, cacheDownload(dl), http.StatusFound)
return
}
if rq.wrpMode == "html" {
rq.captureMarkdown()
return
@@ -359,12 +365,14 @@ func main() {
cncl, acncl = chromedpStart()
defer cncl()
defer acncl()
setupDownloads()
c := make(chan os.Signal)
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
go func() {
<-c
log.Printf("Interrupt - shutting down.")
os.RemoveAll(dlDir)
cncl()
acncl()
srv.Shutdown(context.Background())
@@ -380,6 +388,7 @@ func main() {
http.HandleFunc(imgZpfx, imgServerTxt)
http.HandleFunc("/proxy.pac", pacServer)
http.HandleFunc("/shutdown/", haltServer)
http.HandleFunc("/dl/", dlServer)
http.HandleFunc("/favicon.ico", http.NotFound)
log.Printf("Default Img Type: %v, Geometry: %+v", *defType, defGeom)