Socket
Socket
Sign inDemoInstall

mockttp

Package Overview
Dependencies
Maintainers
1
Versions
125
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

mockttp - npm Package Compare versions

Comparing version 3.9.4 to 3.10.0

4

custom-typings/node-type-extensions.d.ts

@@ -32,6 +32,2 @@ // There's a few places where we attach extra data to some node objects during

// Data that was peeked by httpolyglot, and thereby probably lost from the
// HTTP parser errors, but which might be useful for debugging later
__httpPeekedData?: Buffer;
// Our recordings of various timestamps, used for monitoring &

@@ -38,0 +34,0 @@ // performance analysis later on

20

dist/server/mockttp-server.js

@@ -708,6 +708,5 @@ "use strict";

// (e.g. Q as first char) then this packet data does get thrown! Eugh. In that case,
// we need to avoid using both by accident, so we use just the non-peeked data instead.
rawPacket: error.rawPacket === socket.__httpPeekedData
? undefined
: error.rawPacket
// we need to avoid using both by accident, so we use just the non-peeked data instead
// if the initial data is _exactly_ identical.
rawPacket: error.rawPacket
};

@@ -722,13 +721,4 @@ setImmediate(async () => {

};
// Initially _httpMessage is undefined, until at least one request has been parsed.
// Later it's set to the current ServerResponse, and then null when the socket is
// detached, but never back to undefined. Avoids issues with using old peeked data
// on subsequent requests within keep-alive connections.
const isFirstRequest = socket._httpMessage === undefined;
// HTTPolyglot's byte-peeking can sometimes lose the initial byte from the parser's
// exposed buffer. If that's happened, we need to get it back:
const rawPacket = Buffer.concat([
isFirstRequest && socket.__httpPeekedData,
socket.clientErrorInProgress?.rawPacket
].filter((data) => !!data));
const rawPacket = socket.clientErrorInProgress?.rawPacket
?? Buffer.from([]);
// For packets where we get more than just httpolyglot-peeked data, guess-parse them:

@@ -735,0 +725,0 @@ const parsedRequest = rawPacket.byteLength > 1

@@ -145,5 +145,12 @@ /// <reference types="node" />

/**
* The contents of the response, decoded, parsed as UTF-8 string, and
* then parsed form-encoded data. The response is decoded and returned
* asynchronously as a Promise.
* The contents of the response, decoded, and then parsed automatically as
* either one of the form encoding types (either URL-encoded or multipart),
* determined automatically from the message content-type header.
*
* This method is convenient and offers a single mechanism to parse both
* formats, but you may want to consider parsing on format explicitly with
* the `getUrlEncodedFormData()` or `getMultipartFormData()` methods instead.
*
* After parsing & decoding, the result is returned asynchronously as a
* Promise for a key-value(s) object.
*/

@@ -153,2 +160,21 @@ getFormData(): Promise<{

} | undefined>;
/**
* The contents of the response, decoded, parsed as UTF-8 string, and then
* parsed as URL-encoded form data. After parsing & decoding, the result is
* returned asynchronously as a Promise for a key-value(s) object.
*/
getUrlEncodedFormData(): Promise<{
[key: string]: string | string[] | undefined;
} | undefined>;
/**
* The contents of the response, decoded, and then parsed as multi-part
* form data. The response is result is returned asynchronously as a
* Promise for an array of parts with their names, data and metadata.
*/
getMultipartFormData(): Promise<Array<{
name?: string;
filename?: string;
type?: string;
data: Buffer;
}> | undefined>;
}

@@ -155,0 +181,0 @@ export declare type InitiatedRequest = Request;

@@ -9,2 +9,3 @@ "use strict";

const querystring = require("querystring");
const multipart = require("parse-multipart-data");
const now = require("performance-now");

@@ -173,7 +174,59 @@ const url = require("url");

},
async getFormData() {
async getUrlEncodedFormData() {
return runAsyncOrUndefined(async () => {
const contentType = headers["content-type"];
if (contentType?.includes("multipart/form-data"))
return; // Actively ignore multipart data - won't work as expected
const text = await completedBody.getText();
return text ? querystring.parse(text) : undefined;
});
},
async getMultipartFormData() {
return runAsyncOrUndefined(async () => {
const contentType = headers["content-type"];
if (!contentType?.includes("multipart/form-data"))
return;
const boundary = contentType.match(/;\s*boundary=(\S+)/);
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type#boundary
// `boundary` is required for multipart entities.
if (!boundary)
return;
const multipartBodyBuffer = (0, buffer_utils_1.asBuffer)(await decodeBodyBuffer(this.buffer, headers));
return multipart.parse(multipartBodyBuffer, boundary[1]);
});
},
async getFormData() {
return runAsyncOrUndefined(async () => {
// Return multi-part data if present, or fallback to default URL-encoded
// parsing for all other cases. Data is returned in the same format regardless.
const multiPartBody = await completedBody.getMultipartFormData();
if (multiPartBody) {
const formData = {};
multiPartBody.forEach((part) => {
const name = part.name;
if (name === undefined) {
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition#as_a_header_for_a_multipart_body,
// The header must include `name` property to identify the field name.
// So we ignore parts without a name, treating it as invalid multipart form data.
}
else {
// We do not use `filename` or `type` here, because return value of `getFormData` must be string or string array.
const prevValue = formData[name];
if (prevValue === undefined) {
formData[name] = part.data.toString();
}
else if (Array.isArray(prevValue)) {
prevValue.push(part.data.toString());
}
else {
formData[name] = [prevValue, part.data.toString()];
}
}
});
return formData;
}
else {
return completedBody.getUrlEncodedFormData();
}
});
}

@@ -180,0 +233,0 @@ };

{
"name": "mockttp",
"version": "3.9.4",
"version": "3.10.0",
"description": "Mock HTTP server for testing HTTP clients and stubbing webservices",

@@ -164,3 +164,3 @@ "exports": {

"@graphql-tools/utils": "^8.8.0",
"@httptoolkit/httpolyglot": "^2.1.1",
"@httptoolkit/httpolyglot": "^2.2.1",
"@httptoolkit/subscriptions-transport-ws": "^0.11.2",

@@ -185,3 +185,3 @@ "@httptoolkit/websocket-stream": "^6.0.1",

"http-encoding": "^1.5.1",
"http2-wrapper": "^2.2.0",
"http2-wrapper": "^2.2.1",
"https-proxy-agent": "^5.0.1",

@@ -188,0 +188,0 @@ "isomorphic-ws": "^4.0.1",

@@ -920,6 +920,5 @@ import _ = require("lodash");

// (e.g. Q as first char) then this packet data does get thrown! Eugh. In that case,
// we need to avoid using both by accident, so we use just the non-peeked data instead.
rawPacket: error.rawPacket === socket.__httpPeekedData
? undefined
: error.rawPacket
// we need to avoid using both by accident, so we use just the non-peeked data instead
// if the initial data is _exactly_ identical.
rawPacket: error.rawPacket
};

@@ -937,17 +936,5 @@

// Initially _httpMessage is undefined, until at least one request has been parsed.
// Later it's set to the current ServerResponse, and then null when the socket is
// detached, but never back to undefined. Avoids issues with using old peeked data
// on subsequent requests within keep-alive connections.
const isFirstRequest = (socket as any)._httpMessage === undefined;
const rawPacket = socket.clientErrorInProgress?.rawPacket
?? Buffer.from([]);
// HTTPolyglot's byte-peeking can sometimes lose the initial byte from the parser's
// exposed buffer. If that's happened, we need to get it back:
const rawPacket = Buffer.concat(
[
isFirstRequest && socket.__httpPeekedData,
socket.clientErrorInProgress?.rawPacket
].filter((data) => !!data) as Buffer[]
);
// For packets where we get more than just httpolyglot-peeked data, guess-parse them:

@@ -954,0 +941,0 @@ const parsedRequest = rawPacket.byteLength > 1

@@ -184,7 +184,28 @@ import stream = require('stream');

/**
* The contents of the response, decoded, parsed as UTF-8 string, and
* then parsed form-encoded data. The response is decoded and returned
* asynchronously as a Promise.
* The contents of the response, decoded, and then parsed automatically as
* either one of the form encoding types (either URL-encoded or multipart),
* determined automatically from the message content-type header.
*
* This method is convenient and offers a single mechanism to parse both
* formats, but you may want to consider parsing on format explicitly with
* the `getUrlEncodedFormData()` or `getMultipartFormData()` methods instead.
*
* After parsing & decoding, the result is returned asynchronously as a
* Promise for a key-value(s) object.
*/
getFormData(): Promise<{ [key: string]: string | string[] | undefined } | undefined>;
/**
* The contents of the response, decoded, parsed as UTF-8 string, and then
* parsed as URL-encoded form data. After parsing & decoding, the result is
* returned asynchronously as a Promise for a key-value(s) object.
*/
getUrlEncodedFormData(): Promise<{ [key: string]: string | string[] | undefined } | undefined>;
/**
* The contents of the response, decoded, and then parsed as multi-part
* form data. The response is result is returned asynchronously as a
* Promise for an array of parts with their names, data and metadata.
*/
getMultipartFormData(): Promise<Array<{ name?: string, filename?: string, type?: string, data: Buffer }> | undefined>;
}

