diff --git a/README.md b/README.md index 2049dd0..969740b 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,29 @@ var handler = yakbak('http://api.flickr.com', { - `dirname` the path where recorded responses will be written (required). - `noRecord` if true, requests will return a 404 error if the tape doesn't exist +- `parse` optional hook function to modify the response before writing to a tape + + ```javascript + // Example that rewrites url in content body + parse: function (req, res, body) { + var isGzipped = req._headers['accept-encoding'].indexOf('gzip') > -1; + var replaceRe = new RegExp('http://api.flickr.com', 'g'); + + // Body is an array of Buffers + var newBody = body.map(function (chunk) { + if (isGzipped) { + chunk = zlib.gunzipSync(chunk); + } + var buffer = new Buffer(chunk.toString('utf8).replace(replaceRe, 'http://localhost:3000')); + if (isGzipped) { + buffer = zlib.gzipSync(buffer); + } + return buffer; + }); + + return { req: req, res: res, body: newBody }; + } + ``` ### with node's http module diff --git a/index.js b/index.js index 1022c59..6611ee0 100644 --- a/index.js +++ b/index.js @@ -18,6 +18,7 @@ var debug = require('debug')('yakbak:server'); * @param {Object} opts * @param {String} opts.dirname The tapes directory * @param {Boolean} opts.noRecord if true, requests will return a 404 error if the tape doesn't exist + * @param {Function} opts.parse hook to rewrite the response before writing to a tape * @returns {Function} */ @@ -40,7 +41,7 @@ module.exports = function (host, opts) { throw new RecordingDisabledError('Recording Disabled'); } else { return proxy(req, body, host).then(function (pres) { - return record(pres.req, pres, file); + return record(pres.req, pres, file, opts.parse); }); } diff --git a/lib/record.js b/lib/record.js index 297a288..05f74a7 100644 --- a/lib/record.js +++ b/lib/record.js @@ -23,12 +23,20 @@ var render = ejs.compile(fs.readFileSync(path.resolve(__dirname, '../src/tape.ej * @param {http.ClientRequest} req * @param {http.IncomingMessage} res * @param {String} filename + * @param {Function} parse * @returns {Promise.} */ -module.exports = function (req, res, filename) { +module.exports = function (req, res, filename, parse) { return buffer(res).then(function (body) { - return render({ req: req, res: res, body: body }); + var data; + + if (parse) { + data = parse(req, res, body); + } else { + data = { req: req, res: res, body: body }; + } + return render(data); }).then(function (data) { return write(filename, data); }).then(function () { diff --git a/test/fixtures/custom-parse.js b/test/fixtures/custom-parse.js new file mode 100644 index 0000000..6d19aa0 --- /dev/null +++ b/test/fixtures/custom-parse.js @@ -0,0 +1,25 @@ +var path = require("path"); + +/** + * GET / + * + * host: {addr}:{port} + * user-agent: My User Agent/1.0 + * connection: close + */ + +module.exports = function (req, res) { + res.statusCode = 201; + + res.setHeader("content-type", "text/html"); + res.setHeader("date", "Sat, 26 Oct 1985 08:20:00 GMT"); + res.setHeader("connection", "close"); + res.setHeader("content-length", "2"); + + res.setHeader("x-yakbak-tape", path.basename(__filename, ".js")); + + res.write(new Buffer("cGFyc2VkOjpPSw==", "base64")); + res.end(); + + return __filename; +}; diff --git a/test/record.js b/test/record.js index e01151c..bff284b 100644 --- a/test/record.js +++ b/test/record.js @@ -9,6 +9,7 @@ var createTmpdir = require('./helpers/tmpdir'); var assert = require('assert'); var http = require('http'); var fs = require('fs'); +var path = require('path'); var fixture = require('./fixtures'); @@ -68,4 +69,29 @@ describe('record', function () { req.end(); }); + it('uses the parse function if passed in', function (done) { + var customParseFixture = fs.readFileSync(path.join(__dirname, 'fixtures/custom-parse.js'), 'utf8'); + var expected = customParseFixture.replace('{addr}', server.addr).replace('{port}', server.port); + var parse = function (preq, pres, pbody) { + var newBody = pbody.map(function (chunk) { + var str = 'parsed::' + chunk.toString('utf8'); + + return new Buffer(str, 'utf8'); + }); + + return { req: preq, res: pres, body: newBody }; + }; + + req.on('response', function (res) { + subject(req, res, tmpdir.join('foo.js'), parse).then(function (filename) { + assert.equal(fs.readFileSync(filename, 'utf8'), expected); + done(); + }).catch(function (err) { + done(err); + }); + }); + + req.end(); + }); + });