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 CONTENT_PUBLIC_BROWSER_CONTENT_BROWSER_CLIENT_H_ 6 #define CONTENT_PUBLIC_BROWSER_CONTENT_BROWSER_CLIENT_H_ 7 8 #include <map> 9 #include <string> 10 #include <utility> 11 #include <vector> 12 13 #include "base/callback_forward.h" 14 #include "base/memory/linked_ptr.h" 15 #include "base/memory/scoped_ptr.h" 16 #include "base/memory/scoped_vector.h" 17 #include "base/values.h" 18 #include "content/public/browser/certificate_request_result_type.h" 19 #include "content/public/browser/file_descriptor_info.h" 20 #include "content/public/common/content_client.h" 21 #include "content/public/common/socket_permission_request.h" 22 #include "content/public/common/window_container_type.h" 23 #include "net/base/mime_util.h" 24 #include "net/cookies/canonical_cookie.h" 25 #include "net/url_request/url_request_job_factory.h" 26 #include "third_party/WebKit/public/web/WebNotificationPresenter.h" 27 #include "ui/base/window_open_disposition.h" 28 #include "webkit/common/resource_type.h" 29 30 #if defined(OS_POSIX) && !defined(OS_MACOSX) 31 #include "base/posix/global_descriptors.h" 32 #endif 33 34 class CommandLine; 35 class GURL; 36 struct WebPreferences; 37 38 namespace blink { 39 struct WebWindowFeatures; 40 } 41 42 namespace base { 43 class DictionaryValue; 44 class FilePath; 45 } 46 47 namespace gfx { 48 class ImageSkia; 49 } 50 51 namespace net { 52 class CookieOptions; 53 class HttpNetworkSession; 54 class NetLog; 55 class SSLCertRequestInfo; 56 class SSLInfo; 57 class URLRequest; 58 class URLRequestContext; 59 class URLRequestContextGetter; 60 class X509Certificate; 61 } 62 63 namespace sandbox { 64 class TargetPolicy; 65 } 66 67 namespace ui { 68 class SelectFilePolicy; 69 } 70 71 namespace fileapi { 72 class ExternalMountPoints; 73 class FileSystemBackend; 74 } 75 76 namespace content { 77 78 class AccessTokenStore; 79 class BrowserChildProcessHost; 80 class BrowserContext; 81 class BrowserMainParts; 82 class BrowserPluginGuestDelegate; 83 class BrowserPpapiHost; 84 class BrowserURLHandler; 85 class LocationProvider; 86 class MediaObserver; 87 class QuotaPermissionContext; 88 class RenderProcessHost; 89 class RenderViewHost; 90 class RenderViewHostDelegateView; 91 class ResourceContext; 92 class SiteInstance; 93 class SpeechRecognitionManagerDelegate; 94 class VibrationProvider; 95 class WebContents; 96 class WebContentsViewDelegate; 97 class WebContentsViewPort; 98 struct MainFunctionParams; 99 struct Referrer; 100 struct ShowDesktopNotificationHostMsgParams; 101 102 // A mapping from the scheme name to the protocol handler that services its 103 // content. 104 typedef std::map< 105 std::string, linked_ptr<net::URLRequestJobFactory::ProtocolHandler> > 106 ProtocolHandlerMap; 107 108 // Embedder API (or SPI) for participating in browser logic, to be implemented 109 // by the client of the content browser. See ChromeContentBrowserClient for the 110 // principal implementation. The methods are assumed to be called on the UI 111 // thread unless otherwise specified. Use this "escape hatch" sparingly, to 112 // avoid the embedder interface ballooning and becoming very specific to Chrome. 113 // (Often, the call out to the client can happen in a different part of the code 114 // that either already has a hook out to the embedder, or calls out to one of 115 // the observer interfaces.) 116 class CONTENT_EXPORT ContentBrowserClient { 117 public: 118 virtual ~ContentBrowserClient() {} 119 120 // Allows the embedder to set any number of custom BrowserMainParts 121 // implementations for the browser startup code. See comments in 122 // browser_main_parts.h. 123 virtual BrowserMainParts* CreateBrowserMainParts( 124 const MainFunctionParams& parameters); 125 126 // Allows an embedder to return their own WebContentsViewPort implementation. 127 // Return NULL to let the default one for the platform be created. Otherwise 128 // |render_view_host_delegate_view| also needs to be provided, and it is 129 // owned by the embedder. 130 virtual WebContentsViewPort* OverrideCreateWebContentsView( 131 WebContents* web_contents, 132 RenderViewHostDelegateView** render_view_host_delegate_view); 133 134 // If content creates the WebContentsView implementation, it will ask the 135 // embedder to return an (optional) delegate to customize it. The view will 136 // own the delegate. 137 virtual WebContentsViewDelegate* GetWebContentsViewDelegate( 138 WebContents* web_contents); 139 140 // Notifies that a guest WebContents has been created. A guest WebContents 141 // represents a renderer that's hosted within a BrowserPlugin. Creation can 142 // occur an arbitrary length of time before attachment. If the new guest has 143 // an |opener_web_contents|, then it's a new window created by that opener. 144 // If the guest was created via navigation, then |extra_params| will be 145 // non-NULL. |extra_params| are parameters passed to the BrowserPlugin object 146 // element by the content embedder. These parameters may include the API to 147 // enable for the given guest. |guest_delegate| is a return parameter of 148 // the delegate in the content embedder that will service the guest in the 149 // content layer. The content layer takes ownership of the |guest_delegate|. 150 virtual void GuestWebContentsCreated( 151 SiteInstance* guest_site_instance, 152 WebContents* guest_web_contents, 153 WebContents* opener_web_contents, 154 BrowserPluginGuestDelegate** guest_delegate, 155 scoped_ptr<base::DictionaryValue> extra_params) {} 156 157 // Notifies that a guest WebContents has been attached to a BrowserPlugin. 158 // A guest is attached to a BrowserPlugin when the guest has acquired an 159 // embedder WebContents. This happens on initial navigation or when a new 160 // window is attached to a BrowserPlugin. |extra_params| are params sent 161 // from javascript. 162 virtual void GuestWebContentsAttached( 163 WebContents* guest_web_contents, 164 WebContents* embedder_web_contents, 165 const base::DictionaryValue& extra_params) {} 166 167 // Notifies that a RenderProcessHost has been created. This is called before 168 // the content layer adds its own BrowserMessageFilters, so that the 169 // embedder's IPC filters have priority. 170 virtual void RenderProcessHostCreated(RenderProcessHost* host) {} 171 172 // Notifies that a BrowserChildProcessHost has been created. 173 virtual void BrowserChildProcessHostCreated(BrowserChildProcessHost* host) {} 174 175 // Get the effective URL for the given actual URL, to allow an embedder to 176 // group different url schemes in the same SiteInstance. 177 virtual GURL GetEffectiveURL(BrowserContext* browser_context, 178 const GURL& url); 179 180 // Returns whether all instances of the specified effective URL should be 181 // rendered by the same process, rather than using process-per-site-instance. 182 virtual bool ShouldUseProcessPerSite(BrowserContext* browser_context, 183 const GURL& effective_url); 184 185 // Returns a list additional WebUI schemes, if any. These additional schemes 186 // act as aliases to the chrome: scheme. The additional schemes may or may 187 // not serve specific WebUI pages depending on the particular URLDataSource 188 // and its override of URLDataSource::ShouldServiceRequest. 189 virtual void GetAdditionalWebUISchemes( 190 std::vector<std::string>* additional_schemes) {} 191 192 // Creates the main net::URLRequestContextGetter. Should only be called once 193 // per ContentBrowserClient object. 194 // TODO(ajwong): Remove once http://crbug.com/159193 is resolved. 195 virtual net::URLRequestContextGetter* CreateRequestContext( 196 BrowserContext* browser_context, 197 ProtocolHandlerMap* protocol_handlers); 198 199 // Creates the net::URLRequestContextGetter for a StoragePartition. Should 200 // only be called once per partition_path per ContentBrowserClient object. 201 // TODO(ajwong): Remove once http://crbug.com/159193 is resolved. 202 virtual net::URLRequestContextGetter* CreateRequestContextForStoragePartition( 203 BrowserContext* browser_context, 204 const base::FilePath& partition_path, 205 bool in_memory, 206 ProtocolHandlerMap* protocol_handlers); 207 208 // Returns whether a specified URL is handled by the embedder's internal 209 // protocol handlers. 210 virtual bool IsHandledURL(const GURL& url); 211 212 // Returns whether the given process is allowed to commit |url|. This is a 213 // more conservative check than IsSuitableHost, since it is used after a 214 // navigation has committed to ensure that the process did not exceed its 215 // authority. 216 virtual bool CanCommitURL(RenderProcessHost* process_host, const GURL& url); 217 218 // Returns whether a URL should be allowed to open from a specific context. 219 // This also applies in cases where the new URL will open in another process. 220 virtual bool ShouldAllowOpenURL(SiteInstance* site_instance, const GURL& url); 221 222 // Returns whether a new view for a given |site_url| can be launched in a 223 // given |process_host|. 224 virtual bool IsSuitableHost(RenderProcessHost* process_host, 225 const GURL& site_url); 226 227 // Returns whether a new process should be created or an existing one should 228 // be reused based on the URL we want to load. This should return false, 229 // unless there is a good reason otherwise. 230 virtual bool ShouldTryToUseExistingProcessHost( 231 BrowserContext* browser_context, const GURL& url); 232 233 // Called when a site instance is first associated with a process. 234 virtual void SiteInstanceGotProcess(SiteInstance* site_instance) {} 235 236 // Called from a site instance's destructor. 237 virtual void SiteInstanceDeleting(SiteInstance* site_instance) {} 238 239 // Returns true if for the navigation from |current_url| to |new_url| 240 // in |site_instance|, a new SiteInstance and BrowsingInstance should be 241 // created (even if we are in a process model that doesn't usually swap.) 242 // This forces a process swap and severs script connections with existing 243 // tabs. 244 virtual bool ShouldSwapBrowsingInstancesForNavigation( 245 SiteInstance* site_instance, 246 const GURL& current_url, 247 const GURL& new_url); 248 249 // Returns true if the given navigation redirect should cause a renderer 250 // process swap. 251 // This is called on the IO thread. 252 virtual bool ShouldSwapProcessesForRedirect(ResourceContext* resource_context, 253 const GURL& current_url, 254 const GURL& new_url); 255 256 // Returns true if the passed in URL should be assigned as the site of the 257 // current SiteInstance, if it does not yet have a site. 258 virtual bool ShouldAssignSiteForURL(const GURL& url); 259 260 // See CharacterEncoding's comment. 261 virtual std::string GetCanonicalEncodingNameByAliasName( 262 const std::string& alias_name); 263 264 // Allows the embedder to pass extra command line flags. 265 // switches::kProcessType will already be set at this point. 266 virtual void AppendExtraCommandLineSwitches(CommandLine* command_line, 267 int child_process_id) {} 268 269 // Returns the locale used by the application. 270 // This is called on the UI and IO threads. 271 virtual std::string GetApplicationLocale(); 272 273 // Returns the languages used in the Accept-Languages HTTP header. 274 // (Not called GetAcceptLanguages so it doesn't clash with win32). 275 virtual std::string GetAcceptLangs(BrowserContext* context); 276 277 // Returns the default favicon. The callee doesn't own the given bitmap. 278 virtual gfx::ImageSkia* GetDefaultFavicon(); 279 280 // Allow the embedder to control if an AppCache can be used for the given url. 281 // This is called on the IO thread. 282 virtual bool AllowAppCache(const GURL& manifest_url, 283 const GURL& first_party, 284 ResourceContext* context); 285 286 // Allow the embedder to control if the given cookie can be read. 287 // This is called on the IO thread. 288 virtual bool AllowGetCookie(const GURL& url, 289 const GURL& first_party, 290 const net::CookieList& cookie_list, 291 ResourceContext* context, 292 int render_process_id, 293 int render_view_id); 294 295 // Allow the embedder to control if the given cookie can be set. 296 // This is called on the IO thread. 297 virtual bool AllowSetCookie(const GURL& url, 298 const GURL& first_party, 299 const std::string& cookie_line, 300 ResourceContext* context, 301 int render_process_id, 302 int render_view_id, 303 net::CookieOptions* options); 304 305 // This is called on the IO thread. 306 virtual bool AllowSaveLocalState(ResourceContext* context); 307 308 // Allow the embedder to control if access to web database by a shared worker 309 // is allowed. |render_views| is a vector of pairs of 310 // RenderProcessID/RenderViewID of RenderViews that are using this worker. 311 // This is called on the IO thread. 312 virtual bool AllowWorkerDatabase( 313 const GURL& url, 314 const base::string16& name, 315 const base::string16& display_name, 316 unsigned long estimated_size, 317 ResourceContext* context, 318 const std::vector<std::pair<int, int> >& render_views); 319 320 // Allow the embedder to control if access to file system by a shared worker 321 // is allowed. 322 // This is called on the IO thread. 323 virtual bool AllowWorkerFileSystem( 324 const GURL& url, 325 ResourceContext* context, 326 const std::vector<std::pair<int, int> >& render_views); 327 328 // Allow the embedder to control if access to IndexedDB by a shared worker 329 // is allowed. 330 // This is called on the IO thread. 331 virtual bool AllowWorkerIndexedDB( 332 const GURL& url, 333 const base::string16& name, 334 ResourceContext* context, 335 const std::vector<std::pair<int, int> >& render_views); 336 337 // Allow the embedder to override the request context based on the URL for 338 // certain operations, like cookie access. Returns NULL to indicate the 339 // regular request context should be used. 340 // This is called on the IO thread. 341 virtual net::URLRequestContext* OverrideRequestContextForURL( 342 const GURL& url, ResourceContext* context); 343 344 // Allow the embedder to specify a string version of the storage partition 345 // config with a site. 346 virtual std::string GetStoragePartitionIdForSite( 347 content::BrowserContext* browser_context, 348 const GURL& site); 349 350 // Allows the embedder to provide a validation check for |partition_id|s. 351 // This domain of valid entries should match the range of outputs for 352 // GetStoragePartitionIdForChildProcess(). 353 virtual bool IsValidStoragePartitionId(BrowserContext* browser_context, 354 const std::string& partition_id); 355 356 // Allows the embedder to provide a storage parititon configuration for a 357 // site. A storage partition configuration includes a domain of the embedder's 358 // choice, an optional name within that domain, and whether the partition is 359 // in-memory only. 360 // 361 // If |can_be_default| is false, the caller is telling the embedder that the 362 // |site| is known to not be in the default partition. This is useful in 363 // some shutdown situations where the bookkeeping logic that maps sites to 364 // their partition configuration are no longer valid. 365 // 366 // The |partition_domain| is [a-z]* UTF-8 string, specifying the domain in 367 // which partitions live (similar to namespace). Within a domain, partitions 368 // can be uniquely identified by the combination of |partition_name| and 369 // |in_memory| values. When a partition is not to be persisted, the 370 // |in_memory| value must be set to true. 371 virtual void GetStoragePartitionConfigForSite( 372 content::BrowserContext* browser_context, 373 const GURL& site, 374 bool can_be_default, 375 std::string* partition_domain, 376 std::string* partition_name, 377 bool* in_memory); 378 379 // Create and return a new quota permission context. 380 virtual QuotaPermissionContext* CreateQuotaPermissionContext(); 381 382 // Informs the embedder that a certificate error has occured. If 383 // |overridable| is true and if |strict_enforcement| is false, the user 384 // can ignore the error and continue. The embedder can call the callback 385 // asynchronously. If |result| is not set to 386 // CERTIFICATE_REQUEST_RESULT_TYPE_CONTINUE, the request will be cancelled 387 // or denied immediately, and the callback won't be run. 388 virtual void AllowCertificateError( 389 int render_process_id, 390 int render_view_id, 391 int cert_error, 392 const net::SSLInfo& ssl_info, 393 const GURL& request_url, 394 ResourceType::Type resource_type, 395 bool overridable, 396 bool strict_enforcement, 397 const base::Callback<void(bool)>& callback, 398 CertificateRequestResultType* result) {} 399 400 // Selects a SSL client certificate and returns it to the |callback|. If no 401 // certificate was selected NULL is returned to the |callback|. 402 virtual void SelectClientCertificate( 403 int render_process_id, 404 int render_view_id, 405 const net::HttpNetworkSession* network_session, 406 net::SSLCertRequestInfo* cert_request_info, 407 const base::Callback<void(net::X509Certificate*)>& callback) {} 408 409 // Adds a new installable certificate or private key. 410 // Typically used to install an X.509 user certificate. 411 // Note that it's up to the embedder to verify that the data is 412 // well-formed. |cert_data| will be NULL if file_size is 0. 413 virtual void AddCertificate( 414 net::URLRequest* request, 415 net::CertificateMimeType cert_type, 416 const void* cert_data, 417 size_t cert_size, 418 int render_process_id, 419 int render_view_id) {} 420 421 // Returns a class to get notifications about media event. The embedder can 422 // return NULL if they're not interested. 423 virtual MediaObserver* GetMediaObserver(); 424 425 // Asks permission to show desktop notifications. 426 virtual void RequestDesktopNotificationPermission( 427 const GURL& source_origin, 428 int callback_context, 429 int render_process_id, 430 int render_view_id) {} 431 432 // Checks if the given page has permission to show desktop notifications. 433 // This is called on the IO thread. 434 virtual blink::WebNotificationPresenter::Permission 435 CheckDesktopNotificationPermission( 436 const GURL& source_url, 437 ResourceContext* context, 438 int render_process_id); 439 440 // Show a desktop notification. If |worker| is true, the request came from an 441 // HTML5 web worker, otherwise, it came from a renderer. 442 virtual void ShowDesktopNotification( 443 const ShowDesktopNotificationHostMsgParams& params, 444 int render_process_id, 445 int render_view_id, 446 bool worker) {} 447 448 // Cancels a displayed desktop notification. 449 virtual void CancelDesktopNotification( 450 int render_process_id, 451 int render_view_id, 452 int notification_id) {} 453 454 // Returns true if the given page is allowed to open a window of the given 455 // type. If true is returned, |no_javascript_access| will indicate whether 456 // the window that is created should be scriptable/in the same process. 457 // This is called on the IO thread. 458 virtual bool CanCreateWindow(const GURL& opener_url, 459 const GURL& opener_top_level_frame_url, 460 const GURL& source_origin, 461 WindowContainerType container_type, 462 const GURL& target_url, 463 const content::Referrer& referrer, 464 WindowOpenDisposition disposition, 465 const blink::WebWindowFeatures& features, 466 bool user_gesture, 467 bool opener_suppressed, 468 content::ResourceContext* context, 469 int render_process_id, 470 bool is_guest, 471 int opener_id, 472 bool* no_javascript_access); 473 474 // Returns a title string to use in the task manager for a process host with 475 // the given URL, or the empty string to fall back to the default logic. 476 // This is called on the IO thread. 477 virtual std::string GetWorkerProcessTitle(const GURL& url, 478 ResourceContext* context); 479 480 // Notifies the embedder that the ResourceDispatcherHost has been created. 481 // This is when it can optionally add a delegate. 482 virtual void ResourceDispatcherHostCreated() {} 483 484 // Allows the embedder to return a delegate for the SpeechRecognitionManager. 485 // The delegate will be owned by the manager. It's valid to return NULL. 486 virtual SpeechRecognitionManagerDelegate* 487 GetSpeechRecognitionManagerDelegate(); 488 489 // Getters for common objects. 490 virtual net::NetLog* GetNetLog(); 491 492 // Creates a new AccessTokenStore for gelocation. 493 virtual AccessTokenStore* CreateAccessTokenStore(); 494 495 // Returns true if fast shutdown is possible. 496 virtual bool IsFastShutdownPossible(); 497 498 // Called by WebContents to override the WebKit preferences that are used by 499 // the renderer. The content layer will add its own settings, and then it's up 500 // to the embedder to update it if it wants. 501 virtual void OverrideWebkitPrefs(RenderViewHost* render_view_host, 502 const GURL& url, 503 WebPreferences* prefs) {} 504 505 // Inspector setting was changed and should be persisted. 506 virtual void UpdateInspectorSetting(RenderViewHost* rvh, 507 const std::string& key, 508 const std::string& value) {} 509 510 // Notifies that BrowserURLHandler has been created, so that the embedder can 511 // optionally add their own handlers. 512 virtual void BrowserURLHandlerCreated(BrowserURLHandler* handler) {} 513 514 // Clears browser cache. 515 virtual void ClearCache(RenderViewHost* rvh) {} 516 517 // Clears browser cookies. 518 virtual void ClearCookies(RenderViewHost* rvh) {} 519 520 // Returns the default download directory. 521 // This can be called on any thread. 522 virtual base::FilePath GetDefaultDownloadDirectory(); 523 524 // Returns the default filename used in downloads when we have no idea what 525 // else we should do with the file. 526 virtual std::string GetDefaultDownloadName(); 527 528 // Notification that a pepper plugin has just been spawned. This allows the 529 // embedder to add filters onto the host to implement interfaces. 530 // This is called on the IO thread. 531 virtual void DidCreatePpapiPlugin(BrowserPpapiHost* browser_host) {} 532 533 // Gets the host for an external out-of-process plugin. 534 virtual content::BrowserPpapiHost* GetExternalBrowserPpapiHost( 535 int plugin_child_id); 536 537 // Returns true if the given browser_context and site_url support hosting 538 // BrowserPlugins. 539 virtual bool SupportsBrowserPlugin(BrowserContext* browser_context, 540 const GURL& site_url); 541 542 // Returns true if the socket operation specified by |params| is allowed from 543 // the given |browser_context| and |url|. If |params| is NULL, this method 544 // checks the basic "socket" permission, which is for those operations that 545 // don't require a specific socket permission rule. 546 // |private_api| indicates whether this permission check is for the private 547 // Pepper socket API or the public one. 548 virtual bool AllowPepperSocketAPI(BrowserContext* browser_context, 549 const GURL& url, 550 bool private_api, 551 const SocketPermissionRequest* params); 552 553 // Returns an implementation of a file selecition policy. Can return NULL. 554 virtual ui::SelectFilePolicy* CreateSelectFilePolicy( 555 WebContents* web_contents); 556 557 // Returns additional allowed scheme set which can access files in 558 // FileSystem API. 559 virtual void GetAdditionalAllowedSchemesForFileSystem( 560 std::vector<std::string>* additional_schemes) {} 561 562 // Returns additional file system backends for FileSystem API. 563 // |browser_context| is needed in the additional FileSystemBackends. 564 // It has mount points to create objects returned by additional 565 // FileSystemBackends, and SpecialStoragePolicy for permission granting. 566 virtual void GetAdditionalFileSystemBackends( 567 BrowserContext* browser_context, 568 const base::FilePath& storage_partition_path, 569 ScopedVector<fileapi::FileSystemBackend>* additional_backends) {} 570 571 // Allows an embedder to return its own LocationProvider implementation. 572 // Return NULL to use the default one for the platform to be created. 573 // FYI: Used by an external project; please don't remove. 574 // Contact Viatcheslav Ostapenko at sl.ostapenko (at) samsung.com for more 575 // information. 576 virtual LocationProvider* OverrideSystemLocationProvider(); 577 578 // Allows an embedder to return its own VibrationProvider implementation. 579 // Return NULL to use the default one for the platform to be created. 580 // FYI: Used by an external project; please don't remove. 581 // Contact Viatcheslav Ostapenko at sl.ostapenko (at) samsung.com for more 582 // information. 583 virtual VibrationProvider* OverrideVibrationProvider(); 584 585 #if defined(OS_POSIX) && !defined(OS_MACOSX) 586 // Populates |mappings| with all files that need to be mapped before launching 587 // a child process. 588 virtual void GetAdditionalMappedFilesForChildProcess( 589 const CommandLine& command_line, 590 int child_process_id, 591 std::vector<FileDescriptorInfo>* mappings) {} 592 #endif 593 594 #if defined(OS_WIN) 595 // Returns the name of the dll that contains cursors and other resources. 596 virtual const wchar_t* GetResourceDllName(); 597 598 // This is called on the PROCESS_LAUNCHER thread before the renderer process 599 // is launched. It gives the embedder a chance to add loosen the sandbox 600 // policy. 601 virtual void PreSpawnRenderer(sandbox::TargetPolicy* policy, 602 bool* success) {} 603 #endif 604 605 // Returns true if plugin referred to by the url can use 606 // pp::FileIO::RequestOSFileHandle. 607 virtual bool IsPluginAllowedToCallRequestOSFileHandle( 608 content::BrowserContext* browser_context, 609 const GURL& url); 610 611 // Returns true if dev channel APIs are available for plugins. 612 virtual bool IsPluginAllowedToUseDevChannelAPIs(); 613 }; 614 615 } // namespace content 616 617 #endif // CONTENT_PUBLIC_BROWSER_CONTENT_BROWSER_CLIENT_H_ 618