Skip to content

Commit

Permalink
gateway: implement ipip-0445
Browse files Browse the repository at this point in the history
  • Loading branch information
Jorropo committed Nov 2, 2023
1 parent 9c22812 commit f7bb4b3
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 10 deletions.
32 changes: 26 additions & 6 deletions gateway/blocks_backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,10 @@ func (bb *BlocksBackend) Head(ctx context.Context, path path.ImmutablePath) (Con
var emptyRoot = []cid.Cid{cid.MustParse("bafkqaaa")}

func (bb *BlocksBackend) GetCAR(ctx context.Context, p path.ImmutablePath, params CarParams) (ContentPathMetadata, io.ReadCloser, error) {
if params.SkipRawBlocks.Bool() && p.RootCid().Prefix().Codec == cid.Raw {

Check failure on line 299 in gateway/blocks_backend.go

View workflow job for this annotation

GitHub Actions / go-check / All

empty branch (SA9003)

}

Check warning on line 301 in gateway/blocks_backend.go

View check run for this annotation

Codecov / codecov/patch

gateway/blocks_backend.go#L300-L301

Added lines #L300 - L301 were not covered by tests

pathMetadata, err := bb.ResolvePath(ctx, p)
if err != nil {
rootCid, err := cid.Decode(strings.Split(p.String(), "/")[2])
Expand All @@ -312,8 +316,9 @@ func (bb *BlocksBackend) GetCAR(ctx context.Context, p path.ImmutablePath, param
blockGetter := merkledag.NewDAGService(bb.blockService).Session(ctx)

blockGetter = &nodeGetterToCarExporer{
ng: blockGetter,
cw: cw,
ng: blockGetter,
cw: cw,
skipRawBlocks: params.SkipRawBlocks.Bool(),

Check warning on line 321 in gateway/blocks_backend.go

View check run for this annotation

Codecov / codecov/patch

gateway/blocks_backend.go#L319-L321

Added lines #L319 - L321 were not covered by tests
}

// Setup the UnixFS resolver.
Expand Down Expand Up @@ -352,8 +357,9 @@ func (bb *BlocksBackend) GetCAR(ctx context.Context, p path.ImmutablePath, param
blockGetter := merkledag.NewDAGService(bb.blockService).Session(ctx)

blockGetter = &nodeGetterToCarExporer{
ng: blockGetter,
cw: cw,
ng: blockGetter,
cw: cw,
skipRawBlocks: params.SkipRawBlocks.Bool(),
}

// Setup the UnixFS resolver.
Expand Down Expand Up @@ -732,8 +738,9 @@ func (bb *BlocksBackend) resolvePath(ctx context.Context, p path.Path) (path.Imm
}

type nodeGetterToCarExporer struct {
ng format.NodeGetter
cw storage.WritableCar
ng format.NodeGetter
cw storage.WritableCar
skipRawBlocks bool
}

func (n *nodeGetterToCarExporer) Get(ctx context.Context, c cid.Cid) (format.Node, error) {
Expand Down Expand Up @@ -774,6 +781,19 @@ func (n *nodeGetterToCarExporer) GetMany(ctx context.Context, cids []cid.Cid) <-
}

func (n *nodeGetterToCarExporer) trySendBlock(ctx context.Context, block blocks.Block) error {
// FIXME(@Jorropo): this is very inneficient, we fetch all blocks even if we don't send them.
// I've tried doing so using the ipld stack however the problem is that filtering on the
// selector or traversal callback does not work because the unixfs reifier is ran before,
// so trying to filter raw links do nothing because go-unixfsnode removed them already,
// so we need to filter in a callback from unixfsnode but the reifier does not know a about
// [traversal.SkipMe] making it a lost cause. I've looked into updating unixfsnode but this
// much more work because there are no easy way to pass options or understand what the side
// effects of this would be.
// Abstractions everywhere yet a simple small behaviour change require rethinking everything :'(.
// Will fix with boxo/unixfs.
if n.skipRawBlocks && block.Cid().Prefix().Codec == cid.Raw {
return nil
}

Check warning on line 796 in gateway/blocks_backend.go

View check run for this annotation

Codecov / codecov/patch

gateway/blocks_backend.go#L795-L796

Added lines #L795 - L796 were not covered by tests
return n.cw.Put(ctx, block.Cid().KeyString(), block.RawData())
}

Expand Down
49 changes: 45 additions & 4 deletions gateway/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,11 @@ type PublicGateway struct {
}

type CarParams struct {
Range *DagByteRange
Scope DagScope
Order DagOrder
Duplicates DuplicateBlocksPolicy
Range *DagByteRange
Scope DagScope
Order DagOrder
Duplicates DuplicateBlocksPolicy
SkipRawBlocks SkipRawBlocksPolicy
}

// DagByteRange describes a range request within a UnixFS file. "From" and
Expand Down Expand Up @@ -211,6 +212,46 @@ func (d DuplicateBlocksPolicy) String() string {
return ""
}

// SkipRawBlocksPolicy represents the get parameter 'skip-raw-blocks' (IPIP-445)
type SkipRawBlocksPolicy uint8

const (
SkipRawBlocksImplicit SkipRawBlocksPolicy = iota // implicit default and not skip leaves
SendRawBlocks // explicitely do not skip leaves
SkipRawBlocks // explicitly skip leaves
)

func NewSkipRawBlocksPolicy(v string) (SkipRawBlocksPolicy, error) {
switch v {
case "y":
return SkipRawBlocks, nil
case "n":
return SendRawBlocks, nil
case "":
return SkipRawBlocksImplicit, nil

Check warning on line 231 in gateway/gateway.go

View check run for this annotation

Codecov / codecov/patch

gateway/gateway.go#L224-L231

Added lines #L224 - L231 were not covered by tests
}
return 0, fmt.Errorf("unsupported skip-raw-blocks GET parameter: %q", v)

Check warning on line 233 in gateway/gateway.go

View check run for this annotation

Codecov / codecov/patch

gateway/gateway.go#L233

Added line #L233 was not covered by tests
}

func (d SkipRawBlocksPolicy) Bool() bool {
// duplicates should be returned only when explicitly requested,
// so any other state than SkipRawBlocksIncluded should return false
return d == SkipRawBlocks
}

func (d SkipRawBlocksPolicy) String() string {
switch d {
case SkipRawBlocksImplicit:
return ""
case SkipRawBlocks:
return "y"
case SendRawBlocks:
return "n"
default:
return strconv.FormatUint(uint64(d), 10)

Check warning on line 251 in gateway/gateway.go

View check run for this annotation

Codecov / codecov/patch

gateway/gateway.go#L242-L251

Added lines #L242 - L251 were not covered by tests
}
}

type ContentPathMetadata struct {
PathSegmentRoots []cid.Cid
LastSegment path.ImmutablePath
Expand Down
16 changes: 16 additions & 0 deletions gateway/handler_car.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
const (
carRangeBytesKey = "entity-bytes"
carTerminalElementTypeKey = "dag-scope"
carSkipRawBlocksTypeKey = "skip-raw-blocks"
)

// serveCAR returns a CAR stream for specific DAG+selector
Expand Down Expand Up @@ -118,6 +119,7 @@ func buildCarParams(r *http.Request, contentTypeParams map[string]string) (CarPa
queryParams := r.URL.Query()
rangeStr, hasRange := queryParams.Get(carRangeBytesKey), queryParams.Has(carRangeBytesKey)
scopeStr, hasScope := queryParams.Get(carTerminalElementTypeKey), queryParams.Has(carTerminalElementTypeKey)
skipRawBlocksStr, hasSkipRawBlocks := queryParams.Get(carSkipRawBlocksTypeKey), queryParams.Has(carSkipRawBlocksTypeKey)

params := CarParams{}
if hasRange {
Expand All @@ -141,6 +143,15 @@ func buildCarParams(r *http.Request, contentTypeParams map[string]string) (CarPa
params.Scope = DagScopeAll
}

if hasSkipRawBlocks {
// skip leaves from IPIP-445
skip, err := NewSkipRawBlocksPolicy(skipRawBlocksStr)
if err != nil {
return CarParams{}, err
}
params.SkipRawBlocks = skip

Check warning on line 152 in gateway/handler_car.go

View check run for this annotation

Codecov / codecov/patch

gateway/handler_car.go#L147-L152

Added lines #L147 - L152 were not covered by tests
}

// application/vnd.ipld.car content type parameters from Accept header

// version of CAR format
Expand Down Expand Up @@ -249,6 +260,11 @@ func getCarEtag(imPath path.ImmutablePath, params CarParams, rootCid cid.Cid) st
h.WriteString("\x00dups=y")
}

// 'skip-leaves' from IPIP-445 impact Etag only if 'y'
if skip := params.SkipRawBlocks; skip == SkipRawBlocks {
h.WriteString("\x00skip-leaves=y")
}

Check warning on line 266 in gateway/handler_car.go

View check run for this annotation

Codecov / codecov/patch

gateway/handler_car.go#L265-L266

Added lines #L265 - L266 were not covered by tests

if params.Range != nil {
if params.Range.From != 0 || params.Range.To != nil {
h.WriteString("\x00range=")
Expand Down

0 comments on commit f7bb4b3

Please sign in to comment.