12167: Propagate X-Request-Id in API calls.
[arvados.git] / services / keep-web / handler_test.go
index 508c9cb21e382f115ec0b5422f342a42614b7bbd..4894ceb70b2087d21bf08cd3bae1e20fd78a43e0 100644 (file)
@@ -1,11 +1,18 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
 package main
 
 import (
+       "bytes"
+       "fmt"
        "html"
        "io/ioutil"
        "net/http"
        "net/http/httptest"
        "net/url"
+       "path/filepath"
        "regexp"
        "strings"
 
@@ -38,12 +45,12 @@ func (s *UnitSuite) TestCORSPreflight(c *check.C) {
        c.Check(resp.Code, check.Equals, http.StatusOK)
        c.Check(resp.Body.String(), check.Equals, "")
        c.Check(resp.Header().Get("Access-Control-Allow-Origin"), check.Equals, "*")
-       c.Check(resp.Header().Get("Access-Control-Allow-Methods"), check.Equals, "GET, POST")
-       c.Check(resp.Header().Get("Access-Control-Allow-Headers"), check.Equals, "Range")
+       c.Check(resp.Header().Get("Access-Control-Allow-Methods"), check.Equals, "COPY, DELETE, GET, MKCOL, MOVE, OPTIONS, POST, PROPFIND, PUT, RMCOL")
+       c.Check(resp.Header().Get("Access-Control-Allow-Headers"), check.Equals, "Authorization, Content-Type, Range")
 
        // Check preflight for a disallowed request
        resp = httptest.NewRecorder()
-       req.Header.Set("Access-Control-Request-Method", "DELETE")
+       req.Header.Set("Access-Control-Request-Method", "MAKE-COFFEE")
        h.ServeHTTP(resp, req)
        c.Check(resp.Body.String(), check.Equals, "")
        c.Check(resp.Code, check.Equals, http.StatusMethodNotAllowed)
@@ -326,7 +333,20 @@ func (s *IntegrationSuite) TestVhostRedirectQueryTokenRequestAttachment(c *check
                http.StatusOK,
                "foo",
        )
-       c.Check(strings.Split(resp.Header().Get("Content-Disposition"), ";")[0], check.Equals, "attachment")
+       c.Check(resp.Header().Get("Content-Disposition"), check.Matches, "attachment(;.*)?")
+}
+
+func (s *IntegrationSuite) TestVhostRedirectQueryTokenSiteFS(c *check.C) {
+       s.testServer.Config.AttachmentOnlyHost = "download.example.com"
+       resp := s.testVhostRedirectTokenToCookie(c, "GET",
+               "download.example.com/by_id/"+arvadostest.FooCollection+"/foo",
+               "?api_token="+arvadostest.ActiveToken,
+               "",
+               "",
+               http.StatusOK,
+               "foo",
+       )
+       c.Check(resp.Header().Get("Content-Disposition"), check.Matches, "attachment(;.*)?")
 }
 
 func (s *IntegrationSuite) TestVhostRedirectQueryTokenTrustAllContent(c *check.C) {
@@ -486,49 +506,117 @@ func (s *IntegrationSuite) TestDirectoryListing(c *check.C) {
                "Authorization": {"OAuth2 " + arvadostest.ActiveToken},
        }
        for _, trial := range []struct {
-               uri    string
-               header http.Header
-               expect []string
+               uri      string
+               header   http.Header
+               expect   []string
+               redirect string
+               cutDirs  int
        }{
                {
-                       uri:    strings.Replace(arvadostest.FooAndBarFilesInDirPDH, "+", "-", -1) + ".example.com/",
-                       header: authHeader,
-                       expect: []string{"dir1/foo", "dir1/bar"},
+                       uri:     strings.Replace(arvadostest.FooAndBarFilesInDirPDH, "+", "-", -1) + ".example.com/",
+                       header:  authHeader,
+                       expect:  []string{"dir1/foo", "dir1/bar"},
+                       cutDirs: 0,
                },
                {
-                       uri:    strings.Replace(arvadostest.FooAndBarFilesInDirPDH, "+", "-", -1) + ".example.com/dir1/",
-                       header: authHeader,
-                       expect: []string{"foo", "bar"},
+                       uri:     strings.Replace(arvadostest.FooAndBarFilesInDirPDH, "+", "-", -1) + ".example.com/dir1/",
+                       header:  authHeader,
+                       expect:  []string{"foo", "bar"},
+                       cutDirs: 1,
                },
                {
-                       uri:    "download.example.com/collections/" + arvadostest.FooAndBarFilesInDirUUID + "/",
-                       header: authHeader,
-                       expect: []string{"dir1/foo", "dir1/bar"},
+                       uri:     "download.example.com/collections/" + arvadostest.FooAndBarFilesInDirUUID + "/",
+                       header:  authHeader,
+                       expect:  []string{"dir1/foo", "dir1/bar"},
+                       cutDirs: 2,
                },
                {
-                       uri:    "collections.example.com/collections/download/" + arvadostest.FooAndBarFilesInDirUUID + "/" + arvadostest.ActiveToken + "/",
-                       header: nil,
-                       expect: []string{"dir1/foo", "dir1/bar"},
+                       uri:     "download.example.com/users/active/foo_file_in_dir/",
+                       header:  authHeader,
+                       expect:  []string{"dir1/"},
+                       cutDirs: 3,
                },
                {
-                       uri:    "collections.example.com/c=" + arvadostest.FooAndBarFilesInDirUUID + "/t=" + arvadostest.ActiveToken + "/",
-                       header: nil,
-                       expect: []string{"dir1/foo", "dir1/bar"},
+                       uri:     "download.example.com/users/active/foo_file_in_dir/dir1/",
+                       header:  authHeader,
+                       expect:  []string{"bar"},
+                       cutDirs: 4,
                },
                {
-                       uri:    "download.example.com/c=" + arvadostest.FooAndBarFilesInDirUUID + "/dir1/",
-                       header: authHeader,
-                       expect: []string{"foo", "bar"},
+                       uri:     "download.example.com/",
+                       header:  authHeader,
+                       expect:  []string{"users/"},
+                       cutDirs: 0,
                },
                {
-                       uri:    "download.example.com/c=" + arvadostest.FooAndBarFilesInDirUUID + "/_/dir1/",
-                       header: authHeader,
-                       expect: []string{"foo", "bar"},
+                       uri:      "download.example.com/users",
+                       header:   authHeader,
+                       redirect: "/users/",
+                       expect:   []string{"active/"},
+                       cutDirs:  1,
                },
                {
-                       uri:    arvadostest.FooAndBarFilesInDirUUID + ".example.com/dir1?api_token=" + arvadostest.ActiveToken,
-                       header: authHeader,
-                       expect: []string{"foo", "bar"},
+                       uri:     "download.example.com/users/",
+                       header:  authHeader,
+                       expect:  []string{"active/"},
+                       cutDirs: 1,
+               },
+               {
+                       uri:      "download.example.com/users/active",
+                       header:   authHeader,
+                       redirect: "/users/active/",
+                       expect:   []string{"foo_file_in_dir/"},
+                       cutDirs:  2,
+               },
+               {
+                       uri:     "download.example.com/users/active/",
+                       header:  authHeader,
+                       expect:  []string{"foo_file_in_dir/"},
+                       cutDirs: 2,
+               },
+               {
+                       uri:     "collections.example.com/collections/download/" + arvadostest.FooAndBarFilesInDirUUID + "/" + arvadostest.ActiveToken + "/",
+                       header:  nil,
+                       expect:  []string{"dir1/foo", "dir1/bar"},
+                       cutDirs: 4,
+               },
+               {
+                       uri:     "collections.example.com/c=" + arvadostest.FooAndBarFilesInDirUUID + "/t=" + arvadostest.ActiveToken + "/",
+                       header:  nil,
+                       expect:  []string{"dir1/foo", "dir1/bar"},
+                       cutDirs: 2,
+               },
+               {
+                       uri:     "collections.example.com/c=" + arvadostest.FooAndBarFilesInDirUUID + "/t=" + arvadostest.ActiveToken,
+                       header:  nil,
+                       expect:  []string{"dir1/foo", "dir1/bar"},
+                       cutDirs: 2,
+               },
+               {
+                       uri:     "download.example.com/c=" + arvadostest.FooAndBarFilesInDirUUID,
+                       header:  authHeader,
+                       expect:  []string{"dir1/foo", "dir1/bar"},
+                       cutDirs: 1,
+               },
+               {
+                       uri:      "download.example.com/c=" + arvadostest.FooAndBarFilesInDirUUID + "/dir1",
+                       header:   authHeader,
+                       redirect: "/c=" + arvadostest.FooAndBarFilesInDirUUID + "/dir1/",
+                       expect:   []string{"foo", "bar"},
+                       cutDirs:  2,
+               },
+               {
+                       uri:     "download.example.com/c=" + arvadostest.FooAndBarFilesInDirUUID + "/_/dir1/",
+                       header:  authHeader,
+                       expect:  []string{"foo", "bar"},
+                       cutDirs: 3,
+               },
+               {
+                       uri:      arvadostest.FooAndBarFilesInDirUUID + ".example.com/dir1?api_token=" + arvadostest.ActiveToken,
+                       header:   authHeader,
+                       redirect: "/dir1/",
+                       expect:   []string{"foo", "bar"},
+                       cutDirs:  1,
                },
                {
                        uri:    "collections.example.com/c=" + arvadostest.FooAndBarFilesInDirUUID + "/theperthcountyconspiracydoesnotexist/",
@@ -536,7 +624,7 @@ func (s *IntegrationSuite) TestDirectoryListing(c *check.C) {
                        expect: nil,
                },
        } {
-               c.Logf("%q => %q", trial.uri, trial.expect)
+               c.Logf("HTML: %q => %q", trial.uri, trial.expect)
                resp := httptest.NewRecorder()
                u := mustParseURL("//" + trial.uri)
                req := &http.Request{
@@ -555,7 +643,7 @@ func (s *IntegrationSuite) TestDirectoryListing(c *check.C) {
                                Host:       u.Host,
                                URL:        u,
                                RequestURI: u.RequestURI(),
-                               Header:     http.Header{},
+                               Header:     trial.header,
                        }
                        cookies = append(cookies, (&http.Response{Header: resp.Header()}).Cookies()...)
                        for _, c := range cookies {
@@ -564,6 +652,9 @@ func (s *IntegrationSuite) TestDirectoryListing(c *check.C) {
                        resp = httptest.NewRecorder()
                        s.testServer.Handler.ServeHTTP(resp, req)
                }
+               if trial.redirect != "" {
+                       c.Check(req.URL.Path, check.Equals, trial.redirect)
+               }
                if trial.expect == nil {
                        c.Check(resp.Code, check.Equals, http.StatusNotFound)
                } else {
@@ -571,6 +662,64 @@ func (s *IntegrationSuite) TestDirectoryListing(c *check.C) {
                        for _, e := range trial.expect {
                                c.Check(resp.Body.String(), check.Matches, `(?ms).*href="`+e+`".*`)
                        }
+                       c.Check(resp.Body.String(), check.Matches, `(?ms).*--cut-dirs=`+fmt.Sprintf("%d", trial.cutDirs)+` .*`)
+               }
+
+               c.Logf("WebDAV: %q => %q", trial.uri, trial.expect)
+               req = &http.Request{
+                       Method:     "OPTIONS",
+                       Host:       u.Host,
+                       URL:        u,
+                       RequestURI: u.RequestURI(),
+                       Header:     trial.header,
+                       Body:       ioutil.NopCloser(&bytes.Buffer{}),
+               }
+               resp = httptest.NewRecorder()
+               s.testServer.Handler.ServeHTTP(resp, req)
+               if trial.expect == nil {
+                       c.Check(resp.Code, check.Equals, http.StatusNotFound)
+               } else {
+                       c.Check(resp.Code, check.Equals, http.StatusOK)
+               }
+
+               req = &http.Request{
+                       Method:     "PROPFIND",
+                       Host:       u.Host,
+                       URL:        u,
+                       RequestURI: u.RequestURI(),
+                       Header:     trial.header,
+                       Body:       ioutil.NopCloser(&bytes.Buffer{}),
+               }
+               resp = httptest.NewRecorder()
+               s.testServer.Handler.ServeHTTP(resp, req)
+               if trial.expect == nil {
+                       c.Check(resp.Code, check.Equals, http.StatusNotFound)
+               } else {
+                       c.Check(resp.Code, check.Equals, http.StatusMultiStatus)
+                       for _, e := range trial.expect {
+                               c.Check(resp.Body.String(), check.Matches, `(?ms).*<D:href>`+filepath.Join(u.Path, e)+`</D:href>.*`)
+                       }
                }
        }
 }
+
+func (s *IntegrationSuite) TestHealthCheckPing(c *check.C) {
+       s.testServer.Config.ManagementToken = arvadostest.ManagementToken
+       authHeader := http.Header{
+               "Authorization": {"Bearer " + arvadostest.ManagementToken},
+       }
+
+       resp := httptest.NewRecorder()
+       u := mustParseURL("http://download.example.com/_health/ping")
+       req := &http.Request{
+               Method:     "GET",
+               Host:       u.Host,
+               URL:        u,
+               RequestURI: u.RequestURI(),
+               Header:     authHeader,
+       }
+       s.testServer.Handler.ServeHTTP(resp, req)
+
+       c.Check(resp.Code, check.Equals, http.StatusOK)
+       c.Check(resp.Body.String(), check.Matches, `{"health":"OK"}\n`)
+}