<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[206731] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/206731">206731</a></dd>
<dt>Author</dt> <dd>carlosgc@webkit.org</dd>
<dt>Date</dt> <dd>2016-10-03 03:32:52 -0700 (Mon, 03 Oct 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>[SOUP] Cleanup persistent credential storage code
https://bugs.webkit.org/show_bug.cgi?id=162777

Reviewed by Alex Christensen.

.:

Remove ENABLE(CREDENTIAL_STORAGE) build flag and replace it by USE(LIBSECRET).

* Source/cmake/OptionsGTK.cmake:
* Source/cmake/WebKitFeatures.cmake:

Source/WebCore:

We have this feature behind ENABLE_CREDENTIAL_STORAGE flag, which is confusing, because we use credential
storage unconditionally and this is only about persistent storage. Also the flag assumes libsecret is available,
and since it's only used by GTK sometimes we use GTK ifdefs instead of CREDENTIAL_STORAGE. So, I think we should
use USE(LIBSECRET) instead, and reduce a bit the ifdefs in common soup code. Another problem is that current
implementation is always used, while it should depend on the current network storage session and never used in
ephemeral sessions. This patch moves the code from CredentialBackingStore to NetworkStorageSessionSoup and
modernizes a bit.

* PlatformGTK.cmake: Remove CredentialBackingStore.cpp.
* platform/gtk/GRefPtrGtk.cpp: Use USE(LIBSECRET)
* platform/gtk/GRefPtrGtk.h:
* platform/network/NetworkStorageSession.h:
* platform/network/ResourceHandleInternal.h:
* platform/network/gtk/CredentialBackingStore.cpp: Removed.
* platform/network/gtk/CredentialBackingStore.h: Removed.
* platform/network/soup/NetworkStorageSessionSoup.cpp:
(WebCore::NetworkStorageSession::~NetworkStorageSession):
(WebCore::schemeFromProtectionSpaceServerType):
(WebCore::authTypeFromProtectionSpaceAuthenticationScheme):
(WebCore::NetworkStorageSession::getCredentialFromPersistentStorage):
(WebCore::NetworkStorageSession::saveCredentialToPersistentStorage):
(WebCore::NetworkStorageSession::ensurePrivateBrowsingSession): Deleted.
(WebCore::NetworkStorageSession::switchToNewTestingSession): Deleted.
* platform/network/soup/ResourceHandleSoup.cpp:
(WebCore::gotHeadersCallback):
(WebCore::ResourceHandle::didReceiveAuthenticationChallenge):
(WebCore::ResourceHandle::receivedCredential):
(WebCore::ResourceHandle::continueDidReceiveAuthenticationChallenge): Deleted.
(WebCore::ResourceHandle::receivedRequestToContinueWithoutCredential): Deleted.
(WebCore::ResourceHandle::receivedCancellation): Deleted.

Source/WebKit2:

Use USE(LIBSECRET) instead of ENABLE(CREDENTIAL_STORAGE).

* UIProcess/API/gtk/WebKitAuthenticationRequest.cpp:
(webkit_authentication_request_can_save_credentials):

Tools:

Use USE(LIBSECRET) instead of ENABLE(CREDENTIAL_STORAGE).

* TestWebKitAPI/Tests/WebKit2Gtk/TestAuthentication.cpp:
(testWebViewAuthenticationStorage):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkChangeLog">trunk/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCorePlatformGTKcmake">trunk/Source/WebCore/PlatformGTK.cmake</a></li>
<li><a href="#trunkSourceWebCoreplatformgtkGRefPtrGtkcpp">trunk/Source/WebCore/platform/gtk/GRefPtrGtk.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformgtkGRefPtrGtkh">trunk/Source/WebCore/platform/gtk/GRefPtrGtk.h</a></li>
<li><a href="#trunkSourceWebCoreplatformnetworkNetworkStorageSessionh">trunk/Source/WebCore/platform/network/NetworkStorageSession.h</a></li>
<li><a href="#trunkSourceWebCoreplatformnetworkResourceHandleInternalh">trunk/Source/WebCore/platform/network/ResourceHandleInternal.h</a></li>
<li><a href="#trunkSourceWebCoreplatformnetworksoupNetworkStorageSessionSoupcpp">trunk/Source/WebCore/platform/network/soup/NetworkStorageSessionSoup.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformnetworksoupResourceHandleSoupcpp">trunk/Source/WebCore/platform/network/soup/ResourceHandleSoup.cpp</a></li>
<li><a href="#trunkSourceWebKit2ChangeLog">trunk/Source/WebKit2/ChangeLog</a></li>
<li><a href="#trunkSourceWebKit2UIProcessAPIgtkWebKitAuthenticationRequestcpp">trunk/Source/WebKit2/UIProcess/API/gtk/WebKitAuthenticationRequest.cpp</a></li>
<li><a href="#trunkSourcecmakeOptionsGTKcmake">trunk/Source/cmake/OptionsGTK.cmake</a></li>
<li><a href="#trunkSourcecmakeWebKitFeaturescmake">trunk/Source/cmake/WebKitFeatures.cmake</a></li>
<li><a href="#trunkToolsChangeLog">trunk/Tools/ChangeLog</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebKit2GtkTestAuthenticationcpp">trunk/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestAuthentication.cpp</a></li>
</ul>

<h3>Removed Paths</h3>
<ul>
<li>trunk/Source/WebCore/platform/network/gtk/</li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/ChangeLog (206730 => 206731)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/ChangeLog        2016-10-03 09:51:18 UTC (rev 206730)
+++ trunk/ChangeLog        2016-10-03 10:32:52 UTC (rev 206731)
</span><span class="lines">@@ -1,3 +1,15 @@
</span><ins>+2016-10-03  Carlos Garcia Campos  &lt;cgarcia@igalia.com&gt;
+
+        [SOUP] Cleanup persistent credential storage code
+        https://bugs.webkit.org/show_bug.cgi?id=162777
+
+        Reviewed by Alex Christensen.
+
+        Remove ENABLE(CREDENTIAL_STORAGE) build flag and replace it by USE(LIBSECRET).
+
+        * Source/cmake/OptionsGTK.cmake:
+        * Source/cmake/WebKitFeatures.cmake:
+
</ins><span class="cx"> 2016-09-29  Aaron Chu  &lt;aaron_chu@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Web Inspector: AXI: linkified refs to #document and #text are not usually navigable nodes; consider delinkifying them
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (206730 => 206731)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2016-10-03 09:51:18 UTC (rev 206730)
+++ trunk/Source/WebCore/ChangeLog        2016-10-03 10:32:52 UTC (rev 206731)
</span><span class="lines">@@ -1,5 +1,43 @@
</span><span class="cx"> 2016-10-03  Carlos Garcia Campos  &lt;cgarcia@igalia.com&gt;
</span><span class="cx"> 
</span><ins>+        [SOUP] Cleanup persistent credential storage code
+        https://bugs.webkit.org/show_bug.cgi?id=162777
+
+        Reviewed by Alex Christensen.
+
+        We have this feature behind ENABLE_CREDENTIAL_STORAGE flag, which is confusing, because we use credential
+        storage unconditionally and this is only about persistent storage. Also the flag assumes libsecret is available,
+        and since it's only used by GTK sometimes we use GTK ifdefs instead of CREDENTIAL_STORAGE. So, I think we should
+        use USE(LIBSECRET) instead, and reduce a bit the ifdefs in common soup code. Another problem is that current
+        implementation is always used, while it should depend on the current network storage session and never used in
+        ephemeral sessions. This patch moves the code from CredentialBackingStore to NetworkStorageSessionSoup and
+        modernizes a bit.
+
+        * PlatformGTK.cmake: Remove CredentialBackingStore.cpp.
+        * platform/gtk/GRefPtrGtk.cpp: Use USE(LIBSECRET)
+        * platform/gtk/GRefPtrGtk.h:
+        * platform/network/NetworkStorageSession.h:
+        * platform/network/ResourceHandleInternal.h:
+        * platform/network/gtk/CredentialBackingStore.cpp: Removed.
+        * platform/network/gtk/CredentialBackingStore.h: Removed.
+        * platform/network/soup/NetworkStorageSessionSoup.cpp:
+        (WebCore::NetworkStorageSession::~NetworkStorageSession):
+        (WebCore::schemeFromProtectionSpaceServerType):
+        (WebCore::authTypeFromProtectionSpaceAuthenticationScheme):
+        (WebCore::NetworkStorageSession::getCredentialFromPersistentStorage):
+        (WebCore::NetworkStorageSession::saveCredentialToPersistentStorage):
+        (WebCore::NetworkStorageSession::ensurePrivateBrowsingSession): Deleted.
+        (WebCore::NetworkStorageSession::switchToNewTestingSession): Deleted.
+        * platform/network/soup/ResourceHandleSoup.cpp:
+        (WebCore::gotHeadersCallback):
+        (WebCore::ResourceHandle::didReceiveAuthenticationChallenge):
+        (WebCore::ResourceHandle::receivedCredential):
+        (WebCore::ResourceHandle::continueDidReceiveAuthenticationChallenge): Deleted.
+        (WebCore::ResourceHandle::receivedRequestToContinueWithoutCredential): Deleted.
+        (WebCore::ResourceHandle::receivedCancellation): Deleted.
+
+2016-10-03  Carlos Garcia Campos  &lt;cgarcia@igalia.com&gt;
+
</ins><span class="cx">         Unreviewed. Fix the build with coordinated graphics enabled after r206712.
</span><span class="cx"> 
</span><span class="cx">         * page/scrolling/ScrollingStateTree.cpp:
</span></span></pre></div>
<a id="trunkSourceWebCorePlatformGTKcmake"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/PlatformGTK.cmake (206730 => 206731)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/PlatformGTK.cmake        2016-10-03 09:51:18 UTC (rev 206730)
+++ trunk/Source/WebCore/PlatformGTK.cmake        2016-10-03 10:32:52 UTC (rev 206731)
</span><span class="lines">@@ -162,8 +162,6 @@
</span><span class="cx"> 
</span><span class="cx">     platform/mediastream/gtk/SDPProcessorScriptResourceGtk.cpp
</span><span class="cx"> 
</span><del>-    platform/network/gtk/CredentialBackingStore.cpp
-
</del><span class="cx">     platform/network/soup/AuthenticationChallengeSoup.cpp
</span><span class="cx">     platform/network/soup/CertificateInfo.cpp
</span><span class="cx">     platform/network/soup/CookieJarSoup.cpp
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgtkGRefPtrGtkcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/gtk/GRefPtrGtk.cpp (206730 => 206731)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/gtk/GRefPtrGtk.cpp        2016-10-03 09:51:18 UTC (rev 206730)
+++ trunk/Source/WebCore/platform/gtk/GRefPtrGtk.cpp        2016-10-03 10:32:52 UTC (rev 206731)
</span><span class="lines">@@ -23,7 +23,7 @@
</span><span class="cx"> #include &lt;glib.h&gt;
</span><span class="cx"> #include &lt;gtk/gtk.h&gt;
</span><span class="cx"> 
</span><del>-#if ENABLE(CREDENTIAL_STORAGE)
</del><ins>+#if USE(LIBSECRET)
</ins><span class="cx"> #define SECRET_WITH_UNSTABLE 1
</span><span class="cx"> #define SECRET_API_SUBJECT_TO_CHANGE 1
</span><span class="cx"> #include &lt;libsecret/secret.h&gt;
</span><span class="lines">@@ -44,7 +44,7 @@
</span><span class="cx">         gtk_target_list_unref(ptr);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-#if ENABLE(CREDENTIAL_STORAGE)
</del><ins>+#if USE(LIBSECRET)
</ins><span class="cx"> template &lt;&gt; SecretValue* refGPtr(SecretValue* ptr)
</span><span class="cx"> {
</span><span class="cx">     if (ptr)
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgtkGRefPtrGtkh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/gtk/GRefPtrGtk.h (206730 => 206731)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/gtk/GRefPtrGtk.h        2016-10-03 09:51:18 UTC (rev 206730)
+++ trunk/Source/WebCore/platform/gtk/GRefPtrGtk.h        2016-10-03 10:32:52 UTC (rev 206731)
</span><span class="lines">@@ -31,7 +31,7 @@
</span><span class="cx"> template &lt;&gt; GtkTargetList* refGPtr(GtkTargetList* ptr);
</span><span class="cx"> template &lt;&gt; void derefGPtr(GtkTargetList* ptr);
</span><span class="cx"> 
</span><del>-#if ENABLE(CREDENTIAL_STORAGE)
</del><ins>+#if USE(LIBSECRET)
</ins><span class="cx"> template &lt;&gt; SecretValue* refGPtr(SecretValue* ptr);
</span><span class="cx"> template &lt;&gt; void derefGPtr(SecretValue* ptr);
</span><span class="cx"> #endif
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformnetworkNetworkStorageSessionh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/network/NetworkStorageSession.h (206730 => 206731)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/network/NetworkStorageSession.h        2016-10-03 09:51:18 UTC (rev 206730)
+++ trunk/Source/WebCore/platform/network/NetworkStorageSession.h        2016-10-03 10:32:52 UTC (rev 206731)
</span><span class="lines">@@ -34,6 +34,11 @@
</span><span class="cx"> #include &lt;wtf/RetainPtr.h&gt;
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+#if USE(SOUP)
+#include &lt;wtf/Function.h&gt;
+#include &lt;wtf/glib/GRefPtr.h&gt;
+#endif
+
</ins><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><span class="cx"> class NetworkingContext;
</span><span class="lines">@@ -66,7 +71,8 @@
</span><span class="cx">     ~NetworkStorageSession();
</span><span class="cx"> 
</span><span class="cx">     SoupNetworkSession&amp; soupNetworkSession() const;
</span><del>-    void setSoupNetworkSession(std::unique_ptr&lt;SoupNetworkSession&gt;);
</del><ins>+    void getCredentialFromPersistentStorage(const ProtectionSpace&amp;, Function&lt;void (Credential&amp;&amp;)&gt; completionHandler);
+    void saveCredentialToPersistentStorage(const ProtectionSpace&amp;, const Credential&amp;);
</ins><span class="cx"> #else
</span><span class="cx">     NetworkStorageSession(SessionID, NetworkingContext*);
</span><span class="cx">     ~NetworkStorageSession();
</span><span class="lines">@@ -82,6 +88,10 @@
</span><span class="cx">     RetainPtr&lt;CFURLStorageSessionRef&gt; m_platformSession;
</span><span class="cx"> #elif USE(SOUP)
</span><span class="cx">     std::unique_ptr&lt;SoupNetworkSession&gt; m_session;
</span><ins>+#if USE(LIBSECRET)
+    Function&lt;void (Credential&amp;&amp;)&gt; m_persisentStorageCompletionHandler;
+    GRefPtr&lt;GCancellable&gt; m_persisentStorageCancellable;
+#endif
</ins><span class="cx"> #else
</span><span class="cx">     RefPtr&lt;NetworkingContext&gt; m_context;
</span><span class="cx"> #endif
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformnetworkResourceHandleInternalh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/network/ResourceHandleInternal.h (206730 => 206731)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/network/ResourceHandleInternal.h        2016-10-03 09:51:18 UTC (rev 206730)
+++ trunk/Source/WebCore/platform/network/ResourceHandleInternal.h        2016-10-03 10:32:52 UTC (rev 206731)
</span><span class="lines">@@ -178,11 +178,9 @@
</span><span class="cx">         int m_redirectCount;
</span><span class="cx">         size_t m_previousPosition;
</span><span class="cx">         bool m_useAuthenticationManager;
</span><del>-#endif
-#if PLATFORM(GTK)
</del><span class="cx">         struct {
</span><span class="cx">             Credential credential;
</span><del>-            AuthenticationChallenge challenge;
</del><ins>+            ProtectionSpace protectionSpace;
</ins><span class="cx">         } m_credentialDataToSaveInPersistentStore;
</span><span class="cx"> #endif
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformnetworksoupNetworkStorageSessionSoupcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/network/soup/NetworkStorageSessionSoup.cpp (206730 => 206731)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/network/soup/NetworkStorageSessionSoup.cpp        2016-10-03 09:51:18 UTC (rev 206730)
+++ trunk/Source/WebCore/platform/network/soup/NetworkStorageSessionSoup.cpp        2016-10-03 10:32:52 UTC (rev 206731)
</span><span class="lines">@@ -1,6 +1,7 @@
</span><span class="cx"> /*
</span><span class="cx">  * Copyright (C) 2013 Apple Inc. All rights reserved.
</span><span class="cx">  * Copyright (C) 2013 University of Szeged. All rights reserved.
</span><ins>+ * Copyright (C) 2016 Igalia S.L.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -31,9 +32,19 @@
</span><span class="cx"> 
</span><span class="cx"> #include &quot;ResourceHandle.h&quot;
</span><span class="cx"> #include &quot;SoupNetworkSession.h&quot;
</span><ins>+#include &lt;libsoup/soup.h&gt;
</ins><span class="cx"> #include &lt;wtf/MainThread.h&gt;
</span><span class="cx"> #include &lt;wtf/NeverDestroyed.h&gt;
</span><ins>+#include &lt;wtf/glib/GUniquePtr.h&gt;
</ins><span class="cx"> 
</span><ins>+#if USE(LIBSECRET)
+#include &quot;GRefPtrGtk.h&quot;
+#include &lt;glib/gi18n-lib.h&gt;
+#define SECRET_WITH_UNSTABLE 1
+#define SECRET_API_SUBJECT_TO_CHANGE 1
+#include &lt;libsecret/secret.h&gt;
+#endif
+
</ins><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><span class="cx"> NetworkStorageSession::NetworkStorageSession(SessionID sessionID, std::unique_ptr&lt;SoupNetworkSession&gt; session)
</span><span class="lines">@@ -44,6 +55,9 @@
</span><span class="cx"> 
</span><span class="cx"> NetworkStorageSession::~NetworkStorageSession()
</span><span class="cx"> {
</span><ins>+#if USE(LIBSECRET)
+    g_cancellable_cancel(m_persisentStorageCancellable.get());
+#endif
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static std::unique_ptr&lt;NetworkStorageSession&gt;&amp; defaultSession()
</span><span class="lines">@@ -78,11 +92,150 @@
</span><span class="cx">     return m_session ? *m_session : SoupNetworkSession::defaultSession();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void NetworkStorageSession::setSoupNetworkSession(std::unique_ptr&lt;SoupNetworkSession&gt; session)
</del><ins>+#if USE(LIBSECRET)
+static const char* schemeFromProtectionSpaceServerType(ProtectionSpaceServerType serverType)
</ins><span class="cx"> {
</span><del>-    m_session = WTFMove(session);
</del><ins>+    switch (serverType) {
+    case ProtectionSpaceServerHTTP:
+    case ProtectionSpaceProxyHTTP:
+        return SOUP_URI_SCHEME_HTTP;
+    case ProtectionSpaceServerHTTPS:
+    case ProtectionSpaceProxyHTTPS:
+        return SOUP_URI_SCHEME_HTTPS;
+    case ProtectionSpaceServerFTP:
+    case ProtectionSpaceProxyFTP:
+        return SOUP_URI_SCHEME_FTP;
+    case ProtectionSpaceServerFTPS:
+    case ProtectionSpaceProxySOCKS:
+        break;
+    }
+
+    ASSERT_NOT_REACHED();
+    return SOUP_URI_SCHEME_HTTP;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static const char* authTypeFromProtectionSpaceAuthenticationScheme(ProtectionSpaceAuthenticationScheme scheme)
+{
+    switch (scheme) {
+    case ProtectionSpaceAuthenticationSchemeDefault:
+    case ProtectionSpaceAuthenticationSchemeHTTPBasic:
+        return &quot;Basic&quot;;
+    case ProtectionSpaceAuthenticationSchemeHTTPDigest:
+        return &quot;Digest&quot;;
+    case ProtectionSpaceAuthenticationSchemeNTLM:
+        return &quot;NTLM&quot;;
+    case ProtectionSpaceAuthenticationSchemeNegotiate:
+        return &quot;Negotiate&quot;;
+    case ProtectionSpaceAuthenticationSchemeHTMLForm:
+    case ProtectionSpaceAuthenticationSchemeClientCertificateRequested:
+    case ProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested:
+        ASSERT_NOT_REACHED();
+        break;
+    case ProtectionSpaceAuthenticationSchemeUnknown:
+        return &quot;unknown&quot;;
+    }
+
+    ASSERT_NOT_REACHED();
+    return &quot;unknown&quot;;
</ins><span class="cx"> }
</span><ins>+#endif // USE(LIBSECRET)
</ins><span class="cx"> 
</span><ins>+void NetworkStorageSession::getCredentialFromPersistentStorage(const ProtectionSpace&amp; protectionSpace, Function&lt;void (Credential&amp;&amp;)&gt; completionHandler)
+{
+#if USE(LIBSECRET)
+    if (m_sessionID.isEphemeral()) {
+        completionHandler({ });
+        return;
+    }
+
+    const String&amp; realm = protectionSpace.realm();
+    if (realm.isEmpty()) {
+        completionHandler({ });
+        return;
+    }
+
+    GRefPtr&lt;GHashTable&gt; attributes = adoptGRef(secret_attributes_build(SECRET_SCHEMA_COMPAT_NETWORK,
+        &quot;domain&quot;, realm.utf8().data(),
+        &quot;server&quot;, protectionSpace.host().utf8().data(),
+        &quot;port&quot;, protectionSpace.port(),
+        &quot;protocol&quot;, schemeFromProtectionSpaceServerType(protectionSpace.serverType()),
+        &quot;authtype&quot;, authTypeFromProtectionSpaceAuthenticationScheme(protectionSpace.authenticationScheme()),
+        nullptr));
+    if (!attributes) {
+        completionHandler({ });
+        return;
+    }
+
+    m_persisentStorageCancellable = adoptGRef(g_cancellable_new());
+    m_persisentStorageCompletionHandler = WTFMove(completionHandler);
+    secret_service_search(nullptr, SECRET_SCHEMA_COMPAT_NETWORK, attributes.get(),
+        static_cast&lt;SecretSearchFlags&gt;(SECRET_SEARCH_UNLOCK | SECRET_SEARCH_LOAD_SECRETS), m_persisentStorageCancellable.get(),
+        [](GObject* source, GAsyncResult* result, gpointer userData) {
+            GUniqueOutPtr&lt;GError&gt; error;
+            GUniquePtr&lt;GList&gt; elements(secret_service_search_finish(SECRET_SERVICE(source), result, &amp;error.outPtr()));
+            if (g_error_matches (error.get(), G_IO_ERROR, G_IO_ERROR_CANCELLED))
+                return;
+
+            NetworkStorageSession* session = static_cast&lt;NetworkStorageSession*&gt;(userData);
+            auto completionHandler = std::exchange(session-&gt;m_persisentStorageCompletionHandler, nullptr);
+            if (error || !elements || !elements-&gt;data) {
+                completionHandler({ });
+                return;
+            }
+
+            GRefPtr&lt;SecretItem&gt; secretItem = adoptGRef(static_cast&lt;SecretItem*&gt;(elements-&gt;data));
+            GRefPtr&lt;GHashTable&gt; attributes = adoptGRef(secret_item_get_attributes(secretItem.get()));
+            String user = String::fromUTF8(static_cast&lt;const char*&gt;(g_hash_table_lookup(attributes.get(), &quot;user&quot;)));
+            if (user.isEmpty()) {
+                completionHandler({ });
+                return;
+            }
+
+            size_t length;
+            GRefPtr&lt;SecretValue&gt; secretValue = adoptGRef(secret_item_get_secret(secretItem.get()));
+            const char* passwordData = secret_value_get(secretValue.get(), &amp;length);
+            completionHandler(Credential(user, String::fromUTF8(passwordData, length), CredentialPersistencePermanent));
+    }, this);
+#else
+    UNUSED_PARAM(protectionSpace);
+    completionHandler({ });
</ins><span class="cx"> #endif
</span><ins>+}
+
+void NetworkStorageSession::saveCredentialToPersistentStorage(const ProtectionSpace&amp; protectionSpace, const Credential&amp; credential)
+{
+#if USE(LIBSECRET)
+    if (m_sessionID.isEphemeral())
+        return;
+
+    if (credential.isEmpty())
+        return;
+
+    const String&amp; realm = protectionSpace.realm();
+    if (realm.isEmpty())
+        return;
+
+    GRefPtr&lt;GHashTable&gt; attributes = adoptGRef(secret_attributes_build(SECRET_SCHEMA_COMPAT_NETWORK,
+        &quot;domain&quot;, realm.utf8().data(),
+        &quot;server&quot;, protectionSpace.host().utf8().data(),
+        &quot;port&quot;, protectionSpace.port(),
+        &quot;protocol&quot;, schemeFromProtectionSpaceServerType(protectionSpace.serverType()),
+        &quot;authtype&quot;, authTypeFromProtectionSpaceAuthenticationScheme(protectionSpace.authenticationScheme()),
+        nullptr));
+    if (!attributes)
+        return;
+
+    g_hash_table_insert(attributes.get(), g_strdup(&quot;user&quot;), g_strdup(credential.user().utf8().data()));
+    CString utf8Password = credential.password().utf8();
+    GRefPtr&lt;SecretValue&gt; newSecretValue = adoptGRef(secret_value_new(utf8Password.data(), utf8Password.length(), &quot;text/plain&quot;));
+    secret_service_store(nullptr, SECRET_SCHEMA_COMPAT_NETWORK, attributes.get(), SECRET_COLLECTION_DEFAULT, _(&quot;WebKitGTK+ password&quot;),
+        newSecretValue.get(), nullptr, nullptr, nullptr);
+#else
+    UNUSED_PARAM(protectionSpace);
+    UNUSED_PARAM(credential);
+#endif
+}
+
+} // namespace WebCore
+
+#endif // USE(SOUP)
</ins></span></pre></div>
<a id="trunkSourceWebCoreplatformnetworksoupResourceHandleSoupcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/network/soup/ResourceHandleSoup.cpp (206730 => 206731)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/network/soup/ResourceHandleSoup.cpp        2016-10-03 09:51:18 UTC (rev 206730)
+++ trunk/Source/WebCore/platform/network/soup/ResourceHandleSoup.cpp        2016-10-03 10:32:52 UTC (rev 206731)
</span><span class="lines">@@ -66,10 +66,6 @@
</span><span class="cx"> #include &quot;BlobData.h&quot;
</span><span class="cx"> #include &quot;BlobRegistryImpl.h&quot;
</span><span class="cx"> 
</span><del>-#if PLATFORM(GTK)
-#include &quot;CredentialBackingStore.h&quot;
-#endif
-
</del><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><span class="cx"> static const size_t gDefaultReadBufferSize = 8192;
</span><span class="lines">@@ -230,17 +226,15 @@
</span><span class="cx"> 
</span><span class="cx">     ResourceHandleInternal* d = handle-&gt;getInternal();
</span><span class="cx"> 
</span><del>-#if PLATFORM(GTK)
</del><span class="cx">     // We are a bit more conservative with the persistent credential storage than the session store,
</span><span class="cx">     // since we are waiting until we know that this authentication succeeded before actually storing.
</span><span class="cx">     // This is because we want to avoid hitting the disk twice (once to add and once to remove) for
</span><span class="cx">     // incorrect credentials or polluting the keychain with invalid credentials.
</span><del>-    if (!isAuthenticationFailureStatusCode(message-&gt;status_code) &amp;&amp; message-&gt;status_code &lt; 500 &amp;&amp; !d-&gt;m_credentialDataToSaveInPersistentStore.credential.isEmpty()) {
-        credentialBackingStore().storeCredentialsForChallenge(
-            d-&gt;m_credentialDataToSaveInPersistentStore.challenge,
</del><ins>+    if (!isAuthenticationFailureStatusCode(message-&gt;status_code) &amp;&amp; message-&gt;status_code &lt; 500) {
+        d-&gt;m_context-&gt;storageSession().saveCredentialToPersistentStorage(
+            d-&gt;m_credentialDataToSaveInPersistentStore.protectionSpace,
</ins><span class="cx">             d-&gt;m_credentialDataToSaveInPersistentStore.credential);
</span><span class="cx">     }
</span><del>-#endif
</del><span class="cx"> 
</span><span class="cx">     // The original response will be needed later to feed to willSendRequest in
</span><span class="cx">     // doRedirect() in case we are redirected. For this reason, we store it here.
</span><span class="lines">@@ -970,13 +964,6 @@
</span><span class="cx">     gIgnoreSSLErrors = ignoreSSLErrors;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-#if PLATFORM(GTK)
-void getCredentialFromPersistentStoreCallback(const Credential&amp; credential, void* data)
-{
-    static_cast&lt;ResourceHandle*&gt;(data)-&gt;continueDidReceiveAuthenticationChallenge(credential);
-}
-#endif
-
</del><span class="cx"> void ResourceHandle::continueDidReceiveAuthenticationChallenge(const Credential&amp; credentialFromPersistentStorage)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(!d-&gt;m_currentWebChallenge.isNull());
</span><span class="lines">@@ -1030,16 +1017,16 @@
</span><span class="cx">     d-&gt;m_currentWebChallenge = challenge;
</span><span class="cx">     soup_session_pause_message(challenge.soupSession(), challenge.soupMessage());
</span><span class="cx"> 
</span><del>-#if PLATFORM(GTK)
</del><span class="cx">     // We could also do this before we even start the request, but that would be at the expense
</span><span class="cx">     // of all request latency, versus a one-time latency for the small subset of requests that
</span><span class="cx">     // use HTTP authentication. In the end, this doesn't matter much, because persistent credentials
</span><span class="cx">     // will become session credentials after the first use.
</span><span class="cx">     if (useCredentialStorage) {
</span><del>-        credentialBackingStore().credentialForChallenge(challenge, getCredentialFromPersistentStoreCallback, this);
</del><ins>+        d-&gt;m_context-&gt;storageSession().getCredentialFromPersistentStorage(challenge.protectionSpace(), [this, protectedThis = makeRef(*this)] (Credential&amp;&amp; credential) {
+            continueDidReceiveAuthenticationChallenge(WTFMove(credential));
+        });
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><del>-#endif
</del><span class="cx"> 
</span><span class="cx">     continueDidReceiveAuthenticationChallenge(Credential());
</span><span class="cx"> }
</span><span class="lines">@@ -1074,12 +1061,10 @@
</span><span class="cx">         if (credential.persistence() == CredentialPersistenceForSession || credential.persistence() == CredentialPersistencePermanent)
</span><span class="cx">             CredentialStorage::defaultCredentialStorage().set(credential, challenge.protectionSpace(), challenge.failureResponse().url());
</span><span class="cx"> 
</span><del>-#if PLATFORM(GTK)
</del><span class="cx">         if (credential.persistence() == CredentialPersistencePermanent) {
</span><span class="cx">             d-&gt;m_credentialDataToSaveInPersistentStore.credential = credential;
</span><del>-            d-&gt;m_credentialDataToSaveInPersistentStore.challenge = challenge;
</del><ins>+            d-&gt;m_credentialDataToSaveInPersistentStore.protectionSpace = challenge.protectionSpace();
</ins><span class="cx">         }
</span><del>-#endif
</del><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     ASSERT(challenge.soupSession());
</span></span></pre></div>
<a id="trunkSourceWebKit2ChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/ChangeLog (206730 => 206731)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/ChangeLog        2016-10-03 09:51:18 UTC (rev 206730)
+++ trunk/Source/WebKit2/ChangeLog        2016-10-03 10:32:52 UTC (rev 206731)
</span><span class="lines">@@ -1,3 +1,15 @@
</span><ins>+2016-10-03  Carlos Garcia Campos  &lt;cgarcia@igalia.com&gt;
+
+        [SOUP] Cleanup persistent credential storage code
+        https://bugs.webkit.org/show_bug.cgi?id=162777
+
+        Reviewed by Alex Christensen.
+
+        Use USE(LIBSECRET) instead of ENABLE(CREDENTIAL_STORAGE).
+
+        * UIProcess/API/gtk/WebKitAuthenticationRequest.cpp:
+        (webkit_authentication_request_can_save_credentials):
+
</ins><span class="cx"> 2016-10-02  Ryan Haddad  &lt;ryanhaddad@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Unreviewed, rolling out r206683.
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessAPIgtkWebKitAuthenticationRequestcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/API/gtk/WebKitAuthenticationRequest.cpp (206730 => 206731)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/API/gtk/WebKitAuthenticationRequest.cpp        2016-10-03 09:51:18 UTC (rev 206730)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/WebKitAuthenticationRequest.cpp        2016-10-03 10:32:52 UTC (rev 206731)
</span><span class="lines">@@ -161,7 +161,7 @@
</span><span class="cx"> {
</span><span class="cx">     g_return_val_if_fail(WEBKIT_IS_AUTHENTICATION_REQUEST(request), FALSE);
</span><span class="cx"> 
</span><del>-#if ENABLE(CREDENTIAL_STORAGE)
</del><ins>+#if USE(LIBSECRET)
</ins><span class="cx">     return !request-&gt;priv-&gt;privateBrowsingEnabled;
</span><span class="cx"> #else
</span><span class="cx">     return FALSE;
</span></span></pre></div>
<a id="trunkSourcecmakeOptionsGTKcmake"></a>
<div class="modfile"><h4>Modified: trunk/Source/cmake/OptionsGTK.cmake (206730 => 206731)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/cmake/OptionsGTK.cmake        2016-10-03 09:51:18 UTC (rev 206730)
+++ trunk/Source/cmake/OptionsGTK.cmake        2016-10-03 10:32:52 UTC (rev 206731)
</span><span class="lines">@@ -87,6 +87,7 @@
</span><span class="cx"> WEBKIT_OPTION_DEFINE(ENABLE_WAYLAND_TARGET &quot;Whether to enable support for the Wayland windowing target.&quot; PUBLIC ${GTK3_SUPPORTS_WAYLAND})
</span><span class="cx"> WEBKIT_OPTION_DEFINE(USE_LIBNOTIFY &quot;Whether to enable the default web notification implementation.&quot; PUBLIC ON)
</span><span class="cx"> WEBKIT_OPTION_DEFINE(USE_LIBHYPHEN &quot;Whether to enable the default automatic hyphenation implementation.&quot; PUBLIC ON)
</span><ins>+WEBKIT_OPTION_DEFINE(USE_LIBSECRET &quot;Whether to enable the persistent credential storage using libsecret.&quot; PUBLIC ON)
</ins><span class="cx"> 
</span><span class="cx"> # Private options specific to the GTK+ port. Changing these options is
</span><span class="cx"> # completely unsupported. They are intended for use only by WebKit developers.
</span><span class="lines">@@ -133,7 +134,6 @@
</span><span class="cx"> # without approval from a GTK+ reviewer. There must be strong reason to support
</span><span class="cx"> # changing the value of the option.
</span><span class="cx"> WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_ACCELERATED_2D_CANVAS PUBLIC OFF)
</span><del>-WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_CREDENTIAL_STORAGE PUBLIC ON)
</del><span class="cx"> WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_DRAG_SUPPORT PUBLIC ON)
</span><span class="cx"> WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_GEOLOCATION PUBLIC ON)
</span><span class="cx"> WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_ICONDATABASE PUBLIC ON)
</span><span class="lines">@@ -228,10 +228,10 @@
</span><span class="cx">     endif ()
</span><span class="cx"> endif ()
</span><span class="cx"> 
</span><del>-if (ENABLE_CREDENTIAL_STORAGE)
</del><ins>+if (USE_LIBSECRET)
</ins><span class="cx">     find_package(Libsecret)
</span><span class="cx">     if (NOT LIBSECRET_FOUND)
</span><del>-        message(FATAL_ERROR &quot;libsecret is needed for ENABLE_CREDENTIAL_STORAGE&quot;)
</del><ins>+        message(FATAL_ERROR &quot;libsecret is needed for USE_LIBSECRET&quot;)
</ins><span class="cx">     endif ()
</span><span class="cx"> endif ()
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourcecmakeWebKitFeaturescmake"></a>
<div class="modfile"><h4>Modified: trunk/Source/cmake/WebKitFeatures.cmake (206730 => 206731)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/cmake/WebKitFeatures.cmake        2016-10-03 09:51:18 UTC (rev 206730)
+++ trunk/Source/cmake/WebKitFeatures.cmake        2016-10-03 10:32:52 UTC (rev 206731)
</span><span class="lines">@@ -83,7 +83,6 @@
</span><span class="cx">     WEBKIT_OPTION_DEFINE(ENABLE_CHANNEL_MESSAGING &quot;Toggle MessageChannel and MessagePort support&quot; PRIVATE ON)
</span><span class="cx">     WEBKIT_OPTION_DEFINE(ENABLE_CONTENT_FILTERING &quot;Toggle content filtering support&quot; PRIVATE OFF)
</span><span class="cx">     WEBKIT_OPTION_DEFINE(ENABLE_CONTEXT_MENUS &quot;Toggle Context Menu support&quot; PRIVATE ON)
</span><del>-    WEBKIT_OPTION_DEFINE(ENABLE_CREDENTIAL_STORAGE &quot;Toggle Credential Storage support&quot; PRIVATE OFF)
</del><span class="cx">     WEBKIT_OPTION_DEFINE(ENABLE_CSP_NEXT &quot;Toggle Content Security Policy 1.1 support&quot; PRIVATE OFF)
</span><span class="cx">     WEBKIT_OPTION_DEFINE(ENABLE_CSS3_TEXT &quot;Toggle CSS3 Text support&quot; PRIVATE OFF)
</span><span class="cx">     WEBKIT_OPTION_DEFINE(ENABLE_CSS_BOX_DECORATION_BREAK &quot;Toggle Box Decoration break (CSS Backgrounds and Borders) support&quot; PRIVATE ON)
</span></span></pre></div>
<a id="trunkToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ChangeLog (206730 => 206731)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog        2016-10-03 09:51:18 UTC (rev 206730)
+++ trunk/Tools/ChangeLog        2016-10-03 10:32:52 UTC (rev 206731)
</span><span class="lines">@@ -1,3 +1,15 @@
</span><ins>+2016-10-03  Carlos Garcia Campos  &lt;cgarcia@igalia.com&gt;
+
+        [SOUP] Cleanup persistent credential storage code
+        https://bugs.webkit.org/show_bug.cgi?id=162777
+
+        Reviewed by Alex Christensen.
+
+        Use USE(LIBSECRET) instead of ENABLE(CREDENTIAL_STORAGE).
+
+        * TestWebKitAPI/Tests/WebKit2Gtk/TestAuthentication.cpp:
+        (testWebViewAuthenticationStorage):
+
</ins><span class="cx"> 2016-10-02  Darin Adler  &lt;darin@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Rename ExceptionCode-based exception handling to &quot;legacy&quot;
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKit2GtkTestAuthenticationcpp"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestAuthentication.cpp (206730 => 206731)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestAuthentication.cpp        2016-10-03 09:51:18 UTC (rev 206730)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestAuthentication.cpp        2016-10-03 10:32:52 UTC (rev 206731)
</span><span class="lines">@@ -195,7 +195,7 @@
</span><span class="cx"> 
</span><span class="cx">     // If WebKit has been compiled with libsecret, and private browsing is disabled
</span><span class="cx">     // then check that credentials can be saved.
</span><del>-#if ENABLE(CREDENTIAL_STORAGE)
</del><ins>+#if USE(LIBSECRET)
</ins><span class="cx">     webkit_settings_set_enable_private_browsing(webkit_web_view_get_settings(test-&gt;m_webView), FALSE);
</span><span class="cx">     test-&gt;loadURI(kServer-&gt;getURIForPath(&quot;/auth-test.html&quot;).data());
</span><span class="cx">     request = test-&gt;waitForAuthenticationRequest();
</span></span></pre>
</div>
</div>

</body>
</html>