summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Strømme <christian.stromme@qt.io>2022-04-22 15:32:11 +0200
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2022-05-09 19:48:23 +0000
commit119e21eb0ac0b0adfd4878199b270b07fc1cb141 (patch)
treeb6b7ab10d03122b9d98f95f696ed4d8444cd50cc
parent0cc23985f9e5dcadbc7d0b262143fc7a036df7c3 (diff)
Fix crash due to missing native functions for the cookie APIs
The cookie API that was added in 317e13cb2d97 missed the registration and implementation for the native java functions needed for notifying when a cookie got added/removed. Fixes: QTBUG-102801 Change-Id: I7594f75abba17b6ff1843d5349af085f90aae9b1 Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io> (cherry picked from commit 3702c4ccc19155840b3058631acf5cc015561df0) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r--src/jar/src/org/qtproject/qt/android/view/QtAndroidWebViewController.java85
-rw-r--r--src/plugins/android/qandroidwebview.cpp46
-rw-r--r--tests/auto/qml/qquickwebview/tst_qquickwebview.cpp34
-rw-r--r--tests/auto/qml/qquickwebview/util.h37
-rw-r--r--tests/auto/webview/qwebview/tst_qwebview.cpp6
5 files changed, 169 insertions, 39 deletions
diff --git a/src/jar/src/org/qtproject/qt/android/view/QtAndroidWebViewController.java b/src/jar/src/org/qtproject/qt/android/view/QtAndroidWebViewController.java
index 11aa686..63f6bb8 100644
--- a/src/jar/src/org/qtproject/qt/android/view/QtAndroidWebViewController.java
+++ b/src/jar/src/org/qtproject/qt/android/view/QtAndroidWebViewController.java
@@ -61,6 +61,7 @@ import java.util.concurrent.Semaphore;
import java.lang.reflect.Method;
import android.os.Build;
import java.util.concurrent.TimeUnit;
+import java.time.format.DateTimeFormatter;
public class QtAndroidWebViewController
{
@@ -95,7 +96,7 @@ public class QtAndroidWebViewController
private native void c_onRunJavaScriptResult(long id, long callbackId, String result);
private native void c_onReceivedError(long id, int errorCode, String description, String url);
private native void c_onCookieAdded(long id, boolean result, String domain, String name);
- private native void c_onCookiesRemoved(long id, boolean result);
+ private native void c_onCookieRemoved(long id, boolean result, String domain, String name);
// We need to block the UI thread in some cases, if it takes to long we should timeout before
// ANR kicks in... Usually the hard limit is set to 10s and if exceed that then we're in trouble.
@@ -528,41 +529,87 @@ public class QtAndroidWebViewController
});
}
- public void setCookie(final String url, final String cookieString)
+ private void setCookieImp(final String url, final String cookieString, ValueCallback<Boolean> callback)
{
CookieManager cookieManager = CookieManager.getInstance();
cookieManager.setAcceptCookie(true);
try {
- cookieManager.setCookie(url, cookieString, new ValueCallback<Boolean>() {
- @Override
- public void onReceiveValue(Boolean value) {
- try {
- c_onCookieAdded(m_id, value, url, cookieString.split("=")[0]);
- }
- catch (Exception e) {
- e.printStackTrace();
- }
- }
- });
+ cookieManager.setCookie(url, cookieString, callback);
} catch (Exception e) {
e.printStackTrace();
}
}
- public void removeCookies() {
- try {
- CookieManager.getInstance().removeAllCookies(new ValueCallback<Boolean>() {
+ public void setCookie(final String url, final String cookieString)
+ {
+ setCookieImp(url, cookieString, new ValueCallback<Boolean>() {
+ @Override
+ public void onReceiveValue(Boolean value) {
+ try {
+ c_onCookieAdded(m_id, value, url, cookieString.split("=")[0]);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ });
+ }
+
+ private boolean hasValidCookie(final String url, final String cookieString)
+ {
+ CookieManager cookieManager = CookieManager.getInstance();
+ cookieManager.removeExpiredCookie();
+ boolean cookieFound = false;
+
+ final String domainCookie = cookieManager.getCookie(url);
+
+ String found = null;
+ if (domainCookie != null) {
+ String cookies[] = domainCookie.split(";");
+ for (final String cookie : cookies) {
+ if (cookie.startsWith(cookieString)) {
+ found = cookie;
+ // Cookie is "cleared" so not considered valid.
+ cookieFound = !cookie.endsWith("=");
+ break;
+ }
+ }
+ }
+
+ return cookieFound;
+ }
+
+ private String getExpireString()
+ {
+ return "expires=\"Thu, 1 Jan 1970 00:00:00 GMT\"";
+ }
+
+ public void removeCookie(final String url, final String cookieString)
+ {
+ // We need to work with what we have
+ // 1. Check if there's cookies for the url
+ final boolean hadCookie = hasValidCookie(url, cookieString);
+ if (hadCookie) {
+ // 2. Tag the string with an expire tag so it will be purged
+ final String removeCookieString = cookieString + ";" + getExpireString();
+ setCookieImp(url, removeCookieString, new ValueCallback<Boolean>() {
@Override
public void onReceiveValue(Boolean value) {
try {
- c_onCookiesRemoved(m_id, value);
- }
- catch (Exception e) {
+ // 3. Verify that the cookie was indeed removed
+ final boolean removed = (hadCookie && !hasValidCookie(url, cookieString));
+ c_onCookieRemoved(m_id, removed, url, cookieString.split("=")[0]);
+ } catch (Exception e) {
e.printStackTrace();
}
}
});
+ }
+ }
+
+ public void removeCookies() {
+ try {
+ CookieManager.getInstance().removeAllCookies(null);
} catch (Exception e) {
e.printStackTrace();
}
diff --git a/src/plugins/android/qandroidwebview.cpp b/src/plugins/android/qandroidwebview.cpp
index d142e0c..b291608 100644
--- a/src/plugins/android/qandroidwebview.cpp
+++ b/src/plugins/android/qandroidwebview.cpp
@@ -225,10 +225,10 @@ void QAndroidWebViewPrivate::setCookie(const QString &domain, const QString &nam
void QAndroidWebViewPrivate::deleteCookie(const QString &domain, const QString &name)
{
QNativeInterface::QAndroidApplication::runOnAndroidMainThread([=]() {
- m_viewController.callMethod<void>("setCookie",
+ m_viewController.callMethod<void>("removeCookie",
"(Ljava/lang/String;Ljava/lang/String;)V",
static_cast<jstring>(QJniObject::fromString(domain).object()),
- static_cast<jstring>(QJniObject::fromString(name + "=" + "").object()));
+ static_cast<jstring>(QJniObject::fromString(name.split(u'=').at(0) + u'=').object()));
});
}
@@ -437,6 +437,44 @@ static void c_onReceivedError(JNIEnv *env,
Q_EMIT wc->loadingChanged(loadRequest);
}
+static void c_onCookieAdded(JNIEnv *env,
+ jobject thiz,
+ jlong id,
+ jboolean result,
+ jstring domain,
+ jstring name)
+{
+ Q_UNUSED(env);
+ Q_UNUSED(thiz);
+
+ if (result) {
+ const WebViews &wv = (*g_webViews);
+ QAndroidWebViewPrivate *wc = wv[id];
+ if (!wc)
+ return;
+ Q_EMIT wc->cookieAdded(QJniObject(domain).toString(), QJniObject(name).toString());
+ }
+}
+
+static void c_onCookieRemoved(JNIEnv *env,
+ jobject thiz,
+ jlong id,
+ jboolean result,
+ jstring domain,
+ jstring name)
+{
+ Q_UNUSED(env);
+ Q_UNUSED(thiz);
+
+ if (result) {
+ const WebViews &wv = (*g_webViews);
+ QAndroidWebViewPrivate *wc = wv[id];
+ if (!wc)
+ return;
+ Q_EMIT wc->cookieRemoved(QJniObject(domain).toString(), QJniObject(name).toString());
+ }
+}
+
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* /*reserved*/)
{
static bool initialized = false;
@@ -467,7 +505,9 @@ JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* /*reserved*/)
{"c_onReceivedIcon", "(JLandroid/graphics/Bitmap;)V", reinterpret_cast<void *>(c_onReceivedIcon)},
{"c_onReceivedTitle", "(JLjava/lang/String;)V", reinterpret_cast<void *>(c_onReceivedTitle)},
{"c_onRunJavaScriptResult", "(JJLjava/lang/String;)V", reinterpret_cast<void *>(c_onRunJavaScriptResult)},
- {"c_onReceivedError", "(JILjava/lang/String;Ljava/lang/String;)V", reinterpret_cast<void *>(c_onReceivedError)}
+ {"c_onReceivedError", "(JILjava/lang/String;Ljava/lang/String;)V", reinterpret_cast<void *>(c_onReceivedError)},
+ {"c_onCookieAdded", "(JZLjava/lang/String;Ljava/lang/String;)V", reinterpret_cast<void *>(c_onCookieAdded)},
+ {"c_onCookieRemoved", "(JZLjava/lang/String;Ljava/lang/String;)V", reinterpret_cast<void *>(c_onCookieRemoved)}
};
const int nMethods = sizeof(methods) / sizeof(methods[0]);
diff --git a/tests/auto/qml/qquickwebview/tst_qquickwebview.cpp b/tests/auto/qml/qquickwebview/tst_qquickwebview.cpp
index 9e10d9f..b631d4a 100644
--- a/tests/auto/qml/qquickwebview/tst_qquickwebview.cpp
+++ b/tests/auto/qml/qquickwebview/tst_qquickwebview.cpp
@@ -356,9 +356,6 @@ void tst_QQuickWebView::changeUserAgent()
void tst_QQuickWebView::setAndDeleteCookies()
{
-#ifdef Q_OS_ANDROID
- QSKIP("Craches on Android (QTBUG-102801)");
-#endif
QSignalSpy cookieAddedSpy(webView(), SIGNAL(cookieAdded(const QString &, const QString &)));
QSignalSpy cookieRemovedSpy(webView(), SIGNAL(cookieRemoved(const QString &, const QString &)));
@@ -375,19 +372,25 @@ void tst_QQuickWebView::setAndDeleteCookies()
cookieRemovedSpy.clear();
#endif
- webView()->setCookie(".example.com", "TestCookie", "testValue");
- webView()->setCookie(".example2.com", "TestCookie2", "testValue2");
- webView()->setCookie(".example3.com", "TestCookie3", "testValue3");
- QTRY_COMPARE(cookieAddedSpy.count(), 3);
- QList<QVariant> arguments = cookieAddedSpy.first();
- QCOMPARE(arguments.at(0), ".example.com");
- QCOMPARE(arguments.at(1), "TestCookie");
+ Cookie::List cookies { {".example.com", "TestCookie", "testValue"},
+ {".example2.com", "TestCookie2", "testValue2"},
+ {".example3.com", "TestCookie3", "testValue3"} };
+
+ for (const auto &cookie : cookies)
+ webView()->setCookie(cookie.domain, cookie.name, cookie.value);
+
+ QTRY_COMPARE(cookieAddedSpy.count(), cookies.count());
+ QVERIFY(Cookie::testSignalValues(cookies, cookieAddedSpy));
- webView()->deleteCookie(".example.com", "TestCookie");
+ auto removedCookie = cookies.takeLast();
+
+ webView()->deleteCookie(removedCookie.domain, removedCookie.name);
QTRY_COMPARE(cookieRemovedSpy.count(), 1);
- arguments = cookieRemovedSpy.first();
- QCOMPARE(arguments.at(0), ".example.com");
- QCOMPARE(arguments.at(1), "TestCookie");
+ {
+ const auto &first = cookieRemovedSpy.first();
+ Cookie::SigArg sigArg{ first.at(0).toString(), first.at(1).toString() };
+ QCOMPARE(removedCookie, sigArg);
+ }
// deleting a cookie using a name that has not been set
webView()->deleteCookie(".example.com", "NewCookieName");
@@ -398,6 +401,9 @@ void tst_QQuickWebView::setAndDeleteCookies()
QTRY_COMPARE(cookieRemovedSpy.count(), 1);
webView()->deleteAllCookies();
+#ifdef Q_OS_ANDROID
+ QEXPECT_FAIL("", "Notification for deleteAllCookies() is not implemented on Android, yet!", Continue);
+#endif
QTRY_COMPARE(cookieRemovedSpy.count(), 3);
}
diff --git a/tests/auto/qml/qquickwebview/util.h b/tests/auto/qml/qquickwebview/util.h
index 9909335..5199d4f 100644
--- a/tests/auto/qml/qquickwebview/util.h
+++ b/tests/auto/qml/qquickwebview/util.h
@@ -117,4 +117,41 @@ inline bool waitForLoadFailed(QQuickWebView *webView, int timeout = 10000)
return waitForSignal(&loadSpy, SIGNAL(loadFailed()), timeout);
}
+struct Cookie
+{
+ struct SigArg
+ {
+ QString domain;
+ QString name;
+ };
+
+ using List = QList<Cookie>;
+ using SignalReturnValues = QList<QList<QVariant>>;
+
+ QString domain;
+ QString name;
+ QString value;
+ friend bool operator==(const Cookie &a, const Cookie::SigArg &b)
+ {
+ return (a.domain == b.domain) && (a.name == b.name);
+ }
+
+ static bool testSignalValues(const Cookie::List &cookies, const SignalReturnValues &sigValues)
+ {
+ if (cookies.size() != sigValues.size())
+ return false;
+
+ int found = 0;
+ for (const auto &cookie : cookies) {
+ auto it = std::find_if(sigValues.constBegin(), sigValues.constEnd(), [cookie](const QVariantList &sigArgs) {
+ return (cookie == Cookie::SigArg{sigArgs.at(0).toString(), sigArgs.at(1).toString() });
+ });
+ if (it != sigValues.constEnd())
+ ++found;
+ }
+
+ return (found == cookies.size());
+ }
+};
+
#endif /* UTIL_H */
diff --git a/tests/auto/webview/qwebview/tst_qwebview.cpp b/tests/auto/webview/qwebview/tst_qwebview.cpp
index d4f231d..55d9d49 100644
--- a/tests/auto/webview/qwebview/tst_qwebview.cpp
+++ b/tests/auto/webview/qwebview/tst_qwebview.cpp
@@ -243,9 +243,6 @@ void tst_QWebView::loadRequest()
void tst_QWebView::setAndDeleteCookie()
{
-#ifdef Q_OS_ANDROID
- QSKIP("Craches on Android (QTBUG-102801)");
-#endif
#ifdef QT_WEBVIEW_WEBENGINE_BACKEND
QQmlEngine engine;
QQmlContext * rootContext = engine.rootContext();
@@ -276,6 +273,9 @@ void tst_QWebView::setAndDeleteCookie()
QTRY_COMPARE(cookieRemovedSpy.count(), 1);
view.deleteAllCookies();
+#ifdef Q_OS_ANDROID
+ QEXPECT_FAIL("", "Notification for deleteAllCookies() is not implemented on Android, yet!", Continue);
+#endif
QTRY_COMPARE(cookieRemovedSpy.count(), 3);
}