Skip to content

Commit 7571d9f

Browse files
Roberta001jyxjjj
authored andcommitted
feat: add proxy max concurrent requests per IP limit
1 parent ece1518 commit 7571d9f

4 files changed

Lines changed: 72 additions & 4 deletions

File tree

internal/bootstrap/data/setting.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ func InitialSettings() []model.SettingItem {
238238
{Key: conf.TaskCopyThreadsNum, Value: strconv.Itoa(conf.Conf.Tasks.Copy.Workers), Type: conf.TypeNumber, Group: model.TRAFFIC, Flag: model.PRIVATE},
239239
{Key: conf.TaskDecompressDownloadThreadsNum, Value: strconv.Itoa(conf.Conf.Tasks.Decompress.Workers), Type: conf.TypeNumber, Group: model.TRAFFIC, Flag: model.PRIVATE},
240240
{Key: conf.TaskDecompressUploadThreadsNum, Value: strconv.Itoa(conf.Conf.Tasks.DecompressUpload.Workers), Type: conf.TypeNumber, Group: model.TRAFFIC, Flag: model.PRIVATE},
241+
{Key: conf.ProxyMaxConcurrentRequestsPerIP, Value: "-1", Type: conf.TypeNumber, Group: model.TRAFFIC, Flag: model.PRIVATE},
241242
{Key: conf.StreamMaxClientDownloadSpeed, Value: "-1", Type: conf.TypeNumber, Group: model.TRAFFIC, Flag: model.PRIVATE},
242243
{Key: conf.StreamMaxClientUploadSpeed, Value: "-1", Type: conf.TypeNumber, Group: model.TRAFFIC, Flag: model.PRIVATE},
243244
{Key: conf.StreamMaxServerDownloadSpeed, Value: "-1", Type: conf.TypeNumber, Group: model.TRAFFIC, Flag: model.PRIVATE},

internal/conf/const.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ const (
157157
TaskMoveThreadsNum = "move_task_threads_num"
158158
TaskDecompressDownloadThreadsNum = "decompress_download_task_threads_num"
159159
TaskDecompressUploadThreadsNum = "decompress_upload_task_threads_num"
160+
ProxyMaxConcurrentRequestsPerIP = "proxy_max_concurrent_requests_per_ip"
160161
StreamMaxClientDownloadSpeed = "max_client_download_speed"
161162
StreamMaxClientUploadSpeed = "max_client_upload_speed"
162163
StreamMaxServerDownloadSpeed = "max_server_download_speed"

server/middlewares/ip_limit.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package middlewares
2+
3+
import (
4+
"net/http"
5+
"sync"
6+
7+
"github.com/OpenListTeam/OpenList/v4/internal/conf"
8+
"github.com/OpenListTeam/OpenList/v4/internal/setting"
9+
"github.com/gin-gonic/gin"
10+
)
11+
12+
var (
13+
proxyIPCounts = make(map[string]int)
14+
proxyIPCountsMu sync.Mutex
15+
)
16+
17+
// ProxyIPConcurrencyLimit limits the maximum concurrent server proxy requests per IP Address
18+
func ProxyIPConcurrencyLimit() gin.HandlerFunc {
19+
return func(c *gin.Context) {
20+
limit := setting.GetInt(conf.ProxyMaxConcurrentRequestsPerIP, -1)
21+
22+
if limit < 0 {
23+
// -1 or less means unlimited
24+
c.Next()
25+
return
26+
}
27+
28+
if limit == 0 {
29+
// 0 means completely disabled
30+
c.AbortWithStatusJSON(http.StatusForbidden, gin.H{
31+
"code": http.StatusForbidden,
32+
"message": "Proxy is disabled",
33+
"data": nil,
34+
})
35+
return
36+
}
37+
38+
ip := c.ClientIP()
39+
40+
proxyIPCountsMu.Lock()
41+
count := proxyIPCounts[ip]
42+
if count >= limit {
43+
proxyIPCountsMu.Unlock()
44+
c.AbortWithStatusJSON(http.StatusTooManyRequests, gin.H{
45+
"code": http.StatusTooManyRequests,
46+
"message": "Too Many Proxy Requests from this IP",
47+
"data": nil,
48+
})
49+
return
50+
}
51+
proxyIPCounts[ip] = count + 1
52+
proxyIPCountsMu.Unlock()
53+
54+
defer func() {
55+
proxyIPCountsMu.Lock()
56+
proxyIPCounts[ip]--
57+
if proxyIPCounts[ip] <= 0 {
58+
delete(proxyIPCounts, ip)
59+
}
60+
proxyIPCountsMu.Unlock()
61+
}()
62+
63+
c.Next()
64+
}
65+
}

server/router.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,17 +43,18 @@ func Init(e *gin.Engine) {
4343
S3(g.Group("/s3"))
4444

4545
downloadLimiter := middlewares.DownloadRateLimiter(stream.ClientDownloadLimit)
46+
proxyConcurrencyLimiter := middlewares.ProxyIPConcurrencyLimit()
4647
signCheck := middlewares.Down(sign.Verify)
4748
g.GET("/d/*path", middlewares.PathParse, signCheck, downloadLimiter, handles.Down)
48-
g.GET("/p/*path", middlewares.PathParse, signCheck, downloadLimiter, handles.Proxy)
49+
g.GET("/p/*path", middlewares.PathParse, signCheck, downloadLimiter, proxyConcurrencyLimiter, handles.Proxy)
4950
g.HEAD("/d/*path", middlewares.PathParse, signCheck, handles.Down)
50-
g.HEAD("/p/*path", middlewares.PathParse, signCheck, handles.Proxy)
51+
g.HEAD("/p/*path", middlewares.PathParse, signCheck, proxyConcurrencyLimiter, handles.Proxy)
5152
archiveSignCheck := middlewares.Down(sign.VerifyArchive)
5253
g.GET("/ad/*path", middlewares.PathParse, archiveSignCheck, downloadLimiter, handles.ArchiveDown)
53-
g.GET("/ap/*path", middlewares.PathParse, archiveSignCheck, downloadLimiter, handles.ArchiveProxy)
54+
g.GET("/ap/*path", middlewares.PathParse, archiveSignCheck, downloadLimiter, proxyConcurrencyLimiter, handles.ArchiveProxy)
5455
g.GET("/ae/*path", middlewares.PathParse, archiveSignCheck, downloadLimiter, handles.ArchiveInternalExtract)
5556
g.HEAD("/ad/*path", middlewares.PathParse, archiveSignCheck, handles.ArchiveDown)
56-
g.HEAD("/ap/*path", middlewares.PathParse, archiveSignCheck, handles.ArchiveProxy)
57+
g.HEAD("/ap/*path", middlewares.PathParse, archiveSignCheck, proxyConcurrencyLimiter, handles.ArchiveProxy)
5758
g.HEAD("/ae/*path", middlewares.PathParse, archiveSignCheck, handles.ArchiveInternalExtract)
5859

5960
g.GET("/sd/:sid", middlewares.EmptyPathParse, middlewares.SharingIdParse, downloadLimiter, handles.SharingDown)

0 commit comments

Comments
 (0)