Forum Discussion

Ben_9010's avatar
Ben_9010
Icon for Nimbostratus rankNimbostratus
Jan 12, 2018

iRule ReWrite - Inserting JSON Parameter into Request + Removing Same JSON Parameter from Response

Looking to leverage an iRule to Dynamically insert a JSON Parameter into an HTTP payload and then scrub it in the response back to the client.

 

However, we want to inspect the Payload and only perform this action when a specific JSON Parameter value exsits.

 

Example:

 

When JSON Key/Value of "Animal": "Dog" exists, Dynamically insert new Parameter of "Color": "Brown".

 

The server(pool member) would see this new parameter and act on it, but in the HTTP response to the client, the new parameter is not in the payload.

 

Do iRules know how to handle and work with JSON specifically?

 

Is an LX iRule going to be need to do this advanced rewrite?

 

Thanks!

 

4 Replies

  • Yes, iRules LX would be a good option as it can handle JSON objects natively.

     

    Here's a sample code. It adds the key-value {"newKey":"new"} to the request data (POST), and removed the key "aoc" from the response body. This is just a skeleton code. You can add any conditions you want (such as checking the presence of a certain key etc).

     

    iRule part

     

    when HTTP_REQUEST {
      set RPC_HANDLE [ILX::init RemoveKeyPlugin RemoveKeyExt]
    
      if { [HTTP::method] eq "POST"} {
        HTTP::collect [HTTP::header "Content-Length"]
      }
    }
    
    when HTTP_REQUEST_DATA {
      set payload [HTTP::payload]
      set req [ILX::call $RPC_HANDLE req $payload]
      log local0. "$payload > $req"
      HTTP::payload replace 0 [HTTP::header "Content-Length"] $req
    }
    
    when HTTP_RESPONSE {
        HTTP::collect [HTTP::header "Content-Length"]
    }
    
    when HTTP_RESPONSE_DATA {
      set payload [HTTP::payload]
      set res [ILX::call $RPC_HANDLE res $payload]
      log local0. "$payload > $res"
      HTTP::payload replace 0 [HTTP::header "Content-Length"] $res
    }

    Node (extension) part

     

    var f5 = require('f5-nodejs');
    var ilx = new f5.ILXServer();
    
    var parser = function(str) {
      var json = {"error":"unable to parse"};
      try {
        json = JSON.parse(str);
      }
      catch(e) {
        console.log('Got non-Json data: ' + e + ' >>> ' + str);
      }
      return json;
    }
    
    // Adding an entry
    var addEntry = function(req, res) {
      var json = parser(req.params()[0]);
      json['newKey'] = 'new';      // Adding a new entry
      res.reply(JSON.stringify(json));
    };
    
    // Removing an entry
    var removeEntry = function(req, res) {
      var json = parser(req.params()[0]);
      delete json['aoc'];
      res.reply(JSON.stringify(json));
    }
    
    ilx.addMethod('req', addEntry);
    ilx.addMethod('res', removeEntry);
    ilx.listen();

    Example output

     

    Jul 17 16:59:04 ltm1310 info tmm[17714]: Rule /Common/RemoveKeyPlugin/RemoveKeyRule : {"hello":"world"} > {"hello":"world","newKey":"new"}
    Jul 17 16:59:04 ltm1310 info tmm[17714]: Rule /Common/RemoveKeyPlugin/RemoveKeyRule : {   "name":"Chateau Mouton Rothchild",   "aoc":"Pauillac",   "year":1978 }  > {"name":"Chateau Mouton Rothchild","year":1978}
  • iRules LX comes with two flavour. One is RPC style as above. It uses both iRules (TCL) and node. The other one is Streaming. It's pure Node without TCL, which became available from v13.0.

    Here's a Streaming example. The specification is same as the RPC one.

    var f5 = require('f5-nodejs');
    var plugin = new f5.ILXPlugin();
    
    
    // string to json parser (same as RPC version)
    var parser = function(str) {
      var json = {"error":"unable to parse"};
      try {
        json = JSON.parse(str);
      }
      catch(e) {
        console.log('Got non-Json data: ' + e + ' >>> ' + str);
      }
      return json;
    }
    
    
    // Reading buffer and return string
    var readMe = function(ilxTransaction) {
      var chunk = [];
      while(true) {
        var buffer = ilxTransaction.read();
        if (buffer !== null) {
          chunk.push(buffer);
        }
        else {
          break;
        }
      }
      return chunk.join('').toString() || '{"error":"no data"}';
    }
    
    
    // Main loop
    plugin.on('connect', function(flow) {
    
      // Started to receive client POST data
      var postData = '';
      flow.client.on('readable', function(req) {
        postData = readMe(flow.client);
      });
      
      // Got all the client POST data. Send it over to poolMember
      flow.client.on('requestComplete', function(req) {
        console.log('client req (POST): ' + postData);
        var postDataJson = parser(postData);
        postDataJson['newKey'] = 'new';
        console.log('req to poolmember: ' + JSON.stringify(postDataJson));
        flow.server.write(JSON.stringify(postDataJson));
        req.complete();
        console.log('res done');
      });
      
      // Started to receive poolMember body
      var body = '';
      flow.server.on('readable', function(res) {
        body = readMe(flow.server);
      });
      
      // Got all the server data. Push it to client
      flow.server.on('responseComplete', function(res) {
        console.log('server res (body): ' + body);
        var bodyJson = parser(body);
        delete bodyJson['aoc'];
        console.log('res to client: ' + JSON.stringify(bodyJson));
        flow.client.write(JSON.stringify(bodyJson));
        res.complete();
      });
    
      // Error notification
      flow.client.on('error', function(errorText) {
        console.log("client error event: " + errorText);
      });
      flow.server.on('error', function(errorText) {
        console.log("server error event: " + errorText);
      });
      flow.on("error", function(errorText) {
        console.log("flow error event: " + errorText);
      });
    
    });
      
    var options = new f5.ILXPluginOptions();
    // No specific option here
    plugin.start(options);
    
    • DanSchell's avatar
      DanSchell
      Icon for Nimbostratus rankNimbostratus

      Hi Satoshi,

      that means the pure stream example does not need the iRule part, only the XL Workspace js extension?

      • Satoshi_Toyosa1's avatar
        Satoshi_Toyosa1
        Icon for Employee rankEmployee

        Yes, iRules LX Streaming does not require iRules. Instead, you create the profile from the plugin, and attach it to the virtual.