feat(corehttp) add a Gateway blocklist
use pointer use func comment on decider to clarify whether it allows or denies fix set conf gstw
Brian Tiger Chow committed
Feb 3, 2015 at 15:48 UTC
d50a7ff0037b2fb6d787cf6fb1c3d14a429b1ea0
2 files changed
+71
-9
core/corehttp/gateway.go
+57
-2
@@ -2,13 +2,30 @@ package corehttp
2
3
import (
4
"net/http"
5
+ "sync"
6
7
core "github.com/jbenet/go-ipfs/core"
8
)
9
9
-func GatewayOption(writable bool) ServeOption {
10
+// Gateway should be instantiated using NewGateway
11
+type Gateway struct {
12
+ Config GatewayConfig
13
+}
14
+
15
+type GatewayConfig struct {
16
+ BlockList *BlockList
17
+ Writable bool
18
+}
19
+
20
+func NewGateway(conf GatewayConfig) *Gateway {
21
+ return &Gateway{
22
+ Config: conf,
23
+ }
24
+}
25
+
26
+func (g *Gateway) ServeOption() ServeOption {
27
return func(n *core.IpfsNode, mux *http.ServeMux) error {
11
- gateway, err := newGatewayHandler(n, writable)
28
+ gateway, err := newGatewayHandler(n, g.Config)
29
if err != nil {
30
return err
31
}
@@ -17,3 +34,41 @@ func GatewayOption(writable bool) ServeOption {
34
return nil
35
}
36
}
37
+
38
+func GatewayOption(writable bool) ServeOption {
39
+ g := NewGateway(GatewayConfig{
40
+ Writable: writable,
41
+ BlockList: &BlockList{},
42
+ })
43
+ return g.ServeOption()
44
+}
45
+
46
+// Decider decides whether to Allow string
47
+type Decider func(string) bool
48
+
49
+type BlockList struct {
50
+
51
+ mu sync.RWMutex
52
+ d Decider
53
+}
54
+
55
+func (b *BlockList) ShouldAllow(s string) bool {
56
+ b.mu.RLock()
57
+ d := b.d
58
+ b.mu.RUnlock()
59
+ if d == nil {
60
+ return true
61
+ }
62
+ return d(s)
63
+}
64
+
65
+// SetDecider atomically swaps the blocklist's decider
66
+func (b *BlockList) SetDecider(d Decider) {
67
+ b.mu.Lock()
68
+ b.d = d
69
+ b.mu.Unlock()
70
+}
71
+
72
+func (b *BlockList) ShouldBlock(s string) bool {
73
+ return !b.ShouldAllow(s)
74
+}
core/corehttp/gateway_handler.go
+14
-7
@@ -50,13 +50,13 @@ type directoryItem struct {
50
type gatewayHandler struct {
51
node *core.IpfsNode
52
dirList *template.Template
53
- writable bool
53
+ config GatewayConfig
54
}
55
56
-func newGatewayHandler(node *core.IpfsNode, writable bool) (*gatewayHandler, error) {
56
+func newGatewayHandler(node *core.IpfsNode, conf GatewayConfig) (*gatewayHandler, error) {
57
i := &gatewayHandler{
58
node: node,
59
- writable: writable,
59
+ config: conf,
60
}
61
err := i.loadTemplate()
62
if err != nil {
@@ -125,18 +125,20 @@ func (i *gatewayHandler) NewDagReader(nd *dag.Node) (uio.ReadSeekCloser, error)
125
return uio.NewDagReader(i.node.Context(), nd, i.node.DAG)
126
}
127
128
+// TODO(btc): break this apart into separate handlers using a more expressive
129
+// muxer
130
func (i *gatewayHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
129
- if i.writable && r.Method == "POST" {
131
+ if i.config.Writable && r.Method == "POST" {
132
i.postHandler(w, r)
133
return
134
}
135
134
- if i.writable && r.Method == "PUT" {
136
+ if i.config.Writable && r.Method == "PUT" {
137
i.putHandler(w, r)
138
return
139
}
140
139
- if i.writable && r.Method == "DELETE" {
141
+ if i.config.Writable && r.Method == "DELETE" {
142
i.deleteHandler(w, r)
143
return
144
}
@@ -147,7 +149,7 @@ func (i *gatewayHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
149
}
150
151
errmsg := "Method " + r.Method + " not allowed: "
150
- if !i.writable {
152
+ if !i.config.Writable {
153
w.WriteHeader(http.StatusMethodNotAllowed)
154
errmsg = errmsg + "read only access"
155
} else {
@@ -164,6 +166,11 @@ func (i *gatewayHandler) getHandler(w http.ResponseWriter, r *http.Request) {
166
167
urlPath := r.URL.Path
168
169
+ if i.config.BlockList != nil && i.config.BlockList.ShouldBlock(urlPath) {
170
+ w.WriteHeader(http.StatusNotFound)
171
+ return
172
+ }
173
+
174
nd, p, err := i.ResolvePath(ctx, urlPath)
175
if err != nil {
176
if err == routing.ErrNotFound {