[ARVADOS] created: 1.3.0-3032-g065aa3623

Git user git at public.arvados.org
Fri Aug 28 17:47:48 UTC 2020


        at  065aa362326aae3ec05958436053c72299bdad7d (commit)


commit 065aa362326aae3ec05958436053c72299bdad7d
Author: Tom Clegg <tom at tomclegg.ca>
Date:   Fri Aug 28 11:28:29 2020 -0400

    16535: Avoid including empty CommonPrefixes tag in list response.
    
    Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tom at tomclegg.ca>

diff --git a/services/keep-web/s3.go b/services/keep-web/s3.go
index 01bc8b704..4e8028ae6 100644
--- a/services/keep-web/s3.go
+++ b/services/keep-web/s3.go
@@ -348,12 +348,25 @@ func (h *handler) s3list(w http.ResponseWriter, r *http.Request, fs arvados.Cust
 		walkpath = ""
 	}
 
-	resp := s3.ListResp{
-		Name:      strings.SplitN(r.URL.Path[1:], "/", 2)[0],
-		Prefix:    params.prefix,
-		Delimiter: params.delimiter,
-		Marker:    params.marker,
-		MaxKeys:   params.maxKeys,
+	type commonPrefix struct {
+		Prefix string
+	}
+	type listResp struct {
+		XMLName string `xml:"http://s3.amazonaws.com/doc/2006-03-01/ ListBucketResult"`
+		s3.ListResp
+		// s3.ListResp marshals an empty tag when
+		// CommonPrefixes is nil, which confuses some clients.
+		// Fix by using this nested struct instead.
+		CommonPrefixes []commonPrefix
+	}
+	resp := listResp{
+		ListResp: s3.ListResp{
+			Name:      strings.SplitN(r.URL.Path[1:], "/", 2)[0],
+			Prefix:    params.prefix,
+			Delimiter: params.delimiter,
+			Marker:    params.marker,
+			MaxKeys:   params.maxKeys,
+		},
 	}
 	commonPrefixes := map[string]bool{}
 	err := walkFS(fs, strings.TrimSuffix(bucketdir+"/"+walkpath, "/"), true, func(path string, fi os.FileInfo) error {
@@ -435,18 +448,15 @@ func (h *handler) s3list(w http.ResponseWriter, r *http.Request, fs arvados.Cust
 		return
 	}
 	if params.delimiter != "" {
+		resp.CommonPrefixes = make([]commonPrefix, 0, len(commonPrefixes))
 		for prefix := range commonPrefixes {
-			resp.CommonPrefixes = append(resp.CommonPrefixes, prefix)
-			sort.Strings(resp.CommonPrefixes)
+			resp.CommonPrefixes = append(resp.CommonPrefixes, commonPrefix{prefix})
 		}
+		sort.Slice(resp.CommonPrefixes, func(i, j int) bool { return resp.CommonPrefixes[i].Prefix < resp.CommonPrefixes[j].Prefix })
 	}
-	wrappedResp := struct {
-		XMLName string `xml:"http://s3.amazonaws.com/doc/2006-03-01/ ListBucketResult"`
-		s3.ListResp
-	}{"", resp}
 	w.Header().Set("Content-Type", "application/xml")
 	io.WriteString(w, xml.Header)
-	if err := xml.NewEncoder(w).Encode(wrappedResp); err != nil {
+	if err := xml.NewEncoder(w).Encode(resp); err != nil {
 		ctxlog.FromContext(r.Context()).WithError(err).Error("error writing xml response")
 	}
 }
diff --git a/services/keep-web/s3_test.go b/services/keep-web/s3_test.go
index b82f1efd7..c6d53238e 100644
--- a/services/keep-web/s3_test.go
+++ b/services/keep-web/s3_test.go
@@ -394,6 +394,23 @@ func (s *IntegrationSuite) TestS3GetBucketVersioning(c *check.C) {
 	}
 }
 
+// If there are no CommonPrefixes entries, the CommonPrefixes XML tag
+// should not appear at all.
+func (s *IntegrationSuite) TestS3ListNoCommonPrefixes(c *check.C) {
+	stage := s.s3setup(c)
+	defer stage.teardown(c)
+
+	req, err := http.NewRequest("GET", stage.collbucket.URL("/"), nil)
+	c.Assert(err, check.IsNil)
+	req.Header.Set("Authorization", "AWS "+arvadostest.ActiveTokenV2+":none")
+	req.URL.RawQuery = "prefix=asdfasdfasdf&delimiter=/"
+	resp, err := http.DefaultClient.Do(req)
+	c.Assert(err, check.IsNil)
+	buf, err := ioutil.ReadAll(resp.Body)
+	c.Assert(err, check.IsNil)
+	c.Check(string(buf), check.Not(check.Matches), `(?ms).*CommonPrefixes.*`)
+}
+
 func (s *IntegrationSuite) TestS3CollectionList(c *check.C) {
 	stage := s.s3setup(c)
 	defer stage.teardown(c)

-----------------------------------------------------------------------


hooks/post-receive
-- 




More information about the arvados-commits mailing list