From 96be6bbbd1d6d3a675ebd2fac3fd3fcff7d46039 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=AE=E5=87=89?= <927625802@qq.com> Date: Thu, 13 Jan 2022 19:49:02 +0800 Subject: [PATCH] :bug: fix #334 proxy video can't use range --- server/controllers/down.go | 136 ------------------------------- server/controllers/proxy.go | 155 ++++++++++++++++++++++++++++++++++++ 2 files changed, 155 insertions(+), 136 deletions(-) create mode 100644 server/controllers/proxy.go diff --git a/server/controllers/down.go b/server/controllers/down.go index bb0c1421..26010b2c 100644 --- a/server/controllers/down.go +++ b/server/controllers/down.go @@ -1,21 +1,11 @@ package controllers import ( - "fmt" - "github.com/Xhofe/alist/conf" "github.com/Xhofe/alist/drivers/base" "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" - "io" - "net/http" - "net/http/httputil" - "net/url" - "os" - "path/filepath" - "strings" ) func Down(c *gin.Context) { @@ -39,129 +29,3 @@ func Down(c *gin.Context) { c.Redirect(302, link.Url) 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. 是文本类型文件 - // 4. 开启webdav中转(需要验证sign) - if !account.Proxy && !driver.Config().OnlyProxy && utils.GetFileType(filepath.Ext(rawPath)) != conf.TEXT { - // 只开启了webdav中转,验证sign - ok := false - if account.WebdavProxy { - _, ok = c.Get("sign") - } - if !ok { - common.ErrorResp(c, fmt.Errorf("[%s] not allowed proxy", account.Name), 403) - return - } - } - // 中转时有中转机器使用中转机器,若携带标志位则表明不能再走中转机器了 - if account.DownProxyUrl != "" && c.Query("d") != "1" { - name := utils.Base(rawPath) - link := fmt.Sprintf("%s%s?sign=%s", account.DownProxyUrl, rawPath, utils.SignWithToken(name, conf.Token)) - c.Redirect(302, link) - return - } - // 对于中转,不需要重设IP - link, err := driver.Link(base.Args{Path: path}, account) - if err != nil { - common.ErrorResp(c, err, 500) - return - } - // 本机读取数据 - if link.Data != nil { - //c.Data(http.StatusOK, "application/octet-stream", link.Data) - defer func() { - _ = link.Data.Close() - }() - c.Status(http.StatusOK) - c.Header("content", "application/octet-stream") - _, err = io.Copy(c.Writer, link.Data) - if err != nil { - _, _ = c.Writer.WriteString(err.Error()) - } - return - } - // 本机文件直接返回文件 - if account.Type == "Native" { - // 对于名称为index.html的文件需要特殊处理 - if utils.Base(rawPath) == "index.html" { - file, err := os.Open(link.Url) - if err != nil { - common.ErrorResp(c, err, 500) - return - } - defer func() { - _ = file.Close() - }() - fileStat, err := os.Stat(link.Url) - 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.Url) - 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.Url) - if err != nil { - common.ErrorResp(c, err, 500) - return - } - protocol := "http://" - if strings.HasPrefix(link.Url, "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 *base.Link) { - res, err := client.R().Get(link.Url) - 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) -} diff --git a/server/controllers/proxy.go b/server/controllers/proxy.go new file mode 100644 index 00000000..27fe27ef --- /dev/null +++ b/server/controllers/proxy.go @@ -0,0 +1,155 @@ +package controllers + +import ( + "fmt" + "github.com/Xhofe/alist/conf" + "github.com/Xhofe/alist/drivers/base" + "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" + "io" + "net/http" + "os" + "path/filepath" +) + +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. 是文本类型文件 + // 4. 开启webdav中转(需要验证sign) + if !account.Proxy && !driver.Config().OnlyProxy && utils.GetFileType(filepath.Ext(rawPath)) != conf.TEXT { + // 只开启了webdav中转,验证sign + ok := false + if account.WebdavProxy { + _, ok = c.Get("sign") + } + if !ok { + common.ErrorResp(c, fmt.Errorf("[%s] not allowed proxy", account.Name), 403) + return + } + } + // 中转时有中转机器使用中转机器,若携带标志位则表明不能再走中转机器了 + if account.DownProxyUrl != "" && c.Query("d") != "1" { + name := utils.Base(rawPath) + link := fmt.Sprintf("%s%s?sign=%s", account.DownProxyUrl, rawPath, utils.SignWithToken(name, conf.Token)) + c.Redirect(302, link) + return + } + // 对于中转,不需要重设IP + link, err := driver.Link(base.Args{Path: path}, account) + if err != nil { + common.ErrorResp(c, err, 500) + return + } + // 本机读取数据 + if link.Data != nil { + //c.Data(http.StatusOK, "application/octet-stream", link.Data) + defer func() { + _ = link.Data.Close() + }() + c.Status(http.StatusOK) + c.Header("content", "application/octet-stream") + _, err = io.Copy(c.Writer, link.Data) + if err != nil { + _, _ = c.Writer.WriteString(err.Error()) + } + return + } + // 本机文件直接返回文件 + if account.Type == "Native" { + // 对于名称为index.html的文件需要特殊处理 + if utils.Base(rawPath) == "index.html" { + file, err := os.Open(link.Url) + if err != nil { + common.ErrorResp(c, err, 500) + return + } + defer func() { + _ = file.Close() + }() + fileStat, err := os.Stat(link.Url) + 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.Url) + 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.Url) + //if err != nil { + // common.ErrorResp(c, err, 500) + // return + //} + req, err := http.NewRequest("GET", link.Url, nil) + if err != nil { + common.ErrorResp(c, err, 500) + return + } + for h, val := range r.Header { + req.Header[h] = val + } + res, err := HttpClient.Do(req) + if err != nil { + common.ErrorResp(c, err, 500) + return + } + for h, v := range res.Header { + w.Header()[h] = v + } + _, err = io.Copy(w, res.Body) + if err != nil { + common.ErrorResp(c, err, 500) + return + } + } +} + +var client *resty.Client +var HttpClient = &http.Client{} + +func init() { + client = resty.New() + client.SetRetryCount(3) +} + +func Text(c *gin.Context, link *base.Link) { + res, err := client.R().Get(link.Url) + 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) +}