fix rewrite query param bug

Signed-off-by: Ronni Skansing <rskansing@gmail.com>
This commit is contained in:
Ronni Skansing
2025-12-02 20:31:29 +01:00
parent 30a284da85
commit e90dc9081f
2 changed files with 67 additions and 9 deletions

View File

@@ -4751,10 +4751,13 @@ func (m *ProxyHandler) checkFilter(req *http.Request, reqCtx *RequestContext) (b
// and returns a redirect response if a match is found
func (m *ProxyHandler) checkAndApplyURLRewrite(req *http.Request, reqCtx *RequestContext) *http.Response {
// check if this is already a rewritten URL that we need to reverse map
// lookup by path only to handle query parameter variations
originalPath := m.getReverseURLMapping(req.URL.Path)
// lookup by path and target domain to handle query parameter variations
originalPath := m.getReverseURLMapping(req.URL.Path, reqCtx.TargetDomain)
if originalPath != "" {
// update request to use the original path (keep query as-is)
// reverse query parameters first (before changing path)
rewrittenPath := req.URL.Path
m.reverseQueryParameters(req, rewrittenPath, reqCtx.TargetDomain)
// update request to use the original path
req.URL.Path = originalPath
return nil
}
@@ -4779,7 +4782,10 @@ func (m *ProxyHandler) checkAndApplyURLRewrite(req *http.Request, reqCtx *Reques
if idx := strings.Index(rewrittenURL, "?"); idx != -1 {
rewrittenPath = rewrittenURL[:idx]
}
m.storeURLMapping(rewrittenPath, req.URL.Path)
m.storeURLMapping(rewrittenPath, req.URL.Path, reqCtx.TargetDomain)
// store query parameter mappings for reverse lookup
m.storeQueryParameterMappings(rewrittenPath, rule.Query, reqCtx.TargetDomain)
// create redirect response
return &http.Response{
@@ -4873,19 +4879,55 @@ func contains(slice []string, item string) bool {
}
// storeURLMapping stores the mapping between rewritten and original URLs
func (m *ProxyHandler) storeURLMapping(rewrittenURL, originalURL string) {
m.SessionManager.StoreURLMapping(rewrittenURL, originalURL)
func (m *ProxyHandler) storeURLMapping(rewrittenURL, originalURL, targetDomain string) {
key := targetDomain + "|" + rewrittenURL
m.SessionManager.StoreURLMapping(key, originalURL)
}
// storeQueryParameterMappings stores query parameter mappings for reverse lookup
func (m *ProxyHandler) storeQueryParameterMappings(rewrittenPath string, queryRules []service.ProxyServiceURLRewriteQueryParam, targetDomain string) {
key := targetDomain + "|" + rewrittenPath
m.SessionManager.StoreQueryParameterMappings(key, queryRules)
}
// getReverseURLMapping gets the original path for a rewritten path
// only uses path for lookup to handle query parameter variations
func (m *ProxyHandler) getReverseURLMapping(path string) string {
if originalPath, exists := m.SessionManager.GetURLMapping(path); exists {
// uses path and target domain for lookup to handle per-host configurations
func (m *ProxyHandler) getReverseURLMapping(path, targetDomain string) string {
key := targetDomain + "|" + path
if originalPath, exists := m.SessionManager.GetURLMapping(key); exists {
return originalPath
}
return ""
}
// reverseQueryParameters reverses query parameter names back to their originals
func (m *ProxyHandler) reverseQueryParameters(req *http.Request, rewrittenPath, targetDomain string) {
key := targetDomain + "|" + rewrittenPath
queryRules, exists := m.SessionManager.GetQueryParameterMappings(key)
if !exists || len(queryRules) == 0 {
return
}
query := req.URL.Query()
reversedQuery := url.Values{}
// copy all parameters first
for key, values := range query {
reversedQuery[key] = values
}
// reverse the mapped parameters
for _, rule := range queryRules {
if values, exists := query[rule.Replace]; exists {
// remove the rewritten key and restore the original key
delete(reversedQuery, rule.Replace)
reversedQuery[rule.Find] = values
}
}
req.URL.RawQuery = reversedQuery.Encode()
}
// applyURLPathRewrites applies URL path rewriting to response body content
func (m *ProxyHandler) applyURLPathRewrites(body []byte, reqCtx *RequestContext) []byte {
// get URL rewrite rules from domain config

View File

@@ -38,6 +38,7 @@ type ProxySessionManager struct {
sessions sync.Map // map[sessionID]*ProxySession
campaignRecipientSessions sync.Map // map[campaignRecipientID]sessionID
urlMappings sync.Map // map[rewritten URL]original URL
queryParameterMappings sync.Map // map[rewritten path][]ProxyServiceURLRewriteQueryParam
}
// NewProxySessionManager creates a new proxy session manager
@@ -106,6 +107,21 @@ func (m *ProxySessionManager) GetURLMapping(rewrittenURL string) (string, bool)
return originalURL, ok
}
// StoreQueryParameterMappings stores query parameter mappings for reverse lookup
func (m *ProxySessionManager) StoreQueryParameterMappings(rewrittenPath string, queryRules []ProxyServiceURLRewriteQueryParam) {
m.queryParameterMappings.Store(rewrittenPath, queryRules)
}
// GetQueryParameterMappings retrieves query parameter mappings for a rewritten path
func (m *ProxySessionManager) GetQueryParameterMappings(rewrittenPath string) ([]ProxyServiceURLRewriteQueryParam, bool) {
val, ok := m.queryParameterMappings.Load(rewrittenPath)
if !ok {
return nil, false
}
queryRules, ok := val.([]ProxyServiceURLRewriteQueryParam)
return queryRules, ok
}
// RangeSessions iterates over all sessions
func (m *ProxySessionManager) RangeSessions(fn func(sessionID string, session *ProxySession) bool) {
m.sessions.Range(func(key, value interface{}) bool {