manifest.go 15 KB

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