// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef CHROME_FRAME_UTILS_H_ #define CHROME_FRAME_UTILS_H_ #include <OAidl.h> #include <objidl.h> #include <windows.h> #include <wininet.h> #include <string> #include <vector> #include "base/basictypes.h" #include "base/logging.h" #include "base/metrics/histogram.h" #include "base/strings/string16.h" #include "base/win/scoped_comptr.h" #include "ui/gfx/rect.h" #include "url/gurl.h" class RegistryListPreferencesHolder; interface IBrowserService; interface IWebBrowser2; struct ContextMenuModel; namespace base { class FilePath; } // utils.h : Various utility functions and classes extern const char kGCFProtocol[]; extern const wchar_t kAllowUnsafeURLs[]; extern const wchar_t kChromeContentPrefix[]; extern const wchar_t kChromeFrameAccessibleMode[]; extern const wchar_t kChromeFrameAttachTabPattern[]; extern const wchar_t kChromeFrameConfigKey[]; extern const wchar_t kChromeFrameHeadlessMode[]; extern const wchar_t kChromeFrameUnpinnedMode[]; extern const wchar_t kChromeMimeType[]; extern const wchar_t kChromeProtocolPrefix[]; extern const wchar_t kEnableBuggyBhoIntercept[]; extern const wchar_t kEnableGCFRendererByDefault[]; extern const wchar_t kExcludeUAFromDomainList[]; extern const wchar_t kIexploreProfileName[]; extern const wchar_t kRenderInGCFUrlList[]; extern const wchar_t kRenderInHostUrlList[]; extern const wchar_t kRundllProfileName[]; extern const wchar_t kUseBackgroundThreadForSubResources[]; // This function is very similar to the AtlRegisterTypeLib function except // that it takes a parameter that specifies whether to register the typelib // for the current user only or on a machine-wide basis // Refer to the MSDN documentation for AtlRegisterTypeLib for a description of // the arguments HRESULT UtilRegisterTypeLib(HINSTANCE tlb_instance, LPCOLESTR index, bool for_current_user_only); // This function is very similar to the AtlUnRegisterTypeLib function except // that it takes a parameter that specifies whether to unregister the typelib // for the current user only or on a machine-wide basis // Refer to the MSDN documentation for AtlUnRegisterTypeLib for a description // of the arguments HRESULT UtilUnRegisterTypeLib(HINSTANCE tlb_instance, LPCOLESTR index, bool for_current_user_only); HRESULT UtilRegisterTypeLib(LPCWSTR typelib_path, bool for_current_user_only); HRESULT UtilUnRegisterTypeLib(LPCWSTR typelib_path, bool for_current_user_only); HRESULT UtilRegisterTypeLib(ITypeLib* typelib, LPCWSTR typelib_path, LPCWSTR help_dir, bool for_current_user_only); HRESULT UtilUnRegisterTypeLib(ITypeLib* typelib, bool for_current_user_only); // Clears a marker that causes legacy NPAPI registration to persist across // updates. Returns false if the marker could not be removed. bool UtilRemovePersistentNPAPIMarker(); // Given an HTML fragment, this function looks for the // <meta http-equiv="X-UA-Compatible"> tag and extracts the value of the // "content" attribute // This method will currently return a false positive if the tag appears // inside a string in a <SCRIPT> block. HRESULT UtilGetXUACompatContentValue(const std::wstring& html_string, std::wstring* content_value); // Returns a string from ChromeFrame's string table by resource. Must be // provided with a valid resource id. std::wstring GetResourceString(int resource_id); // Displays a message box indicating that there was a version mismatch between // ChromeFrame and the running instance of Chrome. // server_version is the version of the running instance of Chrome. void DisplayVersionMismatchWarning(HWND parent, const std::string& server_version); // This class provides a base implementation for ATL modules which want to // perform all their registration under HKCU. This class overrides the // RegisterServer and UnregisterServer methods and registers the type libraries // under HKCU (the rest of the registration is made under HKCU by changing the // appropriate .RGS files) template < class BaseAtlModule > class AtlPerUserModule : public BaseAtlModule { public: HRESULT RegisterServer(BOOL reg_typelib = FALSE, const CLSID* clsid = NULL) throw() { HRESULT hr = BaseAtlModule::RegisterServer(FALSE, clsid); if (FAILED(hr)) { return hr; } if (reg_typelib) { hr = UtilRegisterTypeLib(_AtlComModule.m_hInstTypeLib, NULL, false); } return hr; } HRESULT UnregisterServer(BOOL unreg_typelib, const CLSID* clsid = NULL) throw() { HRESULT hr = BaseAtlModule::UnregisterServer(FALSE, clsid); if (FAILED(hr)) { return hr; } if (unreg_typelib) { hr = UtilUnRegisterTypeLib(_AtlComModule.m_hInstTypeLib, NULL, false); } return hr; } }; // Creates a javascript statement for execution from the function name and // arguments passed in. std::string CreateJavascript(const std::string& function_name, const std::string args); // Use to prevent the DLL from being unloaded while there are still living // objects with outstanding references. class AddRefModule { public: AddRefModule(); ~AddRefModule(); }; // Retrieves the executable name of the process hosting us. If // |include_extension| is false, then we strip the extension from the name. std::wstring GetHostProcessName(bool include_extension); typedef enum BrowserType { BROWSER_INVALID = -1, BROWSER_UNKNOWN, BROWSER_IE, }; BrowserType GetBrowserType(); typedef enum IEVersion { IE_INVALID, NON_IE, IE_UNSUPPORTED, IE_6, IE_7, IE_8, IE_9, IE_10, IE_11, }; // The renderer to be used for a page. Values for Chrome also convey the // reason why Chrome is used. enum RendererType { RENDERER_TYPE_UNDETERMINED = 0, RENDERER_TYPE_CHROME_MIN, // NOTE: group all _CHROME_ values together below here, as they are used for // generating metrics reported via UMA (adjust MIN/MAX as needed). RENDERER_TYPE_CHROME_GCF_PROTOCOL = RENDERER_TYPE_CHROME_MIN, RENDERER_TYPE_CHROME_HTTP_EQUIV, RENDERER_TYPE_CHROME_RESPONSE_HEADER, RENDERER_TYPE_CHROME_DEFAULT_RENDERER, RENDERER_TYPE_CHROME_OPT_IN_URL, RENDERER_TYPE_CHROME_WIDGET, // NOTE: all _CHOME_ values must go above here (adjust MIN/MAX as needed). RENDERER_TYPE_CHROME_MAX = RENDERER_TYPE_CHROME_WIDGET, RENDERER_TYPE_OTHER, }; // Returns true if the given RendererType represents Chrome. bool IsChrome(RendererType renderer_type); // Convenience macro for logging a sample for the launch type metric. #define UMA_LAUNCH_TYPE_COUNT(sample) \ UMA_HISTOGRAM_CUSTOM_COUNTS("ChromeFrame.LaunchType", sample, \ RENDERER_TYPE_CHROME_MIN, RENDERER_TYPE_CHROME_MAX, \ RENDERER_TYPE_CHROME_MAX + 1 - RENDERER_TYPE_CHROME_MIN) // To get the IE version when Chrome Frame is hosted in IE. Make sure that // the hosting browser is IE before calling this function, otherwise NON_IE // will be returned. // // Versions newer than the newest supported version are reported as the newest // supported version. IEVersion GetIEVersion(); // Returns the actual major version of the IE in which the current process is // hosted. Returns 0 if the current process is not IE or any other error occurs. uint32 GetIEMajorVersion(); base::FilePath GetIETemporaryFilesFolder(); // Retrieves the file version from a module handle without extra round trips // to the disk (as happens with the regular GetFileVersionInfo API). // // @param module A handle to the module for which to retrieve the version info. // @param high On successful return holds the most significant part of the file // version. Must be non-null. // @param low On successful return holds the least significant part of the file // version. May be NULL. // @returns true if the version info was successfully retrieved. bool GetModuleVersion(HMODULE module, uint32* high, uint32* low); // Return if the IEXPLORE is in private mode. The IEIsInPrivateBrowsing() checks // whether current process is IEXPLORE. bool IsIEInPrivate(); // Calls [ieframe|shdocvw]!DoFileDownload to initiate a download. HRESULT DoFileDownloadInIE(const wchar_t* url); // Construct a menu from the model sent from Chrome. HMENU BuildContextMenu(const ContextMenuModel& menu_model); // Uses GURL internally to append 'relative' to 'document' std::string ResolveURL(const std::string& document, const std::string& relative); // Returns true iff the two urls have the same scheme, same host and same port. bool HaveSameOrigin(const std::string& url1, const std::string& url2); // Get a boolean configuration value from registry. bool GetConfigBool(bool default_value, const wchar_t* value_name); // Gets an integer configuration value from the registry. int GetConfigInt(int default_value, const wchar_t* value_name); // Gets a 64-bit integer configuration value from the registry. int64 GetConfigInt64(int64 default_value, const wchar_t* value_name); // Sets an integer configuration value in the registry. bool SetConfigInt(const wchar_t* value_name, int value); // Sets a boolean integer configuration value in the registry. bool SetConfigBool(const wchar_t* value_name, bool value); // Sets a 64-bit integer configuration value in the registry. bool SetConfigInt64(const wchar_t* value_name, int64 value); // Deletes the configuration value passed in. bool DeleteConfigValue(const wchar_t* value_name); // Returns true if we are running in headless mode in which case we need to // gather crash dumps, etc to send them to the crash server. bool IsHeadlessMode(); // Returns true if we are running in accessible mode in which we need to enable // renderer accessibility for use in automation. bool IsAccessibleMode(); // Returns true if we are running in unpinned mode in which case DLL // eviction should be possible. bool IsUnpinnedMode(); // Returns true if all HTML pages should be rendered in GCF by default. bool IsGcfDefaultRenderer(); // Returns true if the presence of // <meta http-equiv="X-UA-Compatible" content="chrome=1"> // in HTML pages should be ignored bool SkipMetadataCheck(); // Check if this url is opting into Chrome Frame based on static settings. // Returns one of: // - RENDERER_TYPE_UNDETERMINED if not opt-in or if explicit opt-out // - RENDERER_TYPE_CHROME_DEFAULT_RENDERER // - RENDERER_TYPE_CHROME_OPT_IN_URL RendererType RendererTypeForUrl(const std::wstring& url); // Check if we should try to remove the CF user agent based on registry // settings. bool ShouldRemoveUAForUrl(const string16& url); // Testing methods that return the backing stores behind RendererTypeForUrl and // ShouldRemoveUAForUrl. Intended to allow unit testing code that calls the // above methods. // TODO(robertshield): All of the FooForUrl code should be removed from here // and further refactored. RegistryListPreferencesHolder& GetRendererTypePreferencesHolderForTesting(); RegistryListPreferencesHolder& GetUserAgentPreferencesHolderForTesting(); // A shortcut for QueryService template <typename T> HRESULT DoQueryService(const IID& service_id, IUnknown* unk, T** service) { DCHECK(service); if (!unk) return E_INVALIDARG; base::win::ScopedComPtr<IServiceProvider> service_provider; HRESULT hr = service_provider.QueryFrom(unk); if (service_provider) hr = service_provider->QueryService(service_id, service); DCHECK(FAILED(hr) || *service); return hr; } // Navigates an IWebBrowser2 object to a moniker. // |headers| can be NULL. HRESULT NavigateBrowserToMoniker(IUnknown* browser, IMoniker* moniker, const wchar_t* headers, IBindCtx* bind_ctx, const wchar_t* fragment, IStream* post_data, VARIANT* flags); // Raises a flag on the current thread (using TLS) to indicate that an // in-progress navigation should be rendered in chrome frame. void MarkBrowserOnThreadForCFNavigation(IBrowserService* browser); // Checks if this browser instance has been marked as currently navigating // to a CF document. If clear_flag is set to true, the tls flag is cleared but // only if the browser has been marked. bool CheckForCFNavigation(IBrowserService* browser, bool clear_flag); // Returns true if the URL passed in is something which can be handled by // Chrome. If this function returns false then we should fail the navigation. // When is_privileged is true, chrome extension URLs will be considered valid. bool IsValidUrlScheme(const GURL& url, bool is_privileged); // Returns the raw http headers for the current request given an // IWinInetHttpInfo pointer. std::string GetRawHttpHeaders(IWinInetHttpInfo* info); // Can be used to determine whether a given request is being performed for // a sub-frame or iframe in Internet Explorer. This can be called // from various places, notably in request callbacks and the like. // // |service_provider| must not be NULL and should be a pointer to something // that implements IServiceProvider (if it isn't this method returns false). // // Returns true if this method can determine with some certainty that the // request did NOT originate from a top level frame, returns false otherwise. bool IsSubFrameRequest(IUnknown* service_provider); // See COM_INTERFACE_BLIND_DELEGATE below for details. template <class T> STDMETHODIMP CheckOutgoingInterface(void* obj, REFIID iid, void** ret, DWORD cookie) { T* instance = reinterpret_cast<T*>(obj); HRESULT hr = E_NOINTERFACE; IUnknown* delegate = instance ? instance->delegate() : NULL; if (delegate) { hr = delegate->QueryInterface(iid, ret); #if !defined(NDEBUG) if (SUCCEEDED(hr)) { wchar_t iid_string[64] = {0}; StringFromGUID2(iid, iid_string, arraysize(iid_string)); DVLOG(1) << __FUNCTION__ << " Giving out wrapped interface: " << iid_string; } #endif } return hr; } // See COM_INTERFACE_ENTRY_IF_DELEGATE_SUPPORTS below for details. template <class T> STDMETHODIMP QueryInterfaceIfDelegateSupports(void* obj, REFIID iid, void** ret, DWORD cookie) { HRESULT hr = E_NOINTERFACE; T* instance = reinterpret_cast<T*>(obj); IUnknown* delegate = instance ? instance->delegate() : NULL; if (delegate) { base::win::ScopedComPtr<IUnknown> original; hr = delegate->QueryInterface(iid, reinterpret_cast<void**>(original.Receive())); if (original) { IUnknown* supported_interface = reinterpret_cast<IUnknown*>( reinterpret_cast<DWORD_PTR>(obj) + cookie); supported_interface->AddRef(); *ret = supported_interface; hr = S_OK; } } return hr; } // Same as COM_INTERFACE_ENTRY but relies on the class to implement a // delegate() method that returns a pointer to the delegated COM object. #define COM_INTERFACE_ENTRY_IF_DELEGATE_SUPPORTS(x) \ COM_INTERFACE_ENTRY_FUNC(_ATL_IIDOF(x), \ offsetofclass(x, _ComMapClass), \ QueryInterfaceIfDelegateSupports<_ComMapClass>) // Queries the delegated COM object for an interface, bypassing the wrapper. #define COM_INTERFACE_BLIND_DELEGATE() \ COM_INTERFACE_ENTRY_FUNC_BLIND(0, CheckOutgoingInterface<_ComMapClass>) std::wstring GuidToString(const GUID& guid); // The urls retrieved from the IMoniker interface don't contain the anchor // portion of the actual url navigated to. This function checks whether the // url passed in the bho_url parameter contains an anchor and if yes checks // whether it matches the url retrieved from the moniker. If yes it returns // the bho url, if not the moniker url. std::wstring GetActualUrlFromMoniker(IMoniker* moniker, IBindCtx* bind_context, const std::wstring& bho_url); // Checks if a window is a top level window bool IsTopLevelWindow(HWND window); // Seeks a stream back to position 0. HRESULT RewindStream(IStream* stream); // Fired when we want to notify IE about privacy changes. #define WM_FIRE_PRIVACY_CHANGE_NOTIFICATION (WM_APP + 1) // Sent (not posted) when a request needs to be downloaded in the host browser // instead of Chrome. WPARAM is 0 and LPARAM is a pointer to an IMoniker // object. // NOTE: Since the message is sent synchronously, the handler should only // start asynchronous operations in order to not block the sender unnecessarily. #define WM_DOWNLOAD_IN_HOST (WM_APP + 2) // This structure contains the parameters sent over to initiate a download // request in the host browser. struct DownloadInHostParams { base::win::ScopedComPtr<IBindCtx> bind_ctx; base::win::ScopedComPtr<IMoniker> moniker; base::win::ScopedComPtr<IStream> post_data; std::string request_headers; }; // Maps the InternetCookieState enum to the corresponding CookieAction values // used for IE privacy stuff. int32 MapCookieStateToCookieAction(InternetCookieState cookie_state); // Parses the url passed in and returns a GURL instance without the fragment. GURL GetUrlWithoutFragment(const wchar_t* url); // Compares the URLs passed in after removing the fragments from them. bool CompareUrlsWithoutFragment(const wchar_t* url1, const wchar_t* url2); // Returns the Referrer from the HTTP headers and additional headers. std::string FindReferrerFromHeaders(const wchar_t* headers, const wchar_t* additional_headers); // Returns the HTTP headers from the binding passed in. std::string GetHttpHeadersFromBinding(IBinding* binding); // Returns the HTTP response code from the binding passed in. int GetHttpResponseStatusFromBinding(IBinding* binding); // Returns the clipboard format for text/html. CLIPFORMAT GetTextHtmlClipboardFormat(); // Returns true iff the mime type is text/html. bool IsTextHtmlMimeType(const wchar_t* mime_type); // Returns true iff the clipboard format is text/html. bool IsTextHtmlClipFormat(CLIPFORMAT cf); // Returns true if we can detect that we are running as SYSTEM, false otherwise. bool IsSystemProcess(); // STL helper class that implements a functor to delete objects. // E.g: std::for_each(v.begin(), v.end(), utils::DeleteObject()); namespace utils { class DeleteObject { public: template <typename T> void operator()(T* obj) { delete obj; } }; } // Convert various protocol flags to text representation. Used for logging. std::string BindStatus2Str(ULONG bind_status); std::string PiFlags2Str(DWORD flags); std::string Bscf2Str(DWORD flags); // Reads data from a stream into a string. HRESULT ReadStream(IStream* stream, size_t size, std::string* data); // Parses urls targeted at ChromeFrame. This class maintains state like // whether a url is prefixed with the gcf: prefix, whether it is being // attached to an existing external tab, etc. class ChromeFrameUrl { public: ChromeFrameUrl(); // Parses the url passed in. Returns true on success. bool Parse(const std::wstring& url); bool is_chrome_protocol() const { return is_chrome_protocol_; } bool attach_to_external_tab() const { return attach_to_external_tab_; } uint64 cookie() const { return cookie_; } int disposition() const { return disposition_; } const gfx::Rect& dimensions() const { return dimensions_; } const GURL& gurl() const { return parsed_url_; } const std::string& profile_name() const { return profile_name_; } private: // If we are attaching to an existing external tab, this function parses the // suffix portion of the URL which contains the attach_external_tab prefix. bool ParseAttachExternalTabUrl(); // Clear state. void Reset(); bool attach_to_external_tab_; bool is_chrome_protocol_; uint64 cookie_; gfx::Rect dimensions_; int disposition_; GURL parsed_url_; std::string profile_name_; }; class NavigationConstraints; // Returns true if we can navigate to this URL. // These decisions are controlled by the NavigationConstraints object passed // in. bool CanNavigate(const GURL& url, NavigationConstraints* navigation_constraints); // Helper function to spin a message loop and dispatch messages while waiting // for a handle to be signaled. void WaitWithMessageLoop(HANDLE* handles, int count, DWORD timeout); // Enumerates values in a key and adds them to an array. // The names of the values are not returned. void EnumerateKeyValues(HKEY parent_key, const wchar_t* sub_key_name, std::vector<std::wstring>* values); // Interprets the value of an X-UA-Compatible header (or <meta> tag equivalent) // and indicates whether the header value contains a Chrome Frame directive // matching a given host browser version. // // The header is a series of name-value pairs, with the names being HTTP tokens // and the values being either tokens or quoted-strings. Names and values are // joined by '=' and pairs are delimited by either ';' or ','. LWS may be used // liberally before and between names, values, '=', and ';' or ','. See RFC 2616 // for definitions of token, quoted-string, and LWS. See Microsoft's // documentation of the X-UA-COMPATIBLE header here: // http://msdn.microsoft.com/en-us/library/cc288325(VS.85).aspx // // At most one 'Chrome=<FILTER>' entry is expected in the header value. The // first valid instance is used. The value of "<FILTER>" (possibly after // unquoting) is interpreted as follows: // // "1" - Always active // "IE7" - Active for IE major version 7 or lower // // For example: // X-UA-Compatible: IE=8; Chrome=IE6 // // The string is first interpreted using ';' as a delimiter. It is reevaluated // using ',' iff no valid 'chrome=' value is found. bool CheckXUaCompatibleDirective(const std::string& directive, int ie_major_version); // Returns the version of the current module as a string. std::wstring GetCurrentModuleVersion(); // Returns true if ChromeFrame is the currently loaded document. bool IsChromeFrameDocument(IWebBrowser2* web_browser); // Increases the wininet connection limit for HTTP 1.0/1.1 connections to the // value passed in. This is only done if the existing connection limit is // lesser than the connection limit passed in. This function attempts to // increase the connection count once per process. // Returns true on success. bool IncreaseWinInetConnections(DWORD connections); // Sets |profile_path| to the path for the Chrome Frame |profile_name| // profile. void GetChromeFrameProfilePath(const string16& profile_name, base::FilePath* profile_path); #endif // CHROME_FRAME_UTILS_H_