Julian Jelfs’ Blog

Angular auto-retry interceptor for WinInet error codes

Posted in angular, Javascript by julianjelfs on June 5, 2015

It’s a little known fact that IE9 (and maybe lower versions if you have to support them) will occasionally return strange looking codes from xhr requests. You probably won’t be handling these in your angular app because they are not http codes. But they do happen and they happen quite often.

I have found that simply retrying the request (just once) will all but eradicate this problem. You might also consider a single retry on any xhr error.

How do you actually do this? Using an http interceptor as follows is the most generic way I have found.

'use strict';

angular
    .module('app')
    .config(($provide, $httpProvider) => {

    var codesToRetry = [12152,12002,12031,12029,12030,12041,12019];

    $provide.factory('retryInterceptor', ($injector, $q) => {
        return {
            'responseError' : (resp) => {
                if(codesToRetry.indexOf(resp.status) >= 0 &&
                    resp.config.headers['X-Auto-Retry'] == null) {
                    resp.config.headers['X-Auto-Retry'] = resp.status;
                    var $http = $injector.get('$http');
                    return $http(resp.config);
                } else {
                    return $q.reject(resp);
                }
            }
        };
    });

    if ($httpProvider.interceptors.indexOf('retryInterceptor') < 0) {
        $httpProvider.interceptors.push('retryInterceptor');
    }
});

 

Here I have just picked a handful of codes that I saw in my own logs to automatically retry. We ensure that we only retry once by inserting a custom retry header to check on subsequent failures.

Hope this is useful to someone.

Advertisements

Securely posting application/json data to Asp.Net MVC4

Posted in Javascript, MVC by julianjelfs on April 3, 2013

Asp.Net MVC4 has some good mechanisms to protect against cross-site request forgery. The gist is that on the server you generate a unique token that is written out as a cookie and then also written out to the page you are rendering. Then when the system receives data via a POST request, it can check that the anti-forgery token has been supplied in both the submitted form and in the cookie and that they match. This way, if the user has been tricked into submitting a form that did not originate on the server as the user supposes, that request may have assumed the correct cookie, but will not have the matching form field counterpart and the request will fail.

We do this in Asp.Net MVC4 by simply calling the @Html.AntiForgeryToken() helper inside our view and then adorning our controller’s POST actions with the ValidateAntiForgeryToken attribute. Easy. This works really well if you are taking a traditional approach and posting forms of data to the server. But it is now very common for people to be using some kind of client side MVC framework (angular, knockout, ember etc etc) or even just using $.post to send json data back to the server outside a form submission.

I have seen a lot of people asking the question, how come my ValidateAntiForgeryToken doesn’t work when I post data back to the server using an ajax call in this way? Usually the response is that they are using the wrong content type. They are using “application/json” and they should be using “application/x-www-form-urlencoded” and this is why the anti forgery token cannot be read. This is true – the ValidateAntiForgeryToken attribute specifically looks in the Request.Form for the __RequestVerificationToken value and so it will only work with form url encoded data. But the answer is not to change the content type of your request it is to change your attribute.

The content type of “application/json” is entirely appropriate and correct. That is what you are doing – posting json. It’s much more easily parsed and it’s easier to read across the wire using something like fiddler, it’s easy to serialise and deserialise, it works with MVC model binding out of the box, so leave it alone. All you need to do is tag the verification token onto your request somehow and write a new attribute to pick it out of the request according to your rules. For example, it can easily be stored in and retrieved from a custom http header.

Continue to write the token out to the page using @Html.AntiForgeryToken() and replace the ValidateAntiForgeryToken attribute with something like this:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class ValidateJsonAntiForgeryToken : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
var request = filterContext.HttpContext.Request;

if (request.HttpMethod == WebRequestMethods.Http.Post)
{
if (request.IsAjaxRequest())
AntiForgery.Validate(CookieValue(request), request.Headers["__RequestVerificationToken"]);
else
new ValidateAntiForgeryTokenAttribute().OnAuthorization(filterContext);
}
}

private string CookieValue(HttpRequestBase request)
{
var cookie = request.Cookies[AntiForgeryConfig.CookieName];
return cookie != null ? cookie.Value : null;
}
}

