-
Notifications
You must be signed in to change notification settings - Fork 361
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
support putifabsent #8428
base: master
Are you sure you want to change the base?
support putifabsent #8428
Changes from 23 commits
d92b29d
f18a67c
81de1fc
7d2a511
768ef8c
b07a5ab
c8a508c
81c8a79
5fc97da
1dd06fd
a635bb4
717f224
d558f57
150776e
d7e22f4
4b1533b
1528c90
08cc251
2873d3a
7e42c88
b46deb3
126144f
4a56ace
c4387d9
51d8105
6f2431a
047bd48
55a2d72
c620816
69764b1
0b2e2b4
8b4d12f
67da789
005f174
278a345
94ed11f
e7508d5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -2,6 +2,7 @@ | |||||
|
||||||
import ( | ||||||
"errors" | ||||||
"fmt" | ||||||
"net/http" | ||||||
"net/url" | ||||||
"strconv" | ||||||
|
@@ -20,6 +21,7 @@ | |||||
) | ||||||
|
||||||
const ( | ||||||
IfNoneMatchHeader = "If-None-Match" | ||||||
CopySourceHeader = "x-amz-copy-source" | ||||||
CopySourceRangeHeader = "x-amz-copy-source-range" | ||||||
QueryParamUploadID = "uploadId" | ||||||
|
@@ -30,7 +32,6 @@ | |||||
|
||||||
func (controller *PutObject) RequiredPermissions(req *http.Request, repoID, _, destPath string) (permissions.Node, error) { | ||||||
copySource := req.Header.Get(CopySourceHeader) | ||||||
|
||||||
if len(copySource) == 0 { | ||||||
return permissions.Node{ | ||||||
Permission: permissions.Permission{ | ||||||
|
@@ -298,6 +299,15 @@ | |||||
o.Incr("put_object", o.Principal, o.Repository.Name, o.Reference) | ||||||
storageClass := StorageClassFromHeader(req.Header) | ||||||
opts := block.PutOpts{StorageClass: storageClass} | ||||||
allowOverWrite, err := o.checkIfAbsent(req) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
if errors.Is(err, gatewayErrors.ErrPreconditionFailed) { | ||||||
_ = o.EncodeError(w, req, err, gatewayErrors.Codes.ToAPIErr(gatewayErrors.ErrPreconditionFailed)) | ||||||
return | ||||||
} | ||||||
if errors.Is(err, gatewayErrors.ErrNotImplemented) { | ||||||
_ = o.EncodeError(w, req, err, gatewayErrors.Codes.ToAPIErr(gatewayErrors.ErrNotImplemented)) | ||||||
return | ||||||
} | ||||||
address := o.PathProvider.NewPath() | ||||||
blob, err := upload.WriteBlob(req.Context(), o.BlockStore, o.Repository.StorageNamespace, address, req.Body, req.ContentLength, opts) | ||||||
if err != nil { | ||||||
|
@@ -309,7 +319,11 @@ | |||||
// write metadata | ||||||
metadata := amzMetaAsMetadata(req) | ||||||
contentType := req.Header.Get("Content-Type") | ||||||
err = o.finishUpload(req, &blob.CreationDate, blob.Checksum, blob.PhysicalAddress, blob.Size, true, metadata, contentType) | ||||||
err = o.finishUpload(req, &blob.CreationDate, blob.Checksum, blob.PhysicalAddress, blob.Size, true, metadata, contentType, allowOverWrite) | ||||||
if errors.Is(err, graveler.ErrPreconditionFailed) { | ||||||
_ = o.EncodeError(w, req, err, gatewayErrors.Codes.ToAPIErr(gatewayErrors.ErrPreconditionFailed)) | ||||||
return | ||||||
} | ||||||
if errors.Is(err, graveler.ErrWriteToProtectedBranch) { | ||||||
_ = o.EncodeError(w, req, err, gatewayErrors.Codes.ToAPIErr(gatewayErrors.ErrWriteToProtectedBranch)) | ||||||
return | ||||||
|
@@ -325,3 +339,26 @@ | |||||
o.SetHeader(w, "ETag", httputil.ETag(blob.Checksum)) | ||||||
w.WriteHeader(http.StatusOK) | ||||||
} | ||||||
|
||||||
func (o *PathOperation) checkIfAbsent(req *http.Request) (bool, error) { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I find this function confusing because:
Now that is confusing because it's a "lie" - it only's only partially checking ifAbsent as optimization, since the real check performed later and also does input validation. I would prefer something much more explicit like a function that extracts the header and validates it, then inline check if object exist: // checkIfAbsent sets allowOverwrite and validates the header value if set
allowOverwrite, err := o.checkIfAbsent(req)
if err != nil {
// ...
}
if !allowOverwrite {
// first check if object exist as optimization to save resources
_, err := o.Catalog.GetEntry(req.Context(), o.Repository.Name, o.Reference, o.Path, catalog.GetEntryParams{})
// hadle if err != nil ...
} |
||||||
for key, values := range req.Header { | ||||||
for _, value := range values { | ||||||
fmt.Printf("HEADER: %s = %s\n", key, value) | ||||||
|
||||||
} | ||||||
} | ||||||
Header := req.Header.Get(IfNoneMatchHeader) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
fmt.Println("HEADER: ", Header) | ||||||
if Header == "" { | ||||||
return true, nil | ||||||
} | ||||||
if Header == "*" { | ||||||
_, err := o.Catalog.GetEntry(req.Context(), o.Repository.Name, o.Reference, o.Path, catalog.GetEntryParams{}) | ||||||
if err == nil { | ||||||
return false, gatewayErrors.ErrPreconditionFailed | ||||||
} | ||||||
if !errors.Is(err, graveler.ErrNotFound) { | ||||||
return false, gatewayErrors.ErrInternalError | ||||||
} | ||||||
} | ||||||
return false, gatewayErrors.ErrNotImplemented | ||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For future generations, please add comment explaining this, something or exactly like this otherwise it's confusing, since this does not actually the verify core part, it's more optimization (since not atomicity here)