91 Commits
0.1 ... 4.2

Author SHA1 Message Date
Antoni Sawicki
6784d47892 readme update 2019-07-13 00:47:19 -07:00
Antoni Sawicki
c96eb9ae35 readme update 2019-07-13 00:45:01 -07:00
Antoni Sawicki
cebebfa408 ver bump 2019-07-13 00:42:27 -07:00
Antoni Sawicki
9d7bb952c5 added buttons for backspace, enter and arrows 2019-07-13 00:40:56 -07:00
Antoni Sawicki
fd4b7a381e Update README.md 2019-07-12 14:28:26 -07:00
Antoni Sawicki
b894c3f809 readme update 2019-07-12 02:36:04 -07:00
Antoni Sawicki
733efaea56 ver bump 2019-07-12 02:25:17 -07:00
Antoni Sawicki
ad668d1bca readme update 2019-07-12 02:20:56 -07:00
Antoni Sawicki
4e28a50a8d readme update 2019-07-12 02:10:51 -07:00
Antoni Sawicki
2fab53d8a3 readme update 2019-07-12 02:04:35 -07:00
Antoni Sawicki
9557f172ed Merge branch 'clicky' 2019-07-12 01:54:59 -07:00
Antoni Sawicki
a3661003b0 add support for sending keys in to web forms 2019-07-12 01:51:23 -07:00
Antoni Sawicki
7baaa0bd6e more clicky stuff 2019-07-10 23:58:40 -07:00
Antoni Sawicki
e5e5e321e8 more cruft to make clicks work 2019-07-10 18:09:20 -07:00
Antoni Sawicki
650ac026c3 comments 2019-07-10 01:20:18 -07:00
Antoni Sawicki
579d67f7fb made clicky work somehow 2019-07-10 01:01:40 -07:00
0502f7a99d Fix typo in README. 2019-06-27 00:24:21 +01:00
Antoni Sawicki
eb1476e579 fix 2019-06-26 01:25:50 -07:00
Antoni Sawicki
f599a51c8d added more clicky cruft 2019-06-26 01:07:13 -07:00
Antoni Sawicki
dedf7479b8 clicky data encoding 2019-06-25 17:07:43 -07:00
Antoni Sawicki
877c42a388 Update README.md 2019-06-25 12:22:45 -07:00
Antoni Sawicki
1f5592cbde initial 2019-06-24 00:40:34 -07:00
Antoni Sawicki
404af50aa1 Update README.md 2019-06-20 10:20:41 -07:00
Antoni Sawicki
bb59229438 Update README.md 2019-06-18 14:49:32 -07:00
Antoni Sawicki
faa0818f18 Update README.md 2019-06-18 14:48:55 -07:00
Antoni Sawicki
26f999f262 Update README.md 2019-06-18 14:48:39 -07:00
Antoni Sawicki
4d02165619 Update README.md 2019-06-18 14:46:19 -07:00
Antoni Sawicki
1578b14fcd Update README.md 2019-06-18 14:45:50 -07:00
Antoni Sawicki
ceb6a67ff3 added shutdown handler 2019-06-17 23:53:22 -07:00
Antoni Sawicki
3ee146dee7 fix for #38, changed Content to Padding 2019-06-17 00:39:32 -07:00
Antoni Sawicki
1e58c94263 fix for #40 hang on page with no nodes, added timeout for cdp.Nodes 2019-06-17 00:38:52 -07:00
Antoni Sawicki
ce51eb6226 because lint said so 2019-06-17 00:21:32 -07:00
Antoni Sawicki
1b68593fd2 makefile fix 2019-06-17 00:19:01 -07:00
Antoni Sawicki
8f16abacde Update README.md 2019-06-11 02:56:00 -07:00
Antoni Sawicki
b1e0b417c3 Update README.md 2019-06-10 15:14:17 -07:00
Antoni Sawicki
fd6f8592ef Update README.md 2019-06-10 15:12:27 -07:00
Antoni Sawicki
210a12fe3d Update README.md 2019-06-10 15:11:40 -07:00
Antoni Sawicki
92f3cb7aee create new context on context cancelled 2019-06-08 17:32:35 -07:00
Antoni Sawicki
d9381ef71a print error message when failed to start server 2019-06-08 17:30:30 -07:00
Antoni Sawicki
64f86b4fd9 Update README.md 2019-06-07 01:30:32 -07:00
Antoni Sawicki
2d41aa1044 Update README.md 2019-06-06 16:46:40 -07:00
Antoni Sawicki
6e43026100 Update README.md 2019-06-06 16:33:39 -07:00
Antoni Sawicki
3285a60c69 Update README.md 2019-06-06 02:05:03 -07:00
Antoni Sawicki
c873e53df0 Update README.md 2019-06-06 01:35:23 -07:00
Antoni Sawicki
dc6c8eca52 Merge pull request #39 from djames1/master
Add support for PPC64 Little Endian, fix incorrect spelling in wrp.go and README.md
2019-06-06 01:21:23 -07:00
Antoni Sawicki
849239fc8e added real color quantizer, number of colors works now 2019-06-06 01:06:36 -07:00
Daniel James
d71a48b746 README.md: Fix typos 2019-06-06 04:05:29 -04:00
Daniel James
2671fc236c wrp.go: Fixed typos 2019-06-06 04:01:19 -04:00
Daniel James
15b227ccf1 Makefile: Add support for PPC64LE 2019-06-06 04:00:07 -04:00
Antoni Sawicki
89f5f556f9 assign to map before flush 2019-06-06 00:15:57 -07:00
Antoni Sawicki
af3aef5c39 switched to websafe color pallete, disabled number of colors input box for now 2019-06-06 00:15:36 -07:00
Antoni Sawicki
26ad732d99 Update README.md 2019-06-05 01:42:17 -07:00
Antoni Sawicki
033f2f3578 Update README.md 2019-06-05 01:35:42 -07:00
Antoni Sawicki
277d70f4c3 Add files via upload 2019-06-05 01:34:41 -07:00
Antoni Sawicki
ab4122a9ba Update README.md 2019-06-05 01:20:14 -07:00
Antoni Sawicki
9bd1359a4d Update README.md 2019-06-05 01:19:07 -07:00
Antoni Sawicki
adff09c6b9 Update README.md 2019-06-05 01:18:23 -07:00
Antoni Sawicki
93c84fdfca Update README.md 2019-06-05 01:17:25 -07:00
Antoni Sawicki
de780b353d Delete .gitignore 2019-06-04 23:50:27 -07:00
Antoni Sawicki
d64ae7e5d0 readme update 2019-06-04 23:48:26 -07:00
Antoni Sawicki
6f702d74e5 merge 2019-06-04 23:47:00 -07:00
Antoni Sawicki
6a8f655953 delete old readme 2019-06-04 23:46:16 -07:00
Antoni Sawicki
1b8d3544ed Update README.md 2019-06-04 23:35:40 -07:00
Antoni Sawicki
b5f5d6c576 readme update 2019-06-04 02:31:11 -07:00
Antoni Sawicki
99f4c8cac3 cleanup of pywebkit 2019-06-04 02:29:38 -07:00
Antoni Sawicki
6e75da10f3 readme update 2019-06-04 02:20:43 -07:00
Antoni Sawicki
fb4848d235 added makefile 2019-06-04 01:42:22 -07:00
Antoni Sawicki
06317022a6 better scaling 2019-06-04 01:30:00 -07:00
Antoni Sawicki
69d4b39eff restored context 2019-06-04 01:23:46 -07:00
Antoni Sawicki
5f6a1154df single line toolbar 2019-06-04 01:20:41 -07:00
Antoni Sawicki
d6005b52fd removed halt server 2019-06-04 01:20:19 -07:00
Antoni Sawicki
fabcd721c3 obtain server address from context, -l no longer needed 2019-06-04 00:58:45 -07:00
Antoni Sawicki
0ee45139c3 readme update 2019-06-03 17:52:02 -07:00
Antoni Sawicki
936cb97bc0 added headed mode and chromedp debug output 2019-06-03 17:50:16 -07:00
Antoni Sawicki
02758bd039 readme update 2019-06-03 01:47:44 -07:00
Antoni Sawicki
dd1031a35b Merge pull request #32 from rakslice/encoding_fix
Fix unicode encode error
2019-06-03 01:41:00 -07:00
Antoni Sawicki
a05a30c26f hack for ISMAP redirect 2019-06-03 00:12:17 -07:00
Antoni Sawicki
9c96a62816 dont crash on missing image or map 2019-06-02 22:23:41 -07:00
Antoni Sawicki
5dd4b5feab img border=0 2019-06-02 17:07:31 -07:00
Antoni Sawicki
791e87d7ed added number of colors 2019-06-02 17:06:41 -07:00
Antoni Sawicki
a8cc1b6b4e version branding etc 2019-06-02 16:24:46 -07:00
Antoni Sawicki
9358691ce5 version string 2019-06-02 16:19:08 -07:00
Antoni Sawicki
253d36e963 better handling of ismap variable 2019-06-02 16:18:53 -07:00
Antoni Sawicki
719a7fc560 better logging 2019-06-02 16:05:36 -07:00
Antoni Sawicki
3270bbcdd3 ismap server cruft 2019-06-02 15:55:58 -07:00
rakslice
fec97243ba Fix unicode encode error 2019-06-02 14:02:56 -07:00
Antoni Sawicki
6dfe7ddafc added more ismap cruft 2019-06-02 02:25:18 -07:00
Antoni Sawicki
a6df4cbec4 readme update 2019-06-01 01:26:18 -07:00
Antoni Sawicki
e48f0c9ff2 formatting 2019-06-01 01:17:50 -07:00
Antoni Sawicki
c7fcea908f changed names to prev/next due to issue with ie1.5 2019-06-01 01:17:41 -07:00
Antoni Sawicki
aabc8cf021 link to dev branch 2019-05-29 18:54:04 -07:00
7 changed files with 265 additions and 195 deletions

