mirror of
https://github.com/gin-gonic/gin.git
synced 2026-06-23 09:38:22 +08:00
Merge dfff59f1fa93b76a4009741b7500ad1341f7c466 into d75fcd4c9ab260e5225de590f1f0f8c0e0e12d11
This commit is contained in:
commit
3933a905b6
25
context.go
25
context.go
@ -715,6 +715,24 @@ func (c *Context) MultipartForm() (*multipart.Form, error) {
|
||||
return c.Request.MultipartForm, err
|
||||
}
|
||||
|
||||
func dirExists(path string) bool {
|
||||
info, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return info.IsDir()
|
||||
}
|
||||
|
||||
func ensureDirWithMode(dir string, mode fs.FileMode) error {
|
||||
if dirExists(dir) {
|
||||
return nil
|
||||
}
|
||||
if err := os.MkdirAll(dir, mode); err != nil {
|
||||
return err
|
||||
}
|
||||
return os.Chmod(dir, mode)
|
||||
}
|
||||
|
||||
// SaveUploadedFile uploads the form file to specific dst.
|
||||
func (c *Context) SaveUploadedFile(file *multipart.FileHeader, dst string, perm ...fs.FileMode) error {
|
||||
src, err := file.Open()
|
||||
@ -728,10 +746,9 @@ func (c *Context) SaveUploadedFile(file *multipart.FileHeader, dst string, perm
|
||||
mode = perm[0]
|
||||
}
|
||||
dir := filepath.Dir(dst)
|
||||
if err = os.MkdirAll(dir, mode); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = os.Chmod(dir, mode); err != nil {
|
||||
// Only chmod newly created directories. Attempting to chmod
|
||||
// pre-existing directories (e.g. /tmp) may fail with EPERM.
|
||||
if err = ensureDirWithMode(dir, mode); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@ -21,6 +21,7 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
@ -248,13 +249,60 @@ func TestSaveUploadedFileWithPermission(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "permission_test", f.Filename)
|
||||
var mode fs.FileMode = 0o755
|
||||
require.NoError(t, c.SaveUploadedFile(f, "permission_test", mode))
|
||||
t.Cleanup(func() {
|
||||
assert.NoError(t, os.Remove("permission_test"))
|
||||
})
|
||||
info, err := os.Stat(filepath.Dir("permission_test"))
|
||||
tmpDir := t.TempDir()
|
||||
newSubDir := filepath.Join(tmpDir, "newdir")
|
||||
dst := filepath.Join(newSubDir, "permission_test")
|
||||
require.NoError(t, c.SaveUploadedFile(f, dst, mode))
|
||||
if runtime.GOOS != "windows" {
|
||||
info, err := os.Stat(newSubDir)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, mode, info.Mode().Perm())
|
||||
}
|
||||
}
|
||||
|
||||
func TestDirExists(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
assert.True(t, dirExists(tmpDir))
|
||||
assert.False(t, dirExists(filepath.Join(tmpDir, "missing")))
|
||||
|
||||
filePath := filepath.Join(tmpDir, "file")
|
||||
require.NoError(t, os.WriteFile(filePath, []byte("test"), 0o600))
|
||||
assert.False(t, dirExists(filePath))
|
||||
}
|
||||
|
||||
func TestSaveUploadedFileKeepsExistingDirPermission(t *testing.T) {
|
||||
buf := new(bytes.Buffer)
|
||||
mw := multipart.NewWriter(buf)
|
||||
w, err := mw.CreateFormFile("file", "permission_test")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, info.Mode().Perm(), mode)
|
||||
_, err = w.Write([]byte("permission_test"))
|
||||
require.NoError(t, err)
|
||||
mw.Close()
|
||||
c, _ := CreateTestContext(httptest.NewRecorder())
|
||||
c.Request, _ = http.NewRequest(http.MethodPost, "/", buf)
|
||||
c.Request.Header.Set("Content-Type", mw.FormDataContentType())
|
||||
f, err := c.FormFile("file")
|
||||
require.NoError(t, err)
|
||||
|
||||
tmpDir := t.TempDir()
|
||||
existingDir := filepath.Join(tmpDir, "existing")
|
||||
require.NoError(t, os.Mkdir(existingDir, 0o700))
|
||||
if runtime.GOOS != "windows" {
|
||||
require.NoError(t, os.Chmod(existingDir, 0o700))
|
||||
}
|
||||
|
||||
var mode fs.FileMode = 0o755
|
||||
dst := filepath.Join(existingDir, "permission_test")
|
||||
require.NoError(t, c.SaveUploadedFile(f, dst, mode))
|
||||
|
||||
saved, err := os.ReadFile(dst)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "permission_test", string(saved))
|
||||
if runtime.GOOS != "windows" {
|
||||
info, err := os.Stat(existingDir)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, fs.FileMode(0o700), info.Mode().Perm())
|
||||
}
|
||||
}
|
||||
|
||||
func TestSaveUploadedFileWithPermissionFailed(t *testing.T) {
|
||||
|
||||
2
go.mod
2
go.mod
@ -12,7 +12,7 @@ require (
|
||||
github.com/mattn/go-isatty v0.0.20
|
||||
github.com/modern-go/reflect2 v1.0.2
|
||||
github.com/pelletier/go-toml/v2 v2.2.4
|
||||
github.com/quic-go/quic-go v0.59.0
|
||||
github.com/quic-go/quic-go v0.59.1
|
||||
github.com/stretchr/testify v1.11.1
|
||||
github.com/ugorji/go/codec v1.3.1
|
||||
go.mongodb.org/mongo-driver/v2 v2.5.0
|
||||
|
||||
4
go.sum
4
go.sum
@ -52,8 +52,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8=
|
||||
github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII=
|
||||
github.com/quic-go/quic-go v0.59.0 h1:OLJkp1Mlm/aS7dpKgTc6cnpynnD2Xg7C1pwL6vy/SAw=
|
||||
github.com/quic-go/quic-go v0.59.0/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU=
|
||||
github.com/quic-go/quic-go v0.59.1 h1:0Gmua0HW1Tv7ANR7hUYwRyD0MG5OJfgvYSZasGZzBic=
|
||||
github.com/quic-go/quic-go v0.59.1/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU=
|
||||
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user