libgit2: fix gitlab redirection for HTTP
Gitlab only supports HTTP redirection for GET operations, and fails POST operations targeting a repository without the .git suffix. Fixes: https://github.com/fluxcd/image-automation-controller/issues/379 Signed-off-by: Paulo Gomes <paulo.gomes@weave.works>
This commit is contained in:
parent
2a52056594
commit
b764bdbeaa
|
@ -52,6 +52,7 @@ import (
|
|||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
pool "github.com/fluxcd/source-controller/internal/transport"
|
||||
|
@ -59,6 +60,13 @@ import (
|
|||
git2go "github.com/libgit2/git2go/v33"
|
||||
)
|
||||
|
||||
var actionSuffixes = []string{
|
||||
"/info/refs?service=git-upload-pack",
|
||||
"/git-upload-pack",
|
||||
"/info/refs?service=git-receive-pack",
|
||||
"/git-receive-pack",
|
||||
}
|
||||
|
||||
// registerManagedHTTP registers a Go-native implementation of an
|
||||
// HTTP(S) transport that doesn't rely on any lower-level libraries
|
||||
// such as OpenSSL.
|
||||
|
@ -152,12 +160,40 @@ func (t *httpSmartSubtransport) Action(transportOptionsURL string, action git2go
|
|||
|
||||
return http.ErrUseLastResponse
|
||||
}
|
||||
|
||||
// Some Git servers (i.e. Gitlab) only support redirection on the GET operations.
|
||||
// Therefore, on the initial GET operation we update the target URL to include the
|
||||
// new target, so the subsequent actions include the correct target URL.
|
||||
// Example of this is trying to access a Git repository without the .git suffix.
|
||||
if req.Response != nil && req.Response.StatusCode == http.StatusMovedPermanently {
|
||||
if newURL, err := req.Response.Location(); err == nil && newURL != nil {
|
||||
if strings.EqualFold(newURL.Host, req.URL.Host) && strings.EqualFold(newURL.Port(), req.URL.Port()) {
|
||||
opts, _ := getTransportOptions(transportOptionsURL)
|
||||
if opts == nil {
|
||||
opts = &TransportOptions{}
|
||||
}
|
||||
|
||||
opts.TargetURL = trimActionSuffix(newURL.String())
|
||||
AddTransportOptions(transportOptionsURL, *opts)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return stream, nil
|
||||
}
|
||||
|
||||
func trimActionSuffix(url string) string {
|
||||
newUrl := url
|
||||
for _, s := range actionSuffixes {
|
||||
newUrl = strings.TrimSuffix(newUrl, s)
|
||||
}
|
||||
|
||||
return newUrl
|
||||
}
|
||||
|
||||
func createClientRequest(targetURL string, action git2go.SmartServiceAction,
|
||||
t *http.Transport, authOpts *git.AuthOptions) (*http.Client, *http.Request, error) {
|
||||
var req *http.Request
|
||||
|
|
|
@ -200,17 +200,70 @@ func TestHTTPManagedTransport_E2E(t *testing.T) {
|
|||
repo.Free()
|
||||
}
|
||||
|
||||
func TestHTTPManagedTransport_HandleRedirect(t *testing.T) {
|
||||
func TestTrimActionSuffix(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
inURL string
|
||||
wantURL string
|
||||
}{
|
||||
{
|
||||
name: "ignore other suffixes",
|
||||
inURL: "https://gitlab/repo/podinfo.git/somethingelse",
|
||||
wantURL: "https://gitlab/repo/podinfo.git/somethingelse",
|
||||
},
|
||||
{
|
||||
name: "trim /info/refs?service=git-upload-pack",
|
||||
inURL: "https://gitlab/repo/podinfo.git/info/refs?service=git-upload-pack",
|
||||
wantURL: "https://gitlab/repo/podinfo.git",
|
||||
},
|
||||
{
|
||||
name: "trim /git-upload-pack",
|
||||
inURL: "https://gitlab/repo/podinfo.git/git-upload-pack",
|
||||
wantURL: "https://gitlab/repo/podinfo.git",
|
||||
},
|
||||
{
|
||||
name: "trim /info/refs?service=git-receive-pack",
|
||||
inURL: "https://gitlab/repo/podinfo.git/info/refs?service=git-receive-pack",
|
||||
wantURL: "https://gitlab/repo/podinfo.git",
|
||||
},
|
||||
{
|
||||
name: "trim /git-receive-pack",
|
||||
inURL: "https://gitlab/repo/podinfo.git/git-receive-pack",
|
||||
wantURL: "https://gitlab/repo/podinfo.git",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
|
||||
tmpDir := t.TempDir()
|
||||
gotURL := trimActionSuffix(tt.inURL)
|
||||
g.Expect(gotURL).To(Equal(tt.wantURL))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestHTTPManagedTransport_HandleRedirect(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
repoURL string
|
||||
}{
|
||||
{name: "http to https", repoURL: "http://github.com/stefanprodan/podinfo"},
|
||||
{name: "handle gitlab redirect", repoURL: "https://gitlab.com/stefanprodan/podinfo"},
|
||||
}
|
||||
|
||||
// Force managed transport to be enabled
|
||||
InitManagedTransport(logr.Discard())
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
id := "http://obj-id"
|
||||
AddTransportOptions(id, TransportOptions{
|
||||
TargetURL: "http://github.com/stefanprodan/podinfo",
|
||||
TargetURL: tt.repoURL,
|
||||
})
|
||||
|
||||
// GitHub will cause a 301 and redirect to https
|
||||
|
@ -222,4 +275,6 @@ func TestHTTPManagedTransport_HandleRedirect(t *testing.T) {
|
|||
|
||||
g.Expect(err).ToNot(HaveOccurred())
|
||||
repo.Free()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue