@cryptotaxi247 / kubo / commits / 3de5b14e0

fix: ?uri= url-decode and preserve query

This makes ?uri= param able to process URIs passed by web browsers https://developer.mozilla.org/en-US/docs/Web/API/Navigator/registerProtocolHandler

Marcin Rataj committed Dec 12, 2020 at 02:43 UTC 3de5b14e0c248ab1f611215836ace4e134a25b61
2 files changed +24 -7
core/corehttp/gateway_handler.go
+16 -5
@@ -181,10 +181,17 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request
181 }
182 originalUrlPath := prefix + requestURI.Path
183
184 - // Query parameter handling to support requests produced by navigator.registerProtocolHandler.
185 - // E.g. This code will redirect calls to /ipfs/?uri=ipfs%3A%2F%2Fcontent-identifier
186 - // to /ipfs/content-identifier.
187 - if uri := r.URL.Query().Get("uri"); uri != "" {
184 + // ?uri query param support for requests produced by web browsers
185 + // via navigator.registerProtocolHandler Web API
186 + // https://developer.mozilla.org/en-US/docs/Web/API/Navigator/registerProtocolHandler
187 + // TLDR: redirect /ipfs/?uri=ipfs%3A%2F%2Fcid%3Fquery%3Dval to /ipfs/cid?query=val
188 + if uriParam := r.URL.Query().Get("uri"); uriParam != "" {
189 + // Browsers will pass URI in URL-escaped form, we need to unescape it first
190 + uri, err := url.QueryUnescape(uriParam)
191 + if err != nil {
192 + webError(w, "failed to unescape uri query parameter", err, http.StatusBadRequest)
193 + return
194 + }
195 u, err := url.Parse(uri)
196 if err != nil {
197 webError(w, "failed to parse uri query parameter", err, http.StatusBadRequest)
@@ -194,7 +201,11 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request
201 webError(w, "uri query parameter scheme must be ipfs or ipns", err, http.StatusBadRequest)
202 return
203 }
197 - http.Redirect(w, r, gopath.Join("/", prefix, u.Scheme, u.Host), http.StatusMovedPermanently)
204 + path := u.Path
205 + if u.RawQuery != "" { // preserve query if present
206 + path = path + "?" + u.RawQuery
207 + }
208 + http.Redirect(w, r, gopath.Join("/", prefix, u.Scheme, u.Host, path), http.StatusMovedPermanently)
209 return
210 }
211
core/corehttp/gateway_test.go
+8 -2
@@ -170,12 +170,18 @@ func TestUriQueryRedirect(t *testing.T) {
170 status int
171 location string
172 }{
173 + // - Browsers will send original URI in URL-escaped form
174 + // - We expect query parameters to be persisted
175 + // - We drop fragments, as those should not be sent by a browser
176 + {"/ipfs/?uri=ipfs%3A%2F%2FQmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco%2Fwiki%2FFoo_%C4%85%C4%99.html%3Ffilename%3Dtest-%C4%99.html%23header-%C4%85", http.StatusMovedPermanently, "/ipfs/QmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco/wiki/Foo_%c4%85%c4%99.html?filename=test-%c4%99.html"},
177 + {"/ipfs/?uri=ipns%3A%2F%2Fexample.com%2Fwiki%2FFoo_%C4%85%C4%99.html%3Ffilename%3Dtest-%C4%99.html", http.StatusMovedPermanently, "/ipns/example.com/wiki/Foo_%c4%85%c4%99.html?filename=test-%c4%99.html"},
178 {"/ipfs/?uri=ipfs://" + cid, http.StatusMovedPermanently, "/ipfs/" + cid},
174 - {"/ipfs/?uri=ipfs%3A%2F%2F" + cid, http.StatusMovedPermanently, "/ipfs/" + cid},
179 {"/ipfs?uri=ipfs://" + cid, http.StatusMovedPermanently, "/ipfs/?uri=ipfs://" + cid},
180 {"/ipfs/?uri=ipns://" + cid, http.StatusMovedPermanently, "/ipns/" + cid},
181 + {"/ipns/?uri=ipfs%3A%2F%2FQmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco%2Fwiki%2FFoo_%C4%85%C4%99.html%3Ffilename%3Dtest-%C4%99.html%23header-%C4%85", http.StatusMovedPermanently, "/ipfs/QmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco/wiki/Foo_%c4%85%c4%99.html?filename=test-%c4%99.html"},
182 + {"/ipns/?uri=ipns%3A%2F%2Fexample.com%2Fwiki%2FFoo_%C4%85%C4%99.html%3Ffilename%3Dtest-%C4%99.html", http.StatusMovedPermanently, "/ipns/example.com/wiki/Foo_%c4%85%c4%99.html?filename=test-%c4%99.html"},
183 {"/ipns?uri=ipns://" + cid, http.StatusMovedPermanently, "/ipns/?uri=ipns://" + cid},
178 - {"/ipns/?uri=ipfs://" + cid, http.StatusMovedPermanently, "/ipfs/" + cid},
184 + {"/ipns/?uri=ipns://" + cid, http.StatusMovedPermanently, "/ipns/" + cid},
185 {"/ipns/?uri=ipfs://" + cid, http.StatusMovedPermanently, "/ipfs/" + cid},
186 {"/ipfs/?uri=unsupported://" + cid, http.StatusBadRequest, ""},
187 {"/ipfs/?uri=" + cid, http.StatusBadRequest, ""},