Skip to content

Commit

Permalink
filtermanager: cache URL & Cookies
Browse files Browse the repository at this point in the history
Signed-off-by: spacewander <[email protected]>
  • Loading branch information
spacewander committed Feb 24, 2024
1 parent e0d148d commit e18d98a
Show file tree
Hide file tree
Showing 10 changed files with 103 additions and 35 deletions.
7 changes: 3 additions & 4 deletions pkg/expr/cel.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ import (

"mosn.io/htnn/pkg/filtermanager/api"
"mosn.io/htnn/pkg/log"
pkgRequest "mosn.io/htnn/pkg/request"
)

var (
Expand Down Expand Up @@ -205,7 +204,7 @@ func (r *request) Receive(function string, overload string, args []ref.Val) ref.
case "path":
return types.String(r.headers.Path())
case "url_path":
return types.String(pkgRequest.GetUrl(r.headers).Path)
return types.String(r.headers.Url().Path)
case "host":
return types.String(r.headers.Host())
case "scheme":
Expand All @@ -216,7 +215,7 @@ func (r *request) Receive(function string, overload string, args []ref.Val) ref.
name := args[0].Value().(string)
return types.String(r.Header(name))
case "query_path":
return types.String(pkgRequest.GetUrl(r.headers).RawQuery)
return types.String(r.headers.Url().RawQuery)
case "query":
name := args[0].Value().(string)
return types.String(r.Query(name))
Expand All @@ -242,7 +241,7 @@ func (r *request) Header(name string) string {
}

func (r *request) Query(name string) string {
query := pkgRequest.GetUrl(r.headers).Query()
query := r.headers.Url().Query()
v := query[name]
n := len(v)
if n == 1 {
Expand Down
17 changes: 14 additions & 3 deletions pkg/filtermanager/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
package api

import (
"net/http"
"net/url"

"github.com/envoyproxy/envoy/contrib/golang/common/go/api"
"google.golang.org/protobuf/reflect/protoreflect"
)
Expand Down Expand Up @@ -94,16 +97,24 @@ func (f *PassThroughFilter) EncodeTrailers(trailers ResponseTrailerMap) ResultAc

func (f *PassThroughFilter) OnLog() {}

func (f *PassThroughFilter) DecodeRequest(headers api.RequestHeaderMap, data api.BufferInstance, trailers api.RequestTrailerMap) ResultAction {
func (f *PassThroughFilter) DecodeRequest(headers RequestHeaderMap, data BufferInstance, trailers RequestTrailerMap) ResultAction {
return Continue
}

func (f *PassThroughFilter) EncodeResponse(headers api.ResponseHeaderMap, data api.BufferInstance, trailers api.ResponseTrailerMap) ResultAction {
func (f *PassThroughFilter) EncodeResponse(headers ResponseHeaderMap, data BufferInstance, trailers ResponseTrailerMap) ResultAction {
return Continue
}

type HeaderMap = api.HeaderMap
type RequestHeaderMap = api.RequestHeaderMap
type RequestHeaderMap interface {
api.RequestHeaderMap

// Url returns the parsed `url.URL`
Url() *url.URL
// Cookies returns the HTTP Cookies.
// If multiple cookies match the given name, only one cookie will be returned.
Cookies() map[string]*http.Cookie
}
type ResponseHeaderMap = api.ResponseHeaderMap
type DataBufferBase = api.DataBufferBase
type BufferInstance = api.BufferInstance
Expand Down
70 changes: 66 additions & 4 deletions pkg/filtermanager/filtermanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,16 @@ package filtermanager
import (
"encoding/json"
"errors"
"fmt"
"net"
"net/http"
"net/url"
"reflect"
"runtime"
"runtime/debug"
"sort"
"strconv"
"strings"
"sync"

xds "github.com/cncf/xds/go/xds/type/v3"
Expand All @@ -33,6 +37,7 @@ import (
"mosn.io/htnn/pkg/filtermanager/api"
"mosn.io/htnn/pkg/filtermanager/model"
pkgPlugins "mosn.io/htnn/pkg/plugins"
"mosn.io/htnn/pkg/request"
)

// We can't import package below here that will cause build failure in Mac
Expand Down Expand Up @@ -227,6 +232,60 @@ func (m *filterManager) Reset() {
m.callbacks.Reset()
}

type filterManagerRequestHeaderMap struct {
capi.RequestHeaderMap

u *url.URL
cookies map[string]*http.Cookie
}

func (headers *filterManagerRequestHeaderMap) expire(key string) {
switch key {
case ":path":
headers.u = nil
case "cookie":
headers.cookies = nil
}
}

func (headers *filterManagerRequestHeaderMap) Set(key, value string) {
key = strings.ToLower(key)
headers.expire(key)
headers.RequestHeaderMap.Set(key, value)
}

func (headers *filterManagerRequestHeaderMap) Add(key, value string) {
key = strings.ToLower(key)
headers.expire(key)
headers.RequestHeaderMap.Add(key, value)
}

func (headers *filterManagerRequestHeaderMap) Del(key string) {
key = strings.ToLower(key)
headers.expire(key)
headers.RequestHeaderMap.Del(key)
}

func (headers *filterManagerRequestHeaderMap) Url() *url.URL {
if headers.u == nil {
path := headers.Path()
u, err := url.ParseRequestURI(path)
if err != nil {
panic(fmt.Sprintf("unexpected bad request uri given by envoy: %v", err))
}
headers.u = u
}
return headers.u
}

// If multiple cookies match the given name, only one cookie will be returned.
func (headers *filterManagerRequestHeaderMap) Cookies() map[string]*http.Cookie {
if headers.cookies == nil {
headers.cookies = request.ParseCookies(headers)
}
return headers.cookies
}

type filterManagerStreamInfo struct {
capi.StreamInfo

Expand Down Expand Up @@ -470,7 +529,7 @@ func (m *filterManager) localReply(v *api.LocalResponse) {
m.callbacks.SendLocalReply(v.Code, msg, hdr, 0, "")
}

func (m *filterManager) DecodeHeaders(headers api.RequestHeaderMap, endStream bool) capi.StatusType {
func (m *filterManager) DecodeHeaders(headers capi.RequestHeaderMap, endStream bool) capi.StatusType {
if m.canSkipDecodeHeaders {
return capi.Continue
}
Expand All @@ -479,6 +538,9 @@ func (m *filterManager) DecodeHeaders(headers api.RequestHeaderMap, endStream bo
defer m.callbacks.RecoverPanic()
var res api.ResultAction

headers := &filterManagerRequestHeaderMap{
RequestHeaderMap: headers,
}
m.reqHdr = headers
if len(m.consumerFilters) > 0 {
for _, f := range m.consumerFilters {
Expand Down Expand Up @@ -574,7 +636,7 @@ func (m *filterManager) DecodeHeaders(headers api.RequestHeaderMap, endStream bo
return capi.Running
}

func (m *filterManager) DecodeData(buf api.BufferInstance, endStream bool) capi.StatusType {
func (m *filterManager) DecodeData(buf capi.BufferInstance, endStream bool) capi.StatusType {
if m.canSkipDecodeData {
return capi.Continue
}
Expand Down Expand Up @@ -668,7 +730,7 @@ func (m *filterManager) DecodeData(buf api.BufferInstance, endStream bool) capi.
return capi.Running
}

func (m *filterManager) EncodeHeaders(headers api.ResponseHeaderMap, endStream bool) capi.StatusType {
func (m *filterManager) EncodeHeaders(headers capi.ResponseHeaderMap, endStream bool) capi.StatusType {
if m.canSkipEncodeHeaders {
return capi.Continue
}
Expand Down Expand Up @@ -707,7 +769,7 @@ func (m *filterManager) EncodeHeaders(headers api.ResponseHeaderMap, endStream b
return capi.Running
}

func (m *filterManager) EncodeData(buf api.BufferInstance, endStream bool) capi.StatusType {
func (m *filterManager) EncodeData(buf capi.BufferInstance, endStream bool) capi.StatusType {
if m.canSkipEncodeData {
return capi.Continue
}
Expand Down
14 changes: 1 addition & 13 deletions pkg/request/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,14 @@
package request

import (
"fmt"
"net/http"
"net/textproto"
"net/url"
"strings"

"github.com/envoyproxy/envoy/contrib/golang/common/go/api"
"golang.org/x/net/http/httpguts"
)

func GetUrl(headers api.RequestHeaderMap) *url.URL {
path := headers.Path()
// TODO: cache it
uri, err := url.ParseRequestURI(path)
if err != nil {
panic(fmt.Sprintf("unexpected bad request uri given by envoy: %v", err))
}
return uri
}

// The cookie parser is from Go's http/cookie.go, which are not exported

func isNotToken(r rune) bool {
Expand Down Expand Up @@ -66,7 +54,7 @@ func parseCookieValue(raw string, allowDoubleQuote bool) (string, bool) {
}

// If multiple cookies match the given name, only one cookie will be returned.
func GetCookies(headers api.RequestHeaderMap) map[string]*http.Cookie {
func ParseCookies(headers api.RequestHeaderMap) map[string]*http.Cookie {
lines := headers.Values("Cookie")
if len(lines) == 0 {
return map[string]*http.Cookie{}
Expand Down
3 changes: 1 addition & 2 deletions plugins/casbin/filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import (

"mosn.io/htnn/pkg/file"
"mosn.io/htnn/pkg/filtermanager/api"
"mosn.io/htnn/pkg/request"
)

func factory(c interface{}, callbacks api.FilterCallbackHandler) api.Filter {
Expand All @@ -39,7 +38,7 @@ type filter struct {
func (f *filter) DecodeHeaders(headers api.RequestHeaderMap, endStream bool) api.ResultAction {
conf := f.config
role, _ := headers.Get(conf.Token.Name) // role can be ""
url := request.GetUrl(headers)
url := headers.Url()

policyChanged := file.IsChanged(conf.modelFile, conf.policyFile)
if policyChanged && !conf.updating.Load() {
Expand Down
3 changes: 1 addition & 2 deletions plugins/hmac_auth/filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import (
"strings"

"mosn.io/htnn/pkg/filtermanager/api"
"mosn.io/htnn/pkg/request"
)

func factory(c interface{}, callbacks api.FilterCallbackHandler) api.Filter {
Expand Down Expand Up @@ -58,7 +57,7 @@ func (f *filter) getSignContent(header api.RequestHeaderMap, accessKey string) s
dh = f.config.DateHeader
}
date, _ := header.Get(dh)
url := request.GetUrl(header)
url := header.Url()
path := url.Path
if path == "" {
path = "/"
Expand Down
3 changes: 1 addition & 2 deletions plugins/key_auth/filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import (
"net/url"

"mosn.io/htnn/pkg/filtermanager/api"
"mosn.io/htnn/pkg/request"
)

func factory(c interface{}, callbacks api.FilterCallbackHandler) api.Filter {
Expand Down Expand Up @@ -52,7 +51,7 @@ func (f *filter) DecodeHeaders(headers api.RequestHeaderMap, endStream bool) api
var vals []string
if key.Source == Source_QUERY {
if query == nil {
query = request.GetUrl(headers).Query()
query = headers.Url().Query()
}
vals = query[key.Name]
} else {
Expand Down
7 changes: 3 additions & 4 deletions plugins/oidc/filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import (
"golang.org/x/oauth2"

"mosn.io/htnn/pkg/filtermanager/api"
"mosn.io/htnn/pkg/request"
)

func factory(c interface{}, callbacks api.FilterCallbackHandler) api.Filter {
Expand Down Expand Up @@ -152,7 +151,7 @@ func (f *filter) handleCallback(headers api.RequestHeaderMap, query url.Values)
}

if !config.SkipNonceVerify {
nonce, ok := request.GetCookies(headers)["htnn_oidc_nonce"]
nonce, ok := headers.Cookies()["htnn_oidc_nonce"]
if !ok {
api.LogInfof("bad nonce, expected %s", idToken.Nonce)
return &api.LocalResponse{Code: 403, Msg: "bad nonce"}
Expand Down Expand Up @@ -208,12 +207,12 @@ func (f *filter) attachInfo(headers api.RequestHeaderMap, encodedToken string) a
}

func (f *filter) DecodeHeaders(headers api.RequestHeaderMap, endStream bool) api.ResultAction {
token, ok := request.GetCookies(headers)["htnn_oidc_token"]
token, ok := headers.Cookies()["htnn_oidc_token"]
if ok {
return f.attachInfo(headers, token.Value)
}

query := request.GetUrl(headers).Query()
query := headers.Url().Query()
code := query.Get("code")
if code == "" {
return f.handleInitRequest(headers)
Expand Down
2 changes: 1 addition & 1 deletion plugins/opa/filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func mapStrsToMapStr(strs map[string][]string) map[string]string {
}

func (f *filter) buildInput(header api.RequestHeaderMap) map[string]interface{} {
uri := request.GetUrl(header)
uri := header.Url()
headers := request.GetHeaders(header)
req := map[string]interface{}{
"method": header.Method(),
Expand Down
12 changes: 12 additions & 0 deletions plugins/tests/pkg/envoy/capi.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@ import (
"bytes"
"log"
"net/http"
"net/url"
"strconv"
"sync"

capi "github.com/envoyproxy/envoy/contrib/golang/common/go/api"

"mosn.io/htnn/pkg/filtermanager/api"
"mosn.io/htnn/pkg/request"
)

func init() {
Expand Down Expand Up @@ -137,6 +139,16 @@ func (i *RequestHeaderMap) Path() string {
return path
}

func (i *RequestHeaderMap) Url() *url.URL {
path := i.Path()
u, _ := url.ParseRequestURI(path)
return u
}

func (i *RequestHeaderMap) Cookies() map[string]*http.Cookie {
return request.ParseCookies(i)
}

var _ api.RequestHeaderMap = (*RequestHeaderMap)(nil)

type ResponseHeaderMap struct {
Expand Down

0 comments on commit e18d98a

Please sign in to comment.