Then modify your client code to supply the token as a custom http header. In my case, I have created an angular service that wraps $http.post to achieve this as follows:

 

app.factory("xsrfPost", function($http) {
return {
post: function(url, args) {
var config = {
headers: {
'__RequestVerificationToken' : angular.element("input[name='__RequestVerificationToken']").val()
}
};
return $http.post(url, args, config);
}
};
})

Now, you can use a content-type that makes sense and still take advantage of the framework support for anti-XSRF protection.

jQuery keyboard control plug-in

Posted in Javascript, jQuery by julianjelfs on September 11, 2010

I had a requirement to come up with some keyboard control mechanism for our web app which I would like to be able to handle some peculiar requirements. Most tricky is that we do not know what the labels are in advance because they are configurable by the user. In the past this has led to a lot of duplicate access keys because we derive them on the fly.

I though maybe we could use something along the lines of the google chrome mouseless browsing extension which creates a little floating div with a number in it for each “clickable” thing. So I created a simple jQuery plug-in which does just that:

   1: (function($){

   2:  

   3: $.fn.keyboard = function(selector){

   4:     if(!selector || selector.length == 0)

   5:         return this;

   6:     

   7:     var shortcutsShowing = false;

   8:     var timer = null;

   9:     function hideShortcuts(){

  10:         $("div.kb-shortcut").remove();

  11:         target.unbind("keydown.kb");

  12:         target.unbind("keydown", "esc");

  13:         shortcutsShowing = false;

  14:         if(timer){

  15:             clearTimeout(timer);

  16:         }

  17:     }

  18:  

  19:     target.bind("keyup", "alt", function(){

  20:         if(!shortcutsShowing){

  21:             shortcutsShowing = true;

  22:             var kb =  $(selector, target);

  23:             var targets = {};

  24:             kb.each(function(i){

  25:                 targets[i] = $(this);

  26:                 var pos = $(this).offset();

  27:                 $("<div class='kb-shortcut'>" + i + "</div>")

  28:                     .appendTo("body")

  29:                     .css({

  30:                         top : pos.top + 5,

  31:                         left : pos.left + 5,

  32:                         opacity : 0.8

  33:                     });

  34:             });

  35:  

  36:             var buffer = [];

  37:             var timer = null;

  38:             target.bind("keydown.kb", function(e){

  39:                 if(timer){

  40:                     clearTimeout(timer);

  41:                     timer = null;

  42:                 }

  43:  

  44:                 buffer.push(String.fromCharCode(e.which));

  45:  

  46:                 timer = setTimeout(function(){

  47:                     var key = buffer.join("");

  48:                     buffer = [];

  49:                     var target = targets[key];

  50:                     if(target != null){

  51:                         $("div.tree").blur();

  52:                         target.click()

  53:                         hideShortcuts();

  54:                     }

  55:                 }, 500);

  56:             }).bind("keydown", "esc", function(){

  57:                 hideShortcuts();

  58:             }).one("click", function(){

  59:                 hideShortcuts();

  60:             });

  61:         } else {

  62:             hideShortcuts();

  63:         }

  64:     });

  65:     

  66:     return this;

  67: };

  68: })(jQuery);

So basically you call it on the container that you want to provide the scope for the event capture e.g. $(“body”) and you pass it a selector which will identify all the elements which you want it to highlight. So if you want it to highlight buttons you’d do this:

   1: $("body").keyboard(":button");

Having done that, when the user hits the alt key, all buttons will be marked with a little square with a number in it. The user types the number they want and that element gets clicked. Simple. It will also work with numbers of more than one digit, because the key presses are recorded in a buffer and then joined together after a brief pause (the duration of which could easily be made configurable). It has the advantage of being very easy to drop into an existing page without really having to rewrite anything. Don’t know whether we’ll use it – everyone might hate it, but I quite like it.

The little highlight squares have the class “kb-shortcut” attached to them, so you can style them how you like (again that could easily be passed in as an option).

One thing to note, this is currently dependent on the jquery.hotkeys plugin to capture the alt and escape key presses. This could easily be refactored to just use standard jquery functionality only.

jQuery plug-in for deferred resize (or anything)

Posted in Javascript, jQuery by julianjelfs on May 7, 2010

There are a class of UI events that fire many many times in quick succession. Things like mouse move, resize or even keyup. Often (in my experience) you might want to perform some action after the event has stopped happening rather than for each and every event. Suppose you want to do some expensive re-organisation of the UI in response to the resizing of some container element then you most likely don’t want to do this in response to every resize event, rather you want to wait until it appears that the user has stopped resizing and then perform the action. I have found it useful to encapsulate this pattern as a jQuery plug-in so that instead of this:

element.resize(function(){
    //do something expensive
});

I can do this:

element.deferredResize(function(){
    //do something expensive
}, 300);

And the plug-in looks like this:

$.fn.extend({    
    deferredResize : function(fn, delay){
        var timer = null;
        $(this).resize(function(){
            if(timer != null){
                clearTimeout(timer);
                timer = null;
            }
            timer = setTimeout(fn, delay);
        });
        return this;
    }
});

So when it picks up a resize event it will wait 300 milliseconds before kicking of the handler. In the interim, if it receives another resize event it will cancel the first timer and start the wait again. The end result is that you can achieve a nice balance between performance and responsiveness.

You could refactor this as a general extension to $.bind I guess but I think it is less useful for other events.

Scope shenanigans part three

Posted in Javascript by julianjelfs on January 24, 2010

So in my previous posts here and here I described a problem I was having with Microsoft Ajax script library serialisation of Dates that had been created in a different scope to that where the serialisation is actually taking place. I also described a somewhat hacky solution that involves iterating through the data to be serialised, tagging dates and then switching scope and recreating the dates in the new scope.

This works fine, but I don’t like the idea of having to recreate all these dates all the time so I go to thinking a bit more about what (someDate instanceof Date) actually means. Roughly it means, was this date created with the Date function. Given that I wandered if the following two statements were equivalent:

var date = new Date();
alert(date instanceof Date);    //true
alert(date.constructor === Date);    //true

If so then perhaps I can do the following:

var dateA = top.frames["frameB"].date;
alert(dateA instanceof Date);    //false
dateA.constructor = Date;    //change the constructor function
alert(dateA instanceof Date);    //true

If so, I can avoid having to recreate the Date objects, I can just reassign their constructor functions. Sadly, it doesn’t work. It seems that there is more to instanceof than just checking the constructor function. So we still have to be wary of using instanceof, but remember that the original problem was with the Microsoft Ajax script serialisation so all is not lost. The MS code detects type like this:

Type.prototype.isInstanceOfType = function Type$isInstanceOfType(instance) {    
    var e = Function._validateParams(arguments, [{name: "instance", mayBeNull: true}]);    
    if (e) throw e;    
    if (typeof(instance) === "undefined" || instance === null) return false;    
    if (instance instanceof this) return true;    
    var instanceType = Object.getType(instance);    
    return !!(instanceType === this) ||           
        (instanceType.inheritsFrom && instanceType.inheritsFrom(this)) ||           
        (instanceType.implementsInterface && instanceType.implementsInterface(this));
}

So it uses instanceof first, but if that returns false, it goes on to call Object.getType which looks like this:

Object.getType = function Object$getType(instance) {    
    var e = Function._validateParams(arguments, [{name: "instance"}]);    
    if (e) throw e;    
    var ctor = instance.constructor;    
    if (!ctor || (typeof(ctor) !== "function") || !ctor.__typeName || (ctor.__typeName === 'Object')) {        
        return Object;    
    }    
    return ctor;
}

Which is basically just returning the object’s constructor property. So by overwriting the constructor argument as described, although instanceof still cannot be trusted, Date.isInstanceOfType(object) as defined in the Microsoft Ajax script library will work as expected and therefore so will MS javascript serialisation.

The upshot is that by overwriting the date object’s constructor property with the Date function from the required scope we can get Date.isInstanceOfType(object) to return true and there is no need to completely recreate the date in the required scope. If, however, you want instanceof to work – the only way I can achieve that is to recreate the date. If anyone knows of a better way, I’d love to hear it.

Solution to the cross-frame instanceof scope problem

Posted in Javascript by julianjelfs on January 15, 2010

In my previous post I explained how I ran into the problem that dateB defined on frameB would return false if you execute dateB instanceof Date in frameA. I thought that this was because the data somehow got mangled when marshalled from one window to another. In fact it is nothing to do with that. The instanceof function is working entirely correctly, it’s just maybe not doing what you expect.

When you write (dateB instanceof Date) you are really asking was dateB created with function Date. Now when you add the implicit scope you begin to see why it doesn’t work the way you want. dateB was created in frameB with the function frameB.Date. So when you say dateB instanceOf frameA.Date as you implicitly are when you run this code in frameA, then of course it should and does return false.

If you explicitly call dateB instanceof frameB.Date it still returns true.

If you bear this in mind when calling functions that return data on other frames you can get round it. One approach which I have taken is shown here:

var frameB = top.frames["frameB"];

var dateB = crossFrame(frameB, frameB.getMeADate);

alert(dateB instanceof Date);     //give true

function crossFrame(target, func, parms){
    var result = func.apply(target, parms);
    result = tagDates.call(target, result);
    tagDates.call(target, parms);
    fixDates(parms);
    return fixDates(result);
}
function fixDates(val){
    if (val == null) return val;
    if (val["_date"]!==undefined) {        
        return new Date(val);
    }
    if (typeof (val) != 'object') return val;
    if (val instanceof Array) {
        for (var j = 0,len=val.length; j < len; j++) {
            val[j] = fixDates(val[j]);
        };
        return val;
    }
    for (var prop in val)
        val[prop] = fixDates(val[prop]);
    return val;
}

function tagDates(val){
    if (val instanceof Date) {
        val._date = true;
        return val;
    }
    if (typeof (val) != 'object') return val;
    if (val == null) return val;
    if (val instanceof Array) {
        for (var j = 0,len=val.length; j < len; j++) {
            val[j] = tagDates(val[j]);
        };
        return val;
    }
    for (var prop in val)
        val[prop] = tagDates(val[prop]);
    return val;
}

So we pass the target frame and the target function and the arguments array to the function crossFrame. Inside crossFrame we call the function on the target frame and get the results. At this point we are in calling frame scope. We then call tagDates using the target frame as scope. In this scope we can correctly identify the dates in the data. For each one we find, add an attribute so that we can identify it as a date later.

Then back in the calling scope we call fixDates which looks for the objects we tagged as dates and overwrites them with an equivalent Date created in the calling scope.

This means that when the data is returned from the call to crossFrame, any dates will have been re-created in the calling scope and any call to instanceof will work as expected.

The code above is not complete because it only handles dates. That’s all I have a problem with so it works for me but it could easily be extended for any other type because the underlying problem is not about types it is about scope.

Cross-frame dates cannot be serialised by Sys.Serialization.JavaScriptSerializer

Posted in Javascript by julianjelfs on January 15, 2010

Lets say you have a page with two iframes on it (frame A and frame B). In frame A we do this (forget why):

window.testDate = new Date();

and then in frame B we do this:

Sys.Serialization.JavaScriptSerializer.serialize(top.frames["frameA"].testDate);

We will get a stack overflow (in IE7 at least) when using the debug version of the Microsoft Ajax framework and we’ll just get nothing with the release version.

The root cause seems to be that in frame A testDate instanceof Date is true. But if we reference it from frame B it is false. This means that the serialiser does not correctly identify it as a date etc etc.

This is annoying if you are using the serialiser directly, but it is really annoying if you are forced to use it because you are using an MS Ajax script service proxy. I guess I will have to use jQuery to call the script service directly and take charge of serialisation myself using some other JSON library. I have seen it done but I just know it’s going to be painful…

PS – this issue is nicely described here

Nasty issue “sort of with” jquery hotkeys plugin

Posted in Javascript, jQuery by julianjelfs on July 8, 2009

