1

It seems I have found myself in a catch 22.

I am using the Chrome Web Request event in an extension to get the URL of all web requests as such:

chrome.webRequest.onBeforeRequest.addListener(
          function(request) { 
                var cat = getCategory(request.url);
                if(cat == "1") {
                       return {redirectUrl: "http://google.com"}
                  } else {
                      return {cancel: false}
                  }
              }
});

Then, I want to query my server using PHP to get the URL’s category. If it has a category of 1, I want to block it, if it has a category of 0, I want to allow the request to go through.

The big issue I’m seeing is that because there’s an AJAX request in the getCategory function, it doesn’t return a value and execution just continues as normal. I need to find a way to block execution until a return is actually received somehow but I’m not quite sure how to do that while still being able to return the redirect URL to the listener function.

Synchronous requests would almost work, except that you can’t set a timeout with a synchronous AJAX request. As such, if our server goes down, everyone’s web requests will be blocked regardless of category -- not ideal.

function getCategory(url) {
    request = $.ajax( // params);
    request.done(function)
// this code executes even before the done block finishes
}

I’ve tried using AJAX bindings like the .done() function currently being used here. I’ve also tried finding ways to make a synchronous request timeout and using .when().then() function combinations but I’m unable to find a way to return the value in the right scope from in those.

Is there a way I can get this value from the ajax request to the outer function? Everything I’ve seen to try has the wrong return scope. Does anyone know if this is somehow possible?

Ideas about restructuring the code also accepted! (As long as it will work with chrome.webRequest)

user417669
  • 178
  • 3
  • 15
  • That's totally impossible. You cannot magically get a value that doesn't exist yet. – SLaks Jan 28 '14 at 03:35
  • possible duplicate of [How to return the response from an AJAX call?](http://stackoverflow.com/questions/14220321/how-to-return-the-response-from-an-ajax-call) – Evan Trimboli Jan 28 '14 at 03:35
  • You can't use an asynchronous operation in a synchronous fashion. You must either put ALL the code that needs the response IN the success handler or you must call a function from there and pass the data to it. You can't "wait" for the request to be done. That's not how asynchronous requests work in javascript. The duplicate link for more info. This question has been asked and answered hundreds of times. – jfriend00 Jan 28 '14 at 03:38
  • @jfriend00 so do you have any example about how we could make this work with chrome.webRequest? Sorry if I am being dense. – user417669 Jan 28 '14 at 03:42
  • Your problem is that `getCategory()` is itself asynchronous so you CAN'T get it's result in time to use it in `onBeforeRequest`. You just can't. You will either have to retrieve the category beforehand (if possible) so the data is already available or you will have to think of another way to solve your problem. This particular approach isn't supported by javascript unless you turn the ajax call in getCategory into a synchronous/blocking ajax call which has it's own bad issues. – jfriend00 Jan 28 '14 at 03:49
  • @jfriend00 But using web request blocking, I can delay the request as long as I want, can't I? The fact that a synchronous request works seems to prove this. – user417669 Jan 28 '14 at 03:52
  • I'm not sure what you mean by "delay the request as long as you want". How would you delay the request? That isn't something you can normally do in javascript. With synchronous requests the JS engine is suspended by the system until the synchronous request is done - there is no equivalent way to do that yourself in javascript. – jfriend00 Jan 28 '14 at 03:54
  • @jfriend00 just posted an idea as an answer, curious what you think / if you have any additions. – user417669 Jan 28 '14 at 04:16

1 Answers1

0

You're not going to get much out of this.

In your ideal scenario, Chrome has internally built that particular exception to also accept promise-based return values.

I doubt that's the case, but you could always check the API documentation for mention of accepting a promise or a "thenable".

The more-likely solution is that you will need to make pulling that whole list of "category-1" requests into your client-side code.

This will either have to be put into an Object/Array in the program, or placed inside of localStorage.
Because you're using a Chrome extension, I'm going to assume that localStorage may well be available, here.

Also, while localStorage will work, WebSQL(dead) and IndexedDB will not work, because they're also asynchronous access (even though the data is stored right there, by the client's browser).

Those are your options, at this point.

Norguard
  • 26,167
  • 5
  • 41
  • 49
  • And if the list of category 1 values is over a million rows long? – user417669 Jan 28 '14 at 03:58
  • @user417669 Then I would suggest that either you beg Google's Chrome team to imbue that API with promise handling capabilities, or that you find another way to solve that problem-domain, which *can* support asynchronous resolution. If that function doesn't support a generator (it 100% doesn't) or a promise (it most likely doesn't) as a return value, then there is practically nothing you can do to force it to hard-lock the execution of all JS/user-interaction on the page, until your query returns. – Norguard Jan 28 '14 at 04:18
  • We thought of a way to (relatively) safely use synchronous requests -- which do work. Check the below answer! I would love any feedback or expansion on the idea. – user417669 Jan 28 '14 at 04:24