aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmd/gopherproxy/main.go19
-rw-r--r--gopherproxy.go131
-rw-r--r--main.go126
-rw-r--r--template.go2
4 files changed, 151 insertions, 127 deletions
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 @@
1package main
2
3import (
4 "flag"
5 "log"
6
7 "github.com/prologic/gopherproxy"
8)
9
10var (
11 bind = flag.String("bind", ":80", "[int]:port to bind to")
12 uri = flag.String("uri", "127.0.0.1:70", "<host>:[port] to proxy to")
13)
14
15func main() {
16 flag.Parse()
17
18 log.Fatal(gopherproxy.ListenAndServe(*bind, *uri))
19}
diff --git a/gopherproxy.go b/gopherproxy.go
new file mode 100644
index 0000000..4a2255f
--- /dev/null
+++ b/gopherproxy.go
@@ -0,0 +1,131 @@
1package gopherproxy
2
3import (
4 "fmt"
5 "html/template"
6 "io"
7 "io/ioutil"
8 "log"
9 "net/http"
10 "net/url"
11 "strings"
12
13 "github.com/prologic/go-gopher"
14)
15
16type tplRow struct {
17 Link template.URL
18 Type string
19 Text string
20}
21
22// Handler is an aliased type for the standard HTTP handler functions
23type Handler func(w http.ResponseWriter, req *http.Request)
24
25func renderDirectory(w http.ResponseWriter, tpl *template.Template, hostport string, d gopher.Directory) error {
26 out := make([]tplRow, len(d))
27
28 for i, x := range d {
29 tr := tplRow{
30 Text: x.Description,
31 Type: x.Type.String(),
32 }
33
34 if x.Type == gopher.INFO {
35 out[i] = tr
36 continue
37 }
38
39 if strings.HasPrefix(x.Selector, "URL:") {
40 tr.Link = template.URL(x.Selector[4:])
41 } else {
42 var hostport string
43 if x.Port == 70 {
44 hostport = x.Host
45 } else {
46 hostport = fmt.Sprintf("%s:%d", x.Host, x.Port)
47 }
48 path := url.QueryEscape(x.Selector)
49 path = strings.Replace(path, "%2F", "/", -1)
50 tr.Link = template.URL(
51 fmt.Sprintf(
52 "/%s/%s%s",
53 hostport,
54 string(byte(x.Type)),
55 path,
56 ),
57 )
58 }
59
60 out[i] = tr
61 }
62
63 return tpl.Execute(w, struct {
64 Title string
65 Lines []tplRow
66 }{hostport, out})
67}
68
69// MakeGopherProxyHandler returns a Handler that proxies requests
70// to the specified Gopher server as denoated by the first argument
71// to the request path and renders the content using the provided template.
72func MakeGopherProxyHandler(tpl *template.Template, uri string) Handler {
73 return func(w http.ResponseWriter, req *http.Request) {
74 parts := strings.Split(strings.TrimPrefix(req.URL.Path, "/"), "/")
75 hostport := parts[0]
76 path := strings.Join(parts[1:], "/")
77
78 if len(hostport) == 0 {
79 http.Redirect(w, req, "/"+uri, http.StatusFound)
80 return
81 }
82
83 uri, err := url.QueryUnescape(path)
84 if err != nil {
85 io.WriteString(w, fmt.Sprintf("<b>Error:</b><pre>%s</pre>", err))
86 return
87 }
88 res, err := gopher.Get(
89 fmt.Sprintf(
90 "gopher://%s/%s",
91 hostport,
92 uri,
93 ),
94 )
95 if err != nil {
96 io.WriteString(w, fmt.Sprintf("<b>Error:</b><pre>%s</pre>", err))
97 return
98 }
99
100 if res.Body != nil {
101 io.Copy(w, res.Body)
102 } else {
103 if err := renderDirectory(w, tpl, hostport, res.Dir); err != nil {
104 io.WriteString(w, fmt.Sprintf("<b>Error:</b><pre>%s</pre>", err))
105 return
106 }
107 }
108 }
109}
110
111// ListenAndServe creates a listening HTTP server bound to
112// the interface specified by bind and sets up a Gopher to HTTP
113// proxy proxying requests as requested and by default will prozy
114// to a Gopher server address specified by uri if no servers is
115// specified by the request.
116func ListenAndServe(bind, uri string) error {
117 var tpl *template.Template
118
119 tpldata, err := ioutil.ReadFile(".template")
120 if err == nil {
121 tpltext = string(tpldata)
122 }
123
124 tpl, err = template.New("gophermenu").Parse(tpltext)
125 if err != nil {
126 log.Fatal(err)
127 }
128
129 http.HandleFunc("/", MakeGopherProxyHandler(tpl, uri))
130 return http.ListenAndServe(bind, nil)
131}
diff --git a/main.go b/main.go
deleted file mode 100644
index 1da5f8e..0000000
--- a/main.go
+++ /dev/null
@@ -1,126 +0,0 @@
1package main
2
3import (
4 "flag"
5 "fmt"
6 "html/template"
7 "io"
8 "io/ioutil"
9 "log"
10 "net/http"
11 "net/url"
12 "strings"
13
14 "github.com/prologic/go-gopher"
15)
16
17var (
18 bind = flag.String("bind", ":80", "[int]:port to bind to")
19 uri = flag.String("uri", "127.0.0.1:70", "<host>:[port] to proxy to")
20
21 tpl *template.Template
22)
23
24type tplRow struct {
25 Link template.URL
26 Type string
27 Text string
28}
29
30func renderDirectory(w http.ResponseWriter, tpl *template.Template, hostport string, d gopher.Directory) error {
31 out := make([]tplRow, len(d))
32
33 for i, x := range d {
34 tr := tplRow{
35 Text: x.Description,
36 Type: x.Type.String(),
37 }
38
39 if x.Type == gopher.INFO {
40 out[i] = tr
41 continue
42 }
43
44 if strings.HasPrefix(x.Selector, "URL:") {
45 tr.Link = template.URL(x.Selector[4:])
46 } else {
47 var hostport string
48 if x.Port == 70 {
49 hostport = x.Host
50 } else {
51 hostport = fmt.Sprintf("%s:%d", x.Host, x.Port)
52 }
53 path := url.QueryEscape(x.Selector)
54 path = strings.Replace(path, "%2F", "/", -1)
55 tr.Link = template.URL(
56 fmt.Sprintf(
57 "/%s/%s%s",
58 hostport,
59 string(byte(x.Type)),
60 path,
61 ),
62 )
63 }
64
65 out[i] = tr
66 }
67
68 return tpl.Execute(w, struct {
69 Title string
70 Lines []tplRow
71 }{hostport, out})
72}
73
74func proxy(w http.ResponseWriter, req *http.Request) {
75 parts := strings.Split(strings.TrimPrefix(req.URL.Path, "/"), "/")
76 hostport := parts[0]
77 path := strings.Join(parts[1:], "/")
78
79 if len(hostport) == 0 {
80 http.Redirect(w, req, "/"+*uri, http.StatusFound)
81 return
82 }
83
84 uri, err := url.QueryUnescape(path)
85 if err != nil {
86 io.WriteString(w, fmt.Sprintf("<b>Error:</b><pre>%s</pre>", err))
87 return
88 }
89 res, err := gopher.Get(
90 fmt.Sprintf(
91 "gopher://%s/%s",
92 hostport,
93 uri,
94 ),
95 )
96 if err != nil {
97 io.WriteString(w, fmt.Sprintf("<b>Error:</b><pre>%s</pre>", err))
98 return
99 }
100
101 if res.Body != nil {
102 io.Copy(w, res.Body)
103 } else {
104 if err := renderDirectory(w, tpl, hostport, res.Dir); err != nil {
105 io.WriteString(w, fmt.Sprintf("<b>Error:</b><pre>%s</pre>", err))
106 return
107 }
108 }
109}
110
111func main() {
112 flag.Parse()
113
114 tpldata, err := ioutil.ReadFile(".template")
115 if err == nil {
116 tpltext = string(tpldata)
117 }
118
119 tpl, err = template.New("gophermenu").Parse(tpltext)
120 if err != nil {
121 log.Fatal(err)
122 }
123
124 http.HandleFunc("/", proxy)
125 log.Fatal(http.ListenAndServe(*bind, nil))
126}
diff --git a/template.go b/template.go
index 514ff30..604f380 100644
--- a/template.go
+++ b/template.go
@@ -1,4 +1,4 @@
1package main 1package gopherproxy
2 2
3var tpltext = `<!doctype html> 3var tpltext = `<!doctype html>
4<html> 4<html>