server_test.go 35 KB

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