Search code examples
javajavascriptsocketsfirefoxfirefox-addon-sdk

Bridge JavaScript/Java in FF plugin


I'm trying to implement a connection between a FF plugin (using jetpack) and a java server which will handle all requests from the plugin. It seems I can stablish the connection but messages don't flow. I don't get anything coming from the plugin.

Here I post the codes:

JavaScript (client)

const {Cc,Ci} = require("chrome");

exports.main = function() {
try  {
    // At first, we need a nsISocketTransportService
    var transportService =  
        Cc["@mozilla.org/network/socket-transport-service;1"]
        .getService(Ci.nsISocketTransportService);  
       
    // Try to connect to localhost:2222
    var transport = transportService.createTransport(null, 0, "localhost", 2222, null);  

    var stream = transport.openInputStream(Ci.nsITransport.OPEN_UNBUFFERED,null,null); 
    var instream = Cc["@mozilla.org/scriptableinputstream;1"]
        .createInstance(Ci.nsIScriptableInputStream); 
        
    // Initialize
    instream.init(stream);
    var outstream = transport.openOutputStream(0, 0, 0);
     
    // Write data
    var outputData = "bye";
    outstream.write(outputData, outputData.length);

    var dataListener = { 
        data : "", onStartRequest: function(request, context){},
         
        onStopRequest: function(request, context, status){
            instream.close();
            outstream.close();
            listener.finished(this.data); 
        }, 
        
        onDataAvailable: function(request, context, inputStream, offset, count) { 
            this.data += instream.read(count); 
            console.log(this.data);             
        }, 
    };

    var pump = Cc["@mozilla.org/network/input-stream-pump;1"].createInstance(Ci.nsIInputStreamPump); 
    pump.init(stream, -1, -1, 0, 0, false); 
    pump.asyncRead(dataListener, null); 
    
} catch (e){ 
    console.log("Error" + e.result + ": " + e.message); 
    return e; 
} return null;
};

Java (Server)

ServerSocket providerSocket;
Socket connection = null;
ObjectOutputStream out;
ObjectInputStream in;
String message;
GoopirServer(){}
void run() {
    try{
        // Creating a server socket
        providerSocket = new ServerSocket(2222, 10);
        
        // Wait for connection
        System.out.println("Waiting for connection");
        connection = providerSocket.accept();
        System.out.println("Connection received from " + connection.getInetAddress().getHostName());
        
        // Get Input and Output streams
        out = new ObjectOutputStream(connection.getOutputStream());
        out.flush();
        in = new ObjectInputStream(connection.getInputStream());
        sendMessage("Connection successful");
        
        // The two parts communicate via the input and output streams
        do{
            try{
                message = (String)in.readObject();
                System.out.println("client>" + message);
                if (message.equals("bye"))
                    sendMessage("bye");
            }
            catch(ClassNotFoundException classnot){
                System.err.println("Data received in unknown format");
            }
        }while(!message.equals("bye"));
    }
    catch(IOException ioException){
        ioException.printStackTrace();
    }
    finally{
        // Closing connection
        try{
            in.close();
            out.close();
            providerSocket.close();
        }
        catch(IOException ioException){
            ioException.printStackTrace();
        }
    }
}

/*
 * Sends a message to the plugin
 */
void sendMessage(String msg)
{
    try{
        out.writeObject(msg);
        out.flush();
        System.out.println("server>" + msg);
    }
    catch(IOException ioException){
        ioException.printStackTrace();
    }
}

Solution

  • Your Firefox side seems to be correct (other than using a blocking call to write data), the issue is on the Java side. ObjectInputStream and ObjectOutputStream are meant for exchanging serialized objects (in an undocumented format), not strings. And I think that ObjectInputStream expects to receive the magic number immediately, no wonder that it locks up without input. What you probably want to use are BufferedReader and PrintWriter. Also, you should use some separators for your messages, e.g. newlines (this would allow using BufferedReader.readLine()).