1
.gitignore vendored
View File

@@ -1 +0,0 @@
.vscode

25
Makefile Normal file
View File

@@ -0,0 +1,25 @@
all: linux freebsd openbsd macos windows rpi
linux:
GOOS=linux GOARCH=amd64 go build -a -o wrp-linux wrp.go
linux-ppc64le:
GOOS=linux GOARCH=ppc64le go build -a -o wrp-linux-ppc64le wrp.go
rpi:
GOOS=linux GOARCH=arm go build -a -o wrp-linux-rpi 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
clean:
rm -rf wrp-linux wrp-freebsd wrp-openbsd wrp-macos wrp-windows.exe wrp-linux-rpi

View File

@@ -1,32 +1,42 @@
# 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.
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. It sends mouse clicks via ISMAP and keystrokes from a text box form input.
**You are looking at a GoLang / CDP branch of WRP.**
## Current Status
**This code is under active development and not fully usable yet.**
* This is a new reimplementation in GoLang/[ChromeDP](https://github.com/chromedp/chromedp). Python/Webkit being now deprecated.
* Beta but fully supported an maintained.
* Works as browser-in-browser. A real http proxy mode is being investigated. Check [issue #35](https://github.com/tenox7/wrp/issues/35) for updates.
* As of 4.1 supports clicking on non-link elements (eg. cookie warnings, dropdown menus, etc.) and sending keystrokes. Yes, you can login and use Gmail or play web based games from any old browser.
## Done so far
## Usage
* basic browser-in-browser mode
* screenshot and serve image+map via CDP
* gif with FloydSteinberg dithering
* random image addressing
* resolve relative links
* paginated scrolling
* google search on input not starting with ^http
1. [Download a WRP binary](https://github.com/tenox7/wrp/releases/) and run it on a machine that will become your WRP server.
2. Point your legacy browser to `http://address:port` of WRP server. Do not set or use it as a "Proxy Server" (yet).
3. Type a search string or a http/https URL and click GO.
4. Adjust your screen width/height/scale/#colors to fit in your old browser.
5. Scroll web page by clicking on the in-image scroll bar.
6. Send keystrokes by filling in K input box and pressing Go. You also have buttons for backspace, enter and arrow keys.
## Todo
![Internet Explorer 1.5 doing Gmail](wrp.png)
* 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
* padded box model coordinates
* better http server shutdown
* chromedp logging, timeout, non-headless flags
## Flags
```
-l listen address:port, default :8080
-h headed mode, display browser window
-d chromedp debug logging
```
## Python 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/
Check [master branch](https://github.com/tenox7/wrp/tree/master) for "stable" Python-Webkit version.
## Credits
* Uses [chromedp](https://github.com/chromedp), thanks to [mvdan](https://github.com/mvdan) for dealing with my issues
* Uses [go-quantize](https://github.com/ericpauley/go-quantize), thanks to [ericpauley](https://github.com/ericpauley) for developing the missing go quantizer
* Thanks to Jason Stevens of [Fun With Virtualization](https://virtuallyfun.com/) for graciously hosting my rumblings
## Legal Stuff
License: Apache 2.0
Copyright (c) 2013-2018 Antoni Sawicki
Copyright (c) 2019 Google LLC

View File

@@ -284,10 +284,10 @@ if sys.platform.startswith('linux') or sys.platform.startswith('freebsd'):
if ISMAP == True:
mapfile.write("rect %s %i,%i %i,%i\n".decode('utf-8', errors='ignore') % (turl, xmin, ymin, xmax, ymax))
else:
httpout.write("<AREA SHAPE=\"RECT\""
httpout.write(("<AREA SHAPE=\"RECT\""
" COORDS=\"%i,%i,%i,%i\""
" ALT=\"%s\" HREF=\"%s\">\n".decode('utf-8', errors='ignore')
% (xmin, ymin, xmax, ymax, turl, turl))
% (xmin, ymin, xmax, ymax, turl, turl)).encode("utf-8"))
if ISMAP != True:
httpout.write("</MAP>\n")

View File

@@ -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.

340
wrp.go
View File

@@ -12,92 +12,141 @@ import (
"context"
"flag"
"fmt"
_ "image"
"image/gif"
"image/png"
"log"
"math/rand"
"net/http"
"net/url"
"os"
"strconv"
"strings"
"time"
"github.com/chromedp/cdproto/emulation"
"github.com/chromedp/cdproto/runtime"
"github.com/chromedp/cdproto/cdp"
"github.com/chromedp/cdproto/dom"
"github.com/chromedp/chromedp"
"github.com/ericpauley/go-quantize/quantize"
)
var (
ctx context.Context
cancel context.CancelFunc
gifmap = make(map[string]bytes.Buffer)
version = "4.2"
srv http.Server
ctx context.Context
cancel context.CancelFunc
gifmap = make(map[string]bytes.Buffer)
ismap = make(map[string]wrpReq)
)
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
type wrpReq struct {
U string // url
W int64 // width
H int64 // height
S float64 // scale
C int64 // #colors
X int64 // mouseX
Y int64 // mouseY
K string // keys to send
F string // Fn buttons
}
func (w *wrpReq) parseForm(req *http.Request) {
req.ParseForm()
w.U = req.FormValue("url")
if len(w.U) > 1 && !strings.HasPrefix(w.U, "http") {
w.U = fmt.Sprintf("http://www.google.com/search?q=%s", url.QueryEscape(w.U))
}
p, _ := strconv.ParseInt(r.FormValue("p"), 10, 64)
if r.FormValue("pg") == ">>" {
p++
} else if r.FormValue("pg") == "<<" {
p--
} else {
p = 0
w.W, _ = strconv.ParseInt(req.FormValue("w"), 10, 64)
if w.W < 10 {
w.W = 1152
}
w, _ := strconv.ParseInt(r.FormValue("w"), 10, 64)
if w < 10 {
w = 1024
w.H, _ = strconv.ParseInt(req.FormValue("h"), 10, 64)
if w.H < 10 {
w.H = 600
}
h, _ := strconv.ParseInt(r.FormValue("h"), 10, 64)
if h < 10 {
h = 768
w.S, _ = strconv.ParseFloat(req.FormValue("s"), 64)
if w.S < 0.1 {
w.S = 1.0
}
s, _ := strconv.ParseFloat(r.FormValue("s"), 64)
if s < 0.1 {
s = 1.0
w.C, _ = strconv.ParseInt(req.FormValue("c"), 10, 64)
if w.C < 2 || w.C > 256 {
w.C = 256
}
log.Printf("%s Page Reqest for url=\"%s\" [%s]\n", r.RemoteAddr, u, r.URL.Path)
w.K = req.FormValue("k")
w.F = req.FormValue("Fn")
log.Printf("WrpReq from Form: %+v\n", w)
}
func (w wrpReq) printPage(out http.ResponseWriter) {
out.Header().Set("Content-Type", "text/html")
fmt.Fprintf(out, "<HTML>\n<HEAD><TITLE>WRP %s</TITLE></HEAD>\n<BODY BGCOLOR=\"#F0F0F0\">", u)
fmt.Fprintf(out, "<FORM ACTION=\"/\">URL/Search: <INPUT TYPE=\"TEXT\" NAME=\"url\" VALUE=\"%s\" SIZE=\"40\">", u)
fmt.Fprintf(out, "<INPUT TYPE=\"SUBMIT\" VALUE=\"Go\"><P>\n")
fmt.Fprintf(out, "ISMAP:<INPUT TYPE=\"CHECKBOX\" NAME=\"i\" %s> \n", istr)
fmt.Fprintf(out, "Width:<INPUT TYPE=\"TEXT\" NAME=\"w\" VALUE=\"%d\" SIZE=\"4\"> \n", w)
fmt.Fprintf(out, "Height:<INPUT TYPE=\"TEXT\" NAME=\"h\" VALUE=\"%d\" SIZE=\"4\"> \n", h)
fmt.Fprintf(out, "Scale:<INPUT TYPE=\"TEXT\" NAME=\"s\" VALUE=\"%1.2f\" SIZE=\"3\"> \n", s)
fmt.Fprintf(out, "Page:<INPUT TYPE=\"HIDDEN\" NAME=\"p\" VALUE=\"%d\"> \n", p)
fmt.Fprintf(out, "<INPUT TYPE=\"SUBMIT\" NAME=\"pg\" VALUE=\"<<\"> %d \n", p)
fmt.Fprintf(out, "<INPUT TYPE=\"SUBMIT\" NAME=\"pg\" VALUE=\">>\"> \n")
fmt.Fprintf(out, "</FORM><P>\n")
if len(u) > 4 {
if strings.HasPrefix(u, "http") {
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, i, out)
}
fmt.Fprintf(out, "<!-- Web Rendering Proxy Version %s -->\n", version)
fmt.Fprintf(out, "<HTML>\n<HEAD><TITLE>WRP %s</TITLE></HEAD>\n<BODY BGCOLOR=\"#F0F0F0\">\n", w.U)
fmt.Fprintf(out, "<FORM ACTION=\"/\" METHOD=\"POST\">\n")
fmt.Fprintf(out, "<INPUT TYPE=\"TEXT\" NAME=\"url\" VALUE=\"%s\" SIZE=\"10\">", w.U)
fmt.Fprintf(out, "<INPUT TYPE=\"SUBMIT\" VALUE=\"Go\">\n")
fmt.Fprintf(out, "<INPUT TYPE=\"SUBMIT\" NAME=\"Fn\" VALUE=\"Bk\">\n")
fmt.Fprintf(out, "W <INPUT TYPE=\"TEXT\" NAME=\"w\" VALUE=\"%d\" SIZE=\"4\"> \n", w.W)
fmt.Fprintf(out, "H <INPUT TYPE=\"TEXT\" NAME=\"h\" VALUE=\"%d\" SIZE=\"4\"> \n", w.H)
fmt.Fprintf(out, "S <INPUT TYPE=\"TEXT\" NAME=\"s\" VALUE=\"%1.2f\" SIZE=\"3\"> \n", w.S)
fmt.Fprintf(out, "C <INPUT TYPE=\"TEXT\" NAME=\"c\" VALUE=\"%d\" SIZE=\"3\">\n", w.C)
fmt.Fprintf(out, "K <INPUT TYPE=\"TEXT\" NAME=\"k\" VALUE=\"\" SIZE=\"4\"> \n")
fmt.Fprintf(out, "<INPUT TYPE=\"SUBMIT\" NAME=\"Fn\" VALUE=\"Bs\">\n")
fmt.Fprintf(out, "<INPUT TYPE=\"SUBMIT\" NAME=\"Fn\" VALUE=\"Rt\">\n")
fmt.Fprintf(out, "<INPUT TYPE=\"SUBMIT\" NAME=\"Fn\" VALUE=\"&lt;\">\n")
fmt.Fprintf(out, "<INPUT TYPE=\"SUBMIT\" NAME=\"Fn\" VALUE=\"^\">\n")
fmt.Fprintf(out, "<INPUT TYPE=\"SUBMIT\" NAME=\"Fn\" VALUE=\"v\">\n")
fmt.Fprintf(out, "<INPUT TYPE=\"SUBMIT\" NAME=\"Fn\" VALUE=\"&gt;\" SIZE=\"1\">\n")
fmt.Fprintf(out, "</FORM><BR>\n")
}
func (w wrpReq) printFooter(out http.ResponseWriter) {
fmt.Fprintf(out, "\n<P><A HREF=\"/?url=https://github.com/tenox7/wrp/&w=%d&h=%d&s=%1.2f&c=%d\">"+
"Web Rendering Proxy Version %s</A> | <A HREF=\"/shutdown/\">Shutdown WRP</A></BODY>\n</HTML>\n", w.W, w.H, w.S, w.C, version)
}
func pageServer(out http.ResponseWriter, req *http.Request) {
log.Printf("%s Page Request for %s [%+v]\n", req.RemoteAddr, req.URL.Path, req.URL.RawQuery)
var w wrpReq
w.parseForm(req)
if len(w.U) > 4 {
w.capture(req.RemoteAddr, out)
} else {
fmt.Fprintf(out, "No URL or search query specified")
w.printPage(out)
w.printFooter(out)
}
}
func mapServer(out http.ResponseWriter, req *http.Request) {
log.Printf("%s ISMAP Request for %s [%+v]\n", req.RemoteAddr, req.URL.Path, req.URL.RawQuery)
w, ok := ismap[req.URL.Path]
if !ok {
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)
n, err := fmt.Sscanf(req.URL.RawQuery, "%d,%d", &w.X, &w.Y)
if err != nil || n != 2 {
fmt.Fprintf(out, "n=%d, err=%s\n", n, err)
log.Printf("%s ISMAP n=%d, err=%s\n", req.RemoteAddr, n, err)
return
}
log.Printf("%s WrpReq from ISMAP: %+v\n", req.RemoteAddr, w)
if len(w.U) > 4 {
w.capture(req.RemoteAddr, out)
} else {
w.printPage(out)
w.printFooter(out)
}
fmt.Fprintf(out, "</BODY>\n</HTML>\n")
}
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())))
@@ -105,115 +154,138 @@ 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")
fmt.Fprintf(out, "WRP Shutdown")
out.(http.Flusher).Flush()
cancel()
os.Exit(0)
}
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)
func (w wrpReq) capture(c string, out http.ResponseWriter) {
var pngbuf []byte
var gifbuf bytes.Buffer
var loc string
var res *runtime.RemoteObject
var err error
log.Printf("Processing Caputure Request for %s\n", gourl)
// Run ChromeDP Magic
err := chromedp.Run(ctx,
emulation.SetDeviceMetricsOverride(w, h, 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),
chromedp.CaptureScreenshot(&pngbuf),
chromedp.Location(&loc),
chromedp.Nodes("a", &nodes, chromedp.ByQueryAll))
if w.X > 0 && w.Y > 0 {
log.Printf("%s Mouse Click %d,%d\n", c, w.X, w.Y)
err = chromedp.Run(ctx, chromedp.MouseClickXY(int64(float64(w.X)/w.S), int64(float64(w.Y)/w.S)))
} else if len(w.F) > 0 {
log.Printf("%s Button %v\n", c, w.F)
switch w.F {
case "Bk":
err = chromedp.Run(ctx, chromedp.NavigateBack())
case "Bs":
err = chromedp.Run(ctx, chromedp.KeyEvent("\b"))
case "Rt":
err = chromedp.Run(ctx, chromedp.KeyEvent("\r"))
case "<":
err = chromedp.Run(ctx, chromedp.KeyEvent("\u0302"))
case "^":
err = chromedp.Run(ctx, chromedp.KeyEvent("\u0304"))
case "v":
err = chromedp.Run(ctx, chromedp.KeyEvent("\u0301"))
case ">":
err = chromedp.Run(ctx, chromedp.KeyEvent("\u0303"))
}
} else if len(w.K) > 0 {
log.Printf("%s Sending Keys: %#v\n", c, w.K)
err = chromedp.Run(ctx, chromedp.KeyEvent(w.K))
} else {
log.Printf("%s Processing Capture Request for %s\n", c, w.U)
err = chromedp.Run(ctx,
emulation.SetDeviceMetricsOverride(int64(float64(w.W)/w.S), int64(float64(w.H)/w.S), w.S, false),
chromedp.Navigate(w.U),
)
}
if err != nil {
log.Printf("%s", err)
fmt.Fprintf(out, "<BR>%s<BR>", err)
if err.Error() == "context canceled" {
log.Printf("%s Contex cancelled, try again", c)
fmt.Fprintf(out, "<BR>%s<BR> -- restarting, try again", err)
ctx, cancel = chromedp.NewContext(context.Background())
} else {
log.Printf("%s %s", c, err)
fmt.Fprintf(out, "<BR>%s<BR>", err)
}
return
}
log.Printf("Landed on: %s, Nodes: %d\n", loc, len(nodes))
chromedp.Run(
ctx, chromedp.Sleep(time.Second*3),
chromedp.Location(&w.U),
)
log.Printf("%s Landed on: %s\n", c, w.U)
w.printPage(out)
// Process Screenshot Image
err = chromedp.Run(ctx, chromedp.CaptureScreenshot(&pngbuf))
if err != nil {
log.Printf("%s Failed to capture screenshot: %s\n", c, err)
fmt.Fprintf(out, "<BR>Unable to capture screenshot:<BR>%s<BR>\n", err)
return
}
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, "<BR>Unable to decode page screenshot:<BR>%s<BR>\n", err)
return
}
gifbuf.Reset()
err = gif.Encode(&gifbuf, img, nil)
err = gif.Encode(&gifbuf, img, &gif.Options{NumColors: int(w.C), Quantizer: quantize.MedianCutQuantizer{}})
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, "<BR>Unable to encode GIF:<BR>%s<BR>\n", err)
return
}
imgpath := fmt.Sprintf("/img/%04d.gif", rand.Intn(9999))
log.Printf("Encoded GIF image: %s, Size: %dKB\n", imgpath, len(gifbuf.Bytes())/1024)
// Compose map and gif
seq := rand.Intn(9999)
imgpath := fmt.Sprintf("/img/%04d.gif", seq)
mappath := fmt.Sprintf("/map/%04d.map", seq)
gifmap[imgpath] = gifbuf
ismap[mappath] = w
log.Printf("%s Encoded GIF image: %s, Size: %dKB, Colors: %d\n", c, imgpath, len(gifbuf.Bytes())/1024, w.C)
fmt.Fprintf(out, "<A HREF=\"%s\"><IMG SRC=\"%s\" ALT=\"wrp\" BORDER=\"0\" ISMAP></A>", mappath, imgpath)
w.printFooter(out)
log.Printf("%s Done with caputure for %s\n", c, w.U)
}
// Process Nodes
base, _ := url.Parse(loc)
if ismap {
fmt.Fprintf(out, "<A HREF=\"/map/123.map\"><IMG SRC=\"%s\" ALT=\"wrp\" ISMAP></A>", imgpath)
} else {
fmt.Fprintf(out, "<IMG SRC=\"%s\" ALT=\"wrp\" USEMAP=\"#map\">\n<MAP NAME=\"map\">\n", imgpath)
}
for _, n := range nodes {
b, err := dom.GetBoxModel().WithNodeID(n.NodeID).Do(cdp.WithExecutor(ctx, ctxx.Target))
if err != nil {
continue
}
tgt, err := base.Parse(n.AttributeValue("href"))
if err != nil {
continue
}
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, "<AREA SHAPE=\"RECT\" COORDS=\"%.f,%.f,%.f,%.f\" ALT=\"%s\" TITLE=\"%s\" HREF=\"%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)
}
}
}
if !ismap {
fmt.Fprintf(out, "</MAP>\n")
}
out.(http.Flusher).Flush()
log.Printf("Done with caputure for %s\n", gourl)
func haltServer(out http.ResponseWriter, req *http.Request) {
log.Printf("%s Shutdown Request for %s\n", req.RemoteAddr, req.URL.Path)
defer cancel()
srv.Shutdown(context.Background())
}
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.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),
chromedp.Flag("hide-scrollbars", false),
)
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)
http.HandleFunc("/map/", mapServer)
http.HandleFunc("/img/", imgServer)
http.HandleFunc("/shutdown/", haltServer)
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)
srv.Addr = addr
err := srv.ListenAndServe()
if err != nil {
log.Fatal(err)
}
}

BIN
wrp.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 303 KiB