Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
M
mybee
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
vicotor
mybee
Commits
307b154f
Unverified
Commit
307b154f
authored
Feb 02, 2021
by
acud
Committed by
GitHub
Feb 02, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
api: split chunk and soc api (#1143)
parent
42c12ede
Changes
12
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
426 additions
and
127 deletions
+426
-127
io.go
cmd/internal/file/io.go
+1
-2
api_test.go
pkg/api/api_test.go
+18
-0
chunk.go
pkg/api/chunk.go
+32
-22
chunk_test.go
pkg/api/chunk_test.go
+13
-59
export_test.go
pkg/api/export_test.go
+2
-0
gatewaymode_test.go
pkg/api/gatewaymode_test.go
+1
-1
pin_chunks_test.go
pkg/api/pin_chunks_test.go
+9
-22
router.go
pkg/api/router.go
+11
-1
soc.go
pkg/api/soc.go
+134
-0
soc_test.go
pkg/api/soc_test.go
+165
-0
tag_test.go
pkg/api/tag_test.go
+7
-13
soc.go
pkg/soc/soc.go
+33
-7
No files found.
cmd/internal/file/io.go
View file @
307b154f
...
...
@@ -137,9 +137,8 @@ func NewApiStore(host string, port int, ssl bool) PutGetter {
// Put implements storage.Putter.
func
(
a
*
ApiStore
)
Put
(
ctx
context
.
Context
,
mode
storage
.
ModePut
,
chs
...
swarm
.
Chunk
)
(
exist
[]
bool
,
err
error
)
{
for
_
,
ch
:=
range
chs
{
addr
:=
ch
.
Address
()
.
String
()
buf
:=
bytes
.
NewReader
(
ch
.
Data
())
url
:=
strings
.
Join
([]
string
{
a
.
baseUrl
,
addr
},
"/"
)
url
:=
strings
.
Join
([]
string
{
a
.
baseUrl
},
"/"
)
res
,
err
:=
a
.
Client
.
Post
(
url
,
"application/octet-stream"
,
buf
)
if
err
!=
nil
{
return
nil
,
err
...
...
pkg/api/api_test.go
View file @
307b154f
...
...
@@ -6,6 +6,7 @@ package api_test
import
(
"errors"
"io"
"io/ioutil"
"net/http"
"net/http/httptest"
...
...
@@ -88,6 +89,23 @@ func newTestServer(t *testing.T, o testServerOptions) (*http.Client, *websocket.
return
httpClient
,
conn
,
ts
.
Listener
.
Addr
()
.
String
()
}
func
request
(
t
*
testing
.
T
,
client
*
http
.
Client
,
method
,
resource
string
,
body
io
.
Reader
,
responseCode
int
)
*
http
.
Response
{
t
.
Helper
()
req
,
err
:=
http
.
NewRequest
(
method
,
resource
,
body
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
resp
,
err
:=
client
.
Do
(
req
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
resp
.
StatusCode
!=
responseCode
{
t
.
Fatalf
(
"got response status %s, want %v %s"
,
resp
.
Status
,
responseCode
,
http
.
StatusText
(
responseCode
))
}
return
resp
}
func
TestParseName
(
t
*
testing
.
T
)
{
const
bzzHash
=
"89c17d0d8018a19057314aa035e61c9d23c47581a61dd3a79a7839692c617e4d"
...
...
pkg/api/chunk.go
View file @
307b154f
...
...
@@ -12,9 +12,8 @@ import (
"io/ioutil"
"net/http"
"github.com/ethersphere/bee/pkg/
content
"
"github.com/ethersphere/bee/pkg/
bmtpool
"
"github.com/ethersphere/bee/pkg/netstore"
"github.com/ethersphere/bee/pkg/soc"
"github.com/ethersphere/bee/pkg/jsonhttp"
"github.com/ethersphere/bee/pkg/sctx"
...
...
@@ -24,20 +23,15 @@ import (
"github.com/gorilla/mux"
)
func
(
s
*
server
)
chunkUploadHandler
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
nameOrHex
:=
mux
.
Vars
(
r
)[
"addr"
]
address
,
err
:=
s
.
resolveNameOrAddress
(
nameOrHex
)
if
err
!=
nil
{
s
.
Logger
.
Debugf
(
"chunk upload: parse chunk address %s: %v"
,
nameOrHex
,
err
)
s
.
Logger
.
Error
(
"chunk upload: parse chunk address"
)
jsonhttp
.
BadRequest
(
w
,
"invalid chunk address"
)
return
}
type
chunkAddressResponse
struct
{
Reference
swarm
.
Address
`json:"reference"`
}
func
(
s
*
server
)
chunkUploadHandler
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
var
(
tag
*
tags
.
Tag
ctx
=
r
.
Context
()
err
error
)
if
h
:=
r
.
Header
.
Get
(
SwarmTagUidHeader
);
h
!=
""
{
...
...
@@ -68,22 +62,38 @@ func (s *server) chunkUploadHandler(w http.ResponseWriter, r *http.Request) {
if
jsonhttp
.
HandleBodyReadError
(
err
,
w
)
{
return
}
s
.
Logger
.
Debugf
(
"chunk upload: read chunk data error: %v
, addr %s"
,
err
,
address
)
s
.
Logger
.
Debugf
(
"chunk upload: read chunk data error: %v
"
,
err
)
s
.
Logger
.
Error
(
"chunk upload: read chunk data error"
)
jsonhttp
.
InternalServerError
(
w
,
"cannot read chunk data"
)
return
}
chunk
:=
swarm
.
NewChunk
(
address
,
data
)
if
!
content
.
Valid
(
chunk
)
{
if
!
soc
.
Valid
(
chunk
)
{
s
.
Logger
.
Debugf
(
"chunk upload: invalid chunk: %s"
,
address
)
s
.
Logger
.
Error
(
"chunk upload: invalid chunk"
)
jsonhttp
.
BadRequest
(
w
,
nil
)
return
}
if
len
(
data
)
<
swarm
.
SpanSize
{
s
.
Logger
.
Debug
(
"chunk upload: not enough data"
)
s
.
Logger
.
Error
(
"chunk upload: data length"
)
jsonhttp
.
BadRequest
(
w
,
"data length"
)
return
}
hasher
:=
bmtpool
.
Get
()
defer
bmtpool
.
Put
(
hasher
)
err
=
hasher
.
SetSpanBytes
(
data
[
:
swarm
.
SpanSize
])
if
err
!=
nil
{
s
.
Logger
.
Debugf
(
"chunk upload: set span: %v"
,
err
)
s
.
Logger
.
Error
(
"chunk upload: span error"
)
jsonhttp
.
InternalServerError
(
w
,
"span error"
)
return
}
_
,
err
=
hasher
.
Write
(
data
[
swarm
.
SpanSize
:
])
if
err
!=
nil
{
return
}
address
:=
swarm
.
NewAddress
(
hasher
.
Sum
(
nil
))
chunk
:=
swarm
.
NewChunk
(
address
,
data
)
seen
,
err
:=
s
.
Storer
.
Put
(
ctx
,
requestModePut
(
r
),
chunk
)
if
err
!=
nil
{
s
.
Logger
.
Debugf
(
"chunk upload: chunk write error: %v, addr %s"
,
err
,
address
)
...
...
@@ -113,7 +123,7 @@ func (s *server) chunkUploadHandler(w http.ResponseWriter, r *http.Request) {
}
w
.
Header
()
.
Set
(
"Access-Control-Expose-Headers"
,
SwarmTagUidHeader
)
jsonhttp
.
OK
(
w
,
nil
)
jsonhttp
.
OK
(
w
,
chunkAddressResponse
{
Reference
:
address
}
)
}
func
(
s
*
server
)
chunkGetHandler
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
...
...
pkg/api/chunk_test.go
View file @
307b154f
...
...
@@ -6,7 +6,6 @@ package api_test
import
(
"bytes"
"io"
"io/ioutil"
"net/http"
"testing"
...
...
@@ -31,9 +30,9 @@ func TestChunkUploadDownload(t *testing.T) {
var
(
targets
=
"0x222"
resource
=
func
(
addr
swarm
.
Address
)
string
{
return
"/chunks/"
+
addr
.
String
()
}
chunksEndpoint
=
"/chunks"
chunksResource
=
func
(
a
swarm
.
Address
)
string
{
return
"/chunks/"
+
a
.
String
()
}
resourceTargets
=
func
(
addr
swarm
.
Address
)
string
{
return
"/chunks/"
+
addr
.
String
()
+
"?targets="
+
targets
}
someHash
=
swarm
.
MustParseHexAddress
(
"aabbcc"
)
chunk
=
testingc
.
GenerateTestRandomChunk
()
mockStatestore
=
statestore
.
NewStateStore
()
logger
=
logging
.
New
(
ioutil
.
Discard
,
0
)
...
...
@@ -45,42 +44,23 @@ func TestChunkUploadDownload(t *testing.T) {
})
)
t
.
Run
(
"invalid chunk"
,
func
(
t
*
testing
.
T
)
{
jsonhttptest
.
Request
(
t
,
client
,
http
.
MethodPost
,
resource
(
someHash
),
http
.
StatusBadRequest
,
jsonhttptest
.
WithRequestBody
(
bytes
.
NewReader
(
chunk
.
Data
())),
jsonhttptest
.
WithExpectedJSONResponse
(
jsonhttp
.
StatusResponse
{
Message
:
http
.
StatusText
(
http
.
StatusBadRequest
),
Code
:
http
.
StatusBadRequest
,
}),
)
// make sure chunk is not retrievable
_
=
request
(
t
,
client
,
http
.
MethodGet
,
resource
(
someHash
),
nil
,
http
.
StatusNotFound
)
})
t
.
Run
(
"empty chunk"
,
func
(
t
*
testing
.
T
)
{
jsonhttptest
.
Request
(
t
,
client
,
http
.
MethodPost
,
resource
(
someHash
)
,
http
.
StatusBadRequest
,
jsonhttptest
.
Request
(
t
,
client
,
http
.
MethodPost
,
chunksEndpoint
,
http
.
StatusBadRequest
,
jsonhttptest
.
WithExpectedJSONResponse
(
jsonhttp
.
StatusResponse
{
Message
:
http
.
StatusText
(
http
.
StatusBadRequest
)
,
Message
:
"data length"
,
Code
:
http
.
StatusBadRequest
,
}),
)
// make sure chunk is not retrievable
_
=
request
(
t
,
client
,
http
.
MethodGet
,
resource
(
someHash
),
nil
,
http
.
StatusNotFound
)
})
t
.
Run
(
"ok"
,
func
(
t
*
testing
.
T
)
{
jsonhttptest
.
Request
(
t
,
client
,
http
.
MethodPost
,
resource
(
chunk
.
Address
())
,
http
.
StatusOK
,
jsonhttptest
.
Request
(
t
,
client
,
http
.
MethodPost
,
chunksEndpoint
,
http
.
StatusOK
,
jsonhttptest
.
WithRequestBody
(
bytes
.
NewReader
(
chunk
.
Data
())),
jsonhttptest
.
WithExpectedJSONResponse
(
jsonhttp
.
StatusResponse
{
Message
:
http
.
StatusText
(
http
.
StatusOK
),
Code
:
http
.
StatusOK
,
}),
jsonhttptest
.
WithExpectedJSONResponse
(
api
.
ChunkAddressResponse
{
Reference
:
chunk
.
Address
()}),
)
// try to fetch the same chunk
resp
:=
request
(
t
,
client
,
http
.
MethodGet
,
r
esource
(
chunk
.
Address
()),
nil
,
http
.
StatusOK
)
resp
:=
request
(
t
,
client
,
http
.
MethodGet
,
chunksR
esource
(
chunk
.
Address
()),
nil
,
http
.
StatusOK
)
data
,
err
:=
ioutil
.
ReadAll
(
resp
.
Body
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
...
...
@@ -92,12 +72,9 @@ func TestChunkUploadDownload(t *testing.T) {
})
t
.
Run
(
"pin-invalid-value"
,
func
(
t
*
testing
.
T
)
{
jsonhttptest
.
Request
(
t
,
client
,
http
.
MethodPost
,
resource
(
chunk
.
Address
())
,
http
.
StatusOK
,
jsonhttptest
.
Request
(
t
,
client
,
http
.
MethodPost
,
chunksEndpoint
,
http
.
StatusOK
,
jsonhttptest
.
WithRequestBody
(
bytes
.
NewReader
(
chunk
.
Data
())),
jsonhttptest
.
WithExpectedJSONResponse
(
jsonhttp
.
StatusResponse
{
Message
:
http
.
StatusText
(
http
.
StatusOK
),
Code
:
http
.
StatusOK
,
}),
jsonhttptest
.
WithExpectedJSONResponse
(
api
.
ChunkAddressResponse
{
Reference
:
chunk
.
Address
()}),
jsonhttptest
.
WithRequestHeader
(
api
.
SwarmPinHeader
,
"invalid-pin"
),
)
...
...
@@ -107,12 +84,9 @@ func TestChunkUploadDownload(t *testing.T) {
}
})
t
.
Run
(
"pin-header-missing"
,
func
(
t
*
testing
.
T
)
{
jsonhttptest
.
Request
(
t
,
client
,
http
.
MethodPost
,
resource
(
chunk
.
Address
())
,
http
.
StatusOK
,
jsonhttptest
.
Request
(
t
,
client
,
http
.
MethodPost
,
chunksEndpoint
,
http
.
StatusOK
,
jsonhttptest
.
WithRequestBody
(
bytes
.
NewReader
(
chunk
.
Data
())),
jsonhttptest
.
WithExpectedJSONResponse
(
jsonhttp
.
StatusResponse
{
Message
:
http
.
StatusText
(
http
.
StatusOK
),
Code
:
http
.
StatusOK
,
}),
jsonhttptest
.
WithExpectedJSONResponse
(
api
.
ChunkAddressResponse
{
Reference
:
chunk
.
Address
()}),
)
// Also check if the chunk is NOT pinned
...
...
@@ -121,12 +95,9 @@ func TestChunkUploadDownload(t *testing.T) {
}
})
t
.
Run
(
"pin-ok"
,
func
(
t
*
testing
.
T
)
{
jsonhttptest
.
Request
(
t
,
client
,
http
.
MethodPost
,
resource
(
chunk
.
Address
())
,
http
.
StatusOK
,
jsonhttptest
.
Request
(
t
,
client
,
http
.
MethodPost
,
chunksEndpoint
,
http
.
StatusOK
,
jsonhttptest
.
WithRequestBody
(
bytes
.
NewReader
(
chunk
.
Data
())),
jsonhttptest
.
WithExpectedJSONResponse
(
jsonhttp
.
StatusResponse
{
Message
:
http
.
StatusText
(
http
.
StatusOK
),
Code
:
http
.
StatusOK
,
}),
jsonhttptest
.
WithExpectedJSONResponse
(
api
.
ChunkAddressResponse
{
Reference
:
chunk
.
Address
()}),
jsonhttptest
.
WithRequestHeader
(
api
.
SwarmPinHeader
,
"True"
),
)
...
...
@@ -145,20 +116,3 @@ func TestChunkUploadDownload(t *testing.T) {
}
})
}
func
request
(
t
*
testing
.
T
,
client
*
http
.
Client
,
method
,
resource
string
,
body
io
.
Reader
,
responseCode
int
)
*
http
.
Response
{
t
.
Helper
()
req
,
err
:=
http
.
NewRequest
(
method
,
resource
,
body
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
resp
,
err
:=
client
.
Do
(
req
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
resp
.
StatusCode
!=
responseCode
{
t
.
Fatalf
(
"got response status %s, want %v %s"
,
resp
.
Status
,
responseCode
,
http
.
StatusText
(
responseCode
))
}
return
resp
}
pkg/api/export_test.go
View file @
307b154f
...
...
@@ -10,6 +10,8 @@ type Server = server
type
(
BytesPostResponse
=
bytesPostResponse
ChunkAddressResponse
=
chunkAddressResponse
SocPostResponse
=
socPostResponse
FileUploadResponse
=
fileUploadResponse
TagResponse
=
tagResponse
TagRequest
=
tagRequest
...
...
pkg/api/gatewaymode_test.go
View file @
307b154f
...
...
@@ -65,7 +65,7 @@ func TestGatewayMode(t *testing.T) {
})
// should work without pinning
jsonhttptest
.
Request
(
t
,
client
,
http
.
MethodPost
,
"/chunks
/"
+
chunk
.
Address
()
.
String
()
,
http
.
StatusOK
,
jsonhttptest
.
Request
(
t
,
client
,
http
.
MethodPost
,
"/chunks
"
,
http
.
StatusOK
,
jsonhttptest
.
WithRequestBody
(
bytes
.
NewReader
(
chunk
.
Data
())),
)
...
...
pkg/api/pin_chunks_test.go
View file @
307b154f
...
...
@@ -18,7 +18,6 @@ import (
"github.com/ethersphere/bee/pkg/jsonhttp/jsonhttptest"
"github.com/ethersphere/bee/pkg/storage/mock"
testingc
"github.com/ethersphere/bee/pkg/storage/testing"
"github.com/ethersphere/bee/pkg/swarm"
"github.com/ethersphere/bee/pkg/tags"
)
...
...
@@ -28,7 +27,7 @@ import (
// it assumes some state of the DB before another case is run.
func
TestPinChunkHandler
(
t
*
testing
.
T
)
{
var
(
resource
=
func
(
addr
swarm
.
Address
)
string
{
return
"/chunks/"
+
addr
.
String
()
}
chunksEndpoint
=
"/chunks"
chunk
=
testingc
.
GenerateTestRandomChunk
()
mockStorer
=
mock
.
NewStorer
()
mockStatestore
=
statestore
.
NewStateStore
()
...
...
@@ -74,12 +73,9 @@ func TestPinChunkHandler(t *testing.T) {
// unpin on a chunk which is not pinned
t
.
Run
(
"unpin-while-not-pinned"
,
func
(
t
*
testing
.
T
)
{
// Post a chunk
jsonhttptest
.
Request
(
t
,
client
,
http
.
MethodPost
,
resource
(
chunk
.
Address
())
,
http
.
StatusOK
,
jsonhttptest
.
Request
(
t
,
client
,
http
.
MethodPost
,
chunksEndpoint
,
http
.
StatusOK
,
jsonhttptest
.
WithRequestBody
(
bytes
.
NewReader
(
chunk
.
Data
())),
jsonhttptest
.
WithExpectedJSONResponse
(
jsonhttp
.
StatusResponse
{
Message
:
http
.
StatusText
(
http
.
StatusOK
),
Code
:
http
.
StatusOK
,
}),
jsonhttptest
.
WithExpectedJSONResponse
(
api
.
ChunkAddressResponse
{
Reference
:
chunk
.
Address
()}),
)
jsonhttptest
.
Request
(
t
,
client
,
http
.
MethodDelete
,
"/pin/chunks/"
+
chunk
.
Address
()
.
String
(),
http
.
StatusBadRequest
,
...
...
@@ -93,12 +89,9 @@ func TestPinChunkHandler(t *testing.T) {
// pin a existing chunk first time
t
.
Run
(
"pin-chunk-1"
,
func
(
t
*
testing
.
T
)
{
// Post a chunk
jsonhttptest
.
Request
(
t
,
client
,
http
.
MethodPost
,
resource
(
chunk
.
Address
())
,
http
.
StatusOK
,
jsonhttptest
.
Request
(
t
,
client
,
http
.
MethodPost
,
chunksEndpoint
,
http
.
StatusOK
,
jsonhttptest
.
WithRequestBody
(
bytes
.
NewReader
(
chunk
.
Data
())),
jsonhttptest
.
WithExpectedJSONResponse
(
jsonhttp
.
StatusResponse
{
Message
:
http
.
StatusText
(
http
.
StatusOK
),
Code
:
http
.
StatusOK
,
}),
jsonhttptest
.
WithExpectedJSONResponse
(
api
.
ChunkAddressResponse
{
Reference
:
chunk
.
Address
()}),
)
jsonhttptest
.
Request
(
t
,
client
,
http
.
MethodPost
,
"/pin/chunks/"
+
chunk
.
Address
()
.
String
(),
http
.
StatusOK
,
...
...
@@ -175,12 +168,9 @@ func TestPinChunkHandler(t *testing.T) {
// Add 2 chunks, pin it and check if they show up in the list
t
.
Run
(
"list-chunks"
,
func
(
t
*
testing
.
T
)
{
// Post a chunk
jsonhttptest
.
Request
(
t
,
client
,
http
.
MethodPost
,
resource
(
chunk
.
Address
())
,
http
.
StatusOK
,
jsonhttptest
.
Request
(
t
,
client
,
http
.
MethodPost
,
chunksEndpoint
,
http
.
StatusOK
,
jsonhttptest
.
WithRequestBody
(
bytes
.
NewReader
(
chunk
.
Data
())),
jsonhttptest
.
WithExpectedJSONResponse
(
jsonhttp
.
StatusResponse
{
Message
:
http
.
StatusText
(
http
.
StatusOK
),
Code
:
http
.
StatusOK
,
}),
jsonhttptest
.
WithExpectedJSONResponse
(
api
.
ChunkAddressResponse
{
Reference
:
chunk
.
Address
()}),
)
jsonhttptest
.
Request
(
t
,
client
,
http
.
MethodPost
,
"/pin/chunks/"
+
chunk
.
Address
()
.
String
(),
http
.
StatusOK
,
...
...
@@ -192,12 +182,9 @@ func TestPinChunkHandler(t *testing.T) {
// post another chunk
chunk2
:=
testingc
.
GenerateTestRandomChunk
()
jsonhttptest
.
Request
(
t
,
client
,
http
.
MethodPost
,
resource
(
chunk2
.
Address
())
,
http
.
StatusOK
,
jsonhttptest
.
Request
(
t
,
client
,
http
.
MethodPost
,
chunksEndpoint
,
http
.
StatusOK
,
jsonhttptest
.
WithRequestBody
(
bytes
.
NewReader
(
chunk2
.
Data
())),
jsonhttptest
.
WithExpectedJSONResponse
(
jsonhttp
.
StatusResponse
{
Message
:
http
.
StatusText
(
http
.
StatusOK
),
Code
:
http
.
StatusOK
,
}),
jsonhttptest
.
WithExpectedJSONResponse
(
api
.
ChunkAddressResponse
{
Reference
:
chunk2
.
Address
()}),
)
jsonhttptest
.
Request
(
t
,
client
,
http
.
MethodPost
,
"/pin/chunks/"
+
chunk2
.
Address
()
.
String
(),
http
.
StatusOK
,
jsonhttptest
.
WithExpectedJSONResponse
(
jsonhttp
.
StatusResponse
{
...
...
pkg/api/router.go
View file @
307b154f
...
...
@@ -71,11 +71,21 @@ func (s *server) setupRouting() {
),
})
handle
(
router
,
"/chunks"
,
jsonhttp
.
MethodHandler
{
"POST"
:
web
.
ChainHandlers
(
jsonhttp
.
NewMaxBodyBytesHandler
(
swarm
.
ChunkWithSpanSize
),
web
.
FinalHandlerFunc
(
s
.
chunkUploadHandler
),
),
})
handle
(
router
,
"/chunks/{addr}"
,
jsonhttp
.
MethodHandler
{
"GET"
:
http
.
HandlerFunc
(
s
.
chunkGetHandler
),
})
handle
(
router
,
"/soc/{owner}/{id}"
,
jsonhttp
.
MethodHandler
{
"POST"
:
web
.
ChainHandlers
(
jsonhttp
.
NewMaxBodyBytesHandler
(
swarm
.
ChunkWithSpanSize
),
web
.
FinalHandlerFunc
(
s
.
chunk
UploadHandler
),
web
.
FinalHandlerFunc
(
s
.
soc
UploadHandler
),
),
})
...
...
pkg/api/soc.go
0 → 100644
View file @
307b154f
// Copyright 2021 The Swarm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package
api
import
(
"encoding/hex"
"errors"
"io/ioutil"
"net/http"
"github.com/ethersphere/bee/pkg/bmtpool"
"github.com/ethersphere/bee/pkg/jsonhttp"
"github.com/ethersphere/bee/pkg/soc"
"github.com/ethersphere/bee/pkg/swarm"
"github.com/gorilla/mux"
)
var
(
errBadRequestParams
=
errors
.
New
(
"owner, id or span is not well formed"
)
)
type
socPostResponse
struct
{
Reference
swarm
.
Address
`json:"reference"`
}
func
(
s
*
server
)
socUploadHandler
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
owner
,
err
:=
hex
.
DecodeString
(
mux
.
Vars
(
r
)[
"owner"
])
if
err
!=
nil
{
s
.
Logger
.
Debugf
(
"soc upload: bad owner: %v"
,
err
)
s
.
Logger
.
Error
(
"soc upload: %v"
,
errBadRequestParams
)
jsonhttp
.
BadRequest
(
w
,
"bad owner"
)
return
}
id
,
err
:=
hex
.
DecodeString
(
mux
.
Vars
(
r
)[
"id"
])
if
err
!=
nil
{
s
.
Logger
.
Debugf
(
"soc upload: bad id: %v"
,
err
)
s
.
Logger
.
Error
(
"soc upload: %v"
,
errBadRequestParams
)
jsonhttp
.
BadRequest
(
w
,
"bad id"
)
return
}
sigStr
:=
r
.
URL
.
Query
()
.
Get
(
"sig"
)
if
sigStr
==
""
{
s
.
Logger
.
Debugf
(
"soc upload: empty signature"
)
s
.
Logger
.
Error
(
"soc upload: empty signature"
)
jsonhttp
.
BadRequest
(
w
,
"empty signature"
)
return
}
sig
,
err
:=
hex
.
DecodeString
(
sigStr
)
if
err
!=
nil
{
s
.
Logger
.
Debugf
(
"soc upload: bad signature: %v"
,
err
)
s
.
Logger
.
Error
(
"soc upload: bad signature"
)
jsonhttp
.
BadRequest
(
w
,
"bad signature"
)
return
}
data
,
err
:=
ioutil
.
ReadAll
(
r
.
Body
)
if
err
!=
nil
{
if
jsonhttp
.
HandleBodyReadError
(
err
,
w
)
{
return
}
s
.
Logger
.
Debugf
(
"soc upload: read chunk data error: %v"
,
err
)
s
.
Logger
.
Error
(
"soc upload: read chunk data error"
)
jsonhttp
.
InternalServerError
(
w
,
"cannot read chunk data"
)
return
}
if
len
(
data
)
<
swarm
.
SpanSize
{
s
.
Logger
.
Debugf
(
"soc upload: chunk data too short"
)
s
.
Logger
.
Error
(
"soc upload: %v"
,
errBadRequestParams
)
jsonhttp
.
BadRequest
(
w
,
"short chunk data"
)
return
}
if
len
(
data
)
>
swarm
.
ChunkSize
+
swarm
.
SpanSize
{
s
.
Logger
.
Debugf
(
"soc upload: chunk data exceeds %d bytes"
,
swarm
.
ChunkSize
+
swarm
.
SpanSize
)
s
.
Logger
.
Error
(
"soc upload: chunk data error"
)
jsonhttp
.
RequestEntityTooLarge
(
w
,
"payload too large"
)
return
}
ch
,
err
:=
chunk
(
data
)
if
err
!=
nil
{
s
.
Logger
.
Debugf
(
"soc upload: create content addressed chunk: %v"
,
err
)
s
.
Logger
.
Error
(
"soc upload: chunk data error"
)
jsonhttp
.
BadRequest
(
w
,
"chunk data error"
)
return
}
chunk
,
err
:=
soc
.
NewSignedChunk
(
id
,
ch
,
owner
,
sig
)
if
err
!=
nil
{
s
.
Logger
.
Debugf
(
"soc upload: read chunk data error: %v"
,
err
)
s
.
Logger
.
Error
(
"soc upload: read chunk data error"
)
jsonhttp
.
InternalServerError
(
w
,
"cannot read chunk data"
)
return
}
if
!
soc
.
Valid
(
chunk
)
{
s
.
Logger
.
Debugf
(
"soc upload: invalid chunk: %v"
,
err
)
s
.
Logger
.
Error
(
"soc upload: invalid chunk"
)
jsonhttp
.
Unauthorized
(
w
,
"invalid chunk"
)
return
}
ctx
:=
r
.
Context
()
_
,
err
=
s
.
Storer
.
Put
(
ctx
,
requestModePut
(
r
),
chunk
)
if
err
!=
nil
{
s
.
Logger
.
Debugf
(
"soc upload: chunk write error: %v"
,
err
)
s
.
Logger
.
Error
(
"soc upload: chunk write error"
)
jsonhttp
.
BadRequest
(
w
,
"chunk write error"
)
return
}
jsonhttp
.
Created
(
w
,
chunkAddressResponse
{
Reference
:
chunk
.
Address
()})
}
func
chunk
(
data
[]
byte
)
(
swarm
.
Chunk
,
error
)
{
hasher
:=
bmtpool
.
Get
()
defer
bmtpool
.
Put
(
hasher
)
err
:=
hasher
.
SetSpanBytes
(
data
[
:
swarm
.
SpanSize
])
if
err
!=
nil
{
return
nil
,
err
}
_
,
err
=
hasher
.
Write
(
data
[
swarm
.
SpanSize
:
])
if
err
!=
nil
{
return
nil
,
err
}
return
swarm
.
NewChunk
(
swarm
.
NewAddress
(
hasher
.
Sum
(
nil
)),
data
),
nil
}
pkg/api/soc_test.go
0 → 100644
View file @
307b154f
// Copyright 2021 The Swarm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package
api_test
import
(
"bytes"
"encoding/binary"
"encoding/hex"
"fmt"
"io/ioutil"
"net/http"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethersphere/bee/pkg/api"
"github.com/ethersphere/bee/pkg/crypto"
"github.com/ethersphere/bee/pkg/jsonhttp"
"github.com/ethersphere/bee/pkg/jsonhttp/jsonhttptest"
"github.com/ethersphere/bee/pkg/logging"
"github.com/ethersphere/bee/pkg/soc"
statestore
"github.com/ethersphere/bee/pkg/statestore/mock"
"github.com/ethersphere/bee/pkg/storage/mock"
testingc
"github.com/ethersphere/bee/pkg/storage/testing"
"github.com/ethersphere/bee/pkg/swarm"
"github.com/ethersphere/bee/pkg/tags"
)
func
TestSoc
(
t
*
testing
.
T
)
{
var
(
socResource
=
func
(
owner
,
id
,
sig
string
)
string
{
return
fmt
.
Sprintf
(
"/soc/%s/%s?sig=%s"
,
owner
,
id
,
sig
)
}
_
=
testingc
.
GenerateTestRandomChunk
()
mockStatestore
=
statestore
.
NewStateStore
()
logger
=
logging
.
New
(
ioutil
.
Discard
,
0
)
tag
=
tags
.
NewTags
(
mockStatestore
,
logger
)
_
=
common
.
HexToAddress
(
"8d3766440f0d7b949a5e32995d09619a7f86e632"
)
mockStorer
=
mock
.
NewStorer
()
client
,
_
,
_
=
newTestServer
(
t
,
testServerOptions
{
Storer
:
mockStorer
,
Tags
:
tag
,
})
)
t
.
Run
(
"cmpty data"
,
func
(
t
*
testing
.
T
)
{
jsonhttptest
.
Request
(
t
,
client
,
http
.
MethodPost
,
socResource
(
"8d3766440f0d7b949a5e32995d09619a7f86e632"
,
"bb"
,
"cc"
),
http
.
StatusBadRequest
,
jsonhttptest
.
WithExpectedJSONResponse
(
jsonhttp
.
StatusResponse
{
Message
:
"short chunk data"
,
Code
:
http
.
StatusBadRequest
,
}),
)
})
t
.
Run
(
"malformed id"
,
func
(
t
*
testing
.
T
)
{
jsonhttptest
.
Request
(
t
,
client
,
http
.
MethodPost
,
socResource
(
"8d3766440f0d7b949a5e32995d09619a7f86e632"
,
"bbzz"
,
"cc"
),
http
.
StatusBadRequest
,
jsonhttptest
.
WithExpectedJSONResponse
(
jsonhttp
.
StatusResponse
{
Message
:
"bad id"
,
Code
:
http
.
StatusBadRequest
,
}),
)
})
t
.
Run
(
"malformed owner"
,
func
(
t
*
testing
.
T
)
{
jsonhttptest
.
Request
(
t
,
client
,
http
.
MethodPost
,
socResource
(
"xyz"
,
"aa"
,
"bb"
),
http
.
StatusBadRequest
,
jsonhttptest
.
WithExpectedJSONResponse
(
jsonhttp
.
StatusResponse
{
Message
:
"bad owner"
,
Code
:
http
.
StatusBadRequest
,
}),
)
})
t
.
Run
(
"malformed signature"
,
func
(
t
*
testing
.
T
)
{
jsonhttptest
.
Request
(
t
,
client
,
http
.
MethodPost
,
socResource
(
"8d3766440f0d7b949a5e32995d09619a7f86e632"
,
"aa"
,
"badsig"
),
http
.
StatusBadRequest
,
jsonhttptest
.
WithExpectedJSONResponse
(
jsonhttp
.
StatusResponse
{
Message
:
"bad signature"
,
Code
:
http
.
StatusBadRequest
,
}),
)
})
t
.
Run
(
"signature invalid"
,
func
(
t
*
testing
.
T
)
{
s
,
owner
,
payload
:=
mockSoc
(
t
)
id
:=
make
([]
byte
,
soc
.
IdSize
)
// modify the sign
sig
:=
s
.
Signature
()
sig
[
12
]
=
0x98
sig
[
10
]
=
0x12
jsonhttptest
.
Request
(
t
,
client
,
http
.
MethodPost
,
socResource
(
hex
.
EncodeToString
(
owner
),
hex
.
EncodeToString
(
id
),
hex
.
EncodeToString
(
sig
)),
http
.
StatusUnauthorized
,
jsonhttptest
.
WithRequestBody
(
bytes
.
NewReader
(
payload
)),
jsonhttptest
.
WithExpectedJSONResponse
(
jsonhttp
.
StatusResponse
{
Message
:
"invalid chunk"
,
Code
:
http
.
StatusUnauthorized
,
}),
)
})
t
.
Run
(
"ok"
,
func
(
t
*
testing
.
T
)
{
s
,
owner
,
payload
:=
mockSoc
(
t
)
id
:=
make
([]
byte
,
soc
.
IdSize
)
sig
:=
s
.
Signature
()
addr
,
err
:=
s
.
Address
()
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
jsonhttptest
.
Request
(
t
,
client
,
http
.
MethodPost
,
socResource
(
hex
.
EncodeToString
(
owner
),
hex
.
EncodeToString
(
id
),
hex
.
EncodeToString
(
sig
)),
http
.
StatusCreated
,
jsonhttptest
.
WithRequestBody
(
bytes
.
NewReader
(
payload
)),
jsonhttptest
.
WithExpectedJSONResponse
(
api
.
SocPostResponse
{
Reference
:
addr
,
}),
)
// try to fetch the same chunk
rsrc
:=
fmt
.
Sprintf
(
"/chunks/"
+
addr
.
String
())
resp
:=
request
(
t
,
client
,
http
.
MethodGet
,
rsrc
,
nil
,
http
.
StatusOK
)
data
,
err
:=
ioutil
.
ReadAll
(
resp
.
Body
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
ch
,
err
:=
s
.
ToChunk
()
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
!
bytes
.
Equal
(
ch
.
Data
(),
data
)
{
t
.
Fatal
(
"data retrieved doesnt match uploaded content"
)
}
})
}
// returns a valid, mocked SOC
func
mockSoc
(
t
*
testing
.
T
)
(
*
soc
.
Soc
,
[]
byte
,
[]
byte
)
{
// create a valid soc
id
:=
make
([]
byte
,
soc
.
IdSize
)
privKey
,
err
:=
crypto
.
GenerateSecp256k1Key
()
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
signer
:=
crypto
.
NewDefaultSigner
(
privKey
)
bmtHashOfFoo
:=
"2387e8e7d8a48c2a9339c97c1dc3461a9a7aa07e994c5cb8b38fd7c1b3e6ea48"
address
:=
swarm
.
MustParseHexAddress
(
bmtHashOfFoo
)
foo
:=
"foo"
fooLength
:=
len
(
foo
)
fooBytes
:=
make
([]
byte
,
8
+
fooLength
)
binary
.
LittleEndian
.
PutUint64
(
fooBytes
,
uint64
(
fooLength
))
copy
(
fooBytes
[
8
:
],
foo
)
ch
:=
swarm
.
NewChunk
(
address
,
fooBytes
)
sch
:=
soc
.
New
(
id
,
ch
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
err
=
sch
.
AddSigner
(
signer
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
_
,
_
=
sch
.
ToChunk
()
return
sch
,
sch
.
OwnerAddress
(),
ch
.
Data
()
}
pkg/api/tag_test.go
View file @
307b154f
...
...
@@ -38,7 +38,7 @@ func TestTags(t *testing.T) {
filesResource
=
"/files"
dirResource
=
"/dirs"
bytesResource
=
"/bytes"
chunksResource
=
func
(
addr
swarm
.
Address
)
string
{
return
"/chunks/"
+
addr
.
String
()
}
chunksResource
=
"/chunks"
tagsResource
=
"/tags"
chunk
=
testingc
.
GenerateTestRandomChunk
()
someTagName
=
"file.jpg"
...
...
@@ -78,7 +78,7 @@ func TestTags(t *testing.T) {
})
t
.
Run
(
"create tag with invalid id"
,
func
(
t
*
testing
.
T
)
{
jsonhttptest
.
Request
(
t
,
client
,
http
.
MethodPost
,
chunksResource
(
chunk
.
Address
())
,
http
.
StatusBadRequest
,
jsonhttptest
.
Request
(
t
,
client
,
http
.
MethodPost
,
chunksResource
,
http
.
StatusBadRequest
,
jsonhttptest
.
WithRequestBody
(
bytes
.
NewReader
(
chunk
.
Data
())),
jsonhttptest
.
WithExpectedJSONResponse
(
jsonhttp
.
StatusResponse
{
Message
:
"cannot get tag"
,
...
...
@@ -120,20 +120,14 @@ func TestTags(t *testing.T) {
t
.
Fatalf
(
"sent tag name %s does not match received tag name %s"
,
someTagName
,
tr
.
Name
)
}
_
=
jsonhttptest
.
Request
(
t
,
client
,
http
.
MethodPost
,
chunksResource
(
chunk
.
Address
())
,
http
.
StatusOK
,
_
=
jsonhttptest
.
Request
(
t
,
client
,
http
.
MethodPost
,
chunksResource
,
http
.
StatusOK
,
jsonhttptest
.
WithRequestBody
(
bytes
.
NewReader
(
chunk
.
Data
())),
jsonhttptest
.
WithExpectedJSONResponse
(
jsonhttp
.
StatusResponse
{
Message
:
http
.
StatusText
(
http
.
StatusOK
),
Code
:
http
.
StatusOK
,
}),
jsonhttptest
.
WithExpectedJSONResponse
(
api
.
ChunkAddressResponse
{
Reference
:
chunk
.
Address
()}),
)
rcvdHeaders
:=
jsonhttptest
.
Request
(
t
,
client
,
http
.
MethodPost
,
chunksResource
(
chunk
.
Address
())
,
http
.
StatusOK
,
rcvdHeaders
:=
jsonhttptest
.
Request
(
t
,
client
,
http
.
MethodPost
,
chunksResource
,
http
.
StatusOK
,
jsonhttptest
.
WithRequestBody
(
bytes
.
NewReader
(
chunk
.
Data
())),
jsonhttptest
.
WithExpectedJSONResponse
(
jsonhttp
.
StatusResponse
{
Message
:
http
.
StatusText
(
http
.
StatusOK
),
Code
:
http
.
StatusOK
,
}),
jsonhttptest
.
WithExpectedJSONResponse
(
api
.
ChunkAddressResponse
{
Reference
:
chunk
.
Address
()}),
jsonhttptest
.
WithRequestHeader
(
api
.
SwarmTagUidHeader
,
strconv
.
FormatUint
(
uint64
(
tr
.
Uid
),
10
)),
)
...
...
@@ -218,7 +212,7 @@ func TestTags(t *testing.T) {
addr
:=
test
.
RandomAddress
()
// upload content with tag
jsonhttptest
.
Request
(
t
,
client
,
http
.
MethodPost
,
chunksResource
(
chunk
.
Address
())
,
http
.
StatusOK
,
jsonhttptest
.
Request
(
t
,
client
,
http
.
MethodPost
,
chunksResource
,
http
.
StatusOK
,
jsonhttptest
.
WithRequestBody
(
bytes
.
NewReader
(
chunk
.
Data
())),
jsonhttptest
.
WithRequestHeader
(
api
.
SwarmTagUidHeader
,
fmt
.
Sprint
(
tagId
)),
)
...
...
pkg/soc/soc.go
View file @
307b154f
...
...
@@ -58,6 +58,25 @@ func NewChunk(id Id, ch swarm.Chunk, signer crypto.Signer) (swarm.Chunk, error)
return
s
.
ToChunk
()
}
// NewChunk is a convenience function to create a single-owner chunk ready to be sent
// on the network.
func
NewSignedChunk
(
id
Id
,
ch
swarm
.
Chunk
,
owner
,
sig
[]
byte
)
(
swarm
.
Chunk
,
error
)
{
s
:=
New
(
id
,
ch
)
s
.
signature
=
sig
o
,
err
:=
NewOwner
(
owner
)
if
err
!=
nil
{
return
nil
,
err
}
s
.
owner
=
o
// create chunk
socAddress
,
err
:=
s
.
Address
()
if
err
!=
nil
{
return
nil
,
err
}
return
swarm
.
NewChunk
(
socAddress
,
s
.
toBytes
()),
nil
}
// New creates a new Soc representation from arbitrary soc id and
// a content-addressed chunk.
//
...
...
@@ -109,6 +128,10 @@ func (s *Soc) Address() (swarm.Address, error) {
return
CreateAddress
(
s
.
id
,
s
.
owner
)
}
func
(
s
*
Soc
)
Signature
()
[]
byte
{
return
s
.
signature
}
// FromChunk recreates an Soc representation from swarm.Chunk data.
func
FromChunk
(
sch
swarm
.
Chunk
)
(
*
Soc
,
error
)
{
chunkData
:=
sch
.
Data
()
...
...
@@ -174,19 +197,22 @@ func (s *Soc) ToChunk() (swarm.Chunk, error) {
if
err
!=
nil
{
return
nil
,
err
}
// prepare the payload
buf
:=
bytes
.
NewBuffer
(
nil
)
buf
.
Write
(
s
.
id
)
buf
.
Write
(
signature
)
buf
.
Write
(
s
.
Chunk
.
Data
())
s
.
signature
=
signature
// create chunk
socAddress
,
err
:=
s
.
Address
()
if
err
!=
nil
{
return
nil
,
err
}
return
swarm
.
NewChunk
(
socAddress
,
buf
.
Bytes
()),
nil
return
swarm
.
NewChunk
(
socAddress
,
s
.
toBytes
()),
nil
}
func
(
s
*
Soc
)
toBytes
()
[]
byte
{
buf
:=
bytes
.
NewBuffer
(
nil
)
buf
.
Write
(
s
.
id
)
buf
.
Write
(
s
.
signature
)
buf
.
Write
(
s
.
Chunk
.
Data
())
return
buf
.
Bytes
()
}
// toSignDigest creates a digest suitable for signing to represent the soc.
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment