Skip to content

Commit

Permalink
Added variable to track the downloaded content size in response (#1362)
Browse files Browse the repository at this point in the history
  • Loading branch information
parthverma1 authored Jul 29, 2024
1 parent 11877e3 commit 01caecb
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 37 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
unreleased:
fixed bugs:
- GH-1366 Fixed a bug where $randomAvatarImage was returning an invalid URL
chores:
- GH-1362 Updated `Request~size` to handle `downloadedBytes` property

4.4.0:
date: 2024-02-28
Expand Down
68 changes: 35 additions & 33 deletions lib/collection/response.js
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ _.assign(Response.prototype, /** @lends Response.prototype */ {
update (options) {
// options.stream accepts Buffer, Buffer.toJSON() or base64 string
// @todo this temporarily doubles the memory footprint (options.stream + generated buffer).
var stream = normalizeStream(options.stream);
const stream = normalizeStream(options.stream);

_.mergeDefined((this._details = _.clone(httpReasons.lookup(options.code))), {
name: _.choose(options.reason, options.status),
Expand Down Expand Up @@ -255,7 +255,13 @@ _.assign(Response.prototype, /** @lends Response.prototype */ {
* @private
* @type {Number}
*/
responseSize: stream && stream.byteLength
responseSize: stream && stream.byteLength,

/**
* @private
* @type {Number}
*/
downloadedBytes: options.downloadedBytes
});
}
});
Expand Down Expand Up @@ -397,61 +403,57 @@ _.assign(Response.prototype, /** @lends Response.prototype */ {
},

/**
* Get the response size by computing the same from content length header or using the actual response body.
* @typedef Response.sizeInfo
* @property {Number} body - size of the response body in bytes
* @property {Number} header - size of the response header in bytes
* @property {Number} total - total size of the response body and header in bytes
*/
/**
* Get the response size by computing the same from content length header or
* using the actual response body.
*
* @returns {Number}
* @todo write unit tests
* @returns {Response.sizeInfo} - Response size object
*/
size: function () {
var sizeInfo = {
const sizeInfo = {
body: 0,
header: 0,
total: 0
},
contentLength = this.headers.get(CONTENT_LENGTH);

contentEncoding = this.headers.get(CONTENT_ENCODING),
contentLength = this.headers.get(CONTENT_LENGTH),
isCompressed = false,
byteLength;

// if server sent encoded data, we should first try deriving length from headers
if (_.isString(contentEncoding)) {
// desensitise case of content encoding
contentEncoding = contentEncoding.toLowerCase();
// eslint-disable-next-line lodash/prefer-includes
isCompressed = (contentEncoding.indexOf('gzip') > -1) || (contentEncoding.indexOf('deflate') > -1);
// Set body size from downloadedBytes if available
if (util.isNumeric(this.downloadedBytes)) {
sizeInfo.body = this.downloadedBytes;
}

// if 'Content-Length' header is present and encoding is of type gzip/deflate, we take body as declared by
// server. else we need to compute the same.
if (contentLength && isCompressed && util.isNumeric(contentLength)) {
// Rely on content-length header
else if (contentLength && util.isNumeric(contentLength)) {
sizeInfo.body = _.parseInt(contentLength, 10);
}
// if there is a stream defined which looks like buffer, use it's data and move on
else if (this.stream) {
byteLength = this.stream.byteLength;
sizeInfo.body = util.isNumeric(byteLength) ? byteLength :
/* istanbul ignore next */
0;
// Fall back to stream if available
else if (this.stream && util.isNumeric(this.stream.byteLength)) {
sizeInfo.body = this.stream.byteLength;
}
// otherwise, if body is defined, we try get the true length of the body
// Or, calculate size from body string
else if (!_.isNil(this.body)) {
sizeInfo.body = supportsBuffer ? Buffer.byteLength(this.body.toString()) :
sizeInfo.body = supportsBuffer ?
Buffer.byteLength(this.body.toString()) :
/* istanbul ignore next */
this.body.toString().length;
}

// size of header is added
// Header size is calculated as per the HTTP message format
// https://tools.ietf.org/html/rfc7230#section-3
// HTTP-message = start-line (request-line / status-line)
// *( header-field CRLF )
// CRLF
// [ message-body ]
// status-line = HTTP-version SP status-code SP reason-phrase CRLF
sizeInfo.header = (HTTP_X_X + SP + this.code + SP + this.reason() + CRLF + CRLF).length +
this.headers.contentSize();
sizeInfo.header = (
HTTP_X_X + SP + this.code + SP + this.reason() + CRLF + CRLF
).length + this.headers.contentSize();

// compute the approximate total body size by adding size of header and body
// Compute the approximate total body size by adding size of header and body
sizeInfo.total = (sizeInfo.body || 0) + (sizeInfo.header);

return sizeInfo;
Expand Down
48 changes: 47 additions & 1 deletion test/unit/response.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -271,8 +271,20 @@ describe('Response', function () {
it('should handle blank responses correctly', function () {
var response = new Response();

expect(response.size()).to.eql({ body: 0, header: 32, total: 32 });
});

it('should handle string responses correctly', function () {
var response = new Response({ body: 'random' });

expect(response.size()).to.eql({ body: 6, header: 32, total: 38 });
});

it('should report downloaded size correctly', function () {
var response = new Response({ body: 'random', downloadedBytes: 6 });

expect(response.size()).to.eql({
body: 0, header: 32, total: 32
body: 6, header: 32, total: 38
});
});
});
Expand Down Expand Up @@ -477,6 +489,17 @@ describe('Response', function () {
expect(response.size().body).to.equal(20);
});

it('must match the content-length of the response if brotli encoded', function () {
var rawResponse = {
code: 200,
body: 'gzipped content xyzxyzxyzxyzxyzxyz',
header: 'Content-Encoding: br\nContent-Length: 20'
},
response = new Response(rawResponse);

expect(response.size().body).to.equal(20);
});

it('must use byteLength from buffer if provided', function () {
var rawResponse = {
code: 200,
Expand All @@ -487,6 +510,29 @@ describe('Response', function () {

expect(response.size().body).to.equal(14);
});

it('must use downloaded size if provided', function () {
var rawResponse = {
code: 200,
body: 'something nice',
header: 'Transfer-Encoding: chunked\nContent-Length: 20',
downloadedBytes: 10
},
response = new Response(rawResponse);

expect(response.size().body).to.equal(10);
});

it('must use content length of stream if header is provided and downloaded bytes is not present', function () {
var rawResponse = {
code: 200,
stream: Buffer.from('something nice'),
header: 'Transfer-Encoding: chunked\nContent-Length: 20\nContent-Encoding: gzip'
},
response = new Response(rawResponse);

expect(response.size().body).to.equal(20);
});
});

describe('toJSON', function () {
Expand Down
18 changes: 15 additions & 3 deletions types/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Type definitions for postman-collection 4.3.0
// Type definitions for postman-collection 4.4.0
// Project: https://github.com/postmanlabs/postman-collection
// Definitions by: PostmanLabs
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
Expand Down Expand Up @@ -2005,6 +2005,16 @@ declare module "postman-collection" {
stream?: Buffer | ArrayBuffer;
responseTime: number;
};
/**
* @property body - size of the response body in bytes
* @property header - size of the response header in bytes
* @property total - total size of the response body and header in bytes
*/
type sizeInfo = {
body: number;
header: number;
total: number;
};
/**
* Returns the durations of each request phase in milliseconds
* @example
Expand Down Expand Up @@ -2129,9 +2139,11 @@ declare module "postman-collection" {
*/
dataURI(): string;
/**
* Get the response size by computing the same from content length header or using the actual response body.
* Get the response size by computing the same from content length header or
* using the actual response body.
* @returns - Response size object
*/
size(): number;
size(): Response.sizeInfo;
/**
* Check whether an object is an instance of ItemGroup.
* @param obj - -
Expand Down

0 comments on commit 01caecb

Please sign in to comment.