blob: c53d324340167e8b32b10ca07896fc8788bb2d54 [file] [log] [blame]
// Copyright 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.
#import "ios/chrome/browser/ui/chrome_web_view_factory.h"
#include "base/base64.h"
#include "base/logging.h"
#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
#include "ios/web/net/request_group_util.h"
#include "ios/web/net/request_tracker_impl.h"
#include "ios/web/public/web_thread.h"
#include "net/cookies/cookie_store.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
NSString* const kExternalUserAgent = @"UIWebViewForExternalContent";
namespace ChromeWebView {
// Shared desktop user agent used to mimic Safari on a mac.
NSString* const kDesktopUserAgent =
@"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) "
@"AppleWebKit/600.7.12 (KHTML, like Gecko) "
@"Version/8.0.7 "
@"Safari/600.7.12";
NSString* const kExternalRequestGroupID = @"kExternalRequestGroupID";
// Returns an absolute path where sharing service data is stored (such as
// cookies and server-bound certificates).
const base::FilePath GetExternalServicePath(
ios::ChromeBrowserState* browser_state,
IOSWebViewFactoryExternalService service) {
const base::FilePath path =
browser_state->GetOriginalChromeBrowserState()->GetStatePath();
switch (service) {
case SSO_AUTHENTICATION:
return path.Append("SSOAuthentication");
case NUM_SHARING_SERVICES:
NOTREACHED();
return path.Append("ExternalUnknownService");
}
}
} // namespace ChromeWebView
namespace {
ios::ChromeBrowserState* g_external_browser_state = nullptr;
scoped_refptr<web::RequestTrackerImpl> g_request_tracker;
// Empty callback used by ClearCookiesOnIOThread below.
void DoNothing(int n) {}
// Clears the cookies.
void ClearCookiesOnIOThread(net::URLRequestContextGetter* context_getter,
base::Time delete_begin,
base::Time delete_end) {
DCHECK(context_getter);
DCHECK_CURRENTLY_ON(web::WebThread::IO);
net::CookieStore* cookie_store =
context_getter->GetURLRequestContext()->cookie_store();
cookie_store->DeleteAllCreatedBetweenAsync(delete_begin, delete_end,
base::Bind(&DoNothing));
}
// Registers |user_agent| as the user agent string to be used by the UIWebView
// instances that are created from now on.
void RegisterUserAgentForUIWebView(NSString* user_agent) {
[[NSUserDefaults standardUserDefaults] registerDefaults:@{
@"UserAgent" : user_agent,
}];
}
} // namespace
@implementation ChromeWebViewFactory
+ (void)setBrowserStateToUseForExternal:(ios::ChromeBrowserState*)browserState {
g_external_browser_state = browserState;
}
+ (void)externalSessionFinished {
g_external_browser_state = nullptr;
if (g_request_tracker.get())
g_request_tracker->Close();
g_request_tracker = nullptr;
}
+ (net::URLRequestContextGetter*)requestContextForExternalService:
(IOSWebViewFactoryExternalService)externalService {
DCHECK(g_external_browser_state);
const base::FilePath servicePath =
[ChromeWebViewFactory partitionPathForExternalService:externalService];
return g_external_browser_state->CreateIsolatedRequestContext(servicePath);
}
+ (base::FilePath)partitionPathForExternalService:
(IOSWebViewFactoryExternalService)externalService {
return ChromeWebView::GetExternalServicePath(g_external_browser_state,
externalService);
}
+ (ChromeBrowserStateIOData*)ioDataForExternalWebViews {
DCHECK(g_external_browser_state);
return g_external_browser_state->GetIOData();
}
+ (void)clearExternalCookies:(IOSWebViewFactoryExternalService)externalService
browserState:(ios::ChromeBrowserState*)browserState
fromTime:(base::Time)deleteBegin
toTime:(base::Time)deleteEnd {
const base::FilePath servicePath =
ChromeWebView::GetExternalServicePath(browserState, externalService);
scoped_refptr<net::URLRequestContextGetter> contextGetter =
browserState->CreateIsolatedRequestContext(servicePath);
[self clearCookiesForContextGetter:contextGetter
fromTime:deleteBegin
toTime:deleteEnd];
}
+ (void)clearCookiesForContextGetter:
(scoped_refptr<net::URLRequestContextGetter>)contextGetter
fromTime:(base::Time)deleteBegin
toTime:(base::Time)deleteEnd {
DCHECK(contextGetter.get());
web::WebThread::PostTask(
web::WebThread::IO, FROM_HERE,
base::Bind(&ClearCookiesOnIOThread, base::RetainedRef(contextGetter),
deleteBegin, deleteEnd));
}
+ (void)clearExternalCookies:(ios::ChromeBrowserState*)browserState
fromTime:(base::Time)deleteBegin
toTime:(base::Time)deleteEnd {
for (unsigned int i = 0; i < NUM_SHARING_SERVICES; ++i) {
[ChromeWebViewFactory
clearExternalCookies:static_cast<IOSWebViewFactoryExternalService>(i)
browserState:browserState
fromTime:deleteBegin
toTime:deleteEnd];
}
}
#pragma mark -
#pragma mark ChromeWebViewFactory
+ (UIWebView*)newExternalWebView:
(IOSWebViewFactoryExternalService)externalService {
// All UIWebView's created for sharing share the same user agent, as there is
// no need for them to be differentiated and this choice ensures that only
// one request tracker is created on a per-sharing-session basis.
NSString* userAgent = web::AddRequestGroupIDToUserAgent(
kExternalUserAgent, ChromeWebView::kExternalRequestGroupID);
RegisterUserAgentForUIWebView(userAgent);
if (!g_request_tracker.get()) {
DCHECK(g_external_browser_state);
g_request_tracker = web::RequestTrackerImpl::CreateTrackerForRequestGroupID(
ChromeWebView::kExternalRequestGroupID, g_external_browser_state,
[self requestContextForExternalService:externalService], nil);
}
return [[UIWebView alloc] initWithFrame:CGRectZero];
}
@end