Skip to content

Commit 4f49012

Browse files
committed
Add brotli (br) compression support
Update packages to latest Migrate to ES Modules Update major version to 2 since these are breaking changes Update node version. Replace TravisCI with Github Actions
1 parent cd04834 commit 4f49012

File tree

8 files changed

+383
-399
lines changed

8 files changed

+383
-399
lines changed

.github/workflows/node.js.yml

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
2+
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
3+
4+
name: Node.js CI
5+
6+
on: push
7+
8+
jobs:
9+
build:
10+
11+
runs-on: ubuntu-latest
12+
13+
strategy:
14+
matrix:
15+
node-version: [14.x]
16+
17+
steps:
18+
- uses: actions/checkout@v2
19+
- name: Use Node.js ${{ matrix.node-version }}
20+
uses: actions/setup-node@v2
21+
with:
22+
node-version: ${{ matrix.node-version }}
23+
cache: 'npm'
24+
- run: npm ci
25+
- run: npm test

.travis.yml

-5
This file was deleted.

README.md

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
# json-caching-proxy [![Build Status](https://travis-ci.org/sonyseng/json-caching-proxy.svg?branch=master)](https://travis-ci.org/sonyseng/json-caching-proxy) [![NPM Version](http://img.shields.io/npm/v/json-caching-proxy.svg?style=flat)](https://www.npmjs.org/package/json-caching-proxy) [![NPM Downloads](https://img.shields.io/npm/dm/json-caching-proxy.svg?style=flat)](https://www.npmjs.org/package/json-caching-proxy)
1+
# json-caching-proxy ![Build Status](https://github.com/sonyseng/json-caching-proxy/actions/workflows/node.js.yml/badge.svg) [![NPM Version](http://img.shields.io/npm/v/json-caching-proxy.svg?style=flat)](https://www.npmjs.org/package/json-caching-proxy) [![NPM Downloads](https://img.shields.io/npm/dm/json-caching-proxy.svg?style=flat)](https://www.npmjs.org/package/json-caching-proxy)
22

