Просмотр исходного кода

feat: simplify HTTP file server to read-only mode (browse + download only)

Your Name 3 недель назад
Родитель
Сommit
c7319a4686
2 измененных файлов с 3 добавлено и 240 удалено
  1. 0 0
      NDH6SA~M
  2. 3 240
      httpfile/server.go

+ 3 - 240
httpfile/server.go

@@ -3,7 +3,6 @@ package httpfile
 import (
 	"encoding/json"
 	"fmt"
-	"io"
 	"log"
 	"net/http"
 	"os"
@@ -41,12 +40,7 @@ func (s *Server) Start() error {
 
 	// API endpoints
 	mux.HandleFunc("/api/list", s.apiListDir)
-	if s.config.HTTPFile.Upload {
-		mux.HandleFunc("/api/upload", s.apiUpload)
-		mux.HandleFunc("/api/create-folder", s.apiCreateFolder)
-	}
 	mux.HandleFunc("/api/download", s.apiDownload)
-	mux.HandleFunc("/api/delete", s.apiDelete)
 
 	addr := fmt.Sprintf("%s:%d", s.config.HTTPFile.Host, s.config.HTTPFile.Port)
 	log.Printf("HTTP file server listening on http://%s", addr)
@@ -121,110 +115,6 @@ func (s *Server) apiDownload(w http.ResponseWriter, r *http.Request) {
 	log.Printf("HTTP download: %s from %s", file, r.RemoteAddr)
 }
 
-func (s *Server) apiUpload(w http.ResponseWriter, r *http.Request) {
-	if r.Method != http.MethodPost {
-		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
-		return
-	}
-
-	// Parse multipart form (max 500MB)
-	err := r.ParseMultipartForm(500 << 20)
-	if err != nil {
-		http.Error(w, `{"error":"Failed to parse upload"}`, http.StatusBadRequest)
-		return
-	}
-
-	dir := r.FormValue("path")
-	if dir == "" {
-		dir = "/"
-	}
-
-	files := r.MultipartForm.File["files"]
-	if len(files) == 0 {
-		http.Error(w, `{"error":"No files uploaded"}`, http.StatusBadRequest)
-		return
-	}
-
-	realDir := s.toRealPath(dir)
-
-	for _, fileHeader := range files {
-		file, err := fileHeader.Open()
-		if err != nil {
-			continue
-		}
-
-		destPath := filepath.Join(realDir, fileHeader.Filename)
-		destFile, err := os.Create(destPath)
-		if err != nil {
-			file.Close()
-			continue
-		}
-
-		io.Copy(destFile, file)
-		destFile.Close()
-		file.Close()
-
-		log.Printf("HTTP upload: %s (%d bytes) from %s", fileHeader.Filename, fileHeader.Size, r.RemoteAddr)
-	}
-
-	w.Header().Set("Content-Type", "application/json")
-	json.NewEncoder(w).Encode(map[string]string{"status": "ok"})
-}
-
-func (s *Server) apiCreateFolder(w http.ResponseWriter, r *http.Request) {
-	if r.Method != http.MethodPost {
-		http.Error(w, `{"error":"Method not allowed"}`, http.StatusMethodNotAllowed)
-		return
-	}
-
-	var req struct {
-		Path string `json:"path"`
-		Name string `json:"name"`
-	}
-	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
-		http.Error(w, `{"error":"Invalid request"}`, http.StatusBadRequest)
-		return
-	}
-
-	if req.Name == "" {
-		http.Error(w, `{"error":"Folder name required"}`, http.StatusBadRequest)
-		return
-	}
-
-	realPath := filepath.Join(s.toRealPath(req.Path), req.Name)
-	if err := os.MkdirAll(realPath, 0755); err != nil {
-		http.Error(w, `{"error":"Failed to create folder"}`, http.StatusInternalServerError)
-		return
-	}
-
-	w.Header().Set("Content-Type", "application/json")
-	json.NewEncoder(w).Encode(map[string]string{"status": "ok"})
-}
-
-func (s *Server) apiDelete(w http.ResponseWriter, r *http.Request) {
-	if r.Method != http.MethodPost {
-		http.Error(w, `{"error":"Method not allowed"}`, http.StatusMethodNotAllowed)
-		return
-	}
-
-	var req struct {
-		Path string `json:"path"`
-	}
-	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
-		http.Error(w, `{"error":"Invalid request"}`, http.StatusBadRequest)
-		return
-	}
-
-	realPath := s.toRealPath(req.Path)
-	if err := os.RemoveAll(realPath); err != nil {
-		http.Error(w, `{"error":"Delete failed"}`, http.StatusInternalServerError)
-		return
-	}
-
-	w.Header().Set("Content-Type", "application/json")
-	json.NewEncoder(w).Encode(map[string]string{"status": "ok"})
-}
-
 func (s *Server) toRealPath(httpPath string) string {
 	rootDir := s.config.HTTPFile.RootDir
 	cleanPath := strings.TrimPrefix(httpPath, "/")
@@ -313,21 +203,14 @@ const fileBrowserHTML = `<!DOCTYPE html>
     <div class="container">
         <div class="header">
             <h1>&#128193; HTTP 文件服务器</h1>
-            <p>在线浏览、下载、上传文件</p>
+            <p>在线浏览、下载文件</p>
         </div>
 
         <div class="breadcrumb" id="breadcrumb">
         </div>
 
         <div class="actions">
-            <button class="btn btn-primary" onclick="document.getElementById('uploadInput').click()">
-                &#128229; 上传文件
-            </button>
-            <input type="file" id="uploadInput" multiple style="display:none" onchange="uploadFiles(this.files)">
-            <button class="btn btn-success" onclick="showNewFolderModal()">
-                &#128193; 新建文件夹
-            </button>
-            <button class="btn btn-danger" onclick="refresh()">
+            <button class="btn btn-primary" onclick="refresh()">
                 &#128260; 刷新
             </button>
         </div>
@@ -347,30 +230,6 @@ const fileBrowserHTML = `<!DOCTYPE html>
         </div>
     </div>
 
-    <!-- New Folder Modal -->
-    <div class="modal-overlay" id="folderModal">
-        <div class="modal">
-            <h2>&#128193; 新建文件夹</h2>
-            <div class="form-group">
-                <label>文件夹名称</label>
-                <input type="text" id="folderName" placeholder="输入文件夹名称" onkeypress="if(event.key==='Enter')createFolder()">
-            </div>
-            <div class="modal-actions">
-                <button class="btn" style="background:#eee" onclick="closeFolderModal()">取消</button>
-                <button class="btn btn-primary" onclick="createFolder()">创建</button>
-            </div>
-        </div>
-    </div>
-
-    <!-- Upload Progress -->
-    <div class="modal-overlay" id="uploadModal">
-        <div class="modal">
-            <h2>&#128229; 上传进度</h2>
-            <div id="uploadStatus" style="margin-bottom:12px; font-size:14px; color:#666;"></div>
-            <div class="progress-bar show"><div class="progress-fill" id="progressFill"></div></div>
-        </div>
-    </div>
-
 <script>
 let currentPath = '/';
 
@@ -403,7 +262,7 @@ function loadFiles() {
                     (f.isDir ? '<a class="file-link" href="#" onclick="enterFolder(\\'' + escapeStr(f.name) + '\\');return false;">' + f.name + '</a>' : '<span>' + f.name + '</span>') +
                     '</div></td><td>' + (f.isDir ? '-' : f.size) + '</td><td>' + f.modTime + '</td><td class="actions-cell">' +
                     (f.isDir ? '<button class="btn btn-sm btn-primary" onclick="enterFolder(\\'' + escapeStr(f.name) + '\\')">打开</button>' : '<a href="/api/download?file=' + encodeURIComponent(currentPath + f.name) + '" class="btn btn-sm btn-success">下载</a>') +
-                    '<button class="btn btn-sm btn-danger" onclick="deleteItem(\\'' + escapeStr(f.name) + '\\', ' + f.isDir + ')">删除</button></td></tr>';
+                    '</td></tr>';
                 tbody.appendChild(tr);
             });
 
