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

feat: improve redirect to allow url rewrite #969

Merged
merged 2 commits into from
Dec 31, 2021
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
12 changes: 11 additions & 1 deletion client/daemon/proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"net"
"net/http"
"net/http/httputil"
"net/url"
"strings"
"sync"
"time"
Expand Down Expand Up @@ -546,7 +547,16 @@ func (proxy *Proxy) shouldUseDragonfly(req *http.Request) bool {
if rule.UseHTTPS {
req.URL.Scheme = schemaHTTPS
}
if rule.Redirect != "" {
if strings.Contains(rule.Redirect, "/") {
u, err := url.Parse(rule.Regx.ReplaceAllString(req.URL.String(), rule.Redirect))
if err != nil {
logger.Errorf("failed to rewrite url", err)
return false
}
req.URL = u
req.Host = req.URL.Host
req.RequestURI = req.URL.RequestURI()
} else if rule.Redirect != "" {
req.URL.Host = rule.Redirect
req.Host = rule.Redirect
}
Expand Down
54 changes: 49 additions & 5 deletions client/daemon/proxy/proxy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ func (tc *testCase) Test(t *testing.T) {
a.Equal(req.URL.Scheme, "http")
}
if item.Redirect != "" {
a.Equal(item.Redirect, req.Host)
a.Equal(item.Redirect, req.URL.String())
}
}
}
Expand All @@ -122,6 +122,14 @@ func (tc *testCase) TestMirror(t *testing.T) {
if !a.Equal(tp.shouldUseDragonflyForMirror(req), !item.Direct) {
fmt.Println(item.URL)
}
if item.UseHTTPS {
a.Equal(req.URL.Scheme, "https")
} else {
a.Equal(req.URL.Scheme, "http")
}
if item.Redirect != "" {
a.Equal(item.Redirect, req.URL.String())
}
}
}

Expand All @@ -147,7 +155,7 @@ func TestMatch(t *testing.T) {

newTestCase().
WithRule("/a/f", false, false, "r").
WithTest("http://h/a/f", false, false, "r"). // should match /a/f and redirect
WithTest("http://h/a/f", false, false, "http://r/a/f"). // should match /a/f and redirect
Test(t)

newTestCase().
Expand All @@ -174,20 +182,56 @@ func TestMatchWithUseProxies(t *testing.T) {
// should direct as registry is set with direct=false and no proxies are defined
newTestCase().
WithRegistryMirror("http://index.docker.io", false, false, true).
WithTest("http://index.docker.io/v2/blobs/sha256/xxx", true, false, "").
WithTest("http://index.docker.io/v2/blobs/sha256/1", true, false, "").
TestMirror(t)

// should cache as registry is set with direct=false, and one proxy matches
newTestCase().
WithRegistryMirror("http://index.docker.io", false, false, true).
WithRule("/blobs/sha256/", false, false, "").
WithTest("http://index.docker.io/v2/blobs/sha256/xxx", false, false, "").
WithTest("http://index.docker.io/v2/blobs/sha256/2", false, false, "").
TestMirror(t)

// should direct as registry is set with direct=true, even if one proxy matches
newTestCase().
WithRegistryMirror("http://index.docker.io", true, false, true).
WithRule("/blobs/sha256/", false, false, "").
WithTest("http://index.docker.io/v2/blobs/sha256/xxx", true, false, "").
WithTest("http://index.docker.io/v2/blobs/sha256/3", true, false, "").
TestMirror(t)
}

func TestMatchWithRedirect(t *testing.T) {
// redirect as hostname, in direct mode
newTestCase().
WithRegistryMirror("http://index.docker.io", false, false, true).
WithRule("index.docker.io", false, false, "r").
WithTest("http://index.docker.io/1", false, false, "http://r/1").
TestMirror(t)

// redirect as hostname, in proxy mode
newTestCase().
WithRule("index.docker.io", false, false, "r").
WithTest("http://index.docker.io/2", false, false, "http://r/2").
Test(t)

// redirect as url, in direct mode
newTestCase().
WithRegistryMirror("http://index.docker.io", false, false, true).
WithRule("^http://index.docker.io/(.*)", false, false, "http://r/t/$1").
WithTest("http://index.docker.io/1", false, false, "http://r/t/1").
TestMirror(t)

// redirect as url, in proxy mode
newTestCase().
WithRule("^http://index.docker.io/(.*)", false, false, "http://r/t/$1").
WithTest("http://index.docker.io/2", false, false, "http://r/t/2").
Test(t)

// redirect as url, in direct mode, with HTTPS rewrite
newTestCase().
WithRegistryMirror("http://index.docker.io", false, false, true).
WithRule("^http://index.docker.io/(.*)", false, false, "https://r/t/$1").
WithTest("http://index.docker.io/1", false, true, "https://r/t/1").
TestMirror(t)

}
3 changes: 3 additions & 0 deletions docs/en/deployment/configuration/dfget.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,9 @@ proxy:
# proxy requests with redirect
- regx: some-registry
redirect: another-registry
# the same with url rewrite like apache ProxyPass directive
- regx: ^http://some-registry/(.*)
redirect: http://another-registry/$1

hijackHTTPS:
# key pair used to hijack https requests
Expand Down
3 changes: 3 additions & 0 deletions docs/zh-CN/deployment/configuration/dfget.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,9 @@ proxy:
# 转发流量到指定地址
- regx: some-registry
redirect: another-registry
# the same with url rewrite like apache ProxyPass directive
- regx: ^http://some-registry/(.*)
redirect: http://another-registry/$1

hijackHTTPS:
# https 劫持的证书和密钥
Expand Down