Pages

Thursday, October 11, 2012

I worked on a Lift 2.4 web application that used lot of Surround and Embed tags in HTML files. Looking in the LiftSession we can see that lift repeats the merging process again for every request received. This is not required and significant performance can be gained when we cache a merged HTML template and process that instead of evaluating "surround" and "embed" tag on every request. If you enable TemplateCache, then this new cache below will act like a cache one level up in the hierarchy. Note that its a good idea to enable/use this cache only in production mode to not to hinder development activities.

There are multiple ways to implement this. The one I will explain here is by extending the LiftSession class and overriding the processTemplate method. But, if you have a custom content handler DispatchPF appended to lift dispatch, and you do some more stuff before calling the processTemplate yourself then you can add this caching in this class too. The code is very different when compared to the first approach and will try to provide at the end.

First thing to do is to define a synchronized cache that is used to cache the processed templates. The code below is self explanatory. Note that most of the code to follow is copied from Lift and modified to serve the desired purpose.

/** * A synchronized cache that handles the caching of Processed Templates in production mode only. The strategy used * is Least Recently Used caching. */object ProcessedTemplateCache{ private val cache : LRU[String, NodeSeq] = new LRU(50)

Now, lets extend the LiftSession class. Note that, many methods in LiftSession is private and hence not accessible. The only way around the problem is by pulling them in the new CustomLiftSession implementation. So, here the version is very important. The code below uses the LiftSession from 2.4 codebase. Lift 2.5 has modification/extensions to this. I understand this as a bad idea as the methods pulled in from the LiftSession class may be modified in future and HAS to be synched up manually when required, but there is not much we can do using this approach due to private modifiers in the LiftSession class. Note that all the code is written in package net.liftweb.http.

class CustomLiftSession(_contextPath: String, uniqueId: String, httpSession: Box[HTTPSession]) extends LiftSession(_contextPath, uniqueId, httpSession){ //This val is copied as is from the super class, as it is private and not accessible from here. private object overrideResponseCode extends TransientRequestVar[Box[Int]](Empty)

//This val is copied as is from the super class, as it is private and not accessible from here. private val fullPageLoad = new ThreadGlobal[Boolean] { def ? = this.box openOr false }

// But we need to update the function map because there // may be addition functions created during the JsToAppend processing // See issue #983 updateFunctionMap(S.functionMap, RenderVersion get, millis)

Next in Boot.scala you will add the following code that will allow lift to use CachedSurround dispatcher when it encounters the "cachedSurround" lift tag(<lift:cachedSurround with="default" at="pageContent">...</lift:cachedSurround>) and use our CustomLiftSession that does the preprocessing and caching of merged templates (with cachedSurround and embed tags only) in production mode.

Now, many of this code can be avoided if you have a separate content handler dispatcher (this is added again in Boot.scala as LiftRules.dispatch.append(ContentHandler.dispatch)). Note that, this is the way if you want to do more before you process templates or load templates from some other place. I wont go into that detail, but if you do this then you will call the processTemplate on the session manually. So, this is what you can do in that case. Create the below code in net.liftweb.http package. When using below you do not need to extend LiftSession class nor create any new snippet dispatcher (whether you use surround or cachedSurround as in the comments below).

This will improve the performance significantly on long run in production mode as you already have cached templates that are expanded and merged from cachedSurround and embed tags. Note that this improvement is conditional upon the number of templates you use, and the amount of cachedSurround and embed tag in work. Just to make it simple, I am providing the package and the imports below.

Thursday, June 28, 2012

I was very interested in authentication and bumped against SRP. SRP is a protocol that helps in achieving authentication and is defined at http://srp.stanford.edu/. Since, I did not see any implementation of this in my current fav programming language- Scala, I decided to write a small scala based SRP v6a implementation. The code is hosted on Github at https://github.com/shreyaspurohit/SRPScala and is MIT licensed opensource. Feel free to contribute. I have provided an example implementation using Play 2.0 web framework. This is hosted at http://srp.bitourea.com/. The client is authenticated by server, then client authenticates that its speaking to the right server and finally continues to get the secret page over AES 128bit PBE encrypted channel. Since, just scala server side code is not sufficient- there is also srp.js that tags along for the client side javascript. The code scala and JS is small and can be easily understood. Just implement SRPServer trait and you are good to go. The example play 2.0 app provides a sample implementation- ExampleSRPServer.scala. This uses file for storage, you can use DB or any other destination for storage. The usage of javascript is provided as example in login.scala.html. It shows a very cleanly the data that is exchanged between client and server. This is how the example app works. These are just important code snippets. Look in Github for the complete code.

Server calculates the expected session id. There are some more authentication is real code. If the results are defined then save the current session, return s and bvalStr. Refer to SRP design to understand these parameters.

The server returns the verifier. The server and client have authenticated to each other. K has never been sent over the wire, so we use K as secret key for this session to encrypt data exchange between server and client. This is shown in method- getTheSecretPage() in login.scala.html. On the server side check Auth.scala for AES magic. The enc method on the server side does the job in scala.

Saturday, March 31, 2012

I was trying to setup gradle wrapper to work with Teamcity behind a proxy but only to realize that gradle wrapper was not using the java proxy options I was providing in command line. I decided to tweak the gradlew.sh and gradlew.bat a little to make it use the proxy so that I can provide proxy options in teamcity console when I configure the build step using gradlew. I don’t have access to build agents to configure gradle with properties file. Insert the below code in batch and shell script at a place between the first line and last line (Just before the invocation of GradleWrapperMain). If you put below pieces of code at wrong place then this will not work.

Wednesday, January 04, 2012

Though this is very simple and straight forward, there is no direct answer to this question on internet. You can run any webapp in eclipse using this approach, not necessarily with scalatra. The code is available for Lift web framework and works well with scalatra too.