Procházet zdrojové kódy

Fix handling ranged requests by FS storage

DarthSim před 3 měsíci
rodič
revize
9f469dfcba
2 změnil soubory, kde provedl 25 přidání a 8 odebrání
  1. 6 8
      storage/fs/fs.go
  2. 19 0
      storage/fs/fs_test.go

+ 6 - 8
storage/fs/fs.go

@@ -85,12 +85,8 @@ func (s *Storage) GetObject(
 		header.Set(httpheaders.ContentType, mimetype)
 	}
 
-	// calculate Etag and Last-Modified date
-	etag := buildEtag(name, fi)
-	lastModified := fi.ModTime().Format(http.TimeFormat)
-
 	// try requested range
-	start, end, err := httprange.Parse(header.Get(httpheaders.Range))
+	start, end, err := httprange.Parse(reqHeader.Get(httpheaders.Range))
 	switch {
 	case err != nil:
 		f.Close()
@@ -106,17 +102,19 @@ func (s *Storage) GetObject(
 
 		size = end - start + 1
 		body = &fileLimiter{f: f, left: int(size)}
+
+		header.Set(httpheaders.ContentLength, strconv.Itoa(int(size)))
 		header.Set(httpheaders.ContentRange, fmt.Sprintf("bytes %d-%d/%d", start, end, fi.Size()))
 
 		return response.NewPartialContent(header, body), nil
 
 	// Full object requested
 	default:
-		header.Set(httpheaders.Etag, etag)
-		header.Set(httpheaders.LastModified, lastModified)
+		// Set Etag and Last-Modified date
+		header.Set(httpheaders.Etag, buildEtag(name, fi))
+		header.Set(httpheaders.LastModified, fi.ModTime().Format(http.TimeFormat))
 	}
 
-	// Either size of a partial or the total
 	header.Set(httpheaders.ContentLength, strconv.Itoa(int(size)))
 
 	// In case file was not modified, let's not return reader

+ 19 - 0
storage/fs/fs_test.go

@@ -1,6 +1,7 @@
 package fs
 
 import (
+	"fmt"
 	"net/http"
 	"os"
 	"path/filepath"
@@ -20,6 +21,7 @@ type FsTestSuite struct {
 	storage storage.Reader
 	etag    string
 	modTime time.Time
+	size    int64
 }
 
 func (s *FsTestSuite) SetupSuite() {
@@ -31,6 +33,7 @@ func (s *FsTestSuite) SetupSuite() {
 
 	s.etag = buildEtag("/test1.png", fi)
 	s.modTime = fi.ModTime()
+	s.size = fi.Size()
 
 	s.storage, _ = New(&Config{Root: fsRoot}, "?")
 }
@@ -114,6 +117,22 @@ func (s *FsTestSuite) TestRoundTripWithUpdatedLastModifiedReturns200() {
 	response.Body.Close()
 }
 
+func (s *FsTestSuite) TestRoundTripWithRangeReturns206() {
+	ctx := s.T().Context()
+	reqHeader := make(http.Header)
+	reqHeader.Set(httpheaders.Range, "bytes=10-19")
+
+	response, err := s.storage.GetObject(ctx, reqHeader, "", "test1.png", "")
+
+	s.Require().NoError(err)
+	s.Require().Equal(http.StatusPartialContent, response.Status)
+	s.Require().Equal(fmt.Sprintf("bytes 10-19/%d", s.size), response.Headers.Get(httpheaders.ContentRange))
+	s.Require().Equal("10", response.Headers.Get(httpheaders.ContentLength))
+	s.Require().NotNil(response.Body)
+
+	response.Body.Close()
+}
+
 func TestFSTransport(t *testing.T) {
 	suite.Run(t, new(FsTestSuite))
 }