2017-01-30 16:21:46 +03:00
|
|
|
// Copyright 2017 The go-ethereum Authors
|
|
|
|
// This file is part of the go-ethereum library.
|
|
|
|
//
|
|
|
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU Lesser General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
//
|
|
|
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU Lesser General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU Lesser General Public License
|
|
|
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
2018-06-20 15:06:27 +03:00
|
|
|
package http
|
2017-01-26 22:33:39 +03:00
|
|
|
|
|
|
|
import (
|
2018-07-12 16:42:45 +03:00
|
|
|
"archive/tar"
|
2017-01-26 22:33:39 +03:00
|
|
|
"bytes"
|
2018-07-09 15:11:49 +03:00
|
|
|
"context"
|
2018-06-20 15:06:27 +03:00
|
|
|
"crypto/rand"
|
|
|
|
"encoding/json"
|
2017-07-25 12:51:26 +03:00
|
|
|
"errors"
|
2018-06-20 15:06:27 +03:00
|
|
|
"flag"
|
2017-07-25 12:51:26 +03:00
|
|
|
"fmt"
|
2018-07-12 16:42:45 +03:00
|
|
|
"io"
|
2017-01-26 22:33:39 +03:00
|
|
|
"io/ioutil"
|
|
|
|
"net/http"
|
2018-06-20 15:06:27 +03:00
|
|
|
"os"
|
2017-09-08 21:29:09 +03:00
|
|
|
"strings"
|
2017-01-26 22:33:39 +03:00
|
|
|
"testing"
|
2018-07-12 16:42:45 +03:00
|
|
|
"time"
|
2017-01-26 22:33:39 +03:00
|
|
|
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
2018-06-20 15:06:27 +03:00
|
|
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
|
|
|
"github.com/ethereum/go-ethereum/log"
|
2017-07-25 12:51:26 +03:00
|
|
|
"github.com/ethereum/go-ethereum/swarm/api"
|
|
|
|
swarm "github.com/ethereum/go-ethereum/swarm/api/client"
|
2018-06-20 15:06:27 +03:00
|
|
|
"github.com/ethereum/go-ethereum/swarm/multihash"
|
2017-01-26 22:33:39 +03:00
|
|
|
"github.com/ethereum/go-ethereum/swarm/storage"
|
2017-04-05 01:20:07 +03:00
|
|
|
"github.com/ethereum/go-ethereum/swarm/testutil"
|
2017-01-26 22:33:39 +03:00
|
|
|
)
|
|
|
|
|
2018-06-20 15:06:27 +03:00
|
|
|
func init() {
|
|
|
|
loglevel := flag.Int("loglevel", 2, "loglevel")
|
|
|
|
flag.Parse()
|
|
|
|
log.Root().SetHandler(log.CallerFileHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(os.Stderr, log.TerminalFormat(true)))))
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestResourcePostMode(t *testing.T) {
|
|
|
|
path := ""
|
|
|
|
errstr := "resourcePostMode for '%s' should be raw %v frequency %d, was raw %v, frequency %d"
|
|
|
|
r, f, err := resourcePostMode(path)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
} else if r || f != 0 {
|
|
|
|
t.Fatalf(errstr, path, false, 0, r, f)
|
|
|
|
}
|
|
|
|
|
|
|
|
path = "raw"
|
|
|
|
r, f, err = resourcePostMode(path)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
} else if !r || f != 0 {
|
|
|
|
t.Fatalf(errstr, path, true, 0, r, f)
|
|
|
|
}
|
|
|
|
|
|
|
|
path = "13"
|
|
|
|
r, f, err = resourcePostMode(path)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
} else if r || f == 0 {
|
|
|
|
t.Fatalf(errstr, path, false, 13, r, f)
|
|
|
|
}
|
|
|
|
|
|
|
|
path = "raw/13"
|
|
|
|
r, f, err = resourcePostMode(path)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
} else if !r || f == 0 {
|
|
|
|
t.Fatalf(errstr, path, true, 13, r, f)
|
|
|
|
}
|
|
|
|
|
|
|
|
path = "foo/13"
|
|
|
|
r, f, err = resourcePostMode(path)
|
|
|
|
if err == nil {
|
|
|
|
t.Fatal("resourcePostMode for 'foo/13' should fail, returned error nil")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func serverFunc(api *api.API) testutil.TestServer {
|
2018-07-12 16:42:45 +03:00
|
|
|
return NewServer(api, "")
|
2018-06-20 15:06:27 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// test the transparent resolving of multihash resource types with bzz:// scheme
|
|
|
|
//
|
|
|
|
// first upload data, and store the multihash to the resulting manifest in a resource update
|
|
|
|
// retrieving the update with the multihash should return the manifest pointing directly to the data
|
|
|
|
// and raw retrieve of that hash should return the data
|
|
|
|
func TestBzzResourceMultihash(t *testing.T) {
|
|
|
|
|
|
|
|
srv := testutil.NewTestSwarmServer(t, serverFunc)
|
|
|
|
defer srv.Close()
|
|
|
|
|
|
|
|
// add the data our multihash aliased manifest will point to
|
|
|
|
databytes := "bar"
|
|
|
|
url := fmt.Sprintf("%s/bzz:/", srv.URL)
|
|
|
|
resp, err := http.Post(url, "text/plain", bytes.NewReader([]byte(databytes)))
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
|
|
t.Fatalf("err %s", resp.Status)
|
|
|
|
}
|
|
|
|
b, err := ioutil.ReadAll(resp.Body)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
s := common.FromHex(string(b))
|
|
|
|
mh := multihash.ToMultihash(s)
|
|
|
|
|
|
|
|
mhHex := hexutil.Encode(mh)
|
|
|
|
log.Info("added data", "manifest", string(b), "data", common.ToHex(mh))
|
|
|
|
|
|
|
|
// our mutable resource "name"
|
|
|
|
keybytes := "foo.eth"
|
|
|
|
|
|
|
|
// create the multihash update
|
|
|
|
url = fmt.Sprintf("%s/bzz-resource:/%s/13", srv.URL, keybytes)
|
|
|
|
resp, err = http.Post(url, "application/octet-stream", bytes.NewReader([]byte(mhHex)))
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
|
|
t.Fatalf("err %s", resp.Status)
|
|
|
|
}
|
|
|
|
b, err = ioutil.ReadAll(resp.Body)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
rsrcResp := &storage.Address{}
|
|
|
|
err = json.Unmarshal(b, rsrcResp)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("data %s could not be unmarshaled: %v", b, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
correctManifestAddrHex := "d689648fb9e00ddc7ebcf474112d5881c5bf7dbc6e394681b1d224b11b59b5e0"
|
|
|
|
if rsrcResp.Hex() != correctManifestAddrHex {
|
|
|
|
t.Fatalf("Response resource key mismatch, expected '%s', got '%s'", correctManifestAddrHex, rsrcResp)
|
|
|
|
}
|
|
|
|
|
|
|
|
// get bzz manifest transparent resource resolve
|
|
|
|
url = fmt.Sprintf("%s/bzz:/%s", srv.URL, rsrcResp)
|
|
|
|
resp, err = http.Get(url)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
|
|
t.Fatalf("err %s", resp.Status)
|
|
|
|
}
|
|
|
|
b, err = ioutil.ReadAll(resp.Body)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if !bytes.Equal(b, []byte(databytes)) {
|
|
|
|
t.Fatalf("retrieved data mismatch, expected %x, got %x", databytes, b)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test resource updates using the raw update methods
|
|
|
|
func TestBzzResource(t *testing.T) {
|
|
|
|
srv := testutil.NewTestSwarmServer(t, serverFunc)
|
|
|
|
defer srv.Close()
|
|
|
|
|
|
|
|
// our mutable resource "name"
|
|
|
|
keybytes := "foo.eth"
|
|
|
|
|
|
|
|
// data of update 1
|
|
|
|
databytes := make([]byte, 666)
|
|
|
|
_, err := rand.Read(databytes)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// creates resource and sets update 1
|
|
|
|
url := fmt.Sprintf("%s/bzz-resource:/%s/raw/13", srv.URL, []byte(keybytes))
|
|
|
|
resp, err := http.Post(url, "application/octet-stream", bytes.NewReader(databytes))
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
|
|
t.Fatalf("err %s", resp.Status)
|
|
|
|
}
|
|
|
|
b, err := ioutil.ReadAll(resp.Body)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
rsrcResp := &storage.Address{}
|
|
|
|
err = json.Unmarshal(b, rsrcResp)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("data %s could not be unmarshaled: %v", b, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
correctManifestAddrHex := "d689648fb9e00ddc7ebcf474112d5881c5bf7dbc6e394681b1d224b11b59b5e0"
|
|
|
|
if rsrcResp.Hex() != correctManifestAddrHex {
|
|
|
|
t.Fatalf("Response resource key mismatch, expected '%s', got '%s'", correctManifestAddrHex, rsrcResp.Hex())
|
|
|
|
}
|
|
|
|
|
|
|
|
// get the manifest
|
|
|
|
url = fmt.Sprintf("%s/bzz-raw:/%s", srv.URL, rsrcResp)
|
|
|
|
resp, err = http.Get(url)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
|
|
t.Fatalf("err %s", resp.Status)
|
|
|
|
}
|
|
|
|
b, err = ioutil.ReadAll(resp.Body)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
manifest := &api.Manifest{}
|
|
|
|
err = json.Unmarshal(b, manifest)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if len(manifest.Entries) != 1 {
|
|
|
|
t.Fatalf("Manifest has %d entries", len(manifest.Entries))
|
|
|
|
}
|
|
|
|
|
|
|
|
correctRootKeyHex := "f667277e004e8486c7a3631fd226802430e84e9a81b6085d31f512a591ae0065"
|
|
|
|
if manifest.Entries[0].Hash != correctRootKeyHex {
|
|
|
|
t.Fatalf("Expected manifest path '%s', got '%s'", correctRootKeyHex, manifest.Entries[0].Hash)
|
|
|
|
}
|
|
|
|
|
|
|
|
// get bzz manifest transparent resource resolve
|
|
|
|
url = fmt.Sprintf("%s/bzz:/%s", srv.URL, rsrcResp)
|
|
|
|
resp, err = http.Get(url)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
|
|
t.Fatalf("err %s", resp.Status)
|
|
|
|
}
|
|
|
|
b, err = ioutil.ReadAll(resp.Body)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// get non-existent name, should fail
|
|
|
|
url = fmt.Sprintf("%s/bzz-resource:/bar", srv.URL)
|
|
|
|
resp, err = http.Get(url)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
resp.Body.Close()
|
|
|
|
|
|
|
|
// get latest update (1.1) through resource directly
|
|
|
|
log.Info("get update latest = 1.1", "addr", correctManifestAddrHex)
|
|
|
|
url = fmt.Sprintf("%s/bzz-resource:/%s", srv.URL, correctManifestAddrHex)
|
|
|
|
resp, err = http.Get(url)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
|
|
t.Fatalf("err %s", resp.Status)
|
|
|
|
}
|
|
|
|
b, err = ioutil.ReadAll(resp.Body)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if !bytes.Equal(databytes, b) {
|
|
|
|
t.Fatalf("Expected body '%x', got '%x'", databytes, b)
|
|
|
|
}
|
|
|
|
|
|
|
|
// update 2
|
|
|
|
log.Info("update 2")
|
|
|
|
url = fmt.Sprintf("%s/bzz-resource:/%s/raw", srv.URL, correctManifestAddrHex)
|
|
|
|
data := []byte("foo")
|
|
|
|
resp, err = http.Post(url, "application/octet-stream", bytes.NewReader(data))
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
|
|
t.Fatalf("Update returned %s", resp.Status)
|
|
|
|
}
|
|
|
|
|
|
|
|
// get latest update (1.2) through resource directly
|
|
|
|
log.Info("get update 1.2")
|
|
|
|
url = fmt.Sprintf("%s/bzz-resource:/%s", srv.URL, correctManifestAddrHex)
|
|
|
|
resp, err = http.Get(url)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
|
|
t.Fatalf("err %s", resp.Status)
|
|
|
|
}
|
|
|
|
b, err = ioutil.ReadAll(resp.Body)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if !bytes.Equal(data, b) {
|
|
|
|
t.Fatalf("Expected body '%x', got '%x'", data, b)
|
|
|
|
}
|
|
|
|
|
|
|
|
// get latest update (1.2) with specified period
|
|
|
|
log.Info("get update latest = 1.2")
|
|
|
|
url = fmt.Sprintf("%s/bzz-resource:/%s/1", srv.URL, correctManifestAddrHex)
|
|
|
|
resp, err = http.Get(url)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
|
|
t.Fatalf("err %s", resp.Status)
|
|
|
|
}
|
|
|
|
b, err = ioutil.ReadAll(resp.Body)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if !bytes.Equal(data, b) {
|
|
|
|
t.Fatalf("Expected body '%x', got '%x'", data, b)
|
|
|
|
}
|
|
|
|
|
|
|
|
// get first update (1.1) with specified period and version
|
|
|
|
log.Info("get first update 1.1")
|
|
|
|
url = fmt.Sprintf("%s/bzz-resource:/%s/1/1", srv.URL, correctManifestAddrHex)
|
|
|
|
resp, err = http.Get(url)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
|
|
t.Fatalf("err %s", resp.Status)
|
|
|
|
}
|
|
|
|
b, err = ioutil.ReadAll(resp.Body)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if !bytes.Equal(databytes, b) {
|
|
|
|
t.Fatalf("Expected body '%x', got '%x'", databytes, b)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-21 15:47:10 +03:00
|
|
|
func TestBzzGetPath(t *testing.T) {
|
2018-06-20 15:06:27 +03:00
|
|
|
testBzzGetPath(false, t)
|
|
|
|
testBzzGetPath(true, t)
|
|
|
|
}
|
2017-01-26 22:33:39 +03:00
|
|
|
|
2018-07-12 16:42:45 +03:00
|
|
|
func TestBzzTar(t *testing.T) {
|
|
|
|
testBzzTar(false, t)
|
|
|
|
testBzzTar(true, t)
|
|
|
|
}
|
|
|
|
|
2018-06-20 15:06:27 +03:00
|
|
|
func testBzzGetPath(encrypted bool, t *testing.T) {
|
2017-01-26 22:33:39 +03:00
|
|
|
var err error
|
|
|
|
|
|
|
|
testmanifest := []string{
|
|
|
|
`{"entries":[{"path":"b","hash":"011b4d03dd8c01f1049143cf9c4c817e4b167f1d1b83e5c6f0f10d89ba1e7bce","contentType":"","status":0},{"path":"c","hash":"011b4d03dd8c01f1049143cf9c4c817e4b167f1d1b83e5c6f0f10d89ba1e7bce","contentType":"","status":0}]}`,
|
2018-06-20 15:06:27 +03:00
|
|
|
`{"entries":[{"path":"a","hash":"011b4d03dd8c01f1049143cf9c4c817e4b167f1d1b83e5c6f0f10d89ba1e7bce","contentType":"","status":0},{"path":"b/","hash":"<key0>","contentType":"application/bzz-manifest+json","status":0}]}`,
|
|
|
|
`{"entries":[{"path":"a/","hash":"<key1>","contentType":"application/bzz-manifest+json","status":0}]}`,
|
2017-01-26 22:33:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
testrequests := make(map[string]int)
|
2018-06-20 15:06:27 +03:00
|
|
|
testrequests["/"] = 2
|
2017-04-07 01:22:22 +03:00
|
|
|
testrequests["/a/"] = 1
|
2018-06-20 15:06:27 +03:00
|
|
|
testrequests["/a/b/"] = 0
|
2017-01-26 22:33:39 +03:00
|
|
|
testrequests["/x"] = 0
|
|
|
|
testrequests[""] = 0
|
|
|
|
|
|
|
|
expectedfailrequests := []string{"", "/x"}
|
|
|
|
|
|
|
|
reader := [3]*bytes.Reader{}
|
|
|
|
|
2018-06-20 15:06:27 +03:00
|
|
|
addr := [3]storage.Address{}
|
2017-01-26 22:33:39 +03:00
|
|
|
|
2018-06-20 15:06:27 +03:00
|
|
|
srv := testutil.NewTestSwarmServer(t, serverFunc)
|
2017-04-05 01:20:07 +03:00
|
|
|
defer srv.Close()
|
2017-01-26 22:33:39 +03:00
|
|
|
|
|
|
|
for i, mf := range testmanifest {
|
|
|
|
reader[i] = bytes.NewReader([]byte(mf))
|
2018-07-09 15:11:49 +03:00
|
|
|
var wait func(context.Context) error
|
|
|
|
ctx := context.TODO()
|
|
|
|
addr[i], wait, err = srv.FileStore.Store(ctx, reader[i], int64(len(mf)), encrypted)
|
2018-06-20 15:06:27 +03:00
|
|
|
for j := i + 1; j < len(testmanifest); j++ {
|
|
|
|
testmanifest[j] = strings.Replace(testmanifest[j], fmt.Sprintf("<key%v>", i), addr[i].Hex(), -1)
|
|
|
|
}
|
2017-01-26 22:33:39 +03:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2018-07-09 15:11:49 +03:00
|
|
|
err = wait(ctx)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2017-01-26 22:33:39 +03:00
|
|
|
}
|
|
|
|
|
2018-06-20 15:06:27 +03:00
|
|
|
rootRef := addr[2].Hex()
|
|
|
|
|
|
|
|
_, err = http.Get(srv.URL + "/bzz-raw:/" + rootRef + "/a")
|
2017-04-05 01:20:07 +03:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Failed to connect to proxy: %v", err)
|
2017-01-26 22:33:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
for k, v := range testrequests {
|
|
|
|
var resp *http.Response
|
|
|
|
var respbody []byte
|
|
|
|
|
2017-12-19 11:49:30 +03:00
|
|
|
url := srv.URL + "/bzz-raw:/"
|
2017-01-26 22:33:39 +03:00
|
|
|
if k[:] != "" {
|
2018-06-20 15:06:27 +03:00
|
|
|
url += rootRef + "/" + k[1:] + "?content_type=text/plain"
|
2017-01-26 22:33:39 +03:00
|
|
|
}
|
|
|
|
resp, err = http.Get(url)
|
2017-02-17 12:48:26 +03:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Request failed: %v", err)
|
|
|
|
}
|
2017-01-26 22:33:39 +03:00
|
|
|
defer resp.Body.Close()
|
|
|
|
respbody, err = ioutil.ReadAll(resp.Body)
|
|
|
|
|
|
|
|
if string(respbody) != testmanifest[v] {
|
|
|
|
isexpectedfailrequest := false
|
|
|
|
|
|
|
|
for _, r := range expectedfailrequests {
|
|
|
|
if k[:] == r {
|
|
|
|
isexpectedfailrequest = true
|
|
|
|
}
|
|
|
|
}
|
2017-08-08 20:34:35 +03:00
|
|
|
if !isexpectedfailrequest {
|
2017-01-26 22:33:39 +03:00
|
|
|
t.Fatalf("Response body does not match, expected: %v, got %v", testmanifest[v], string(respbody))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-21 15:47:10 +03:00
|
|
|
for k, v := range testrequests {
|
|
|
|
var resp *http.Response
|
|
|
|
var respbody []byte
|
|
|
|
|
|
|
|
url := srv.URL + "/bzz-hash:/"
|
|
|
|
if k[:] != "" {
|
2018-06-20 15:06:27 +03:00
|
|
|
url += rootRef + "/" + k[1:]
|
2017-12-21 15:47:10 +03:00
|
|
|
}
|
|
|
|
resp, err = http.Get(url)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Request failed: %v", err)
|
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
respbody, err = ioutil.ReadAll(resp.Body)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Read request body: %v", err)
|
|
|
|
}
|
|
|
|
|
2018-06-20 15:06:27 +03:00
|
|
|
if string(respbody) != addr[v].Hex() {
|
2017-12-21 15:47:10 +03:00
|
|
|
isexpectedfailrequest := false
|
|
|
|
|
|
|
|
for _, r := range expectedfailrequests {
|
|
|
|
if k[:] == r {
|
|
|
|
isexpectedfailrequest = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !isexpectedfailrequest {
|
2018-06-20 15:06:27 +03:00
|
|
|
t.Fatalf("Response body does not match, expected: %v, got %v", addr[v], string(respbody))
|
2017-12-21 15:47:10 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-20 15:06:27 +03:00
|
|
|
ref := addr[2].Hex()
|
|
|
|
|
2017-12-19 11:49:30 +03:00
|
|
|
for _, c := range []struct {
|
|
|
|
path string
|
|
|
|
json string
|
|
|
|
html string
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
path: "/",
|
|
|
|
json: `{"common_prefixes":["a/"]}`,
|
2018-06-20 15:06:27 +03:00
|
|
|
html: fmt.Sprintf("<!DOCTYPE html>\n<html>\n<head>\n <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n\t\t<link rel=\"shortcut icon\" type=\"image/x-icon\" href=\"data:image/png;base64,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
|
2017-12-19 11:49:30 +03:00
|
|
|
},
|
|
|
|
{
|
|
|
|
path: "/a/",
|
|
|
|
json: `{"common_prefixes":["a/b/"],"entries":[{"hash":"011b4d03dd8c01f1049143cf9c4c817e4b167f1d1b83e5c6f0f10d89ba1e7bce","path":"a/a","mod_time":"0001-01-01T00:00:00Z"}]}`,
|
2018-06-20 15:06:27 +03:00
|
|
|
html: fmt.Sprintf("<!DOCTYPE html>\n<html>\n<head>\n <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n\t\t<link rel=\"shortcut icon\" type=\"image/x-icon\" href=\"data:image/png;base64,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
|
2017-12-19 11:49:30 +03:00
|
|
|
},
|
|
|
|
{
|
|
|
|
path: "/a/b/",
|
|
|
|
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"}]}`,
|
2018-06-20 15:06:27 +03:00
|
|
|
html: fmt.Sprintf("<!DOCTYPE html>\n<html>\n<head>\n <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n\t\t<link rel=\"shortcut icon\" type=\"image/x-icon\" href=\"data:image/png;base64,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
|
2017-12-19 11:49:30 +03:00
|
|
|
},
|
|
|
|
{
|
|
|
|
path: "/x",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
path: "",
|
|
|
|
},
|
|
|
|
} {
|
|
|
|
k := c.path
|
|
|
|
url := srv.URL + "/bzz-list:/"
|
|
|
|
if k[:] != "" {
|
2018-06-20 15:06:27 +03:00
|
|
|
url += rootRef + "/" + k[1:]
|
2017-12-19 11:49:30 +03:00
|
|
|
}
|
|
|
|
t.Run("json list "+c.path, func(t *testing.T) {
|
|
|
|
resp, err := http.Get(url)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("HTTP request: %v", err)
|
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
respbody, err := ioutil.ReadAll(resp.Body)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Read response body: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
body := strings.TrimSpace(string(respbody))
|
|
|
|
if body != c.json {
|
|
|
|
isexpectedfailrequest := false
|
|
|
|
|
|
|
|
for _, r := range expectedfailrequests {
|
|
|
|
if k[:] == r {
|
|
|
|
isexpectedfailrequest = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !isexpectedfailrequest {
|
|
|
|
t.Errorf("Response list body %q does not match, expected: %v, got %v", k, c.json, body)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
t.Run("html list "+c.path, func(t *testing.T) {
|
|
|
|
req, err := http.NewRequest(http.MethodGet, url, nil)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("New request: %v", err)
|
|
|
|
}
|
|
|
|
req.Header.Set("Accept", "text/html")
|
|
|
|
resp, err := http.DefaultClient.Do(req)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("HTTP request: %v", err)
|
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
respbody, err := ioutil.ReadAll(resp.Body)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Read response body: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if string(respbody) != c.html {
|
|
|
|
isexpectedfailrequest := false
|
|
|
|
|
|
|
|
for _, r := range expectedfailrequests {
|
|
|
|
if k[:] == r {
|
|
|
|
isexpectedfailrequest = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !isexpectedfailrequest {
|
|
|
|
t.Errorf("Response list body %q does not match, expected: %q, got %q", k, c.html, string(respbody))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2017-04-13 12:06:19 +03:00
|
|
|
nonhashtests := []string{
|
|
|
|
srv.URL + "/bzz:/name",
|
2017-12-19 11:49:30 +03:00
|
|
|
srv.URL + "/bzz-immutable:/nonhash",
|
|
|
|
srv.URL + "/bzz-raw:/nonhash",
|
|
|
|
srv.URL + "/bzz-list:/nonhash",
|
2017-12-21 15:47:10 +03:00
|
|
|
srv.URL + "/bzz-hash:/nonhash",
|
2017-04-13 12:06:19 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
nonhashresponses := []string{
|
2018-06-20 15:06:27 +03:00
|
|
|
"cannot resolve name: no DNS to resolve name: "name"",
|
|
|
|
"cannot resolve nonhash: immutable address not a content hash: "nonhash"",
|
|
|
|
"cannot resolve nonhash: no DNS to resolve name: "nonhash"",
|
|
|
|
"cannot resolve nonhash: no DNS to resolve name: "nonhash"",
|
|
|
|
"cannot resolve nonhash: no DNS to resolve name: "nonhash"",
|
2017-04-13 12:06:19 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
for i, url := range nonhashtests {
|
|
|
|
var resp *http.Response
|
|
|
|
var respbody []byte
|
|
|
|
|
|
|
|
resp, err = http.Get(url)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Request failed: %v", err)
|
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
respbody, err = ioutil.ReadAll(resp.Body)
|
2017-08-08 20:34:35 +03:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("ReadAll failed: %v", err)
|
|
|
|
}
|
2017-09-08 21:29:09 +03:00
|
|
|
if !strings.Contains(string(respbody), nonhashresponses[i]) {
|
2017-04-13 12:06:19 +03:00
|
|
|
t.Fatalf("Non-Hash response body does not match, expected: %v, got: %v", nonhashresponses[i], string(respbody))
|
|
|
|
}
|
|
|
|
}
|
2017-01-26 22:33:39 +03:00
|
|
|
}
|
2017-07-25 12:51:26 +03:00
|
|
|
|
2018-07-12 16:42:45 +03:00
|
|
|
func testBzzTar(encrypted bool, t *testing.T) {
|
|
|
|
srv := testutil.NewTestSwarmServer(t, serverFunc)
|
|
|
|
defer srv.Close()
|
|
|
|
fileNames := []string{"tmp1.txt", "tmp2.lock", "tmp3.rtf"}
|
|
|
|
fileContents := []string{"tmp1textfilevalue", "tmp2lockfilelocked", "tmp3isjustaplaintextfile"}
|
|
|
|
|
|
|
|
buf := &bytes.Buffer{}
|
|
|
|
tw := tar.NewWriter(buf)
|
|
|
|
defer tw.Close()
|
|
|
|
|
|
|
|
for i, v := range fileNames {
|
|
|
|
size := int64(len(fileContents[i]))
|
|
|
|
hdr := &tar.Header{
|
|
|
|
Name: v,
|
|
|
|
Mode: 0644,
|
|
|
|
Size: size,
|
|
|
|
ModTime: time.Now(),
|
|
|
|
Xattrs: map[string]string{
|
|
|
|
"user.swarm.content-type": "text/plain",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
if err := tw.WriteHeader(hdr); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// copy the file into the tar stream
|
|
|
|
n, err := io.Copy(tw, bytes.NewBufferString(fileContents[i]))
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
} else if n != size {
|
|
|
|
t.Fatal("size mismatch")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//post tar stream
|
|
|
|
url := srv.URL + "/bzz:/"
|
|
|
|
if encrypted {
|
|
|
|
url = url + "encrypt"
|
|
|
|
}
|
|
|
|
req, err := http.NewRequest("POST", url, buf)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
req.Header.Add("Content-Type", "application/x-tar")
|
|
|
|
client := &http.Client{}
|
|
|
|
resp2, err := client.Do(req)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if resp2.StatusCode != http.StatusOK {
|
|
|
|
t.Fatalf("err %s", resp2.Status)
|
|
|
|
}
|
|
|
|
swarmHash, err := ioutil.ReadAll(resp2.Body)
|
|
|
|
resp2.Body.Close()
|
|
|
|
t.Logf("uploaded tarball successfully and got manifest address at %s", string(swarmHash))
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// now do a GET to get a tarball back
|
|
|
|
req, err = http.NewRequest("GET", fmt.Sprintf(srv.URL+"/bzz:/%s", string(swarmHash)), nil)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
req.Header.Add("Accept", "application/x-tar")
|
|
|
|
resp2, err = client.Do(req)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
defer resp2.Body.Close()
|
|
|
|
|
|
|
|
file, err := ioutil.TempFile("", "swarm-downloaded-tarball")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
defer os.Remove(file.Name())
|
|
|
|
_, err = io.Copy(file, resp2.Body)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("error getting tarball: %v", err)
|
|
|
|
}
|
|
|
|
file.Sync()
|
|
|
|
file.Close()
|
|
|
|
|
|
|
|
tarFileHandle, err := os.Open(file.Name())
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
tr := tar.NewReader(tarFileHandle)
|
|
|
|
|
|
|
|
for {
|
|
|
|
hdr, err := tr.Next()
|
|
|
|
if err == io.EOF {
|
|
|
|
break
|
|
|
|
} else if err != nil {
|
|
|
|
t.Fatalf("error reading tar stream: %s", err)
|
|
|
|
}
|
|
|
|
bb := make([]byte, hdr.Size)
|
|
|
|
_, err = tr.Read(bb)
|
|
|
|
if err != nil && err != io.EOF {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
passed := false
|
|
|
|
for i, v := range fileNames {
|
|
|
|
if v == hdr.Name {
|
|
|
|
if string(bb) == fileContents[i] {
|
|
|
|
passed = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !passed {
|
|
|
|
t.Fatalf("file %s did not pass content assertion", hdr.Name)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-25 12:51:26 +03:00
|
|
|
// TestBzzRootRedirect tests that getting the root path of a manifest without
|
|
|
|
// a trailing slash gets redirected to include the trailing slash so that
|
|
|
|
// relative URLs work as expected.
|
|
|
|
func TestBzzRootRedirect(t *testing.T) {
|
2018-06-20 15:06:27 +03:00
|
|
|
testBzzRootRedirect(false, t)
|
|
|
|
}
|
|
|
|
func TestBzzRootRedirectEncrypted(t *testing.T) {
|
|
|
|
testBzzRootRedirect(true, t)
|
|
|
|
}
|
|
|
|
|
|
|
|
func testBzzRootRedirect(toEncrypt bool, t *testing.T) {
|
|
|
|
srv := testutil.NewTestSwarmServer(t, serverFunc)
|
2017-07-25 12:51:26 +03:00
|
|
|
defer srv.Close()
|
|
|
|
|
|
|
|
// create a manifest with some data at the root path
|
|
|
|
client := swarm.NewClient(srv.URL)
|
|
|
|
data := []byte("data")
|
|
|
|
file := &swarm.File{
|
|
|
|
ReadCloser: ioutil.NopCloser(bytes.NewReader(data)),
|
|
|
|
ManifestEntry: api.ManifestEntry{
|
|
|
|
Path: "",
|
|
|
|
ContentType: "text/plain",
|
|
|
|
Size: int64(len(data)),
|
|
|
|
},
|
|
|
|
}
|
2018-06-20 15:06:27 +03:00
|
|
|
hash, err := client.Upload(file, "", toEncrypt)
|
2017-07-25 12:51:26 +03:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// define a CheckRedirect hook which ensures there is only a single
|
|
|
|
// redirect to the correct URL
|
|
|
|
redirected := false
|
|
|
|
httpClient := http.Client{
|
|
|
|
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
|
|
|
if redirected {
|
|
|
|
return errors.New("too many redirects")
|
|
|
|
}
|
|
|
|
redirected = true
|
|
|
|
expectedPath := "/bzz:/" + hash + "/"
|
|
|
|
if req.URL.Path != expectedPath {
|
|
|
|
return fmt.Errorf("expected redirect to %q, got %q", expectedPath, req.URL.Path)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
// perform the GET request and assert the response
|
|
|
|
res, err := httpClient.Get(srv.URL + "/bzz:/" + hash)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
defer res.Body.Close()
|
|
|
|
if !redirected {
|
|
|
|
t.Fatal("expected GET /bzz:/<hash> to redirect to /bzz:/<hash>/ but it didn't")
|
|
|
|
}
|
|
|
|
gotData, err := ioutil.ReadAll(res.Body)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if !bytes.Equal(gotData, data) {
|
|
|
|
t.Fatalf("expected response to equal %q, got %q", data, gotData)
|
|
|
|
}
|
|
|
|
}
|
2018-06-20 15:06:27 +03:00
|
|
|
|
|
|
|
func TestMethodsNotAllowed(t *testing.T) {
|
|
|
|
srv := testutil.NewTestSwarmServer(t, serverFunc)
|
|
|
|
defer srv.Close()
|
|
|
|
databytes := "bar"
|
|
|
|
for _, c := range []struct {
|
|
|
|
url string
|
|
|
|
code int
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
url: fmt.Sprintf("%s/bzz-list:/", srv.URL),
|
|
|
|
code: 405,
|
|
|
|
}, {
|
|
|
|
url: fmt.Sprintf("%s/bzz-hash:/", srv.URL),
|
|
|
|
code: 405,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
url: fmt.Sprintf("%s/bzz-immutable:/", srv.URL),
|
|
|
|
code: 405,
|
|
|
|
},
|
|
|
|
} {
|
|
|
|
res, _ := http.Post(c.url, "text/plain", bytes.NewReader([]byte(databytes)))
|
|
|
|
if res.StatusCode != c.code {
|
|
|
|
t.Fatal("should have failed")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|