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 }