@@ -439,91 +298,6 @@ function goTo(path) {
 
 function refresh() {
     loadFiles();
-    showToast('已刷新');
-}
-
-function showNewFolderModal() {
-    document.getElementById('folderName').value = '';
-    document.getElementById('folderModal').classList.add('show');
-    document.getElementById('folderName').focus();
-}
-
-function closeFolderModal() {
-    document.getElementById('folderModal').classList.remove('show');
-}
-
-function createFolder() {
-    const name = document.getElementById('folderName').value.trim();
-    if (!name) { showToast('请输入文件夹名称', 'error'); return; }
-
-    fetch('/api/create-folder', {
-        method: 'POST',
-        headers: { 'Content-Type': 'application/json' },
-        body: JSON.stringify({ path: currentPath, name: name })
-    }).then(r => r.json()).then(data => {
-        if (data.status === 'ok') {
-            showToast('文件夹已创建');
-            closeFolderModal();
-            loadFiles();
-        } else {
-            showToast(data.error || '创建失败', 'error');
-        }
-    });
-}
-
-function uploadFiles(files) {
-    if (!files || files.length === 0) return;
-
-    document.getElementById('uploadModal').classList.add('show');
-    document.getElementById('uploadStatus').textContent = '正在上传 ' + files.length + ' 个文件...';
-    document.getElementById('progressFill').style.width = '0%';
-
-    const formData = new FormData();
-    formData.append('path', currentPath);
-    for (let i = 0; i < files.length; i++) {
-        formData.append('files', files[i]);
-    }
-
-    const xhr = new XMLHttpRequest();
-    xhr.open('POST', '/api/upload');
-    xhr.upload.onprogress = function(e) {
-        if (e.lengthComputable) {
-            const percent = (e.loaded / e.total * 100).toFixed(1);
-            document.getElementById('progressFill').style.width = percent + '%';
-        }
-    };
-    xhr.onload = function() {
-        setTimeout(() => {
-            document.getElementById('uploadModal').classList.remove('show');
-            if (xhr.status === 200) {
-                showToast('上传成功');
-                loadFiles();
-            } else {
-                showToast('上传失败', 'error');
-            }
-        }, 500);
-    };
-    xhr.send(formData);
-
-    document.getElementById('uploadInput').value = '';
-}
-
-function deleteItem(name, isDir) {
-    const confirmMsg = isDir ? '确定要删除文件夹 "' + name + '" 及其所有内容吗?' : '确定要删除文件 "' + name + '" 吗?';
-    if (!confirm(confirmMsg)) return;
-
-    fetch('/api/delete', {
-        method: 'POST',
-        headers: { 'Content-Type': 'application/json' },
-        body: JSON.stringify({ path: currentPath + name })
-    }).then(r => r.json()).then(data => {
-        if (data.status === 'ok') {
-            showToast('已删除');
-            loadFiles();
-        } else {
-            showToast(data.error || '删除失败', 'error');
-        }
-    });
 }
 
 function getFileIcon(name) {
@@ -556,17 +330,6 @@ function showToast(msg, type) {
     setTimeout(() => toast.remove(), 3000);
 }
 
-// Drag and drop support
-document.addEventListener('DOMContentLoaded', function() {
-    document.addEventListener('dragover', function(e) { e.preventDefault(); });
-    document.addEventListener('drop', function(e) {
-        e.preventDefault();
-        if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {
-            uploadFiles(e.dataTransfer.files);
-        }
-    });
-});
-
 init();
 </script>
 </body>