122 lines
2.8 KiB
Go
Executable File
122 lines
2.8 KiB
Go
Executable File
package server
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/tls"
|
|
"io"
|
|
"log"
|
|
"net/http"
|
|
"net/http/httputil"
|
|
"net/url"
|
|
"strings"
|
|
|
|
"gitea.bel.blue/local/rproxy3/config"
|
|
"gitea.bel.blue/local/rproxy3/storage/packable"
|
|
)
|
|
|
|
type redirPurge struct {
|
|
proxyHost string
|
|
targetHost string
|
|
baseTransport http.RoundTripper
|
|
}
|
|
|
|
type rewrite struct {
|
|
rewrites map[string]string
|
|
baseTransport http.RoundTripper
|
|
}
|
|
|
|
func (s *Server) Proxy(w http.ResponseWriter, r *http.Request) {
|
|
newURL, err := s.lookup(mapKey(r.Host))
|
|
r.URL.Path = strings.TrimPrefix(r.URL.Path, config.GetTrim())
|
|
var transport http.RoundTripper
|
|
http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
|
|
transport = &redirPurge{
|
|
proxyHost: r.Host,
|
|
targetHost: newURL.Host,
|
|
baseTransport: http.DefaultTransport,
|
|
}
|
|
if err != nil {
|
|
http.NotFound(w, r)
|
|
log.Printf("unknown host lookup %q", r.Host)
|
|
return
|
|
}
|
|
//r.Host = newURL.Host
|
|
proxy := httputil.NewSingleHostReverseProxy(newURL)
|
|
proxy.Transport = transport
|
|
proxy.ServeHTTP(w, r)
|
|
}
|
|
|
|
func (s *Server) lookup(host string) (*url.URL, error) {
|
|
v := packable.NewURL()
|
|
err := s.db.Get(nsRouting, host, v)
|
|
return v.URL(), err
|
|
}
|
|
|
|
func (s *Server) lookupAuth(host string) (string, error) {
|
|
v := packable.NewString()
|
|
err := s.db.Get(nsRouting, host+"//auth", v)
|
|
return v.String(), err
|
|
}
|
|
|
|
func (s *Server) lookupFrom(host string) (string, error) {
|
|
v := packable.NewString()
|
|
err := s.db.Get(nsRouting, host+"//from", v)
|
|
return v.String(), err
|
|
}
|
|
|
|
func mapKey(host string) string {
|
|
host = strings.Split(host, ".")[0]
|
|
host = strings.Split(host, ":")[0]
|
|
return host
|
|
}
|
|
|
|
func (rp *redirPurge) RoundTrip(r *http.Request) (*http.Response, error) {
|
|
resp, err := rp.baseTransport.RoundTrip(r)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
if loc := resp.Header.Get("Location"); loc != "" {
|
|
resp.Header.Set("Location", strings.Replace(loc, rp.targetHost, rp.proxyHost, 1))
|
|
}
|
|
// google floc https://paramdeo.com/blog/opting-your-website-out-of-googles-floc-network
|
|
resp.Header.Set("Permissions-Policy", "interest-cohort=()")
|
|
return resp, err
|
|
}
|
|
|
|
func (rw *rewrite) RoundTrip(r *http.Request) (*http.Response, error) {
|
|
resp, err := rw.baseTransport.RoundTrip(r)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
if len(rw.rewrites) == 0 {
|
|
return resp, err
|
|
}
|
|
resp.Header.Del("Content-Length")
|
|
pr, pw := io.Pipe()
|
|
body := resp.Body
|
|
resp.Body = pr
|
|
go func() {
|
|
buff := make([]byte, 1024)
|
|
n, err := body.Read(buff)
|
|
for err == nil || n > 0 {
|
|
chunk := buff[:n]
|
|
for k, v := range rw.rewrites {
|
|
chunk = bytes.Replace(chunk, []byte(k), []byte(v), -1)
|
|
}
|
|
n = len(chunk)
|
|
m := 0
|
|
for m < n {
|
|
l, err := pw.Write(chunk[m:])
|
|
if err != nil {
|
|
pw.CloseWithError(err)
|
|
return
|
|
}
|
|
m += l
|
|
}
|
|
n, err = body.Read(buff)
|
|
}
|
|
pw.CloseWithError(err)
|
|
}()
|
|
return resp, err
|
|
}
|