rproxy3/server/proxy.go

115 lines
2.7 KiB
Go
Executable File

package server
import (
"bytes"
"crypto/tls"
"io"
"gitea.inhome.blapointe.com/local/rproxy3/config"
"gitea.inhome.blapointe.com/local/rproxy3/storage/packable"
"log"
"net/http"
"net/http/httputil"
"net/url"
"strings"
)
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) (bool, error) {
v := packable.NewString()
err := s.db.Get(nsBOAuthZ, host, v)
return v.String() == "true", 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
}