MicrosoftEdge / WebView2Feedback

Feedback and discussions about Microsoft Edge WebView2
https://aka.ms/webview2
441 stars 52 forks source link

File Download API #419

Closed ukandrewc closed 3 years ago

ukandrewc commented 4 years ago

To be able to intercept and handle a file download, including blobs. Ideal scenario would be a BeforeFileDownload event that allows dev access to the downloaded file. Unless I've missed something and there is already a way to do that. Thanks

AB#27202431

ghost commented 4 years ago

@liminzhu : Waiting for the feature!!!

JoshuaWeber commented 4 years ago

Hi. I've started to spec out the solution to this. I'm still a bit unclear on what the use case is for this. If I could get more details from you it would help out.

I'm kind of curious why you describe this as tied to a download event. I'm assuming this is independent from just an app triggered http request. Is the trigger for behavior a user action (e.g. user clicks a link, that triggers a download). And you need to be involved in the flow?

ukandrewc commented 4 years ago

@JoshuaWeber Yes, you've got it ;-) Ideally this would include types that can be handled by Edge, such as PDF. I was basing this request on other web controls that don't trigger a navigation started event for downloads. I really need to check more of how WebView2 behaves with downloads, to be sure of what I'm asking for.

ghost commented 4 years ago

@JoshuaWeber I'm from SAP and we would like to use it in Excel as an embedded browser control for our OAuth2 workflow. However, we have 2 use-cases;

  1. disable all downloads (case for regular logon process)
  2. get notified when a file download is being started and then cancel it
    (start file download is the point that user has successfully authenticated himself on the browser, then we do not want the file download to happen, but (close the browser &) copy the cookies / XCSRF tokens and use them in HTTP WebRequests from .net)

Hope the above is clear enough..

ukandrewc commented 4 years ago

Same as @dhammika777 with added:

Need to control anything that would be considered a download, including blobs and content that can be displayed inside Edge, e.g. PDF.

I appreciate we can intercept most content, and download it ourselves inside NavigationStarting but this doesn't work for blob content.

Ideal Events would be DownloadStarting and DownloadCompleted. Similar to NavigationStarting/Completed, with options to see URI, change filepath, use default behaviour or Cancel and handle the download.

JoshuaWeber commented 4 years ago

Thanks for sharing this additional info. I think I understand the scenario. I'm going to see if I can put together a proposal to share out. Keep an eye out for it in the future.

ukandrewc commented 4 years ago

Great, thanks

wjvii commented 4 years ago

This sounds like something I am also extremely interested in. In our market we must conduct business a lot via website vs webapis and one thing we interact with constantly are files, usually pdfs, that are linked to via a webpage that must be downloaded and then uploaded into our database. Ideally what we want is to be able to do is iterate over all the links to pdfs on the page and within the hosted browser control download them all into our database vs having to download them one by one to disk and then re-upload them into our database. If that is not an option then I would like to be able to at least have the user click on the document and be able to provide a way for them to save it directly to the database. What is particularly important is that this happens in the security context of the browser that was established when we logged in because if not, the user will be denied access. This may be where the per document option might have to come into play, but let me decide what to do with the data, ideally let me get it in a stream or a byte array if not. Then my code can store it in the database vs saving it to disk.

Thank you very much for considering a feature to support this type of capability.

studylamp commented 4 years ago

They closed my (very similar) request, saying that http file downloading is outside of the scope of web controls. (Which is an odd thing to say, since every other web control I know of, including WebView, has it.)

https://github.com/MicrosoftEdge/WebViewFeedback/issues/302

ukandrewc commented 4 years ago

I think the difference is that you were asking for an API to use for downloading, whereas this is just asking for events to control existing downloads.

For your needs, did you know you can get the cookies using DevTools Protocol for using WebClient, etc. Or as MS suggested, use XHR to download your data, then you don't need to get the cookies?

studylamp commented 4 years ago

I think the difference is that you were asking for an API to use for downloading, whereas this is just asking for events to control existing downloads.

If they decide that distinction is relevant, and decide to implement it, that would be great. Then we could just navigate to download URLs and get the same outcome we need.

For your needs, did you know you can get the cookies using DevTools Protocol for using WebClient, etc. Or as MS suggested, use XHR to download your data, then you don't need to get the cookies?

Yes, both of these were considered. DevTools is not a good thing to rely on, especially since we disable DevTools in the browser to start with, and IIRC it can be disabled by policy? And relying on Javascript running in the browser to download large media files (potentially gigabytes) is not really a good option for us.

Anyway, I have a functioning workaround for all of it.

michael-russin commented 4 years ago

We would also find some hooks into the download file process helpful. The main reason would be to provide a custom UI for download/save/open options. Currently the WebVew2 will show the file download progress on the bottom the page which is nice but doesn't fit in with our existing application. Our users are used to a popup message with a message asking if they would like to save or open or cancel the file.

