Skip to main content

Using Fiddler to mock web responses

Introduction

I recently had a need to debug an issue that a customer was having, but it seemed as though it was related to their data. I had two options, take a copy of their data and configuration files and set them up in my development environment, or find another way.

"The Other Way"

What I really needed to be able to do was to return specific responses to certain requests, but allow other requests to go through unhindered, thus spoofing the client into believing I had the customer's data set up. That's when I remembered that Telerik Fiddler can be used as a proxy and has something called an AutoResponder which sounds like it could do what I wanted.

AutoResponder


The way the AutoResponder works is by matching the URL with a known string, and then performing an action if it matches (see the AutoResponder documentation for more info). This could be as simple as returning the response from a file, setting a header, or performing a redirect. The benefit to this is that it's very easy to set up, but unfortunately for me, it wasn't the solution I needed. The AutoResponder is ideal for data which can be returned verbatim (XML, JSON), but the data I was working with (JSONP) meant I needed to modify the response before it was sent back to the client, and I couldn't see a way to get the AutoResponder to do this (jQuery gives each JSONP request a dynamic function name to use, and waits for that function to be called when the response arrives).

FiddlerScript

So I started investigating FiddlerScript which, as it's name suggests, is Fiddler's scripting language. The FiddlerScript documentation is a bit sparse, but luckily the in-built editor has autocompletion which makes things a bit easier. The language is basically JavaScript which means it should be fairly easy to pick up, but it's based on JScript.NET which may or may not have some of the more advanced JavaScript features, so I found it best to stick to the tried and tested methods. The way FiddlerScript works is that there are several functions which are called at certain times during the request (like events), and we can add code to those functions to do what we need at the right time.

OnBeforeRequest

In this function, you can modify the request before the server sees it, so things like adding a request header, modifying the request data etc. can all be done here. You cannot modify the response as at this point, the server hasn't seen the request, so the response hasn't been generated yet.

OnBeforeResponse

This function happens after the server has seen the request and then generated the response for the client. This is where you need to put your code if you want to modify the data going back to the client (as I did). You can modify the original request, but as the server has already processed it, it will make no difference.

The Solution

The way I accomplished this was to add the following code to the OnBeforeResponse function, which retrieves the function name from the request object, then appends that to the specially crafted contents of a file on disk, then allow that to be returned to the client.

The way I accomplished this was to add the following code to the OnBeforeResponse function, which retrieves the function name from the request object, then appends that to the specially crafted contents of a file on disk, then allow that to be returned to the client.

The Code

if (oSession.uriContains('Layers=some_council_data')) {
    var data = File.ReadAllText("C:\\somedata.json");
    var url = oSession.fullUrl;
    var found = url.match(/jQuery\d{1,}_\d{1,}/i);
    if (found) {
        oSession.responseCode = 200;
        oSession.oResponse["Content-Type"] = 'application/json';
        oSession.utilSetResponseBody(data.replace(/\*\*id\*\*/gi, found[0]));
    }
}

The Original Data

jQuery164022858497596061111_1518526135138([
   {
      "type":"FeatureCollection",
      "features":[
         {
            "type":"Feature",
            "id":"1",
            "geometry":{
               "type":"Polygon",
               "coordinates":[
                  [ 389161.500000, 284626.300000 ],
                  [ 389161.500000, 286392.800000 ],
                  [ 392691.300000, 286392.800000 ],
                  [ 392691.300000, 284626.300000 ],
                  [ 389161.500000, 284626.300000 ]
               ]
            },
            "properties":{
               "fields":{ "Ward_Name_and_Councillor_Link":"Amber Nectar Ward" },
               "links":{ "Ward_Name_and_Councillor_Link":"http://councillors.acouncil.gov.uk/borough-wards/ambernectar" },
               "html":"<div class=\"infoResult\"> <p> <strong>Ward Name and Councillor Link:</strong> <strong><a title=\"Click here to go to the related web page\" target=\"_top\" href=\"http://councillors.acouncil.gov.uk/borough-wards/ambernectar\">Amber Nectar Ward</a></strong> </p> </div>"
            }
         }
      ],
      "properties":{
         "layer":"Electoral Wards",
         "layerName":"wards",
         "uniqueField":"",
         "uniqueFieldSelected":false,
         "htmlHeader":"<div class=\"contentDisplay popup-Electoral-Wards\"><h3>Electoral Wards</h3>",
         "htmlFooter":"</div>"
      }
   }
]);

