Catching errors in native-messaging API when receiving bad JSON

When using the native-messaging API, if there is an error in receiving a message from the native application, is there a way to catch and handle it?

It appears that, if the native application posts an incorrectly formed JSON string (which I guess isn’t really JSON then), the extension closes the native application and throws a JSON.parse subprocess_common.jsm:493 error.

Is there a way to catch the error before the native application is closed and attempt to handle it in some manner?

I’m fairly certain that it is the extension that is closing the native application and not an error in the application itself. I write the same message to a local file as to stdin and the purposely bad JSON attempt is written to the local file without error.

I have control of both sides of the communication and build the JSON in the application; so, there should never be an error. However, if there is one, I don’t want the application to close.

If an error cannot be captured, is there a way to have the JSON string treated as a plain text string and parse it in a try-catch after it has been received?

Thank you.

1 Like

Does the “onDisconnect” event fire in the extension?
https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/Port

Yes, the onDisconnect event fires in the extension and logs the error to the console. Thanks.

I read that documentation before and again after your response and still cannot tell for sure if it means that onDisconnect in the extension will fire only if the native application initiated it.

It seems to state that but I’m not certain. In addition, I have no code in the C application that explicitly disconnects or sends an exit failure. It has been commented out.

First, all the code works, that is, the extension sends a message to the C app., which processes the request and sends back a JSON response, which is also written to a local file during testing. The message is received by the extension and written to the console, and, at that point, the C app. remains open and awaiting another message. I know this because, while the browser tab is still open, I cannot delete the .exe file because it is in use, nor can I delete the SQLite database because the extension has an open connection through the C app.

If a character is added to the JSON string such that it is no longer correctly formed, the C app writes the string to the local file without error, but the extension throws the JSON.parse error directly from the onMessage handler, or, I think, before the code of the handler is executed. There is not a JSON.parse in the extension code at this time to generate that error. The order the events appear in the console is, first, the JSON.parse error and then a Disconnected due to an error: An unexpected error occurred message logged by the onDisconnect handler.

I think the extension is closing the C application simply because the JSON.parse in the subprocess_common.jsm code receiving the message throws the error before the onMessage handler is invoked.

I think this is the part of the view-source:resource://gre/modules/subprocess/subprocess_common.jsm code that throws the error, but I cannot see where the last throw e is caught to see if the connection is closed there.

 /**
   * Reads exactly `length` bytes from the input stream, and parses them as
   * UTF-8 JSON data.
   *
   * @param {integer} length
   *        The number of bytes to read.
   * @returns {Promise<object>}
   *
   * @rejects {object}
   *          May be rejected with an Error object, or an object with similar
   *          properties. The object will include an `errorCode` property with
   *          one of the following values if it was rejected for the
   *          corresponding reason:
   *
   *            - Subprocess.ERROR_END_OF_FILE: The pipe was closed before
   *              enough input could be read to satisfy the request.
   *            - Subprocess.ERROR_INVALID_JSON: The data read from the pipe
   *              could not be parsed as a valid JSON string.
   */
  readJSON(length) {
    if (!Number.isInteger(length) || length <= 0) {
      throw new RangeError("Length must be a positive integer");
    }

    return this.readString(length).then(string => {
      try {
        return JSON.parse(string);
      } catch (e) {
        e.errorCode = SubprocessConstants.ERROR_INVALID_JSON;
        throw e;
      }
    });
  }

It may be this code that catches the throw e; but I don’t know where the Cu.reportError(e) is.

 onmessage(event) {
    let { msg } = event.data;
    let listeners = this.listeners.get(msg) || new Set();

    for (let listener of listeners) {
      try {
        listener(event.data);
      } catch (e) {
        Cu.reportError(e);
      }
    }
  }
1 Like