From f96974f1473ea19719369ee7600d3c5c2fb8cf22 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Thu, 18 Apr 2024 01:35:05 +0200 Subject: [PATCH] gateway: test Accept header overides conflicting ?format --- gateway/gateway_test.go | 6 ++++-- gateway/handler.go | 15 ++++++++++++--- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/gateway/gateway_test.go b/gateway/gateway_test.go index d59f0d66f..d48334b92 100644 --- a/gateway/gateway_test.go +++ b/gateway/gateway_test.go @@ -440,7 +440,7 @@ func TestHeaders(t *testing.T) { DeserializedResponses: true, }) - runTest := func(name, path, accept, host, expectedContentPath string) { + runTest := func(name, path, accept, host, expectedContentLocationHdr string) { t.Run(name, func(t *testing.T) { t.Parallel() @@ -461,7 +461,7 @@ func TestHeaders(t *testing.T) { require.NoError(t, err) require.Equal(t, http.StatusOK, resp.StatusCode, string(body)) - require.Equal(t, expectedContentPath, resp.Header.Get("Content-Location")) + require.Equal(t, expectedContentLocationHdr, resp.Header.Get("Content-Location")) }) } @@ -490,6 +490,8 @@ func TestHeaders(t *testing.T) { runTest("DNSLink gateway with Accept: "+responseFormat, "/empty-dir/", responseFormat, dnslinkGatewayHost, "/empty-dir/?format="+formatParam) runTest("DNSLink gateway with ?format="+formatParam, "/empty-dir/?format="+formatParam, "", dnslinkGatewayHost, "") } + + runTest("Accept: application/vnd.ipld.car overrides ?format=raw in Content-Location", contentPath+"?format=raw", "application/vnd.ipld.car", "", contentPath+"?format=car") }) } diff --git a/gateway/handler.go b/gateway/handler.go index 522af1eb5..4360d2163 100644 --- a/gateway/handler.go +++ b/gateway/handler.go @@ -652,13 +652,22 @@ func customResponseFormat(r *http.Request) (mediaType string, params map[string] // correct caching of such format requests when the format is passed via the // Accept header, for example. func addContentLocation(r *http.Request, w http.ResponseWriter, rq *requestData) { - // Skip Content-Location if no explicit format was requested via the HTTP - // Accept header, or if it was requested via URL query parameter. - if rq.responseFormat == "" || r.URL.Query().Get("format") != "" { + // Skip Content-Location if no explicit format was requested + // via Accept HTTP header or ?format URL param + if rq.responseFormat == "" { return } format := responseFormatToFormatParam[rq.responseFormat] + + // Skip Content-Location if there is no conflict between + // 'format' in URL and value in 'Accept' header. + // If both are present and don't match, we continue and generate + // Content-Location to ensure value from Accept overrides 'format' from URL. + if urlFormat := r.URL.Query().Get("format"); urlFormat != "" && urlFormat == format { + return + } + path := r.URL.Path if p, ok := r.Context().Value(OriginalPathKey).(string); ok { path = p