mirror of
git://source.winehq.org/git/wine.git
synced 2024-09-01 17:03:39 +00:00
mshtml: Send StorageEvents to iframe windows properly.
Signed-off-by: Gabriel Ivăncescu <gabrielopcode@gmail.com>
This commit is contained in:
parent
e64ab65a5e
commit
2297623f01
|
@ -197,6 +197,8 @@ static inline HTMLStorage *impl_from_IHTMLStorage(IHTMLStorage *iface)
|
|||
return CONTAINING_RECORD(iface, HTMLStorage, IHTMLStorage_iface);
|
||||
}
|
||||
|
||||
static HRESULT build_session_origin(IUri*,BSTR,BSTR*);
|
||||
|
||||
struct storage_event_task {
|
||||
task_t header;
|
||||
HTMLInnerWindow *window;
|
||||
|
@ -226,22 +228,22 @@ static void storage_event_destr(task_t *_task)
|
|||
IHTMLWindow2_Release(&task->window->base.IHTMLWindow2_iface);
|
||||
}
|
||||
|
||||
/* Takes ownership of old_value */
|
||||
static HRESULT send_storage_event(HTMLStorage *storage, BSTR key, BSTR old_value, BSTR new_value)
|
||||
struct send_storage_event_ctx {
|
||||
HTMLInnerWindow *skip_window;
|
||||
const WCHAR *origin;
|
||||
UINT origin_len;
|
||||
BSTR key;
|
||||
BSTR old_value;
|
||||
BSTR new_value;
|
||||
};
|
||||
|
||||
static HRESULT push_storage_event_task(struct send_storage_event_ctx *ctx, HTMLInnerWindow *window, BOOL commit)
|
||||
{
|
||||
HTMLInnerWindow *window = storage->window;
|
||||
BOOL local = !!storage->filename;
|
||||
struct storage_event_task *task;
|
||||
DOMEvent *event;
|
||||
HRESULT hres;
|
||||
|
||||
if(!window) {
|
||||
SysFreeString(old_value);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
hres = create_storage_event(window->doc, key, old_value, new_value, local, &event);
|
||||
SysFreeString(old_value);
|
||||
hres = create_storage_event(window->doc, ctx->key, ctx->old_value, ctx->new_value, commit, &event);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
|
@ -256,6 +258,102 @@ static HRESULT send_storage_event(HTMLStorage *storage, BSTR key, BSTR old_value
|
|||
return push_task(&task->header, storage_event_proc, storage_event_destr, window->task_magic);
|
||||
}
|
||||
|
||||
static HRESULT send_storage_event_impl(struct send_storage_event_ctx *ctx, HTMLInnerWindow *window)
|
||||
{
|
||||
HTMLOuterWindow *child;
|
||||
const WCHAR *origin;
|
||||
UINT origin_len;
|
||||
BOOL matches;
|
||||
HRESULT hres;
|
||||
BSTR bstr;
|
||||
|
||||
if(!window)
|
||||
return S_OK;
|
||||
|
||||
LIST_FOR_EACH_ENTRY(child, &window->children, HTMLOuterWindow, sibling_entry) {
|
||||
hres = send_storage_event_impl(ctx, child->base.inner_window);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
}
|
||||
|
||||
if(window == ctx->skip_window)
|
||||
return S_OK;
|
||||
|
||||
/* Try it quick from session storage first, if available */
|
||||
if(window->session_storage) {
|
||||
HTMLStorage *storage = impl_from_IHTMLStorage(window->session_storage);
|
||||
origin = storage->session_storage->origin;
|
||||
origin_len = ctx->skip_window ? wcslen(origin) : storage->session_storage->origin_len;
|
||||
bstr = NULL;
|
||||
}else {
|
||||
hres = IUri_GetHost(window->base.outer_window->uri, &bstr);
|
||||
if(hres != S_OK) {
|
||||
if(SUCCEEDED(hres))
|
||||
SysFreeString(bstr);
|
||||
return S_OK;
|
||||
}
|
||||
if(ctx->skip_window)
|
||||
_wcslwr(bstr);
|
||||
else {
|
||||
BSTR tmp = bstr;
|
||||
hres = build_session_origin(window->base.outer_window->uri, tmp, &bstr);
|
||||
SysFreeString(tmp);
|
||||
if(hres != S_OK) {
|
||||
if(SUCCEEDED(hres))
|
||||
SysFreeString(bstr);
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
origin = bstr;
|
||||
origin_len = SysStringLen(bstr);
|
||||
}
|
||||
|
||||
matches = (origin_len == ctx->origin_len && !memcmp(origin, ctx->origin, origin_len * sizeof(WCHAR)));
|
||||
SysFreeString(bstr);
|
||||
|
||||
return matches ? push_storage_event_task(ctx, window, FALSE) : S_OK;
|
||||
}
|
||||
|
||||
/* Takes ownership of old_value */
|
||||
static HRESULT send_storage_event(HTMLStorage *storage, BSTR key, BSTR old_value, BSTR new_value)
|
||||
{
|
||||
HTMLInnerWindow *window = storage->window;
|
||||
struct send_storage_event_ctx ctx;
|
||||
HTMLOuterWindow *top_window;
|
||||
BSTR hostname = NULL;
|
||||
HRESULT hres = S_OK;
|
||||
|
||||
if(!window)
|
||||
goto done;
|
||||
get_top_window(window->base.outer_window, &top_window);
|
||||
|
||||
ctx.key = key;
|
||||
ctx.old_value = old_value;
|
||||
ctx.new_value = new_value;
|
||||
if(!storage->filename) {
|
||||
ctx.origin = storage->session_storage->origin;
|
||||
ctx.origin_len = storage->session_storage->origin_len;
|
||||
ctx.skip_window = NULL;
|
||||
}else {
|
||||
hres = IUri_GetHost(window->base.outer_window->uri, &hostname);
|
||||
if(hres != S_OK)
|
||||
goto done;
|
||||
_wcslwr(hostname);
|
||||
ctx.origin = hostname;
|
||||
ctx.origin_len = SysStringLen(hostname);
|
||||
ctx.skip_window = top_window->base.inner_window; /* localStorage on native skips top window */
|
||||
}
|
||||
hres = send_storage_event_impl(&ctx, top_window->base.inner_window);
|
||||
|
||||
if(ctx.skip_window && hres == S_OK)
|
||||
hres = push_storage_event_task(&ctx, window, TRUE);
|
||||
|
||||
done:
|
||||
SysFreeString(hostname);
|
||||
SysFreeString(old_value);
|
||||
return hres;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI HTMLStorage_QueryInterface(IHTMLStorage *iface, REFIID riid, void **ppv)
|
||||
{
|
||||
HTMLStorage *This = impl_from_IHTMLStorage(iface);
|
||||
|
|
|
@ -1253,6 +1253,130 @@ sync_test("storage", function() {
|
|||
sessionStorage.clear();
|
||||
});
|
||||
|
||||
async_test("storage events", function() {
|
||||
var iframe = document.createElement("iframe"), iframe2 = document.createElement("iframe");
|
||||
var local = false, storage, storage2, v = document.documentMode, i = 0;
|
||||
|
||||
var tests = [
|
||||
function() {
|
||||
expect();
|
||||
storage.removeItem("foobar");
|
||||
},
|
||||
function() {
|
||||
expect(0, "foobar", "", "test");
|
||||
storage.setItem("foobar", "test");
|
||||
},
|
||||
function() {
|
||||
expect(1, "foobar", "test", "TEST", true);
|
||||
storage2.setItem("foobar", "TEST");
|
||||
},
|
||||
function() {
|
||||
expect(0, "foobar", "TEST", "");
|
||||
storage.removeItem("foobar");
|
||||
},
|
||||
function() {
|
||||
expect(1, "winetest", "", "WineTest");
|
||||
storage2.setItem("winetest", "WineTest");
|
||||
},
|
||||
function() {
|
||||
expect(0, "", "", "");
|
||||
storage.clear();
|
||||
}
|
||||
];
|
||||
|
||||
function next() {
|
||||
if(++i < tests.length)
|
||||
tests[i]();
|
||||
else if(local)
|
||||
next_test();
|
||||
else {
|
||||
// w10pro64 testbot VM throws WININET_E_INTERNAL_ERROR for some reason
|
||||
storage = null, storage2 = null;
|
||||
try {
|
||||
storage = window.localStorage, storage2 = iframe.contentWindow.localStorage;
|
||||
}catch(e) {
|
||||
ok(e.number === 0x72ee4 - 0x80000000, "localStorage threw " + e.number + ": " + e);
|
||||
}
|
||||
if(!storage || !storage2) {
|
||||
win_skip("localStorage is buggy and not available, skipping");
|
||||
next_test();
|
||||
return;
|
||||
}
|
||||
i = 0, local = true;
|
||||
|
||||
if(!storage.length)
|
||||
setTimeout(function() { tests[0](); });
|
||||
else {
|
||||
// Get rid of any entries first, since native doesn't update immediately
|
||||
var w = [ window, iframe.contentWindow ];
|
||||
for(var j = 0; j < w.length; j++)
|
||||
w[j].onstorage = w[j].document.onstorage = w[j].document.onstoragecommit = null;
|
||||
document.onstoragecommit = function() {
|
||||
if(!storage.length)
|
||||
setTimeout(function() { tests[0](); });
|
||||
else
|
||||
storage.clear();
|
||||
};
|
||||
storage.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function test_event(e, key, oldValue, newValue) {
|
||||
if(v < 9) {
|
||||
ok(e === undefined, "event not undefined in legacy mode: " + e);
|
||||
return;
|
||||
}
|
||||
var s = Object.prototype.toString.call(e);
|
||||
todo_wine.
|
||||
ok(s === "[object StorageEvent]", "Object.toString = " + s);
|
||||
ok(e.key === key, "key = " + e.key + ", expected " + key);
|
||||
ok(e.oldValue === oldValue, "oldValue = " + e.oldValue + ", expected " + oldValue);
|
||||
ok(e.newValue === newValue, "newValue = " + e.newValue + ", expected " + newValue);
|
||||
}
|
||||
|
||||
function expect(idx, key, oldValue, newValue, quirk) {
|
||||
var window2 = iframe.contentWindow, document2 = window2.document;
|
||||
window.onstorage = function() { ok(false, "window.onstorage called"); };
|
||||
document.onstorage = function() { ok(false, "doc.onstorage called"); };
|
||||
document.onstoragecommit = function() { ok(false, "doc.onstoragecommit called"); };
|
||||
window2.onstorage = function() { ok(false, "iframe window.onstorage called"); };
|
||||
document2.onstorage = function() { ok(false, "iframe doc.onstorage called"); };
|
||||
document2.onstoragecommit = function() { ok(false, "iframe doc.onstoragecommit called"); };
|
||||
|
||||
if(idx === undefined) {
|
||||
setTimeout(function() { next(); });
|
||||
}else {
|
||||
// Native sometimes calls this for some reason
|
||||
if(local && quirk) document.onstoragecommit = null;
|
||||
|
||||
(v < 9 ? document2 : window2)["onstorage"] = function(e) {
|
||||
(local && idx ? document2 : (local || v < 9 ? document : window))[local ? "onstoragecommit" : "onstorage"] = function(e) {
|
||||
test_event(e, local ? "" : key, local ? "" : oldValue, local ? "" : newValue);
|
||||
next();
|
||||
}
|
||||
test_event(e, key, oldValue, newValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
iframe.onload = function() {
|
||||
iframe2.onload = function() {
|
||||
var w = iframe2.contentWindow;
|
||||
w.onstorage = function() { ok(false, "about:blank window.onstorage called"); };
|
||||
w.document.onstorage = function() { ok(false, "about:blank document.onstorage called"); };
|
||||
w.document.onstoragecommit = function() { ok(false, "about:blank document.onstoragecommit called"); };
|
||||
|
||||
storage = window.sessionStorage, storage2 = iframe.contentWindow.sessionStorage;
|
||||
tests[0]();
|
||||
};
|
||||
iframe2.src = "about:blank";
|
||||
document.body.appendChild(iframe2);
|
||||
};
|
||||
iframe.src = "blank.html";
|
||||
document.body.appendChild(iframe);
|
||||
});
|
||||
|
||||
sync_test("elem_attr", function() {
|
||||
var v = document.documentMode;
|
||||
var elem = document.createElement("div"), r;
|
||||
|
|
Loading…
Reference in a new issue