| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | // Copyright 2016 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/>. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package api | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2018-10-01 18:39:39 +07:00
										 |  |  | 	"bytes" | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2017-05-12 17:02:25 -07:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2018-08-15 17:41:52 +02:00
										 |  |  | 	"flag" | 
					
						
							| 
									
										
										
										
											2017-02-22 14:10:07 +02:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | 	"io" | 
					
						
							|  |  |  | 	"io/ioutil" | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 	"math/big" | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | 	"os" | 
					
						
							|  |  |  | 	"testing" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-06 23:22:22 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/common" | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/core/types" | 
					
						
							| 
									
										
										
										
											2018-08-15 17:41:52 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/log" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/swarm/sctx" | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/swarm/storage" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-15 17:41:52 +02: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))))) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | func testAPI(t *testing.T, f func(*API, bool)) { | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | 	datadir, err := ioutil.TempDir("", "bzz-test") | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("unable to create temp dir: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer os.RemoveAll(datadir) | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 	fileStore, err := storage.NewLocalFileStore(datadir, make([]byte, 32)) | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-08-15 17:41:52 +02:00
										 |  |  | 	api := NewAPI(fileStore, nil, nil, nil) | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 	f(api, false) | 
					
						
							|  |  |  | 	f(api, true) | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type testResponse struct { | 
					
						
							|  |  |  | 	reader storage.LazySectionReader | 
					
						
							|  |  |  | 	*Response | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func checkResponse(t *testing.T, resp *testResponse, exp *Response) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if resp.MimeType != exp.MimeType { | 
					
						
							|  |  |  | 		t.Errorf("incorrect mimeType. expected '%s', got '%s'", exp.MimeType, resp.MimeType) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if resp.Status != exp.Status { | 
					
						
							|  |  |  | 		t.Errorf("incorrect status. expected '%d', got '%d'", exp.Status, resp.Status) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if resp.Size != exp.Size { | 
					
						
							|  |  |  | 		t.Errorf("incorrect size. expected '%d', got '%d'", exp.Size, resp.Size) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if resp.reader != nil { | 
					
						
							|  |  |  | 		content := make([]byte, resp.Size) | 
					
						
							|  |  |  | 		read, _ := resp.reader.Read(content) | 
					
						
							|  |  |  | 		if int64(read) != exp.Size { | 
					
						
							|  |  |  | 			t.Errorf("incorrect content length. expected '%d...', got '%d...'", read, exp.Size) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		resp.Content = string(content) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if resp.Content != exp.Content { | 
					
						
							|  |  |  | 		// if !bytes.Equal(resp.Content, exp.Content) | 
					
						
							|  |  |  | 		t.Errorf("incorrect content. expected '%s...', got '%s...'", string(exp.Content), string(resp.Content)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // func expResponse(content []byte, mimeType string, status int) *Response { | 
					
						
							|  |  |  | func expResponse(content string, mimeType string, status int) *Response { | 
					
						
							| 
									
										
										
										
											2017-02-22 14:10:07 +02:00
										 |  |  | 	log.Trace(fmt.Sprintf("expected content (%v): %v ", len(content), content)) | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | 	return &Response{mimeType, status, int64(len(content)), content} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | func testGet(t *testing.T, api *API, bzzhash, path string) *testResponse { | 
					
						
							|  |  |  | 	addr := storage.Address(common.Hex2Bytes(bzzhash)) | 
					
						
							| 
									
										
										
										
											2018-08-15 17:41:52 +02:00
										 |  |  | 	reader, mimeType, status, _, err := api.Get(context.TODO(), NOOPDecrypt, addr, path) | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("unexpected error: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	quitC := make(chan bool) | 
					
						
							| 
									
										
										
										
											2018-07-13 17:40:28 +02:00
										 |  |  | 	size, err := reader.Size(context.TODO(), quitC) | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("unexpected error: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-02-22 14:10:07 +02:00
										 |  |  | 	log.Trace(fmt.Sprintf("reader size: %v ", size)) | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | 	s := make([]byte, size) | 
					
						
							|  |  |  | 	_, err = reader.Read(s) | 
					
						
							|  |  |  | 	if err != io.EOF { | 
					
						
							|  |  |  | 		t.Fatalf("unexpected error: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	reader.Seek(0, 0) | 
					
						
							|  |  |  | 	return &testResponse{reader, &Response{mimeType, status, size, string(s)}} | 
					
						
							|  |  |  | 	// return &testResponse{reader, &Response{mimeType, status, reader.Size(), nil}} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestApiPut(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 	testAPI(t, func(api *API, toEncrypt bool) { | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | 		content := "hello" | 
					
						
							|  |  |  | 		exp := expResponse(content, "text/plain", 0) | 
					
						
							| 
									
										
										
										
											2018-07-09 14:11:49 +02:00
										 |  |  | 		ctx := context.TODO() | 
					
						
							|  |  |  | 		addr, wait, err := api.Put(ctx, content, exp.MimeType, toEncrypt) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			t.Fatalf("unexpected error: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		err = wait(ctx) | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			t.Fatalf("unexpected error: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 		resp := testGet(t, api, addr.Hex(), "") | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | 		checkResponse(t, resp, exp) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2017-05-12 17:02:25 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | // testResolver implements the Resolver interface and either returns the given | 
					
						
							|  |  |  | // hash if it is set, or returns a "name not found" error | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | type testResolveValidator struct { | 
					
						
							| 
									
										
										
										
											2017-05-12 17:02:25 -07:00
										 |  |  | 	hash *common.Hash | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | func newTestResolveValidator(addr string) *testResolveValidator { | 
					
						
							|  |  |  | 	r := &testResolveValidator{} | 
					
						
							| 
									
										
										
										
											2017-05-12 17:02:25 -07:00
										 |  |  | 	if addr != "" { | 
					
						
							|  |  |  | 		hash := common.HexToHash(addr) | 
					
						
							|  |  |  | 		r.hash = &hash | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return r | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | func (t *testResolveValidator) Resolve(addr string) (common.Hash, error) { | 
					
						
							| 
									
										
										
										
											2017-05-12 17:02:25 -07:00
										 |  |  | 	if t.hash == nil { | 
					
						
							|  |  |  | 		return common.Hash{}, fmt.Errorf("DNS name not found: %q", addr) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return *t.hash, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | func (t *testResolveValidator) Owner(node [32]byte) (addr common.Address, err error) { | 
					
						
							|  |  |  | 	return | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | func (t *testResolveValidator) HeaderByNumber(context.Context, *big.Int) (header *types.Header, err error) { | 
					
						
							|  |  |  | 	return | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-12 17:02:25 -07:00
										 |  |  | // TestAPIResolve tests resolving URIs which can either contain content hashes | 
					
						
							|  |  |  | // or ENS names | 
					
						
							|  |  |  | func TestAPIResolve(t *testing.T) { | 
					
						
							|  |  |  | 	ensAddr := "swarm.eth" | 
					
						
							|  |  |  | 	hashAddr := "1111111111111111111111111111111111111111111111111111111111111111" | 
					
						
							|  |  |  | 	resolvedAddr := "2222222222222222222222222222222222222222222222222222222222222222" | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 	doesResolve := newTestResolveValidator(resolvedAddr) | 
					
						
							|  |  |  | 	doesntResolve := newTestResolveValidator("") | 
					
						
							| 
									
										
										
										
											2017-05-12 17:02:25 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	type test struct { | 
					
						
							|  |  |  | 		desc      string | 
					
						
							|  |  |  | 		dns       Resolver | 
					
						
							|  |  |  | 		addr      string | 
					
						
							|  |  |  | 		immutable bool | 
					
						
							|  |  |  | 		result    string | 
					
						
							|  |  |  | 		expectErr error | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tests := []*test{ | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			desc:   "DNS not configured, hash address, returns hash address", | 
					
						
							|  |  |  | 			dns:    nil, | 
					
						
							|  |  |  | 			addr:   hashAddr, | 
					
						
							|  |  |  | 			result: hashAddr, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			desc:      "DNS not configured, ENS address, returns error", | 
					
						
							|  |  |  | 			dns:       nil, | 
					
						
							|  |  |  | 			addr:      ensAddr, | 
					
						
							|  |  |  | 			expectErr: errors.New(`no DNS to resolve name: "swarm.eth"`), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			desc:   "DNS configured, hash address, hash resolves, returns resolved address", | 
					
						
							|  |  |  | 			dns:    doesResolve, | 
					
						
							|  |  |  | 			addr:   hashAddr, | 
					
						
							|  |  |  | 			result: resolvedAddr, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			desc:      "DNS configured, immutable hash address, hash resolves, returns hash address", | 
					
						
							|  |  |  | 			dns:       doesResolve, | 
					
						
							|  |  |  | 			addr:      hashAddr, | 
					
						
							|  |  |  | 			immutable: true, | 
					
						
							|  |  |  | 			result:    hashAddr, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			desc:   "DNS configured, hash address, hash doesn't resolve, returns hash address", | 
					
						
							|  |  |  | 			dns:    doesntResolve, | 
					
						
							|  |  |  | 			addr:   hashAddr, | 
					
						
							|  |  |  | 			result: hashAddr, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			desc:   "DNS configured, ENS address, name resolves, returns resolved address", | 
					
						
							|  |  |  | 			dns:    doesResolve, | 
					
						
							|  |  |  | 			addr:   ensAddr, | 
					
						
							|  |  |  | 			result: resolvedAddr, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			desc:      "DNS configured, immutable ENS address, name resolves, returns error", | 
					
						
							|  |  |  | 			dns:       doesResolve, | 
					
						
							|  |  |  | 			addr:      ensAddr, | 
					
						
							|  |  |  | 			immutable: true, | 
					
						
							|  |  |  | 			expectErr: errors.New(`immutable address not a content hash: "swarm.eth"`), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			desc:      "DNS configured, ENS address, name doesn't resolve, returns error", | 
					
						
							|  |  |  | 			dns:       doesntResolve, | 
					
						
							|  |  |  | 			addr:      ensAddr, | 
					
						
							|  |  |  | 			expectErr: errors.New(`DNS name not found: "swarm.eth"`), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for _, x := range tests { | 
					
						
							|  |  |  | 		t.Run(x.desc, func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 			api := &API{dns: x.dns} | 
					
						
							| 
									
										
										
										
											2017-05-12 17:02:25 -07:00
										 |  |  | 			uri := &URI{Addr: x.addr, Scheme: "bzz"} | 
					
						
							|  |  |  | 			if x.immutable { | 
					
						
							| 
									
										
										
										
											2017-12-19 09:49:30 +01:00
										 |  |  | 				uri.Scheme = "bzz-immutable" | 
					
						
							| 
									
										
										
										
											2017-05-12 17:02:25 -07:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-08-15 17:41:52 +02:00
										 |  |  | 			res, err := api.ResolveURI(context.TODO(), uri, "") | 
					
						
							| 
									
										
										
										
											2017-05-12 17:02:25 -07:00
										 |  |  | 			if err == nil { | 
					
						
							|  |  |  | 				if x.expectErr != nil { | 
					
						
							|  |  |  | 					t.Fatalf("expected error %q, got result %q", x.expectErr, res) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				if res.String() != x.result { | 
					
						
							|  |  |  | 					t.Fatalf("expected result %q, got %q", x.result, res) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				if x.expectErr == nil { | 
					
						
							|  |  |  | 					t.Fatalf("expected no error, got %q", err) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				if err.Error() != x.expectErr.Error() { | 
					
						
							|  |  |  | 					t.Fatalf("expected error %q, got %q", x.expectErr, err) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2017-12-01 10:32:14 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | func TestMultiResolver(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 	doesntResolve := newTestResolveValidator("") | 
					
						
							| 
									
										
										
										
											2017-12-01 10:32:14 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	ethAddr := "swarm.eth" | 
					
						
							|  |  |  | 	ethHash := "0x2222222222222222222222222222222222222222222222222222222222222222" | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 	ethResolve := newTestResolveValidator(ethHash) | 
					
						
							| 
									
										
										
										
											2017-12-01 10:32:14 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	testAddr := "swarm.test" | 
					
						
							|  |  |  | 	testHash := "0x1111111111111111111111111111111111111111111111111111111111111111" | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 	testResolve := newTestResolveValidator(testHash) | 
					
						
							| 
									
										
										
										
											2017-12-01 10:32:14 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	tests := []struct { | 
					
						
							|  |  |  | 		desc   string | 
					
						
							|  |  |  | 		r      Resolver | 
					
						
							|  |  |  | 		addr   string | 
					
						
							|  |  |  | 		result string | 
					
						
							|  |  |  | 		err    error | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			desc: "No resolvers, returns error", | 
					
						
							|  |  |  | 			r:    NewMultiResolver(), | 
					
						
							| 
									
										
										
										
											2017-12-18 23:07:48 +01:00
										 |  |  | 			err:  NewNoResolverError(""), | 
					
						
							| 
									
										
										
										
											2017-12-01 10:32:14 +01:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			desc:   "One default resolver, returns resolved address", | 
					
						
							|  |  |  | 			r:      NewMultiResolver(MultiResolverOptionWithResolver(ethResolve, "")), | 
					
						
							|  |  |  | 			addr:   ethAddr, | 
					
						
							|  |  |  | 			result: ethHash, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			desc: "Two default resolvers, returns resolved address", | 
					
						
							|  |  |  | 			r: NewMultiResolver( | 
					
						
							|  |  |  | 				MultiResolverOptionWithResolver(ethResolve, ""), | 
					
						
							|  |  |  | 				MultiResolverOptionWithResolver(ethResolve, ""), | 
					
						
							|  |  |  | 			), | 
					
						
							|  |  |  | 			addr:   ethAddr, | 
					
						
							|  |  |  | 			result: ethHash, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			desc: "Two default resolvers, first doesn't resolve, returns resolved address", | 
					
						
							|  |  |  | 			r: NewMultiResolver( | 
					
						
							|  |  |  | 				MultiResolverOptionWithResolver(doesntResolve, ""), | 
					
						
							|  |  |  | 				MultiResolverOptionWithResolver(ethResolve, ""), | 
					
						
							|  |  |  | 			), | 
					
						
							|  |  |  | 			addr:   ethAddr, | 
					
						
							|  |  |  | 			result: ethHash, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			desc: "Default resolver doesn't resolve, tld resolver resolve, returns resolved address", | 
					
						
							|  |  |  | 			r: NewMultiResolver( | 
					
						
							|  |  |  | 				MultiResolverOptionWithResolver(doesntResolve, ""), | 
					
						
							|  |  |  | 				MultiResolverOptionWithResolver(ethResolve, "eth"), | 
					
						
							|  |  |  | 			), | 
					
						
							|  |  |  | 			addr:   ethAddr, | 
					
						
							|  |  |  | 			result: ethHash, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			desc: "Three TLD resolvers, third resolves, returns resolved address", | 
					
						
							|  |  |  | 			r: NewMultiResolver( | 
					
						
							|  |  |  | 				MultiResolverOptionWithResolver(doesntResolve, "eth"), | 
					
						
							|  |  |  | 				MultiResolverOptionWithResolver(doesntResolve, "eth"), | 
					
						
							|  |  |  | 				MultiResolverOptionWithResolver(ethResolve, "eth"), | 
					
						
							|  |  |  | 			), | 
					
						
							|  |  |  | 			addr:   ethAddr, | 
					
						
							|  |  |  | 			result: ethHash, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			desc: "One TLD resolver doesn't resolve, returns error", | 
					
						
							|  |  |  | 			r: NewMultiResolver( | 
					
						
							|  |  |  | 				MultiResolverOptionWithResolver(doesntResolve, ""), | 
					
						
							|  |  |  | 				MultiResolverOptionWithResolver(ethResolve, "eth"), | 
					
						
							|  |  |  | 			), | 
					
						
							|  |  |  | 			addr:   ethAddr, | 
					
						
							|  |  |  | 			result: ethHash, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			desc: "One defautl and one TLD resolver, all doesn't resolve, returns error", | 
					
						
							|  |  |  | 			r: NewMultiResolver( | 
					
						
							|  |  |  | 				MultiResolverOptionWithResolver(doesntResolve, ""), | 
					
						
							|  |  |  | 				MultiResolverOptionWithResolver(doesntResolve, "eth"), | 
					
						
							|  |  |  | 			), | 
					
						
							|  |  |  | 			addr:   ethAddr, | 
					
						
							|  |  |  | 			result: ethHash, | 
					
						
							|  |  |  | 			err:    errors.New(`DNS name not found: "swarm.eth"`), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			desc: "Two TLD resolvers, both resolve, returns resolved address", | 
					
						
							|  |  |  | 			r: NewMultiResolver( | 
					
						
							|  |  |  | 				MultiResolverOptionWithResolver(ethResolve, "eth"), | 
					
						
							|  |  |  | 				MultiResolverOptionWithResolver(testResolve, "test"), | 
					
						
							|  |  |  | 			), | 
					
						
							|  |  |  | 			addr:   testAddr, | 
					
						
							|  |  |  | 			result: testHash, | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2017-12-18 23:07:48 +01:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			desc: "One TLD resolver, no default resolver, returns error for different TLD", | 
					
						
							|  |  |  | 			r: NewMultiResolver( | 
					
						
							|  |  |  | 				MultiResolverOptionWithResolver(ethResolve, "eth"), | 
					
						
							|  |  |  | 			), | 
					
						
							|  |  |  | 			addr: testAddr, | 
					
						
							|  |  |  | 			err:  NewNoResolverError("test"), | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2017-12-01 10:32:14 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	for _, x := range tests { | 
					
						
							|  |  |  | 		t.Run(x.desc, func(t *testing.T) { | 
					
						
							|  |  |  | 			res, err := x.r.Resolve(x.addr) | 
					
						
							|  |  |  | 			if err == nil { | 
					
						
							|  |  |  | 				if x.err != nil { | 
					
						
							|  |  |  | 					t.Fatalf("expected error %q, got result %q", x.err, res.Hex()) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				if res.Hex() != x.result { | 
					
						
							|  |  |  | 					t.Fatalf("expected result %q, got %q", x.result, res.Hex()) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				if x.err == nil { | 
					
						
							|  |  |  | 					t.Fatalf("expected no error, got %q", err) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				if err.Error() != x.err.Error() { | 
					
						
							|  |  |  | 					t.Fatalf("expected error %q, got %q", x.err, err) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-08-15 17:41:52 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | func TestDecryptOriginForbidden(t *testing.T) { | 
					
						
							|  |  |  | 	ctx := context.TODO() | 
					
						
							|  |  |  | 	ctx = sctx.SetHost(ctx, "swarm-gateways.net") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	me := &ManifestEntry{ | 
					
						
							|  |  |  | 		Access: &AccessEntry{Type: AccessTypePass}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	api := NewAPI(nil, nil, nil, nil) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	f := api.Decryptor(ctx, "") | 
					
						
							|  |  |  | 	err := f(me) | 
					
						
							|  |  |  | 	if err != ErrDecryptDomainForbidden { | 
					
						
							|  |  |  | 		t.Fatalf("should fail with ErrDecryptDomainForbidden, got %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestDecryptOrigin(t *testing.T) { | 
					
						
							|  |  |  | 	for _, v := range []struct { | 
					
						
							|  |  |  | 		host        string | 
					
						
							|  |  |  | 		expectError error | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			host:        "localhost", | 
					
						
							|  |  |  | 			expectError: ErrDecrypt, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			host:        "127.0.0.1", | 
					
						
							|  |  |  | 			expectError: ErrDecrypt, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			host:        "swarm-gateways.net", | 
					
						
							|  |  |  | 			expectError: ErrDecryptDomainForbidden, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} { | 
					
						
							|  |  |  | 		ctx := context.TODO() | 
					
						
							|  |  |  | 		ctx = sctx.SetHost(ctx, v.host) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		me := &ManifestEntry{ | 
					
						
							|  |  |  | 			Access: &AccessEntry{Type: AccessTypePass}, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		api := NewAPI(nil, nil, nil, nil) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		f := api.Decryptor(ctx, "") | 
					
						
							|  |  |  | 		err := f(me) | 
					
						
							|  |  |  | 		if err != v.expectError { | 
					
						
							|  |  |  | 			t.Fatalf("should fail with %v, got %v", v.expectError, err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-10-01 18:39:39 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  | func TestDetectContentType(t *testing.T) { | 
					
						
							|  |  |  | 	for _, tc := range []struct { | 
					
						
							|  |  |  | 		file                string | 
					
						
							|  |  |  | 		content             string | 
					
						
							|  |  |  | 		expectedContentType string | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			file:                "file-with-correct-css.css", | 
					
						
							|  |  |  | 			content:             "body {background-color: orange}", | 
					
						
							|  |  |  | 			expectedContentType: "text/css; charset=utf-8", | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			file:                "empty-file.css", | 
					
						
							|  |  |  | 			content:             "", | 
					
						
							|  |  |  | 			expectedContentType: "text/css; charset=utf-8", | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			file:                "empty-file.pdf", | 
					
						
							|  |  |  | 			content:             "", | 
					
						
							|  |  |  | 			expectedContentType: "application/pdf", | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			file:                "empty-file.md", | 
					
						
							|  |  |  | 			content:             "", | 
					
						
							|  |  |  | 			expectedContentType: "text/markdown; charset=utf-8", | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			file:                "empty-file-with-unknown-content.strangeext", | 
					
						
							|  |  |  | 			content:             "", | 
					
						
							|  |  |  | 			expectedContentType: "text/plain; charset=utf-8", | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			file:                "file-with-unknown-extension-and-content.strangeext", | 
					
						
							|  |  |  | 			content:             "Lorem Ipsum", | 
					
						
							|  |  |  | 			expectedContentType: "text/plain; charset=utf-8", | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			file:                "file-no-extension", | 
					
						
							|  |  |  | 			content:             "Lorem Ipsum", | 
					
						
							|  |  |  | 			expectedContentType: "text/plain; charset=utf-8", | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			file:                "file-no-extension-no-content", | 
					
						
							|  |  |  | 			content:             "", | 
					
						
							|  |  |  | 			expectedContentType: "text/plain; charset=utf-8", | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			file:                "css-file-with-html-inside.css", | 
					
						
							|  |  |  | 			content:             "<!doctype html><html><head></head><body></body></html>", | 
					
						
							|  |  |  | 			expectedContentType: "text/css; charset=utf-8", | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} { | 
					
						
							|  |  |  | 		t.Run(tc.file, func(t *testing.T) { | 
					
						
							|  |  |  | 			detected, err := DetectContentType(tc.file, bytes.NewReader([]byte(tc.content))) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				t.Fatal(err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if detected != tc.expectedContentType { | 
					
						
							|  |  |  | 				t.Fatalf("File: %s, Expected mime type %s, got %s", tc.file, tc.expectedContentType, detected) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |