From 8b62f100b6de24a4feed75ee7310b9de1cabeafe Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Wed, 11 Jan 2023 03:40:58 +0100 Subject: [PATCH] fix(gateway): JSON when Accept is a list Block/CAR responses always had single explicit type, and we did not bother with implementing/testing lists. With the introduction of JSON people may start passing a list. This is the most basic fix which will return on the first matching type (in order). This does not implements weights (can be added in future, if needed). Closes #9520 --- core/corehttp/gateway_handler.go | 26 ++++++++++++++---------- test/sharness/t0123-gateway-json-cbor.sh | 5 +++++ 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/core/corehttp/gateway_handler.go b/core/corehttp/gateway_handler.go index 1222b17bcd7..64c388df427 100644 --- a/core/corehttp/gateway_handler.go +++ b/core/corehttp/gateway_handler.go @@ -890,18 +890,22 @@ func customResponseFormat(r *http.Request) (mediaType string, params map[string] } // Browsers and other user agents will send Accept header with generic types like: // Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8 - // We only care about explicit, vendor-specific content-types. - for _, accept := range r.Header.Values("Accept") { - // respond to the very first ipld content type - if strings.HasPrefix(accept, "application/vnd.ipld") || - strings.HasPrefix(accept, "application/x-tar") || - strings.HasPrefix(accept, "application/json") || - strings.HasPrefix(accept, "application/cbor") { - mediatype, params, err := mime.ParseMediaType(accept) - if err != nil { - return "", nil, err + // We only care about explicit, vendor-specific content-types and respond to the first match (in order). + // TODO: make this RFC compliant and respect weights (eg. return CAR for Accept:application/vnd.ipld.dag-json;q=0.1,application/vnd.ipld.car;q=0.2) + for _, header := range r.Header.Values("Accept") { + for _, value := range strings.Split(header, ",") { + accept := strings.TrimSpace(value) + // respond to the very first matching content type + if strings.HasPrefix(accept, "application/vnd.ipld") || + strings.HasPrefix(accept, "application/x-tar") || + strings.HasPrefix(accept, "application/json") || + strings.HasPrefix(accept, "application/cbor") { + mediatype, params, err := mime.ParseMediaType(accept) + if err != nil { + return "", nil, err + } + return mediatype, params, nil } - return mediatype, params, nil } } return "", nil, nil diff --git a/test/sharness/t0123-gateway-json-cbor.sh b/test/sharness/t0123-gateway-json-cbor.sh index 812d90f24b9..f4ebca19d2c 100755 --- a/test/sharness/t0123-gateway-json-cbor.sh +++ b/test/sharness/t0123-gateway-json-cbor.sh @@ -56,6 +56,11 @@ test_dag_pb_headers () { test_should_contain "Content-Type: application/$format" curl_output && test_should_not_contain "Content-Type: application/vnd.ipld.dag-$format" curl_output ' + + test_expect_success "GET UnixFS as $name with 'Accept: foo, application/$format,bar' has expected Content-Type" ' + curl -sD - -H "Accept: foo, application/$format,text/plain" "http://127.0.0.1:$GWAY_PORT/ipfs/$FILE_CID" > curl_output 2>&1 && + test_should_contain "Content-Type: application/$format" curl_output + ' } test_dag_pb_headers "DAG-JSON" "json" "inline"