Skip to main content

Daniel

Go Search
Infusion Blogs - Beta
  

Other Blogs
There are no items in this list.
Links
There are no items in this list.
Infusion Blogs - Beta > Daniel
Quick RegExp Matching in Java
Quick, what does the following line of code print:
 
System.out.println("Hello, world!".matches("[a-z]+"));
 
The answer? false!
 
As I (tortuously) discovered, the matches() method interprets "[a-z]+" as "^[a-z]+$". In other words, unless the whole string is a match, we're out of luck. There, is of course, a way to circumvent this problem: use the Pattern class.
 
Pattern p = Pattern.compile("[a-z]+");
Matcher m = p.matcher("Hello, world!");
System.out.println(m.find()); // Prints "true"
Proxies, NTLM, and Java
Recently I was trying to read the contents of a URL from a computer that accessed the internet through a proxy. I discovered (via inspection of headers in LiveHTTPHeaders!) that the proxy was using NTLM for its auhtentication method. I searched (largely in vain) for how to deal with this, but eventually gave up and hacked it out myself. Here's my code, in case anyone else runs into the same problem:
 
public interface NTLMInfoRetriever {
    public static final int DOMAIN = 0;
    public static final int USER = 1;
    public static final int PASSWORD = 2;
 
    public List<String> getNTLMInfo();
}
 
public class NTLMAuthenticator {
    private NTLMInfoRetriever retriever;
 
    public NTLMAuthenticator(NTLMInfoRetriever r) {
        retriever = r;
    }
 
    public PasswordAuthentication getPasswordAuthentication() {
        List<String> userPwd = retriever.getNTLMInfo();
        return new PasswordAuthentication(
            userPwd.get(NTLMInfoRetriever.DOMAIN)+
            "\\"+userPwd.get(NTLMInfoRetriever.USER),
            userPwd.get(PASSWORD)
        );
    }
}
 
This interface and class provide an easy-to-use Authenticator for NTLM-based schemes. The getNTLMInfo() method can be implemented in whatever manner is easiest (with a Swing UI, using the console, from a file, etc.), so it's flexible as well. To use NTLM authentication with a proxy, the following lines must be added before any attempt to access a URL through the proxy:
 
// [host] and [port] must be replaced with the system-dependent values
System.getProperties().put("proxySet","true");
System.getProperties().put("proxyHost","[host]");
System.getProperties().put("proxyPort","[port]");
 
// Set our Authenticator as the default
// Assumes the current class implements NTLMInfoRetriever
Authenticator.setDefault(new NTLMAuthenticator(this));
 
One important feature to note is that before calling the getPasswordAuthentication() method of the default Authenticator, the JRE will attempt to use the credentials of the currently logged-in user; if those fail, our method will be invoked.
AJAX Performance Evaluation
Interesting article about analyzing the AJAX components of a web app for performance.
Browser Emulation for Fun and Profit (Part II)
In the first part of this tutorial, I went through a number of important concepts involved in browser emulation, including:
  1. The tools to use.
  2. How to determine a form's action.
  3. How to use that information to emulate a form submission.
  4. How to emulate cookie-based authentication.

In this part (which is, probably thankfully, much shorter than the last one,) I'm going to use the code we developed last time to actually access the real-time quote service available to registered E*Trade customers. Onward!

In order to access the real-time quote feature of the E*Trade Canada site, we need to follow the same steps we did last time, when trying to emulate the login process:

  • Determine what data is being sent with the form request
  • Mimc that request in our code
  • Parse the response appropriately

After logging into the E*Trade Canada site, we fire up Live HTTP Headers, enter in a desired quote, submit it, and observe the results:

Before

After

What does all this tell us? Just as before, we see what URL the form is acessing, how it is doing so, and what the content being posted is. We are now almost ready to use this information to properly emulate the real-time quote feature.

One wrinkle in this case is that while the form has a dropdown listing the available exchanges by using their full names, the data actually being passed identifies the selected exchange by a short-hand code (in this case "O" indicates teh NASDAQ exchange.) To properly account for this, we must inspect the form's source, and integrate the available options into our own code:

Source

With that done, we simply follow the process set forth in the first part of this tutorial for posting to a website (with the proper cookies attached):

// Prepare the request
string content = QUOTE_CONTENT.Replace(SYMBOL_PLACEHOLDER,symbol);
content = content.Replace(EXHANGE_PLACEHOLDER,exchange);

