Custom JavaFX WebView Protocol Handler

后端 未结 3 604
孤街浪徒
孤街浪徒 2020-12-18 10:43

I am trying to write my own protocol handler for a JavaFX application that uses webview to access a single website. What I have done so far

My custom URLStreamHandle

相关标签:
3条回答
  • 2020-12-18 10:49

    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.

    0 讨论(0)
  • 2020-12-18 11:10

    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?

    0 讨论(0)
  • 2020-12-18 11:11

    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.

    0 讨论(0)
提交回复
热议问题