The Modified Data

**id**([
   {
      "type":"FeatureCollection",
      "features":[
         {
            "type":"Feature",
            "id":"1",
            "geometry":{
               "type":"Polygon",
               "coordinates":[
                  [ 389161.500000, 284626.300000 ],
                  [ 389161.500000, 286392.800000 ],
                  [ 392691.300000, 286392.800000 ],
                  [ 392691.300000, 284626.300000 ],
                  [ 389161.500000, 284626.300000 ]
               ]
            },
            "properties":{
               "fields":{ "Ward_Name_and_Councillor_Link":"Amber Nectar Ward" },
               "links":{ "Ward_Name_and_Councillor_Link":"http://councillors.acouncil.gov.uk/borough-wards/ambernectar" },
               "html":"<div class=\"infoResult\"> <p> <strong>Ward Name and Councillor Link:</strong> <strong><a title=\"Click here to go to the related web page\" target=\"_top\" href=\"http://councillors.acouncil.gov.uk/borough-wards/ambernectar\">Amber Nectar Ward</a></strong> </p> </div>"
            }
         }
      ],
      "properties":{
         "layer":"Electoral Wards",
         "layerName":"wards",
         "uniqueField":"",
         "uniqueFieldSelected":false,
         "htmlHeader":"<div class=\"contentDisplay popup-Electoral-Wards\"><h3>Electoral Wards</h3>",
         "htmlFooter":"</div>"
      }
   }
]);

Conclusion

The result is that when the request is made by the client that matches the criteria, it loads the file from disk, replaces the ID in the file data, and then returns the response to the client. You can see this response as shown in the Chrome Developer Tools network tab below.



Comments

Popular posts from this blog

QGIS 3.0: the time has come...

QGIS 3.0 was released in February, and although it's labelled an 'early adopter' release, with the long term release (LTR) available in October, there's plenty in it to excite not just the early adopters, but the rest of us too. We've had a chance now to have a good look at it, kick the tyres a bit and see what everyone has to say about it, so here are our thoughts.

There are a few big steps forward - for example 3D support and multiple map canvasses - and while many of the other changes are relatively minor on their own, put together they represent a major leap in usability and effectiveness. There's been work on consolidation, upgrades of core packages, efficiency and speed improvements, resulting in a slicker, easier to use and more tightly integrated application.

You could say that the 'easier to use' bit is the best thing about QGIS 3.0 - and when you think about it, that's not a description that could be applied to most application upgrades or…

FOSS4GUK 2018 Musings

A look back at FOSS4GUK 2018


Dan The whole event was great and I'm really glad I managed to go.  One person I was chatting to during one of the coffee breaks told me they were just so struck by what a friendly event it was compared to conferences they had attended - and I couldn't agree more! For me though, that manifested itself in the open and transparent way that the speakers and delegates shared their knowledge and expertise, with a real willingness to help others.  It really brings it home that the thing that is as amazing as the technology aspect of FOSS, is the real community of people who are working on it and with it.

In terms of talks and workshops (aside from all the fantastic Astun-led sessions 😊 which were great), other highlights for me were the sessions by Ross McDonald (@mixedbredie) and Tom Armitage (@MapNav_Tom), both of whom did great workshops and presentations around routing and cartographic visualisation; I used our QGIS in the Cloud environment for bot…

Astun Conference 2018

In late September and October Astun hosted two regional conferences in Bristol and Leeds. In the current environment it isn’t easy to persuade people in Local and Central Government to take a day out of their schedules and travel to to a conference, so getting over 70 delegates over the two days was a strong indication of the value that Astun brings to its clients. After a brief welcome from Steven Feldman (Bristol) or Dan Ormsby (Leeds) Mike Saunt, Astun’s founder and MD, gave a keynote entitled “Much ado about Mapping” Mike talked about Astun as a passionate company, passionate about geo, passionate about open, passionate about the cloud and fanatical about support. He ran through the way Astun’s offer had evolved in the last year with new features, an improved user experience, simplified administration, more automation of cloud deployment and most importantly major investments in testing, quality enhancement and reducing technical debt. Then Mike moved on to the direction of travel for…