Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-cw
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-cw
Commits
2297623f
Commit
2297623f
authored
Sep 13, 2022
by
Gabriel Ivăncescu
Committed by
Alexandre Julliard
Sep 14, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
mshtml: Send StorageEvents to iframe windows properly.
Signed-off-by:
Gabriel Ivăncescu
<
gabrielopcode@gmail.com
>
parent
e64ab65a
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
233 additions
and
11 deletions
+233
-11
htmlstorage.c
dlls/mshtml/htmlstorage.c
+109
-11
documentmode.js
dlls/mshtml/tests/documentmode.js
+124
-0
No files found.
dlls/mshtml/htmlstorage.c
View file @
2297623f
...
@@ -197,6 +197,8 @@ static inline HTMLStorage *impl_from_IHTMLStorage(IHTMLStorage *iface)
...
@@ -197,6 +197,8 @@ static inline HTMLStorage *impl_from_IHTMLStorage(IHTMLStorage *iface)
return
CONTAINING_RECORD
(
iface
,
HTMLStorage
,
IHTMLStorage_iface
);
return
CONTAINING_RECORD
(
iface
,
HTMLStorage
,
IHTMLStorage_iface
);
}
}
static
HRESULT
build_session_origin
(
IUri
*
,
BSTR
,
BSTR
*
);
struct
storage_event_task
{
struct
storage_event_task
{
task_t
header
;
task_t
header
;
HTMLInnerWindow
*
window
;
HTMLInnerWindow
*
window
;
...
@@ -226,22 +228,22 @@ static void storage_event_destr(task_t *_task)
...
@@ -226,22 +228,22 @@ static void storage_event_destr(task_t *_task)
IHTMLWindow2_Release
(
&
task
->
window
->
base
.
IHTMLWindow2_iface
);
IHTMLWindow2_Release
(
&
task
->
window
->
base
.
IHTMLWindow2_iface
);
}
}
/* Takes ownership of old_value */
struct
send_storage_event_ctx
{
static
HRESULT
send_storage_event
(
HTMLStorage
*
storage
,
BSTR
key
,
BSTR
old_value
,
BSTR
new_value
)
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
;
struct
storage_event_task
*
task
;
DOMEvent
*
event
;
DOMEvent
*
event
;
HRESULT
hres
;
HRESULT
hres
;
if
(
!
window
)
{
hres
=
create_storage_event
(
window
->
doc
,
ctx
->
key
,
ctx
->
old_value
,
ctx
->
new_value
,
commit
,
&
event
);
SysFreeString
(
old_value
);
return
S_OK
;
}
hres
=
create_storage_event
(
window
->
doc
,
key
,
old_value
,
new_value
,
local
,
&
event
);
SysFreeString
(
old_value
);
if
(
FAILED
(
hres
))
if
(
FAILED
(
hres
))
return
hres
;
return
hres
;
...
@@ -256,6 +258,102 @@ static HRESULT send_storage_event(HTMLStorage *storage, BSTR key, BSTR old_value
...
@@ -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
);
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
)
static
HRESULT
WINAPI
HTMLStorage_QueryInterface
(
IHTMLStorage
*
iface
,
REFIID
riid
,
void
**
ppv
)
{
{
HTMLStorage
*
This
=
impl_from_IHTMLStorage
(
iface
);
HTMLStorage
*
This
=
impl_from_IHTMLStorage
(
iface
);
...
...
dlls/mshtml/tests/documentmode.js
View file @
2297623f
...
@@ -1253,6 +1253,130 @@ sync_test("storage", function() {
...
@@ -1253,6 +1253,130 @@ sync_test("storage", function() {
sessionStorage
.
clear
();
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
()
{
sync_test
(
"elem_attr"
,
function
()
{
var
v
=
document
.
documentMode
;
var
v
=
document
.
documentMode
;
var
elem
=
document
.
createElement
(
"div"
),
r
;
var
elem
=
document
.
createElement
(
"div"
),
r
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment