]> Sergey Matveev's repositories - tofuproxy.git/blob - rounds/redirectHTML.go
Raised copyright years
[tofuproxy.git] / rounds / redirectHTML.go
1 /*
2 tofuproxy -- flexible HTTP/HTTPS proxy, TLS terminator, X.509 TOFU
3              manager, WARC/geminispace browser
4 Copyright (C) 2021-2022 Sergey Matveev <stargrave@stargrave.org>
5
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, version 3 of the License.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 package rounds
20
21 import (
22         "fmt"
23         "net/http"
24         "path/filepath"
25         "strings"
26
27         "go.stargrave.org/tofuproxy/fifos"
28 )
29
30 var imageExts = map[string]struct{}{
31         ".apng": {},
32         ".avif": {},
33         ".gif":  {},
34         ".heic": {},
35         ".jp2":  {},
36         ".jpeg": {},
37         ".jpg":  {},
38         ".jxl":  {},
39         ".mng":  {},
40         ".png":  {},
41         ".svg":  {},
42         ".tif":  {},
43         ".tiff": {},
44         ".webp": {},
45 }
46
47 func isNewsboat(req *http.Request) bool {
48         return strings.Contains(req.Header.Get("User-Agent"), "newsboat/")
49 }
50
51 func RoundRedirectHTML(
52         host string,
53         resp *http.Response,
54         w http.ResponseWriter,
55         req *http.Request,
56 ) (bool, error) {
57         if req.Method != http.MethodGet {
58                 return true, nil
59         }
60         var redirType string
61         switch resp.StatusCode {
62         case http.StatusMovedPermanently, http.StatusPermanentRedirect:
63                 redirType = "permanent"
64         case http.StatusFound, http.StatusSeeOther, http.StatusTemporaryRedirect:
65                 if isNewsboat(req) {
66                         return true, nil
67                 }
68                 if _, ok := imageExts[filepath.Ext(req.URL.Path)]; ok {
69                         return true, nil
70                 }
71                 redirType = "temporary"
72         default:
73                 return true, nil
74         }
75         resp.Body.Close()
76         w.Header().Add("Content-Type", "text/html")
77         w.WriteHeader(http.StatusOK)
78         location := resp.Header.Get("Location")
79         w.Write([]byte(
80                 fmt.Sprintf(
81                         `<!DOCTYPE html>
82 <html><head><title>%d %s: %s redirection</title></head>
83 <body><a href="%s">%s</a></body></html>`,
84                         resp.StatusCode, http.StatusText(resp.StatusCode),
85                         redirType, location, location,
86                 )))
87         fifos.LogRedir <- fmt.Sprintf(
88                 "%s %s\t%s\t%s", req.Method, req.URL, resp.Status, location,
89         )
90         return false, nil
91 }