Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

path: replace ImmutablePath interface with struct #481

Merged
merged 1 commit into from
Oct 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion coreiface/tests/unixfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,7 @@ func (tp *TestSuite) TestAdd(t *testing.T) {
t.Errorf("Event.Name didn't match, %s != %s", expected[0].Name, event.Name)
}

if expected[0].Path != nil && event.Path != nil {
if (expected[0].Path != path.ImmutablePath{} && event.Path != path.ImmutablePath{}) {
if expected[0].Path.RootCid().String() != event.Path.RootCid().String() {
t.Errorf("Event.Hash didn't match, %s != %s", expected[0].Path, event.Path)
}
Expand Down
22 changes: 11 additions & 11 deletions gateway/blocks_backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -595,16 +595,16 @@ func (bb *BlocksBackend) getPathRoots(ctx context.Context, contentPath path.Immu
sp.WriteString(root)
p, err := path.NewPath(sp.String())
if err != nil {
return nil, nil, nil, err
return nil, path.ImmutablePath{}, nil, err
}
resolvedSubPath, remainderSubPath, err := bb.resolvePath(ctx, p)
if err != nil {
// TODO: should we be more explicit here and is this part of the IPFSBackend contract?
// The issue here was that we returned datamodel.ErrWrongKind instead of this resolver error
if isErrNotFound(err) {
return nil, nil, nil, &resolver.ErrNoLink{Name: root, Node: lastPath.RootCid()}
return nil, path.ImmutablePath{}, nil, &resolver.ErrNoLink{Name: root, Node: lastPath.RootCid()}
}
return nil, nil, nil, err
return nil, path.ImmutablePath{}, nil, err
}
lastPath = resolvedSubPath
remainder = remainderSubPath
Expand All @@ -620,13 +620,13 @@ func (bb *BlocksBackend) ResolveMutable(ctx context.Context, p path.Path) (path.
case path.IPNSNamespace:
p, err := resolve.ResolveIPNS(ctx, bb.namesys, p)
if err != nil {
return nil, err
return path.ImmutablePath{}, err
}
return path.NewImmutablePath(p)
case path.IPFSNamespace:
return path.NewImmutablePath(p)
default:
return nil, NewErrorStatusCode(fmt.Errorf("unsupported path namespace: %s", p.Namespace()), http.StatusNotImplemented)
return path.ImmutablePath{}, NewErrorStatusCode(fmt.Errorf("unsupported path namespace: %s", p.Namespace()), http.StatusNotImplemented)
}
}

Expand Down Expand Up @@ -690,32 +690,32 @@ func (bb *BlocksBackend) resolvePath(ctx context.Context, p path.Path) (path.Imm
if p.Namespace() == path.IPNSNamespace {
p, err = resolve.ResolveIPNS(ctx, bb.namesys, p)
if err != nil {
return nil, nil, err
return path.ImmutablePath{}, nil, err
}
}

if p.Namespace() != path.IPFSNamespace {
return nil, nil, fmt.Errorf("unsupported path namespace: %s", p.Namespace())
return path.ImmutablePath{}, nil, fmt.Errorf("unsupported path namespace: %s", p.Namespace())
}

imPath, err := path.NewImmutablePath(p)
if err != nil {
return nil, nil, err
return path.ImmutablePath{}, nil, err
}

node, remainder, err := bb.resolver.ResolveToLastNode(ctx, imPath)
if err != nil {
return nil, nil, err
return path.ImmutablePath{}, nil, err
}

p, err = path.Join(path.FromCid(node), remainder...)
if err != nil {
return nil, nil, err
return path.ImmutablePath{}, nil, err
}

imPath, err = path.NewImmutablePath(p)
if err != nil {
return nil, nil, err
return path.ImmutablePath{}, nil, err
}

return imPath, remainder, nil
Expand Down
2 changes: 1 addition & 1 deletion gateway/gateway_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -736,7 +736,7 @@ func (mb *errorMockBackend) GetCAR(ctx context.Context, path path.ImmutablePath,
}

func (mb *errorMockBackend) ResolveMutable(ctx context.Context, p path.Path) (path.ImmutablePath, error) {
return nil, mb.err
return path.ImmutablePath{}, mb.err
}

func (mb *errorMockBackend) GetIPNSRecord(ctx context.Context, c cid.Cid) ([]byte, error) {
Expand Down
8 changes: 4 additions & 4 deletions gateway/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -745,14 +745,14 @@ func (i *handler) handleWebRequestErrors(w http.ResponseWriter, r *http.Request,
if errors.Is(err, ErrServiceUnavailable) {
err = fmt.Errorf("failed to resolve %s: %w", debugStr(contentPath.String()), err)
i.webError(w, r, err, http.StatusServiceUnavailable)
return nil, false
return path.ImmutablePath{}, false
}

// If the error is not an IPLD traversal error then we should not be looking for _redirects or legacy 404s
if !isErrNotFound(err) {
err = fmt.Errorf("failed to resolve %s: %w", debugStr(contentPath.String()), err)
i.webError(w, r, err, http.StatusInternalServerError)
return nil, false
return path.ImmutablePath{}, false
}

// If we have origin isolation (subdomain gw, DNSLink website),
Expand All @@ -774,12 +774,12 @@ func (i *handler) handleWebRequestErrors(w http.ResponseWriter, r *http.Request,
// follow https://docs.ipfs.tech/how-to/websites-on-ipfs/redirects-and-custom-404s/ instead.
if i.serveLegacy404IfPresent(w, r, immutableContentPath, logger) {
logger.Debugw("served legacy 404")
return nil, false
return path.ImmutablePath{}, false
}

err = fmt.Errorf("failed to resolve %s: %w", debugStr(contentPath.String()), err)
i.webError(w, r, err, http.StatusInternalServerError)
return nil, false
return path.ImmutablePath{}, false
}

// Detect 'Cache-Control: only-if-cached' in request and return data if it is already in the local datastore.
Expand Down
16 changes: 8 additions & 8 deletions gateway/handler_unixfs__redirects.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,40 +42,40 @@ func (i *handler) serveRedirectsIfPresent(w http.ResponseWriter, r *http.Request
if err != nil {
err = fmt.Errorf("trouble processing _redirects path %q: %w", immutableContentPath.String(), err)
i.webError(w, r, err, http.StatusInternalServerError)
return nil, false, true
return path.ImmutablePath{}, false, true
}

redirectsPath, err := path.Join(rootPath, "_redirects")
if err != nil {
err = fmt.Errorf("trouble processing _redirects path %q: %w", rootPath.String(), err)
i.webError(w, r, err, http.StatusInternalServerError)
return nil, false, true
return path.ImmutablePath{}, false, true
}

imRedirectsPath, err := path.NewImmutablePath(redirectsPath)
if err != nil {
err = fmt.Errorf("trouble processing _redirects path %q: %w", redirectsPath, err)
i.webError(w, r, err, http.StatusInternalServerError)
return nil, false, true
return path.ImmutablePath{}, false, true
}

foundRedirect, redirectRules, err := i.getRedirectRules(r, imRedirectsPath)
if err != nil {
err = fmt.Errorf("trouble processing _redirects file at %q: %w", redirectsPath, err)
i.webError(w, r, err, http.StatusInternalServerError)
return nil, false, true
return path.ImmutablePath{}, false, true
}

if foundRedirect {
redirected, newPath, err := i.handleRedirectsFileRules(w, r, immutableContentPath, contentPath, redirectRules, logger)
if err != nil {
err = fmt.Errorf("trouble processing _redirects file at %q: %w", redirectsPath, err)
i.webError(w, r, err, http.StatusInternalServerError)
return nil, false, true
return path.ImmutablePath{}, false, true
}

if redirected {
return nil, false, true
return path.ImmutablePath{}, false, true
}

// 200 is treated as a rewrite, so update the path and continue
Expand All @@ -85,13 +85,13 @@ func (i *handler) serveRedirectsIfPresent(w http.ResponseWriter, r *http.Request
if err != nil {
err = fmt.Errorf("could not use _redirects file to %q: %w", p, err)
i.webError(w, r, err, http.StatusInternalServerError)
return nil, false, true
return path.ImmutablePath{}, false, true
}
imPath, err := path.NewImmutablePath(p)
if err != nil {
err = fmt.Errorf("could not use _redirects file to %q: %w", p, err)
i.webError(w, r, err, http.StatusInternalServerError)
return nil, false, true
return path.ImmutablePath{}, false, true
}
return imPath, true, true
}
Expand Down
6 changes: 3 additions & 3 deletions gateway/utilities_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,18 +186,18 @@ func (mb *mockBackend) resolvePathNoRootsReturned(ctx context.Context, ip path.P
if ip.Mutable() {
imPath, err = mb.ResolveMutable(ctx, ip)
if err != nil {
return nil, err
return path.ImmutablePath{}, err
}
} else {
imPath, err = path.NewImmutablePath(ip)
if err != nil {
return nil, err
return path.ImmutablePath{}, err
}
}

md, err := mb.ResolvePath(ctx, imPath)
if err != nil {
return nil, err
return path.ImmutablePath{}, err
}
return md.LastSegment, nil
}
Expand Down
34 changes: 13 additions & 21 deletions path/path.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,58 +73,50 @@ func (p path) Segments() []string {
}

// ImmutablePath is a [Path] which is guaranteed to have an immutable [Namespace].
type ImmutablePath interface {
Path

// RootCid returns the [cid.Cid] of the root object of the path.
RootCid() cid.Cid
}

var _ Path = immutablePath{}
var _ ImmutablePath = immutablePath{}

type immutablePath struct {
type ImmutablePath struct {
path Path
rootCid cid.Cid
}

var _ Path = ImmutablePath{}

func NewImmutablePath(p Path) (ImmutablePath, error) {
if p.Mutable() {
return nil, &ErrInvalidPath{err: ErrExpectedImmutable, path: p.String()}
return ImmutablePath{}, &ErrInvalidPath{err: ErrExpectedImmutable, path: p.String()}
}

segments := p.Segments()
cid, err := cid.Decode(segments[1])
if err != nil {
return nil, &ErrInvalidPath{err: err, path: p.String()}
return ImmutablePath{}, &ErrInvalidPath{err: err, path: p.String()}
}

return immutablePath{path: p, rootCid: cid}, nil
return ImmutablePath{path: p, rootCid: cid}, nil
}

func (ip immutablePath) String() string {
func (ip ImmutablePath) String() string {
return ip.path.String()
}

func (ip immutablePath) Namespace() string {
func (ip ImmutablePath) Namespace() string {
return ip.path.Namespace()
}

func (ip immutablePath) Mutable() bool {
func (ip ImmutablePath) Mutable() bool {
return false
}

func (ip immutablePath) Segments() []string {
func (ip ImmutablePath) Segments() []string {
return ip.path.Segments()
}

func (ip immutablePath) RootCid() cid.Cid {
func (ip ImmutablePath) RootCid() cid.Cid {
return ip.rootCid
}

// FromCid returns a new "/ipfs" path with the provided CID.
func FromCid(cid cid.Cid) ImmutablePath {
return immutablePath{
return ImmutablePath{
path: path{
str: fmt.Sprintf("/%s/%s", IPFSNamespace, cid.String()),
namespace: IPFSNamespace,
Expand Down Expand Up @@ -161,7 +153,7 @@ func NewPath(str string) (Path, error) {
return nil, &ErrInvalidPath{err: err, path: str}
}

return immutablePath{
return ImmutablePath{
path: path{
str: cleaned,
namespace: segments[0],
Expand Down
12 changes: 6 additions & 6 deletions path/path_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
)

func newIPLDPath(cid cid.Cid) ImmutablePath {
return immutablePath{
return ImmutablePath{
path: path{
str: fmt.Sprintf("/%s/%s", IPLDNamespace, cid.String()),
namespace: IPLDNamespace,
Expand Down Expand Up @@ -134,7 +134,7 @@ func TestNewPath(t *testing.T) {
for _, testCase := range testCases {
p, err := NewPath(testCase.src)
assert.NoError(t, err)
assert.IsType(t, immutablePath{}, p)
assert.IsType(t, ImmutablePath{}, p)
}
})
}
Expand All @@ -149,7 +149,7 @@ func TestFromCid(t *testing.T) {
assert.NoError(t, err)

p := FromCid(c)
assert.IsType(t, immutablePath{}, p)
assert.IsType(t, ImmutablePath{}, p)
assert.Equal(t, "/ipfs/QmdfTbBqBPQ7VNxZEYEj14VmRuZBkqFbiwReogJgS1zR1n", p.String())
assert.Equal(t, c, p.RootCid())
})
Expand All @@ -161,7 +161,7 @@ func TestFromCid(t *testing.T) {
assert.NoError(t, err)

p := FromCid(c)
assert.IsType(t, immutablePath{}, p)
assert.IsType(t, ImmutablePath{}, p)
assert.Equal(t, "/ipfs/bafybeihdwdcefgh4dqkjv67uzcmw7ojee6xedzdetojuzjevtenxquvyku", p.String())
assert.Equal(t, c, p.RootCid())
})
Expand All @@ -171,7 +171,7 @@ func TestFromCid(t *testing.T) {
assert.NoError(t, err)

p := newIPLDPath(c)
assert.IsType(t, immutablePath{}, p)
assert.IsType(t, ImmutablePath{}, p)
assert.Equal(t, "/ipld/QmdfTbBqBPQ7VNxZEYEj14VmRuZBkqFbiwReogJgS1zR1n", p.String())
assert.Equal(t, c, p.RootCid())

Expand All @@ -180,7 +180,7 @@ func TestFromCid(t *testing.T) {
assert.NoError(t, err)

p = newIPLDPath(c)
assert.IsType(t, immutablePath{}, p)
assert.IsType(t, ImmutablePath{}, p)
assert.Equal(t, "/ipld/bafybeihdwdcefgh4dqkjv67uzcmw7ojee6xedzdetojuzjevtenxquvyku", p.String())
assert.Equal(t, c, p.RootCid())
})
Expand Down