diff options
Diffstat (limited to 'gopherproxy.go')
-rw-r--r-- | gopherproxy.go | 78 |
1 files changed, 54 insertions, 24 deletions
diff --git a/gopherproxy.go b/gopherproxy.go index 62b7446..1fcd29f 100644 --- a/gopherproxy.go +++ b/gopherproxy.go | |||
@@ -2,6 +2,7 @@ package gopherproxy | |||
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | "bytes" | 4 | "bytes" |
5 | "crypto/md5" | ||
5 | "fmt" | 6 | "fmt" |
6 | "html" | 7 | "html" |
7 | "html/template" | 8 | "html/template" |
@@ -28,7 +29,14 @@ type Item struct { | |||
28 | Text string | 29 | Text string |
29 | } | 30 | } |
30 | 31 | ||
31 | func renderDirectory(w http.ResponseWriter, tpl *template.Template, styletext string, jstext string, uri string, hostport string, d gopher.Directory) error { | 32 | type AssetHashList struct { |
33 | Style string | ||
34 | JS string | ||
35 | FontW string | ||
36 | FontW2 string | ||
37 | } | ||
38 | |||
39 | func renderDirectory(w http.ResponseWriter, tpl *template.Template, assetHashList AssetHashList, uri string, hostport string, d gopher.Directory) error { | ||
32 | var title string | 40 | var title string |
33 | 41 | ||
34 | out := make([]Item, len(d.Items)) | 42 | out := make([]Item, len(d.Items)) |
@@ -78,13 +86,12 @@ func renderDirectory(w http.ResponseWriter, tpl *template.Template, styletext st | |||
78 | } | 86 | } |
79 | 87 | ||
80 | return tpl.Execute(w, struct { | 88 | return tpl.Execute(w, struct { |
81 | Title string | 89 | Title string |
82 | URI string | 90 | URI string |
83 | Style string | 91 | AssetHashList AssetHashList |
84 | Script string | 92 | Lines []Item |
85 | Lines []Item | 93 | RawText string |
86 | RawText string | 94 | }{title, fmt.Sprintf("%s/%s", hostport, uri), assetHashList, out, ""}) |
87 | }{title, fmt.Sprintf("%s/%s", hostport, uri), styletext, jstext, out, ""}) | ||
88 | } | 95 | } |
89 | 96 | ||
90 | // GopherHandler returns a Handler that proxies requests | 97 | // GopherHandler returns a Handler that proxies requests |
@@ -92,7 +99,7 @@ func renderDirectory(w http.ResponseWriter, tpl *template.Template, styletext st | |||
92 | // to the request path and renders the content using the provided template. | 99 | // to the request path and renders the content using the provided template. |
93 | // The optional robots parameters points to a robotstxt.RobotsData struct | 100 | // The optional robots parameters points to a robotstxt.RobotsData struct |
94 | // to test user agents against a configurable robotst.txt file. | 101 | // to test user agents against a configurable robotst.txt file. |
95 | func GopherHandler(tpl *template.Template, robotsdata *robotstxt.RobotsData, robotsdebug bool, styletext string, jstext string, uri string) http.HandlerFunc { | 102 | func GopherHandler(tpl *template.Template, robotsdata *robotstxt.RobotsData, assetHashList AssetHashList, robotsdebug bool, uri string) http.HandlerFunc { |
96 | return func(w http.ResponseWriter, req *http.Request) { | 103 | return func(w http.ResponseWriter, req *http.Request) { |
97 | agent := req.UserAgent() | 104 | agent := req.UserAgent() |
98 | path := strings.TrimPrefix(req.URL.Path, "/") | 105 | path := strings.TrimPrefix(req.URL.Path, "/") |
@@ -141,13 +148,12 @@ func GopherHandler(tpl *template.Template, robotsdata *robotstxt.RobotsData, rob | |||
141 | buf := new(bytes.Buffer) | 148 | buf := new(bytes.Buffer) |
142 | buf.ReadFrom(res.Body) | 149 | buf.ReadFrom(res.Body) |
143 | tpl.Execute(w, struct { | 150 | tpl.Execute(w, struct { |
144 | Title string | 151 | Title string |
145 | URI string | 152 | URI string |
146 | Style string | 153 | AssetHashList AssetHashList |
147 | Script string | 154 | RawText string |
148 | RawText string | 155 | Lines []Item |
149 | Lines []Item | 156 | }{uri, fmt.Sprintf("%s/%s", hostport, uri), assetHashList, buf.String(), nil}) |
150 | }{uri, fmt.Sprintf("%s/%s", hostport, uri), styletext, jstext, buf.String(), nil}) | ||
151 | } else if parts[1] == "T" { | 157 | } else if parts[1] == "T" { |
152 | _, _, err = vips.NewTransform(). | 158 | _, _, err = vips.NewTransform(). |
153 | Load(res.Body). | 159 | Load(res.Body). |
@@ -160,7 +166,7 @@ func GopherHandler(tpl *template.Template, robotsdata *robotstxt.RobotsData, rob | |||
160 | io.Copy(w, res.Body) | 166 | io.Copy(w, res.Body) |
161 | } | 167 | } |
162 | } else { | 168 | } else { |
163 | if err := renderDirectory(w, tpl, styletext, jstext, uri, hostport, res.Dir); err != nil { | 169 | if err := renderDirectory(w, tpl, assetHashList, uri, hostport, res.Dir); err != nil { |
164 | io.WriteString(w, fmt.Sprintf("<b>Error:</b><pre>%s</pre>", err)) | 170 | io.WriteString(w, fmt.Sprintf("<b>Error:</b><pre>%s</pre>", err)) |
165 | return | 171 | return |
166 | } | 172 | } |
@@ -190,10 +196,27 @@ func FaviconHandler(favicondata []byte) http.HandlerFunc { | |||
190 | } | 196 | } |
191 | 197 | ||
192 | w.Header().Set("Content-Type", "image/vnd.microsoft.icon") | 198 | w.Header().Set("Content-Type", "image/vnd.microsoft.icon") |
199 | w.Header().Set("Cache-Control", "max-age=2592000") | ||
193 | w.Write(favicondata) | 200 | w.Write(favicondata) |
194 | } | 201 | } |
195 | } | 202 | } |
196 | 203 | ||
204 | func StyleHandler(styledata []byte) http.HandlerFunc { | ||
205 | return func(w http.ResponseWriter, req *http.Request) { | ||
206 | w.Header().Set("Content-Type", "text/css") | ||
207 | w.Header().Set("Cache-Control", "max-age=2592000") | ||
208 | w.Write(styledata) | ||
209 | } | ||
210 | } | ||
211 | |||
212 | func JavaScriptHandler(jsdata []byte) http.HandlerFunc { | ||
213 | return func(w http.ResponseWriter, req *http.Request) { | ||
214 | w.Header().Set("Content-Type", "text/javascript") | ||
215 | w.Header().Set("Cache-Control", "max-age=2592000") | ||
216 | w.Write(jsdata) | ||
217 | } | ||
218 | } | ||
219 | |||
197 | func FontHandler(woff2 bool, fontdata []byte) http.HandlerFunc { | 220 | func FontHandler(woff2 bool, fontdata []byte) http.HandlerFunc { |
198 | return func(w http.ResponseWriter, req *http.Request) { | 221 | return func(w http.ResponseWriter, req *http.Request) { |
199 | if fontdata == nil { | 222 | if fontdata == nil { |
@@ -206,6 +229,7 @@ func FontHandler(woff2 bool, fontdata []byte) http.HandlerFunc { | |||
206 | } else { | 229 | } else { |
207 | w.Header().Set("Content-Type", "font/woff") | 230 | w.Header().Set("Content-Type", "font/woff") |
208 | } | 231 | } |
232 | w.Header().Set("Cache-Control", "max-age=2592000") | ||
209 | 233 | ||
210 | w.Write(fontdata) | 234 | w.Write(fontdata) |
211 | } | 235 | } |
@@ -242,21 +266,25 @@ func ListenAndServe(bind, robotsfile string, robotsdebug bool, uri string) error | |||
242 | if err != nil { | 266 | if err != nil { |
243 | fontdataw = []byte{} | 267 | fontdataw = []byte{} |
244 | } | 268 | } |
269 | fontwhash := fmt.Sprintf("%x", md5.Sum(fontdataw)) | ||
245 | 270 | ||
246 | fontdataw2, err := box.Find("iosevka-term-ss03-regular.woff2") | 271 | fontdataw2, err := box.Find("iosevka-term-ss03-regular.woff2") |
247 | if err != nil { | 272 | if err != nil { |
248 | fontdataw2 = []byte{} | 273 | fontdataw2 = []byte{} |
249 | } | 274 | } |
275 | fontw2hash := fmt.Sprintf("%x", md5.Sum(fontdataw2)) | ||
250 | 276 | ||
251 | styletext, err := box.FindString("style.css") | 277 | styledata, err := box.Find("style.css") |
252 | if err != nil { | 278 | if err != nil { |
253 | styletext = "" | 279 | styledata = []byte{} |
254 | } | 280 | } |
281 | stylehash := fmt.Sprintf("%x", md5.Sum(styledata)) | ||
255 | 282 | ||
256 | jstext, err := box.FindString("main.js") | 283 | jsdata, err := box.Find("main.js") |
257 | if err != nil { | 284 | if err != nil { |
258 | jstext = "" | 285 | jsdata = []byte{} |
259 | } | 286 | } |
287 | jshash := fmt.Sprintf("%x", md5.Sum(jsdata)) | ||
260 | 288 | ||
261 | favicondata, err := box.Find("favicon.ico") | 289 | favicondata, err := box.Find("favicon.ico") |
262 | if err != nil { | 290 | if err != nil { |
@@ -304,11 +332,13 @@ func ListenAndServe(bind, robotsfile string, robotsdebug bool, uri string) error | |||
304 | ConcurrencyLevel: 2, | 332 | ConcurrencyLevel: 2, |
305 | }) | 333 | }) |
306 | 334 | ||
307 | http.HandleFunc("/", GopherHandler(tpl, robotsdata, robotsdebug, styletext, jstext, uri)) | 335 | http.HandleFunc("/", GopherHandler(tpl, robotsdata, AssetHashList{stylehash, jshash, fontwhash, fontw2hash}, robotsdebug, uri)) |
308 | http.HandleFunc("/robots.txt", RobotsTxtHandler(robotstxtdata)) | 336 | http.HandleFunc("/robots.txt", RobotsTxtHandler(robotstxtdata)) |
309 | http.HandleFunc("/favicon.ico", FaviconHandler(favicondata)) | 337 | http.HandleFunc("/favicon.ico", FaviconHandler(favicondata)) |
310 | http.HandleFunc("/iosevka-term-ss03-regular.woff", FontHandler(false, fontdataw)) | 338 | http.HandleFunc("/style-"+stylehash+".css", StyleHandler(styledata)) |
311 | http.HandleFunc("/iosevka-term-ss03-regular.woff2", FontHandler(true, fontdataw2)) | 339 | http.HandleFunc("/main-"+jshash+".js", JavaScriptHandler(jsdata)) |
340 | http.HandleFunc("/iosevka-term-ss03-regular-"+fontwhash+".woff", FontHandler(false, fontdataw)) | ||
341 | http.HandleFunc("/iosevka-term-ss03-regular-"+fontw2hash+".woff2", FontHandler(true, fontdataw2)) | ||
312 | //http.Handle("/assets/", http.StripPrefix("/assets/", http.FileServer(http.Dir("assets/")))) | 342 | //http.Handle("/assets/", http.StripPrefix("/assets/", http.FileServer(http.Dir("assets/")))) |
313 | 343 | ||
314 | return http.ListenAndServe(bind, nil) | 344 | return http.ListenAndServe(bind, nil) |