HttpWebRequest req = (HttpWebRequest)WebRequest.Create(QUOTE_HOST + QUOTE_PATH);
req.ContentType = FORM_CONTENT_TYPE;
req.Method = POST_METHOD;
req.ContentLength = content.Length;
req.CookieContainer = cookies;

// Send the request
StreamWriter sw = new StreamWriter(req.GetRequestStream());
sw.Write(content);
sw.Flush();
sw.Close();

The final step is reading the response, and parsing it for the desired data:

string responseContent = "";
using (HttpWebResponse res = req.GetResponse())
{
    using (StreamReader sr = new StreamReader(res.GetResponseStream()))
    {
        responseContent = sr.ReadToEnd();
    }
}

// Parse the response for the quote data
QuoteData qd = ParseQuoteData(responseContent.ToUpper(),symbol.ToUpper());

That's it! Any remaining difficulties in terms of using the real-time quote feature are confined to extracting the quote from the returned HTML, a process that is, though somewhat tedious, not altogether that difficult.

Complete code for the EtradeConnectionCanada class (along with the skeleton of a very simple WCF service that wraps it): EtradeService.zip

Some Cool Webkit Stuff
This article has a couple of interesting notes about the GTK+ port of Apple's WebKit HTML rendering module.
 
That it now passes Acid3 with 100% accuracy is pretty impressive, but that's not really what caught my eye. Rather, it was the link to WebKit's implementation of a novel CSS feature, called -webkit-gradient. It allows developers to specify the parameters for both linear and radial gradients, which are then automatically rendered. This obviates the need for any other server-side support, and makes these often annoying-to-implement artifacts a breeze to create.
Browser Emulation for Fun and Profit (Part I)
There are many websites in common use whose functionality would be useful to an application programmer. Unfortunately, a great many of them fail to provide a publicly accessible webservice that would grant the programmer the most convenient and expedient method of using functionality developed by others. That, however, doesn't mean we as programmers should give up. Rather, it simply means we must adapt. In order to utilize the services made available via the web, one must simply instruct a program to behave like a web browser.
 
For the most part, if a website is providing a service of some sort, then there is a good chance that it is being offered via a form of some kind. Thus all that we need to do is figure out what action the form takes on submission, and copy that in our own request. At that point, the response data sent back from the server, while (likely) not in convenient XML form, will still contain the information we need, so a little bit of simple parsing and our job is done.
 
The easiest way to figure out exactly what is being sent by the browser for a given form is the LiveHTTP Headers tool for FireFox. With it, you can get a live picture of every request and response header that is being sent and received by the browser. Once it's installed, we'll navigate to the desired form, and launch LHH.
 
For this example, we'll be trying to get access to the live quote service provided by E*Trade Canada. However, it's only available to members, so we first have to figure out how to properly submit the logon form, and furthermore we need to figure out how the site keeps track of our logged in status from request to request. In most cases (and E*Trade is no different, as we shall see,) the site will send a Set-Cookie header with the login successful response. Thus we must ensure that all our subsequent requests include that cookie. This is what my screen looks like right before I try to login:
 
Step 1
(Note that I have whited-out the userid and password; no need to compromise my security more than necessary.)
 
Now I click the Logon button, LHH will do the rest. Here are the results:
 
Step 2
 
The first line tells us that the actual request was to https://swww.canada.etrade.com/login.fcc (which indicates that E*Trade is using SiteMinder. No real consequence to us, but interesting anyway.) The next lines are the actual headers sent along, which tell us the following:
  1. The request was a POST
  2. The Content-type is (unsurprisingly) application/x-www-form-encoded
  3. The actual content passed in consisted of more than just the USERID and PASSWORD fields (as we can see in the last line.)

That's all we need to know for this part. We can now move over to our code, and start filling in the details of our initial HttpWebRequest object. First, we need to specify the correct URL, then specify that it should be a POST. We need to add the correct Content-type header, and finally, we need to set the correct data to send. The easiest way to handle the data string is to make a parameterized version into a constant, and then replace the userid and password parameters as necessary. This is what our code looks like so far:

