From d50a7ff0037b2fb6d787cf6fb1c3d14a429b1ea0 Mon Sep 17 00:00:00 2001 From: Brian Tiger Chow Date: Tue, 3 Feb 2015 15:48:10 -0800 Subject: [PATCH] feat(corehttp) add a Gateway blocklist use pointer use func comment on decider to clarify whether it allows or denies fix set conf gstw --- core/corehttp/gateway.go | 59 ++++++++++++++++++++++++++++++-- core/corehttp/gateway_handler.go | 21 ++++++++---- 2 files changed, 71 insertions(+), 9 deletions(-) diff --git a/core/corehttp/gateway.go b/core/corehttp/gateway.go index c6b5545e9..0e0601b34 100644 --- a/core/corehttp/gateway.go +++ b/core/corehttp/gateway.go @@ -2,13 +2,30 @@ package corehttp import ( "net/http" + "sync" core "github.com/jbenet/go-ipfs/core" ) -func GatewayOption(writable bool) ServeOption { +// Gateway should be instantiated using NewGateway +type Gateway struct { + Config GatewayConfig +} + +type GatewayConfig struct { + BlockList *BlockList + Writable bool +} + +func NewGateway(conf GatewayConfig) *Gateway { + return &Gateway{ + Config: conf, + } +} + +func (g *Gateway) ServeOption() ServeOption { return func(n *core.IpfsNode, mux *http.ServeMux) error { - gateway, err := newGatewayHandler(n, writable) + gateway, err := newGatewayHandler(n, g.Config) if err != nil { return err } @@ -17,3 +34,41 @@ func GatewayOption(writable bool) ServeOption { return nil } } + +func GatewayOption(writable bool) ServeOption { + g := NewGateway(GatewayConfig{ + Writable: writable, + BlockList: &BlockList{}, + }) + return g.ServeOption() +} + +// Decider decides whether to Allow string +type Decider func(string) bool + +type BlockList struct { + + mu sync.RWMutex + d Decider +} + +func (b *BlockList) ShouldAllow(s string) bool { + b.mu.RLock() + d := b.d + b.mu.RUnlock() + if d == nil { + return true + } + return d(s) +} + +// SetDecider atomically swaps the blocklist's decider +func (b *BlockList) SetDecider(d Decider) { + b.mu.Lock() + b.d = d + b.mu.Unlock() +} + +func (b *BlockList) ShouldBlock(s string) bool { + return !b.ShouldAllow(s) +} diff --git a/core/corehttp/gateway_handler.go b/core/corehttp/gateway_handler.go index 5ea654360..93c33cb2e 100644 --- a/core/corehttp/gateway_handler.go +++ b/core/corehttp/gateway_handler.go @@ -50,13 +50,13 @@ type directoryItem struct { type gatewayHandler struct { node *core.IpfsNode dirList *template.Template - writable bool + config GatewayConfig } -func newGatewayHandler(node *core.IpfsNode, writable bool) (*gatewayHandler, error) { +func newGatewayHandler(node *core.IpfsNode, conf GatewayConfig) (*gatewayHandler, error) { i := &gatewayHandler{ node: node, - writable: writable, + config: conf, } err := i.loadTemplate() if err != nil { @@ -125,18 +125,20 @@ func (i *gatewayHandler) NewDagReader(nd *dag.Node) (uio.ReadSeekCloser, error) return uio.NewDagReader(i.node.Context(), nd, i.node.DAG) } +// TODO(btc): break this apart into separate handlers using a more expressive +// muxer func (i *gatewayHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - if i.writable && r.Method == "POST" { + if i.config.Writable && r.Method == "POST" { i.postHandler(w, r) return } - if i.writable && r.Method == "PUT" { + if i.config.Writable && r.Method == "PUT" { i.putHandler(w, r) return } - if i.writable && r.Method == "DELETE" { + if i.config.Writable && r.Method == "DELETE" { i.deleteHandler(w, r) return } @@ -147,7 +149,7 @@ func (i *gatewayHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { } errmsg := "Method " + r.Method + " not allowed: " - if !i.writable { + if !i.config.Writable { w.WriteHeader(http.StatusMethodNotAllowed) errmsg = errmsg + "read only access" } else { @@ -164,6 +166,11 @@ func (i *gatewayHandler) getHandler(w http.ResponseWriter, r *http.Request) { urlPath := r.URL.Path + if i.config.BlockList != nil && i.config.BlockList.ShouldBlock(urlPath) { + w.WriteHeader(http.StatusNotFound) + return + } + nd, p, err := i.ResolvePath(ctx, urlPath) if err != nil { if err == routing.ErrNotFound {