Stay Out Please
Itai Koren | July 2013
Framework Frontend Team @LivePerson
Who am I?
Itai Koren
Tech-savvy Engineer @LivePerson
A Programmer
itaik@liveperson.com
Who am I?
ā€œProgrammer - an
organism that turns
coffee into software.ā€ -
Author Unknown
Who am I?
~10 x Cups === feature
Who am I?
LivePerson Framework
Frontend Team
Today’s Web Applications
Today’s web
applications/platforms are
more than just websites
Today’s Web Applications
Javascript SDK’s/API’s
Today’s Web Applications
Today’s Web Applications
Today’s Web Applications
Today’s Web Applications
Today’s Web Applications
Widgets
Today’s Web Applications
Today’s Web Applications
Today’s Web Applications
ā€œLearning JavaScript used to
mean you weren't a serious
software developer.
Today, not learning Javascript
means the same thing.ā€ -
Jens Ohlig
Stay Out Please
XMLHttpRequest
api.lpprod.net
Backbone
jQuery as transport
Stay Out Please
S O Ptay ut leaseame rigin olicy
Same Origin Policy
• Important security concept within modern browsers
• Originally released with Netscape Navigator 2 (March 1996)
• Permits script tags, images, css from any site (origin)
• Permits XHR only from the same site (origin)
• Prevents access to most methods and properties across different sites
(origins)
Same Origin Policy
So which solution can we use?
Today’s Web Applications
ā€œA good programmer is
someone who always looks
both ways before crossing a
one-way street.ā€ - Doug
Linder
Same Origin Policy
We can always use JSONP
WOT?
JSONP
• Stands for JSON with Padding
• Script tags are exception to the Same Origin Policy
• Just loading a script with JSON data cannot help us (will be lost in the
global context)
• The padding allows us to wrap the result with a global callback
• The response will be evaluated by the JavaScript interpreter and invoked
JSONP
So, we can always use JSONP
BUT…
Why not use JSONP?
• Only valid for GET requests
• Limited payload size
• Not flexible (no headers etc.)
• Insecure
• Causes IE to leak memory (most implementations)
Same Origin Policy
What about CORS?
CORS
• Stands for Cross Origin Resource Sharing
• A W3C spec that allows cross-domain communication from the browser
• Defines a way to determine whether or not to allow the cross-origin
request
• Works by adding new HTTP headers
CORS
So what about CORS?
Why not use CORS?
• Only IE9+ support it natively (IE8 only via XDomainRequest)
• Requires ā€œpreflightsā€ for requests other than GET or POST (with certain
MIME types) and for JSON.
Same Origin Policy
So, we will probably have to
use proxy
WAIT!!!
Stay Out Please
S O Ptay riginal leaseame rigin olicy
lpAjax to the rescue
• Developed in LivePerson
• Self contained (Vanilla JS)
• Easy to use
• Used by entire LivePerson clients as a transport layer
• Supports three main transport types: XHR, JSONP
AND
postMessage
Browser to server communications
url.com
api.liveperson.com
api.liveperson.com/pm.html
lpAjax postmessage client
pm.html
Postmessage server
xhr
lpAjax postMessage
• It works!!!
• Almost as fast as JSONP
• Can work with REST API’S
• Very small latency for first API call (iframe creation)
• Small latency for serialization of data for use with postMessage
• Beware: 401 Response Codes & failed requests issues
Browser Support
• Firefox >= 3
• Safari >= 4
• Chrome
• Opera >= 9
• IE >= 8
lpAjax postMessage
And there is even a
shim/polyfill for IE7
window.name… (limited to
2MB only )
lpAjax postMessage
Cool
I am convinced
BUT, how can I use it with
Backbone
Backbone with lpAjax postMessage
• Backbone utilizes jQuery as a transport
• jQuery allows us to manipulate ajax transports at multiple levels
• $.ajaxPrefilters - Handle custom options/modify existing options before
request is processed by $.ajax()
• $.ajaxTransport - Creates an object that handles the actual transmission
of Ajax data and used by $.ajax() to issue requests
• Converters – to manipulate and parse the data returned from the
response
Our custom ajaxPrefilter
// Register jQuery Ajax Prefilter that detects cross-domain requests and set the request data-type to "postmessage".
$.ajaxPrefilter(function (options, originalOptions, jqXHR) {
// Get our current origin
var originBrowser = window.location;
// Get the API url origin
var originApi = document.createElement("a");
originApi.href = options.url;
// Skip Same Origin API URL's
if (originApi.hostname == originBrowser.hostname &&
originApi.port == originBrowser.port &&
originApi.protocol == originBrowser.protocol) {
return;
}
// If the domains aren't the same and this isn't a jsonp request, force the data-type of the request to "postmessage".
if ("jsonp" !== options.dataType.toLowerCase()) {
// Redirect to our ā€œpostmessageā€ temporary transport type
return "postmessage";
}
});
Our ajaxTransport Implementation
// Create the postmessage transport handler (which will proxy the request to lpAjax) and register it for handling postmessage
// (the '+' forces overriding any existing implementations for a transport).
$.ajaxTransport("+postmessage", function (options, originalOptions, jqXHR) {
// Remove the temporary transport dataType
options.dataTypes.shift();
return {
send:function (requestHeaders, done) {
// Build the request object based on what jQuery created for us so far
var req = $.extend({}, lpTag.taglets.lpAjax_request);
req.headers = requestHeaders;
req.method = originalOptions.type;
req.data = originalOptions.data;
req.url = options.url;
// Implement the success and error handlers
req.success = function (data) {
handlePostMessageResponse(data, done);
};
req.error = function (data) {
handlePostMessageResponse(data, done);
};
// Issue the request using lpAjax postMessage.
lpAjax.postmessage.issueCall(req);
},
abort:function () {}
};
}));
Implement the response handler
// Create the response handler for lpAjax to call
var handlePostMessageResponse = function (data, done) {
// Do any parsing on the response if needed - Here I do nothing for simplicity
// Now call the jQuery callback to return the response to jQuery handling
done(
data.code, // status,
data.status, // nativeStatusText,
data.body, // responses,
data.headers // headers
);
};
Backbone with lpAjax postMessage
ā€œIf you can’t explain it simply,
you don’t understand it well
enough.ā€ -Leonardo Da Vinci
Q&A
itaik@liveperson.com
Want to work on cool stuff like this?
Questions?
Thank You

Stay Out Please

  • 1.
    Stay Out Please ItaiKoren | July 2013 Framework Frontend Team @LivePerson
  • 2.
    Who am I? ItaiKoren Tech-savvy Engineer @LivePerson A Programmer itaik@liveperson.com
  • 3.
    Who am I? ā€œProgrammer- an organism that turns coffee into software.ā€ - Author Unknown
  • 4.
    Who am I? ~10x Cups === feature
  • 5.
    Who am I? LivePersonFramework Frontend Team
  • 6.
    Today’s Web Applications Today’sweb applications/platforms are more than just websites
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
    Today’s Web Applications ā€œLearningJavaScript used to mean you weren't a serious software developer. Today, not learning Javascript means the same thing.ā€ - Jens Ohlig
  • 16.
  • 17.
    Stay Out Please SO Ptay ut leaseame rigin olicy
  • 18.
    Same Origin Policy •Important security concept within modern browsers • Originally released with Netscape Navigator 2 (March 1996) • Permits script tags, images, css from any site (origin) • Permits XHR only from the same site (origin) • Prevents access to most methods and properties across different sites (origins)
  • 19.
    Same Origin Policy Sowhich solution can we use?
  • 20.
    Today’s Web Applications ā€œAgood programmer is someone who always looks both ways before crossing a one-way street.ā€ - Doug Linder
  • 21.
    Same Origin Policy Wecan always use JSONP WOT?
  • 22.
    JSONP • Stands forJSON with Padding • Script tags are exception to the Same Origin Policy • Just loading a script with JSON data cannot help us (will be lost in the global context) • The padding allows us to wrap the result with a global callback • The response will be evaluated by the JavaScript interpreter and invoked
  • 23.
    JSONP So, we canalways use JSONP BUT…
  • 24.
    Why not useJSONP? • Only valid for GET requests • Limited payload size • Not flexible (no headers etc.) • Insecure • Causes IE to leak memory (most implementations)
  • 25.
  • 26.
    CORS • Stands forCross Origin Resource Sharing • A W3C spec that allows cross-domain communication from the browser • Defines a way to determine whether or not to allow the cross-origin request • Works by adding new HTTP headers
  • 27.
  • 28.
    Why not useCORS? • Only IE9+ support it natively (IE8 only via XDomainRequest) • Requires ā€œpreflightsā€ for requests other than GET or POST (with certain MIME types) and for JSON.
  • 29.
    Same Origin Policy So,we will probably have to use proxy WAIT!!!
  • 30.
    Stay Out Please SO Ptay riginal leaseame rigin olicy
  • 31.
    lpAjax to therescue • Developed in LivePerson • Self contained (Vanilla JS) • Easy to use • Used by entire LivePerson clients as a transport layer • Supports three main transport types: XHR, JSONP AND postMessage
  • 32.
    Browser to servercommunications url.com api.liveperson.com api.liveperson.com/pm.html lpAjax postmessage client pm.html Postmessage server xhr
  • 33.
    lpAjax postMessage • Itworks!!! • Almost as fast as JSONP • Can work with REST API’S • Very small latency for first API call (iframe creation) • Small latency for serialization of data for use with postMessage • Beware: 401 Response Codes & failed requests issues
  • 34.
    Browser Support • Firefox>= 3 • Safari >= 4 • Chrome • Opera >= 9 • IE >= 8
  • 35.
    lpAjax postMessage And thereis even a shim/polyfill for IE7 window.name… (limited to 2MB only )
  • 36.
    lpAjax postMessage Cool I amconvinced BUT, how can I use it with Backbone
  • 37.
    Backbone with lpAjaxpostMessage • Backbone utilizes jQuery as a transport • jQuery allows us to manipulate ajax transports at multiple levels • $.ajaxPrefilters - Handle custom options/modify existing options before request is processed by $.ajax() • $.ajaxTransport - Creates an object that handles the actual transmission of Ajax data and used by $.ajax() to issue requests • Converters – to manipulate and parse the data returned from the response
  • 38.
    Our custom ajaxPrefilter //Register jQuery Ajax Prefilter that detects cross-domain requests and set the request data-type to "postmessage". $.ajaxPrefilter(function (options, originalOptions, jqXHR) { // Get our current origin var originBrowser = window.location; // Get the API url origin var originApi = document.createElement("a"); originApi.href = options.url; // Skip Same Origin API URL's if (originApi.hostname == originBrowser.hostname && originApi.port == originBrowser.port && originApi.protocol == originBrowser.protocol) { return; } // If the domains aren't the same and this isn't a jsonp request, force the data-type of the request to "postmessage". if ("jsonp" !== options.dataType.toLowerCase()) { // Redirect to our ā€œpostmessageā€ temporary transport type return "postmessage"; } });
  • 39.
    Our ajaxTransport Implementation //Create the postmessage transport handler (which will proxy the request to lpAjax) and register it for handling postmessage // (the '+' forces overriding any existing implementations for a transport). $.ajaxTransport("+postmessage", function (options, originalOptions, jqXHR) { // Remove the temporary transport dataType options.dataTypes.shift(); return { send:function (requestHeaders, done) { // Build the request object based on what jQuery created for us so far var req = $.extend({}, lpTag.taglets.lpAjax_request); req.headers = requestHeaders; req.method = originalOptions.type; req.data = originalOptions.data; req.url = options.url; // Implement the success and error handlers req.success = function (data) { handlePostMessageResponse(data, done); }; req.error = function (data) { handlePostMessageResponse(data, done); }; // Issue the request using lpAjax postMessage. lpAjax.postmessage.issueCall(req); }, abort:function () {} }; }));
  • 40.
    Implement the responsehandler // Create the response handler for lpAjax to call var handlePostMessageResponse = function (data, done) { // Do any parsing on the response if needed - Here I do nothing for simplicity // Now call the jQuery callback to return the response to jQuery handling done( data.code, // status, data.status, // nativeStatusText, data.body, // responses, data.headers // headers ); };
  • 41.
    Backbone with lpAjaxpostMessage ā€œIf you can’t explain it simply, you don’t understand it well enough.ā€ -Leonardo Da Vinci
  • 42.
    Q&A itaik@liveperson.com Want to workon cool stuff like this? Questions?
  • 43.

