diff --git a/swarm/api/api.go b/swarm/api/api.go index 1393fa4406..2a3de5b5ca 100644 --- a/swarm/api/api.go +++ b/swarm/api/api.go @@ -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(key storage.Key, name string, period uint32, version uint32) (storage.Key, []byte, error) { +func (self *Api) DbLookup(name string, period uint32, version uint32) (storage.Key, []byte, error) { var err error if version != 0 { if period == 0 { diff --git a/swarm/api/http/server.go b/swarm/api/http/server.go index 2a8046f1c7..49103f5f85 100644 --- a/swarm/api/http/server.go +++ b/swarm/api/http/server.go @@ -292,7 +292,8 @@ func (s *Server) HandleDelete(w http.ResponseWriter, r *Request) { } func (s *Server) HandlePostDb(w http.ResponseWriter, r *Request) { - if r.ContentLength == 0 { + var outdata string + if r.uri.Path != "" { frequency, err := strconv.ParseUint(r.uri.Path, 10, 64) if err != nil { s.BadRequest(w, r, fmt.Sprintf("Cannot parse frequency parameter: %v", err)) @@ -303,20 +304,50 @@ func (s *Server) HandlePostDb(w http.ResponseWriter, r *Request) { s.Error(w, r, fmt.Errorf("Resource creation failed: %v", err)) return } - } else { - data, err := ioutil.ReadAll(r.Body) + manifestKey, err := s.api.NewManifest() if err != nil { - w.WriteHeader(http.StatusInternalServerError) + s.Error(w, r, fmt.Errorf("create manifest err: %v", err)) return } - _, _, _, err = s.api.DbUpdate(r.uri.Addr, data) + newKey, err := s.updateManifest(manifestKey, func(mw *api.ManifestWriter) error { + key, err := mw.AddEntry(bytes.NewReader([]byte(r.uri.Addr)), &api.ManifestEntry{ + Path: r.uri.Addr, + ContentType: api.ResourceContentType, + Mode: 0644, + Size: int64(len(r.uri.Addr)), + ModTime: time.Now(), + }) + if err != nil { + return err + } + s.logDebug("resource manifest for for %s stored", key.Log()) + return nil + }) if err != nil { - w.WriteHeader(http.StatusUnauthorized) - http.ServeContent(w, &r.Request, "", time.Now(), bytes.NewReader([]byte(err.Error()))) + s.Error(w, r, fmt.Errorf("update manifest err: %v", err)) return } + log.Debug("manifests", "new", newKey, "old", manifestKey) + outdata = fmt.Sprintf("%s", newKey) } + + data, err := ioutil.ReadAll(r.Body) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + return + } + _, _, _, err = s.api.DbUpdate(r.uri.Addr, data) + if err != nil { + w.Header().Add("Status", fmt.Sprintf("%d", http.StatusUnauthorized)) + http.ServeContent(w, &r.Request, "", time.Now(), bytes.NewReader([]byte(err.Error()))) + return + } + w.WriteHeader(http.StatusOK) + if outdata != "" { + w.Header().Set("Content-type", "text/plain") + fmt.Fprintf(w, outdata) + } } // Retrieve mutable resource updates: @@ -325,13 +356,10 @@ func (s *Server) HandlePostDb(w http.ResponseWriter, r *Request) { // bzz-db[-[immutable|-raw]]://// - get update version m of period n // = ens name or hash func (s *Server) HandleGetDb(w http.ResponseWriter, r *Request) { + s.handleGetDb(w, r, r.uri.Addr) +} - rootKey, err := s.api.Resolve(r.uri) - if err != nil { - s.Error(w, r, fmt.Errorf("error resolving %s: %s", r.uri.Addr, err)) - return - } - +func (s *Server) handleGetDb(w http.ResponseWriter, r *Request, name string) { var params []string if len(r.uri.Path) > 0 { params = strings.Split(r.uri.Path, "/") @@ -341,16 +369,18 @@ func (s *Server) HandleGetDb(w http.ResponseWriter, r *Request) { var version uint64 var data []byte var dataLength int + var err error now := time.Now() + log.Debug("handlegetdb", "name", name) switch len(params) { case 0: - updateKey, data, err = s.api.DbLookup(rootKey, r.uri.Addr, 0, 0) + updateKey, data, err = s.api.DbLookup(name, 0, 0) case 2: version, err = strconv.ParseUint(params[1], 10, 32) if err != nil { break } - updateKey, data, err = s.api.DbLookup(rootKey, r.uri.Addr, uint32(period), uint32(version)) + updateKey, data, err = s.api.DbLookup(name, uint32(period), uint32(version)) case 1: version, err = strconv.ParseUint(params[1], 10, 32) if err != nil { @@ -360,7 +390,7 @@ func (s *Server) HandleGetDb(w http.ResponseWriter, r *Request) { if err != nil { break } - updateKey, data, err = s.api.DbLookup(rootKey, r.uri.Addr, uint32(period), uint32(version)) + updateKey, data, err = s.api.DbLookup(name, uint32(period), uint32(version)) default: s.BadRequest(w, r, fmt.Sprintf("Invalid mutable resource request")) return @@ -373,9 +403,9 @@ func (s *Server) HandleGetDb(w http.ResponseWriter, r *Request) { w.Header().Set("Content-Type", "application/octet-stream") } else { entry := api.ManifestEntry{ - Hash: rootKey.Hex(), + Hash: name, Path: updateKey.Hex(), - ContentType: api.DbManifestType, + ContentType: api.ManifestType, Size: int64(dataLength), ModTime: now, Status: http.StatusOK, @@ -395,7 +425,7 @@ func (s *Server) HandleGetDb(w http.ResponseWriter, r *Request) { s.Error(w, r, fmt.Errorf("Could not convert manifest to json: %v", err)) return } - w.Header().Set("Content-Type", api.DbManifestType) + w.Header().Set("Content-Type", api.ManifestType) data = []byte(manifestJson) } http.ServeContent(w, &r.Request, "", now, bytes.NewReader(data)) @@ -461,6 +491,17 @@ func (s *Server) HandleGet(w http.ResponseWriter, r *Request) { switch { case r.uri.Raw(): + m := &api.Manifest{} + sz, _ := reader.Size(nil) + b := make([]byte, sz) + reader.Read(b) + err = json.Unmarshal(b, m) + if len(m.Entries) > 0 { + if m.Entries[0].ContentType == api.ResourceContentType { + s.handleGetDb(w, r, m.Entries[0].Path) + return + } + } // allow the request to overwrite the content type using a query // parameter contentType := "application/octet-stream" @@ -468,7 +509,6 @@ func (s *Server) HandleGet(w http.ResponseWriter, r *Request) { contentType = typ } w.Header().Set("Content-Type", contentType) - http.ServeContent(w, &r.Request, "", time.Now(), reader) case r.uri.Hash(): w.Header().Set("Content-Type", "text/plain") diff --git a/swarm/api/http/server_test.go b/swarm/api/http/server_test.go index 42c9ce3f56..cd7d1a0c9b 100644 --- a/swarm/api/http/server_test.go +++ b/swarm/api/http/server_test.go @@ -45,21 +45,27 @@ func TestBzzGetDb(t *testing.T) { defer srv.Close() keybytes := make([]byte, common.HashLength) // nearest we get to source of info - _, err := rand.Read(keybytes) + copy(keybytes, []byte{42}) + + databytes := make([]byte, 42) + _, err := rand.Read(databytes) if err != nil { t.Fatal(err) } - url := fmt.Sprintf("%s/bzz-db:/%s/42", srv.URL, fmt.Sprintf("%x", keybytes)) - resp, err := http.Post(url, "application/octet-stream", nil) + url := fmt.Sprintf("%s/bzz-db:/%x/42", srv.URL, keybytes) + resp, err := http.Post(url, "application/octet-stream", bytes.NewReader(databytes)) if err != nil { t.Fatal(err) } - b, err := ioutil.ReadAll(resp.Body) + manifesthash, err := ioutil.ReadAll(resp.Body) if err != nil { t.Fatal(err) } - log.Debug("Create", "status", resp.Status, "body", b) + if resp.StatusCode != http.StatusOK { + t.Fatalf("err %s", resp.Status) + } + log.Debug("Create", "status", resp.Status, "body", manifesthash) url = fmt.Sprintf("%s/bzz-db:/%x", srv.URL, keybytes) data := []byte("foo") @@ -67,13 +73,13 @@ func TestBzzGetDb(t *testing.T) { if err != nil { t.Fatal(err) } - b, err = ioutil.ReadAll(resp.Body) + b, err := ioutil.ReadAll(resp.Body) if err != nil { t.Fatal(err) } - log.Debug("Update", "status", resp.Status, "body", b) + log.Debug("Update", "status", resp.Status) - url = fmt.Sprintf("%s/bzz-db-raw:/%s", srv.URL, fmt.Sprintf("%x", keybytes)) + url = fmt.Sprintf("%s/bzz-raw:/%s", srv.URL, manifesthash) resp, err = http.Get(url) if err != nil { t.Fatal(err) @@ -82,9 +88,9 @@ func TestBzzGetDb(t *testing.T) { if err != nil { t.Fatal(err) } - log.Debug("Get raw", "status", resp.Status, "body", b) + log.Debug("Manifest", "status", resp.Status, "body", fmt.Sprintf("%s", b)) - url = fmt.Sprintf("%s/bzz-db:/%s", srv.URL, fmt.Sprintf("%x", keybytes)) + url = fmt.Sprintf("%s/bzz-db-raw:/%x", srv.URL, keybytes) resp, err = http.Get(url) if err != nil { t.Fatal(err) @@ -93,7 +99,18 @@ func TestBzzGetDb(t *testing.T) { if err != nil { t.Fatal(err) } - log.Debug("Get manifest", "status", resp.Status, "body", b) + log.Debug("Get raw", "status", resp.Status) + + url = fmt.Sprintf("%s/bzz-db:/%x", srv.URL, keybytes) + resp, err = http.Get(url) + if err != nil { + t.Fatal(err) + } + b, err = ioutil.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } + log.Debug("Get manifest", "status", resp.Status) } diff --git a/swarm/api/manifest.go b/swarm/api/manifest.go index 46b55b3b7a..fde086b7ac 100644 --- a/swarm/api/manifest.go +++ b/swarm/api/manifest.go @@ -33,8 +33,8 @@ import ( ) const ( - ManifestType = "application/bzz-manifest+json" - DbManifestType = "application/bzz-db-manifest+json" + ManifestType = "application/bzz-manifest+json" + ResourceContentType = "application/bzz-resource" ) // Manifest represents a swarm manifest