func (c *controller) ListTree(user *entities.User, pathSpec string) ([]*entities.ObjectInfo, error) { storagePath := c.getStoragePath(user, pathSpec) finfo, err := os.Stat(storagePath) if err != nil { if os.IsNotExist(err) { return nil, codes.NewErr(codes.NotFound, err.Error()) } return nil, err } if !finfo.IsDir() { return nil, codes.NewErr(codes.BadInputData, "object is not a tree") } fd, err := os.Open(storagePath) if err != nil { if os.IsNotExist(err) { return nil, codes.NewErr(codes.NotFound, err.Error()) } return nil, err } finfos, err := fd.Readdir(-1) // read all files inside the directory. if err != nil { return nil, err } var oinfos []*entities.ObjectInfo for _, fi := range finfos { p := filepath.Join(pathSpec, filepath.Base(fi.Name())) oinfos = append(oinfos, c.getObjectInfo(p, fi)) } return oinfos, nil }
// UploadBLOB saves a blob to disk. // This operation has 4 phases: // 1) Write the blob to a temporary directory. // 2) Optional: calculate the checksum of the blob if server-checksum is enabled. // 3) Optional: if a client-checksum is provided, check if it matches with the server-checksum. // 4) Move the blob from the temporary directory to user directory. func (c *controller) UploadBLOB(user *entities.User, pathSpec string, r io.Reader, clientchecksum string) error { tempFileName, err := c.saveToTempFile(r) if err != nil { return err } // 2) Optional: calculate the checksum of the blob. if c.conf.GetDirectives().Data.Simple.Checksum != "" { serverchecksum, err := c.computeChecksum(tempFileName) if err != nil { return err } // 3) Optional: verify if server-checksum matches client-checksum. if c.conf.GetDirectives().Data.Simple.VerifyClientChecksum { if serverchecksum != clientchecksum { msg := fmt.Sprintf("checksums differ. serverchksum:%q clientchksum:%q", serverchecksum, clientchecksum) return codes.NewErr(codes.BadChecksum, msg) } } } // 4) Move the blob from the temporary directory to user directory. storagePath := c.getStoragePath(user, pathSpec) if err := os.Rename(tempFileName, storagePath); err != nil { if os.IsNotExist(err) { return codes.NewErr(codes.NotFound, err.Error()) } return err } return c.metaDataController.SetDBMetaData(c.metaDataController.GetVirtualPath(user, pathSpec), clientchecksum, c.metaDataController.GetVirtualPath(user, "/")) }
func (c *controller) MoveObject(user *entities.User, sourcePathSpec, targetPathSpec string) error { sourceStoragePath := c.getStoragePath(user, sourcePathSpec) targetStoragePath := c.getStoragePath(user, targetPathSpec) err := os.Rename(sourceStoragePath, targetStoragePath) if err != nil { if os.IsNotExist(err) { return codes.NewErr(codes.NotFound, err.Error()) } else if _, ok := err.(*os.LinkError); ok { return codes.NewErr(codes.BadInputData, err.Error()) } return err } return nil }
// Authenticate authenticates an user using an username and a password. func (s *svc) Token(w http.ResponseWriter, r *http.Request) { log := keys.MustGetLog(r) if r.Body == nil { log.WithError(errors.New("body is nil")).Info("cannot read body") w.WriteHeader(http.StatusInternalServerError) return } authReq := &TokenRequest{} if err := json.NewDecoder(r.Body).Decode(authReq); err != nil { e := codes.NewErr(codes.BadInputData, "") log.WithError(e).Error(codes.BadInputData.String()) w.WriteHeader(http.StatusBadRequest) if err := json.NewEncoder(w).Encode(e); err != nil { log.WithError(err).Error("cannot encode") } return } token, err := s.authenticationController.Authenticate(authReq.Username, authReq.Password) if err != nil { s.handleTokenError(err, w, r) return } log.WithField("user", authReq.Username).Info("token generated") res := &TokenResponse{AccessToken: token} w.WriteHeader(http.StatusCreated) if err := json.NewEncoder(w).Encode(res); err != nil { log.WithError(err).Error("cannot encode") } }
func (s *svc) handleTokenError(err error, w http.ResponseWriter, r *http.Request) { log := keys.MustGetLog(r) e := codes.NewErr(codes.BadInputData, "user or password do not match") log.WithError(e).Error(codes.BadInputData.String()) w.WriteHeader(http.StatusBadRequest) if err := json.NewEncoder(w).Encode(e); err != nil { log.WithError(err).Error("cannot encode") } return }
func (c *controller) DownloadBLOB(user *entities.User, pathSpec string) (io.Reader, error) { storagePath := c.getStoragePath(user, pathSpec) fd, err := os.Open(storagePath) if err != nil { if os.IsNotExist(err) { return nil, codes.NewErr(codes.NotFound, err.Error()) } return nil, err } return fd, nil }
func (c *controller) ExamineObject(user *entities.User, pathSpec string) (*entities.ObjectInfo, error) { storagePath := c.getStoragePath(user, pathSpec) finfo, err := os.Stat(storagePath) if err != nil { if os.IsNotExist(err) { return nil, codes.NewErr(codes.NotFound, err.Error()) } return nil, err } oinfo := c.getObjectInfo(pathSpec, finfo) return oinfo, nil }
func TestMove_withError(t *testing.T) { dirs := defaultDirs o := newObject(t) o.setupService(t, &dirs) o.mockMetaDataController.On("MoveObject").Once().Return(codes.NewErr(99, "")) r, err := http.NewRequest("POST", moveURL+"tree", nil) require.Nil(t, err) w := httptest.NewRecorder() o.wrapAuthenticatedRequest(w, r, http.HandlerFunc(o.service.MoveObject)) require.Equal(t, http.StatusInternalServerError, w.Code) }
func TestListTree_withBadInputError(t *testing.T) { dirs := defaultDirs o := newObject(t) o.setupService(t, &dirs) o.mockMetaDataController.On("ListTree").Once().Return(oinfos, codes.NewErr(codes.BadInputData, "")) r, err := http.NewRequest("GET", listURL+"tree", nil) require.Nil(t, err) w := httptest.NewRecorder() o.wrapAuthenticatedRequest(w, r, http.HandlerFunc(o.service.ListTree)) require.Equal(t, http.StatusBadRequest, w.Code) }
func TestUpload_withError(t *testing.T) { dirs := defaultDirs o := newObject(t) o.setupService(t, &dirs) reader := strings.NewReader("1") o.mockDataController.On("UploadBLOB").Return(codes.NewErr(99, "")) r, err := http.NewRequest("PUT", uploadURL+"myblob", reader) require.Nil(t, err) w := httptest.NewRecorder() o.wrapAuthenticatedRequest(w, r, http.HandlerFunc(o.service.Upload)) require.Equal(t, http.StatusInternalServerError, w.Code) }
func TestDownload_withNotFoundError(t *testing.T) { dirs := defaultDirs o := newObject(t) o.setupService(t, &dirs) reader := strings.NewReader("1") o.mockDataController.On("DownloadBLOB").Return(reader, codes.NewErr(codes.NotFound, "")) r, err := http.NewRequest("GET", downloadURL+"myblob", nil) require.Nil(t, err) w := httptest.NewRecorder() o.wrapAuthenticatedRequest(w, r, http.HandlerFunc(o.service.Download)) require.Equal(t, http.StatusNotFound, w.Code) }
// ExamineObject returns the metadata associated with the object. func (c *Controller) ExamineObject(user *entities.User, pathSpec string) (*entities.ObjectInfo, error) { storagePath := c.getStoragePath(user, pathSpec) finfo, err := os.Stat(storagePath) if err != nil { if os.IsNotExist(err) { return nil, codes.NewErr(codes.NotFound, err.Error()) } return nil, err } rec, err := c.GetDBMetaData(c.GetVirtualPath(user, pathSpec), true, c.GetVirtualPath(user, "/")) if err != nil { return nil, err } oinfo := c.getObjectInfo(pathSpec, finfo, rec) return oinfo, nil }