github.com/keltia/go-ipfs@v0.3.8-0.20150909044612-210793031c63/core/corehttp/gateway_test.go (about)

     1  package corehttp
     2  
     3  import (
     4  	"errors"
     5  	"io/ioutil"
     6  	"net/http"
     7  	"net/http/httptest"
     8  	"strings"
     9  	"testing"
    10  
    11  	context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
    12  	core "github.com/ipfs/go-ipfs/core"
    13  	coreunix "github.com/ipfs/go-ipfs/core/coreunix"
    14  	namesys "github.com/ipfs/go-ipfs/namesys"
    15  	ci "github.com/ipfs/go-ipfs/p2p/crypto"
    16  	path "github.com/ipfs/go-ipfs/path"
    17  	repo "github.com/ipfs/go-ipfs/repo"
    18  	config "github.com/ipfs/go-ipfs/repo/config"
    19  	testutil "github.com/ipfs/go-ipfs/util/testutil"
    20  )
    21  
    22  type mockNamesys map[string]path.Path
    23  
    24  func (m mockNamesys) Resolve(ctx context.Context, name string) (value path.Path, err error) {
    25  	return m.ResolveN(ctx, name, namesys.DefaultDepthLimit)
    26  }
    27  
    28  func (m mockNamesys) ResolveN(ctx context.Context, name string, depth int) (value path.Path, err error) {
    29  	p, ok := m[name]
    30  	if !ok {
    31  		return "", namesys.ErrResolveFailed
    32  	}
    33  	return p, nil
    34  }
    35  
    36  func (m mockNamesys) Publish(ctx context.Context, name ci.PrivKey, value path.Path) error {
    37  	return errors.New("not implemented for mockNamesys")
    38  }
    39  
    40  func newNodeWithMockNamesys(ns mockNamesys) (*core.IpfsNode, error) {
    41  	c := config.Config{
    42  		Identity: config.Identity{
    43  			PeerID: "Qmfoo", // required by offline node
    44  		},
    45  	}
    46  	r := &repo.Mock{
    47  		C: c,
    48  		D: testutil.ThreadSafeCloserMapDatastore(),
    49  	}
    50  	n, err := core.NewNode(context.Background(), &core.BuildCfg{Repo: r})
    51  	if err != nil {
    52  		return nil, err
    53  	}
    54  	n.Namesys = ns
    55  	return n, nil
    56  }
    57  
    58  type delegatedHandler struct {
    59  	http.Handler
    60  }
    61  
    62  func (dh *delegatedHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    63  	dh.Handler.ServeHTTP(w, r)
    64  }
    65  
    66  func doWithoutRedirect(req *http.Request) (*http.Response, error) {
    67  	tag := "without-redirect"
    68  	c := &http.Client{
    69  		CheckRedirect: func(req *http.Request, via []*http.Request) error {
    70  			return errors.New(tag)
    71  		},
    72  	}
    73  	res, err := c.Do(req)
    74  	if err != nil && !strings.Contains(err.Error(), tag) {
    75  		return nil, err
    76  	}
    77  	return res, nil
    78  }
    79  
    80  func newTestServerAndNode(t *testing.T, ns mockNamesys) (*httptest.Server, *core.IpfsNode) {
    81  	n, err := newNodeWithMockNamesys(ns)
    82  	if err != nil {
    83  		t.Fatal(err)
    84  	}
    85  
    86  	// need this variable here since we need to construct handler with
    87  	// listener, and server with handler. yay cycles.
    88  	dh := &delegatedHandler{}
    89  	ts := httptest.NewServer(dh)
    90  
    91  	dh.Handler, err = makeHandler(n,
    92  		ts.Listener,
    93  		IPNSHostnameOption(),
    94  		GatewayOption(false),
    95  	)
    96  	if err != nil {
    97  		t.Fatal(err)
    98  	}
    99  
   100  	return ts, n
   101  }
   102  
   103  func TestGatewayGet(t *testing.T) {
   104  	ns := mockNamesys{}
   105  	ts, n := newTestServerAndNode(t, ns)
   106  	defer ts.Close()
   107  
   108  	k, err := coreunix.Add(n, strings.NewReader("fnord"))
   109  	if err != nil {
   110  		t.Fatal(err)
   111  	}
   112  	ns["/ipns/example.com"] = path.FromString("/ipfs/" + k)
   113  
   114  	t.Log(ts.URL)
   115  	for _, test := range []struct {
   116  		host   string
   117  		path   string
   118  		status int
   119  		text   string
   120  	}{
   121  		{"localhost:5001", "/", http.StatusNotFound, "404 page not found\n"},
   122  		{"localhost:5001", "/" + k, http.StatusNotFound, "404 page not found\n"},
   123  		{"localhost:5001", "/ipfs/" + k, http.StatusOK, "fnord"},
   124  		{"localhost:5001", "/ipns/nxdomain.example.com", http.StatusBadRequest, "Path Resolve error: " + namesys.ErrResolveFailed.Error()},
   125  		{"localhost:5001", "/ipns/example.com", http.StatusOK, "fnord"},
   126  		{"example.com", "/", http.StatusOK, "fnord"},
   127  	} {
   128  		var c http.Client
   129  		r, err := http.NewRequest("GET", ts.URL+test.path, nil)
   130  		if err != nil {
   131  			t.Fatal(err)
   132  		}
   133  		r.Host = test.host
   134  		resp, err := c.Do(r)
   135  
   136  		urlstr := "http://" + test.host + test.path
   137  		if err != nil {
   138  			t.Errorf("error requesting %s: %s", urlstr, err)
   139  			continue
   140  		}
   141  		defer resp.Body.Close()
   142  		if resp.StatusCode != test.status {
   143  			t.Errorf("got %d, expected %d from %s", resp.StatusCode, test.status, urlstr)
   144  			continue
   145  		}
   146  		body, err := ioutil.ReadAll(resp.Body)
   147  		if err != nil {
   148  			t.Fatalf("error reading response from %s: %s", urlstr, err)
   149  		}
   150  		if string(body) != test.text {
   151  			t.Errorf("unexpected response body from %s: expected %q; got %q", urlstr, test.text, body)
   152  			continue
   153  		}
   154  	}
   155  }
   156  
   157  func TestIPNSHostnameRedirect(t *testing.T) {
   158  	ns := mockNamesys{}
   159  	ts, n := newTestServerAndNode(t, ns)
   160  	t.Logf("test server url: %s", ts.URL)
   161  	defer ts.Close()
   162  
   163  	// create /ipns/example.net/foo/index.html
   164  	_, dagn1, err := coreunix.AddWrapped(n, strings.NewReader("_"), "_")
   165  	if err != nil {
   166  		t.Fatal(err)
   167  	}
   168  	_, dagn2, err := coreunix.AddWrapped(n, strings.NewReader("_"), "index.html")
   169  	if err != nil {
   170  		t.Fatal(err)
   171  	}
   172  	dagn1.AddNodeLink("foo", dagn2)
   173  	if err != nil {
   174  		t.Fatal(err)
   175  	}
   176  
   177  	err = n.DAG.AddRecursive(dagn1)
   178  	if err != nil {
   179  		t.Fatal(err)
   180  	}
   181  
   182  	k, err := dagn1.Key()
   183  	if err != nil {
   184  		t.Fatal(err)
   185  	}
   186  	t.Logf("k: %s\n", k)
   187  	ns["/ipns/example.net"] = path.FromString("/ipfs/" + k.String())
   188  
   189  	// make request to directory containing index.html
   190  	req, err := http.NewRequest("GET", ts.URL+"/foo", nil)
   191  	if err != nil {
   192  		t.Fatal(err)
   193  	}
   194  	req.Host = "example.net"
   195  
   196  	res, err := doWithoutRedirect(req)
   197  	if err != nil {
   198  		t.Fatal(err)
   199  	}
   200  
   201  	// expect 302 redirect to same path, but with trailing slash
   202  	if res.StatusCode != 302 {
   203  		t.Errorf("status is %d, expected 302", res.StatusCode)
   204  	}
   205  	hdr := res.Header["Location"]
   206  	if len(hdr) < 1 {
   207  		t.Errorf("location header not present")
   208  	} else if hdr[0] != "/foo/" {
   209  		t.Errorf("location header is %v, expected /foo/", hdr[0])
   210  	}
   211  }
   212  
   213  func TestIPNSHostnameBacklinks(t *testing.T) {
   214  	ns := mockNamesys{}
   215  	ts, n := newTestServerAndNode(t, ns)
   216  	t.Logf("test server url: %s", ts.URL)
   217  	defer ts.Close()
   218  
   219  	// create /ipns/example.net/foo/
   220  	_, dagn1, err := coreunix.AddWrapped(n, strings.NewReader("1"), "file.txt")
   221  	if err != nil {
   222  		t.Fatal(err)
   223  	}
   224  	_, dagn2, err := coreunix.AddWrapped(n, strings.NewReader("2"), "file.txt")
   225  	if err != nil {
   226  		t.Fatal(err)
   227  	}
   228  	_, dagn3, err := coreunix.AddWrapped(n, strings.NewReader("3"), "file.txt")
   229  	if err != nil {
   230  		t.Fatal(err)
   231  	}
   232  	dagn2.AddNodeLink("bar", dagn3)
   233  	dagn1.AddNodeLink("foo", dagn2)
   234  	if err != nil {
   235  		t.Fatal(err)
   236  	}
   237  
   238  	err = n.DAG.AddRecursive(dagn1)
   239  	if err != nil {
   240  		t.Fatal(err)
   241  	}
   242  
   243  	k, err := dagn1.Key()
   244  	if err != nil {
   245  		t.Fatal(err)
   246  	}
   247  	t.Logf("k: %s\n", k)
   248  	ns["/ipns/example.net"] = path.FromString("/ipfs/" + k.String())
   249  
   250  	// make request to directory listing
   251  	req, err := http.NewRequest("GET", ts.URL+"/foo/", nil)
   252  	if err != nil {
   253  		t.Fatal(err)
   254  	}
   255  	req.Host = "example.net"
   256  
   257  	res, err := doWithoutRedirect(req)
   258  	if err != nil {
   259  		t.Fatal(err)
   260  	}
   261  
   262  	// expect correct backlinks
   263  	body, err := ioutil.ReadAll(res.Body)
   264  	if err != nil {
   265  		t.Fatalf("error reading response: %s", err)
   266  	}
   267  	s := string(body)
   268  	t.Logf("body: %s\n", string(body))
   269  
   270  	if !strings.Contains(s, "Index of /foo/") {
   271  		t.Fatalf("expected a path in directory listing")
   272  	}
   273  	if !strings.Contains(s, "<a href=\"/\">") {
   274  		t.Fatalf("expected backlink in directory listing")
   275  	}
   276  	if !strings.Contains(s, "<a href=\"/foo/file.txt\">") {
   277  		t.Fatalf("expected file in directory listing")
   278  	}
   279  
   280  	// make request to directory listing
   281  	req, err = http.NewRequest("GET", ts.URL, nil)
   282  	if err != nil {
   283  		t.Fatal(err)
   284  	}
   285  	req.Host = "example.net"
   286  
   287  	res, err = doWithoutRedirect(req)
   288  	if err != nil {
   289  		t.Fatal(err)
   290  	}
   291  
   292  	// expect correct backlinks
   293  	body, err = ioutil.ReadAll(res.Body)
   294  	if err != nil {
   295  		t.Fatalf("error reading response: %s", err)
   296  	}
   297  	s = string(body)
   298  	t.Logf("body: %s\n", string(body))
   299  
   300  	if !strings.Contains(s, "Index of /") {
   301  		t.Fatalf("expected a path in directory listing")
   302  	}
   303  	if !strings.Contains(s, "<a href=\"/\">") {
   304  		t.Fatalf("expected backlink in directory listing")
   305  	}
   306  	if !strings.Contains(s, "<a href=\"/file.txt\">") {
   307  		t.Fatalf("expected file in directory listing")
   308  	}
   309  
   310  	// make request to directory listing
   311  	req, err = http.NewRequest("GET", ts.URL+"/foo/bar/", nil)
   312  	if err != nil {
   313  		t.Fatal(err)
   314  	}
   315  	req.Host = "example.net"
   316  
   317  	res, err = doWithoutRedirect(req)
   318  	if err != nil {
   319  		t.Fatal(err)
   320  	}
   321  
   322  	// expect correct backlinks
   323  	body, err = ioutil.ReadAll(res.Body)
   324  	if err != nil {
   325  		t.Fatalf("error reading response: %s", err)
   326  	}
   327  	s = string(body)
   328  	t.Logf("body: %s\n", string(body))
   329  
   330  	if !strings.Contains(s, "Index of /foo/bar/") {
   331  		t.Fatalf("expected a path in directory listing")
   332  	}
   333  	if !strings.Contains(s, "<a href=\"/foo/\">") {
   334  		t.Fatalf("expected backlink in directory listing")
   335  	}
   336  	if !strings.Contains(s, "<a href=\"/foo/bar/file.txt\">") {
   337  		t.Fatalf("expected file in directory listing")
   338  	}
   339  }