chromium/ios/chrome/browser/profile/model/off_the_record_profile_ios_io_data.mm

// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#import "ios/chrome/browser/profile/model/off_the_record_profile_ios_io_data.h"

#import <UIKit/UIKit.h>

#import <utility>

#import "base/check_op.h"
#import "base/command_line.h"
#import "base/functional/bind.h"
#import "base/functional/callback_helpers.h"
#import "components/net_log/chrome_net_log.h"
#import "components/prefs/pref_service.h"
#import "ios/chrome/browser/browser_state/model/constants.h"
#import "ios/chrome/browser/browser_state/model/ios_chrome_io_thread.h"
#import "ios/chrome/browser/net/model/ios_chrome_network_delegate.h"
#import "ios/chrome/browser/net/model/ios_chrome_url_request_context_getter.h"
#import "ios/chrome/browser/shared/model/prefs/pref_names.h"
#import "ios/chrome/browser/shared/model/profile/profile_ios.h"
#import "ios/components/cookie_util/cookie_util.h"
#import "ios/net/cookies/system_cookie_store.h"
#import "ios/web/public/thread/web_task_traits.h"
#import "ios/web/public/thread/web_thread.h"
#import "net/cookies/cookie_store.h"
#import "net/disk_cache/disk_cache.h"
#import "net/http/http_cache.h"
#import "net/http/http_network_session.h"
#import "net/http/http_server_properties.h"
#import "net/url_request/url_request_context_builder.h"
#import "net/url_request/url_request_job_factory.h"

namespace {

// Called by the notification center on memory warnings.
void OnMemoryWarningReceived(CFNotificationCenterRef center,
                             void* observer,
                             CFStringRef name,
                             const void* object,
                             CFDictionaryRef userInfo) {
  OffTheRecordProfileIOSIOData::Handle* handle =
      (OffTheRecordProfileIOSIOData::Handle*)observer;
  handle->DoomIncognitoCache();
}

}  // namespace

void OffTheRecordProfileIOSIOData::Handle::DoomIncognitoCache() {
  // The cache for the incognito profile is in RAM.
  scoped_refptr<net::URLRequestContextGetter> getter =
      main_request_context_getter_;
  web::GetIOThreadTaskRunner({})->PostTask(
      FROM_HERE, base::BindOnce(^{
        DCHECK_CURRENTLY_ON(web::WebThread::IO);
        net::HttpCache* cache = getter->GetURLRequestContext()
                                    ->http_transaction_factory()
                                    ->GetCache();
        if (!cache->GetCurrentBackend()) {
          return;
        }
        cache->GetCurrentBackend()->DoomAllEntries(base::DoNothing());
      }));
}

OffTheRecordProfileIOSIOData::Handle::Handle(
    ChromeBrowserState* browser_state)
    : io_data_(new OffTheRecordProfileIOSIOData()),
      browser_state_(browser_state),
      initialized_(false) {
  DCHECK_CURRENTLY_ON(web::WebThread::UI);
  DCHECK(browser_state);
  io_data_->cookie_path_ =
      browser_state->GetStatePath().Append(kIOSChromeCookieFilename);
}

OffTheRecordProfileIOSIOData::Handle::~Handle() {
  DCHECK_CURRENTLY_ON(web::WebThread::UI);

  // Stop listening to notifications.
  CFNotificationCenterRemoveObserver(CFNotificationCenterGetLocalCenter(), this,
                                     nullptr, nullptr);

  io_data_->ShutdownOnUIThread(GetAllContextGetters());
}

scoped_refptr<IOSChromeURLRequestContextGetter>
OffTheRecordProfileIOSIOData::Handle::CreateMainRequestContextGetter(
    ProtocolHandlerMap* protocol_handlers) const {
  DCHECK_CURRENTLY_ON(web::WebThread::UI);
  LazyInitialize();
  DCHECK(!main_request_context_getter_.get());
  main_request_context_getter_ =
      IOSChromeURLRequestContextGetter::Create(io_data_, protocol_handlers);
  return main_request_context_getter_;
}

ProfileIOSIOData* OffTheRecordProfileIOSIOData::Handle::io_data() const {
  LazyInitialize();
  return io_data_;
}

void OffTheRecordProfileIOSIOData::Handle::LazyInitialize() const {
  if (initialized_) {
    return;
  }

  // Set initialized_ to true at the beginning in case any of the objects
  // below try to get the ResourceContext pointer.
  initialized_ = true;
  io_data_->InitializeOnUIThread(browser_state_);

  // Once initialized, listen to memory warnings.
  CFNotificationCenterAddObserver(
      CFNotificationCenterGetLocalCenter(), this, &OnMemoryWarningReceived,
      static_cast<CFStringRef>(
          UIApplicationDidReceiveMemoryWarningNotification),
      nullptr, CFNotificationSuspensionBehaviorCoalesce);
}

std::unique_ptr<
    ProfileIOSIOData::IOSChromeURLRequestContextGetterVector>
OffTheRecordProfileIOSIOData::Handle::GetAllContextGetters() {
  std::unique_ptr<IOSChromeURLRequestContextGetterVector> context_getters(
      new IOSChromeURLRequestContextGetterVector());
  if (main_request_context_getter_.get()) {
    context_getters->push_back(main_request_context_getter_);
  }

  return context_getters;
}

OffTheRecordProfileIOSIOData::OffTheRecordProfileIOSIOData()
    : ProfileIOSIOData(
          ChromeBrowserStateType::INCOGNITO_BROWSER_STATE) {}

OffTheRecordProfileIOSIOData::~OffTheRecordProfileIOSIOData() {}

void OffTheRecordProfileIOSIOData::InitializeInternal(
    net::URLRequestContextBuilder* context_builder,
    ProfileParams* profile_params) const {
  IOSChromeIOThread* const io_thread = profile_params->io_thread;

  context_builder->SetCookieStore(cookie_util::CreateCookieStore(
      cookie_util::CookieStoreConfig(
          cookie_path_,
          cookie_util::CookieStoreConfig::RESTORED_SESSION_COOKIES,
          cookie_util::CookieStoreConfig::COOKIE_STORE_IOS),
      std::move(profile_params->system_cookie_store), io_thread->net_log()));

  net::URLRequestContextBuilder::HttpCacheParams cache_params;
  cache_params.type = net::URLRequestContextBuilder::HttpCacheParams::IN_MEMORY;
  context_builder->EnableHttpCache(cache_params);
}