Tuesday, December 28, 2010

The thrill of being a developer - Fixing the problem of weird URL's

There are days when as a developer, I feel bored, bored to death, angry, happy, sad and many other emotions.  But there are a few days in life of a developer, when you feel truly thrilled!

Recently, one such thrilling day occurred in my life.

In one of the project, we were facing a weird and interesting issue in production.  The application server would get weird requests from the browser.  The weird thing about these request was that, the parts of the requested URL would be valid but, the end part would contain some weird html tags!  Since the resource would not be found on the server, app server would log the request and return a 404 error page.

For e.g. one such log message was:

The request that browser sent was:

The above URL is to fetch jquery.maskedinput.min.js file.  

Generally when an issue is reported by the QA/Client, I already have some idea as to what could have caused the issue.  But, this issue was special.  When I first saw these error, I was completely blank.  I had no idea what so ever why would something like this every happen!

We were using a pretty common Java stack.  Spring MVC and Hibernate, app was deployed on Weblogic server.  I had used these frameworks in so many other projects, but never ever faced an issue like this.

The most frighting part was, I had no idea what was the end user impact.  Was the user logged off?  Was he shown any error?  Did he see a garbled page?  No idea at all!

Coming back to the issue.

Yes believe it or not, the above request is to fetch the jquery masked input javascript! Notice that the beginning part of the URL is valid, but what gets added at the end is really not expected.

From where did

text get appended to the URL?

Digging a little deeper, I found something totally bizarre.  Turns out that the text

is present in the same page after some 4096 bytes!

How is it possible that something that comes after a few thousand bytes gets appended to the request URL of jquery.maskedinputments.min.js?

After two and half days of hard core googling, trying hundreds of different things with the script tag, the textarea tag, using different permutation combinations, and countless hours of analyzing the server logs over and over again, finally I have found a credible explanation to weird URL’s issue we were facing.

It happens because of a bug in IE8’s Lookahead Downloader.  The problem has nothing to do with the application!

What are you talking about?  Explain me in detail:

Following is an extract from this URL: http://blogs.msdn.com/b/ieinternals/archive/2009/07/27/bugs-in-the-ie8-lookahead-downloader.aspx which describes the bug in full detail.


Lookahead Downloader is used to quickly scan the page as it comes in, looking for the URLs of resources which will be needed later in the rendering of the page (specifically, JavaScript files). The lookahead downloader runs ahead of the main parser and is much simpler-- its sole job is to hunt for those resource urls and get requests into the network request queue as quickly as possible.

The problem here is that there are a number of tags which will cause the parser and lookahead downloader to restart scanning of the page from the beginning. One such tag is the META HTTP-EQUIV Content-Type tag which contains a CHARSET directive. Since the CHARSET specified in this tag defines what encoding is used for the page, the parser must restart to ensure that is parsing the bytes of the page in the encoding intended by the author. Unfortunately, IE8 has a bug where the restart of the parser may cause incorrect behaviour in the Lookahead downloader, depending on certain timing and network conditions.

The incorrect behavior occurs if your page contains a JavaScript URL which spans exactly the 4096th byte of the HTTP response. If such a URL is present, under certain timing conditions the lookahead downloader will attempt to download a malformed URL consisting of the part of the URL preceding the 4096th byte combined with whatever text follows the 8192nd byte, up to the next quotation mark.  Web developers encountering this problem will find that their logs contain requests for bogus URLs with long strings of URLEncoded HTML at the end.

Impact on the end user:

Generally this has no direct impact on the visitor's experience, because when the parser actually reaches a tag that requires a sub-download, if the speculative downloader has not already requested the proper resource, the main parser will at that time request download of the proper resource.  Hence,
  • The visitor will not notice any problems like script errors, etc
  • The visitor will have a slightly slower experience when rendering the page because the speculative requests all "miss"
  • IIS/Apache logs will note requests for non-existent or incorrect resources

The fix:

The fix is simple.  We needed to apply a IE8 Cumulative Update (KB980182) patch on the client machine’s which have this problem.

