Repository: node-nock/nock
Pull request #683 (2016-09-13 17:32:49)

Add gzip and deflate decoder for json content type
This pull request adds corresponding decoders when content encoding is 'gzip'`or`'deflate'`, but only if the content type is JSON. 

Motivation:
currently, nock tries to parse JSON from the requestBody even if it is compressed and ultimately fails with a `SyntaxError`:

```
SyntaxError: Unexpected token f in JSON at position 1
    at Object.parse (native)
    at RequestOverrider.end (/omitted/node_modules/nock/lib/request_overrider.js:298:28)
```

This pull request solves this issue and in the request handler you get a decoded/parsed JSON. Behaviour for other content types should be unaffected.
As it uses sync API, it only works above node >=0.12


vrinek: Hello and sorry for the lack of response. Please rebase on top of (or merge in) latest master as the tests are (finally) green again.

Patch:
diff --git a/lib/common.js b/lib/common.js
index 4995db5..5e78fe3 100644
--- a/lib/common.js
+++ b/lib/common.js
@@ -186,6 +186,11 @@ function isContentEncoded(headers) {
   return _.isString(contentEncoding) && contentEncoding !== '';
 }
 
+function contentEncoding(headers, encoder) {
+  var contentEncoding = _.get(headers, 'content-encoding');
+  return contentEncoding === encoder;
+}
+
 function isJSONContent(headers) {
   var contentType = _.get(headers, 'content-type');
   if (Array.isArray(contentType)) {
@@ -337,6 +342,7 @@ exports.overrideRequests = overrideRequests;
 exports.restoreOverriddenRequests = restoreOverriddenRequests;
 exports.stringifyRequest = stringifyRequest;
 exports.isContentEncoded = isContentEncoded;
+exports.contentEncoding = contentEncoding;
 exports.isJSONContent = isJSONContent;
 exports.headersFieldNamesToLowerCase = headersFieldNamesToLowerCase;
 exports.headersFieldsArrayToLowerCase = headersFieldsArrayToLowerCase;
diff --git a/lib/request_overrider.js b/lib/request_overrider.js
index f6e2ea3..85ceea9 100644
--- a/lib/request_overrider.js
+++ b/lib/request_overrider.js
@@ -12,7 +12,8 @@ var EventEmitter     = require('events').EventEmitter,
     debug            = require('debug')('nock.request_overrider'),
     timers           = require('timers'),
     ReadableStream   = require('stream').Readable,
-    globalEmitter    = require('./global_emitter');
+    globalEmitter    = require('./global_emitter'),
+    zlib             = require('zlib');
 
 function getHeader(request, name) {
   if (!request._headers) {
@@ -295,6 +296,20 @@ function RequestOverrider(req, options, interceptors, remove, cb) {
 
     if (typeof interceptor.body === 'function') {
       if (requestBody && common.isJSONContent(options.headers)) {
+        if (requestBody && common.contentEncoding(options.headers, 'gzip')) {
+          if (typeof zlib.gunzipSync !== 'function') {
+            emitError(new Error('Gzip encoding is currently not supported in this version of Node.'));
+            return;
+          }
+          requestBody = String(zlib.gunzipSync(new Buffer(requestBody, 'hex')), 'hex')
+        } else if (requestBody && common.contentEncoding(options.headers, 'deflate')) {
+          if (typeof zlib.deflateSync !== 'function') {
+            emitError(new Error('Deflate encoding is currently not supported in this version of Node.'));
+            return;
+          }
+          requestBody = String(zlib.inflateSync(new Buffer(requestBody, 'hex')), 'hex')
+        }
+
         requestBody = JSON.parse(requestBody);
       }
 


Test patch:
diff --git a/tests/test_gzip_request.js b/tests/test_gzip_request.js
new file mode 100644
index 0000000..e179b43
--- /dev/null
+++ b/tests/test_gzip_request.js
@@ -0,0 +1,74 @@
+'use strict';
+
+var nock = require('../');
+var test = require('tap').test;
+var http = require('http');
+var assert = require('assert');
+var zlib = require('zlib');
+
+if (zlib.gzipSync && zlib.gunzipSync) {
+  test('accepts and decodes gzip encoded application/json', function (t) {
+    var message = {
+      my: 'contents'
+    };
+
+    t.plan(1);
+
+    nock('http://gzipped.com')
+      .post('/')
+      .reply(function (url, actual) {
+        t.same(actual, message);
+        t.end();
+        return 200
+      });
+
+    var req = http.request({
+        hostname: 'gzipped.com',
+        path: '/',
+        method: 'POST',
+        headers: {
+          'content-encoding': 'gzip',
+          'content-type': 'application/json'
+        }
+      });
+
+    var compressedMessage = zlib.gzipSync(JSON.stringify(message));
+
+    req.write(compressedMessage);
+    req.end();
+  });
+}
+
+if (zlib.deflateSync && zlib.inflateSync) {
+
+  test('accepts and decodes deflate encoded application/json', function (t) {
+    var message = {
+      my: 'contents'
+    };
+
+    t.plan(1);
+
+    nock('http://gzipped.com')
+      .post('/')
+      .reply(function (url, actual) {
+        t.same(actual, message);
+        t.end();
+        return 200
+      });
+
+    var req = http.request({
+        hostname: 'gzipped.com',
+        path: '/',
+        method: 'POST',
+        headers: {
+          'content-encoding': 'deflate',
+          'content-type': 'application/json'
+        }
+      });
+
+    var compressedMessage = zlib.deflateSync(JSON.stringify(message));
+
+    req.write(compressedMessage);
+    req.end();
+  });
+}