diff --git a/core/corehttp/gateway_handler.go b/core/corehttp/gateway_handler.go index 525ae2c1f98..41a096c87a3 100644 --- a/core/corehttp/gateway_handler.go +++ b/core/corehttp/gateway_handler.go @@ -423,7 +423,7 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request return case "application/vnd.ipld.raw": logger.Debugw("serving raw block", "path", contentPath) - i.serveRawBlock(r.Context(), w, r, resolvedPath, contentPath, begin, responseFormat) + i.serveRawBlock(r.Context(), w, r, resolvedPath, contentPath, begin) return case "application/vnd.ipld.car": logger.Debugw("serving car stream", "path", contentPath) diff --git a/core/corehttp/gateway_handler_block.go b/core/corehttp/gateway_handler_block.go index e3dff1c0ae2..3bf7c76be2d 100644 --- a/core/corehttp/gateway_handler_block.go +++ b/core/corehttp/gateway_handler_block.go @@ -14,7 +14,7 @@ import ( ) // serveRawBlock returns bytes behind a raw block -func (i *gatewayHandler) serveRawBlock(ctx context.Context, w http.ResponseWriter, r *http.Request, resolvedPath ipath.Resolved, contentPath ipath.Path, begin time.Time, contentType string) { +func (i *gatewayHandler) serveRawBlock(ctx context.Context, w http.ResponseWriter, r *http.Request, resolvedPath ipath.Resolved, contentPath ipath.Path, begin time.Time) { ctx, span := tracing.Span(ctx, "Gateway", "ServeRawBlock", trace.WithAttributes(attribute.String("path", resolvedPath.String()))) defer span.End() blockCid := resolvedPath.Cid() @@ -41,7 +41,7 @@ func (i *gatewayHandler) serveRawBlock(ctx context.Context, w http.ResponseWrite // Set remaining headers modtime := addCacheControlHeaders(w, r, contentPath, blockCid) - w.Header().Set("Content-Type", contentType) + w.Header().Set("Content-Type", "application/vnd.ipld.raw") w.Header().Set("X-Content-Type-Options", "nosniff") // no funny business in the browsers :^) // ServeContent will take care of diff --git a/core/corehttp/gateway_handler_codec.go b/core/corehttp/gateway_handler_codec.go index 615c28e9279..7e01ab7923e 100644 --- a/core/corehttp/gateway_handler_codec.go +++ b/core/corehttp/gateway_handler_codec.go @@ -1,9 +1,11 @@ package corehttp import ( + "bytes" "context" "fmt" "html" + "io" "net/http" "time" @@ -42,28 +44,43 @@ func (i *gatewayHandler) serveCodec(ctx context.Context, w http.ResponseWriter, return } - // If the data is already encoded with the possible codecs, we can defer execution to - // serveRawBlock, which will simply stream the raw data of this block. + // Set Cache-Control and read optional Last-Modified time + modtime := addCacheControlHeaders(w, r, contentPath, resolvedPath.Cid()) + name := addContentDispositionHeader(w, r, contentPath) + w.Header().Set("Content-Type", contentType) + w.Header().Set("X-Content-Type-Options", "nosniff") + + // If the data is already encoded with the possible codecs, we can just 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.serveRawBlock(ctx, w, r, resolvedPath, contentPath, begin, contentType) + + blockCid := resolvedPath.Cid() + blockReader, err := i.api.Block().Get(ctx, resolvedPath) + if err != nil { + webError(w, "ipfs block get "+blockCid.String(), err, http.StatusInternalServerError) + return + } + block, err := io.ReadAll(blockReader) + if err != nil { + webError(w, "ipfs block get "+blockCid.String(), err, http.StatusInternalServerError) + return + } + content := bytes.NewReader(block) + + // ServeContent will take care of + // If-None-Match+Etag, Content-Length and range requests + _, _, _ = ServeContent(w, r, name, modtime, content) return } } - // Set Cache-Control and read optional Last-Modified time - modtime := addCacheControlHeaders(w, r, contentPath, resolvedPath.Cid()) - // Sets correct Last-Modified header. This code is borrowed from the standard // library (net/http/server.go) as we cannot use serveFile. if !(modtime.IsZero() || modtime.Equal(unixEpochTime)) { w.Header().Set("Last-Modified", modtime.UTC().Format(http.TimeFormat)) } - addContentDispositionHeader(w, r, contentPath) - w.Header().Set("Content-Type", contentType) - w.Header().Set("X-Content-Type-Options", "nosniff") - obj, err := i.api.Dag().Get(ctx, resolvedPath.Cid()) if err != nil { webError(w, "ipfs dag get "+html.EscapeString(resolvedPath.String()), err, http.StatusInternalServerError)