]> git.ipfire.org Git - thirdparty/hostap.git/blame - src/utils/browser.c
webkit2: Split resource-load-started handler into a separate function
[thirdparty/hostap.git] / src / utils / browser.c
CommitLineData
d0b79d74
JM
1/*
2 * Hotspot 2.0 client - Web browser using WebKit
3 * Copyright (c) 2013, Qualcomm Atheros, Inc.
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
9#include "includes.h"
b4b1b122
BG
10#ifdef USE_WEBKIT2
11#include <webkit2/webkit2.h>
12#else /* USE_WEBKIT2 */
d0b79d74 13#include <webkit/webkit.h>
b4b1b122 14#endif /* USE_WEBKIT2 */
d0b79d74
JM
15
16#include "common.h"
17#include "browser.h"
18
19
20struct browser_context {
21 GtkWidget *win;
c0c4685d 22 WebKitWebView *view;
d0b79d74
JM
23 int success;
24 int progress;
25 char *hover_link;
26 char *title;
7de8bd50
JM
27 int gtk_main_started;
28 int quit_gtk_main;
d0b79d74
JM
29};
30
31static void win_cb_destroy(GtkWidget *win, struct browser_context *ctx)
32{
33 wpa_printf(MSG_DEBUG, "BROWSER:%s", __func__);
7de8bd50
JM
34 if (ctx->gtk_main_started)
35 gtk_main_quit();
d0b79d74
JM
36}
37
38
39static void browser_update_title(struct browser_context *ctx)
40{
41 char buf[100];
42
43 if (ctx->hover_link) {
44 gtk_window_set_title(GTK_WINDOW(ctx->win), ctx->hover_link);
45 return;
46 }
47
48 if (ctx->progress == 100) {
49 gtk_window_set_title(GTK_WINDOW(ctx->win),
50 ctx->title ? ctx->title :
51 "Hotspot 2.0 client");
52 return;
53 }
54
55 snprintf(buf, sizeof(buf), "[%d%%] %s", ctx->progress,
56 ctx->title ? ctx->title : "Hotspot 2.0 client");
57 gtk_window_set_title(GTK_WINDOW(ctx->win), buf);
58}
59
60
b4b1b122 61#ifdef USE_WEBKIT2
9ea9d18d
JM
62static void view_cb_notify_estimated_load_progress(WebKitWebView *view,
63 GParamSpec *pspec,
64 struct browser_context *ctx)
65{
b4b1b122 66 ctx->progress = 100 * webkit_web_view_get_estimated_load_progress(view);
9ea9d18d
JM
67 wpa_printf(MSG_DEBUG, "BROWSER:%s progress=%d", __func__,
68 ctx->progress);
69 browser_update_title(ctx);
70}
b4b1b122 71#else /* USE_WEBKIT2 */
9ea9d18d
JM
72static void view_cb_notify_progress(WebKitWebView *view, GParamSpec *pspec,
73 struct browser_context *ctx)
74{
d0b79d74
JM
75 ctx->progress = 100 * webkit_web_view_get_progress(view);
76 wpa_printf(MSG_DEBUG, "BROWSER:%s progress=%d", __func__,
77 ctx->progress);
78 browser_update_title(ctx);
79}
9ea9d18d 80#endif /* USE_WEBKIT2 */
d0b79d74
JM
81
82
ae07bc46 83#ifndef USE_WEBKIT2
d0b79d74
JM
84static void view_cb_notify_load_status(WebKitWebView *view, GParamSpec *pspec,
85 struct browser_context *ctx)
86{
87 int status = webkit_web_view_get_load_status(view);
88 wpa_printf(MSG_DEBUG, "BROWSER:%s load-status=%d uri=%s",
89 __func__, status, webkit_web_view_get_uri(view));
7de8bd50
JM
90 if (ctx->quit_gtk_main) {
91 gtk_main_quit();
92 ctx->gtk_main_started = 0;
93 }
d0b79d74 94}
ae07bc46 95#endif /* USE_WEBKIT2 */
d0b79d74
JM
96
97
02ed737e
JM
98static void process_request_starting_uri(struct browser_context *ctx,
99 const char *uri)
d0b79d74 100{
7de8bd50
JM
101 int quit = 0;
102
d0b79d74
JM
103 if (g_str_has_prefix(uri, "osu://")) {
104 ctx->success = atoi(uri + 6);
7de8bd50
JM
105 quit = 1;
106 } else if (g_str_has_prefix(uri, "http://localhost:12345")) {
d0b79d74
JM
107 /*
108 * This is used as a special trigger to indicate that the
109 * user exchange has been completed.
110 */
111 ctx->success = 1;
7de8bd50
JM
112 quit = 1;
113 }
114
115 if (quit) {
116 if (ctx->gtk_main_started) {
117 gtk_main_quit();
118 ctx->gtk_main_started = 0;
119 } else {
120 ctx->quit_gtk_main = 1;
121 }
d0b79d74
JM
122 }
123}
124
125
02ed737e
JM
126#ifdef USE_WEBKIT2
127static void view_cb_resource_load_starting(WebKitWebView *view,
128 WebKitWebResource *res,
129 WebKitURIRequest *req,
130 struct browser_context *ctx)
131{
132 const gchar *uri = webkit_uri_request_get_uri(req);
133
134 wpa_printf(MSG_DEBUG, "BROWSER:%s uri=%s", __func__, uri);
135 if (g_str_has_suffix(uri, "/favicon.ico"))
136 webkit_uri_request_set_uri(req, "about:blank");
137
138 process_request_starting_uri(ctx, uri);
139}
140#else /* USE_WEBKIT2 */
141static void view_cb_resource_request_starting(WebKitWebView *view,
142 WebKitWebFrame *frame,
143 WebKitWebResource *res,
144 WebKitNetworkRequest *req,
145 WebKitNetworkResponse *resp,
146 struct browser_context *ctx)
147{
148 const gchar *uri = webkit_network_request_get_uri(req);
149
150 wpa_printf(MSG_DEBUG, "BROWSER:%s uri=%s", __func__, uri);
151 if (g_str_has_suffix(uri, "/favicon.ico"))
152 webkit_network_request_set_uri(req, "about:blank");
153
154 process_request_starting_uri(ctx, uri);
155}
156#endif /* USE_WEBKIT2 */
157
158
d0b79d74 159static gboolean view_cb_mime_type_policy_decision(
b4b1b122
BG
160 WebKitWebView *view,
161#ifndef USE_WEBKIT2
162 WebKitWebFrame *frame, WebKitNetworkRequest *req,
d0b79d74 163 gchar *mime, WebKitWebPolicyDecision *policy,
b4b1b122
BG
164#else /* USE_WEBKIT2 */
165 WebKitPolicyDecision *policy,
166 WebKitPolicyDecisionType type,
167#endif /* USE_WEBKIT2 */
d0b79d74
JM
168 struct browser_context *ctx)
169{
b4b1b122
BG
170#ifdef USE_WEBKIT2
171 wpa_printf(MSG_DEBUG, "BROWSER:%s type=%d", __func__, type);
172 switch (type) {
173 case WEBKIT_POLICY_DECISION_TYPE_RESPONSE: {
174 /* This function makes webkit send a download signal for all
175 * unknown mime types. */
176 WebKitResponsePolicyDecision *response;
177
178 response = WEBKIT_RESPONSE_POLICY_DECISION(policy);
179 if (!webkit_response_policy_decision_is_mime_type_supported(
180 response)) {
181 webkit_policy_decision_download(policy);
182 return TRUE;
183 }
184 break;
185 }
186 default:
187 break;
188 }
189#else /* USE_WEBKIT2 */
d0b79d74
JM
190 wpa_printf(MSG_DEBUG, "BROWSER:%s mime=%s", __func__, mime);
191
192 if (!webkit_web_view_can_show_mime_type(view, mime)) {
193 webkit_web_policy_decision_download(policy);
194 return TRUE;
195 }
b4b1b122 196#endif /* USE_WEBKIT2 */
d0b79d74
JM
197
198 return FALSE;
199}
200
201
b4b1b122 202#ifndef USE_WEBKIT2
d0b79d74
JM
203static gboolean view_cb_download_requested(WebKitWebView *view,
204 WebKitDownload *dl,
205 struct browser_context *ctx)
206{
207 const gchar *uri;
208 uri = webkit_download_get_uri(dl);
209 wpa_printf(MSG_DEBUG, "BROWSER:%s uri=%s", __func__, uri);
210 return FALSE;
211}
b4b1b122 212#endif /* USE_WEBKIT2 */
d0b79d74
JM
213
214
ffeafc08
JM
215#ifdef USE_WEBKIT2
216static void view_cb_mouse_target_changed(WebKitWebView *view,
217 WebKitHitTestResult *h,
218 guint modifiers,
219 struct browser_context *ctx)
220{
221 WebKitHitTestResultContext hc = webkit_hit_test_result_get_context(h);
222 const char *uri = NULL;
223
224 if (hc & WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK)
225 uri = webkit_hit_test_result_get_link_uri(h);
226 else if (hc & WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE)
227 uri = webkit_hit_test_result_get_image_uri(h);
228 else if (hc & WEBKIT_HIT_TEST_RESULT_CONTEXT_MEDIA)
229 uri = webkit_hit_test_result_get_media_uri(h);
230
231 wpa_printf(MSG_DEBUG, "BROWSER:%s uri=%s", __func__, uri ? uri : "N/A");
232 os_free(ctx->hover_link);
233 if (uri)
234 ctx->hover_link = os_strdup(uri);
235 else
236 ctx->hover_link = NULL;
237
238 browser_update_title(ctx);
239}
240#else /* USE_WEBKIT2 */
d0b79d74
JM
241static void view_cb_hovering_over_link(WebKitWebView *view, gchar *title,
242 gchar *uri, struct browser_context *ctx)
243{
244 wpa_printf(MSG_DEBUG, "BROWSER:%s title=%s uri=%s", __func__, title,
245 uri);
246 os_free(ctx->hover_link);
247 if (uri)
248 ctx->hover_link = os_strdup(uri);
249 else
250 ctx->hover_link = NULL;
251
252 browser_update_title(ctx);
253}
ffeafc08 254#endif /* USE_WEBKIT2 */
d0b79d74
JM
255
256
c0c4685d
JM
257#ifdef USE_WEBKIT2
258static void view_cb_notify_title(WebKitWebView *view, GParamSpec *ps,
259 struct browser_context *ctx)
260{
261 const char *title;
262
263 title = webkit_web_view_get_title(ctx->view);
264 wpa_printf(MSG_DEBUG, "BROWSER:%s title=%s", __func__, title);
265 os_free(ctx->title);
266 ctx->title = os_strdup(title);
267 browser_update_title(ctx);
268}
269#else /* USE_WEBKIT2 */
d0b79d74
JM
270static void view_cb_title_changed(WebKitWebView *view, WebKitWebFrame *frame,
271 const char *title,
272 struct browser_context *ctx)
273{
274 wpa_printf(MSG_DEBUG, "BROWSER:%s title=%s", __func__, title);
275 os_free(ctx->title);
276 ctx->title = os_strdup(title);
277 browser_update_title(ctx);
278}
b4b1b122 279#endif /* USE_WEBKIT2 */
d0b79d74
JM
280
281
61bf9819 282int hs20_web_browser(const char *url, int ignore_tls)
d0b79d74
JM
283{
284 GtkWidget *scroll;
d0b79d74 285 WebKitWebView *view;
b4b1b122
BG
286#ifdef USE_WEBKIT2
287 WebKitSettings *settings;
288#else /* USE_WEBKIT2 */
d0b79d74 289 WebKitWebSettings *settings;
b4b1b122
BG
290 SoupSession *s;
291#endif /* USE_WEBKIT2 */
d0b79d74
JM
292 struct browser_context ctx;
293
294 memset(&ctx, 0, sizeof(ctx));
295 if (!gtk_init_check(NULL, NULL))
296 return -1;
297
b4b1b122 298#ifndef USE_WEBKIT2
d0b79d74
JM
299 s = webkit_get_default_session();
300 g_object_set(G_OBJECT(s), "ssl-ca-file",
301 "/etc/ssl/certs/ca-certificates.crt", NULL);
61bf9819
JM
302 if (ignore_tls)
303 g_object_set(G_OBJECT(s), "ssl-strict", FALSE, NULL);
b4b1b122 304#endif /* USE_WEBKIT2 */
d0b79d74
JM
305
306 ctx.win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
a139ddb6 307 gtk_window_set_role(GTK_WINDOW(ctx.win), "Hotspot 2.0 client");
d0b79d74
JM
308 gtk_window_set_default_size(GTK_WINDOW(ctx.win), 800, 600);
309
310 scroll = gtk_scrolled_window_new(NULL, NULL);
311 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
312 GTK_POLICY_NEVER, GTK_POLICY_NEVER);
313
314 g_signal_connect(G_OBJECT(ctx.win), "destroy",
315 G_CALLBACK(win_cb_destroy), &ctx);
316
317 view = WEBKIT_WEB_VIEW(webkit_web_view_new());
c0c4685d 318 ctx.view = view;
b4b1b122 319#ifdef USE_WEBKIT2
9ea9d18d
JM
320 g_signal_connect(G_OBJECT(view), "notify::estimated-load-progress",
321 G_CALLBACK(view_cb_notify_estimated_load_progress),
322 &ctx);
b4b1b122 323 g_signal_connect(G_OBJECT(view), "resource-load-started",
02ed737e 324 G_CALLBACK(view_cb_resource_load_starting), &ctx);
b4b1b122
BG
325 g_signal_connect(G_OBJECT(view), "decide-policy",
326 G_CALLBACK(view_cb_mime_type_policy_decision), &ctx);
ffeafc08
JM
327 g_signal_connect(G_OBJECT(view), "mouse-target-changed",
328 G_CALLBACK(view_cb_mouse_target_changed), &ctx);
c0c4685d
JM
329 g_signal_connect(G_OBJECT(view), "notify::title",
330 G_CALLBACK(view_cb_notify_title), &ctx);
b4b1b122 331#else /* USE_WEBKIT2 */
ae07bc46
JM
332 g_signal_connect(G_OBJECT(view), "notify::load-status",
333 G_CALLBACK(view_cb_notify_load_status), &ctx);
9ea9d18d
JM
334 g_signal_connect(G_OBJECT(view), "notify::progress",
335 G_CALLBACK(view_cb_notify_progress), &ctx);
d0b79d74
JM
336 g_signal_connect(G_OBJECT(view), "resource-request-starting",
337 G_CALLBACK(view_cb_resource_request_starting), &ctx);
338 g_signal_connect(G_OBJECT(view), "mime-type-policy-decision-requested",
339 G_CALLBACK(view_cb_mime_type_policy_decision), &ctx);
340 g_signal_connect(G_OBJECT(view), "download-requested",
341 G_CALLBACK(view_cb_download_requested), &ctx);
ffeafc08
JM
342 g_signal_connect(G_OBJECT(view), "hovering-over-link",
343 G_CALLBACK(view_cb_hovering_over_link), &ctx);
d0b79d74
JM
344 g_signal_connect(G_OBJECT(view), "title-changed",
345 G_CALLBACK(view_cb_title_changed), &ctx);
b4b1b122
BG
346#endif /* USE_WEBKIT2 */
347
d0b79d74
JM
348 gtk_container_add(GTK_CONTAINER(scroll), GTK_WIDGET(view));
349 gtk_container_add(GTK_CONTAINER(ctx.win), GTK_WIDGET(scroll));
350
351 gtk_widget_grab_focus(GTK_WIDGET(view));
352 gtk_widget_show_all(ctx.win);
353
354 settings = webkit_web_view_get_settings(view);
355 g_object_set(G_OBJECT(settings), "user-agent",
356 "Mozilla/5.0 (X11; U; Unix; en-US) "
357 "AppleWebKit/537.15 (KHTML, like Gecko) "
358 "hs20-client/1.0", NULL);
359 g_object_set(G_OBJECT(settings), "auto-load-images", TRUE, NULL);
360
921ea496 361#ifdef USE_WEBKIT2
61bf9819
JM
362 if (ignore_tls) {
363 WebKitWebContext *wkctx;
364
365 wkctx = webkit_web_context_get_default();
366 webkit_web_context_set_tls_errors_policy(
367 wkctx, WEBKIT_TLS_ERRORS_POLICY_IGNORE);
368 }
921ea496
BG
369#endif /* USE_WEBKIT2 */
370
d0b79d74
JM
371 webkit_web_view_load_uri(view, url);
372
7de8bd50 373 ctx.gtk_main_started = 1;
d0b79d74
JM
374 gtk_main();
375 gtk_widget_destroy(ctx.win);
376 while (gtk_events_pending())
377 gtk_main_iteration();
378
379 free(ctx.hover_link);
380 free(ctx.title);
381 return ctx.success;
382}