@@ -75,10 +75,10 @@ func (i *handler) serveCodec(ctx context.Context, w http.ResponseWriter, r *http
75
75
return false
76
76
}
77
77
78
- return i .renderCodec (ctx , w , r , rq , blockSize , data )
78
+ return i .renderCodec (ctx , w , r , rq , blockSize , data , false )
79
79
}
80
80
81
- func (i * handler ) renderCodec (ctx context.Context , w http.ResponseWriter , r * http.Request , rq * requestData , blockSize int64 , blockData io.ReadSeekCloser ) bool {
81
+ func (i * handler ) renderCodec (ctx context.Context , w http.ResponseWriter , r * http.Request , rq * requestData , blockSize int64 , blockData io.ReadSeekCloser , isRangeRequest bool ) bool {
82
82
resolvedPath := rq .pathMetadata .LastSegment
83
83
ctx , span := spanTrace (ctx , "Handler.RenderCodec" , trace .WithAttributes (attribute .String ("path" , resolvedPath .String ()), attribute .String ("requestedContentType" , rq .responseFormat )))
84
84
defer span .End ()
@@ -124,7 +124,7 @@ func (i *handler) renderCodec(ctx context.Context, w http.ResponseWriter, r *htt
124
124
download := r .URL .Query ().Get ("download" ) == "true"
125
125
126
126
if isDAG && acceptsHTML && ! download {
127
- return i .serveCodecHTML (ctx , w , r , blockCid , blockData , resolvedPath , rq .contentPath )
127
+ return i .serveCodecHTML (ctx , w , r , blockCid , blockData , resolvedPath , rq .contentPath , isRangeRequest )
128
128
} else {
129
129
// This covers CIDs with codec 'json' and 'cbor' as those do not have
130
130
// an explicit requested content type.
@@ -156,7 +156,7 @@ func (i *handler) renderCodec(ctx context.Context, w http.ResponseWriter, r *htt
156
156
return i .serveCodecConverted (ctx , w , r , blockCid , blockData , rq .contentPath , toCodec , modtime , rq .begin )
157
157
}
158
158
159
- func (i * handler ) serveCodecHTML (ctx context.Context , w http.ResponseWriter , r * http.Request , blockCid cid.Cid , blockData io.Reader , resolvedPath path.ImmutablePath , contentPath path.Path ) bool {
159
+ func (i * handler ) serveCodecHTML (ctx context.Context , w http.ResponseWriter , r * http.Request , blockCid cid.Cid , blockData io.Reader , resolvedPath path.ImmutablePath , contentPath path.Path , isRangeRequest bool ) bool {
160
160
// WithHostname may have constructed an IPFS (or IPNS) path using the Host header.
161
161
// In this case, we need the original path for constructing the redirect.
162
162
requestURI , err := url .ParseRequestURI (r .RequestURI )
@@ -201,7 +201,7 @@ func (i *handler) serveCodecHTML(ctx context.Context, w http.ResponseWriter, r *
201
201
CID : resolvedPath .RootCid ().String (),
202
202
CodecName : cidCodec .String (),
203
203
CodecHex : fmt .Sprintf ("0x%x" , uint64 (cidCodec )),
204
- Node : parseNode (blockCid , blockData ),
204
+ Node : i . parseNode (ctx , blockCid , blockData , isRangeRequest ),
205
205
})
206
206
if err != nil {
207
207
_ , _ = w .Write ([]byte (fmt .Sprintf ("error during body generation: %v" , err )))
@@ -213,7 +213,7 @@ func (i *handler) serveCodecHTML(ctx context.Context, w http.ResponseWriter, r *
213
213
// parseNode does a best effort attempt to parse this request's block such that
214
214
// a preview can be displayed in the gateway. If something fails along the way,
215
215
// returns nil, therefore not displaying the preview.
216
- func parseNode (blockCid cid.Cid , blockData io.Reader ) * assets.ParsedNode {
216
+ func ( i * handler ) parseNode (ctx context. Context , blockCid cid.Cid , blockData io.Reader , tryGetBlockIfFailed bool ) * assets.ParsedNode {
217
217
codec := blockCid .Prefix ().Codec
218
218
decoder , err := multicodec .LookupDecoder (codec )
219
219
if err != nil {
@@ -222,6 +222,18 @@ func parseNode(blockCid cid.Cid, blockData io.Reader) *assets.ParsedNode {
222
222
223
223
nodeBuilder := basicnode .Prototype .Any .NewBuilder ()
224
224
err = decoder (nodeBuilder , blockData )
225
+ if err != nil && tryGetBlockIfFailed {
226
+ // It is possible we don't have the whole data for this block, e.g.,
227
+ // if range request is made from a browser where we want to display HTML.
228
+ // This does one attempt of fetching the data.
229
+ _ , blockData , err = i .backend .GetBlock (ctx , path .FromCid (blockCid ))
230
+ if err != nil {
231
+ return nil
232
+ }
233
+
234
+ nodeBuilder = basicnode .Prototype .Any .NewBuilder ()
235
+ err = decoder (nodeBuilder , blockData )
236
+ }
225
237
if err != nil {
226
238
return nil
227
239
}
0 commit comments