From fd01acdfc0cede60706d59cfdeaa9784c8f7c8f3 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Wed, 16 Sep 2020 22:10:36 +0200 Subject: [PATCH] feat(gateway): ?filename with download=true This implements 'attachment' mode triggered then ?filename parameter is accompanied with &download=true When Content-Disposition: attachment is detected by a modern browser it will skip rendering and immediately open the "save as" dialog, making this useful feature for using IPFS gateway as target of "Download" links on various websites. Parameter name was suggested in: https://github.com/ipfs/go-ipfs/pull/4177#issuecomment-414870327 --- core/corehttp/gateway_handler.go | 6 +++++- docs/gateway.md | 10 ++++++++++ test/sharness/t0110-gateway.sh | 7 ++++++- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/core/corehttp/gateway_handler.go b/core/corehttp/gateway_handler.go index b9e7f144b9d..0c708f87be4 100644 --- a/core/corehttp/gateway_handler.go +++ b/core/corehttp/gateway_handler.go @@ -261,7 +261,11 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request urlFilename := r.URL.Query().Get("filename") var name string if urlFilename != "" { - w.Header().Set("Content-Disposition", fmt.Sprintf("inline; filename*=UTF-8''%s", url.PathEscape(urlFilename))) + disposition := "inline" + if r.URL.Query().Get("download") == "true" { + disposition = "attachment" + } + w.Header().Set("Content-Disposition", fmt.Sprintf("%s; filename*=UTF-8''%s", disposition, url.PathEscape(urlFilename))) name = urlFilename } else { name = getFilename(urlPath) diff --git a/docs/gateway.md b/docs/gateway.md index 2344ee55ea8..dab41e09171 100644 --- a/docs/gateway.md +++ b/docs/gateway.md @@ -49,6 +49,16 @@ your query string to explicitly specify the filename. For example: > https://ipfs.io/ipfs/QmfM2r8seH2GiRaC4esTjeraXEachRt8ZsSeGaWTPLyMoG?filename=hello_world.txt +When you try to save above page, you browser will use passed `filename` instead of a CID. + +## Downloads + +It is possible to skip browser rendering of supported filetypes (plain text, +images, audio, video, PDF) and trigger immediate "save as" dialog by appending +`&download=true`: + +> https://ipfs.io/ipfs/QmfM2r8seH2GiRaC4esTjeraXEachRt8ZsSeGaWTPLyMoG?filename=hello_world.txt&download=true + ## MIME-Types TODO diff --git a/test/sharness/t0110-gateway.sh b/test/sharness/t0110-gateway.sh index 2a1f58c71a4..3880880c274 100755 --- a/test/sharness/t0110-gateway.sh +++ b/test/sharness/t0110-gateway.sh @@ -31,11 +31,16 @@ test_expect_success "GET IPFS path succeeds" ' curl -sfo actual "http://127.0.0.1:$port/ipfs/$HASH" ' -test_expect_success "GET IPFS path with explicit filename succeeds with proper header" " +test_expect_success "GET IPFS path with explicit ?filename succeeds with proper header" " curl -fo actual -D actual_headers 'http://127.0.0.1:$port/ipfs/$HASH?filename=testтест' && grep -F \"Content-Disposition: inline; filename*=UTF-8''test%D1%82%D0%B5%D1%81%D1%82\" actual_headers " +test_expect_success "GET IPFS path with explicit ?filename and download=true succeeds with proper header" " + curl -fo actual -D actual_headers 'http://127.0.0.1:$port/ipfs/$HASH?filename=testтест&download=true' && + grep -F \"Content-Disposition: attachment; filename*=UTF-8''test%D1%82%D0%B5%D1%81%D1%82\" actual_headers +" + # https://github.com/ipfs/go-ipfs/issues/4025#issuecomment-342250616 test_expect_success "GET for Service Worker registration outside of an IPFS content root errors" " curl -H 'Service-Worker: script' -svX GET 'http://127.0.0.1:$port/ipfs/$HASH?filename=sw.js' > curl_sw_out 2>&1 &&