manifest.go 16 KB

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