mirror of
https://github.com/tobychui/zoraxy.git
synced 2025-06-03 06:07:20 +02:00
Added new custom header structure
+ Moved custom header rewrite to dpcore + Restructure dpcore header rewrite sequence + Added advance custom header settings (zoraxy to upstream and zoraxy to downstream mode) + Added header remove feature + Removed password requirement for SMTP #80 + Completed stream proxy module (TCP and UDP) + Optimized UX for reminding user to click Apply after port change + Added version number to footer #160
This commit is contained in:
parent
deddb17803
commit
b00e302f6d
@ -39,9 +39,6 @@ func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//Inject headers
|
|
||||||
w.Header().Set("x-proxy-by", "zoraxy/"+h.Parent.Option.HostVersion)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Redirection Routing
|
Redirection Routing
|
||||||
*/
|
*/
|
||||||
|
46
src/mod/dynamicproxy/customHeader.go
Normal file
46
src/mod/dynamicproxy/customHeader.go
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
package dynamicproxy
|
||||||
|
|
||||||
|
/*
|
||||||
|
CustomHeader.go
|
||||||
|
|
||||||
|
This script handle parsing and injecting custom headers
|
||||||
|
into the dpcore routing logic
|
||||||
|
*/
|
||||||
|
|
||||||
|
//SplitInboundOutboundHeaders split user defined headers into upstream and downstream headers
|
||||||
|
//return upstream header and downstream header key-value pairs
|
||||||
|
//if the header is expected to be deleted, the value will be set to empty string
|
||||||
|
func (ept *ProxyEndpoint) SplitInboundOutboundHeaders() ([][]string, [][]string) {
|
||||||
|
if len(ept.UserDefinedHeaders) == 0 {
|
||||||
|
//Early return if there are no defined headers
|
||||||
|
return [][]string{}, [][]string{}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Use pre-allocation for faster performance
|
||||||
|
upstreamHeaders := make([][]string, len(ept.UserDefinedHeaders))
|
||||||
|
downstreamHeaders := make([][]string, len(ept.UserDefinedHeaders))
|
||||||
|
upstreamHeaderCounter := 0
|
||||||
|
downstreamHeaderCounter := 0
|
||||||
|
|
||||||
|
//Sort the headers into upstream or downstream
|
||||||
|
for _, customHeader := range ept.UserDefinedHeaders {
|
||||||
|
thisHeaderSet := make([]string, 2)
|
||||||
|
thisHeaderSet[0] = customHeader.Key
|
||||||
|
thisHeaderSet[1] = customHeader.Value
|
||||||
|
if customHeader.IsRemove {
|
||||||
|
//Prevent invalid config
|
||||||
|
thisHeaderSet[1] = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
//Assign to slice
|
||||||
|
if customHeader.Direction == HeaderDirection_ZoraxyToUpstream {
|
||||||
|
upstreamHeaders[upstreamHeaderCounter] = thisHeaderSet
|
||||||
|
upstreamHeaderCounter++
|
||||||
|
} else if customHeader.Direction == HeaderDirection_ZoraxyToDownstream {
|
||||||
|
downstreamHeaders[downstreamHeaderCounter] = thisHeaderSet
|
||||||
|
downstreamHeaderCounter++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return upstreamHeaders, downstreamHeaders
|
||||||
|
}
|
@ -57,11 +57,14 @@ type ReverseProxy struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ResponseRewriteRuleSet struct {
|
type ResponseRewriteRuleSet struct {
|
||||||
ProxyDomain string
|
ProxyDomain string
|
||||||
OriginalHost string
|
OriginalHost string
|
||||||
UseTLS bool
|
UseTLS bool
|
||||||
NoCache bool
|
NoCache bool
|
||||||
PathPrefix string //Vdir prefix for root, / will be rewrite to this
|
PathPrefix string //Vdir prefix for root, / will be rewrite to this
|
||||||
|
UpstreamHeaders [][]string
|
||||||
|
DownstreamHeaders [][]string
|
||||||
|
Version string //Version number of Zoraxy, use for X-Proxy-By
|
||||||
}
|
}
|
||||||
|
|
||||||
type requestCanceler interface {
|
type requestCanceler interface {
|
||||||
@ -248,82 +251,6 @@ func (p *ReverseProxy) logf(format string, args ...interface{}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func removeHeaders(header http.Header, noCache bool) {
|
|
||||||
// Remove hop-by-hop headers listed in the "Connection" header.
|
|
||||||
if c := header.Get("Connection"); c != "" {
|
|
||||||
for _, f := range strings.Split(c, ",") {
|
|
||||||
if f = strings.TrimSpace(f); f != "" {
|
|
||||||
header.Del(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove hop-by-hop headers
|
|
||||||
for _, h := range hopHeaders {
|
|
||||||
if header.Get(h) != "" {
|
|
||||||
header.Del(h)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Restore the Upgrade header if any
|
|
||||||
if header.Get("Zr-Origin-Upgrade") != "" {
|
|
||||||
header.Set("Upgrade", header.Get("Zr-Origin-Upgrade"))
|
|
||||||
header.Del("Zr-Origin-Upgrade")
|
|
||||||
}
|
|
||||||
|
|
||||||
//Disable cache if nocache is set
|
|
||||||
if noCache {
|
|
||||||
header.Del("Cache-Control")
|
|
||||||
header.Set("Cache-Control", "no-store")
|
|
||||||
}
|
|
||||||
|
|
||||||
//Hide Go-HTTP-Client UA if the client didnt sent us one
|
|
||||||
if _, ok := header["User-Agent"]; !ok {
|
|
||||||
// If the outbound request doesn't have a User-Agent header set,
|
|
||||||
// don't send the default Go HTTP client User-Agent.
|
|
||||||
header.Set("User-Agent", "")
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func addXForwardedForHeader(req *http.Request) {
|
|
||||||
if clientIP, _, err := net.SplitHostPort(req.RemoteAddr); err == nil {
|
|
||||||
// If we aren't the first proxy retain prior
|
|
||||||
// X-Forwarded-For information as a comma+space
|
|
||||||
// separated list and fold multiple headers into one.
|
|
||||||
if prior, ok := req.Header["X-Forwarded-For"]; ok {
|
|
||||||
clientIP = strings.Join(prior, ", ") + ", " + clientIP
|
|
||||||
}
|
|
||||||
req.Header.Set("X-Forwarded-For", clientIP)
|
|
||||||
if req.TLS != nil {
|
|
||||||
req.Header.Set("X-Forwarded-Proto", "https")
|
|
||||||
} else {
|
|
||||||
req.Header.Set("X-Forwarded-Proto", "http")
|
|
||||||
}
|
|
||||||
|
|
||||||
if req.Header.Get("X-Real-Ip") == "" {
|
|
||||||
//Check if CF-Connecting-IP header exists
|
|
||||||
CF_Connecting_IP := req.Header.Get("CF-Connecting-IP")
|
|
||||||
Fastly_Client_IP := req.Header.Get("Fastly-Client-IP")
|
|
||||||
if CF_Connecting_IP != "" {
|
|
||||||
//Use CF Connecting IP
|
|
||||||
req.Header.Set("X-Real-Ip", CF_Connecting_IP)
|
|
||||||
} else if Fastly_Client_IP != "" {
|
|
||||||
//Use Fastly Client IP
|
|
||||||
req.Header.Set("X-Real-Ip", Fastly_Client_IP)
|
|
||||||
} else {
|
|
||||||
// Not exists. Fill it in with first entry in X-Forwarded-For
|
|
||||||
ips := strings.Split(clientIP, ",")
|
|
||||||
if len(ips) > 0 {
|
|
||||||
req.Header.Set("X-Real-Ip", strings.TrimSpace(ips[0]))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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) error {
|
||||||
transport := p.Transport
|
transport := p.Transport
|
||||||
|
|
||||||
@ -362,12 +289,18 @@ func (p *ReverseProxy) ProxyHTTP(rw http.ResponseWriter, req *http.Request, rrr
|
|||||||
outreq.Header = make(http.Header)
|
outreq.Header = make(http.Header)
|
||||||
copyHeader(outreq.Header, req.Header)
|
copyHeader(outreq.Header, req.Header)
|
||||||
|
|
||||||
// Remove hop-by-hop headers listed in the "Connection" header, Remove hop-by-hop headers.
|
// Remove hop-by-hop headers.
|
||||||
removeHeaders(outreq.Header, rrr.NoCache)
|
removeHeaders(outreq.Header, rrr.NoCache)
|
||||||
|
|
||||||
// Add X-Forwarded-For Header.
|
// Add X-Forwarded-For Header.
|
||||||
addXForwardedForHeader(outreq)
|
addXForwardedForHeader(outreq)
|
||||||
|
|
||||||
|
// Add user defined headers (to upstream)
|
||||||
|
injectUserDefinedHeaders(outreq.Header, rrr.UpstreamHeaders)
|
||||||
|
|
||||||
|
// Rewrite outbound UA, must be after user headers
|
||||||
|
rewriteUserAgent(outreq.Header, "Zoraxy/"+rrr.Version)
|
||||||
|
|
||||||
res, err := transport.RoundTrip(outreq)
|
res, err := transport.RoundTrip(outreq)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if p.Verbal {
|
if p.Verbal {
|
||||||
@ -398,13 +331,17 @@ func (p *ReverseProxy) ProxyHTTP(rw http.ResponseWriter, req *http.Request, rrr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO: Figure out a way to proxy for proxmox
|
||||||
//if res.StatusCode == 501 || res.StatusCode == 500 {
|
//if res.StatusCode == 501 || res.StatusCode == 500 {
|
||||||
// fmt.Println(outreq.Proto, outreq.RemoteAddr, outreq.RequestURI)
|
// fmt.Println(outreq.Proto, outreq.RemoteAddr, outreq.RequestURI)
|
||||||
// fmt.Println(">>>", outreq.Method, res.Header, res.ContentLength, res.StatusCode)
|
// fmt.Println(">>>", outreq.Method, res.Header, res.ContentLength, res.StatusCode)
|
||||||
// fmt.Println(outreq.Header, req.Host)
|
// fmt.Println(outreq.Header, req.Host)
|
||||||
//}
|
//}
|
||||||
|
|
||||||
//Custom header rewriter functions
|
//Add debug X-Proxy-By tracker
|
||||||
|
res.Header.Set("x-proxy-by", "zoraxy/"+rrr.Version)
|
||||||
|
|
||||||
|
//Custom Location header rewriter functions
|
||||||
if res.Header.Get("Location") != "" {
|
if res.Header.Get("Location") != "" {
|
||||||
locationRewrite := res.Header.Get("Location")
|
locationRewrite := res.Header.Get("Location")
|
||||||
originLocation := res.Header.Get("Location")
|
originLocation := res.Header.Get("Location")
|
||||||
@ -430,6 +367,9 @@ func (p *ReverseProxy) ProxyHTTP(rw http.ResponseWriter, req *http.Request, rrr
|
|||||||
res.Header.Set("Location", locationRewrite)
|
res.Header.Set("Location", locationRewrite)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add user defined headers (to downstream)
|
||||||
|
injectUserDefinedHeaders(res.Header, rrr.DownstreamHeaders)
|
||||||
|
|
||||||
// Copy header from response to client.
|
// Copy header from response to client.
|
||||||
copyHeader(rw.Header(), res.Header)
|
copyHeader(rw.Header(), res.Header)
|
||||||
|
|
||||||
|
121
src/mod/dynamicproxy/dpcore/header.go
Normal file
121
src/mod/dynamicproxy/dpcore/header.go
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
package dpcore
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
Header.go
|
||||||
|
|
||||||
|
This script handles headers rewrite and remove
|
||||||
|
in dpcore.
|
||||||
|
|
||||||
|
Added in Zoraxy v3.0.6 by tobychui
|
||||||
|
*/
|
||||||
|
|
||||||
|
// removeHeaders Remove hop-by-hop headers listed in the "Connection" header, Remove hop-by-hop headers.
|
||||||
|
func removeHeaders(header http.Header, noCache bool) {
|
||||||
|
// Remove hop-by-hop headers listed in the "Connection" header.
|
||||||
|
if c := header.Get("Connection"); c != "" {
|
||||||
|
for _, f := range strings.Split(c, ",") {
|
||||||
|
if f = strings.TrimSpace(f); f != "" {
|
||||||
|
header.Del(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove hop-by-hop headers
|
||||||
|
for _, h := range hopHeaders {
|
||||||
|
if header.Get(h) != "" {
|
||||||
|
header.Del(h)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Restore the Upgrade header if any
|
||||||
|
if header.Get("Zr-Origin-Upgrade") != "" {
|
||||||
|
header.Set("Upgrade", header.Get("Zr-Origin-Upgrade"))
|
||||||
|
header.Del("Zr-Origin-Upgrade")
|
||||||
|
}
|
||||||
|
|
||||||
|
//Disable cache if nocache is set
|
||||||
|
if noCache {
|
||||||
|
header.Del("Cache-Control")
|
||||||
|
header.Set("Cache-Control", "no-store")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// rewriteUserAgent rewrite the user agent based on incoming request
|
||||||
|
func rewriteUserAgent(header http.Header, UA string) {
|
||||||
|
//Hide Go-HTTP-Client UA if the client didnt sent us one
|
||||||
|
if header.Get("User-Agent") == "" {
|
||||||
|
// If the outbound request doesn't have a User-Agent header set,
|
||||||
|
// don't send the default Go HTTP client User-Agent
|
||||||
|
header.Del("User-Agent")
|
||||||
|
header.Set("User-Agent", UA)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add X-Forwarded-For Header and rewrite X-Real-Ip according to sniffing logics
|
||||||
|
func addXForwardedForHeader(req *http.Request) {
|
||||||
|
if clientIP, _, err := net.SplitHostPort(req.RemoteAddr); err == nil {
|
||||||
|
// If we aren't the first proxy retain prior
|
||||||
|
// X-Forwarded-For information as a comma+space
|
||||||
|
// separated list and fold multiple headers into one.
|
||||||
|
if prior, ok := req.Header["X-Forwarded-For"]; ok {
|
||||||
|
clientIP = strings.Join(prior, ", ") + ", " + clientIP
|
||||||
|
}
|
||||||
|
req.Header.Set("X-Forwarded-For", clientIP)
|
||||||
|
if req.TLS != nil {
|
||||||
|
req.Header.Set("X-Forwarded-Proto", "https")
|
||||||
|
} else {
|
||||||
|
req.Header.Set("X-Forwarded-Proto", "http")
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.Header.Get("X-Real-Ip") == "" {
|
||||||
|
//Check if CF-Connecting-IP header exists
|
||||||
|
CF_Connecting_IP := req.Header.Get("CF-Connecting-IP")
|
||||||
|
Fastly_Client_IP := req.Header.Get("Fastly-Client-IP")
|
||||||
|
if CF_Connecting_IP != "" {
|
||||||
|
//Use CF Connecting IP
|
||||||
|
req.Header.Set("X-Real-Ip", CF_Connecting_IP)
|
||||||
|
} else if Fastly_Client_IP != "" {
|
||||||
|
//Use Fastly Client IP
|
||||||
|
req.Header.Set("X-Real-Ip", Fastly_Client_IP)
|
||||||
|
} else {
|
||||||
|
// Not exists. Fill it in with first entry in X-Forwarded-For
|
||||||
|
ips := strings.Split(clientIP, ",")
|
||||||
|
if len(ips) > 0 {
|
||||||
|
req.Header.Set("X-Real-Ip", strings.TrimSpace(ips[0]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// injectUserDefinedHeaders inject the user headers from slice
|
||||||
|
// if a value is empty string, the key will be removed from header.
|
||||||
|
// if a key is empty string, the function will return immediately
|
||||||
|
func injectUserDefinedHeaders(header http.Header, userHeaders [][]string) {
|
||||||
|
for _, userHeader := range userHeaders {
|
||||||
|
if len(userHeader) == 0 {
|
||||||
|
//End of header slice
|
||||||
|
return
|
||||||
|
}
|
||||||
|
headerKey := userHeader[0]
|
||||||
|
headerValue := userHeader[1]
|
||||||
|
if headerValue == "" {
|
||||||
|
//Remove header from head
|
||||||
|
header.Del(headerKey)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
//Default: Set header value
|
||||||
|
header.Del(headerKey) //Remove header if it already exists
|
||||||
|
header.Set(headerKey, headerValue)
|
||||||
|
}
|
||||||
|
}
|
@ -142,6 +142,7 @@ func (router *Router) StartProxyService() error {
|
|||||||
OriginalHost: originalHostHeader,
|
OriginalHost: originalHostHeader,
|
||||||
UseTLS: sep.RequireTLS,
|
UseTLS: sep.RequireTLS,
|
||||||
PathPrefix: "",
|
PathPrefix: "",
|
||||||
|
Version: sep.parent.Option.HostVersion,
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,6 @@ func (ep *ProxyEndpoint) UserDefinedHeaderExists(key string) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,16 +48,13 @@ func (ep *ProxyEndpoint) RemoveUserDefinedHeader(key string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add a user defined header to the list, duplicates will be automatically removed
|
// Add a user defined header to the list, duplicates will be automatically removed
|
||||||
func (ep *ProxyEndpoint) AddUserDefinedHeader(key string, value string) error {
|
func (ep *ProxyEndpoint) AddUserDefinedHeader(newHeaderRule *UserDefinedHeader) error {
|
||||||
if ep.UserDefinedHeaderExists(key) {
|
if ep.UserDefinedHeaderExists(newHeaderRule.Key) {
|
||||||
ep.RemoveUserDefinedHeader(key)
|
ep.RemoveUserDefinedHeader(newHeaderRule.Key)
|
||||||
}
|
}
|
||||||
|
|
||||||
ep.UserDefinedHeaders = append(ep.UserDefinedHeaders, &UserDefinedHeader{
|
newHeaderRule.Key = cases.Title(language.Und, cases.NoLower).String(newHeaderRule.Key)
|
||||||
Key: cases.Title(language.Und, cases.NoLower).String(key), //e.g. x-proxy-by -> X-Proxy-By
|
ep.UserDefinedHeaders = append(ep.UserDefinedHeaders, newHeaderRule)
|
||||||
Value: value,
|
|
||||||
})
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,13 +111,6 @@ func (h *ProxyHandler) hostRequest(w http.ResponseWriter, r *http.Request, targe
|
|||||||
r.Header.Set("X-Forwarded-Host", r.Host)
|
r.Header.Set("X-Forwarded-Host", r.Host)
|
||||||
r.Header.Set("X-Forwarded-Server", "zoraxy-"+h.Parent.Option.HostUUID)
|
r.Header.Set("X-Forwarded-Server", "zoraxy-"+h.Parent.Option.HostUUID)
|
||||||
|
|
||||||
//Inject custom headers
|
|
||||||
if len(target.UserDefinedHeaders) > 0 {
|
|
||||||
for _, customHeader := range target.UserDefinedHeaders {
|
|
||||||
r.Header.Set(customHeader.Key, customHeader.Value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
requestURL := r.URL.String()
|
requestURL := r.URL.String()
|
||||||
if r.Header["Upgrade"] != nil && strings.ToLower(r.Header["Upgrade"][0]) == "websocket" {
|
if r.Header["Upgrade"] != nil && strings.ToLower(r.Header["Upgrade"][0]) == "websocket" {
|
||||||
//Handle WebSocket request. Forward the custom Upgrade header and rewrite origin
|
//Handle WebSocket request. Forward the custom Upgrade header and rewrite origin
|
||||||
@ -152,12 +145,18 @@ func (h *ProxyHandler) hostRequest(w http.ResponseWriter, r *http.Request, targe
|
|||||||
r.URL, _ = url.Parse(originalHostHeader)
|
r.URL, _ = url.Parse(originalHostHeader)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Build downstream and upstream header rules
|
||||||
|
upstreamHeaders, downstreamHeaders := target.SplitInboundOutboundHeaders()
|
||||||
|
|
||||||
err := target.proxy.ServeHTTP(w, r, &dpcore.ResponseRewriteRuleSet{
|
err := target.proxy.ServeHTTP(w, r, &dpcore.ResponseRewriteRuleSet{
|
||||||
ProxyDomain: target.Domain,
|
ProxyDomain: target.Domain,
|
||||||
OriginalHost: originalHostHeader,
|
OriginalHost: originalHostHeader,
|
||||||
UseTLS: target.RequireTLS,
|
UseTLS: target.RequireTLS,
|
||||||
NoCache: h.Parent.Option.NoCache,
|
NoCache: h.Parent.Option.NoCache,
|
||||||
PathPrefix: "",
|
PathPrefix: "",
|
||||||
|
UpstreamHeaders: upstreamHeaders,
|
||||||
|
DownstreamHeaders: downstreamHeaders,
|
||||||
|
Version: target.parent.Option.HostVersion,
|
||||||
})
|
})
|
||||||
|
|
||||||
var dnsError *net.DNSError
|
var dnsError *net.DNSError
|
||||||
@ -184,13 +183,6 @@ func (h *ProxyHandler) vdirRequest(w http.ResponseWriter, r *http.Request, targe
|
|||||||
r.Header.Set("X-Forwarded-Host", r.Host)
|
r.Header.Set("X-Forwarded-Host", r.Host)
|
||||||
r.Header.Set("X-Forwarded-Server", "zoraxy-"+h.Parent.Option.HostUUID)
|
r.Header.Set("X-Forwarded-Server", "zoraxy-"+h.Parent.Option.HostUUID)
|
||||||
|
|
||||||
//Inject custom headers
|
|
||||||
if len(target.parent.UserDefinedHeaders) > 0 {
|
|
||||||
for _, customHeader := range target.parent.UserDefinedHeaders {
|
|
||||||
r.Header.Set(customHeader.Key, customHeader.Value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if r.Header["Upgrade"] != nil && strings.ToLower(r.Header["Upgrade"][0]) == "websocket" {
|
if r.Header["Upgrade"] != nil && strings.ToLower(r.Header["Upgrade"][0]) == "websocket" {
|
||||||
//Handle WebSocket request. Forward the custom Upgrade header and rewrite origin
|
//Handle WebSocket request. Forward the custom Upgrade header and rewrite origin
|
||||||
r.Header.Set("Zr-Origin-Upgrade", "websocket")
|
r.Header.Set("Zr-Origin-Upgrade", "websocket")
|
||||||
@ -219,11 +211,17 @@ func (h *ProxyHandler) vdirRequest(w http.ResponseWriter, r *http.Request, targe
|
|||||||
r.URL, _ = url.Parse(originalHostHeader)
|
r.URL, _ = url.Parse(originalHostHeader)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Build downstream and upstream header rules
|
||||||
|
upstreamHeaders, downstreamHeaders := target.parent.SplitInboundOutboundHeaders()
|
||||||
|
|
||||||
err := target.proxy.ServeHTTP(w, r, &dpcore.ResponseRewriteRuleSet{
|
err := target.proxy.ServeHTTP(w, r, &dpcore.ResponseRewriteRuleSet{
|
||||||
ProxyDomain: target.Domain,
|
ProxyDomain: target.Domain,
|
||||||
OriginalHost: originalHostHeader,
|
OriginalHost: originalHostHeader,
|
||||||
UseTLS: target.RequireTLS,
|
UseTLS: target.RequireTLS,
|
||||||
PathPrefix: target.MatchingPath,
|
PathPrefix: target.MatchingPath,
|
||||||
|
UpstreamHeaders: upstreamHeaders,
|
||||||
|
DownstreamHeaders: downstreamHeaders,
|
||||||
|
Version: target.parent.parent.Option.HostVersion,
|
||||||
})
|
})
|
||||||
|
|
||||||
var dnsError *net.DNSError
|
var dnsError *net.DNSError
|
||||||
|
@ -86,7 +86,6 @@ type UserDefinedHeader struct {
|
|||||||
Key string
|
Key string
|
||||||
Value string
|
Value string
|
||||||
IsRemove bool //Instead of set, remove this key instead
|
IsRemove bool //Instead of set, remove this key instead
|
||||||
IsAppend bool //Instead of set, append to the current one with "," as seperator
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// A Virtual Directory endpoint, provide a subset of ProxyEndpoint for better
|
// A Virtual Directory endpoint, provide a subset of ProxyEndpoint for better
|
||||||
|
@ -42,17 +42,22 @@ SendEmail(
|
|||||||
)
|
)
|
||||||
*/
|
*/
|
||||||
func (s *Sender) SendEmail(to string, subject string, content string) error {
|
func (s *Sender) SendEmail(to string, subject string, content string) error {
|
||||||
//Parse the email content
|
// Parse the email content
|
||||||
msg := []byte("To: " + to + "\n" +
|
msg := []byte("To: " + to + "\n" +
|
||||||
"From: Zoraxy <" + s.SenderAddr + ">\n" +
|
"From: Zoraxy <" + s.SenderAddr + ">\n" +
|
||||||
"Subject: " + subject + "\n" +
|
"Subject: " + subject + "\n" +
|
||||||
"MIME-version: 1.0;\nContent-Type: text/html; charset=\"UTF-8\";\n\n" +
|
"MIME-version: 1.0;\nContent-Type: text/html; charset=\"UTF-8\";\n\n" +
|
||||||
content + "\n\n")
|
content + "\n\n")
|
||||||
|
|
||||||
//Login to the SMTP server
|
// Initialize the auth variable
|
||||||
//Username can be username (e.g. admin) or email (e.g. admin@example.com), depending on SMTP service provider
|
var auth smtp.Auth
|
||||||
auth := smtp.PlainAuth("", s.Username, s.Password, s.Hostname)
|
if s.Password != "" {
|
||||||
|
// Login to the SMTP server
|
||||||
|
// Username can be username (e.g. admin) or email (e.g. admin@example.com), depending on SMTP service provider
|
||||||
|
auth = smtp.PlainAuth("", s.Username, s.Password, s.Hostname)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the email
|
||||||
err := smtp.SendMail(s.Hostname+":"+strconv.Itoa(s.Port), auth, s.SenderAddr, []string{to}, msg)
|
err := smtp.SendMail(s.Hostname+":"+strconv.Itoa(s.Port), auth, s.SenderAddr, []string{to}, msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -1076,9 +1076,9 @@ func HandleCustomHeaderList(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
// Add a new header to the target endpoint
|
// Add a new header to the target endpoint
|
||||||
func HandleCustomHeaderAdd(w http.ResponseWriter, r *http.Request) {
|
func HandleCustomHeaderAdd(w http.ResponseWriter, r *http.Request) {
|
||||||
epType, err := utils.PostPara(r, "type")
|
rewriteType, err := utils.PostPara(r, "type")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.SendErrorResponse(w, "endpoint type not defined")
|
utils.SendErrorResponse(w, "rewriteType not defined")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1088,6 +1088,12 @@ func HandleCustomHeaderAdd(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
direction, err := utils.PostPara(r, "direction")
|
||||||
|
if err != nil {
|
||||||
|
utils.SendErrorResponse(w, "HTTP modifiy direction not set")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
name, err := utils.PostPara(r, "name")
|
name, err := utils.PostPara(r, "name")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.SendErrorResponse(w, "HTTP header name not set")
|
utils.SendErrorResponse(w, "HTTP header name not set")
|
||||||
@ -1095,26 +1101,46 @@ func HandleCustomHeaderAdd(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
value, err := utils.PostPara(r, "value")
|
value, err := utils.PostPara(r, "value")
|
||||||
if err != nil {
|
if err != nil && rewriteType == "add" {
|
||||||
utils.SendErrorResponse(w, "HTTP header value not set")
|
utils.SendErrorResponse(w, "HTTP header value not set")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var targetProxyEndpoint *dynamicproxy.ProxyEndpoint
|
targetProxyEndpoint, err := dynamicProxyRouter.LoadProxy(domain)
|
||||||
if epType == "root" {
|
if err != nil {
|
||||||
targetProxyEndpoint = dynamicProxyRouter.Root
|
utils.SendErrorResponse(w, "target endpoint not exists")
|
||||||
} else {
|
return
|
||||||
ep, err := dynamicProxyRouter.LoadProxy(domain)
|
}
|
||||||
if err != nil {
|
|
||||||
utils.SendErrorResponse(w, "target endpoint not exists")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
targetProxyEndpoint = ep
|
//Create a Custom Header Defination type
|
||||||
|
var rewriteDirection dynamicproxy.HeaderDirection
|
||||||
|
if direction == "toOrigin" {
|
||||||
|
rewriteDirection = dynamicproxy.HeaderDirection_ZoraxyToUpstream
|
||||||
|
} else if direction == "toClient" {
|
||||||
|
rewriteDirection = dynamicproxy.HeaderDirection_ZoraxyToDownstream
|
||||||
|
} else {
|
||||||
|
//Unknown direction
|
||||||
|
utils.SendErrorResponse(w, "header rewrite direction not supported")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
isRemove := false
|
||||||
|
if rewriteType == "remove" {
|
||||||
|
isRemove = true
|
||||||
|
}
|
||||||
|
headerRewriteDefination := dynamicproxy.UserDefinedHeader{
|
||||||
|
Key: name,
|
||||||
|
Value: value,
|
||||||
|
Direction: rewriteDirection,
|
||||||
|
IsRemove: isRemove,
|
||||||
}
|
}
|
||||||
|
|
||||||
//Create a new custom header object
|
//Create a new custom header object
|
||||||
targetProxyEndpoint.AddUserDefinedHeader(name, value)
|
err = targetProxyEndpoint.AddUserDefinedHeader(&headerRewriteDefination)
|
||||||
|
if err != nil {
|
||||||
|
utils.SendErrorResponse(w, "unable to add header rewrite rule: "+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
//Save it (no need reload as header are not handled by dpcore)
|
//Save it (no need reload as header are not handled by dpcore)
|
||||||
err = SaveReverseProxyConfig(targetProxyEndpoint)
|
err = SaveReverseProxyConfig(targetProxyEndpoint)
|
||||||
@ -1128,12 +1154,6 @@ func HandleCustomHeaderAdd(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
// Remove a header from the target endpoint
|
// Remove a header from the target endpoint
|
||||||
func HandleCustomHeaderRemove(w http.ResponseWriter, r *http.Request) {
|
func HandleCustomHeaderRemove(w http.ResponseWriter, r *http.Request) {
|
||||||
epType, err := utils.PostPara(r, "type")
|
|
||||||
if err != nil {
|
|
||||||
utils.SendErrorResponse(w, "endpoint type not defined")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
domain, err := utils.PostPara(r, "domain")
|
domain, err := utils.PostPara(r, "domain")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.SendErrorResponse(w, "domain or matching rule not defined")
|
utils.SendErrorResponse(w, "domain or matching rule not defined")
|
||||||
@ -1146,20 +1166,17 @@ func HandleCustomHeaderRemove(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var targetProxyEndpoint *dynamicproxy.ProxyEndpoint
|
targetProxyEndpoint, err := dynamicProxyRouter.LoadProxy(domain)
|
||||||
if epType == "root" {
|
if err != nil {
|
||||||
targetProxyEndpoint = dynamicProxyRouter.Root
|
utils.SendErrorResponse(w, "target endpoint not exists")
|
||||||
} else {
|
return
|
||||||
ep, err := dynamicProxyRouter.LoadProxy(domain)
|
|
||||||
if err != nil {
|
|
||||||
utils.SendErrorResponse(w, "target endpoint not exists")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
targetProxyEndpoint = ep
|
|
||||||
}
|
}
|
||||||
|
|
||||||
targetProxyEndpoint.RemoveUserDefinedHeader(name)
|
err = targetProxyEndpoint.RemoveUserDefinedHeader(name)
|
||||||
|
if err != nil {
|
||||||
|
utils.SendErrorResponse(w, "unable to remove header rewrite rule: "+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
err = SaveReverseProxyConfig(targetProxyEndpoint)
|
err = SaveReverseProxyConfig(targetProxyEndpoint)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -68,12 +68,13 @@
|
|||||||
<div class="standardContainer">
|
<div class="standardContainer">
|
||||||
<div class="ui divider"></div>
|
<div class="ui divider"></div>
|
||||||
<h4>Global Settings</h4>
|
<h4>Global Settings</h4>
|
||||||
<p>Inbound Port (Port to be proxied)</p>
|
<p>Inbound Port (Reverse Proxy Listening Port)</p>
|
||||||
<div class="ui action fluid notloopbackOnly input">
|
<div class="ui action fluid notloopbackOnly input">
|
||||||
|
<small id="applyButtonReminder">Click "Apply" button to confirm listening port changes</small>
|
||||||
<input type="text" id="incomingPort" placeholder="Incoming Port" value="80">
|
<input type="text" id="incomingPort" placeholder="Incoming Port" value="80">
|
||||||
<button class="ui basic notloopbackOnly button" onclick="handlePortChange();"><i class="ui green checkmark icon"></i> Apply</button>
|
<button class="ui green notloopbackOnly button" style="background: linear-gradient(60deg, #27e7ff, #00ca52);" onclick="handlePortChange();"><i class="ui checkmark icon"></i> Apply</button>
|
||||||
</div>
|
</div>
|
||||||
<br>
|
<br><br>
|
||||||
<div id="tls" class="ui toggle notloopbackOnly checkbox">
|
<div id="tls" class="ui toggle notloopbackOnly checkbox">
|
||||||
<input type="checkbox">
|
<input type="checkbox">
|
||||||
<label>Use TLS to serve proxy request</label>
|
<label>Use TLS to serve proxy request</label>
|
||||||
@ -160,6 +161,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
let loopbackProxiedInterface = false;
|
let loopbackProxiedInterface = false;
|
||||||
|
let currentListeningPort = 80;
|
||||||
$(".advanceSettings").accordion();
|
$(".advanceSettings").accordion();
|
||||||
|
|
||||||
//Initial the start stop button if this is reverse proxied
|
//Initial the start stop button if this is reverse proxied
|
||||||
@ -176,6 +178,8 @@
|
|||||||
//Get the latest server status from proxy server
|
//Get the latest server status from proxy server
|
||||||
function initRPStaste(){
|
function initRPStaste(){
|
||||||
$.get("/api/proxy/status", function(data){
|
$.get("/api/proxy/status", function(data){
|
||||||
|
$("#incomingPort").off("change");
|
||||||
|
|
||||||
if (data.Running == true){
|
if (data.Running == true){
|
||||||
$("#startbtn").addClass("disabled");
|
$("#startbtn").addClass("disabled");
|
||||||
if (!loopbackProxiedInterface){
|
if (!loopbackProxiedInterface){
|
||||||
@ -194,6 +198,15 @@
|
|||||||
$("#serverstatus").removeClass("green");
|
$("#serverstatus").removeClass("green");
|
||||||
}
|
}
|
||||||
$("#incomingPort").val(data.Option.Port);
|
$("#incomingPort").val(data.Option.Port);
|
||||||
|
currentListeningPort = data.Option.Port;
|
||||||
|
$("#incomingPort").on("change", function(){
|
||||||
|
let newPortValue = $("#incomingPort").val().trim();
|
||||||
|
if (currentListeningPort != newPortValue){
|
||||||
|
$("#applyButtonReminder").show();
|
||||||
|
}else{
|
||||||
|
$("#applyButtonReminder").hide();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -353,8 +366,11 @@
|
|||||||
msgbox(data.error, false, 5000);
|
msgbox(data.error, false, 5000);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
msgbox("Setting Updated");
|
msgbox("Listening Port Updated");
|
||||||
initRPStaste();
|
initRPStaste();
|
||||||
|
|
||||||
|
//Hide the reminder text
|
||||||
|
$("#applyButtonReminder").hide();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,7 +112,6 @@
|
|||||||
}
|
}
|
||||||
clearStreamProxyAddEditForm();
|
clearStreamProxyAddEditForm();
|
||||||
initProxyConfigList();
|
initProxyConfigList();
|
||||||
$("#addproxyConfig").slideUp("fast");
|
|
||||||
},
|
},
|
||||||
error: function() {
|
error: function() {
|
||||||
msgbox('An error occurred while processing the request', false);
|
msgbox('An error occurred while processing the request', false);
|
||||||
@ -123,6 +122,7 @@
|
|||||||
function clearStreamProxyAddEditForm(){
|
function clearStreamProxyAddEditForm(){
|
||||||
$('#streamProxyForm input, #streamProxyForm select').val('');
|
$('#streamProxyForm input, #streamProxyForm select').val('');
|
||||||
$('#streamProxyForm select').dropdown('clear');
|
$('#streamProxyForm select').dropdown('clear');
|
||||||
|
$("#streamProxyForm input[name=timeout]").val(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
function cancelStreamProxyEdit(event=undefined) {
|
function cancelStreamProxyEdit(event=undefined) {
|
||||||
@ -268,8 +268,6 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
editingStreamProxyConfigUUID = configUUID;
|
editingStreamProxyConfigUUID = configUUID;
|
||||||
$("#addproxyConfig").slideDown("fast");
|
|
||||||
|
|
||||||
}else{
|
}else{
|
||||||
msgbox("Unable to load target config", false);
|
msgbox("Unable to load target config", false);
|
||||||
}
|
}
|
||||||
|
@ -217,6 +217,7 @@
|
|||||||
$("#zoraxyinfo .uuid").text(data.NodeUUID);
|
$("#zoraxyinfo .uuid").text(data.NodeUUID);
|
||||||
$("#zoraxyinfo .development").text(data.Development?"Development":"Release");
|
$("#zoraxyinfo .development").text(data.Development?"Development":"Release");
|
||||||
$("#zoraxyinfo .version").text(data.Version);
|
$("#zoraxyinfo .version").text(data.Version);
|
||||||
|
$(".zrversion").text("v." + data.Version); //index footer
|
||||||
$("#zoraxyinfo .boottime").text(timeConverter(data.BootTime) + ` ( ${secondsToDhms(parseInt(Date.now()/1000) - data.BootTime)} ago)`);
|
$("#zoraxyinfo .boottime").text(timeConverter(data.BootTime) + ` ( ${secondsToDhms(parseInt(Date.now()/1000) - data.BootTime)} ago)`);
|
||||||
$("#zoraxyinfo .zt").html(data.ZerotierConnected?`<i class="ui green check icon"></i> Connected`:`<i class="ui red times icon"></i> Link Error`);
|
$("#zoraxyinfo .zt").html(data.ZerotierConnected?`<i class="ui green check icon"></i> Connected`:`<i class="ui red times icon"></i> Link Error`);
|
||||||
$("#zoraxyinfo .sshlb").html(data.EnableSshLoopback?`<i class="ui yellow exclamation triangle icon"></i> Enabled`:`Disabled`);
|
$("#zoraxyinfo .sshlb").html(data.EnableSshLoopback?`<i class="ui yellow exclamation triangle icon"></i> Enabled`:`Disabled`);
|
||||||
@ -341,15 +342,6 @@
|
|||||||
form.find('input[name="username"]').parent().removeClass('error');
|
form.find('input[name="username"]').parent().removeClass('error');
|
||||||
}
|
}
|
||||||
|
|
||||||
// validate password
|
|
||||||
const password = form.find('input[name="password"]').val().trim();
|
|
||||||
if (password === '') {
|
|
||||||
form.find('input[name="password"]').parent().addClass('error');
|
|
||||||
isValid = false;
|
|
||||||
} else {
|
|
||||||
form.find('input[name="password"]').parent().removeClass('error');
|
|
||||||
}
|
|
||||||
|
|
||||||
// validate sender address
|
// validate sender address
|
||||||
const senderAddr = form.find('input[name="senderAddr"]').val().trim();
|
const senderAddr = form.find('input[name="senderAddr"]').val().trim();
|
||||||
if (!emailRegex.test(senderAddr)) {
|
if (!emailRegex.test(senderAddr)) {
|
||||||
|
@ -154,7 +154,7 @@
|
|||||||
<br><br>
|
<br><br>
|
||||||
<div class="ui divider"></div>
|
<div class="ui divider"></div>
|
||||||
<div class="ui container" style="color: grey; font-size: 90%">
|
<div class="ui container" style="color: grey; font-size: 90%">
|
||||||
<p>CopyRight Zoraxy Project and its authors © 2021 - <span class="year"></span></p>
|
<p><a href="https://zoraxy.arozos.com" target="_blank">Zoraxy</a> <span class="zrversion"></span> © 2021 - <span class="year"></span> tobychui. Licensed under AGPL</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="messageBox" class="ui green floating big compact message">
|
<div id="messageBox" class="ui green floating big compact message">
|
||||||
|
@ -509,6 +509,16 @@ body{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Remind message for user forgetting to click Apply button*/
|
||||||
|
#applyButtonReminder{
|
||||||
|
position: absolute;
|
||||||
|
bottom:-1.6em;
|
||||||
|
left: 0;
|
||||||
|
font-weight: bolder;
|
||||||
|
color: #faac26;
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
HTTP Proxy & Virtual Directory
|
HTTP Proxy & Virtual Directory
|
||||||
*/
|
*/
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
<table class="ui very basic compacted unstackable celled table">
|
<table class="ui very basic compacted unstackable celled table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Name</th>
|
<th>Key</th>
|
||||||
<th>Value</th>
|
<th>Value</th>
|
||||||
<th>Remove</th>
|
<th>Remove</th>
|
||||||
</tr></thead>
|
</tr></thead>
|
||||||
@ -34,18 +34,29 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<div class="ui divider"></div>
|
<div class="ui divider"></div>
|
||||||
<h4>Add Custom Header</h4>
|
<h4>Edit Custom Header</h4>
|
||||||
<p>Add custom header(s) into this proxy target</p>
|
<p>Add or remove custom header(s) over this proxy target</p>
|
||||||
<div class="scrolling content ui form">
|
<div class="scrolling content ui form">
|
||||||
<div class="three small fields credentialEntry">
|
<div class="five small fields credentialEntry">
|
||||||
<div class="field">
|
<div class="field" align="center">
|
||||||
<input id="headerName" type="text" placeholder="X-Custom-Header" autocomplete="off">
|
<button id="toOriginButton" title="Downstream to Upstream" class="ui circular basic active button">Zoraxy <i class="angle double right blue icon" style="margin-right: 0.4em;"></i> Origin</button>
|
||||||
|
<button id="toClientButton" title="Upstream to Downstream" class="ui circular basic button">Client <i class="angle double left orange icon" style="margin-left: 0.4em;"></i> Zoraxy</button>
|
||||||
|
</div>
|
||||||
|
<div class="field" align="center">
|
||||||
|
<button id="headerModeAdd" class="ui circular basic active button"><i class="ui green circle add icon"></i> Add Header</button>
|
||||||
|
<button id="headerModeRemove" class="ui circular basic button"><i class="ui red circle times icon"></i> Remove Header</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
|
<label>Header Key</label>
|
||||||
|
<input id="headerName" type="text" placeholder="X-Custom-Header" autocomplete="off">
|
||||||
|
<small>The header key is <b>NOT</b> case sensitive</small>
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label>Header Value</label>
|
||||||
<input id="headerValue" type="text" placeholder="value1,value2,value3" autocomplete="off">
|
<input id="headerValue" type="text" placeholder="value1,value2,value3" autocomplete="off">
|
||||||
</div>
|
</div>
|
||||||
<div class="field" >
|
<div class="field" >
|
||||||
<button class="ui basic button" onclick="addCustomHeader();"><i class="green add icon"></i> Add Header</button>
|
<button class="ui basic button" onclick="addCustomHeader();"><i class="green add icon"></i> Add Header Rewrite Rule</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui divider"></div>
|
<div class="ui divider"></div>
|
||||||
</div>
|
</div>
|
||||||
@ -75,6 +86,47 @@
|
|||||||
parent.hideSideWrapper(true);
|
parent.hideSideWrapper(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Bind events to header mod mode
|
||||||
|
$("#headerModeAdd").on("click", function(){
|
||||||
|
$("#headerModeAdd").addClass("active");
|
||||||
|
$("#headerModeRemove").removeClass("active");
|
||||||
|
$("#headerValue").parent().show();
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#headerModeRemove").on("click", function(){
|
||||||
|
$("#headerModeAdd").removeClass("active");
|
||||||
|
$("#headerModeRemove").addClass("active");
|
||||||
|
$("#headerValue").parent().hide();
|
||||||
|
});
|
||||||
|
|
||||||
|
//Bind events to header directions option
|
||||||
|
$("#toOriginButton").on("click", function(){
|
||||||
|
$("#toOriginButton").addClass("active");
|
||||||
|
$("#toClientButton").removeClass("active");
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#toClientButton").on("click", function(){
|
||||||
|
$("#toOriginButton").removeClass("active");
|
||||||
|
$("#toClientButton").addClass("active");
|
||||||
|
});
|
||||||
|
|
||||||
|
//Return "add" or "remove" depending on mode user selected
|
||||||
|
function getHeaderEditMode(){
|
||||||
|
if ($("#headerModeAdd").hasClass("active")){
|
||||||
|
return "add";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "remove";
|
||||||
|
}
|
||||||
|
|
||||||
|
//Return "toOrigin" or "toClient"
|
||||||
|
function getHeaderDirection(){
|
||||||
|
if ($("#toOriginButton").hasClass("active")){
|
||||||
|
return "toOrigin";
|
||||||
|
}
|
||||||
|
return "toClient";
|
||||||
|
}
|
||||||
|
|
||||||
//$("#debug").text(JSON.stringify(editingEndpoint));
|
//$("#debug").text(JSON.stringify(editingEndpoint));
|
||||||
|
|
||||||
function addCustomHeader(){
|
function addCustomHeader(){
|
||||||
@ -88,18 +140,21 @@
|
|||||||
$("#headerName").parent().removeClass("error");
|
$("#headerName").parent().removeClass("error");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value == ""){
|
if (getHeaderEditMode() == "add"){
|
||||||
$("#headerValue").parent().addClass("error");
|
if (value == ""){
|
||||||
return
|
$("#headerValue").parent().addClass("error");
|
||||||
}else{
|
return
|
||||||
$("#headerValue").parent().removeClass("error");
|
}else{
|
||||||
|
$("#headerValue").parent().removeClass("error");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: "/api/proxy/header/add",
|
url: "/api/proxy/header/add",
|
||||||
data: {
|
data: {
|
||||||
"type": editingEndpoint.ept,
|
"type": getHeaderEditMode(),
|
||||||
"domain": editingEndpoint.ep,
|
"domain": editingEndpoint.ep,
|
||||||
|
"direction":getHeaderDirection(),
|
||||||
"name": name,
|
"name": name,
|
||||||
"value": value
|
"value": value
|
||||||
},
|
},
|
||||||
@ -129,7 +184,7 @@
|
|||||||
$.ajax({
|
$.ajax({
|
||||||
url: "/api/proxy/header/remove",
|
url: "/api/proxy/header/remove",
|
||||||
data: {
|
data: {
|
||||||
"type": editingEndpoint.ept,
|
//"type": editingEndpoint.ept,
|
||||||
"domain": editingEndpoint.ep,
|
"domain": editingEndpoint.ep,
|
||||||
"name": name,
|
"name": name,
|
||||||
},
|
},
|
||||||
@ -157,10 +212,16 @@
|
|||||||
|
|
||||||
$("#headerTable").html("");
|
$("#headerTable").html("");
|
||||||
data.forEach(header => {
|
data.forEach(header => {
|
||||||
|
let editModeIcon = header.IsRemove?`<i class="ui red times circle icon"></i>`:`<i class="ui green add circle icon"></i>`;
|
||||||
|
let direction = (header.Direction==0)?`<i class="angle double right blue icon"></i>`:`<i class="angle double left orange icon"></i>`;
|
||||||
|
let valueField = header.Value;
|
||||||
|
if (header.IsRemove){
|
||||||
|
valueField = "<small style='color: grey;'>(Field Removed)</small>";
|
||||||
|
}
|
||||||
$("#headerTable").append(`
|
$("#headerTable").append(`
|
||||||
<tr>
|
<tr>
|
||||||
<td>${header.Key}</td>
|
<td>${direction} ${header.Key}</td>
|
||||||
<td>${header.Value}</td>
|
<td>${editModeIcon} ${valueField}</td>
|
||||||
<td><button class="ui basic circular mini red icon button" onclick="deleteCustomHeader('${header.Key}');"><i class="ui trash icon"></i></button></td>
|
<td><button class="ui basic circular mini red icon button" onclick="deleteCustomHeader('${header.Key}');"><i class="ui trash icon"></i></button></td>
|
||||||
</tr>
|
</tr>
|
||||||
`);
|
`);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user