swarm/api: Add raw form to api+server WIP

This commit is contained in:
lash 2018-01-19 18:28:10 +01:00
parent 81ec1f9694
commit 1bf4f4a37f
6 changed files with 105 additions and 50 deletions

View file

@ -46,9 +46,9 @@ on top of the dpa
it is the public interface of the dpa which is included in the ethereum stack it is the public interface of the dpa which is included in the ethereum stack
*/ */
type Api struct { type Api struct {
resource *storage.ResourceHandler
dpa *storage.DPA dpa *storage.DPA
dns Resolver dns Resolver
resource *storage.ResourceHandler
} }
//the api constructor initialises //the api constructor initialises
@ -365,7 +365,7 @@ func (self *Api) BuildDirectoryTree(mhash string, nameresolver bool) (key storag
} }
// Look up mutable resource updates at specific periods and versions // Look up mutable resource updates at specific periods and versions
func (self *Api) DbLookup(name string, period uint32, version uint32) (io.ReadSeeker, error) { func (self *Api) DbLookup(key storage.Key, name string, period uint32, version uint32) (io.ReadSeeker, error) {
var err error var err error
if version != 0 { if version != 0 {
if period == 0 { if period == 0 {
@ -375,16 +375,20 @@ func (self *Api) DbLookup(name string, period uint32, version uint32) (io.ReadSe
} }
period = self.resource.BlockToPeriod(name, currentblocknumber) period = self.resource.BlockToPeriod(name, currentblocknumber)
} }
_, err = self.resource.LookupVersion(name, period, version, true) _, err = self.resource.LookupVersionByName(name, period, version, true)
} else if period != 0 { } else if period != 0 {
_, err = self.resource.LookupHistorical(name, period, true) _, err = self.resource.LookupHistoricalByName(name, period, true)
} else { } else {
_, err = self.resource.LookupLatest(name, true) _, err = self.resource.LookupLatestByName(name, true)
} }
if err != nil { if err != nil {
return nil, err return nil, err
} }
return bytes.NewReader(self.resource.GetData(name)), nil data, err := self.resource.GetData(name)
if err != nil {
return nil, err
}
return bytes.NewReader(data), nil
} }
func (self *Api) DbCreate(name string, frequency uint64) (err error) { func (self *Api) DbCreate(name string, frequency uint64) (err error) {
@ -394,5 +398,11 @@ func (self *Api) DbCreate(name string, frequency uint64) (err error) {
func (self *Api) DbUpdate(name string, data []byte) (storage.Key, uint32, uint32, error) { func (self *Api) DbUpdate(name string, data []byte) (storage.Key, uint32, uint32, error) {
key, err := self.resource.Update(name, data) key, err := self.resource.Update(name, data)
return key, self.resource.GetLastPeriod(name), self.resource.GetVersion(name), err period, _ := self.resource.GetLastPeriod(name)
version, _ := self.resource.GetVersion(name)
return key, period, version, err
}
func (self *Api) DbHashSize() int {
return self.resource.HashSize()
} }

View file

@ -332,36 +332,42 @@ func (s *Server) HandleGetDb(w http.ResponseWriter, r *Request) {
s.Error(w, r, fmt.Errorf("error resolving %s: %s", r.uri.Addr, err)) s.Error(w, r, fmt.Errorf("error resolving %s: %s", r.uri.Addr, err))
return return
} }
_ = key
var params []string var params []string
if len(r.uri.Path) > 0 { if len(r.uri.Path) > 0 {
params = strings.Split(r.uri.Path, "/") params = strings.Split(r.uri.Path, "/")
} }
var period uint64
var version uint64
var data io.ReadSeeker
switch len(params) { switch len(params) {
case 0: case 0:
data, err := s.api.DbLookup(r.uri.Addr) data, err = s.api.DbLookup(key, r.uri.Addr, 0, 0)
break break
case 2: case 2:
strconv.ParseUint(params[1], 10, 32) version, err = strconv.ParseUint(params[1], 10, 32)
if err != nil {
break
}
case 1: case 1:
strconv.ParseUint(params[0], 10, 32) period, err = strconv.ParseUint(params[0], 10, 32)
if err != nil {
break
}
data, err = s.api.DbLookup(key, r.uri.Addr, uint32(period), uint32(version))
break break
default: default:
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
err = "params 0-2" err = fmt.Errorf("params 0-2")
} }
if err != nil { if err != nil {
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
return return
} }
wrappedData := wrapDbContent(data, s.uri.Scheme) if !r.uri.DbRaw() {
http.ServeContent(w, &r.Request, "", time.Now(), data)
} }
http.ServeContent(w, &r.Request, "", time.Now(), data)
func wrapDbContent(data io.Reader, scheme *string) io.Reader {
} }
// HandleGet handles a GET request to // HandleGet handles a GET request to
@ -705,6 +711,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
s.HandleDelete(w, req) s.HandleDelete(w, req)
case "GET": case "GET":
if uri.Db() || uri.DbRaw() {
s.HandleGetDb(w, req)
return
}
if uri.Raw() || uri.Hash() || uri.DeprecatedRaw() { if uri.Raw() || uri.Hash() || uri.DeprecatedRaw() {
s.HandleGet(w, req) s.HandleGet(w, req)
return return
@ -720,11 +732,6 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return return
} }
if uri.Db() {
s.HandleGetDb(w, req)
return
}
s.HandleGetFile(w, req) s.HandleGetFile(w, req)
default: default:

