Migrated to a Library structure with gopherproxy cmd for reuse by gopherclient

This commit is contained in:
James Mills 2016-09-30 19:40:24 -07:00
parent 69a768a2d7
commit c51b6d8887
No known key found for this signature in database
GPG Key ID: AC4C014F1440EBD6
4 changed files with 151 additions and 127 deletions

19
cmd/gopherproxy/main.go Normal file
View File

@ -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", "<host>:[port] to proxy to")
)
func main() {
flag.Parse()
log.Fatal(gopherproxy.ListenAndServe(*bind, *uri))
}

131
gopherproxy.go Normal file
View File

@ -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("<b>Error:</b><pre>%s</pre>", err))
return
}
res, err := gopher.Get(
fmt.Sprintf(
"gopher://%s/%s",
hostport,
uri,
),
)
if err != nil {
io.WriteString(w, fmt.Sprintf("<b>Error:</b><pre>%s</pre>", 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("<b>Error:</b><pre>%s</pre>", 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)
}

126
main.go
View File

@ -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", "<host>:[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("<b>Error:</b><pre>%s</pre>", err))
return
}
res, err := gopher.Get(
fmt.Sprintf(
"gopher://%s/%s",
hostport,
uri,
),
)
if err != nil {
io.WriteString(w, fmt.Sprintf("<b>Error:</b><pre>%s</pre>", 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("<b>Error:</b><pre>%s</pre>", 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))
}

View File

@ -1,4 +1,4 @@
package main
package gopherproxy
var tpltext = `<!doctype html>
<html>