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

Usage of custom protocol scheme using WebView2 on a WinForms application (c#) #1825

Closed
bpassaro95 opened this issue Oct 13, 2021 · 40 comments
Closed
Labels
bug Something isn't working tracked We are tracking this work internally.

Comments

@bpassaro95
Copy link

bpassaro95 commented Oct 13, 2021

I'm developing a WinForms app, and trying to integrate the WebView2 control on it, and I'm having difficulties trying to access to local files on my computer using custom schemes.

I've managed to access those local files by catching before navigation the routes that use that custom scheme protocol ("my-files") and parsing them to use file:///.

The problem is that this only work to the .js or .html of the top level , but inside those files there are more calls to another files that use that custom scheme and I could not find the way to handle those.

Before the integration of WebView2 I've been using CefSharp, where I managed the custom schemes using the function RegisterScheme alongside with the CefCustomScheme data type. (Code Below)

settings.RegisterScheme(new CefCustomScheme
			{
				SchemeName = "my-files",
				IsLocal = true,
				IsFetchEnabled = true,
				SchemeHandlerFactory = new global::CefSharp.SchemeHandler.FolderSchemeHandlerFactory(
					rootFolder: Application.StartupPath
				)
			});

I've decided to migrate from CefSharp to WebView2 due to WebView2 being a control that has official support and documentation, thus improving the maintainability of the app.

But doing some research I didn't find a way to accomplish something similar to this on WebView2.

So, my question is, Is there a way to achieve this on WebView2?

Note: I've also tried to use the javascript funcion navigator.registerProtocolHandler(), but in order to use the custom scheme I have to change it, but it is something that I can't do.

The custom scheme is already defined and I have no control of the .html or .js that will be used.

AB#41390672

@champnic
Copy link
Member

Hey @bpassaro95 - Unfortunately there isn't a good way for you to do this yet. We are tracking adding some custom protocol support in #172/#173, and are hoping to start that work soon. We do have an API for creating a mapping between a domain and a local file folder: https://docs.microsoft.com/en-us/dotnet/api/microsoft.web.webview2.core.corewebview2.setvirtualhostnametofoldermapping?view=webview2-dotnet-1.0.992.28
But if you have no ability to change the html/js files then this won't really help you either. Sorry!

@bpassaro95
Copy link
Author

@champnic thanks for the insight!

I'm wondering if there's a roadmap you can share about when this capability will be implemented.

@champnic
Copy link
Member

We're hoping to start work on it soon, so it might be available around the end of the year or early 2022. Thanks!

@bpassaro95
Copy link
Author

@champnic how are you doing?

Do you have any updates on this?

Thanks.

@champnic
Copy link
Member

I'm going well :) We have the code in a draft PR right now, but it's rather complex. I don't have an accurate timeline for how much work is left to get it working and checked in.

@bpassaro95
Copy link
Author

@champnic how are you doing?

Sorry to bother you again but do you have any updates on this?

Thanks.

@champnic
Copy link
Member

@yildirimcagri is owning this experience and might be able to update status. Thanks!

@bpassaro95
Copy link
Author

@yildirimcagri how are you?

Do you have any updates you could share on this?

Thanks.

@yildirimcagri-msft
Copy link
Member

Hi, the CustomSchemeRegistration API for WebView2 will be released as experimental in the next prerelease SDK with Edge 105.

@bpassaro95
Copy link
Author

@yildirimcagri Thanks for the update!

@baseline808
Copy link

baseline808 commented Sep 8, 2022

@yildirimcagri I started playing with the Custom Scheme Registration functionality in WebView2 (1.0.1369-prerelease), and it seems to be working great for get requests but not post requests.

Am I doing something wrong or does the Custom Scheme Registration functionality not support post requests yet? My breakpoint in CoreWebView2_WebResourceRequested isn't getting hit when the html form is doing a post.

Thanks!

CSharpCodeSample
HTMLCodeSample

@bpassaro95
Copy link
Author

@yildirimcagri how are you?

I have a similar issue as @baseline808 , Im trying to use the new CustomSchemeRegistration Feature, but when trying to access resources through the custom scheme it still gives the Unknown URL Scheme Error on the Dev Tools Console.

Maybe Im doing something wrong or using the feature wrongly?

Down here is my code in case you manage to spot the error or the incorrect use/call.

Thanks!!

Code

private async void WebView2Browser_Load(object sender, EventArgs e)
		{
			
			CoreWebView2CustomSchemeRegistration customScheme = new CoreWebView2CustomSchemeRegistration("mycustomscheme");
			List<CoreWebView2CustomSchemeRegistration> customSchemes = new List<CoreWebView2CustomSchemeRegistration>();
			customSchemes.Add(customScheme);
			CoreWebView2EnvironmentOptions opts = new CoreWebView2EnvironmentOptions("--disable-web-security --allow-file-access-from-files --allow-file-access",null,null,false,customSchemes);
			var env = await CoreWebView2Environment.CreateAsync(options: opts);
			await m_Control.EnsureCoreWebView2Async(env);

@baseline808
Copy link

@bpassaro95 I noticed that you aren't calling CoreWebView2.AddWebResourceRequestedFilter in your code sample. Are you calling it somewhere else? I think you may need it in order for the custom scheme to take effect. That seems to be the main difference between your sample and mine. For me, it's working with "get" requests but not "post" requests.

@bpassaro95
Copy link
Author

@baseline808 thanks for the feedback, I did not have the Filter, just tried adding it to the code and still doesn't work.

@baseline808
Copy link

@bpassaro95 Ok, can you try calling the code which sets up the custom scheme & environment much sooner (e.g. before the WebView2 control is initialized)?

@yildirimcagri-msft
Copy link
Member

Hi @baseline808 , thanks for the report! We'll look into why custom scheme registration is not working for POST requests.

@yildirimcagri-msft yildirimcagri-msft added bug Something isn't working tracked We are tracking this work internally. labels Sep 19, 2022
@baseline808
Copy link

baseline808 commented Sep 22, 2022

@yildirimcagri

Thanks!

@darbid
Copy link

darbid commented Sep 23, 2022

Hi @yildirimcagri

I just wanted to check, this new CustomSchemeRegistration will not avoid CSP, right?

I tried adding a scheme so that I could add my own js and css files to a script element like this

(function addScript()
{   
    var scriptEl = document.createElement('script');
    scriptEl.type = 'text/javascript';
    scriptEl.src = 'mycustomscheme://myapp/resources/script.js';
    document.getElementsByTagName("head")[0].appendChild(scriptEl);
})()

but I get in the console these 2 things.

Refused to load the script 'mycustomscheme://myapp/resources/script.js' because it violates the following Content Security Policy directive: "script-src 'self' 'unsafe-inline' 'unsafe-eval'". Note that 'script-src-elem' was not explicitly set, so 'script-src' is used as a fallback.

Mixed Content: The page at 'https://XXXXX.XXXX.de/ipms/AppIpms.jsp' was loaded over HTTPS, but requested an insecure script 'mycustomscheme://myapp/resources/script.js'. This request has been blocked; the content must be served over HTTPS.

@yildirimcagri-msft
Copy link
Member

Hi @yildirimcagri

I just wanted to check, this new CustomSchemeRegistration will not avoid CSP, right?

I tried adding a scheme so that I could add my own js and css files to a script element like this

(function addScript()
{   
    var scriptEl = document.createElement('script');
    scriptEl.type = 'text/javascript';
    scriptEl.src = 'mycustomscheme://myapp/resources/script.js';
    document.getElementsByTagName("head")[0].appendChild(scriptEl);
})()

but I get in the console these 2 things.

Refused to load the script 'mycustomscheme://myapp/resources/script.js' because it violates the following Content Security Policy directive: "script-src 'self' 'unsafe-inline' 'unsafe-eval'". Note that 'script-src-elem' was not explicitly set, so 'script-src' is used as a fallback.

Mixed Content: The page at 'https://XXXXX.XXXX.de/ipms/AppIpms.jsp' was loaded over HTTPS, but requested an insecure script 'mycustomscheme://myapp/resources/script.js'. This request has been blocked; the content must be served over HTTPS.

That is correct, custom scheme URLs also abide by the CSP currently. For the second error, you can specify your custom scheme to be secure, which should prevent the mixed content error. Feel free to open a different issue if you'd like to make a feature request for custom schemes to be able to bypass CSP.

@bpassaro95
Copy link
Author

@baseline808 I tried calling the code way sooner but still having issues when trying to reach files using the custom scheme.

lets say my the custom url of the file I'm trying to reach is "mycustomscheme://./Scripts/Organization/Documents/bubblesort.js"

I've tried using the examples provided on the documentation https://learn.microsoft.com/en-us/dotnet/api/microsoft.web.webview2.core.corewebview2customschemeregistration?view=webview2-dotnet-1.0.1340-prerelease&preserve-view=true#examples using "mycustomscheme" or "mycustomscheme://" or "mycustomscheme://./" or any of the possible combinations I could think of in order to reach the file but none of them worked.

Maybe I'm missing something, or maybe I misunderstood the examples given on the documentation @yildirimcagri please correct me if that is the case.

Very much appreciated.

@bpassaro95
Copy link
Author

@yildirimcagri how are you doing?

Sorry to bother you with this but did you managed to see my previous comment?

I'm still trying to make the custom scheme registration work with the new features added but couldn't make it work so far.

Again sorry to bother you with this again.

Thank you.

@yildirimcagri-msft
Copy link
Member

Hi @bpassaro95 , sorry, I missed your previous question. After registering the custom scheme, are you using WebResourceRequested event to point the request with custom scheme to the local file that will serve the request, if so how?

@bpassaro95
Copy link
Author

@yildirimcagri yes I'm using the WebResourceRequested event to point the request.

This is how I'm using it:

private void CoreWebView2_WebResourceRequested(object sender, CoreWebView2WebResourceRequestedEventArgs e)
		{
			if (Uri.TryCreate(e.Request.Uri, UriKind.Absolute, out Uri reqUri))
			{
				if (reqUri.IsFile)
					SendFileAsResponse(reqUri.LocalPath, e);
				else if (reqUri.Scheme == "mycustomscheme")
				{
					string filePath = reqUri.LocalPath.Replace('/', '\\');
					if (reqUri.Host == "." && filePath.StartsWith("\\"))
						filePath = filePath.Substring(1);
					filePath = Path.Combine(Application.StartupPath, filePath);
					SendFileAsResponse(filePath, e);
				}
			}
		}

@yildirimcagri-msft
Copy link
Member

Are you not seeing any WebResourceRequested event firing? Do you see any console output in DevTools Window and the request with the custom scheme in Network tab?

@bpassaro95
Copy link
Author

I dont see the Event Being fired even though the event is attached to the control.

On the console the only thing I see is the failed to load resource error message

image

And on the network tab I don't see any call to the resources. Maybe that is related to the event not being called?

@yildirimcagri-msft
Copy link
Member

Hi @bpassaro95 , that error would mean the custom scheme was not registered properly. Is the sample code you shared above how you are registering the custom scheme and trying to access it? One issue I can see there, is that URL for the resource you are accessing is mycustomscheme://myapp/resources/script.js, which means your custom scheme has an authority component (myapp). Therefore, you would need to set the HasAuthorityComponent flag for the custom scheme registration. Also please ensure your runtime is 105+, which is when the functionality was released.

@baseline808
Copy link

baseline808 commented Dec 2, 2022

Hi @baseline808 , thanks for the report! We'll look into why custom scheme registration is not working for POST requests.

Hi @yildirimcagri, I just wanted to follow up on the custom scheme issue with POST requests. I am blocked until this is resolved. Thanks!

@yildirimcagri-msft
Copy link
Member

Hi @baseline808 , thanks for the report! We'll look into why custom scheme registration is not working for POST requests.

Hi @yildirimcagri, I just wanted to follow up on the custom scheme issue with POST requests. I am blocked until this is resolved. Thanks!

Hi again @baseline808 , This has been recently fixed and the fix is currently available in Edge Canary. Let me know if the fix works for you!

@baseline808
Copy link

Hi @baseline808 , thanks for the report! We'll look into why custom scheme registration is not working for POST requests.

Hi @yildirimcagri, I just wanted to follow up on the custom scheme issue with POST requests. I am blocked until this is resolved. Thanks!

Hi again @baseline808 , This has been recently fixed and the fix is currently available in Edge Canary. Let me know if the fix works for you!

Hi @yildirimcagri, I tried testing with WebView2 prelease 1.0.1466-prerelease and Edge Canary version 110.0.1544.0, and I am still seeing the issue. Is there a bug number by any chance or anywhere in the release notes where the bug would be mentioned? I'm wondering if maybe I need to wait for a new prerelease version of WebView2 to come out.

FYI, this is how I was wiring things up to test with the latest Edge Canary.

    async Task InitializeAsync()
    {
        var customSchemeRegistration = new CoreWebView2CustomSchemeRegistration("mycustomscheme");
        var customSchemeRegistrations = new List<CoreWebView2CustomSchemeRegistration>();
        customSchemeRegistrations.Add(customSchemeRegistration);

        CoreWebView2EnvironmentOptions options = new CoreWebView2EnvironmentOptions(null, null, null, false, customSchemeRegistrations);
        var environment = await CoreWebView2Environment.CreateAsync("C:\\Users\\<myuserId>\\AppData\\Local\\Microsoft\\Edge SXS\\Application\\110.0.1544.0",
        "C:\\Users\\<myUserId>\\AppData\\Local\\Microsoft\\Edge SXS\\User Data", options);
        await Browser1.EnsureCoreWebView2Async(environment);

        Browser1.CoreWebView2.AddWebResourceRequestedFilter("*", CoreWebView2WebResourceContext.All);
        Browser1.CoreWebView2.WebResourceRequested += CoreWebView2_WebResourceRequested;
        Browser1.CoreWebView2.NavigationStarting += CoreWebView2_NavigationStarting;
    }

Thanks for your help with this.

@bpassaro95
Copy link
Author

Hi @bpassaro95 , that error would mean the custom scheme was not registered properly. Is the sample code you shared above how you are registering the custom scheme and trying to access it? One issue I can see there, is that URL for the resource you are accessing is mycustomscheme://myapp/resources/script.js, which means your custom scheme has an authority component (myapp). Therefore, you would need to set the HasAuthorityComponent flag for the custom scheme registration. Also please ensure your runtime is 105+, which is when the functionality was released.

@yildirimcagri I tried the HasAuthorityComponent flag and it helped but it could not resolve completely my issues, I'm attaching my sample app with simple cases to test, the issue I'm still having is, when trying to call nested js inside the js I'm calling from the html using the custom-scheme it does not work not recognizing the second js.

I divided the sample into 3 cases in order to be easy to reproduce. The cases are incremental meaning that for each test a new grade of complexity to the html is added.

At first sight it seems to be a js issue with nested imports but I appreciate it if you could review it an see if indeed it is a js issue or it can be something webview2 related.

https://drive.google.com/file/d/1-UTDw-6M_1OJjAUIMwAjAQQjn8MtRZck/view?usp=share_link

Much appreciated.

@yildirimcagri-msft
Copy link
Member

Hi @baseline808 , thanks for the report! We'll look into why custom scheme registration is not working for POST requests.

Hi @yildirimcagri, I just wanted to follow up on the custom scheme issue with POST requests. I am blocked until this is resolved. Thanks!

Hi again @baseline808 , This has been recently fixed and the fix is currently available in Edge Canary. Let me know if the fix works for you!

Hi @yildirimcagri, I tried testing with WebView2 prelease 1.0.1466-prerelease and Edge Canary version 110.0.1544.0, and I am still seeing the issue. Is there a bug number by any chance or anywhere in the release notes where the bug would be mentioned? I'm wondering if maybe I need to wait for a new prerelease version of WebView2 to come out.

FYI, this is how I was wiring things up to test with the latest Edge Canary.

    async Task InitializeAsync()
    {
        var customSchemeRegistration = new CoreWebView2CustomSchemeRegistration("mycustomscheme");
        var customSchemeRegistrations = new List<CoreWebView2CustomSchemeRegistration>();
        customSchemeRegistrations.Add(customSchemeRegistration);

        CoreWebView2EnvironmentOptions options = new CoreWebView2EnvironmentOptions(null, null, null, false, customSchemeRegistrations);
        var environment = await CoreWebView2Environment.CreateAsync("C:\\Users\\<myuserId>\\AppData\\Local\\Microsoft\\Edge SXS\\Application\\110.0.1544.0",
        "C:\\Users\\<myUserId>\\AppData\\Local\\Microsoft\\Edge SXS\\User Data", options);
        await Browser1.EnsureCoreWebView2Async(environment);

        Browser1.CoreWebView2.AddWebResourceRequestedFilter("*", CoreWebView2WebResourceContext.All);
        Browser1.CoreWebView2.WebResourceRequested += CoreWebView2_WebResourceRequested;
        Browser1.CoreWebView2.NavigationStarting += CoreWebView2_NavigationStarting;
    }

Thanks for your help with this.

One issue I can see here, (which is a little subtle, but due to the web standard) is that for a POST request the origin header is included even if the request is from same origin. Since the origin that is used to make the request needs to be in the list of allowed origins even if the document is also from the same custom scheme, for a POST request that scheme needs to be one with authority component and include itself in allowed origins list.

@bpassaro95
Copy link
Author

bpassaro95 commented Dec 14, 2022

@yildirimcagri How are you?

Sorry to bother you again but I ran against some issue with this that seems to be a bug.
Managed to call nested js using custom schemes but a problem appeared when using fetch on those js, that fetch , that request does not invoke the WebResourceRequested Event , thus, not failing to work with the custom scheme registered.

image

I think this bug/issue was addressed on the issue #1114 , on the issue seemed to be corrected but at least for me is not working right.

Attached I sent you a new example window where this issue can be reproduced simply by executing and pressing the case 4 button.

FetchTestWebView2.zip

Thanks!!

@bpassaro95
Copy link
Author

@yildirimcagri How are you?

First of all merry Christmas, sorry to bother you , but did you manage to take a look at this?
Because it seems to be something that it is supposed to be working but its not working anymore or I am not using it the right way , and I would appreciate some feedback on this because this feature is blocking me for continuing with further development.

Much appreciated, sorry to bother you during these dates.

@yildirimcagri-msft
Copy link
Member

Hi @bpassaro95 , sorry for delayed reply, I'm currently on vacation. Do you have the WebResourceRequested filter for Fetch enabled? Otherwise, I can't think of anything else of top of my head, and I'll get back to you after new years.

@bpassaro95
Copy link
Author

@yildirimcagri

Thanks for answering during vacation, I really apreciated.

I currently have this on the filter

webView2.CoreWebView2.AddWebResourceRequestedFilter("*", CoreWebView2WebResourceContext.All, CoreWebView2WebResourceRequestSourceKinds.All);

So I think it should be working for fetch, I tried on browser and fetch seemed to be working, what it seems to be the problem is fetch on js.

There should be a particular WebResourceRequestedFilter for js calls?

Again much appreciated your answer during your vacation time, dont worry about the answer we could look at it when you return from vacation.

@bpassaro95
Copy link
Author

@yildirimcagri how are you?

I don't know if you are back from vacations but in case you are, did you manage to take a look at this?
Just to see if it is something wrong with my implementation or if it is a bug regarding this new feature of custom schemes with the request filter feature.

Thanks!

@yildirimcagri-msft
Copy link
Member

Hi @bpassaro95 , first of thanks for your patience and providing the sample for this issue. Looking at your sample, I can confirm we are not properly enabling custom schemes for Fetch requests. I've filed a separate bug and will keep you updated for when this is fixed.

@bpassaro95
Copy link
Author

bpassaro95 commented Feb 23, 2023

@yildirimcagri how are you?

Do you have any updates on this?

Thanks!

@yildirimcagri-msft
Copy link
Member

Hi @bpassaro95, I was about to get back to you on this! This is recently fixed, and the fix is available with Edge Canary runtime. You can verify by installing the latest Edge Canary and pointing the WEBVIEW2_BROWSER_EXECUTABLE_FOLDER environment variable to the Edge Canary installation directory. Let us know if this is working for you!

@champnic
Copy link
Member

champnic commented Mar 4, 2023

Fixed in runtimes 110.0.1531.0+. Thanks!

@champnic champnic closed this as completed Mar 4, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working tracked We are tracking this work internally.
Projects
None yet
Development

No branches or pull requests

5 participants