api.go 32 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076
  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. //go:generate mimegen --types=./../../cmd/swarm/mimegen/mime.types --package=api --out=gen_mime.go
  18. //go:generate gofmt -s -w gen_mime.go
  19. import (
  20. "archive/tar"
  21. "context"
  22. "crypto/ecdsa"
  23. "encoding/hex"
  24. "errors"
  25. "fmt"
  26. "io"
  27. "math/big"
  28. "net/http"
  29. "path"
  30. "strings"
  31. "bytes"
  32. "mime"
  33. "path/filepath"
  34. "time"
  35. "github.com/ethereum/go-ethereum/common"
  36. "github.com/ethereum/go-ethereum/contracts/ens"
  37. "github.com/ethereum/go-ethereum/core/types"
  38. "github.com/ethereum/go-ethereum/metrics"
  39. "github.com/ethereum/go-ethereum/swarm/log"
  40. "github.com/ethereum/go-ethereum/swarm/multihash"
  41. "github.com/ethereum/go-ethereum/swarm/spancontext"
  42. "github.com/ethereum/go-ethereum/swarm/storage"
  43. "github.com/ethereum/go-ethereum/swarm/storage/feed"
  44. "github.com/ethereum/go-ethereum/swarm/storage/feed/lookup"
  45. opentracing "github.com/opentracing/opentracing-go"
  46. )
  47. var (
  48. ErrNotFound = errors.New("not found")
  49. )
  50. var (
  51. apiResolveCount = metrics.NewRegisteredCounter("api.resolve.count", nil)
  52. apiResolveFail = metrics.NewRegisteredCounter("api.resolve.fail", nil)
  53. apiPutCount = metrics.NewRegisteredCounter("api.put.count", nil)
  54. apiPutFail = metrics.NewRegisteredCounter("api.put.fail", nil)
  55. apiGetCount = metrics.NewRegisteredCounter("api.get.count", nil)
  56. apiGetNotFound = metrics.NewRegisteredCounter("api.get.notfound", nil)
  57. apiGetHTTP300 = metrics.NewRegisteredCounter("api.get.http.300", nil)
  58. apiManifestUpdateCount = metrics.NewRegisteredCounter("api.manifestupdate.count", nil)
  59. apiManifestUpdateFail = metrics.NewRegisteredCounter("api.manifestupdate.fail", nil)
  60. apiManifestListCount = metrics.NewRegisteredCounter("api.manifestlist.count", nil)
  61. apiManifestListFail = metrics.NewRegisteredCounter("api.manifestlist.fail", nil)
  62. apiDeleteCount = metrics.NewRegisteredCounter("api.delete.count", nil)
  63. apiDeleteFail = metrics.NewRegisteredCounter("api.delete.fail", nil)
  64. apiGetTarCount = metrics.NewRegisteredCounter("api.gettar.count", nil)
  65. apiGetTarFail = metrics.NewRegisteredCounter("api.gettar.fail", nil)
  66. apiUploadTarCount = metrics.NewRegisteredCounter("api.uploadtar.count", nil)
  67. apiUploadTarFail = metrics.NewRegisteredCounter("api.uploadtar.fail", nil)
  68. apiModifyCount = metrics.NewRegisteredCounter("api.modify.count", nil)
  69. apiModifyFail = metrics.NewRegisteredCounter("api.modify.fail", nil)
  70. apiAddFileCount = metrics.NewRegisteredCounter("api.addfile.count", nil)
  71. apiAddFileFail = metrics.NewRegisteredCounter("api.addfile.fail", nil)
  72. apiRmFileCount = metrics.NewRegisteredCounter("api.removefile.count", nil)
  73. apiRmFileFail = metrics.NewRegisteredCounter("api.removefile.fail", nil)
  74. apiAppendFileCount = metrics.NewRegisteredCounter("api.appendfile.count", nil)
  75. apiAppendFileFail = metrics.NewRegisteredCounter("api.appendfile.fail", nil)
  76. apiGetInvalid = metrics.NewRegisteredCounter("api.get.invalid", nil)
  77. )
  78. // Resolver interface resolve a domain name to a hash using ENS
  79. type Resolver interface {
  80. Resolve(string) (common.Hash, error)
  81. }
  82. // ResolveValidator is used to validate the contained Resolver
  83. type ResolveValidator interface {
  84. Resolver
  85. Owner(node [32]byte) (common.Address, error)
  86. HeaderByNumber(context.Context, *big.Int) (*types.Header, error)
  87. }
  88. // NoResolverError is returned by MultiResolver.Resolve if no resolver
  89. // can be found for the address.
  90. type NoResolverError struct {
  91. TLD string
  92. }
  93. // NewNoResolverError creates a NoResolverError for the given top level domain
  94. func NewNoResolverError(tld string) *NoResolverError {
  95. return &NoResolverError{TLD: tld}
  96. }
  97. // Error NoResolverError implements error
  98. func (e *NoResolverError) Error() string {
  99. if e.TLD == "" {
  100. return "no ENS resolver"
  101. }
  102. return fmt.Sprintf("no ENS endpoint configured to resolve .%s TLD names", e.TLD)
  103. }
  104. // MultiResolver is used to resolve URL addresses based on their TLDs.
  105. // Each TLD can have multiple resolvers, and the resolution from the
  106. // first one in the sequence will be returned.
  107. type MultiResolver struct {
  108. resolvers map[string][]ResolveValidator
  109. nameHash func(string) common.Hash
  110. }
  111. // MultiResolverOption sets options for MultiResolver and is used as
  112. // arguments for its constructor.
  113. type MultiResolverOption func(*MultiResolver)
  114. // MultiResolverOptionWithResolver adds a Resolver to a list of resolvers
  115. // for a specific TLD. If TLD is an empty string, the resolver will be added
  116. // to the list of default resolver, the ones that will be used for resolution
  117. // of addresses which do not have their TLD resolver specified.
  118. func MultiResolverOptionWithResolver(r ResolveValidator, tld string) MultiResolverOption {
  119. return func(m *MultiResolver) {
  120. m.resolvers[tld] = append(m.resolvers[tld], r)
  121. }
  122. }
  123. // MultiResolverOptionWithNameHash is unused at the time of this writing
  124. func MultiResolverOptionWithNameHash(nameHash func(string) common.Hash) MultiResolverOption {
  125. return func(m *MultiResolver) {
  126. m.nameHash = nameHash
  127. }
  128. }
  129. // NewMultiResolver creates a new instance of MultiResolver.
  130. func NewMultiResolver(opts ...MultiResolverOption) (m *MultiResolver) {
  131. m = &MultiResolver{
  132. resolvers: make(map[string][]ResolveValidator),
  133. nameHash: ens.EnsNode,
  134. }
  135. for _, o := range opts {
  136. o(m)
  137. }
  138. return m
  139. }
  140. // Resolve resolves address by choosing a Resolver by TLD.
  141. // If there are more default Resolvers, or for a specific TLD,
  142. // the Hash from the first one which does not return error
  143. // will be returned.
  144. func (m *MultiResolver) Resolve(addr string) (h common.Hash, err error) {
  145. rs, err := m.getResolveValidator(addr)
  146. if err != nil {
  147. return h, err
  148. }
  149. for _, r := range rs {
  150. h, err = r.Resolve(addr)
  151. if err == nil {
  152. return
  153. }
  154. }
  155. return
  156. }
  157. // ValidateOwner checks the ENS to validate that the owner of the given domain is the given eth address
  158. func (m *MultiResolver) ValidateOwner(name string, address common.Address) (bool, error) {
  159. rs, err := m.getResolveValidator(name)
  160. if err != nil {
  161. return false, err
  162. }
  163. var addr common.Address
  164. for _, r := range rs {
  165. addr, err = r.Owner(m.nameHash(name))
  166. // we hide the error if it is not for the last resolver we check
  167. if err == nil {
  168. return addr == address, nil
  169. }
  170. }
  171. return false, err
  172. }
  173. // HeaderByNumber uses the validator of the given domainname and retrieves the header for the given block number
  174. func (m *MultiResolver) HeaderByNumber(ctx context.Context, name string, blockNr *big.Int) (*types.Header, error) {
  175. rs, err := m.getResolveValidator(name)
  176. if err != nil {
  177. return nil, err
  178. }
  179. for _, r := range rs {
  180. var header *types.Header
  181. header, err = r.HeaderByNumber(ctx, blockNr)
  182. // we hide the error if it is not for the last resolver we check
  183. if err == nil {
  184. return header, nil
  185. }
  186. }
  187. return nil, err
  188. }
  189. // getResolveValidator uses the hostname to retrieve the resolver associated with the top level domain
  190. func (m *MultiResolver) getResolveValidator(name string) ([]ResolveValidator, error) {
  191. rs := m.resolvers[""]
  192. tld := path.Ext(name)
  193. if tld != "" {
  194. tld = tld[1:]
  195. rstld, ok := m.resolvers[tld]
  196. if ok {
  197. return rstld, nil
  198. }
  199. }
  200. if len(rs) == 0 {
  201. return rs, NewNoResolverError(tld)
  202. }
  203. return rs, nil
  204. }
  205. // SetNameHash sets the hasher function that hashes the domain into a name hash that ENS uses
  206. func (m *MultiResolver) SetNameHash(nameHash func(string) common.Hash) {
  207. m.nameHash = nameHash
  208. }
  209. /*
  210. API implements webserver/file system related content storage and retrieval
  211. on top of the FileStore
  212. it is the public interface of the FileStore which is included in the ethereum stack
  213. */
  214. type API struct {
  215. feed *feed.Handler
  216. fileStore *storage.FileStore
  217. dns Resolver
  218. Decryptor func(context.Context, string) DecryptFunc
  219. }
  220. // NewAPI the api constructor initialises a new API instance.
  221. func NewAPI(fileStore *storage.FileStore, dns Resolver, feedHandler *feed.Handler, pk *ecdsa.PrivateKey) (self *API) {
  222. self = &API{
  223. fileStore: fileStore,
  224. dns: dns,
  225. feed: feedHandler,
  226. Decryptor: func(ctx context.Context, credentials string) DecryptFunc {
  227. return self.doDecrypt(ctx, credentials, pk)
  228. },
  229. }
  230. return
  231. }
  232. // Retrieve FileStore reader API
  233. func (a *API) Retrieve(ctx context.Context, addr storage.Address) (reader storage.LazySectionReader, isEncrypted bool) {
  234. return a.fileStore.Retrieve(ctx, addr)
  235. }
  236. // Store wraps the Store API call of the embedded FileStore
  237. func (a *API) Store(ctx context.Context, data io.Reader, size int64, toEncrypt bool) (addr storage.Address, wait func(ctx context.Context) error, err error) {
  238. log.Debug("api.store", "size", size)
  239. return a.fileStore.Store(ctx, data, size, toEncrypt)
  240. }
  241. // ErrResolve is returned when an URI cannot be resolved from ENS.
  242. type ErrResolve error
  243. // Resolve a name into a content-addressed hash
  244. // where address could be an ENS name, or a content addressed hash
  245. func (a *API) Resolve(ctx context.Context, address string) (storage.Address, error) {
  246. // if DNS is not configured, return an error
  247. if a.dns == nil {
  248. if hashMatcher.MatchString(address) {
  249. return common.Hex2Bytes(address), nil
  250. }
  251. apiResolveFail.Inc(1)
  252. return nil, fmt.Errorf("no DNS to resolve name: %q", address)
  253. }
  254. // try and resolve the address
  255. resolved, err := a.dns.Resolve(address)
  256. if err != nil {
  257. if hashMatcher.MatchString(address) {
  258. return common.Hex2Bytes(address), nil
  259. }
  260. return nil, err
  261. }
  262. return resolved[:], nil
  263. }
  264. // Resolve resolves a URI to an Address using the MultiResolver.
  265. func (a *API) ResolveURI(ctx context.Context, uri *URI, credentials string) (storage.Address, error) {
  266. apiResolveCount.Inc(1)
  267. log.Trace("resolving", "uri", uri.Addr)
  268. var sp opentracing.Span
  269. ctx, sp = spancontext.StartSpan(
  270. ctx,
  271. "api.resolve")
  272. defer sp.Finish()
  273. // if the URI is immutable, check if the address looks like a hash
  274. if uri.Immutable() {
  275. key := uri.Address()
  276. if key == nil {
  277. return nil, fmt.Errorf("immutable address not a content hash: %q", uri.Addr)
  278. }
  279. return key, nil
  280. }
  281. addr, err := a.Resolve(ctx, uri.Addr)
  282. if err != nil {
  283. return nil, err
  284. }
  285. if uri.Path == "" {
  286. return addr, nil
  287. }
  288. walker, err := a.NewManifestWalker(ctx, addr, a.Decryptor(ctx, credentials), nil)
  289. if err != nil {
  290. return nil, err
  291. }
  292. var entry *ManifestEntry
  293. walker.Walk(func(e *ManifestEntry) error {
  294. // if the entry matches the path, set entry and stop
  295. // the walk
  296. if e.Path == uri.Path {
  297. entry = e
  298. // return an error to cancel the walk
  299. return errors.New("found")
  300. }
  301. // ignore non-manifest files
  302. if e.ContentType != ManifestType {
  303. return nil
  304. }
  305. // if the manifest's path is a prefix of the
  306. // requested path, recurse into it by returning
  307. // nil and continuing the walk
  308. if strings.HasPrefix(uri.Path, e.Path) {
  309. return nil
  310. }
  311. return ErrSkipManifest
  312. })
  313. if entry == nil {
  314. return nil, errors.New("not found")
  315. }
  316. addr = storage.Address(common.Hex2Bytes(entry.Hash))
  317. return addr, nil
  318. }
  319. // Put provides singleton manifest creation on top of FileStore store
  320. func (a *API) Put(ctx context.Context, content string, contentType string, toEncrypt bool) (k storage.Address, wait func(context.Context) error, err error) {
  321. apiPutCount.Inc(1)
  322. r := strings.NewReader(content)
  323. key, waitContent, err := a.fileStore.Store(ctx, r, int64(len(content)), toEncrypt)
  324. if err != nil {
  325. apiPutFail.Inc(1)
  326. return nil, nil, err
  327. }
  328. manifest := fmt.Sprintf(`{"entries":[{"hash":"%v","contentType":"%s"}]}`, key, contentType)
  329. r = strings.NewReader(manifest)
  330. key, waitManifest, err := a.fileStore.Store(ctx, r, int64(len(manifest)), toEncrypt)
  331. if err != nil {
  332. apiPutFail.Inc(1)
  333. return nil, nil, err
  334. }
  335. return key, func(ctx context.Context) error {
  336. err := waitContent(ctx)
  337. if err != nil {
  338. return err
  339. }
  340. return waitManifest(ctx)
  341. }, nil
  342. }
  343. // Get uses iterative manifest retrieval and prefix matching
  344. // to resolve basePath to content using FileStore retrieve
  345. // it returns a section reader, mimeType, status, the key of the actual content and an error
  346. func (a *API) Get(ctx context.Context, decrypt DecryptFunc, manifestAddr storage.Address, path string) (reader storage.LazySectionReader, mimeType string, status int, contentAddr storage.Address, err error) {
  347. log.Debug("api.get", "key", manifestAddr, "path", path)
  348. apiGetCount.Inc(1)
  349. trie, err := loadManifest(ctx, a.fileStore, manifestAddr, nil, decrypt)
  350. if err != nil {
  351. apiGetNotFound.Inc(1)
  352. status = http.StatusNotFound
  353. return nil, "", http.StatusNotFound, nil, err
  354. }
  355. log.Debug("trie getting entry", "key", manifestAddr, "path", path)
  356. entry, _ := trie.getEntry(path)
  357. if entry != nil {
  358. log.Debug("trie got entry", "key", manifestAddr, "path", path, "entry.Hash", entry.Hash)
  359. if entry.ContentType == ManifestType {
  360. log.Debug("entry is manifest", "key", manifestAddr, "new key", entry.Hash)
  361. adr, err := hex.DecodeString(entry.Hash)
  362. if err != nil {
  363. return nil, "", 0, nil, err
  364. }
  365. return a.Get(ctx, decrypt, adr, entry.Path)
  366. }
  367. // we need to do some extra work if this is a Swarm feed manifest
  368. if entry.ContentType == FeedContentType {
  369. if entry.Feed == nil {
  370. return reader, mimeType, status, nil, fmt.Errorf("Cannot decode Feed in manifest")
  371. }
  372. _, err := a.feed.Lookup(ctx, feed.NewQueryLatest(entry.Feed, lookup.NoClue))
  373. if err != nil {
  374. apiGetNotFound.Inc(1)
  375. status = http.StatusNotFound
  376. log.Debug(fmt.Sprintf("get feed update content error: %v", err))
  377. return reader, mimeType, status, nil, err
  378. }
  379. // get the data of the update
  380. _, rsrcData, err := a.feed.GetContent(entry.Feed)
  381. if err != nil {
  382. apiGetNotFound.Inc(1)
  383. status = http.StatusNotFound
  384. log.Warn(fmt.Sprintf("get feed update content error: %v", err))
  385. return reader, mimeType, status, nil, err
  386. }
  387. // extract multihash
  388. decodedMultihash, err := multihash.FromMultihash(rsrcData)
  389. if err != nil {
  390. apiGetInvalid.Inc(1)
  391. status = http.StatusUnprocessableEntity
  392. log.Warn("invalid multihash in feed update", "err", err)
  393. return reader, mimeType, status, nil, err
  394. }
  395. manifestAddr = storage.Address(decodedMultihash)
  396. log.Trace("feed update contains multihash", "key", manifestAddr)
  397. // get the manifest the multihash digest points to
  398. trie, err := loadManifest(ctx, a.fileStore, manifestAddr, nil, NOOPDecrypt)
  399. if err != nil {
  400. apiGetNotFound.Inc(1)
  401. status = http.StatusNotFound
  402. log.Warn(fmt.Sprintf("loadManifestTrie (feed update multihash) error: %v", err))
  403. return reader, mimeType, status, nil, err
  404. }
  405. // finally, get the manifest entry
  406. // it will always be the entry on path ""
  407. entry, _ = trie.getEntry(path)
  408. if entry == nil {
  409. status = http.StatusNotFound
  410. apiGetNotFound.Inc(1)
  411. err = fmt.Errorf("manifest (feed update multihash) entry for '%s' not found", path)
  412. log.Trace("manifest (feed update multihash) entry not found", "key", manifestAddr, "path", path)
  413. return reader, mimeType, status, nil, err
  414. }
  415. }
  416. // regardless of feed update manifests or normal manifests we will converge at this point
  417. // get the key the manifest entry points to and serve it if it's unambiguous
  418. contentAddr = common.Hex2Bytes(entry.Hash)
  419. status = entry.Status
  420. if status == http.StatusMultipleChoices {
  421. apiGetHTTP300.Inc(1)
  422. return nil, entry.ContentType, status, contentAddr, err
  423. }
  424. mimeType = entry.ContentType
  425. log.Debug("content lookup key", "key", contentAddr, "mimetype", mimeType)
  426. reader, _ = a.fileStore.Retrieve(ctx, contentAddr)
  427. } else {
  428. // no entry found
  429. status = http.StatusNotFound
  430. apiGetNotFound.Inc(1)
  431. err = fmt.Errorf("manifest entry for '%s' not found", path)
  432. log.Trace("manifest entry not found", "key", contentAddr, "path", path)
  433. }
  434. return
  435. }
  436. func (a *API) Delete(ctx context.Context, addr string, path string) (storage.Address, error) {
  437. apiDeleteCount.Inc(1)
  438. uri, err := Parse("bzz:/" + addr)
  439. if err != nil {
  440. apiDeleteFail.Inc(1)
  441. return nil, err
  442. }
  443. key, err := a.ResolveURI(ctx, uri, EMPTY_CREDENTIALS)
  444. if err != nil {
  445. return nil, err
  446. }
  447. newKey, err := a.UpdateManifest(ctx, key, func(mw *ManifestWriter) error {
  448. log.Debug(fmt.Sprintf("removing %s from manifest %s", path, key.Log()))
  449. return mw.RemoveEntry(path)
  450. })
  451. if err != nil {
  452. apiDeleteFail.Inc(1)
  453. return nil, err
  454. }
  455. return newKey, nil
  456. }
  457. // GetDirectoryTar fetches a requested directory as a tarstream
  458. // it returns an io.Reader and an error. Do not forget to Close() the returned ReadCloser
  459. func (a *API) GetDirectoryTar(ctx context.Context, decrypt DecryptFunc, uri *URI) (io.ReadCloser, error) {
  460. apiGetTarCount.Inc(1)
  461. addr, err := a.Resolve(ctx, uri.Addr)
  462. if err != nil {
  463. return nil, err
  464. }
  465. walker, err := a.NewManifestWalker(ctx, addr, decrypt, nil)
  466. if err != nil {
  467. apiGetTarFail.Inc(1)
  468. return nil, err
  469. }
  470. piper, pipew := io.Pipe()
  471. tw := tar.NewWriter(pipew)
  472. go func() {
  473. err := walker.Walk(func(entry *ManifestEntry) error {
  474. // ignore manifests (walk will recurse into them)
  475. if entry.ContentType == ManifestType {
  476. return nil
  477. }
  478. // retrieve the entry's key and size
  479. reader, _ := a.Retrieve(ctx, storage.Address(common.Hex2Bytes(entry.Hash)))
  480. size, err := reader.Size(ctx, nil)
  481. if err != nil {
  482. return err
  483. }
  484. // write a tar header for the entry
  485. hdr := &tar.Header{
  486. Name: entry.Path,
  487. Mode: entry.Mode,
  488. Size: size,
  489. ModTime: entry.ModTime,
  490. Xattrs: map[string]string{
  491. "user.swarm.content-type": entry.ContentType,
  492. },
  493. }
  494. if err := tw.WriteHeader(hdr); err != nil {
  495. return err
  496. }
  497. // copy the file into the tar stream
  498. n, err := io.Copy(tw, io.LimitReader(reader, hdr.Size))
  499. if err != nil {
  500. return err
  501. } else if n != size {
  502. return fmt.Errorf("error writing %s: expected %d bytes but sent %d", entry.Path, size, n)
  503. }
  504. return nil
  505. })
  506. // close tar writer before closing pipew
  507. // to flush remaining data to pipew
  508. // regardless of error value
  509. tw.Close()
  510. if err != nil {
  511. apiGetTarFail.Inc(1)
  512. pipew.CloseWithError(err)
  513. } else {
  514. pipew.Close()
  515. }
  516. }()
  517. return piper, nil
  518. }
  519. // GetManifestList lists the manifest entries for the specified address and prefix
  520. // and returns it as a ManifestList
  521. func (a *API) GetManifestList(ctx context.Context, decryptor DecryptFunc, addr storage.Address, prefix string) (list ManifestList, err error) {
  522. apiManifestListCount.Inc(1)
  523. walker, err := a.NewManifestWalker(ctx, addr, decryptor, nil)
  524. if err != nil {
  525. apiManifestListFail.Inc(1)
  526. return ManifestList{}, err
  527. }
  528. err = walker.Walk(func(entry *ManifestEntry) error {
  529. // handle non-manifest files
  530. if entry.ContentType != ManifestType {
  531. // ignore the file if it doesn't have the specified prefix
  532. if !strings.HasPrefix(entry.Path, prefix) {
  533. return nil
  534. }
  535. // if the path after the prefix contains a slash, add a
  536. // common prefix to the list, otherwise add the entry
  537. suffix := strings.TrimPrefix(entry.Path, prefix)
  538. if index := strings.Index(suffix, "/"); index > -1 {
  539. list.CommonPrefixes = append(list.CommonPrefixes, prefix+suffix[:index+1])
  540. return nil
  541. }
  542. if entry.Path == "" {
  543. entry.Path = "/"
  544. }
  545. list.Entries = append(list.Entries, entry)
  546. return nil
  547. }
  548. // if the manifest's path is a prefix of the specified prefix
  549. // then just recurse into the manifest by returning nil and
  550. // continuing the walk
  551. if strings.HasPrefix(prefix, entry.Path) {
  552. return nil
  553. }
  554. // if the manifest's path has the specified prefix, then if the
  555. // path after the prefix contains a slash, add a common prefix
  556. // to the list and skip the manifest, otherwise recurse into
  557. // the manifest by returning nil and continuing the walk
  558. if strings.HasPrefix(entry.Path, prefix) {
  559. suffix := strings.TrimPrefix(entry.Path, prefix)
  560. if index := strings.Index(suffix, "/"); index > -1 {
  561. list.CommonPrefixes = append(list.CommonPrefixes, prefix+suffix[:index+1])
  562. return ErrSkipManifest
  563. }
  564. return nil
  565. }
  566. // the manifest neither has the prefix or needs recursing in to
  567. // so just skip it
  568. return ErrSkipManifest
  569. })
  570. if err != nil {
  571. apiManifestListFail.Inc(1)
  572. return ManifestList{}, err
  573. }
  574. return list, nil
  575. }
  576. func (a *API) UpdateManifest(ctx context.Context, addr storage.Address, update func(mw *ManifestWriter) error) (storage.Address, error) {
  577. apiManifestUpdateCount.Inc(1)
  578. mw, err := a.NewManifestWriter(ctx, addr, nil)
  579. if err != nil {
  580. apiManifestUpdateFail.Inc(1)
  581. return nil, err
  582. }
  583. if err := update(mw); err != nil {
  584. apiManifestUpdateFail.Inc(1)
  585. return nil, err
  586. }
  587. addr, err = mw.Store()
  588. if err != nil {
  589. apiManifestUpdateFail.Inc(1)
  590. return nil, err
  591. }
  592. log.Debug(fmt.Sprintf("generated manifest %s", addr))
  593. return addr, nil
  594. }
  595. // Modify loads manifest and checks the content hash before recalculating and storing the manifest.
  596. func (a *API) Modify(ctx context.Context, addr storage.Address, path, contentHash, contentType string) (storage.Address, error) {
  597. apiModifyCount.Inc(1)
  598. quitC := make(chan bool)
  599. trie, err := loadManifest(ctx, a.fileStore, addr, quitC, NOOPDecrypt)
  600. if err != nil {
  601. apiModifyFail.Inc(1)
  602. return nil, err
  603. }
  604. if contentHash != "" {
  605. entry := newManifestTrieEntry(&ManifestEntry{
  606. Path: path,
  607. ContentType: contentType,
  608. }, nil)
  609. entry.Hash = contentHash
  610. trie.addEntry(entry, quitC)
  611. } else {
  612. trie.deleteEntry(path, quitC)
  613. }
  614. if err := trie.recalcAndStore(); err != nil {
  615. apiModifyFail.Inc(1)
  616. return nil, err
  617. }
  618. return trie.ref, nil
  619. }
  620. // AddFile creates a new manifest entry, adds it to swarm, then adds a file to swarm.
  621. func (a *API) AddFile(ctx context.Context, mhash, path, fname string, content []byte, nameresolver bool) (storage.Address, string, error) {
  622. apiAddFileCount.Inc(1)
  623. uri, err := Parse("bzz:/" + mhash)
  624. if err != nil {
  625. apiAddFileFail.Inc(1)
  626. return nil, "", err
  627. }
  628. mkey, err := a.ResolveURI(ctx, uri, EMPTY_CREDENTIALS)
  629. if err != nil {
  630. apiAddFileFail.Inc(1)
  631. return nil, "", err
  632. }
  633. // trim the root dir we added
  634. if path[:1] == "/" {
  635. path = path[1:]
  636. }
  637. entry := &ManifestEntry{
  638. Path: filepath.Join(path, fname),
  639. ContentType: mime.TypeByExtension(filepath.Ext(fname)),
  640. Mode: 0700,
  641. Size: int64(len(content)),
  642. ModTime: time.Now(),
  643. }
  644. mw, err := a.NewManifestWriter(ctx, mkey, nil)
  645. if err != nil {
  646. apiAddFileFail.Inc(1)
  647. return nil, "", err
  648. }
  649. fkey, err := mw.AddEntry(ctx, bytes.NewReader(content), entry)
  650. if err != nil {
  651. apiAddFileFail.Inc(1)
  652. return nil, "", err
  653. }
  654. newMkey, err := mw.Store()
  655. if err != nil {
  656. apiAddFileFail.Inc(1)
  657. return nil, "", err
  658. }
  659. return fkey, newMkey.String(), nil
  660. }
  661. func (a *API) UploadTar(ctx context.Context, bodyReader io.ReadCloser, manifestPath, defaultPath string, mw *ManifestWriter) (storage.Address, error) {
  662. apiUploadTarCount.Inc(1)
  663. var contentKey storage.Address
  664. tr := tar.NewReader(bodyReader)
  665. defer bodyReader.Close()
  666. var defaultPathFound bool
  667. for {
  668. hdr, err := tr.Next()
  669. if err == io.EOF {
  670. break
  671. } else if err != nil {
  672. apiUploadTarFail.Inc(1)
  673. return nil, fmt.Errorf("error reading tar stream: %s", err)
  674. }
  675. // only store regular files
  676. if !hdr.FileInfo().Mode().IsRegular() {
  677. continue
  678. }
  679. // add the entry under the path from the request
  680. manifestPath := path.Join(manifestPath, hdr.Name)
  681. contentType := hdr.Xattrs["user.swarm.content-type"]
  682. if contentType == "" {
  683. contentType = mime.TypeByExtension(filepath.Ext(hdr.Name))
  684. }
  685. //DetectContentType("")
  686. entry := &ManifestEntry{
  687. Path: manifestPath,
  688. ContentType: contentType,
  689. Mode: hdr.Mode,
  690. Size: hdr.Size,
  691. ModTime: hdr.ModTime,
  692. }
  693. contentKey, err = mw.AddEntry(ctx, tr, entry)
  694. if err != nil {
  695. apiUploadTarFail.Inc(1)
  696. return nil, fmt.Errorf("error adding manifest entry from tar stream: %s", err)
  697. }
  698. if hdr.Name == defaultPath {
  699. contentType := hdr.Xattrs["user.swarm.content-type"]
  700. if contentType == "" {
  701. contentType = mime.TypeByExtension(filepath.Ext(hdr.Name))
  702. }
  703. entry := &ManifestEntry{
  704. Hash: contentKey.Hex(),
  705. Path: "", // default entry
  706. ContentType: contentType,
  707. Mode: hdr.Mode,
  708. Size: hdr.Size,
  709. ModTime: hdr.ModTime,
  710. }
  711. contentKey, err = mw.AddEntry(ctx, nil, entry)
  712. if err != nil {
  713. apiUploadTarFail.Inc(1)
  714. return nil, fmt.Errorf("error adding default manifest entry from tar stream: %s", err)
  715. }
  716. defaultPathFound = true
  717. }
  718. }
  719. if defaultPath != "" && !defaultPathFound {
  720. return contentKey, fmt.Errorf("default path %q not found", defaultPath)
  721. }
  722. return contentKey, nil
  723. }
  724. // RemoveFile removes a file entry in a manifest.
  725. func (a *API) RemoveFile(ctx context.Context, mhash string, path string, fname string, nameresolver bool) (string, error) {
  726. apiRmFileCount.Inc(1)
  727. uri, err := Parse("bzz:/" + mhash)
  728. if err != nil {
  729. apiRmFileFail.Inc(1)
  730. return "", err
  731. }
  732. mkey, err := a.ResolveURI(ctx, uri, EMPTY_CREDENTIALS)
  733. if err != nil {
  734. apiRmFileFail.Inc(1)
  735. return "", err
  736. }
  737. // trim the root dir we added
  738. if path[:1] == "/" {
  739. path = path[1:]
  740. }
  741. mw, err := a.NewManifestWriter(ctx, mkey, nil)
  742. if err != nil {
  743. apiRmFileFail.Inc(1)
  744. return "", err
  745. }
  746. err = mw.RemoveEntry(filepath.Join(path, fname))
  747. if err != nil {
  748. apiRmFileFail.Inc(1)
  749. return "", err
  750. }
  751. newMkey, err := mw.Store()
  752. if err != nil {
  753. apiRmFileFail.Inc(1)
  754. return "", err
  755. }
  756. return newMkey.String(), nil
  757. }
  758. // AppendFile removes old manifest, appends file entry to new manifest and adds it to Swarm.
  759. func (a *API) AppendFile(ctx context.Context, mhash, path, fname string, existingSize int64, content []byte, oldAddr storage.Address, offset int64, addSize int64, nameresolver bool) (storage.Address, string, error) {
  760. apiAppendFileCount.Inc(1)
  761. buffSize := offset + addSize
  762. if buffSize < existingSize {
  763. buffSize = existingSize
  764. }
  765. buf := make([]byte, buffSize)
  766. oldReader, _ := a.Retrieve(ctx, oldAddr)
  767. io.ReadAtLeast(oldReader, buf, int(offset))
  768. newReader := bytes.NewReader(content)
  769. io.ReadAtLeast(newReader, buf[offset:], int(addSize))
  770. if buffSize < existingSize {
  771. io.ReadAtLeast(oldReader, buf[addSize:], int(buffSize))
  772. }
  773. combinedReader := bytes.NewReader(buf)
  774. totalSize := int64(len(buf))
  775. // TODO(jmozah): to append using pyramid chunker when it is ready
  776. //oldReader := a.Retrieve(oldKey)
  777. //newReader := bytes.NewReader(content)
  778. //combinedReader := io.MultiReader(oldReader, newReader)
  779. uri, err := Parse("bzz:/" + mhash)
  780. if err != nil {
  781. apiAppendFileFail.Inc(1)
  782. return nil, "", err
  783. }
  784. mkey, err := a.ResolveURI(ctx, uri, EMPTY_CREDENTIALS)
  785. if err != nil {
  786. apiAppendFileFail.Inc(1)
  787. return nil, "", err
  788. }
  789. // trim the root dir we added
  790. if path[:1] == "/" {
  791. path = path[1:]
  792. }
  793. mw, err := a.NewManifestWriter(ctx, mkey, nil)
  794. if err != nil {
  795. apiAppendFileFail.Inc(1)
  796. return nil, "", err
  797. }
  798. err = mw.RemoveEntry(filepath.Join(path, fname))
  799. if err != nil {
  800. apiAppendFileFail.Inc(1)
  801. return nil, "", err
  802. }
  803. entry := &ManifestEntry{
  804. Path: filepath.Join(path, fname),
  805. ContentType: mime.TypeByExtension(filepath.Ext(fname)),
  806. Mode: 0700,
  807. Size: totalSize,
  808. ModTime: time.Now(),
  809. }
  810. fkey, err := mw.AddEntry(ctx, io.Reader(combinedReader), entry)
  811. if err != nil {
  812. apiAppendFileFail.Inc(1)
  813. return nil, "", err
  814. }
  815. newMkey, err := mw.Store()
  816. if err != nil {
  817. apiAppendFileFail.Inc(1)
  818. return nil, "", err
  819. }
  820. return fkey, newMkey.String(), nil
  821. }
  822. // BuildDirectoryTree used by swarmfs_unix
  823. func (a *API) BuildDirectoryTree(ctx context.Context, mhash string, nameresolver bool) (addr storage.Address, manifestEntryMap map[string]*manifestTrieEntry, err error) {
  824. uri, err := Parse("bzz:/" + mhash)
  825. if err != nil {
  826. return nil, nil, err
  827. }
  828. addr, err = a.Resolve(ctx, uri.Addr)
  829. if err != nil {
  830. return nil, nil, err
  831. }
  832. quitC := make(chan bool)
  833. rootTrie, err := loadManifest(ctx, a.fileStore, addr, quitC, NOOPDecrypt)
  834. if err != nil {
  835. return nil, nil, fmt.Errorf("can't load manifest %v: %v", addr.String(), err)
  836. }
  837. manifestEntryMap = map[string]*manifestTrieEntry{}
  838. err = rootTrie.listWithPrefix(uri.Path, quitC, func(entry *manifestTrieEntry, suffix string) {
  839. manifestEntryMap[suffix] = entry
  840. })
  841. if err != nil {
  842. return nil, nil, fmt.Errorf("list with prefix failed %v: %v", addr.String(), err)
  843. }
  844. return addr, manifestEntryMap, nil
  845. }
  846. // FeedsLookup finds Swarm feeds updates at specific points in time, or the latest update
  847. func (a *API) FeedsLookup(ctx context.Context, query *feed.Query) ([]byte, error) {
  848. _, err := a.feed.Lookup(ctx, query)
  849. if err != nil {
  850. return nil, err
  851. }
  852. var data []byte
  853. _, data, err = a.feed.GetContent(&query.Feed)
  854. if err != nil {
  855. return nil, err
  856. }
  857. return data, nil
  858. }
  859. // FeedsNewRequest creates a Request object to update a specific feed
  860. func (a *API) FeedsNewRequest(ctx context.Context, feed *feed.Feed) (*feed.Request, error) {
  861. return a.feed.NewRequest(ctx, feed)
  862. }
  863. // FeedsUpdate publishes a new update on the given feed
  864. func (a *API) FeedsUpdate(ctx context.Context, request *feed.Request) (storage.Address, error) {
  865. return a.feed.Update(ctx, request)
  866. }
  867. // FeedsHashSize returned the size of the digest produced by Swarm feeds' hashing function
  868. func (a *API) FeedsHashSize() int {
  869. return a.feed.HashSize
  870. }
  871. // ErrCannotLoadFeedManifest is returned when looking up a feeds manifest fails
  872. var ErrCannotLoadFeedManifest = errors.New("Cannot load feed manifest")
  873. // ErrNotAFeedManifest is returned when the address provided returned something other than a valid manifest
  874. var ErrNotAFeedManifest = errors.New("Not a feed manifest")
  875. // ResolveFeedManifest retrieves the Swarm feed manifest for the given address, and returns the referenced Feed.
  876. func (a *API) ResolveFeedManifest(ctx context.Context, addr storage.Address) (*feed.Feed, error) {
  877. trie, err := loadManifest(ctx, a.fileStore, addr, nil, NOOPDecrypt)
  878. if err != nil {
  879. return nil, ErrCannotLoadFeedManifest
  880. }
  881. entry, _ := trie.getEntry("")
  882. if entry.ContentType != FeedContentType {
  883. return nil, ErrNotAFeedManifest
  884. }
  885. return entry.Feed, nil
  886. }
  887. // ErrCannotResolveFeedURI is returned when the ENS resolver is not able to translate a name to a Swarm feed
  888. var ErrCannotResolveFeedURI = errors.New("Cannot resolve Feed URI")
  889. // ErrCannotResolveFeed is returned when values provided are not enough or invalid to recreate a
  890. // feed out of them.
  891. var ErrCannotResolveFeed = errors.New("Cannot resolve Feed")
  892. // ResolveFeed attempts to extract feed information out of the manifest, if provided
  893. // If not, it attempts to extract the feed out of a set of key-value pairs
  894. func (a *API) ResolveFeed(ctx context.Context, uri *URI, values feed.Values) (*feed.Feed, error) {
  895. var fd *feed.Feed
  896. var err error
  897. if uri.Addr != "" {
  898. // resolve the content key.
  899. manifestAddr := uri.Address()
  900. if manifestAddr == nil {
  901. manifestAddr, err = a.Resolve(ctx, uri.Addr)
  902. if err != nil {
  903. return nil, ErrCannotResolveFeedURI
  904. }
  905. }
  906. // get the Swarm feed from the manifest
  907. fd, err = a.ResolveFeedManifest(ctx, manifestAddr)
  908. if err != nil {
  909. return nil, err
  910. }
  911. log.Debug("handle.get.feed: resolved", "manifestkey", manifestAddr, "feed", fd.Hex())
  912. } else {
  913. var f feed.Feed
  914. if err := f.FromValues(values); err != nil {
  915. return nil, ErrCannotResolveFeed
  916. }
  917. fd = &f
  918. }
  919. return fd, nil
  920. }
  921. // MimeOctetStream default value of http Content-Type header
  922. const MimeOctetStream = "application/octet-stream"
  923. // DetectContentType by file file extension, or fallback to content sniff
  924. func DetectContentType(fileName string, f io.ReadSeeker) (string, error) {
  925. ctype := mime.TypeByExtension(filepath.Ext(fileName))
  926. if ctype != "" {
  927. return ctype, nil
  928. }
  929. // save/rollback to get content probe from begin of file
  930. currentPosition, err := f.Seek(0, io.SeekCurrent)
  931. if err != nil {
  932. return MimeOctetStream, fmt.Errorf("seeker can't seek, %s", err)
  933. }
  934. // read a chunk to decide between utf-8 text and binary
  935. var buf [512]byte
  936. n, _ := f.Read(buf[:])
  937. ctype = http.DetectContentType(buf[:n])
  938. _, err = f.Seek(currentPosition, io.SeekStart) // rewind to output whole file
  939. if err != nil {
  940. return MimeOctetStream, fmt.Errorf("seeker can't seek, %s", err)
  941. }
  942. return ctype, nil
  943. }