New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

htcp-purge

Package Overview
Dependencies
Maintainers
4
Versions
8
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

htcp-purge - npm Package Compare versions

Comparing version 0.3.0 to 0.3.1

.github/workflows/nodejs.yml

201

index.js

@@ -1,5 +0,5 @@

"use strict";
'use strict';
const P = require('bluebird');
const dgram = P.promisifyAll(require('dgram'));
const P = require( 'bluebird' );
const dgram = P.promisifyAll( require( 'dgram' ) );

@@ -9,3 +9,3 @@ /**

*
* @param options object containing options for a cache purger:
* @param {Object} options object containing options for a cache purger:
* - log: logging function (default no-op)

@@ -20,34 +20,34 @@ * - routes: array of route objects to map a resource url to the cache endpoint

class HTCPPurger {
constructor(options) {
this.options = options || {};
this.log = this.options.log || (() => {});
constructor( options ) {
this.options = options || {};
this.log = this.options.log || ( () => {} );
if (!this.options.routes) {
throw new Error('Config error. At least one route must be specified');
}
if ( !this.options.routes ) {
throw new Error( 'Config error. At least one route must be specified' );
}
this.options.routes.forEach((routeSpec) => {
if (routeSpec.rule && /^\/.+\/$/.test(routeSpec.rule)) {
const regExp = new RegExp(routeSpec.rule.substring(1, routeSpec.rule.length - 1));
routeSpec.rule = url => regExp.test(url);
} else {
routeSpec.rule = () => true;
}
});
this.options.routes.forEach( ( routeSpec ) => {
if ( routeSpec.rule && /^\/.+\/$/.test( routeSpec.rule ) ) {
const regExp = new RegExp( routeSpec.rule
.substring( 1, routeSpec.rule.length - 1 ) );
routeSpec.rule = ( url ) => regExp.test( url );
} else {
routeSpec.rule = () => true;
}
} );
this.options.multicast_ttl = this.options.multicast_ttl || 8;
this.seqReqId = 1;
this.socket = dgram.createSocket('udp4');
}
this.options.multicast_ttl = this.options.multicast_ttl || 8;
this.seqReqId = 1;
this.socket = dgram.createSocket( 'udp4' );
}
bind() {
return this.socket.bindAsync({ exclusive: true })
.then(() => {
this.socket.setMulticastLoopback(false);
this.socket.setMulticastTTL(this.options.multicast_ttl);
});
}
bind() {
return this.socket.bindAsync( { exclusive: true } )
.then( () => {
this.socket.setMulticastLoopback( false );
this.socket.setMulticastTTL( this.options.multicast_ttl );
} );
}
/**
/**
* Purge a list of resources cahced under provided URLs

@@ -57,22 +57,23 @@ * @param {Array} urls array of urls to purge

*/
purge(urls) {
return P.all(urls.map((url) => {
const datagram = this._constructHTCPRequest(url);
const route = this._lookupRoute(url);
if (route) {
return this.socket.sendAsync(datagram, 0, datagram.length, route.port, route.host);
} else {
return P.resolve();
}
}));
}
purge( urls ) {
return P.all( urls.map( ( url ) => {
const datagram = this._constructHTCPRequest( url );
const route = this._lookupRoute( url );
if ( route ) {
return this.socket
.sendAsync( datagram, 0, datagram.length, route.port, route.host );
} else {
return P.resolve();
}
} ) );
}
close() {
try {
return this.socket.close();
} catch (e) {
// We've tried, but seems like socket is already closed, so swallow the error.
}
}
/**
close() {
try {
return this.socket.close();
} catch ( e ) {
// We've tried, but seems like socket is already closed, so swallow the error.
}
}
/**
* Construct a UDP datagram with HTCP packet for Varnish flush of the url

@@ -83,42 +84,42 @@ * @param {string} url a url of the resource that should be flushed

*/
_constructHTCPRequest(url) {
const urlByteLen = Buffer.byteLength(url);
const htcpSpecifierLen = 2 + 4 + 2 + urlByteLen + 2 + 8 + 2;
const htcpDataLen = 8 + 2 + htcpSpecifierLen;
const htcpLen = 4 + htcpDataLen + 2;
_constructHTCPRequest( url ) {
const urlByteLen = Buffer.byteLength( url );
const htcpSpecifierLen = 2 + 4 + 2 + urlByteLen + 2 + 8 + 2;
const htcpDataLen = 8 + 2 + htcpSpecifierLen;
const htcpLen = 4 + htcpDataLen + 2;
const result = new Buffer(htcpLen);
// Length
result.writeInt16BE(htcpLen, 0);
// Major-minor version
result.writeInt16BE(0, 2);
// Data length
result.writeInt16BE(htcpDataLen, 4);
// Op code & response
result.writeInt8(4, 6);
// Reserved & flags
result.writeInt8(0, 7);
// Transaction Id - seq number of a a request
result.writeInt32BE(this.seqReqId++, 8);
const result = Buffer.alloc( htcpLen );
// Length
result.writeUInt16BE( htcpLen, 0 );
// Major-minor version
result.writeUInt16BE( 0, 2 );
// Data length
result.writeUInt16BE( htcpDataLen, 4 );
// Op code & response
result.writeUInt8( 4, 6 );
// Reserved & flags
result.writeUInt8( 0, 7 );
// Transaction Id - seq number of a request
this.seqReqId &= 0xFFFFFFFF;
result.writeUInt32BE( this.seqReqId++, 8 );
// HTCP packet contents - CLR specifier
// Reserved & reason
result.writeUInt16BE( 0, 12 );
// COUNTSTR method: length + method (HEAD & GET are equivalent)
result.writeUInt16BE( 4, 14 );
result.write( 'HEAD', 16, 4 );
// COUNTSTR uri: length + URI
result.writeUInt16BE( urlByteLen, 20 );
result.write( url, 22, urlByteLen );
// COUNTSTR version: length + http version
result.writeUInt16BE( 8, 22 + urlByteLen );
result.write( 'HTTP/1.0', 24 + urlByteLen, 8 );
// COUNTSTR headers: empty, use just as padding
result.writeUInt16BE( 0, 32 + urlByteLen );
result.writeUInt16BE( 2, 14 + htcpSpecifierLen );
// HTCP packet contents - CLR specifier
// Reserved & reason
result.writeInt16BE(0, 12);
// COUNTSTR method: length + method (HEAD & GET are equivalent)
result.writeInt16BE(4, 14);
result.write('HEAD', 16, 4);
// COUNTSTR uri: length + URI
result.writeInt16BE(urlByteLen, 20);
result.write(url, 22, urlByteLen);
// COUNTSTR version: length + http version
result.writeInt16BE(8, 22 + urlByteLen);
result.write('HTTP/1.0', 24 + urlByteLen, 8);
// COUNTSTR headers: empty, use just as padding
result.writeInt16BE(0, 32 + urlByteLen);
result.writeInt16BE(2, 14 + htcpSpecifierLen);
return result;
}
return result;
}
/**
/**
* Lookup a cache endpoint for a concrete URL, based on options

@@ -130,17 +131,17 @@ * supplied in constructor

*/
_lookupRoute(url) {
const route = this.options.routes.find(route => route.rule(url));
if (!route) {
this.log('error/htcp-purge', {
msg: `Could not find route for ${url}`
});
return undefined;
}
return {
host: route.host,
port: route.port
};
}
_lookupRoute( url ) {
const route = this.options.routes.find( ( route ) => route.rule( url ) );
if ( !route ) {
this.log( 'error/htcp-purge', {
msg: `Could not find route for ${url}`
} );
return undefined;
}
return {
host: route.host,
port: route.port
};
}
}
module.exports = HTCPPurger;

