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

Improving project documentation with a codesprint

Background  At the end of November I was asked by Francois Prunayre at Titellus to help organise and manage a 3-day code-sprint with the aim of improving GeoNetwork documentation . Documentation can be problematic for projects, even open source, where the majority of the work is done by volunteers. Updating documentation is rarely a priority for developers, who are time-poor and have actual project issues to deal with, and efforts to widen the base of contributors so that others can help, also take time. Back to the code-sprint This code-sprint was timed very well though, as it comes on the back of work being done to update GeoNetwork documentation as part of OSGeo's participation in Google's Season of Docs . This pairs a paid technical writer with an open source project for either three or six months, with the aim of seeing a rapid improvement in that project's documentation. I'm an admin and mentor for OSGeo on Season of Docs, so was well-placed to provide inp...

Astun Technology Announced as Approved Supplier on G-Cloud 12

Switching to Cloud GIS with Astun Technology just got easier! Astun Technology are delighted to announce that they have been awarded status as a Crown Commercial Service (CCS) Approved  Supplier on the latest G-Cloud 12 framework and that our award winning GIS software and services will continue to be available via the Government’s Digital Marketplace . Astun have been an Approved Supplier on the G-cloud since 2013. The cloud hosted and managed GIS solutions available from Astun on G-Cloud 12 free users from the costs and complexity of managing Geographic Information infrastructure (software, servers, networks, bandwidth) allowing GI managers and analysts to focus on delivering Geographic Intelligence to staff and stakeholders. The G-Cloud 12 framework itself makes buying cloud solutions and services faster and cheaper than entering into individual procurement contracts, so switching to Cloud based GIS has just got easier! For G-Cloud 12 , Astun have added a number of new options ...

Reflections on the Amazon Web Services Summit, 2018

Last month, a handful of us from 'operations' attended the AWS Summit to keep up to date with what is going on in the Amazon Web Services world.  We've shared our reflections in this Blog and linked through to videos or slides of the sessions where we can. What is the AWS Summit? Amazon run a series of global events in major cities around the world getting to each one every couple of years; 2018 was London's turn. Amazon Web Services (AWS) is a cloud hosted computing platform, that Astun use for pretty much everything.  Our own cloud products and services such as iShare in the Cloud, Astun Data Services, Geonetwork / INSPIRE are all hosted there.  Even if what you use from us is exclusively deployed on your own premises, all of software development and most of our internal IT is done in the AWS environment.  It is critical to our business.  If you think that we are putting all our eggs in one basket, it is worth remembering that AWS is a $22 billion p.a. ...