From 1361f6e2379c038b91e777b89509ef7a86ed305d Mon Sep 17 00:00:00 2001 From: wjqserver <114663932+WJQSERVER@users.noreply.github.com> Date: Tue, 21 Oct 2025 14:47:29 +0800 Subject: [PATCH] update --- context.go | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) diff --git a/context.go b/context.go index b6fbd46..0a57ee1 100644 --- a/context.go +++ b/context.go @@ -19,6 +19,7 @@ import ( "net/url" "os" "path" + "path/filepath" "strings" "sync" "time" @@ -280,6 +281,118 @@ func (c *Context) Text(code int, text string) { c.Writer.Write([]byte(text)) } +// FileText +func (c *Context) FileText(code int, filePath string) { + // 清理path + cleanPath := path.Clean(filePath) + if !filepath.IsAbs(cleanPath) { + c.AddError(fmt.Errorf("relative path not allowed: %s", cleanPath)) + c.ErrorUseHandle(http.StatusBadRequest, fmt.Errorf("relative path not allowed")) + return + } + if strings.Contains(cleanPath, "..") { + c.AddError(fmt.Errorf("path traversal attempt detected: %s", cleanPath)) + c.ErrorUseHandle(http.StatusBadRequest, fmt.Errorf("path traversal attempt detected")) + return + } + // 检查文件是否存在 + if _, err := os.Stat(cleanPath); os.IsNotExist(err) { + c.AddError(fmt.Errorf("file not found: %s", cleanPath)) + c.ErrorUseHandle(http.StatusNotFound, fmt.Errorf("file not found")) + return + } + + // 打开文件 + file, err := os.Open(cleanPath) + if err != nil { + c.AddError(fmt.Errorf("failed to open file %s: %w", cleanPath, err)) + c.ErrorUseHandle(http.StatusInternalServerError, fmt.Errorf("failed to open file: %w", err)) + return + } + defer file.Close() + + // 获取文件信息以获取文件大小 + fileInfo, err := file.Stat() + if err != nil { + c.AddError(fmt.Errorf("failed to get file info for %s: %w", cleanPath, err)) + c.ErrorUseHandle(http.StatusInternalServerError, fmt.Errorf("failed to get file info: %w", err)) + return + } + // 判断是否是dir + if fileInfo.IsDir() { + c.AddError(fmt.Errorf("path is a directory, not a file: %s", cleanPath)) + c.ErrorUseHandle(http.StatusBadRequest, fmt.Errorf("path is a directory")) + return + } + + c.SetHeader("Content-Type", "text/plain; charset=utf-8") + + c.SetBodyStream(file, int(fileInfo.Size())) +} + +/* +// not fot work +// FileTextSafeDir +func (c *Context) FileTextSafeDir(code int, filePath string, safeDir string) { + + // 清理path + cleanPath := path.Clean(filePath) + if !filepath.IsAbs(cleanPath) { + c.AddError(fmt.Errorf("relative path not allowed: %s", cleanPath)) + c.ErrorUseHandle(http.StatusBadRequest, fmt.Errorf("relative path not allowed")) + return + } + if strings.Contains(cleanPath, "..") { + c.AddError(fmt.Errorf("path traversal attempt detected: %s", cleanPath)) + c.ErrorUseHandle(http.StatusBadRequest, fmt.Errorf("path traversal attempt detected")) + return + } + + // 判断filePath是否包含在safeDir内, 防止路径穿越 + relPath, err := filepath.Rel(safeDir, cleanPath) + if err != nil { + c.AddError(fmt.Errorf("failed to get relative path: %w", err)) + c.ErrorUseHandle(http.StatusBadRequest, fmt.Errorf("failed to get relative path: %w", err)) + return + } + cleanPath = filepath.Join(safeDir, relPath) + + // 检查文件是否存在 + if _, err := os.Stat(cleanPath); os.IsNotExist(err) { + c.AddError(fmt.Errorf("file not found: %s", cleanPath)) + c.ErrorUseHandle(http.StatusNotFound, fmt.Errorf("file not found")) + return + } + + // 打开文件 + file, err := os.Open(cleanPath) + if err != nil { + c.AddError(fmt.Errorf("failed to open file %s: %w", cleanPath, err)) + c.ErrorUseHandle(http.StatusInternalServerError, fmt.Errorf("failed to open file: %w", err)) + return + } + defer file.Close() + + // 获取文件信息以获取文件大小 + fileInfo, err := file.Stat() + if err != nil { + c.AddError(fmt.Errorf("failed to get file info for %s: %w", cleanPath, err)) + c.ErrorUseHandle(http.StatusInternalServerError, fmt.Errorf("failed to get file info: %w", err)) + return + } + // 判断是否是dir + if fileInfo.IsDir() { + c.AddError(fmt.Errorf("path is a directory, not a file: %s", cleanPath)) + c.ErrorUseHandle(http.StatusBadRequest, fmt.Errorf("path is a directory")) + return + } + + c.SetHeader("Content-Type", "text/plain; charset=utf-8") + + c.SetBodyStream(file, int(fileInfo.Size())) +} +*/ + // JSON 向响应写入 JSON 数据 // 设置 Content-Type 为 application/json func (c *Context) JSON(code int, obj any) {