From b0c6175be83b185f8995dbf79a1981db89b0a85e Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Thu, 19 Jan 2023 11:10:02 +0100 Subject: [PATCH] fix(gateway): only convert between dag-* variants --- core/corehttp/gateway_handler_codec.go | 53 +++++++----------------- test/sharness/t0123-gateway-json-cbor.sh | 37 ++--------------- 2 files changed, 18 insertions(+), 72 deletions(-) diff --git a/core/corehttp/gateway_handler_codec.go b/core/corehttp/gateway_handler_codec.go index 95a151c79437..67f55ac6e101 100644 --- a/core/corehttp/gateway_handler_codec.go +++ b/core/corehttp/gateway_handler_codec.go @@ -32,15 +32,11 @@ var codecToContentType = map[uint64]string{ uint64(mc.DagCbor): "application/vnd.ipld.dag-cbor", } -// contentTypeToCodecs maps the HTTP Content Type to the respective -// possible codecs. If the original data is in one of those codecs, -// we stream the raw bytes. Otherwise, we encode in the last codec -// of the list. -var contentTypeToCodecs = map[string][]uint64{ - "application/json": {uint64(mc.Json), uint64(mc.DagJson)}, - "application/vnd.ipld.dag-json": {uint64(mc.DagJson)}, - "application/cbor": {uint64(mc.Cbor), uint64(mc.DagCbor)}, - "application/vnd.ipld.dag-cbor": {uint64(mc.DagCbor)}, +// convertibleContentTypeToCodec maps the HTTP Content Type to the respective +// possible codec to convert. +var convertibleContentTypeToCodec = map[string]uint64{ + "application/vnd.ipld.dag-json": uint64(mc.DagJson), + "application/vnd.ipld.dag-cbor": uint64(mc.DagCbor), } // contentTypeToExtension maps the HTTP Content Type to the respective file @@ -103,38 +99,17 @@ func (i *gatewayHandler) serveCodec(ctx context.Context, w http.ResponseWriter, return } - // Otherwise, the user has requested a specific content type. Let's first get - // the codecs that can be used with this content type. - codecs, ok := contentTypeToCodecs[requestedContentType] - if !ok { - // This is never supposed to happen unless function is called with wrong parameters. - err := fmt.Errorf("unsupported content type: %s", requestedContentType) - webError(w, err.Error(), err, http.StatusInternalServerError) - return - } - - // If we need to convert, use the last codec (strict dag- variant) - toCodec := codecs[len(codecs)-1] - - // If the requested content type has "dag-", ALWAYS go through the encoding - // process in order to validate the content. - if strings.Contains(requestedContentType, "dag-") { + // If the user has requested a specific content type that we can convert to + // (dag-*), we check the codecs and go through the encoding process in order + // to validate the content. Otherwise, we directly stream the raw data. + // serveRawBlock cannot be directly used here as it sets different headers. + // Note that we cannot convert between json and cbor. Only between dag-json + // and dag-cbor. + if toCodec, ok := convertibleContentTypeToCodec[requestedContentType]; ok { i.serveCodecConverted(ctx, w, r, resolvedPath, contentPath, toCodec, modtime) - return - } - - // Otherwise, check if the data is encoded with the requested content type. - // If so, we can directly stream the raw data. serveRawBlock cannot be directly - // used here as it sets different headers. - for _, codec := range codecs { - if resolvedPath.Cid().Prefix().Codec == codec { - i.serveCodecRaw(ctx, w, r, resolvedPath, contentPath, name, modtime) - return - } + } else { + i.serveCodecRaw(ctx, w, r, resolvedPath, contentPath, name, modtime) } - - // Finally, if nothing of the above is true, we have to actually convert the codec. - i.serveCodecConverted(ctx, w, r, resolvedPath, contentPath, toCodec, modtime) } func (i *gatewayHandler) serveCodecHTML(ctx context.Context, w http.ResponseWriter, r *http.Request, resolvedPath ipath.Resolved, contentPath ipath.Path) { diff --git a/test/sharness/t0123-gateway-json-cbor.sh b/test/sharness/t0123-gateway-json-cbor.sh index f4ebca19d2c0..3bb97888a6f9 100755 --- a/test/sharness/t0123-gateway-json-cbor.sh +++ b/test/sharness/t0123-gateway-json-cbor.sh @@ -81,12 +81,6 @@ test_dag_pb () { ipfs dag get --output-codec dag-$format $DIR_CID > ipfs_dag_get_output 2>&1 && test_cmp ipfs_dag_get_output curl_output ' - - test_expect_success "GET UnixFS as $name with format=dag-$format and format=$format produce same output" ' - curl -s "http://127.0.0.1:$GWAY_PORT/ipfs/$DIR_CID?format=dag-$format" > curl_output_1 2>&1 && - curl -s "http://127.0.0.1:$GWAY_PORT/ipfs/$DIR_CID?format=$format" > curl_output_2 2>&1 && - test_cmp curl_output_1 curl_output_2 - ' } test_dag_pb "DAG-JSON" "json" @@ -146,23 +140,6 @@ test_cmp_dag_get "JSON" "json" "inline" test_cmp_dag_get "CBOR" "cbor" "attachment" -## Lossless conversion between JSON and CBOR - -test_expect_success "GET JSON as CBOR produces DAG-CBOR output" ' - CID=$(echo "{ \"test\": \"json\" }" | ipfs dag put --input-codec json --store-codec json) && - curl -s "http://127.0.0.1:$GWAY_PORT/ipfs/$CID?format=cbor" > curl_output 2>&1 && - ipfs dag get --output-codec dag-cbor $CID > ipfs_dag_get_output 2>&1 && - test_cmp ipfs_dag_get_output curl_output -' - -test_expect_success "GET CBOR as JSON produces DAG-JSON output" ' - CID=$(echo "{ \"test\": \"json\" }" | ipfs dag put --input-codec json --store-codec cbor) && - curl -s "http://127.0.0.1:$GWAY_PORT/ipfs/$CID?format=json" > curl_output 2>&1 && - ipfs dag get --output-codec dag-json $CID > ipfs_dag_get_output 2>&1 && - test_cmp ipfs_dag_get_output curl_output -' - - ## Pathing, traversal DAG_CBOR_TRAVERSAL_CID="bafyreibs4utpgbn7uqegmd2goqz4bkyflre2ek2iwv743fhvylwi4zeeim" @@ -204,12 +181,6 @@ test_expect_success "GET DAG-CBOR traverses multiple links" ' test_cmp expected actual ' -# test_expect_success "GET DAG-PB has expected output" ' -# curl -s "http://127.0.0.1:$GWAY_PORT/ipfs/$DAG_PB_CID?format=dag-json" > curl_output 2>&1 && -# jq --sort-keys . curl_output > actual && -# test_cmp ../t0123-gateway-json-cbor/dag-pb.json actual -# ' - ## NATIVE TESTS: ## DAG- regression tests for core behaviors when native DAG-(CBOR|JSON) is requested @@ -302,11 +273,11 @@ test_native_dag () { test_should_contain "Content-Type: application/vnd.ipld.dag-$format" output && test_should_contain "Content-Length: " output ' - test_expect_success "HEAD $name with an explicit JSON format returns HTTP 200" ' - curl -I "http://127.0.0.1:$GWAY_PORT/ipfs/$CID?format=json" -o output && + test_expect_success "HEAD $name with an explicit DAG-JSON format returns HTTP 200" ' + curl -I "http://127.0.0.1:$GWAY_PORT/ipfs/$CID?format=dag-json" -o output && test_should_contain "HTTP/1.1 200 OK" output && - test_should_contain "Etag: \"$CID.json\"" output && - test_should_contain "Content-Type: application/json" output && + test_should_contain "Etag: \"$CID.dag-json\"" output && + test_should_contain "Content-Type: application/vnd.ipld.dag-json" output && test_should_contain "Content-Length: " output ' test_expect_success "HEAD dag-pb with ?format=$format returns HTTP 200" '