Skip to content

Commit

Permalink
refactor: new go-libipfs/gateway API, deprecate Gateway.Writable (#9616)
Browse files Browse the repository at this point in the history
  • Loading branch information
hacdias authored Feb 2, 2023
1 parent 4e8271b commit 14649aa
Show file tree
Hide file tree
Showing 11 changed files with 376 additions and 18 deletions.
8 changes: 6 additions & 2 deletions cmd/ipfs/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ Headers.
cmds.StringOption(initProfileOptionKwd, "Configuration profiles to apply for --init. See ipfs init --help for more"),
cmds.StringOption(routingOptionKwd, "Overrides the routing option").WithDefault(routingOptionDefaultKwd),
cmds.BoolOption(mountKwd, "Mounts IPFS to the filesystem using FUSE (experimental)"),
cmds.BoolOption(writableKwd, "Enable writing objects (with POST, PUT and DELETE)"),
cmds.BoolOption(writableKwd, "Enable legacy Gateway.Writable (deprecated)"),
cmds.StringOption(ipfsMountKwd, "Path to the mountpoint for IPFS (if using --mount). Defaults to config setting."),
cmds.StringOption(ipnsMountKwd, "Path to the mountpoint for IPNS (if using --mount). Defaults to config setting."),
cmds.BoolOption(unrestrictedAPIAccessKwd, "Allow API access to unlisted hashes"),
Expand Down Expand Up @@ -791,7 +791,11 @@ func serveHTTPGateway(req *cmds.Request, cctx *oldcmds.Context) (<-chan error, e

writable, writableOptionFound := req.Options[writableKwd].(bool)
if !writableOptionFound {
writable = cfg.Gateway.Writable
writable = cfg.Gateway.Writable.WithDefault(false)
}

if writable {
log.Error("serveHTTPGateway: legacy Gateway.Writable is DEPRECATED and will be removed or changed in future versions. If you are still using this, provide feedback in https://github.com/ipfs/specs/issues/375")
}

listeners, err := sockets.TakeListeners("io.ipfs.gateway")
Expand Down
6 changes: 3 additions & 3 deletions config/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ type Gateway struct {
// should be redirected.
RootRedirect string

// Writable enables PUT/POST request handling by this gateway. Usually,
// writing is done through the API, not the gateway.
Writable bool
// DEPRECATED: Enables legacy PUT/POST request handling.
// Modern replacement tracked in https://github.com/ipfs/specs/issues/375
Writable Flag `json:",omitempty"`

// PathPrefixes was removed: https://github.com/ipfs/go-ipfs/issues/7702
PathPrefixes []string
Expand Down
1 change: 0 additions & 1 deletion config/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ func InitWithIdentity(identity Identity) (*Config, error) {

Gateway: Gateway{
RootRedirect: "",
Writable: false,
NoFetch: false,
PathPrefixes: []string{},
HTTPHeaders: map[string][]string{
Expand Down
93 changes: 88 additions & 5 deletions core/corehttp/gateway.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
package corehttp

import (
"context"
"fmt"
"io"
"net"
"net/http"

cid "github.com/ipfs/go-cid"
"github.com/ipfs/go-libipfs/blocks"
"github.com/ipfs/go-libipfs/files"
"github.com/ipfs/go-libipfs/gateway"
iface "github.com/ipfs/interface-go-ipfs-core"
options "github.com/ipfs/interface-go-ipfs-core/options"
"github.com/ipfs/interface-go-ipfs-core/path"
version "github.com/ipfs/kubo"
core "github.com/ipfs/kubo/core"
coreapi "github.com/ipfs/kubo/core/coreapi"
Expand Down Expand Up @@ -38,15 +45,45 @@ func GatewayOption(writable bool, paths ...string) ServeOption {
return nil, err
}

gateway := gateway.NewHandler(gateway.Config{
Headers: headers,
Writable: writable,
}, api, offlineAPI)
gatewayConfig := gateway.Config{
Headers: headers,
}

gatewayAPI := &gatewayAPI{
api: api,
offlineAPI: offlineAPI,
}

gateway := gateway.NewHandler(gatewayConfig, gatewayAPI)
gateway = otelhttp.NewHandler(gateway, "Gateway.Request")

var writableGateway *writableGatewayHandler
if writable {
writableGateway = &writableGatewayHandler{
config: &gatewayConfig,
api: api,
}
}

for _, p := range paths {
mux.Handle(p+"/", gateway)
mux.HandleFunc(p+"/", func(w http.ResponseWriter, r *http.Request) {
if writable {
switch r.Method {
case http.MethodPost:
writableGateway.postHandler(w, r)
case http.MethodDelete:
writableGateway.deleteHandler(w, r)
case http.MethodPut:
writableGateway.putHandler(w, r)
default:
gateway.ServeHTTP(w, r)
}

return
}

gateway.ServeHTTP(w, r)
})
}
return mux, nil
}
Expand All @@ -62,3 +99,49 @@ func VersionOption() ServeOption {
return mux, nil
}
}

type gatewayAPI struct {
api iface.CoreAPI
offlineAPI iface.CoreAPI
}

func (gw *gatewayAPI) GetUnixFsNode(ctx context.Context, pth path.Resolved) (files.Node, error) {
return gw.api.Unixfs().Get(ctx, pth)
}

func (gw *gatewayAPI) LsUnixFsDir(ctx context.Context, pth path.Resolved) (<-chan iface.DirEntry, error) {
// Optimization: use Unixfs.Ls without resolving children, but using the
// cumulative DAG size as the file size. This allows for a fast listing
// while keeping a good enough Size field.
return gw.api.Unixfs().Ls(ctx, pth,
options.Unixfs.ResolveChildren(false),
options.Unixfs.UseCumulativeSize(true),
)
}

func (gw *gatewayAPI) GetBlock(ctx context.Context, cid cid.Cid) (blocks.Block, error) {
r, err := gw.api.Block().Get(ctx, path.IpfsPath(cid))
if err != nil {
return nil, err
}

data, err := io.ReadAll(r)
if err != nil {
return nil, err
}

return blocks.NewBlockWithCid(data, cid)
}

func (gw *gatewayAPI) GetIPNSRecord(ctx context.Context, c cid.Cid) ([]byte, error) {
return gw.api.Routing().Get(ctx, "/ipns/"+c.String())
}

func (gw *gatewayAPI) IsCached(ctx context.Context, pth path.Path) bool {
_, err := gw.offlineAPI.Block().Stat(ctx, pth)
return err == nil
}

func (gw *gatewayAPI) ResolvePath(ctx context.Context, pth path.Path) (path.Resolved, error) {
return gw.api.ResolvePath(ctx, pth)
}
Loading

0 comments on commit 14649aa

Please sign in to comment.