Move NetworkStorageSession ownership to NetworkProcess
[WebKit-https.git] / Source / WebCore / platform / network / soup / DNSResolveQueueSoup.cpp
1 /*
2  * Copyright (C) 2008 Apple Inc.  All rights reserved.
3  * Copyright (C) 2009, 2012 Igalia S.L.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
25  */
26
27 #include "config.h"
28 #include "DNSResolveQueueSoup.h"
29
30 #if USE(SOUP)
31
32 #include "NetworkStorageSession.h"
33 #include "SoupNetworkSession.h"
34 #include <libsoup/soup.h>
35 #include <wtf/CompletionHandler.h>
36 #include <wtf/Function.h>
37 #include <wtf/MainThread.h>
38 #include <wtf/NeverDestroyed.h>
39 #include <wtf/glib/GUniquePtr.h>
40 #include <wtf/text/CString.h>
41
42 namespace WebCore {
43
44 // Initially true to ensure prefetch stays disabled until we have proxy settings.
45 static bool isUsingHttpProxy = true;
46 static bool isUsingHttpsProxy = true;
47
48 static bool didResolveProxy(char** uris)
49 {
50     // We have a list of possible proxies to use for the URI. If the first item in the list is
51     // direct:// (the usual case), then the user prefers not to use a proxy. This is similar to
52     // resolving hostnames: there could be many possibilities returned in order of preference, and
53     // if we're trying to connect we should attempt each one in order, but here we are not trying
54     // to connect, merely to decide whether a proxy "should" be used.
55     return uris && *uris && strcmp(*uris, "direct://");
56 }
57
58 static void didResolveProxy(GProxyResolver* resolver, GAsyncResult* result, bool* isUsingProxyType, bool* isUsingProxy)
59 {
60     GUniqueOutPtr<GError> error;
61     GUniquePtr<char*> uris(g_proxy_resolver_lookup_finish(resolver, result, &error.outPtr()));
62     if (error) {
63         WTFLogAlways("Error determining system proxy settings: %s", error->message);
64         return;
65     }
66
67     *isUsingProxyType = didResolveProxy(uris.get());
68     *isUsingProxy = isUsingHttpProxy || isUsingHttpsProxy;
69 }
70
71 static void proxyResolvedForHttpUriCallback(GObject* source, GAsyncResult* result, void* userData)
72 {
73     didResolveProxy(G_PROXY_RESOLVER(source), result, &isUsingHttpProxy, static_cast<bool*>(userData));
74 }
75
76 static void proxyResolvedForHttpsUriCallback(GObject* source, GAsyncResult* result, void* userData)
77 {
78     didResolveProxy(G_PROXY_RESOLVER(source), result, &isUsingHttpsProxy, static_cast<bool*>(userData));
79 }
80
81 Function<NetworkStorageSession&()>& globalDefaultNetworkStorageSessionAccessor()
82 {
83     static NeverDestroyed<Function<NetworkStorageSession&()>> accessor;
84     return accessor.get();
85 }
86
87 void DNSResolveQueueSoup::setGlobalDefaultNetworkStorageSessionAccessor(Function<NetworkStorageSession&()>&& accessor)
88 {
89     globalDefaultNetworkStorageSessionAccessor() = WTFMove(accessor);
90 }
91
92 void DNSResolveQueueSoup::updateIsUsingProxy()
93 {
94     GRefPtr<GProxyResolver> resolver;
95     g_object_get(globalDefaultNetworkStorageSessionAccessor()().getOrCreateSoupNetworkSession().soupSession(), "proxy-resolver", &resolver.outPtr(), nullptr);
96     ASSERT(resolver);
97
98     g_proxy_resolver_lookup_async(resolver.get(), "http://example.com/", nullptr, proxyResolvedForHttpUriCallback, &m_isUsingProxy);
99     g_proxy_resolver_lookup_async(resolver.get(), "https://example.com/", nullptr, proxyResolvedForHttpsUriCallback, &m_isUsingProxy);
100 }
101
102 static void resolvedCallback(SoupAddress*, guint, void*)
103 {
104     DNSResolveQueue::singleton().decrementRequestCount();
105 }
106
107 static void resolvedWithObserverCallback(SoupAddress* address, guint status, void* data)
108 {
109     ASSERT(data);
110     auto* resolveQueue = static_cast<DNSResolveQueueSoup*>(data);
111
112     uint64_t identifier = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(address), "identifier"));
113
114     auto completionAndCancelHandlers = resolveQueue->takeCompletionAndCancelHandlers(identifier);
115
116     if (!completionAndCancelHandlers)
117         return;
118
119     auto completionHandler = WTFMove(completionAndCancelHandlers.get()->first);
120
121     if (status != SOUP_STATUS_OK) {
122         DNSError error = DNSError::Unknown;
123
124         switch (status) {
125         case SOUP_STATUS_CANT_RESOLVE:
126             error = DNSError::CannotResolve;
127             break;
128         case SOUP_STATUS_CANCELLED:
129             error = DNSError::Cancelled;
130             break;
131         case SOUP_STATUS_OK:
132         default:
133             ASSERT_NOT_REACHED();
134         };
135
136         completionHandler(makeUnexpected(error));
137         return;
138     }
139
140     if (!soup_address_is_resolved(address)) {
141         completionHandler(makeUnexpected(DNSError::Unknown));
142         return;
143     }
144
145     Vector<WebCore::IPAddress> addresses;
146     addresses.reserveInitialCapacity(1);
147     int len;
148     auto* ipAddress = reinterpret_cast<const struct sockaddr_in*>(soup_address_get_sockaddr(address, &len));
149     for (unsigned i = 0; i < sizeof(*ipAddress) / len; i++)
150         addresses.uncheckedAppend(WebCore::IPAddress(ipAddress[i]));
151
152     completionHandler(addresses);
153 }
154
155 std::unique_ptr<DNSResolveQueueSoup::CompletionAndCancelHandlers> DNSResolveQueueSoup::takeCompletionAndCancelHandlers(uint64_t identifier)
156 {
157     ASSERT(isMainThread());
158
159     auto completionAndCancelHandlers = m_completionAndCancelHandlers.take(identifier);
160
161     if (!completionAndCancelHandlers)
162         return nullptr;
163
164     return WTFMove(completionAndCancelHandlers);
165 }
166
167 void DNSResolveQueueSoup::removeCancelAndCompletionHandler(uint64_t identifier)
168 {
169     ASSERT(isMainThread());
170
171     m_completionAndCancelHandlers.remove(identifier);
172 }
173
174 void DNSResolveQueueSoup::platformResolve(const String& hostname)
175 {
176     ASSERT(isMainThread());
177
178     soup_session_prefetch_dns(globalDefaultNetworkStorageSessionAccessor()().getOrCreateSoupNetworkSession().soupSession(), hostname.utf8().data(), nullptr, resolvedCallback, nullptr);
179 }
180
181 void DNSResolveQueueSoup::resolve(const String& hostname, uint64_t identifier, DNSCompletionHandler&& completionHandler)
182 {
183     ASSERT(isMainThread());
184
185     auto address = adoptGRef(soup_address_new(hostname.utf8().data(), 0));
186     auto cancellable = adoptGRef(g_cancellable_new());
187     soup_address_resolve_async(address.get(), soup_session_get_async_context(WebCore::globalDefaultNetworkStorageSessionAccessor()().getOrCreateSoupNetworkSession().soupSession()), cancellable.get(), resolvedWithObserverCallback, this);
188
189     g_object_set_data(G_OBJECT(address.get()), "identifier", GUINT_TO_POINTER(identifier));
190
191     m_completionAndCancelHandlers.add(identifier, std::make_unique<DNSResolveQueueSoup::CompletionAndCancelHandlers>(WTFMove(completionHandler), WTFMove(cancellable)));
192 }
193
194 void DNSResolveQueueSoup::stopResolve(uint64_t identifier)
195 {
196     ASSERT(isMainThread());
197
198     if (auto completionAndCancelHandler = m_completionAndCancelHandlers.take(identifier)) {
199         g_cancellable_cancel(completionAndCancelHandler.get()->second.get());
200         completionAndCancelHandler.get()->first(makeUnexpected(DNSError::Cancelled));
201     }
202 }
203
204 }
205
206 #endif