From c51b6d8887c38d538c0e2db2adfe0848fc662986 Mon Sep 17 00:00:00 2001 From: James Mills Date: Fri, 30 Sep 2016 19:40:24 -0700 Subject: Migrated to a Library structure with gopherproxy cmd for reuse by gopherclient --- cmd/gopherproxy/main.go | 19 +++++++ gopherproxy.go | 131 ++++++++++++++++++++++++++++++++++++++++++++++++ main.go | 126 ---------------------------------------------- template.go | 2 +- 4 files changed, 151 insertions(+), 127 deletions(-) create mode 100644 cmd/gopherproxy/main.go create mode 100644 gopherproxy.go delete mode 100644 main.go diff --git a/cmd/gopherproxy/main.go b/cmd/gopherproxy/main.go new file mode 100644 index 0000000..bc5050e --- /dev/null +++ b/cmd/gopherproxy/main.go @@ -0,0 +1,19 @@ +package main + +import ( + "flag" + "log" + + "github.com/prologic/gopherproxy" +) + +var ( + bind = flag.String("bind", ":80", "[int]:port to bind to") + uri = flag.String("uri", "127.0.0.1:70", ":[port] to proxy to") +) + +func main() { + flag.Parse() + + log.Fatal(gopherproxy.ListenAndServe(*bind, *uri)) +} diff --git a/gopherproxy.go b/gopherproxy.go new file mode 100644 index 0000000..4a2255f --- /dev/null +++ b/gopherproxy.go @@ -0,0 +1,131 @@ +package gopherproxy + +import ( + "fmt" + "html/template" + "io" + "io/ioutil" + "log" + "net/http" + "net/url" + "strings" + + "github.com/prologic/go-gopher" +) + +type tplRow struct { + Link template.URL + Type string + Text string +} + +// Handler is an aliased type for the standard HTTP handler functions +type Handler func(w http.ResponseWriter, req *http.Request) + +func renderDirectory(w http.ResponseWriter, tpl *template.Template, hostport string, d gopher.Directory) error { + out := make([]tplRow, len(d)) + + for i, x := range d { + tr := tplRow{ + Text: x.Description, + Type: x.Type.String(), + } + + if x.Type == gopher.INFO { + out[i] = tr + continue + } + + if strings.HasPrefix(x.Selector, "URL:") { + tr.Link = template.URL(x.Selector[4:]) + } else { + var hostport string + if x.Port == 70 { + hostport = x.Host + } else { + hostport = fmt.Sprintf("%s:%d", x.Host, x.Port) + } + path := url.QueryEscape(x.Selector) + path = strings.Replace(path, "%2F", "/", -1) + tr.Link = template.URL( + fmt.Sprintf( + "/%s/%s%s", + hostport, + string(byte(x.Type)), + path, + ), + ) + } + + out[i] = tr + } + + return tpl.Execute(w, struct { + Title string + Lines []tplRow + }{hostport, out}) +} + +// MakeGopherProxyHandler returns a Handler that proxies requests +// to the specified Gopher server as denoated by the first argument +// to the request path and renders the content using the provided template. +func MakeGopherProxyHandler(tpl *template.Template, uri string) Handler { + return func(w http.ResponseWriter, req *http.Request) { + parts := strings.Split(strings.TrimPrefix(req.URL.Path, "/"), "/") + hostport := parts[0] + path := strings.Join(parts[1:], "/") + + if len(hostport) == 0 { + http.Redirect(w, req, "/"+uri, http.StatusFound) + return + } + + uri, err := url.QueryUnescape(path) + if err != nil { + io.WriteString(w, fmt.Sprintf("Error:
%s
", err)) + return + } + res, err := gopher.Get( + fmt.Sprintf( + "gopher://%s/%s", + hostport, + uri, + ), + ) + if err != nil { + io.WriteString(w, fmt.Sprintf("Error:
%s
", err)) + return + } + + if res.Body != nil { + io.Copy(w, res.Body) + } else { + if err := renderDirectory(w, tpl, hostport, res.Dir); err != nil { + io.WriteString(w, fmt.Sprintf("Error:
%s
", err)) + return + } + } + } +} + +// ListenAndServe creates a listening HTTP server bound to +// the interface specified by bind and sets up a Gopher to HTTP +// proxy proxying requests as requested and by default will prozy +// to a Gopher server address specified by uri if no servers is +// specified by the request. +func ListenAndServe(bind, uri string) error { + var tpl *template.Template + + tpldata, err := ioutil.ReadFile(".template") + if err == nil { + tpltext = string(tpldata) + } + + tpl, err = template.New("gophermenu").Parse(tpltext) + if err != nil { + log.Fatal(err) + } + + http.HandleFunc("/", MakeGopherProxyHandler(tpl, uri)) + return http.ListenAndServe(bind, nil) +} diff --git a/main.go b/main.go deleted file mode 100644 index 1da5f8e..0000000 --- a/main.go +++ /dev/null @@ -1,126 +0,0 @@ -package main - -import ( - "flag" - "fmt" - "html/template" - "io" - "io/ioutil" - "log" - "net/http" - "net/url" - "strings" - - "github.com/prologic/go-gopher" -) - -var ( - bind = flag.String("bind", ":80", "[int]:port to bind to") - uri = flag.String("uri", "127.0.0.1:70", ":[port] to proxy to") - - tpl *template.Template -) - -type tplRow struct { - Link template.URL - Type string - Text string -} - -func renderDirectory(w http.ResponseWriter, tpl *template.Template, hostport string, d gopher.Directory) error { - out := make([]tplRow, len(d)) - - for i, x := range d { - tr := tplRow{ - Text: x.Description, - Type: x.Type.String(), - } - - if x.Type == gopher.INFO { - out[i] = tr - continue - } - - if strings.HasPrefix(x.Selector, "URL:") { - tr.Link = template.URL(x.Selector[4:]) - } else { - var hostport string - if x.Port == 70 { - hostport = x.Host - } else { - hostport = fmt.Sprintf("%s:%d", x.Host, x.Port) - } - path := url.QueryEscape(x.Selector) - path = strings.Replace(path, "%2F", "/", -1) - tr.Link = template.URL( - fmt.Sprintf( - "/%s/%s%s", - hostport, - string(byte(x.Type)), - path, - ), - ) - } - - out[i] = tr - } - - return tpl.Execute(w, struct { - Title string - Lines []tplRow - }{hostport, out}) -} - -func proxy(w http.ResponseWriter, req *http.Request) { - parts := strings.Split(strings.TrimPrefix(req.URL.Path, "/"), "/") - hostport := parts[0] - path := strings.Join(parts[1:], "/") - - if len(hostport) == 0 { - http.Redirect(w, req, "/"+*uri, http.StatusFound) - return - } - - uri, err := url.QueryUnescape(path) - if err != nil { - io.WriteString(w, fmt.Sprintf("Error:
%s
", err)) - return - } - res, err := gopher.Get( - fmt.Sprintf( - "gopher://%s/%s", - hostport, - uri, - ), - ) - if err != nil { - io.WriteString(w, fmt.Sprintf("Error:
%s
", err)) - return - } - - if res.Body != nil { - io.Copy(w, res.Body) - } else { - if err := renderDirectory(w, tpl, hostport, res.Dir); err != nil { - io.WriteString(w, fmt.Sprintf("Error:
%s
", err)) - return - } - } -} - -func main() { - flag.Parse() - - tpldata, err := ioutil.ReadFile(".template") - if err == nil { - tpltext = string(tpldata) - } - - tpl, err = template.New("gophermenu").Parse(tpltext) - if err != nil { - log.Fatal(err) - } - - http.HandleFunc("/", proxy) - log.Fatal(http.ListenAndServe(*bind, nil)) -} diff --git a/template.go b/template.go index 514ff30..604f380 100644 --- a/template.go +++ b/template.go @@ -1,4 +1,4 @@ -package main +package gopherproxy var tpltext = ` -- cgit v1.2.3-70-g09d2