Add support for reading a file's content or downloading it
This commit is contained in:
		
							parent
							
								
									314a5ad546
								
							
						
					
					
						commit
						aef9521190
					
				
							
								
								
									
										44
									
								
								http.go
									
									
									
									
									
								
							
							
						
						
									
										44
									
								
								http.go
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -1,6 +1,7 @@
 | 
			
		|||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"github.com/julienschmidt/httprouter"
 | 
			
		||||
| 
						 | 
				
			
			@ -189,6 +190,48 @@ func (rt *Router) routeServerLogs(w http.ResponseWriter, r *http.Request, ps htt
 | 
			
		|||
	json.NewEncoder(w).Encode(struct{Data []string `json:"data"`}{Data: out })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Handle a request to get the contents of a file on the server.
 | 
			
		||||
func (rt *Router) routeServerFileRead(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
 | 
			
		||||
	s := rt.Servers.Get(ps.ByName("server"))
 | 
			
		||||
 | 
			
		||||
	cleaned, err := s.Filesystem().SafePath(ps.ByName("path"))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		http.Error(w, "could not determine path", http.StatusInternalServerError)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	st, err := os.Stat(cleaned)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if !os.IsNotExist(err) {
 | 
			
		||||
			zap.S().Errorw("failed to stat file for reading", zap.String("path", ps.ByName("path")), zap.String("server", s.Uuid), zap.Error(err))
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		http.Error(w, "failed to stat file", http.StatusInternalServerError)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	f, err := os.OpenFile(cleaned, os.O_RDONLY, 0)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if !os.IsNotExist(err) {
 | 
			
		||||
			zap.S().Errorw("failed to open file for reading", zap.String("path", ps.ByName("path")), zap.String("server", s.Uuid), zap.Error(err))
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		http.Error(w, "failed to open file", http.StatusInternalServerError)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	defer f.Close()
 | 
			
		||||
 | 
			
		||||
	// If a download parameter is included in the URL go ahead and attach the necessary headers
 | 
			
		||||
	// so that the file can be downloaded.
 | 
			
		||||
	if r.URL.Query().Get("download") != "" {
 | 
			
		||||
		w.Header().Set("Content-Disposition", "attachment; filename=" + st.Name())
 | 
			
		||||
		w.Header().Set("Content-Type", "application/octet-stream")
 | 
			
		||||
		w.Header().Set("Content-Length", strconv.Itoa(int(st.Size())))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bufio.NewReader(f).WriteTo(w)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Configures the router and all of the associated routes.
 | 
			
		||||
func (rt *Router) ConfigureRouter() *httprouter.Router {
 | 
			
		||||
	router := httprouter.New()
 | 
			
		||||
| 
						 | 
				
			
			@ -197,6 +240,7 @@ func (rt *Router) ConfigureRouter() *httprouter.Router {
 | 
			
		|||
	router.GET("/api/servers", rt.AuthenticateToken("i:servers", rt.routeAllServers))
 | 
			
		||||
	router.GET("/api/servers/:server", rt.AuthenticateToken("s:view", rt.AuthenticateServer(rt.routeServer)))
 | 
			
		||||
	router.GET("/api/servers/:server/logs", rt.AuthenticateToken("s:logs", rt.AuthenticateServer(rt.routeServerLogs)))
 | 
			
		||||
	router.GET("/api/servers/:server/files/*path", rt.AuthenticateToken("s:files", rt.AuthenticateServer(rt.routeServerFileRead)))
 | 
			
		||||
 | 
			
		||||
	router.POST("/api/servers/:server/power", rt.AuthenticateToken("s:power", rt.AuthenticateServer(rt.routeServerPower)))
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,8 +1,10 @@
 | 
			
		|||
package server
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"go.uber.org/zap"
 | 
			
		||||
	"io"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
| 
						 | 
				
			
			@ -167,4 +169,21 @@ func (fs *Filesystem) DirectorySize(dir string) (int64, error) {
 | 
			
		|||
	wg.Wait()
 | 
			
		||||
 | 
			
		||||
	return size, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Reads a file on the system and returns it as a byte representation in a file
 | 
			
		||||
// reader. This is not the most memory efficient usage since it will be reading the
 | 
			
		||||
// entirety of the file into memory.
 | 
			
		||||
func (fs *Filesystem) Readfile(p string) (io.Reader, error) {
 | 
			
		||||
	cleaned, err := fs.SafePath(p)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	b, err := ioutil.ReadFile(cleaned)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return bytes.NewReader(b), nil
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user