Skip to content
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

Pass contentLength to the worker #791

Merged
merged 5 commits into from
Dec 6, 2023

Conversation

mike76-dev
Copy link
Contributor

There is an unused contentLength field in s3.UploadPart. On the other hand, when a file is uploaded from the renterd UI, the Content-Length header is always set.
Unfortunately, when I try to set the Content-Length header in the API request to the worker, it gets stripped out (probably because of the encoding). For this reason, I set X-Content-Length, which can also be checked by the handler.

@peterjan
Copy link
Member

peterjan commented Dec 6, 2023

Hi @mike76-dev, thanks for your contribution, could you give a little more context to the PR, I don't really follow how or why it is useful and where we are using the Content-Length. If we do decide to add it I think we'd add it as an upload option rather than an extra parameter too by the way.

@mike76-dev
Copy link
Contributor Author

I'm encrypting the data in renterd before it goes over to the satellite. The satellite can store the file metadata, the partial slabs, the files uploaded by the renter pending uploading to the network, or the parts of a multipart upload. The additional encryption is important, because it prevents a malicious satellite operator from accessing the filenames or the contents of the files. The data is decrypted back either in renterd or in the dashboard of the satellite web portal, and only the renter has the encryption key.
Now, when parts of a multipart upload are uploaded to the satellite, it has to put them together and upload to the network. If each part was encrypted separately, it's not possible to decrypt back the complete file, because the offset of an individual part is unknown during upload to the satellite.
I've found a workaround where I want to prepend each part with its length and then encrypt using ChaCha20. This works, but I need to know the length of the piece of data to encrypt. It's not a problem with conventional single-part uploads, because the Content-Length header is usually set correctly. But I'm missing that with the multipart uploads.
If you are OK with that, I can rewrite the code to have the content length as an upload option.

@@ -194,6 +194,7 @@ func (c *Client) UploadMultipartUploadPart(ctx context.Context, r io.Reader, buc
panic(err)
}
req.SetBasicAuth("", c.c.WithContext(ctx).Password)
req.Header.Add("X-Content-Length", fmt.Sprintf("%d", contentLength))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Try setting req.ContentLength = contentLength instead. That way the Content-Length header will be set.
But contentLength should be part of opts and only be set if opts.ContentLength != 0.

It would also help us a lot if you did the same for PutObject in backend.go since that also seems to have a size that is currently not used.

Copy link
Member

@ChrisSchinnerl ChrisSchinnerl Dec 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want to go the extra mile you can extend the client methods to try and cast r.(io.Seeker) iff opts.ContentLength = 0 and then seek to the end and back to the beginning to determine the content length of the input. That would make sure that calling the client methods with an os.File or bytes.Reader will set the content length implicitly.

Copy link
Contributor Author

@mike76-dev mike76-dev Dec 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would make sure that calling the client methods with an os.File or bytes.Reader will set the content length implicitly.

So, no need to set req.ContentLength = <offset> in this case?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, in that case we don't set it and just use the seeker.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh sry I misunderstood your question. We still need to set the content length. Just not from the input but from the offset of the seeker.

Please also make sure to handle all errors

api/object.go Outdated
@@ -196,11 +196,13 @@ type (
ContractSet string
MimeType string
DisablePreshardingEncryption bool
Size int64
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Size int64
ContentLength int64

@ChrisSchinnerl
Copy link
Member

Thanks for the contribution!

@ChrisSchinnerl ChrisSchinnerl merged commit 23cb783 into SiaFoundation:master Dec 6, 2023
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants