- Added experimental proxmox fixes
- Fixed upstream error resp code not logging bug
This commit is contained in:
Toby Chui
2024-07-27 17:33:41 +08:00
parent c1e16d55ab
commit ca37bfbfa6
7 changed files with 144 additions and 50 deletions

View File

@@ -11,6 +11,7 @@ import (
"strings"
"time"
"imuslab.com/zoraxy/mod/dynamicproxy/domainsniff"
"imuslab.com/zoraxy/mod/dynamicproxy/permissionpolicy"
)
@@ -50,7 +51,6 @@ type ReverseProxy struct {
ModifyResponse func(*http.Response) error
//Prepender is an optional prepend text for URL rewrite
//
Prepender string
Verbal bool
@@ -258,7 +258,7 @@ func (p *ReverseProxy) logf(format string, args ...interface{}) {
}
}
func (p *ReverseProxy) ProxyHTTP(rw http.ResponseWriter, req *http.Request, rrr *ResponseRewriteRuleSet) error {
func (p *ReverseProxy) ProxyHTTP(rw http.ResponseWriter, req *http.Request, rrr *ResponseRewriteRuleSet) (int, error) {
transport := p.Transport
outreq := new(http.Request)
@@ -313,6 +313,11 @@ func (p *ReverseProxy) ProxyHTTP(rw http.ResponseWriter, req *http.Request, rrr
// Rewrite outbound UA, must be after user headers
rewriteUserAgent(outreq.Header, "Zoraxy/"+rrr.Version)
//Fix proxmox transfer encoding bug if detected Proxmox Cookie
if domainsniff.IsProxmox(req) {
outreq.TransferEncoding = []string{"identity"}
}
res, err := transport.RoundTrip(outreq)
if err != nil {
if p.Verbal {
@@ -320,7 +325,7 @@ func (p *ReverseProxy) ProxyHTTP(rw http.ResponseWriter, req *http.Request, rrr
}
//rw.WriteHeader(http.StatusBadGateway)
return err
return http.StatusBadGateway, err
}
// Remove hop-by-hop headers listed in the "Connection" header of the response, Remove hop-by-hop headers.
@@ -341,7 +346,7 @@ func (p *ReverseProxy) ProxyHTTP(rw http.ResponseWriter, req *http.Request, rrr
}
//rw.WriteHeader(http.StatusBadGateway)
return err
return http.StatusBadGateway, err
}
}
@@ -388,7 +393,6 @@ func (p *ReverseProxy) ProxyHTTP(rw http.ResponseWriter, req *http.Request, rrr
copyHeader(rw.Header(), res.Header)
// inject permission policy headers
//TODO: Load permission policy from rrr
permissionpolicy.InjectPermissionPolicyHeader(rw, nil)
// The "Trailer" header isn't included in the Transport's response, Build it up from Trailer.
@@ -418,14 +422,14 @@ func (p *ReverseProxy) ProxyHTTP(rw http.ResponseWriter, req *http.Request, rrr
res.Body.Close()
copyHeader(rw.Header(), res.Trailer)
return nil
return res.StatusCode, nil
}
func (p *ReverseProxy) ProxyHTTPS(rw http.ResponseWriter, req *http.Request) error {
func (p *ReverseProxy) ProxyHTTPS(rw http.ResponseWriter, req *http.Request) (int, error) {
hij, ok := rw.(http.Hijacker)
if !ok {
p.logf("http server does not support hijacker")
return errors.New("http server does not support hijacker")
return http.StatusNotImplemented, errors.New("http server does not support hijacker")
}
clientConn, _, err := hij.Hijack()
@@ -433,7 +437,7 @@ func (p *ReverseProxy) ProxyHTTPS(rw http.ResponseWriter, req *http.Request) err
if p.Verbal {
p.logf("http: proxy error: %v", err)
}
return err
return http.StatusInternalServerError, err
}
proxyConn, err := net.Dial("tcp", req.URL.Host)
@@ -442,7 +446,7 @@ func (p *ReverseProxy) ProxyHTTPS(rw http.ResponseWriter, req *http.Request) err
p.logf("http: proxy error: %v", err)
}
return err
return http.StatusInternalServerError, err
}
// The returned net.Conn may have read or write deadlines
@@ -461,7 +465,7 @@ func (p *ReverseProxy) ProxyHTTPS(rw http.ResponseWriter, req *http.Request) err
if p.Verbal {
p.logf("http: proxy error: %v", err)
}
return err
return http.StatusGatewayTimeout, err
}
err = proxyConn.SetDeadline(deadline)
@@ -470,7 +474,7 @@ func (p *ReverseProxy) ProxyHTTPS(rw http.ResponseWriter, req *http.Request) err
p.logf("http: proxy error: %v", err)
}
return err
return http.StatusGatewayTimeout, err
}
_, err = clientConn.Write([]byte("HTTP/1.0 200 OK\r\n\r\n"))
@@ -479,7 +483,7 @@ func (p *ReverseProxy) ProxyHTTPS(rw http.ResponseWriter, req *http.Request) err
p.logf("http: proxy error: %v", err)
}
return err
return http.StatusInternalServerError, err
}
go func() {
@@ -492,15 +496,13 @@ func (p *ReverseProxy) ProxyHTTPS(rw http.ResponseWriter, req *http.Request) err
proxyConn.Close()
clientConn.Close()
return nil
return http.StatusOK, nil
}
func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request, rrr *ResponseRewriteRuleSet) error {
func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request, rrr *ResponseRewriteRuleSet) (int, error) {
if req.Method == "CONNECT" {
err := p.ProxyHTTPS(rw, req)
return err
return p.ProxyHTTPS(rw, req)
} else {
err := p.ProxyHTTP(rw, req, rrr)
return err
return p.ProxyHTTP(rw, req, rrr)
}
}

