17

I am trying to build a Google Chrome extension that makes an ajax request. Something similar to the GMail Checker extension. The problem is that when I do the request using jquery, and I put in the wrong username/password, it fails silently, with the error callback function ignored.

If I move the ajax call out of the background.html script (where I can't see the requests in the developer window), to the options.html script, I get a dialog box to re-authenticate. If I hit cancel, THEN the jquery error callback fires.

But in the original model extension (again, the Gmail checker), they use plain (non-jquery) ajax calls with a try/catch, and if I put in the wrong credentials, I get an alert saying as much.

I tried wrapping the entire jquery call in a try/catch, like so:

try {
    $.ajax({
        type: "POST",
        url: someurl,
        contentType : "text/xml",
        data: somedata,
        username: user,
        password: pass,
        success: function(data,status,xhr){
            alert("Hurrah!");
        },
        error: function(xhr, status, error){
            alert("Error!" + xhr.status);
        },
        dataType: "xml"
    });
} catch(e) {
    alert("You messed something up!");
}

But still nothing.

Is the error due to it being asynchronous, or is Chrome not returning the request as an error since it wants to re-prompt for credentials? Or do I just not know how to use try/catch?

Update

Here is a very slimmed down version of how the model code does the request:

var req = new XMLHttpRequest();
req.onreadystatechange = function() {
    try {
        if ( req.readyState == 4 ) {
            //Do some stuff with results
        }
    }
    catch (ex) {
        alert('Error parsing response.');
    }
}
try {
    req.send (data);
}
catch (ex) {
    alert ('Something went wrong with the request.');
}
Community
  • 1
  • 1
Anthony
  • 36,459
  • 25
  • 97
  • 163
  • If you add a complete callback, does it fire?, e.g. adding `complete: function(xhr, status) { alert(xhr.status + " - " + status); }` to what you have. – Nick Craver May 11 '10 at 11:17
  • Good idea, I'll let you know in a second. – Anthony May 11 '10 at 11:31
  • Complete does work (as do the other callbacks) for 404 and 0 codes (0 meaning server not found). Would it be safe, do you think, to have the success callback set a boolean like "validLogin" to true, and assume that any other errors besides 301/302 and 401 will get returned as errors, and thus if the boolean variable is false, it must mean invalid login (assuming redirects have been dealt with elsewhere)? – Anthony May 11 '10 at 12:05
  • 3
    The reason `try/catch` doesn't improve things is that the call to `ajax` *succeeded* without errors. It's the *response handling* that you need to fix. Look at the response in Fiddler. What is it, precisely? – Craig Stuntz May 11 '10 at 12:45
  • @Craig: Not everyone runs windows, so fiddler wasn't an option at the moment. But I spend a while testing out various alternatives. With Wireshark I can see that requests are being sent to the remote IP, but without the benefit of a full SSL proxy, I can't make heads or tails of it. And with burp proxy, I can view all requests EXCEPT those from the extension, my best guess is that Chrome doesn't pass along proxy info to the extension level (or that I have to manually configure the extension... I grow tired of chrome FAST). I'll try it with Fiddler at work later and post results. – Anthony May 11 '10 at 15:51
  • @Craig, and I'm not sure I agree it's the response handling, like you say. I have a callback for success, failure, and complete, none throw ANYTHING. But I think you're on the right track. – Anthony May 11 '10 at 15:53
  • @Anthony, Firebug's Net panel will do, if that's available to you. – Craig Stuntz May 11 '10 at 17:18
  • Firebug is not an option since this Chrome. If this was a Firefox extension, I probably would be done already. I digress. I did Fiddler at work, there are three requests sent, each getting 401 responses. It makes sense that there are 3 since the remote server is NTLM (so it passes NTLM tokens back and forth). What is odd is that it never (as far as I can tell) returns a "Bad Username/Password" response. When I switch off async, it hangs up Chrome for a good while, then eventually just stops. So I just know Chrome is trying in some way to wait for new credentials when it gets the last 401. – Anthony May 11 '10 at 21:11

2 Answers2

15

Try something more like this, where you have a function that runs on every request once completed, regardless of what happens. This should solve the problem:

// Store a global var so we can all play nicely.

// Make sure this gets reset to false right before your AJAX call,
// or it will only work once!
var weHaveSuccess = false;

$.ajax({
    type: "POST",
    url: someurl,
    contentType : "text/xml",
    data: somedata,
    username: user,
    password: pass,
    success: function(data,status,xhr){
        alert("Hurrah!");
        weHaveSuccess = true;
    },
    error: function(xhr, status, error){
        alert("Error!" + xhr.status);
    },
    complete: function(){
        if(!weHaveSuccess){
             alert('Your username/password seems to be incorrect!');
        }
    },
    dataType: "xml"
});
NeoNexus DeMortis
  • 1,286
  • 10
  • 26
  • This was part of a bigger project that due to lots of little things (including this issue) ended up getting pushed aside and may never get restarted (maybe someday). The issue is (or at least was) that Chrome (and perhaps Webkit in general) would hang on the HTTP response for invalid Basic authentication, and eventually would timeout without returning the http response code.... (more below) – Anthony Feb 16 '12 at 19:48
  • I probably won't get a chance to test your idea soon, but the only 2 weaknesses I can see are : 1) won't the complete callback fire on error as well? (easy enough to handle, just curious if you know) 2) We have to assume the only reason there is no success or error on complete is the username/pw are wrong. Maybe a safe bet or at least good enough to get around the issue, but it would be better if in the complete callback more details could be pulled out. Either way, this seems like a solid workaround, so maybe I'll go back and dig up that code. Thanks. – Anthony Feb 16 '12 at 19:51
  • I didn't realize when I initially answered the question that it was out of date. I was trying to clear out unanswered questions. However, yes, the complete function will run even on an error response, which is why I incorporated the "weHaveSuccess" variable, which essentially determined if it was a "success" or a "failure". – NeoNexus DeMortis Feb 20 '12 at 05:37
4

The ajax error callback function do not throw an exception by itself. If you want to have a try/catch you should probably throw an exception yourself inside your error function. This will trigger your surrounding catch.

PS! Sometimes you need to set the async:false parameter in the ajax call when you need to evaluate the result because by default the code will continue after the ajax request is initiated and asynchronously call the success or error callback at a later stage and only call that code.

Stig Husby
  • 1,677
  • 12
  • 15