ukandrewc commented 4 years ago

@michael-russin We are the same, we need to offer the user the choice to import content from the browser, into our application. BTW there are DevTools Protocol Page events that can at least tell you when a file download has started and is complete.

JoshuaWeber commented 4 years ago

@studylamp I am thinking about these asks as different scenarios. With possibly different implementation / solutions.

1) is to interact with the user initiated download flow. For example the user clicking on a pdf link and the app performing extra work with the download. This is the work I'm currently investigating and specing out. 2) App generated downloads for a long running download (such that WebApis for download don't work because the user may navigate away from the page). I also think this is a valid scenario. It is also a proposed WebApi addition, or blog post. I'm also curious to understand the tradeoffs in your case about doing the long running download in the host app, instead of in the JS layer.

cbra-caa commented 3 years ago

Our current use case is that the WebView is acting as a preview component for a folder structure containing files. But if a file is broken, f.ex. an image which has been corrupted the WebView will start a download of this file instead of showing an error page. The same can be said for files that do not naturally have a preview, f.ex. a Zip-file.

What we would like to do is intercept the call and replace it with a navigation event to a page which explains the nature of the lack-of-preview.

Currently we can catch it on the backside via NavigationCompleted, as it will return that

CoreWebView2NavigationCompletedEventArgs.IsSuccess = false CoreWebView2NavigationCompletedEventArgs.CoreWebView2NavigationCompletedEventArgs = ConnectionAborted

