Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 18 additions & 8 deletions docs/files.md
Original file line number Diff line number Diff line change
Expand Up @@ -622,7 +622,8 @@ Hello world!
- 412 Precondition Failed, when the md5sum is `Content-MD5` is not equal to
the md5sum computed by the server
- 413 Payload Too Large, when there is not enough available space on the cozy
to upload the file
to upload the file or the file is larger than the server's filesystem maximum
file size
- 422 Unprocessable Entity, when the sent data is invalid (for example, the
parent doesn't exist, `Type` or `Name` parameter is missing or invalid,
etc.)
Expand Down Expand Up @@ -901,15 +902,21 @@ The `updated_at` field will be the first value in this list:
- the `Date` HTTP header
- the current time from the server.

/!\ If the `updated_at` field is older than the `created_at` one, then the
`updated_at` will be set with the value of the `created_at`.

#### Query-String

| Parameter | Description |
| ---------- | -------------------------------------------------- |
| Tags | an array of tags |
| Executable | `true` if the file is executable (UNIX permission) |
| Encrypted | `true` if the file is client-side encrypted |
| MetadataID | the identifier of a metadata object |
| UpdatedAt | the modification date of the file |
| Parameter | Description |
| ----------------------- | -------------------------------------------------------------- |
| Size | the file size (when `Content-Length` can't be used) |
| Tags | an array of tags |
| Executable | `true` if the file is executable (UNIX permission) |
| Encrypted | `true` if the file is client-side encrypted |
| MetadataID | the identifier of a metadata object |
| UpdatedAt | the modification date of the file |
| SourceAccount | the id of the source account used by a konnector |
| SourceAccountIdentifier | the unique identifier of the account targeted by the connector |

#### HTTP headers

Expand All @@ -935,6 +942,9 @@ HELLO WORLD!
- 404 Not Found, when the file wasn't existing
- 412 Precondition Failed, when the `If-Match` header is set and doesn't match
the last revision of the file
- 413 Payload Too Large, when there is not enough available space on the cozy
to upload the file or the file is larger than the server's filesystem maximum
file size

#### Response

Expand Down
2 changes: 1 addition & 1 deletion model/sharing/sharing.go
Original file line number Diff line number Diff line change
Expand Up @@ -1708,7 +1708,7 @@ func isFileTooBigForInstance(inst *instance.Instance, doc couchdb.JSONDoc) bool
}

_, _, _, err = vfs.CheckAvailableDiskSpace(inst.VFS(), file)
return errors.Is(err, vfs.ErrFileTooBig)
return errors.Is(err, vfs.ErrFileTooBig) || errors.Is(err, vfs.ErrMaxFileSize)
}

// wasUpdatedRecently returns true if the given document's latest update, given
Expand Down
2 changes: 2 additions & 0 deletions model/vfs/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ var (
ErrWrongCouchdbState = errors.New("Wrong couchdb reduce value")
// ErrFileTooBig is used when there is no more space left on the filesystem
ErrFileTooBig = errors.New("The file is too big and exceeds the disk quota")
// ErrMaxFileSize is used when a file is larger than the filesystem's maximum file size
ErrMaxFileSize = errors.New("The file is too big and exceeds the filesystem maximum file size")
// ErrFsckFailFast is used when the FSCK is stopped by the fail-fast option
ErrFsckFailFast = errors.New("FSCK has been stopped on first failure")
// ErrWrongToken is used when a key is not found on the store
Expand Down
2 changes: 1 addition & 1 deletion model/vfs/vfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -908,7 +908,7 @@ func CheckAvailableDiskSpace(fs VFS, doc *FileDoc) (newsize, maxsize, capsize in

maxsize = fs.MaxFileSize()
if maxsize > 0 && newsize > maxsize {
return 0, 0, 0, ErrFileTooBig
return 0, 0, 0, ErrMaxFileSize
}

diskQuota := fs.DiskQuota()
Expand Down
2 changes: 1 addition & 1 deletion model/vfs/vfs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -685,7 +685,7 @@ func TestVfs(t *testing.T) {
require.NoError(t, err)
_, _, _, err = vfs.CheckAvailableDiskSpace(fs, doc)
assert.Error(t, err)
assert.Equal(t, vfs.ErrFileTooBig, err)
assert.Equal(t, vfs.ErrMaxFileSize, err)
}
})
})
Expand Down
2 changes: 1 addition & 1 deletion web/files/files.go
Original file line number Diff line number Diff line change
Expand Up @@ -1946,7 +1946,7 @@ func wrapVfsError(err error) *jsonapi.Error {
case vfs.ErrFileInTrash, vfs.ErrNonAbsolutePath,
vfs.ErrDirNotEmpty:
return jsonapi.BadRequest(err)
case vfs.ErrFileTooBig:
case vfs.ErrFileTooBig, vfs.ErrMaxFileSize:
return jsonapi.Errorf(http.StatusRequestEntityTooLarge, "%s", err)
case vfs.ErrWrongToken:
return jsonapi.BadRequest(err)
Expand Down
25 changes: 25 additions & 0 deletions web/files/files_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"testing"
"time"

"github.com/cozy/cozy-stack/model/instance/lifecycle"
"github.com/cozy/cozy-stack/model/permission"
"github.com/cozy/cozy-stack/model/vfs"
"github.com/cozy/cozy-stack/pkg/config/config"
Expand Down Expand Up @@ -595,6 +596,30 @@ func TestFiles(t *testing.T) {
assert.Equal(t, "foo", string(buf))
})

