package server import ( "bytes" "crypto/tls" "io" "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)) 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) lookupBOAuthZ(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)) } 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 }