MicrosoftEdge / WebView2Feedback

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

Donwload pdf like attachment #1127

Open bagnos opened 3 years ago

bagnos commented 3 years ago

I have a webapp embedded in webview2 that download a pdf by window.open js istruction. The result is a new page over the app with pdf like attachment. Do you know any way to download pdf without opening this new page? The UX should be like in ms edge where pdf is visibile in the bottom of the browser and not in the second page.

AB#32437347

champnic commented 3 years ago

Hey @bagnos - could you share some of the code for how you are invoking window.open to download the PDF?

bagnos commented 3 years ago

the code is very simple, this window.open call a resource that download pdf like attachment file in a new window.

window.open('/WebHost/LTQ1MTY5Mzk1Nw');

I'd like to find a way to close this window and show the attachment file in the parent webview2, like all browser.

champnic commented 3 years ago

You just want it to navigate the existing WebView2 to the PDF? In the browser case, is it downloading and then opening the downloaded file (with "file://" protocol)? Or opening a new tab? If you have an example of the behavior you would like to replicate that would be helpful.

You can try handling the NewWindowRequested event and instead kickoff a navigation.

If you own the page that's calling window.open, you could try using the "_self" second parameter, or do a regular navigation instead of a window.open.

bagnos commented 3 years ago

You can write an html page with the code below, the url called in onclick button is a java servlet that download a txt file like attachment (es. Content-disposition", "attachment; filename=sample.txt")

Hola

When you click the button you can see the scenarios in msege and webview2 (see issue attachment), I need a way to open an attachment like ms edge scenario without to open a new window.

I would like to find a solution without having to change the application code.

[attachment.pdf](https://github.com/MicrosoftEdge/WebView2Feedback/files/6265774/attachment.pdf)

emimvi commented 3 years ago

I might be having a similar issue, if i understand correctly. i think the problem is that window.open(..) by default in chrome/edge chromium seems to open a new tab for a split second before detecting the Content-Disposition=attachment header, which then closes the tab and triggers a normal download.

This is nice because you're now on the exactly same page, and have the downloaded file accessible in the download drawer.

WebView2 opens a new window and then downloads the file, and now there's 2 issues compared to the browser behavior: 1) The new window stays open on an about:blank page. 2) The download drawer is opened in the new window, and not in the old one, so even if application code somehow manages to detect a download (perhaps using the newly proposed download api or custom code), the drawer will get lost as well. This seems to be because WebView2 does not support tabbing and thus won't be able to share the download drawer across several WebViews?

I've managed to make a workaround when the attachment header is specified, which is to intercept the new window request, manually requesting the uri using eg. HttpClient, detecting the header, and then simply .Navigate() directly to the uri, which will trigger a download, such that we stay on the same page, and have a download drawer open, exactly as in the browser.

It's not a very good workaround though, because the browser also handles downloads without the attachment header, i guess by mime sniffing or the like, so now the workaround needs to reimplement that entire sniffing logic, and keep it in sync in the future, to make sure that the .Navigate doesn't actually navigate, but instead downloads.

It would be nice to be able to have similar behavior as in the browser, eg. simply download non-browser-viewable files, and otherwise be able to manually do a fallback, eg continue opening the new webview, opening a browser or the like. Or maybe just be able to download and add a file to the drawer.

champnic commented 3 years ago

Glad you found a semi-workaround @emimvi! We do have a Downloads API that will be coming out soon, details here: https://github.com/MicrosoftEdge/WebView2Feedback/pull/1104/files?short_path=4950770#diff-49507708bcbcf26557279cf38a0dc688cf32374ba0aa65c383cab5aa6b5d11b5

darbid commented 3 years ago

@champnic I think I am facing a similar issue and am now also testing the Downloads API. I do not get a DownloadsStarting event for any pdfs. Is it correct to say that the browser by default attempts to show pdf files and that if we want a different action we need to implement it? Thus, as @emimvi has pointed out we will need to detect the content/mimetype as a pdf and then cancel the current action of showing the file in the browser.

If I am correct then this is my use case where a StartDownload method which accepts a URL (and uses all the current websites' headers) would be really handy. StartDownload is the method name from CefSharp and thus I assume CEF would natively support it too. I am pretty sure this feature request is here somewhere and if i find it I will comment in that issue too.

If webview2 had such a method then when a navigation takes place which is of type pdf then we could cancel it and point the url to a download. Currently I believe we would need to use some HTTPClient. The issue I am having is dynamically creating the same headers, especially cookies that the server is expecting.

wjvii commented 3 years ago

I am running into the same issue with pdfs, I need to download them vs view them. When I clicked on the link to the pdf it does trigger the NavigationStarting event but how do I then download that pdf instead of viewing it? Not as good an option for my use case, but if I must view it first, is there a way to get the pdf that is downloaded or an api where I can get control if they save the pdf?

For compliance reasons I must store certain pdfs and right now the process is labor intensive because you must save or view and save and then import, several steps instead of one if I could capture the initial click with the download api or download it from the NavigationStarting event.

ukandrewc commented 3 years ago

@champnic We would also want to see PDF through the download API.

@darbid I haven't had a chance to look at the Cookie API yet, so don't know if that provides all the cookies you need, but you can get all the cookies from DevTools Protocol with "Network.getAllCookies" or "Network.getCookies", Urls()

darbid commented 2 years ago

@champnic just circling back to this one to find out if there are any updates. I can make it a clear feature request in a new issue if you like.

The use case I am seeing is the following

My feeling is that CEF does it this way too as CEFSharp from memory behaved in a similar way.

Thus for PDFs if the user does not want the browser to display it we need to intercept the file as soon as possible and also catch the new window and then also still download the file.

In the case of CEFSharp it has a StartDownload https://cefsharp.github.io/api/63.0.0/html/M_CefSharp_IBrowserHost_StartDownload.htm function which accepts a uri, it proceeds to download the file without interfering with the current page open and does it with the current permissions (cookies etc) of the current browser. The advantage is that it can be done on the main browser object.

Would something like this be possible?

Other than effectively reproducing a download manager with cookies, headers etc and some HTTPCliet etc (ie. reinventing the wheel) is there any alternative?

Might there be some javascript we could call, giving it the url of the pdf which would fire a download but not navigate the user away from their current page?

champnic commented 2 years ago

Thanks for the suggestions @darbid - I've called them out explicitly in our tracking Scenario. No updates here yet - this isn't a high priority item for us at the moment.

darbid commented 2 years ago

I note that when a PDF is open there is a save/download button in the toolbar which downloads the PDF so you have an internal API to just "download" a pdf. Exposing this would be great.

darbid commented 1 year ago

@champnic I wanted to update the above as I have learnt why I "thought" webview2 was not downloading a PDF. I am dealing with one inTRAnet site and it always servers up PDFs in a new window with no Content-Disposition header which of course means the browser will display it.

This means my use case is to be able to easily download these pdfs with a "StartDownload" feature.

One additional note is that I would like to use WebView2's default page for AllDownloads, however this will not work for the above pdfs that I download with my own code, If there was the ability to do something like "StartDownload" forcing webview2 to download then it would appear also in the downloads page. Once again I see that if you save the pdf in the pdf viewer then that pdf is then listed in the edge://downloads/all page.

With respect to downloading the content I thought I would try to get it from the Response content to save me setting up a HTTPClient/Cookies etc but that does not seem to work. I consider it not really an issue for here so have posted it over in Stackoverflow Where is the PDF in a browser response, where Content-Type is application/pdf - WebView2](https://stackoverflow.com/questions/73673095/where-is-the-pdf-in-a-browser-response-where-content-type-is-application-pdf)

champnic commented 1 year ago

Thanks for the extra insight here!