t.Run("UploadExceedingQuota", func(t *testing.T) {
e := testutils.CreateTestClient(t, ts.URL)

lifecycle.Patch(testInstance, &lifecycle.Options{DiskQuota: 3})

e.POST("/files/").
WithQuery("Type", "file").
WithQuery("Name", "too-large").
WithQuery("Size", 3).
WithHeader("Content-Type", "text/plain").
WithHeader("Authorization", "Bearer "+token).
WithTransformer(func(r *http.Request) { r.ContentLength = -1 }).
WithBytes([]byte("baz")).
Expect().
Status(413).
Body().Contains(vfs.ErrFileTooBig.Error())

storage := testInstance.VFS()
_, err := readFile(storage, "/toolarge")
assert.Error(t, err)

lifecycle.Patch(testInstance, &lifecycle.Options{DiskQuota: -1})
})

t.Run("UploadImage", func(t *testing.T) {
e := testutils.CreateTestClient(t, ts.URL)

Expand Down
4 changes: 2 additions & 2 deletions web/notes/notes.go
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ func UploadImage(c echo.Context) error {
return jsonapi.InvalidParameter(echo.HeaderContentLength, err)
}
if size > note.MaxImageWeight {
return jsonapi.Errorf(http.StatusRequestEntityTooLarge, "%s", vfs.ErrFileTooBig)
return jsonapi.Errorf(http.StatusRequestEntityTooLarge, "%s", vfs.ErrMaxFileSize)
}
used, err := inst.VFS().FilesUsage()
if err != nil {
Expand Down Expand Up @@ -472,7 +472,7 @@ func wrapError(err error) *jsonapi.Error {
return jsonapi.Conflict(err)
case os.ErrNotExist, vfs.ErrParentDoesNotExist, vfs.ErrParentInTrash:
return jsonapi.NotFound(err)
case vfs.ErrFileTooBig:
case vfs.ErrFileTooBig, vfs.ErrMaxFileSize:
return jsonapi.Errorf(http.StatusRequestEntityTooLarge, "%s", err)
case sharing.ErrMemberNotFound:
return jsonapi.NotFound(err)
Expand Down
2 changes: 1 addition & 1 deletion web/sharings/sharings.go
Original file line number Diff line number Diff line change
Expand Up @@ -904,7 +904,7 @@ func wrapErrors(err error) error {
return jsonapi.PreconditionFailed("Content-Length", err)
case vfs.ErrConflict:
return jsonapi.Conflict(err)
case vfs.ErrFileTooBig:
case vfs.ErrFileTooBig, vfs.ErrMaxFileSize:
return jsonapi.Errorf(http.StatusRequestEntityTooLarge, "%s", err)
case permission.ErrExpiredToken:
return jsonapi.BadRequest(err)
Expand Down
2 changes: 1 addition & 1 deletion web/shortcuts/shortcuts.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ func wrapError(err error) *jsonapi.Error {
switch err {
case os.ErrNotExist, vfs.ErrParentDoesNotExist, vfs.ErrParentInTrash:
return jsonapi.NotFound(err)
case vfs.ErrFileTooBig:
case vfs.ErrFileTooBig, vfs.ErrMaxFileSize:
return jsonapi.Errorf(http.StatusRequestEntityTooLarge, "%s", err)
case shortcut.ErrInvalidShortcut:
return jsonapi.BadRequest(err)
Expand Down