When I read this post, I was just stunned!  Problems like these truly blow your mind away!

Today, when I think about the problem, I realize that, its because of problems like these, I love being a Developer!

True developers, solve Real problems!

Sunday, December 26, 2010

How to tell GIT about a new remote SVN branch

If your GIT over SVN repository is setup up correctly, then you might not need to do anything mentioned in this post.  GIT can work with both Standard and Non-Standard SVN repositories.

If you have followed the instructions properly, any new remote SVN branch would be fetched by running the following command

But if your setup is different from the once mentioned in the earlier post then, continue reading ahead.

You are a cool developer/QA/BA (or simply a cool person), who uses GIT over SVN.  Someone created a new SVN branch.  You want to checkout this new SVN branch and do some commits on it.  But wait!  When you setup your GIT SVN repository this branch did not exist.  Hence, GIT does not know anything about this new remote branch!  How can you say,

Hey Mr. GIT, here is a new SVN branch.  Could you please start tracking it for me?

How do they do it?

Actually, turns out, its very simple.
  • Do some edit in the .git/config file
  • Do a git svn fetch of the new remote branch
  • Create a local branch pointing to the newly added remote branch
  • Start hacking the code on the new branch!
The key here is only the first step.  Without wasting anymore time lets dive into the solution.

Step - 1:

Open the "config" file in the .git directory in your favorite text editor. 

Lets say that the new SVN branch is called "branch1".  Its located at http://non-standard-repository.googlecode.com/svn/branches/module1/branch1  

Add the following entries to the .git/config file

Almost there!

If you do not feel comfortable editing the .git/config file manually then use the following commands to achieve the same effect

Step - 2:

The setup is done.  All we now need to do is execute the following command

This will get the version history from the "branch1" SVN branch into the local GIT repository. By now you should have a remote branch "branch1" created in your git repository

Step - 3:

Crete a local branch from the newly added remote branch is simpel enough

You are now all set to start hacking the code on the local_branch1!

Step - 4:

No explanations required here!

That's it!  With GIT there are always multiple ways of solving any problem!  Go GIT it!

Sunday, December 19, 2010

How to setup KDiff as the diff tool for GIT

The git diff command does a great job of showing what has changed.  But it shows this information on the command prompt.  Some people who are addicted to nice and pretty GUI's, might get bogged down because of this.

Do not worry you people, there is a nice GUI based option.  KDiff3 is the answer to this problem!  This post will show how easily we can integrate the KDiff3 tool with GIT.

KDiff3 had nice and easy GUI.  It does its job very well.  It might not be the prettiest but its extremely simple and intuitive to use.  +1 for KDiff3 from my side!

So how do we integrate KDiff3 with GIT?

How do they do it?

GIT can be integrated easily with any third party diff tools.  We will integrate GIT to with KDiff3.  The simple steps to follow are
  1. Download and install KDiff3 from here.
  2. GIT needs to know that KDiff3 should be used as the preferred diff/merge tool.  For this, we need to make a simple change in the .gitconfig file.  This file can be found under your home directory.
Lets look at the second step in more detail.  On a windows machine the .gitconfig file is found under C:\Users\<your user name>\ directory.  This path can also be referred via the shortcut ~ on the GIT prompt.

Open the .gitconfig file in your favorite text editor

It should look something like this

Add the following lines to the file

The path config property under the mergetool and difftool, should point to the installation path of KDiff3 tool on your machine.  The updated .gitconfig file should look somewhat like this


NOTE: please use forward slash "/" as the path separator even on windows machines.  Using back slash "\" will not work!

The above config tells GIT to use the KDiff3 tool as the external diff/merge tool.

All set!  Lights, Camera, Action!

Lets edit a few files in a GIT repository:

Lets view the difftool in action.

GIT will ask your permission to launch KDiff3 for viewing the test1.txt.
Once you exit the KDiff3 view of test1.txt, it will ask your permission to launch KDiff3 for test2.txt

