feat: remove writable gateway (#9743)
Co-authored-by: Marcin Rataj <lidel@lidel.org>
Henrique Dias committed
Mar 27, 2023 at 15:19 UTC
88d431c8129aeef2ea5076336412cb54161342ce
12 files changed
+18
-464
cmd/ipfs/daemon.go
+7
-12
@@ -163,7 +163,7 @@ Headers.
163
cmds.StringOption(initProfileOptionKwd, "Configuration profiles to apply for --init. See ipfs init --help for more"),
164
cmds.StringOption(routingOptionKwd, "Overrides the routing option").WithDefault(routingOptionDefaultKwd),
165
cmds.BoolOption(mountKwd, "Mounts IPFS to the filesystem using FUSE (experimental)"),
166
- cmds.BoolOption(writableKwd, "Enable legacy Gateway.Writable (deprecated)"),
166
+ cmds.BoolOption(writableKwd, "Enable legacy Gateway.Writable (REMOVED)"),
167
cmds.StringOption(ipfsMountKwd, "Path to the mountpoint for IPFS (if using --mount). Defaults to config setting."),
168
cmds.StringOption(ipnsMountKwd, "Path to the mountpoint for IPNS (if using --mount). Defaults to config setting."),
169
cmds.BoolOption(unrestrictedAPIAccessKwd, "Allow API access to unlisted hashes"),
@@ -679,7 +679,7 @@ func serveHTTPApi(req *cmds.Request, cctx *oldcmds.Context) (<-chan error, error
679
680
for _, listener := range listeners {
681
// we might have listened to /tcp/0 - let's see what we are listing on
682
- fmt.Printf("API server listening on %s\n", listener.Multiaddr())
682
+ fmt.Printf("RPC API server listening on %s\n", listener.Multiaddr())
683
// Browsers require TCP.
684
switch listener.Addr().Network() {
685
case "tcp", "tcp4", "tcp6":
@@ -692,9 +692,9 @@ func serveHTTPApi(req *cmds.Request, cctx *oldcmds.Context) (<-chan error, error
692
// only the webui objects are allowed.
693
// if you know what you're doing, go ahead and pass --unrestricted-api.
694
unrestricted, _ := req.Options[unrestrictedAPIAccessKwd].(bool)
695
- gatewayOpt := corehttp.GatewayOption(false, corehttp.WebUIPaths...)
695
+ gatewayOpt := corehttp.GatewayOption(corehttp.WebUIPaths...)
696
if unrestricted {
697
- gatewayOpt = corehttp.GatewayOption(true, "/ipfs", "/ipns")
697
+ gatewayOpt = corehttp.GatewayOption("/ipfs", "/ipns")
698
}
699
700
var opts = []corehttp.ServeOption{
@@ -804,7 +804,7 @@ func serveHTTPGateway(req *cmds.Request, cctx *oldcmds.Context) (<-chan error, e
804
}
805
806
if writable {
807
- 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")
807
+ log.Fatalf("Support for Gateway.Writable and --writable has been REMOVED. Please remove it from your config file or CLI. Modern replacement tracked in https://github.com/ipfs/specs/issues/375")
808
}
809
810
listeners, err := sockets.TakeListeners("io.ipfs.gateway")
@@ -837,13 +837,8 @@ func serveHTTPGateway(req *cmds.Request, cctx *oldcmds.Context) (<-chan error, e
837
}
838
839
// we might have listened to /tcp/0 - let's see what we are listing on
840
- gwType := "readonly"
841
- if writable {
842
- gwType = "writable"
843
- }
844
-
840
for _, listener := range listeners {
846
- fmt.Printf("Gateway (%s) server listening on %s\n", gwType, listener.Multiaddr())
841
+ fmt.Printf("Gateway server listening on %s\n", listener.Multiaddr())
842
}
843
844
cmdctx := *cctx
@@ -852,7 +847,7 @@ func serveHTTPGateway(req *cmds.Request, cctx *oldcmds.Context) (<-chan error, e
847
var opts = []corehttp.ServeOption{
848
corehttp.MetricsCollectionOption("gateway"),
849
corehttp.HostnameOption(),
855
- corehttp.GatewayOption(writable, "/ipfs", "/ipns"),
850
+ corehttp.GatewayOption("/ipfs", "/ipns"),
851
corehttp.VersionOption(),
852
corehttp.CheckVersionOption(),
853
corehttp.CommandsROOption(cmdctx),
cmd/ipfswatch/main.go
+1
-1
@@ -94,7 +94,7 @@ func run(ipfsPath, watchPath string) error {
94
if *http {
95
addr := "/ip4/127.0.0.1/tcp/5001"
96
var opts = []corehttp.ServeOption{
97
- corehttp.GatewayOption(true, "/ipfs", "/ipns"),
97
+ corehttp.GatewayOption("/ipfs", "/ipns"),
98
corehttp.WebUIOption,
99
corehttp.CommandsOption(cmdCtx(node, ipfsPath)),
100
}
config/gateway.go
+1
-2
@@ -38,8 +38,7 @@ type Gateway struct {
38
// should be redirected.
39
RootRedirect string
40
41
- // DEPRECATED: Enables legacy PUT/POST request handling.
42
- // Modern replacement tracked in https://github.com/ipfs/specs/issues/375
41
+ // REMOVED: modern replacement tracked in https://github.com/ipfs/specs/issues/375
42
Writable Flag `json:",omitempty"`
43
44
// PathPrefixes was removed: https://github.com/ipfs/go-ipfs/issues/7702
core/corehttp/corehttp.go
+1
-1
@@ -75,7 +75,7 @@ func ListenAndServe(n *core.IpfsNode, listeningMultiAddr string, options ...Serv
75
76
// we might have listened to /tcp/0 - let's see what we are listing on
77
addr = list.Multiaddr()
78
- fmt.Printf("API server listening on %s\n", addr)
78
+ fmt.Printf("RPC API server listening on %s\n", addr)
79
80
return Serve(n, manet.NetListener(list), options...)
81
}
core/corehttp/gateway.go
+1
-28
@@ -24,18 +24,13 @@ import (
24
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
25
)
26
27
-func GatewayOption(writable bool, paths ...string) ServeOption {
27
+func GatewayOption(paths ...string) ServeOption {
28
return func(n *core.IpfsNode, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
29
cfg, err := n.Repo.Config()
30
if err != nil {
31
return nil, err
32
}
33
34
- api, err := coreapi.NewCoreAPI(n, options.Api.FetchBlocks(!cfg.Gateway.NoFetch))
35
- if err != nil {
36
- return nil, err
37
- }
38
-
34
headers := make(map[string][]string, len(cfg.Gateway.HTTPHeaders))
35
for h, v := range cfg.Gateway.HTTPHeaders {
36
headers[http.CanonicalHeaderKey(h)] = v
@@ -58,28 +53,6 @@ func GatewayOption(writable bool, paths ...string) ServeOption {
53
// By default, our HTTP handler is the gateway handler.
54
handler := gw.ServeHTTP
55
61
- // If we have the writable gateway enabled, we have to replace our
62
- // http handler by a handler that takes care of the different methods.
63
- if writable {
64
- writableGw := &writableGatewayHandler{
65
- config: &gwConfig,
66
- api: api,
67
- }
68
-
69
- handler = func(w http.ResponseWriter, r *http.Request) {
70
- switch r.Method {
71
- case http.MethodPost:
72
- writableGw.postHandler(w, r)
73
- case http.MethodDelete:
74
- writableGw.deleteHandler(w, r)
75
- case http.MethodPut:
76
- writableGw.putHandler(w, r)
77
- default:
78
- gw.ServeHTTP(w, r)
79
- }
80
- }
81
- }
82
-
56
for _, p := range paths {
57
mux.HandleFunc(p+"/", handler)
58
}
core/corehttp/gateway_test.go
+1
-1
@@ -124,7 +124,7 @@ func newTestServerAndNode(t *testing.T, ns mockNamesys) (*httptest.Server, iface
124
dh.Handler, err = makeHandler(n,
125
ts.Listener,
126
HostnameOption(),
127
- GatewayOption(false, "/ipfs", "/ipns"),
127
+ GatewayOption("/ipfs", "/ipns"),
128
VersionOption(),
129
)
130
if err != nil {
core/corehttp/gateway_writable.go
deleted
-265
@@ -1,265 +0,0 @@
1
-package corehttp
2
-
3
-import (
4
- "context"
5
- "fmt"
6
- "net/http"
7
- "os"
8
- gopath "path"
9
-
10
- cid "github.com/ipfs/go-cid"
11
- ipld "github.com/ipfs/go-ipld-format"
12
- "github.com/ipfs/go-libipfs/files"
13
- "github.com/ipfs/go-libipfs/gateway"
14
- dag "github.com/ipfs/go-merkledag"
15
- "github.com/ipfs/go-mfs"
16
- path "github.com/ipfs/go-path"
17
- "github.com/ipfs/go-path/resolver"
18
- iface "github.com/ipfs/interface-go-ipfs-core"
19
- routing "github.com/libp2p/go-libp2p/core/routing"
20
-)
21
-
22
-const (
23
- ipfsPathPrefix = "/ipfs/"
24
-)
25
-
26
-type writableGatewayHandler struct {
27
- api iface.CoreAPI
28
- config *gateway.Config
29
-}
30
-
31
-func (i *writableGatewayHandler) addUserHeaders(w http.ResponseWriter) {
32
- for k, v := range i.config.Headers {
33
- w.Header()[http.CanonicalHeaderKey(k)] = v
34
- }
35
-}
36
-
37
-func (i *writableGatewayHandler) postHandler(w http.ResponseWriter, r *http.Request) {
38
- p, err := i.api.Unixfs().Add(r.Context(), files.NewReaderFile(r.Body))
39
- if err != nil {
40
- internalWebError(w, err)
41
- return
42
- }
43
-
44
- i.addUserHeaders(w) // ok, _now_ write user's headers.
45
- w.Header().Set("IPFS-Hash", p.Cid().String())
46
- log.Debugw("CID created, http redirect", "from", r.URL, "to", p, "status", http.StatusCreated)
47
- http.Redirect(w, r, p.String(), http.StatusCreated)
48
-}
49
-
50
-func (i *writableGatewayHandler) putHandler(w http.ResponseWriter, r *http.Request) {
51
- ctx := r.Context()
52
- ds := i.api.Dag()
53
-
54
- // Parse the path
55
- rootCid, newPath, err := parseIpfsPath(r.URL.Path)
56
- if err != nil {
57
- webError(w, "WritableGateway: failed to parse the path", err, http.StatusBadRequest)
58
- return
59
- }
60
- if newPath == "" || newPath == "/" {
61
- http.Error(w, "WritableGateway: empty path", http.StatusBadRequest)
62
- return
63
- }
64
- newDirectory, newFileName := gopath.Split(newPath)
65
-
66
- // Resolve the old root.
67
-
68
- rnode, err := ds.Get(ctx, rootCid)
69
- if err != nil {
70
- webError(w, "WritableGateway: Could not create DAG from request", err, http.StatusInternalServerError)
71
- return
72
- }
73
-
74
- pbnd, ok := rnode.(*dag.ProtoNode)
75
- if !ok {
76
- webError(w, "Cannot read non protobuf nodes through gateway", dag.ErrNotProtobuf, http.StatusBadRequest)
77
- return
78
- }
79
-
80
- // Create the new file.
81
- newFilePath, err := i.api.Unixfs().Add(ctx, files.NewReaderFile(r.Body))
82
- if err != nil {
83
- webError(w, "WritableGateway: could not create DAG from request", err, http.StatusInternalServerError)
84
- return
85
- }
86
-
87
- newFile, err := ds.Get(ctx, newFilePath.Cid())
88
- if err != nil {
89
- webError(w, "WritableGateway: failed to resolve new file", err, http.StatusInternalServerError)
90
- return
91
- }
92
-
93
- // Patch the new file into the old root.
94
-
95
- root, err := mfs.NewRoot(ctx, ds, pbnd, nil)
96
- if err != nil {
97
- webError(w, "WritableGateway: failed to create MFS root", err, http.StatusBadRequest)
98
- return
99
- }
100
-
101
- if newDirectory != "" {
102
- err := mfs.Mkdir(root, newDirectory, mfs.MkdirOpts{Mkparents: true, Flush: false})
103
- if err != nil {
104
- webError(w, "WritableGateway: failed to create MFS directory", err, http.StatusInternalServerError)
105
- return
106
- }
107
- }
108
- dirNode, err := mfs.Lookup(root, newDirectory)
109
- if err != nil {
110
- webError(w, "WritableGateway: failed to lookup directory", err, http.StatusInternalServerError)
111
- return
112
- }
113
- dir, ok := dirNode.(*mfs.Directory)
114
- if !ok {
115
- http.Error(w, "WritableGateway: target directory is not a directory", http.StatusBadRequest)
116
- return
117
- }
118
- err = dir.Unlink(newFileName)
119
- switch err {
120
- case os.ErrNotExist, nil:
121
- default:
122
- webError(w, "WritableGateway: failed to replace existing file", err, http.StatusBadRequest)
123
- return
124
- }
125
- err = dir.AddChild(newFileName, newFile)
126
- if err != nil {
127
- webError(w, "WritableGateway: failed to link file into directory", err, http.StatusInternalServerError)
128
- return
129
- }
130
- nnode, err := root.GetDirectory().GetNode()
131
- if err != nil {
132
- webError(w, "WritableGateway: failed to finalize", err, http.StatusInternalServerError)
133
- return
134
- }
135
- newcid := nnode.Cid()
136
-
137
- i.addUserHeaders(w) // ok, _now_ write user's headers.
138
- w.Header().Set("IPFS-Hash", newcid.String())
139
-
140
- redirectURL := gopath.Join(ipfsPathPrefix, newcid.String(), newPath)
141
- log.Debugw("CID replaced, redirect", "from", r.URL, "to", redirectURL, "status", http.StatusCreated)
142
- http.Redirect(w, r, redirectURL, http.StatusCreated)
143
-}
144
-
145
-func (i *writableGatewayHandler) deleteHandler(w http.ResponseWriter, r *http.Request) {
146
- ctx := r.Context()
147
-
148
- // parse the path
149
-
150
- rootCid, newPath, err := parseIpfsPath(r.URL.Path)
151
- if err != nil {
152
- webError(w, "WritableGateway: failed to parse the path", err, http.StatusBadRequest)
153
- return
154
- }
155
- if newPath == "" || newPath == "/" {
156
- http.Error(w, "WritableGateway: empty path", http.StatusBadRequest)
157
- return
158
- }
159
- directory, filename := gopath.Split(newPath)
160
-
161
- // lookup the root
162
-
163
- rootNodeIPLD, err := i.api.Dag().Get(ctx, rootCid)
164
- if err != nil {
165
- webError(w, "WritableGateway: failed to resolve root CID", err, http.StatusInternalServerError)
166
- return
167
- }
168
- rootNode, ok := rootNodeIPLD.(*dag.ProtoNode)
169
- if !ok {
170
- http.Error(w, "WritableGateway: empty path", http.StatusInternalServerError)
171
- return
172
- }
173
-
174
- // construct the mfs root
175
-
176
- root, err := mfs.NewRoot(ctx, i.api.Dag(), rootNode, nil)
177
- if err != nil {
178
- webError(w, "WritableGateway: failed to construct the MFS root", err, http.StatusBadRequest)
179
- return
180
- }
181
-
182
- // lookup the parent directory
183
-
184
- parentNode, err := mfs.Lookup(root, directory)
185
- if err != nil {
186
- webError(w, "WritableGateway: failed to look up parent", err, http.StatusInternalServerError)
187
- return
188
- }
189
-
190
- parent, ok := parentNode.(*mfs.Directory)
191
- if !ok {
192
- http.Error(w, "WritableGateway: parent is not a directory", http.StatusInternalServerError)
193
- return
194
- }
195
-
196
- // delete the file
197
-
198
- switch parent.Unlink(filename) {
199
- case nil, os.ErrNotExist:
200
- default:
201
- webError(w, "WritableGateway: failed to remove file", err, http.StatusInternalServerError)
202
- return
203
- }
204
-
205
- nnode, err := root.GetDirectory().GetNode()
206
- if err != nil {
207
- webError(w, "WritableGateway: failed to finalize", err, http.StatusInternalServerError)
208
- return
209
- }
210
- ncid := nnode.Cid()
211
-
212
- i.addUserHeaders(w) // ok, _now_ write user's headers.
213
- w.Header().Set("IPFS-Hash", ncid.String())
214
-
215
- redirectURL := gopath.Join(ipfsPathPrefix+ncid.String(), directory)
216
- // note: StatusCreated is technically correct here as we created a new resource.
217
- log.Debugw("CID deleted, redirect", "from", r.RequestURI, "to", redirectURL, "status", http.StatusCreated)
218
- http.Redirect(w, r, redirectURL, http.StatusCreated)
219
-}
220
-
221
-func parseIpfsPath(p string) (cid.Cid, string, error) {
222
- rootPath, err := path.ParsePath(p)
223
- if err != nil {
224
- return cid.Cid{}, "", err
225
- }
226
-
227
- // Check the path.
228
- rsegs := rootPath.Segments()
229
- if rsegs[0] != "ipfs" {
230
- return cid.Cid{}, "", fmt.Errorf("WritableGateway: only ipfs paths supported")
231
- }
232
-
233
- rootCid, err := cid.Decode(rsegs[1])
234
- if err != nil {
235
- return cid.Cid{}, "", err
236
- }
237
-
238
- return rootCid, path.Join(rsegs[2:]), nil
239
-}
240
-
241
-func webError(w http.ResponseWriter, message string, err error, defaultCode int) {
242
- if _, ok := err.(resolver.ErrNoLink); ok {
243
- webErrorWithCode(w, message, err, http.StatusNotFound)
244
- } else if err == routing.ErrNotFound {
245
- webErrorWithCode(w, message, err, http.StatusNotFound)
246
- } else if ipld.IsNotFound(err) {
247
- webErrorWithCode(w, message, err, http.StatusNotFound)
248
- } else if err == context.DeadlineExceeded {
249
- webErrorWithCode(w, message, err, http.StatusRequestTimeout)
250
- } else {
251
- webErrorWithCode(w, message, err, defaultCode)
252
- }
253
-}
254
-
255
-func webErrorWithCode(w http.ResponseWriter, message string, err error, code int) {
256
- http.Error(w, fmt.Sprintf("%s: %s", message, err), code)
257
- if code >= 500 {
258
- log.Warnf("server error: %s: %s", message, err)
259
- }
260
-}
261
-
262
-// return a 500 error and log
263
-func internalWebError(w http.ResponseWriter, err error) {
264
- webErrorWithCode(w, "internalWebError", err, http.StatusInternalServerError)
265
-}
docs/config.md
+2
-7
@@ -681,14 +681,9 @@ Type: `string` (url)
681
682
### `Gateway.Writable`
683
684
-**DEPRECATED**: Enables legacy PUT/POST request handling.
684
+**REMOVED**: this option no longer available as of [Kubo 0.20](https://github.com/ipfs/kubo/blob/master/docs/changelogs/v0.20.md).
685
686
-This API is not standardized, and should not be used for new projects.
687
-We are working on a modern replacement. IPIP can be tracked in [ipfs/specs#375](https://github.com/ipfs/specs/issues/375).
688
-
689
-Default: `false`
690
-
691
-Type: `bool`
686
+We are working on developing a modern replacement. To support our efforts, please leave a comment describing your use case in [ipfs/specs#375](https://github.com/ipfs/specs/issues/375).
687
688
### `Gateway.PathPrefixes`
689
test/cli/gateway_test.go
+1
-1
@@ -436,7 +436,7 @@ func TestGateway(t *testing.T) {
436
437
t.Run("verify gateway file", func(t *testing.T) {
438
t.Parallel()
439
- r := regexp.MustCompile(`Gateway \(readonly\) server listening on (?P<addr>.+)\s`)
439
+ r := regexp.MustCompile(`Gateway server listening on (?P<addr>.+)\s`)
440
matches := r.FindStringSubmatch(node.Daemon.Stdout.String())
441
ma, err := multiaddr.NewMultiaddr(matches[1])
442
require.NoError(t, err)
test/sharness/lib/test-lib.sh
+1
-8
@@ -214,13 +214,6 @@ test_init_ipfs() {
214
215
}
216
217
-test_config_ipfs_gateway_writable() {
218
- test_expect_success "prepare config -- gateway writable" '
219
- test_config_set --bool Gateway.Writable true ||
220
- test_fsh cat "\"$IPFS_PATH/config\""
221
- '
222
-}
223
-
217
test_wait_for_file() {
218
loops=$1
219
delay=$2
@@ -247,7 +240,7 @@ test_set_address_vars() {
240
API_ADDR=$(convert_tcp_maddr $API_MADDR) &&
241
API_PORT=$(port_from_maddr $API_MADDR) &&
242
250
- GWAY_MADDR=$(sed -n "s/^Gateway (.*) server listening on //p" "$daemon_output") &&
243
+ GWAY_MADDR=$(sed -n "s/^Gateway server listening on //p" "$daemon_output") &&
244
GWAY_ADDR=$(convert_tcp_maddr $GWAY_MADDR) &&
245
GWAY_PORT=$(port_from_maddr $GWAY_MADDR)
246
'
test/sharness/t0060-daemon.sh
+2
-2
@@ -89,9 +89,9 @@ test_expect_success "ipfs daemon output looks good" '
89
echo "" >>expected_daemon &&
90
sed "s/^/Swarm listening on /" listen_addrs >>expected_daemon &&
91
sed "s/^/Swarm announcing /" local_addrs >>expected_daemon &&
92
- echo "API server listening on '$API_MADDR'" >>expected_daemon &&
92
+ echo "RPC API server listening on '$API_MADDR'" >>expected_daemon &&
93
echo "WebUI: http://'$API_ADDR'/webui" >>expected_daemon &&
94
- echo "Gateway (readonly) server listening on '$GWAY_MADDR'" >>expected_daemon &&
94
+ echo "Gateway server listening on '$GWAY_MADDR'" >>expected_daemon &&
95
echo "Daemon is ready" >>expected_daemon &&
96
test_cmp expected_daemon actual_daemon
97
'
test/sharness/t0111-gateway-writeable.sh
deleted
-136
@@ -1,136 +0,0 @@
1
-#!/usr/bin/env bash
2
-#
3
-# Copyright (c) 2014 Christian Couder
4
-# MIT Licensed; see the LICENSE file in this repository.
5
-#
6
-
7
-test_description="Test HTTP Gateway (Writable)"
8
-
9
-. lib/test-lib.sh
10
-
11
-test_init_ipfs
12
-
13
-test_launch_ipfs_daemon --writable
14
-test_expect_success "ipfs daemon --writable overrides config" '
15
- curl -v -X POST http://$GWAY_ADDR/ipfs/ 2> outfile &&
16
- grep "HTTP/1.1 201 Created" outfile &&
17
- grep "Location: /ipfs/QmbFMke1KXqnYyBBWxB74N4c5SBnJMVAiMNRcGu6x1AwQH" outfile
18
-'
19
-test_kill_ipfs_daemon
20
-
21
-test_config_ipfs_gateway_writable
22
-test_launch_ipfs_daemon --writable=false
23
-test_expect_success "ipfs daemon --writable=false overrides Writable=true config" '
24
- curl -v -X POST http://$GWAY_ADDR/ipfs/ 2> outfile &&
25
- grep "HTTP/1.1 405 Method Not Allowed" outfile
26
-'
27
-test_kill_ipfs_daemon
28
-test_launch_ipfs_daemon
29
-
30
-port=$GWAY_PORT
31
-
32
-test_expect_success "ipfs daemon up" '
33
- pollEndpoint -host $GWAY_MADDR -v -tout=1s -tries=60 2>poll_apierr > poll_apiout ||
34
- test_fsh cat poll_apierr || test_fsh cat poll_apiout
35
-'
36
-
37
-test_expect_success "deprecation notice is printed when Gateway.Writable=true" '
38
- test_should_contain "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" daemon_err
39
-'
40
-
41
-test_expect_success "HTTP gateway gives access to sample file" '
42
- curl -s -o welcome "http://$GWAY_ADDR/ipfs/$HASH_WELCOME_DOCS/readme" &&
43
- grep "Hello and Welcome to IPFS!" welcome
44
-'
45
-
46
-test_expect_success "HTTP POST file gives Hash" '
47
- echo "$RANDOM" >infile &&
48
- URL="http://127.0.0.1:$port/ipfs/" &&
49
- curl -svX POST --data-binary @infile "$URL" 2>curl_post.out &&
50
- grep "HTTP/1.1 201 Created" curl_post.out &&
51
- LOCATION=$(grep Location curl_post.out) &&
52
- HASH=$(echo $LOCATION | cut -d":" -f2- |tr -d " \n\r")
53
-'
54
-
55
-test_expect_success "We can HTTP GET file just created" '
56
- URL="http://127.0.0.1:${port}${HASH}" &&
57
- curl -so outfile "$URL" &&
58
- test_cmp infile outfile
59
-'
60
-
61
-test_expect_success "We got the correct hash" '
62
- ADD_HASH="/ipfs/$(ipfs add -q infile)" &&
63
- test "x$ADD_HASH" = "x$HASH" || test_fsh echo "$ADD_HASH != $HASH"
64
-'
65
-
66
-test_expect_success "HTTP GET empty directory" '
67
- URL="http://127.0.0.1:$port/ipfs/$HASH_EMPTY_DIR/" &&
68
- echo "GET $URL" &&
69
- curl -so outfile "$URL" 2>curl_getEmpty.out &&
70
- cat outfile | tr -s "\n" " " | grep "Index of /ipfs/<a href=\"/ipfs/$HASH_EMPTY_DIR\">$HASH_EMPTY_DIR</a>"
71
-'
72
-
73
-test_expect_success "HTTP PUT file to construct a hierarchy" '
74
- echo "$RANDOM" >infile &&
75
- URL="http://127.0.0.1:$port/ipfs/$HASH_EMPTY_DIR/test.txt" &&
76
- echo "PUT $URL" &&
77
- curl -svX PUT --data-binary @infile "$URL" 2>curl_put.out &&
78
- grep "HTTP/1.1 201 Created" curl_put.out &&
79
- LOCATION=$(grep Location curl_put.out) &&
80
- HASH=$(expr "$LOCATION" : "< Location: /ipfs/\(.*\)/test.txt")
81
-'
82
-
83
-test_expect_success "We can HTTP GET file just created" '
84
- URL="http://127.0.0.1:$port/ipfs/$HASH/test.txt" &&
85
- echo "GET $URL" &&
86
- curl -so outfile "$URL" &&
87
- test_cmp infile outfile
88
-'
89
-
90
-test_expect_success "HTTP PUT file to append to existing hierarchy" '
91
- echo "$RANDOM" >infile2 &&
92
- URL="http://127.0.0.1:$port/ipfs/$HASH/test/test.txt" &&
93
- echo "PUT $URL" &&
94
- curl -svX PUT --data-binary @infile2 "$URL" 2>curl_putAgain.out &&
95
- grep "HTTP/1.1 201 Created" curl_putAgain.out &&
96
- LOCATION=$(grep Location curl_putAgain.out) &&
97
- HASH=$(expr "$LOCATION" : "< Location: /ipfs/\(.*\)/test/test.txt")
98
-'
99
-
100
-
101
-test_expect_success "We can HTTP GET file just updated" '
102
- URL="http://127.0.0.1:$port/ipfs/$HASH/test/test.txt" &&
103
- echo "GET $URL" &&
104
- curl -svo outfile2 "$URL" 2>curl_getAgain.out &&
105
- test_cmp infile2 outfile2
106
-'
107
-
108
-test_expect_success "HTTP PUT to replace a directory" '
109
- echo "$RANDOM" >infile3 &&
110
- URL="http://127.0.0.1:$port/ipfs/$HASH/test" &&
111
- echo "PUT $URL" &&
112
- curl -svX PUT --data-binary @infile3 "$URL" 2>curl_putOverDirectory.out &&
113
- grep "HTTP/1.1 201 Created" curl_putOverDirectory.out &&
114
- LOCATION=$(grep Location curl_putOverDirectory.out) &&
115
- HASH=$(expr "$LOCATION" : "< Location: /ipfs/\(.*\)/test")
116
-'
117
-
118
-test_expect_success "We can HTTP GET file just put over a directory" '
119
- URL="http://127.0.0.1:$port/ipfs/$HASH/test" &&
120
- echo "GET $URL" &&
121
- curl -svo outfile3 "$URL" 2>curl_getOverDirectory.out &&
122
- test_cmp infile3 outfile3
123
-'
124
-
125
-test_expect_success "HTTP PUT to /ipns fails" '
126
- PEERID=`ipfs id --format="<id>"` &&
127
- URL="http://127.0.0.1:$port/ipns/$PEERID/test.txt" &&
128
- echo "PUT $URL" &&
129
- curl -svX PUT --data-binary @infile1 "$URL" 2>curl_putIpns.out &&
130
- grep "HTTP/1.1 400 Bad Request" curl_putIpns.out
131
-'
132
-
133
-
134
-test_kill_ipfs_daemon
135
-
136
-test_done