View file

@ -18,6 +18,7 @@ package http_test
import ( import (
"bytes" "bytes"
"crypto/rand"
"errors" "errors"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
@ -43,7 +44,14 @@ func TestBzzGetDb(t *testing.T) {
srv := testutil.NewTestSwarmServer(t) srv := testutil.NewTestSwarmServer(t)
defer srv.Close() defer srv.Close()
url := srv.URL + "/bzz-db:/foo/42" keybytes := make([]byte, common.HashLength) // nearest we get to source of info
_, err := rand.Read(keybytes)
if err != nil {
fmt.Printf("err: %v\n", err)
return
}
url := fmt.Sprintf("%s/bzz-db:/%s/42", srv.URL, fmt.Sprintf("%x", keybytes))
resp, err := http.Post(url, "application/octet-stream", nil) resp, err := http.Post(url, "application/octet-stream", nil)
if err != nil { if err != nil {
fmt.Printf("err: %v\n", err) fmt.Printf("err: %v\n", err)
@ -52,7 +60,7 @@ func TestBzzGetDb(t *testing.T) {
b, err := ioutil.ReadAll(resp.Body) b, err := ioutil.ReadAll(resp.Body)
fmt.Printf("Create: %s : %s\n", resp.Status, b) fmt.Printf("Create: %s : %s\n", resp.Status, b)
url = srv.URL + "/bzz-db:/foo" url = fmt.Sprintf("%s/bzz-db:/%s", srv.URL, fmt.Sprintf("%x", keybytes))
data := []byte("foo") data := []byte("foo")
resp, err = http.Post(url, "application/octet-stream", bytes.NewReader(data)) resp, err = http.Post(url, "application/octet-stream", bytes.NewReader(data))
if err != nil { if err != nil {
@ -62,7 +70,7 @@ func TestBzzGetDb(t *testing.T) {
b, err = ioutil.ReadAll(resp.Body) b, err = ioutil.ReadAll(resp.Body)
fmt.Printf("Update: %s : %s\n", resp.Status, b) fmt.Printf("Update: %s : %s\n", resp.Status, b)
url = srv.URL + "/bzz-db:/foo" url = fmt.Sprintf("%s/bzz-db-raw:/%s", srv.URL, fmt.Sprintf("%x", keybytes))
resp, err = http.Get(url) resp, err = http.Get(url)
if err != nil { if err != nil {
fmt.Printf("err: %v\n", err) fmt.Printf("err: %v\n", err)
@ -70,7 +78,6 @@ func TestBzzGetDb(t *testing.T) {
} }
b, err = ioutil.ReadAll(resp.Body) b, err = ioutil.ReadAll(resp.Body)
fmt.Printf("Get: %s : %s\n", resp.Status, b) fmt.Printf("Get: %s : %s\n", resp.Status, b)
} }
func TestBzzGetPath(t *testing.T) { func TestBzzGetPath(t *testing.T) {

View file

@ -51,6 +51,7 @@ func (self *resource) isSynced() bool {
// Implement to activate validation of resource updates // Implement to activate validation of resource updates
// Specifically signing data and verification of signatures // Specifically signing data and verification of signatures
type ResourceValidator interface { type ResourceValidator interface {
hashSize() int
checkAccess(string, common.Address) (bool, error) checkAccess(string, common.Address) (bool, error)
nameHash(string) common.Hash // nameHashFunc nameHash(string) common.Hash // nameHashFunc
sign(common.Hash) (Signature, error) // SignFunc sign(common.Hash) (Signature, error) // SignFunc
@ -166,28 +167,34 @@ func NewResourceHandler(datadir string, cloudStore CloudStore, rpcClient *rpc.Cl
return rh, nil return rh, nil
} }
func (self *ResourceHandler) GetData(name string) []byte { func (self *ResourceHandler) HashSize() int {
rsrc := self.getResource(name) return self.validator.hashSize()
if rsrc == nil {
return nil
}
return rsrc.data
} }
func (self *ResourceHandler) GetLastPeriod(name string) uint32 { // get data from current resource
func (self *ResourceHandler) GetData(name string) ([]byte, error) {
rsrc := self.getResource(name) rsrc := self.getResource(name)
if rsrc == nil { if rsrc == nil || !rsrc.isSynced() {
return 0 return nil, fmt.Errorf("Resource does not exist or is not synced")
} }
return rsrc.lastPeriod return rsrc.data, nil
} }
func (self *ResourceHandler) GetVersion(name string) uint32 { func (self *ResourceHandler) GetLastPeriod(name string) (uint32, error) {
rsrc := self.getResource(name) rsrc := self.getResource(name)
if rsrc == nil {
return 0 if rsrc == nil || !rsrc.isSynced() {
return 0, fmt.Errorf("Resource does not exist or is not synced")
} }
return rsrc.version return rsrc.lastPeriod, nil
}
func (self *ResourceHandler) GetVersion(name string) (uint32, error) {
rsrc := self.getResource(name)
if rsrc == nil || !rsrc.isSynced() {
return 0, fmt.Errorf("Resource does not exist or is not synced")
}
return rsrc.version, nil
} }
// \TODO should be hashsize * branches from the chosen chunker, implement with dpa // \TODO should be hashsize * branches from the chosen chunker, implement with dpa
@ -269,8 +276,14 @@ func (self *ResourceHandler) NewResource(name string, frequency uint64) (*resour
// root chunk. // root chunk.
// It is the callers responsibility to make sure that this chunk exists (if the resource // It is the callers responsibility to make sure that this chunk exists (if the resource
// update root data was retrieved externally, it typically doesn't) // update root data was retrieved externally, it typically doesn't)
func (self *ResourceHandler) LookupVersion(name string, period uint32, version uint32, refresh bool) (*resource, error) { //
rsrc, err := self.loadResource(name, refresh) //
func (self *ResourceHandler) LookupVersionByName(name string, period uint32, version uint32, refresh bool) (*resource, error) {
return self.LookupVersion(self.nameHash(name), name, period, version, refresh)
}
func (self *ResourceHandler) LookupVersion(nameHash common.Hash, name string, period uint32, version uint32, refresh bool) (*resource, error) {
rsrc, err := self.loadResource(nameHash, name, refresh)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -285,8 +298,12 @@ func (self *ResourceHandler) LookupVersion(name string, period uint32, version u
// and returned. // and returned.
// //
// See also (*ResourceHandler).LookupVersion // See also (*ResourceHandler).LookupVersion
func (self *ResourceHandler) LookupHistorical(name string, period uint32, refresh bool) (*resource, error) { func (self *ResourceHandler) LookupHistoricalByName(name string, period uint32, refresh bool) (*resource, error) {
rsrc, err := self.loadResource(name, refresh) return self.LookupHistorical(self.nameHash(name), name, period, refresh)
}
func (self *ResourceHandler) LookupHistorical(nameHash common.Hash, name string, period uint32, refresh bool) (*resource, error) {
rsrc, err := self.loadResource(nameHash, name, refresh)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -303,10 +320,14 @@ func (self *ResourceHandler) LookupHistorical(name string, period uint32, refres
// Version iteration is done as in (*ResourceHandler).LookupHistorical // Version iteration is done as in (*ResourceHandler).LookupHistorical
// //
// See also (*ResourceHandler).LookupHistorical // See also (*ResourceHandler).LookupHistorical
func (self *ResourceHandler) LookupLatest(name string, refresh bool) (*resource, error) { func (self *ResourceHandler) LookupLatestByName(name string, refresh bool) (*resource, error) {
return self.LookupLatest(self.nameHash(name), name, refresh)
}
func (self *ResourceHandler) LookupLatest(nameHash common.Hash, name string, refresh bool) (*resource, error) {
// get our blockheight at this time and the next block of the update period // get our blockheight at this time and the next block of the update period
rsrc, err := self.loadResource(name, refresh) rsrc, err := self.loadResource(nameHash, name, refresh)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -362,7 +383,11 @@ func (self *ResourceHandler) lookup(rsrc *resource, period uint32, version uint3
} }
// load existing mutable resource into resource struct // load existing mutable resource into resource struct
func (self *ResourceHandler) loadResource(name string, refresh bool) (*resource, error) { func (self *ResourceHandler) loadResource(nameHash common.Hash, name string, refresh bool) (*resource, error) {
if name == "" {
name = nameHash.Hex()
}
// if the resource is not known to this session we must load it // if the resource is not known to this session we must load it
// if refresh is set, we force load // if refresh is set, we force load
@ -374,7 +399,7 @@ func (self *ResourceHandler) loadResource(name string, refresh bool) (*resource,
return nil, fmt.Errorf("Invalid name '%s'", name) return nil, fmt.Errorf("Invalid name '%s'", name)
} }
rsrc.name = &name rsrc.name = &name
rsrc.nameHash = self.nameHash(name) rsrc.nameHash = nameHash
// get the root info chunk and update the cached value // get the root info chunk and update the cached value
chunk, err := self.Get(Key(rsrc.nameHash[:])) chunk, err := self.Get(Key(rsrc.nameHash[:]))

View file

@ -10,6 +10,7 @@ import (
type baseValidator struct { type baseValidator struct {
signFunc SignFunc signFunc SignFunc
hashsize int
} }
func (b *baseValidator) sign(datahash common.Hash) (signature Signature, err error) { func (b *baseValidator) sign(datahash common.Hash) (signature Signature, err error) {
@ -19,6 +20,10 @@ func (b *baseValidator) sign(datahash common.Hash) (signature Signature, err err
return b.signFunc(datahash) return b.signFunc(datahash)
} }
func (b *baseValidator) hashSize() int {
return b.hashsize
}
// ENS validation of mutable resource owners // ENS validation of mutable resource owners
type ENSValidator struct { type ENSValidator struct {
*baseValidator *baseValidator
@ -30,6 +35,7 @@ func NewENSValidator(contractaddress common.Address, backend bind.ContractBacken
validator := &ENSValidator{ validator := &ENSValidator{
baseValidator: &baseValidator{ baseValidator: &baseValidator{
signFunc: signFunc, signFunc: signFunc,
hashsize: common.HashLength,
}, },
} }
validator.api, err = ens.NewENS(transactOpts, contractaddress, backend) validator.api, err = ens.NewENS(transactOpts, contractaddress, backend)

View file

@ -89,7 +89,7 @@ func NewTestSwarmServer(t *testing.T) *TestSwarmServer {
Server: srv, Server: srv,
Dpa: dpa, Dpa: dpa,
dir: dir, dir: dir,
hasher: storage.MakeHashFunc("SHA3")(), hasher: storage.MakeHashFunc(storage.SHA3Hash)(),
cleanup: func() { cleanup: func() {
rh.Close() rh.Close()
rpcClean() rpcClean()