105 lines
		
	
	
		
			2.2 KiB
		
	
	
	
		
			Go
		
	
	
	
		
		
			
		
	
	
			105 lines
		
	
	
		
			2.2 KiB
		
	
	
	
		
			Go
		
	
	
	
|  | package http | ||
|  | 
 | ||
|  | import ( | ||
|  | 	"bufio" | ||
|  | 	"io" | ||
|  | 	"log" | ||
|  | 	"net/http" | ||
|  | 	"os/exec" | ||
|  | 	"strings" | ||
|  | 	"time" | ||
|  | 
 | ||
|  | 	"github.com/filebrowser/filebrowser/v2/runner" | ||
|  | 	"github.com/gorilla/websocket" | ||
|  | ) | ||
|  | 
 | ||
|  | var upgrader = websocket.Upgrader{ | ||
|  | 	ReadBufferSize:  1024, | ||
|  | 	WriteBufferSize: 1024, | ||
|  | } | ||
|  | 
 | ||
|  | var ( | ||
|  | 	cmdNotAllowed = []byte("Command not allowed.") | ||
|  | ) | ||
|  | 
 | ||
|  | func wsErr(ws *websocket.Conn, r *http.Request, status int, err error) { | ||
|  | 	txt := http.StatusText(status) | ||
|  | 	if err != nil || status >= 400 { | ||
|  | 		log.Printf("%s: %v %s %v", r.URL.Path, status, r.RemoteAddr, err) | ||
|  | 	} | ||
|  | 	ws.WriteControl(websocket.CloseInternalServerErr, []byte(txt), time.Now().Add(10*time.Second)) | ||
|  | } | ||
|  | 
 | ||
|  | var commandsHandler = withUser(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) { | ||
|  | 	conn, err := upgrader.Upgrade(w, r, nil) | ||
|  | 	if err != nil { | ||
|  | 		return http.StatusInternalServerError, err | ||
|  | 	} | ||
|  | 	defer conn.Close() | ||
|  | 
 | ||
|  | 	var raw string | ||
|  | 
 | ||
|  | 	for { | ||
|  | 		_, msg, err := conn.ReadMessage() | ||
|  | 		if err != nil { | ||
|  | 			wsErr(conn, r, http.StatusInternalServerError, err) | ||
|  | 			return 0, nil | ||
|  | 		} | ||
|  | 
 | ||
|  | 		raw = strings.TrimSpace(string(msg)) | ||
|  | 		if raw != "" { | ||
|  | 			break | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	if !d.user.CanExecute(strings.Split(raw, " ")[0]) { | ||
|  | 		err := conn.WriteMessage(websocket.TextMessage, cmdNotAllowed) | ||
|  | 		if err != nil { | ||
|  | 			wsErr(conn, r, http.StatusInternalServerError, err) | ||
|  | 		} | ||
|  | 
 | ||
|  | 		return 0, nil | ||
|  | 	} | ||
|  | 
 | ||
|  | 	command, err := runner.ParseCommand(d.settings, raw) | ||
|  | 	if err != nil { | ||
|  | 		err := conn.WriteMessage(websocket.TextMessage, []byte(err.Error())) | ||
|  | 		if err != nil { | ||
|  | 			wsErr(conn, r, http.StatusInternalServerError, err) | ||
|  | 		} | ||
|  | 
 | ||
|  | 		return 0, nil | ||
|  | 	} | ||
|  | 
 | ||
|  | 	cmd := exec.Command(command[0], command[1:]...) | ||
|  | 	cmd.Dir = d.user.FullPath(r.URL.Path) | ||
|  | 
 | ||
|  | 	stdout, err := cmd.StdoutPipe() | ||
|  | 	if err != nil { | ||
|  | 		wsErr(conn, r, http.StatusInternalServerError, err) | ||
|  | 		return 0, nil | ||
|  | 	} | ||
|  | 
 | ||
|  | 	stderr, err := cmd.StderrPipe() | ||
|  | 	if err != nil { | ||
|  | 		wsErr(conn, r, http.StatusInternalServerError, err) | ||
|  | 		return 0, nil | ||
|  | 	} | ||
|  | 
 | ||
|  | 	if err := cmd.Start(); err != nil { | ||
|  | 		wsErr(conn, r, http.StatusInternalServerError, err) | ||
|  | 		return 0, nil | ||
|  | 	} | ||
|  | 
 | ||
|  | 	s := bufio.NewScanner(io.MultiReader(stdout, stderr)) | ||
|  | 	for s.Scan() { | ||
|  | 		conn.WriteMessage(websocket.TextMessage, s.Bytes()) | ||
|  | 	} | ||
|  | 
 | ||
|  | 	if err := cmd.Wait(); err != nil { | ||
|  | 		wsErr(conn, r, http.StatusInternalServerError, err) | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return 0, nil | ||
|  | }) |