@cryptotaxi247 / kubo / commits / 1e5ce9365

fix: use %-encoded headers in most compatible way

Henrique Dias committed Aug 15, 2023 at 15:11 UTC 1e5ce936596c3404f7a2890ea1827ae743de5fc0
14 files changed +233 -49
client/rpc/api.go
+53 -6
@@ -1,18 +1,24 @@
1 package rpc
2
3 import (
4 + "context"
5 + "encoding/json"
6 "errors"
7 "fmt"
8 "net/http"
9 "os"
10 "path/filepath"
11 "strings"
12 + "sync"
13 + "time"
14
15 + "github.com/blang/semver/v4"
16 iface "github.com/ipfs/boxo/coreiface"
17 caopts "github.com/ipfs/boxo/coreiface/options"
18 "github.com/ipfs/boxo/ipld/merkledag"
19 "github.com/ipfs/go-cid"
20 legacy "github.com/ipfs/go-ipld-legacy"
21 + ipfs "github.com/ipfs/kubo"
22 dagpb "github.com/ipld/go-codec-dagpb"
23 _ "github.com/ipld/go-ipld-prime/codec/dagcbor"
24 "github.com/ipld/go-ipld-prime/node/basicnode"
@@ -42,6 +48,8 @@ type HttpApi struct {
48 Headers http.Header
49 applyGlobal func(*requestBuilder)
50 ipldDecoder *legacy.Decoder
51 + versionMu sync.Mutex
52 + version *semver.Version
53 }
54
55 // NewLocalApi tries to construct new HttpApi instance communicating with local
@@ -151,6 +159,7 @@ func NewURLApiWithClient(url string, c *http.Client) (*HttpApi, error) {
159 api.httpcli.CheckRedirect = func(_ *http.Request, _ []*http.Request) error {
160 return fmt.Errorf("unexpected redirect")
161 }
162 +
163 return api, nil
164 }
165
@@ -160,14 +169,19 @@ func (api *HttpApi) WithOptions(opts ...caopts.ApiOption) (iface.CoreAPI, error)
169 return nil, err
170 }
171
163 - subApi := *api
164 - subApi.applyGlobal = func(req *requestBuilder) {
165 - if options.Offline {
166 - req.Option("offline", options.Offline)
167 - }
172 + subApi := &HttpApi{
173 + url: api.url,
174 + httpcli: api.httpcli,
175 + Headers: api.Headers,
176 + applyGlobal: func(req *requestBuilder) {
177 + if options.Offline {
178 + req.Option("offline", options.Offline)
179 + }
180 + },
181 + ipldDecoder: api.ipldDecoder,
182 }
183
170 - return &subApi, nil
184 + return subApi, nil
185 }
186
187 func (api *HttpApi) Request(command string, args ...string) RequestBuilder {
@@ -228,3 +242,36 @@ func (api *HttpApi) PubSub() iface.PubSubAPI {
242 func (api *HttpApi) Routing() iface.RoutingAPI {
243 return (*RoutingAPI)(api)
244 }
245 +
246 +func (api *HttpApi) loadRemoteVersion() (*semver.Version, error) {
247 + api.versionMu.Lock()
248 + defer api.versionMu.Unlock()
249 +
250 + if api.version == nil {
251 + ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(time.Second*30))
252 + defer cancel()
253 +
254 + resp, err := api.Request("version").Send(ctx)
255 + if err != nil {
256 + return nil, err
257 + }
258 + if resp.Error != nil {
259 + return nil, resp.Error
260 + }
261 + defer resp.Close()
262 + var out ipfs.VersionInfo
263 + dec := json.NewDecoder(resp.Output)
264 + if err := dec.Decode(&out); err != nil {
265 + return nil, err
266 + }
267 +
268 + remoteVersion, err := semver.New(out.Version)
269 + if err != nil {
270 + return nil, err
271 + }
272 +
273 + api.version = remoteVersion
274 + }
275 +
276 + return api.version, nil
277 +}
client/rpc/requestbuilder.go
+27 -6
@@ -8,6 +8,7 @@ import (
8 "strconv"
9 "strings"
10
11 + "github.com/blang/semver/v4"
12 "github.com/ipfs/boxo/files"
13 )
14
@@ -23,13 +24,18 @@ type RequestBuilder interface {
24 Exec(ctx context.Context, res interface{}) error
25 }
26
27 +// encodedAbsolutePathVersion is the version from which the absolute path header in
28 +// multipart requests is %-encoded. Before this version, its sent raw.
29 +var encodedAbsolutePathVersion = semver.MustParse("0.23.0-dev")
30 +
31 // requestBuilder is an IPFS commands request builder.
32 type requestBuilder struct {
28 - command string
29 - args []string
30 - opts map[string]string
31 - headers map[string]string
32 - body io.Reader
33 + command string
34 + args []string
35 + opts map[string]string
36 + headers map[string]string
37 + body io.Reader
38 + buildError error
39
40 shell *HttpApi
41 }
@@ -60,7 +66,18 @@ func (r *requestBuilder) Body(body io.Reader) RequestBuilder {
66 func (r *requestBuilder) FileBody(body io.Reader) RequestBuilder {
67 pr, _ := files.NewReaderPathFile("/dev/stdin", io.NopCloser(body), nil)
68 d := files.NewMapDirectory(map[string]files.Node{"": pr})
63 - r.body = files.NewMultiFileReader(d, false)
69 +
70 + version, err := r.shell.loadRemoteVersion()
71 + if err != nil {
72 + // Unfortunately, we cannot return an error here. Changing this API is also
73 + // not the best since we would otherwise have an inconsistent RequestBuilder.
74 + // We save the error and return it when calling [requestBuilder.Send].
75 + r.buildError = err
76 + return r
77 + }
78 +
79 + useEncodedAbsPaths := version.LT(encodedAbsolutePathVersion)
80 + r.body = files.NewMultiFileReader(d, false, useEncodedAbsPaths)
81
82 return r
83 }
@@ -97,6 +114,10 @@ func (r *requestBuilder) Header(name, value string) RequestBuilder {
114
115 // Send sends the request and return the response.
116 func (r *requestBuilder) Send(ctx context.Context) (*Response, error) {
117 + if r.buildError != nil {
118 + return nil, r.buildError
119 + }
120 +
121 r.shell.applyGlobal(r)
122
123 req := NewRequest(ctx, r.shell.url, r.command, r.args...)
client/rpc/unixfs.go
+7 -1
@@ -62,7 +62,13 @@ func (api *UnixfsAPI) Add(ctx context.Context, f files.Node, opts ...caopts.Unix
62 }
63
64 d := files.NewMapDirectory(map[string]files.Node{"": f}) // unwrapped on the other side
65 - req.Body(files.NewMultiFileReader(d, false))
65 +
66 + version, err := api.core().loadRemoteVersion()
67 + if err != nil {
68 + return nil, err
69 + }
70 + useEncodedAbsPaths := version.LT(encodedAbsolutePathVersion)
71 + req.Body(files.NewMultiFileReader(d, false, useEncodedAbsPaths))
72
73 var out addEvent
74 resp, err := req.Send(ctx)
cmd/ipfs/main.go
+57 -2
@@ -2,9 +2,12 @@
2 package main
3
4 import (
5 + "bytes"
6 "context"
7 + "encoding/json"
8 "errors"
9 "fmt"
10 + "io"
11 "net"
12 "net/http"
13 "os"
@@ -12,12 +15,14 @@ import (
15 "strings"
16 "time"
17
18 + "github.com/blang/semver/v4"
19 "github.com/google/uuid"
20 u "github.com/ipfs/boxo/util"
21 cmds "github.com/ipfs/go-ipfs-cmds"
22 "github.com/ipfs/go-ipfs-cmds/cli"
23 cmdhttp "github.com/ipfs/go-ipfs-cmds/http"
24 logging "github.com/ipfs/go-log"
25 + ipfs "github.com/ipfs/kubo"
26 "github.com/ipfs/kubo/cmd/ipfs/util"
27 oldcmds "github.com/ipfs/kubo/commands"
28 "github.com/ipfs/kubo/core"
@@ -224,6 +229,10 @@ func apiAddrOption(req *cmds.Request) (ma.Multiaddr, error) {
229 return ma.NewMultiaddr(apiAddrStr)
230 }
231
232 +// encodedAbsolutePathVersion is the version from which the absolute path header in
233 +// multipart requests is %-encoded. Before this version, its sent raw.
234 +var encodedAbsolutePathVersion = semver.MustParse("0.23.0-dev")
235 +
236 func makeExecutor(req *cmds.Request, env interface{}) (cmds.Executor, error) {
237 exe := tracingWrappedExecutor{cmds.NewExecutor(req.Root)}
238 cctx := env.(*oldcmds.Context)
@@ -315,9 +324,18 @@ func makeExecutor(req *cmds.Request, env interface{}) (cmds.Executor, error) {
324 default:
325 return nil, fmt.Errorf("unsupported API address: %s", apiAddr)
326 }
318 - opts = append(opts, cmdhttp.ClientWithHTTPClient(&http.Client{
327 +
328 + httpClient := &http.Client{
329 Transport: otelhttp.NewTransport(tpt),
320 - }))
330 + }
331 + opts = append(opts, cmdhttp.ClientWithHTTPClient(httpClient))
332 +
333 + // Fetch remove version, as some feature compatibility might change depending on it.
334 + remoteVersion, err := getRemoteVersion(tracingWrappedExecutor{cmdhttp.NewClient(host, opts...)})
335 + if err != nil {
336 + return nil, err
337 + }
338 + opts = append(opts, cmdhttp.ClientWithRawAbsPath(remoteVersion.LT(encodedAbsolutePathVersion)))
339
340 return tracingWrappedExecutor{cmdhttp.NewClient(host, opts...)}, nil
341 }
@@ -417,3 +435,40 @@ func resolveAddr(ctx context.Context, addr ma.Multiaddr) (ma.Multiaddr, error) {
435
436 return addrs[0], nil
437 }
438 +
439 +type nopWriter struct {
440 + io.Writer
441 +}
442 +
443 +func (nw nopWriter) Close() error {
444 + return nil
445 +}
446 +
447 +func getRemoteVersion(exe cmds.Executor) (*semver.Version, error) {
448 + ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(time.Second*30))
449 + defer cancel()
450 +
451 + req, err := cmds.NewRequest(ctx, []string{"version"}, nil, nil, nil, Root)
452 + if err != nil {
453 + return nil, err
454 + }
455 +
456 + var buf bytes.Buffer
457 + re, err := cmds.NewWriterResponseEmitter(nopWriter{&buf}, req)
458 + if err != nil {
459 + return nil, err
460 + }
461 +
462 + err = exe.Execute(req, re, nil)
463 + if err != nil {
464 + return nil, err
465 + }
466 +
467 + var out ipfs.VersionInfo
468 + dec := json.NewDecoder(&buf)
469 + if err := dec.Decode(&out); err != nil {
470 + return nil, err
471 + }
472 +
473 + return semver.New(out.Version)
474 +}
docs/changelogs/v0.23.md
+16
@@ -8,6 +8,7 @@
8 - [🔦 Highlights](#-highlights)
9 - [Mplex deprecation](#mplex-deprecation)
10 - [Gateway: meaningful CAR responses on Not Found errors](#gateway-meaningful-car-responses-on-not-found-errors)
11 + - [Binary characters in file names: no longer works with old clients and new Kubo servers](#binary-characters-in-file-names-no-longer-works-with-old-clients-and-new-kubo-servers)
12 - [📝 Changelog](#-changelog)
13 - [👨‍👩‍👧‍👦 Contributors](#-contributors)
14
@@ -43,6 +44,21 @@ the path does not exist, a CAR will be sent with a root of `bafkqaaa` (empty CID
44 This CAR will contain all blocks necessary to validate that the path does not
45 exist without having to trust the gateway.
46
47 +#### Binary characters in file names: no longer works with old clients and new Kubo servers
48 +
49 +In this version, we updated Kubo to support Go 1.20+. In Go 1.20, a regression
50 +regarding multipart headers was [introduced](https://github.com/golang/go/issues/60674).
51 +This only affects `ipfs add` when a file name has binary characters in its name.
52 +As a consequence, we had to update the encoding of the file name headers. This is
53 +the compatibility table:
54 +
55 +| | New Client | Old Client |
56 +|------------|------------|-------------|
57 +| New Server | ✅ | 🟡* |
58 +| Old Server | ✅ | ✅ |
59 +
60 +*Old clients can only send Unicode file paths to the server.
61 +
62 ### 📝 Changelog
63
64 ### 👨‍👩‍👧‍👦 Contributors
docs/examples/kubo-as-a-library/go.mod
+2 -2
@@ -7,7 +7,7 @@ go 1.20
7 replace github.com/ipfs/kubo => ./../../..
8
9 require (
10 - github.com/ipfs/boxo v0.11.1-0.20230818062747-654231b2bda3
10 + github.com/ipfs/boxo v0.12.0
11 github.com/ipfs/kubo v0.0.0-00010101000000-000000000000
12 github.com/libp2p/go-libp2p v0.29.2
13 github.com/multiformats/go-multiaddr v0.10.1
@@ -91,7 +91,7 @@ require (
91 github.com/ipfs/go-unixfsnode v1.7.1 // indirect
92 github.com/ipld/go-car/v2 v2.10.2-0.20230622090957-499d0c909d33 // indirect
93 github.com/ipld/go-codec-dagpb v1.6.0 // indirect
94 - github.com/ipld/go-ipld-prime v0.20.0 // indirect
94 + github.com/ipld/go-ipld-prime v0.21.0 // indirect
95 github.com/jackpal/go-nat-pmp v1.0.2 // indirect
96 github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect
97 github.com/jbenet/goprocess v0.1.4 // indirect
docs/examples/kubo-as-a-library/go.sum
+6 -6
@@ -159,7 +159,7 @@ github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJn
159 github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
160 github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
161 github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og=
162 -github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
162 +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
163 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
164 github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
165 github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
@@ -301,8 +301,8 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:
301 github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
302 github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
303 github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0=
304 -github.com/ipfs/boxo v0.11.1-0.20230818062747-654231b2bda3 h1:oiMqmivloEHtlCkS+8rCq1Pkz/rf6m3sC45lL4cnwBA=
305 -github.com/ipfs/boxo v0.11.1-0.20230818062747-654231b2bda3/go.mod h1:8IfDmp+FzFGcF4zjAgHMVPpwYw4AjN9ePEzDfkaYJ1w=
304 +github.com/ipfs/boxo v0.12.0 h1:AXHg/1ONZdRQHQLgG5JHsSC3XoE4DjCAMgK+asZvUcQ=
305 +github.com/ipfs/boxo v0.12.0/go.mod h1:xAnfiU6PtxWCnRqu7dcXQ10bB5/kvI1kXRotuGqGBhg=
306 github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA=
307 github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU=
308 github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY=
@@ -398,8 +398,8 @@ github.com/ipld/go-codec-dagpb v1.6.0 h1:9nYazfyu9B1p3NAgfVdpRco3Fs2nFC72DqVsMj6
398 github.com/ipld/go-codec-dagpb v1.6.0/go.mod h1:ANzFhfP2uMJxRBr8CE+WQWs5UsNa0pYtmKZ+agnUw9s=
399 github.com/ipld/go-ipld-prime v0.11.0/go.mod h1:+WIAkokurHmZ/KwzDOMUuoeJgaRQktHtEaLglS3ZeV8=
400 github.com/ipld/go-ipld-prime v0.14.1/go.mod h1:QcE4Y9n/ZZr8Ijg5bGPT0GqYWgZ1704nH0RDcQtgTP0=
401 -github.com/ipld/go-ipld-prime v0.20.0 h1:Ud3VwE9ClxpO2LkCYP7vWPc0Fo+dYdYzgxUJZ3uRG4g=
402 -github.com/ipld/go-ipld-prime v0.20.0/go.mod h1:PzqZ/ZR981eKbgdr3y2DJYeD/8bgMawdGVlJDE8kK+M=
401 +github.com/ipld/go-ipld-prime v0.21.0 h1:n4JmcpOlPDIxBcY037SVfpd1G+Sj1nKZah0m6QH9C2E=
402 +github.com/ipld/go-ipld-prime v0.21.0/go.mod h1:3RLqy//ERg/y5oShXXdx5YIp50cFGOanyMctpPjsvxQ=
403 github.com/ipld/go-ipld-prime/storage/bsadapter v0.0.0-20230102063945-1a409dc236dd h1:gMlw/MhNr2Wtp5RwGdsW23cs+yCuj9k2ON7i9MiJlRo=
404 github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
405 github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
@@ -737,7 +737,7 @@ github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMI
737 github.com/wangjia184/sortedset v0.0.0-20160527075905-f5d03557ba30/go.mod h1:YkocrP2K2tcw938x9gCOmT5G5eCD6jsTz0SZuyAqwIE=
738 github.com/warpfork/go-testmark v0.3.0/go.mod h1:jhEf8FVxd+F17juRubpmut64NEG6I2rgkUhlcqqXwE0=
739 github.com/warpfork/go-testmark v0.9.0/go.mod h1:jhEf8FVxd+F17juRubpmut64NEG6I2rgkUhlcqqXwE0=
740 -github.com/warpfork/go-testmark v0.11.0 h1:J6LnV8KpceDvo7spaNU4+DauH2n1x+6RaO2rJrmpQ9U=
740 +github.com/warpfork/go-testmark v0.12.1 h1:rMgCpJfwy1sJ50x0M0NgyphxYYPMOODIJHhsXyEHU0s=
741 github.com/warpfork/go-wish v0.0.0-20180510122957-5ad1f5abf436/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw=
742 github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw=
743 github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0 h1:GDDkbFiaK8jsSDJfjId/PEGEShv6ugrt4kYsC5UIDaQ=
go.mod
+4 -5
@@ -15,7 +15,7 @@ require (
15 github.com/fsnotify/fsnotify v1.6.0
16 github.com/google/uuid v1.3.0
17 github.com/hashicorp/go-multierror v1.1.1
18 - github.com/ipfs/boxo v0.11.1-0.20230818062747-654231b2bda3
18 + github.com/ipfs/boxo v0.12.0
19 github.com/ipfs/go-block-format v0.1.2
20 github.com/ipfs/go-cid v0.4.1
21 github.com/ipfs/go-cidutil v0.1.0
@@ -27,7 +27,7 @@ require (
27 github.com/ipfs/go-ds-measure v0.2.0
28 github.com/ipfs/go-fs-lock v0.0.7
29 github.com/ipfs/go-graphsync v0.14.4
30 - github.com/ipfs/go-ipfs-cmds v0.9.0
30 + github.com/ipfs/go-ipfs-cmds v0.10.0
31 github.com/ipfs/go-ipld-format v0.5.0
32 github.com/ipfs/go-ipld-git v0.1.1
33 github.com/ipfs/go-ipld-legacy v0.2.1
@@ -39,7 +39,7 @@ require (
39 github.com/ipld/go-car v0.5.0
40 github.com/ipld/go-car/v2 v2.10.2-0.20230622090957-499d0c909d33
41 github.com/ipld/go-codec-dagpb v1.6.0
42 - github.com/ipld/go-ipld-prime v0.20.0
42 + github.com/ipld/go-ipld-prime v0.21.0
43 github.com/jbenet/go-random v0.0.0-20190219211222-123a90aedc0c
44 github.com/jbenet/go-temp-err-catcher v0.1.0
45 github.com/jbenet/goprocess v0.1.4
@@ -92,7 +92,6 @@ require (
92 require (
93 github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 // indirect
94 github.com/Jorropo/jsync v1.0.1 // indirect
95 - github.com/Kubuxu/go-os-helper v0.0.1 // indirect
95 github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect
96 github.com/alexbrainman/goissue34681 v0.0.0-20191006012335-3fc7a47baff5 // indirect
97 github.com/beorn7/perks v1.0.1 // indirect
@@ -166,7 +165,7 @@ require (
165 github.com/libp2p/go-yamux/v4 v4.0.1 // indirect
166 github.com/libp2p/zeroconf/v2 v2.2.0 // indirect
167 github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect
169 - github.com/mattn/go-colorable v0.1.4 // indirect
168 + github.com/mattn/go-colorable v0.1.6 // indirect
169 github.com/mattn/go-isatty v0.0.19 // indirect
170 github.com/mattn/go-runewidth v0.0.4 // indirect
171 github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
go.sum
+11 -11
@@ -49,8 +49,6 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
49 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
50 github.com/Jorropo/jsync v1.0.1 h1:6HgRolFZnsdfzRUj+ImB9og1JYOxQoReSywkHOGSaUU=
51 github.com/Jorropo/jsync v1.0.1/go.mod h1:jCOZj3vrBCri3bSU3ErUYvevKlnbssrXeCivybS5ABQ=
52 -github.com/Kubuxu/go-os-helper v0.0.1 h1:EJiD2VUQyh5A9hWJLmc6iWg6yIcJ7jpBcwC8GMGXfDk=
53 -github.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETFUpAzWW2ep1Y=
52 github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
53 github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
54 github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
@@ -179,7 +177,7 @@ github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJn
177 github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
178 github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
179 github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og=
182 -github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
180 +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
181 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
182 github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
183 github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
@@ -337,8 +335,8 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:
335 github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
336 github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
337 github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0=
340 -github.com/ipfs/boxo v0.11.1-0.20230818062747-654231b2bda3 h1:oiMqmivloEHtlCkS+8rCq1Pkz/rf6m3sC45lL4cnwBA=
341 -github.com/ipfs/boxo v0.11.1-0.20230818062747-654231b2bda3/go.mod h1:8IfDmp+FzFGcF4zjAgHMVPpwYw4AjN9ePEzDfkaYJ1w=
338 +github.com/ipfs/boxo v0.12.0 h1:AXHg/1ONZdRQHQLgG5JHsSC3XoE4DjCAMgK+asZvUcQ=
339 +github.com/ipfs/boxo v0.12.0/go.mod h1:xAnfiU6PtxWCnRqu7dcXQ10bB5/kvI1kXRotuGqGBhg=
340 github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA=
341 github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU=
342 github.com/ipfs/go-bitswap v0.11.0 h1:j1WVvhDX1yhG32NTC9xfxnqycqYIlhzEzLXG/cU1HyQ=
@@ -383,8 +381,8 @@ github.com/ipfs/go-ipfs-blockstore v1.3.0 h1:m2EXaWgwTzAfsmt5UdJ7Is6l4gJcaM/A12X
381 github.com/ipfs/go-ipfs-blockstore v1.3.0/go.mod h1:KgtZyc9fq+P2xJUiCAzbRdhhqJHvsw8u2Dlqy2MyRTE=
382 github.com/ipfs/go-ipfs-blocksutil v0.0.1 h1:Eh/H4pc1hsvhzsQoMEP3Bke/aW5P5rVM1IWFJMcGIPQ=
383 github.com/ipfs/go-ipfs-chunker v0.0.5 h1:ojCf7HV/m+uS2vhUGWcogIIxiO5ubl5O57Q7NapWLY8=
386 -github.com/ipfs/go-ipfs-cmds v0.9.0 h1:K0VcXg1l1k6aY6sHnoxYcyimyJQbcV1ueXuWgThmK9Q=
387 -github.com/ipfs/go-ipfs-cmds v0.9.0/go.mod h1:SBFHK8WNwC416QWH9Vz1Ql42SSMAOqKpaHUMBu3jpLo=
384 +github.com/ipfs/go-ipfs-cmds v0.10.0 h1:ZB4+RgYaH4UARfJY0uLKl5UXgApqnRjKbuCiJVcErYk=
385 +github.com/ipfs/go-ipfs-cmds v0.10.0/go.mod h1:sX5d7jkCft9XLPnkgEfXY0z2UBOB5g6fh/obBS0enJE=
386 github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw=
387 github.com/ipfs/go-ipfs-delay v0.0.1 h1:r/UXYyRcddO6thwOnhiznIAiSvxMECGgtv35Xs1IeRQ=
388 github.com/ipfs/go-ipfs-delay v0.0.1/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw=
@@ -446,8 +444,8 @@ github.com/ipld/go-codec-dagpb v1.6.0 h1:9nYazfyu9B1p3NAgfVdpRco3Fs2nFC72DqVsMj6
444 github.com/ipld/go-codec-dagpb v1.6.0/go.mod h1:ANzFhfP2uMJxRBr8CE+WQWs5UsNa0pYtmKZ+agnUw9s=
445 github.com/ipld/go-ipld-prime v0.11.0/go.mod h1:+WIAkokurHmZ/KwzDOMUuoeJgaRQktHtEaLglS3ZeV8=
446 github.com/ipld/go-ipld-prime v0.14.1/go.mod h1:QcE4Y9n/ZZr8Ijg5bGPT0GqYWgZ1704nH0RDcQtgTP0=
449 -github.com/ipld/go-ipld-prime v0.20.0 h1:Ud3VwE9ClxpO2LkCYP7vWPc0Fo+dYdYzgxUJZ3uRG4g=
450 -github.com/ipld/go-ipld-prime v0.20.0/go.mod h1:PzqZ/ZR981eKbgdr3y2DJYeD/8bgMawdGVlJDE8kK+M=
447 +github.com/ipld/go-ipld-prime v0.21.0 h1:n4JmcpOlPDIxBcY037SVfpd1G+Sj1nKZah0m6QH9C2E=
448 +github.com/ipld/go-ipld-prime v0.21.0/go.mod h1:3RLqy//ERg/y5oShXXdx5YIp50cFGOanyMctpPjsvxQ=
449 github.com/ipld/go-ipld-prime/storage/bsadapter v0.0.0-20230102063945-1a409dc236dd h1:gMlw/MhNr2Wtp5RwGdsW23cs+yCuj9k2ON7i9MiJlRo=
450 github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
451 github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
@@ -572,12 +570,14 @@ github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8
570 github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU=
571 github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
572 github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
575 -github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
573 github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
574 +github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE=
575 +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
576 github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
577 github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
578 github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
579 github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
580 +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
581 github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
582 github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
583 github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
@@ -859,7 +859,7 @@ github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMI
859 github.com/wangjia184/sortedset v0.0.0-20160527075905-f5d03557ba30/go.mod h1:YkocrP2K2tcw938x9gCOmT5G5eCD6jsTz0SZuyAqwIE=
860 github.com/warpfork/go-testmark v0.3.0/go.mod h1:jhEf8FVxd+F17juRubpmut64NEG6I2rgkUhlcqqXwE0=
861 github.com/warpfork/go-testmark v0.9.0/go.mod h1:jhEf8FVxd+F17juRubpmut64NEG6I2rgkUhlcqqXwE0=
862 -github.com/warpfork/go-testmark v0.11.0 h1:J6LnV8KpceDvo7spaNU4+DauH2n1x+6RaO2rJrmpQ9U=
862 +github.com/warpfork/go-testmark v0.12.1 h1:rMgCpJfwy1sJ50x0M0NgyphxYYPMOODIJHhsXyEHU0s=
863 github.com/warpfork/go-wish v0.0.0-20180510122957-5ad1f5abf436/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw=
864 github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw=
865 github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0 h1:GDDkbFiaK8jsSDJfjId/PEGEShv6ugrt4kYsC5UIDaQ=
test/cli/content_routing_http_test.go
+10
@@ -9,12 +9,14 @@ import (
9 "testing"
10 "time"
11
12 + "github.com/ipfs/boxo/ipns"
13 "github.com/ipfs/boxo/routing/http/server"
14 "github.com/ipfs/boxo/routing/http/types"
15 "github.com/ipfs/boxo/routing/http/types/iter"
16 "github.com/ipfs/go-cid"
17 "github.com/ipfs/kubo/test/cli/harness"
18 "github.com/ipfs/kubo/test/cli/testutils"
19 + "github.com/libp2p/go-libp2p/core/routing"
20 "github.com/stretchr/testify/assert"
21 )
22
@@ -45,6 +47,14 @@ func (r *fakeHTTPContentRouter) Provide(ctx context.Context, req *server.WritePr
47 return nil, nil
48 }
49
50 +func (r *fakeHTTPContentRouter) FindIPNSRecord(ctx context.Context, name ipns.Name) (*ipns.Record, error) {
51 + return nil, routing.ErrNotSupported
52 +}
53 +
54 +func (r *fakeHTTPContentRouter) ProvideIPNSRecord(ctx context.Context, name ipns.Name, rec *ipns.Record) error {
55 + return routing.ErrNotSupported
56 +}
57 +
58 func (r *fakeHTTPContentRouter) numFindProvidersCalls() int {
59 r.m.Lock()
60 defer r.m.Unlock()
test/dependencies/go.mod
+2 -2
@@ -7,7 +7,7 @@ replace github.com/ipfs/kubo => ../../
7 require (
8 github.com/Kubuxu/gocovmerge v0.0.0-20161216165753-7ecaa51963cd
9 github.com/golangci/golangci-lint v1.54.1
10 - github.com/ipfs/boxo v0.11.1-0.20230818062747-654231b2bda3
10 + github.com/ipfs/boxo v0.12.0
11 github.com/ipfs/go-cid v0.4.1
12 github.com/ipfs/go-cidutil v0.1.0
13 github.com/ipfs/go-datastore v0.6.0
@@ -16,7 +16,7 @@ require (
16 github.com/ipfs/hang-fds v0.1.0
17 github.com/ipfs/iptb v1.4.0
18 github.com/ipfs/iptb-plugins v0.5.0
19 - github.com/ipld/go-ipld-prime v0.20.0
19 + github.com/ipld/go-ipld-prime v0.21.0
20 github.com/jbenet/go-random v0.0.0-20190219211222-123a90aedc0c
21 github.com/jbenet/go-random-files v0.0.0-20190219210431-31b3f20ebded
22 github.com/libp2p/go-libp2p v0.29.2
test/dependencies/go.sum
+6 -6
@@ -188,7 +188,7 @@ github.com/flynn/noise v1.0.0 h1:DlTHqmzmvcEiKj+4RYo/imoswx/4r6iBlCMfVtrMXpQ=
188 github.com/flynn/noise v1.0.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag=
189 github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk=
190 github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
191 -github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
191 +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
192 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
193 github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
194 github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
@@ -396,8 +396,8 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2
396 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
397 github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
398 github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0=
399 -github.com/ipfs/boxo v0.11.1-0.20230818062747-654231b2bda3 h1:oiMqmivloEHtlCkS+8rCq1Pkz/rf6m3sC45lL4cnwBA=
400 -github.com/ipfs/boxo v0.11.1-0.20230818062747-654231b2bda3/go.mod h1:8IfDmp+FzFGcF4zjAgHMVPpwYw4AjN9ePEzDfkaYJ1w=
399 +github.com/ipfs/boxo v0.12.0 h1:AXHg/1ONZdRQHQLgG5JHsSC3XoE4DjCAMgK+asZvUcQ=
400 +github.com/ipfs/boxo v0.12.0/go.mod h1:xAnfiU6PtxWCnRqu7dcXQ10bB5/kvI1kXRotuGqGBhg=
401 github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA=
402 github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU=
403 github.com/ipfs/go-block-format v0.1.2 h1:GAjkfhVx1f4YTODS6Esrj1wt2HhrtwTnhEr+DyPUaJo=
@@ -462,8 +462,8 @@ github.com/ipld/go-car v0.5.0 h1:kcCEa3CvYMs0iE5BzD5sV7O2EwMiCIp3uF8tA6APQT8=
462 github.com/ipld/go-car/v2 v2.10.2-0.20230622090957-499d0c909d33 h1:0OZwzSYWIuiKEOXd/2vm5cMcEmmGLFn+1h6lHELCm3s=
463 github.com/ipld/go-codec-dagpb v1.6.0 h1:9nYazfyu9B1p3NAgfVdpRco3Fs2nFC72DqVsMj6rOcc=
464 github.com/ipld/go-codec-dagpb v1.6.0/go.mod h1:ANzFhfP2uMJxRBr8CE+WQWs5UsNa0pYtmKZ+agnUw9s=
465 -github.com/ipld/go-ipld-prime v0.20.0 h1:Ud3VwE9ClxpO2LkCYP7vWPc0Fo+dYdYzgxUJZ3uRG4g=
466 -github.com/ipld/go-ipld-prime v0.20.0/go.mod h1:PzqZ/ZR981eKbgdr3y2DJYeD/8bgMawdGVlJDE8kK+M=
465 +github.com/ipld/go-ipld-prime v0.21.0 h1:n4JmcpOlPDIxBcY037SVfpd1G+Sj1nKZah0m6QH9C2E=
466 +github.com/ipld/go-ipld-prime v0.21.0/go.mod h1:3RLqy//ERg/y5oShXXdx5YIp50cFGOanyMctpPjsvxQ=
467 github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
468 github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
469 github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA=
@@ -885,7 +885,7 @@ github.com/uudashr/gocognit v1.0.7 h1:e9aFXgKgUJrQ5+bs61zBigmj7bFJ/5cC6HmMahVzuD
885 github.com/uudashr/gocognit v1.0.7/go.mod h1:nAIUuVBnYU7pcninia3BHOvQkpQCeO76Uscky5BOwcY=
886 github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
887 github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
888 -github.com/warpfork/go-testmark v0.11.0 h1:J6LnV8KpceDvo7spaNU4+DauH2n1x+6RaO2rJrmpQ9U=
888 +github.com/warpfork/go-testmark v0.12.1 h1:rMgCpJfwy1sJ50x0M0NgyphxYYPMOODIJHhsXyEHU0s=
889 github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0 h1:GDDkbFiaK8jsSDJfjId/PEGEShv6ugrt4kYsC5UIDaQ=
890 github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw=
891 github.com/whyrusleeping/cbor v0.0.0-20171005072247-63513f603b11 h1:5HZfQkwe0mIfyDmc1Em5GqlNRzcdtlv4HTNmdpt7XH0=
test/sharness/t0235-cli-request.sh
+16 -1
@@ -31,7 +31,22 @@ test_expect_success "can make http request against nc server" '
31 ipfs cat /ipfs/Qmabcdef --api /ip4/127.0.0.1/tcp/5005 &
32 IPFSPID=$!
33
34 - # handle request
34 + # handle request for /api/v0/version
35 + while read line; do
36 + if [[ "$line" == "$(echo -e "\r")" ]]; then
37 + break
38 + fi
39 + echo "$line"
40 + done <&7 >nc_out &&
41 +
42 + echo -e "HTTP/1.1 200 OK\r" >&6 &&
43 + echo -e "Content-Type: application/json\r" >&6 &&
44 + echo -e "Content-Length: 21\r" >&6 &&
45 + echo -e "\r" >&6 &&
46 + echo -e "{\"Version\":\"0.23.0\"}\r" >&6 &&
47 + echo -e "\r" >&6 &&
48 +
49 + # handle request for /api/v0/cat
50 while read line; do
51 if [[ "$line" == "$(echo -e "\r")" ]]; then
52 break
test/sharness/t0236-cli-api-dns-resolve.sh
+16 -1
@@ -30,7 +30,22 @@ test_expect_success "can make http request against dns resolved nc server" '
30 ipfs cat /ipfs/Qmabcdef --api /dns4/localhost/tcp/5006 &
31 IPFSPID=$!
32
33 - # handle request
33 + # handle request for /api/v0/version
34 + while read line; do
35 + if [[ "$line" == "$(echo -e "\r")" ]]; then
36 + break
37 + fi
38 + echo "$line"
39 + done <&7 >nc_out &&
40 +
41 + echo -e "HTTP/1.1 200 OK\r" >&6 &&
42 + echo -e "Content-Type: application/json\r" >&6 &&
43 + echo -e "Content-Length: 21\r" >&6 &&
44 + echo -e "\r" >&6 &&
45 + echo -e "{\"Version\":\"0.23.0\"}\r" >&6 &&
46 + echo -e "\r" >&6 &&
47 +
48 + # handle request for /api/v0/cat
49 while read line; do
50 if [[ "$line" == "$(echo -e "\r")" ]]; then
51 break