Fix crash in ~WebProcessPool when using Geolocation with useNetworkProcess=true
[WebKit-https.git] / Tools / TestWebKitAPI / Tests / WebKit2 / Geolocation.cpp
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
28 #if WK_HAVE_C_SPI
29
30 #include "PlatformUtilities.h"
31 #include "PlatformWebView.h"
32 #include "Test.h"
33 #include <WebKit/WKContextPrivate.h>
34 #include <WebKit/WKRetainPtr.h>
35 #include <string.h>
36 #include <vector>
37
38 using namespace std;
39
40 namespace TestWebKitAPI {
41
42 enum class GeolocationEvent {
43     StartUpdating,
44     StopUpdating,
45     EnableHighAccuracy,
46     DisableHighAccuracy
47 };
48
49 ostream& operator<<(ostream& outputStream, const GeolocationEvent& geolocationEvent)
50 {
51     switch (geolocationEvent) {
52     case GeolocationEvent::StartUpdating:
53         outputStream << "GeolocationEvent::StartUpdating";
54         break;
55     case GeolocationEvent::StopUpdating:
56         outputStream << "GeolocationEvent::StopUpdating";
57         break;
58     case GeolocationEvent::EnableHighAccuracy:
59         outputStream << "GeolocationEvent::EnableHighAccuracy";
60         break;
61     case GeolocationEvent::DisableHighAccuracy:
62         outputStream << "GeolocationEvent::DisableHighAccuracy";
63         break;
64     }
65     return outputStream;
66 }
67
68 struct GeolocationStateTracker {
69     vector<GeolocationEvent> events;
70
71     virtual ~GeolocationStateTracker() { }
72     virtual void eventsChanged() { }
73
74     static void startUpdatingCallback(WKGeolocationManagerRef manager, const void* clientInfo)
75     {
76         GeolocationStateTracker* stateTracker = static_cast<GeolocationStateTracker*>(const_cast<void*>(clientInfo));
77         stateTracker->events.push_back(GeolocationEvent::StartUpdating);
78         stateTracker->eventsChanged();
79
80         WKRetainPtr<WKGeolocationPositionRef> position = adoptWK(WKGeolocationPositionCreate(0, 50.644358, 3.345453, 2.53));
81         WKGeolocationManagerProviderDidChangePosition(manager, position.get());
82     }
83
84     static void stopUpdatingCallback(WKGeolocationManagerRef, const void* clientInfo)
85     {
86         GeolocationStateTracker* stateTracker = static_cast<GeolocationStateTracker*>(const_cast<void*>(clientInfo));
87         stateTracker->events.push_back(GeolocationEvent::StopUpdating);
88         stateTracker->eventsChanged();
89     }
90
91     static void setEnableHighAccuracyCallback(WKGeolocationManagerRef, bool enable, const void* clientInfo)
92     {
93         GeolocationStateTracker* stateTracker = static_cast<GeolocationStateTracker*>(const_cast<void*>(clientInfo));
94         if (enable)
95             stateTracker->events.push_back(GeolocationEvent::EnableHighAccuracy);
96         else
97             stateTracker->events.push_back(GeolocationEvent::DisableHighAccuracy);
98         stateTracker->eventsChanged();
99     }
100 };
101
102 void decidePolicyForGeolocationPermissionRequestCallBack(WKPageRef page, WKFrameRef frame, WKSecurityOriginRef origin, WKGeolocationPermissionRequestRef permissionRequest, const void* clientInfo)
103 {
104     WKGeolocationPermissionRequestAllow(permissionRequest);
105 }
106
107 void setupGeolocationProvider(WKContextRef context, void *clientInfo)
108 {
109     WKGeolocationProviderV1 providerCallback;
110     memset(&providerCallback, 0, sizeof(WKGeolocationProviderV1));
111
112     providerCallback.base.version = 1;
113     providerCallback.base.clientInfo = clientInfo;
114     providerCallback.startUpdating = GeolocationStateTracker::startUpdatingCallback;
115     providerCallback.stopUpdating = GeolocationStateTracker::stopUpdatingCallback;
116     providerCallback.setEnableHighAccuracy = GeolocationStateTracker::setEnableHighAccuracyCallback;
117
118     WKGeolocationManagerSetProvider(WKContextGetGeolocationManager(context), &providerCallback.base);
119 }
120
121 void setupView(PlatformWebView& webView)
122 {
123     WKPageUIClientV2 uiClient;
124     memset(&uiClient, 0, sizeof(uiClient));
125
126     uiClient.base.version = 2;
127     uiClient.decidePolicyForGeolocationPermissionRequest = decidePolicyForGeolocationPermissionRequestCallBack;
128
129     WKPageSetPageUIClient(webView.page(), &uiClient.base);
130 }
131
132 // GeolocationBasic.
133 struct GeolocationBasicStateTracker : GeolocationStateTracker {
134     bool finished;
135
136     GeolocationBasicStateTracker() : finished(false) { }
137     virtual void eventsChanged()
138     {
139         switch (events.size()) {
140         case 1:
141             EXPECT_EQ(GeolocationEvent::DisableHighAccuracy, events[0]);
142             break;
143         case 2:
144             EXPECT_EQ(GeolocationEvent::StartUpdating, events[1]);
145             break;
146         case 3:
147             EXPECT_EQ(GeolocationEvent::StopUpdating, events[2]);
148             finished = true;
149             break;
150         default:
151             EXPECT_TRUE(false);
152             finished = true;
153         }
154     }
155 };
156
157 TEST(WebKit2, GeolocationBasic)
158 {
159     WKRetainPtr<WKContextRef> context(AdoptWK, WKContextCreate());
160
161     GeolocationBasicStateTracker stateTracker;
162     setupGeolocationProvider(context.get(), &stateTracker);
163
164     PlatformWebView webView(context.get());
165     setupView(webView);
166
167     WKRetainPtr<WKURLRef> url(AdoptWK, Util::createURLForResource("geolocationGetCurrentPosition", "html"));
168     WKPageLoadURL(webView.page(), url.get());
169
170     Util::run(&stateTracker.finished);
171 }
172
173 // Geolocation requested with High Accuracy.
174 struct GeolocationBasicWithHighAccuracyStateTracker : GeolocationStateTracker {
175     bool finished;
176
177     GeolocationBasicWithHighAccuracyStateTracker() : finished(false) { }
178     virtual void eventsChanged()
179     {
180         switch (events.size()) {
181         case 1:
182             EXPECT_EQ(GeolocationEvent::EnableHighAccuracy, events[0]);
183             break;
184         case 2:
185             EXPECT_EQ(GeolocationEvent::StartUpdating, events[1]);
186             break;
187         case 3:
188             EXPECT_EQ(GeolocationEvent::StopUpdating, events[2]);
189             finished = true;
190             break;
191         default:
192             EXPECT_TRUE(false);
193             finished = true;
194         }
195     }
196 };
197
198 TEST(WebKit2, GeolocationBasicWithHighAccuracy)
199 {
200     WKRetainPtr<WKContextRef> context(AdoptWK, WKContextCreate());
201
202     GeolocationBasicWithHighAccuracyStateTracker stateTracker;
203     setupGeolocationProvider(context.get(), &stateTracker);
204
205     PlatformWebView webView(context.get());
206     setupView(webView);
207
208     WKRetainPtr<WKURLRef> url(AdoptWK, Util::createURLForResource("geolocationGetCurrentPositionWithHighAccuracy", "html"));
209     WKPageLoadURL(webView.page(), url.get());
210
211     Util::run(&stateTracker.finished);
212 }
213
214 // Geolocation start without High Accuracy, then requires High Accuracy.
215 struct GeolocationTransitionToHighAccuracyStateTracker : GeolocationStateTracker {
216     bool finishedFirstStep { false };
217     bool enabledHighAccuracy { false };
218     bool finished { false };
219
220     virtual void eventsChanged()
221     {
222         switch (events.size()) {
223         case 1:
224             EXPECT_EQ(GeolocationEvent::DisableHighAccuracy, events[0]);
225             break;
226         case 2:
227             EXPECT_EQ(GeolocationEvent::StartUpdating, events[1]);
228             finishedFirstStep = true;
229             break;
230         case 3:
231             EXPECT_EQ(GeolocationEvent::EnableHighAccuracy, events[2]);
232             enabledHighAccuracy = true;
233             break;
234         case 4:
235             EXPECT_EQ(GeolocationEvent::DisableHighAccuracy, events[3]);
236             break;
237         case 5:
238             EXPECT_EQ(GeolocationEvent::StopUpdating, events[4]);
239             finished = true;
240             break;
241         default:
242             EXPECT_TRUE(false);
243             finishedFirstStep = true;
244             enabledHighAccuracy = true;
245             finished = true;
246         }
247     }
248 };
249
250 TEST(WebKit2, GeolocationTransitionToHighAccuracy)
251 {
252     WKRetainPtr<WKContextRef> context(AdoptWK, WKContextCreate());
253     WKContextSetUsesNetworkProcess(context.get(), true);
254
255     GeolocationTransitionToHighAccuracyStateTracker stateTracker;
256     setupGeolocationProvider(context.get(), &stateTracker);
257
258     PlatformWebView lowAccuracyWebView(context.get());
259     setupView(lowAccuracyWebView);
260     WKRetainPtr<WKURLRef> lowAccuracyURL(AdoptWK, Util::createURLForResource("geolocationWatchPosition", "html"));
261     WKPageLoadURL(lowAccuracyWebView.page(), lowAccuracyURL.get());
262     Util::run(&stateTracker.finishedFirstStep);
263
264     PlatformWebView highAccuracyWebView(context.get());
265     setupView(highAccuracyWebView);
266     WKRetainPtr<WKURLRef> highAccuracyURL(AdoptWK, Util::createURLForResource("geolocationWatchPositionWithHighAccuracy", "html"));
267     WKPageLoadURL(highAccuracyWebView.page(), highAccuracyURL.get());
268     Util::run(&stateTracker.enabledHighAccuracy);
269     
270     WKRetainPtr<WKURLRef> resetUrl = adoptWK(WKURLCreateWithUTF8CString("about:blank"));
271     WKPageLoadURL(highAccuracyWebView.page(), resetUrl.get());
272     Util::run(&stateTracker.enabledHighAccuracy);
273     WKPageLoadURL(lowAccuracyWebView.page(), resetUrl.get());
274     Util::run(&stateTracker.finished);
275 }
276
277 // Geolocation start with High Accuracy, then should fall back to low accuracy.
278 struct GeolocationTransitionToLowAccuracyStateTracker : GeolocationStateTracker {
279     bool finishedFirstStep { false };
280     bool disabledHighAccuracy { false };
281     bool finished { false };
282
283     virtual void eventsChanged()
284     {
285         switch (events.size()) {
286         case 1:
287             EXPECT_EQ(GeolocationEvent::EnableHighAccuracy, events[0]);
288             break;
289         case 2:
290             EXPECT_EQ(GeolocationEvent::StartUpdating, events[1]);
291             finishedFirstStep = true;
292             break;
293         case 3:
294             EXPECT_EQ(GeolocationEvent::DisableHighAccuracy, events[2]);
295             disabledHighAccuracy = true;
296             break;
297         case 4:
298             EXPECT_EQ(GeolocationEvent::StopUpdating, events[3]);
299             finished = true;
300             break;
301         default:
302             EXPECT_TRUE(false);
303             finishedFirstStep = true;
304             disabledHighAccuracy = true;
305             finished = true;
306         }
307     }
308 };
309
310 static void didFinishLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void* clientInfo)
311 {
312     *static_cast<bool*>(const_cast<void*>(clientInfo)) = true;
313 }
314
315 TEST(WebKit2, GeolocationTransitionToLowAccuracy)
316 {
317     WKRetainPtr<WKContextRef> context(AdoptWK, WKContextCreate());
318
319     GeolocationTransitionToLowAccuracyStateTracker stateTracker;
320     setupGeolocationProvider(context.get(), &stateTracker);
321
322     PlatformWebView highAccuracyWebView(context.get());
323     setupView(highAccuracyWebView);
324     WKRetainPtr<WKURLRef> highAccuracyURL(AdoptWK, Util::createURLForResource("geolocationWatchPositionWithHighAccuracy", "html"));
325     WKPageLoadURL(highAccuracyWebView.page(), highAccuracyURL.get());
326     Util::run(&stateTracker.finishedFirstStep);
327
328     PlatformWebView lowAccuracyWebView(context.get());
329     setupView(lowAccuracyWebView);
330
331     bool finishedSecondStep = false;
332
333     WKPageLoaderClientV0 loaderClient;
334     memset(&loaderClient, 0, sizeof(loaderClient));
335
336     loaderClient.base.version = 0;
337     loaderClient.base.clientInfo = &finishedSecondStep;
338     loaderClient.didFinishLoadForFrame = didFinishLoadForFrame;
339
340     WKPageSetPageLoaderClient(lowAccuracyWebView.page(), &loaderClient.base);
341
342     WKRetainPtr<WKURLRef> lowAccuracyURL(AdoptWK, Util::createURLForResource("geolocationWatchPosition", "html"));
343     WKPageLoadURL(lowAccuracyWebView.page(), lowAccuracyURL.get());
344     Util::run(&finishedSecondStep);
345
346     WKRetainPtr<WKURLRef> resetUrl = adoptWK(WKURLCreateWithUTF8CString("about:blank"));
347     WKPageLoadURL(highAccuracyWebView.page(), resetUrl.get());
348     Util::run(&stateTracker.disabledHighAccuracy);
349     WKPageLoadURL(lowAccuracyWebView.page(), resetUrl.get());
350     Util::run(&stateTracker.finished);
351 }
352
353 } // namespace TestWebKitAPI
354
355 #endif