but we would rather have something along the lines of what @ukandrewc posted (https://github.com/MicrosoftEdge/WebView2Feedback/issues/419#issuecomment-685656445)

dbuechel commented 3 years ago

We'd be interested in an API which would allow handling of uploads as well, not just downloads.

DineshSolanki commented 3 years ago

+1

alexisuk24 commented 3 years ago

Hi @JoshuaWeber, I have the following use case that would require the exposing of Upload/Download APIs (and some others currently available in CefSharp which appears to be where most developers are migrating from to WebView2).

We maintain a tool that monitors for captive portals on public Wi-Fi connections and facilitates a user to authenticate to these captive portals before forcing a VPN connection to be established. This tool is allow-listed in our host based firewall policy and we use hooks into the browser to prevent the user from using the tool to upload files, download files, copy/paste into and out of the browser. Currently WebView2 does not respect the AllowDrop WinForms property and therefore we cannot prevent drag/drop of a hyperlink lnk file or a drag/drop upload form. We also, cannot prevent File Open and File Save common dialogs that appear when a website requests an upload or provides a download.

Hopefully this use case clearly articulates why we would need WebView2 to additionally implement the following CefSharp events or equivilent:

ChromiumWebBrowser.MenuHandler (OnBeforeContextMenu, OnContextMenuCommand and RunContextMenu) ChromiumWebBrowser.KeyboardHandler (OnPreKeyEvent and OnKeyEvent) ChromiumWebBrowser.DialogHandler (OnFileDialog) ChromiumWebBrowser.DragHandler (OnDragEnter)

If you think this should be a separate feature request, happy to open a new issue.

JoshuaWeber commented 3 years ago

Thanks for all the engagement on this discussion everyone. It really does help us. We have been doing some investigation and design work to solve this scenario. And are planning to post a proposal for review soon.

JoshuaWeber commented 3 years ago

@alexisuk24 I think I understand your scenario, but I'd like to confirm. I think your root problem is you want to disable upload/download/copy/paste for your tool. Because WebView2 doesn't follow the WinForms AllowDrop property (I think you are disabling this property), drag and drop is acting as a escape from your limits on behavior. This download API may also act as a way to catch those escapes.

I do see the drag drop part as a bit independent. While not exactly your issue (it is just direct control instead of linking to WinForms) #278 is an issue asking to disable drag and drop. Perhaps that would also help in your scenario?

alexisuk24 commented 3 years ago

@JoshuaWeber yes, #278 covers my need to control (disable) drag/drop behavior, I would be satisfied with the AllowDrop=False fully disabling any drag/drop features in the WebView2 control, but CefSharp's DragHandler pattern works for us too and has more flexibility for others potentially

alexisuk24 commented 3 years ago

@JoshuaWeber yes, the root problem is that we want to prevent the WebView from facilitating:

or more simply put, any ways the user could use the embedded WebView2 to exfiltrate data or download content that wasn't explicitly typed into the control for the purposes of authenticating to a Wi-Fi hotspot with a captive portal

jasonstephen15 commented 3 years ago

@dbuechel - Thanks for your comment regarding the need to handle uploads. Just to better understand your use case, do you mind expanding on your app's scenario, and what you'd like out of an API to handle uploads? Would an API to disable uploads be enough?

dbuechel commented 3 years ago

@jasonstephen15 We are building the open-source lockdown software Safe Exam Browser which contains a configurable browser component currently built with CefSharp / CEF. The browser can be configured to e.g. permit or deny file downloads / uploads as well as whether a user may browse the entire file system or only a certain folder when down- or uploading. So the API should ideally provide the same functionality as CefSharp / CEF currently does:

Really awesome would be if there also were an API to control / monitor file uploads (e.g. something like an IUploadHandler which doesn't exist in CefSharp / CEF) to be able to e.g. show status info about file uploads to users.

jasonstephen15 commented 3 years ago

@dbuechel - Got it noted, thanks! As Josh mentioned above, the download api spec should be out sson!

jasonstephen15 commented 3 years ago

Hi all! We are working to release the custom download api spec soon for review - the api should include ways to disable downloads, expose download metadata, and more! Aside from the custom download api, we are also in the works of changing the download experience in response to the Browser's changes. Here is a quick overview post: https://github.com/MicrosoftEdge/WebView2Feedback/issues/797, would appreciate any feedback thanks!

jasonstephen15 commented 3 years ago

Hi all, thank you for your patience! We've completed our design for the Custom Download API! We would appreciate any feedback, please leave it in the PR above!

DineshSolanki commented 3 years ago

Hi all, thank you for your patience! We've completed our design for the Custom Download API! We would appreciate any feedback, please leave it in the PR above!

This looks good, when can we use it.

DineshSolanki commented 3 years ago

is there a way to allow multiple downloads programmatically, I hide the webview2 control while executing some scripts and the user can't click to allow multiple downloads.

darbid commented 3 years ago

Just looking at your proposal. Looks similar to the Chrome Extension API which makes sense you both have only what CEF gives you. I would therefore ask why you don't expose when the filename is resolved? Correct me if I am wrong but what do we show as the name of the file being downloaded in the UI?

soumas commented 3 years ago

I am about to replace the old WebBrowser with the new WebView2 control in a project. I miss the possibility to refuse any file download. Is there already a forecast when the Download API will be released? Thank you!

jasonstephen15 commented 3 years ago

Hi all, thank you for your patience! Our download API has finally reached our pre-release package and is ready to be tried out in an experimental state! Would love to hear any feedback!

https://docs.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2experimentaldownloadoperation?view=webview2-1.0.865-prerelease

https://docs.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2experimental2?view=webview2-1.0.865-prerelease#add_downloadstarting

soumas commented 3 years ago

Thanks for the good news, @JoshuaWeber! I can confirm that canceling downloads works as expected.

jarno9981 commented 3 years ago

@jasonstephen15 , @JoshuaWeber ( is there any example for c# download handler like documentation)

darbid commented 3 years ago

Have a look at the notes. Scroll down for C# https://github.com/MicrosoftEdge/WebView2Feedback/blob/bbffbe5fcad3f3c1e23a4b2f83fc9887c58e9625/specs/CustomDownload.md

jarno9981 commented 3 years ago

@darbid
Schermafbeelding 2021-04-30 191655

Few Issues Returning From Latest webview 2

jasonstephen15 commented 3 years ago

https://github.com/MicrosoftEdge/WebView2Feedback/blob/master/specs/CustomDownload.md

jasonstephen15 commented 3 years ago

Closing this issue as the API is now experimental, although feel free to continue feedback on this thread or open new issues! Thanks all.

wjvii commented 3 years ago

How do I handle the download of a pdf file? When I click on a pdf link in the webview2 control I need to save the pdf but it opens it in the webview2 control instead of triggering the download event. It does trigger the NavigationStarting event but how do I then download that pdf instead?

Thank you in advance.

MSE1188 commented 2 years ago

Same here. I am having a online pdf shown in the webview, but no download. I cannot use httpclient class for download, as the webview2 holds the cookies to access this pdf. How can I trigger the download automatically?

darbid commented 2 years ago

You can check what the site is sending and copy it, including cookies, but it really is just reinventing the wheel.

MSE1188 commented 2 years ago

Thanks, I found a workaround by passing the cookies to a httpclient and then run the download there. For anyone who is interested:

public async Task<Stream> Download(string url)
{
   var clientCookies = new CookieContainer();
   using (var handler = new HttpClientHandler() { CookieContainer = clientCookies })
   using(var client = new HttpClient(handler))
   {
      var cookies = await this.webview.CoreWebView2.CookieManager.GetCookiesAsync(url);
      foreach(var ck in cookies)
      {
         clientCookies.Add(ck.ToSystemNetCookie());
      }
      var response = await client.GetAsync(url);
      if(response.StatusCode != HttpStatusCode.OK)
      {
         throw new InvalidOperationException($"Downloading from url '{url}' failed with status code '{response.StatusCode}'.");
      }
      return await response.Content.ReadAsStreamAsync();
   }
}

However, would be really great, if I could simply start the download from the webview itself. The ChromiumWebBrowser (CefSharp) had a StartDownload extension for this. Something like this would be nice to have on CoreWebView2 :)