From e869291f8e84a07c26b883283bbe149b851816da Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Wed, 29 May 2019 01:29:01 -0700 Subject: [PATCH 01/55] gocdp initial checkin --- README.md | 26 ++------ Changelog.md => pywebkit/Changelog.md | 0 wrp.py => pywebkit/wrp.py | 0 wrp.go | 90 +++++++++++++++++++++++++++ 4 files changed, 94 insertions(+), 22 deletions(-) rename Changelog.md => pywebkit/Changelog.md (100%) rename wrp.py => pywebkit/wrp.py (100%) mode change 100755 => 100644 create mode 100644 wrp.go diff --git a/README.md b/README.md index 2b97769..0866e2e 100644 --- a/README.md +++ b/README.md @@ -1,30 +1,12 @@ # WRP - Web Rendering Proxy -A HTTP proxy server that allows to use historical and obsolete web browsers on the modern web. It works by rendering the web page in to a GIF/PNG/JPEG image associated with clickable imagemap of original web links. +A HTTP proxy server that allows to use historical and obsolete web browsers on the modern web. It works by rendering the web page in to a GIF image associated with clickable imagemap of original web links. -New: Version 2.1 brings support for sslstrip to allow browsing https/SSL/TSL websites. +You are looking at a GoLang / CDP branch of WRP. +This code is under active development and not fully usable yet. -# Current Status +Check master branch for "stable" Python-Webkit version. -* This is a WebKit / Python version of WRP. -* It mostly works for casual browsing but the app is not very stable and your mileage may vary. -* Secure aka https/SSL/TLS websites might work with use of [sslstrip](https://moxie.org/software/sslstrip/) cheat (enabled by default). -* Web form submission is not yet implemented. -* New version using Chrome and GoLang is actively being developed. Stay tuned for updates. - -## OS Support -WRP works on macOS (Mac OS X), Linux and FreeBSD. On macOS it uses Cocoa Webkit, on Linux/FreeBSD QT Webkit, for which needs PyQT4 or PyQT5. - -## Installation -* macOS - should just work -* Linux/FreeBSD install `python-pyqt5.qtwebkit` and `sslstrip` -* For PythonMagick (Imagemagick library) install `python-pythonmagick` - -## Configuration -Edit wrp.py, scroll past Copyright section to find config parameters - -## Usage -Configure your web browser to use HTTP proxy at IP address and port where WRP is running. If using browsers prior to HTML 3.2, ISMAP option may need to be enabled. Check configuration. ## More info and screenshots * http://virtuallyfun.superglobalmegacorp.com/2014/03/11/web-rendering-proxy-update/ diff --git a/Changelog.md b/pywebkit/Changelog.md similarity index 100% rename from Changelog.md rename to pywebkit/Changelog.md diff --git a/wrp.py b/pywebkit/wrp.py old mode 100755 new mode 100644 similarity index 100% rename from wrp.py rename to pywebkit/wrp.py diff --git a/wrp.go b/wrp.go new file mode 100644 index 0000000..a361c17 --- /dev/null +++ b/wrp.go @@ -0,0 +1,90 @@ +package main + +import ( + "context" + "fmt" + "log" + "net/http" + "strconv" + "strings" + "time" + + "github.com/chromedp/cdproto/cdp" + "github.com/chromedp/cdproto/dom" + "github.com/chromedp/chromedp" +) + +var ( + ctx context.Context + cancel context.CancelFunc + scrcap []byte +) + +func pageServer(out http.ResponseWriter, req *http.Request) { + req.ParseForm() + furl := req.Form["url"] + var url string + if len(furl) >= 1 && len(furl[0]) > 4 { + url = furl[0] + } else { + url = "https://www.google.com/" + } + log.Printf("%s Page Reqest for %s URL=%s\n", req.RemoteAddr, req.URL.Path, url) + out.Header().Set("Content-Type", "text/html") + fmt.Fprintf(out, "\nWRP %s\n", url) + fmt.Fprintf(out, "
URL: ", url) + fmt.Fprintf(out, "

