diff --git a/filters/builtin/builtin.go b/filters/builtin/builtin.go index 1003756c60..d51974e7af 100644 --- a/filters/builtin/builtin.go +++ b/filters/builtin/builtin.go @@ -139,6 +139,8 @@ func Filters() []filters.Spec { NewSetPath(), NewModRequestHeader(), NewModResponseHeader(), + NewEncodeRequestHeader(), + NewEncodeResponseHeader(), NewDropQuery(), NewSetQuery(), NewHealthCheck(), diff --git a/filters/builtin/header_encode.go b/filters/builtin/header_encode.go new file mode 100644 index 0000000000..cd57f26ac1 --- /dev/null +++ b/filters/builtin/header_encode.go @@ -0,0 +1,112 @@ +package builtin + +import ( + log "github.com/sirupsen/logrus" + "github.com/zalando/skipper/filters" + xencoding "golang.org/x/text/encoding" + "golang.org/x/text/encoding/charmap" +) + +type encodeTyp int + +const ( + requestEncoder encodeTyp = iota + 1 + responseEncoder +) + +type encodeHeaderSpec struct { + typ encodeTyp +} + +type encodeHeader struct { + typ encodeTyp + header string + encoder *xencoding.Encoder +} + +func NewEncodeRequestHeader() *encodeHeaderSpec { + return &encodeHeaderSpec{ + typ: requestEncoder, + } +} +func NewEncodeResponseHeader() *encodeHeaderSpec { + return &encodeHeaderSpec{ + typ: responseEncoder, + } +} + +func (spec *encodeHeaderSpec) Name() string { + switch spec.typ { + case requestEncoder: + return filters.EncodeRequestHeaderName + case responseEncoder: + return filters.EncodeResponseHeaderName + } + return "unknown" +} + +func (spec *encodeHeaderSpec) CreateFilter(args []interface{}) (filters.Filter, error) { + if len(args) != 2 { + return nil, filters.ErrInvalidFilterParameters + } + + header, ok := args[0].(string) + if !ok { + return nil, filters.ErrInvalidFilterParameters + } + to, ok := args[1].(string) + if !ok { + return nil, filters.ErrInvalidFilterParameters + } + + var ( + encoder *xencoding.Encoder + ) + + switch to { + case "ISO8859_1": + encoder = charmap.ISO8859_1.NewEncoder() + case "Windows1252": + encoder = charmap.Windows1252.NewEncoder() + } + + return &encodeHeader{ + typ: spec.typ, + header: header, + encoder: encoder, + }, nil +} + +func (f *encodeHeader) Request(ctx filters.FilterContext) { + if f.typ != requestEncoder { + return + } + + s := ctx.Request().Header.Get(f.header) + if s == "" { + return + } + + sNew, err := f.encoder.String(s) + if err != nil { + log.Errorf("Failed to encode %q: %v", s, err) + } + ctx.Request().Header.Set(f.header, sNew) +} + +func (f *encodeHeader) Response(ctx filters.FilterContext) { + if f.typ != responseEncoder { + return + } + s := ctx.Response().Header.Get(f.header) + if s == "" { + return + } + + sNew, err := f.encoder.String(s) + if err != nil { + log.Errorf("Failed to encode %q: %v", s, err) + } + ctx.Response().Header.Set(f.header, sNew) + +} diff --git a/filters/filters.go b/filters/filters.go index 358e666b17..82cbeb77d9 100644 --- a/filters/filters.go +++ b/filters/filters.go @@ -230,6 +230,8 @@ const ( AppendContextResponseHeaderName = "appendContextResponseHeader" CopyRequestHeaderName = "copyRequestHeader" CopyResponseHeaderName = "copyResponseHeader" + EncodeRequestHeaderName = "encodeRequestHeader" + EncodeResponseHeaderName = "encodeResponseHeader" ModPathName = "modPath" SetPathName = "setPath" RedirectToName = "redirectTo"