121 lines
2.6 KiB
Go
121 lines
2.6 KiB
Go
package view
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"local/dndex/config"
|
|
"local/dndex/storage"
|
|
"local/simpleserve/simpleserve"
|
|
"net/http"
|
|
"net/url"
|
|
"os"
|
|
"path"
|
|
"strings"
|
|
)
|
|
|
|
func files(_ storage.RateLimitedGraph, w http.ResponseWriter, r *http.Request) error {
|
|
namespace, err := getNamespace(r)
|
|
if err != nil {
|
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
|
return nil
|
|
}
|
|
r.URL.Path = strings.TrimPrefix(r.URL.Path, config.New().FilePrefix)
|
|
if len(strings.TrimPrefix("/"+namespace, r.URL.Path)) < 2 {
|
|
http.NotFound(w, r)
|
|
return nil
|
|
}
|
|
simpleserve.SetContentTypeIfMedia(w, r)
|
|
switch r.Method {
|
|
case http.MethodGet:
|
|
return filesGet(w, r)
|
|
case http.MethodPost:
|
|
return filesPost(w, r)
|
|
default:
|
|
http.NotFound(w, r)
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func filesGet(w http.ResponseWriter, r *http.Request) error {
|
|
http.ServeFile(w, r, toLocalPath(r.URL.Path))
|
|
return nil
|
|
}
|
|
|
|
func filesPost(w http.ResponseWriter, r *http.Request) error {
|
|
p := toLocalPath(r.URL.Path)
|
|
if err := os.MkdirAll(path.Dir(p), os.ModePerm); err != nil {
|
|
return err
|
|
}
|
|
switch r.URL.Query().Get("direct") {
|
|
case "true":
|
|
return filesPostFromDirectLink(w, r)
|
|
default:
|
|
return filesPostFromUpload(w, r)
|
|
}
|
|
}
|
|
|
|
func filesPostFromDirectLink(w http.ResponseWriter, r *http.Request) error {
|
|
b, err := ioutil.ReadAll(r.Body)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
url, err := url.Parse(string(b))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
resp, err := http.Get(url.String())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
return fmt.Errorf("bad status from direct: %v", resp.StatusCode)
|
|
}
|
|
|
|
path := toLocalPath(r.URL.Path)
|
|
f, err := os.Create(path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
_, err = io.Copy(f, resp.Body)
|
|
return err
|
|
}
|
|
|
|
func filesPostFromUpload(w http.ResponseWriter, r *http.Request) error {
|
|
p := toLocalPath(r.URL.Path)
|
|
if err := os.MkdirAll(path.Dir(p), os.ModePerm); err != nil {
|
|
return err
|
|
}
|
|
if fi, err := os.Stat(p); err != nil && !os.IsNotExist(err) {
|
|
return err
|
|
} else if err == nil && fi.IsDir() {
|
|
return errors.New("path is a directory")
|
|
}
|
|
f, err := os.Create(p)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
megabyte := 1 << 20
|
|
chunkSize := 10 * megabyte
|
|
r.ParseMultipartForm(int64(chunkSize))
|
|
file, _, err := r.FormFile("file")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer file.Close()
|
|
if _, err := io.Copy(f, file); err != nil {
|
|
return err
|
|
}
|
|
return json.NewEncoder(w).Encode(map[string]interface{}{"status": "ok"})
|
|
}
|
|
|
|
func toLocalPath(p string) string {
|
|
return path.Join(config.New().FileRoot, p)
|
|
}
|