refactor: FilterReadMeScripts (#8154 close #8150)

* refactor: FilterReadMeScripts

* .
This commit is contained in:
j2rong4cn 2025-03-18 22:02:33 +08:00 committed by GitHub
parent 3499c4db87
commit b4e6ab12d9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 51 additions and 98 deletions

View File

@ -316,7 +316,7 @@ func (d *Quqi) Put(ctx context.Context, dstDir model.Obj, stream model.FileStrea
// if the file already exists in Quqi server, there is no need to actually upload it
if uploadInitResp.Data.Exist {
// the file name returned by Quqi does not include the extension name
nodeName, nodeExt := uploadInitResp.Data.NodeName, rawExt(stream.GetName())
nodeName, nodeExt := uploadInitResp.Data.NodeName, utils.Ext(stream.GetName())
if nodeExt != "" {
nodeName = nodeName + "." + nodeExt
}
@ -432,7 +432,7 @@ func (d *Quqi) Put(ctx context.Context, dstDir model.Obj, stream model.FileStrea
return nil, err
}
// the file name returned by Quqi does not include the extension name
nodeName, nodeExt := uploadFinishResp.Data.NodeName, rawExt(stream.GetName())
nodeName, nodeExt := uploadFinishResp.Data.NodeName, utils.Ext(stream.GetName())
if nodeExt != "" {
nodeName = nodeName + "." + nodeExt
}

View File

@ -9,7 +9,6 @@ import (
"io"
"net/http"
"net/url"
stdpath "path"
"strings"
"time"
@ -115,16 +114,6 @@ func (d *Quqi) checkLogin() bool {
return true
}
// rawExt 保留扩展名大小写
func rawExt(name string) string {
ext := stdpath.Ext(name)
if strings.HasPrefix(ext, ".") {
ext = ext[1:]
}
return ext
}
// decryptKey 获取密码
func decryptKey(encodeKey string) []byte {
// 移除非法字符

View File

@ -8,9 +8,7 @@ import (
"fmt"
"io"
"net/http"
"path"
"strconv"
"strings"
"github.com/alist-org/alist/v3/drivers/base"
"github.com/alist-org/alist/v3/internal/driver"
@ -151,7 +149,7 @@ func (d *Vtencent) ApplyUploadUGC(signature string, stream model.FileStreamer) (
form := base.Json{
"signature": signature,
"videoName": stream.GetName(),
"videoType": strings.ReplaceAll(path.Ext(stream.GetName()), ".", ""),
"videoType": utils.Ext(stream.GetName()),
"videoSize": stream.GetSize(),
}
var resps RspApplyUploadUGC

View File

@ -619,10 +619,9 @@ type Buf struct {
// NewBuf is a buffer that can have 1 read & 1 write at the same time.
// when read is faster write, immediately feed data to read after written
func NewBuf(ctx context.Context, maxSize int) *Buf {
d := make([]byte, 0, maxSize)
return &Buf{
ctx: ctx,
buffer: bytes.NewBuffer(d),
buffer: bytes.NewBuffer(make([]byte, 0, maxSize)),
size: maxSize,
}
}
@ -677,5 +676,5 @@ func (br *Buf) Write(p []byte) (n int, err error) {
}
func (br *Buf) Close() {
br.buffer.Reset()
br.buffer = nil
}

View File

@ -45,7 +45,7 @@ func IsSubPath(path string, subPath string) bool {
func Ext(path string) string {
ext := stdpath.Ext(path)
if strings.HasPrefix(ext, ".") {
if len(ext) > 0 && ext[0] == '.' {
ext = ext[1:]
}
return strings.ToLower(ext)

View File

@ -1,97 +1,25 @@
package common
import (
"bytes"
"context"
"fmt"
"io"
"net/http"
"net/url"
"os"
"strconv"
"strings"
"github.com/alist-org/alist/v3/internal/conf"
"maps"
"github.com/alist-org/alist/v3/internal/model"
"github.com/alist-org/alist/v3/internal/net"
"github.com/alist-org/alist/v3/internal/setting"
"github.com/alist-org/alist/v3/internal/stream"
"github.com/alist-org/alist/v3/pkg/http_range"
"github.com/alist-org/alist/v3/pkg/utils"
"github.com/microcosm-cc/bluemonday"
log "github.com/sirupsen/logrus"
"github.com/yuin/goldmark"
)
func processMarkdown(content []byte) ([]byte, error) {
var buf bytes.Buffer
if err := goldmark.New().Convert(content, &buf); err != nil {
return nil, fmt.Errorf("markdown conversion failed: %w", err)
}
return bluemonday.UGCPolicy().SanitizeBytes(buf.Bytes()), nil
}
func Proxy(w http.ResponseWriter, r *http.Request, link *model.Link, file model.Obj) error {
//优先处理md文件
if utils.Ext(file.GetName()) == "md" && setting.GetBool(conf.FilterReadMeScripts) {
var markdownContent []byte
var err error
if link.MFile != nil {
defer link.MFile.Close()
attachHeader(w, file)
markdownContent, err = io.ReadAll(link.MFile)
if err != nil {
return fmt.Errorf("failed to read markdown content: %w", err)
}
} else if link.RangeReadCloser != nil {
attachHeader(w, file)
rrc, err := link.RangeReadCloser.RangeRead(r.Context(), http_range.Range{Start: 0, Length: -1})
if err != nil {
return err
}
defer rrc.Close()
markdownContent, err = io.ReadAll(rrc)
if err != nil {
return fmt.Errorf("failed to read markdown content: %w", err)
}
} else {
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()
for h, v := range res.Header {
w.Header()[h] = v
}
w.WriteHeader(res.StatusCode)
if r.Method == http.MethodHead {
return nil
}
markdownContent, err = io.ReadAll(res.Body)
if err != nil {
return fmt.Errorf("failed to read markdown content: %w", err)
}
}
safeHTML, err := processMarkdown(markdownContent)
if err != nil {
return err
}
safeHTMLReader := bytes.NewReader(safeHTML)
w.Header().Set("Content-Length", strconv.FormatInt(int64(len(safeHTML)), 10))
w.Header().Set("Content-Type", "text/html; charset=utf-8")
_, err = utils.CopyWithBuffer(w, safeHTMLReader)
if err != nil {
return err
}
return nil
}
if link.MFile != nil {
defer link.MFile.Close()
attachHeader(w, file)
@ -152,9 +80,7 @@ func Proxy(w http.ResponseWriter, r *http.Request, link *model.Link, file model.
}
defer res.Body.Close()
for h, v := range res.Header {
w.Header()[h] = v
}
maps.Copy(w.Header(), res.Header)
w.WriteHeader(res.StatusCode)
if r.Method == http.MethodHead {
return nil

View File

@ -1,9 +1,12 @@
package handles
import (
"bytes"
"fmt"
"io"
"net/http"
stdpath "path"
"strconv"
"strings"
"github.com/alist-org/alist/v3/internal/conf"
@ -15,7 +18,9 @@ import (
"github.com/alist-org/alist/v3/pkg/utils"
"github.com/alist-org/alist/v3/server/common"
"github.com/gin-gonic/gin"
"github.com/microcosm-cc/bluemonday"
log "github.com/sirupsen/logrus"
"github.com/yuin/goldmark"
)
func Down(c *gin.Context) {
@ -124,7 +129,34 @@ func localProxy(c *gin.Context, link *model.Link, file model.Obj, proxyRange boo
if proxyRange {
common.ProxyRange(link, file.GetSize())
}
err = common.Proxy(c.Writer, c.Request, link, file)
//优先处理md文件
if utils.Ext(file.GetName()) == "md" && setting.GetBool(conf.FilterReadMeScripts) {
w := c.Writer
buf := bytes.NewBuffer(make([]byte, 0, file.GetSize()))
err = common.Proxy(&proxyResponseWriter{ResponseWriter: w, Writer: buf}, c.Request, link, file)
if err == nil && buf.Len() > 0 {
if w.Status() < 200 || w.Status() > 300 {
w.Write(buf.Bytes())
return
}
var html bytes.Buffer
if err = goldmark.Convert(buf.Bytes(), &html); err != nil {
err = fmt.Errorf("markdown conversion failed: %w", err)
} else {
buf.Reset()
err = bluemonday.UGCPolicy().SanitizeReaderToWriter(&html, buf)
if err == nil {
w.Header().Set("Content-Length", strconv.FormatInt(int64(buf.Len()), 10))
w.Header().Set("Content-Type", "text/html; charset=utf-8")
_, err = utils.CopyWithBuffer(c.Writer, buf)
}
}
}
} else {
err = common.Proxy(c.Writer, c.Request, link, file)
}
if err != nil {
common.ErrorResp(c, err, 500, true)
return
@ -150,3 +182,12 @@ func canProxy(storage driver.Driver, filename string) bool {
}
return false
}
type proxyResponseWriter struct {
http.ResponseWriter
io.Writer
}
func (pw *proxyResponseWriter) Write(p []byte) (int, error) {
return pw.Writer.Write(p)
}