Hitting enter will launch the KDiff3 again for viewing test2.txt
Basically, GIT will launch the KDiff3 for all the files that have changes since the last commit.

If you feel annoyed about GIT asking your permission for showing the KDiff3 for each changed file, use the following command

This command will launch the KDiff3 for each edited file, without any prompt!

To use KDiff as the merge tool use the following command

Hitting enter will launch the KDiff3 as the merge tool
KDiff3 shows nice GUI to do the merge easily.  It shows the original file on the leftmost window called "A" or "Base", local file in the middle called "B" or "Local" and remote file in the rightmost window called "C" or "Remote".

As you can see its pretty trivial to use KDiff3 as the external diff/merge tool with GIT.  Have fun with GIT!  Go GIT it!

Thursday, December 9, 2010

How to work on multiple streams of work with GIT over SVN

In the last few posts, I have mentioned several times that working on multiple streams of work using GIT is childs play.  In this post, lets actually look at the actual steps, to work on multiple streams of work.

Lets say that Deep is working on the next generation Math package.  He aims to write the next generation Factorial program (yea yea! I know, how hard could that be).  This program would be the highly optimized and best performing Factorial program ever!

He is currently on the master branch i.e. the default branch.

Lets start:

Deep starts of with the simplest solution first.  He writes the code to find the factorial of zero.  Here is what it looks like.

Deep decides that, he is at a logical point (the point at which all his tests are passing and code is in a good shape)

He has achieved the unthinkable, the factorial of Zero is found!  Wow! what a discovery!  Lets commit this change to GIT.

He moves on, adds more code to find the factorial value of 1.

Again, a logical point. Time to commit.

Next, he adds code to find the factorial of any given number

Thats quite some progress. Lets commit again.

At this point, Deep thinks, he has developed the ultimate algorithm to find factorial of any number! He decides to push his changes to SVN and make them public (so that other people can appreciate the awesome code!)

Pushing changes to SVN

World has one less problem to solve! Deep decides to take up another challenge, he decides to write the code for Fibonacci series!

He starts off in the simplest possible way. Fibonacci value of numbers less than 2 is 1.

Logical point, need to commit to GIT.

Turning point:

At this point, Deep's boss, comes over and tells Deep, you moron, dumb a**, @#$#, you don't know that, the Factorial of zero is not zero its 1!  Fix it! And fix it now!  Deep is all terrified!  He has to fix this goof up as soon as possible!  After the initial hysteria!  He says to him self Aal izz well!

Current git log looks like this:

As you can see there is one commit on the top, which is not yet pushed to SVN. He does not want to push the Fibonacci commit to SVN but still wants to fix the issue. He does not want to lose the Fibonacci change either!

Basically he wants to work on two things, Factorial bug fix and Fibonacci series!

GIT has awesome support for working on multiple streams of work! Let see how GIT enables Deep to deal with this situation.

How do they do it?

He decides to create a bug_fix local branch. This branch will have the code that points to the current code in the SVN repository. This branch will not have the Fibonacci commit. This is how its done

GIT log will show that this branch does not have the Fibonacci commit

This is because we have created the bug_fix branch to point to the current code in SVN.

Next, Deep fixes his goof-up like this

Committing,

Since boss wanted this fix checked-in asap, pushing to SVN

The GIT log will show that we have pushed only the bug fix to SVN

Boss is happy! The goof-up is fixed!

Back to work! Lets continue coding on the Fibonacci series. Remember? That code is still in the master local branch. Hence, to continue working on the Fibonacci series we need to switch to the master branch.

Before moving any further, lets get the latest from SVN

GIT log will show that, we have received the commit that fixed the goof-up, and the Fibonacci commit is placed right on top of it!

End result:
  • Boss is happy because Deep fixed the goof-up pretty fast
  • Deep is happy because he did not have to revert, patch or do any kind of circus to work on multiple streams of work!
  • World is happy because, optimized Factorial program is available :)
Thats all folks!  Is this example enough?  Do not waste any more time Go GIT it!
Have some Fun!