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.Graph, 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, path.Join(config.New().FilePrefix, namespace)) if len(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, io.LimitReader(resp.Body, config.New().MaxFileSize)) 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, io.LimitReader(file, config.New().MaxFileSize)); 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) }