Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose route for context #1128

Merged
merged 3 commits into from
Nov 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions docs/07.Reference/7.02.Filters.md
Original file line number Diff line number Diff line change
Expand Up @@ -1392,7 +1392,7 @@ Commmon Use-Cases:

1. Replace Prefix:

Substitute a prefix with `/account` and return a `302 Found` status code.
Substitute a prefix with `/account` and return a `302 Found` status code. The prefix was decided in `pathPrefix` in te matchting rule in HTTPServer.

```yaml
name: demo-pipeline
Expand All @@ -1402,7 +1402,6 @@ flow:
filters:
- name: redirectorv2
kind: RedirectorV2
pathPrefix: /user
path:
type: ReplacePrefixMatch
replacePrefixMatch: /account
Expand Down Expand Up @@ -1441,7 +1440,6 @@ filters:
kind: RedirectorV2
scheme: https
hostname: newdomain.com
pathPrefix: /user
path:
type: ReplacePrefixMatch
replacePrefixMatch: /account
Expand Down
15 changes: 15 additions & 0 deletions pkg/context/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ type Context struct {

activeNs string

route protocols.Route
requests map[string]*requestRef
responses map[string]*responseRef

Expand All @@ -92,6 +93,20 @@ func New(span *tracing.Span) *Context {
return ctx
}

// SetRoute sets the route.
func (ctx *Context) SetRoute(route protocols.Route) {
ctx.route = route
}

// GetRoute returns the route with the existing flag.
func (ctx *Context) GetRoute() (protocols.Route, bool) {
if ctx.route == nil {
return nil, false
}

return ctx.route, true
}

// Span returns the span of this Context.
func (ctx *Context) Span() *tracing.Span {
return ctx.span
Expand Down
25 changes: 19 additions & 6 deletions pkg/filters/redirectorv2/redirectorv2.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (

"github.com/megaease/easegress/v2/pkg/context"
"github.com/megaease/easegress/v2/pkg/filters"
httprouters "github.com/megaease/easegress/v2/pkg/object/httpserver/routers"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me. Just a little advice. How about add a type alias in github.com/megaease/easegress/v2/pkg/protocols/httpprot say:

var Route = github.com/megaease/easegress/v2/pkg/object/httpserver/routers.Route

then

prefix := route.(httpprot.Route).GetPathPrefix()

The code produce exactly same result. But for future developers, it may a little bit easier for them to find right interface?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That will cause an import cycle.

"github.com/megaease/easegress/v2/pkg/protocols/httpprot"

gwapis "sigs.k8s.io/gateway-api/apis/v1beta1"
Expand Down Expand Up @@ -76,7 +77,6 @@ type (
Spec struct {
filters.BaseSpec `json:",inline"`

PathPrefix *string `json:"pathPrefix,omitempty"`
suchen-sci marked this conversation as resolved.
Show resolved Hide resolved
gwapis.HTTPRequestRedirectFilter `json:",inline"`
}
)
Expand Down Expand Up @@ -108,10 +108,6 @@ func (s *Spec) Validate() error {
return errors.New("invalid path of Redirector, replaceFullPath can't be empty")
}
case gwapis.PrefixMatchHTTPPathModifier:
if s.PathPrefix == nil || *s.PathPrefix == "" {
return errors.New("invalid path of Redirector, pathPrefix can't be empty")
}

if s.Path.ReplacePrefixMatch == nil {
return errors.New("invalid path of Redirector, replacePrefixMatch can't be empty")
}
Expand Down Expand Up @@ -178,8 +174,25 @@ func (r *Redirector) Handle(ctx *context.Context) string {
case gwapis.FullPathHTTPPathModifier:
redirectURL.Path = string(*r.spec.Path.ReplaceFullPath)
case gwapis.PrefixMatchHTTPPathModifier:
route, existed := ctx.GetRoute()
if !existed {
ctx.AddTag("route not found")
break
}

if route.Protocol() != "http" {
ctx.AddTag("route is not an http route")
break
}

prefix := route.(httprouters.Route).GetPathPrefix()
if prefix == "" {
ctx.AddTag("route has no path prefix")
break
}

redirectURL.Path = r.subPrefix(redirectURL.Path,
*r.spec.PathPrefix, string(*r.spec.Path.ReplacePrefixMatch))
prefix, string(*r.spec.Path.ReplacePrefixMatch))
}
}

Expand Down
15 changes: 12 additions & 3 deletions pkg/filters/redirectorv2/redirectorv2_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,20 @@ import (
"testing"

"github.com/megaease/easegress/v2/pkg/context"
"github.com/megaease/easegress/v2/pkg/object/httpserver/routers"
"github.com/megaease/easegress/v2/pkg/protocols/httpprot"
"github.com/stretchr/testify/assert"

gwapis "sigs.k8s.io/gateway-api/apis/v1beta1"
)

type fakeMuxPath struct {
routers.Path
}

func (mp *fakeMuxPath) Protocol() string { return "http" }
func (mp *fakeMuxPath) Rewrite(context *routers.RouteContext) {}

func TestSpecValidate(t *testing.T) {
tests := []struct {
name string
Expand Down Expand Up @@ -123,7 +131,7 @@ func TestSpecValidate(t *testing.T) {
},
},
expectErr: true,
errMsg: "invalid path of Redirector, pathPrefix can't be empty",
errMsg: "invalid path of Redirector, replacePrefixMatch can't be empty",
},
}

Expand Down Expand Up @@ -169,7 +177,6 @@ func TestRedirectorHandle2(t *testing.T) {
name: "Redirect prefix",
reqURL: "http://localhost/user/data/profile",
spec: &Spec{
PathPrefix: new(string),
HTTPRequestRedirectFilter: gwapis.HTTPRequestRedirectFilter{
Path: &gwapis.HTTPPathModifier{
Type: gwapis.PrefixMatchHTTPPathModifier,
Expand Down Expand Up @@ -232,13 +239,15 @@ func TestRedirectorHandle2(t *testing.T) {
req, _ := httpprot.NewRequest(stdReq)
ctx := context.New(nil)
ctx.SetInputRequest(req)
ctx.SetRoute(&fakeMuxPath{
Path: routers.Path{PathPrefix: "/user/"},
})

if tt.spec.Path != nil && tt.spec.Path.ReplaceFullPath != nil {
*tt.spec.Path.ReplaceFullPath = "/newpath"
}

if tt.spec.Path != nil && tt.spec.Path.ReplacePrefixMatch != nil {
*tt.spec.PathPrefix = "/user/"
*tt.spec.Path.ReplacePrefixMatch = "/account/"
}

Expand Down
5 changes: 4 additions & 1 deletion pkg/object/httpserver/mux.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,8 @@ func (mi *muxInstance) putRouteToCache(req *httpprot.Request, rc *cachedRoute) {
}

func newMux(httpStat *httpstat.HTTPStat, topN *httpstat.TopN,
metrics *metrics, mapper context.MuxMapper) *mux {
metrics *metrics, mapper context.MuxMapper,
) *mux {
m := &mux{
httpStat: httpStat,
topN: topN,
Expand Down Expand Up @@ -267,6 +268,8 @@ func (mi *muxInstance) serveHTTP(stdw http.ResponseWriter, stdr *http.Request) {

routeCtx := routers.NewContext(req)
route := mi.search(routeCtx)
ctx.SetRoute(route.route)

var respHeader http.Header

defer func() {
Expand Down
4 changes: 4 additions & 0 deletions pkg/object/httpserver/routers/ordered/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ func newMuxPath(p *routers.Path) *muxPath {
}
}

func (mp *muxPath) Protocol() string {
return "http"
}

func (mp *muxPath) matchPath(path string) bool {
if mp.Path.Path == "" && mp.PathPrefix == "" && mp.pathRE == nil {
return true
Expand Down
4 changes: 4 additions & 0 deletions pkg/object/httpserver/routers/radixtree/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,10 @@ func (mp *muxPath) initRewrite() {
mp.rewriteTemplate = template.Must(template.New("").Parse(repl))
}

func (mp *muxPath) Protocol() string {
return "http"
}

func (mp *muxPath) Rewrite(context *routers.RouteContext) {
req := context.Request

Expand Down
13 changes: 13 additions & 0 deletions pkg/object/httpserver/routers/routers.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"net/http"
"net/url"

"github.com/megaease/easegress/v2/pkg/protocols"
"github.com/megaease/easegress/v2/pkg/protocols/httpprot"
)

Expand All @@ -49,12 +50,24 @@ type (

// Route is the corresponding route interface for different routing policies.
Route interface {
protocols.Route

// Rewrite for path rewriting.
Rewrite(context *RouteContext)
// GetBackend is used to get the backend corresponding to the route.
GetBackend() string
// GetClientMaxBodySize is used to get the clientMaxBodySize corresponding to the route.
GetClientMaxBodySize() int64

// NOTE: Currently we only support path information in readonly.
// Without further requirements, we choose not to expose too much information.

// GetExactPath is used to get the exact path corresponding to the route.
GetExactPath() string
// GetPathPrefix is used to get the path prefix corresponding to the route.
GetPathPrefix() string
// GetPathRegexp is used to get the path regexp corresponding to the route.
GetPathRegexp() string
}

// Params are used to store the variables in the search path and their corresponding values.
Expand Down
15 changes: 15 additions & 0 deletions pkg/object/httpserver/routers/spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,21 @@ func (p *Path) GetClientMaxBodySize() int64 {
return p.ClientMaxBodySize
}

// GetExactPath returns the exact path of the route.
func (p *Path) GetExactPath() string {
return p.Path
}

// GetPathPrefix returns the path prefix of the route.
func (p *Path) GetPathPrefix() string {
return p.PathPrefix
}

// GetPathRegexp returns the path regexp of the route.
func (p *Path) GetPathRegexp() string {
return p.PathRegexp
}

func (hs Headers) init() {
for _, h := range hs {
if h.Regexp != "" {
Expand Down
7 changes: 7 additions & 0 deletions pkg/protocols/protocols.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,3 +150,10 @@ type Protocol interface {
NewResponseInfo() interface{}
BuildResponse(respInfo interface{}) (Response, error)
}

// Route is the interface of a route.
// Filters could assert the real type according to the protocol.
type Route interface {
// Protocol returns the canonical name of the protocol in lower case, such as http, grpc.
Protocol() string
}
Loading