alist/server/controllers/down.go

143 lines
3.2 KiB
Go

package controllers
import (
"fmt"
"github.com/Xhofe/alist/conf"
"github.com/Xhofe/alist/server/common"
"github.com/Xhofe/alist/utils"
"github.com/gin-gonic/gin"
"github.com/go-resty/resty/v2"
log "github.com/sirupsen/logrus"
"net/http"
"net/http/httputil"
"net/url"
"os"
"path/filepath"
"strings"
)
func Down(c *gin.Context) {
rawPath := c.Param("path")
rawPath = utils.ParsePath(rawPath)
log.Debugf("down: %s", rawPath)
account, path, driver, err := common.ParsePath(rawPath)
if err != nil {
common.ErrorResp(c, err, 500)
return
}
if driver.Config().OnlyProxy || account.Proxy {
Proxy(c)
return
}
link, err := driver.Link(path, account)
if err != nil {
common.ErrorResp(c, err, 500)
return
}
c.Redirect(302, link)
return
}
func Proxy(c *gin.Context) {
rawPath := c.Param("path")
rawPath = utils.ParsePath(rawPath)
log.Debugf("proxy: %s", rawPath)
account, path, driver, err := common.ParsePath(rawPath)
if err != nil {
common.ErrorResp(c, err, 500)
return
}
// 只有三种情况允许中转:
// 1. 账号开启中转
// 2. driver只能中转
// 3. 是文本类型文件
if !account.Proxy && !driver.Config().OnlyProxy && utils.GetFileType(filepath.Ext(rawPath)) != conf.TEXT {
common.ErrorResp(c, fmt.Errorf("[%s] not allowed proxy", account.Name), 403)
return
}
// 中转时有中转机器使用中转机器
if account.ProxyUrl != "" {
name := utils.Base(rawPath)
link := fmt.Sprintf("%s%s?sign=%s", account.ProxyUrl, rawPath, utils.SignWithToken(name, conf.Token))
c.Redirect(302, link)
return
}
link, err := driver.Link(path, account)
if err != nil {
common.ErrorResp(c, err, 500)
return
}
// 本机文件直接返回文件
if account.Type == "Native" {
// 对于名称为index.html的文件需要特殊处理
if utils.Base(rawPath) == "index.html" {
file, err := os.Open(link)
if err != nil {
common.ErrorResp(c, err, 500)
return
}
defer func() {
_ = file.Close()
}()
fileStat, err := os.Stat(link)
if err != nil {
common.ErrorResp(c, err, 500)
return
}
http.ServeContent(c.Writer, c.Request, utils.Base(rawPath), fileStat.ModTime(), file)
return
}
c.File(link)
return
} else {
if utils.GetFileType(filepath.Ext(rawPath)) == conf.TEXT {
Text(c, link)
return
}
driver.Proxy(c, account)
r := c.Request
w := c.Writer
target, err := url.Parse(link)
if err != nil {
common.ErrorResp(c, err, 500)
return
}
protocol := "http://"
if strings.HasPrefix(link, "https://") {
protocol = "https://"
}
targetHost, err := url.Parse(fmt.Sprintf("%s%s", protocol, target.Host))
proxy := httputil.NewSingleHostReverseProxy(targetHost)
r.URL = target
r.Host = target.Host
proxy.ServeHTTP(w, r)
}
}
var client *resty.Client
func init() {
client = resty.New()
client.SetRetryCount(3)
}
func Text(c *gin.Context, link string) {
res, err := client.R().Get(link)
if err != nil {
common.ErrorResp(c, err, 500)
return
}
text := res.String()
t := utils.GetStrCoding(res.Body())
log.Debugf("text type: %s", t)
if t != utils.UTF8 {
body, err := utils.GbkToUtf8(res.Body())
if err != nil {
common.ErrorResp(c, err, 500)
return
}
text = string(body)
}
c.String(200, text)
}