Skip to content

Commit

Permalink
Added host substitution in MTProxy match type #189
Browse files Browse the repository at this point in the history
A host substitution functionality has been added to the match logic for the MTProxy match type. This allows for more flexible routing rules, enabling the replacement of "$host" and "${host}" placeholders in the destination URL with the server name, before performing the regex match. Updated corresponding tests to reflect this change.
  • Loading branch information
umputun committed May 22, 2024
1 parent 899e101 commit dd563d6
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 17 deletions.
14 changes: 12 additions & 2 deletions app/discovery/discovery.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,15 @@ func (s *Service) Run(ctx context.Context) error {
// For MTStatic always a single match because fail-over doesn't supported for assets
func (s *Service) Match(srv, src string) (res Matches) {

replaceHost := func(dest, srv string) string {
// $host or ${host} in dest replaced by srv
dest = strings.ReplaceAll(dest, "$host", srv)
if strings.Contains(dest, "${host}") {
dest = strings.ReplaceAll(dest, "${host}", srv)
}
return dest
}

s.lock.RLock()
defer s.lock.RUnlock()

Expand All @@ -179,8 +188,9 @@ func (s *Service) Match(srv, src string) (res Matches) {

switch m.MatchType {
case MTProxy:
dest := m.SrcMatch.ReplaceAllString(src, m.Dst)
if src != dest { // regex matched
dest := replaceHost(m.Dst, srv) // replace $host and ${host} in dest first, before regex match
dest = m.SrcMatch.ReplaceAllString(src, dest)
if src != dest { // regex matched because dest changed after replacement
lastSrcMatch = m.SrcMatch.String()
res.MatchType = MTProxy
res.Routes = append(res.Routes, MatchedRoute{Destination: dest, Alive: m.IsAlive(), Mapper: m})
Expand Down
48 changes: 33 additions & 15 deletions app/discovery/discovery_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,6 @@ func TestService_Match(t *testing.T) {
}

for i, tt := range tbl {
tt := tt
t.Run(strconv.Itoa(i)+"-"+tt.server, func(t *testing.T) {
res := svc.Match(tt.server, tt.src)
require.Equal(t, len(tt.res.Routes), len(res.Routes), res.Routes)
Expand Down Expand Up @@ -192,8 +191,8 @@ func TestService_MatchServerRegex(t *testing.T) {
Dst: "http://127.0.0.10:8080/", MatchType: MTProxy, dead: false},

// regex servers
{Server: "test-prefix\\.(.*)", SrcMatch: *regexp.MustCompile("^/"),
Dst: "http://127.0.0.1:8080/", MatchType: MTProxy, dead: false},
{Server: "test-prefix\\.(.*)", SrcMatch: *regexp.MustCompile("^/(.*)"),
Dst: "http://127.0.0.1:8080/$host/blah/$1", MatchType: MTProxy, dead: false},
{Server: "(.*)\\.test-domain\\.(com|org)", SrcMatch: *regexp.MustCompile("^/"),
Dst: "http://127.0.0.2:8080/", MatchType: MTProxy, dead: false},

Expand All @@ -212,21 +211,43 @@ func TestService_MatchServerRegex(t *testing.T) {
assert.Equal(t, context.DeadlineExceeded, err)

tbl := []struct {
name string
server, src string
res Matches
}{
// strict match should take priority
{"test-prefix.exact.com", "/", Matches{MTProxy, []MatchedRoute{{Destination: "http://127.0.0.4:8080/", Alive: true}}}},

// regex servers
{"test-prefix.example.com", "/", Matches{MTProxy, []MatchedRoute{{Destination: "http://127.0.0.1:8080/", Alive: true}}}},
{"another-prefix.example.com", "/", Matches{MTProxy, nil}},
{"another-prefix.test-domain.org", "/", Matches{MTProxy, []MatchedRoute{{Destination: "http://127.0.0.2:8080/", Alive: true}}}},
{"another-prefix.test-domain.net", "/", Matches{MTProxy, nil}},
{
name: "strict match",
server: "test-prefix.exact.com",
src: "/",
res: Matches{MTProxy, []MatchedRoute{{Destination: "http://127.0.0.4:8080/", Alive: true}}},
},
{
name: "regex server with host match",
server: "test-prefix.example.com",
src: "/some",
res: Matches{MTProxy, []MatchedRoute{{Destination: "http://127.0.0.1:8080/test-prefix.example.com/blah/some", Alive: true}}},
},
{
name: "regex server without a match",
server: "another-prefix.example.com",
src: "/",
res: Matches{MTProxy, nil},
},
{
name: "regex server with test-domain.org match",
server: "another-prefix.test-domain.org",
src: "/",
res: Matches{MTProxy, []MatchedRoute{{Destination: "http://127.0.0.2:8080/", Alive: true}}},
},
{
name: "regex server with test-domain.net mismatch",
server: "another-prefix.test-domain.net",
src: "/",
res: Matches{MTProxy, nil},
},
}

for i, tt := range tbl {
tt := tt
t.Run(strconv.Itoa(i)+"-"+tt.server, func(t *testing.T) {
res := svc.Match(tt.server, tt.src)
require.Equal(t, len(tt.res.Routes), len(res.Routes), res.Routes)
Expand Down Expand Up @@ -374,7 +395,6 @@ func TestService_Servers(t *testing.T) {
}

func TestService_extendRule(t *testing.T) {

tbl := []struct {
inp URLMapper
out URLMapper
Expand Down Expand Up @@ -411,11 +431,9 @@ func TestService_extendRule(t *testing.T) {
assert.Equal(t, tt.out, res)
})
}

}

func TestService_redirects(t *testing.T) {

tbl := []struct {
inp URLMapper
out URLMapper
Expand Down

0 comments on commit dd563d6

Please sign in to comment.