Custom JavaFX WebView Protocol Handler

人走茶凉 提交于 2019-11-29 07:47:44

It might be that all you are missing is a setDoInput(true) or override getDoInput() and return true (that's what i did).

If that does not help check out my working solution:

MyURLStreamHandlerFactory:

import java.net.URLStreamHandler;
import java.net.URLStreamHandlerFactory;

public class MyURLStreamHandlerFactory implements URLStreamHandlerFactory
{

    public URLStreamHandler createURLStreamHandler(String protocol)
    {
        if (protocol.equals("myapp"))
        {
            return new MyURLHandler();
        }
        return null;
    }

}

Register Factory:

URL.setURLStreamHandlerFactory(new MyURLStreamHandlerFactory());

MyURLHandler :

import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;

public class MyURLHandler extends URLStreamHandler
{

    @Override
    protected URLConnection openConnection(URL url) throws IOException
    {
        return new MyURLConnection(url);
    }

}

MyURLConnection:

import java.io.*;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.URLConnection;

/**
 * Register a protocol handler for URLs like this: <code>myapp:///pics/sland.gif</code><br>
 */
public class MyURLConnection extends URLConnection
{

    private byte[] data;

    @Override
    public void connect() throws IOException
    {
        if (connected)
        {
            return;
        }
        loadImage();
        connected = true;
    }

    public String getHeaderField(String name)
    {
        if ("Content-Type".equalsIgnoreCase(name))
        {
            return getContentType();
        }
        else if ("Content-Length".equalsIgnoreCase(name))
        {
            return "" + getContentLength();
        }
        return null;
    }

    public String getContentType()
    {
        String fileName = getURL().getFile();
        String ext = fileName.substring(fileName.lastIndexOf('.'));
        return "image/" + ext; // TODO: switch based on file-type
    }

    public int getContentLength()
    {
        return data.length;
    }

    public long getContentLengthLong()
    {
        return data.length;
    }

    public boolean getDoInput()
    {
        return true;
    }

    public InputStream getInputStream() throws IOException
    {
        connect();
        return new ByteArrayInputStream(data);
    }

    private void loadImage() throws IOException
    {
        if (data != null)
        {
            return;
        }
        try
        {
            int timeout = this.getConnectTimeout();
            long start = System.currentTimeMillis();
            URL url = getURL();

            String imgPath = url.toExternalForm();
            imgPath = imgPath.startsWith("myapp://") ? imgPath.substring("myapp://".length()) : imgPath.substring("myapp:".length()); // attention: triple '/' is reduced to a single '/'

            // this is my own asynchronous image implementation
            // instead of this part (including the following loop) you could do your own (synchronous) loading logic
            MyImage img = MyApp.getImage(imgPath);
            do
            {
                if (img.isFailed())
                {
                    throw new IOException("Could not load image: " + getURL());
                }
                else if (!img.hasData())
                {
                    long now = System.currentTimeMillis();
                    if (now - start > timeout)
                    {
                        throw new SocketTimeoutException();
                    }
                    Thread.sleep(100);
                }
            } while (!img.hasData());
            data = img.getData();
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }
    }

    public OutputStream getOutputStream() throws IOException
    {
        // this might be unnecessary - the whole method can probably be omitted for our purposes
        return new ByteArrayOutputStream();
    }

    public java.security.Permission getPermission() throws IOException
    {
        return null; // we need no permissions to access this URL
    }

}

Some parts of MyURLConnection might not be necessary for it to work, but like this it works for me.

Usage in JavaFX WebView:

<img src="myapp:///pics/image.png"/>

Note about permissions:

I used an applet with AllPermissions for my test with the above code.

In a Sandbox-Applet this won't work, as the setFactory permission is missing.

This is not directly related to the question asked, but might make the question itself obsolete.

With Java SE 6 Update 10 Java Applets support to access resources on any domain and port which is correctly set up with a crossdomain.xml.

With this the reason to register your own protocol might become obsolete, as you can access all resources that you need.

Another idea is: If you are trying to create a kind of network sniffer, why not directly use a network sniffer/analyzer program designed for such a task?

By activating Logging and Tracing in the Java Control-Panel your Java-Console will print all attempts and executed network calls including those from the WebView.

You can see all HTTP & HTTPS calls and their return-code + cookie data. You might also see other protocol connections, but probably not any data sent over them.

This applies to Applets in a Browser. If you need this in a different context maybe there is a way to activate the same options by passing command line parameters.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!