diff options
author | Michael Catanzaro <mcatanzaro@gnome.org> | 2016-09-11 15:03:13 -0500 |
---|---|---|
committer | Michael Catanzaro <mcatanzaro@gnome.org> | 2016-09-12 13:38:48 -0500 |
commit | d6d9d250121871e2e21271a2d88ecc585388c23c (patch) | |
tree | e8fd7c2143ee80996b9cb7e8dec2bd2b63e44dd5 | |
parent | 2cd8859fa6029649c0cceab0ef81a0f9c492d28c (diff) | |
download | epiphany-d6d9d250121871e2e21271a2d88ecc585388c23c.tar.gz |
Add URI handler for view source mode
So we don't have to open these in gedit anymore.
Disadvantage: the URL that gets displayed is actually pulled from the
server again, so it might not actually be what's displayed in your
browser. This might be undesirable.
https://bugzilla.gnome.org/show_bug.cgi?id=738475
-rw-r--r-- | embed/Makefile.am | 4 | ||||
-rw-r--r-- | embed/ephy-embed-shell.c | 18 | ||||
-rw-r--r-- | embed/ephy-embed-utils.c | 4 | ||||
-rw-r--r-- | embed/ephy-view-source-handler.c | 230 | ||||
-rw-r--r-- | embed/ephy-view-source-handler.h | 37 | ||||
-rw-r--r-- | embed/ephy-web-view.c | 5 | ||||
-rw-r--r-- | src/window-commands.c | 32 |
7 files changed, 318 insertions, 12 deletions
diff --git a/embed/Makefile.am b/embed/Makefile.am index 62bb1c95c..7152d6373 100644 --- a/embed/Makefile.am +++ b/embed/Makefile.am @@ -25,6 +25,7 @@ libephyembed_la_SOURCES = \ ephy-embed-container.h \ ephy-embed-event.c \ ephy-embed-event.h \ + ephy-embed-prefs.c \ ephy-embed-prefs.h \ ephy-embed-private.h \ ephy-embed-shell.c \ @@ -39,7 +40,8 @@ libephyembed_la_SOURCES = \ ephy-file-monitor.h \ ephy-find-toolbar.c \ ephy-find-toolbar.h \ - ephy-embed-prefs.c \ + ephy-view-source-handler.c \ + ephy-view-source-handler.h \ ephy-web-view.c \ ephy-web-view.h \ ephy-web-extension-proxy.c \ diff --git a/embed/ephy-embed-shell.c b/embed/ephy-embed-shell.c index 2d86f32fb..70556a101 100644 --- a/embed/ephy-embed-shell.c +++ b/embed/ephy-embed-shell.c @@ -33,6 +33,7 @@ #include "ephy-profile-utils.h" #include "ephy-settings.h" #include "ephy-snapshot-service.h" +#include "ephy-view-source-handler.h" #include "ephy-web-app-utils.h" #include "ephy-web-extension-proxy.h" #include "ephy-web-extension-names.h" @@ -55,6 +56,7 @@ typedef struct { WebKitUserContentManager *user_content; EphyDownloadsManager *downloads_manager; EphyAboutHandler *about_handler; + EphyViewSourceHandler *source_handler; guint update_overview_timeout_id; guint hiding_overview_item; GDBusServer *dbus_server; @@ -100,6 +102,7 @@ ephy_embed_shell_dispose (GObject *object) g_clear_object (&priv->print_settings); g_clear_object (&priv->global_history_service); g_clear_object (&priv->about_handler); + g_clear_object (&priv->source_handler); g_clear_object (&priv->user_content); g_clear_object (&priv->downloads_manager); g_clear_object (&priv->web_context); @@ -474,6 +477,15 @@ about_request_cb (WebKitURISchemeRequest *request, } static void +source_request_cb (WebKitURISchemeRequest *request, + EphyEmbedShell *shell) +{ + EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (shell); + + ephy_view_source_handler_handle_request (priv->source_handler, request); +} + +static void ephy_resource_request_cb (WebKitURISchemeRequest *request) { const char *path; @@ -778,6 +790,12 @@ ephy_embed_shell_startup (GApplication *application) webkit_security_manager_register_uri_scheme_as_local (webkit_web_context_get_security_manager (priv->web_context), EPHY_ABOUT_SCHEME); + /* view source handler */ + priv->source_handler = ephy_view_source_handler_new (); + webkit_web_context_register_uri_scheme (priv->web_context, EPHY_VIEW_SOURCE_SCHEME, + (WebKitURISchemeRequestCallback)source_request_cb, + shell, NULL); + /* ephy-resource handler */ webkit_web_context_register_uri_scheme (priv->web_context, "ephy-resource", (WebKitURISchemeRequestCallback)ephy_resource_request_cb, diff --git a/embed/ephy-embed-utils.c b/embed/ephy-embed-utils.c index cb870807d..bdd14f7b0 100644 --- a/embed/ephy-embed-utils.c +++ b/embed/ephy-embed-utils.c @@ -26,6 +26,7 @@ #include "ephy-embed-private.h" #include "ephy-settings.h" #include "ephy-string.h" +#include "ephy-view-source-handler.h" #include <string.h> #include <glib/gi18n.h> @@ -294,6 +295,9 @@ ephy_embed_utils_is_no_show_address (const char *address) if (g_str_equal (address, do_not_show_address[i])) return TRUE; + if (strstr (address, EPHY_VIEW_SOURCE_SCHEME) == address) + return TRUE; + return FALSE; } diff --git a/embed/ephy-view-source-handler.c b/embed/ephy-view-source-handler.c new file mode 100644 index 000000000..8be34b7ff --- /dev/null +++ b/embed/ephy-view-source-handler.c @@ -0,0 +1,230 @@ +/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * Copyright © 2016 Igalia S.L. + * + * This file is part of Epiphany. + * + * Epiphany is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Epiphany is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Epiphany. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "config.h" +#include "ephy-view-source-handler.h" + +#include "ephy-embed-shell.h" + +#include <gio/gio.h> +#include <string.h> + +struct _EphyViewSourceHandler { + GObject parent_instance; + + GList *outstanding_requests; +}; + +G_DEFINE_TYPE (EphyViewSourceHandler, ephy_view_source_handler, G_TYPE_OBJECT) + +typedef struct { + EphyViewSourceHandler *source_handler; + WebKitURISchemeRequest *scheme_request; + WebKitWebView *web_view; + GCancellable *cancellable; + guint load_changed_id; +} EphyViewSourceRequest; + +static EphyViewSourceRequest * +ephy_view_source_request_new (EphyViewSourceHandler *handler, + WebKitURISchemeRequest *request) +{ + EphyViewSourceRequest *view_source_request; + EphyEmbedShell *shell = ephy_embed_shell_get_default (); + WebKitWebContext *context = ephy_embed_shell_get_web_context (shell); + + view_source_request = g_slice_new (EphyViewSourceRequest); + view_source_request->source_handler = handler; + view_source_request->scheme_request = g_object_ref (request); + view_source_request->web_view = g_object_ref_sink (webkit_web_view_new_with_context (context)); + view_source_request->cancellable = g_cancellable_new (); + view_source_request->load_changed_id = 0; + + return view_source_request; +} + +static void +ephy_view_source_request_free (EphyViewSourceRequest *request) +{ + if (request->load_changed_id > 0) + g_signal_handler_disconnect (request->web_view, request->load_changed_id); + + g_object_unref (request->scheme_request); + g_object_unref (request->web_view); + + g_cancellable_cancel (request->cancellable); + g_object_unref (request->cancellable); + + g_slice_free (EphyViewSourceRequest, request); +} + +static void +finish_uri_scheme_request (EphyViewSourceRequest *request, + gchar *data) +{ + GInputStream *stream; + gssize data_length; + + data_length = MIN (strlen (data), G_MAXSSIZE); + stream = g_memory_input_stream_new_from_data (data, data_length, g_free); + webkit_uri_scheme_request_finish (request->scheme_request, stream, data_length, "text/html"); + + request->source_handler->outstanding_requests = + g_list_remove (request->source_handler->outstanding_requests, + request); + + ephy_view_source_request_free (request); + g_object_unref (stream); +} + +static void +web_resource_data_cb (WebKitWebResource *resource, + GAsyncResult *result, + EphyViewSourceRequest *request) +{ + guchar *data; + char *data_str; + char *escaped_str; + char *html; + gsize length; + GError *error = NULL; + + data = webkit_web_resource_get_data_finish (resource, result, &length, &error); + if (error) { + html = g_strdup (error->message); + length = strlen (html); + g_error_free (error); + finish_uri_scheme_request (request, html); + return; + } + + data_str = g_malloc (length + 1); + strncpy (data_str, (const char *)data, length); + data_str[length] = '\0'; + g_free (data); + + escaped_str = g_markup_escape_text (data_str, -1); + g_free (data_str); + + html = g_strdup_printf ("<body>" + "<pre>" + "<code class=\"language-html\">%s</code>" + "</pre>" + "</body>", + escaped_str); + g_free (escaped_str); + + finish_uri_scheme_request (request, html); +} + +static void +load_changed_cb (WebKitWebView *web_view, + WebKitLoadEvent load_event, + EphyViewSourceRequest *request) +{ + if (load_event == WEBKIT_LOAD_FINISHED) { + WebKitWebResource *resource = webkit_web_view_get_main_resource (web_view); + webkit_web_resource_get_data (resource, + request->cancellable, + (GAsyncReadyCallback)(web_resource_data_cb), + request); + } +} + +static void +ephy_view_source_request_start (EphyViewSourceRequest *request) +{ + SoupURI *soup_uri; + char *modified_uri; + char *decoded_fragment; + const char *original_uri; + + request->source_handler->outstanding_requests = + g_list_prepend (request->source_handler->outstanding_requests, request); + + original_uri = webkit_uri_scheme_request_get_uri (request->scheme_request); + soup_uri = soup_uri_new (original_uri); + + if (!soup_uri) { + g_critical ("Failed to construct SoupURI for %s", original_uri); + finish_uri_scheme_request (request, g_strdup ("")); + return; + } + + /* Convert e.g. ephy-source://gnome.org#https to https://gnome.org */ + g_assert (soup_uri->fragment); + decoded_fragment = soup_uri_decode (soup_uri->fragment); + soup_uri_set_scheme (soup_uri, decoded_fragment); + soup_uri_set_fragment (soup_uri, NULL); + modified_uri = soup_uri_to_string (soup_uri, FALSE); + + g_assert(request->load_changed_id == 0); + request->load_changed_id = g_signal_connect (request->web_view, "load-changed", + G_CALLBACK (load_changed_cb), + request); + + webkit_web_view_load_uri (request->web_view, modified_uri); + + g_free (decoded_fragment); + g_free (modified_uri); + soup_uri_free (soup_uri); +} + +static void +ephy_view_source_handler_dispose (GObject *object) +{ + EphyViewSourceHandler *handler = EPHY_VIEW_SOURCE_HANDLER (object); + + if (handler->outstanding_requests) { + g_list_free_full (handler->outstanding_requests, (GDestroyNotify)ephy_view_source_request_free); + handler->outstanding_requests = NULL; + } + + G_OBJECT_CLASS (ephy_view_source_handler_parent_class)->dispose (object); +} + +static void +ephy_view_source_handler_init (EphyViewSourceHandler *handler) +{ +} + +static void +ephy_view_source_handler_class_init (EphyViewSourceHandlerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = ephy_view_source_handler_dispose; +} + +EphyViewSourceHandler * +ephy_view_source_handler_new (void) +{ + return EPHY_VIEW_SOURCE_HANDLER (g_object_new (EPHY_TYPE_VIEW_SOURCE_HANDLER, NULL)); +} + +void +ephy_view_source_handler_handle_request (EphyViewSourceHandler *handler, + WebKitURISchemeRequest *scheme_request) +{ + EphyViewSourceRequest *view_source_request; + + view_source_request = ephy_view_source_request_new (handler, scheme_request); + ephy_view_source_request_start (view_source_request); +} diff --git a/embed/ephy-view-source-handler.h b/embed/ephy-view-source-handler.h new file mode 100644 index 000000000..9c268a391 --- /dev/null +++ b/embed/ephy-view-source-handler.h @@ -0,0 +1,37 @@ +/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * Copyright © 2016 Igalia S.L. + * + * This file is part of Epiphany. + * + * Epiphany is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Epiphany is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Epiphany. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include <webkit2/webkit2.h> + +G_BEGIN_DECLS + +#define EPHY_TYPE_VIEW_SOURCE_HANDLER (ephy_view_source_handler_get_type ()) + +G_DECLARE_FINAL_TYPE (EphyViewSourceHandler, ephy_view_source_handler, EPHY, VIEW_SOURCE_HANDLER, GObject) + +#define EPHY_VIEW_SOURCE_SCHEME "ephy-source" + +EphyViewSourceHandler *ephy_view_source_handler_new (void); + +void ephy_view_source_handler_handle_request (EphyViewSourceHandler *handler, + WebKitURISchemeRequest *request); +G_END_DECLS diff --git a/embed/ephy-web-view.c b/embed/ephy-web-view.c index e21982c7e..5777656f2 100644 --- a/embed/ephy-web-view.c +++ b/embed/ephy-web-view.c @@ -40,6 +40,7 @@ #include "ephy-snapshot-service.h" #include "ephy-string.h" #include "ephy-uri-helpers.h" +#include "ephy-view-source-handler.h" #include "ephy-web-app-utils.h" #include "ephy-web-dom-utils.h" #include "ephy-web-extension-proxy.h" @@ -1457,7 +1458,9 @@ update_security_status_for_committed_load (EphyWebView *view, g_clear_object (&view->certificate); g_clear_pointer (&view->tls_error_failing_uri, g_free); - if (!soup_uri || webkit_security_manager_uri_scheme_is_local (security_manager, soup_uri->scheme)) { + if (!soup_uri || + strcmp (soup_uri_get_scheme (soup_uri), EPHY_VIEW_SOURCE_SCHEME) == 0 || + webkit_security_manager_uri_scheme_is_local (security_manager, soup_uri->scheme)) { security_level = EPHY_SECURITY_LEVEL_LOCAL_PAGE; } else if (webkit_web_view_get_tls_info (WEBKIT_WEB_VIEW (view), &view->certificate, &view->tls_errors)) { g_object_ref (view->certificate); diff --git a/src/window-commands.c b/src/window-commands.c index feb7a8838..ab007d137 100644 --- a/src/window-commands.c +++ b/src/window-commands.c @@ -46,6 +46,7 @@ #include "ephy-settings.h" #include "ephy-shell.h" #include "ephy-string.h" +#include "ephy-view-source-handler.h" #include "ephy-web-app-utils.h" #include "ephy-zoom.h" @@ -1369,6 +1370,23 @@ static void view_source_embedded (const char *uri, EphyEmbed *embed) { EphyEmbed *new_embed; + SoupURI *soup_uri; + char *source_uri; + + /* Abort if we're already in view source mode */ + if (strstr (uri, EPHY_VIEW_SOURCE_SCHEME) == uri) + return; + + soup_uri = soup_uri_new (uri); + if (!soup_uri) { + g_critical ("Failed to construct SoupURI for %s", uri); + return; + } + + /* Convert e.g. https://gnome.org to ephy-source://gnome.org#https */ + soup_uri_set_fragment (soup_uri, soup_uri->scheme); + soup_uri_set_scheme (soup_uri, EPHY_VIEW_SOURCE_SCHEME); + source_uri = soup_uri_to_string (soup_uri, FALSE); new_embed = ephy_shell_new_tab (ephy_shell_get_default (), @@ -1376,13 +1394,11 @@ view_source_embedded (const char *uri, EphyEmbed *embed) embed, EPHY_NEW_TAB_JUMP | EPHY_NEW_TAB_APPEND_AFTER); - /* FIXME: Implement embedded view source mode using a custom URI handler and a - * javascript library for the syntax highlighting. - * https://bugzilla.gnome.org/show_bug.cgi?id=731558 - */ - webkit_web_view_load_uri - (EPHY_GET_WEBKIT_WEB_VIEW_FROM_EMBED (new_embed), uri); + webkit_web_view_load_uri (EPHY_GET_WEBKIT_WEB_VIEW_FROM_EMBED (new_embed), source_uri); gtk_widget_grab_focus (GTK_WIDGET (new_embed)); + + g_free (source_uri); + soup_uri_free (soup_uri); } static void @@ -1569,15 +1585,11 @@ window_cmd_page_source (GSimpleAction *action, address = ephy_web_view_get_address (ephy_embed_get_web_view (embed)); -#if 0 - FIXME: Disabled due to bug #738475 - if (g_settings_get_boolean (EPHY_SETTINGS_MAIN, EPHY_PREFS_INTERNAL_VIEW_SOURCE)) { view_source_embedded (address, embed); return; } -#endif user_time = gtk_get_current_event_time (); |