Skip to content
This repository has been archived by the owner on Oct 5, 2023. It is now read-only.

Commit

Permalink
fix: make Block().* return correct ABI based ipld.ErrNotFound errors
Browse files Browse the repository at this point in the history
  • Loading branch information
Jorropo committed Mar 27, 2022
1 parent 0675169 commit 647592e
Show file tree
Hide file tree
Showing 5 changed files with 418 additions and 32 deletions.
104 changes: 104 additions & 0 deletions abyfy_errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package httpapi

import (
"errors"
"strings"

"github.com/ipfs/go-cid"
ipld "github.com/ipfs/go-ipld-format"
)

type prePostWrappedNotFoundError struct {
pre string
post string

wrapped ipld.ErrNotFound
}

func (e prePostWrappedNotFoundError) String() string {
return e.Error()
}

func (e prePostWrappedNotFoundError) Error() string {
return e.pre + e.wrapped.Error() + e.post
}

func (e prePostWrappedNotFoundError) Unwrap() error {
return e.wrapped
}

func abyfyIpldNotFoundFallbackToMSG(msg string) error {
err, handled := abyfyIpldNotFound(msg)
if handled {
return err
}

return errors.New(msg)
}

func abyfyIpldNotFoundFallbackToError(msg error) error {
err, handled := abyfyIpldNotFound(msg.Error())
if handled {
return err
}

return err
}

// This file handle parsing and returning the correct ABI based errors from error messages
//lint: ignore ST1008 this function is not using the error as a mean to return failure but it massages it to return the correct type
func abyfyIpldNotFound(msg string) (error, bool) {
if msg == "" {
return nil, true // Fast path
}

// The patern we search for is:
// node not found (fallback)
// or
// CID not found (here we parse the CID)
notFoundIndex := strings.LastIndex(msg, " not found")

if notFoundIndex == -1 {
// Unknown, ot found not found
return nil, false
}

preNotFound := msg[:notFoundIndex]

var c cid.Cid
var preIndex int
if strings.HasSuffix(preNotFound, "node") {
// Fallback case
c = cid.Undef
preIndex = notFoundIndex - len("node")
} else {
// Assume that CIDs does not include whitespace to pull out the CID
preIndex = strings.LastIndexByte(preNotFound, ' ')
// + 1 is to normalise not founds to zeros and point to the start of the CID, not the previous space
preIndex++
var err error
c, err = cid.Decode(preNotFound[preIndex:])
if err != nil {
// Unknown
return nil, false
}
}

postIndex := notFoundIndex + len(" not found")

err := ipld.ErrNotFound{Cid: c}

pre := msg[:preIndex]
post := msg[postIndex:]

if len(pre) > 0 || len(post) > 0 {
// We have some text to wrap arround the ErrNotFound one
return prePostWrappedNotFoundError{
pre: pre,
post: post,
wrapped: err,
}, true
}

return err, true
}
60 changes: 60 additions & 0 deletions abyfy_errors_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package httpapi

import (
"errors"
"fmt"
"testing"

"github.com/ipfs/go-cid"
ipld "github.com/ipfs/go-ipld-format"
mh "github.com/multiformats/go-multihash"
)

var randomSha256MH = mh.Multihash{0x12, 0x20, 0x88, 0x82, 0x73, 0x37, 0x7c, 0xc1, 0xc9, 0x96, 0xad, 0xee, 0xd, 0x26, 0x84, 0x2, 0xc9, 0xc9, 0x5c, 0xf9, 0x5c, 0x4d, 0x9b, 0xc3, 0x3f, 0xfb, 0x4a, 0xd8, 0xaf, 0x28, 0x6b, 0xca, 0x1a, 0xf2}

func doAbyfyIpldNotFoundTest(t *testing.T, original error) {
originalMsg := original.Error()

rebuilt := abyfyIpldNotFoundFallbackToMSG(originalMsg)

rebuiltMsg := rebuilt.Error()

if originalMsg != rebuiltMsg {
t.Errorf("expected message to be %q; got %q", originalMsg, rebuiltMsg)
}

originalNotFound := ipld.IsNotFound(original)
rebuiltNotFound := ipld.IsNotFound(original)
if originalNotFound != rebuiltNotFound {
t.Errorf("expected Ipld.IsNotFound to be %t; got %t", originalNotFound, rebuiltNotFound)
}
}

func TestAbyfyIpldNotFound(t *testing.T) {
if err := abyfyIpldNotFoundFallbackToMSG(""); err != nil {
t.Errorf("expected empty string to give no error; got %T %q", err, err.Error())
}

for _, wrap := range [...]string{
"",
"merkledag: %w",
"testing: %w the test",
"%w is wrong",
} {
for _, err := range [...]error{
errors.New("file not found"),
errors.New(" not found"),
errors.New("Bad_CID not found"),
errors.New("network connection timeout"),
ipld.ErrNotFound{Cid: cid.Undef},
ipld.ErrNotFound{Cid: cid.NewCidV0(randomSha256MH)},
ipld.ErrNotFound{Cid: cid.NewCidV1(cid.Raw, randomSha256MH)},
} {
if wrap != "" {
err = fmt.Errorf(wrap, err)
}

doAbyfyIpldNotFoundTest(t, err)
}
}
}
11 changes: 3 additions & 8 deletions block.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package httpapi
import (
"bytes"
"context"
"errors"
"fmt"
"io"

Expand Down Expand Up @@ -67,7 +66,7 @@ func (api *BlockAPI) Get(ctx context.Context, p path.Path) (io.Reader, error) {
return nil, err
}
if resp.Error != nil {
return nil, resp.Error
return nil, abyfyIpldNotFoundFallbackToError(resp.Error)
}

//TODO: make get return ReadCloser to avoid copying
Expand Down Expand Up @@ -99,18 +98,14 @@ func (api *BlockAPI) Rm(ctx context.Context, p path.Path, opts ...caopts.BlockRm
return err
}

if removedBlock.Error != "" {
return errors.New(removedBlock.Error)
}

return nil
return abyfyIpldNotFoundFallbackToMSG(removedBlock.Error)
}

func (api *BlockAPI) Stat(ctx context.Context, p path.Path) (iface.BlockStat, error) {
var out blockStat
err := api.core().Request("block/stat", p.String()).Exec(ctx, &out)
if err != nil {
return nil, err
return nil, abyfyIpldNotFoundFallbackToError(err)
}
out.cid, err = cid.Parse(out.Key)
if err != nil {
Expand Down
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ require (
github.com/ipfs/go-cid v0.0.7
github.com/ipfs/go-ipfs-cmds v0.6.0
github.com/ipfs/go-ipfs-files v0.0.8
github.com/ipfs/go-ipld-format v0.2.0
github.com/ipfs/go-merkledag v0.4.0
github.com/ipfs/go-ipld-format v0.3.1
github.com/ipfs/go-merkledag v0.6.0
github.com/ipfs/go-path v0.1.1
github.com/ipfs/go-unixfs v0.2.5
github.com/ipfs/interface-go-ipfs-core v0.5.2
github.com/ipfs/interface-go-ipfs-core v0.6.1
github.com/ipfs/iptb v1.4.0
github.com/ipfs/iptb-plugins v0.3.0
github.com/libp2p/go-libp2p-core v0.8.6
Expand Down
Loading

0 comments on commit 647592e

Please sign in to comment.