@@ -52,7 +52,7 @@ type Repo struct {
52
52
Auth func () docker.Authorizer
53
53
}
54
54
55
- func rewriteURL (u * url.URL , fromRepo , toRepo , host , tag string ) {
55
+ func rewriteDockerAPIURL (u * url.URL , fromRepo , toRepo , host , tag string ) {
56
56
var (
57
57
from = "/v2/" + strings .Trim (fromRepo , "/" ) + "/"
58
58
to = "/v2/" + strings .Trim (toRepo , "/" ) + "/"
@@ -79,6 +79,27 @@ func rewriteURL(u *url.URL, fromRepo, toRepo, host, tag string) {
79
79
u .Host = host
80
80
}
81
81
82
+ // rewriteNonDockerAPIURL is used when a url has to be rewritten but the url
83
+ // contains a non docker api path
84
+ func rewriteNonDockerAPIURL (u * url.URL , fromPrefix , toPrefix , host , tag string ) {
85
+ var (
86
+ from = "/" + strings .Trim (fromPrefix , "/" ) + "/"
87
+ to = "/" + strings .Trim (toPrefix , "/" ) + "/"
88
+ )
89
+ if fromPrefix == "" {
90
+ from = "/"
91
+ }
92
+ if toPrefix == "" {
93
+ to = "/"
94
+ }
95
+ u .Path = to + strings .TrimPrefix (u .Path , from )
96
+
97
+ // we reset the escaped encoding hint, because EscapedPath will produce a valid encoding.
98
+ u .RawPath = ""
99
+
100
+ u .Host = host
101
+ }
102
+
82
103
// ServeHTTP serves the proxy
83
104
func (proxy * Proxy ) ServeHTTP (w http.ResponseWriter , r * http.Request ) {
84
105
ctx := r .Context ()
@@ -88,9 +109,20 @@ func (proxy *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
88
109
alias string
89
110
)
90
111
for k , v := range proxy .Aliases {
112
+ // Docker api request
91
113
if strings .HasPrefix (r .URL .Path , "/v2/" + k + "/" ) {
92
114
repo = & v
93
115
alias = k
116
+ rewriteDockerAPIURL (r .URL , alias , repo .Repo , repo .Host , repo .Tag )
117
+ break
118
+ }
119
+ // Non-Docker api request
120
+ if strings .HasPrefix (r .URL .Path , "/" + k + "/" ) {
121
+ // We will use the same repo/alias and its credentials but we will set target
122
+ // repo as empty
123
+ repo = & v
124
+ alias = k
125
+ rewriteNonDockerAPIURL (r .URL , alias , "" , repo .Host , repo .Tag )
94
126
break
95
127
}
96
128
}
@@ -99,7 +131,6 @@ func (proxy *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
99
131
return
100
132
}
101
133
102
- rewriteURL (r .URL , alias , repo .Repo , repo .Host , repo .Tag )
103
134
r .Host = r .URL .Host
104
135
105
136
auth := repo .Auth ()
@@ -186,13 +217,23 @@ func (proxy *Proxy) reverse(alias string) *httputil.ReverseProxy {
186
217
rp .ModifyResponse = func (r * http.Response ) error {
187
218
// Some registries return a Location header which we must rewrite to still push
188
219
// through this proxy.
220
+ // We support only relative URLs and not absolute URLs.
189
221
if loc := r .Header .Get ("Location" ); loc != "" {
190
222
lurl , err := url .Parse (loc )
191
223
if err != nil {
192
224
return err
193
225
}
194
226
195
- rewriteURL (lurl , repo .Repo , alias , proxy .Host .Host , "" )
227
+ if strings .HasPrefix (loc , "/v2/" ) {
228
+ rewriteDockerAPIURL (lurl , repo .Repo , alias , proxy .Host .Host , "" )
229
+ } else {
230
+ // since this is a non docker api location we
231
+ // do not need to process the path.
232
+ // All docker api URLs always start with /v2/. See spec
233
+ // https://github.com/opencontainers/distribution-spec/blob/main/spec.md#endpoints
234
+ rewriteNonDockerAPIURL (lurl , "" , alias , repo .Host , repo .Tag )
235
+ }
236
+
196
237
lurl .Host = proxy .Host .Host
197
238
// force scheme to http assuming this proxy never runs as https
198
239
lurl .Scheme = proxy .Host .Scheme
0 commit comments