-
-
Notifications
You must be signed in to change notification settings - Fork 4k
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
rc: Add operations/uploadfile to upload a file through rc using multipart/form-data #4221
Conversation
Interesting. I was actually considering doing this very thing in the httplib so that we could optionally upload files from the serve webdav/http templates. |
Will this be of help to you? |
@negative0 I believe so! When I have a chance i'm going to see what needs to be done on the http/webdav side but this may help me expedite that. Thanks! |
Nice @calisro . How to fix the failing race tests? |
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.
This looks interesting :-)
I've given it a very brief look over - comments inline.
Is a multipart form easiest from a browser?
From practically anything else a POST with parametesr fs=drive: remote=filename (the handler will already parse these) then put the file as the body of the request. That can then be streamed to Rcat without needing to be written to disk...
fs/operations/rc.go
Outdated
@@ -150,6 +154,7 @@ func init() { | |||
{name: "delete", title: "Remove files in the path", noRemote: true}, | |||
{name: "deletefile", title: "Remove the single file pointed to"}, | |||
{name: "copyurl", title: "Copy the URL to the object", help: "- url - string, URL to read from\n - autoFilename - boolean, set to true to retrieve destination file name from url"}, | |||
{name: "uploadfile", title: "Copy the file to path", help: "- url - string, URL to read from\n - autoFilename - boolean, set to true to retrieve destination file name from url"}, |
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.
I think this is the wrong help here?
fs/rc/rcserver/rcserver.go
Outdated
@@ -249,6 +249,24 @@ func (s *Server) handlePost(w http.ResponseWriter, r *http.Request, path string) | |||
} | |||
} | |||
|
|||
// Parse multipart/form-data (useful for file upload through rc) | |||
if contentType != "" && strings.HasPrefix(contentType, "multipart/form-data") { | |||
err := r.ParseMultipartForm(32 << 20) |
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.
32 MB might be too large here to store file in memory.
Apparently they will get stored on disk if they are bigger than this limit.
fs/operations/rc.go
Outdated
return nil, err | ||
} | ||
fs.Debugf(obj, "File upload success") | ||
return nil, CleanUp(ctx, f) |
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.
Don't think you wanted to Cleanup
here!
fs/rc/rcserver/rcserver.go
Outdated
return | ||
} | ||
|
||
for k, vs := range r.MultipartForm.Value { |
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.
I think I'd pass the whole MultipartForm on here as we need to call RemoveAll
on it at some point to remove temporary files if any.
So something like
in["multipartForm"] = r.MultipartForm
I believe it may be inefficient to use a application/x-www-form-urlencoded to POST it which is, I believe, the option you're talking about. It would work but for binary data, I believe, each non-alpha character gets encoded by the browser. Thats 3:1 for each. For text and small amounts of data its fine though. http://www.w3.org/TR/html401/interact/forms.html REf: 17.13.4 Form content types |
The problem with multipart uploads is they are quite difficult to stream (but not impossible - we do this in some of the rclone backends). The actual file data is sent as binary data so it is efficient, but there are mime markers bounding it Here is a really clear explanation of what actually gets sent: https://ec.haxx.se/http/http-multipart Doing a bit more reading I think we need to call the Request.MultipartReader which makes receiving multipart uploads as a stream easy on the server. So probably what we should do is put the entire http.Request into the input rc.Params and stream the input files to What do you think @negative0 ? |
@ncw, This is an interesting approach. I will try to do that. |
Should we add the request into the params only if it's a |
A good question... Maybe we should add the request in always with an I suggest you try it and see how many tests break! |
Interesting :-p |
What we should probably do is add a new flag here Lines 19 to 25 in 50e31c6
Called That should avoid the suprises! What do you think? |
The needs request code looks great :-) How are you at re-writing history? Can you re-arrange these commits into just two commits, so the first one is your needs request code and the second one is the upload file? |
I'll do that :-) |
Done :) |
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.
Code looks great now :-)
One minor nit inline.
Can can you change the first commit to be "rc: ..." as that is what you are changing rather than "uploadfile: ..."
Thanks!
@ncw This PR is ready to be merged! |
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.
The code looks great now :-)
How about doing a test?
The tests for these live in https://github.com/rclone/rclone/blob/master/fs/operations/rc_test.go
If you want I can merge this now as long as you promise me a test later!
I am not very good at writing tests. I will give it my best!. Expect updates this week. |
rc: Go import file rc_test.go
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.
Looks great now - nice test :-)
I'll merge it now - thank you!
Thank you :-) |
What is the purpose of this change?
Add functionality to upload a file to a remote using the rc.
This will allow a file to be uploaded directly through the web GUI.
May close #3412
Was the change discussed in an issue or in the forum before?
No
Checklist