CGS: implement MimeTyper interface

This commit is contained in:
Nicola Murino
2020-09-28 22:12:46 +02:00
parent cd56039ab7
commit d1f0e9ae9f
5 changed files with 23 additions and 50 deletions

View File

@@ -58,7 +58,7 @@ Setting an empty `bind_address` means that the service will listen on all availa
Now restart the SFTPGo service to apply the changes. Now restart the SFTPGo service to apply the changes.
```shell ```shell
systemctl restart sftpgo sudo systemctl restart sftpgo
``` ```
You are done! Now login to the Web Admin interface using the username and password created above. You are done! Now login to the Web Admin interface using the username and password created above.
@@ -108,7 +108,7 @@ Search for the `httpd` section and change it as follow.
Now restart the SFTPGo service to apply the changes. Now restart the SFTPGo service to apply the changes.
```shell ```shell
systemctl restart sftpgo sudo systemctl restart sftpgo
``` ```
You are done! Now SFTPGo web admin and REST API are exposed over HTTPS and password protected. You are done! Now SFTPGo web admin and REST API are exposed over HTTPS and password protected.

View File

@@ -6,27 +6,19 @@ import (
"time" "time"
) )
// FileContentTyper is an optional interface for vfs.FileInfo
type FileContentTyper interface {
GetContentType() string
}
// FileInfo implements os.FileInfo for a Cloud Storage file. // FileInfo implements os.FileInfo for a Cloud Storage file.
type FileInfo struct { type FileInfo struct {
name string name string
sizeInBytes int64 sizeInBytes int64
modTime time.Time modTime time.Time
mode os.FileMode mode os.FileMode
contentType string
} }
// NewFileInfo creates file info. // NewFileInfo creates file info.
func NewFileInfo(name string, isDirectory bool, sizeInBytes int64, modTime time.Time, fullName bool) FileInfo { func NewFileInfo(name string, isDirectory bool, sizeInBytes int64, modTime time.Time, fullName bool) FileInfo {
mode := os.FileMode(0644) mode := os.FileMode(0644)
contentType := ""
if isDirectory { if isDirectory {
mode = os.FileMode(0755) | os.ModeDir mode = os.FileMode(0755) | os.ModeDir
contentType = "inode/directory"
} }
if !fullName { if !fullName {
// we have always Unix style paths here // we have always Unix style paths here
@@ -38,7 +30,6 @@ func NewFileInfo(name string, isDirectory bool, sizeInBytes int64, modTime time.
sizeInBytes: sizeInBytes, sizeInBytes: sizeInBytes,
modTime: modTime, modTime: modTime,
mode: mode, mode: mode,
contentType: contentType,
} }
} }
@@ -71,12 +62,3 @@ func (fi FileInfo) IsDir() bool {
func (fi FileInfo) Sys() interface{} { func (fi FileInfo) Sys() interface{} {
return fi.getFileInfoSys() return fi.getFileInfoSys()
} }
func (fi *FileInfo) setContentType(contenType string) {
fi.contentType = contenType
}
// GetContentType implements FileContentTyper interface
func (fi FileInfo) GetContentType() string {
return fi.contentType
}

View File

@@ -27,7 +27,7 @@ import (
) )
var ( var (
gcsDefaultFieldsSelection = []string{"Name", "Size", "Deleted", "Updated", "ContentType"} gcsDefaultFieldsSelection = []string{"Name", "Size", "Deleted", "Updated"}
) )
// GCSFs is a Fs implementation for Google Cloud Storage. // GCSFs is a Fs implementation for Google Cloud Storage.
@@ -121,9 +121,6 @@ func (fs GCSFs) Stat(name string) (os.FileInfo, error) {
if fs.isEqual(attrs.Name, name) { if fs.isEqual(attrs.Name, name) {
isDir := strings.HasSuffix(attrs.Name, "/") isDir := strings.HasSuffix(attrs.Name, "/")
result = NewFileInfo(name, isDir, attrs.Size, attrs.Updated, false) result = NewFileInfo(name, isDir, attrs.Size, attrs.Updated, false)
if !isDir {
result.setContentType(attrs.ContentType)
}
break break
} }
} }
@@ -184,7 +181,7 @@ func (fs GCSFs) Create(name string, flag int) (*os.File, *PipeWriter, func(), er
objectWriter := obj.NewWriter(ctx) objectWriter := obj.NewWriter(ctx)
contentType := mime.TypeByExtension(path.Ext(name)) contentType := mime.TypeByExtension(path.Ext(name))
if contentType != "" { if contentType != "" {
objectWriter.ObjectAttrs.ContentType = contentType objectWriter.ObjectAttrs.ContentType = contentType
} }
if len(fs.config.StorageClass) > 0 { if len(fs.config.StorageClass) > 0 {
objectWriter.ObjectAttrs.StorageClass = fs.config.StorageClass objectWriter.ObjectAttrs.StorageClass = fs.config.StorageClass
@@ -359,9 +356,6 @@ func (fs GCSFs) ReadDir(dirname string) ([]os.FileInfo, error) {
continue continue
} }
fi := NewFileInfo(name, isDir, attrs.Size, attrs.Updated, false) fi := NewFileInfo(name, isDir, attrs.Size, attrs.Updated, false)
if !isDir {
fi.setContentType(attrs.ContentType)
}
result = append(result, fi) result = append(result, fi)
} }
} }
@@ -596,3 +590,17 @@ func (fs *GCSFs) getPrefixForStat(name string) string {
} }
return prefix return prefix
} }
// GetMimeType implements MimeTyper interface
func (fs GCSFs) GetMimeType(name string) (string, error) {
ctx, cancelFn := context.WithDeadline(context.Background(), time.Now().Add(fs.ctxTimeout))
defer cancelFn()
bkt := fs.svc.Bucket(fs.config.Bucket)
obj := bkt.Object(name)
attrs, err := obj.Attrs(ctx)
if err != nil {
return "", err
}
logger.DebugToConsole("content type: %v", attrs.ContentType)
return attrs.ContentType, nil
}

View File

@@ -57,15 +57,8 @@ type webDavFileInfo struct {
// ContentType implements webdav.ContentTyper interface // ContentType implements webdav.ContentTyper interface
func (fi webDavFileInfo) ContentType(ctx context.Context) (string, error) { func (fi webDavFileInfo) ContentType(ctx context.Context) (string, error) {
var contentType string contentType := mime.TypeByExtension(path.Ext(fi.file.GetVirtualPath()))
if c, ok := fi.FileInfo.(vfs.FileContentTyper); ok { if contentType != "" {
contentType = c.GetContentType()
}
if len(contentType) > 0 {
return contentType, nil
}
contentType = mime.TypeByExtension(path.Ext(fi.file.GetVirtualPath()))
if len(contentType) > 0 {
return contentType, nil return contentType, nil
} }
if c, ok := fi.file.Fs.(vfs.MimeTyper); ok { if c, ok := fi.file.Fs.(vfs.MimeTyper); ok {

View File

@@ -430,22 +430,12 @@ func TestContentType(t *testing.T) {
ctx := context.Background() ctx := context.Background()
baseTransfer := common.NewBaseTransfer(nil, connection.BaseConnection, nil, testFilePath, testFile, baseTransfer := common.NewBaseTransfer(nil, connection.BaseConnection, nil, testFilePath, testFile,
common.TransferDownload, 0, 0, 0, false, fs) common.TransferDownload, 0, 0, 0, false, fs)
info := vfs.NewFileInfo(testFilePath, true, 0, time.Now(), false)
davFile := newWebDavFile(baseTransfer, nil, nil, info)
fi, err := davFile.Stat()
if assert.NoError(t, err) {
ctype, err := fi.(webDavFileInfo).ContentType(ctx)
assert.NoError(t, err)
assert.Equal(t, "inode/directory", ctype)
}
err = davFile.Close()
assert.NoError(t, err)
fs = newMockOsFs(nil, false, fs.ConnectionID(), user.GetHomeDir()) fs = newMockOsFs(nil, false, fs.ConnectionID(), user.GetHomeDir())
err = ioutil.WriteFile(testFilePath, []byte(""), os.ModePerm) err := ioutil.WriteFile(testFilePath, []byte(""), os.ModePerm)
assert.NoError(t, err) assert.NoError(t, err)
fi, err = os.Stat(testFilePath) fi, err := os.Stat(testFilePath)
assert.NoError(t, err) assert.NoError(t, err)
davFile = newWebDavFile(baseTransfer, nil, nil, fi) davFile := newWebDavFile(baseTransfer, nil, nil, fi)
davFile.Fs = fs davFile.Fs = fs
fi, err = davFile.Stat() fi, err = davFile.Stat()
if assert.NoError(t, err) { if assert.NoError(t, err) {