Skip to content

Commit

Permalink
fix(gateway): only convert between dag-* variants
Browse files Browse the repository at this point in the history
  • Loading branch information
hacdias committed Jan 19, 2023
1 parent 73ebad1 commit b0c6175
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 72 deletions.
53 changes: 14 additions & 39 deletions core/corehttp/gateway_handler_codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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) {
Expand Down
37 changes: 4 additions & 33 deletions test/sharness/t0123-gateway-json-cbor.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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" '
Expand Down

0 comments on commit b0c6175

Please sign in to comment.