I encountered a quite nasty JavaScript issue today. The symptom was that a page that had been working quite happily was suddenly causing IE to crash. After a lot of head scratching I finally tracked it down to the hotkeys jQuery plug-in. I should say up front that there is arguably nothing wrong with the hotkeys plug-in. What the hotkeys plug-in does is to take a copy of jQuery’s own bind function and stores it in a variable called __bind__ on the jQuery object. It then override the bind function with its own in order to extend the functionality for certain event types. If you bind an event that it is not interested in, it delegates the call back to the original jQuery function by calling this.__bind__.

Nothing wrong with that, perfectly sensible and works fine. The problem arises if you accidentally include the script file for the hotkeys plug-in twice. This is not that unlikely if you are writing components that may depend on it and write them such that each component is responsible for its own script registration. This is what I am doing. Ordinarily, duplicate scripts would be filtered out but there was a bug in that code so I ended up with duplicate scripts.

In that case, the second time the script loads,  the following script:

jQuery.fn.__bind__ = jQuery.fn.bind;
It overwrites __bind__ with the already overridden bind function i.e. itself. This has disastrous consequences when the plug-in subsequently calls __bind__ because it enters into an infinite loop and crashes the browser.
Although this only arises if you misuse the hotkeys plug-in, it seems that it could protect itself from this possibility by simply checking to see whether jQuery.fn.__bind__ had already been set before setting it.

Interrupted XmlHttpRequests cause IE to hang

Posted in Javascript by julianjelfs on May 6, 2009

I ran into a problem using MS Ajax script services recently. I was getting reports of intermittent hanging in IE (6 and 7) with some newly developed pages. I had a vague feeling it was something to do with the Script Services and a quick search revealed that this is a relatively well known problem.

As described in one of the responses to that question, the issues is caused when a page closes after an asynchronous ajax request is started but before it completes. In this scenario one of the browser’s available connections (of which it has 2 by default) is tied up and not released. So if this happens a couple of times, the browser has no available connections to service normal requests and appears to hang.

The solution is to abort any pending XmlHttpRequest when the page unloads. It’s not totally obvious how to do this when you are using Script Services with the generated proxy, because the actual XmlHttpRequest object itself is buried in multiple layers of magic. After a bit of digging I came up with the following solution:

$(function(){
    var pending = null;
    Sys.Net.WebRequestManager.add_invokingRequest(function(executor, args){
        pending = args.get_webRequest().get_executor();
    });

    Sys.Net.WebRequestManager.add_completedRequest(function(executor, args){
        pending = null;
    });

    $(window).unload(function(){
        if(pending!==null){
            pending.abort();
        }
    });
});

So what this does is just track the executor of the currently executing web request and set it to null when the request completes. On unload, we check if there are any pending request executors, and if there are we call abort on them. This prevents the hanging issue for me in IE which is a big relief.

Obviously this mechanism may not be adequate for you if ajax calls are not queued because there may be more than one pending request. In my case, all service calls are channelled through a queue so that can’t happen. Otherwise you would have to implement some mechanism to correlate the invoked request with the completed request.

Tagged with: ,

Beware empty/null selectors with jQuery

Posted in Javascript, jQuery, Uncategorized by julianjelfs on April 17, 2009

I encountered a problem today with one of my JavaScript components which I use to wrap and extend the normal checkbox input control. My component uses jQuery to add an onclick event to the underlying dom element as follows:

$(this._element).click(fn);

The problem arises when the underlying element does not actually exists (never mind why). In this case this._element is null. My assumption was that if jQuery did not throw an exception here (which it rarely does) then it would probably just do nothing in this case. My assumption was wrong, as in this case it appears that jQuery will attach the click event handler to the whole document body. This is pretty obvious when you look at the jQuery code itself as the first thing it does is to make sure that you have indeed specified a selector:

jQuery.fn = jQuery.prototype = {
    init: function( selector, context ) {
        // Make sure that a selection was provided
        selector = selector || document;
....

The end result is that the click function I was trying to assign to the checkbox click was actually happening when clicking anything. I’m sure there is a good reason for this but it seems likely a slightly odd default behaviour to me and one to watch out for.