mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-07-31 04:23:34 +00:00
* s3: answer application/x-directory for a directory without a stored mime A real directory reached via a trailing-slash GET/HEAD answered the octet-stream default when it had no stored mime, so Hadoop-style S3 filesystems (flink-s3-fs-presto and friends) classified the path as a 0-byte file instead of a directory and then failed reading it as one. Answer application/x-directory, the marker type those clients probe for. Stored mimes still echo verbatim, and a file promoted to a directory keeps octet-stream for its data. * s3: 404 GET and HEAD on a bare directory path consistently A directory with no object data of its own answered differently per path: plain GET gave an empty 200, ranged GET and non-versioned HEAD gave 404, and on versioned buckets the null-version fallback adopted the filer directory as a 0-byte object and answered 200. Clients that probe HEAD-then-GET took the 200s at face value, treated the path as an empty file, and never fell back to LIST-based directory discovery. Answer 404 for a bare directory path everywhere, which is what AWS returns for a prefix. A file promoted to a directory keeps its data and stays retrievable.
50 lines
1.4 KiB
Go
50 lines
1.4 KiB
Go
package s3api
|
|
|
|
import (
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
|
|
)
|
|
|
|
func TestServeDirectoryContentContentType(t *testing.T) {
|
|
s3a := &S3ApiServer{}
|
|
|
|
tests := []struct {
|
|
name string
|
|
entry *filer_pb.Entry
|
|
wantType string
|
|
}{
|
|
{
|
|
name: "bare directory answers the directory marker type",
|
|
entry: &filer_pb.Entry{Name: "savepoint", IsDirectory: true, Attributes: &filer_pb.FuseAttributes{}},
|
|
wantType: "application/x-directory",
|
|
},
|
|
{
|
|
name: "promoted file with data keeps octet-stream",
|
|
entry: &filer_pb.Entry{Name: "promoted", IsDirectory: true, Content: []byte("data"), Attributes: &filer_pb.FuseAttributes{FileSize: 4}},
|
|
wantType: "application/octet-stream",
|
|
},
|
|
{
|
|
name: "stored mime is echoed verbatim",
|
|
entry: &filer_pb.Entry{Name: "marker", IsDirectory: true, Attributes: &filer_pb.FuseAttributes{Mime: "httpd/unix-directory"}},
|
|
wantType: "httpd/unix-directory",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
req := httptest.NewRequest(http.MethodHead, "/bucket/dir/", nil)
|
|
rec := httptest.NewRecorder()
|
|
s3a.serveDirectoryContent(rec, req, tt.entry)
|
|
if rec.Code != http.StatusOK {
|
|
t.Fatalf("status = %d, want 200", rec.Code)
|
|
}
|
|
if got := rec.Header().Get("Content-Type"); got != tt.wantType {
|
|
t.Fatalf("Content-Type = %q, want %q", got, tt.wantType)
|
|
}
|
|
})
|
|
}
|
|
}
|