Commit 8a67308f authored by Gabriel Ivăncescu's avatar Gabriel Ivăncescu Committed by Alexandre Julliard

ieframe: Navigate to a basic error page on failed navigation.

parent 125c390f
...@@ -277,6 +277,7 @@ HRESULT go_home(DocHost*); ...@@ -277,6 +277,7 @@ HRESULT go_home(DocHost*);
HRESULT go_back(DocHost*); HRESULT go_back(DocHost*);
HRESULT go_forward(DocHost*); HRESULT go_forward(DocHost*);
HRESULT refresh_document(DocHost*,const VARIANT*); HRESULT refresh_document(DocHost*,const VARIANT*);
HRESULT get_window(DocHost*,IHTMLWindow2**);
HRESULT get_location_url(DocHost*,BSTR*); HRESULT get_location_url(DocHost*,BSTR*);
HRESULT set_dochost_url(DocHost*,const WCHAR*); HRESULT set_dochost_url(DocHost*,const WCHAR*);
void handle_navigation_error(DocHost*,HRESULT,BSTR,IHTMLWindow2*); void handle_navigation_error(DocHost*,HRESULT,BSTR,IHTMLWindow2*);
......
...@@ -306,12 +306,13 @@ static HRESULT WINAPI BindStatusCallback_OnProgress(IBindStatusCallback *iface, ...@@ -306,12 +306,13 @@ static HRESULT WINAPI BindStatusCallback_OnProgress(IBindStatusCallback *iface,
return S_OK; return S_OK;
} }
void handle_navigation_error(DocHost* doc_host, HRESULT hres, BSTR url, IHTMLWindow2 *win2) void handle_navigation_error(DocHost* doc_host, HRESULT status_code, BSTR url, IHTMLWindow2 *win2)
{ {
VARIANT var_status_code, var_frame_name, var_url; VARIANT var_status_code, var_frame_name, var_url;
DISPPARAMS dispparams; DISPPARAMS dispparams;
VARIANTARG params[5]; VARIANTARG params[5];
VARIANT_BOOL cancel = VARIANT_FALSE; VARIANT_BOOL cancel = VARIANT_FALSE;
HRESULT hres;
dispparams.cArgs = 5; dispparams.cArgs = 5;
dispparams.cNamedArgs = 0; dispparams.cNamedArgs = 0;
...@@ -324,7 +325,7 @@ void handle_navigation_error(DocHost* doc_host, HRESULT hres, BSTR url, IHTMLWin ...@@ -324,7 +325,7 @@ void handle_navigation_error(DocHost* doc_host, HRESULT hres, BSTR url, IHTMLWin
V_VT(params+1) = VT_VARIANT|VT_BYREF; V_VT(params+1) = VT_VARIANT|VT_BYREF;
V_VARIANTREF(params+1) = &var_status_code; V_VARIANTREF(params+1) = &var_status_code;
V_VT(&var_status_code) = VT_I4; V_VT(&var_status_code) = VT_I4;
V_I4(&var_status_code) = hres; V_I4(&var_status_code) = status_code;
V_VT(params+2) = VT_VARIANT|VT_BYREF; V_VT(params+2) = VT_VARIANT|VT_BYREF;
V_VARIANTREF(params+2) = &var_frame_name; V_VARIANTREF(params+2) = &var_frame_name;
...@@ -347,8 +348,48 @@ void handle_navigation_error(DocHost* doc_host, HRESULT hres, BSTR url, IHTMLWin ...@@ -347,8 +348,48 @@ void handle_navigation_error(DocHost* doc_host, HRESULT hres, BSTR url, IHTMLWin
call_sink(doc_host->cps.wbe2, DISPID_NAVIGATEERROR, &dispparams); call_sink(doc_host->cps.wbe2, DISPID_NAVIGATEERROR, &dispparams);
SysFreeString(V_BSTR(&var_frame_name)); SysFreeString(V_BSTR(&var_frame_name));
if(!cancel) if(!cancel) {
FIXME("Navigate to error page\n"); IHTMLPrivateWindow *priv_window;
IHTMLWindow2 *tmp;
if(win2)
hres = IHTMLWindow2_QueryInterface(win2, &IID_IHTMLPrivateWindow, (void**)&priv_window);
else {
hres = get_window(doc_host, &tmp);
if(SUCCEEDED(hres)) {
if(!tmp)
hres = E_UNEXPECTED;
else {
hres = IHTMLWindow2_QueryInterface(tmp, &IID_IHTMLPrivateWindow, (void**)&priv_window);
IHTMLWindow2_Release(tmp);
}
}
}
if(SUCCEEDED(hres)) {
/* Error page navigation URL is a local resource (varies on native, also depending on error),
* with the fragment being the original URL of the page that failed to load. We add a query
* with the error code so the generic error page can display the actual error code there. */
WCHAR buf[32], sysdirbuf[MAX_PATH];
BSTR nav_url;
UINT len;
if(SUCCEEDED(status_code))
len = swprintf(buf, ARRAY_SIZE(buf), L"ERROR.HTM?HTTP %u", status_code);
else
len = swprintf(buf, ARRAY_SIZE(buf), L"ERROR.HTM?0x%08x", status_code);
len = 6 /* res:// */ + GetSystemDirectoryW(sysdirbuf, ARRAY_SIZE(sysdirbuf)) +
ARRAY_SIZE(L"\\shdoclc.dll/")-1 + len + 1 /* # */ + wcslen(url);
nav_url = SysAllocStringLen(NULL, len);
if(nav_url) {
swprintf(nav_url, len + 1, L"res://%s\\shdoclc.dll/%s#%s", sysdirbuf, buf, url);
IHTMLPrivateWindow_SuperNavigate(priv_window, nav_url, NULL, NULL, NULL, NULL, NULL, 2);
SysFreeString(nav_url);
}
IHTMLPrivateWindow_Release(priv_window);
}
}
} }
static HRESULT WINAPI BindStatusCallback_OnStopBinding(IBindStatusCallback *iface, static HRESULT WINAPI BindStatusCallback_OnStopBinding(IBindStatusCallback *iface,
......
...@@ -55,9 +55,72 @@ ...@@ -55,9 +55,72 @@
expect_ ## func = called_ ## func = FALSE; \ expect_ ## func = called_ ## func = FALSE; \
}while(0) }while(0)
DEFINE_EXPECT(Invoke_BEFORENAVIGATE2);
DEFINE_EXPECT(Invoke_NAVIGATECOMPLETE2); DEFINE_EXPECT(Invoke_NAVIGATECOMPLETE2);
DEFINE_EXPECT(Invoke_NAVIGATEERROR);
DEFINE_EXPECT(Invoke_DOCUMENTCOMPLETE);
static BOOL navigate_complete; static BOOL navigate_complete, navigation_timed_out;
static const WCHAR *navigate_url;
static BSTR get_window_url(IDispatch *webbrowser)
{
IHTMLPrivateWindow *priv_window;
IHTMLLocation *location;
IHTMLWindow2 *window;
IServiceProvider *sp;
IHTMLDocument2 *doc;
HRESULT hres;
BSTR url;
hres = IDispatch_QueryInterface(webbrowser, &IID_IServiceProvider, (void**)&sp);
ok(hres == S_OK, "QueryInterface(IServiceProvider) failed: %08lx\n", hres);
hres = IServiceProvider_QueryService(sp, &SID_SHTMLWindow, &IID_IHTMLWindow2, (void**)&window);
ok(hres == S_OK, "Could not get SHTMLWindow service: %08lx\n", hres);
ok(window != NULL, "window = NULL\n");
IServiceProvider_Release(sp);
hres = IHTMLWindow2_QueryInterface(window, &IID_IHTMLPrivateWindow, (void**)&priv_window);
ok(hres == E_NOINTERFACE, "QueryInterface(IID_IHTMLPrivateWindow) returned: %08lx\n", hres);
hres = IHTMLWindow2_get_document(window, &doc);
ok(hres == S_OK, "get_document failed: %08lx\n", hres);
ok(doc != NULL, "doc = NULL\n");
IHTMLWindow2_Release(window);
hres = IHTMLDocument2_get_parentWindow(doc, &window);
ok(hres == S_OK, "get_parentWindow failed: %08lx\n", hres);
ok(window != NULL, "window = NULL\n");
IHTMLDocument2_Release(doc);
hres = IHTMLWindow2_get_location(window, &location);
ok(hres == S_OK, "get_location failed: %08lx\n", hres);
ok(location != NULL, "location = NULL\n");
IHTMLWindow2_Release(window);
hres = IHTMLLocation_get_href(location, &url);
ok(hres == S_OK, "get_href failed: %08lx\n", hres);
ok(url != NULL, "url = NULL\n");
IHTMLLocation_Release(location);
return url;
}
#define test_url(a) _test_url(__LINE__,a)
static void _test_url(unsigned line, const WCHAR *url)
{
/* If error page, it actually returns the error page's resource URL, followed by #, followed by the original URL.
Since the error page's location varies on native, and depends on the error itself, just check for res:// here. */
if(called_Invoke_NAVIGATEERROR) {
ok_(__FILE__,line)(!wcsncmp(url, L"res://", ARRAY_SIZE(L"res://")-1), "url is not a local resource: %s\n", wine_dbgstr_w(url));
url = wcschr(url, '#');
ok_(__FILE__,line)(url != NULL, "url has no fragment: %s\n", wine_dbgstr_w(url));
ok_(__FILE__,line)(!wcscmp(url + 1, navigate_url), "url after fragment = %s\n", wine_dbgstr_w(url + 1));
}else {
ok_(__FILE__,line)(!wcscmp(url, navigate_url), "url = %s\n", wine_dbgstr_w(url));
}
}
static HRESULT WINAPI Dispatch_QueryInterface(IDispatch *iface, REFIID riid, void **ppv) static HRESULT WINAPI Dispatch_QueryInterface(IDispatch *iface, REFIID riid, void **ppv)
{ {
...@@ -104,10 +167,64 @@ static HRESULT WINAPI Dispatch_Invoke(IDispatch *iface, DISPID dispIdMember, REF ...@@ -104,10 +167,64 @@ static HRESULT WINAPI Dispatch_Invoke(IDispatch *iface, DISPID dispIdMember, REF
LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult,
EXCEPINFO *pExcepInfo, UINT *puArgErr) EXCEPINFO *pExcepInfo, UINT *puArgErr)
{ {
VARIANT *arg;
BSTR url;
switch(dispIdMember) { switch(dispIdMember) {
case DISPID_BEFORENAVIGATE2:
CHECK_EXPECT(Invoke_BEFORENAVIGATE2);
arg = pDispParams->rgvarg + 5;
ok(V_VT(arg) == (VT_BYREF | VT_VARIANT), "VT = %d\n", V_VT(arg));
ok(V_VT(V_VARIANTREF(arg)) == VT_BSTR, "VT = %d\n", V_VT(V_VARIANTREF(arg)));
test_url(V_BSTR(V_VARIANTREF(arg)));
return S_OK;
case DISPID_NAVIGATECOMPLETE2: case DISPID_NAVIGATECOMPLETE2:
CHECK_EXPECT(Invoke_NAVIGATECOMPLETE2); CHECK_EXPECT(Invoke_NAVIGATECOMPLETE2);
arg = pDispParams->rgvarg;
ok(V_VT(arg) == (VT_BYREF | VT_VARIANT), "VT = %d\n", V_VT(arg));
ok(V_VT(V_VARIANTREF(arg)) == VT_BSTR, "VT = %d\n", V_VT(V_VARIANTREF(arg)));
todo_wine_if(called_Invoke_NAVIGATEERROR)
ok(!wcscmp(V_BSTR(V_VARIANTREF(arg)), navigate_url), "url = %s\n", wine_dbgstr_w(V_BSTR(V_VARIANTREF(arg))));
arg = pDispParams->rgvarg + 1;
ok(V_VT(arg) == VT_DISPATCH, "VT = %d\n", V_VT(arg));
ok(V_DISPATCH(arg) != NULL, "V_DISPATCH = NULL\n");
url = get_window_url(V_DISPATCH(arg));
test_url(url);
SysFreeString(url);
return S_OK;
case DISPID_NAVIGATEERROR:
CHECK_EXPECT(Invoke_NAVIGATEERROR);
ok(!called_Invoke_NAVIGATECOMPLETE2, "NAVIGATECOMPLETE2 called before NAVIGATEERROR\n");
arg = pDispParams->rgvarg;
ok(V_VT(arg) == (VT_BYREF | VT_BOOL), "VT = %d\n", V_VT(arg));
ok(*V_BOOLREF(arg) == VARIANT_FALSE, "cancel = %#x\n", *V_BOOLREF(arg));
arg = pDispParams->rgvarg + 3;
ok(V_VT(arg) == (VT_BYREF | VT_VARIANT), "VT = %d\n", V_VT(arg));
ok(V_VT(V_VARIANTREF(arg)) == VT_BSTR, "VT = %d\n", V_VT(V_VARIANTREF(arg)));
ok(!wcscmp(V_BSTR(V_VARIANTREF(arg)), navigate_url), "url = %s\n", wine_dbgstr_w(V_BSTR(V_VARIANTREF(arg))));
return S_OK;
case DISPID_DOCUMENTCOMPLETE:
CHECK_EXPECT(Invoke_DOCUMENTCOMPLETE);
navigate_complete = TRUE; navigate_complete = TRUE;
arg = pDispParams->rgvarg;
ok(V_VT(arg) == (VT_BYREF | VT_VARIANT), "VT = %d\n", V_VT(arg));
ok(V_VT(V_VARIANTREF(arg)) == VT_BSTR, "VT = %d\n", V_VT(V_VARIANTREF(arg)));
todo_wine_if(called_Invoke_NAVIGATEERROR)
ok(!wcscmp(V_BSTR(V_VARIANTREF(arg)), navigate_url), "url = %s\n", wine_dbgstr_w(V_BSTR(V_VARIANTREF(arg))));
arg = pDispParams->rgvarg + 1;
ok(V_VT(arg) == VT_DISPATCH, "VT = %d\n", V_VT(arg));
ok(V_DISPATCH(arg) != NULL, "V_DISPATCH = NULL\n");
url = get_window_url(V_DISPATCH(arg));
test_url(url);
SysFreeString(url);
return S_OK; return S_OK;
} }
...@@ -141,7 +258,8 @@ static void advise_cp(IUnknown *unk, BOOL init) ...@@ -141,7 +258,8 @@ static void advise_cp(IUnknown *unk, BOOL init)
hres = IConnectionPointContainer_FindConnectionPoint(container, &DIID_DWebBrowserEvents2, &point); hres = IConnectionPointContainer_FindConnectionPoint(container, &DIID_DWebBrowserEvents2, &point);
IConnectionPointContainer_Release(container); IConnectionPointContainer_Release(container);
ok(hres == S_OK, "FindConnectionPoint failed: %08lx\n", hres); if(!navigation_timed_out)
ok(hres == S_OK, "FindConnectionPoint failed: %08lx\n", hres);
if(FAILED(hres)) if(FAILED(hres))
return; return;
...@@ -211,13 +329,31 @@ static void test_window(IWebBrowser2 *wb) ...@@ -211,13 +329,31 @@ static void test_window(IWebBrowser2 *wb)
ok(!strcmp(buf, "IEFrame"), "Unexpected class name %s\n", buf); ok(!strcmp(buf, "IEFrame"), "Unexpected class name %s\n", buf);
} }
static void test_navigate(IWebBrowser2 *wb, const WCHAR *url) static void CALLBACK navigate_timeout(HWND hwnd, UINT msg, UINT_PTR timer, DWORD time)
{
win_skip("Navigation timed out, skipping tests...\n");
called_Invoke_BEFORENAVIGATE2 = TRUE;
called_Invoke_NAVIGATECOMPLETE2 = TRUE;
called_Invoke_DOCUMENTCOMPLETE = TRUE;
if(expect_Invoke_NAVIGATEERROR)
CHECK_EXPECT(Invoke_NAVIGATEERROR);
navigation_timed_out = TRUE;
navigate_complete = TRUE;
}
static void test_navigate(IWebBrowser2 *wb, const WCHAR *url, DWORD timeout)
{ {
VARIANT urlv, emptyv; VARIANT urlv, emptyv;
UINT_PTR timer = 0;
MSG msg; MSG msg;
HRESULT hres; HRESULT hres;
SET_EXPECT(Invoke_BEFORENAVIGATE2);
SET_EXPECT(Invoke_NAVIGATECOMPLETE2); SET_EXPECT(Invoke_NAVIGATECOMPLETE2);
SET_EXPECT(Invoke_DOCUMENTCOMPLETE);
navigation_timed_out = FALSE;
navigate_complete = FALSE;
navigate_url = url;
V_VT(&urlv) = VT_BSTR; V_VT(&urlv) = VT_BSTR;
V_BSTR(&urlv) = SysAllocString(url); V_BSTR(&urlv) = SysAllocString(url);
...@@ -226,12 +362,20 @@ static void test_navigate(IWebBrowser2 *wb, const WCHAR *url) ...@@ -226,12 +362,20 @@ static void test_navigate(IWebBrowser2 *wb, const WCHAR *url)
ok(hres == S_OK, "Navigate2 failed: %08lx\n", hres); ok(hres == S_OK, "Navigate2 failed: %08lx\n", hres);
SysFreeString(V_BSTR(&urlv)); SysFreeString(V_BSTR(&urlv));
if(timeout)
timer = SetTimer(NULL, 0, timeout, navigate_timeout);
while(!navigate_complete && GetMessageW(&msg, NULL, 0, 0)) { while(!navigate_complete && GetMessageW(&msg, NULL, 0, 0)) {
TranslateMessage(&msg); TranslateMessage(&msg);
DispatchMessageW(&msg); DispatchMessageW(&msg);
} }
if(timer)
KillTimer(NULL, timer);
CHECK_CALLED(Invoke_BEFORENAVIGATE2);
CHECK_CALLED(Invoke_NAVIGATECOMPLETE2); CHECK_CALLED(Invoke_NAVIGATECOMPLETE2);
CHECK_CALLED(Invoke_DOCUMENTCOMPLETE);
} }
static void test_busy(IWebBrowser2 *wb) static void test_busy(IWebBrowser2 *wb)
...@@ -272,7 +416,11 @@ static void test_InternetExplorer(void) ...@@ -272,7 +416,11 @@ static void test_InternetExplorer(void)
test_visible(wb); test_visible(wb);
test_html_window(wb); test_html_window(wb);
test_window(wb); test_window(wb);
test_navigate(wb, L"http://test.winehq.org/tests/hello.html"); test_navigate(wb, L"http://test.winehq.org/tests/hello.html", 0);
SET_EXPECT(Invoke_NAVIGATEERROR);
test_navigate(wb, L"http://0.0.0.0:1234/#frag?query=foo&wine=bar", 6000);
CHECK_CALLED(Invoke_NAVIGATEERROR);
advise_cp(unk, FALSE); advise_cp(unk, FALSE);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment