@cryptotaxi247 / kubo / commits / 36368ee4d

feat: support requests from registerProtocolHandler

This commit adds support for requests produced by navigator.registerProtocolHandler on gateways. Now one can register `dweb.link` as an URI handler for `ipfs://`: ``` navigator.registerProtocolHandler('ipfs', 'https://dweb.link/ipfs/?uri=%s', 'ipfs resolver') ``` Then opening `ipfs://QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR` will produce an HTTP GET call to: ``` https://dweb.link/ipfs?uri=ipfs%3A%2F%2FQmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR ``` The query parameter `uri` will now be parsed and the given content identifier resolved via: `https://dweb.link/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR`

Dennis Trautwein committed Dec 5, 2020 at 17:02 UTC 36368ee4ddfb8943d96f2e34b3283d11a1498ff6
2 files changed +58
core/corehttp/gateway_handler.go
+17
@@ -181,6 +181,23 @@ 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 != "" {
188 + u, err := url.Parse(uri)
189 + if err != nil {
190 + webError(w, "failed to parse uri query parameter", err, http.StatusBadRequest)
191 + return
192 + }
193 + if u.Scheme != "ipfs" && u.Scheme != "ipns" {
194 + webError(w, "uri query parameter scheme must be ipfs or ipns", err, http.StatusBadRequest)
195 + return
196 + }
197 + http.Redirect(w, r, gopath.Join("/", prefix, u.Scheme, u.Host), http.StatusMovedPermanently)
198 + return
199 + }
200 +
201 // Service Worker registration request
202 if r.Header.Get("Service-Worker") == "script" {
203 // Disallow Service Worker registration on namespace roots
core/corehttp/gateway_test.go
+41
@@ -161,6 +161,47 @@ func matchPathOrBreadcrumbs(s string, expected string) bool {
161 return matched
162 }
163
164 +func TestUriQueryRedirect(t *testing.T) {
165 + ts, _, _ := newTestServerAndNode(t, mockNamesys{})
166 +
167 + cid := "QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR"
168 + for i, test := range []struct {
169 + path string
170 + status int
171 + location string
172 + }{
173 + {"/ipfs/?uri=ipfs://" + cid, http.StatusMovedPermanently, "/ipfs/" + cid},
174 + {"/ipfs/?uri=ipfs%3A%2F%2F" + cid, http.StatusMovedPermanently, "/ipfs/" + cid},
175 + {"/ipfs?uri=ipfs://" + cid, http.StatusMovedPermanently, "/ipfs/?uri=ipfs://" + cid},
176 + {"/ipfs/?uri=ipns://" + cid, http.StatusMovedPermanently, "/ipns/" + cid},
177 + {"/ipns?uri=ipns://" + cid, http.StatusMovedPermanently, "/ipns/?uri=ipns://" + cid},
178 + {"/ipns/?uri=ipfs://" + cid, http.StatusMovedPermanently, "/ipfs/" + cid},
179 + {"/ipns/?uri=ipfs://" + cid, http.StatusMovedPermanently, "/ipfs/" + cid},
180 + {"/ipfs/?uri=unsupported://" + cid, http.StatusBadRequest, ""},
181 + {"/ipfs/?uri=" + cid, http.StatusBadRequest, ""},
182 + } {
183 +
184 + r, err := http.NewRequest(http.MethodGet, ts.URL+test.path, nil)
185 + if err != nil {
186 + t.Fatal(err)
187 + }
188 + resp, err := doWithoutRedirect(r)
189 + if err != nil {
190 + t.Fatal(err)
191 + }
192 + defer resp.Body.Close()
193 +
194 + if resp.StatusCode != test.status {
195 + t.Errorf("(%d) got %d, expected %d from %s", i, resp.StatusCode, test.status, ts.URL+test.path)
196 + }
197 +
198 + locHdr := resp.Header.Get("Location")
199 + if locHdr != test.location {
200 + t.Errorf("(%d) location header got %s, expected %s from %s", i, locHdr, test.location, ts.URL+test.path)
201 + }
202 + }
203 +}
204 +
205 func TestGatewayGet(t *testing.T) {
206 ns := mockNamesys{}
207 ts, api, ctx := newTestServerAndNode(t, ns)