Sync with trunk r63174.
[reactos.git] / dll / win32 / urlmon / http.c
index 5a606ca..24e2340 100644 (file)
  */
 
 #include "urlmon_main.h"
-#include "wininet.h"
-
-#define NO_SHLWAPI_REG
-#include "shlwapi.h"
-
-#include "wine/debug.h"
-
-WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
 
 typedef struct {
     Protocol base;
@@ -79,18 +71,13 @@ static LPWSTR query_http_info(HttpProtocol *This, DWORD option)
     return ret;
 }
 
-static inline BOOL set_security_flag(HttpProtocol *This, DWORD new_flag)
+static inline BOOL set_security_flag(HttpProtocol *This, DWORD flags)
 {
-    DWORD flags, size = sizeof(flags);
     BOOL res;
 
-    res = InternetQueryOptionW(This->base.request, INTERNET_OPTION_SECURITY_FLAGS, &flags, &size);
-    if(res) {
-        flags |= new_flag;
-        res = InternetSetOptionW(This->base.request, INTERNET_OPTION_SECURITY_FLAGS, &flags, size);
-    }
+    res = InternetSetOptionW(This->base.request, INTERNET_OPTION_SECURITY_FLAGS, &flags, sizeof(flags));
     if(!res)
-        ERR("Failed to set security flag(s): %x\n", new_flag);
+        ERR("Failed to set security flags: %x\n", flags);
 
     return res;
 }
@@ -103,6 +90,11 @@ static inline HRESULT internet_error_to_hres(DWORD error)
     case ERROR_INTERNET_SEC_CERT_CN_INVALID:
     case ERROR_INTERNET_INVALID_CA:
     case ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED:
+    case ERROR_INTERNET_SEC_INVALID_CERT:
+    case ERROR_INTERNET_SEC_CERT_ERRORS:
+    case ERROR_INTERNET_SEC_CERT_REV_FAILED:
+    case ERROR_INTERNET_SEC_CERT_NO_REV:
+    case ERROR_INTERNET_SEC_CERT_REVOKED:
         return INET_E_INVALID_CERTIFICATE;
     case ERROR_INTERNET_HTTP_TO_HTTPS_ON_REDIR:
     case ERROR_INTERNET_HTTPS_TO_HTTP_ON_REDIR:
@@ -119,16 +111,26 @@ static HRESULT handle_http_error(HttpProtocol *This, DWORD error)
     IWindowForBindingUI *wfb_ui;
     IHttpSecurity *http_security;
     BOOL security_problem;
+    DWORD dlg_flags;
+    HWND hwnd;
+    DWORD res;
     HRESULT hres;
 
+    TRACE("(%p %u)\n", This, error);
+
     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:
+    case ERROR_INTERNET_SEC_INVALID_CERT:
+    case ERROR_INTERNET_SEC_CERT_ERRORS:
+    case ERROR_INTERNET_SEC_CERT_REV_FAILED:
+    case ERROR_INTERNET_SEC_CERT_NO_REV:
+    case ERROR_INTERNET_SEC_CERT_REVOKED:
+    case ERROR_HTTP_REDIRECT_NEEDS_CONFIRMATION:
         security_problem = TRUE;
         break;
     default:
@@ -149,6 +151,8 @@ static HRESULT handle_http_error(HttpProtocol *This, DWORD error)
             hres = IHttpSecurity_OnSecurityProblem(http_security, error);
             IHttpSecurity_Release(http_security);
 
+            TRACE("OnSecurityProblem returned %08x\n", hres);
+
             if(hres != S_FALSE)
             {
                 BOOL res = FALSE;
@@ -180,42 +184,43 @@ static HRESULT handle_http_error(HttpProtocol *This, DWORD error)
         }
     }
 
-    hres = IServiceProvider_QueryService(serv_prov, &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;
+    switch(error) {
+    case ERROR_INTERNET_SEC_CERT_REV_FAILED:
+        if(hres != S_FALSE) {
+            /* Silently ignore the error. We will get more detailed error from wininet anyway. */
+            set_security_flag(This, SECURITY_FLAG_IGNORE_REVOCATION);
+            hres = RPC_E_RETRY;
+            break;
+        }
+        /* fallthrough */
+    default:
+        hres = IServiceProvider_QueryService(serv_prov, &IID_IWindowForBindingUI, &IID_IWindowForBindingUI, (void**)&wfb_ui);
+        if(SUCCEEDED(hres)) {
+            const IID *iid_reason;
+
+            if(security_problem)
+                iid_reason = &IID_IHttpSecurity;
+            else if(error == ERROR_INTERNET_INCORRECT_PASSWORD)
+                iid_reason = &IID_IAuthenticate;
             else
-                hres = E_FAIL;
+                iid_reason = &IID_IWindowForBindingUI;
+
+            hres = IWindowForBindingUI_GetWindow(wfb_ui, iid_reason, &hwnd);
+            IWindowForBindingUI_Release(wfb_ui);
         }
-        IWindowForBindingUI_Release(wfb_ui);
-    }
 
-    IServiceProvider_Release(serv_prov);
+        if(FAILED(hres)) hwnd = NULL;
 
-    if(hres == RPC_E_RETRY)
-        return hres;
+        dlg_flags = FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS | FLAGS_ERROR_UI_FLAGS_GENERATE_DATA;
+        if(This->base.bindf & BINDF_NO_UI)
+            dlg_flags |= FLAGS_ERROR_UI_FLAGS_NO_UI;
+
+        res = InternetErrorDlg(hwnd, This->base.request, error, dlg_flags, NULL);
+        hres = res == ERROR_INTERNET_FORCE_RETRY || res == ERROR_SUCCESS ? RPC_E_RETRY : internet_error_to_hres(error);
+    }
 