\n") + if len(url) > 4 { + capture(url, out) + } + fmt.Fprintf(out, "\n\n") +} + +func imgServer(out http.ResponseWriter, req *http.Request) { + log.Printf("%s Img Reqest for %s\n", req.RemoteAddr, req.URL.Path) + out.Header().Set("Content-Type", "image/png") + out.Header().Set("Content-Length", strconv.Itoa(len(scrcap))) + out.Write(scrcap) +} + +func capture(url string, out http.ResponseWriter) { + var nodes []*cdp.Node + ctxx := chromedp.FromContext(ctx) + var target string + + log.Printf("Caputure Request for %s\n", url) + chromedp.Run(ctx, + chromedp.Navigate(url), + chromedp.Sleep(time.Second*2), + chromedp.CaptureScreenshot(&scrcap), + chromedp.Nodes("a", &nodes, chromedp.ByQueryAll)) + + fmt.Fprintf(out, "\"wrp\"\n\n") + + for _, n := range nodes { + b, err := dom.GetBoxModel().WithNodeID(n.NodeID).Do(cdp.WithExecutor(ctx, ctxx.Target)) + if strings.HasPrefix(n.AttributeValue("href"), "/") { + target = fmt.Sprintf("/?url=%s%s", url, n.AttributeValue("href")) + } else { + target = fmt.Sprintf("/?url=%s", n.AttributeValue("href")) + } + + if err == nil && len(b.Content) > 6 { + fmt.Fprintf(out, "\"%s\"\n", + b.Content[0], b.Content[1], b.Content[4], b.Content[5], n.AttributeValue("href"), n.AttributeValue("href"), target) + } + } + + fmt.Fprintf(out, "\n") + log.Printf("Done with caputure for %s\n", url) +} + +func main() { + ctx, cancel = chromedp.NewContext(context.Background()) + defer cancel() + + http.HandleFunc("/", pageServer) + http.HandleFunc("/wrp.png", imgServer) + log.Printf("Starting http server on :8080\n") + http.ListenAndServe(":8080", nil) +} From 0680b4a72e9e0fb2ac79c1137237ea53897c8619 Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Wed, 29 May 2019 01:52:28 -0700 Subject: [PATCH 02/55] add flags --- wrp.go | 132 +++++++++++++++++++++++++++++---------------------------- 1 file changed, 68 insertions(+), 64 deletions(-) diff --git a/wrp.go b/wrp.go index a361c17..b18c59c 100644 --- a/wrp.go +++ b/wrp.go @@ -1,90 +1,94 @@ package main import ( - "context" - "fmt" - "log" - "net/http" - "strconv" - "strings" - "time" + "context" + "flag" + "fmt" + "log" + "net/http" + "strconv" + "strings" + "time" - "github.com/chromedp/cdproto/cdp" - "github.com/chromedp/cdproto/dom" - "github.com/chromedp/chromedp" + "github.com/chromedp/cdproto/cdp" + "github.com/chromedp/cdproto/dom" + "github.com/chromedp/chromedp" ) var ( - ctx context.Context - cancel context.CancelFunc - scrcap []byte + ctx context.Context + cancel context.CancelFunc + scrcap []byte ) func pageServer(out http.ResponseWriter, req *http.Request) { - req.ParseForm() - furl := req.Form["url"] - var url string - if len(furl) >= 1 && len(furl[0]) > 4 { - url = furl[0] - } else { - url = "https://www.google.com/" - } - log.Printf("%s Page Reqest for %s URL=%s\n", req.RemoteAddr, req.URL.Path, url) - out.Header().Set("Content-Type", "text/html") - fmt.Fprintf(out, "\nWRP %s\n", url) - fmt.Fprintf(out, "

URL: ", url) - fmt.Fprintf(out, "

\n") - if len(url) > 4 { - capture(url, out) - } - fmt.Fprintf(out, "\n\n") + req.ParseForm() + furl := req.Form["url"] + var url string + if len(furl) >= 1 && len(furl[0]) > 4 { + url = furl[0] + } else { + url = "https://www.google.com/" + } + log.Printf("%s Page Reqest for %s URL=%s\n", req.RemoteAddr, req.URL.Path, url) + out.Header().Set("Content-Type", "text/html") + fmt.Fprintf(out, "\nWRP %s\n", url) + fmt.Fprintf(out, "

URL: ", url) + fmt.Fprintf(out, "

\n") + if len(url) > 4 { + capture(url, out) + } + fmt.Fprintf(out, "\n\n") } func imgServer(out http.ResponseWriter, req *http.Request) { - log.Printf("%s Img Reqest for %s\n", req.RemoteAddr, req.URL.Path) - out.Header().Set("Content-Type", "image/png") - out.Header().Set("Content-Length", strconv.Itoa(len(scrcap))) - out.Write(scrcap) + log.Printf("%s Img Reqest for %s\n", req.RemoteAddr, req.URL.Path) + out.Header().Set("Content-Type", "image/png") + out.Header().Set("Content-Length", strconv.Itoa(len(scrcap))) + out.Write(scrcap) } func capture(url string, out http.ResponseWriter) { - var nodes []*cdp.Node - ctxx := chromedp.FromContext(ctx) - var target string + var nodes []*cdp.Node + ctxx := chromedp.FromContext(ctx) + var target string - log.Printf("Caputure Request for %s\n", url) - chromedp.Run(ctx, - chromedp.Navigate(url), - chromedp.Sleep(time.Second*2), - chromedp.CaptureScreenshot(&scrcap), - chromedp.Nodes("a", &nodes, chromedp.ByQueryAll)) + log.Printf("Caputure Request for %s\n", url) + chromedp.Run(ctx, + chromedp.Navigate(url), + chromedp.Sleep(time.Second*2), + chromedp.CaptureScreenshot(&scrcap), + chromedp.Nodes("a", &nodes, chromedp.ByQueryAll)) - fmt.Fprintf(out, "\"wrp\"\n\n") + fmt.Fprintf(out, "\"wrp\"\n\n") - for _, n := range nodes { - b, err := dom.GetBoxModel().WithNodeID(n.NodeID).Do(cdp.WithExecutor(ctx, ctxx.Target)) - if strings.HasPrefix(n.AttributeValue("href"), "/") { - target = fmt.Sprintf("/?url=%s%s", url, n.AttributeValue("href")) - } else { - target = fmt.Sprintf("/?url=%s", n.AttributeValue("href")) - } + for _, n := range nodes { + b, err := dom.GetBoxModel().WithNodeID(n.NodeID).Do(cdp.WithExecutor(ctx, ctxx.Target)) + if strings.HasPrefix(n.AttributeValue("href"), "/") { + target = fmt.Sprintf("/?url=%s%s", url, n.AttributeValue("href")) + } else { + target = fmt.Sprintf("/?url=%s", n.AttributeValue("href")) + } - if err == nil && len(b.Content) > 6 { - fmt.Fprintf(out, "\"%s\"\n", - b.Content[0], b.Content[1], b.Content[4], b.Content[5], n.AttributeValue("href"), n.AttributeValue("href"), target) - } - } + if err == nil && len(b.Content) > 6 { + fmt.Fprintf(out, "\"%s\"\n", + b.Content[0], b.Content[1], b.Content[4], b.Content[5], n.AttributeValue("href"), n.AttributeValue("href"), target) + } + } - fmt.Fprintf(out, "\n") - log.Printf("Done with caputure for %s\n", url) + fmt.Fprintf(out, "\n") + log.Printf("Done with caputure for %s\n", url) } func main() { - ctx, cancel = chromedp.NewContext(context.Background()) - defer cancel() + ctx, cancel = chromedp.NewContext(context.Background()) + defer cancel() + var addr string + flag.StringVar(&addr, "l", ":8080", "Listen address:port, default :8080") + flag.Parse() - http.HandleFunc("/", pageServer) - http.HandleFunc("/wrp.png", imgServer) - log.Printf("Starting http server on :8080\n") - http.ListenAndServe(":8080", nil) + http.HandleFunc("/", pageServer) + http.HandleFunc("/wrp.png", imgServer) + log.Printf("Starting http server on %s\n", addr) + http.ListenAndServe(addr, nil) } From 5b827bffb07d01798bde279d05af9c0d278a716a Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Wed, 29 May 2019 02:39:06 -0700 Subject: [PATCH 03/55] add browser size setting --- wrp.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/wrp.go b/wrp.go index b18c59c..fb49f17 100644 --- a/wrp.go +++ b/wrp.go @@ -10,6 +10,8 @@ import ( "strings" "time" + "github.com/chromedp/cdproto/emulation" + "github.com/chromedp/cdproto/cdp" "github.com/chromedp/cdproto/dom" "github.com/chromedp/chromedp" @@ -54,7 +56,9 @@ func capture(url string, out http.ResponseWriter) { var target string log.Printf("Caputure Request for %s\n", url) + chromedp.Run(ctx, + emulation.SetDeviceMetricsOverride(1024, 768, 1.0, false), chromedp.Navigate(url), chromedp.Sleep(time.Second*2), chromedp.CaptureScreenshot(&scrcap), From 7d84d01268a9264b51f60630c310a9c9586c87cf Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Wed, 29 May 2019 18:02:29 -0700 Subject: [PATCH 04/55] encode image as gif --- wrp.go | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/wrp.go b/wrp.go index fb49f17..0d0f3ef 100644 --- a/wrp.go +++ b/wrp.go @@ -9,6 +9,10 @@ import ( "strconv" "strings" "time" + "bytes" + _ "image" + "image/png" + "image/gif" "github.com/chromedp/cdproto/emulation" @@ -20,7 +24,7 @@ import ( var ( ctx context.Context cancel context.CancelFunc - scrcap []byte + gifbuf bytes.Buffer ) func pageServer(out http.ResponseWriter, req *http.Request) { @@ -30,7 +34,7 @@ func pageServer(out http.ResponseWriter, req *http.Request) { if len(furl) >= 1 && len(furl[0]) > 4 { url = furl[0] } else { - url = "https://www.google.com/" + url = "https://en.wikipedia.org/wiki/" } log.Printf("%s Page Reqest for %s URL=%s\n", req.RemoteAddr, req.URL.Path, url) out.Header().Set("Content-Type", "text/html") @@ -45,15 +49,16 @@ func pageServer(out http.ResponseWriter, req *http.Request) { func imgServer(out http.ResponseWriter, req *http.Request) { log.Printf("%s Img Reqest for %s\n", req.RemoteAddr, req.URL.Path) - out.Header().Set("Content-Type", "image/png") - out.Header().Set("Content-Length", strconv.Itoa(len(scrcap))) - out.Write(scrcap) + out.Header().Set("Content-Type", "image/gif") + out.Header().Set("Content-Length", strconv.Itoa(len(gifbuf.Bytes()))) + out.Write(gifbuf.Bytes()) } func capture(url string, out http.ResponseWriter) { var nodes []*cdp.Node ctxx := chromedp.FromContext(ctx) var target string + var scrcap []byte log.Printf("Caputure Request for %s\n", url) @@ -64,7 +69,14 @@ func capture(url string, out http.ResponseWriter) { chromedp.CaptureScreenshot(&scrcap), chromedp.Nodes("a", &nodes, chromedp.ByQueryAll)) - fmt.Fprintf(out, "\"wrp\"\n\n") + img, err:= png.Decode(bytes.NewReader(scrcap) ) + if err != nil { + log.Fatal(err) + } + gifbuf.Reset() + gif.Encode(&gifbuf, img, nil) + + fmt.Fprintf(out, "\"wrp\"\n\n") for _, n := range nodes { b, err := dom.GetBoxModel().WithNodeID(n.NodeID).Do(cdp.WithExecutor(ctx, ctxx.Target)) @@ -92,7 +104,7 @@ func main() { flag.Parse() http.HandleFunc("/", pageServer) - http.HandleFunc("/wrp.png", imgServer) + http.HandleFunc("/wrp.gif", imgServer) log.Printf("Starting http server on %s\n", addr) http.ListenAndServe(addr, nil) } From c6186d6fb48722741b6e9f1ad41bf8e81153c6bb Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Wed, 29 May 2019 18:47:03 -0700 Subject: [PATCH 05/55] added favico handler --- wrp.go | 1 + 1 file changed, 1 insertion(+) diff --git a/wrp.go b/wrp.go index 0d0f3ef..ab5e430 100644 --- a/wrp.go +++ b/wrp.go @@ -105,6 +105,7 @@ func main() { http.HandleFunc("/", pageServer) http.HandleFunc("/wrp.gif", imgServer) + http.HandleFunc("/favicon.ico", http.NotFound) log.Printf("Starting http server on %s\n", addr) http.ListenAndServe(addr, nil) } From d8617af9c2d3773c715cd04f24cc7d542030ab87 Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Wed, 29 May 2019 18:48:07 -0700 Subject: [PATCH 06/55] resolve relative a href urls --- wrp.go | 58 +++++++++++++++++++++++++++++++++------------------------- 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/wrp.go b/wrp.go index ab5e430..9d163a1 100644 --- a/wrp.go +++ b/wrp.go @@ -7,12 +7,12 @@ import ( "log" "net/http" "strconv" - "strings" "time" "bytes" _ "image" "image/png" "image/gif" + "net/url" "github.com/chromedp/cdproto/emulation" @@ -30,19 +30,19 @@ var ( func pageServer(out http.ResponseWriter, req *http.Request) { req.ParseForm() furl := req.Form["url"] - var url string + var gourl string if len(furl) >= 1 && len(furl[0]) > 4 { - url = furl[0] + gourl = furl[0] } else { - url = "https://en.wikipedia.org/wiki/" + gourl = "https://en.wikipedia.org/wiki/" } - log.Printf("%s Page Reqest for %s URL=%s\n", req.RemoteAddr, req.URL.Path, url) + log.Printf("%s Page Reqest for %s URL=%s\n", req.RemoteAddr, req.URL.Path, gourl) out.Header().Set("Content-Type", "text/html") - fmt.Fprintf(out, "\nWRP %s\n", url) - fmt.Fprintf(out, "

URL: ", url) + fmt.Fprintf(out, "\nWRP %s\n", gourl) + fmt.Fprintf(out, "URL: ", gourl) fmt.Fprintf(out, "

\n") - if len(url) > 4 { - capture(url, out) + if len(gourl) > 4 { + capture(gourl, out) } fmt.Fprintf(out, "\n\n") } @@ -54,46 +54,54 @@ func imgServer(out http.ResponseWriter, req *http.Request) { out.Write(gifbuf.Bytes()) } -func capture(url string, out http.ResponseWriter) { +func capture(gourl string, out http.ResponseWriter) { var nodes []*cdp.Node ctxx := chromedp.FromContext(ctx) - var target string var scrcap []byte + var loc string - log.Printf("Caputure Request for %s\n", url) + log.Printf("Caputure Request for %s\n", gourl) chromedp.Run(ctx, emulation.SetDeviceMetricsOverride(1024, 768, 1.0, false), - chromedp.Navigate(url), + chromedp.Navigate(gourl), chromedp.Sleep(time.Second*2), chromedp.CaptureScreenshot(&scrcap), + chromedp.Location(&loc), chromedp.Nodes("a", &nodes, chromedp.ByQueryAll)) - img, err:= png.Decode(bytes.NewReader(scrcap) ) - if err != nil { - log.Fatal(err) - } - gifbuf.Reset() - gif.Encode(&gifbuf, img, nil) + log.Printf("Landed on: %s, Got %d nodes\n", loc, len(nodes)) + img, err:= png.Decode(bytes.NewReader(scrcap) ) + if err != nil { + log.Fatal(err) + } + gifbuf.Reset() + gif.Encode(&gifbuf, img, nil) + + base, _ := url.Parse(loc) + fmt.Fprintf(out, "\n", base) fmt.Fprintf(out, "\"wrp\"\n\n") for _, n := range nodes { b, err := dom.GetBoxModel().WithNodeID(n.NodeID).Do(cdp.WithExecutor(ctx, ctxx.Target)) - if strings.HasPrefix(n.AttributeValue("href"), "/") { - target = fmt.Sprintf("/?url=%s%s", url, n.AttributeValue("href")) - } else { - target = fmt.Sprintf("/?url=%s", n.AttributeValue("href")) + if err != nil { + continue } + tgt, err := base.Parse(n.AttributeValue("href")) + if err != nil { + continue + } + target := fmt.Sprintf("/?url=%s", tgt) - if err == nil && len(b.Content) > 6 { + if len(b.Content) > 6 && len(target) > 7 { fmt.Fprintf(out, "\"%s\"\n", b.Content[0], b.Content[1], b.Content[4], b.Content[5], n.AttributeValue("href"), n.AttributeValue("href"), target) } } fmt.Fprintf(out, "\n") - log.Printf("Done with caputure for %s\n", url) + log.Printf("Done with caputure for %s\n", gourl) } func main() { From a3eb7cb69a1f7b467f1c4bfe3cecfcdd6715ad00 Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Wed, 29 May 2019 18:53:05 -0700 Subject: [PATCH 07/55] add copyright --- wrp.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/wrp.go b/wrp.go index 9d163a1..d9ece02 100644 --- a/wrp.go +++ b/wrp.go @@ -1,3 +1,10 @@ +// +// WRP - Web Rendering Proxy +// +// Copyright (c) 2013-2018 Antoni Sawicki +// Copyright (c) 2019 Google LLC +// + package main import ( From 57a107aa69c92f86570e3e83448346cc3a7fba5d Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Wed, 29 May 2019 23:49:39 -0700 Subject: [PATCH 08/55] log decode error instead of bailing out --- wrp.go | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/wrp.go b/wrp.go index d9ece02..e7a4ed6 100644 --- a/wrp.go +++ b/wrp.go @@ -8,18 +8,18 @@ package main import ( + "bytes" "context" "flag" "fmt" + _ "image" + "image/gif" + "image/png" "log" "net/http" + "net/url" "strconv" "time" - "bytes" - _ "image" - "image/png" - "image/gif" - "net/url" "github.com/chromedp/cdproto/emulation" @@ -79,15 +79,16 @@ func capture(gourl string, out http.ResponseWriter) { log.Printf("Landed on: %s, Got %d nodes\n", loc, len(nodes)) - img, err:= png.Decode(bytes.NewReader(scrcap) ) + img, err := png.Decode(bytes.NewReader(scrcap)) if err != nil { - log.Fatal(err) + log.Printf("Failed to decode screenshot: %s\n", err) + fmt.Fprintf(out, "
Unable to decode page screenshot:
%s
\n", err) + return } gifbuf.Reset() gif.Encode(&gifbuf, img, nil) base, _ := url.Parse(loc) - fmt.Fprintf(out, "\n", base) fmt.Fprintf(out, "\"wrp\"\n\n") for _, n := range nodes { From 546e686cbc4d0d12cce3433f7af3d54bf31d5c9f Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Thu, 30 May 2019 00:07:08 -0700 Subject: [PATCH 09/55] shutdown function via /halt url --- wrp.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/wrp.go b/wrp.go index e7a4ed6..8412079 100644 --- a/wrp.go +++ b/wrp.go @@ -18,6 +18,7 @@ import ( "log" "net/http" "net/url" + "os" "strconv" "time" @@ -61,6 +62,15 @@ func imgServer(out http.ResponseWriter, req *http.Request) { out.Write(gifbuf.Bytes()) } +func haltServer(out http.ResponseWriter, req *http.Request) { + log.Printf("%s Shutdown request received [%s]\n", req.RemoteAddr, req.URL.Path) + out.Header().Set("Content-Type", "text/plain") + fmt.Fprintf(out, "WRP Shutdown") + out.(http.Flusher).Flush() + cancel() + os.Exit(0) +} + func capture(gourl string, out http.ResponseWriter) { var nodes []*cdp.Node ctxx := chromedp.FromContext(ctx) @@ -122,6 +132,7 @@ func main() { http.HandleFunc("/", pageServer) http.HandleFunc("/wrp.gif", imgServer) http.HandleFunc("/favicon.ico", http.NotFound) + http.HandleFunc("/halt", haltServer) log.Printf("Starting http server on %s\n", addr) http.ListenAndServe(addr, nil) } From df400d57b3d978b812383a3d80112e685ca39e64 Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Thu, 30 May 2019 00:53:59 -0700 Subject: [PATCH 10/55] log encode errors --- wrp.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/wrp.go b/wrp.go index 8412079..1f57cc4 100644 --- a/wrp.go +++ b/wrp.go @@ -96,7 +96,12 @@ func capture(gourl string, out http.ResponseWriter) { return } gifbuf.Reset() - gif.Encode(&gifbuf, img, nil) + err = gif.Encode(&gifbuf, img, nil) + if err != nil { + log.Printf("Failed to encode GIF: %s\n", err) + fmt.Fprintf(out, "
Unable to encode GIF:
%s
\n", err) + return + } base, _ := url.Parse(loc) fmt.Fprintf(out, "\"wrp\"\n\n") From a897f76e20287c07eb0e327c54a3e842469e6364 Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Thu, 30 May 2019 02:02:24 -0700 Subject: [PATCH 11/55] readme updates --- README.md | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 0866e2e..465abe1 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,30 @@ # WRP - Web Rendering Proxy A HTTP proxy server that allows to use historical and obsolete web browsers on the modern web. It works by rendering the web page in to a GIF image associated with clickable imagemap of original web links. + You are looking at a GoLang / CDP branch of WRP. This code is under active development and not fully usable yet. + -Check master branch for "stable" Python-Webkit version. +## Done so far +* basic browser-in-browser mode +* process and serve image+map via cdp +* gif with Floyd–Steinberg dithering +* random image addressing +* resolve relative links + +## Todo +* configurable size and scale +* ISMAP +* configurable color palete and quantization +* paginated scrolling +* real http proxy support +* encode to png/jpeg option +* padded box model coordinates +* better http server shutdown +* chromedp logging, timeout, non-headless flags + +Check [master branch](https://github.com/tenox7/wrp/tree/master) for "stable" Python-Webkit version. -## More info and screenshots -* http://virtuallyfun.superglobalmegacorp.com/2014/03/11/web-rendering-proxy-update/ -* http://virtuallyfun.superglobalmegacorp.com/2014/03/03/surfing-modern-web-with-ancient-browsers/ - From 9ad651c72c4aac85d37f1db21ce7350bc00a01e7 Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Thu, 30 May 2019 02:03:17 -0700 Subject: [PATCH 12/55] randomized image url --- wrp.go | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/wrp.go b/wrp.go index 1f57cc4..b6f9206 100644 --- a/wrp.go +++ b/wrp.go @@ -16,6 +16,7 @@ import ( "image/gif" "image/png" "log" + "math/rand" "net/http" "net/url" "os" @@ -32,7 +33,7 @@ import ( var ( ctx context.Context cancel context.CancelFunc - gifbuf bytes.Buffer + gifmap = make(map[string]bytes.Buffer) ) func pageServer(out http.ResponseWriter, req *http.Request) { @@ -42,9 +43,9 @@ func pageServer(out http.ResponseWriter, req *http.Request) { if len(furl) >= 1 && len(furl[0]) > 4 { gourl = furl[0] } else { - gourl = "https://en.wikipedia.org/wiki/" + gourl = "https://www.bbc.com/news" } - log.Printf("%s Page Reqest for %s URL=%s\n", req.RemoteAddr, req.URL.Path, gourl) + log.Printf("%s Page Reqest for %s [%s]\n", req.RemoteAddr, gourl, req.URL.Path) out.Header().Set("Content-Type", "text/html") fmt.Fprintf(out, "\nWRP %s\n", gourl) fmt.Fprintf(out, "

URL: ", gourl) @@ -56,10 +57,13 @@ func pageServer(out http.ResponseWriter, req *http.Request) { } func imgServer(out http.ResponseWriter, req *http.Request) { - log.Printf("%s Img Reqest for %s\n", req.RemoteAddr, req.URL.Path) + log.Printf("%s Img Request for %s\n", req.RemoteAddr, req.URL.Path) + gifbuf := gifmap[req.URL.Path] + defer delete(gifmap, req.URL.Path) out.Header().Set("Content-Type", "image/gif") out.Header().Set("Content-Length", strconv.Itoa(len(gifbuf.Bytes()))) out.Write(gifbuf.Bytes()) + out.(http.Flusher).Flush() } func haltServer(out http.ResponseWriter, req *http.Request) { @@ -74,22 +78,25 @@ func haltServer(out http.ResponseWriter, req *http.Request) { func capture(gourl string, out http.ResponseWriter) { var nodes []*cdp.Node ctxx := chromedp.FromContext(ctx) - var scrcap []byte + var pngbuf []byte + var gifbuf bytes.Buffer var loc string - log.Printf("Caputure Request for %s\n", gourl) + log.Printf("Processing Caputure Request for %s\n", gourl) + // Run ChromeDP Magic chromedp.Run(ctx, emulation.SetDeviceMetricsOverride(1024, 768, 1.0, false), chromedp.Navigate(gourl), chromedp.Sleep(time.Second*2), - chromedp.CaptureScreenshot(&scrcap), + chromedp.CaptureScreenshot(&pngbuf), chromedp.Location(&loc), chromedp.Nodes("a", &nodes, chromedp.ByQueryAll)) log.Printf("Landed on: %s, Got %d nodes\n", loc, len(nodes)) - img, err := png.Decode(bytes.NewReader(scrcap)) + // Process Screenshot Image + img, err := png.Decode(bytes.NewReader(pngbuf)) if err != nil { log.Printf("Failed to decode screenshot: %s\n", err) fmt.Fprintf(out, "
Unable to decode page screenshot:
%s
\n", err) @@ -102,9 +109,13 @@ func capture(gourl string, out http.ResponseWriter) { fmt.Fprintf(out, "
Unable to encode GIF:
%s
\n", err) return } + imgpath := fmt.Sprintf("/img/%04d.gif", rand.Intn(9999)) + gifmap[imgpath] = gifbuf + // Process Nodes base, _ := url.Parse(loc) - fmt.Fprintf(out, "\"wrp\"\n\n") + fmt.Fprintf(out, "\"wrp\"\n\n", imgpath) + log.Printf("Image path will be: %s", imgpath) for _, n := range nodes { b, err := dom.GetBoxModel().WithNodeID(n.NodeID).Do(cdp.WithExecutor(ctx, ctxx.Target)) @@ -124,6 +135,7 @@ func capture(gourl string, out http.ResponseWriter) { } fmt.Fprintf(out, "\n") + out.(http.Flusher).Flush() log.Printf("Done with caputure for %s\n", gourl) } @@ -133,9 +145,9 @@ func main() { var addr string flag.StringVar(&addr, "l", ":8080", "Listen address:port, default :8080") flag.Parse() - + rand.Seed(time.Now().UnixNano()) http.HandleFunc("/", pageServer) - http.HandleFunc("/wrp.gif", imgServer) + http.HandleFunc("/img/", imgServer) http.HandleFunc("/favicon.ico", http.NotFound) http.HandleFunc("/halt", haltServer) log.Printf("Starting http server on %s\n", addr) From e643ec1d69db28a3c55e73636e174bd6bff07e04 Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Thu, 30 May 2019 02:04:25 -0700 Subject: [PATCH 13/55] readme fix --- README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 465abe1..6688a4d 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,10 @@ # WRP - Web Rendering Proxy A HTTP proxy server that allows to use historical and obsolete web browsers on the modern web. It works by rendering the web page in to a GIF image associated with clickable imagemap of original web links. - -You are looking at a GoLang / CDP branch of WRP. +**You are looking at a GoLang / CDP branch of WRP.** + +**This code is under active development and not fully usable yet.** -This code is under active development and not fully usable yet. - ## Done so far * basic browser-in-browser mode From 12664e6a10ee707641b94c79a811c25b8caaad12 Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Thu, 30 May 2019 02:05:04 -0700 Subject: [PATCH 14/55] readme fix --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 6688a4d..7246403 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ A HTTP proxy server that allows to use historical and obsolete web browsers on t * better http server shutdown * chromedp logging, timeout, non-headless flags +## Python version Check [master branch](https://github.com/tenox7/wrp/tree/master) for "stable" Python-Webkit version. From d382c38547bdfcdc6d9f0511303c428d0d9a796e Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Thu, 30 May 2019 02:15:52 -0700 Subject: [PATCH 15/55] unexpected eof on windows --- README.md | 1 + wrp.go | 1 + 2 files changed, 2 insertions(+) diff --git a/README.md b/README.md index 7246403..a030bca 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ A HTTP proxy server that allows to use historical and obsolete web browsers on t ## Todo * configurable size and scale * ISMAP +* unexpected EOF on Windows * configurable color palete and quantization * paginated scrolling * real http proxy support diff --git a/wrp.go b/wrp.go index b6f9206..d700209 100644 --- a/wrp.go +++ b/wrp.go @@ -96,6 +96,7 @@ func capture(gourl string, out http.ResponseWriter) { log.Printf("Landed on: %s, Got %d nodes\n", loc, len(nodes)) // Process Screenshot Image + bytes.NewReader(pngbuf).Seek(0, 0) img, err := png.Decode(bytes.NewReader(pngbuf)) if err != nil { log.Printf("Failed to decode screenshot: %s\n", err) From d905704a2a77ec6e2398819438d9fe8f494f085f Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Thu, 30 May 2019 18:08:48 -0700 Subject: [PATCH 16/55] add width height and scale input boxes --- wrp.go | 44 ++++++++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/wrp.go b/wrp.go index d700209..4e7d5a7 100644 --- a/wrp.go +++ b/wrp.go @@ -36,22 +36,34 @@ var ( gifmap = make(map[string]bytes.Buffer) ) -func pageServer(out http.ResponseWriter, req *http.Request) { - req.ParseForm() - furl := req.Form["url"] - var gourl string - if len(furl) >= 1 && len(furl[0]) > 4 { - gourl = furl[0] - } else { - gourl = "https://www.bbc.com/news" +func pageServer(out http.ResponseWriter, r *http.Request) { + r.ParseForm() + u := r.FormValue("url") + w, _ := strconv.ParseInt(r.FormValue("w"), 10, 64) + if w < 10 { + w = 1024 } - log.Printf("%s Page Reqest for %s [%s]\n", req.RemoteAddr, gourl, req.URL.Path) + h, _ := strconv.ParseInt(r.FormValue("h"), 10, 64) + if h < 10 { + h = 768 + } + s, _ := strconv.ParseFloat(r.FormValue("s"), 64) + if s < 0.1 { + s = 1.0 + } + log.Printf("%s Page Reqest for url=\"%s\" [%s]\n", r.RemoteAddr, u, r.URL.Path) out.Header().Set("Content-Type", "text/html") - fmt.Fprintf(out, "\nWRP %s\n", gourl) - fmt.Fprintf(out, "URL: ", gourl) - fmt.Fprintf(out, "

\n") - if len(gourl) > 4 { - capture(gourl, out) + fmt.Fprintf(out, "\nWRP %s\n", u) + fmt.Fprintf(out, "

URL: ", u) + fmt.Fprintf(out, "

\n") + fmt.Fprintf(out, "Width: \n", w) + fmt.Fprintf(out, "Height: \n", h) + fmt.Fprintf(out, "Scale: \n", s) + fmt.Fprintf(out, "

") + if len(u) > 4 { + capture(u, w, h, s, out) + } else { + fmt.Fprintf(out, "No URL specified") } fmt.Fprintf(out, "\n\n") } @@ -75,7 +87,7 @@ func haltServer(out http.ResponseWriter, req *http.Request) { os.Exit(0) } -func capture(gourl string, out http.ResponseWriter) { +func capture(gourl string, w int64, h int64, s float64, out http.ResponseWriter) { var nodes []*cdp.Node ctxx := chromedp.FromContext(ctx) var pngbuf []byte @@ -86,7 +98,7 @@ func capture(gourl string, out http.ResponseWriter) { // Run ChromeDP Magic chromedp.Run(ctx, - emulation.SetDeviceMetricsOverride(1024, 768, 1.0, false), + emulation.SetDeviceMetricsOverride(w, h, s, false), chromedp.Navigate(gourl), chromedp.Sleep(time.Second*2), chromedp.CaptureScreenshot(&pngbuf), From 5d8f51ac66fd2a4ab10c5c156da13e075f6d4b3c Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Thu, 30 May 2019 18:10:52 -0700 Subject: [PATCH 17/55] width height and scale go to area target --- wrp.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wrp.go b/wrp.go index 4e7d5a7..aaf31c3 100644 --- a/wrp.go +++ b/wrp.go @@ -58,7 +58,7 @@ func pageServer(out http.ResponseWriter, r *http.Request) { fmt.Fprintf(out, "

\n") fmt.Fprintf(out, "Width: \n", w) fmt.Fprintf(out, "Height: \n", h) - fmt.Fprintf(out, "Scale: \n", s) + fmt.Fprintf(out, "Scale: \n", s) fmt.Fprintf(out, "

") if len(u) > 4 { capture(u, w, h, s, out) @@ -139,7 +139,7 @@ func capture(gourl string, w int64, h int64, s float64, out http.ResponseWriter) if err != nil { continue } - target := fmt.Sprintf("/?url=%s", tgt) + target := fmt.Sprintf("/?url=%s&w=%d&h=%d&s=%1.2f", tgt, w, h, s) if len(b.Content) > 6 && len(target) > 7 { fmt.Fprintf(out, "\"%s\"\n", From ebe19912e64a40bea8caf4ca49f3c5502bb47eb7 Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Thu, 30 May 2019 23:40:43 -0700 Subject: [PATCH 18/55] scale area map too --- README.md | 1 - wrp.go | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a030bca..2344fda 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,6 @@ A HTTP proxy server that allows to use historical and obsolete web browsers on t * resolve relative links ## Todo -* configurable size and scale * ISMAP * unexpected EOF on Windows * configurable color palete and quantization diff --git a/wrp.go b/wrp.go index aaf31c3..550a728 100644 --- a/wrp.go +++ b/wrp.go @@ -143,7 +143,7 @@ func capture(gourl string, w int64, h int64, s float64, out http.ResponseWriter) if len(b.Content) > 6 && len(target) > 7 { fmt.Fprintf(out, "\"%s\"\n", - b.Content[0], b.Content[1], b.Content[4], b.Content[5], n.AttributeValue("href"), n.AttributeValue("href"), target) + b.Content[0]*s, b.Content[1]*s, b.Content[4]*s, b.Content[5]*s, n.AttributeValue("href"), n.AttributeValue("href"), target) } } @@ -163,6 +163,6 @@ func main() { http.HandleFunc("/img/", imgServer) http.HandleFunc("/favicon.ico", http.NotFound) http.HandleFunc("/halt", haltServer) - log.Printf("Starting http server on %s\n", addr) + log.Printf("Starting WRP http server on %s\n", addr) http.ListenAndServe(addr, nil) } From cb87a83d26b947d969638ac3e5e0058b12609aa4 Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Fri, 31 May 2019 00:19:10 -0700 Subject: [PATCH 19/55] add simple page scrolling --- wrp.go | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/wrp.go b/wrp.go index 550a728..956762a 100644 --- a/wrp.go +++ b/wrp.go @@ -24,6 +24,7 @@ import ( "time" "github.com/chromedp/cdproto/emulation" + "github.com/chromedp/cdproto/runtime" "github.com/chromedp/cdproto/cdp" "github.com/chromedp/cdproto/dom" @@ -39,6 +40,7 @@ var ( func pageServer(out http.ResponseWriter, r *http.Request) { r.ParseForm() u := r.FormValue("url") + y, _ := strconv.ParseInt(r.FormValue("y"), 10, 64) w, _ := strconv.ParseInt(r.FormValue("w"), 10, 64) if w < 10 { w = 1024 @@ -56,12 +58,13 @@ func pageServer(out http.ResponseWriter, r *http.Request) { fmt.Fprintf(out, "\nWRP %s\n", u) fmt.Fprintf(out, "

URL: ", u) fmt.Fprintf(out, "

\n") - fmt.Fprintf(out, "Width: \n", w) - fmt.Fprintf(out, "Height: \n", h) - fmt.Fprintf(out, "Scale: \n", s) + fmt.Fprintf(out, "Width: \n", w) + fmt.Fprintf(out, "Height: \n", h) + fmt.Fprintf(out, "Scale: \n", s) + fmt.Fprintf(out, "Scroll: \n", y) fmt.Fprintf(out, "

") if len(u) > 4 { - capture(u, w, h, s, out) + capture(u, w, h, s, y, out) } else { fmt.Fprintf(out, "No URL specified") } @@ -87,25 +90,28 @@ func haltServer(out http.ResponseWriter, req *http.Request) { os.Exit(0) } -func capture(gourl string, w int64, h int64, s float64, out http.ResponseWriter) { +func capture(gourl string, w int64, h int64, s float64, y int64, out http.ResponseWriter) { var nodes []*cdp.Node ctxx := chromedp.FromContext(ctx) var pngbuf []byte var gifbuf bytes.Buffer var loc string + var res *runtime.RemoteObject log.Printf("Processing Caputure Request for %s\n", gourl) // Run ChromeDP Magic + scrl := fmt.Sprintf("window.scrollTo(0, %d);", y) chromedp.Run(ctx, emulation.SetDeviceMetricsOverride(w, h, s, false), chromedp.Navigate(gourl), - chromedp.Sleep(time.Second*2), + chromedp.Evaluate(scrl, &res), + chromedp.Sleep(time.Second*1), chromedp.CaptureScreenshot(&pngbuf), chromedp.Location(&loc), chromedp.Nodes("a", &nodes, chromedp.ByQueryAll)) - log.Printf("Landed on: %s, Got %d nodes\n", loc, len(nodes)) + log.Printf("Landed on: %s, Nodes: %d\n", loc, len(nodes)) // Process Screenshot Image bytes.NewReader(pngbuf).Seek(0, 0) @@ -139,7 +145,7 @@ func capture(gourl string, w int64, h int64, s float64, out http.ResponseWriter) if err != nil { continue } - target := fmt.Sprintf("/?url=%s&w=%d&h=%d&s=%1.2f", tgt, w, h, s) + target := fmt.Sprintf("/?url=%s&w=%d&h=%d&s=%1.2f&y=%d", tgt, w, h, s, y) if len(b.Content) > 6 && len(target) > 7 { fmt.Fprintf(out, "\"%s\"\n", From 0ae49044c237505d3e26186bc966c4c738d834fc Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Fri, 31 May 2019 00:36:53 -0700 Subject: [PATCH 20/55] simple google search if url doesnt start with http --- wrp.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/wrp.go b/wrp.go index 956762a..196b3cb 100644 --- a/wrp.go +++ b/wrp.go @@ -21,6 +21,7 @@ import ( "net/url" "os" "strconv" + "strings" "time" "github.com/chromedp/cdproto/emulation" @@ -56,7 +57,7 @@ func pageServer(out http.ResponseWriter, r *http.Request) { log.Printf("%s Page Reqest for url=\"%s\" [%s]\n", r.RemoteAddr, u, r.URL.Path) out.Header().Set("Content-Type", "text/html") fmt.Fprintf(out, "\nWRP %s\n", u) - fmt.Fprintf(out, "

URL: ", u) + fmt.Fprintf(out, "URL/Search: ", u) fmt.Fprintf(out, "

\n") fmt.Fprintf(out, "Width: \n", w) fmt.Fprintf(out, "Height: \n", h) @@ -64,9 +65,13 @@ func pageServer(out http.ResponseWriter, r *http.Request) { fmt.Fprintf(out, "Scroll: \n", y) fmt.Fprintf(out, "

") if len(u) > 4 { - capture(u, w, h, s, y, out) + if strings.HasPrefix(u, "http") { + capture(u, w, h, s, y, out) + } else { + capture(fmt.Sprintf("http://www.google.com/search?q=%s", url.QueryEscape(u)), w, h, s, y, out) + } } else { - fmt.Fprintf(out, "No URL specified") + fmt.Fprintf(out, "No URL or search query specified") } fmt.Fprintf(out, "\n\n") } @@ -101,11 +106,10 @@ func capture(gourl string, w int64, h int64, s float64, y int64, out http.Respon log.Printf("Processing Caputure Request for %s\n", gourl) // Run ChromeDP Magic - scrl := fmt.Sprintf("window.scrollTo(0, %d);", y) chromedp.Run(ctx, emulation.SetDeviceMetricsOverride(w, h, s, false), chromedp.Navigate(gourl), - chromedp.Evaluate(scrl, &res), + chromedp.Evaluate(fmt.Sprintf("window.scrollTo(0, %d);", y), &res), chromedp.Sleep(time.Second*1), chromedp.CaptureScreenshot(&pngbuf), chromedp.Location(&loc), From 416490289db4c7c97a4300ba9e83a3d1f7dd8120 Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Fri, 31 May 2019 00:41:46 -0700 Subject: [PATCH 21/55] chromedp.run error handling --- wrp.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/wrp.go b/wrp.go index 196b3cb..5e75af1 100644 --- a/wrp.go +++ b/wrp.go @@ -106,7 +106,7 @@ func capture(gourl string, w int64, h int64, s float64, y int64, out http.Respon log.Printf("Processing Caputure Request for %s\n", gourl) // Run ChromeDP Magic - chromedp.Run(ctx, + err := chromedp.Run(ctx, emulation.SetDeviceMetricsOverride(w, h, s, false), chromedp.Navigate(gourl), chromedp.Evaluate(fmt.Sprintf("window.scrollTo(0, %d);", y), &res), @@ -115,6 +115,12 @@ func capture(gourl string, w int64, h int64, s float64, y int64, out http.Respon chromedp.Location(&loc), chromedp.Nodes("a", &nodes, chromedp.ByQueryAll)) + if err != nil { + log.Printf("%s", err) + fmt.Fprintf(out, "
%s
", err) + return + } + log.Printf("Landed on: %s, Nodes: %d\n", loc, len(nodes)) // Process Screenshot Image From 7610f525746858abadf7cc4f2c54f67408fd812b Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Fri, 31 May 2019 00:44:50 -0700 Subject: [PATCH 22/55] readme update --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2344fda..5cf7ee4 100644 --- a/README.md +++ b/README.md @@ -8,10 +8,12 @@ A HTTP proxy server that allows to use historical and obsolete web browsers on t ## Done so far * basic browser-in-browser mode -* process and serve image+map via cdp +* screenshot and serve image+map via CDP * gif with Floyd–Steinberg dithering * random image addressing * resolve relative links +* simple scrolling +* google search on input not starting with ^http ## Todo * ISMAP @@ -19,7 +21,7 @@ A HTTP proxy server that allows to use historical and obsolete web browsers on t * configurable color palete and quantization * paginated scrolling * real http proxy support -* encode to png/jpeg option +* option to encode as png/jpeg * padded box model coordinates * better http server shutdown * chromedp logging, timeout, non-headless flags From 186fda4949952b0810c142b9f2952b25d3c09ac2 Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Fri, 31 May 2019 01:34:44 -0700 Subject: [PATCH 23/55] windows bug --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5cf7ee4..02dd491 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ A HTTP proxy server that allows to use historical and obsolete web browsers on t ## Todo * ISMAP -* unexpected EOF on Windows +* net/url: invalid control character in URL on Windows * configurable color palete and quantization * paginated scrolling * real http proxy support From deb0cf792390444bbb5efff3f780fc2ba46361d0 Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Fri, 31 May 2019 01:56:34 -0700 Subject: [PATCH 24/55] ISMAP checkbox --- wrp.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/wrp.go b/wrp.go index 5e75af1..fbfa18b 100644 --- a/wrp.go +++ b/wrp.go @@ -41,6 +41,15 @@ var ( func pageServer(out http.ResponseWriter, r *http.Request) { r.ParseForm() u := r.FormValue("url") + var istr string + var i bool + if r.FormValue("i") == "on" { + istr = "CHECKED" + i = true + } else { + istr = "" + i = false + } y, _ := strconv.ParseInt(r.FormValue("y"), 10, 64) w, _ := strconv.ParseInt(r.FormValue("w"), 10, 64) if w < 10 { @@ -59,6 +68,7 @@ func pageServer(out http.ResponseWriter, r *http.Request) { fmt.Fprintf(out, "\nWRP %s\n", u) fmt.Fprintf(out, "

URL/Search: ", u) fmt.Fprintf(out, "

\n") + fmt.Fprintf(out, "ISMAP: [%v]\n", istr, i) fmt.Fprintf(out, "Width: \n", w) fmt.Fprintf(out, "Height: \n", h) fmt.Fprintf(out, "Scale: \n", s) From 981055dff90083f50ab5a3411c1531c474cd7a4c Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Fri, 31 May 2019 16:41:25 -0700 Subject: [PATCH 25/55] paginated scrolling --- README.md | 7 ++----- wrp.go | 21 ++++++++++++++------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 02dd491..07e3c72 100644 --- a/README.md +++ b/README.md @@ -12,14 +12,13 @@ A HTTP proxy server that allows to use historical and obsolete web browsers on t * gif with Floyd–Steinberg dithering * random image addressing * resolve relative links -* simple scrolling +* paginated scrolling * google search on input not starting with ^http ## Todo * ISMAP * net/url: invalid control character in URL on Windows * configurable color palete and quantization -* paginated scrolling * real http proxy support * option to encode as png/jpeg * padded box model coordinates @@ -27,6 +26,4 @@ A HTTP proxy server that allows to use historical and obsolete web browsers on t * chromedp logging, timeout, non-headless flags ## Python version -Check [master branch](https://github.com/tenox7/wrp/tree/master) for "stable" Python-Webkit version. - - +Check [master branch](https://github.com/tenox7/wrp/tree/master) for "stable" Python-Webkit version. \ No newline at end of file diff --git a/wrp.go b/wrp.go index fbfa18b..cbd0d22 100644 --- a/wrp.go +++ b/wrp.go @@ -50,7 +50,12 @@ func pageServer(out http.ResponseWriter, r *http.Request) { istr = "" i = false } - y, _ := strconv.ParseInt(r.FormValue("y"), 10, 64) + p, _ := strconv.ParseInt(r.FormValue("p"), 10, 64) + if r.FormValue("pg") == ">>" { + p++ + } else if r.FormValue("pg") == "<<" { + p-- + } w, _ := strconv.ParseInt(r.FormValue("w"), 10, 64) if w < 10 { w = 1024 @@ -72,13 +77,15 @@ func pageServer(out http.ResponseWriter, r *http.Request) { fmt.Fprintf(out, "Width: \n", w) fmt.Fprintf(out, "Height: \n", h) fmt.Fprintf(out, "Scale: \n", s) - fmt.Fprintf(out, "Scroll: \n", y) + fmt.Fprintf(out, "Page: \n", p) + fmt.Fprintf(out, " %d \n", p) + fmt.Fprintf(out, ">\"> \n") fmt.Fprintf(out, "

") if len(u) > 4 { if strings.HasPrefix(u, "http") { - capture(u, w, h, s, y, out) + capture(u, w, h, s, p, out) } else { - capture(fmt.Sprintf("http://www.google.com/search?q=%s", url.QueryEscape(u)), w, h, s, y, out) + capture(fmt.Sprintf("http://www.google.com/search?q=%s", url.QueryEscape(u)), w, h, s, p, out) } } else { fmt.Fprintf(out, "No URL or search query specified") @@ -105,7 +112,7 @@ func haltServer(out http.ResponseWriter, req *http.Request) { os.Exit(0) } -func capture(gourl string, w int64, h int64, s float64, y int64, out http.ResponseWriter) { +func capture(gourl string, w int64, h int64, s float64, p int64, out http.ResponseWriter) { var nodes []*cdp.Node ctxx := chromedp.FromContext(ctx) var pngbuf []byte @@ -119,7 +126,7 @@ func capture(gourl string, w int64, h int64, s float64, y int64, out http.Respon err := chromedp.Run(ctx, emulation.SetDeviceMetricsOverride(w, h, s, false), chromedp.Navigate(gourl), - chromedp.Evaluate(fmt.Sprintf("window.scrollTo(0, %d);", y), &res), + chromedp.Evaluate(fmt.Sprintf("window.scrollTo(0, %d);", p*int64(float64(h)*float64(0.9))), &res), chromedp.Sleep(time.Second*1), chromedp.CaptureScreenshot(&pngbuf), chromedp.Location(&loc), @@ -165,7 +172,7 @@ func capture(gourl string, w int64, h int64, s float64, y int64, out http.Respon if err != nil { continue } - target := fmt.Sprintf("/?url=%s&w=%d&h=%d&s=%1.2f&y=%d", tgt, w, h, s, y) + target := fmt.Sprintf("/?url=%s&w=%d&h=%d&s=%1.2f&", tgt, w, h, s) // no page# here if len(b.Content) > 6 && len(target) > 7 { fmt.Fprintf(out, "\"%s\"\n", From ea738f206aeaed5e3ce42956ba1475e41900cc12 Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Fri, 31 May 2019 17:12:26 -0700 Subject: [PATCH 26/55] log image size --- wrp.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wrp.go b/wrp.go index cbd0d22..1a1d8b7 100644 --- a/wrp.go +++ b/wrp.go @@ -156,12 +156,12 @@ func capture(gourl string, w int64, h int64, s float64, p int64, out http.Respon return } imgpath := fmt.Sprintf("/img/%04d.gif", rand.Intn(9999)) + log.Printf("Encoded GIF image: %s, Size: %dKB\n", imgpath, len(gifbuf.Bytes())/1024) gifmap[imgpath] = gifbuf // Process Nodes base, _ := url.Parse(loc) fmt.Fprintf(out, "\"wrp\"\n\n", imgpath) - log.Printf("Image path will be: %s", imgpath) for _, n := range nodes { b, err := dom.GetBoxModel().WithNodeID(n.NodeID).Do(cdp.WithExecutor(ctx, ctxx.Target)) From 61b84116b1101001eb67444a9c8f5b647ae7bff9 Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Fri, 31 May 2019 17:49:14 -0700 Subject: [PATCH 27/55] default to 0 page when go button is pressed --- wrp.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/wrp.go b/wrp.go index 1a1d8b7..625e7e8 100644 --- a/wrp.go +++ b/wrp.go @@ -55,6 +55,8 @@ func pageServer(out http.ResponseWriter, r *http.Request) { p++ } else if r.FormValue("pg") == "<<" { p-- + } else { + p = 0 } w, _ := strconv.ParseInt(r.FormValue("w"), 10, 64) if w < 10 { From 7a2f673fd04273d6af0941b39f6c69a460d32d90 Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Fri, 31 May 2019 18:20:55 -0700 Subject: [PATCH 28/55] more ismap stuff --- wrp.go | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/wrp.go b/wrp.go index 625e7e8..f477bac 100644 --- a/wrp.go +++ b/wrp.go @@ -72,22 +72,22 @@ func pageServer(out http.ResponseWriter, r *http.Request) { } log.Printf("%s Page Reqest for url=\"%s\" [%s]\n", r.RemoteAddr, u, r.URL.Path) out.Header().Set("Content-Type", "text/html") - fmt.Fprintf(out, "\nWRP %s\n", u) + fmt.Fprintf(out, "\nWRP %s\n", u) fmt.Fprintf(out, "

URL/Search: ", u) fmt.Fprintf(out, "

\n") - fmt.Fprintf(out, "ISMAP: [%v]\n", istr, i) + fmt.Fprintf(out, "ISMAP: \n", istr) fmt.Fprintf(out, "Width: \n", w) fmt.Fprintf(out, "Height: \n", h) fmt.Fprintf(out, "Scale: \n", s) fmt.Fprintf(out, "Page: \n", p) fmt.Fprintf(out, " %d \n", p) fmt.Fprintf(out, ">\"> \n") - fmt.Fprintf(out, "

") + fmt.Fprintf(out, "

\n") if len(u) > 4 { if strings.HasPrefix(u, "http") { - capture(u, w, h, s, p, out) + capture(u, w, h, s, p, i, out) } else { - capture(fmt.Sprintf("http://www.google.com/search?q=%s", url.QueryEscape(u)), w, h, s, p, out) + capture(fmt.Sprintf("http://www.google.com/search?q=%s", url.QueryEscape(u)), w, h, s, p, i, out) } } else { fmt.Fprintf(out, "No URL or search query specified") @@ -96,7 +96,7 @@ func pageServer(out http.ResponseWriter, r *http.Request) { } func imgServer(out http.ResponseWriter, req *http.Request) { - log.Printf("%s Img Request for %s\n", req.RemoteAddr, req.URL.Path) + log.Printf("%s IMG Request for %s\n", req.RemoteAddr, req.URL.Path) gifbuf := gifmap[req.URL.Path] defer delete(gifmap, req.URL.Path) out.Header().Set("Content-Type", "image/gif") @@ -105,6 +105,11 @@ func imgServer(out http.ResponseWriter, req *http.Request) { out.(http.Flusher).Flush() } +func mapServer(out http.ResponseWriter, req *http.Request) { + log.Printf("%s MAP Request for %s [%v]\n", req.RemoteAddr, req.URL.Path, req.URL.Query()) +} + + func haltServer(out http.ResponseWriter, req *http.Request) { log.Printf("%s Shutdown request received [%s]\n", req.RemoteAddr, req.URL.Path) out.Header().Set("Content-Type", "text/plain") @@ -114,7 +119,7 @@ func haltServer(out http.ResponseWriter, req *http.Request) { os.Exit(0) } -func capture(gourl string, w int64, h int64, s float64, p int64, out http.ResponseWriter) { +func capture(gourl string, w int64, h int64, s float64, p int64, ismap bool, out http.ResponseWriter) { var nodes []*cdp.Node ctxx := chromedp.FromContext(ctx) var pngbuf []byte @@ -163,7 +168,11 @@ func capture(gourl string, w int64, h int64, s float64, p int64, out http.Respon // Process Nodes base, _ := url.Parse(loc) - fmt.Fprintf(out, "\"wrp\"\n\n", imgpath) + if ismap { + fmt.Fprintf(out, "\"wrp\"", imgpath) + } else { + fmt.Fprintf(out, "\"wrp\"\n\n", imgpath) + } for _, n := range nodes { b, err := dom.GetBoxModel().WithNodeID(n.NodeID).Do(cdp.WithExecutor(ctx, ctxx.Target)) @@ -177,12 +186,18 @@ func capture(gourl string, w int64, h int64, s float64, p int64, out http.Respon target := fmt.Sprintf("/?url=%s&w=%d&h=%d&s=%1.2f&", tgt, w, h, s) // no page# here if len(b.Content) > 6 && len(target) > 7 { + if ismap { + + } else { fmt.Fprintf(out, "\"%s\"\n", b.Content[0]*s, b.Content[1]*s, b.Content[4]*s, b.Content[5]*s, n.AttributeValue("href"), n.AttributeValue("href"), target) + } } } - fmt.Fprintf(out, "\n") + if !ismap { + fmt.Fprintf(out, "\n") + } out.(http.Flusher).Flush() log.Printf("Done with caputure for %s\n", gourl) } @@ -196,6 +211,7 @@ func main() { rand.Seed(time.Now().UnixNano()) http.HandleFunc("/", pageServer) http.HandleFunc("/img/", imgServer) + http.HandleFunc("/map/", mapServer) http.HandleFunc("/favicon.ico", http.NotFound) http.HandleFunc("/halt", haltServer) log.Printf("Starting WRP http server on %s\n", addr) From b91bbed4a74f3932edae5d989cda6ddadc158553 Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Fri, 31 May 2019 18:28:48 -0700 Subject: [PATCH 29/55] readme fix --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 07e3c72..9393f82 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,13 @@ # WRP - Web Rendering Proxy + A HTTP proxy server that allows to use historical and obsolete web browsers on the modern web. It works by rendering the web page in to a GIF image associated with clickable imagemap of original web links. **You are looking at a GoLang / CDP branch of WRP.** **This code is under active development and not fully usable yet.** - ## Done so far + * basic browser-in-browser mode * screenshot and serve image+map via CDP * gif with Floyd–Steinberg dithering @@ -16,7 +17,8 @@ A HTTP proxy server that allows to use historical and obsolete web browsers on t * google search on input not starting with ^http ## Todo -* ISMAP + +* ISMAP - underway * net/url: invalid control character in URL on Windows * configurable color palete and quantization * real http proxy support @@ -26,4 +28,5 @@ A HTTP proxy server that allows to use historical and obsolete web browsers on t * chromedp logging, timeout, non-headless flags ## Python version + Check [master branch](https://github.com/tenox7/wrp/tree/master) for "stable" Python-Webkit version. \ No newline at end of file From c7fcea908f85ad97331c3352fe398f3cc371b652 Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Sat, 1 Jun 2019 01:17:41 -0700 Subject: [PATCH 30/55] changed names to prev/next due to issue with ie1.5 --- wrp.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/wrp.go b/wrp.go index f477bac..ef05f9f 100644 --- a/wrp.go +++ b/wrp.go @@ -51,9 +51,9 @@ func pageServer(out http.ResponseWriter, r *http.Request) { i = false } p, _ := strconv.ParseInt(r.FormValue("p"), 10, 64) - if r.FormValue("pg") == ">>" { + if r.FormValue("pg") == "Next" { p++ - } else if r.FormValue("pg") == "<<" { + } else if r.FormValue("pg") == "Prev" { p-- } else { p = 0 @@ -80,8 +80,8 @@ func pageServer(out http.ResponseWriter, r *http.Request) { fmt.Fprintf(out, "Height: \n", h) fmt.Fprintf(out, "Scale: \n", s) fmt.Fprintf(out, "Page: \n", p) - fmt.Fprintf(out, " %d \n", p) - fmt.Fprintf(out, ">\"> \n") + fmt.Fprintf(out, " %d \n", p) + fmt.Fprintf(out, " \n") fmt.Fprintf(out, "

\n") if len(u) > 4 { if strings.HasPrefix(u, "http") { @@ -109,7 +109,6 @@ func mapServer(out http.ResponseWriter, req *http.Request) { log.Printf("%s MAP Request for %s [%v]\n", req.RemoteAddr, req.URL.Path, req.URL.Query()) } - func haltServer(out http.ResponseWriter, req *http.Request) { log.Printf("%s Shutdown request received [%s]\n", req.RemoteAddr, req.URL.Path) out.Header().Set("Content-Type", "text/plain") From e48f0c9ff234d05c464720fa8a9024d7885cce67 Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Sat, 1 Jun 2019 01:17:50 -0700 Subject: [PATCH 31/55] formatting --- wrp.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wrp.go b/wrp.go index ef05f9f..a487f1e 100644 --- a/wrp.go +++ b/wrp.go @@ -188,8 +188,8 @@ func capture(gourl string, w int64, h int64, s float64, p int64, ismap bool, out if ismap { } else { - fmt.Fprintf(out, "\"%s\"\n", - b.Content[0]*s, b.Content[1]*s, b.Content[4]*s, b.Content[5]*s, n.AttributeValue("href"), n.AttributeValue("href"), target) + fmt.Fprintf(out, "\"%s\"\n", + b.Content[0]*s, b.Content[1]*s, b.Content[4]*s, b.Content[5]*s, n.AttributeValue("href"), n.AttributeValue("href"), target) } } } From a6df4cbec48f04b5655585ae99d503ca1e87e5ea Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Sat, 1 Jun 2019 01:26:18 -0700 Subject: [PATCH 32/55] readme update --- README.md | 5 ++--- pywebkit/README.md | 29 +++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 pywebkit/README.md diff --git a/README.md b/README.md index 9393f82..1156540 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,6 @@ A HTTP proxy server that allows to use historical and obsolete web browsers on t ## Todo * ISMAP - underway -* net/url: invalid control character in URL on Windows * configurable color palete and quantization * real http proxy support * option to encode as png/jpeg @@ -27,6 +26,6 @@ A HTTP proxy server that allows to use historical and obsolete web browsers on t * better http server shutdown * chromedp logging, timeout, non-headless flags -## Python version +## Old Python version -Check [master branch](https://github.com/tenox7/wrp/tree/master) for "stable" Python-Webkit version. \ No newline at end of file +Check [pywebkit/](/pywebkit) folder for the old Python-Webkit version. \ No newline at end of file diff --git a/pywebkit/README.md b/pywebkit/README.md new file mode 100644 index 0000000..0384ad4 --- /dev/null +++ b/pywebkit/README.md @@ -0,0 +1,29 @@ +# WRP - Web Rendering Proxy +A HTTP proxy server that allows to use historical and obsolete web browsers on the modern web. It works by rendering the web page in to a GIF/PNG/JPEG image associated with clickable imagemap of original web links. + + +# Current Status +* This is a WebKit / Python version of WRP. +* No longer maintained / supported. +* You should be using GoLang/CDP version instead. +* It mostly works for casual browsing but it's not very stable. +* Secure aka https/SSL/TLS websites might work with use of [sslstrip](https://moxie.org/software/sslstrip/) cheat (enabled by default). + + +## OS Support +WRP works on macOS (Mac OS X), Linux and FreeBSD. On macOS it uses Cocoa Webkit, on Linux/FreeBSD QT Webkit, for which needs PyQT4 or PyQT5. It does not work on Windows. Use Go/CDP version for that. + +## Installation +* macOS - should just work +* Linux/FreeBSD install `python-pyqt5.qtwebkit` and `sslstrip` +* For PythonMagick (Imagemagick library) install `python-pythonmagick` + +## Configuration +Edit wrp.py, scroll past Copyright section to find config parameters + +## Usage +Configure your web browser to use HTTP proxy at IP address and port where WRP is running. If using browsers prior to HTML 3.2, ISMAP option may need to be enabled. Check configuration. + +## More info and screenshots +* http://virtuallyfun.superglobalmegacorp.com/2014/03/11/web-rendering-proxy-update/ +* http://virtuallyfun.superglobalmegacorp.com/2014/03/03/surfing-modern-web-with-ancient-browsers/ From 6dfe7ddafc1010e291e74617a97c1be88abc5163 Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Sun, 2 Jun 2019 02:25:18 -0700 Subject: [PATCH 33/55] added more ismap cruft --- wrp.go | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/wrp.go b/wrp.go index a487f1e..25abdc4 100644 --- a/wrp.go +++ b/wrp.go @@ -32,10 +32,20 @@ import ( "github.com/chromedp/chromedp" ) +// Ismap for server side processing +type Ismap struct { + xmin int64 + ymin int64 + xmax int64 + ymax int64 + url string +} + var ( ctx context.Context cancel context.CancelFunc gifmap = make(map[string]bytes.Buffer) + ismap = make(map[string][]Ismap) ) func pageServer(out http.ResponseWriter, r *http.Request) { @@ -106,7 +116,7 @@ func imgServer(out http.ResponseWriter, req *http.Request) { } func mapServer(out http.ResponseWriter, req *http.Request) { - log.Printf("%s MAP Request for %s [%v]\n", req.RemoteAddr, req.URL.Path, req.URL.Query()) + log.Printf("%s MAP Request for %s [%+v]\n", req.RemoteAddr, req.URL.Path, req.URL.RawQuery) } func haltServer(out http.ResponseWriter, req *http.Request) { @@ -118,13 +128,14 @@ func haltServer(out http.ResponseWriter, req *http.Request) { os.Exit(0) } -func capture(gourl string, w int64, h int64, s float64, p int64, ismap bool, out http.ResponseWriter) { +func capture(gourl string, w int64, h int64, s float64, p int64, i bool, out http.ResponseWriter) { var nodes []*cdp.Node ctxx := chromedp.FromContext(ctx) var pngbuf []byte var gifbuf bytes.Buffer var loc string var res *runtime.RemoteObject + is := make([]Ismap, 0) log.Printf("Processing Caputure Request for %s\n", gourl) @@ -161,14 +172,17 @@ func capture(gourl string, w int64, h int64, s float64, p int64, ismap bool, out fmt.Fprintf(out, "
Unable to encode GIF:
%s
\n", err) return } - imgpath := fmt.Sprintf("/img/%04d.gif", rand.Intn(9999)) + seq := rand.Intn(9999) + imgpath := fmt.Sprintf("/img/%04d.gif", seq) + mappath := fmt.Sprintf("/map/%04d.map", seq) log.Printf("Encoded GIF image: %s, Size: %dKB\n", imgpath, len(gifbuf.Bytes())/1024) gifmap[imgpath] = gifbuf // Process Nodes base, _ := url.Parse(loc) - if ismap { - fmt.Fprintf(out, "\"wrp\"", imgpath) + if i { + fmt.Fprintf(out, "\"wrp\"", mappath, imgpath) + is = append(is, Ismap{xmin: -1, xmax: -1, ymin: -1, ymax: -1, url: "default"}) } else { fmt.Fprintf(out, "\"wrp\"\n\n", imgpath) } @@ -185,8 +199,11 @@ func capture(gourl string, w int64, h int64, s float64, p int64, ismap bool, out target := fmt.Sprintf("/?url=%s&w=%d&h=%d&s=%1.2f&", tgt, w, h, s) // no page# here if len(b.Content) > 6 && len(target) > 7 { - if ismap { - + if i { + is = append(is, Ismap{ + xmin: int64(b.Content[0] * s), ymin: int64(b.Content[1] * s), + xmax: int64(b.Content[4] * s), ymax: int64(b.Content[5] * s), + url: target}) } else { fmt.Fprintf(out, "\"%s\"\n", b.Content[0]*s, b.Content[1]*s, b.Content[4]*s, b.Content[5]*s, n.AttributeValue("href"), n.AttributeValue("href"), target) @@ -194,11 +211,12 @@ func capture(gourl string, w int64, h int64, s float64, p int64, ismap bool, out } } - if !ismap { + if !i { fmt.Fprintf(out, "\n") } out.(http.Flusher).Flush() log.Printf("Done with caputure for %s\n", gourl) + ismap[mappath] = is } func main() { From 3270bbcdd3b5ba565d37ad17d803572672cd531a Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Sun, 2 Jun 2019 15:55:58 -0700 Subject: [PATCH 34/55] ismap server cruft --- wrp.go | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/wrp.go b/wrp.go index 25abdc4..fb73bd3 100644 --- a/wrp.go +++ b/wrp.go @@ -116,7 +116,27 @@ func imgServer(out http.ResponseWriter, req *http.Request) { } func mapServer(out http.ResponseWriter, req *http.Request) { - log.Printf("%s MAP Request for %s [%+v]\n", req.RemoteAddr, req.URL.Path, req.URL.RawQuery) + log.Printf("%s ISMAP Request for %s [%+v]\n", req.RemoteAddr, req.URL.Path, req.URL.RawQuery) + var loc string + var x, y int64 + n, err := fmt.Sscanf(req.URL.RawQuery, "%d,%d", &x, &y) + if err != nil || n != 2 { + fmt.Fprintf(out, "n=%d, err=%s\n", n, err) + log.Printf("n=%d, err=%s\n", n, err) + return + } + is := ismap[req.URL.Path] + defer delete(ismap, req.URL.Path) + for _, i := range is { + if x >= i.xmin && x <= i.xmax && y >= i.ymin && y <= i.ymax { + loc = i.url + } + } + if len(loc) < 1 { + loc = is[0].url + } + log.Printf("ISMAP Redirect to: %s\n", loc) + http.Redirect(out, req, loc, 301) } func haltServer(out http.ResponseWriter, req *http.Request) { @@ -136,6 +156,7 @@ func capture(gourl string, w int64, h int64, s float64, p int64, i bool, out htt var loc string var res *runtime.RemoteObject is := make([]Ismap, 0) + var istr string log.Printf("Processing Caputure Request for %s\n", gourl) @@ -182,7 +203,8 @@ func capture(gourl string, w int64, h int64, s float64, p int64, i bool, out htt base, _ := url.Parse(loc) if i { fmt.Fprintf(out, "\"wrp\"", mappath, imgpath) - is = append(is, Ismap{xmin: -1, xmax: -1, ymin: -1, ymax: -1, url: "default"}) + is = append(is, Ismap{xmin: -1, xmax: -1, ymin: -1, ymax: -1, url: fmt.Sprintf("/?url=%s&w=%d&h=%d&s=%1.2f&i=on", loc, w, h, s)}) + istr = "i=on" } else { fmt.Fprintf(out, "\"wrp\"\n\n", imgpath) } @@ -196,7 +218,7 @@ func capture(gourl string, w int64, h int64, s float64, p int64, i bool, out htt if err != nil { continue } - target := fmt.Sprintf("/?url=%s&w=%d&h=%d&s=%1.2f&", tgt, w, h, s) // no page# here + target := fmt.Sprintf("/?url=%s&w=%d&h=%d&s=%1.2f&%s", tgt, w, h, s, istr) // no page# here if len(b.Content) > 6 && len(target) > 7 { if i { From 719a7fc560adcca0eae5d3040131838d39b36b69 Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Sun, 2 Jun 2019 16:05:36 -0700 Subject: [PATCH 35/55] better logging --- wrp.go | 50 ++++++++++++++++++++++++++------------------------ 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/wrp.go b/wrp.go index fb73bd3..29b6358 100644 --- a/wrp.go +++ b/wrp.go @@ -48,39 +48,39 @@ var ( ismap = make(map[string][]Ismap) ) -func pageServer(out http.ResponseWriter, r *http.Request) { - r.ParseForm() - u := r.FormValue("url") +func pageServer(out http.ResponseWriter, req *http.Request) { + req.ParseForm() + u := req.FormValue("url") var istr string var i bool - if r.FormValue("i") == "on" { + if req.FormValue("i") == "on" { istr = "CHECKED" i = true } else { istr = "" i = false } - p, _ := strconv.ParseInt(r.FormValue("p"), 10, 64) - if r.FormValue("pg") == "Next" { + p, _ := strconv.ParseInt(req.FormValue("p"), 10, 64) + if req.FormValue("pg") == "Next" { p++ - } else if r.FormValue("pg") == "Prev" { + } else if req.FormValue("pg") == "Prev" { p-- } else { p = 0 } - w, _ := strconv.ParseInt(r.FormValue("w"), 10, 64) + w, _ := strconv.ParseInt(req.FormValue("w"), 10, 64) if w < 10 { w = 1024 } - h, _ := strconv.ParseInt(r.FormValue("h"), 10, 64) + h, _ := strconv.ParseInt(req.FormValue("h"), 10, 64) if h < 10 { h = 768 } - s, _ := strconv.ParseFloat(r.FormValue("s"), 64) + s, _ := strconv.ParseFloat(req.FormValue("s"), 64) if s < 0.1 { s = 1.0 } - log.Printf("%s Page Reqest for url=\"%s\" [%s]\n", r.RemoteAddr, u, r.URL.Path) + log.Printf("%s Page Reqest for url=\"%s\" [%s]\n", req.RemoteAddr, u, req.URL.Path) out.Header().Set("Content-Type", "text/html") fmt.Fprintf(out, "\nWRP %s\n", u) fmt.Fprintf(out, "

URL/Search: ", u) @@ -95,9 +95,9 @@ func pageServer(out http.ResponseWriter, r *http.Request) { fmt.Fprintf(out, "

\n") if len(u) > 4 { if strings.HasPrefix(u, "http") { - capture(u, w, h, s, p, i, out) + capture(u, w, h, s, p, i, req.RemoteAddr, out) } else { - capture(fmt.Sprintf("http://www.google.com/search?q=%s", url.QueryEscape(u)), w, h, s, p, i, out) + capture(fmt.Sprintf("http://www.google.com/search?q=%s", url.QueryEscape(u)), w, h, s, p, i, req.RemoteAddr, out) } } else { fmt.Fprintf(out, "No URL or search query specified") @@ -122,7 +122,7 @@ func mapServer(out http.ResponseWriter, req *http.Request) { n, err := fmt.Sscanf(req.URL.RawQuery, "%d,%d", &x, &y) if err != nil || n != 2 { fmt.Fprintf(out, "n=%d, err=%s\n", n, err) - log.Printf("n=%d, err=%s\n", n, err) + log.Printf("%s ISMAP n=%d, err=%s\n", req.RemoteAddr, n, err) return } is := ismap[req.URL.Path] @@ -135,7 +135,7 @@ func mapServer(out http.ResponseWriter, req *http.Request) { if len(loc) < 1 { loc = is[0].url } - log.Printf("ISMAP Redirect to: %s\n", loc) + log.Printf("%s ISMAP Redirect to: %s\n", req.RemoteAddr, loc) http.Redirect(out, req, loc, 301) } @@ -148,7 +148,7 @@ func haltServer(out http.ResponseWriter, req *http.Request) { os.Exit(0) } -func capture(gourl string, w int64, h int64, s float64, p int64, i bool, out http.ResponseWriter) { +func capture(gourl string, w int64, h int64, s float64, p int64, i bool, c string, out http.ResponseWriter) { var nodes []*cdp.Node ctxx := chromedp.FromContext(ctx) var pngbuf []byte @@ -158,7 +158,7 @@ func capture(gourl string, w int64, h int64, s float64, p int64, i bool, out htt is := make([]Ismap, 0) var istr string - log.Printf("Processing Caputure Request for %s\n", gourl) + log.Printf("%s Processing Caputure Request for %s\n", c, gourl) // Run ChromeDP Magic err := chromedp.Run(ctx, @@ -171,32 +171,32 @@ func capture(gourl string, w int64, h int64, s float64, p int64, i bool, out htt chromedp.Nodes("a", &nodes, chromedp.ByQueryAll)) if err != nil { - log.Printf("%s", err) + log.Printf("%s %s", c, err) fmt.Fprintf(out, "
%s
", err) return } - log.Printf("Landed on: %s, Nodes: %d\n", loc, len(nodes)) + log.Printf("%s Landed on: %s, Nodes: %d\n", c, loc, len(nodes)) // Process Screenshot Image bytes.NewReader(pngbuf).Seek(0, 0) img, err := png.Decode(bytes.NewReader(pngbuf)) if err != nil { - log.Printf("Failed to decode screenshot: %s\n", err) + log.Printf("%s Failed to decode screenshot: %s\n", c, err) fmt.Fprintf(out, "
Unable to decode page screenshot:
%s
\n", err) return } gifbuf.Reset() err = gif.Encode(&gifbuf, img, nil) if err != nil { - log.Printf("Failed to encode GIF: %s\n", err) + log.Printf("%s Failed to encode GIF: %s\n", c, err) fmt.Fprintf(out, "
Unable to encode GIF:
%s
\n", err) return } seq := rand.Intn(9999) imgpath := fmt.Sprintf("/img/%04d.gif", seq) mappath := fmt.Sprintf("/map/%04d.map", seq) - log.Printf("Encoded GIF image: %s, Size: %dKB\n", imgpath, len(gifbuf.Bytes())/1024) + log.Printf("%s Encoded GIF image: %s, Size: %dKB\n", c, imgpath, len(gifbuf.Bytes())/1024) gifmap[imgpath] = gifbuf // Process Nodes @@ -233,11 +233,13 @@ func capture(gourl string, w int64, h int64, s float64, p int64, i bool, out htt } } - if !i { + if i { + log.Printf("%s Encoded ISMAP %s\n", c, mappath) + } else { fmt.Fprintf(out, "\n") } out.(http.Flusher).Flush() - log.Printf("Done with caputure for %s\n", gourl) + log.Printf("%s Done with caputure for %s\n", c, gourl) ismap[mappath] = is } From 253d36e96328db44de556256d9c2bd97445cc36b Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Sun, 2 Jun 2019 16:18:53 -0700 Subject: [PATCH 36/55] better handling of ismap variable --- wrp.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wrp.go b/wrp.go index 29b6358..6e23a79 100644 --- a/wrp.go +++ b/wrp.go @@ -156,7 +156,7 @@ func capture(gourl string, w int64, h int64, s float64, p int64, i bool, c strin var loc string var res *runtime.RemoteObject is := make([]Ismap, 0) - var istr string + var ion string log.Printf("%s Processing Caputure Request for %s\n", c, gourl) @@ -204,7 +204,7 @@ func capture(gourl string, w int64, h int64, s float64, p int64, i bool, c strin if i { fmt.Fprintf(out, "\"wrp\"", mappath, imgpath) is = append(is, Ismap{xmin: -1, xmax: -1, ymin: -1, ymax: -1, url: fmt.Sprintf("/?url=%s&w=%d&h=%d&s=%1.2f&i=on", loc, w, h, s)}) - istr = "i=on" + ion = "&i=on" } else { fmt.Fprintf(out, "\"wrp\"\n\n", imgpath) } @@ -218,7 +218,7 @@ func capture(gourl string, w int64, h int64, s float64, p int64, i bool, c strin if err != nil { continue } - target := fmt.Sprintf("/?url=%s&w=%d&h=%d&s=%1.2f&%s", tgt, w, h, s, istr) // no page# here + target := fmt.Sprintf("/?url=%s&w=%d&h=%d&s=%1.2f%s", tgt, w, h, s, ion) // no page# here if len(b.Content) > 6 && len(target) > 7 { if i { From 9358691ce589a2ffe53255d7291ca205e1eaaa2a Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Sun, 2 Jun 2019 16:19:08 -0700 Subject: [PATCH 37/55] version string --- wrp.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/wrp.go b/wrp.go index 6e23a79..3e6b351 100644 --- a/wrp.go +++ b/wrp.go @@ -42,20 +42,23 @@ type Ismap struct { } var ( - ctx context.Context - cancel context.CancelFunc - gifmap = make(map[string]bytes.Buffer) - ismap = make(map[string][]Ismap) + version = "3.0" + ctx context.Context + cancel context.CancelFunc + gifmap = make(map[string]bytes.Buffer) + ismap = make(map[string][]Ismap) ) func pageServer(out http.ResponseWriter, req *http.Request) { req.ParseForm() u := req.FormValue("url") var istr string + var ion string var i bool if req.FormValue("i") == "on" { istr = "CHECKED" i = true + ion = "&i=on" } else { istr = "" i = false @@ -102,7 +105,7 @@ func pageServer(out http.ResponseWriter, req *http.Request) { } else { fmt.Fprintf(out, "No URL or search query specified") } - fmt.Fprintf(out, "\n\n") + fmt.Fprintf(out, "\n

Web Rendering Proxy v%s\n\n", w, h, s, ion, version) } func imgServer(out http.ResponseWriter, req *http.Request) { From a8cc1b6b4e5a27b02abeda5d9c62f184ff538579 Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Sun, 2 Jun 2019 16:24:46 -0700 Subject: [PATCH 38/55] version branding etc --- wrp.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/wrp.go b/wrp.go index 3e6b351..826e6fb 100644 --- a/wrp.go +++ b/wrp.go @@ -85,7 +85,8 @@ func pageServer(out http.ResponseWriter, req *http.Request) { } log.Printf("%s Page Reqest for url=\"%s\" [%s]\n", req.RemoteAddr, u, req.URL.Path) out.Header().Set("Content-Type", "text/html") - fmt.Fprintf(out, "\nWRP %s\n", u) + fmt.Fprintf(out, "\n", version) + fmt.Fprintf(out, "\nWRP %s\n\n", u) fmt.Fprintf(out, "

URL/Search: ", u) fmt.Fprintf(out, "

\n") fmt.Fprintf(out, "ISMAP: \n", istr) @@ -105,7 +106,7 @@ func pageServer(out http.ResponseWriter, req *http.Request) { } else { fmt.Fprintf(out, "No URL or search query specified") } - fmt.Fprintf(out, "\n

Web Rendering Proxy v%s\n\n", w, h, s, ion, version) + fmt.Fprintf(out, "\n

Web Rendering Proxy Version %s\n\n", w, h, s, ion, version) } func imgServer(out http.ResponseWriter, req *http.Request) { @@ -258,6 +259,7 @@ func main() { http.HandleFunc("/map/", mapServer) http.HandleFunc("/favicon.ico", http.NotFound) http.HandleFunc("/halt", haltServer) + log.Printf("Web Rendering Proxy Version %s\n", version) log.Printf("Starting WRP http server on %s\n", addr) http.ListenAndServe(addr, nil) } From 791e87d7ed47fa553a7b32343220d9dbea83ed64 Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Sun, 2 Jun 2019 17:06:41 -0700 Subject: [PATCH 39/55] added number of colors --- wrp.go | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/wrp.go b/wrp.go index 826e6fb..b4b64a9 100644 --- a/wrp.go +++ b/wrp.go @@ -83,30 +83,35 @@ func pageServer(out http.ResponseWriter, req *http.Request) { if s < 0.1 { s = 1.0 } + c, _ := strconv.ParseInt(req.FormValue("c"), 10, 64) + if c < 2 || c > 256 { + c = 256 + } log.Printf("%s Page Reqest for url=\"%s\" [%s]\n", req.RemoteAddr, u, req.URL.Path) out.Header().Set("Content-Type", "text/html") fmt.Fprintf(out, "\n", version) fmt.Fprintf(out, "\nWRP %s\n\n", u) - fmt.Fprintf(out, "URL/Search: ", u) - fmt.Fprintf(out, "

\n") + fmt.Fprintf(out, "URL/Search: ", u) + fmt.Fprintf(out, " \n") + fmt.Fprintf(out, "Page: \n") + fmt.Fprintf(out, " \n", p) + fmt.Fprintf(out, "

\n") fmt.Fprintf(out, "ISMAP: \n", istr) fmt.Fprintf(out, "Width: \n", w) fmt.Fprintf(out, "Height: \n", h) fmt.Fprintf(out, "Scale: \n", s) - fmt.Fprintf(out, "Page: \n", p) - fmt.Fprintf(out, " %d \n", p) - fmt.Fprintf(out, " \n") + fmt.Fprintf(out, "Colors: \n", c) fmt.Fprintf(out, "

\n") if len(u) > 4 { if strings.HasPrefix(u, "http") { - capture(u, w, h, s, p, i, req.RemoteAddr, out) + capture(u, w, h, s, int(c), p, i, req.RemoteAddr, out) } else { - capture(fmt.Sprintf("http://www.google.com/search?q=%s", url.QueryEscape(u)), w, h, s, p, i, req.RemoteAddr, out) + capture(fmt.Sprintf("http://www.google.com/search?q=%s", url.QueryEscape(u)), w, h, s, int(c), p, i, req.RemoteAddr, out) } } else { fmt.Fprintf(out, "No URL or search query specified") } - fmt.Fprintf(out, "\n

Web Rendering Proxy Version %s\n\n", w, h, s, ion, version) + fmt.Fprintf(out, "\n

Web Rendering Proxy Version %s\n\n", w, h, s, c, ion, version) } func imgServer(out http.ResponseWriter, req *http.Request) { @@ -152,7 +157,7 @@ func haltServer(out http.ResponseWriter, req *http.Request) { os.Exit(0) } -func capture(gourl string, w int64, h int64, s float64, p int64, i bool, c string, out http.ResponseWriter) { +func capture(gourl string, w int64, h int64, s float64, co int, p int64, i bool, c string, out http.ResponseWriter) { var nodes []*cdp.Node ctxx := chromedp.FromContext(ctx) var pngbuf []byte @@ -191,7 +196,7 @@ func capture(gourl string, w int64, h int64, s float64, p int64, i bool, c strin return } gifbuf.Reset() - err = gif.Encode(&gifbuf, img, nil) + err = gif.Encode(&gifbuf, img, &gif.Options{NumColors: co}) if err != nil { log.Printf("%s Failed to encode GIF: %s\n", c, err) fmt.Fprintf(out, "
Unable to encode GIF:
%s
\n", err) @@ -207,7 +212,7 @@ func capture(gourl string, w int64, h int64, s float64, p int64, i bool, c strin base, _ := url.Parse(loc) if i { fmt.Fprintf(out, "\"wrp\"", mappath, imgpath) - is = append(is, Ismap{xmin: -1, xmax: -1, ymin: -1, ymax: -1, url: fmt.Sprintf("/?url=%s&w=%d&h=%d&s=%1.2f&i=on", loc, w, h, s)}) + is = append(is, Ismap{xmin: -1, xmax: -1, ymin: -1, ymax: -1, url: fmt.Sprintf("/?url=%s&w=%d&h=%d&s=%1.2f&c=%d&i=on", loc, w, h, s, co)}) ion = "&i=on" } else { fmt.Fprintf(out, "\"wrp\"\n\n", imgpath) @@ -222,7 +227,7 @@ func capture(gourl string, w int64, h int64, s float64, p int64, i bool, c strin if err != nil { continue } - target := fmt.Sprintf("/?url=%s&w=%d&h=%d&s=%1.2f%s", tgt, w, h, s, ion) // no page# here + target := fmt.Sprintf("/?url=%s&w=%d&h=%d&s=%1.2f&c=%d%s", tgt, w, h, s, co, ion) // no page# here if len(b.Content) > 6 && len(target) > 7 { if i { From 5dd4b5feab6fb74258fd88dabf5413109bb2e799 Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Sun, 2 Jun 2019 17:07:31 -0700 Subject: [PATCH 40/55] img border=0 --- wrp.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wrp.go b/wrp.go index b4b64a9..6736e64 100644 --- a/wrp.go +++ b/wrp.go @@ -211,11 +211,11 @@ func capture(gourl string, w int64, h int64, s float64, co int, p int64, i bool, // Process Nodes base, _ := url.Parse(loc) if i { - fmt.Fprintf(out, "\"wrp\"", mappath, imgpath) + fmt.Fprintf(out, "\"wrp\"", mappath, imgpath) is = append(is, Ismap{xmin: -1, xmax: -1, ymin: -1, ymax: -1, url: fmt.Sprintf("/?url=%s&w=%d&h=%d&s=%1.2f&c=%d&i=on", loc, w, h, s, co)}) ion = "&i=on" } else { - fmt.Fprintf(out, "\"wrp\"\n\n", imgpath) + fmt.Fprintf(out, "\"wrp\"\n\n", imgpath) } for _, n := range nodes { From 9c96a62816e90056ae9b365d2a086c2793c91355 Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Sun, 2 Jun 2019 22:23:41 -0700 Subject: [PATCH 41/55] dont crash on missing image or map --- wrp.go | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/wrp.go b/wrp.go index 6736e64..eedb049 100644 --- a/wrp.go +++ b/wrp.go @@ -116,7 +116,12 @@ func pageServer(out http.ResponseWriter, req *http.Request) { func imgServer(out http.ResponseWriter, req *http.Request) { log.Printf("%s IMG Request for %s\n", req.RemoteAddr, req.URL.Path) - gifbuf := gifmap[req.URL.Path] + gifbuf, ok := gifmap[req.URL.Path] + if !ok || gifbuf.Bytes() == nil { + fmt.Fprintf(out, "Unable to find image %s\n", req.URL.Path) + log.Printf("Unable to find image %s\n", req.URL.Path) + return + } defer delete(gifmap, req.URL.Path) out.Header().Set("Content-Type", "image/gif") out.Header().Set("Content-Length", strconv.Itoa(len(gifbuf.Bytes()))) @@ -134,7 +139,12 @@ func mapServer(out http.ResponseWriter, req *http.Request) { log.Printf("%s ISMAP n=%d, err=%s\n", req.RemoteAddr, n, err) return } - is := ismap[req.URL.Path] + is, ok := ismap[req.URL.Path] + if !ok || is == nil { + fmt.Fprintf(out, "Unable to find map %s\n", req.URL.Path) + log.Printf("Unable to find map %s\n", req.URL.Path) + return + } defer delete(ismap, req.URL.Path) for _, i := range is { if x >= i.xmin && x <= i.xmax && y >= i.ymin && y <= i.ymax { From a05a30c26fb429cf236735e15c79874845100aaa Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Mon, 3 Jun 2019 00:12:17 -0700 Subject: [PATCH 42/55] hack for ISMAP redirect --- wrp.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/wrp.go b/wrp.go index eedb049..4256032 100644 --- a/wrp.go +++ b/wrp.go @@ -45,6 +45,7 @@ var ( version = "3.0" ctx context.Context cancel context.CancelFunc + iaddr string gifmap = make(map[string]bytes.Buffer) ismap = make(map[string][]Ismap) ) @@ -154,8 +155,14 @@ func mapServer(out http.ResponseWriter, req *http.Request) { if len(loc) < 1 { loc = is[0].url } - log.Printf("%s ISMAP Redirect to: %s\n", req.RemoteAddr, loc) - http.Redirect(out, req, loc, 301) + log.Printf("%s ISMAP Redirect to: http://%s%s\n", req.RemoteAddr, iaddr, loc) + if len(iaddr) > 4 { + http.Redirect(out, req, fmt.Sprintf("http://%s%s", iaddr, loc), 301) + } else { + out.Header().Set("Content-Type", "text/html") + fmt.Fprintf(out, "\n\n\n\n", loc) + fmt.Fprintf(out, "\nIf not redirected click Here...\n\n\n", loc) + } } func haltServer(out http.ResponseWriter, req *http.Request) { @@ -267,6 +274,7 @@ func main() { defer cancel() var addr string flag.StringVar(&addr, "l", ":8080", "Listen address:port, default :8080") + flag.StringVar(&iaddr, "i", "", "Address:port prefix for ISMAP Redirect") flag.Parse() rand.Seed(time.Now().UnixNano()) http.HandleFunc("/", pageServer) From 02758bd039deca2ef0a6f9f65f45856402492f66 Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Mon, 3 Jun 2019 01:47:44 -0700 Subject: [PATCH 43/55] readme update --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1156540..270e766 100644 --- a/README.md +++ b/README.md @@ -15,16 +15,16 @@ A HTTP proxy server that allows to use historical and obsolete web browsers on t * resolve relative links * paginated scrolling * google search on input not starting with ^http +* ISMAP, although for a redirect to work `-i` flag must be specified + otherwise http-equiv refresh will be used and/or link provided ## Todo -* ISMAP - underway * configurable color palete and quantization * real http proxy support -* option to encode as png/jpeg * padded box model coordinates * better http server shutdown -* chromedp logging, timeout, non-headless flags +* chromedp logging, timeout, non-headless allocator flags ## Old Python version From 936cb97bc0abfa48a6cca102411abc9d15ff6e0d Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Mon, 3 Jun 2019 17:50:16 -0700 Subject: [PATCH 44/55] added headed mode and chromedp debug output --- wrp.go | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/wrp.go b/wrp.go index 4256032..55d72e3 100644 --- a/wrp.go +++ b/wrp.go @@ -270,12 +270,30 @@ func capture(gourl string, w int64, h int64, s float64, co int, p int64, i bool, } func main() { - ctx, cancel = chromedp.NewContext(context.Background()) - defer cancel() var addr string + var head,headless bool + var debug bool flag.StringVar(&addr, "l", ":8080", "Listen address:port, default :8080") - flag.StringVar(&iaddr, "i", "", "Address:port prefix for ISMAP Redirect") + flag.StringVar(&iaddr, "i", "", "Address:port prefix for ISMAP Redirect, otherwise http-equiv/redirect will be used") + flag.BoolVar(&head, "h", false, "Headed mode - display browser window") + flag.BoolVar(&debug, "d", false, "Debug ChromeDP") flag.Parse() + if head { + headless = false + } else { + headless = true + } + opts := append(chromedp.DefaultExecAllocatorOptions[:], + chromedp.Flag("headless", headless), + ) + actx, cancel := chromedp.NewExecAllocator(context.Background(), opts...) + defer cancel() + if debug { + ctx, cancel = chromedp.NewContext(actx, chromedp.WithDebugf(log.Printf)) + } else { + ctx, cancel = chromedp.NewContext(actx) + } + defer cancel() rand.Seed(time.Now().UnixNano()) http.HandleFunc("/", pageServer) http.HandleFunc("/img/", imgServer) From 0ee45139c31896e85069e0822496b20d6e5fe73f Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Mon, 3 Jun 2019 17:52:02 -0700 Subject: [PATCH 45/55] readme update --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 270e766..8a6a41b 100644 --- a/README.md +++ b/README.md @@ -11,12 +11,13 @@ A HTTP proxy server that allows to use historical and obsolete web browsers on t * basic browser-in-browser mode * screenshot and serve image+map via CDP * gif with Floyd–Steinberg dithering -* random image addressing +* multiple concurent client support * resolve relative links * paginated scrolling * google search on input not starting with ^http * ISMAP, although for a redirect to work `-i` flag must be specified otherwise http-equiv refresh will be used and/or link provided +* headed mode and chromedp debug output ## Todo @@ -24,7 +25,6 @@ A HTTP proxy server that allows to use historical and obsolete web browsers on t * real http proxy support * padded box model coordinates * better http server shutdown -* chromedp logging, timeout, non-headless allocator flags ## Old Python version From fabcd721c3a59b217eddccf9b25d0838588872e2 Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Tue, 4 Jun 2019 00:58:45 -0700 Subject: [PATCH 46/55] obtain server address from context, -l no longer needed --- wrp.go | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/wrp.go b/wrp.go index 55d72e3..1d33cdf 100644 --- a/wrp.go +++ b/wrp.go @@ -45,7 +45,6 @@ var ( version = "3.0" ctx context.Context cancel context.CancelFunc - iaddr string gifmap = make(map[string]bytes.Buffer) ismap = make(map[string][]Ismap) ) @@ -103,7 +102,7 @@ func pageServer(out http.ResponseWriter, req *http.Request) { fmt.Fprintf(out, "Scale: \n", s) fmt.Fprintf(out, "Colors: \n", c) fmt.Fprintf(out, "

\n") - if len(u) > 4 { + if len(u) > 1 { if strings.HasPrefix(u, "http") { capture(u, w, h, s, int(c), p, i, req.RemoteAddr, out) } else { @@ -155,14 +154,8 @@ func mapServer(out http.ResponseWriter, req *http.Request) { if len(loc) < 1 { loc = is[0].url } - log.Printf("%s ISMAP Redirect to: http://%s%s\n", req.RemoteAddr, iaddr, loc) - if len(iaddr) > 4 { - http.Redirect(out, req, fmt.Sprintf("http://%s%s", iaddr, loc), 301) - } else { - out.Header().Set("Content-Type", "text/html") - fmt.Fprintf(out, "\n\n\n\n", loc) - fmt.Fprintf(out, "\nIf not redirected click Here...\n\n\n", loc) - } + log.Printf("%s ISMAP Redirect to: http://%s%s\n", req.RemoteAddr, req.Context().Value(http.LocalAddrContextKey), loc) + http.Redirect(out, req, fmt.Sprintf("http://%s%s", req.Context().Value(http.LocalAddrContextKey), loc), 301) } func haltServer(out http.ResponseWriter, req *http.Request) { @@ -271,10 +264,9 @@ func capture(gourl string, w int64, h int64, s float64, co int, p int64, i bool, func main() { var addr string - var head,headless bool + var head, headless bool var debug bool flag.StringVar(&addr, "l", ":8080", "Listen address:port, default :8080") - flag.StringVar(&iaddr, "i", "", "Address:port prefix for ISMAP Redirect, otherwise http-equiv/redirect will be used") flag.BoolVar(&head, "h", false, "Headed mode - display browser window") flag.BoolVar(&debug, "d", false, "Debug ChromeDP") flag.Parse() @@ -284,7 +276,7 @@ func main() { headless = true } opts := append(chromedp.DefaultExecAllocatorOptions[:], - chromedp.Flag("headless", headless), + chromedp.Flag("headless", headless), ) actx, cancel := chromedp.NewExecAllocator(context.Background(), opts...) defer cancel() From d6005b52fd102128c1e7993b8958cbdd92bdf32a Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Tue, 4 Jun 2019 01:20:19 -0700 Subject: [PATCH 47/55] removed halt server --- wrp.go | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/wrp.go b/wrp.go index 1d33cdf..ee251ce 100644 --- a/wrp.go +++ b/wrp.go @@ -19,7 +19,6 @@ import ( "math/rand" "net/http" "net/url" - "os" "strconv" "strings" "time" @@ -43,8 +42,6 @@ type Ismap struct { var ( version = "3.0" - ctx context.Context - cancel context.CancelFunc gifmap = make(map[string]bytes.Buffer) ismap = make(map[string][]Ismap) ) @@ -158,15 +155,6 @@ func mapServer(out http.ResponseWriter, req *http.Request) { http.Redirect(out, req, fmt.Sprintf("http://%s%s", req.Context().Value(http.LocalAddrContextKey), loc), 301) } -func haltServer(out http.ResponseWriter, req *http.Request) { - log.Printf("%s Shutdown request received [%s]\n", req.RemoteAddr, req.URL.Path) - out.Header().Set("Content-Type", "text/plain") - fmt.Fprintf(out, "WRP Shutdown") - out.(http.Flusher).Flush() - cancel() - os.Exit(0) -} - func capture(gourl string, w int64, h int64, s float64, co int, p int64, i bool, c string, out http.ResponseWriter) { var nodes []*cdp.Node ctxx := chromedp.FromContext(ctx) @@ -281,9 +269,9 @@ func main() { actx, cancel := chromedp.NewExecAllocator(context.Background(), opts...) defer cancel() if debug { - ctx, cancel = chromedp.NewContext(actx, chromedp.WithDebugf(log.Printf)) + ctx, cancel := chromedp.NewContext(actx, chromedp.WithDebugf(log.Printf)) } else { - ctx, cancel = chromedp.NewContext(actx) + ctx, cancel := chromedp.NewContext(actx) } defer cancel() rand.Seed(time.Now().UnixNano()) @@ -291,7 +279,6 @@ func main() { http.HandleFunc("/img/", imgServer) http.HandleFunc("/map/", mapServer) http.HandleFunc("/favicon.ico", http.NotFound) - http.HandleFunc("/halt", haltServer) log.Printf("Web Rendering Proxy Version %s\n", version) log.Printf("Starting WRP http server on %s\n", addr) http.ListenAndServe(addr, nil) From 5f6a1154df0957262e7bad5723a2634e407f7171 Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Tue, 4 Jun 2019 01:20:41 -0700 Subject: [PATCH 48/55] single line toolbar --- wrp.go | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/wrp.go b/wrp.go index ee251ce..7cf41dd 100644 --- a/wrp.go +++ b/wrp.go @@ -61,9 +61,9 @@ func pageServer(out http.ResponseWriter, req *http.Request) { i = false } p, _ := strconv.ParseInt(req.FormValue("p"), 10, 64) - if req.FormValue("pg") == "Next" { + if req.FormValue("pg") == "Dn" { p++ - } else if req.FormValue("pg") == "Prev" { + } else if req.FormValue("pg") == "Up" { p-- } else { p = 0 @@ -88,17 +88,17 @@ func pageServer(out http.ResponseWriter, req *http.Request) { out.Header().Set("Content-Type", "text/html") fmt.Fprintf(out, "\n", version) fmt.Fprintf(out, "\nWRP %s\n\n", u) - fmt.Fprintf(out, "

URL/Search: ", u) + fmt.Fprintf(out, "", u) fmt.Fprintf(out, " \n") - fmt.Fprintf(out, "Page: \n") + fmt.Fprintf(out, " \n") fmt.Fprintf(out, " \n", p) - fmt.Fprintf(out, "

\n") - fmt.Fprintf(out, "ISMAP: \n", istr) - fmt.Fprintf(out, "Width: \n", w) - fmt.Fprintf(out, "Height: \n", h) - fmt.Fprintf(out, "Scale: \n", s) - fmt.Fprintf(out, "Colors: \n", c) - fmt.Fprintf(out, "

\n") + fmt.Fprintf(out, " \n") + fmt.Fprintf(out, "I \n", istr) + fmt.Fprintf(out, "W \n", w) + fmt.Fprintf(out, "H \n", h) + fmt.Fprintf(out, "S \n", s) + fmt.Fprintf(out, "C \n", c) + fmt.Fprintf(out, "
\n") if len(u) > 1 { if strings.HasPrefix(u, "http") { capture(u, w, h, s, int(c), p, i, req.RemoteAddr, out) From 69d4b39eff84dd9df9248d4fe803052f28efb130 Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Tue, 4 Jun 2019 01:23:46 -0700 Subject: [PATCH 49/55] restored context --- wrp.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/wrp.go b/wrp.go index 7cf41dd..5db9c5c 100644 --- a/wrp.go +++ b/wrp.go @@ -42,6 +42,8 @@ type Ismap struct { var ( version = "3.0" + ctx context.Context + cancel context.CancelFunc gifmap = make(map[string]bytes.Buffer) ismap = make(map[string][]Ismap) ) @@ -269,9 +271,9 @@ func main() { actx, cancel := chromedp.NewExecAllocator(context.Background(), opts...) defer cancel() if debug { - ctx, cancel := chromedp.NewContext(actx, chromedp.WithDebugf(log.Printf)) + ctx, cancel = chromedp.NewContext(actx, chromedp.WithDebugf(log.Printf)) } else { - ctx, cancel := chromedp.NewContext(actx) + ctx, cancel = chromedp.NewContext(actx) } defer cancel() rand.Seed(time.Now().UnixNano()) From 06317022a6dcf6aaf727af893e367f6170ab5eda Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Tue, 4 Jun 2019 01:30:00 -0700 Subject: [PATCH 50/55] better scaling --- wrp.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wrp.go b/wrp.go index 5db9c5c..442399d 100644 --- a/wrp.go +++ b/wrp.go @@ -171,7 +171,7 @@ func capture(gourl string, w int64, h int64, s float64, co int, p int64, i bool, // Run ChromeDP Magic err := chromedp.Run(ctx, - emulation.SetDeviceMetricsOverride(w, h, s, false), + emulation.SetDeviceMetricsOverride(int64(float64(w)/s), int64(float64(h)/s), s, false), chromedp.Navigate(gourl), chromedp.Evaluate(fmt.Sprintf("window.scrollTo(0, %d);", p*int64(float64(h)*float64(0.9))), &res), chromedp.Sleep(time.Second*1), From fb4848d235be0bd6e824d4e4143c8d61d9fb9edf Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Tue, 4 Jun 2019 01:42:22 -0700 Subject: [PATCH 51/55] added makefile --- Makefile | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..8be649a --- /dev/null +++ b/Makefile @@ -0,0 +1,22 @@ +all: linux freebsd openbsd macos windows rpi + +linux: + GOOS=linux GOARCH=amd64 go build -a -o wrp-linux wrp.go + +freebsd: + GOOS=freebsd GOARCH=amd64 go build -a -o wrp-freebsd wrp.go + +openbsd: + GOOS=openbsd GOARCH=amd64 go build -a -o wrp-openbsd wrp.go + +macos: + GOOS=darwin GOARCH=amd64 go build -a -o wrp-macos wrp.go + +windows: + GOOS=windows GOARCH=amd64 go build -a -o wrp-windows.exe wrp.go + +rpi: + GOOS=linux GOARCH=arm go build -a -o wrp-linux-rpi wrp.go + +clean: + rm -rf wrp-linux wrp-freebsd wrp-openbsd wrp-macos wrp-windows.exe wrp-linux-rpi From 6e75da10f3ef1e22abbb5f5609180d0da8b0d0f0 Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Tue, 4 Jun 2019 02:20:43 -0700 Subject: [PATCH 52/55] readme update --- README.md | 47 ++++++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 8a6a41b..0ed4675 100644 --- a/README.md +++ b/README.md @@ -2,30 +2,35 @@ A HTTP proxy server that allows to use historical and obsolete web browsers on the modern web. It works by rendering the web page in to a GIF image associated with clickable imagemap of original web links. -**You are looking at a GoLang / CDP branch of WRP.** +## Current Status -**This code is under active development and not fully usable yet.** - -## Done so far - -* basic browser-in-browser mode -* screenshot and serve image+map via CDP -* gif with Floyd–Steinberg dithering -* multiple concurent client support -* resolve relative links -* paginated scrolling -* google search on input not starting with ^http -* ISMAP, although for a redirect to work `-i` flag must be specified - otherwise http-equiv refresh will be used and/or link provided -* headed mode and chromedp debug output +* This is a new GoLang/ChdomeDP version. +* It's still lacking some features of the older [pywebkit/](/pywebkit) version (eg real http proxy mode and image manipulation) but it surpases it in terms of stability and usability. +* It's beta quality but I can fix/maintain the code unlike the older version. ## Todo -* configurable color palete and quantization -* real http proxy support -* padded box model coordinates -* better http server shutdown +* Configurable color palete and quantization. +* Real http proxy support via [goproxy](https://github.com/elazarl/goproxy) - if you really need a real proxy for now try [pywebkit/](/pywebkit) version. +* Padded box model coordinates. +* Input boxes support. However today you can cheat by using headed mode and input your data on the WRP server. -## Old Python version +## Usage -Check [pywebkit/](/pywebkit) folder for the old Python-Webkit version. \ No newline at end of file +1. [Download a WRP binary](https://github.com/tenox7/wrp/releases) and run on a server/gateway. +2. Point your legacy browser to the IP address:port of WRP server. +3. Type a search string or a http/https URL and click Go. +4. Adjust your screen width/heigh/scale to fit in your old browser. +5. For very very very old browsers such as Mosaic 2.x and IBM WebExplorer 1.x check the I checkbox to enable ISMAP mode. However this normally should not be needed. +6. Scroll web page by clicking Up/Down. To go to top enter 0 and click Go. + +## Flags +``` +-l listen address:port, default :8080 +-h headed mode, display browser window +-d chromedp debug logging +``` + +## More info and screenshots +* http://virtuallyfun.superglobalmegacorp.com/2014/03/11/web-rendering-proxy-update/ +* http://virtuallyfun.superglobalmegacorp.com/2014/03/03/surfing-modern-web-with-ancient-browsers/ From 99f4c8cac388e9936113cc34a5011a2a4cdf2f70 Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Tue, 4 Jun 2019 02:29:38 -0700 Subject: [PATCH 53/55] cleanup of pywebkit --- {pywebkit => old}/wrp.py | 0 pywebkit/Changelog.md | 36 ------------------------------------ pywebkit/README.md | 29 ----------------------------- 3 files changed, 65 deletions(-) rename {pywebkit => old}/wrp.py (100%) delete mode 100644 pywebkit/Changelog.md delete mode 100644 pywebkit/README.md diff --git a/pywebkit/wrp.py b/old/wrp.py similarity index 100% rename from pywebkit/wrp.py rename to old/wrp.py diff --git a/pywebkit/Changelog.md b/pywebkit/Changelog.md deleted file mode 100644 index 631d786..0000000 --- a/pywebkit/Changelog.md +++ /dev/null @@ -1,36 +0,0 @@ -## [2.0] - 2017-05-10 -### Added -- Support PyQt5 if available. -- Sets title from original one. -- Returns server errors as is. -- Download non-HTML files as is. -- For JavaScript capable browsers detect and automatically set view width. -- Add support for configuring which image format to use. -- Added support for PythonMagick. If found, allows to dither, color-reduce, or convert to grayscale or monochrome. -- If PythonMagick is found, render as PNG and convert to user-requested format using it, for better quality. - -### Changed -- Support www prepented to http://wrp.stop command. - -### Fixed -- Prevent python crashes with non-ASCII character in URLs. - -## [1.4] - 2017-01-22 -### Added -- Suport for ISMAP on Linux. -- Use queues instead of globals in Linux. - -## [1.3] - 2017-01-21 -### Changed -- Merged mac OS and Linux in a single executable. -- Use queues instead of globals in Linux. - -### Fixed -- Call PyQt to close application on http://wrp.stop - -## [1.2] - 2016-12-27 -### Added -- Support for IMAP on mac OS. - -### Changed -- Use queues instead of globals in mac OS. \ No newline at end of file diff --git a/pywebkit/README.md b/pywebkit/README.md deleted file mode 100644 index 0384ad4..0000000 --- a/pywebkit/README.md +++ /dev/null @@ -1,29 +0,0 @@ -# WRP - Web Rendering Proxy -A HTTP proxy server that allows to use historical and obsolete web browsers on the modern web. It works by rendering the web page in to a GIF/PNG/JPEG image associated with clickable imagemap of original web links. - - -# Current Status -* This is a WebKit / Python version of WRP. -* No longer maintained / supported. -* You should be using GoLang/CDP version instead. -* It mostly works for casual browsing but it's not very stable. -* Secure aka https/SSL/TLS websites might work with use of [sslstrip](https://moxie.org/software/sslstrip/) cheat (enabled by default). - - -## OS Support -WRP works on macOS (Mac OS X), Linux and FreeBSD. On macOS it uses Cocoa Webkit, on Linux/FreeBSD QT Webkit, for which needs PyQT4 or PyQT5. It does not work on Windows. Use Go/CDP version for that. - -## Installation -* macOS - should just work -* Linux/FreeBSD install `python-pyqt5.qtwebkit` and `sslstrip` -* For PythonMagick (Imagemagick library) install `python-pythonmagick` - -## Configuration -Edit wrp.py, scroll past Copyright section to find config parameters - -## Usage -Configure your web browser to use HTTP proxy at IP address and port where WRP is running. If using browsers prior to HTML 3.2, ISMAP option may need to be enabled. Check configuration. - -## More info and screenshots -* http://virtuallyfun.superglobalmegacorp.com/2014/03/11/web-rendering-proxy-update/ -* http://virtuallyfun.superglobalmegacorp.com/2014/03/03/surfing-modern-web-with-ancient-browsers/ From b5f5d6c57636fb5c375005f3404cf523a6e28744 Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Tue, 4 Jun 2019 02:31:11 -0700 Subject: [PATCH 54/55] readme update --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0ed4675..b9d5012 100644 --- a/README.md +++ b/README.md @@ -5,13 +5,13 @@ A HTTP proxy server that allows to use historical and obsolete web browsers on t ## Current Status * This is a new GoLang/ChdomeDP version. -* It's still lacking some features of the older [pywebkit/](/pywebkit) version (eg real http proxy mode and image manipulation) but it surpases it in terms of stability and usability. +* It's still lacking some features of the older [old/](/old) version (eg real http proxy mode and image manipulation) but it surpases it in terms of stability and usability. * It's beta quality but I can fix/maintain the code unlike the older version. ## Todo * Configurable color palete and quantization. -* Real http proxy support via [goproxy](https://github.com/elazarl/goproxy) - if you really need a real proxy for now try [pywebkit/](/pywebkit) version. +* Real http proxy support via [goproxy](https://github.com/elazarl/goproxy) - if you really need a real proxy for now try [old/](/old) version. * Padded box model coordinates. * Input boxes support. However today you can cheat by using headed mode and input your data on the WRP server. From 1b8d3544ed3ac1df8c97ccaf120e82aff5fb5ca2 Mon Sep 17 00:00:00 2001 From: Antoni Sawicki Date: Tue, 4 Jun 2019 23:35:40 -0700 Subject: [PATCH 55/55] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b9d5012..2a86ad0 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,8 @@ A HTTP proxy server that allows to use historical and obsolete web browsers on t ## Current Status -* This is a new GoLang/ChdomeDP version. -* It's still lacking some features of the older [old/](/old) version (eg real http proxy mode and image manipulation) but it surpases it in terms of stability and usability. +* This is the new GoLang/ChdomeDP version. +* It's still lacking some features of the [older version](/old) (eg real http proxy mode and image manipulation) but it surpases it in terms of stability and usability. * It's beta quality but I can fix/maintain the code unlike the older version. ## Todo