The JavaScript response filter is the most flexible of all HTTP response filters. It can potentially be called for any response, and can modify traffic in any way it sees fit.
Optional. Specifies for which URL(s) the filter should be executed. This does not include the protocol, host and port number. If specified, it can be either:
a URL as a string for which this filter should get executed. For instance: /rest/state
a regular expression (starting with regex: ) that matches the URL. For instance: regex:/rest/state/[0-9]+
Optional. If specified, the HTTP method (e.g. GET, POST, PUT, etc...) for which this filter should get executed. If not specified, all methods will match.
Optional. If specified, a comma-separated (or line-break separated) list of IP4 or IP6 addresses or regular expressions for IP addresses. If specified, only requests from matching IP addresses will cause the execution of the filter. For example:
201.43.1.33, 88.49.9.199, regex:88\.48\.23\.\d{1,3}
0:0:0:0:0:0:0:1, regex:2600:1700:6270:6aa0:51:92ca:\d+:\d+
Optional. If specified, a newline-separated list of header specifications which must match the response's headers. The name of the header is a simple string (case-insensitive), followed by a colon, and a regular expression for the header value. For instance:
Content-type: ((application/json)|(text/json))
If more than one pattern is specified (separated by line breaks), then the filter will be executed if at least one of the patterns matches at least one of the headers in the response.
Optional. If specified, this filter will be invoked only if the response's HTTP status code matches one of the patterns specified. Examples:
200
200, 201, 202
regex:20\d
A regular expression that must match the body of the response. This is only valid for text responses, and for request methods that can contain a body, normally POST, PUT, and PATCH. If the response's body is not text, this parameter should not be set.
For example, if the body of a response contains the following:
[
{
"color": "red",
"value": "#f00"
},
{
"color": "green",
"value": "#0f0"
}
]
then any of the following regular expressions would match:
\[.*green.*\]
.*"color": "red".*
A common use for this type of response filter is to translate URLs in JSON responses in one go, so that they point to the Gallium Data instance rather than to the HTTP server. This is easily done with:
let payload = context.response.payloadString;
context.response.payloadString = payload.replaceAll("http://myserver:8080", "http://myproxy:8079");
if (context.response.responseCode === 404) {
context.response.responseCode = 200;
context.response.payloadString = "<html><body>Sorry, this URL does not exist: " +
context.request.url + "</html></body>";
}
Setting a header's value to null removes it.
context.response.setResponseHeader("X-Content-Type-Options", null);
In this example, we'll create a response filter to modify a specific HTML response.
The filter must be set to execute only for the right response, so we might set the parameters to something like:
URL pattern: /ui/login.html
Method: GET
Header patterns: Content-type:text/html
The code for the filter can then be:
// Replace a specific string in the HTML code
let p = context.response.payloadString
p = p.replaceAll("Password not allowed", "Gallium Data says Hello!");
// Insert a bit of code in the page after a specific button
let lookFor = "Log In</button>";
let idx = p.search(new RegExp(lookFor, 'g'));
if (idx > 0) {
let helloButton = `<button type="button" class="btn btn-block"
style="background-color: red; color: white;"
onclick="alert('Welcome to Gallium Data!')">Click me!</button>`;
context.response.payloadString = p.substring(0, idx + lookFor.length) +
helloButton + p.substring(idx + lookFor.length);
}
You can do this with HTML, JavaScript, CSS, etc... but be careful! It's easy to break an application by modifying something you did not expect.
Of course, you can just turn off the filter to get back to the normal behavior.
In this example, we'll set a response filter that will read an image as it come from the server, overlay some text on the image using Java's ImageIO library, and send the result to the client.
First, the filter must be set so that it gets executed only for actual images and not anything else. For instance, we might set the parameters to:
URL pattern: regex:.*/images/.*\.png
Method: GET
Header patterns: Content-type:image/png
With that in place, we can then change the image with:
// Important to let Java know that there is no UI
let System = Java.type("java.lang.System");
System.setProperty("java.awt.headless", "true");
// Read the image from the response's payload
let ImageIO = Java.type("javax.imageio.ImageIO");
let img = ImageIO.read(context.response.payloadStream);
// Don't do anything if the image is small
if (img.getWidth() < 50 || img.getHeight() < 30) {
return;
}
// Set up the color, font and alpha level
let g = img.createGraphics();
let Color = Java.type("java.awt.Color");
g.setColor(Color.RED);
let Font = Java.type("java.awt.Font");
let font = new Font("sans-serif", Font.BOLD, 36);
g.setFont(font);
let AlphaComposite = Java.type("java.awt.AlphaComposite");
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5));
// Add some text to the image
let txt = "Gallium Data";
let rect = font.getStringBounds(txt, g.getFontRenderContext());
g.drawString(txt, (img.getHeight() / 2) - (rect.getWidth() / 2),
(img.getHeight() / 2) + 24);
let outStream = context.response.payloadWriteStream;
ImageIO.write(img, "png", outStream);
If you want to see this in action, you can set a connection with:
Server address: www.parks.ca.gov
Server port: 443
Use HTTPS with server: Yes
Local address: <whatever is appropriate for your machine>
Local port: 8097 (or any other port that is not already taken)
Then create a JavaScript response filter with parameters:
URL pattern: regex:(.*\.jpg)|(.*\.png)
Method: GET
Header patterns: Content-type:regex:(image/png)|(image/jpeg)
Make sure the filter is active and published.
Pick a photo on that website, such as https://www.parks.ca.gov/pages/531/images/Park_image090-P92745.jpg
Now visit it through your filter: http://localhost:8097/pages/531/images/Park_image090-P92745.jpg