manifest.go 15 KB

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