server_test.go 34 KB

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