1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef CHROME_FRAME_UTILS_H_
6#define CHROME_FRAME_UTILS_H_
7
8#include <OAidl.h>
9#include <objidl.h>
10#include <windows.h>
11#include <wininet.h>
12#include <string>
13#include <vector>
14
15#include "base/basictypes.h"
16#include "base/logging.h"
17#include "base/metrics/histogram.h"
18#include "base/strings/string16.h"
19#include "base/win/scoped_comptr.h"
20#include "ui/gfx/rect.h"
21#include "url/gurl.h"
22
23class RegistryListPreferencesHolder;
24interface IBrowserService;
25interface IWebBrowser2;
26struct ContextMenuModel;
27
28namespace base {
29class FilePath;
30}
31
32// utils.h : Various utility functions and classes
33extern const char kGCFProtocol[];
34
35extern const wchar_t kAllowUnsafeURLs[];
36extern const wchar_t kChromeContentPrefix[];
37extern const wchar_t kChromeFrameAccessibleMode[];
38extern const wchar_t kChromeFrameAttachTabPattern[];
39extern const wchar_t kChromeFrameConfigKey[];
40extern const wchar_t kChromeFrameHeadlessMode[];
41extern const wchar_t kChromeFrameUnpinnedMode[];
42extern const wchar_t kChromeMimeType[];
43extern const wchar_t kChromeProtocolPrefix[];
44extern const wchar_t kEnableBuggyBhoIntercept[];
45extern const wchar_t kEnableGCFRendererByDefault[];
46extern const wchar_t kExcludeUAFromDomainList[];
47extern const wchar_t kIexploreProfileName[];
48extern const wchar_t kRenderInGCFUrlList[];
49extern const wchar_t kRenderInHostUrlList[];
50extern const wchar_t kRundllProfileName[];
51extern const wchar_t kUseBackgroundThreadForSubResources[];
52
53// This function is very similar to the AtlRegisterTypeLib function except
54// that it takes a parameter that specifies whether to register the typelib
55// for the current user only or on a machine-wide basis
56// Refer to the MSDN documentation for AtlRegisterTypeLib for a description of
57// the arguments
58HRESULT UtilRegisterTypeLib(HINSTANCE tlb_instance,
59                            LPCOLESTR index,
60                            bool for_current_user_only);
61
62// This function is very similar to the AtlUnRegisterTypeLib function except
63// that it takes a parameter that specifies whether to unregister the typelib
64// for the current user only or on a machine-wide basis
65// Refer to the MSDN documentation for AtlUnRegisterTypeLib for a description
66// of the arguments
67HRESULT UtilUnRegisterTypeLib(HINSTANCE tlb_instance,
68                              LPCOLESTR index,
69                              bool for_current_user_only);
70
71HRESULT UtilRegisterTypeLib(LPCWSTR typelib_path, bool for_current_user_only);
72
73HRESULT UtilUnRegisterTypeLib(LPCWSTR typelib_path, bool for_current_user_only);
74
75HRESULT UtilRegisterTypeLib(ITypeLib* typelib,
76                            LPCWSTR typelib_path,
77                            LPCWSTR help_dir,
78                            bool for_current_user_only);
79
80HRESULT UtilUnRegisterTypeLib(ITypeLib* typelib,
81                              bool for_current_user_only);
82
83// Clears a marker that causes legacy NPAPI registration to persist across
84// updates. Returns false if the marker could not be removed.
85bool UtilRemovePersistentNPAPIMarker();
86
87// Given an HTML fragment, this function looks for the
88// <meta http-equiv="X-UA-Compatible"> tag and extracts the value of the
89// "content" attribute
90// This method will currently return a false positive if the tag appears
91// inside a string in a <SCRIPT> block.
92HRESULT UtilGetXUACompatContentValue(const std::wstring& html_string,
93                                     std::wstring* content_value);
94
95// Returns a string from ChromeFrame's string table by resource. Must be
96// provided with a valid resource id.
97std::wstring GetResourceString(int resource_id);
98
99// Displays a message box indicating that there was a version mismatch between
100// ChromeFrame and the running instance of Chrome.
101// server_version is the version of the running instance of Chrome.
102void DisplayVersionMismatchWarning(HWND parent,
103                                   const std::string& server_version);
104
105// This class provides a base implementation for ATL modules which want to
106// perform all their registration under HKCU. This class overrides the
107// RegisterServer and UnregisterServer methods and registers the type libraries
108// under HKCU (the rest of the registration is made under HKCU by changing the
109// appropriate .RGS files)
110template < class BaseAtlModule >
111class AtlPerUserModule : public BaseAtlModule {
112 public:
113  HRESULT RegisterServer(BOOL reg_typelib = FALSE,
114                         const CLSID* clsid = NULL) throw() {
115    HRESULT hr = BaseAtlModule::RegisterServer(FALSE, clsid);
116    if (FAILED(hr)) {
117      return hr;
118    }
119    if (reg_typelib)  {
120      hr = UtilRegisterTypeLib(_AtlComModule.m_hInstTypeLib, NULL, false);
121    }
122    return hr;
123  }
124
125  HRESULT UnregisterServer(BOOL unreg_typelib,
126                           const CLSID* clsid = NULL) throw() {
127    HRESULT hr = BaseAtlModule::UnregisterServer(FALSE, clsid);
128    if (FAILED(hr)) {
129      return hr;
130    }
131    if (unreg_typelib)  {
132      hr = UtilUnRegisterTypeLib(_AtlComModule.m_hInstTypeLib, NULL, false);
133    }
134    return hr;
135  }
136};
137
138// Creates a javascript statement for execution from the function name and
139// arguments passed in.
140std::string CreateJavascript(const std::string& function_name,
141                             const std::string args);
142
143// Use to prevent the DLL from being unloaded while there are still living
144// objects with outstanding references.
145class AddRefModule {
146 public:
147  AddRefModule();
148  ~AddRefModule();
149};
150
151// Retrieves the executable name of the process hosting us. If
152// |include_extension| is false, then we strip the extension from the name.
153std::wstring GetHostProcessName(bool include_extension);
154
155typedef enum BrowserType {
156  BROWSER_INVALID = -1,
157  BROWSER_UNKNOWN,
158  BROWSER_IE,
159};
160
161BrowserType GetBrowserType();
162
163typedef enum IEVersion {
164  IE_INVALID,
165  NON_IE,
166  IE_UNSUPPORTED,
167  IE_6,
168  IE_7,
169  IE_8,
170  IE_9,
171  IE_10,
172  IE_11,
173};
174
175// The renderer to be used for a page.  Values for Chrome also convey the
176// reason why Chrome is used.
177enum RendererType {
178  RENDERER_TYPE_UNDETERMINED = 0,
179  RENDERER_TYPE_CHROME_MIN,
180  // NOTE: group all _CHROME_ values together below here, as they are used for
181  // generating metrics reported via UMA (adjust MIN/MAX as needed).
182  RENDERER_TYPE_CHROME_GCF_PROTOCOL = RENDERER_TYPE_CHROME_MIN,
183  RENDERER_TYPE_CHROME_HTTP_EQUIV,
184  RENDERER_TYPE_CHROME_RESPONSE_HEADER,
185  RENDERER_TYPE_CHROME_DEFAULT_RENDERER,
186  RENDERER_TYPE_CHROME_OPT_IN_URL,
187  RENDERER_TYPE_CHROME_WIDGET,
188  // NOTE: all _CHOME_ values must go above here (adjust MIN/MAX as needed).
189  RENDERER_TYPE_CHROME_MAX = RENDERER_TYPE_CHROME_WIDGET,
190  RENDERER_TYPE_OTHER,
191};
192
193// Returns true if the given RendererType represents Chrome.
194bool IsChrome(RendererType renderer_type);
195
196// Convenience macro for logging a sample for the launch type metric.
197#define UMA_LAUNCH_TYPE_COUNT(sample) \
198  UMA_HISTOGRAM_CUSTOM_COUNTS("ChromeFrame.LaunchType", sample, \
199  RENDERER_TYPE_CHROME_MIN, RENDERER_TYPE_CHROME_MAX, \
200  RENDERER_TYPE_CHROME_MAX + 1 - RENDERER_TYPE_CHROME_MIN)
201
202// To get the IE version when Chrome Frame is hosted in IE.  Make sure that
203// the hosting browser is IE before calling this function, otherwise NON_IE
204// will be returned.
205//
206// Versions newer than the newest supported version are reported as the newest
207// supported version.
208IEVersion GetIEVersion();
209
210// Returns the actual major version of the IE in which the current process is
211// hosted. Returns 0 if the current process is not IE or any other error occurs.
212uint32 GetIEMajorVersion();
213
214base::FilePath GetIETemporaryFilesFolder();
215
216// Retrieves the file version from a module handle without extra round trips
217// to the disk (as happens with the regular GetFileVersionInfo API).
218//
219// @param module A handle to the module for which to retrieve the version info.
220// @param high On successful return holds the most significant part of the file
221// version.  Must be non-null.
222// @param low On successful return holds the least significant part of the file
223// version.  May be NULL.
224// @returns true if the version info was successfully retrieved.
225bool GetModuleVersion(HMODULE module, uint32* high, uint32* low);
226
227// Return if the IEXPLORE is in private mode. The IEIsInPrivateBrowsing() checks
228// whether current process is IEXPLORE.
229bool IsIEInPrivate();
230
231// Calls [ieframe|shdocvw]!DoFileDownload to initiate a download.
232HRESULT DoFileDownloadInIE(const wchar_t* url);
233
234// Construct a menu from the model sent from Chrome.
235HMENU BuildContextMenu(const ContextMenuModel& menu_model);
236
237// Uses GURL internally to append 'relative' to 'document'
238std::string ResolveURL(const std::string& document,
239                       const std::string& relative);
240
241// Returns true iff the two urls have the same scheme, same host and same port.
242bool HaveSameOrigin(const std::string& url1, const std::string& url2);
243
244// Get a boolean configuration value from registry.
245bool GetConfigBool(bool default_value, const wchar_t* value_name);
246
247// Gets an integer configuration value from the registry.
248int GetConfigInt(int default_value, const wchar_t* value_name);
249
250// Gets a 64-bit integer configuration value from the registry.
251int64 GetConfigInt64(int64 default_value, const wchar_t* value_name);
252
253// Sets an integer configuration value in the registry.
254bool SetConfigInt(const wchar_t* value_name, int value);
255
256// Sets a boolean integer configuration value in the registry.
257bool SetConfigBool(const wchar_t* value_name, bool value);
258
259// Sets a 64-bit integer configuration value in the registry.
260bool SetConfigInt64(const wchar_t* value_name, int64 value);
261
262// Deletes the configuration value passed in.
263bool DeleteConfigValue(const wchar_t* value_name);
264
265// Returns true if we are running in headless mode in which case we need to
266// gather crash dumps, etc to send them to the crash server.
267bool IsHeadlessMode();
268
269// Returns true if we are running in accessible mode in which we need to enable
270// renderer accessibility for use in automation.
271bool IsAccessibleMode();
272
273// Returns true if we are running in unpinned mode in which case DLL
274// eviction should be possible.
275bool IsUnpinnedMode();
276
277// Returns true if all HTML pages should be rendered in GCF by default.
278bool IsGcfDefaultRenderer();
279
280// Returns true if the presence of
281// <meta http-equiv="X-UA-Compatible" content="chrome=1">
282// in HTML pages should be ignored
283bool SkipMetadataCheck();
284
285// Check if this url is opting into Chrome Frame based on static settings.
286// Returns one of:
287// - RENDERER_TYPE_UNDETERMINED if not opt-in or if explicit opt-out
288// - RENDERER_TYPE_CHROME_DEFAULT_RENDERER
289// - RENDERER_TYPE_CHROME_OPT_IN_URL
290RendererType RendererTypeForUrl(const std::wstring& url);
291
292// Check if we should try to remove the CF user agent based on registry
293// settings.
294bool ShouldRemoveUAForUrl(const string16& url);
295
296// Testing methods that return the backing stores behind RendererTypeForUrl and
297// ShouldRemoveUAForUrl. Intended to allow unit testing code that calls the
298// above methods.
299// TODO(robertshield): All of the FooForUrl code should be removed from here
300// and further refactored.
301RegistryListPreferencesHolder& GetRendererTypePreferencesHolderForTesting();
302RegistryListPreferencesHolder& GetUserAgentPreferencesHolderForTesting();
303
304// A shortcut for QueryService
305template <typename T>
306HRESULT DoQueryService(const IID& service_id, IUnknown* unk, T** service) {
307  DCHECK(service);
308  if (!unk)
309    return E_INVALIDARG;
310
311  base::win::ScopedComPtr<IServiceProvider> service_provider;
312  HRESULT hr = service_provider.QueryFrom(unk);
313  if (service_provider)
314    hr = service_provider->QueryService(service_id, service);
315
316  DCHECK(FAILED(hr) || *service);
317  return hr;
318}
319
320// Navigates an IWebBrowser2 object to a moniker.
321// |headers| can be NULL.
322HRESULT NavigateBrowserToMoniker(IUnknown* browser, IMoniker* moniker,
323                                 const wchar_t* headers, IBindCtx* bind_ctx,
324                                 const wchar_t* fragment, IStream* post_data,
325                                 VARIANT* flags);
326
327// Raises a flag on the current thread (using TLS) to indicate that an
328// in-progress navigation should be rendered in chrome frame.
329void MarkBrowserOnThreadForCFNavigation(IBrowserService* browser);
330
331// Checks if this browser instance has been marked as currently navigating
332// to a CF document.  If clear_flag is set to true, the tls flag is cleared but
333// only if the browser has been marked.
334bool CheckForCFNavigation(IBrowserService* browser, bool clear_flag);
335
336// Returns true if the URL passed in is something which can be handled by
337// Chrome. If this function returns false then we should fail the navigation.
338// When is_privileged is true, chrome extension URLs will be considered valid.
339bool IsValidUrlScheme(const GURL& url, bool is_privileged);
340
341// Returns the raw http headers for the current request given an
342// IWinInetHttpInfo pointer.
343std::string GetRawHttpHeaders(IWinInetHttpInfo* info);
344
345// Can be used to determine whether a given request is being performed for
346// a sub-frame or iframe in Internet Explorer. This can be called
347// from various places, notably in request callbacks and the like.
348//
349// |service_provider| must not be NULL and should be a pointer to something
350// that implements IServiceProvider (if it isn't this method returns false).
351//
352// Returns true if this method can determine with some certainty that the
353// request did NOT originate from a top level frame, returns false otherwise.
354bool IsSubFrameRequest(IUnknown* service_provider);
355
356// See COM_INTERFACE_BLIND_DELEGATE below for details.
357template <class T>
358STDMETHODIMP CheckOutgoingInterface(void* obj, REFIID iid, void** ret,
359                                    DWORD cookie) {
360  T* instance = reinterpret_cast<T*>(obj);
361  HRESULT hr = E_NOINTERFACE;
362  IUnknown* delegate = instance ? instance->delegate() : NULL;
363  if (delegate) {
364    hr = delegate->QueryInterface(iid, ret);
365#if !defined(NDEBUG)
366    if (SUCCEEDED(hr)) {
367      wchar_t iid_string[64] = {0};
368      StringFromGUID2(iid, iid_string, arraysize(iid_string));
369      DVLOG(1) << __FUNCTION__ << " Giving out wrapped interface: "
370               << iid_string;
371    }
372#endif
373  }
374
375  return hr;
376}
377
378// See COM_INTERFACE_ENTRY_IF_DELEGATE_SUPPORTS below for details.
379template <class T>
380STDMETHODIMP QueryInterfaceIfDelegateSupports(void* obj, REFIID iid,
381                                              void** ret, DWORD cookie) {
382  HRESULT hr = E_NOINTERFACE;
383  T* instance = reinterpret_cast<T*>(obj);
384  IUnknown* delegate = instance ? instance->delegate() : NULL;
385  if (delegate) {
386    base::win::ScopedComPtr<IUnknown> original;
387    hr = delegate->QueryInterface(iid,
388                                  reinterpret_cast<void**>(original.Receive()));
389    if (original) {
390      IUnknown* supported_interface = reinterpret_cast<IUnknown*>(
391          reinterpret_cast<DWORD_PTR>(obj) + cookie);
392      supported_interface->AddRef();
393      *ret = supported_interface;
394      hr = S_OK;
395    }
396  }
397
398  return hr;
399}
400
401// Same as COM_INTERFACE_ENTRY but relies on the class to implement a
402// delegate() method that returns a pointer to the delegated COM object.
403#define COM_INTERFACE_ENTRY_IF_DELEGATE_SUPPORTS(x) \
404    COM_INTERFACE_ENTRY_FUNC(_ATL_IIDOF(x), \
405        offsetofclass(x, _ComMapClass), \
406        QueryInterfaceIfDelegateSupports<_ComMapClass>)
407
408// Queries the delegated COM object for an interface, bypassing the wrapper.
409#define COM_INTERFACE_BLIND_DELEGATE() \
410    COM_INTERFACE_ENTRY_FUNC_BLIND(0, CheckOutgoingInterface<_ComMapClass>)
411
412std::wstring GuidToString(const GUID& guid);
413
414// The urls retrieved from the IMoniker interface don't contain the anchor
415// portion of the actual url navigated to. This function checks whether the
416// url passed in the bho_url parameter contains an anchor and if yes checks
417// whether it matches the url retrieved from the moniker. If yes it returns
418// the bho url, if not the moniker url.
419std::wstring GetActualUrlFromMoniker(IMoniker* moniker,
420                                     IBindCtx* bind_context,
421                                     const std::wstring& bho_url);
422
423// Checks if a window is a top level window
424bool IsTopLevelWindow(HWND window);
425
426// Seeks a stream back to position 0.
427HRESULT RewindStream(IStream* stream);
428
429// Fired when we want to notify IE about privacy changes.
430#define WM_FIRE_PRIVACY_CHANGE_NOTIFICATION (WM_APP + 1)
431
432// Sent (not posted) when a request needs to be downloaded in the host browser
433// instead of Chrome.  WPARAM is 0 and LPARAM is a pointer to an IMoniker
434// object.
435// NOTE: Since the message is sent synchronously, the handler should only
436// start asynchronous operations in order to not block the sender unnecessarily.
437#define WM_DOWNLOAD_IN_HOST (WM_APP + 2)
438
439// This structure contains the parameters sent over to initiate a download
440// request in the host browser.
441struct DownloadInHostParams {
442  base::win::ScopedComPtr<IBindCtx> bind_ctx;
443  base::win::ScopedComPtr<IMoniker> moniker;
444  base::win::ScopedComPtr<IStream> post_data;
445  std::string request_headers;
446};
447
448// Maps the InternetCookieState enum to the corresponding CookieAction values
449// used for IE privacy stuff.
450int32 MapCookieStateToCookieAction(InternetCookieState cookie_state);
451
452// Parses the url passed in and returns a GURL instance without the fragment.
453GURL GetUrlWithoutFragment(const wchar_t* url);
454
455// Compares the URLs passed in after removing the fragments from them.
456bool CompareUrlsWithoutFragment(const wchar_t* url1, const wchar_t* url2);
457
458// Returns the Referrer from the HTTP headers and additional headers.
459std::string FindReferrerFromHeaders(const wchar_t* headers,
460                                     const wchar_t* additional_headers);
461
462// Returns the HTTP headers from the binding passed in.
463std::string GetHttpHeadersFromBinding(IBinding* binding);
464
465// Returns the HTTP response code from the binding passed in.
466int GetHttpResponseStatusFromBinding(IBinding* binding);
467
468// Returns the clipboard format for text/html.
469CLIPFORMAT GetTextHtmlClipboardFormat();
470
471// Returns true iff the mime type is text/html.
472bool IsTextHtmlMimeType(const wchar_t* mime_type);
473
474// Returns true iff the clipboard format is text/html.
475bool IsTextHtmlClipFormat(CLIPFORMAT cf);
476
477// Returns true if we can detect that we are running as SYSTEM, false otherwise.
478bool IsSystemProcess();
479
480// STL helper class that implements a functor to delete objects.
481// E.g: std::for_each(v.begin(), v.end(), utils::DeleteObject());
482namespace utils {
483class DeleteObject {
484 public:
485  template <typename T>
486  void operator()(T* obj) {
487    delete obj;
488  }
489};
490}
491
492// Convert various protocol flags to text representation. Used for logging.
493std::string BindStatus2Str(ULONG bind_status);
494std::string PiFlags2Str(DWORD flags);
495std::string Bscf2Str(DWORD flags);
496
497// Reads data from a stream into a string.
498HRESULT ReadStream(IStream* stream, size_t size, std::string* data);
499
500// Parses urls targeted at ChromeFrame. This class maintains state like
501// whether a url is prefixed with the gcf: prefix, whether it is being
502// attached to an existing external tab, etc.
503class ChromeFrameUrl {
504 public:
505  ChromeFrameUrl();
506
507  // Parses the url passed in. Returns true on success.
508  bool Parse(const std::wstring& url);
509
510  bool is_chrome_protocol() const {
511    return is_chrome_protocol_;
512  }
513
514  bool attach_to_external_tab() const {
515    return attach_to_external_tab_;
516  }
517
518  uint64 cookie() const {
519    return cookie_;
520  }
521
522  int disposition() const {
523    return disposition_;
524  }
525
526  const gfx::Rect& dimensions() const {
527    return dimensions_;
528  }
529
530  const GURL& gurl() const {
531    return parsed_url_;
532  }
533
534  const std::string& profile_name() const {
535    return profile_name_;
536  }
537
538 private:
539  // If we are attaching to an existing external tab, this function parses the
540  // suffix portion of the URL which contains the attach_external_tab prefix.
541  bool ParseAttachExternalTabUrl();
542
543  // Clear state.
544  void Reset();
545
546  bool attach_to_external_tab_;
547  bool is_chrome_protocol_;
548  uint64 cookie_;
549  gfx::Rect dimensions_;
550  int disposition_;
551
552  GURL parsed_url_;
553  std::string profile_name_;
554};
555
556class NavigationConstraints;
557// Returns true if we can navigate to this URL.
558// These decisions are controlled by the NavigationConstraints object passed
559// in.
560bool CanNavigate(const GURL& url,
561                 NavigationConstraints* navigation_constraints);
562
563// Helper function to spin a message loop and dispatch messages while waiting
564// for a handle to be signaled.
565void WaitWithMessageLoop(HANDLE* handles, int count, DWORD timeout);
566
567// Enumerates values in a key and adds them to an array.
568// The names of the values are not returned.
569void EnumerateKeyValues(HKEY parent_key, const wchar_t* sub_key_name,
570                        std::vector<std::wstring>* values);
571
572// Interprets the value of an X-UA-Compatible header (or <meta> tag equivalent)
573// and indicates whether the header value contains a Chrome Frame directive
574// matching a given host browser version.
575//
576// The header is a series of name-value pairs, with the names being HTTP tokens
577// and the values being either tokens or quoted-strings. Names and values are
578// joined by '=' and pairs are delimited by either ';' or ','. LWS may be used
579// liberally before and between names, values, '=', and ';' or ','. See RFC 2616
580// for definitions of token, quoted-string, and LWS. See Microsoft's
581// documentation of the X-UA-COMPATIBLE header here:
582// http://msdn.microsoft.com/en-us/library/cc288325(VS.85).aspx
583//
584// At most one 'Chrome=<FILTER>' entry is expected in the header value. The
585// first valid instance is used. The value of "<FILTER>" (possibly after
586// unquoting) is interpreted as follows:
587//
588// "1"   - Always active
589// "IE7" - Active for IE major version 7 or lower
590//
591// For example:
592// X-UA-Compatible: IE=8; Chrome=IE6
593//
594// The string is first interpreted using ';' as a delimiter. It is reevaluated
595// using ',' iff no valid 'chrome=' value is found.
596bool CheckXUaCompatibleDirective(const std::string& directive,
597                                 int ie_major_version);
598
599// Returns the version of the current module as a string.
600std::wstring GetCurrentModuleVersion();
601
602// Returns true if ChromeFrame is the currently loaded document.
603bool IsChromeFrameDocument(IWebBrowser2* web_browser);
604
605// Increases the wininet connection limit for HTTP 1.0/1.1 connections to the
606// value passed in. This is only done if the existing connection limit is
607// lesser than the connection limit passed in. This function attempts to
608// increase the connection count once per process.
609// Returns true on success.
610bool IncreaseWinInetConnections(DWORD connections);
611
612// Sets |profile_path| to the path for the Chrome Frame |profile_name|
613// profile.
614void GetChromeFrameProfilePath(const string16& profile_name,
615                               base::FilePath* profile_path);
616
617#endif  // CHROME_FRAME_UTILS_H_
618