@@ -191,0 +212,0 @@

@@ -8,2 +8,3 @@ import * as _ from 'lodash';

import * as querystring from 'querystring';
import * as multipart from 'parse-multipart-data';
import now = require("performance-now");

@@ -239,7 +240,59 @@ import * as url from 'url';

},
async getFormData() {
async getUrlEncodedFormData() {
return runAsyncOrUndefined(async () => {
const contentType = headers["content-type"];
if (contentType?.includes("multipart/form-data")) return; // Actively ignore multipart data - won't work as expected
const text = await completedBody.getText();
return text ? querystring.parse(text) : undefined;
});
},
async getMultipartFormData() {
return runAsyncOrUndefined(async () => {
const contentType = headers["content-type"];
if (!contentType?.includes("multipart/form-data")) return;
const boundary = contentType.match(/;\s*boundary=(\S+)/);
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type#boundary
// `boundary` is required for multipart entities.
if (!boundary) return;
const multipartBodyBuffer = asBuffer(await decodeBodyBuffer(this.buffer, headers));
return multipart.parse(multipartBodyBuffer, boundary[1]);
});
},
async getFormData(): Promise<querystring.ParsedUrlQuery | undefined> {
return runAsyncOrUndefined(async () => {
// Return multi-part data if present, or fallback to default URL-encoded
// parsing for all other cases. Data is returned in the same format regardless.
const multiPartBody = await completedBody.getMultipartFormData();
if (multiPartBody) {
const formData: querystring.ParsedUrlQuery = {};
multiPartBody.forEach((part) => {
const name = part.name;
if (name === undefined) {
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition#as_a_header_for_a_multipart_body,
// The header must include `name` property to identify the field name.
// So we ignore parts without a name, treating it as invalid multipart form data.
} else {
// We do not use `filename` or `type` here, because return value of `getFormData` must be string or string array.
const prevValue = formData[name];
if (prevValue === undefined) {
formData[name] = part.data.toString();
} else if (Array.isArray(prevValue)) {
prevValue.push(part.data.toString());
} else {
formData[name] = [prevValue, part.data.toString()];
}
}
});
return formData;
} else {
return completedBody.getUrlEncodedFormData();
}
});
}

@@ -246,0 +299,0 @@ };

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc