Files
OpenList/server/handles/fsup.go

229 lines
5.7 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package handles
import (
"io"
"net/url"
stdpath "path"
"strconv"
"time"
"github.com/OpenListTeam/OpenList/v4/internal/conf"
"github.com/OpenListTeam/OpenList/v4/internal/errs"
"github.com/OpenListTeam/OpenList/v4/internal/fs"
"github.com/OpenListTeam/OpenList/v4/internal/model"
"github.com/OpenListTeam/OpenList/v4/internal/setting"
"github.com/OpenListTeam/OpenList/v4/internal/stream"
"github.com/OpenListTeam/OpenList/v4/internal/task"
"github.com/OpenListTeam/OpenList/v4/pkg/utils"
"github.com/OpenListTeam/OpenList/v4/server/common"
"github.com/gin-gonic/gin"
)
func getLastModified(c *gin.Context) time.Time {
now := time.Now()
lastModifiedStr := c.GetHeader("Last-Modified")
lastModifiedMillisecond, err := strconv.ParseInt(lastModifiedStr, 10, 64)
if err != nil {
return now
}
lastModified := time.UnixMilli(lastModifiedMillisecond)
return lastModified
}
// shouldIgnoreSystemFile checks if the filename should be ignored based on settings
func shouldIgnoreSystemFile(filename string) bool {
if setting.GetBool(conf.IgnoreSystemFiles) {
return utils.IsSystemFile(filename)
}
return false
}
func FsStream(c *gin.Context) {
defer func() {
if n, _ := io.ReadFull(c.Request.Body, []byte{0}); n == 1 {
_, _ = utils.CopyWithBuffer(io.Discard, c.Request.Body)
}
_ = c.Request.Body.Close()
}()
path := c.GetHeader("File-Path")
path, err := url.PathUnescape(path)
if err != nil {
common.ErrorResp(c, err, 400)
return
}
asTask := c.GetHeader("As-Task") == "true"
overwrite := c.GetHeader("Overwrite") != "false"
user := c.Request.Context().Value(conf.UserKey).(*model.User)
path, err = user.JoinPath(path)
if err != nil {
common.ErrorResp(c, err, 403)
return
}
if !overwrite {
if res, _ := fs.Get(c.Request.Context(), path, &fs.GetArgs{NoLog: true}); res != nil {
common.ErrorStrResp(c, "file exists", 403)
return
}
}
dir, name := stdpath.Split(path)
// Check if system file should be ignored
if shouldIgnoreSystemFile(name) {
common.ErrorStrResp(c, errs.IgnoredSystemFile.Error(), 403)
return
}
// 如果请求头 Content-Length 和 X-File-Size 都没有,则 size=-1表示未知大小的流式上传
size := c.Request.ContentLength
if size < 0 {
sizeStr := c.GetHeader("X-File-Size")
if sizeStr != "" {
size, err = strconv.ParseInt(sizeStr, 10, 64)
if err != nil {
common.ErrorResp(c, err, 400)
return
}
}
}
h := make(map[*utils.HashType]string)
if md5 := c.GetHeader("X-File-Md5"); md5 != "" {
h[utils.MD5] = md5
}
if sha1 := c.GetHeader("X-File-Sha1"); sha1 != "" {
h[utils.SHA1] = sha1
}
if sha256 := c.GetHeader("X-File-Sha256"); sha256 != "" {
h[utils.SHA256] = sha256
}
mimetype := c.GetHeader("Content-Type")
if len(mimetype) == 0 {
mimetype = utils.GetMimeType(name)
}
s := &stream.FileStream{
Obj: &model.Object{
Name: name,
Size: size,
Modified: getLastModified(c),
HashInfo: utils.NewHashInfoByMap(h),
},
Reader: c.Request.Body,
Mimetype: mimetype,
WebPutAsTask: asTask,
}
var t task.TaskExtensionInfo
if asTask {
t, err = fs.PutAsTask(c.Request.Context(), dir, s)
} else {
err = fs.PutDirectly(c.Request.Context(), dir, s, true)
}
if err != nil {
common.ErrorResp(c, err, 500)
return
}
if t == nil {
common.SuccessResp(c)
return
}
common.SuccessResp(c, gin.H{
"task": getTaskInfo(t),
})
}
func FsForm(c *gin.Context) {
defer func() {
if n, _ := io.ReadFull(c.Request.Body, []byte{0}); n == 1 {
_, _ = utils.CopyWithBuffer(io.Discard, c.Request.Body)
}
_ = c.Request.Body.Close()
}()
path := c.GetHeader("File-Path")
path, err := url.PathUnescape(path)
if err != nil {
common.ErrorResp(c, err, 400)
return
}
asTask := c.GetHeader("As-Task") == "true"
overwrite := c.GetHeader("Overwrite") != "false"
user := c.Request.Context().Value(conf.UserKey).(*model.User)
path, err = user.JoinPath(path)
if err != nil {
common.ErrorResp(c, err, 403)
return
}
if !overwrite {
if res, _ := fs.Get(c.Request.Context(), path, &fs.GetArgs{NoLog: true}); res != nil {
common.ErrorStrResp(c, "file exists", 403)
return
}
}
storage, err := fs.GetStorage(path, &fs.GetStoragesArgs{})
if err != nil {
common.ErrorResp(c, err, 400)
return
}
if storage.Config().NoUpload {
common.ErrorStrResp(c, "Current storage doesn't support upload", 405)
return
}
file, err := c.FormFile("file")
if err != nil {
common.ErrorResp(c, err, 500)
return
}
f, err := file.Open()
if err != nil {
common.ErrorResp(c, err, 500)
return
}
defer f.Close()
dir, name := stdpath.Split(path)
// Check if system file should be ignored
if shouldIgnoreSystemFile(name) {
common.ErrorStrResp(c, errs.IgnoredSystemFile.Error(), 403)
return
}
h := make(map[*utils.HashType]string)
if md5 := c.GetHeader("X-File-Md5"); md5 != "" {
h[utils.MD5] = md5
}
if sha1 := c.GetHeader("X-File-Sha1"); sha1 != "" {
h[utils.SHA1] = sha1
}
if sha256 := c.GetHeader("X-File-Sha256"); sha256 != "" {
h[utils.SHA256] = sha256
}
mimetype := file.Header.Get("Content-Type")
if len(mimetype) == 0 {
mimetype = utils.GetMimeType(name)
}
s := &stream.FileStream{
Obj: &model.Object{
Name: name,
Size: file.Size,
Modified: getLastModified(c),
HashInfo: utils.NewHashInfoByMap(h),
},
Reader: f,
Mimetype: mimetype,
WebPutAsTask: asTask,
}
var t task.TaskExtensionInfo
if asTask {
s.Reader = struct {
io.Reader
}{f}
t, err = fs.PutAsTask(c.Request.Context(), dir, s)
} else {
err = fs.PutDirectly(c.Request.Context(), dir, s, true)
}
if err != nil {
common.ErrorResp(c, err, 500)
return
}
if t == nil {
common.SuccessResp(c)
return
}
common.SuccessResp(c, gin.H{
"task": getTaskInfo(t),
})
}