mirror of
https://github.com/OpenListTeam/OpenList.git
synced 2025-09-19 04:06:18 +08:00

* feat(proxy): add disable proxy sign * Update driver.go * GenerateDownProxyUrl * . * Update internal/op/driver.go Signed-off-by: j2rong4cn <36783515+j2rong4cn@users.noreply.github.com> * . --------- Signed-off-by: j2rong4cn <36783515+j2rong4cn@users.noreply.github.com> Co-authored-by: j2rong4cn <j2rong@qq.com> Co-authored-by: j2rong4cn <36783515+j2rong4cn@users.noreply.github.com>
159 lines
3.8 KiB
Go
159 lines
3.8 KiB
Go
package common
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"maps"
|
|
|
|
"github.com/OpenListTeam/OpenList/v4/internal/conf"
|
|
"github.com/OpenListTeam/OpenList/v4/internal/model"
|
|
"github.com/OpenListTeam/OpenList/v4/internal/net"
|
|
"github.com/OpenListTeam/OpenList/v4/internal/sign"
|
|
"github.com/OpenListTeam/OpenList/v4/internal/stream"
|
|
"github.com/OpenListTeam/OpenList/v4/pkg/utils"
|
|
)
|
|
|
|
func Proxy(w http.ResponseWriter, r *http.Request, link *model.Link, file model.Obj) error {
|
|
if link.MFile != nil {
|
|
attachHeader(w, file, link)
|
|
http.ServeContent(w, r, file.GetName(), file.ModTime(), link.MFile)
|
|
return nil
|
|
}
|
|
|
|
if link.Concurrency > 0 || link.PartSize > 0 {
|
|
attachHeader(w, file, link)
|
|
size := link.ContentLength
|
|
if size <= 0 {
|
|
size = file.GetSize()
|
|
}
|
|
rrf, _ := stream.GetRangeReaderFromLink(size, link)
|
|
if link.RangeReader == nil {
|
|
r = r.WithContext(context.WithValue(r.Context(), conf.RequestHeaderKey, r.Header))
|
|
}
|
|
return net.ServeHTTP(w, r, file.GetName(), file.ModTime(), size, &model.RangeReadCloser{
|
|
RangeReader: rrf,
|
|
})
|
|
}
|
|
|
|
if link.RangeReader != nil {
|
|
attachHeader(w, file, link)
|
|
size := link.ContentLength
|
|
if size <= 0 {
|
|
size = file.GetSize()
|
|
}
|
|
return net.ServeHTTP(w, r, file.GetName(), file.ModTime(), size, &model.RangeReadCloser{
|
|
RangeReader: link.RangeReader,
|
|
})
|
|
}
|
|
|
|
//transparent proxy
|
|
header := net.ProcessHeader(r.Header, link.Header)
|
|
res, err := net.RequestHttp(r.Context(), r.Method, header, link.URL)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer res.Body.Close()
|
|
|
|
maps.Copy(w.Header(), res.Header)
|
|
w.WriteHeader(res.StatusCode)
|
|
if r.Method == http.MethodHead {
|
|
return nil
|
|
}
|
|
_, err = utils.CopyWithBuffer(w, &stream.RateLimitReader{
|
|
Reader: res.Body,
|
|
Limiter: stream.ServerDownloadLimit,
|
|
Ctx: r.Context(),
|
|
})
|
|
return err
|
|
}
|
|
func attachHeader(w http.ResponseWriter, file model.Obj, link *model.Link) {
|
|
fileName := file.GetName()
|
|
w.Header().Set("Content-Disposition", utils.GenerateContentDisposition(fileName))
|
|
w.Header().Set("Content-Type", utils.GetMimeType(fileName))
|
|
size := link.ContentLength
|
|
if size <= 0 {
|
|
size = file.GetSize()
|
|
}
|
|
w.Header().Set("Etag", GetEtag(file, size))
|
|
contentType := link.Header.Get("Content-Type")
|
|
if len(contentType) > 0 {
|
|
w.Header().Set("Content-Type", contentType)
|
|
} else {
|
|
w.Header().Set("Content-Type", utils.GetMimeType(fileName))
|
|
}
|
|
}
|
|
func GetEtag(file model.Obj, size int64) string {
|
|
hash := ""
|
|
for _, v := range file.GetHash().Export() {
|
|
if v > hash {
|
|
hash = v
|
|
}
|
|
}
|
|
if len(hash) > 0 {
|
|
return fmt.Sprintf(`"%s"`, hash)
|
|
}
|
|
// 参考nginx
|
|
return fmt.Sprintf(`"%x-%x"`, file.ModTime().Unix(), size)
|
|
}
|
|
|
|
func ProxyRange(ctx context.Context, link *model.Link, size int64) *model.Link {
|
|
if link.MFile == nil && link.RangeReader == nil && !strings.HasPrefix(link.URL, GetApiUrl(ctx)+"/") {
|
|
if link.ContentLength > 0 {
|
|
size = link.ContentLength
|
|
}
|
|
rrf, err := stream.GetRangeReaderFromLink(size, link)
|
|
if err == nil {
|
|
return &model.Link{
|
|
RangeReader: rrf,
|
|
ContentLength: size,
|
|
}
|
|
}
|
|
}
|
|
return link
|
|
}
|
|
|
|
type InterceptResponseWriter struct {
|
|
http.ResponseWriter
|
|
io.Writer
|
|
}
|
|
|
|
func (iw *InterceptResponseWriter) Write(p []byte) (int, error) {
|
|
return iw.Writer.Write(p)
|
|
}
|
|
|
|
type WrittenResponseWriter struct {
|
|
http.ResponseWriter
|
|
written bool
|
|
}
|
|
|
|
func (ww *WrittenResponseWriter) Write(p []byte) (int, error) {
|
|
n, err := ww.ResponseWriter.Write(p)
|
|
if !ww.written && n > 0 {
|
|
ww.written = true
|
|
}
|
|
return n, err
|
|
}
|
|
|
|
func (ww *WrittenResponseWriter) IsWritten() bool {
|
|
return ww.written
|
|
}
|
|
|
|
func GenerateDownProxyURL(storage *model.Storage, reqPath string) string {
|
|
if storage.DownProxyURL == "" {
|
|
return ""
|
|
}
|
|
query := ""
|
|
if !storage.DisableProxySign {
|
|
query = "?sign=" + sign.Sign(reqPath)
|
|
}
|
|
return fmt.Sprintf("%s%s%s",
|
|
strings.Split(storage.DownProxyURL, "\n")[0],
|
|
utils.EncodePath(reqPath, true),
|
|
query,
|
|
)
|
|
}
|