Skip to content

Instantly share code, notes, and snippets.

@thomasdarimont
Last active May 28, 2023 20:43
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save thomasdarimont/310c3839bc63501680e6 to your computer and use it in GitHub Desktop.
Save thomasdarimont/310c3839bc63501680e6 to your computer and use it in GitHub Desktop.
Hack for allowing dedicated proxy settings to be used for URL with http and https protocol handling in JavaFXs Webkit based WebView. Tested with JDK8

Run with:

-Dhttp.proxy=none.local
-Dhttp.proxyPort=1234
-Dhack.webkit.http.proxy=localhost
-Dhack.webkit.http.proxyPort=8080

I used -Dhttp.proxy=none.local and -Dhttp.proxyPort=1234 to "simulate" a non working default proxy configuration for all "other" URL load requests.

package de.tutorials.training.fx.proxy;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import java.net.InetSocketAddress;
import java.net.Proxy;
/**
* @author Thomas Darimont
*/
public class ProxyProblemExample extends Application {
@Override
public void start(Stage stage) throws Exception {
StackPane root = new StackPane();
WebView view = new WebView();
WebEngine engine = view.getEngine();
engine.load("https://www.google.com");
root.getChildren().add(view);
Scene scene = new Scene(root, 960, 640);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) throws Exception {
Proxy proxy = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress(System.getProperty("hack.webkit.http.proxy"), Integer.getInteger("hack.webkit.http.proxyPort")));
URLStreamFactoryCustomizer.useDedicatedProxyForWebkit(proxy, "http, https");
Application.launch(ProxyProblemExample.class);
}
}
package de.tutorials.training.fx.proxy;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.*;
import java.util.Hashtable;
import java.util.function.Consumer;
import static java.util.Arrays.asList;
/**
* @author Thomas Darimont
*/
public class URLStreamFactoryCustomizer {
public static void useDedicatedProxyForWebkit(Proxy proxy, String protocols) {
forceInitializationOfOriginalUrlStreamHandlers();
tryReplaceOriginalUrlStreamHandlersWithScopeProxyAwareVariants(proxy, protocols);
}
private static void tryReplaceOriginalUrlStreamHandlersWithScopeProxyAwareVariants(Proxy proxy, String protocols) {
try {
Hashtable handlers = tryExtractInternalHandlerTableFromUrl();
//System.out.println(handlers);
Consumer<String> wrapStreamHandlerWithScopedProxyHandler = protocol ->
{
URLStreamHandler originalHandler = (URLStreamHandler) handlers.get(protocol);
handlers.put(protocol, new DelegatingScopedProxyAwareUrlStreamHandler(originalHandler, proxy));
};
asList(protocols.split(",")).stream().map(String::trim).filter(s -> !s.isEmpty()).forEach(wrapStreamHandlerWithScopedProxyHandler);
//System.out.println(handlers);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
private static Hashtable tryExtractInternalHandlerTableFromUrl() {
try {
Field handlersField = URL.class.getDeclaredField("handlers");
handlersField.setAccessible(true);
return (Hashtable) handlersField.get(null);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static void forceInitializationOfOriginalUrlStreamHandlers() {
try {
new URL("http://.");
new URL("https://.");
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
}
static class DelegatingScopedProxyAwareUrlStreamHandler extends URLStreamHandler {
private static final Method openConnectionMethod;
private static final Method openConnectionWithProxyMethod;
static {
try {
openConnectionMethod = URLStreamHandler.class.getDeclaredMethod("openConnection", URL.class);
openConnectionWithProxyMethod = URLStreamHandler.class.getDeclaredMethod("openConnection", URL.class, Proxy.class);
openConnectionMethod.setAccessible(true);
openConnectionWithProxyMethod.setAccessible(true);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private final URLStreamHandler delegatee;
private final Proxy proxy;
public DelegatingScopedProxyAwareUrlStreamHandler(URLStreamHandler delegatee, Proxy proxy) {
this.delegatee = delegatee;
this.proxy = proxy;
}
@Override
protected URLConnection openConnection(URL url) throws IOException {
try {
if (isWebKitURLLoaderThread(Thread.currentThread())) {
//WebKit requested loading the given url, use provided proxy.
return (URLConnection) openConnectionWithProxyMethod.invoke(delegatee, url, proxy);
}
//Invoke the standard url handler.
return (URLConnection) openConnectionMethod.invoke(delegatee, url);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
}
private boolean isWebKitURLLoaderThread(Thread thread) {
StackTraceElement[] st = thread.getStackTrace();
//TODO Add more robust stack-trace inspection.
return st.length > 4 && st[4].getClassName().startsWith("com.sun.webkit.network");
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment