feat: update the error parsing for go-ipld-format to v0.4.0
This commit was moved from ipfs/go-ipfs-http-client@296534fd1647a1ec9cae08314daf41ec96d55763
Jorropo committed
Mar 31, 2022 at 23:43 UTC
ddd36645b25c97651deb81c092c7669efabd959e
2 files changed
+44
-24
client/httpapi/errors.go
+33
-21
@@ -45,6 +45,18 @@ func parseIPLDNotFoundWithFallbackToError(msg error) error {
45
return msg
46
}
47
48
+// Use a string to move it into RODATA
49
+// print("".join("\\x01" if chr(i) not in string.ascii_letters + string.digits else "\\x00" for i in range(ord('z')+1)))
50
+const notAsciiLetterOrDigitsLUT = "\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x01\x01\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x01\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
51
+
52
+func notAsciiLetterOrDigits(r rune) bool {
53
+ if r > 'z' {
54
+ return true
55
+ }
56
+
57
+ return notAsciiLetterOrDigitsLUT[r] > 0
58
+}
59
+
60
// This file handle parsing and returning the correct ABI based errors from error messages
61
//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
62
func parseIPLDNotFound(msg string) (error, bool) {
@@ -53,46 +65,46 @@ func parseIPLDNotFound(msg string) (error, bool) {
65
}
66
67
// The patern we search for is:
56
- // node not found (fallback)
57
- // or
58
- // CID not found (here we parse the CID)
59
- notFoundIndex := strings.LastIndex(msg, " not found")
68
+ const ipldErrNotFoundKey = "ipld: could not find " /*CID*/
69
+ // We try to parse the CID, if it's invalid we give up and return a simple text error.
70
+ // We also accept "node" in place of the CID because that means it's an Undefined CID.
71
61
- if notFoundIndex == -1 {
62
- // Unknown, ot found not found
72
+ keyIndex := strings.Index(msg, ipldErrNotFoundKey)
73
+
74
+ if keyIndex < 0 { // Unknown error
75
return nil, false
76
}
77
66
- preNotFound := msg[:notFoundIndex]
78
+ cidStart := keyIndex + len(ipldErrNotFoundKey)
79
80
+ msgPostKey := msg[cidStart:]
81
var c cid.Cid
69
- var preIndex int
70
- if strings.HasSuffix(preNotFound, "node") {
82
+ var postIndex int
83
+ if strings.HasPrefix(msgPostKey, "node") {
84
// Fallback case
85
c = cid.Undef
73
- preIndex = notFoundIndex - len("node")
86
+ postIndex = len("node")
87
} else {
75
- // Assume that CIDs does not include whitespace to pull out the CID
76
- preIndex = strings.LastIndexByte(preNotFound, ' ')
77
- // + 1 is to normalise not founds to zeros and point to the start of the CID, not the previous space
78
- preIndex++
88
+ // Assume that CIDs only contain a-zA-Z0-9 characters.
89
+ // This is true because go-ipld-format use go-cid#Cid.String which use base{3{2,6},58}.
90
+ postIndex = strings.IndexFunc(msgPostKey, notAsciiLetterOrDigits)
91
+ if postIndex < 0 {
92
+ postIndex = len(msgPostKey)
93
+ }
94
+
95
var err error
80
- c, err = cid.Decode(preNotFound[preIndex:])
96
+ c, err = cid.Decode(msgPostKey[:postIndex])
97
if err != nil {
98
// Unknown
99
return nil, false
100
}
101
}
102
87
- postIndex := notFoundIndex + len(" not found")
88
-
103
err := ipld.ErrNotFound{Cid: c}
90
-
91
- pre := msg[:preIndex]
92
- post := msg[postIndex:]
104
+ pre := msg[:keyIndex]
105
+ post := msgPostKey[postIndex:]
106
107
if len(pre) > 0 || len(post) > 0 {
95
- // We have some text to wrap arround the ErrNotFound one
108
return prePostWrappedNotFoundError{
109
pre: pre,
110
post: post,
client/httpapi/errors_test.go
+11
-3
@@ -3,6 +3,7 @@ package httpapi
3
import (
4
"errors"
5
"fmt"
6
+ "strings"
7
"testing"
8
9
"github.com/ipfs/go-cid"
@@ -42,9 +43,8 @@ func TestParseIPLDNotFound(t *testing.T) {
43
"%w is wrong",
44
} {
45
for _, err := range [...]error{
45
- errors.New("file not found"),
46
- errors.New(" not found"),
47
- errors.New("Bad_CID not found"),
46
+ errors.New("ipld: could not find "),
47
+ errors.New("ipld: could not find Bad_CID"),
48
errors.New("network connection timeout"),
49
ipld.ErrNotFound{Cid: cid.Undef},
50
ipld.ErrNotFound{Cid: cid.NewCidV0(randomSha256MH)},
@@ -58,3 +58,11 @@ func TestParseIPLDNotFound(t *testing.T) {
58
}
59
}
60
}
61
+
62
+func TestNotAsciiLetterOrDigits(t *testing.T) {
63
+ for i := rune(0); i <= 256; i++ {
64
+ if notAsciiLetterOrDigits(i) != !strings.ContainsAny(string(i), "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") {
65
+ t.Errorf("%q is incorrectly identified", i)
66
+ }
67
+ }
68
+}