mirror of
https://github.com/1f349/site-hosting.git
synced 2024-11-09 22:42:58 +00:00
86 lines
1.9 KiB
Go
86 lines
1.9 KiB
Go
package upload
|
|
|
|
import (
|
|
"archive/tar"
|
|
"compress/gzip"
|
|
"fmt"
|
|
"github.com/julienschmidt/httprouter"
|
|
"github.com/spf13/afero"
|
|
"io"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
)
|
|
|
|
func New(storagePath string) *Handler {
|
|
fs := afero.NewBasePathFs(afero.NewOsFs(), storagePath)
|
|
return &Handler{fs}
|
|
}
|
|
|
|
type Handler struct {
|
|
storageFs afero.Fs
|
|
}
|
|
|
|
func (h *Handler) Handle(rw http.ResponseWriter, req *http.Request, params httprouter.Params) {
|
|
site := params.ByName("site")
|
|
branch := req.URL.Query().Get("branch")
|
|
|
|
fileData, fileHeader, err := req.FormFile("upload")
|
|
if err != nil {
|
|
http.Error(rw, "Missing file upload", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
// if file is bigger than 1GiB
|
|
if fileHeader.Size > 1074000000 {
|
|
http.Error(rw, "File too big", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
err = h.extractTarGzUpload(fileData, site, branch)
|
|
if err != nil {
|
|
http.Error(rw, fmt.Sprintf("Invalid upload: %s", err), http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
rw.WriteHeader(http.StatusAccepted)
|
|
}
|
|
|
|
func (h *Handler) extractTarGzUpload(fileData io.Reader, site, branch string) error {
|
|
storeFs := afero.NewBasePathFs(h.storageFs, filepath.Join(site, branch))
|
|
|
|
// decompress gzip wrapper
|
|
gzipReader, err := gzip.NewReader(fileData)
|
|
if err != nil {
|
|
return fmt.Errorf("invalid gzip file: %w", err)
|
|
}
|
|
|
|
// parse tar encoding
|
|
tarReader := tar.NewReader(gzipReader)
|
|
for {
|
|
next, err := tarReader.Next()
|
|
if err == io.EOF {
|
|
break
|
|
}
|
|
if err != nil {
|
|
return fmt.Errorf("invalid tar archive: %w", err)
|
|
}
|
|
|
|
err = storeFs.MkdirAll(filepath.Dir(next.Name), os.ModePerm)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to make directory tree: %w", err)
|
|
}
|
|
|
|
create, err := storeFs.Create(next.Name)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create output file: '%s': %w", next.Name, err)
|
|
}
|
|
|
|
_, err = io.Copy(create, tarReader)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to copy from archive to output file: '%s': %w", next.Name, err)
|
|
}
|
|
}
|
|
return nil
|
|
}
|