-    return internet_error_to_hres(error);
+    IServiceProvider_Release(serv_prov);
+    return hres;
 }
 
 static ULONG send_http_request(HttpProtocol *This)
@@ -269,14 +274,14 @@ static HRESULT HttpProtocol_open_request(Protocol *prot, IUri *uri, DWORD reques
         HINTERNET internet_session, IInternetBindInfo *bind_info)
 {
     HttpProtocol *This = impl_from_Protocol(prot);
-    LPWSTR addl_header = NULL, post_cookie = NULL;
+    WCHAR *addl_header = NULL, *post_cookie = NULL, *rootdoc_url = NULL;
     IServiceProvider *service_provider = NULL;
     IHttpNegotiate2 *http_negotiate2 = NULL;
     BSTR url, host, user, pass, path;
     LPOLESTR accept_mimes[257];
     const WCHAR **accept_types;
     BYTE security_id[512];
-    DWORD len, port;
+    DWORD len, port, flags;
     ULONG num, error;
     BOOL res, b;
     HRESULT hres;
@@ -313,6 +318,13 @@ static HRESULT HttpProtocol_open_request(Protocol *prot, IUri *uri, DWORD reques
         return INET_E_CANNOT_CONNECT;
     }
 
+    num = 0;
+    hres = IInternetBindInfo_GetBindString(bind_info, BINDSTRING_ROOTDOC_URL, &rootdoc_url, 1, &num);
+    if(hres == S_OK && num) {
+        FIXME("Use root doc URL %s\n", debugstr_w(rootdoc_url));
+        CoTaskMemFree(rootdoc_url);
+    }
+
     num = sizeof(accept_mimes)/sizeof(accept_mimes[0])-1;
     hres = IInternetBindInfo_GetBindString(bind_info, BINDSTRING_ACCEPT_MIMES, accept_mimes, num, &num);
     if(hres == INET_E_USE_DEFAULT_SETTING) {
@@ -419,19 +431,31 @@ static HRESULT HttpProtocol_open_request(Protocol *prot, IUri *uri, DWORD reques
         }
     }
 
+    flags = INTERNET_ERROR_MASK_COMBINED_SEC_CERT;
+    res = InternetSetOptionW(This->base.request, INTERNET_OPTION_ERROR_MASK, &flags, sizeof(flags));
+    if(!res)
+        WARN("InternetSetOption(INTERNET_OPTION_ERROR_MASK) failed: %u\n", GetLastError());
+
     b = TRUE;
     res = InternetSetOptionW(This->base.request, INTERNET_OPTION_HTTP_DECODING, &b, sizeof(b));
     if(!res)
-        WARN("InternetSetOption(INTERNET_OPTION_HTTP_DECODING) failed: %08x\n", GetLastError());
+        WARN("InternetSetOption(INTERNET_OPTION_HTTP_DECODING) failed: %u\n", GetLastError());
 
     do {
         error = send_http_request(This);
 
-        if(error == ERROR_IO_PENDING || error == ERROR_SUCCESS)
+        switch(error) {
+        case ERROR_IO_PENDING:
             return S_OK;
-
-        hres = handle_http_error(This, error);
-
+        case ERROR_SUCCESS:
+            /*
+             * If sending response ended synchronously, it means that we have the whole data
+             * available locally (most likely in cache).
+             */
+            return protocol_syncbinding(&This->base);
+        default:
+            hres = handle_http_error(This, error);
+        }
     } while(hres == RPC_E_RETRY);
 
     WARN("HttpSendRequest failed: %d\n", error);
@@ -528,10 +552,8 @@ static void HttpProtocol_close_connection(Protocol *prot)
         This->http_negotiate = NULL;
     }
 
-    if(This->full_header) {
-        heap_free(This->full_header);
-        This->full_header = NULL;
-    }
+    heap_free(This->full_header);
+    This->full_header = NULL;
 }
 
 static void HttpProtocol_on_error(Protocol *prot, DWORD error)
@@ -595,7 +617,7 @@ static HRESULT WINAPI HttpProtocol_QueryInterface(IInternetProtocolEx *iface, RE
     }
 
     if(*ppv) {
-        IInternetProtocol_AddRef(iface);
+        IInternetProtocolEx_AddRef(iface);
         return S_OK;
     }