Skip to content

Instantly share code, notes, and snippets.

@radut
Forked from thomasdarimont/ProxyProblemExample.java
Created August 28, 2019 09:36
Show Gist options
  • Save radut/9a2b0804b60fe123722e182fd829e99d to your computer and use it in GitHub Desktop.
Save radut/9a2b0804b60fe123722e182fd829e99d 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