diff options
-rw-r--r-- | gopherproxy.go | 71 | ||||
-rw-r--r-- | template.go | 2 |
2 files changed, 45 insertions, 28 deletions
diff --git a/gopherproxy.go b/gopherproxy.go index 65c8f89..751cebf 100644 --- a/gopherproxy.go +++ b/gopherproxy.go | |||
@@ -50,25 +50,25 @@ type AssetList struct { | |||
50 | PropFontW2 string | 50 | PropFontW2 string |
51 | } | 51 | } |
52 | 52 | ||
53 | func resolveURI(uri string, baseUrl *url.URL) (resolvedUri string) { | 53 | func resolveURI(uri string, baseURL *url.URL) (resolvedURI string) { |
54 | if strings.HasPrefix(uri, "//") { | 54 | if strings.HasPrefix(uri, "//") { |
55 | resolvedUri = "/gemini/" + strings.TrimPrefix(uri, "//") | 55 | resolvedURI = "/gemini/" + strings.TrimPrefix(uri, "//") |
56 | } else if strings.HasPrefix(uri, "gemini://") { | 56 | } else if strings.HasPrefix(uri, "gemini://") { |
57 | resolvedUri = "/gemini/" + strings.TrimPrefix(uri, "gemini://") | 57 | resolvedURI = "/gemini/" + strings.TrimPrefix(uri, "gemini://") |
58 | } else if strings.HasPrefix(uri, "gopher://") { | 58 | } else if strings.HasPrefix(uri, "gopher://") { |
59 | resolvedUri = "/gopher/" + strings.TrimPrefix(uri, "gopher://") | 59 | resolvedURI = "/gopher/" + strings.TrimPrefix(uri, "gopher://") |
60 | } else { | 60 | } else { |
61 | url, err := url.Parse(uri) | 61 | url, err := url.Parse(uri) |
62 | if err != nil { | 62 | if err != nil { |
63 | return "" | 63 | return "" |
64 | } | 64 | } |
65 | adjustedUrl := baseUrl.ResolveReference(url) | 65 | adjustedURI := baseURL.ResolveReference(url) |
66 | if adjustedUrl.Scheme == "gemini" { | 66 | if adjustedURI.Scheme == "gemini" { |
67 | resolvedUri = "/gemini/" + adjustedUrl.Host + adjustedUrl.Path | 67 | resolvedURI = "/gemini/" + adjustedURI.Host + adjustedURI.Path |
68 | } else if adjustedUrl.Scheme == "gopher" { | 68 | } else if adjustedURI.Scheme == "gopher" { |
69 | resolvedUri = "/gopher/" + adjustedUrl.Host + adjustedUrl.Path | 69 | resolvedURI = "/gopher/" + adjustedURI.Host + adjustedURI.Path |
70 | } else { | 70 | } else { |
71 | resolvedUri = adjustedUrl.String() | 71 | resolvedURI = adjustedURI.String() |
72 | } | 72 | } |
73 | } | 73 | } |
74 | 74 | ||
@@ -123,7 +123,11 @@ func renderGopherDirectory(w http.ResponseWriter, tpl *template.Template, assetL | |||
123 | } | 123 | } |
124 | 124 | ||
125 | if title == "" { | 125 | if title == "" { |
126 | title = hostport | 126 | if uri != "" { |
127 | title = fmt.Sprintf("%s/%s", hostport, uri) | ||
128 | } else { | ||
129 | title = hostport | ||
130 | } | ||
127 | } | 131 | } |
128 | 132 | ||
129 | return tpl.Execute(w, struct { | 133 | return tpl.Execute(w, struct { |
@@ -138,7 +142,7 @@ func renderGopherDirectory(w http.ResponseWriter, tpl *template.Template, assetL | |||
138 | } | 142 | } |
139 | 143 | ||
140 | func parseGeminiDocument(body *bytes.Buffer, uri string, hostport string) (items []Item) { | 144 | func parseGeminiDocument(body *bytes.Buffer, uri string, hostport string) (items []Item) { |
141 | baseUrl, err := url.Parse(fmt.Sprintf( | 145 | baseURL, err := url.Parse(fmt.Sprintf( |
142 | "gemini://%s/%s", | 146 | "gemini://%s/%s", |
143 | hostport, | 147 | hostport, |
144 | uri, | 148 | uri, |
@@ -160,7 +164,7 @@ func parseGeminiDocument(body *bytes.Buffer, uri string, hostport string) (items | |||
160 | linkMatch := GeminiLinkPattern.FindStringSubmatch(line) | 164 | linkMatch := GeminiLinkPattern.FindStringSubmatch(line) |
161 | if len(linkMatch) != 0 && linkMatch[0] != "" { | 165 | if len(linkMatch) != 0 && linkMatch[0] != "" { |
162 | item.Type = ITEM_TYPE_GEMINI_LINK | 166 | item.Type = ITEM_TYPE_GEMINI_LINK |
163 | item.Link = template.URL(resolveURI(linkMatch[1], baseUrl)) | 167 | item.Link = template.URL(resolveURI(linkMatch[1], baseURL)) |
164 | item.Text = linkMatch[2] | 168 | item.Text = linkMatch[2] |
165 | if item.Text == "" { | 169 | if item.Text == "" { |
166 | item.Text = linkMatch[1] | 170 | item.Text = linkMatch[1] |
@@ -201,6 +205,8 @@ func GopherHandler(tpl *template.Template, robotsdata *robotstxt.RobotsData, ass | |||
201 | return | 205 | return |
202 | } | 206 | } |
203 | 207 | ||
208 | title := hostport | ||
209 | |||
204 | var qs string | 210 | var qs string |
205 | 211 | ||
206 | if req.URL.RawQuery != "" { | 212 | if req.URL.RawQuery != "" { |
@@ -217,10 +223,14 @@ func GopherHandler(tpl *template.Template, robotsdata *robotstxt.RobotsData, ass | |||
217 | Lines []Item | 223 | Lines []Item |
218 | Error bool | 224 | Error bool |
219 | Protocol string | 225 | Protocol string |
220 | }{"", hostport, assetList, fmt.Sprintf("Error: %s", err), nil, true, "gopher"}) | 226 | }{title, hostport, assetList, fmt.Sprintf("Error: %s", err), nil, true, "gopher"}) |
221 | return | 227 | return |
222 | } | 228 | } |
223 | 229 | ||
230 | if uri != "" { | ||
231 | title = fmt.Sprintf("%s/%s", hostport, uri) | ||
232 | } | ||
233 | |||
224 | res, err := gopher.Get( | 234 | res, err := gopher.Get( |
225 | fmt.Sprintf( | 235 | fmt.Sprintf( |
226 | "gopher://%s/%s%s", | 236 | "gopher://%s/%s%s", |
@@ -239,15 +249,14 @@ func GopherHandler(tpl *template.Template, robotsdata *robotstxt.RobotsData, ass | |||
239 | Lines []Item | 249 | Lines []Item |
240 | Error bool | 250 | Error bool |
241 | Protocol string | 251 | Protocol string |
242 | }{uri, fmt.Sprintf("%s/%s", hostport, uri), assetList, fmt.Sprintf("Error: %s", err), nil, true, "gopher"}) | 252 | }{title, fmt.Sprintf("%s/%s", hostport, uri), assetList, fmt.Sprintf("Error: %s", err), nil, true, "gopher"}) |
243 | return | 253 | return |
244 | } | 254 | } |
245 | 255 | ||
246 | if res.Body != nil { | 256 | if res.Body != nil { |
247 | if len(parts) < 2 { | 257 | if len(parts) < 2 { |
248 | io.Copy(w, res.Body) | 258 | io.Copy(w, res.Body) |
249 | } else if strings.HasPrefix(parts[1], "0") && !strings.HasSuffix(uri, ".xml") && !strings.HasSuffix(uri, ".asc") { //strings.HasSuffix(uri, ".txt") || strings.HasSuffix(uri, ".md") { | 259 | } else if strings.HasPrefix(parts[1], "0") && !strings.HasSuffix(uri, ".xml") && !strings.HasSuffix(uri, ".asc") { |
250 | // handle .txt files | ||
251 | buf := new(bytes.Buffer) | 260 | buf := new(bytes.Buffer) |
252 | buf.ReadFrom(res.Body) | 261 | buf.ReadFrom(res.Body) |
253 | tpl.Execute(w, struct { | 262 | tpl.Execute(w, struct { |
@@ -258,7 +267,7 @@ func GopherHandler(tpl *template.Template, robotsdata *robotstxt.RobotsData, ass | |||
258 | Lines []Item | 267 | Lines []Item |
259 | Error bool | 268 | Error bool |
260 | Protocol string | 269 | Protocol string |
261 | }{uri, fmt.Sprintf("%s/%s", hostport, uri), assetList, buf.String(), nil, false, "gopher"}) | 270 | }{title, fmt.Sprintf("%s/%s", hostport, uri), assetList, buf.String(), nil, false, "gopher"}) |
262 | } else if strings.HasPrefix(parts[1], "T") { | 271 | } else if strings.HasPrefix(parts[1], "T") { |
263 | _, _, err = vips.NewTransform(). | 272 | _, _, err = vips.NewTransform(). |
264 | Load(res.Body). | 273 | Load(res.Body). |
@@ -280,8 +289,7 @@ func GopherHandler(tpl *template.Template, robotsdata *robotstxt.RobotsData, ass | |||
280 | Lines []Item | 289 | Lines []Item |
281 | Error bool | 290 | Error bool |
282 | Protocol string | 291 | Protocol string |
283 | }{uri, fmt.Sprintf("%s/%s", hostport, uri), assetList, fmt.Sprintf("Error: %s", err), nil, true, "gopher"}) | 292 | }{title, fmt.Sprintf("%s/%s", hostport, uri), assetList, fmt.Sprintf("Error: %s", err), nil, true, "gopher"}) |
284 | return | ||
285 | } | 293 | } |
286 | } | 294 | } |
287 | } | 295 | } |
@@ -304,6 +312,8 @@ func GeminiHandler(tpl *template.Template, robotsdata *robotstxt.RobotsData, ass | |||
304 | return | 312 | return |
305 | } | 313 | } |
306 | 314 | ||
315 | title := hostport | ||
316 | |||
307 | var qs string | 317 | var qs string |
308 | 318 | ||
309 | if req.URL.RawQuery != "" { | 319 | if req.URL.RawQuery != "" { |
@@ -320,10 +330,14 @@ func GeminiHandler(tpl *template.Template, robotsdata *robotstxt.RobotsData, ass | |||
320 | Lines []Item | 330 | Lines []Item |
321 | Error bool | 331 | Error bool |
322 | Protocol string | 332 | Protocol string |
323 | }{"", hostport, assetList, fmt.Sprintf("Error: %s", err), nil, true, "gemini"}) | 333 | }{title, hostport, assetList, fmt.Sprintf("Error: %s", err), nil, true, "gemini"}) |
324 | return | 334 | return |
325 | } | 335 | } |
326 | 336 | ||
337 | if uri != "" { | ||
338 | title = fmt.Sprintf("%s/%s", hostport, uri) | ||
339 | } | ||
340 | |||
327 | res, err := GeminiGet( | 341 | res, err := GeminiGet( |
328 | fmt.Sprintf( | 342 | fmt.Sprintf( |
329 | "gemini://%s/%s%s", | 343 | "gemini://%s/%s%s", |
@@ -342,12 +356,12 @@ func GeminiHandler(tpl *template.Template, robotsdata *robotstxt.RobotsData, ass | |||
342 | Lines []Item | 356 | Lines []Item |
343 | Error bool | 357 | Error bool |
344 | Protocol string | 358 | Protocol string |
345 | }{uri, fmt.Sprintf("%s/%s", hostport, uri), assetList, fmt.Sprintf("Error: %s", err), nil, true, "gemini"}) | 359 | }{title, fmt.Sprintf("%s/%s", hostport, uri), assetList, fmt.Sprintf("Error: %s", err), nil, true, "gemini"}) |
346 | return | 360 | return |
347 | } | 361 | } |
348 | 362 | ||
349 | if int(res.Header.Status/10) == 3 { | 363 | if int(res.Header.Status/10) == 3 { |
350 | baseUrl, err := url.Parse(fmt.Sprintf( | 364 | baseURL, err := url.Parse(fmt.Sprintf( |
351 | "gemini://%s/%s", | 365 | "gemini://%s/%s", |
352 | hostport, | 366 | hostport, |
353 | uri, | 367 | uri, |
@@ -361,11 +375,11 @@ func GeminiHandler(tpl *template.Template, robotsdata *robotstxt.RobotsData, ass | |||
361 | Lines []Item | 375 | Lines []Item |
362 | Error bool | 376 | Error bool |
363 | Protocol string | 377 | Protocol string |
364 | }{uri, fmt.Sprintf("%s/%s", hostport, uri), assetList, fmt.Sprintf("Error: %s", err), nil, true, "gemini"}) | 378 | }{title, fmt.Sprintf("%s/%s", hostport, uri), assetList, fmt.Sprintf("Error: %s", err), nil, true, "gemini"}) |
365 | return | 379 | return |
366 | } | 380 | } |
367 | 381 | ||
368 | http.Redirect(w, req, resolveURI(res.Header.Meta, baseUrl), http.StatusFound) | 382 | http.Redirect(w, req, resolveURI(res.Header.Meta, baseURL), http.StatusFound) |
369 | return | 383 | return |
370 | } | 384 | } |
371 | 385 | ||
@@ -378,7 +392,7 @@ func GeminiHandler(tpl *template.Template, robotsdata *robotstxt.RobotsData, ass | |||
378 | Lines []Item | 392 | Lines []Item |
379 | Error bool | 393 | Error bool |
380 | Protocol string | 394 | Protocol string |
381 | }{uri, fmt.Sprintf("%s/%s", hostport, uri), assetList, fmt.Sprintf("Error %d: %s", res.Header.Status, res.Header.Meta), nil, true, "gemini"}) | 395 | }{title, fmt.Sprintf("%s/%s", hostport, uri), assetList, fmt.Sprintf("Error %d: %s", res.Header.Status, res.Header.Meta), nil, true, "gemini"}) |
382 | return | 396 | return |
383 | } | 397 | } |
384 | 398 | ||
@@ -417,7 +431,7 @@ func GeminiHandler(tpl *template.Template, robotsdata *robotstxt.RobotsData, ass | |||
417 | Lines []Item | 431 | Lines []Item |
418 | Error bool | 432 | Error bool |
419 | Protocol string | 433 | Protocol string |
420 | }{uri, fmt.Sprintf("%s/%s", hostport, uri), assetList, rawText, items, false, "gemini"}) | 434 | }{title, fmt.Sprintf("%s/%s", hostport, uri), assetList, rawText, items, false, "gemini"}) |
421 | } else { | 435 | } else { |
422 | io.Copy(w, res.Body) | 436 | io.Copy(w, res.Body) |
423 | } | 437 | } |
@@ -594,6 +608,9 @@ func ListenAndServe(bind, robotsfile string, robotsdebug bool, vipsconcurrency i | |||
594 | "hasPrefix": func(s string, prefix string) bool { | 608 | "hasPrefix": func(s string, prefix string) bool { |
595 | return strings.HasPrefix(s, prefix) | 609 | return strings.HasPrefix(s, prefix) |
596 | }, | 610 | }, |
611 | "title": func(s string) string { | ||
612 | return strings.Title(s) | ||
613 | }, | ||
597 | } | 614 | } |
598 | 615 | ||
599 | tpl, err = template.New("gophermenu").Funcs(funcMap).Parse(tpltext) | 616 | tpl, err = template.New("gophermenu").Funcs(funcMap).Parse(tpltext) |
diff --git a/template.go b/template.go index 6a9c6fe..3bd8950 100644 --- a/template.go +++ b/template.go | |||
@@ -5,7 +5,7 @@ var tpltext = `<!doctype html> | |||
5 | <head> | 5 | <head> |
6 | <meta charset="utf-8"> | 6 | <meta charset="utf-8"> |
7 | <meta name="viewport" content="width=device-width, initial-scale=1" /> | 7 | <meta name="viewport" content="width=device-width, initial-scale=1" /> |
8 | <title>{{ .Title }}</title> | 8 | <title>{{ .Title }} - {{ .Protocol | title }} proxy</title> |
9 | <link rel="stylesheet" href="{{ .Assets.Style }}" /> | 9 | <link rel="stylesheet" href="{{ .Assets.Style }}" /> |
10 | <style> | 10 | <style> |
11 | @font-face { | 11 | @font-face { |