From e85a6b1c934d1070e40d11ad94b3ad4d79bdc9b2 Mon Sep 17 00:00:00 2001 From: Feuerfuchs Date: Sun, 17 Nov 2019 10:14:58 +0100 Subject: Report template errors, add support for start page --- cmd/gopherproxy/main.go | 3 +- gopherproxy.go | 97 ++++++++++++++------ startpage.txt | 1 + template.go | 229 ++++++++++++++++++++++++------------------------ 4 files changed, 187 insertions(+), 143 deletions(-) create mode 100644 startpage.txt diff --git a/cmd/gopherproxy/main.go b/cmd/gopherproxy/main.go index 66248ac..e84e978 100644 --- a/cmd/gopherproxy/main.go +++ b/cmd/gopherproxy/main.go @@ -13,7 +13,6 @@ var ( bind = flag.String("bind", "0.0.0.0:8000", "[int]:port to bind to") robotsfile = flag.String("robots-file", "robots.txt", "robots.txt file") robotsdebug = flag.Bool("robots-debug", false, "print output about ignored robots.txt") - uri = flag.String("uri", "gopher/floodgap.com", "/:[port] to proxy to") vipsconcurrency = flag.Int("vips-concurrency", 1, "Concurrency level of libvips") ) @@ -21,5 +20,5 @@ func main() { flag.Parse() // Use a config struct - log.Fatal(gopherproxy.ListenAndServe(*bind, *robotsfile, *robotsdebug, *vipsconcurrency, *uri)) + log.Fatal(gopherproxy.ListenAndServe(*bind, *robotsfile, *robotsdebug, *vipsconcurrency)) } diff --git a/gopherproxy.go b/gopherproxy.go index 751cebf..2a6358c 100644 --- a/gopherproxy.go +++ b/gopherproxy.go @@ -177,9 +177,19 @@ func parseGeminiDocument(body *bytes.Buffer, uri string, hostport string) (items return } -func DefaultHandler(tpl *template.Template, uri string) http.HandlerFunc { +func DefaultHandler(tpl *template.Template, startpagetext string, assetList AssetList) http.HandlerFunc { return func(w http.ResponseWriter, req *http.Request) { - http.Redirect(w, req, "/"+uri, http.StatusFound) + if err := tpl.Execute(w, struct { + Title string + URI string + Assets AssetList + RawText string + Lines []Item + Error bool + Protocol string + }{"Gopher/Gemini proxy", "", assetList, startpagetext, nil, false, "startpage"}); err != nil { + log.Println("Template error: " + err.Error()) + } } } @@ -188,7 +198,7 @@ func DefaultHandler(tpl *template.Template, uri string) http.HandlerFunc { // to the request path and renders the content using the provided template. // The optional robots parameters points to a robotstxt.RobotsData struct // to test user agents against a configurable robotst.txt file. -func GopherHandler(tpl *template.Template, robotsdata *robotstxt.RobotsData, assetList AssetList, robotsdebug bool, uri string) http.HandlerFunc { +func GopherHandler(tpl *template.Template, robotsdata *robotstxt.RobotsData, assetList AssetList, robotsdebug bool) http.HandlerFunc { return func(w http.ResponseWriter, req *http.Request) { agent := req.UserAgent() path := strings.TrimPrefix(req.URL.Path, "/gopher/") @@ -201,7 +211,7 @@ func GopherHandler(tpl *template.Template, robotsdata *robotstxt.RobotsData, ass hostport := parts[0] if len(hostport) == 0 { - http.Redirect(w, req, "/"+uri, http.StatusFound) + http.Redirect(w, req, "/", http.StatusFound) return } @@ -215,7 +225,7 @@ func GopherHandler(tpl *template.Template, robotsdata *robotstxt.RobotsData, ass uri, err := url.QueryUnescape(strings.Join(parts[1:], "/")) if err != nil { - tpl.Execute(w, struct { + if e := tpl.Execute(w, struct { Title string URI string Assets AssetList @@ -223,7 +233,10 @@ func GopherHandler(tpl *template.Template, robotsdata *robotstxt.RobotsData, ass Lines []Item Error bool Protocol string - }{title, hostport, assetList, fmt.Sprintf("Error: %s", err), nil, true, "gopher"}) + }{title, hostport, assetList, fmt.Sprintf("Error: %s", err), nil, true, "gopher"}); e != nil { + log.Println("Template error: " + e.Error()) + log.Println(err.Error()) + } return } @@ -241,7 +254,7 @@ func GopherHandler(tpl *template.Template, robotsdata *robotstxt.RobotsData, ass ) if err != nil { - tpl.Execute(w, struct { + if e := tpl.Execute(w, struct { Title string URI string Assets AssetList @@ -249,7 +262,9 @@ func GopherHandler(tpl *template.Template, robotsdata *robotstxt.RobotsData, ass Lines []Item Error bool Protocol string - }{title, fmt.Sprintf("%s/%s", hostport, uri), assetList, fmt.Sprintf("Error: %s", err), nil, true, "gopher"}) + }{title, fmt.Sprintf("%s/%s", hostport, uri), assetList, fmt.Sprintf("Error: %s", err), nil, true, "gopher"}); e != nil { + log.Println("Template error: " + e.Error()) + } return } @@ -259,7 +274,7 @@ func GopherHandler(tpl *template.Template, robotsdata *robotstxt.RobotsData, ass } else if strings.HasPrefix(parts[1], "0") && !strings.HasSuffix(uri, ".xml") && !strings.HasSuffix(uri, ".asc") { buf := new(bytes.Buffer) buf.ReadFrom(res.Body) - tpl.Execute(w, struct { + if err := tpl.Execute(w, struct { Title string URI string Assets AssetList @@ -267,7 +282,9 @@ func GopherHandler(tpl *template.Template, robotsdata *robotstxt.RobotsData, ass Lines []Item Error bool Protocol string - }{title, fmt.Sprintf("%s/%s", hostport, uri), assetList, buf.String(), nil, false, "gopher"}) + }{title, fmt.Sprintf("%s/%s", hostport, uri), assetList, buf.String(), nil, false, "gopher"}); err != nil { + log.Println("Template error: " + err.Error()) + } } else if strings.HasPrefix(parts[1], "T") { _, _, err = vips.NewTransform(). Load(res.Body). @@ -281,7 +298,7 @@ func GopherHandler(tpl *template.Template, robotsdata *robotstxt.RobotsData, ass } } else { if err := renderGopherDirectory(w, tpl, assetList, uri, hostport, res.Dir); err != nil { - tpl.Execute(w, struct { + if e := tpl.Execute(w, struct { Title string URI string Assets AssetList @@ -289,13 +306,16 @@ func GopherHandler(tpl *template.Template, robotsdata *robotstxt.RobotsData, ass Lines []Item Error bool Protocol string - }{title, fmt.Sprintf("%s/%s", hostport, uri), assetList, fmt.Sprintf("Error: %s", err), nil, true, "gopher"}) + }{title, fmt.Sprintf("%s/%s", hostport, uri), assetList, fmt.Sprintf("Error: %s", err), nil, true, "gopher"}); e != nil { + log.Println("Template error: " + e.Error()) + log.Println(e.Error()) + } } } } } -func GeminiHandler(tpl *template.Template, robotsdata *robotstxt.RobotsData, assetList AssetList, robotsdebug bool, uri string) http.HandlerFunc { +func GeminiHandler(tpl *template.Template, robotsdata *robotstxt.RobotsData, assetList AssetList, robotsdebug bool) http.HandlerFunc { return func(w http.ResponseWriter, req *http.Request) { agent := req.UserAgent() path := strings.TrimPrefix(req.URL.Path, "/gemini/") @@ -308,7 +328,7 @@ func GeminiHandler(tpl *template.Template, robotsdata *robotstxt.RobotsData, ass hostport := parts[0] if len(hostport) == 0 { - http.Redirect(w, req, "/"+uri, http.StatusFound) + http.Redirect(w, req, "/", http.StatusFound) return } @@ -322,7 +342,7 @@ func GeminiHandler(tpl *template.Template, robotsdata *robotstxt.RobotsData, ass uri, err := url.QueryUnescape(strings.Join(parts[1:], "/")) if err != nil { - tpl.Execute(w, struct { + if e := tpl.Execute(w, struct { Title string URI string Assets AssetList @@ -330,7 +350,10 @@ func GeminiHandler(tpl *template.Template, robotsdata *robotstxt.RobotsData, ass Lines []Item Error bool Protocol string - }{title, hostport, assetList, fmt.Sprintf("Error: %s", err), nil, true, "gemini"}) + }{title, hostport, assetList, fmt.Sprintf("Error: %s", err), nil, true, "gemini"}); e != nil { + log.Println("Template error: " + e.Error()) + log.Println(err.Error()) + } return } @@ -348,7 +371,7 @@ func GeminiHandler(tpl *template.Template, robotsdata *robotstxt.RobotsData, ass ) if err != nil { - tpl.Execute(w, struct { + if e := tpl.Execute(w, struct { Title string URI string Assets AssetList @@ -356,7 +379,10 @@ func GeminiHandler(tpl *template.Template, robotsdata *robotstxt.RobotsData, ass Lines []Item Error bool Protocol string - }{title, fmt.Sprintf("%s/%s", hostport, uri), assetList, fmt.Sprintf("Error: %s", err), nil, true, "gemini"}) + }{title, fmt.Sprintf("%s/%s", hostport, uri), assetList, fmt.Sprintf("Error: %s", err), nil, true, "gemini"}); e != nil { + log.Println("Template error: " + e.Error()) + log.Println(err.Error()) + } return } @@ -367,7 +393,7 @@ func GeminiHandler(tpl *template.Template, robotsdata *robotstxt.RobotsData, ass uri, )) if err != nil { - tpl.Execute(w, struct { + if e := tpl.Execute(w, struct { Title string URI string Assets AssetList @@ -375,7 +401,10 @@ func GeminiHandler(tpl *template.Template, robotsdata *robotstxt.RobotsData, ass Lines []Item Error bool Protocol string - }{title, fmt.Sprintf("%s/%s", hostport, uri), assetList, fmt.Sprintf("Error: %s", err), nil, true, "gemini"}) + }{title, fmt.Sprintf("%s/%s", hostport, uri), assetList, fmt.Sprintf("Error: %s", err), nil, true, "gemini"}); e != nil { + log.Println("Template error: " + e.Error()) + log.Println(err.Error()) + } return } @@ -384,7 +413,7 @@ func GeminiHandler(tpl *template.Template, robotsdata *robotstxt.RobotsData, ass } if int(res.Header.Status/10) != 2 { - tpl.Execute(w, struct { + if err := tpl.Execute(w, struct { Title string URI string Assets AssetList @@ -392,7 +421,9 @@ func GeminiHandler(tpl *template.Template, robotsdata *robotstxt.RobotsData, ass Lines []Item Error bool Protocol string - }{title, fmt.Sprintf("%s/%s", hostport, uri), assetList, fmt.Sprintf("Error %d: %s", res.Header.Status, res.Header.Meta), nil, true, "gemini"}) + }{title, fmt.Sprintf("%s/%s", hostport, uri), assetList, fmt.Sprintf("Error %d: %s", res.Header.Status, res.Header.Meta), nil, true, "gemini"}); err != nil { + log.Println("Template error: " + err.Error()) + } return } @@ -423,7 +454,7 @@ func GeminiHandler(tpl *template.Template, robotsdata *robotstxt.RobotsData, ass rawText = buf.String() } - tpl.Execute(w, struct { + if err := tpl.Execute(w, struct { Title string URI string Assets AssetList @@ -431,7 +462,9 @@ func GeminiHandler(tpl *template.Template, robotsdata *robotstxt.RobotsData, ass Lines []Item Error bool Protocol string - }{title, fmt.Sprintf("%s/%s", hostport, uri), assetList, rawText, items, false, "gemini"}) + }{title, fmt.Sprintf("%s/%s", hostport, uri), assetList, rawText, items, false, "gemini"}); err != nil { + log.Println("Template error: " + err.Error()) + } } else { io.Copy(w, res.Body) } @@ -506,7 +539,7 @@ func FontHandler(woff2 bool, fontdata []byte) http.HandlerFunc { // specified by the request. The robots argument is a pointer to // a robotstxt.RobotsData struct for testing user agents against // a configurable robots.txt file. -func ListenAndServe(bind, robotsfile string, robotsdebug bool, vipsconcurrency int, uri string) error { +func ListenAndServe(bind, robotsfile string, robotsdebug bool, vipsconcurrency int) error { var ( tpl *template.Template robotsdata *robotstxt.RobotsData @@ -567,6 +600,12 @@ func ListenAndServe(bind, robotsfile string, robotsdebug bool, vipsconcurrency i favicondata = []byte{} } + startpagedata, err := ioutil.ReadFile("startpage.txt") + if err != nil { + startpagedata = []byte{} + } + startpagetext := string(startpagedata) + tpldata, err := ioutil.ReadFile(".template") if err == nil { tpltext = string(tpldata) @@ -622,9 +661,11 @@ func ListenAndServe(bind, robotsfile string, robotsdebug bool, vipsconcurrency i ConcurrencyLevel: vipsconcurrency, }) - http.Handle("/", gziphandler.GzipHandler(DefaultHandler(tpl, uri))) - http.Handle("/gopher/", gziphandler.GzipHandler(GopherHandler(tpl, robotsdata, AssetList{styleAsset, jsAsset, fontwAsset, fontw2Asset, propfontwAsset, propfontw2Asset}, robotsdebug, uri))) - http.Handle("/gemini/", gziphandler.GzipHandler(GeminiHandler(tpl, robotsdata, AssetList{styleAsset, jsAsset, fontwAsset, fontw2Asset, propfontwAsset, propfontw2Asset}, robotsdebug, uri))) + assets := AssetList{styleAsset, jsAsset, fontwAsset, fontw2Asset, propfontwAsset, propfontw2Asset} + + http.Handle("/", gziphandler.GzipHandler(DefaultHandler(tpl, startpagetext, assets))) + http.Handle("/gopher/", gziphandler.GzipHandler(GopherHandler(tpl, robotsdata, assets, robotsdebug))) + http.Handle("/gemini/", gziphandler.GzipHandler(GeminiHandler(tpl, robotsdata, assets, robotsdebug))) http.Handle("/robots.txt", gziphandler.GzipHandler(RobotsTxtHandler(robotstxtdata))) http.Handle("/favicon.ico", gziphandler.GzipHandler(FaviconHandler(favicondata))) http.Handle(styleAsset, gziphandler.GzipHandler(StyleHandler(styledata))) diff --git a/startpage.txt b/startpage.txt new file mode 100644 index 0000000..b411de6 --- /dev/null +++ b/startpage.txt @@ -0,0 +1 @@ +>>>> Gopher/Gemini proxy <<<< diff --git a/template.go b/template.go index 3bd8950..7ddc460 100644 --- a/template.go +++ b/template.go @@ -2,118 +2,121 @@ package gopherproxy var tpltext = ` - - - - {{ .Title }} - {{ .Protocol | title }} proxy - - - - -
-
- {{- $page := . -}} - {{- $href := "" -}} - {{- $uriParts := split .URI "/" -}} - {{- $uriLast := $uriParts | last -}} - {{- $uriParts = $uriParts | pop -}} - {{- if eq $uriLast "" -}} - {{- $uriLast = $uriParts | last -}} - {{- $uriParts = $uriParts | pop -}} - {{- end -}} + + + + {{ .Title }} - {{ .Protocol | title }} proxy + + + + +
+
+ {{ .Protocol }}://:// + + {{- if .URI -}} + {{- $page := . -}} + {{- $href := printf "/%s" .Protocol -}} + {{- $uriParts := split .URI "/" -}} + + {{- $uriLast := $uriParts | last -}} + {{- $uriParts = $uriParts | pop -}} + {{- if eq $uriLast "" -}} + {{- $uriLast = $uriParts | last -}} + {{- $uriParts = $uriParts | pop -}} + {{- end -}} - {{ .Protocol }}://:// - {{- $href = printf "%s/%s" $href .Protocol -}} - {{- range $i, $part := $uriParts -}} - {{- if and (eq $page.Protocol "gopher") (eq $i 1) -}} - {{- $href = printf "%s/1" $href -}} - {{- $part = $part | trimLeftChar -}} - {{- if not (eq $part "") -}} - {{- $href = printf "%s/%s" $href $part -}} - /{{ $part }} - {{- end -}} - {{- else -}} - {{- $href = printf "%s/%s" $href . -}} - {{- if ne $i 0 -}} - / - {{- end -}} - {{ . }} - {{- end -}} - {{- end -}} - {{- if ne (len $uriParts) 0 -}} - / - {{- end -}} - {{- if and (eq $page.Protocol "gopher") (eq (len $uriParts) 1) -}} - {{- $uriLast = $uriLast | trimLeftChar -}} - {{- end -}} - {{ $uriLast }} -
-
- {{- if and (not .Lines) (not .Error) (eq .Protocol "gopher") -}} - - {{- end -}} -
-
-
-
-
-        {{- if .Lines -}}
-          {{- $content := "" -}}
-          {{- range .Lines -}}
-            {{- if ne $content "" -}}
-              {{- $content = printf "%s\n" $content -}}
-            {{- end -}}
-            {{- if .Link -}}
-              {{- $content = printf "%s%s" $content (printf "%s  %s" .Type .Type .Link (.Text | HTMLEscape)) -}}
-            {{- else -}}
-              {{- $content = printf "%s%s" $content (printf "     %s" (.Text | HTMLEscape)) -}}
-            {{- end -}}
-          {{- end -}}
-          {{- $content | safeHtml -}}
-        {{- else -}}
-          {{- .RawText -}}
-        {{- end -}}
-      
-
- - - + {{- range $i, $part := $uriParts -}} + {{- if and (eq $page.Protocol "gopher") (eq $i 1) -}} + {{- $href = printf "%s/1" $href -}} + {{- $part = $part | trimLeftChar -}} + {{- if not (eq $part "") -}} + {{- $href = printf "%s/%s" $href $part -}} + /{{ $part }} + {{- end -}} + {{- else -}} + {{- $href = printf "%s/%s" $href . -}} + {{- if ne $i 0 -}} + / + {{- end -}} + {{ . }} + {{- end -}} + {{- end -}} + {{- if ne (len $uriParts) 0 -}} + / + {{- end -}} + {{- if and (eq $page.Protocol "gopher") (eq (len $uriParts) 1) -}} + {{- $uriLast = $uriLast | trimLeftChar -}} + {{- end -}} + {{ $uriLast }} + {{- end -}} +
+
+ {{- if and (not .Lines) (not .Error) (eq .Protocol "gopher") -}} + + {{- end -}} +
+
+
+
+
+				{{- if .Lines -}}
+					{{- $content := "" -}}
+					{{- range .Lines -}}
+						{{- if ne $content "" -}}
+							{{- $content = printf "%s\n" $content -}}
+						{{- end -}}
+						{{- if .Link -}}
+							{{- $content = printf "%s%s" $content (printf "%s  %s" .Type .Type .Link (.Text | HTMLEscape)) -}}
+						{{- else -}}
+							{{- $content = printf "%s%s" $content (printf "     %s" (.Text | HTMLEscape)) -}}
+						{{- end -}}
+					{{- end -}}
+					{{- $content | safeHtml -}}
+				{{- else -}}
+					{{- .RawText -}}
+				{{- end -}}
+			
+
+ + + ` -- cgit v1.2.3-70-g09d2