View File

@@ -1,7 +1,10 @@
package dpcore
import (
"bytes"
"io"
"net"
"net/http"
"net/url"
"strings"
)
@@ -92,3 +95,63 @@ func isExternalDomainName(hostname string) bool {
return true
}
// DeepCopyRequest returns a deep copy of the given http.Request.
func DeepCopyRequest(req *http.Request) (*http.Request, error) {
// Copy the URL
urlCopy := *req.URL
// Copy the headers
headersCopy := make(http.Header, len(req.Header))
for k, vv := range req.Header {
vvCopy := make([]string, len(vv))
copy(vvCopy, vv)
headersCopy[k] = vvCopy
}
// Copy the cookies
cookiesCopy := make([]*http.Cookie, len(req.Cookies()))
for i, cookie := range req.Cookies() {
cookieCopy := *cookie
cookiesCopy[i] = &cookieCopy
}
// Copy the body, if present
var bodyCopy io.ReadCloser
if req.Body != nil {
var buf bytes.Buffer
if _, err := buf.ReadFrom(req.Body); err != nil {
return nil, err
}
// Reset the request body so it can be read again
if err := req.Body.Close(); err != nil {
return nil, err
}
req.Body = io.NopCloser(&buf)
bodyCopy = io.NopCloser(bytes.NewReader(buf.Bytes()))
}
// Create the new request
reqCopy := &http.Request{
Method: req.Method,
URL: &urlCopy,
Proto: req.Proto,
ProtoMajor: req.ProtoMajor,
ProtoMinor: req.ProtoMinor,
Header: headersCopy,
Body: bodyCopy,
ContentLength: req.ContentLength,
TransferEncoding: append([]string(nil), req.TransferEncoding...),
Close: req.Close,
Host: req.Host,
Form: req.Form,
PostForm: req.PostForm,
MultipartForm: req.MultipartForm,
Trailer: req.Trailer,
RemoteAddr: req.RemoteAddr,
TLS: req.TLS,
// Cancel and Context are not copied as it might cause issues
}
return reqCopy, nil
}