From 1bf4f4a37f02b57e1a90929c10413fa47b1d42d1 Mon Sep 17 00:00:00 2001 From: lash Date: Fri, 19 Jan 2018 18:28:10 +0100 Subject: [PATCH] swarm/api: Add raw form to api+server WIP --- swarm/api/api.go | 24 ++++++++---- swarm/api/http/server.go | 39 ++++++++++++-------- swarm/api/http/server_test.go | 15 ++++++-- swarm/storage/resource.go | 69 ++++++++++++++++++++++++----------- swarm/storage/resource_ens.go | 6 +++ swarm/testutil/http.go | 2 +- 6 files changed, 105 insertions(+), 50 deletions(-) diff --git a/swarm/api/api.go b/swarm/api/api.go index 827e89ad1d..cfc26aeff5 100644 --- a/swarm/api/api.go +++ b/swarm/api/api.go @@ -46,9 +46,9 @@ on top of the dpa it is the public interface of the dpa which is included in the ethereum stack */ type Api struct { + resource *storage.ResourceHandler dpa *storage.DPA dns Resolver - resource *storage.ResourceHandler } //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 -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 if version != 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) } - _, err = self.resource.LookupVersion(name, period, version, true) + _, err = self.resource.LookupVersionByName(name, period, version, true) } else if period != 0 { - _, err = self.resource.LookupHistorical(name, period, true) + _, err = self.resource.LookupHistoricalByName(name, period, true) } else { - _, err = self.resource.LookupLatest(name, true) + _, err = self.resource.LookupLatestByName(name, true) } if err != nil { 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) { @@ -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) { 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() } diff --git a/swarm/api/http/server.go b/swarm/api/http/server.go index bcdb4d2e59..9e3c7711c1 100644 --- a/swarm/api/http/server.go +++ b/swarm/api/http/server.go @@ -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)) return } - _ = key var params []string if len(r.uri.Path) > 0 { params = strings.Split(r.uri.Path, "/") } + var period uint64 + var version uint64 + var data io.ReadSeeker switch len(params) { case 0: - data, err := s.api.DbLookup(r.uri.Addr) + data, err = s.api.DbLookup(key, r.uri.Addr, 0, 0) break case 2: - strconv.ParseUint(params[1], 10, 32) + version, err = strconv.ParseUint(params[1], 10, 32) + if err != nil { + break + } 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 default: w.WriteHeader(http.StatusBadRequest) - err = "params 0-2" + err = fmt.Errorf("params 0-2") } if err != nil { w.WriteHeader(http.StatusInternalServerError) return } - wrappedData := wrapDbContent(data, s.uri.Scheme) + if !r.uri.DbRaw() { + + } http.ServeContent(w, &r.Request, "", time.Now(), data) - -} - -func wrapDbContent(data io.Reader, scheme *string) io.Reader { - } // HandleGet handles a GET request to @@ -705,6 +711,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { s.HandleDelete(w, req) case "GET": + + if uri.Db() || uri.DbRaw() { + s.HandleGetDb(w, req) + return + } + if uri.Raw() || uri.Hash() || uri.DeprecatedRaw() { s.HandleGet(w, req) return @@ -720,11 +732,6 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } - if uri.Db() { - s.HandleGetDb(w, req) - return - } - s.HandleGetFile(w, req) default: diff --git a/swarm/api/http/server_test.go b/swarm/api/http/server_test.go index 06d4660d6b..888445d88d 100644 --- a/swarm/api/http/server_test.go +++ b/swarm/api/http/server_test.go @@ -18,6 +18,7 @@ package http_test import ( "bytes" + "crypto/rand" "errors" "fmt" "io/ioutil" @@ -43,7 +44,14 @@ func TestBzzGetDb(t *testing.T) { srv := testutil.NewTestSwarmServer(t) 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) if err != nil { fmt.Printf("err: %v\n", err) @@ -52,7 +60,7 @@ func TestBzzGetDb(t *testing.T) { b, err := ioutil.ReadAll(resp.Body) 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") resp, err = http.Post(url, "application/octet-stream", bytes.NewReader(data)) if err != nil { @@ -62,7 +70,7 @@ func TestBzzGetDb(t *testing.T) { b, err = ioutil.ReadAll(resp.Body) 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) if err != nil { fmt.Printf("err: %v\n", err) @@ -70,7 +78,6 @@ func TestBzzGetDb(t *testing.T) { } b, err = ioutil.ReadAll(resp.Body) fmt.Printf("Get: %s : %s\n", resp.Status, b) - } func TestBzzGetPath(t *testing.T) { diff --git a/swarm/storage/resource.go b/swarm/storage/resource.go index 33845da40d..b76117b336 100644 --- a/swarm/storage/resource.go +++ b/swarm/storage/resource.go @@ -51,6 +51,7 @@ func (self *resource) isSynced() bool { // Implement to activate validation of resource updates // Specifically signing data and verification of signatures type ResourceValidator interface { + hashSize() int checkAccess(string, common.Address) (bool, error) nameHash(string) common.Hash // nameHashFunc sign(common.Hash) (Signature, error) // SignFunc @@ -166,28 +167,34 @@ func NewResourceHandler(datadir string, cloudStore CloudStore, rpcClient *rpc.Cl return rh, nil } -func (self *ResourceHandler) GetData(name string) []byte { - rsrc := self.getResource(name) - if rsrc == nil { - return nil - } - return rsrc.data +func (self *ResourceHandler) HashSize() int { + return self.validator.hashSize() } -func (self *ResourceHandler) GetLastPeriod(name string) uint32 { +// get data from current resource +func (self *ResourceHandler) GetData(name string) ([]byte, error) { rsrc := self.getResource(name) - if rsrc == nil { - return 0 + if rsrc == nil || !rsrc.isSynced() { + 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) - 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 @@ -269,8 +276,14 @@ func (self *ResourceHandler) NewResource(name string, frequency uint64) (*resour // root chunk. // 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) -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 { return nil, err } @@ -285,8 +298,12 @@ func (self *ResourceHandler) LookupVersion(name string, period uint32, version u // and returned. // // See also (*ResourceHandler).LookupVersion -func (self *ResourceHandler) LookupHistorical(name string, period uint32, refresh bool) (*resource, error) { - rsrc, err := self.loadResource(name, refresh) +func (self *ResourceHandler) LookupHistoricalByName(name string, period uint32, refresh bool) (*resource, error) { + 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 { return nil, err } @@ -303,10 +320,14 @@ func (self *ResourceHandler) LookupHistorical(name string, period uint32, refres // Version iteration is done as in (*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 - rsrc, err := self.loadResource(name, refresh) + rsrc, err := self.loadResource(nameHash, name, refresh) if err != nil { return nil, err } @@ -362,7 +383,11 @@ func (self *ResourceHandler) lookup(rsrc *resource, period uint32, version uint3 } // 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 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) } rsrc.name = &name - rsrc.nameHash = self.nameHash(name) + rsrc.nameHash = nameHash // get the root info chunk and update the cached value chunk, err := self.Get(Key(rsrc.nameHash[:])) diff --git a/swarm/storage/resource_ens.go b/swarm/storage/resource_ens.go index 0a4500309d..df008efa17 100644 --- a/swarm/storage/resource_ens.go +++ b/swarm/storage/resource_ens.go @@ -10,6 +10,7 @@ import ( type baseValidator struct { signFunc SignFunc + hashsize int } 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) } +func (b *baseValidator) hashSize() int { + return b.hashsize +} + // ENS validation of mutable resource owners type ENSValidator struct { *baseValidator @@ -30,6 +35,7 @@ func NewENSValidator(contractaddress common.Address, backend bind.ContractBacken validator := &ENSValidator{ baseValidator: &baseValidator{ signFunc: signFunc, + hashsize: common.HashLength, }, } validator.api, err = ens.NewENS(transactOpts, contractaddress, backend) diff --git a/swarm/testutil/http.go b/swarm/testutil/http.go index fbe52e1111..dcba90c9c5 100644 --- a/swarm/testutil/http.go +++ b/swarm/testutil/http.go @@ -89,7 +89,7 @@ func NewTestSwarmServer(t *testing.T) *TestSwarmServer { Server: srv, Dpa: dpa, dir: dir, - hasher: storage.MakeHashFunc("SHA3")(), + hasher: storage.MakeHashFunc(storage.SHA3Hash)(), cleanup: func() { rh.Close() rpcClean()