2023-04-19 01:30:23 +01:00
|
|
|
package target
|
|
|
|
|
|
|
|
import (
|
2023-04-19 01:30:38 +01:00
|
|
|
"fmt"
|
2023-07-22 01:11:47 +01:00
|
|
|
"github.com/1f349/violet/utils"
|
2023-04-19 01:30:23 +01:00
|
|
|
"net/http"
|
|
|
|
"net/url"
|
2023-04-19 01:30:38 +01:00
|
|
|
"path"
|
2023-04-24 15:36:21 +01:00
|
|
|
"strings"
|
2023-04-19 01:30:23 +01:00
|
|
|
)
|
|
|
|
|
2023-04-24 15:36:21 +01:00
|
|
|
// Redirect is a target used by the router to manage redirecting the request
|
|
|
|
// using the specified configuration.
|
2023-04-19 01:30:23 +01:00
|
|
|
type Redirect struct {
|
2023-07-12 16:55:09 +01:00
|
|
|
Src string `json:"src"` // request source
|
|
|
|
Dst string `json:"dst"` // redirect destination
|
2023-10-28 22:20:04 +01:00
|
|
|
Desc string `json:"desc"` // description for admin panel use
|
2023-07-12 16:55:09 +01:00
|
|
|
Flags Flags `json:"flags"` // extra flags
|
|
|
|
Code int `json:"code"` // status code used to redirect
|
2023-04-19 01:30:23 +01:00
|
|
|
}
|
|
|
|
|
2023-07-13 00:15:00 +01:00
|
|
|
type RedirectWithActive struct {
|
|
|
|
Redirect
|
|
|
|
Active bool `json:"active"`
|
|
|
|
}
|
|
|
|
|
2023-10-27 11:55:18 +01:00
|
|
|
func (r Redirect) OnDomain(domain string) bool {
|
|
|
|
// if there is no / then the first part is still the domain
|
|
|
|
domainPart, _, _ := strings.Cut(r.Src, "/")
|
|
|
|
if domainPart == domain {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
// domainPart could start with a subdomain
|
|
|
|
return strings.HasSuffix(domainPart, "."+domain)
|
|
|
|
}
|
|
|
|
|
2023-08-28 23:09:29 +01:00
|
|
|
func (r Redirect) HasFlag(flag Flags) bool {
|
2023-07-12 16:55:09 +01:00
|
|
|
return r.Flags&flag != 0
|
2023-04-19 01:30:38 +01:00
|
|
|
}
|
|
|
|
|
2023-04-24 15:36:21 +01:00
|
|
|
// ServeHTTP responds with the redirect to the response writer provided.
|
2023-04-19 01:30:38 +01:00
|
|
|
func (r Redirect) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
2023-04-24 15:36:21 +01:00
|
|
|
// default to redirecting with StatusFound if code is not set
|
|
|
|
code := r.Code
|
|
|
|
if r.Code == 0 {
|
|
|
|
code = http.StatusFound
|
|
|
|
}
|
|
|
|
|
2023-07-12 16:55:09 +01:00
|
|
|
// split the host and path
|
|
|
|
host, p := utils.SplitHostPath(r.Dst)
|
|
|
|
|
2023-04-24 15:36:21 +01:00
|
|
|
// if not Abs then join with the ending of the current path
|
2023-07-12 16:55:09 +01:00
|
|
|
if !r.Flags.HasFlag(FlagAbs) {
|
|
|
|
p = path.Join(p, req.URL.Path)
|
2023-04-24 15:36:21 +01:00
|
|
|
|
|
|
|
// replace the trailing slash that path.Join() strips off
|
|
|
|
if strings.HasSuffix(req.URL.Path, "/") {
|
|
|
|
p += "/"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// fix empty path
|
|
|
|
if p == "" {
|
|
|
|
p = "/"
|
2023-04-19 01:30:38 +01:00
|
|
|
}
|
2023-04-24 15:36:21 +01:00
|
|
|
|
|
|
|
// create a new URL
|
2023-04-20 02:53:43 +01:00
|
|
|
u := &url.URL{
|
2023-04-19 01:30:38 +01:00
|
|
|
Scheme: req.URL.Scheme,
|
2023-07-12 16:55:09 +01:00
|
|
|
Host: host,
|
2023-04-19 01:30:38 +01:00
|
|
|
Path: p,
|
|
|
|
}
|
2023-04-24 15:36:21 +01:00
|
|
|
|
2023-09-10 15:20:51 +01:00
|
|
|
// close the incoming body after use
|
|
|
|
if req.Body != nil {
|
|
|
|
defer req.Body.Close()
|
|
|
|
}
|
|
|
|
|
2023-04-24 15:36:21 +01:00
|
|
|
// use fast redirect for speed
|
|
|
|
utils.FastRedirect(rw, req, u.String(), code)
|
2023-04-19 01:30:38 +01:00
|
|
|
}
|
|
|
|
|
2023-04-24 15:36:21 +01:00
|
|
|
// String outputs a debug string for the redirect.
|
2023-04-19 01:30:38 +01:00
|
|
|
func (r Redirect) String() string {
|
|
|
|
return fmt.Sprintf("%#v", r)
|
2023-04-19 01:30:23 +01:00
|
|
|
}
|