swarm/api: Add contenttype contingent resolve manifest -> rsrc

This commit is contained in:
lash 2018-01-22 05:08:45 +01:00
parent a16d0af41d
commit 11c3b4cae1
4 changed files with 91 additions and 34 deletions

View file

@ -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 {

View file

@ -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]]://<id>/<n>/<m> - get update version m of period n
// <id> = 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")

View file

@ -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)
}

View file

@ -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