Editor's Notes

  • #2Ā Ido
  • #22Ā IE<=8 leaks 4kb each request
  • #25Ā IE<=8 leaks 4kb each request
  • #28Ā IE<=8 leaks 4kb each request
  • #29Ā Creates each domain iframe only onceThere are browsers which already support postMessage with objects (with no need for serialization)401 response code will cause the browser to pop up an authentication (can be fixed by overriding the default WWW-Authenticate: BasicĀ realm=ā€œxxxā€header) 8 consecutive failed requests from the same iframe will abort the iframe usage
  • #32Ā Creates each domain iframe only onceThere are browsers which already support postMessage with objects (with no need for serialization)401 response code will cause the browser to pop up an authentication (can be fixed by overriding the default WWW-Authenticate: BasicĀ realm=ā€œxxxā€header) 8 consecutive failed requests from the same iframe will abort the iframe usage
  • #33Ā Creates each domain iframe only onceThere are browsers which already support postMessage with objects (with no need for serialization)401 response code will cause the browser to pop up an authentication (can be fixed by overriding the default WWW-Authenticate: BasicĀ realm=ā€œxxxā€header) 8 consecutive failed requests from the same iframe will abort the iframe usage
  • #34Ā Creates each domain iframe only onceThere are browsers which already support postMessage with objects (with no need for serialization)401 response code will cause the browser to pop up an authentication (can be fixed by overriding the default WWW-Authenticate: BasicĀ realm=ā€œxxxā€header) 8 consecutive failed requests from the same iframe will abort the iframe usage
  • #35Ā Creates each domain iframe only onceThere are browsers which already support postMessage with objects (with no need for serialization)401 response code will cause the browser to pop up an authentication (can be fixed by overriding the default WWW-Authenticate: BasicĀ realm=ā€œxxxā€header) 8 consecutive failed requests from the same iframe will abort the iframe usage