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

Wychavon District, Malvern Hills District, and Worcester City councils sponsor improvements to the Gemini metadata plugin for Geonetwork

Astun have been working with Wychavon District, Malvern Hills District and Worcester City councils on some improvements to the Gemini 2.2 Metadata Plugin for Geonetwork.

The councils approached us at one of our User Group events in 2018 for some assistance with their joint data and metadata publishing workflow. In this workflow, data is published as WMS and WFS using Geoserver. Metadata in the WMS and WFS responses are harvested by Geonetwork to create metadata records, which are then published to data.gov.uk. The goal was to create fully valid Gemini 2.2 metadata directly from Geoserver, without the need for editing the records in Geonetwork. We worked with the councils to establish that the Geoserver INSPIRE plugin and built-in metadata tools met most of that requirement, but that some elements were either incorrectly added or missing entirely when the metadata was harvested into Geonetwork.

Astun have enhanced the Gemini 2.2 metadata plugin for Geonetwork to improve it's WMS an…

FOSS4G UK Edinburgh 2019

This year, Astun staff are giving 4 presentations and 1 workshop at FOSS4G UK Edinburgh to share with the community what we are passionate about as individuals, and as an organisation. At Astun we believe that we are the 'Experts in Place', but to live up to this claim we must do everything but stay 'in place' by constantly evolving what works, and revolutionising what doesn't. With that in mind, here's a preview of the presentations we're giving next month:
Matt Walker; OpenLayers Workshop The OpenLayers (OL) Workshop will guide attendees through the official Workshop material, providing a comprehensive overview of OL as a web mapping solution. The workshop format follows a series of modules covering everything from the basics of creating an OL map, through to specific functionality such as handling vector data, and building content for consumption on mobile devices.

We will work through as many of these modules as we have time for! The workshop material is…

Reflections on FOSS4G UK Edinburgh 2019

Six members of the Astun team recently headed en mass to the Free and Open Source Software for Geo (FOSS4G) UK conference in Edinburgh - and we came back with a 7th!

FOSS4G is a great forum to find out all the latest on what is going on in the OSGeo community and to spread the word via talks and workshops about some of the exciting work we’ve been involved in. Check out the post to find out about our own personal reflections of the event … and find out who our latest recruit is in the final post!

Dan The FOSS4G UK conference just seems to get better and better each year, and this year was no exception. As the baton gets passed annually to a new organising team, the advice and guidance on running a great event goes with it. This year’s team led by co-chairs Tom Armitage and Ross McDonald did an amazing job. The venue was breathtaking, the agenda was packed with outstanding talks and workshops and the atmosphere both during the day and in the evening social just had a great buzz to it. …