server_test.go 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297
  1. // Copyright 2017 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 http
  17. import (
  18. "archive/tar"
  19. "bytes"
  20. "context"
  21. "crypto/rand"
  22. "encoding/json"
  23. "errors"
  24. "flag"
  25. "fmt"
  26. "io"
  27. "io/ioutil"
  28. "math/big"
  29. "mime/multipart"
  30. "net/http"
  31. "net/url"
  32. "os"
  33. "path"
  34. "strconv"
  35. "strings"
  36. "testing"
  37. "time"
  38. "github.com/ethereum/go-ethereum/swarm/storage/mru/lookup"
  39. "github.com/ethereum/go-ethereum/common"
  40. "github.com/ethereum/go-ethereum/core/types"
  41. "github.com/ethereum/go-ethereum/crypto"
  42. "github.com/ethereum/go-ethereum/log"
  43. "github.com/ethereum/go-ethereum/swarm/api"
  44. swarm "github.com/ethereum/go-ethereum/swarm/api/client"
  45. "github.com/ethereum/go-ethereum/swarm/multihash"
  46. "github.com/ethereum/go-ethereum/swarm/storage"
  47. "github.com/ethereum/go-ethereum/swarm/storage/mru"
  48. "github.com/ethereum/go-ethereum/swarm/testutil"
  49. )
  50. func init() {
  51. loglevel := flag.Int("loglevel", 2, "loglevel")
  52. flag.Parse()
  53. log.Root().SetHandler(log.CallerFileHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(os.Stderr, log.TerminalFormat(true)))))
  54. }
  55. func TestResourcePostMode(t *testing.T) {
  56. path := ""
  57. errstr := "resourcePostMode for '%s' should be raw %v frequency %d, was raw %v, frequency %d"
  58. r, f, err := resourcePostMode(path)
  59. if err != nil {
  60. t.Fatal(err)
  61. } else if r || f != 0 {
  62. t.Fatalf(errstr, path, false, 0, r, f)
  63. }
  64. path = "raw"
  65. r, f, err = resourcePostMode(path)
  66. if err != nil {
  67. t.Fatal(err)
  68. } else if !r || f != 0 {
  69. t.Fatalf(errstr, path, true, 0, r, f)
  70. }
  71. path = "13"
  72. r, f, err = resourcePostMode(path)
  73. if err != nil {
  74. t.Fatal(err)
  75. } else if r || f == 0 {
  76. t.Fatalf(errstr, path, false, 13, r, f)
  77. }
  78. path = "raw/13"
  79. r, f, err = resourcePostMode(path)
  80. if err != nil {
  81. t.Fatal(err)
  82. } else if !r || f == 0 {
  83. t.Fatalf(errstr, path, true, 13, r, f)
  84. }
  85. path = "foo/13"
  86. r, f, err = resourcePostMode(path)
  87. if err == nil {
  88. t.Fatal("resourcePostMode for 'foo/13' should fail, returned error nil")
  89. }
  90. }
  91. func serverFunc(api *api.API) testutil.TestServer {
  92. return NewServer(api, "")
  93. }
  94. func newTestSigner() (*mru.GenericSigner, error) {
  95. privKey, err := crypto.HexToECDSA("deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef")
  96. if err != nil {
  97. return nil, err
  98. }
  99. return mru.NewGenericSigner(privKey), nil
  100. }
  101. // test the transparent resolving of multihash resource types with bzz:// scheme
  102. //
  103. // first upload data, and store the multihash to the resulting manifest in a resource update
  104. // retrieving the update with the multihash should return the manifest pointing directly to the data
  105. // and raw retrieve of that hash should return the data
  106. func TestBzzResourceMultihash(t *testing.T) {
  107. signer, _ := newTestSigner()
  108. srv := testutil.NewTestSwarmServer(t, serverFunc, nil)
  109. defer srv.Close()
  110. // add the data our multihash aliased manifest will point to
  111. databytes := "bar"
  112. testBzzUrl := fmt.Sprintf("%s/bzz:/", srv.URL)
  113. resp, err := http.Post(testBzzUrl, "text/plain", bytes.NewReader([]byte(databytes)))
  114. if err != nil {
  115. t.Fatal(err)
  116. }
  117. defer resp.Body.Close()
  118. if resp.StatusCode != http.StatusOK {
  119. t.Fatalf("err %s", resp.Status)
  120. }
  121. b, err := ioutil.ReadAll(resp.Body)
  122. if err != nil {
  123. t.Fatal(err)
  124. }
  125. s := common.FromHex(string(b))
  126. mh := multihash.ToMultihash(s)
  127. log.Info("added data", "manifest", string(b), "data", common.ToHex(mh))
  128. topic, _ := mru.NewTopic("foo.eth", nil)
  129. updateRequest := mru.NewFirstRequest(topic)
  130. updateRequest.SetData(mh)
  131. if err := updateRequest.Sign(signer); err != nil {
  132. t.Fatal(err)
  133. }
  134. log.Info("added data", "manifest", string(b), "data", common.ToHex(mh))
  135. testUrl, err := url.Parse(fmt.Sprintf("%s/bzz-resource:/", srv.URL))
  136. if err != nil {
  137. t.Fatal(err)
  138. }
  139. query := testUrl.Query()
  140. body := updateRequest.AppendValues(query) // this adds all query parameters and returns the data to be posted
  141. query.Set("manifest", "1") // indicate we want a manifest back
  142. testUrl.RawQuery = query.Encode()
  143. // create the multihash update
  144. resp, err = http.Post(testUrl.String(), "application/octet-stream", bytes.NewReader(body))
  145. if err != nil {
  146. t.Fatal(err)
  147. }
  148. defer resp.Body.Close()
  149. if resp.StatusCode != http.StatusOK {
  150. t.Fatalf("err %s", resp.Status)
  151. }
  152. b, err = ioutil.ReadAll(resp.Body)
  153. if err != nil {
  154. t.Fatal(err)
  155. }
  156. rsrcResp := &storage.Address{}
  157. err = json.Unmarshal(b, rsrcResp)
  158. if err != nil {
  159. t.Fatalf("data %s could not be unmarshaled: %v", b, err)
  160. }
  161. correctManifestAddrHex := "6ef40ba1492cf2a029dc9a8b5896c822cf689d3cd010842f4f1744e6db8824bd"
  162. if rsrcResp.Hex() != correctManifestAddrHex {
  163. t.Fatalf("Response resource key mismatch, expected '%s', got '%s'", correctManifestAddrHex, rsrcResp.Hex())
  164. }
  165. // get bzz manifest transparent resource resolve
  166. testBzzUrl = fmt.Sprintf("%s/bzz:/%s", srv.URL, rsrcResp)
  167. resp, err = http.Get(testBzzUrl)
  168. if err != nil {
  169. t.Fatal(err)
  170. }
  171. defer resp.Body.Close()
  172. if resp.StatusCode != http.StatusOK {
  173. t.Fatalf("err %s", resp.Status)
  174. }
  175. b, err = ioutil.ReadAll(resp.Body)
  176. if err != nil {
  177. t.Fatal(err)
  178. }
  179. if !bytes.Equal(b, []byte(databytes)) {
  180. t.Fatalf("retrieved data mismatch, expected %x, got %x", databytes, b)
  181. }
  182. }
  183. // Test Swarm Feeds using the raw update methods
  184. func TestBzzResource(t *testing.T) {
  185. srv := testutil.NewTestSwarmServer(t, serverFunc, nil)
  186. signer, _ := newTestSigner()
  187. defer srv.Close()
  188. // data of update 1
  189. update1Data := make([]byte, 666)
  190. update1Timestamp := srv.CurrentTime
  191. _, err := rand.Read(update1Data)
  192. if err != nil {
  193. t.Fatal(err)
  194. }
  195. //data for update 2
  196. update2Data := []byte("foo")
  197. topic, _ := mru.NewTopic("foo.eth", nil)
  198. updateRequest := mru.NewFirstRequest(topic)
  199. if err != nil {
  200. t.Fatal(err)
  201. }
  202. updateRequest.SetData(update1Data)
  203. if err := updateRequest.Sign(signer); err != nil {
  204. t.Fatal(err)
  205. }
  206. // creates resource and sets update 1
  207. testUrl, err := url.Parse(fmt.Sprintf("%s/bzz-resource:/", srv.URL))
  208. if err != nil {
  209. t.Fatal(err)
  210. }
  211. urlQuery := testUrl.Query()
  212. body := updateRequest.AppendValues(urlQuery) // this adds all query parameters
  213. urlQuery.Set("manifest", "1") // indicate we want a manifest back
  214. testUrl.RawQuery = urlQuery.Encode()
  215. resp, err := http.Post(testUrl.String(), "application/octet-stream", bytes.NewReader(body))
  216. if err != nil {
  217. t.Fatal(err)
  218. }
  219. defer resp.Body.Close()
  220. if resp.StatusCode != http.StatusOK {
  221. t.Fatalf("err %s", resp.Status)
  222. }
  223. b, err := ioutil.ReadAll(resp.Body)
  224. if err != nil {
  225. t.Fatal(err)
  226. }
  227. rsrcResp := &storage.Address{}
  228. err = json.Unmarshal(b, rsrcResp)
  229. if err != nil {
  230. t.Fatalf("data %s could not be unmarshaled: %v", b, err)
  231. }
  232. correctManifestAddrHex := "6ef40ba1492cf2a029dc9a8b5896c822cf689d3cd010842f4f1744e6db8824bd"
  233. if rsrcResp.Hex() != correctManifestAddrHex {
  234. t.Fatalf("Response resource manifest mismatch, expected '%s', got '%s'", correctManifestAddrHex, rsrcResp.Hex())
  235. }
  236. // get the manifest
  237. testRawUrl := fmt.Sprintf("%s/bzz-raw:/%s", srv.URL, rsrcResp)
  238. resp, err = http.Get(testRawUrl)
  239. if err != nil {
  240. t.Fatal(err)
  241. }
  242. defer resp.Body.Close()
  243. if resp.StatusCode != http.StatusOK {
  244. t.Fatalf("err %s", resp.Status)
  245. }
  246. b, err = ioutil.ReadAll(resp.Body)
  247. if err != nil {
  248. t.Fatal(err)
  249. }
  250. manifest := &api.Manifest{}
  251. err = json.Unmarshal(b, manifest)
  252. if err != nil {
  253. t.Fatal(err)
  254. }
  255. if len(manifest.Entries) != 1 {
  256. t.Fatalf("Manifest has %d entries", len(manifest.Entries))
  257. }
  258. correctViewHex := "0x666f6f2e65746800000000000000000000000000000000000000000000000000c96aaa54e2d44c299564da76e1cd3184a2386b8d"
  259. if manifest.Entries[0].ResourceView.Hex() != correctViewHex {
  260. t.Fatalf("Expected manifest Resource View '%s', got '%s'", correctViewHex, manifest.Entries[0].ResourceView.Hex())
  261. }
  262. // get bzz manifest transparent resource resolve
  263. testBzzUrl := fmt.Sprintf("%s/bzz:/%s", srv.URL, rsrcResp)
  264. resp, err = http.Get(testBzzUrl)
  265. if err != nil {
  266. t.Fatal(err)
  267. }
  268. defer resp.Body.Close()
  269. if resp.StatusCode == http.StatusOK {
  270. t.Fatal("Expected error status since resource is not multihash. Received 200 OK")
  271. }
  272. b, err = ioutil.ReadAll(resp.Body)
  273. if err != nil {
  274. t.Fatal(err)
  275. }
  276. // get non-existent name, should fail
  277. testBzzResUrl := fmt.Sprintf("%s/bzz-resource:/bar", srv.URL)
  278. resp, err = http.Get(testBzzResUrl)
  279. if err != nil {
  280. t.Fatal(err)
  281. }
  282. if resp.StatusCode != http.StatusNotFound {
  283. t.Fatalf("Expected get non-existent resource to fail with StatusNotFound (404), got %d", resp.StatusCode)
  284. }
  285. resp.Body.Close()
  286. // get latest update (1.1) through resource directly
  287. log.Info("get update latest = 1.1", "addr", correctManifestAddrHex)
  288. testBzzResUrl = fmt.Sprintf("%s/bzz-resource:/%s", srv.URL, correctManifestAddrHex)
  289. resp, err = http.Get(testBzzResUrl)
  290. if err != nil {
  291. t.Fatal(err)
  292. }
  293. defer resp.Body.Close()
  294. if resp.StatusCode != http.StatusOK {
  295. t.Fatalf("err %s", resp.Status)
  296. }
  297. b, err = ioutil.ReadAll(resp.Body)
  298. if err != nil {
  299. t.Fatal(err)
  300. }
  301. if !bytes.Equal(update1Data, b) {
  302. t.Fatalf("Expected body '%x', got '%x'", update1Data, b)
  303. }
  304. // update 2
  305. // Move the clock ahead 1 second
  306. srv.CurrentTime++
  307. log.Info("update 2")
  308. // 1.- get metadata about this resource
  309. testBzzResUrl = fmt.Sprintf("%s/bzz-resource:/%s/", srv.URL, correctManifestAddrHex)
  310. resp, err = http.Get(testBzzResUrl + "?meta=1")
  311. if err != nil {
  312. t.Fatal(err)
  313. }
  314. defer resp.Body.Close()
  315. if resp.StatusCode != http.StatusOK {
  316. t.Fatalf("Get resource metadata returned %s", resp.Status)
  317. }
  318. b, err = ioutil.ReadAll(resp.Body)
  319. if err != nil {
  320. t.Fatal(err)
  321. }
  322. updateRequest = &mru.Request{}
  323. if err = updateRequest.UnmarshalJSON(b); err != nil {
  324. t.Fatalf("Error decoding resource metadata: %s", err)
  325. }
  326. updateRequest.SetData(update2Data)
  327. if err = updateRequest.Sign(signer); err != nil {
  328. t.Fatal(err)
  329. }
  330. testUrl, err = url.Parse(fmt.Sprintf("%s/bzz-resource:/", srv.URL))
  331. if err != nil {
  332. t.Fatal(err)
  333. }
  334. urlQuery = testUrl.Query()
  335. body = updateRequest.AppendValues(urlQuery) // this adds all query parameters
  336. testUrl.RawQuery = urlQuery.Encode()
  337. resp, err = http.Post(testUrl.String(), "application/octet-stream", bytes.NewReader(body))
  338. if err != nil {
  339. t.Fatal(err)
  340. }
  341. defer resp.Body.Close()
  342. if resp.StatusCode != http.StatusOK {
  343. t.Fatalf("Update returned %s", resp.Status)
  344. }
  345. // get latest update (1.2) through resource directly
  346. log.Info("get update 1.2")
  347. testBzzResUrl = fmt.Sprintf("%s/bzz-resource:/%s", srv.URL, correctManifestAddrHex)
  348. resp, err = http.Get(testBzzResUrl)
  349. if err != nil {
  350. t.Fatal(err)
  351. }
  352. defer resp.Body.Close()
  353. if resp.StatusCode != http.StatusOK {
  354. t.Fatalf("err %s", resp.Status)
  355. }
  356. b, err = ioutil.ReadAll(resp.Body)
  357. if err != nil {
  358. t.Fatal(err)
  359. }
  360. if !bytes.Equal(update2Data, b) {
  361. t.Fatalf("Expected body '%x', got '%x'", update2Data, b)
  362. }
  363. // test manifest-less queries
  364. log.Info("get first update in update1Timestamp via direct query")
  365. query := mru.NewQuery(&updateRequest.Feed, update1Timestamp, lookup.NoClue)
  366. urlq, err := url.Parse(fmt.Sprintf("%s/bzz-resource:/", srv.URL))
  367. if err != nil {
  368. t.Fatal(err)
  369. }
  370. values := urlq.Query()
  371. query.AppendValues(values) // this adds view query parameters
  372. urlq.RawQuery = values.Encode()
  373. resp, err = http.Get(urlq.String())
  374. if err != nil {
  375. t.Fatal(err)
  376. }
  377. defer resp.Body.Close()
  378. if resp.StatusCode != http.StatusOK {
  379. t.Fatalf("err %s", resp.Status)
  380. }
  381. b, err = ioutil.ReadAll(resp.Body)
  382. if err != nil {
  383. t.Fatal(err)
  384. }
  385. if !bytes.Equal(update1Data, b) {
  386. t.Fatalf("Expected body '%x', got '%x'", update1Data, b)
  387. }
  388. }
  389. func TestBzzGetPath(t *testing.T) {
  390. testBzzGetPath(false, t)
  391. testBzzGetPath(true, t)
  392. }
  393. func testBzzGetPath(encrypted bool, t *testing.T) {
  394. var err error
  395. testmanifest := []string{
  396. `{"entries":[{"path":"b","hash":"011b4d03dd8c01f1049143cf9c4c817e4b167f1d1b83e5c6f0f10d89ba1e7bce","contentType":"","status":0},{"path":"c","hash":"011b4d03dd8c01f1049143cf9c4c817e4b167f1d1b83e5c6f0f10d89ba1e7bce","contentType":"","status":0}]}`,
  397. `{"entries":[{"path":"a","hash":"011b4d03dd8c01f1049143cf9c4c817e4b167f1d1b83e5c6f0f10d89ba1e7bce","contentType":"","status":0},{"path":"b/","hash":"<key0>","contentType":"application/bzz-manifest+json","status":0}]}`,
  398. `{"entries":[{"path":"a/","hash":"<key1>","contentType":"application/bzz-manifest+json","status":0}]}`,
  399. }
  400. testrequests := make(map[string]int)
  401. testrequests["/"] = 2
  402. testrequests["/a/"] = 1
  403. testrequests["/a/b/"] = 0
  404. testrequests["/x"] = 0
  405. testrequests[""] = 0
  406. expectedfailrequests := []string{"", "/x"}
  407. reader := [3]*bytes.Reader{}
  408. addr := [3]storage.Address{}
  409. srv := testutil.NewTestSwarmServer(t, serverFunc, nil)
  410. defer srv.Close()
  411. for i, mf := range testmanifest {
  412. reader[i] = bytes.NewReader([]byte(mf))
  413. var wait func(context.Context) error
  414. ctx := context.TODO()
  415. addr[i], wait, err = srv.FileStore.Store(ctx, reader[i], int64(len(mf)), encrypted)
  416. if err != nil {
  417. t.Fatal(err)
  418. }
  419. for j := i + 1; j < len(testmanifest); j++ {
  420. testmanifest[j] = strings.Replace(testmanifest[j], fmt.Sprintf("<key%v>", i), addr[i].Hex(), -1)
  421. }
  422. err = wait(ctx)
  423. if err != nil {
  424. t.Fatal(err)
  425. }
  426. }
  427. rootRef := addr[2].Hex()
  428. _, err = http.Get(srv.URL + "/bzz-raw:/" + rootRef + "/a")
  429. if err != nil {
  430. t.Fatalf("Failed to connect to proxy: %v", err)
  431. }
  432. for k, v := range testrequests {
  433. var resp *http.Response
  434. var respbody []byte
  435. url := srv.URL + "/bzz-raw:/"
  436. if k != "" {
  437. url += rootRef + "/" + k[1:] + "?content_type=text/plain"
  438. }
  439. resp, err = http.Get(url)
  440. if err != nil {
  441. t.Fatalf("Request failed: %v", err)
  442. }
  443. defer resp.Body.Close()
  444. respbody, err = ioutil.ReadAll(resp.Body)
  445. if string(respbody) != testmanifest[v] {
  446. isexpectedfailrequest := false
  447. for _, r := range expectedfailrequests {
  448. if k == r {
  449. isexpectedfailrequest = true
  450. }
  451. }
  452. if !isexpectedfailrequest {
  453. t.Fatalf("Response body does not match, expected: %v, got %v", testmanifest[v], string(respbody))
  454. }
  455. }
  456. }
  457. for k, v := range testrequests {
  458. var resp *http.Response
  459. var respbody []byte
  460. url := srv.URL + "/bzz-hash:/"
  461. if k != "" {
  462. url += rootRef + "/" + k[1:]
  463. }
  464. resp, err = http.Get(url)
  465. if err != nil {
  466. t.Fatalf("Request failed: %v", err)
  467. }
  468. defer resp.Body.Close()
  469. respbody, err = ioutil.ReadAll(resp.Body)
  470. if err != nil {
  471. t.Fatalf("Read request body: %v", err)
  472. }
  473. if string(respbody) != addr[v].Hex() {
  474. isexpectedfailrequest := false
  475. for _, r := range expectedfailrequests {
  476. if k == r {
  477. isexpectedfailrequest = true
  478. }
  479. }
  480. if !isexpectedfailrequest {
  481. t.Fatalf("Response body does not match, expected: %v, got %v", addr[v], string(respbody))
  482. }
  483. }
  484. }
  485. ref := addr[2].Hex()
  486. for _, c := range []struct {
  487. path string
  488. json string
  489. pageFragments []string
  490. }{
  491. {
  492. path: "/",
  493. json: `{"common_prefixes":["a/"]}`,
  494. pageFragments: []string{
  495. fmt.Sprintf("Swarm index of bzz:/%s/", ref),
  496. `<a class="normal-link" href="a/">a/</a>`,
  497. },
  498. },
  499. {
  500. path: "/a/",
  501. json: `{"common_prefixes":["a/b/"],"entries":[{"hash":"011b4d03dd8c01f1049143cf9c4c817e4b167f1d1b83e5c6f0f10d89ba1e7bce","path":"a/a","mod_time":"0001-01-01T00:00:00Z"}]}`,
  502. pageFragments: []string{
  503. fmt.Sprintf("Swarm index of bzz:/%s/a/", ref),
  504. `<a class="normal-link" href="b/">b/</a>`,
  505. fmt.Sprintf(`<a class="normal-link" href="/bzz:/%s/a/a">a</a>`, ref),
  506. },
  507. },
  508. {
  509. path: "/a/b/",
  510. json: `{"entries":[{"hash":"011b4d03dd8c01f1049143cf9c4c817e4b167f1d1b83e5c6f0f10d89ba1e7bce","path":"a/b/b","mod_time":"0001-01-01T00:00:00Z"},{"hash":"011b4d03dd8c01f1049143cf9c4c817e4b167f1d1b83e5c6f0f10d89ba1e7bce","path":"a/b/c","mod_time":"0001-01-01T00:00:00Z"}]}`,
  511. pageFragments: []string{
  512. fmt.Sprintf("Swarm index of bzz:/%s/a/b/", ref),
  513. fmt.Sprintf(`<a class="normal-link" href="/bzz:/%s/a/b/b">b</a>`, ref),
  514. fmt.Sprintf(`<a class="normal-link" href="/bzz:/%s/a/b/c">c</a>`, ref),
  515. },
  516. },
  517. {
  518. path: "/x",
  519. },
  520. {
  521. path: "",
  522. },
  523. } {
  524. k := c.path
  525. url := srv.URL + "/bzz-list:/"
  526. if k != "" {
  527. url += rootRef + "/" + k[1:]
  528. }
  529. t.Run("json list "+c.path, func(t *testing.T) {
  530. resp, err := http.Get(url)
  531. if err != nil {
  532. t.Fatalf("HTTP request: %v", err)
  533. }
  534. defer resp.Body.Close()
  535. respbody, err := ioutil.ReadAll(resp.Body)
  536. if err != nil {
  537. t.Fatalf("Read response body: %v", err)
  538. }
  539. body := strings.TrimSpace(string(respbody))
  540. if body != c.json {
  541. isexpectedfailrequest := false
  542. for _, r := range expectedfailrequests {
  543. if k == r {
  544. isexpectedfailrequest = true
  545. }
  546. }
  547. if !isexpectedfailrequest {
  548. t.Errorf("Response list body %q does not match, expected: %v, got %v", k, c.json, body)
  549. }
  550. }
  551. })
  552. t.Run("html list "+c.path, func(t *testing.T) {
  553. req, err := http.NewRequest(http.MethodGet, url, nil)
  554. if err != nil {
  555. t.Fatalf("New request: %v", err)
  556. }
  557. req.Header.Set("Accept", "text/html")
  558. resp, err := http.DefaultClient.Do(req)
  559. if err != nil {
  560. t.Fatalf("HTTP request: %v", err)
  561. }
  562. defer resp.Body.Close()
  563. b, err := ioutil.ReadAll(resp.Body)
  564. if err != nil {
  565. t.Fatalf("Read response body: %v", err)
  566. }
  567. body := string(b)
  568. for _, f := range c.pageFragments {
  569. if !strings.Contains(body, f) {
  570. isexpectedfailrequest := false
  571. for _, r := range expectedfailrequests {
  572. if k == r {
  573. isexpectedfailrequest = true
  574. }
  575. }
  576. if !isexpectedfailrequest {
  577. t.Errorf("Response list body %q does not contain %q: body %q", k, f, body)
  578. }
  579. }
  580. }
  581. })
  582. }
  583. nonhashtests := []string{
  584. srv.URL + "/bzz:/name",
  585. srv.URL + "/bzz-immutable:/nonhash",
  586. srv.URL + "/bzz-raw:/nonhash",
  587. srv.URL + "/bzz-list:/nonhash",
  588. srv.URL + "/bzz-hash:/nonhash",
  589. }
  590. nonhashresponses := []string{
  591. `cannot resolve name: no DNS to resolve name: "name"`,
  592. `cannot resolve nonhash: no DNS to resolve name: "nonhash"`,
  593. `cannot resolve nonhash: no DNS to resolve name: "nonhash"`,
  594. `cannot resolve nonhash: no DNS to resolve name: "nonhash"`,
  595. `cannot resolve nonhash: no DNS to resolve name: "nonhash"`,
  596. }
  597. for i, url := range nonhashtests {
  598. var resp *http.Response
  599. var respbody []byte
  600. resp, err = http.Get(url)
  601. if err != nil {
  602. t.Fatalf("Request failed: %v", err)
  603. }
  604. defer resp.Body.Close()
  605. respbody, err = ioutil.ReadAll(resp.Body)
  606. if err != nil {
  607. t.Fatalf("ReadAll failed: %v", err)
  608. }
  609. if !strings.Contains(string(respbody), nonhashresponses[i]) {
  610. t.Fatalf("Non-Hash response body does not match, expected: %v, got: %v", nonhashresponses[i], string(respbody))
  611. }
  612. }
  613. }
  614. func TestBzzTar(t *testing.T) {
  615. testBzzTar(false, t)
  616. testBzzTar(true, t)
  617. }
  618. func testBzzTar(encrypted bool, t *testing.T) {
  619. srv := testutil.NewTestSwarmServer(t, serverFunc, nil)
  620. defer srv.Close()
  621. fileNames := []string{"tmp1.txt", "tmp2.lock", "tmp3.rtf"}
  622. fileContents := []string{"tmp1textfilevalue", "tmp2lockfilelocked", "tmp3isjustaplaintextfile"}
  623. buf := &bytes.Buffer{}
  624. tw := tar.NewWriter(buf)
  625. defer tw.Close()
  626. for i, v := range fileNames {
  627. size := int64(len(fileContents[i]))
  628. hdr := &tar.Header{
  629. Name: v,
  630. Mode: 0644,
  631. Size: size,
  632. ModTime: time.Now(),
  633. Xattrs: map[string]string{
  634. "user.swarm.content-type": "text/plain",
  635. },
  636. }
  637. if err := tw.WriteHeader(hdr); err != nil {
  638. t.Fatal(err)
  639. }
  640. // copy the file into the tar stream
  641. n, err := io.Copy(tw, bytes.NewBufferString(fileContents[i]))
  642. if err != nil {
  643. t.Fatal(err)
  644. } else if n != size {
  645. t.Fatal("size mismatch")
  646. }
  647. }
  648. //post tar stream
  649. url := srv.URL + "/bzz:/"
  650. if encrypted {
  651. url = url + "encrypt"
  652. }
  653. req, err := http.NewRequest("POST", url, buf)
  654. if err != nil {
  655. t.Fatal(err)
  656. }
  657. req.Header.Add("Content-Type", "application/x-tar")
  658. client := &http.Client{}
  659. resp2, err := client.Do(req)
  660. if err != nil {
  661. t.Fatal(err)
  662. }
  663. if resp2.StatusCode != http.StatusOK {
  664. t.Fatalf("err %s", resp2.Status)
  665. }
  666. swarmHash, err := ioutil.ReadAll(resp2.Body)
  667. resp2.Body.Close()
  668. if err != nil {
  669. t.Fatal(err)
  670. }
  671. // now do a GET to get a tarball back
  672. req, err = http.NewRequest("GET", fmt.Sprintf(srv.URL+"/bzz:/%s", string(swarmHash)), nil)
  673. if err != nil {
  674. t.Fatal(err)
  675. }
  676. req.Header.Add("Accept", "application/x-tar")
  677. resp2, err = client.Do(req)
  678. if err != nil {
  679. t.Fatal(err)
  680. }
  681. defer resp2.Body.Close()
  682. if h := resp2.Header.Get("Content-Type"); h != "application/x-tar" {
  683. t.Fatalf("Content-Type header expected: application/x-tar, got: %s", h)
  684. }
  685. expectedFileName := string(swarmHash) + ".tar"
  686. expectedContentDisposition := fmt.Sprintf("inline; filename=\"%s\"", expectedFileName)
  687. if h := resp2.Header.Get("Content-Disposition"); h != expectedContentDisposition {
  688. t.Fatalf("Content-Disposition header expected: %s, got: %s", expectedContentDisposition, h)
  689. }
  690. file, err := ioutil.TempFile("", "swarm-downloaded-tarball")
  691. if err != nil {
  692. t.Fatal(err)
  693. }
  694. defer os.Remove(file.Name())
  695. _, err = io.Copy(file, resp2.Body)
  696. if err != nil {
  697. t.Fatalf("error getting tarball: %v", err)
  698. }
  699. file.Sync()
  700. file.Close()
  701. tarFileHandle, err := os.Open(file.Name())
  702. if err != nil {
  703. t.Fatal(err)
  704. }
  705. tr := tar.NewReader(tarFileHandle)
  706. for {
  707. hdr, err := tr.Next()
  708. if err == io.EOF {
  709. break
  710. } else if err != nil {
  711. t.Fatalf("error reading tar stream: %s", err)
  712. }
  713. bb := make([]byte, hdr.Size)
  714. _, err = tr.Read(bb)
  715. if err != nil && err != io.EOF {
  716. t.Fatal(err)
  717. }
  718. passed := false
  719. for i, v := range fileNames {
  720. if v == hdr.Name {
  721. if string(bb) == fileContents[i] {
  722. passed = true
  723. break
  724. }
  725. }
  726. }
  727. if !passed {
  728. t.Fatalf("file %s did not pass content assertion", hdr.Name)
  729. }
  730. }
  731. }
  732. // TestBzzRootRedirect tests that getting the root path of a manifest without
  733. // a trailing slash gets redirected to include the trailing slash so that
  734. // relative URLs work as expected.
  735. func TestBzzRootRedirect(t *testing.T) {
  736. testBzzRootRedirect(false, t)
  737. }
  738. func TestBzzRootRedirectEncrypted(t *testing.T) {
  739. testBzzRootRedirect(true, t)
  740. }
  741. func testBzzRootRedirect(toEncrypt bool, t *testing.T) {
  742. srv := testutil.NewTestSwarmServer(t, serverFunc, nil)
  743. defer srv.Close()
  744. // create a manifest with some data at the root path
  745. client := swarm.NewClient(srv.URL)
  746. data := []byte("data")
  747. file := &swarm.File{
  748. ReadCloser: ioutil.NopCloser(bytes.NewReader(data)),
  749. ManifestEntry: api.ManifestEntry{
  750. Path: "",
  751. ContentType: "text/plain",
  752. Size: int64(len(data)),
  753. },
  754. }
  755. hash, err := client.Upload(file, "", toEncrypt)
  756. if err != nil {
  757. t.Fatal(err)
  758. }
  759. // define a CheckRedirect hook which ensures there is only a single
  760. // redirect to the correct URL
  761. redirected := false
  762. httpClient := http.Client{
  763. CheckRedirect: func(req *http.Request, via []*http.Request) error {
  764. if redirected {
  765. return errors.New("too many redirects")
  766. }
  767. redirected = true
  768. expectedPath := "/bzz:/" + hash + "/"
  769. if req.URL.Path != expectedPath {
  770. return fmt.Errorf("expected redirect to %q, got %q", expectedPath, req.URL.Path)
  771. }
  772. return nil
  773. },
  774. }
  775. // perform the GET request and assert the response
  776. res, err := httpClient.Get(srv.URL + "/bzz:/" + hash)
  777. if err != nil {
  778. t.Fatal(err)
  779. }
  780. defer res.Body.Close()
  781. if !redirected {
  782. t.Fatal("expected GET /bzz:/<hash> to redirect to /bzz:/<hash>/ but it didn't")
  783. }
  784. gotData, err := ioutil.ReadAll(res.Body)
  785. if err != nil {
  786. t.Fatal(err)
  787. }
  788. if !bytes.Equal(gotData, data) {
  789. t.Fatalf("expected response to equal %q, got %q", data, gotData)
  790. }
  791. }
  792. func TestMethodsNotAllowed(t *testing.T) {
  793. srv := testutil.NewTestSwarmServer(t, serverFunc, nil)
  794. defer srv.Close()
  795. databytes := "bar"
  796. for _, c := range []struct {
  797. url string
  798. code int
  799. }{
  800. {
  801. url: fmt.Sprintf("%s/bzz-list:/", srv.URL),
  802. code: http.StatusMethodNotAllowed,
  803. }, {
  804. url: fmt.Sprintf("%s/bzz-hash:/", srv.URL),
  805. code: http.StatusMethodNotAllowed,
  806. },
  807. {
  808. url: fmt.Sprintf("%s/bzz-immutable:/", srv.URL),
  809. code: http.StatusMethodNotAllowed,
  810. },
  811. } {
  812. res, _ := http.Post(c.url, "text/plain", bytes.NewReader([]byte(databytes)))
  813. if res.StatusCode != c.code {
  814. t.Fatalf("should have failed. requested url: %s, expected code %d, got %d", c.url, c.code, res.StatusCode)
  815. }
  816. }
  817. }
  818. func httpDo(httpMethod string, url string, reqBody io.Reader, headers map[string]string, verbose bool, t *testing.T) (*http.Response, string) {
  819. // Build the Request
  820. req, err := http.NewRequest(httpMethod, url, reqBody)
  821. if err != nil {
  822. t.Fatal(err)
  823. }
  824. for key, value := range headers {
  825. req.Header.Set(key, value)
  826. }
  827. if verbose {
  828. t.Log(req.Method, req.URL, req.Header, req.Body)
  829. }
  830. // Send Request out
  831. httpClient := &http.Client{}
  832. res, err := httpClient.Do(req)
  833. if err != nil {
  834. t.Fatal(err)
  835. }
  836. // Read the HTTP Body
  837. buffer, err := ioutil.ReadAll(res.Body)
  838. if err != nil {
  839. t.Fatal(err)
  840. }
  841. defer res.Body.Close()
  842. body := string(buffer)
  843. return res, body
  844. }
  845. func TestGet(t *testing.T) {
  846. srv := testutil.NewTestSwarmServer(t, serverFunc, nil)
  847. defer srv.Close()
  848. for _, testCase := range []struct {
  849. uri string
  850. method string
  851. headers map[string]string
  852. expectedStatusCode int
  853. assertResponseBody string
  854. verbose bool
  855. }{
  856. {
  857. uri: fmt.Sprintf("%s/", srv.URL),
  858. method: "GET",
  859. headers: map[string]string{"Accept": "text/html"},
  860. expectedStatusCode: http.StatusOK,
  861. assertResponseBody: "Swarm: Serverless Hosting Incentivised Peer-To-Peer Storage And Content Distribution",
  862. verbose: false,
  863. },
  864. {
  865. uri: fmt.Sprintf("%s/", srv.URL),
  866. method: "GET",
  867. headers: map[string]string{"Accept": "application/json"},
  868. expectedStatusCode: http.StatusOK,
  869. assertResponseBody: "Swarm: Please request a valid ENS or swarm hash with the appropriate bzz scheme",
  870. verbose: false,
  871. },
  872. {
  873. uri: fmt.Sprintf("%s/robots.txt", srv.URL),
  874. method: "GET",
  875. headers: map[string]string{"Accept": "text/html"},
  876. expectedStatusCode: http.StatusOK,
  877. assertResponseBody: "User-agent: *\nDisallow: /",
  878. verbose: false,
  879. },
  880. {
  881. uri: fmt.Sprintf("%s/nonexistent_path", srv.URL),
  882. method: "GET",
  883. headers: map[string]string{},
  884. expectedStatusCode: http.StatusNotFound,
  885. verbose: false,
  886. },
  887. {
  888. uri: fmt.Sprintf("%s/bzz:asdf/", srv.URL),
  889. method: "GET",
  890. headers: map[string]string{},
  891. expectedStatusCode: http.StatusNotFound,
  892. verbose: false,
  893. },
  894. {
  895. uri: fmt.Sprintf("%s/tbz2/", srv.URL),
  896. method: "GET",
  897. headers: map[string]string{},
  898. expectedStatusCode: http.StatusNotFound,
  899. verbose: false,
  900. },
  901. {
  902. uri: fmt.Sprintf("%s/bzz-rack:/", srv.URL),
  903. method: "GET",
  904. headers: map[string]string{},
  905. expectedStatusCode: http.StatusNotFound,
  906. verbose: false,
  907. },
  908. {
  909. uri: fmt.Sprintf("%s/bzz-ls", srv.URL),
  910. method: "GET",
  911. headers: map[string]string{},
  912. expectedStatusCode: http.StatusNotFound,
  913. verbose: false,
  914. }} {
  915. t.Run("GET "+testCase.uri, func(t *testing.T) {
  916. res, body := httpDo(testCase.method, testCase.uri, nil, testCase.headers, testCase.verbose, t)
  917. if res.StatusCode != testCase.expectedStatusCode {
  918. t.Fatalf("expected status code %d but got %d", testCase.expectedStatusCode, res.StatusCode)
  919. }
  920. if testCase.assertResponseBody != "" && !strings.Contains(body, testCase.assertResponseBody) {
  921. t.Fatalf("expected response to be: %s but got: %s", testCase.assertResponseBody, body)
  922. }
  923. })
  924. }
  925. }
  926. func TestModify(t *testing.T) {
  927. srv := testutil.NewTestSwarmServer(t, serverFunc, nil)
  928. defer srv.Close()
  929. swarmClient := swarm.NewClient(srv.URL)
  930. data := []byte("data")
  931. file := &swarm.File{
  932. ReadCloser: ioutil.NopCloser(bytes.NewReader(data)),
  933. ManifestEntry: api.ManifestEntry{
  934. Path: "",
  935. ContentType: "text/plain",
  936. Size: int64(len(data)),
  937. },
  938. }
  939. hash, err := swarmClient.Upload(file, "", false)
  940. if err != nil {
  941. t.Fatal(err)
  942. }
  943. for _, testCase := range []struct {
  944. uri string
  945. method string
  946. headers map[string]string
  947. requestBody []byte
  948. expectedStatusCode int
  949. assertResponseBody string
  950. assertResponseHeaders map[string]string
  951. verbose bool
  952. }{
  953. {
  954. uri: fmt.Sprintf("%s/bzz:/%s", srv.URL, hash),
  955. method: "DELETE",
  956. headers: map[string]string{},
  957. expectedStatusCode: http.StatusOK,
  958. assertResponseBody: "8b634aea26eec353ac0ecbec20c94f44d6f8d11f38d4578a4c207a84c74ef731",
  959. verbose: false,
  960. },
  961. {
  962. uri: fmt.Sprintf("%s/bzz:/%s", srv.URL, hash),
  963. method: "PUT",
  964. headers: map[string]string{},
  965. expectedStatusCode: http.StatusMethodNotAllowed,
  966. verbose: false,
  967. },
  968. {
  969. uri: fmt.Sprintf("%s/bzz-raw:/%s", srv.URL, hash),
  970. method: "PUT",
  971. headers: map[string]string{},
  972. expectedStatusCode: http.StatusMethodNotAllowed,
  973. verbose: false,
  974. },
  975. {
  976. uri: fmt.Sprintf("%s/bzz:/%s", srv.URL, hash),
  977. method: "PATCH",
  978. headers: map[string]string{},
  979. expectedStatusCode: http.StatusMethodNotAllowed,
  980. verbose: false,
  981. },
  982. {
  983. uri: fmt.Sprintf("%s/bzz-raw:/", srv.URL),
  984. method: "POST",
  985. headers: map[string]string{},
  986. requestBody: []byte("POSTdata"),
  987. expectedStatusCode: http.StatusOK,
  988. assertResponseHeaders: map[string]string{"Content-Length": "64"},
  989. verbose: false,
  990. },
  991. {
  992. uri: fmt.Sprintf("%s/bzz-raw:/encrypt", srv.URL),
  993. method: "POST",
  994. headers: map[string]string{},
  995. requestBody: []byte("POSTdata"),
  996. expectedStatusCode: http.StatusOK,
  997. assertResponseHeaders: map[string]string{"Content-Length": "128"},
  998. verbose: false,
  999. },
  1000. } {
  1001. t.Run(testCase.method+" "+testCase.uri, func(t *testing.T) {
  1002. reqBody := bytes.NewReader(testCase.requestBody)
  1003. res, body := httpDo(testCase.method, testCase.uri, reqBody, testCase.headers, testCase.verbose, t)
  1004. if res.StatusCode != testCase.expectedStatusCode {
  1005. t.Fatalf("expected status code %d but got %d, %s", testCase.expectedStatusCode, res.StatusCode, body)
  1006. }
  1007. if testCase.assertResponseBody != "" && !strings.Contains(body, testCase.assertResponseBody) {
  1008. t.Log(body)
  1009. t.Fatalf("expected response %s but got %s", testCase.assertResponseBody, body)
  1010. }
  1011. for key, value := range testCase.assertResponseHeaders {
  1012. if res.Header.Get(key) != value {
  1013. t.Logf("expected %s=%s in HTTP response header but got %s", key, value, res.Header.Get(key))
  1014. }
  1015. }
  1016. })
  1017. }
  1018. }
  1019. func TestMultiPartUpload(t *testing.T) {
  1020. // POST /bzz:/ Content-Type: multipart/form-data
  1021. verbose := false
  1022. // Setup Swarm
  1023. srv := testutil.NewTestSwarmServer(t, serverFunc, nil)
  1024. defer srv.Close()
  1025. url := fmt.Sprintf("%s/bzz:/", srv.URL)
  1026. buf := new(bytes.Buffer)
  1027. form := multipart.NewWriter(buf)
  1028. form.WriteField("name", "John Doe")
  1029. file1, _ := form.CreateFormFile("cv", "cv.txt")
  1030. file1.Write([]byte("John Doe's Credentials"))
  1031. file2, _ := form.CreateFormFile("profile_picture", "profile.jpg")
  1032. file2.Write([]byte("imaginethisisjpegdata"))
  1033. form.Close()
  1034. headers := map[string]string{
  1035. "Content-Type": form.FormDataContentType(),
  1036. "Content-Length": strconv.Itoa(buf.Len()),
  1037. }
  1038. res, body := httpDo("POST", url, buf, headers, verbose, t)
  1039. if res.StatusCode != http.StatusOK {
  1040. t.Fatalf("expected POST multipart/form-data to return 200, but it returned %d", res.StatusCode)
  1041. }
  1042. if len(body) != 64 {
  1043. t.Fatalf("expected POST multipart/form-data to return a 64 char manifest but the answer was %d chars long", len(body))
  1044. }
  1045. }
  1046. // TestBzzGetFileWithResolver tests fetching a file using a mocked ENS resolver
  1047. func TestBzzGetFileWithResolver(t *testing.T) {
  1048. resolver := newTestResolveValidator("")
  1049. srv := testutil.NewTestSwarmServer(t, serverFunc, resolver)
  1050. defer srv.Close()
  1051. fileNames := []string{"dir1/tmp1.txt", "dir2/tmp2.lock", "dir3/tmp3.rtf"}
  1052. fileContents := []string{"tmp1textfilevalue", "tmp2lockfilelocked", "tmp3isjustaplaintextfile"}
  1053. buf := &bytes.Buffer{}
  1054. tw := tar.NewWriter(buf)
  1055. for i, v := range fileNames {
  1056. size := len(fileContents[i])
  1057. hdr := &tar.Header{
  1058. Name: v,
  1059. Mode: 0644,
  1060. Size: int64(size),
  1061. ModTime: time.Now(),
  1062. Xattrs: map[string]string{
  1063. "user.swarm.content-type": "text/plain",
  1064. },
  1065. }
  1066. if err := tw.WriteHeader(hdr); err != nil {
  1067. t.Fatal(err)
  1068. }
  1069. // copy the file into the tar stream
  1070. n, err := io.WriteString(tw, fileContents[i])
  1071. if err != nil {
  1072. t.Fatal(err)
  1073. } else if n != size {
  1074. t.Fatal("size mismatch")
  1075. }
  1076. }
  1077. if err := tw.Close(); err != nil {
  1078. t.Fatal(err)
  1079. }
  1080. //post tar stream
  1081. url := srv.URL + "/bzz:/"
  1082. req, err := http.NewRequest("POST", url, buf)
  1083. if err != nil {
  1084. t.Fatal(err)
  1085. }
  1086. req.Header.Add("Content-Type", "application/x-tar")
  1087. client := &http.Client{}
  1088. serverResponse, err := client.Do(req)
  1089. if err != nil {
  1090. t.Fatal(err)
  1091. }
  1092. if serverResponse.StatusCode != http.StatusOK {
  1093. t.Fatalf("err %s", serverResponse.Status)
  1094. }
  1095. swarmHash, err := ioutil.ReadAll(serverResponse.Body)
  1096. serverResponse.Body.Close()
  1097. if err != nil {
  1098. t.Fatal(err)
  1099. }
  1100. // set the resolved hash to be the swarm hash of what we've just uploaded
  1101. hash := common.HexToHash(string(swarmHash))
  1102. resolver.hash = &hash
  1103. for _, v := range []struct {
  1104. addr string
  1105. path string
  1106. expectedStatusCode int
  1107. expectedContentType string
  1108. expectedFileName string
  1109. }{
  1110. {
  1111. addr: string(swarmHash),
  1112. path: fileNames[0],
  1113. expectedStatusCode: http.StatusOK,
  1114. expectedContentType: "text/plain",
  1115. expectedFileName: path.Base(fileNames[0]),
  1116. },
  1117. {
  1118. addr: "somebogusensname",
  1119. path: fileNames[0],
  1120. expectedStatusCode: http.StatusOK,
  1121. expectedContentType: "text/plain",
  1122. expectedFileName: path.Base(fileNames[0]),
  1123. },
  1124. } {
  1125. req, err := http.NewRequest("GET", fmt.Sprintf(srv.URL+"/bzz:/%s/%s", v.addr, v.path), nil)
  1126. if err != nil {
  1127. t.Fatal(err)
  1128. }
  1129. serverResponse, err := client.Do(req)
  1130. if err != nil {
  1131. t.Fatal(err)
  1132. }
  1133. defer serverResponse.Body.Close()
  1134. if serverResponse.StatusCode != v.expectedStatusCode {
  1135. t.Fatalf("expected %d, got %d", v.expectedStatusCode, serverResponse.StatusCode)
  1136. }
  1137. if h := serverResponse.Header.Get("Content-Type"); h != v.expectedContentType {
  1138. t.Fatalf("Content-Type header expected: %s, got %s", v.expectedContentType, h)
  1139. }
  1140. expectedContentDisposition := fmt.Sprintf("inline; filename=\"%s\"", v.expectedFileName)
  1141. if h := serverResponse.Header.Get("Content-Disposition"); h != expectedContentDisposition {
  1142. t.Fatalf("Content-Disposition header expected: %s, got: %s", expectedContentDisposition, h)
  1143. }
  1144. }
  1145. }
  1146. // testResolver implements the Resolver interface and either returns the given
  1147. // hash if it is set, or returns a "name not found" error
  1148. type testResolveValidator struct {
  1149. hash *common.Hash
  1150. }
  1151. func newTestResolveValidator(addr string) *testResolveValidator {
  1152. r := &testResolveValidator{}
  1153. if addr != "" {
  1154. hash := common.HexToHash(addr)
  1155. r.hash = &hash
  1156. }
  1157. return r
  1158. }
  1159. func (t *testResolveValidator) Resolve(addr string) (common.Hash, error) {
  1160. if t.hash == nil {
  1161. return common.Hash{}, fmt.Errorf("DNS name not found: %q", addr)
  1162. }
  1163. return *t.hash, nil
  1164. }
  1165. func (t *testResolveValidator) Owner(node [32]byte) (addr common.Address, err error) {
  1166. return
  1167. }
  1168. func (t *testResolveValidator) HeaderByNumber(context.Context, *big.Int) (header *types.Header, err error) {
  1169. return
  1170. }