-
Notifications
You must be signed in to change notification settings - Fork 54
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
API for host objects for iframes #1122
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,275 @@ | ||||||
# Background | ||||||
Currently WebView2 supports adding host objects to script from client application | ||||||
and then later those objects can be accessed from the JavaScript of the top level frame | ||||||
using `window.chrome.webview.hostObjects.{name}`. | ||||||
Documentation can be found [here](https://docs.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2?view=webview2-1.0.705.50#addhostobjecttoscript). | ||||||
|
||||||
We were asked to support this feature in iframes including | ||||||
child frames that don't match the origin of the parent. In this document we describe API | ||||||
additions to support host objects in iframes. We'd appreciate your feedback. | ||||||
|
||||||
|
||||||
# Description | ||||||
The FrameCreated event is raised when an iframe is created and before starting any | ||||||
navigation and content loading. The FrameDeleted event is raised when an iframe is deleted | ||||||
or the document containing that iframe is destroyed. | ||||||
By providing event handler for frame created event, | ||||||
user can obtain the iframe and add host objects to it specifying the list of origins | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What happens if I use a malformed origin, like Is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Document and implement that less than an origin (scheme, host, port) or more than an origin, or just not any of those things will fail. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (with allowance for optional trailing slash) |
||||||
using `AddHostObjectToScriptWithOrigins` method. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I assume name collisions are resolved the same way as There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Update docs here and for AddHostObjectToScript how this works (or make it clearer if its already in the existing method docs). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What origins does
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Update docs for old method to say what equivalent is in new method There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I found the name There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For .NET & WinRT lets name this AddHostObjectToScript (like overload) and then in the ABI and in COM AddHostObjectToScriptWithAllowedOrigins. |
||||||
When script in the iframe tries to access a host object the origin of the iframe will be | ||||||
checked against the provided list. The Frame object has a Name property with the value of the | ||||||
name attribute from the iframe html tag declaring it. The NameChanged event is raised when | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is the principle of least surprise here? Meaning if I don't see that event (or somehow forget to hook it up) and now the frame has a new name... is that most likely to be a bug (possibly a security bug) or is it just some obscure edge-cases that care? Reason for asking: if it's more likely to be a (security) bug, then make the de-registration automatic and provide a way to opt-out of it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wouldn't removing the object when the name changes be closing the door after the horse has bolted? The page already got the object and could have uploaded your sensitive information to a secret server. Revoking access after the name changed won't delete your sensitive information from the secret server. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider doing something else with the name event in the sample. This is unrelated to normal web security practices. |
||||||
corresponding iframe changes its window.name property. | ||||||
|
||||||
The host object will be removed during iframe deletion automatically. | ||||||
|
||||||
|
||||||
# Examples | ||||||
## Frame created event, frame name changed event, adding and removing host object | ||||||
|
||||||
## .NET, WinRT | ||||||
```c# | ||||||
void SubscribeToFrameCreated() | ||||||
{ | ||||||
webView.CoreWebView2.FrameCreated += delegate (object sender, CoreWebView2FrameCreatedEventArgs args) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sample: adding lambdas as event handlers means you can't unregister them. It is better to have a specific method that you can unregister later (if needed). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Replace with ( ) => { } syntax rather than delegate () { } syntax. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You might not in this sample, but people might copy-paste and then have problems There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's true but that's a general principle of event handlers. This sounds like a suggestion that all sample code avoid lambda event handlers, but I think that's taking the issue too far. In samples and in my code I don't like the noise of a method for the typical case of a short handler that doesn't need to be unregistered. |
||||||
{ | ||||||
if (args.Frame.Name.Equals("iframe_name")) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe we decided that unnamed frames return There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That works, I think I got it backwards; in HSTRING there's no support for empty, but if you pass a null HSTRING to C# it projects as String.Empty. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||||
{ | ||||||
String[] origins = new String[] { "https://appassets.example" }; | ||||||
args.Frame.AddHostObjectToScriptWithOrigins("bridge", new BridgeAddRemoteObject(), origins); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do you need There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, see above |
||||||
} | ||||||
args.Frame.NameChanged += delegate (object nameChangedSender, object nameChangedArgs) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Any reason why the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use actual types instead of object. (Or just remove type names and use () => { } syntax) |
||||||
{ | ||||||
CoreWebView2Frame frame = (CoreWebView2Frame)nameChangedSender; | ||||||
if (!frame.Name.Equals("iframe_name")) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As noted earlier, this doesn't improve security since the page already got the bridge object under the old name. I think a more realistic example would be if (frame.Name.Equals("iframe_name"))
{
String[] origins = new String[] { "https://appassets.example" };
frame.AddHostObjectToScriptWithOrigins("bridge", new BridgeAddRemoteObject(), origins);
} where we deal with a frame that starts out nameless, but later changes its name, and then we recognize that it's the special frame and inject the object for it to use. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, like above we'll find a better sample for this. |
||||||
{ | ||||||
frame.RemoveHostObjectFromScript("bridge"); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will crash the second time the frame name changes, since "bridge" was already removed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Discussion: Should Remove not throw if the object doesn't exist? Silently ignore calling remove for something that doesn't exist? Makes it easier to write cleanup code. Result: Continue to throw. But update sample app and add comment explaining that Remove can throw in that case. |
||||||
} | ||||||
}; | ||||||
}; | ||||||
} | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How synchronous is the NameChanged event? If I want to inject an object when the name matches the special name, is injecting in the NameChanged handler sufficient to deal with this: // Set my name to the magic value that gives me access to the bridge
window.name = "iframe_name";
// Go get it!
var bridge = chrome.webview.hostObjects.bridge; // does this succeed?
var token = await bridge.GetToken(); // ask the bridge for a token or is there a race condition where the script needs to wait for the object to be injected // Set my name to the magic value that gives me access to the bridge
window.name = "iframe_name";
// Poll waiting for the bridge to show up
var check = async () => {
var bridge = chrome.webview.hostObjects.bridge;
if (!bridge) { setTimeout(check, 100); return; } // check again in 100ms
var token = await bridge.GetToken(); // finally we can ask the bridge for a token
};
check(); There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Additional point against adding host object to script based on name because name is async as mentioned. |
||||||
``` | ||||||
|
||||||
## Win32 C++ | ||||||
```cpp | ||||||
void SampleClass::SampleMethod() | ||||||
{ | ||||||
// Register a handler for the FrameCreated event. | ||||||
// This handler can be used to add host objects to the created iframe. | ||||||
CHECK_FAILURE(m_webView->add_FrameCreated( | ||||||
Callback<ICoreWebView2FrameCreatedEventHandler>( | ||||||
[this]( | ||||||
ICoreWebView2* sender, | ||||||
ICoreWebView2FrameCreatedEventArgs* args) -> HRESULT | ||||||
{ | ||||||
wil::com_ptr<ICoreWebView2Frame> webviewFrame; | ||||||
CHECK_FAILURE(args->get_Frame(&webviewFrame)); | ||||||
|
||||||
// Subscribe to frame name changed event and remove host object when name is changed | ||||||
webviewFrame->add_NameChanged( | ||||||
Callback<ICoreWebView2FrameNameChangedEventHandler>( | ||||||
[this](ICoreWebView2Frame* sender, | ||||||
IUnknown* args) -> HRESULT { | ||||||
LPWSTR newName; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this string need to be freed?
Suggested change
Similarly below. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes. Pls update |
||||||
CHECK_FAILURE(sender->get_Name(&newName)); | ||||||
if (std::wcscmp(newName, L"iframe_name") != 0) | ||||||
{ | ||||||
sender->RemoveHostObjectFromScript(L"sample"); | ||||||
} | ||||||
return S_OK; | ||||||
}).Get(), NULL); | ||||||
|
||||||
LPWSTR name; | ||||||
CHECK_FAILURE(webviewFrame->get_Name(&name)); | ||||||
if (std::wcscmp(name, L"iframe_name") == 0) | ||||||
{ | ||||||
// Wrap host object | ||||||
VARIANT remoteObjectAsVariant = {}; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. RAII type will auto-VariantClear the object at destruction.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes. Pls use this |
||||||
m_hostObject.query_to<IDispatch>(&remoteObjectAsVariant.pdispVal); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note that this will throw if m_hostObject fails the QI. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add a comment noting this and that its our object so should always succeed. |
||||||
remoteObjectAsVariant.vt = VT_DISPATCH; | ||||||
|
||||||
// Create list of origins which will be checked. | ||||||
// iframe will have access to host object only if its origin belongs | ||||||
// to this list. | ||||||
LPCWSTR origin = L"https://appassets.example/"; | ||||||
// Add host object to a script for iframe access | ||||||
CHECK_FAILURE( | ||||||
webviewFrame->AddHostObjectToScriptWithOrigins( | ||||||
L"sample", &remoteObjectAsVariant, 1, &origin)); | ||||||
|
||||||
remoteObjectAsVariant.pdispVal->Release(); | ||||||
} | ||||||
|
||||||
return S_OK; | ||||||
}).Get(), &m_frameCreatedToken)); | ||||||
} | ||||||
``` | ||||||
|
||||||
# API Notes | ||||||
See [API Details](#api-details) section below for API reference. | ||||||
|
||||||
# API Details | ||||||
## IDL | ||||||
```c# | ||||||
/// WebView2Frame provides direct access to the iframes information and use. | ||||||
[uuid(18ae830b-8c83-459f-8a8c-95a1022af774), object, pointer_default(unique)] | ||||||
interface ICoreWebView2Frame : IUnknown { | ||||||
/// The name of the iframe from the iframe html tag declaring it. | ||||||
/// Calling this method fails if it is called after the iframe is deleted. | ||||||
[propget] HRESULT Name([ out, retval ] LPWSTR * name); | ||||||
/// Raised when the iframe changes its window.name property | ||||||
HRESULT add_NameChanged( | ||||||
[in] ICoreWebView2FrameNameChangedEventHandler *eventHandler, | ||||||
[out] EventRegistrationToken * token); | ||||||
/// Remove an event handler previously added with add_NameChanged. | ||||||
HRESULT remove_NameChanged([in] EventRegistrationToken token); | ||||||
|
||||||
/// Add the provided host object to script running in the iframe with the | ||||||
/// specified name for the list of the specified origins. The host object | ||||||
/// will be accessible for this iframe only if the iframe's origin during | ||||||
/// access matches one of the origins which are passed. The provided origins | ||||||
/// will be normalized before comparing to the origin of the document. | ||||||
/// So the scheme name is made lower case, the host will be punycode decoded | ||||||
/// as appropriate, default port values will be removed, and so on. | ||||||
/// This means the origin's host may be punycode encoded or not and will match | ||||||
/// regardless. | ||||||
/// If the iframe is declared with no src attribute its origin is considered | ||||||
/// the same as the origin of the parent document. | ||||||
/// List of origins will be treated as following: | ||||||
/// 1. empty list - call will fail and no host object will be added for the | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Or should this successfully add an object that is visible to no one? Could be an edge case where somebody builds a vector of allowed origins, and wind up with no allowed origins, and now they have to catch the edge case here and bypass the call to avoid a crash. (Depending on the rules for how name collisions are resolved, it might be useful to create an object that is visible to no one, just so you can squat the name.) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure. Let's allow empty list for that reason (but still not null). And empty list means the object is not exposed to any origin |
||||||
/// iframe; | ||||||
/// 2. list with origins - during access to host object from iframe the | ||||||
/// origin will be checked that it belongs to this list; | ||||||
/// 3. list with "*" element - host object will be available for iframe for | ||||||
/// all origins. We suggest not to use this feature without understanding | ||||||
/// security implications of giving access to host object from from iframes | ||||||
/// with unknown origins. | ||||||
/// Calling this method fails if it is called after the iframe is deleted. | ||||||
/// \snippet ScenarioAddHostObject.cpp AddHostObjectToScriptWithOrigins | ||||||
/// For more information about host objects navigate to [AddHostObjectToScript] | ||||||
HRESULT AddHostObjectToScriptWithOrigins( | ||||||
[in] LPCWSTR name, | ||||||
[in] VARIANT *object, | ||||||
[in] UINT32 originsCount, | ||||||
[in, size_is(originsCount)] LPCWSTR* origins); | ||||||
/// Remove the host object specified by the name so that it is no longer | ||||||
/// accessible from JavaScript code in the iframe. While new access | ||||||
/// attempts are denied, if the object is already obtained by JavaScript code | ||||||
/// in the iframe, the JavaScript code continues to have access to that | ||||||
/// object. Calling this method for a name that is already removed or was never | ||||||
/// added fails. If the iframe is deleted this method will return fail also. | ||||||
HRESULT RemoveHostObjectFromScript([in] LPCWSTR name); | ||||||
|
||||||
/// The FrameDeleted event is raised when the iframe corresponding to this CoreWebView2Frame | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This event is already on the Frame object, so would this just be "Deleted"? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove 'Frame' prefix from the one on this runtimeclass (the created event still needs the prefix since its for a different runtimeclass) |
||||||
/// object is removed or the document containing that iframe is destroyed | ||||||
HRESULT add_FrameDeleted( | ||||||
[in] ICoreWebView2FrameDeletedEventHandler *eventHandler, | ||||||
[out] EventRegistrationToken * token); | ||||||
/// Remove an event handler previously added with add_FrameDeleted. | ||||||
HRESULT remove_FrameDeleted([in] EventRegistrationToken token); | ||||||
} | ||||||
|
||||||
[uuid(ae64d3bc-01ba-4769-a470-a1888de6d30b), object, pointer_default(unique)] | ||||||
interface ICoreWebView2 : IUnknown { | ||||||
/// Raised when a new iframe is created. Use the CoreWebView2Frame.add_FrameDeleted | ||||||
/// to listen for when this iframe goes away. | ||||||
HRESULT add_FrameCreated( | ||||||
[in] ICoreWebView2FrameCreatedEventHandler *eventHandler, | ||||||
[out] EventRegistrationToken * token); | ||||||
/// Remove an event handler previously added with add_FrameCreated. | ||||||
HRESULT remove_FrameCreated([in] EventRegistrationToken token); | ||||||
} | ||||||
|
||||||
[uuid(6c2d169c-7912-4332-a288-0aee1626759f), object, pointer_default(unique)] | ||||||
interface ICoreWebView2FrameCreatedEventHandler: IUnknown { | ||||||
/// Provides the result for the iframe created event | ||||||
HRESULT Invoke([in] ICoreWebView2 * sender, | ||||||
[in] ICoreWebView2FrameCreatedEventArgs * | ||||||
args); | ||||||
} | ||||||
|
||||||
// Event args for the iframe created events. | ||||||
[uuid(5fc1cd71-cd9a-4e8f-ab5f-2f134f941a3d), object, pointer_default(unique)] | ||||||
interface ICoreWebView2FrameCreatedEventArgs : IUnknown { | ||||||
/// The frame which was created. | ||||||
[propget] HRESULT Frame([ out, retval ] ICoreWebView2Frame **frame); | ||||||
} | ||||||
|
||||||
[uuid(8a1860c1-528f-4286-823c-23b0439340d2), object, pointer_default(unique)] | ||||||
interface ICoreWebView2FrameDeletedEventHandler: IUnknown { | ||||||
/// Provides the result for the iframe deleted event. | ||||||
/// No event args exist and the `args` parameter is set to `null`. | ||||||
HRESULT Invoke([in] ICoreWebView2Frame * sender, [in] IUnknown * args); | ||||||
} | ||||||
|
||||||
[uuid(cfd00c6a-8889-47de-84b2-3016d44dbaf4), object, pointer_default(unique)] | ||||||
interface ICoreWebView2FrameNameChangedEventHandler : IUnknown { | ||||||
/// Provides the result for the iframe name changed event. | ||||||
/// No event args exist and the `args` parameter is set to `null`. | ||||||
HRESULT Invoke([in] ICoreWebView2Frame * sender, [in] IUnknown * args); | ||||||
} | ||||||
``` | ||||||
## .NET and WinRT | ||||||
```c# | ||||||
namespace Microsoft.Web.WebView2.Core | ||||||
{ | ||||||
/// CoreWebView2Frame provides direct access to the iframes information and use. | ||||||
runtimeclass CoreWebView2Frame | ||||||
{ | ||||||
/// The name of the iframe from the iframe html tag declaring it. | ||||||
/// Calling this method fails if it is called after the iframe is deleted. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This can be a problem for code that posts work to the UI thread, since by the time the posted work runs, the frame may already be dead. webView.CoreWebView2.FrameCreated += async (s, e) =>
{
var bridge = await Bridge.CreateAsync(); // creating a bridge takes time
bridge.Server = GetServerFromFrameName(e.Frame.Name); // crash
e.Frame.AddHostObjectToScriptWithOrigins("bridge", bridge, trustedOrigins); // crash
}; There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We'll add a property IsDestroyed that works even after the frame is destroyed. Must be true during the destroyed event. Allow removing event handlers without throwing. |
||||||
String Name { get; }; | ||||||
|
||||||
/// Raised when the iframe changes its window.name property | ||||||
event Windows.Foundation.TypedEventHandler<CoreWebView2Frame, Object> NameChanged; | ||||||
/// The FrameDeleted event is raised when the iframe corresponding to this CoreWebView2Frame | ||||||
/// object is removed or the document containing that iframe is destroyed | ||||||
event Windows.Foundation.TypedEventHandler<CoreWebView2Frame, Object> FrameDeleted; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is the frame still valid during this event? E.g. can I access the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See above. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there a way to ask a frame, "Have you been deleted"? Or does the app have to keep its own Hash webView2.FrameCreated += (s, e) =>
{
activeFrames.Add(e.Frame);
e.Frame.FrameDeleted += (s, e) =>
{
activeFrames.Remove(s);
};
};
string TryGetFrameName(Frame frame)
{
if (activeFrames.Contains(frame)) return frame.Name;
return "";
}
void TryAddHostObjectToFrame(Frame frame, string name, object o)
{
if (activeFrames.Contains(frame)) return frame.AddHostObject(name, o);
return;
}
...etc for every member of Frame... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See above. |
||||||
|
||||||
/// Add the provided host object to script running in the iframe with the | ||||||
/// specified name for the list of the specified origins. The host object | ||||||
/// will be accessible for this iframe only if the iframe's origin during | ||||||
/// access matches one of the origins which are passed. The provided origins | ||||||
/// will be normalized before comparing to the origin of the document. | ||||||
/// So the scheme name is made lower case, the host will be punycode decoded | ||||||
/// as appropriate, default port values will be removed, and so on. | ||||||
/// This means the origin's host may be punycode encoded or not and will match | ||||||
/// regardless. | ||||||
/// If the iframe is declared with no src attribute its origin is considered | ||||||
/// the same as the origin of the parent document. | ||||||
/// List of origins will be treated as following: | ||||||
/// 1. empty list - call will fail and no host object will be added for the | ||||||
/// iframe; | ||||||
/// 2. list with origins - during access to host object from iframe the | ||||||
/// origin will be checked that it belongs to this list; | ||||||
/// 3. list with "*" element - host object will be available for iframe for | ||||||
/// all origins. We suggest not to use this feature without understanding | ||||||
/// security implications of giving access to host object from from iframes | ||||||
/// with unknown origins. | ||||||
/// Calling this method fails if it is called after the iframe is deleted. | ||||||
/// \snippet ScenarioAddHostObject.cpp AddHostObjectToScriptWithOrigins | ||||||
/// For more information about host objects navigate to [AddHostObjectToScript] | ||||||
void AddHostObjectToScriptWithOrigins(String name, Object rawObject, String[] origins); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||||
/// Remove the host object specified by the name so that it is no longer | ||||||
/// accessible from JavaScript code in the iframe. While new access | ||||||
/// attempts are denied, if the object is already obtained by JavaScript code | ||||||
/// in the iframe, the JavaScript code continues to have access to that | ||||||
/// object. Calling this method for a name that is already removed or was never | ||||||
/// added fails. If the iframe is deleted this method will return fail also. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What does "fail" mean? It should be a no-op to delete something that was never there, for example (not an exception). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. see above |
||||||
void RemoveHostObjectFromScript(String name); | ||||||
} | ||||||
|
||||||
runtimeclass CoreWebView2 | ||||||
{ | ||||||
//.. | ||||||
/// Raised when a new iframe is created. Use the CoreWebView2Frame.FrameDeleted event to | ||||||
/// listen for when this iframe goes away. | ||||||
event Windows.Foundation.TypedEventHandler<CoreWebView2, CoreWebView2FrameCreatedEventArgs> FrameCreated; | ||||||
} | ||||||
runtimeclass CoreWebView2FrameCreatedEventArgs | ||||||
{ | ||||||
/// The frame which was created. | ||||||
CoreWebView2Frame Frame { get; }; | ||||||
} | ||||||
} | ||||||
``` |
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.
I'm guessing that a "deleted" frame is one that has been removed from the document, but may not have been destroyed. Is there a FrameAdded event that lets me know when it has been added back to the document? Right now, there seems to be a mismatch in event pairing.
Another way of looking at it is with a frame lifetime diagram:
but we are told only about Created and Deleted. So if we create some tracking object in Created, we might leak it if it never got Added. And if a frame is Deleted, we can prematurely destroy the tracking object if the frame is subsequently Added back.
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.
Let's use Created and Destroyed for naming based on conversation.