@@ -1,34 +0,34 @@

"use strict";
'use strict';
/* eslint no-console: ["error", { allow: ["log"] }] */
const HTCPPurger = require('../index.js');
const HTCPPurger = require( '../index.js' );
function validateArgs() {
if (process.argv.length !== 4) {
return false;
}
const varnishIP = process.argv[2];
return /(?:\d{1,3}\.){3}\d{1,3}:\d{4}/.test(varnishIP);
if ( process.argv.length !== 4 ) {
return false;
}
const varnishIP = process.argv[ 2 ];
return /(?:\d{1,3}\.){3}\d{1,3}:\d{4}/.test( varnishIP );
}
if (!validateArgs()) {
console.log('Usage: node purge.js <varnish ip:port> <resource uri>');
process.exit(1);
if ( !validateArgs() ) {
console.log( 'Usage: node purge.js <varnish ip:port> <resource uri>' );
process.exit( 1 );
}
const varnishIP = process.argv[2];
const purgeURL = process.argv[3];
const hostPortMatch = varnishIP.match(/((?:\d{1,3}\.){3}\d{1,3}):(\d{4})/);
const varnishHostIp = hostPortMatch[1];
const varnishPort = parseInt(hostPortMatch[2]);
const varnishIP = process.argv[ 2 ];
const purgeURL = process.argv[ 3 ];
const hostPortMatch = varnishIP.match( /((?:\d{1,3}\.){3}\d{1,3}):(\d{4})/ );
const varnishHostIp = hostPortMatch[ 1 ];
const varnishPort = parseInt( hostPortMatch[ 2 ] );
const purger = new HTCPPurger({
log: console.log.bind(console),
routes: [{
host: varnishHostIp,
port: varnishPort
}]
});
const purger = new HTCPPurger( {
log: console.log.bind( console ),
routes: [ {
host: varnishHostIp,
port: varnishPort
} ]
} );
console.log(`Sending a datagram to ${varnishHostIp}:${varnishPort} for uri ${purgeURL}`);
purger.bind().then(() => purger.purge([purgeURL])).delay(100).then(() => purger.close());
console.log( `Sending a datagram to ${varnishHostIp}:${varnishPort} for uri ${purgeURL}` );
purger.bind().then( () => purger.purge( [ purgeURL ] ) ).delay( 100 ).then( () => purger.close() );
{
"name": "htcp-purge",
"version": "0.3.0",
"version": "0.3.1",
"description": "Varnish caches purging method",
"main": "index.js",
"scripts": {
"test": "mocha",
"coverage": "istanbul cover _mocha -- -R spec",
"test": "npm run lint && mocha",
"lint": "eslint --max-warnings 0 .",
"coverage": "nyc --reporter=lcov npm test",
"coveralls": "cat ./coverage/lcov.info | coveralls"

@@ -29,12 +30,10 @@ },

"devDependencies": {
"istanbul": "^0.4.5",
"mocha": "^5.1.0",
"mocha-jshint": "^2.3.1",
"eslint": "^5.16.0",
"eslint-config-wikimedia": "^0.13.1",
"eslint-plugin-jsdoc": "^15.8.0",
"eslint-plugin-json": "^2.0.1",
"mocha": "^6.2.0",
"mocha-lcov-reporter": "^1.3.0",
"mocha-eslint": "^4.1.0",
"eslint-config-node-services": "^2.2.5",
"eslint-config-wikimedia": "^0.5.0",
"eslint-plugin-jsdoc": "^3.6.3",
"eslint-plugin-json": "^1.2.0"
"nyc": "^15.0.0"
}
}

@@ -1,113 +0,126 @@

"use strict";
'use strict';
require('mocha-jshint')();
require('mocha-eslint')([ 'index.js' ]);
const HTCPPurger = require( '../index' );
const assert = require( 'assert' );
const dgram = require( 'dgram' );
const HTCPPurger = require('../index');
const assert = require('assert');
const dgram = require('dgram');
describe( 'Protocol tests', () => {
const referenceBuffer = Buffer.from( [ 0, 44, 0, 0, 0, 38, 4, 0,
0, 0, 0, 1, 0, 0, 0, 4, 72, 69, 65, 68, 0, 8,
116, 101, 115, 116, 46, 99, 111, 109, 0, 8, 72,
84, 84, 80, 47, 49, 46, 48, 0, 0, 0, 2 ] );
const referenceBuffer2 = Buffer.from( [ 0, 44, 0, 0, 0, 38, 4, 0,
0, 0, 0, 2, 0, 0, 0, 4, 72, 69, 65, 68, 0, 8,
116, 101, 115, 116, 46, 99, 111, 109, 0, 8, 72,
84, 84, 80, 47, 49, 46, 48, 0, 0, 0, 2 ] );
describe('Protocol tests', () => {
const referenceBuffer = new Buffer([0, 44, 0, 0, 0, 38, 4, 0,
0, 0, 0, 1, 0, 0, 0, 4, 72, 69, 65, 68, 0, 8,
116, 101, 115, 116, 46, 99, 111, 109, 0, 8, 72,
84, 84, 80, 47, 49, 46, 48, 0, 0, 0, 2]);
const referenceBuffer2 = new Buffer([0, 44, 0, 0, 0, 38, 4, 0,
0, 0, 0, 2, 0, 0, 0, 4, 72, 69, 65, 68, 0, 8,
116, 101, 115, 116, 46, 99, 111, 109, 0, 8, 72,
84, 84, 80, 47, 49, 46, 48, 0, 0, 0, 2]);
it( 'should construct correct datagram', () => {
const purger = new HTCPPurger( {
routes: [
{
host: 'default',
port: 4827
}
]
} );
const resultDatagram = purger._constructHTCPRequest( 'test.com' );
assert.deepEqual( referenceBuffer, resultDatagram );
} );
it('should construct correct datagram', () => {
const purger = new HTCPPurger({
routes: [
{
host: 'default',
port: 4827
}
]
});
const resultDatagram = purger._constructHTCPRequest('test.com');
assert.deepEqual(referenceBuffer, resultDatagram);
});
it( 'should lookup route by regex', () => {
const purger = new HTCPPurger( {
routes: [
{
rule: '/https?:\\/\\/test\\.com/',
host: '123.123.123.123',
port: 1234
},
{
host: 'default',
port: 1234
}
]
} );
const route = purger._lookupRoute( 'http://test.com' );
assert.deepEqual( '123.123.123.123', route.host );
assert.deepEqual( 1234, route.port );
const route2 = purger._lookupRoute( 'http://test2.com' );
assert.deepEqual( 'default', route2.host );
assert.deepEqual( 1234, route2.port );
} );
it ('should lookup route by regex', () => {
const purger = new HTCPPurger({
routes: [
{
rule: '/https?:\\/\\/test\\.com/',
host: '123.123.123.123',
port: 1234
},
{
host: 'default',
port: 1234
}
]
});
const route = purger._lookupRoute('http://test.com');
assert.deepEqual('123.123.123.123', route.host);
assert.deepEqual(1234, route.port);
const route2 = purger._lookupRoute('http://test2.com');
assert.deepEqual('default', route2.host);
assert.deepEqual(1234, route2.port);
});
it( 'should send datagrams', function ( done ) {
this.timeout( 5000 );
const purger = new HTCPPurger( {
routes: [
{
host: 'localhost',
port: 12345
}
]
} );
const server = dgram.createSocket( 'udp4' );
server.on( 'message', ( msg ) => {
assert.deepEqual( referenceBuffer, msg );
done();
} );
server.bind( 12345 );
purger
.bind()
.then( () => purger.purge( [ 'test.com' ] ) )
.delay( 100 )
.finally( () => {
purger.close();
server.close();
} );
} );
it ('should send datagrams' ,function(done) {
this.timeout(5000);
const purger = new HTCPPurger({
routes: [
{
host: 'localhost',
port: 12345
}
]
});
const server = dgram.createSocket('udp4');
server.on("message", msg => {
assert.deepEqual(referenceBuffer, msg);
done();
});
server.bind(12345);
purger
.bind()
.then(() => purger.purge(['test.com']))
.delay(100)
.finally(() => {
purger.close();
server.close();
});
});
it( 'should increase seq num of datagrams', ( done ) => {
const purger = new HTCPPurger( {
routes: [
{
host: 'localhost',
port: 12346
}
]
} );
const server = dgram.createSocket( 'udp4' );
let msgIdx = 1;
server.on( 'message', ( msg ) => {
if ( msgIdx === 1 ) {
assert.deepEqual( referenceBuffer, msg );
msgIdx++;
} else {
assert.deepEqual( referenceBuffer2, msg );
done();
}
} );
server.bind( 12346 );
it ('should increase seq num of datagrams' ,done => {
const purger = new HTCPPurger({
routes: [
{
host: 'localhost',
port: 12346
}
]
});
const server = dgram.createSocket('udp4');
let msgIdx = 1;
server.on("message", msg => {
if (msgIdx === 1) {
assert.deepEqual(referenceBuffer, msg);
msgIdx++;
} else {
assert.deepEqual(referenceBuffer2, msg);
done();
}
});
server.bind(12346);
purger.bind()
.then( () => purger.purge( [ 'test.com' ] ) )
.delay( 100 )
.then( () => purger.purge( [ 'test.com' ] ) )
.delay( 100 )
.then( () => {
purger.close();
server.close();
} );
} );
purger.bind()
.then(() => purger.purge(['test.com']))
.delay(100)
.then(() => purger.purge(['test.com']))
.delay(100)
.then(() => {
purger.close();
server.close();
})
});
});
it( 'should reset seqReqId after max 32-int is reached', () => {
const purger = new HTCPPurger( {
routes: [
{
host: 'localhost',
port: 999
}
]
} );
purger.seqReqId = 0xFFFFFFFF + 1;
purger._constructHTCPRequest( 'test.com' );
assert.equal( purger.seqReqId, 1 );
} );
} );

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