Getting to Know Fiddler: Part VI: Use FiddlerScript to identify common problems
Our tour of Fiddler has covered a lot of ground so far, and while there's still more to cover, I'm going to have to let you in on a secret before we can continue. The UI is definitely powerful, but here's the thing: it's not the killer feature. The real killer feature is FiddlerScript.
Getting Started
Fiddler already detects invalid requests and broken responses. What more could we possibly add, you might ask. We have the benefit of domain knowledge. We know the quirks of the systems we deal with. Two such bits of domain knowledge:
- An HTTP status isn't the only thing that can indicate a failure; an unexpected response body can also indicate failure.
- If a failure occurs, the response body could help us automate a diagnosis.
In this case, we're going to look at some FiddlerScript that helps me with an API that I use. For certain calls, a server error will return a 200 response code and a body of “null”.1 For most failures it will return a status of 500, and a failure code that starts with a ‘#’ and is then followed by five hex digits.
FiddlerScript
Before we start, there's one thing we need to do: let's install the Syntax-Highlighting Add-Ons bundle from Telerik.
After installing our new plugin you'll notice a FiddlerScript tab. If you open it, you'll see the contents of the default “CustomRules.js”. Take a minute to look around.
The first thing worth noticing is that FiddlerScript is written in JScript.NET. If you don't know JScript, no need to be concerned: most of it's syntax looks to be derivite of the C family of languages, so we can make safe assumptions about syntax and behavior most of the time.
As you scan the file you'll likely see a number of static functions, including OnBeforeRequest, and OnBeforeResponse. These two are called, not surprisingly, before the request is sent to the server, and before it is passed back to the client, and they're called with a Session object named oSession. Look at what is available off of oSession by typing “oSession.” and then pressing CTRL-Space.
Identifying Errors
In order to examine the response, we'll be adding our code directly into the existing OnBeforeResponse. To start with we'll just try to format every request to be white text on a red background. Make sure to press “Save Script” at the top of the page after you're done editing: CTRL-S does not work.
static function OnBeforeResponse(oSession: Session) {
...
oSession["ui-color"] = "white";
oSession["ui-backcolor"] = "red";
}
The next page load should give us what appears to be a page of really bad errors. For once, that's exactly what I wanted to see. In general that's a bit useless though; let's update the code so that only happens when one of the responses contains “null”.
So, where do we start? In FiddlerScript most things start and end with a Session object. If you look at the autocompletion off of oSession again, you should find oSession.GetResponseBodyAsString(), a method that gives us the entire response as a string. Now we should be able to compare it to the text “null”. If it is null then and only then will we change the highlighting.
static function OnBeforeResponse(oSession: Session) {
...
if (oSession.GetResponseBodyAsString().Equals("null")) {
oSession["ui-color"] = "white";
oSession["ui-backcolor"] = "red";
}
}
Let's try it out with a simple echo service: Null and [Not Null](http://urlecho.appspot.com/echo?status=200&Content-Type=text%2Fhtml&body=not null). The first link should be colored, the second should not.
It works, so technically we're done. Personally though, I suggest we take just another moment to clean up our code, as to save our future selves.
static function OnBeforeResponse(oSession: Session) {
...
if (IsSessionError(oSession)) {
SetErrorHighlight(oSession);
}
}
static function IsSessionError(oSession: Session) {
return oSession.GetResponseBodyAsString().Equals("null");
}
static function SetErrorHighlight(oSession: Session) {
oSession["ui-color"] = "white";
oSession["ui-backcolor"] = "red";
}
Finding Error Codes
With the highlighting behind us, we've only got one more task in front of us: identifying error codes in responses. So, how are we going to do that and where are we going to display the results?
Well, most of the code will be very similar to the code we wrote for our last exercise. We'll be searching a plain string to see if we can find a pattern. That's all well and good, but we've neglected to mention where the results will be stored. Ah. Good point.
If you take a look at the columns in the left pane, you should see a column named “Custom”. Here we can place any data that we like. Let's try that now. In much the same way that we changed the coloring in the previous section, we'll populate the “Custom” column here. I recommend moving the column to be closer to the more used columns on the left.
static function OnBeforeResponse(oSession: Session) {
...
oSession["ui-customcolumn"] = "Hello World";
}
At this point, every request should have the value “Hello World” in the Custom column.
Great! Most of the work will be done with regexs. We can check for a match by calling test off of a regex, and we can get the matched portion of a string by calling match off of the string. The regex for our particular error code format is /#[0-9A-F]{5}[^0-9A-F]/i. Since this post isn't about regular expressions, I'll avoid going into any further detail on them.
static var gs_errorCodeRegexp = /#[0-9A-F]{5}[^0-9A-F]/i;
static function OnBeforeResponse(oSession: Session) {
...
if (gs_errorCodeRegexp.test(oSession.GetResponseBodyAsString())) {
oSession["ui-customcolumn"] = oSession.GetResponseBodyAsString().match(gs_errorCodeRegexp);
}
}
Adding the above bit of code to our OnBeforeResponse causes error codes to be copied to our custom column, if an error code is present. Let's try it: Error Page.
While it would work like this, once again I'd prefer to clean it up just a bit for maintainability.
static var gs_errorCodeRegexp = /#[0-9A-F]{5}[^0-9A-F]/i;
static function OnBeforeResponse(oSession: Session) {
...
if (ContainsErrorCode(oSession.GetResponseBodyAsString())) {
DisplayErrorCode(oSession);
}
}
static function ContainsErrorCode(sResponseBody: String) {
return gs_errorCodeRegexp.test(sResponseBody);
}
static function DisplayErrorCode(oSession: Session) {
oSession["ui-customcolumn"] = GetErrorCode(oSession.GetResponseBodyAsString());
}
static function GetErrorCode(sResponseBody: String) {
return sResponseBody.match(gs_errorCodeRegexp);
}
And there you have it: the start of the possibilities that FiddlerScript provides us. Speaking from experience, these scripts can save, and indeed have saved much time while debugging systems. 2
Footnotes
“The API returns a 200 for some errors?! It should return a 5xx!” Yes, it should, but it doesn't. Until it does, I'd like those failures not to silently masquerade as successes. ↩︎
Today even. I started to debug an issue where things just wouldn't work only to notice a giant red block. 200 null. Yup. Web API failed. That would do it. ↩︎