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

rc: Add operations/uploadfile to upload a file through rc using multipart/form-data #4221

Merged
merged 3 commits into from
Jun 25, 2020

Conversation

negative0
Copy link
Member

@negative0 negative0 commented May 11, 2020

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

  • I have read the contribution guidelines.
  • I have added tests for all changes in this PR if appropriate.
  • I have added documentation for the changes if appropriate.
  • All commit messages are in house style.
  • I'm done, this Pull Request is ready for review :-)

@calisro
Copy link
Member

calisro commented May 11, 2020

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.

@negative0
Copy link
Member Author

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?

@calisro
Copy link
Member

calisro commented May 12, 2020

@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!

@negative0
Copy link
Member Author

Nice @calisro . How to fix the failing race tests?

Copy link
Member

@ncw ncw left a 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...

@@ -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"},
Copy link
Member

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?

@@ -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)
Copy link
Member

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.

return nil, err
}
fs.Debugf(obj, "File upload success")
return nil, CleanUp(ctx, f)
Copy link
Member

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!

return
}

for k, vs := range r.MultipartForm.Value {
Copy link
Member

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

@calisro
Copy link
Member

calisro commented May 14, 2020

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

@ncw
Copy link
Member

ncw commented May 15, 2020

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 operations.Rcat like this example.

What do you think @negative0 ?

@negative0
Copy link
Member Author

So probably what we should do is put the entire http.Request into the input rc.Params and stream the input files to operations.Rcat like this example.

@ncw, This is an interesting approach. I will try to do that.

@negative0
Copy link
Member Author

Should we add the request into the params only if it's a multipart/formdata or regardless?

@ncw
Copy link
Member

ncw commented May 19, 2020

Should we add the request into the params only if it's a multipart/formdata or regardless?

A good question...

Maybe we should add the request in always with an _request input? That will break some things to for example the core/echo which is used for testing...

I suggest you try it and see how many tests break!

@negative0
Copy link
Member Author

Interesting :-p

@ncw
Copy link
Member

ncw commented Jun 4, 2020

Interesting :-p

What we should probably do is add a new flag here

rclone/fs/rc/registry.go

Lines 19 to 25 in 50e31c6

type Call struct {
Path string // path to activate this RC
Fn Func `json:"-"` // function to call
Title string // help for the function
AuthRequired bool // if set then this call requires authorisation to be set
Help string // multi-line markdown formatted help
}

Called NeedsRequest and only add the _request parameter it on rc methods which have that set.

That should avoid the suprises!

What do you think?

@ncw
Copy link
Member

ncw commented Jun 5, 2020

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?

@negative0
Copy link
Member Author

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 :-)

@negative0
Copy link
Member Author

Done :)

Copy link
Member

@ncw ncw left a 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!

fs/rc/params.go Outdated Show resolved Hide resolved
@negative0
Copy link
Member Author

@ncw This PR is ready to be merged!

Copy link
Member

@ncw ncw left a 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!

@negative0
Copy link
Member Author

I am not very good at writing tests. I will give it my best!.

Expect updates this week.

@negative0 negative0 requested a review from ncw June 18, 2020 10:38
rc: Go import file rc_test.go
Copy link
Member

@ncw ncw left a 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!

@ncw ncw merged commit a2dd23e into rclone:master Jun 25, 2020
@negative0
Copy link
Member Author

Thank you :-)

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.

Upload files through the rc
3 participants