From 5df03415c2af382af253ba27c4ffe220935f24ae Mon Sep 17 00:00:00 2001 From: "carlosgc@webkit.org" Date: Tue, 24 Jan 2012 09:45:28 +0000 Subject: [PATCH] [GTK] Implement DownloadClient in WebKit2 GTK+ API https://bugs.webkit.org/show_bug.cgi?id=72952 Reviewed by Martin Robinson. Source/WebKit2: * GNUmakefile.am: Add new files to compilation. * UIProcess/API/gtk/WebKitDownloadClient.cpp: Added. (didStart): Call webkitWebContextDownloadStarted(). (didReceiveResponse): Call webkitDownloadSetResponse() with the received response. (didReceiveData): Call webkitDownloadNotifyProgress(). (decideDestinationWithSuggestedFilename): Call webkitDownloadDecideDestinationWithSuggestedFilename(). (didCreateDestination): Call webkitDownloadDestinationCreated(). (didFail): Call webkitDownloadFailed() or webkitDownloadCancelled() if the download was cancelled before failing. (didCancel): Call webkitDownloadCancelled(). (didFinish): Call webkitDownloadFinished(). (attachDownloadClientToContext): Add implementation for download client callbacks. * UIProcess/API/gtk/WebKitDownloadClient.h: Added. * UIProcess/API/gtk/WebKitError.cpp: (webkit_download_error_quark): Add quark for download errors. * UIProcess/API/gtk/WebKitError.h: * UIProcess/API/gtk/WebKitWebContext.cpp: (webkit_web_context_class_init): Add download-started signal. (createDefaultWebContext): Initialize the download client. (downloadsMap): HashMap containing download objects for all ongoing download operations. (webkit_web_context_download_uri): Start a new download for the given URI. (webkitWebContextGetOrCreateDownload): Helper function to create a new download object or return the existing one from the downloads map. (webkitWebContextRemoveDownload): Remove the download object from the downloads map. (webkitWebContextDownloadStarted): Emit WebKitWebContext::download-started for the given download object. * UIProcess/API/gtk/WebKitWebContext.h: * UIProcess/API/gtk/WebKitWebContextPrivate.h: * UIProcess/API/gtk/docs/webkit2gtk-sections.txt: Add new symbols. * UIProcess/API/gtk/tests/GNUmakefile.am: Add new test for downloads. * UIProcess/API/gtk/tests/TestDownloads.cpp: Added. (getWebKit1TestResoucesDir): (testDownloadLocalFile): (testDownloadLocalFileError): (serverCallback): (testDownloadRemoteFile): (testDownloadRemoteFileError): (beforeAll): (afterAll): Tools: * gtk/generate-gtkdoc: (get_webkit2_options): Ignore WebKitDownloadClient. git-svn-id: http://svn.webkit.org/repository/webkit/trunk@105708 268f45cc-cd09-0410-ab3c-d52691b4dbfc --- Source/WebKit2/ChangeLog | 54 +++ Source/WebKit2/GNUmakefile.am | 2 + .../UIProcess/API/gtk/WebKitDownloadClient.cpp | 115 ++++++ .../UIProcess/API/gtk/WebKitDownloadClient.h | 27 ++ Source/WebKit2/UIProcess/API/gtk/WebKitError.cpp | 9 + Source/WebKit2/UIProcess/API/gtk/WebKitError.h | 24 +- .../WebKit2/UIProcess/API/gtk/WebKitWebContext.cpp | 88 ++++- .../WebKit2/UIProcess/API/gtk/WebKitWebContext.h | 5 + .../UIProcess/API/gtk/WebKitWebContextPrivate.h | 3 + .../UIProcess/API/gtk/docs/webkit2gtk-sections.txt | 4 + .../WebKit2/UIProcess/API/gtk/tests/GNUmakefile.am | 13 +- .../UIProcess/API/gtk/tests/TestDownloads.cpp | 410 +++++++++++++++++++++ Tools/ChangeLog | 10 + Tools/gtk/generate-gtkdoc | 1 + 14 files changed, 759 insertions(+), 6 deletions(-) create mode 100644 Source/WebKit2/UIProcess/API/gtk/WebKitDownloadClient.cpp create mode 100644 Source/WebKit2/UIProcess/API/gtk/WebKitDownloadClient.h create mode 100644 Source/WebKit2/UIProcess/API/gtk/tests/TestDownloads.cpp diff --git a/Source/WebKit2/ChangeLog b/Source/WebKit2/ChangeLog index da52816..7b9b3cd 100644 --- a/Source/WebKit2/ChangeLog +++ b/Source/WebKit2/ChangeLog @@ -1,3 +1,57 @@ +2012-01-24 Carlos Garcia Campos + + [GTK] Implement DownloadClient in WebKit2 GTK+ API + https://bugs.webkit.org/show_bug.cgi?id=72952 + + Reviewed by Martin Robinson. + + * GNUmakefile.am: Add new files to compilation. + * UIProcess/API/gtk/WebKitDownloadClient.cpp: Added. + (didStart): Call webkitWebContextDownloadStarted(). + (didReceiveResponse): Call webkitDownloadSetResponse() with the + received response. + (didReceiveData): Call webkitDownloadNotifyProgress(). + (decideDestinationWithSuggestedFilename): Call + webkitDownloadDecideDestinationWithSuggestedFilename(). + (didCreateDestination): Call webkitDownloadDestinationCreated(). + (didFail): Call webkitDownloadFailed() or + webkitDownloadCancelled() if the download was cancelled before + failing. + (didCancel): Call webkitDownloadCancelled(). + (didFinish): Call webkitDownloadFinished(). + (attachDownloadClientToContext): Add + implementation for download client callbacks. + * UIProcess/API/gtk/WebKitDownloadClient.h: Added. + * UIProcess/API/gtk/WebKitError.cpp: + (webkit_download_error_quark): Add quark for download errors. + * UIProcess/API/gtk/WebKitError.h: + * UIProcess/API/gtk/WebKitWebContext.cpp: + (webkit_web_context_class_init): Add download-started signal. + (createDefaultWebContext): Initialize the download client. + (downloadsMap): HashMap containing download objects for all + ongoing download operations. + (webkit_web_context_download_uri): Start a new download for the + given URI. + (webkitWebContextGetOrCreateDownload): Helper function to create a + new download object or return the existing one from the downloads map. + (webkitWebContextRemoveDownload): Remove the download object from + the downloads map. + (webkitWebContextDownloadStarted): Emit + WebKitWebContext::download-started for the given download object. + * UIProcess/API/gtk/WebKitWebContext.h: + * UIProcess/API/gtk/WebKitWebContextPrivate.h: + * UIProcess/API/gtk/docs/webkit2gtk-sections.txt: Add new symbols. + * UIProcess/API/gtk/tests/GNUmakefile.am: Add new test for downloads. + * UIProcess/API/gtk/tests/TestDownloads.cpp: Added. + (getWebKit1TestResoucesDir): + (testDownloadLocalFile): + (testDownloadLocalFileError): + (serverCallback): + (testDownloadRemoteFile): + (testDownloadRemoteFileError): + (beforeAll): + (afterAll): + 2012-01-23 Carlos Garcia Campos [GTK] Add WebKitDownload to WebKit2 GTK+ API diff --git a/Source/WebKit2/GNUmakefile.am b/Source/WebKit2/GNUmakefile.am index b5f5624..9200262 100644 --- a/Source/WebKit2/GNUmakefile.am +++ b/Source/WebKit2/GNUmakefile.am @@ -525,6 +525,8 @@ libwebkit2gtk_@WEBKITGTK_API_MAJOR_VERSION@_@WEBKITGTK_API_MINOR_VERSION@_la_SOU Source/WebKit2/UIProcess/API/gtk/WebKitDownload.cpp \ Source/WebKit2/UIProcess/API/gtk/WebKitDownload.h \ Source/WebKit2/UIProcess/API/gtk/WebKitDownloadPrivate.h \ + Source/WebKit2/UIProcess/API/gtk/WebKitDownloadClient.cpp \ + Source/WebKit2/UIProcess/API/gtk/WebKitDownloadClient.h \ Source/WebKit2/UIProcess/API/gtk/WebKitError.h \ Source/WebKit2/UIProcess/API/gtk/WebKitError.cpp \ Source/WebKit2/UIProcess/API/gtk/WebKitPrivate.h \ diff --git a/Source/WebKit2/UIProcess/API/gtk/WebKitDownloadClient.cpp b/Source/WebKit2/UIProcess/API/gtk/WebKitDownloadClient.cpp new file mode 100644 index 0000000..6e72496 --- /dev/null +++ b/Source/WebKit2/UIProcess/API/gtk/WebKitDownloadClient.cpp @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2012 Igalia S.L. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "WebKitDownloadClient.h" + +#include "WebContext.h" +#include "WebKitDownloadPrivate.h" +#include "WebKitURIResponsePrivate.h" +#include "WebKitWebContextPrivate.h" +#include "WebURLResponse.h" +#include +#include +#include + +using namespace WebCore; +using namespace WebKit; + +static void didStart(WKContextRef, WKDownloadRef wkDownload, const void* clientInfo) +{ + GRefPtr download = webkitWebContextGetOrCreateDownload(wkDownload); + webkitWebContextDownloadStarted(WEBKIT_WEB_CONTEXT(clientInfo), download.get()); +} + +static void didReceiveResponse(WKContextRef, WKDownloadRef wkDownload, WKURLResponseRef wkResponse, const void* clientInfo) +{ + GRefPtr download = webkitWebContextGetOrCreateDownload(wkDownload); + if (webkitDownloadIsCancelled(download.get())) + return; + + GRefPtr response = adoptGRef(webkitURIResponseCreateForResourceResponse(toImpl(wkResponse)->resourceResponse())); + webkitDownloadSetResponse(download.get(), response.get()); +} + +static void didReceiveData(WKContextRef, WKDownloadRef wkDownload, uint64_t length, const void* clientInfo) +{ + GRefPtr download = webkitWebContextGetOrCreateDownload(wkDownload); + webkitDownloadNotifyProgress(download.get(), length); +} + +static WKStringRef decideDestinationWithSuggestedFilename(WKContextRef, WKDownloadRef wkDownload, WKStringRef filename, bool* allowOverwrite, const void* clientInfo) +{ + GRefPtr download = webkitWebContextGetOrCreateDownload(wkDownload); + CString destinationURI = webkitDownloadDecideDestinationWithSuggestedFilename(download.get(), + toImpl(filename)->string().utf8()); + return WKStringCreateWithUTF8CString(destinationURI.data()); +} + +static void didCreateDestination(WKContextRef, WKDownloadRef wkDownload, WKStringRef path, const void* clientInfo) +{ + GRefPtr download = webkitWebContextGetOrCreateDownload(wkDownload); + webkitDownloadDestinationCreated(download.get(), toImpl(path)->string().utf8()); +} + +static void didFail(WKContextRef, WKDownloadRef wkDownload, WKErrorRef error, const void *clientInfo) +{ + GRefPtr download = webkitWebContextGetOrCreateDownload(wkDownload); + if (webkitDownloadIsCancelled(download.get())) { + // Cancellation takes precedence over other errors. + webkitDownloadCancelled(download.get()); + } else + webkitDownloadFailed(download.get(), toImpl(error)->platformError()); + webkitWebContextRemoveDownload(wkDownload); +} + +static void didCancel(WKContextRef, WKDownloadRef wkDownload, const void *clientInfo) +{ + GRefPtr download = webkitWebContextGetOrCreateDownload(wkDownload); + webkitDownloadCancelled(download.get()); + webkitWebContextRemoveDownload(wkDownload); +} + +static void didFinish(WKContextRef wkContext, WKDownloadRef wkDownload, const void *clientInfo) +{ + GRefPtr download = webkitWebContextGetOrCreateDownload(wkDownload); + webkitDownloadFinished(download.get()); + webkitWebContextRemoveDownload(wkDownload); +} + +void attachDownloadClientToContext(WebKitWebContext* webContext) +{ + WKContextDownloadClient wkDownloadClient = { + kWKContextDownloadClientCurrentVersion, + webContext, // ClientInfo + didStart, + 0, // didReceiveAuthenticationChallenge + didReceiveResponse, + didReceiveData, + 0, // shouldDecodeSourceDataOfMIMEType + decideDestinationWithSuggestedFilename, + didCreateDestination, + didFinish, + didFail, + didCancel, + 0, // processDidCrash + }; + WKContextSetDownloadClient(webkitWebContextGetWKContext(webContext), &wkDownloadClient); +} + diff --git a/Source/WebKit2/UIProcess/API/gtk/WebKitDownloadClient.h b/Source/WebKit2/UIProcess/API/gtk/WebKitDownloadClient.h new file mode 100644 index 0000000..c2566e8 --- /dev/null +++ b/Source/WebKit2/UIProcess/API/gtk/WebKitDownloadClient.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2012 Igalia S.L. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef WebKitDownloadClient_h +#define WebKitDownloadClient_h + +#include "WebKitWebContext.h" + +void attachDownloadClientToContext(WebKitWebContext*); + +#endif diff --git a/Source/WebKit2/UIProcess/API/gtk/WebKitError.cpp b/Source/WebKit2/UIProcess/API/gtk/WebKitError.cpp index 6c24aa1..addcf1b 100644 --- a/Source/WebKit2/UIProcess/API/gtk/WebKitError.cpp +++ b/Source/WebKit2/UIProcess/API/gtk/WebKitError.cpp @@ -57,3 +57,12 @@ COMPILE_ASSERT_MATCHING_ENUM(WEBKIT_PLUGIN_ERROR_CANNOT_LOAD_PLUGIN, PluginError COMPILE_ASSERT_MATCHING_ENUM(WEBKIT_PLUGIN_ERROR_JAVA_UNAVAILABLE, PluginErrorJavaUnavailable); COMPILE_ASSERT_MATCHING_ENUM(WEBKIT_PLUGIN_ERROR_CONNECTION_CANCELLED, PluginErrorConnectionCancelled); COMPILE_ASSERT_MATCHING_ENUM(WEBKIT_PLUGIN_ERROR_WILL_HANDLE_LOAD, PluginErrorWillHandleLoad); + +GQuark webkit_download_error_quark() +{ + return g_quark_from_static_string(WebCore::errorDomainDownload); +} + +COMPILE_ASSERT_MATCHING_ENUM(WEBKIT_DOWNLOAD_ERROR_NETWORK, DownloadErrorNetwork); +COMPILE_ASSERT_MATCHING_ENUM(WEBKIT_DOWNLOAD_ERROR_CANCELLED_BY_USER, DownloadErrorCancelledByUser); +COMPILE_ASSERT_MATCHING_ENUM(WEBKIT_DOWNLOAD_ERROR_DESTINATION, DownloadErrorDestination); diff --git a/Source/WebKit2/UIProcess/API/gtk/WebKitError.h b/Source/WebKit2/UIProcess/API/gtk/WebKitError.h index 3ce0e20..9b0e630 100644 --- a/Source/WebKit2/UIProcess/API/gtk/WebKitError.h +++ b/Source/WebKit2/UIProcess/API/gtk/WebKitError.h @@ -32,6 +32,7 @@ G_BEGIN_DECLS #define WEBKIT_NETWORK_ERROR webkit_network_error_quark () #define WEBKIT_POLICY_ERROR webkit_policy_error_quark () #define WEBKIT_PLUGIN_ERROR webkit_plugin_error_quark () +#define WEBKIT_DOWNLOAD_ERROR webkit_download_error_quark () /** * WebKitNetworkError: @@ -89,14 +90,31 @@ typedef enum { WEBKIT_PLUGIN_ERROR_WILL_HANDLE_LOAD = 204, } WebKitPluginError; +/** + * WebKitDownloadError: + * @WEBKIT_DOWNLOAD_ERROR_NETWORK: Download failure due to network error + * @WEBKIT_DOWNLOAD_ERROR_CANCELLED_BY_USER: Download was cancelled by user + * @WEBKIT_DOWNLOAD_ERROR_DESTINATION: Download failure due to destination error + * + * Enum values used to denote the various download errors. + */ +typedef enum { + WEBKIT_DOWNLOAD_ERROR_NETWORK = 499, + WEBKIT_DOWNLOAD_ERROR_CANCELLED_BY_USER = 400, + WEBKIT_DOWNLOAD_ERROR_DESTINATION = 401 +} WebKitDownloadError; + +WEBKIT_API GQuark +webkit_network_error_quark (void); + WEBKIT_API GQuark -webkit_network_error_quark (void); +webkit_policy_error_quark (void); WEBKIT_API GQuark -webkit_policy_error_quark (void); +webkit_plugin_error_quark (void); WEBKIT_API GQuark -webkit_plugin_error_quark (void); +webkit_download_error_quark (void); G_END_DECLS diff --git a/Source/WebKit2/UIProcess/API/gtk/WebKitWebContext.cpp b/Source/WebKit2/UIProcess/API/gtk/WebKitWebContext.cpp index ff85bca..360b0a6 100644 --- a/Source/WebKit2/UIProcess/API/gtk/WebKitWebContext.cpp +++ b/Source/WebKit2/UIProcess/API/gtk/WebKitWebContext.cpp @@ -20,13 +20,29 @@ #include "config.h" #include "WebKitWebContext.h" +#include "WebContext.h" +#include "WebKitDownloadClient.h" +#include "WebKitDownloadPrivate.h" #include "WebKitPrivate.h" #include "WebKitWebContextPrivate.h" +#include +#include +#include + +using namespace WebKit; + +enum { + DOWNLOAD_STARTED, + + LAST_SIGNAL +}; struct _WebKitWebContextPrivate { WKRetainPtr context; }; +static guint signals[LAST_SIGNAL] = { 0, }; + G_DEFINE_TYPE(WebKitWebContext, webkit_web_context, G_TYPE_OBJECT) static void webkitWebContextFinalize(GObject* object) @@ -47,15 +63,32 @@ static void webkit_web_context_class_init(WebKitWebContextClass* webContextClass GObjectClass* gObjectClass = G_OBJECT_CLASS(webContextClass); gObjectClass->finalize = webkitWebContextFinalize; + /** + * WebKitWebContext::download-started: + * @context: the #WebKitWebContext + * @download: the #WebKitDownload associated with this event + * + * This signal is emitted when a new download request is made. + */ + signals[DOWNLOAD_STARTED] = + g_signal_new("download-started", + G_TYPE_FROM_CLASS(gObjectClass), + G_SIGNAL_RUN_LAST, + 0, 0, 0, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + WEBKIT_TYPE_DOWNLOAD); + g_type_class_add_private(webContextClass, sizeof(WebKitWebContextPrivate)); } - static gpointer createDefaultWebContext(gpointer) { WebKitWebContext* webContext = WEBKIT_WEB_CONTEXT(g_object_new(WEBKIT_TYPE_WEB_CONTEXT, NULL)); webContext->priv->context = WKContextGetSharedProcessContext(); WKContextSetCacheModel(webContext->priv->context.get(), kWKCacheModelPrimaryWebBrowser); + attachDownloadClientToContext(webContext); + return webContext; } @@ -150,6 +183,59 @@ WebKitCacheModel webkit_web_context_get_cache_model(WebKitWebContext* context) return WEBKIT_CACHE_MODEL_WEB_BROWSER; } +typedef HashMap > DownloadsMap; + +static DownloadsMap& downloadsMap() +{ + DEFINE_STATIC_LOCAL(DownloadsMap, downloads, ()); + return downloads; +} + +/** + * webkit_web_context_download_uri: + * @context: a #WebKitWebContext + * @uri: the URI to download + * + * Requests downloading of the specified URI string. + * + * Returns: (transfer full): a new #WebKitDownload representing the + * the download operation. + */ +WebKitDownload* webkit_web_context_download_uri(WebKitWebContext* context, const gchar* uri) +{ + g_return_val_if_fail(WEBKIT_IS_WEB_CONTEXT(context), 0); + g_return_val_if_fail(uri, 0); + + WebKitWebContextPrivate* priv = context->priv; + WKRetainPtr wkURL(AdoptWK, WKURLCreateWithUTF8CString(uri)); + WKRetainPtr wkRequest(AdoptWK, WKURLRequestCreateWithWKURL(wkURL.get())); + WKRetainPtr wkDownload = WKContextDownloadURLRequest(priv->context.get(), wkRequest.get()); + WebKitDownload* download = webkitDownloadCreate(wkDownload.get()); + downloadsMap().set(wkDownload.get(), download); + return download; +} + +WebKitDownload* webkitWebContextGetOrCreateDownload(WKDownloadRef wkDownload) +{ + GRefPtr download = downloadsMap().get(wkDownload); + if (download) + return download.get(); + + download = adoptGRef(webkitDownloadCreate(wkDownload)); + downloadsMap().set(wkDownload, download.get()); + return download.get(); +} + +void webkitWebContextRemoveDownload(WKDownloadRef wkDownload) +{ + downloadsMap().remove(wkDownload); +} + +void webkitWebContextDownloadStarted(WebKitWebContext* context, WebKitDownload* download) +{ + g_signal_emit(context, signals[DOWNLOAD_STARTED], 0, download); +} + WKContextRef webkitWebContextGetWKContext(WebKitWebContext* context) { g_assert(WEBKIT_IS_WEB_CONTEXT(context)); diff --git a/Source/WebKit2/UIProcess/API/gtk/WebKitWebContext.h b/Source/WebKit2/UIProcess/API/gtk/WebKitWebContext.h index 2f38dbc2..b88bed0 100644 --- a/Source/WebKit2/UIProcess/API/gtk/WebKitWebContext.h +++ b/Source/WebKit2/UIProcess/API/gtk/WebKitWebContext.h @@ -26,6 +26,7 @@ #include #include +#include G_BEGIN_DECLS @@ -89,6 +90,10 @@ webkit_web_context_set_cache_model (WebKitWebContext *context, WEBKIT_API WebKitCacheModel webkit_web_context_get_cache_model (WebKitWebContext *context); +WEBKIT_API WebKitDownload * +webkit_web_context_download_uri (WebKitWebContext *context, + const gchar *uri); + G_END_DECLS #endif diff --git a/Source/WebKit2/UIProcess/API/gtk/WebKitWebContextPrivate.h b/Source/WebKit2/UIProcess/API/gtk/WebKitWebContextPrivate.h index 86d7dec..d2dd813 100644 --- a/Source/WebKit2/UIProcess/API/gtk/WebKitWebContextPrivate.h +++ b/Source/WebKit2/UIProcess/API/gtk/WebKitWebContextPrivate.h @@ -32,6 +32,9 @@ G_BEGIN_DECLS WKContextRef webkitWebContextGetWKContext(WebKitWebContext*); +WebKitDownload* webkitWebContextGetOrCreateDownload(WKDownloadRef); +void webkitWebContextRemoveDownload(WKDownloadRef); +void webkitWebContextDownloadStarted(WebKitWebContext*, WebKitDownload*); G_END_DECLS diff --git a/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-sections.txt b/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-sections.txt index 637976a..478979b 100644 --- a/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-sections.txt +++ b/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-sections.txt @@ -27,6 +27,7 @@ WebKitCacheModel webkit_web_context_get_default webkit_web_context_get_cache_model webkit_web_context_set_cache_model +webkit_web_context_download_uri WebKitWebContextClass @@ -315,11 +316,14 @@ webkit_download_get_type WEBKIT_NETWORK_ERROR WEBKIT_PLUGIN_ERROR WEBKIT_POLICY_ERROR +WEBKIT_DOWNLOAD_ERROR WebKitNetworkError WebKitPluginError WebKitPolicyError +WebKitDownloadError webkit_network_error_quark webkit_plugin_error_quark webkit_policy_error_quark +webkit_download_error_quark diff --git a/Source/WebKit2/UIProcess/API/gtk/tests/GNUmakefile.am b/Source/WebKit2/UIProcess/API/gtk/tests/GNUmakefile.am index 1759d04..d7cb2ed 100644 --- a/Source/WebKit2/UIProcess/API/gtk/tests/GNUmakefile.am +++ b/Source/WebKit2/UIProcess/API/gtk/tests/GNUmakefile.am @@ -3,7 +3,8 @@ TEST_PROGS += \ Programs/WebKit2APITests/TestWebKitWebView \ Programs/WebKit2APITests/TestWebKitWebLoaderClient \ Programs/WebKit2APITests/TestWebKitSettings \ - Programs/WebKit2APITests/TestBackForwardList + Programs/WebKit2APITests/TestBackForwardList \ + Programs/WebKit2APITests/TestDownloads noinst_PROGRAMS += $(TEST_PROGS) @@ -15,6 +16,7 @@ endif webkit2_tests_cppflags = \ -DWEBKIT_EXEC_PATH=\"${shell pwd}/$(top_builddir)/Programs\" \ + -DWEBKIT_SRC_DIR=\"${shell pwd}/${srcdir}\" \ $(javascriptcore_cppflags) \ -I$(srcdir)/Source/JavaScriptCore \ -I$(srcdir)/Source \ @@ -95,4 +97,11 @@ Programs_WebKit2APITests_TestWebKitAccessibility_SOURCES = \ Programs_WebKit2APITests_TestWebKitAccessibility_CPPFLAGS = $(webkit2_tests_cppflags) $(ATSPI2_CFLAGS) Programs_WebKit2APITests_TestWebKitAccessibility_LDADD = $(webkit2_tests_ldadd) $(ATSPI2_LIBS) Programs_WebKit2APITests_TestWebKitAccessibility_LDFLAGS = $(webkit2_tests_ldflags) -endif \ No newline at end of file +endif + +Programs_WebKit2APITests_TestDownloads_SOURCES = \ + Source/WebKit2/UIProcess/API/gtk/tests/TestDownloads.cpp +Programs_WebKit2APITests_TestDownloads_CPPFLAGS = $(webkit2_tests_cppflags) +Programs_WebKit2APITests_TestDownloads_LDADD = $(webkit2_tests_ldadd) +Programs_WebKit2APITests_TestDownloads_LDFLAGS = $(webkit2_tests_ldflags) + diff --git a/Source/WebKit2/UIProcess/API/gtk/tests/TestDownloads.cpp b/Source/WebKit2/UIProcess/API/gtk/tests/TestDownloads.cpp new file mode 100644 index 0000000..461cefa --- /dev/null +++ b/Source/WebKit2/UIProcess/API/gtk/tests/TestDownloads.cpp @@ -0,0 +1,410 @@ +/* + * Copyright (C) 2012 Igalia S.L. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#include "TestMain.h" +#include "WebKitTestServer.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static char* kTempDirectory; + +class DownloadTest: public Test { +public: + MAKE_GLIB_TEST_FIXTURE(DownloadTest); + + enum DownloadEvent { + Started, + ReceivedResponse, + CreatedDestination, + ReceivedData, + Failed, + Finished + }; + + static void receivedResponseCallback(WebKitDownload* download, GParamSpec*, DownloadTest* test) + { + g_assert(webkit_download_get_response(download)); + test->receivedResponse(download); + } + + static gboolean createdDestinationCallback(WebKitDownload* download, const gchar* destination, DownloadTest* test) + { + g_assert(webkit_download_get_destination(download)); + g_assert_cmpstr(webkit_download_get_destination(download), ==, destination); + test->createdDestination(download, destination); + return TRUE; + } + + static gboolean receivedDataCallback(WebKitDownload* download, guint64 dataLength, DownloadTest* test) + { + test->receivedData(download, dataLength); + return TRUE; + } + + static gboolean finishedCallback(WebKitDownload* download, DownloadTest* test) + { + test->finished(download); + return TRUE; + } + + static gboolean failedCallback(WebKitDownload* download, GError* error, DownloadTest* test) + { + g_assert(error); + test->failed(download, error); + return TRUE; + } + + static gboolean decideDestinationCallback(WebKitDownload* download, const gchar* suggestedFilename, DownloadTest* test) + { + g_assert(suggestedFilename); + test->decideDestination(download, suggestedFilename); + return TRUE; + } + + static void downloadStartedCallback(WebKitWebContext* context, WebKitDownload* download, DownloadTest* test) + { + test->started(download); + g_signal_connect(download, "notify::response", G_CALLBACK(receivedResponseCallback), test); + g_signal_connect(download, "created-destination", G_CALLBACK(createdDestinationCallback), test); + g_signal_connect(download, "received-data", G_CALLBACK(receivedDataCallback), test); + g_signal_connect(download, "finished", G_CALLBACK(finishedCallback), test); + g_signal_connect(download, "failed", G_CALLBACK(failedCallback), test); + g_signal_connect(download, "decide-destination", G_CALLBACK(decideDestinationCallback), test); + } + + DownloadTest() + : m_webContext(webkit_web_context_get_default()) + , m_mainLoop(g_main_loop_new(0, TRUE)) + , m_downloadSize(0) + { + g_signal_connect(m_webContext, "download-started", G_CALLBACK(downloadStartedCallback), this); + } + + ~DownloadTest() + { + g_signal_handlers_disconnect_matched(m_webContext, G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, this); + g_main_loop_unref(m_mainLoop); + } + + virtual void started(WebKitDownload* download) + { + m_downloadEvents.append(Started); + } + + virtual void receivedResponse(WebKitDownload* download) + { + m_downloadEvents.append(ReceivedResponse); + } + + virtual void createdDestination(WebKitDownload* download, const char* destination) + { + m_downloadEvents.append(CreatedDestination); + } + + virtual void receivedData(WebKitDownload* download, guint64 dataLength) + { + m_downloadSize += dataLength; + if (!m_downloadEvents.contains(ReceivedData)) + m_downloadEvents.append(ReceivedData); + } + + virtual void finished(WebKitDownload* download) + { + m_downloadEvents.append(Finished); + g_main_loop_quit(m_mainLoop); + } + + virtual void failed(WebKitDownload* download, GError* error) + { + m_downloadEvents.append(Failed); + } + + virtual void decideDestination(WebKitDownload* download, const gchar* suggestedFilename) + { + GOwnPtr destination(g_build_filename(kTempDirectory, suggestedFilename, NULL)); + GOwnPtr destinationURI(g_filename_to_uri(destination.get(), 0, 0)); + webkit_download_set_destination(download, destinationURI.get()); + } + + void waitUntilDownloadFinishes() + { + g_main_loop_run(m_mainLoop); + } + + void checkDestinationAndDeleteFile(WebKitDownload* download, const char* expectedName) + { + if (!webkit_download_get_destination(download)) + return; + GRefPtr destFile = adoptGRef(g_file_new_for_uri(webkit_download_get_destination(download))); + GOwnPtr destBasename(g_file_get_basename(destFile.get())); + g_assert_cmpstr(destBasename.get(), ==, expectedName); + + g_file_delete(destFile.get(), 0, 0); + } + + WebKitWebContext* m_webContext; + GMainLoop* m_mainLoop; + Vector m_downloadEvents; + guint64 m_downloadSize; +}; + +static CString getWebKit1TestResoucesDir() +{ + GOwnPtr resourcesDir(g_build_filename(WEBKIT_SRC_DIR, "Source", "WebKit", "gtk", "tests", "resources", NULL)); + return resourcesDir.get(); +} + +static void testDownloadLocalFile(DownloadTest* test, gconstpointer) +{ + GOwnPtr sourcePath(g_build_filename(getWebKit1TestResoucesDir().data(), "test.pdf", NULL)); + GRefPtr source = adoptGRef(g_file_new_for_path(sourcePath.get())); + GRefPtr sourceInfo = adoptGRef(g_file_query_info(source.get(), G_FILE_ATTRIBUTE_STANDARD_SIZE, static_cast(0), 0, 0)); + GOwnPtr sourceURI(g_file_get_uri(source.get())); + GRefPtr download = adoptGRef(webkit_web_context_download_uri(test->m_webContext, sourceURI.get())); + test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(download.get())); + test->waitUntilDownloadFinishes(); + + Vector& events = test->m_downloadEvents; + g_assert_cmpint(events.size(), ==, 5); + g_assert_cmpint(events[0], ==, DownloadTest::Started); + g_assert_cmpint(events[1], ==, DownloadTest::ReceivedResponse); + g_assert_cmpint(events[2], ==, DownloadTest::CreatedDestination); + g_assert_cmpint(events[3], ==, DownloadTest::ReceivedData); + g_assert_cmpint(events[4], ==, DownloadTest::Finished); + + g_assert_cmpint(test->m_downloadSize, ==, g_file_info_get_size(sourceInfo.get())); + g_assert(webkit_download_get_destination(download.get())); + g_assert_cmpfloat(webkit_download_get_estimated_progress(download.get()), ==, 1); + test->checkDestinationAndDeleteFile(download.get(), "test.pdf"); +} + +class DownloadErrorTest: public DownloadTest { +public: + MAKE_GLIB_TEST_FIXTURE(DownloadErrorTest); + + DownloadErrorTest() + : m_expectedError(WEBKIT_DOWNLOAD_ERROR_NETWORK) + { + } + + void receivedResponse(WebKitDownload* download) + { + DownloadTest::receivedResponse(download); + if (m_expectedError == WEBKIT_DOWNLOAD_ERROR_CANCELLED_BY_USER) + webkit_download_cancel(download); + } + + void createdDestination(WebKitDownload* download, const char* destination) + { + g_assert_not_reached(); + } + + void failed(WebKitDownload* download, GError* error) + { + g_assert(g_error_matches(error, WEBKIT_DOWNLOAD_ERROR, m_expectedError)); + DownloadTest::failed(download, error); + } + + void decideDestination(WebKitDownload* download, const gchar* suggestedFilename) + { + if (m_expectedError != WEBKIT_DOWNLOAD_ERROR_DESTINATION) { + DownloadTest::decideDestination(download, suggestedFilename); + return; + } + webkit_download_set_destination(download, "file:///foo/bar"); + } + + WebKitDownloadError m_expectedError; +}; + +static void testDownloadLocalFileError(DownloadErrorTest* test, gconstpointer) +{ + test->m_expectedError = WEBKIT_DOWNLOAD_ERROR_NETWORK; + GRefPtr download = adoptGRef(webkit_web_context_download_uri(test->m_webContext, "file:///foo/bar")); + test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(download.get())); + test->waitUntilDownloadFinishes(); + + Vector& events = test->m_downloadEvents; + g_assert_cmpint(events.size(), ==, 3); + g_assert_cmpint(events[0], ==, DownloadTest::Started); + g_assert_cmpint(events[1], ==, DownloadTest::Failed); + g_assert_cmpint(events[2], ==, DownloadTest::Finished); + events.clear(); + g_assert_cmpfloat(webkit_download_get_estimated_progress(download.get()), <, 1); + + test->m_expectedError = WEBKIT_DOWNLOAD_ERROR_DESTINATION; + GOwnPtr path(g_build_filename(getWebKit1TestResoucesDir().data(), "test.pdf", NULL)); + GRefPtr file = adoptGRef(g_file_new_for_path(path.get())); + GOwnPtr uri(g_file_get_uri(file.get())); + download = adoptGRef(webkit_web_context_download_uri(test->m_webContext, uri.get())); + test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(download.get())); + test->waitUntilDownloadFinishes(); + + events = test->m_downloadEvents; + g_assert_cmpint(events.size(), ==, 4); + g_assert_cmpint(events[0], ==, DownloadTest::Started); + g_assert_cmpint(events[1], ==, DownloadTest::ReceivedResponse); + g_assert_cmpint(events[2], ==, DownloadTest::Failed); + g_assert_cmpint(events[3], ==, DownloadTest::Finished); + events.clear(); + g_assert_cmpfloat(webkit_download_get_estimated_progress(download.get()), <, 1); + test->checkDestinationAndDeleteFile(download.get(), "bar"); + + test->m_expectedError = WEBKIT_DOWNLOAD_ERROR_CANCELLED_BY_USER; + download = adoptGRef(webkit_web_context_download_uri(test->m_webContext, uri.get())); + test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(download.get())); + test->waitUntilDownloadFinishes(); + + events = test->m_downloadEvents; + g_assert_cmpint(events.size(), ==, 4); + g_assert_cmpint(events[0], ==, DownloadTest::Started); + g_assert_cmpint(events[1], ==, DownloadTest::ReceivedResponse); + g_assert_cmpint(events[2], ==, DownloadTest::Failed); + g_assert_cmpint(events[3], ==, DownloadTest::Finished); + events.clear(); + g_assert_cmpfloat(webkit_download_get_estimated_progress(download.get()), <, 1); + test->checkDestinationAndDeleteFile(download.get(), "test.pdf"); +} + +static WebKitTestServer* kServer; +static const char* kServerSuggestedFilename = "webkit-downloaded-file"; + +static void serverCallback(SoupServer* server, SoupMessage* message, const char* path, GHashTable*, SoupClientContext*, gpointer) +{ + if (message->method != SOUP_METHOD_GET) { + soup_message_set_status(message, SOUP_STATUS_NOT_IMPLEMENTED); + return; + } + + GOwnPtr filePath(g_build_filename(getWebKit1TestResoucesDir().data(), path, NULL)); + char* contents; + gsize contentsLength; + if (!g_file_get_contents(filePath.get(), &contents, &contentsLength, 0)) { + soup_message_set_status(message, SOUP_STATUS_NOT_FOUND); + soup_message_body_complete(message->response_body); + return; + } + + soup_message_set_status(message, SOUP_STATUS_OK); + + GOwnPtr contentDisposition(g_strdup_printf("filename=%s", kServerSuggestedFilename)); + soup_message_headers_append(message->response_headers, "Content-Disposition", contentDisposition.get()); + soup_message_body_append(message->response_body, SOUP_MEMORY_TAKE, contents, contentsLength); + + soup_message_body_complete(message->response_body); +} + +static void testDownloadRemoteFile(DownloadTest* test, gconstpointer) +{ + GRefPtr download = adoptGRef(webkit_web_context_download_uri(test->m_webContext, kServer->getURIForPath("/test.pdf").data())); + test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(download.get())); + test->waitUntilDownloadFinishes(); + + Vector& events = test->m_downloadEvents; + g_assert_cmpint(events.size(), ==, 5); + g_assert_cmpint(events[0], ==, DownloadTest::Started); + g_assert_cmpint(events[1], ==, DownloadTest::ReceivedResponse); + g_assert_cmpint(events[2], ==, DownloadTest::CreatedDestination); + g_assert_cmpint(events[3], ==, DownloadTest::ReceivedData); + g_assert_cmpint(events[4], ==, DownloadTest::Finished); + events.clear(); + + g_assert(webkit_download_get_destination(download.get())); + g_assert_cmpfloat(webkit_download_get_estimated_progress(download.get()), ==, 1); + test->checkDestinationAndDeleteFile(download.get(), kServerSuggestedFilename); +} + +static void testDownloadRemoteFileError(DownloadErrorTest* test, gconstpointer) +{ + test->m_expectedError = WEBKIT_DOWNLOAD_ERROR_NETWORK; + GRefPtr download = adoptGRef(webkit_web_context_download_uri(test->m_webContext, + kServer->getURIForPath("/foo").data())); + test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(download.get())); + test->waitUntilDownloadFinishes(); + + Vector& events = test->m_downloadEvents; + g_assert_cmpint(events.size(), ==, 4); + g_assert_cmpint(events[0], ==, DownloadTest::Started); + g_assert_cmpint(events[1], ==, DownloadTest::ReceivedResponse); + g_assert_cmpint(events[2], ==, DownloadTest::Failed); + g_assert_cmpint(events[3], ==, DownloadTest::Finished); + events.clear(); + WebKitURIResponse* response = webkit_download_get_response(download.get()); + g_assert_cmpuint(webkit_uri_response_get_status_code(response), ==, 404); + g_assert_cmpfloat(webkit_download_get_estimated_progress(download.get()), <, 1); + + test->m_expectedError = WEBKIT_DOWNLOAD_ERROR_DESTINATION; + download = adoptGRef(webkit_web_context_download_uri(test->m_webContext, kServer->getURIForPath("/test.pdf").data())); + test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(download.get())); + test->waitUntilDownloadFinishes(); + + events = test->m_downloadEvents; + g_assert_cmpint(events.size(), ==, 4); + g_assert_cmpint(events[0], ==, DownloadTest::Started); + g_assert_cmpint(events[1], ==, DownloadTest::ReceivedResponse); + g_assert_cmpint(events[2], ==, DownloadTest::Failed); + g_assert_cmpint(events[3], ==, DownloadTest::Finished); + events.clear(); + g_assert_cmpfloat(webkit_download_get_estimated_progress(download.get()), <, 1); + test->checkDestinationAndDeleteFile(download.get(), "bar"); + + test->m_expectedError = WEBKIT_DOWNLOAD_ERROR_CANCELLED_BY_USER; + download = adoptGRef(webkit_web_context_download_uri(test->m_webContext, kServer->getURIForPath("/test.pdf").data())); + test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(download.get())); + test->waitUntilDownloadFinishes(); + + events = test->m_downloadEvents; + g_assert_cmpint(events.size(), ==, 4); + g_assert_cmpint(events[0], ==, DownloadTest::Started); + g_assert_cmpint(events[1], ==, DownloadTest::ReceivedResponse); + g_assert_cmpint(events[2], ==, DownloadTest::Failed); + g_assert_cmpint(events[3], ==, DownloadTest::Finished); + events.clear(); + g_assert_cmpfloat(webkit_download_get_estimated_progress(download.get()), <, 1); + test->checkDestinationAndDeleteFile(download.get(), kServerSuggestedFilename); +} + +void beforeAll() +{ + kServer = new WebKitTestServer(); + kServer->run(serverCallback); + + kTempDirectory = g_dir_make_tmp("WebKit2Tests-XXXXXX", 0); + g_assert(kTempDirectory); + + DownloadTest::add("Downloads", "local-file", testDownloadLocalFile); + DownloadErrorTest::add("Downloads", "local-file-error", testDownloadLocalFileError); + DownloadTest::add("Downloads", "remote-file", testDownloadRemoteFile); + DownloadErrorTest::add("Downloads", "remote-file-error", testDownloadRemoteFileError); +} + +void afterAll() +{ + delete kServer; + g_rmdir(kTempDirectory); +} diff --git a/Tools/ChangeLog b/Tools/ChangeLog index 224f9f1..e076809 100644 --- a/Tools/ChangeLog +++ b/Tools/ChangeLog @@ -1,3 +1,13 @@ +2012-01-24 Carlos Garcia Campos + + [GTK] Implement DownloadClient in WebKit2 GTK+ API + https://bugs.webkit.org/show_bug.cgi?id=72952 + + Reviewed by Martin Robinson. + + * gtk/generate-gtkdoc: + (get_webkit2_options): Ignore WebKitDownloadClient. + 2012-01-23 Zan Dobersek [GTK] editing/deleting/5408255.html results are incorrect diff --git a/Tools/gtk/generate-gtkdoc b/Tools/gtk/generate-gtkdoc index 0c18a38..317487b 100755 --- a/Tools/gtk/generate-gtkdoc +++ b/Tools/gtk/generate-gtkdoc @@ -60,6 +60,7 @@ def get_webkit2_options(): ' -I' + src_path(), 'ignored_files': glob.glob(src_path('*Private.h')) + \ glob.glob(src_path('PageClientImpl.*')) + \ + glob.glob(src_path('WebKitDownloadClient.*')) + \ glob.glob(src_path('WebKitUIClient.*')) + \ glob.glob(src_path('WebKitWebLoaderClient.*')) + \ glob.glob(src_path('WebKitWebViewBaseAccessible.*')) + \ -- 2.7.4