1/*
2 * Copyright (C) 2013 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "CookieStorageShim.h"
28
29#if ENABLE(NETWORK_PROCESS)
30
31#include "CookieStorageShimLibrary.h"
32#include "NetworkConnectionToWebProcess.h"
33#include "NetworkProcessConnection.h"
34#include "WebCoreArgumentCoders.h"
35#include "WebProcess.h"
36#include <WebCore/SessionID.h>
37#include <WebCore/SoftLinking.h>
38#include <WebCore/URL.h>
39#include <dlfcn.h>
40#include <wtf/MainThread.h>
41#include <wtf/RetainPtr.h>
42#include <wtf/RunLoop.h>
43#include <wtf/text/WTFString.h>
44
45typedef const struct _CFURLRequest* CFURLRequestRef;
46@class NSURLSessionTask;
47
48SOFT_LINK_FRAMEWORK(CFNetwork)
49SOFT_LINK(CFNetwork, CFURLRequestGetURL, CFURLRef, (CFURLRequestRef request), (request))
50
51using namespace WebCore;
52
53@interface WKNSURLSessionLocal : NSObject
54- (CFDictionaryRef) _copyCookiesForRequestUsingAllAppropriateStorageSemantics:(CFURLRequestRef) request;
55#if PLATFORM(IOS) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
56- (void)_getCookieHeadersForTask:(NSURLSessionTask*)task completionHandler:(void (^)(CFDictionaryRef))completionHandler;
57#endif
58@end
59
60namespace WebKit {
61
62static CFDictionaryRef webKitCookieStorageCopyRequestHeaderFieldsForURL(CFHTTPCookieStorageRef inCookieStorage, CFURLRef inRequestURL)
63{
64    String cookies;
65    URL firstPartyForCookiesURL;
66    if (!WebProcess::shared().networkConnection()->connection()->sendSync(Messages::NetworkConnectionToWebProcess::CookieRequestHeaderFieldValue(SessionID::defaultSessionID(), firstPartyForCookiesURL, inRequestURL), Messages::NetworkConnectionToWebProcess::CookiesForDOM::Reply(cookies), 0))
67        return 0;
68
69    if (cookies.isNull())
70        return 0;
71
72    RetainPtr<CFStringRef> cfCookies = cookies.createCFString();
73    static const void* cookieKeys[] = { CFSTR("Cookie") };
74    const void* cookieValues[] = { cfCookies.get() };
75    return CFDictionaryCreate(0, cookieKeys, cookieValues, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
76}
77
78CookieStorageShim& CookieStorageShim::shared()
79{
80    static NeverDestroyed<CookieStorageShim> storage;
81    return storage;
82}
83
84void CookieStorageShim::initialize()
85{
86    CookieStorageShimCallbacks callbacks = { &webKitCookieStorageCopyRequestHeaderFieldsForURL };
87    CookieStorageShimInitializeFunc func = reinterpret_cast<CookieStorageShimInitializeFunc>(dlsym(RTLD_DEFAULT, "WebKitCookieStorageShimInitialize"));
88    if (func)
89        func(callbacks);
90
91    Class __NSURLSessionLocalClass = objc_getClass("__NSURLSessionLocal");
92    if (!__NSURLSessionLocalClass)
93        return;
94
95    if (Method original = class_getInstanceMethod(__NSURLSessionLocalClass, @selector(_copyCookiesForRequestUsingAllAppropriateStorageSemantics:))) {
96        Method replacement = class_getInstanceMethod([WKNSURLSessionLocal class], @selector(_copyCookiesForRequestUsingAllAppropriateStorageSemantics:));
97        ASSERT(replacement);
98        method_exchangeImplementations(original, replacement);
99    }
100
101#if PLATFORM(IOS) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
102    if (Method original = class_getInstanceMethod(__NSURLSessionLocalClass, @selector(_getCookieHeadersForTask:completionHandler:))) {
103        Method replacement = class_getInstanceMethod([WKNSURLSessionLocal class], @selector(_getCookieHeadersForTask:completionHandler:));
104        ASSERT(replacement);
105        method_exchangeImplementations(original, replacement);
106    }
107#endif
108}
109
110}
111
112@implementation WKNSURLSessionLocal
113- (CFDictionaryRef)_copyCookiesForRequestUsingAllAppropriateStorageSemantics:(CFURLRequestRef) request
114{
115    return WebKit::webKitCookieStorageCopyRequestHeaderFieldsForURL(nullptr, CFURLRequestGetURL(request));
116}
117
118#if PLATFORM(IOS) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
119using CompletionHandlerBlock = void(^)(CFDictionaryRef);
120- (void)_getCookieHeadersForTask:(NSURLSessionTask*)task completionHandler:(CompletionHandlerBlock)completionHandler
121{
122    if (!completionHandler)
123        return;
124
125    RetainPtr<NSURLSessionTask> strongTask = task;
126    CompletionHandlerBlock completionHandlerCopy = [completionHandler copy];
127    RunLoop::main().dispatch([strongTask, completionHandlerCopy]{
128        completionHandlerCopy(WebKit::webKitCookieStorageCopyRequestHeaderFieldsForURL(nullptr, (CFURLRef)[[strongTask currentRequest] URL]));
129        [completionHandlerCopy release];
130    });
131}
132#endif
133@end
134
135#endif // ENABLE(NETWORK_PROCESS)
136