public bool login(String userid, String password)
{
    // Setup the content string
    string content = LOGIN_CONTENT.Replace(USERID_PLACEHOLDER,userid);
    content = content.Replace(PASSWORD_PLACEHOLDER,password);

    // Setup the request
    HttpWebRequest req = (HttpWebRequest)WebRequest.Create(LOGIN_HOST + LOGIN_PATH);
    req.ContentType = FORM_CONTENT_TYPE;
    req.ContentLength = content.Length;
    req.Method = POST_METHOD;
    req.AllowAutoRedirect = false;   // We need to handle the redirect ourselves

We now have to examine the server's response to the initial login request, to see what happens:

Step 3

Looking at the headers, we learn a few things. The first is that we're being redirected (that's what 302 means.) Note the presence of the "Location" header, which tells us where our next destination is. Further, we see that there are two "Set-Cookie" headers. These hold the key to mimicing a browser's behaviour.

If we had not turned off auto-redirection for the request, then the .Net class would have happily followed the redirect to the next location without setting the cookies appropriately. Thus the server assumes our request is ill-formatted, and will boot us back to the beginning. Thus by handling the redirection ourselves, we can parse the headers correctly, and thus have the proper information in the subsequent request:

using (HttpWebResponse res = (HttpWebResponse)req.GetResponse())
{
    // Check if it's 302'ing us
    if (res.StatusCode == HttpStatusCode.Found)
    {
        string cookies = res.Headers.GetValues(SET_COOKIE_HEADER);
        foreach (string cookie in cookies)
            this.cookieCollection.Add(ParseCookie(cookie));
    }

The cookieCollection member is .Net CookieCollection object. HttpWebRequest objects have a property called CookieContainer of the same type, so once we populate our copy appropriately, we can use it with all of our subsequent requests to the site. In fact, we are now ready to follow the redirect:

string location = res.Headers.Get(LOCATION_HEADER);
req = (HttpWebRequest)WebRequest.Create(LOGIN_HOST + location);

// Set the cookie container
req.CookieContainer = this.CookieCollection;

// Getting the response submits the request
using (HttpWebResponse redirRes = (HttpWebResponse)req.GetResponse())
{
    // Get the cookies as above; note that if a cookie
    // is Added that already exists, then its value
    // will just be overwritten with the updated data
   
    // ... At this point, we'd check for login success, etc.

There are a number of interesting points here, but the most important is the use of the CookieContainer property; setting it ensures that the correct authentication information is sent to the server each time. Let us look at what that actually is:

Step 4

Once again, we can see exactly what is going on. The top headers are for the GET request for the page to which we were redirected. Though not visible (since they're off the screen,) the cookies set in the previous response are appended at the end of the "Cookie" header. In the response headers, we get the final cookie we need, the SMSESSION cookie.

Having verified our login information, SiteMinder generates a unique session id, and marks it in the DB as logged in. Thus every time we send that cookie, SiteMinder can verify its logged in status. Note also that the previous two SiteMinder cookies are set back to empty, to indicate the login process has come to an end.

This is the end of Part I of this tutorial. At this point, we have successfully filled in a login form, and followed the steps required to ensure that we can use a successful login to utilize otherwise inaccessible features of the site. In the next part, I'll go through an example of doing just that. Stay tuned!

Code: EtradeCon.zip

Improv - The Informal Performance

Last night, Infusion Improv Toronto had its first ever live performance in front of an audience. And it was fantastic. And I'm not just saying that because I'm part of it.

 

The show was invitation only, restricted to fellow Infusion employees, as well as those friends that the players felt would be the least judgmental. It was held in the back area of The Savannah Room, a quaint little bar near College & Spadina. My fellow actors and I arrived at 6, guests (including Alim Somani, with clients in tow,) began to trickle in at 6:30, and the performance officially kicked off just after 7.

 

Ben introduced the evening with his typical lightning-speed patter, explaining that the evening was about long-form improv, specifically "Harolds". After taking a moment to catch his breath, he introduced Improv Team Z, aka "Thundercats!" (Note the exclamation point. As Cecily pointed out before they started their show, it's an important part of their identity.) Cecily took the suggestion from the audience ("kindergarten",) and with that the Harold was off and running.

 

Thundercats! chose the "answering machine" opening, so Cecily spoke the answering machine greeting of two distraught parents whose child had gone to kindergarten for the first time that day. Those who left messages for the couple included "little Bobby" himself, Michael Jackson's bodyguard, concerned citizens who noticed Bobby entering a "strange man's van" and other associated characters. The ideation was very strong, and it easily carried the group through their performance. Once a caller finally came back to a kindergarten oriented message, the opening gave way to the scene-work.

 

In the scenes themselves, each group member played to their strengths, and consequently the Harold was spectacular. In the first pairing, Irene made good use of her prodigious vocal and characterization talents, while her scene partner, Cecily, couched her often disturbing (and thus hilarious) lines in her usual matter-of-fact manner.

 

Andrew, as is generally the case, had zinger after zinger in his scenes with Andrea (which one again related to sex, porn et al.) Andrea provided the perfect complement to Andrew's style with her magnificently flamboyant and visceral reactions to his chicanery. The opening of their second scene, time-dashed to the point where they were in bed enjoying a post-coital smoke, was pure comedic genius.

 

Finally, Ricky and Nadeem played out a situation that has gone through many a California parent's mind: what happens when Michael Jackson "entertains" children? Ricky played the one-gloved wonder with an innocence that made his untoward advances on wide-eyed child Nadeem seem all the creepier. Nadeem's choice to reinforce the small stature of the child by literally kneeing his way around the stage was inspired.

 

The between-beat group scenes both went similarly: a chaotic beginning slowly but surely gave way to a coherent (and ultimately humourous) end. Can't ask for too much more. As well, the convergence of the three scenes in the third beat could not have gone better had it been scripted: The witless parents stumbling upon their one child being abused mentally by the seemingly inoccuous Cecily while their other child is physically abused by an ever-smiling Michael Jackson was something to behold.

 

In accordance with the quality of the performance, the audience (myself included) laughed throughout, and applauded mightily when the show was called.

 

At that point, there was a brief intermission, wherein I became nervous for the first time. Up until then, I hadn't worried about going up on stage; unfortunatley, Thundercats! had set the bar very high indeed, and I knew that my team, Macrohard, would have our work cut out for us. That worry disappeared quickly, however, as Devon's hilarious greeting message set the tone for what I firmly believe was our team's best performance by far.

 

The suggestion from the crowd was "pirates" (initially misheard as "pomegranates",) and the ideas were numerous: non-pirate-like dates for a wedding, a dog humping a peg-leg, costumes for Halloween. We set ourselves up really well in the opening, which allowed our subsequent scene-work to flow freely.

 

In the first pairing, Devon and Quinn were fretting about wedding plans, dates, and dogs. Their back-and-forth banter was spell-binding, as each one took turns thinking about the absurdities that could arise. The presence of Pookie the dog (possibly the Poodle?) was a key touch that informed the rest of their interplay.

 

Next, we met two pirate shipmates (Andrea and Amy) who were so hungry they decided it made sense to eat the pigeon which had fallen from the sky to their deck. In the following beat, it was a hapless (though generous!) dolphin that provided the best moments of comedy in the show. (If you haven't witnessed what happens when a deceased dolphin proffers you its liver, you haven't lived.)

 

Finally, Darren introduced us to a man who may have contracted a rare disease in Hong Kong, while Eric tried to avoid being used as Darren's towel. Midway through the scene, I entered as a Pirate from Hong Kong who holds the map that may lead to the answer to the Darren's problem. That quest, however, was eventually side-tracked by the discovery of my sister's underwear in Eric's pocket, and the revelation that Eric and Darren enjoyed the culture of NYC's gay bars. Did not see that one coming.

 

I felt the third-beat scene tied the stories together very nicely, with me confronting my sister (whose wedding it was), falling for her friend, and my former shipmates coming by trying to sell dolphin meat (I think) door to door. The audience seemed appreciative of our efforts, for which I was grateful.

 

In general, I am completely convinced that both groups performed their best work ever at the show. While the Harolds done in class have gone well, I don't think any of them approached the coherence and comedy that were on display last night. I'm very much looking forward to our public performance at Diesel. I can't wait to see how much better again we get!

Welcome!
What I hope to cover on this blog: Things at <client> that make you go "hmm...", cool new Java stuff (I'm working on a post about Seam,) legal issues (for example, did you know that the US Supreme Court recently issued rulings that could call into question the validity of all software patents?) and, should it get off the ground, updates about Infusion's entry in the Netflix Prize. Stay tuned!

 The Blogger in Question

 ‭(Hidden)‬ Admin Links