[jcef] setCookie is working, improved by adding some checks before call native method

also JBCefCookie wrapper is introduced

GitOrigin-RevId: 6ebcb5dca911480303bb84b3ee6a8d457219f6af
This commit is contained in:
Aleksey Rostovskiy
2020-05-12 22:13:41 +00:00
committed by intellij-monorepo-bot
parent bb5c14ab84
commit a117e82db3
4 changed files with 172 additions and 73 deletions
@@ -0,0 +1,114 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.ui.jcef;
import org.cef.network.CefCookie;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Date;
import java.util.Objects;
/**
* A wrapper over {@link CefCookie}.
*
* @author Aleksey.Rostovskiy
*/
public class JBCefCookie {
private final CefCookie myCefCookie;
public JBCefCookie(CefCookie cefCookie) {
myCefCookie = cefCookie;
}
public JBCefCookie(@NotNull String name,
@NotNull String value,
@NotNull String domain,
@NotNull String path,
boolean secure,
boolean httponly,
@Nullable Date creation,
@Nullable Date lastAccess,
boolean hasExpires,
@Nullable Date expires) {
this(new CefCookie(name, value, domain, path, secure, httponly, creation, lastAccess, hasExpires, expires));
}
public JBCefCookie(@NotNull String name,
@NotNull String value,
@NotNull String domain,
@NotNull String path,
boolean secure,
boolean httponly) {
this(name, value, domain, path, secure, httponly, null, null, false, null);
}
@NotNull
public CefCookie getCefCookie() {
return myCefCookie;
}
@NotNull
public String getName() {
return myCefCookie.name;
}
@NotNull
public String getValue() {
return myCefCookie.value;
}
@NotNull
public String getDomain() {
return myCefCookie.domain;
}
@NotNull
public String getPath() {
return myCefCookie.path;
}
public boolean isSecure() {
return myCefCookie.secure;
}
public boolean isHttpOnly() {
return myCefCookie.httponly;
}
@Nullable
public Date getCreation() {
return myCefCookie.creation;
}
@Nullable
public Date getLastAccess() {
return myCefCookie.lastAccess;
}
public boolean hasExpires() {
return myCefCookie.hasExpires;
}
@Nullable
public Date getExpires() {
return myCefCookie.expires;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
JBCefCookie cookie = (JBCefCookie)o;
return getName().equals(cookie.getName()) &&
getValue().equals(cookie.getValue()) &&
getDomain().equals(cookie.getDomain()) &&
getPath().equals(cookie.getPath()) &&
isSecure() == cookie.isSecure() &&
isHttpOnly() == cookie.isHttpOnly();
}
@Override
public int hashCode() {
return Objects.hash(getName(), getValue(), getDomain(), getPath(), isSecure(), isHttpOnly());
}
}
@@ -11,6 +11,8 @@ import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
@@ -24,7 +26,7 @@ import static com.intellij.openapi.util.Clock.getTime;
* <p>
* Use {@link #getCookies()} and others for retrieving cookies synchronously.
* <p>
* Use {@link #setCookie(String, CefCookie, boolean)} and others for setting cookie. Can be used both with synchronization or without one.
* Use {@link #setCookie(String, JBCefCookie, boolean)} and others for setting cookie. Can be used both with synchronization or without one.
* <p>
* Use {@link #deleteCookies(boolean)} and others for deleting cookies. Can be used both with synchronization or without one.
*
@@ -57,16 +59,14 @@ public class JBCefCookieManager {
/**
* @see JBCefCookieManager#getCookies(String, Boolean, Integer)
*/
public @Nullable List<CefCookie> getCookies() {
public @Nullable List<JBCefCookie> getCookies() {
return getCookies(null, false, null);
}
/**
* TODO[hatari] Doesn't work now, waiting for JCEF library update <p/>
*
* @see JBCefCookieManager#getCookies(String, Boolean, Integer)
*/
public @Nullable List<CefCookie> getCookies(@NotNull String url) {
public @Nullable List<JBCefCookie> getCookies(@NotNull String url) {
return getCookies(url, false, null);
}
@@ -78,9 +78,9 @@ public class JBCefCookieManager {
* @param includeHttpOnly include only true HTTP-only cookies.
* @param maxTimeToWait time to wait getting cookies in ms, default value is
* {@link JBCefCookieManager#DEFAULT_TIMEOUT_FOR_SYNCHRONOUS_FUNCTION}.
* @return list of {@link CefCookie} or null if cookies cannot be accessed
* @return list of {@link JBCefCookie} or null if cookies cannot be accessed
*/
public @Nullable List<CefCookie> getCookies(@Nullable String url, @Nullable Boolean includeHttpOnly, @Nullable Integer maxTimeToWait) {
public @Nullable List<JBCefCookie> getCookies(@Nullable String url, @Nullable Boolean includeHttpOnly, @Nullable Integer maxTimeToWait) {
long startTime = getTime();
boolean httpOnly = includeHttpOnly != null ? includeHttpOnly : false;
@@ -91,7 +91,6 @@ public class JBCefCookieManager {
boolean result;
if (url != null) {
// TODO[hatari] Doesn't work now, waiting for JCEF library update <p/>
result = myCefCookieManager.visitUrlCookies(url, httpOnly, cookieVisitor);
}
else {
@@ -123,20 +122,18 @@ public class JBCefCookieManager {
}
/**
* @see JBCefCookieManager#setCookie(String, CefCookie, Integer)
* @see JBCefCookieManager#setCookie(String, JBCefCookie, Integer)
*/
public boolean setCookie(@NotNull String url, @NotNull CefCookie cefCookie, boolean doSync) {
public boolean setCookie(@NotNull String url, @NotNull JBCefCookie jbCefCookie, boolean doSync) {
if (doSync) {
return setCookie(url, cefCookie, null);
return setCookie(url, jbCefCookie, null);
}
else {
return myCefCookieManager.setCookie(url, cefCookie);
return myCefCookieManager.setCookie(url, jbCefCookie.getCefCookie());
}
}
/**
* TODO[hatari] Doesn't work now, waiting for JCEF library update <p/>
* <p>
* Sets a cookie given a valid URL and explicit user-provided cookie attributes.
* Underlying native method {@link CefCookieManager#setCookie(String, CefCookie)} is asynchronous.
* This method is synchronous and will wait up to `maxTimeToWait` ms.
@@ -145,15 +142,35 @@ public class JBCefCookieManager {
* {@link JBCefCookieManager#DEFAULT_TIMEOUT_FOR_SYNCHRONOUS_FUNCTION} ms.
* @return true if setting the cookie was successful.
*/
public boolean setCookie(@NotNull String url, @NotNull CefCookie cefCookie, @Nullable Integer maxTimeToWait) {
public boolean setCookie(@NotNull String url, @NotNull JBCefCookie jbCefCookie, @Nullable Integer maxTimeToWait) {
try {
URI uri = new URI(url);
String scheme = uri.getScheme();
String domain = uri.getHost();
domain = domain.startsWith("www") ? domain : "." + domain;
if (scheme.equals("http") && jbCefCookie.isSecure()) {
LOG.warn("Cannot set cookie without secure flag for HTTPS web-site");
return false;
}
if (!domain.contains(jbCefCookie.getDomain())) {
LOG.warn("Cookie domain `" + jbCefCookie.getDomain() + "` doesn't match URL host `" + domain + "`");
return false;
}
}
catch (URISyntaxException e) {
LOG.error(e);
return false;
}
int timeout = maxTimeToWait != null ? maxTimeToWait : DEFAULT_TIMEOUT_FOR_SYNCHRONOUS_FUNCTION;
IntFunction<Boolean> checkFunction = (timeoutForCheck) -> {
List<CefCookie> cookies = getCookies(url, null, timeoutForCheck);
List<JBCefCookie> cookies = getCookies(url, null, timeoutForCheck);
if (cookies == null) {
return false;
}
return cookies.contains(cefCookie);
return cookies.contains(jbCefCookie);
};
myLock.lock();
@@ -163,7 +180,7 @@ public class JBCefCookieManager {
LOG.debug("Cookie is already set");
return true;
}
if (!myCefCookieManager.setCookie(url, cefCookie)) {
if (!myCefCookieManager.setCookie(url, jbCefCookie.getCefCookie())) {
LOG.error("Posting task to set cookie is failed");
return false;
}
@@ -204,7 +221,7 @@ public class JBCefCookieManager {
public boolean deleteCookies(boolean doSync) {
if (doSync) {
return deleteCookies("", "", (timeout) -> {
List<CefCookie> cookies = getCookies(null, false, timeout);
List<JBCefCookie> cookies = getCookies(null, false, timeout);
if (cookies == null) {
return false;
}
@@ -225,7 +242,7 @@ public class JBCefCookieManager {
public boolean deleteCookies(@NotNull String url, boolean doSync) {
if (doSync) {
return deleteCookies(url, "", (timeout) -> {
List<CefCookie> cookies = getCookies(url, false, timeout);
List<JBCefCookie> cookies = getCookies(url, false, timeout);
if (cookies == null) {
return false;
}
@@ -259,11 +276,11 @@ public class JBCefCookieManager {
*/
public boolean deleteCookies(@NotNull String url, @NotNull String cookieName, @Nullable Integer maxTimeToWait) {
IntFunction<Boolean> checkFunction = (timeout) -> {
List<CefCookie> cookies = getCookies(url, false, timeout);
List<JBCefCookie> cookies = getCookies(url, false, timeout);
if (cookies == null) {
return false;
}
return cookies.stream().allMatch(cefCookie -> cefCookie.name != cookieName);
return cookies.stream().noneMatch(cefCookie -> cefCookie.getName().equals(cookieName));
};
return deleteCookies(url, cookieName, checkFunction, maxTimeToWait);
@@ -327,7 +344,7 @@ public class JBCefCookieManager {
}
private static class JBCookieVisitor implements CefCookieVisitor {
final List<CefCookie> myCefCookies = new ArrayList<>();
final List<JBCefCookie> myCefCookies = new ArrayList<>();
final CountDownLatch myCountDownLatch;
JBCookieVisitor(CountDownLatch countDownLatch) {
@@ -338,7 +355,7 @@ public class JBCefCookieManager {
// TODO[hatari]: This method may never be called if no cookies are found.
// So CountDownLatch can't countDown() well except timeout.
public boolean visit(CefCookie cookie, int count, int total, BoolRef delete) {
myCefCookies.add(cookie);
myCefCookies.add(new JBCefCookie(cookie));
if (count >= total - 1) {
// last element
myCountDownLatch.countDown();
@@ -346,7 +363,7 @@ public class JBCefCookieManager {
return true;
}
public List<CefCookie> getCookies() {
public List<JBCefCookie> getCookies() {
return myCefCookies;
}
}
@@ -4,10 +4,10 @@
package com.intellij.internal.jcef;
import com.intellij.ui.jcef.JBCefBrowser;
import com.intellij.ui.jcef.JBCefCookie;
import com.intellij.ui.jcef.JBCefCookieManager;
import com.intellij.ui.table.JBTable;
import com.intellij.util.ui.JBUI;
import org.cef.network.CefCookie;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
@@ -22,7 +22,6 @@ import java.util.List;
class CookieManagerDialog extends JDialog {
private static final String myTitle = "Cookie Manager";
private static final String myDeleteCookiesButtonText = "Delete All Cookies";
private static final String myAdditionalButtonText = "Test SetCookie";
@SuppressWarnings("unused") private final JBCefBrowser myJBCefBrowser;
private final JBCefCookieManager myJBCefCookieManager;
private final CookieTableModel myTableModel = new CookieTableModel();
@@ -46,7 +45,7 @@ class CookieManagerDialog extends JDialog {
@Override
public void actionPerformed(ActionEvent e) {
if (myJBCefCookieManager.deleteCookies(true)) {
List<CefCookie> cookies = myJBCefCookieManager.getCookies();
List<JBCefCookie> cookies = myJBCefCookieManager.getCookies();
if (cookies != null) {
update(cookies);
}
@@ -55,41 +54,10 @@ class CookieManagerDialog extends JDialog {
});
controlPanel.add(myDeleteCookiesButton);
final JButton myAdditionalButton = new JButton(myAdditionalButtonText);
myAdditionalButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
List<CefCookie> cookies = myJBCefCookieManager.getCookies();
if (cookies == null || cookies.isEmpty()) return;
CefCookie firstCookie = cookies.get(0);
CefCookie newCookie = new CefCookie(
"Cookie",
"Value",
firstCookie.domain,
firstCookie.path,
firstCookie.secure,
firstCookie.secure,
firstCookie.creation,
firstCookie.lastAccess,
firstCookie.hasExpires,
firstCookie.expires
);
if (myJBCefCookieManager.setCookie("http://maps.google.com", newCookie, true)) {
cookies = myJBCefCookieManager.getCookies();
if (cookies != null) {
update(cookies);
}
}
}
});
controlPanel.add(myAdditionalButton);
add(controlPanel, BorderLayout.SOUTH);
}
public void update(List<CefCookie> cefCookies) {
public void update(List<JBCefCookie> cefCookies) {
myTableModel.clear();
myTableModel.show(cefCookies);
}
@@ -99,18 +67,18 @@ class CookieManagerDialog extends JDialog {
new String[]{"Name", "Value", "Domain", "Path", "Secure", "HTTP only", "Created", "Last Access", "Expires"};
private final ArrayList<Object[]> rowData = new ArrayList<>();
private void show(@NotNull List<CefCookie> cefCookies) {
for (CefCookie cookie : cefCookies) {
private void show(@NotNull List<JBCefCookie> cefCookies) {
for (JBCefCookie cookie : cefCookies) {
Object[] entry = {
cookie.name,
cookie.value,
cookie.domain,
cookie.path,
Boolean.valueOf(cookie.secure),
Boolean.valueOf(cookie.httponly),
cookie.creation,
cookie.lastAccess,
cookie.expires
cookie.getName(),
cookie.getValue(),
cookie.getDomain(),
cookie.getPath(),
cookie.isSecure(),
cookie.isHttpOnly(),
cookie.getCreation(),
cookie.getLastAccess(),
cookie.getExpires()
};
int row = rowData.size();
rowData.add(entry);
@@ -9,10 +9,10 @@ import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.wm.impl.IdeFrameImpl;
import com.intellij.ui.jcef.JBCefApp;
import com.intellij.ui.jcef.JBCefBrowser;
import com.intellij.ui.jcef.JBCefCookie;
import org.cef.browser.CefBrowser;
import org.cef.browser.CefFrame;
import org.cef.handler.CefLoadHandlerAdapter;
import org.cef.network.CefCookie;
import org.cef.network.CefRequest;
import org.jetbrains.annotations.NotNull;
@@ -84,7 +84,7 @@ public class WebBrowser extends AnAction implements DumbAware {
@Override
public void actionPerformed(ActionEvent e) {
myCookieManagerDialog.setVisible(true);
List<CefCookie> cookies = myJBCefBrowser.getJBCefCookieManager().getCookies();
List<JBCefCookie> cookies = myJBCefBrowser.getJBCefCookieManager().getCookies();
if (cookies != null) {
myCookieManagerDialog.update(cookies);
}