Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion changelog.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# Change Log
All notable changes to this project will be documented in this file. For change log formatting, see http://keepachangelog.com/

## 4.2.0
- Adds `safe-regex2` to check for unsafe regexes in SampleStream filter input
- Throws an error on lines bigger than 1KB to prevent potential resource exhaustion

## 4.1.0
- Adds option to include given headers in requests

Expand All @@ -12,7 +16,7 @@ All notable changes to this project will be documented in this file. For change
- Use github actions for running tests

## 3.0.0 2022-08-11
- Include request method in stream when generating a path. This will introduce a breaking change. More info in the [#55](https://github.com/mapbox/aws-log-replay/pull/55) PR description
- Include request method in stream when generating a path. This will introduce a breaking change. More info in the [#55](https://github.com/mapbox/aws-log-replay/pull/55) PR description
- Request method will be used if passed to RequestStream. Only `GET` or `HEAD` requests are allowed to be replayed

## 2.6.1 2022-05-27
Expand Down
26 changes: 16 additions & 10 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ var url = require('url');
var stream = require('stream');
var crypto = require('crypto');
var parallel = require('parallel-stream');
const safe = require('safe-regex2');

module.exports = {};
module.exports.RequestStream = RequestStream;
Expand Down Expand Up @@ -58,8 +59,8 @@ function GeneratePath(type, keepReferer = false) {
const obj = { path, method };
if (referer) obj.referer = referer;
generatePath.push(obj);
}
}
}
}
} else if (type.toLowerCase() == 'lb') {
if (line.indexOf('Amazon Route 53 Health Check Service') > -1) return callback();
parts = line.split(/\s+/g);
Expand Down Expand Up @@ -97,7 +98,7 @@ function RequestStream(options) {

referer = data['referer'];
if (referer && typeof referer !== 'string') referer = referer.toString('utf8');

pathname = data['path'];
if (pathname && typeof pathname !== 'string') pathname = pathname.toString('utf8');
if (!pathname || pathname.indexOf('/') !== 0) return callback();
Expand All @@ -107,7 +108,7 @@ function RequestStream(options) {
var gotOptions = {
method: method || 'GET',
prefixUrl: options.baseurl,
https: {
https: {
rejectUnauthorized: options.strictSSL === false ? false : true
},
responseType: 'buffer',
Expand All @@ -134,10 +135,10 @@ function RequestStream(options) {

got(url, gotOptions)
.then(({ statusCode, body, timings }) => {
this.push({
url: url.toString(),
elapsedTime: timings.phases.total,
statusCode,
this.push({
url: url.toString(),
elapsedTime: timings.phases.total,
statusCode,
body
});
callback();
Expand Down Expand Up @@ -172,17 +173,22 @@ function SampleStream(options) {
sampleStream.count = 0;
sampleStream.threshold = Math.round(parseFloat(options.rate) * Math.pow(2, 16));
if (options.filter) {
if (!safe(options.filter)) throw new Error('Unsafe regex provided');
sampleStream.filterFunction = new RegExp(options.filter);
}
sampleStream._transform = function(line, enc, callback) {
if (!line) return callback();
// Check if line is larger than 1KB
if (Buffer.byteLength(line, 'utf8') > 1024) {
return callback(new Error('Log line exceeds 1KB'));
}
if (sampleStream.filterFunction && !sampleStream.filterFunction.test(line)) return callback();

var hash = crypto.createHash('md5').update('cloudfront-log-read-salt-' + sampleStream.count).digest().readUInt16LE(0);
if (hash < sampleStream.threshold)
sampleStream.push(line);
sampleStream.count++;

callback();
};

Expand Down
33 changes: 31 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@
"name": "@mapbox/aws-log-replay",
"license": "BSD-2-Clause",
"author": "Mapbox",
"version": "4.1.0",
"version": "4.2.0",
"dependencies": {
"agentkeepalive": "^3.5.1",
"got": "^11.8.6",
"minimist": "^1.2.8",
"parallel-stream": "^1.1.2",
"safe-regex2": "^5.0.0",
"split": "^1.0.1"
},
"scripts": {
Expand Down
26 changes: 26 additions & 0 deletions test/SampleStream.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,29 @@ var expectedFiltered = [299, 607, 904, 1218, 1509, 1788, 2085, 2384, 2716];
for (rate = 1; rate < 10; rate++) {
tape('filtered, sample rate ' + (rate * 0.1).toFixed(1), testFunc.bind(null, rate, 'a.json', expectedFiltered[rate - 1]));
}

tape('throws error for unsafe regex', function(t) {
try {
reader.SampleStream({ rate: 0.5, filter: /(a+)+b/ });
t.fail('Should have thrown for unsafe regex');
} catch (err) {
t.equal(err.message, 'Unsafe regex provided', 'throws correct error for unsafe regex');
t.end();
}
});

tape('throws error for log lines larger than 1KB', function(t) {
var sample = reader.SampleStream({ rate: 0.5, filter: /test/ });
var splitStream = split();
splitStream.pipe(sample);

sample.on('error', function(err) {
t.equal(err.message, 'Log line exceeds 1KB', 'throws correct error for oversized log line');
t.end();
});

// Create a line larger than 1KB
var bigLine = 'A'.repeat(1234) + '\n';
splitStream.write(bigLine);
splitStream.end();
});