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