diff --git a/cdp.go b/cdp.go index 4e04a2f..a698d72 100644 --- a/cdp.go +++ b/cdp.go @@ -13,6 +13,8 @@ import ( "math" "math/rand" "net/http" + "strconv" + "strings" "time" "github.com/chromedp/cdproto/css" @@ -261,3 +263,32 @@ func mapServer(w http.ResponseWriter, r *http.Request) { rq.navigate() // TODO: if error from navigate do not capture rq.captureScreenshot() } + +// Process HTTP requests for images '/img/' url +// TODO: merge this with html mode IMGZ +func imgServer(w http.ResponseWriter, r *http.Request) { + log.Printf("%s IMG Request for %s\n", r.RemoteAddr, r.URL.Path) + imgBuf, ok := img[r.URL.Path] + if !ok || imgBuf.Bytes() == nil { + fmt.Fprintf(w, "Unable to find image %s\n", r.URL.Path) + log.Printf("%s Unable to find image %s\n", r.RemoteAddr, r.URL.Path) + return + } + if !*noDel { + defer delete(img, r.URL.Path) + } + switch { + case strings.HasSuffix(r.URL.Path, ".gif"): + w.Header().Set("Content-Type", "image/gif") + case strings.HasSuffix(r.URL.Path, ".png"): + w.Header().Set("Content-Type", "image/png") + case strings.HasSuffix(r.URL.Path, ".jpg"): + w.Header().Set("Content-Type", "image/jpeg") + } + w.Header().Set("Content-Length", strconv.Itoa(len(imgBuf.Bytes()))) + w.Header().Set("Cache-Control", "max-age=0") + w.Header().Set("Expires", "-1") + w.Header().Set("Pragma", "no-cache") + w.Write(imgBuf.Bytes()) + w.(http.Flusher).Flush() +} diff --git a/txt.go b/txt.go index f1791f8..d1f4df6 100644 --- a/txt.go +++ b/txt.go @@ -7,6 +7,8 @@ package main // - garbage collector / delete old images from map // - add referer header // - svg support +// - incorrect cert support in both markdown and image download +// - unify cdp and txt image handlers // - BOG: DomainFromURL always prefixes with http instead of https // reproduces on vsi vms docs // - BUG: markdown table errors @@ -184,18 +186,6 @@ func (t *astTransformer) Transform(node *ast.Document, reader text.Reader, pc pa }) } -func asciify(s []byte) []byte { - a := make([]byte, len(s)) - for i := 0; i < len(s); i++ { - if s[i] > 127 { - a[i] = '.' - continue - } - a[i] = s[i] - } - return a -} - func (rq *wrpReq) captureMarkdown() { log.Printf("Processing Markdown conversion request for %v", rq.url) // TODO: bug - DomainFromURL always prefixes with http:// instead of https diff --git a/util.go b/util.go new file mode 100644 index 0000000..c746e18 --- /dev/null +++ b/util.go @@ -0,0 +1,89 @@ +// wrp utility functions +package main + +import ( + "image" + "image/color/palette" + "log" + "net" + "strings" + + "github.com/MaxHalford/halfgone" + "github.com/soniakeys/quant/median" +) + +func printIPs(b string) { + ap := strings.Split(b, ":") + if len(ap) < 1 { + log.Fatal("Wrong format of ipaddress:port") + } + log.Printf("Listen address: %v", b) + if ap[0] != "" && ap[0] != "0.0.0.0" { + return + } + a, err := net.InterfaceAddrs() + if err != nil { + log.Print("Unable to get interfaces: ", err) + return + } + var m string + for _, i := range a { + n, ok := i.(*net.IPNet) + if !ok || n.IP.IsLoopback() || strings.Contains(n.IP.String(), ":") { + continue + } + m = m + n.IP.String() + " " + } + log.Print("My IP addresses: ", m) +} + +func gifPalette(i image.Image, n int64) image.Image { + switch n { + case 2: + i = halfgone.FloydSteinbergDitherer{}.Apply(halfgone.ImageToGray(i)) + case 216: + var FastGifLut = [256]int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5} + r := i.Bounds() + // NOTE: the color index computation below works only for palette.WebSafe! + p := image.NewPaletted(r, palette.WebSafe) + if i64, ok := i.(image.RGBA64Image); ok { + for y := r.Min.Y; y < r.Max.Y; y++ { + for x := r.Min.X; x < r.Max.X; x++ { + c := i64.RGBA64At(x, y) + r6 := FastGifLut[c.R>>8] + g6 := FastGifLut[c.G>>8] + b6 := FastGifLut[c.B>>8] + p.SetColorIndex(x, y, uint8(36*r6+6*g6+b6)) + } + } + } else { + for y := r.Min.Y; y < r.Max.Y; y++ { + for x := r.Min.X; x < r.Max.X; x++ { + c := i.At(x, y) + r, g, b, _ := c.RGBA() + r6 := FastGifLut[r&0xff] + g6 := FastGifLut[g&0xff] + b6 := FastGifLut[b&0xff] + p.SetColorIndex(x, y, uint8(36*r6+6*g6+b6)) + } + } + } + i = p + default: + q := median.Quantizer(n) + i = q.Paletted(i) + } + return i +} + +func asciify(s []byte) []byte { + a := make([]byte, len(s)) + for i := 0; i < len(s); i++ { + if s[i] > 127 { + a[i] = '.' + continue + } + a[i] = s[i] + } + return a +} diff --git a/wrp.go b/wrp.go index c8fcc23..1005476 100644 --- a/wrp.go +++ b/wrp.go @@ -13,11 +13,8 @@ import ( "embed" "flag" "fmt" - "image" - "image/color/palette" "io" "log" - "net" "net/http" "net/url" "os" @@ -28,9 +25,6 @@ import ( "syscall" "text/template" "time" - - "github.com/MaxHalford/halfgone" - "github.com/soniakeys/quant/median" ) const version = "4.8.0" @@ -68,6 +62,9 @@ type geom struct { c int64 } +// TODO: there is a major overlap/duplication/triplication +// between the 3 data structs, perhps we could reduce to just one? + // Data for html template type uiData struct { Version string @@ -200,45 +197,6 @@ func (rq *wrpReq) printHTML(p printParams) { } } -func gifPalette(i image.Image, n int64) image.Image { - switch n { - case 2: - i = halfgone.FloydSteinbergDitherer{}.Apply(halfgone.ImageToGray(i)) - case 216: - var FastGifLut = [256]int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5} - r := i.Bounds() - // NOTE: the color index computation below works only for palette.WebSafe! - p := image.NewPaletted(r, palette.WebSafe) - if i64, ok := i.(image.RGBA64Image); ok { - for y := r.Min.Y; y < r.Max.Y; y++ { - for x := r.Min.X; x < r.Max.X; x++ { - c := i64.RGBA64At(x, y) - r6 := FastGifLut[c.R>>8] - g6 := FastGifLut[c.G>>8] - b6 := FastGifLut[c.B>>8] - p.SetColorIndex(x, y, uint8(36*r6+6*g6+b6)) - } - } - } else { - for y := r.Min.Y; y < r.Max.Y; y++ { - for x := r.Min.X; x < r.Max.X; x++ { - c := i.At(x, y) - r, g, b, _ := c.RGBA() - r6 := FastGifLut[r&0xff] - g6 := FastGifLut[g&0xff] - b6 := FastGifLut[b&0xff] - p.SetColorIndex(x, y, uint8(36*r6+6*g6+b6)) - } - } - } - i = p - default: - q := median.Quantizer(n) - i = q.Paletted(i) - } - return i -} - // Process HTTP requests to WRP '/' url func pageServer(w http.ResponseWriter, r *http.Request) { log.Printf("%s Page Request for %s [%+v]\n", r.RemoteAddr, r.URL.Path, r.URL.RawQuery) @@ -259,35 +217,6 @@ func pageServer(w http.ResponseWriter, r *http.Request) { rq.captureScreenshot() } -// Process HTTP requests for images '/img/' url -// TODO: merge this with html mode IMGZ -func imgServer(w http.ResponseWriter, r *http.Request) { - log.Printf("%s IMG Request for %s\n", r.RemoteAddr, r.URL.Path) - imgBuf, ok := img[r.URL.Path] - if !ok || imgBuf.Bytes() == nil { - fmt.Fprintf(w, "Unable to find image %s\n", r.URL.Path) - log.Printf("%s Unable to find image %s\n", r.RemoteAddr, r.URL.Path) - return - } - if !*noDel { - defer delete(img, r.URL.Path) - } - switch { - case strings.HasSuffix(r.URL.Path, ".gif"): - w.Header().Set("Content-Type", "image/gif") - case strings.HasSuffix(r.URL.Path, ".png"): - w.Header().Set("Content-Type", "image/png") - case strings.HasSuffix(r.URL.Path, ".jpg"): - w.Header().Set("Content-Type", "image/jpeg") - } - w.Header().Set("Content-Length", strconv.Itoa(len(imgBuf.Bytes()))) - w.Header().Set("Cache-Control", "max-age=0") - w.Header().Set("Expires", "-1") - w.Header().Set("Pragma", "no-cache") - w.Write(imgBuf.Bytes()) - w.(http.Flusher).Flush() -} - // Process HTTP requests for Shutdown via '/shutdown/' url func haltServer(w http.ResponseWriter, r *http.Request) { log.Printf("%s Shutdown Request for %s\n", r.RemoteAddr, r.URL.Path) @@ -332,32 +261,6 @@ builtin: return string(tmpl) } -// Print my own IP addresses -func printIPs(b string) { - ap := strings.Split(b, ":") - if len(ap) < 1 { - log.Fatal("Wrong format of ipaddress:port") - } - log.Printf("Listen address: %v", b) - if ap[0] != "" && ap[0] != "0.0.0.0" { - return - } - a, err := net.InterfaceAddrs() - if err != nil { - log.Print("Unable to get interfaces: ", err) - return - } - var m string - for _, i := range a { - n, ok := i.(*net.IPNet) - if !ok || n.IP.IsLoopback() || strings.Contains(n.IP.String(), ":") { - continue - } - m = m + n.IP.String() + " " - } - log.Print("My IP addresses: ", m) -} - // Main func main() { var err error