Native Messaging stops working after receiving chunked response

0

I made two extensions, one for firefox and one for chrome(will post only firefox code here, if it is necessary to post Chrome code, let me know, but it is extremely similar) that has some actions, calls to native host app. One of this calls returns a message with > 1 mb. According to https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Native_messaging, "The maximum size of a single message from the application is 1 MB". According to chrome native messaging: how to receive > 1MB, data > 1mb must be chunked into less than 1 mb data and sent as many chunks. I Made a Java host app, and made a solution to chunk data. The data is chunked and many responses are sent, each with a chunk in a json string. The sending and responses worked ok, the messages are joined in an input of the web page, and the action works. However, after making this action, any other call fail. If I go to windows task manager, and kill the native host process, everything works again. If I do the action that gets chunked response, it works again, but next calls fail silently, firefox browser console gives me nothing. I guess there is something wrong with my solution. The actions work. When I do the action that receives more than 1 mb, the action works, but after that no other action work again. Any help is appreciated. Tell me if the question is not clear, or is a big mess, I will improve it. I did everythink I could to make it work, and it works, but oddly only one time, then it fails and do nothing. Sorry, but I can't say what the actions are, i mean, what im tryng to do, if it is realy necessary to know, I will ask my manager to explain it here.

Background.js

function sendNativeMessage(message) {
  port.postMessage(message);
}

function onDisconnected() {
  msg = '{"message": "Failed to connect: '+browser.runtime.lastError+'"}';
  browser.tabs.query({active: true, currentWindow: true}, function(tabs){
    browser.tabs.sendMessage(tabs[0].id, msg, function(response) {});  
});
  port = null;
}

function connect() {
  var hostName = "com.companyname.hostname";
  port = browser.runtime.connectNative(hostName);

  port.onMessage.addListener(function(msg) {
    browser.tabs.query({active: true, currentWindow: true}, function(tabs){
        browser.tabs.sendMessage(tabs[0].id, JSON.stringify(msg), function(response) {});  
    });
    
    });
  port.onDisconnect.addListener(onDisconnected);
}

browser.runtime.onMessageExternal.addListener(
  function(request, sender, sendResponse) {
    if (port == null) {
        connect();
    }
    sendNativeMessage(request);
  });

Inject.js

//Prevent code being injected twice(probably because of click listeners on web page)
if (document.readyState !== "complete") {

browser.runtime.onMessage.addListener(function(msg, sender, sendResponse) {
        
        var obj = JSON.parse(msg);
        if (!obj.success) {
            (...)
        }

        if (obj.action == "doSomething") {
           if (obj.last == "true") {
               do something
            }else {
                var value = $("#input").val().trim() + obj.value.trim();
                $("#input").val(value.trim());
            }
        }

        var s = document.createElement('script');
        // TODO: add "script.js" to web_accessible_resources in manifest.json
        s.src = browser.runtime.getURL('script.js');
        s.onload = function() {
            this.remove();
        };
        (document.head || document.documentElement).appendChild(s);

}

script.js

class extensionName{
    getValues() {
        window.postMessage({ type: "FROM_PAGE", text: {action: "getValues"} }, "*");
    }
//This is the function that returns more than 1 mb.
    dosomething(parameter1,parameter2,parameter3,parameter4) {
        window.postMessage({ type: "FROM_PAGE", text: {action: "dosomething",parameter1Key:parameter1,parameter2Key:parameter2,parameter3Key:parameter3,parameter4Key:parameter4} }, "*");
    }
}

Native app in Java (aux is an instance of an auxiliary class that has a sendMessage function that sends messages according to the native messaging protocol)

switch (parameter1) {
                    case "getValues":
                        json = functions.getValues();
                        aux.sendMessage(json);
                        break;
                   
                   case "doSomething":
funcoes.doSomething(...);
                        break;

(...)

public String doSomething(...) {
(...)
     Matcher m = Pattern.compile(".{1,565048}").matcher(valueMoreThan1Mb);

            String chunk = "";
            
            while(m.find()) {
                System.setOut(originalStream);//let stream output values
                chunk = newSignatureBase64.substring(m.start(), m.end());
                
                //a json is done here, with needed parameters, action, chunked value.
json = "{\"success\":\"true\",\"action\":\"sign\",\"last\":\"false\",\"value\":\""+chunk+"\"}";/Sorry for this. This code will be improved when everything is working.

                aux.sendMessage(json);//auxiliar class sends message according to native messaging protocol.
                System.setOut(dummyStream);//avoid 3rd party library output contents and mess native messaging port.
            }
            
            System.setOut(originalStream);//let stream output values

            json = "{\"success\":\"true\",\"action\":\"sign\",\"last\":\"true\"}";//Sorry for this. This code will be improved when everything is working.
            aux.sendMessage(json);
            System.setOut(dummyStream);
         
            return "";
}

Auxiliar.java

public class Auxiliar {
    public int getInt(byte[] bytes) {
        return (bytes[3] << 24) & 0xff000000 | (bytes[2] << 16) & 0x00ff0000
            | (bytes[1] << 8) & 0x0000ff00 | (bytes[0] << 0) & 0x000000ff;
    }
    
    public String readMessage(InputStream in) throws IOException {
        byte[] b = new byte[4];
        in.read(b);

        int size = getInt(b);
        //log(String.format("The size is %d", size));

        if (size == 0) {
          throw new InterruptedIOException("Blocked communication");
        }

        b = new byte[size];
        in.read(b);

        return new String(b, "UTF-8");
    }
    
    public boolean sendMessage(String message) {
        try {
            System.out.write(getBytes(message.length()));
            System.out.write(message.getBytes("UTF-8"));
            System.out.flush();
            return true;
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return false;
        }
    }
    
    
    //Use this in case the other method get deprecated
    public byte[] getBytes(int length) {
        byte[] bytes = new byte[4];
        bytes[0] = (byte) (length & 0xFF);
        bytes[1] = (byte) ((length >> 8) & 0xFF);
        bytes[2] = (byte) ((length >> 16) & 0xFF);
        bytes[3] = (byte) ((length >> 24) & 0xFF);
        return bytes;
    }
}
google-chrome-extension
firefox-addon
chrome-native-messaging
asked on Stack Overflow Sep 3, 2020 by giancarloap • edited Sep 4, 2020 by giancarloap

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0