diff --git a/core/corehttp/gateway_handler.go b/core/corehttp/gateway_handler.go index a96799f5875a..3649609e1f16 100644 --- a/core/corehttp/gateway_handler.go +++ b/core/corehttp/gateway_handler.go @@ -26,6 +26,7 @@ import ( coreiface "github.com/ipfs/interface-go-ipfs-core" ipath "github.com/ipfs/interface-go-ipfs-core/path" routing "github.com/libp2p/go-libp2p/core/routing" + mc "github.com/multiformats/go-multicodec" prometheus "github.com/prometheus/client_golang/prometheus" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" @@ -430,6 +431,14 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request carVersion := formatParams["version"] i.serveCAR(r.Context(), w, r, resolvedPath, contentPath, carVersion, begin) return + case "application/vnd.ipld.dag-json": + logger.Debugw("serving dag-json", "path", contentPath) + i.serveJSON(r.Context(), w, r, resolvedPath, begin, "application/vnd.ipld.dag-json", uint64(mc.DagJson)) + return + case "application/vnd.ipld.dag-cbor": + logger.Debugw("serving dag-cbor", "path", contentPath) + i.serveJSON(r.Context(), w, r, resolvedPath, begin, "application/vnd.ipld.dag-cbor", uint64(mc.DagCbor)) + return default: // catch-all for unsuported application/vnd.* err := fmt.Errorf("unsupported format %q", responseFormat) webError(w, "failed respond with requested content type", err, http.StatusBadRequest) @@ -859,6 +868,10 @@ func customResponseFormat(r *http.Request) (mediaType string, params map[string] return "application/vnd.ipld.raw", nil, nil case "car": return "application/vnd.ipld.car", nil, nil + case "dag-json": + return "application/vnd.ipld.dag-json", nil, nil + case "dag-cbor": + return "application/vnd.ipld.dag-cbor", nil, nil } } // Browsers and other user agents will send Accept header with generic types like: diff --git a/core/corehttp/gateway_handler_json.go b/core/corehttp/gateway_handler_json.go new file mode 100644 index 000000000000..dc0959393c83 --- /dev/null +++ b/core/corehttp/gateway_handler_json.go @@ -0,0 +1,44 @@ +package corehttp + +import ( + "context" + "fmt" + "html" + "net/http" + "time" + + ipldlegacy "github.com/ipfs/go-ipld-legacy" + ipath "github.com/ipfs/interface-go-ipfs-core/path" + "github.com/ipld/go-ipld-prime" + "github.com/ipld/go-ipld-prime/multicodec" +) + +// serveCAR returns a CAR stream for specific DAG+selector +func (i *gatewayHandler) serveJSON(ctx context.Context, w http.ResponseWriter, r *http.Request, resolvedPath ipath.Resolved, begin time.Time, ctype string, codec uint64) { + // ctx, span := tracing.Span(ctx, "Gateway", "ServeCAR", trace.WithAttributes(attribute.String("path", resolvedPath.String()))) + // defer span.End() + // ctx, cancel := context.WithCancel(ctx) + // defer cancel() + + obj, err := i.api.Dag().Get(r.Context(), resolvedPath.Cid()) + if err != nil { + webError(w, "ipfs dag get "+html.EscapeString(resolvedPath.String()), err, http.StatusInternalServerError) + return + } + + universal, ok := obj.(ipldlegacy.UniversalNode) + if !ok { + webError(w, "todo", fmt.Errorf("%T is not a valid IPLD node", obj), http.StatusInternalServerError) + return + } + finalNode := universal.(ipld.Node) + + encoder, err := multicodec.LookupEncoder(codec) + if err != nil { + webError(w, "todo", err, http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", ctype) + _ = encoder(finalNode, w) +}