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

refactor: new go-libipfs/gateway API, deprecate Gateway.Writable #9616

Merged
merged 2 commits into from
Feb 2, 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
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