mountebank icon indicating copy to clipboard operation
mountebank copied to clipboard

Add support for binary HTTP request bodies

Open connorworley opened this issue 5 years ago • 5 comments

Relates to #78

Expected behavior

An HTTP request with a binary body is sent through a mountebank proxy (such as a multipart/form-data request to upload an image). The request is proxied and somehow saved to a stub if predicated on its body.

Actual behavior

The binary request body is mangled with unicode replacement characters, and the request fails.


In addition to fixing the proxying behavior, I'd like to introduce a new body:base64 predicate type to match base64-encoded binary request bodies. If that sounds good I'll submit a PR soon.

connorworley avatar May 06 '19 18:05 connorworley

Err, with further thinking body:base64 doesn't really make sense - a new comparison operator like base64Equals would make more sense.

connorworley avatar May 07 '19 00:05 connorworley

For starters, this diff seems to fix the mangling:

index 872ef420..04c85da1 100644
--- a/src/models/http/httpProxy.js
+++ b/src/models/http/httpProxy.js
@@ -79,12 +79,12 @@ function create (logger) {
         if (originalRequest.body &&
             !headersHelper.hasHeader('Transfer-Encoding', originalRequest.headers) &&
             !headersHelper.hasHeader('Content-Length', originalRequest.headers)) {
-            options.headers['Content-Length'] = Buffer.byteLength(originalRequest.body);
+            options.headers['Content-Length'] = Buffer.byteLength(originalRequest.body, 'binary');
         }
 
         const proxiedRequest = protocol.request(options);
         if (originalRequest.body) {
-            proxiedRequest.write(originalRequest.body);
+            proxiedRequest.write(originalRequest.body, 'binary');
         }
         return proxiedRequest;
     }
diff --git a/src/models/http/httpRequest.js b/src/models/http/httpRequest.js
index 65dd80c3..8a0084f8 100644
--- a/src/models/http/httpRequest.js
+++ b/src/models/http/httpRequest.js
@@ -54,7 +54,7 @@ function createFrom (request) {
     const Q = require('q'),
         deferred = Q.defer();
     request.body = '';
-    request.setEncoding('utf8');
+    request.setEncoding('binary');
     request.on('data', chunk => { request.body += chunk; });
     request.on('end', () => { deferred.resolve(transform(request)); });
     return deferred.promise;

connorworley avatar May 09 '19 00:05 connorworley

Thinking further, comparing multipart/form-data requests is probably going to be more complicated than comparing base64-encoded bodies as the boundary is subject to change between requests. I'll try an injection-based approach once #416 lands.

edit: I may not actually need to predicate against the multipart/form-data request body at all, but I believe I do need the above diff for my use case. Will keep updating here.

connorworley avatar May 09 '19 01:05 connorworley

Resolved via #418

connorworley avatar May 13 '19 04:05 connorworley

Reopening as previous fix broke cirillic character predicate matching.

bbyars avatar Nov 08 '19 18:11 bbyars