Skip to content

Commit 9c84b65

Browse files
authored
feat: stand-alone port s3 server (#6242)
* feat: single port s3 server * fix: unable to PUT files if not in root dir
1 parent 022e0ca commit 9c84b65

File tree

9 files changed

+70
-21
lines changed

9 files changed

+70
-21
lines changed

cmd/server.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,27 @@ the address is defined in config file`,
9191
}
9292
}()
9393
}
94+
s3r := gin.New()
95+
s3r.Use(gin.LoggerWithWriter(log.StandardLogger().Out), gin.RecoveryWithWriter(log.StandardLogger().Out))
96+
server.InitS3(s3r)
97+
if conf.Conf.S3.Port != -1 {
98+
s3Base := fmt.Sprintf("%s:%d", conf.Conf.Scheme.Address, conf.Conf.S3.Port)
99+
utils.Log.Infof("start S3 server @ %s", s3Base)
100+
go func() {
101+
var err error
102+
if conf.Conf.S3.SSL {
103+
httpsSrv = &http.Server{Addr: s3Base, Handler: s3r}
104+
err = httpsSrv.ListenAndServeTLS(conf.Conf.Scheme.CertFile, conf.Conf.Scheme.KeyFile)
105+
}
106+
if !conf.Conf.S3.SSL {
107+
httpSrv = &http.Server{Addr: s3Base, Handler: s3r}
108+
err = httpSrv.ListenAndServe()
109+
}
110+
if err != nil && !errors.Is(err, http.ErrServerClosed) {
111+
utils.Log.Fatalf("failed to start s3 server: %s", err.Error())
112+
}
113+
}()
114+
}
94115
// Wait for interrupt signal to gracefully shutdown the server with
95116
// a timeout of 1 second.
96117
quit := make(chan os.Signal, 1)

internal/bootstrap/data/setting.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,6 @@ func InitialSettings() []model.SettingItem {
180180
{Key: conf.LdapLoginTips, Value: "login with ldap", Type: conf.TypeString, Group: model.LDAP, Flag: model.PUBLIC},
181181

182182
//s3 settings
183-
{Key: conf.S3Enabled, Value: "false", Type: conf.TypeBool, Group: model.S3, Flag: model.PRIVATE},
184183
{Key: conf.S3AccessKeyId, Value: "", Type: conf.TypeString, Group: model.S3, Flag: model.PRIVATE},
185184
{Key: conf.S3SecretAccessKey, Value: "", Type: conf.TypeString, Group: model.S3, Flag: model.PRIVATE},
186185
{Key: conf.S3Buckets, Value: "[]", Type: conf.TypeString, Group: model.S3, Flag: model.PRIVATE},

internal/conf/config.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
package conf
22

33
import (
4+
"path/filepath"
5+
46
"github.com/alist-org/alist/v3/cmd/flags"
57
"github.com/alist-org/alist/v3/pkg/utils/random"
6-
"path/filepath"
78
)
89

910
type Database struct {
@@ -63,6 +64,12 @@ type Cors struct {
6364
AllowHeaders []string `json:"allow_headers" env:"ALLOW_HEADERS"`
6465
}
6566

67+
type S3 struct {
68+
Enable bool `json:"enable" env:"ENABLE"`
69+
Port int `json:"port" env:"PORT"`
70+
SSL bool `json:"ssl" env:"SSL"`
71+
}
72+
6673
type Config struct {
6774
Force bool `json:"force" env:"FORCE"`
6875
SiteURL string `json:"site_url" env:"SITE_URL"`
@@ -81,6 +88,7 @@ type Config struct {
8188
TlsInsecureSkipVerify bool `json:"tls_insecure_skip_verify" env:"TLS_INSECURE_SKIP_VERIFY"`
8289
Tasks TasksConfig `json:"tasks" envPrefix:"TASKS_"`
8390
Cors Cors `json:"cors" envPrefix:"CORS_"`
91+
S3 S3 `json:"s3" envPrefix:"S3_"`
8492
}
8593

8694
func DefaultConfig() *Config {
@@ -142,5 +150,10 @@ func DefaultConfig() *Config {
142150
AllowMethods: []string{"*"},
143151
AllowHeaders: []string{"*"},
144152
},
153+
S3: S3{
154+
Enable: false,
155+
Port: 5246,
156+
SSL: false,
157+
},
145158
}
146159
}

internal/conf/const.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,9 @@ const (
8585
LdapLoginTips = "ldap_login_tips"
8686

8787
//s3
88-
S3Enabled = "s3_enabled"
88+
S3Buckets = "s3_buckets"
8989
S3AccessKeyId = "s3_access_key_id"
9090
S3SecretAccessKey = "s3_secret_access_key"
91-
S3Buckets = "s3_buckets"
9291

9392
// qbittorrent
9493
QbittorrentUrl = "qbittorrent_url"

server/router.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,3 +171,8 @@ func Cors(r *gin.Engine) {
171171
config.AllowMethods = conf.Conf.Cors.AllowMethods
172172
r.Use(cors.New(config))
173173
}
174+
175+
func InitS3(e *gin.Engine) {
176+
Cors(e)
177+
S3Server(e.Group("/"))
178+
}

server/s3.go

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,40 @@ import (
66
"strings"
77

88
"github.com/alist-org/alist/v3/internal/conf"
9-
"github.com/alist-org/alist/v3/internal/setting"
109
"github.com/alist-org/alist/v3/server/common"
1110
"github.com/alist-org/alist/v3/server/s3"
1211
"github.com/gin-gonic/gin"
1312
)
1413

1514
func S3(g *gin.RouterGroup) {
16-
if !setting.GetBool(conf.S3Enabled) {
15+
if !conf.Conf.S3.Enable {
1716
g.Any("/*path", func(c *gin.Context) {
1817
common.ErrorStrResp(c, "S3 server is not enabled", 403)
1918
})
2019
return
2120
}
22-
h, _ := s3.NewServer(context.Background(), []string{setting.GetStr(conf.S3AccessKeyId) + "," + setting.GetStr(conf.S3SecretAccessKey)})
21+
if conf.Conf.S3.Port != -1 {
22+
g.Any("/*path", func(c *gin.Context) {
23+
common.ErrorStrResp(c, "S3 server bound to single port", 403)
24+
})
25+
return
26+
}
27+
h, _ := s3.NewServer(context.Background())
2328

2429
g.Any("/*path", func(c *gin.Context) {
2530
adjustedPath := strings.TrimPrefix(c.Request.URL.Path, path.Join(conf.URL.Path, "/s3"))
2631
c.Request.URL.Path = adjustedPath
2732
gin.WrapH(h)(c)
2833
})
2934
}
35+
36+
func S3Server(g *gin.RouterGroup) {
37+
if !conf.Conf.S3.Enable {
38+
g.Any("/*path", func(c *gin.Context) {
39+
common.ErrorStrResp(c, "S3 server is not enabled", 403)
40+
})
41+
return
42+
}
43+
h, _ := s3.NewServer(context.Background())
44+
g.Any("/*path", gin.WrapH(h))
45+
}

server/s3/backend.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ func (b *s3Backend) PutObject(
299299
Mimetype: meta["Content-Type"],
300300
}
301301

302-
err = fs.PutDirectly(ctx, path.Dir(reqPath), stream)
302+
err = fs.PutDirectly(ctx, reqPath, stream)
303303
if err != nil {
304304
return result, err
305305
}

server/s3/server.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@ import (
1111
)
1212

1313
// Make a new S3 Server to serve the remote
14-
func NewServer(ctx context.Context, authpair []string) (h http.Handler, err error) {
14+
func NewServer(ctx context.Context) (h http.Handler, err error) {
1515
var newLogger logger
1616
faker := gofakes3.New(
1717
newBackend(),
1818
// gofakes3.WithHostBucket(!opt.pathBucketMode),
1919
gofakes3.WithLogger(newLogger),
2020
gofakes3.WithRequestID(rand.Uint64()),
2121
gofakes3.WithoutVersioning(),
22-
gofakes3.WithV4Auth(authlistResolver(authpair)),
22+
gofakes3.WithV4Auth(authlistResolver()),
2323
gofakes3.WithIntegrityCheck(true), // Check Content-MD5 if supplied
2424
)
2525

server/s3/utils.go

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ package s3
55
import (
66
"context"
77
"encoding/json"
8-
"fmt"
98
"strings"
109

1110
"github.com/Mikubill/gofakes3"
@@ -15,7 +14,6 @@ import (
1514
"github.com/alist-org/alist/v3/internal/model"
1615
"github.com/alist-org/alist/v3/internal/op"
1716
"github.com/alist-org/alist/v3/internal/setting"
18-
"github.com/alist-org/alist/v3/pkg/utils"
1917
)
2018

2119
type Bucket struct {
@@ -150,15 +148,13 @@ func prefixParser(p *gofakes3.Prefix) (path, remaining string) {
150148
// }
151149
// }
152150

153-
func authlistResolver(list []string) map[string]string {
154-
authList := make(map[string]string)
155-
for _, v := range list {
156-
parts := strings.Split(v, ",")
157-
if len(parts) != 2 {
158-
utils.Log.Infof(fmt.Sprintf("Ignored: invalid auth pair %s", v))
159-
continue
160-
}
161-
authList[parts[0]] = parts[1]
151+
func authlistResolver() map[string]string {
152+
s3accesskeyid := setting.GetStr(conf.S3AccessKeyId)
153+
s3secretaccesskey := setting.GetStr(conf.S3SecretAccessKey)
154+
if s3accesskeyid == "" && s3secretaccesskey == "" {
155+
return nil
162156
}
157+
authList := make(map[string]string)
158+
authList[s3accesskeyid] = s3secretaccesskey
163159
return authList
164160
}

0 commit comments

Comments
 (0)