github.com/Blockdaemon/celo-blockchain@v0.0.0-20200129231733-e667f6b08419/swarm/api/manifest.go (about) 1 // Copyright 2016 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package api 18 19 import ( 20 "bytes" 21 "context" 22 "encoding/json" 23 "errors" 24 "fmt" 25 "io" 26 "net/http" 27 "strings" 28 "time" 29 30 "github.com/ethereum/go-ethereum/common" 31 "github.com/ethereum/go-ethereum/swarm/log" 32 "github.com/ethereum/go-ethereum/swarm/storage" 33 "github.com/ethereum/go-ethereum/swarm/storage/feed" 34 ) 35 36 const ( 37 ManifestType = "application/bzz-manifest+json" 38 FeedContentType = "application/bzz-feed" 39 40 manifestSizeLimit = 5 * 1024 * 1024 41 ) 42 43 // Manifest represents a swarm manifest 44 type Manifest struct { 45 Entries []ManifestEntry `json:"entries,omitempty"` 46 } 47 48 // ManifestEntry represents an entry in a swarm manifest 49 type ManifestEntry struct { 50 Hash string `json:"hash,omitempty"` 51 Path string `json:"path,omitempty"` 52 ContentType string `json:"contentType,omitempty"` 53 Mode int64 `json:"mode,omitempty"` 54 Size int64 `json:"size,omitempty"` 55 ModTime time.Time `json:"mod_time,omitempty"` 56 Status int `json:"status,omitempty"` 57 Access *AccessEntry `json:"access,omitempty"` 58 Feed *feed.Feed `json:"feed,omitempty"` 59 } 60 61 // ManifestList represents the result of listing files in a manifest 62 type ManifestList struct { 63 CommonPrefixes []string `json:"common_prefixes,omitempty"` 64 Entries []*ManifestEntry `json:"entries,omitempty"` 65 } 66 67 // NewManifest creates and stores a new, empty manifest 68 func (a *API) NewManifest(ctx context.Context, toEncrypt bool) (storage.Address, error) { 69 var manifest Manifest 70 data, err := json.Marshal(&manifest) 71 if err != nil { 72 return nil, err 73 } 74 addr, wait, err := a.Store(ctx, bytes.NewReader(data), int64(len(data)), toEncrypt) 75 if err != nil { 76 return nil, err 77 } 78 err = wait(ctx) 79 return addr, err 80 } 81 82 // Manifest hack for supporting Swarm feeds from the bzz: scheme 83 // see swarm/api/api.go:API.Get() for more information 84 func (a *API) NewFeedManifest(ctx context.Context, feed *feed.Feed) (storage.Address, error) { 85 var manifest Manifest 86 entry := ManifestEntry{ 87 Feed: feed, 88 ContentType: FeedContentType, 89 } 90 manifest.Entries = append(manifest.Entries, entry) 91 data, err := json.Marshal(&manifest) 92 if err != nil { 93 return nil, err 94 } 95 addr, wait, err := a.Store(ctx, bytes.NewReader(data), int64(len(data)), false) 96 if err != nil { 97 return nil, err 98 } 99 err = wait(ctx) 100 return addr, err 101 } 102 103 // ManifestWriter is used to add and remove entries from an underlying manifest 104 type ManifestWriter struct { 105 api *API 106 trie *manifestTrie 107 quitC chan bool 108 } 109 110 func (a *API) NewManifestWriter(ctx context.Context, addr storage.Address, quitC chan bool) (*ManifestWriter, error) { 111 trie, err := loadManifest(ctx, a.fileStore, addr, quitC, NOOPDecrypt) 112 if err != nil { 113 return nil, fmt.Errorf("error loading manifest %s: %s", addr, err) 114 } 115 return &ManifestWriter{a, trie, quitC}, nil 116 } 117 118 // AddEntry stores the given data and adds the resulting address to the manifest 119 func (m *ManifestWriter) AddEntry(ctx context.Context, data io.Reader, e *ManifestEntry) (addr storage.Address, err error) { 120 entry := newManifestTrieEntry(e, nil) 121 if data != nil { 122 var wait func(context.Context) error 123 addr, wait, err = m.api.Store(ctx, data, e.Size, m.trie.encrypted) 124 if err != nil { 125 return nil, err 126 } 127 err = wait(ctx) 128 if err != nil { 129 return nil, err 130 } 131 entry.Hash = addr.Hex() 132 } 133 if entry.Hash == "" { 134 return addr, errors.New("missing entry hash") 135 } 136 m.trie.addEntry(entry, m.quitC) 137 return addr, nil 138 } 139 140 // RemoveEntry removes the given path from the manifest 141 func (m *ManifestWriter) RemoveEntry(path string) error { 142 m.trie.deleteEntry(path, m.quitC) 143 return nil 144 } 145 146 // Store stores the manifest, returning the resulting storage address 147 func (m *ManifestWriter) Store() (storage.Address, error) { 148 return m.trie.ref, m.trie.recalcAndStore() 149 } 150 151 // ManifestWalker is used to recursively walk the entries in the manifest and 152 // all of its submanifests 153 type ManifestWalker struct { 154 api *API 155 trie *manifestTrie 156 quitC chan bool 157 } 158 159 func (a *API) NewManifestWalker(ctx context.Context, addr storage.Address, decrypt DecryptFunc, quitC chan bool) (*ManifestWalker, error) { 160 trie, err := loadManifest(ctx, a.fileStore, addr, quitC, decrypt) 161 if err != nil { 162 return nil, fmt.Errorf("error loading manifest %s: %s", addr, err) 163 } 164 return &ManifestWalker{a, trie, quitC}, nil 165 } 166 167 // ErrSkipManifest is used as a return value from WalkFn to indicate that the 168 // manifest should be skipped 169 var ErrSkipManifest = errors.New("skip this manifest") 170 171 // WalkFn is the type of function called for each entry visited by a recursive 172 // manifest walk 173 type WalkFn func(entry *ManifestEntry) error 174 175 // Walk recursively walks the manifest calling walkFn for each entry in the 176 // manifest, including submanifests 177 func (m *ManifestWalker) Walk(walkFn WalkFn) error { 178 return m.walk(m.trie, "", walkFn) 179 } 180 181 func (m *ManifestWalker) walk(trie *manifestTrie, prefix string, walkFn WalkFn) error { 182 for _, entry := range &trie.entries { 183 if entry == nil { 184 continue 185 } 186 entry.Path = prefix + entry.Path 187 err := walkFn(&entry.ManifestEntry) 188 if err != nil { 189 if entry.ContentType == ManifestType && err == ErrSkipManifest { 190 continue 191 } 192 return err 193 } 194 if entry.ContentType != ManifestType { 195 continue 196 } 197 if err := trie.loadSubTrie(entry, nil); err != nil { 198 return err 199 } 200 if err := m.walk(entry.subtrie, entry.Path, walkFn); err != nil { 201 return err 202 } 203 } 204 return nil 205 } 206 207 type manifestTrie struct { 208 fileStore *storage.FileStore 209 entries [257]*manifestTrieEntry // indexed by first character of basePath, entries[256] is the empty basePath entry 210 ref storage.Address // if ref != nil, it is stored 211 encrypted bool 212 decrypt DecryptFunc 213 } 214 215 func newManifestTrieEntry(entry *ManifestEntry, subtrie *manifestTrie) *manifestTrieEntry { 216 return &manifestTrieEntry{ 217 ManifestEntry: *entry, 218 subtrie: subtrie, 219 } 220 } 221 222 type manifestTrieEntry struct { 223 ManifestEntry 224 225 subtrie *manifestTrie 226 } 227 228 func loadManifest(ctx context.Context, fileStore *storage.FileStore, addr storage.Address, quitC chan bool, decrypt DecryptFunc) (trie *manifestTrie, err error) { // non-recursive, subtrees are downloaded on-demand 229 log.Trace("manifest lookup", "addr", addr) 230 // retrieve manifest via FileStore 231 manifestReader, isEncrypted := fileStore.Retrieve(ctx, addr) 232 log.Trace("reader retrieved", "addr", addr) 233 return readManifest(manifestReader, addr, fileStore, isEncrypted, quitC, decrypt) 234 } 235 236 func readManifest(mr storage.LazySectionReader, addr storage.Address, fileStore *storage.FileStore, isEncrypted bool, quitC chan bool, decrypt DecryptFunc) (trie *manifestTrie, err error) { // non-recursive, subtrees are downloaded on-demand 237 238 // TODO check size for oversized manifests 239 size, err := mr.Size(mr.Context(), quitC) 240 if err != nil { // size == 0 241 // can't determine size means we don't have the root chunk 242 log.Trace("manifest not found", "addr", addr) 243 err = fmt.Errorf("Manifest not Found") 244 return 245 } 246 if size > manifestSizeLimit { 247 log.Warn("manifest exceeds size limit", "addr", addr, "size", size, "limit", manifestSizeLimit) 248 err = fmt.Errorf("Manifest size of %v bytes exceeds the %v byte limit", size, manifestSizeLimit) 249 return 250 } 251 manifestData := make([]byte, size) 252 read, err := mr.Read(manifestData) 253 if int64(read) < size { 254 log.Trace("manifest not found", "addr", addr) 255 if err == nil { 256 err = fmt.Errorf("Manifest retrieval cut short: read %v, expect %v", read, size) 257 } 258 return 259 } 260 261 log.Debug("manifest retrieved", "addr", addr) 262 var man struct { 263 Entries []*manifestTrieEntry `json:"entries"` 264 } 265 err = json.Unmarshal(manifestData, &man) 266 if err != nil { 267 err = fmt.Errorf("Manifest %v is malformed: %v", addr.Log(), err) 268 log.Trace("malformed manifest", "addr", addr) 269 return 270 } 271 272 log.Trace("manifest entries", "addr", addr, "len", len(man.Entries)) 273 274 trie = &manifestTrie{ 275 fileStore: fileStore, 276 encrypted: isEncrypted, 277 decrypt: decrypt, 278 } 279 for _, entry := range man.Entries { 280 err = trie.addEntry(entry, quitC) 281 if err != nil { 282 return 283 } 284 } 285 return 286 } 287 288 func (mt *manifestTrie) addEntry(entry *manifestTrieEntry, quitC chan bool) error { 289 mt.ref = nil // trie modified, hash needs to be re-calculated on demand 290 291 if entry.ManifestEntry.Access != nil { 292 if mt.decrypt == nil { 293 return errors.New("dont have decryptor") 294 } 295 296 err := mt.decrypt(&entry.ManifestEntry) 297 if err != nil { 298 return err 299 } 300 } 301 302 if len(entry.Path) == 0 { 303 mt.entries[256] = entry 304 return nil 305 } 306 307 b := entry.Path[0] 308 oldentry := mt.entries[b] 309 if (oldentry == nil) || (oldentry.Path == entry.Path && oldentry.ContentType != ManifestType) { 310 mt.entries[b] = entry 311 return nil 312 } 313 314 cpl := 0 315 for (len(entry.Path) > cpl) && (len(oldentry.Path) > cpl) && (entry.Path[cpl] == oldentry.Path[cpl]) { 316 cpl++ 317 } 318 319 if (oldentry.ContentType == ManifestType) && (cpl == len(oldentry.Path)) { 320 if mt.loadSubTrie(oldentry, quitC) != nil { 321 return nil 322 } 323 entry.Path = entry.Path[cpl:] 324 oldentry.subtrie.addEntry(entry, quitC) 325 oldentry.Hash = "" 326 return nil 327 } 328 329 commonPrefix := entry.Path[:cpl] 330 331 subtrie := &manifestTrie{ 332 fileStore: mt.fileStore, 333 encrypted: mt.encrypted, 334 } 335 entry.Path = entry.Path[cpl:] 336 oldentry.Path = oldentry.Path[cpl:] 337 subtrie.addEntry(entry, quitC) 338 subtrie.addEntry(oldentry, quitC) 339 340 mt.entries[b] = newManifestTrieEntry(&ManifestEntry{ 341 Path: commonPrefix, 342 ContentType: ManifestType, 343 }, subtrie) 344 return nil 345 } 346 347 func (mt *manifestTrie) getCountLast() (cnt int, entry *manifestTrieEntry) { 348 for _, e := range &mt.entries { 349 if e != nil { 350 cnt++ 351 entry = e 352 } 353 } 354 return 355 } 356 357 func (mt *manifestTrie) deleteEntry(path string, quitC chan bool) { 358 mt.ref = nil // trie modified, hash needs to be re-calculated on demand 359 360 if len(path) == 0 { 361 mt.entries[256] = nil 362 return 363 } 364 365 b := path[0] 366 entry := mt.entries[b] 367 if entry == nil { 368 return 369 } 370 if entry.Path == path { 371 mt.entries[b] = nil 372 return 373 } 374 375 epl := len(entry.Path) 376 if (entry.ContentType == ManifestType) && (len(path) >= epl) && (path[:epl] == entry.Path) { 377 if mt.loadSubTrie(entry, quitC) != nil { 378 return 379 } 380 entry.subtrie.deleteEntry(path[epl:], quitC) 381 entry.Hash = "" 382 // remove subtree if it has less than 2 elements 383 cnt, lastentry := entry.subtrie.getCountLast() 384 if cnt < 2 { 385 if lastentry != nil { 386 lastentry.Path = entry.Path + lastentry.Path 387 } 388 mt.entries[b] = lastentry 389 } 390 } 391 } 392 393 func (mt *manifestTrie) recalcAndStore() error { 394 if mt.ref != nil { 395 return nil 396 } 397 398 var buffer bytes.Buffer 399 buffer.WriteString(`{"entries":[`) 400 401 list := &Manifest{} 402 for _, entry := range &mt.entries { 403 if entry != nil { 404 if entry.Hash == "" { // TODO: paralellize 405 err := entry.subtrie.recalcAndStore() 406 if err != nil { 407 return err 408 } 409 entry.Hash = entry.subtrie.ref.Hex() 410 } 411 list.Entries = append(list.Entries, entry.ManifestEntry) 412 } 413 414 } 415 416 manifest, err := json.Marshal(list) 417 if err != nil { 418 return err 419 } 420 421 sr := bytes.NewReader(manifest) 422 ctx := context.TODO() 423 addr, wait, err2 := mt.fileStore.Store(ctx, sr, int64(len(manifest)), mt.encrypted) 424 if err2 != nil { 425 return err2 426 } 427 err2 = wait(ctx) 428 mt.ref = addr 429 return err2 430 } 431 432 func (mt *manifestTrie) loadSubTrie(entry *manifestTrieEntry, quitC chan bool) (err error) { 433 if entry.ManifestEntry.Access != nil { 434 if mt.decrypt == nil { 435 return errors.New("dont have decryptor") 436 } 437 438 err := mt.decrypt(&entry.ManifestEntry) 439 if err != nil { 440 return err 441 } 442 } 443 444 if entry.subtrie == nil { 445 hash := common.Hex2Bytes(entry.Hash) 446 entry.subtrie, err = loadManifest(context.TODO(), mt.fileStore, hash, quitC, mt.decrypt) 447 entry.Hash = "" // might not match, should be recalculated 448 } 449 return 450 } 451 452 func (mt *manifestTrie) listWithPrefixInt(prefix, rp string, quitC chan bool, cb func(entry *manifestTrieEntry, suffix string)) error { 453 plen := len(prefix) 454 var start, stop int 455 if plen == 0 { 456 start = 0 457 stop = 256 458 } else { 459 start = int(prefix[0]) 460 stop = start 461 } 462 463 for i := start; i <= stop; i++ { 464 select { 465 case <-quitC: 466 return fmt.Errorf("aborted") 467 default: 468 } 469 entry := mt.entries[i] 470 if entry != nil { 471 epl := len(entry.Path) 472 if entry.ContentType == ManifestType { 473 l := plen 474 if epl < l { 475 l = epl 476 } 477 if prefix[:l] == entry.Path[:l] { 478 err := mt.loadSubTrie(entry, quitC) 479 if err != nil { 480 return err 481 } 482 err = entry.subtrie.listWithPrefixInt(prefix[l:], rp+entry.Path[l:], quitC, cb) 483 if err != nil { 484 return err 485 } 486 } 487 } else { 488 if (epl >= plen) && (prefix == entry.Path[:plen]) { 489 cb(entry, rp+entry.Path[plen:]) 490 } 491 } 492 } 493 } 494 return nil 495 } 496 497 func (mt *manifestTrie) listWithPrefix(prefix string, quitC chan bool, cb func(entry *manifestTrieEntry, suffix string)) (err error) { 498 return mt.listWithPrefixInt(prefix, "", quitC, cb) 499 } 500 501 func (mt *manifestTrie) findPrefixOf(path string, quitC chan bool) (entry *manifestTrieEntry, pos int) { 502 log.Trace(fmt.Sprintf("findPrefixOf(%s)", path)) 503 504 if len(path) == 0 { 505 return mt.entries[256], 0 506 } 507 508 //see if first char is in manifest entries 509 b := path[0] 510 entry = mt.entries[b] 511 if entry == nil { 512 return mt.entries[256], 0 513 } 514 515 epl := len(entry.Path) 516 log.Trace(fmt.Sprintf("path = %v entry.Path = %v epl = %v", path, entry.Path, epl)) 517 if len(path) <= epl { 518 if entry.Path[:len(path)] == path { 519 if entry.ContentType == ManifestType { 520 err := mt.loadSubTrie(entry, quitC) 521 if err == nil && entry.subtrie != nil { 522 subentries := entry.subtrie.entries 523 for i := 0; i < len(subentries); i++ { 524 sub := subentries[i] 525 if sub != nil && sub.Path == "" { 526 return sub, len(path) 527 } 528 } 529 } 530 entry.Status = http.StatusMultipleChoices 531 } 532 pos = len(path) 533 return 534 } 535 return nil, 0 536 } 537 if path[:epl] == entry.Path { 538 log.Trace(fmt.Sprintf("entry.ContentType = %v", entry.ContentType)) 539 //the subentry is a manifest, load subtrie 540 if entry.ContentType == ManifestType && (strings.Contains(entry.Path, path) || strings.Contains(path, entry.Path)) { 541 err := mt.loadSubTrie(entry, quitC) 542 if err != nil { 543 return nil, 0 544 } 545 sub, pos := entry.subtrie.findPrefixOf(path[epl:], quitC) 546 if sub != nil { 547 entry = sub 548 pos += epl 549 return sub, pos 550 } else if path == entry.Path { 551 entry.Status = http.StatusMultipleChoices 552 } 553 554 } else { 555 //entry is not a manifest, return it 556 if path != entry.Path { 557 return nil, 0 558 } 559 } 560 } 561 return nil, 0 562 } 563 564 // file system manifest always contains regularized paths 565 // no leading or trailing slashes, only single slashes inside 566 func RegularSlashes(path string) (res string) { 567 for i := 0; i < len(path); i++ { 568 if (path[i] != '/') || ((i > 0) && (path[i-1] != '/')) { 569 res = res + path[i:i+1] 570 } 571 } 572 if (len(res) > 0) && (res[len(res)-1] == '/') { 573 res = res[:len(res)-1] 574 } 575 return 576 } 577 578 func (mt *manifestTrie) getEntry(spath string) (entry *manifestTrieEntry, fullpath string) { 579 path := RegularSlashes(spath) 580 var pos int 581 quitC := make(chan bool) 582 entry, pos = mt.findPrefixOf(path, quitC) 583 return entry, path[:pos] 584 }