[PATCH 4/6] urlmon: Add some error handling to the http protocol.
David Hedberg
dhedberg at codeweavers.com
Tue Dec 21 17:50:26 CST 2010
---
dlls/urlmon/http.c | 99 +++++++++++++++++++++++++++++++++++++++++++++--
dlls/urlmon/tests/url.c | 25 ++++++++++++
2 files changed, 120 insertions(+), 4 deletions(-)
diff --git a/dlls/urlmon/http.c b/dlls/urlmon/http.c
index cfa2fc6..1ed5e15 100644
--- a/dlls/urlmon/http.c
+++ b/dlls/urlmon/http.c
@@ -80,6 +80,92 @@ static LPWSTR query_http_info(HttpProtocol *This, DWORD option)
return ret;
}
+static HRESULT handle_http_error(HttpProtocol *This, DWORD error)
+{
+ IWindowForBindingUI *wfb_ui;
+ IHttpSecurity *http_security;
+ BOOL security_problem;
+ HRESULT hres;
+
+ switch(error) {
+ case ERROR_INTERNET_SEC_CERT_DATE_INVALID:
+ case ERROR_INTERNET_SEC_CERT_CN_INVALID:
+ case ERROR_INTERNET_HTTP_TO_HTTPS_ON_REDIR:
+ case ERROR_INTERNET_HTTPS_TO_HTTP_ON_REDIR:
+ case ERROR_HTTP_REDIRECT_NEEDS_CONFIRMATION:
+ case ERROR_INTERNET_INVALID_CA:
+ case ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED:
+ security_problem = TRUE;
+ break;
+ default:
+ security_problem = FALSE;
+ }
+
+ if(security_problem) {
+ hres = IUnknown_QueryService((IUnknown*)This->base.protocol_sink,
+ &IID_IHttpSecurity, &IID_IHttpSecurity, (void **)&http_security);
+ if(SUCCEEDED(hres)) {
+ hres = IHttpSecurity_OnSecurityProblem(http_security, error);
+ IHttpSecurity_Release(http_security);
+
+ if(hres == S_OK || hres == E_ABORT)
+ return E_ABORT;
+ if(hres == RPC_E_RETRY)
+ return RPC_E_RETRY;
+ if(hres != S_FALSE)
+ return INET_E_SECURITY_PROBLEM;
+ }
+ }
+
+ hres = IUnknown_QueryService((IUnknown*)This->base.protocol_sink,
+ &IID_IWindowForBindingUI, &IID_IWindowForBindingUI, (void **)&wfb_ui);
+ if(SUCCEEDED(hres)) {
+ HWND hwnd;
+ const IID *iid_reason;
+
+ if(security_problem)
+ iid_reason = &IID_IHttpSecurity;
+ else if(error == ERROR_INTERNET_INCORRECT_PASSWORD)
+ iid_reason = &IID_IAuthenticate;
+ else
+ iid_reason = &IID_IWindowForBindingUI;
+
+ hres = IWindowForBindingUI_GetWindow(wfb_ui, iid_reason, &hwnd);
+ if(SUCCEEDED(hres) && hwnd)
+ {
+ DWORD res;
+
+ res = InternetErrorDlg(hwnd, This->base.request, error,
+ FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS | FLAGS_ERROR_UI_FLAGS_GENERATE_DATA,
+ NULL);
+
+ if(res == ERROR_INTERNET_FORCE_RETRY || res == ERROR_SUCCESS)
+ hres = RPC_E_RETRY;
+ else
+ hres = E_FAIL;
+ }
+ IWindowForBindingUI_Release(wfb_ui);
+ }
+
+ if(hres == RPC_E_RETRY)
+ return hres;
+
+ switch(error)
+ {
+ case ERROR_INTERNET_SEC_CERT_DATE_INVALID:
+ case ERROR_INTERNET_SEC_CERT_CN_INVALID:
+ case ERROR_INTERNET_INVALID_CA:
+ case ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED:
+ return INET_E_INVALID_CERTIFICATE;
+ case ERROR_INTERNET_HTTP_TO_HTTPS_ON_REDIR:
+ case ERROR_INTERNET_HTTPS_TO_HTTP_ON_REDIR:
+ case ERROR_HTTP_REDIRECT_NEEDS_CONFIRMATION:
+ return INET_E_REDIRECT_FAILED;
+ default:
+ return INET_E_DOWNLOAD_FAILURE;
+ }
+}
+
static ULONG send_http_request(HttpProtocol *This)
{
INTERNET_BUFFERSW send_buffer = {sizeof(INTERNET_BUFFERSW)};
@@ -282,13 +368,18 @@ static HRESULT HttpProtocol_open_request(Protocol *prot, IUri *uri, DWORD reques
if(!res)
WARN("InternetSetOption(INTERNET_OPTION_HTTP_DECODING) failed: %08x\n", GetLastError());
- error = send_http_request(This);
+ do {
+ error = send_http_request(This);
- if(error == ERROR_IO_PENDING || error == ERROR_SUCCESS)
- return S_OK;
+ if(error == ERROR_IO_PENDING || error == ERROR_SUCCESS)
+ return S_OK;
+
+ hres = handle_http_error(This, error);
+
+ } while(hres == RPC_E_RETRY);
WARN("HttpSendRequest failed: %d\n", error);
- return INET_E_DOWNLOAD_FAILURE;
+ return hres;
}
static HRESULT HttpProtocol_end_request(Protocol *protocol)
diff --git a/dlls/urlmon/tests/url.c b/dlls/urlmon/tests/url.c
index 875294b..c2cf152 100644
--- a/dlls/urlmon/tests/url.c
+++ b/dlls/urlmon/tests/url.c
@@ -91,10 +91,12 @@ DEFINE_EXPECT(QueryInterface_IInternetBindInfo);
DEFINE_EXPECT(QueryInterface_IAuthenticate);
DEFINE_EXPECT(QueryInterface_IInternetProtocol);
DEFINE_EXPECT(QueryInterface_IWindowForBindingUI);
+DEFINE_EXPECT(QueryInterface_IHttpSecurity);
DEFINE_EXPECT(QueryService_IAuthenticate);
DEFINE_EXPECT(QueryService_IInternetProtocol);
DEFINE_EXPECT(QueryService_IInternetBindInfo);
DEFINE_EXPECT(QueryService_IWindowForBindingUI);
+DEFINE_EXPECT(QueryService_IHttpSecurity);
DEFINE_EXPECT(BeginningTransaction);
DEFINE_EXPECT(OnResponse);
DEFINE_EXPECT(QueryInterface_IHttpNegotiate2);
@@ -627,6 +629,7 @@ static HRESULT WINAPI Protocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
IServiceProvider *service_provider;
IHttpNegotiate *http_negotiate;
IHttpNegotiate2 *http_negotiate2;
+ IHttpSecurity *http_security;
LPWSTR ua = (LPWSTR)0xdeadbeef, accept_mimes[256];
LPWSTR additional_headers = (LPWSTR)0xdeadbeef;
BYTE sec_id[100];
@@ -708,6 +711,18 @@ static HRESULT WINAPI Protocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
ok(hres == E_FAIL, "GetRootSecurityId failed: %08x, expected E_FAIL\n", hres);
ok(size == no_callback ? 512 : 13, "size=%d\n", size);
+ if(!no_callback) {
+ SET_EXPECT(QueryService_IHttpSecurity);
+ SET_EXPECT(QueryInterface_IHttpSecurity);
+ }
+ hres = IServiceProvider_QueryService(service_provider, &IID_IHttpSecurity,
+ &IID_IHttpSecurity, (void**)&http_security);
+ ok(hres == E_NOINTERFACE, "QueryService failed: 0x%08x\n", hres);
+ if(!no_callback) {
+ CHECK_CALLED(QueryService_IHttpSecurity);
+ CHECK_CALLED(QueryInterface_IHttpSecurity);
+ }
+
IServiceProvider_Release(service_provider);
IInternetProtocolSink_AddRef(pOIProtSink);
@@ -1212,6 +1227,11 @@ static HRESULT WINAPI ServiceProvider_QueryService(IServiceProvider *iface,
return E_NOTIMPL;
}
+ if(IsEqualGUID(&IID_IHttpSecurity, guidService)) {
+ CHECK_EXPECT(QueryService_IHttpSecurity);
+ return E_NOTIMPL;
+ }
+
ok(0, "unexpected service %s\n", debugstr_guid(guidService));
return E_NOINTERFACE;
}
@@ -1292,6 +1312,11 @@ static HRESULT WINAPI statusclb_QueryInterface(IBindStatusCallbackEx *iface, REF
CHECK_EXPECT2(QueryInterface_IWindowForBindingUI);
return E_NOINTERFACE;
}
+ else if(IsEqualGUID(&IID_IHttpSecurity, riid))
+ {
+ CHECK_EXPECT2(QueryInterface_IHttpSecurity);
+ return E_NOINTERFACE;
+ }
else
{
ok(0, "unexpected interface %s\n", debugstr_guid(riid));
--
1.7.3.4
More information about the wine-patches
mailing list