cujojs/curl

Unhandled error is eaten by curl when bootstrap code has a json plugin dependency

Closed this issue · 5 comments

I've and app where the bootstrap code depends on a file loaded by json plugin and it appears that when an error is thrown and is not handled, it is eaten by some curl code related to the json plugin. Here is a test that exposes this error:

https://github.com/azazel75/curl_json_eat_error

Hey @azazel75,

There's definitely some anomalies in the logic in this plugin. For instance, I noticed that the success path is different if the strictJSONParse config property is truthy. (e.g. strictJSONParse: true). If you have a minutes and can try setting that in a curl() or curl.config() call, that would be helpful.

I will continue to research and add tests...

-- J

Nm. I cloned your example repo and tried it. This looks like a problem with all plugins specified in a call to curl([]).

Actually, it seems like it's just a problem with json!, style!, and locale! plugins. Each of these plugins catches errors that are thrown from the success callbacks (which ultimately call the bootstrap success callback). The plugins send the error back into curl's loading mechanics which detects and suppresses multiple callbacks/errbacks. In short, the error is suppressed on purpose. The fix is to stop catching errors that happen in callbacks -- only catch errors that throw during fetch/processing of resources.

Here's the updated curl/plugin/json.js if you want to proceed. I'll continue to fix & test the other plugins.

/** MIT License (c) copyright 2010-2013 B Cavalier & J Hann */

/**
 * curl json! plugin
 *
 * Like the text! plugin, will only load same-domain resources.
 */

(function (globalEval) {
define(/*=='curl/plugin/json',==*/ ['./_fetchText'], function (fetchText) {

    var hasJsonParse, missingJsonMsg;

    hasJsonParse = typeof JSON != 'undefined' && JSON.parse;
    missingJsonMsg = 'Cannot use strictJSONParse without JSON.parse';

    return {

        load: function (absId, require, loaded, config) {
            var evaluator, errback;

            errback = loaded['error'] || error;

            // create a json evaluator function
            evaluator = config.strictJSONParse
                ? guard(parseSource, loaded, errback)
                : guard(evalSource, loaded, errback);

            // get the text, then eval it
            fetchText(require['toUrl'](absId), evaluator, errback);

        },

        'cramPlugin': '../cram/json'

    };

    function error (ex) {
        throw ex;
    }

    function evalSource (source) {
        return globalEval('(' + source + ')');
    }

    function parseSource (source) {
        if (!hasJsonParse) throw new Error(missingJsonMsg);
        return JSON.parse(source);
    }

    function guard (evaluator, success, fail) {
        return function (source) {
            var value;
            try {
                value = evaluator(source);
            }
            catch (ex) {
                return fail(ex);
            }
            return success(value);
        }
    }

});
}(
    function () {/*jshint evil:true*/ return (1,eval)(arguments[0]); }
));

It works!