33
Node caching HTTP proxy built on top of [express-http-proxy](https://github.com/villadora/express-http-proxy). Persists requests and responses to an in-memory HAR-like data structure based on [HAR1.2](http://www.softwareishard.com/blog/har-12-spec/) . Caches JSON content-type responses by default with the ability to cache an entire site; including content-types describing images. Useful for testing front end code, mocking api, and saving the cache to a HAR file which can be used for further tests.
4+
45
## Installation
56

6-
Requires Node >= 10
7+
Requires Node >= 14
78

89
Command line tool:
910
```
@@ -226,7 +227,7 @@ cacheBustingParams: ['time', 'dc', 'cacheSlayer', '_']
226227
```
227228

228229
## Controlling the Proxy
229-
Once the proxy has started, you may point your browser to the following urls to affect the state of the proxy:
230+
Once the proxy has started on a port (e.g. 3001), you may point your browser to the following urls to affect the state of the proxy:
230231
```
231232
http://localhost:3001/proxy/playback?enabled=[true|false] - Start/Stop replaying cached requests.
232233
http://localhost:3001/proxy/record?enabled=[true|false] - Start/Stop recording request/responses to the cache.

bin.js

+7-7
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
#!/usr/bin/env node
22

3-
const version = require('./package.json').version;
4-
const JsonCachingProxy = require('./');
3+
import { program } from "commander";
4+
import fs from "fs";
5+
import path from "path";
6+
import stripJsonComments from "strip-json-comments";
57

6-
const fs = require('fs');
7-
const url = require('url');
8-
const path = require('path');
9-
const program = require('commander');
10-
const stripJsonComments = require('strip-json-comments');
8+
import JsonCachingProxy from "./index.js";
119

10+
const npmPackage = JSON.parse(fs.readFileSync('./package.json'));
11+
const version = npmPackage.version;
1212
const cwd = process.cwd();
1313

1414
function list (val) {

index.js

+34-24
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
1-
const npmPackage = require('./package.json');
2-
const crypto = require('crypto');
3-
const express = require('express');
4-
const proxy = require('express-http-proxy');
5-
const cors = require('cors');
6-
const bodyParser = require('body-parser');
7-
const urlUtil = require('url');
8-
const chalk = require('chalk');
9-
10-
/** The caching proxy server. */
11-
class JsonCachingProxy {
1+
import bodyParser from 'body-parser';
2+
import chalk from 'chalk';
3+
import cors from 'cors';
4+
import crypto from 'crypto';
5+
import express from 'express';
6+
import fs from 'fs';
7+
import proxy from 'express-http-proxy';
8+
import urlUtil from 'url';
9+
import { promisify } from 'util';
10+
import zlib from 'zlib';
11+
12+
const brotliDecompress = promisify(zlib.brotliDecompress);
13+
const npmPackage = JSON.parse(fs.readFileSync('package.json'));
14+
15+
export default class JsonCachingProxy {
1216
/**
1317
* @param {Object} options - Options passed into the ctor will override defaults if defined
1418
*/
@@ -130,10 +134,10 @@ class JsonCachingProxy {
130134
* @param {string} startedDateTime - An ISO Datetime String
131135
* @param {Object} req - An express IncomingMessage request
132136
* @param {Object} res - An express ServerResponse response
133-
* @param {Object} data - An express response body (the content)
137+
* @param {Buffer} data - An express response body (the content buffer)
134138
* @returns {Object} A HAR entry object
135139
*/
136-
createHarEntry(startedDateTime, req, res, data) {
140+
async createHarEntry(startedDateTime, req, res, data) {
137141
let reqMimeType = req.get('Content-Type');
138142
let resMimeType = res.get('Content-Type') || 'text/plain';
139143
let encoding = (/^text\/|^application\/(javascript|json)/).test(resMimeType) ? 'utf8' : 'base64';
@@ -153,11 +157,16 @@ class JsonCachingProxy {
153157
status: res.statusCode,
154158
statusText: res.statusMessage,
155159
cookies: this.convertToNameValueList(res.cookies),
156-
headers: this.convertToNameValueList(res._headers).filter(header => header.name.toLowerCase() !== 'content-encoding'), // Not compressed
160+
headers: this.convertToNameValueList(res.getHeaders()).filter(header => header.name.toLowerCase() !== 'content-encoding'), // Not compressed
157161
content: {
158162
size: -1,
159163
mimeType: resMimeType,
160-
text: data.toString(encoding),
164+
165+
// Workaround for http-express-proxy not handling brotli encoding. TODO: remove this code when HEP fixes this
166+
text: (res.getHeaders()['content-encoding'] || '').toLowerCase() == 'br' ?
167+
(await brotliDecompress(data)).toString(encoding) :
168+
data.toString(encoding),
169+
161170
encoding: encoding
162171
},
163172
headersSize: -1,
@@ -301,7 +310,7 @@ class JsonCachingProxy {
301310
}
302311

303312
/**
304-
* Add Request body parsing into RAW if there is actual body content
313+
* Add Request body parsing into bodyParser if there is actual body content
305314
* @returns {JsonCachingProxy}
306315
*/
307316
addBodyParser() {
@@ -376,9 +385,11 @@ class JsonCachingProxy {
376385
* Modifies locations on redirects.
377386
* @returns {JsonCachingProxy}
378387
*/
379-
addProxyRoute() {
388+
async addProxyRoute() {
380389
this.app.use('/', proxy(this.options.remoteServerUrl, {
381-
userResDecorator: (rsp, rspData, req, res) => {
390+
userResDecorator: async (rsp, rspData, req, res) => {
391+
let headers = res.getHeaders();
392+
382393
// Handle Redirects by modifying the location property of the response header
383394
let location = res.get('location');
384395
if (location) {
@@ -389,20 +400,21 @@ class JsonCachingProxy {
389400
res.header('access-control-allow-origin', this.options.overrideCors);
390401
}
391402

392-
if (this.options.deleteCookieDomain && res._headers['set-cookie']) {
393-
res.header('set-cookie', this.removeCookiesDomain(res._headers['set-cookie'] || []));
403+
if (this.options.deleteCookieDomain && headers['set-cookie']) {
404+
res.header('set-cookie', this.removeCookiesDomain(headers['set-cookie'] || []));
394405
}
395406

396407
if (this.isRouteExcluded(req.method, req.url)) {
397408
this.log(chalk.red('Exclude Proxied Resource', chalk.bold(req.method, req.url)));
398409
} else if (this.isStatusExcluded(res.statusCode)) {
399410
this.log(chalk.red('Exclude Proxied Resource', chalk.bold(req.method, req.url, `\tStatus: ${res.statusCode}`)));
400411
} else {
401-
let mimeType = res._headers['content-type'];
412+
let mimeType = headers['content-type'];
402413

403414
if (this.options.dataRecord && (this.options.cacheEverything || !this.options.cacheEverything && mimeType && mimeType.indexOf('application/json') >= 0)) {
404415
let { key, hash } = this.genKeyFromExpressReq(req);
405-
let entry = this.createHarEntry(new Date().toISOString(), req, res, rspData);
416+
let entry = await this.createHarEntry(new Date().toISOString(), req, res, rspData);
417+
406418
this.routeCache[key] = entry;
407419
this.log(chalk.yellow('Saved to Cache', hash, chalk.bold(entry.request.method, entry.request.url)));
408420
} else {
@@ -532,5 +544,3 @@ class JsonCachingProxy {
532544
*/
533545
isRecording() { return this.options.dataRecord; }
534546
}
535-
536-
module.exports = JsonCachingProxy;

0 commit comments

Comments
 (0)