Skip to content

Commit 9b8e63b

Browse files
hacdiaslidel
andauthored
fix(routing/v1): add newline in NDJSON responses (#300)
Co-authored-by: Marcin Rataj <[email protected]>
1 parent 5e94b9d commit 9b8e63b

File tree

2 files changed

+72
-0
lines changed

2 files changed

+72
-0
lines changed

routing/http/server/server.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,13 @@ func (s *server) findProvidersNDJSON(w http.ResponseWriter, provIter iter.Result
254254
logger.Warn("FindProviders ndjson write error", "Error", err)
255255
return
256256
}
257+
258+
_, err = w.Write([]byte{'\n'})
259+
if err != nil {
260+
logger.Warn("FindProviders ndjson write error", "Error", err)
261+
return
262+
}
263+
257264
if f, ok := w.(http.Flusher); ok {
258265
f.Flush()
259266
}

routing/http/server/server_test.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package server
22

33
import (
44
"context"
5+
"io"
56
"net/http"
67
"net/http/httptest"
78
"testing"
@@ -10,6 +11,7 @@ import (
1011
"github.com/ipfs/boxo/routing/http/types"
1112
"github.com/ipfs/boxo/routing/http/types/iter"
1213
"github.com/ipfs/go-cid"
14+
"github.com/libp2p/go-libp2p/core/peer"
1315
"github.com/stretchr/testify/mock"
1416
"github.com/stretchr/testify/require"
1517
)
@@ -48,6 +50,69 @@ func TestHeaders(t *testing.T) {
4850
require.Equal(t, "text/plain; charset=utf-8", header)
4951
}
5052

53+
func TestResponse(t *testing.T) {
54+
pidStr := "12D3KooWM8sovaEGU1bmiWGWAzvs47DEcXKZZTuJnpQyVTkRs2Vn"
55+
pid2Str := "12D3KooWM8sovaEGU1bmiWGWAzvs47DEcXKZZTuJnpQyVTkRs2Vz"
56+
cidStr := "bafkreifjjcie6lypi6ny7amxnfftagclbuxndqonfipmb64f2km2devei4"
57+
58+
pid, err := peer.Decode(pidStr)
59+
require.NoError(t, err)
60+
pid2, err := peer.Decode(pid2Str)
61+
require.NoError(t, err)
62+
63+
cid, err := cid.Decode(cidStr)
64+
require.NoError(t, err)
65+
66+
runTest := func(t *testing.T, contentType string, expected string) {
67+
t.Parallel()
68+
69+
results := iter.FromSlice([]iter.Result[types.ProviderResponse]{
70+
{Val: &types.ReadBitswapProviderRecord{
71+
Protocol: "transport-bitswap",
72+
Schema: types.SchemaBitswap,
73+
ID: &pid,
74+
Addrs: []types.Multiaddr{},
75+
}},
76+
{Val: &types.ReadBitswapProviderRecord{
77+
Protocol: "transport-bitswap",
78+
Schema: types.SchemaBitswap,
79+
ID: &pid2,
80+
Addrs: []types.Multiaddr{},
81+
}}},
82+
)
83+
84+
router := &mockContentRouter{}
85+
server := httptest.NewServer(Handler(router))
86+
t.Cleanup(server.Close)
87+
serverAddr := "http://" + server.Listener.Addr().String()
88+
router.On("FindProviders", mock.Anything, cid).Return(results, nil)
89+
urlStr := serverAddr + ProvidePath + cidStr
90+
91+
req, err := http.NewRequest(http.MethodGet, urlStr, nil)
92+
require.NoError(t, err)
93+
req.Header.Set("Accept", contentType)
94+
95+
resp, err := http.DefaultClient.Do(req)
96+
require.NoError(t, err)
97+
require.Equal(t, 200, resp.StatusCode)
98+
header := resp.Header.Get("Content-Type")
99+
require.Equal(t, contentType, header)
100+
101+
body, err := io.ReadAll(resp.Body)
102+
require.NoError(t, err)
103+
104+
require.Equal(t, string(body), expected)
105+
}
106+
107+
t.Run("JSON Response", func(t *testing.T) {
108+
runTest(t, mediaTypeJSON, `{"Providers":[{"Protocol":"transport-bitswap","Schema":"bitswap","ID":"12D3KooWM8sovaEGU1bmiWGWAzvs47DEcXKZZTuJnpQyVTkRs2Vn","Addrs":[]},{"Protocol":"transport-bitswap","Schema":"bitswap","ID":"12D3KooWM8sovaEGU1bmiWGWAzvs47DEcXKZZTuJnpQyVTkRs2Vz","Addrs":[]}]}`)
109+
})
110+
111+
t.Run("NDJSON Response", func(t *testing.T) {
112+
runTest(t, mediaTypeNDJSON, `{"Protocol":"transport-bitswap","Schema":"bitswap","ID":"12D3KooWM8sovaEGU1bmiWGWAzvs47DEcXKZZTuJnpQyVTkRs2Vn","Addrs":[]}`+"\n"+`{"Protocol":"transport-bitswap","Schema":"bitswap","ID":"12D3KooWM8sovaEGU1bmiWGWAzvs47DEcXKZZTuJnpQyVTkRs2Vz","Addrs":[]}`+"\n")
113+
})
114+
}
115+
51116
type mockContentRouter struct{ mock.Mock }
52117

53118
func (m *mockContentRouter) FindProviders(ctx context.Context, key cid.Cid) (iter.ResultIter[types.ProviderResponse], error) {

0 commit comments

Comments
 (0)