mirror of
https://github.com/alibaba/higress.git
synced 2026-02-28 14:40:50 +08:00
311 lines
7.0 KiB
Go
311 lines
7.0 KiB
Go
package pkg
|
|
|
|
import (
|
|
"maps"
|
|
"net/url"
|
|
"strings"
|
|
|
|
"github.com/higress-group/wasm-go/pkg/log"
|
|
)
|
|
|
|
type Stage int
|
|
|
|
const (
|
|
StageInvalid Stage = iota
|
|
StageRequestHeaders
|
|
StageRequestBody
|
|
StageResponseHeaders
|
|
StageResponseBody
|
|
|
|
pathHeader = ":path"
|
|
)
|
|
|
|
var (
|
|
OrderedStages = []Stage{
|
|
StageRequestHeaders,
|
|
StageRequestBody,
|
|
StageResponseHeaders,
|
|
StageResponseBody,
|
|
}
|
|
Stage2String = map[Stage]string{
|
|
StageRequestHeaders: "request_headers",
|
|
StageRequestBody: "request_body",
|
|
StageResponseHeaders: "response_headers",
|
|
StageResponseBody: "response_body",
|
|
}
|
|
)
|
|
|
|
type EditorContext interface {
|
|
GetEffectiveCommandSet() *CommandSet
|
|
SetEffectiveCommandSet(cmdSet *CommandSet)
|
|
GetCommandExecutors() []Executor
|
|
SetCommandExecutors(executors []Executor)
|
|
GetCurrentStage() Stage
|
|
SetCurrentStage(stage Stage)
|
|
|
|
GetRequestPath() string
|
|
SetRequestPath(path string)
|
|
GetRequestHeader(key string) []string
|
|
GetRequestHeaders() map[string][]string
|
|
SetRequestHeaders(map[string][]string)
|
|
GetRequestQuery(key string) []string
|
|
GetRequestQueries() map[string][]string
|
|
SetRequestQueries(map[string][]string)
|
|
GetResponseHeader(key string) []string
|
|
GetResponseHeaders() map[string][]string
|
|
SetResponseHeaders(map[string][]string)
|
|
|
|
GetRefValue(ref *Ref) string
|
|
GetRefValues(ref *Ref) []string
|
|
SetRefValue(ref *Ref, value string)
|
|
SetRefValues(ref *Ref, values []string)
|
|
DeleteRefValues(ref *Ref)
|
|
|
|
IsRequestHeadersDirty() bool
|
|
IsResponseHeadersDirty() bool
|
|
ResetDirtyFlags()
|
|
}
|
|
|
|
func NewEditorContext() EditorContext {
|
|
return &editorContext{}
|
|
}
|
|
|
|
type editorContext struct {
|
|
effectiveCommandSet *CommandSet
|
|
commandExecutors []Executor
|
|
|
|
currentStage Stage
|
|
|
|
requestPath string
|
|
requestHeaders map[string][]string
|
|
requestQueries map[string][]string
|
|
responseHeaders map[string][]string
|
|
|
|
requestHeadersDirty bool
|
|
responseHeadersDirty bool
|
|
}
|
|
|
|
func (ctx *editorContext) GetEffectiveCommandSet() *CommandSet {
|
|
return ctx.effectiveCommandSet
|
|
}
|
|
|
|
func (ctx *editorContext) SetEffectiveCommandSet(cmdSet *CommandSet) {
|
|
ctx.effectiveCommandSet = cmdSet
|
|
}
|
|
|
|
func (ctx *editorContext) GetCommandExecutors() []Executor {
|
|
return ctx.commandExecutors
|
|
}
|
|
|
|
func (ctx *editorContext) SetCommandExecutors(executors []Executor) {
|
|
ctx.commandExecutors = executors
|
|
}
|
|
|
|
func (ctx *editorContext) GetCurrentStage() Stage {
|
|
return ctx.currentStage
|
|
}
|
|
|
|
func (ctx *editorContext) SetCurrentStage(stage Stage) {
|
|
ctx.currentStage = stage
|
|
}
|
|
|
|
func (ctx *editorContext) GetRequestPath() string {
|
|
return ctx.requestPath
|
|
}
|
|
|
|
func (ctx *editorContext) SetRequestPath(path string) {
|
|
ctx.requestPath = path
|
|
ctx.savePathToHeader()
|
|
}
|
|
|
|
func (ctx *editorContext) GetRequestHeader(key string) []string {
|
|
if ctx.requestHeaders == nil {
|
|
return nil
|
|
}
|
|
return ctx.requestHeaders[strings.ToLower(key)]
|
|
}
|
|
|
|
func (ctx *editorContext) GetRequestHeaders() map[string][]string {
|
|
return maps.Clone(ctx.requestHeaders)
|
|
}
|
|
|
|
func (ctx *editorContext) SetRequestHeaders(headers map[string][]string) {
|
|
ctx.requestHeaders = headers
|
|
ctx.loadPathFromHeader()
|
|
ctx.requestHeadersDirty = true
|
|
}
|
|
|
|
func (ctx *editorContext) GetRequestQuery(key string) []string {
|
|
if ctx.requestQueries == nil {
|
|
return nil
|
|
}
|
|
return ctx.requestQueries[key]
|
|
}
|
|
|
|
func (ctx *editorContext) GetRequestQueries() map[string][]string {
|
|
return maps.Clone(ctx.requestQueries)
|
|
}
|
|
|
|
func (ctx *editorContext) SetRequestQueries(queries map[string][]string) {
|
|
ctx.requestQueries = queries
|
|
ctx.savePathToHeader()
|
|
}
|
|
|
|
func (ctx *editorContext) GetResponseHeader(key string) []string {
|
|
if ctx.responseHeaders == nil {
|
|
return nil
|
|
}
|
|
return ctx.responseHeaders[strings.ToLower(key)]
|
|
}
|
|
|
|
func (ctx *editorContext) GetResponseHeaders() map[string][]string {
|
|
return maps.Clone(ctx.responseHeaders)
|
|
}
|
|
|
|
func (ctx *editorContext) SetResponseHeaders(headers map[string][]string) {
|
|
ctx.responseHeaders = headers
|
|
ctx.responseHeadersDirty = true
|
|
}
|
|
|
|
func (ctx *editorContext) GetRefValue(ref *Ref) string {
|
|
values := ctx.GetRefValues(ref)
|
|
if len(values) == 0 {
|
|
return ""
|
|
}
|
|
return values[0]
|
|
}
|
|
|
|
func (ctx *editorContext) GetRefValues(ref *Ref) []string {
|
|
if ref == nil {
|
|
return nil
|
|
}
|
|
switch ref.Type {
|
|
case RefTypeRequestHeader:
|
|
return ctx.GetRequestHeader(strings.ToLower(ref.Name))
|
|
case RefTypeRequestQuery:
|
|
return ctx.GetRequestQuery(ref.Name)
|
|
case RefTypeResponseHeader:
|
|
return ctx.GetResponseHeader(strings.ToLower(ref.Name))
|
|
default:
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func (ctx *editorContext) SetRefValue(ref *Ref, value string) {
|
|
if ref == nil {
|
|
return
|
|
}
|
|
ctx.SetRefValues(ref, []string{value})
|
|
}
|
|
|
|
func (ctx *editorContext) SetRefValues(ref *Ref, values []string) {
|
|
if ref == nil {
|
|
return
|
|
}
|
|
switch ref.Type {
|
|
case RefTypeRequestHeader:
|
|
if ctx.requestHeaders == nil {
|
|
ctx.requestHeaders = make(map[string][]string)
|
|
}
|
|
loweredRefName := strings.ToLower(ref.Name)
|
|
ctx.requestHeaders[loweredRefName] = values
|
|
ctx.requestHeadersDirty = true
|
|
if loweredRefName == pathHeader {
|
|
ctx.loadPathFromHeader()
|
|
}
|
|
break
|
|
case RefTypeRequestQuery:
|
|
if ctx.requestQueries == nil {
|
|
ctx.requestQueries = make(map[string][]string)
|
|
}
|
|
ctx.requestQueries[ref.Name] = values
|
|
ctx.savePathToHeader()
|
|
break
|
|
case RefTypeResponseHeader:
|
|
if ctx.responseHeaders == nil {
|
|
ctx.responseHeaders = make(map[string][]string)
|
|
}
|
|
ctx.responseHeaders[strings.ToLower(ref.Name)] = values
|
|
ctx.responseHeadersDirty = true
|
|
break
|
|
}
|
|
}
|
|
|
|
func (ctx *editorContext) DeleteRefValues(ref *Ref) {
|
|
if ref == nil {
|
|
return
|
|
}
|
|
switch ref.Type {
|
|
case RefTypeRequestHeader:
|
|
delete(ctx.requestHeaders, strings.ToLower(ref.Name))
|
|
ctx.requestHeadersDirty = true
|
|
break
|
|
case RefTypeRequestQuery:
|
|
delete(ctx.requestQueries, ref.Name)
|
|
ctx.savePathToHeader()
|
|
break
|
|
case RefTypeResponseHeader:
|
|
delete(ctx.responseHeaders, strings.ToLower(ref.Name))
|
|
ctx.responseHeadersDirty = true
|
|
break
|
|
}
|
|
}
|
|
|
|
func (ctx *editorContext) IsRequestHeadersDirty() bool {
|
|
return ctx.requestHeadersDirty
|
|
}
|
|
|
|
func (ctx *editorContext) IsResponseHeadersDirty() bool {
|
|
return ctx.responseHeadersDirty
|
|
}
|
|
|
|
func (ctx *editorContext) ResetDirtyFlags() {
|
|
ctx.requestHeadersDirty = false
|
|
ctx.responseHeadersDirty = false
|
|
}
|
|
|
|
func (ctx *editorContext) savePathToHeader() {
|
|
u, err := url.Parse(ctx.requestPath)
|
|
if err != nil {
|
|
log.Errorf("failed to build the new path with query strings: %v", err)
|
|
return
|
|
}
|
|
|
|
query := url.Values{}
|
|
for k, vs := range ctx.requestQueries {
|
|
for _, v := range vs {
|
|
query.Add(k, v)
|
|
}
|
|
}
|
|
u.RawQuery = query.Encode()
|
|
ctx.SetRefValue(&Ref{Type: RefTypeRequestHeader, Name: pathHeader}, u.String())
|
|
}
|
|
|
|
func (ctx *editorContext) loadPathFromHeader() {
|
|
paths := ctx.GetRequestHeader(pathHeader)
|
|
|
|
if len(paths) == 0 || paths[0] == "" {
|
|
log.Warn("the request has an empty path")
|
|
ctx.requestPath = ""
|
|
ctx.requestQueries = make(map[string][]string)
|
|
return
|
|
}
|
|
|
|
path := paths[0]
|
|
queries := make(map[string][]string)
|
|
|
|
u, err := url.Parse(path)
|
|
if err != nil {
|
|
log.Warnf("unable to parse the request path: %s", path)
|
|
ctx.requestPath = ""
|
|
ctx.requestQueries = make(map[string][]string)
|
|
return
|
|
}
|
|
|
|
ctx.requestPath = u.Path
|
|
for k, vs := range u.Query() {
|
|
queries[k] = vs
|
|
}
|
|
ctx.requestQueries = queries
|
|
}
|