aboutsummaryrefslogtreecommitdiffstats
path: root/gopherproxy.go
diff options
context:
space:
mode:
authorJames Mills <prologic@shortcircuit.net.au>2016-09-30 19:40:24 -0700
committerJames Mills <prologic@shortcircuit.net.au>2016-09-30 19:40:24 -0700
commitc51b6d8887c38d538c0e2db2adfe0848fc662986 (patch)
treebc010e879a8e399d95371142c3298e37dabbdffb /gopherproxy.go
parentExplicitly set font-family to Monospace (diff)
downloadgopherproxy-c51b6d8887c38d538c0e2db2adfe0848fc662986.tar.gz
gopherproxy-c51b6d8887c38d538c0e2db2adfe0848fc662986.tar.bz2
gopherproxy-c51b6d8887c38d538c0e2db2adfe0848fc662986.zip
Migrated to a Library structure with gopherproxy cmd for reuse by gopherclient
Diffstat (limited to 'gopherproxy.go')
-rw-r--r--gopherproxy.go131
1 files changed, 131 insertions, 0 deletions
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}