-
Notifications
You must be signed in to change notification settings - Fork 386
Signed URL resumable upload support #640
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
Conversation
Forgot to mention another issue: right now I have signed URLs returned as strings. But if you use the SignedUrlUploader to obtain a session URI, that's returned as a Uri instance because that's what the base logic in ResumableUpload uses. It seemed a little strange to "upwrap" it to return a string and then wrap it in a Uri again when it is passed back to ResumableUpload. So I just want to get anyone's thoughts on whether it seems ok to leave it like this or if we should be consistent and use all strings or all Uris. I'm leaning to all Uris if we do want to be consistent. |
85787f5
to
85e36dc
Compare
(fixed the CI builds) |
Just a quick note - I'm not ignoring this; it's on my to-do list. I just have other more urgent things today. Will try to review tomorrow (or later today if it all works out). |
No rush |
Just to check, is the TmpMediaDownloader needed at all? I haven't spotted why it would be, but I could be missing something. I'm having trouble understanding the ResumableUpload differences at the moment, but I'll have another look at those when I'm more awake. |
The TmpMediaDownloader was just added to quiet some compiler errors if I recall. As for ResumableUpload, like I said its kind of hacked for now but essentially its split into a base and derived class and there are two virtual members now (overridden in |
85e36dc
to
94a4b78
Compare
Rebased and removed TmpMediaDownloader. It wasn't needed after all. |
Great. Will concentrate on just the signing bit then - thanks. |
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.
Okay, I've had a look now, mostly at the SignedUrlUploader part. I think I need a little more context. In particular, I can see two use cases here:
- My app wants to create a signed upload URL that another app can use to upload content.
- My app wants to use a signed upload URL provided by another app to upload content.
In each case, the "other app" may or may not be in .NET, using this client library.
With your choices you laid out in the first comment, it's not clear whether this is even feasible, as it sounds like there may not be any standardized way of constructing the signed URL.
The regular resumable uploader goes through a "get a session URI, then use it" process, doesn't it? Is there any reason we need to expose a different process here? I may well be missing something - it feels like we should be able to just introduce a virtual method for "get session URI" and override that (and only that) in SignedUrlUploader. (In an ideal world, the signed URL would contain everything required, and we wouldn't need any extra code for this, possibly after a small change to the ResumableUpload code to allow for extra information.)
It could be worth us having a VC, as I suspect I may be missing several subtleties.
public static async Task<SignedUrlUploader> CreateFromSignedUrlAsync( | ||
string signedUrl, | ||
Stream contentStream, | ||
ConfigurableHttpClient httpClient = null, |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
(VC might be best if this doesn't clear things up, and sorry for the 2nd wall of text)
So it looks like 1 is the only case I need to worry about here. However, due to my misunderstanding about 2, I have unintentionally created support for Y's side of things in the scenario described in the help there: X performs initial POST and sends session URI to Y. With this PR's code, Y can use As for your other points:
|
94a4b78
to
cefabbb
Compare
@jskeet PTAL. After offline discussion with you and Nathan, it looks like these are the scenarios to be supported. They involve authenticated app X communicating with unauthenticated app Y (possibly via Xc, an unauthenticated client of X). S is the signed URL to which a POST request can be made to initiate a resumable upload and U is the session URI for the upload session.
Also, I've moved everything pertinent to the review to the top of |
@evildour: I'm on vacation now until early January - I'll see what I can do anyway, but it may be in bits and pieces. |
Not a problem. In that case, I may start adding comments to the new APIs at some point. |
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.
Apologies if I'm being dense again - I'm hoping we can simplify this further.
|
||
private ResumableUploadSessionOptions Options { get; } | ||
|
||
private string SignedUrl { get; set; } |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Oh, and your other questions:
|
For the RESUMABLE method, that never goes into the signed URL. The URL is created as if you had used the POST method. "RESUMABLE" is just a sentinel value meaning 'please create a signed URL with the POST method and the x-goog-resumable header value of "start" (and all other info specified by the caller)'. I don't think there would be any conflict if we went with something else. The only issue would probably be potential user confusion. And I agree about string vs. Uri - let's wait until everything else is clearer. |
I'm now away from work for a week - will see if I can find 15 minutes to try to get my head back into this. We'll get there :) |
Not a problem. I'm a bit swamped with some other stuff anyway, so I probably won't have much time for this either until later next week or the week after. |
cefabbb
to
6a2841e
Compare
Okay, I think I now understand what's going on, and it's looking good. The tricky bit is understanding how much the existing ResumableUpload is changing due to this. Obviously we've gone back and forth via quite huge changes - is it now reasonably simple? I can see the addition of I think this is now the form we want... I'm sufficiently convinced that it would worth creating a PR on google-api-dotnet-client to make that diff clear, if that's feasible. Happy to have a VC to iron out any lingering doubts though. |
Yes, as far as what's changing in google-api-dotnet-client, its the addition of I'll try to put together a PR for google-api-dotnet-client later today or tomorrow so we can get this in. I'll also leave this PR open for now just in case that process reveals something we haven't thought of. Thanks! |
Now that there's been a new storage release, presumably this can be modified so it's releasable? |
Yes. About to push an update. Although I got a little confused with the visibility of MediaApiErrorHandling, forgetting that it was internal to Google.Apis. So I had to hack things a bit in the static |
6a2841e
to
30961c5
Compare
This is ready for submission now. PTAL. |
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.
A few comments, but generally I think we're there. Hooray :)
name, | ||
duration, | ||
UrlSigner.ResumableHttpMethod, | ||
requestHeaders: new Dictionary<string, IEnumerable<string>> { |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
return uploader.InitiateSessionAsync(cancellationToken); | ||
} | ||
|
||
private static T GetResult<T>(Func<CancellationToken, Task<T>> operation) |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
{ | ||
requestMethod = HttpMethod.Get; | ||
} | ||
else if (requestMethod.Equals(ResumableHttpMethod)) |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
ResumableUploadOptions options = null, | ||
CancellationToken cancellationToken = default(CancellationToken)) | ||
{ | ||
var uploader = new SignedUrlResumableUpload(signedUrl, new MemoryStream(), options); |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Thanks Jon! Will merge when green, unless you have additional comments. |
(It might help to read this section of docs for background)
The main thing needing review is the SignedUrlUploader class (which I'll comment and move to its own file if we decide to stick with it) and the way in which the user must create a the signed URL for the initial POST to kick off the resumable upload. I had a few choices here:
So I opted for 1, but I'm open to changing this.
Note that this requires a refactor of
ResumableUpload<TRequest>
, which I've split into a baseResumableUpload
class and derived class. So @chrisdunelm, I've added you in case you want to look at those changes. However, keep in mind the refactor is kind of hacked together for now, but if we agree on this, I'll make the changes to google-api-dotnet-client in a much cleaner way. Once that's merged and published, I'll send out the real PR for resumable upload support.