Fix network tests for node-libcurl (#141)

This commit is contained in:
Gregory Schier 2017-04-12 14:17:40 -07:00 committed by GitHub
parent 584423abae
commit 6e8ad9636f
4 changed files with 405 additions and 278 deletions

View File

@ -0,0 +1,117 @@
import {EventEmitter} from 'events';
class Curl extends EventEmitter {
constructor () {
super();
this._options = {};
}
setOpt (name, value) {
if (!name) {
throw new Error(`Invalid option ${name} ${value}`);
}
if (name === Curl.option.CAINFO) {
// Just ignore this because it's platform-specific
return;
}
if (name === Curl.option.COOKIELIST) {
// This can be set multiple times
this._options[name] = this._options[name] || [];
this._options[name].push(value);
} else {
this._options[name] = value;
}
}
getInfo (name) {
switch (name) {
case Curl.info.COOKIELIST:
return [`#HttpOnly_.insomnia.rest\tTRUE\t/url/path\tTRUE\t${Date.now() / 1000}\tfoo\tbar`];
case Curl.info.EFFECTIVE_URL:
return this._options[Curl.option.URL];
case Curl.info.TOTAL_TIME:
return 700;
case Curl.info.SIZE_DOWNLOAD:
return 800;
default:
throw new Error(`Invalid info ${name}`);
}
}
perform () {
process.nextTick(() => {
const data = Buffer.from(JSON.stringify({
options: this._options
}));
this.emit('data', data);
process.nextTick(() => {
this.emit('end', 'NOT_USED', 'NOT_USED', [{
'Content-Length': `${data.length}`,
'Content-Type': 'application/json',
result: {code: 200, reason: 'OK'}
}]);
});
});
}
close () {
}
}
Curl.info = {
COOKIELIST: 'COOKIELIST',
EFFECTIVE_URL: 'EFFECTIVE_URL',
SIZE_DOWNLOAD: 'SIZE_DOWNLOAD',
TOTAL_TIME: 'TOTAL_TIME',
debug: {
DATA_IN: 'DATA_IN',
DATA_OUT: 'DATA_OUT',
SSL_DATA_IN: 'SSL_DATA_IN',
SSL_DATA_OUT: 'SSL_DATA_OUT',
TEXT: 'TEXT'
}
};
Curl.auth = {
ANY: 'ANY'
};
Curl.option = {
CAINFO: 'CAINFO',
COOKIEFILE: 'COOKIEFILE',
COOKIELIST: 'COOKIELIST',
CUSTOMREQUEST: 'CUSTOMREQUEST',
DEBUGFUNCTION: 'DEBUGFUNCTION',
ENCODING: 'ENCODING',
FOLLOWLOCATION: 'FOLLOWLOCATION',
HTTPAUTH: 'HTTPAUTH',
HTTPHEADER: 'HTTPHEADER',
HTTPPOST: 'HTTPPOST',
KEYPASSWD: 'KEYPASSWD',
NOPROGRESS: 'NOPROGRESS',
PASSWORD: 'PASSWORD',
POSTFIELDS: 'POSTFIELDS',
PROXY: 'PROXY',
PROXYAUTH: 'PROXYAUTH',
READDATA: 'READDATA',
SSLCERT: 'SSLCERT',
SSLCERTTYPE: 'SSLCERTTYPE',
SSLKEY: 'SSLKEY',
SSL_VERIFYHOST: 'SSL_VERIFYHOST',
SSL_VERIFYPEER: 'SSL_VERIFYPEER',
TIMEOUT_MS: 'TIMEOUT_MS',
UPLOAD: 'UPLOAD',
URL: 'URL',
USERAGENT: 'USERAGENT',
USERNAME: 'USERNAME',
VERBOSE: 'VERBOSE',
XFERINFOFUNCTION: 'XFERINFOFUNCTION'
};
module.exports = {
Curl: Curl
};

View File

@ -1,273 +1,283 @@
// import * as networkUtils from '../network';
// import * as db from '../../common/database';
// import nock from 'nock';
// import {resolve as pathResolve, join as pathJoin} from 'path';
// import {getRenderedRequest} from '../../common/render';
// import * as models from '../../models';
// import {CONTENT_TYPE_FORM_URLENCODED, getAppVersion, CONTENT_TYPE_FILE, CONTENT_TYPE_FORM_DATA, AUTH_BASIC} from '../../common/constants';
import * as networkUtils from '../network';
import * as db from '../../common/database';
import {join as pathJoin, resolve as pathResolve} from 'path';
import {getRenderedRequest} from '../../common/render';
import * as models from '../../models';
import {AUTH_BASIC, CONTENT_TYPE_FILE, CONTENT_TYPE_FORM_DATA, CONTENT_TYPE_FORM_URLENCODED, getAppVersion} from '../../common/constants';
describe('no-op', () => {
it('no-ops', () => {
expect(true).toBeTruthy();
describe('actuallySend()', () => {
beforeEach(() => db.init(models.types(), {inMemoryOnly: true}, true));
it('sends a generic request', async () => {
const workspace = await models.workspace.create();
const settings = await models.settings.create();
const cookies = [{
creation: new Date('2016-10-05T04:40:49.505Z'),
key: 'foo',
value: 'barrrrr',
expires: new Date('2096-10-12T04:40:49.000Z'),
domain: 'notlocalhost',
path: '/',
hostOnly: true,
lastAccessed: new Date('2096-10-05T04:40:49.505Z')
}, {
creation: new Date('2016-10-05T04:40:49.505Z'),
key: 'foo',
value: 'bar',
expires: new Date('2096-10-12T04:40:49.000Z'),
domain: 'localhost',
path: '/',
hostOnly: true,
lastAccessed: new Date('2096-10-05T04:40:49.505Z')
}];
await models.cookieJar.create({
parentId: workspace._id,
cookies
});
const request = Object.assign(models.request.init(), {
_id: 'req_123',
parentId: workspace._id,
headers: [{name: 'Content-Type', value: 'application/json'}],
parameters: [{name: 'foo bar', value: 'hello&world'}],
method: 'POST',
body: {
mimeType: CONTENT_TYPE_FORM_URLENCODED,
params: [{name: 'foo', value: 'bar'}]
},
url: 'http://localhost',
authentication: {
type: AUTH_BASIC,
username: 'user',
password: 'pass'
}
});
const renderedRequest = await getRenderedRequest(request);
const response = await networkUtils._actuallySend(
renderedRequest,
workspace,
settings
);
const body = JSON.parse(Buffer.from(response.body, 'base64'));
expect(body).toEqual({
options: {
COOKIEFILE: '',
COOKIELIST: [
'notlocalhost\tTRUE\t/\tFALSE\t4000855249\tfoo\tbarrrrr',
'localhost\tTRUE\t/\tFALSE\t4000855249\tfoo\tbar'
],
CUSTOMREQUEST: 'POST',
ENCODING: '',
FOLLOWLOCATION: true,
HTTPHEADER: [
'Content-Type: application/json',
'Expect: ',
'Transfer-Encoding: '
],
NOPROGRESS: false,
USERNAME: 'user',
PASSWORD: 'pass',
POSTFIELDS: 'foo=bar',
PROXY: '',
TIMEOUT_MS: 0,
URL: 'http://localhost/?foo%20bar=hello%26world',
USERAGENT: `insomnia/${getAppVersion()}`,
VERBOSE: true
}
});
});
it('skips sending and storing cookies with setting', async () => {
const workspace = await models.workspace.create();
const settings = await models.settings.create();
const cookies = [{
creation: new Date('2016-10-05T04:40:49.505Z'),
key: 'foo',
value: 'barrrrr',
expires: new Date('2096-10-12T04:40:49.000Z'),
domain: 'notlocalhost',
path: '/',
hostOnly: true,
lastAccessed: new Date('2096-10-05T04:40:49.505Z')
}, {
creation: new Date('2016-10-05T04:40:49.505Z'),
key: 'foo',
value: 'barrrrr',
expires: new Date('2096-10-12T04:40:49.000Z'),
domain: 'localhost',
path: '/',
hostOnly: true,
lastAccessed: new Date('2096-10-05T04:40:49.505Z')
}];
await models.cookieJar.create({
parentId: workspace._id,
cookies
});
const request = Object.assign(models.request.init(), {
_id: 'req_123',
parentId: workspace._id,
headers: [{name: 'Content-Type', value: 'application/json'}],
parameters: [{name: 'foo bar', value: 'hello&world'}],
method: 'POST',
body: {
mimeType: CONTENT_TYPE_FORM_URLENCODED,
params: [{name: 'foo', value: 'bar'}]
},
url: 'http://localhost',
authentication: {
type: AUTH_BASIC,
username: 'user',
password: 'pass'
},
settingStoreCookies: false,
settingSendCookies: false
});
const renderedRequest = await getRenderedRequest(request);
const response = await networkUtils._actuallySend(
renderedRequest,
workspace,
settings
);
const body = JSON.parse(Buffer.from(response.body, 'base64'));
expect(body).toEqual({
options: {
COOKIEFILE: '',
CUSTOMREQUEST: 'POST',
ENCODING: '',
FOLLOWLOCATION: true,
HTTPHEADER: [
'Content-Type: application/json',
'Expect: ',
'Transfer-Encoding: '
],
NOPROGRESS: false,
USERNAME: 'user',
PASSWORD: 'pass',
POSTFIELDS: 'foo=bar',
PROXY: '',
TIMEOUT_MS: 0,
URL: 'http://localhost/?foo%20bar=hello%26world',
USERAGENT: `insomnia/${getAppVersion()}`,
VERBOSE: true
}
});
});
it('sends a file', async () => {
const workspace = await models.workspace.create();
const settings = await models.settings.create();
await models.cookieJar.create({parentId: workspace._id});
const request = Object.assign(models.request.init(), {
_id: 'req_123',
parentId: workspace._id,
headers: [{name: 'Content-Type', value: 'application/octet-stream'}],
url: 'http://localhost',
method: 'POST',
body: {
mimeType: CONTENT_TYPE_FILE,
fileName: pathResolve(pathJoin(__dirname, './testfile.txt')) // Let's send ourselves
}
});
const renderedRequest = await getRenderedRequest(request);
const response = await networkUtils._actuallySend(
renderedRequest,
workspace,
settings
);
const body = JSON.parse(Buffer.from(response.body, 'base64'));
// READDATA is an fd (random int), so fuzzy assert this one
expect(typeof body.options.READDATA).toBe('number');
delete body.options.READDATA;
expect(body).toEqual({
options: {
COOKIEFILE: '',
CUSTOMREQUEST: 'POST',
ENCODING: '',
FOLLOWLOCATION: true,
HTTPHEADER: [
'Content-Type: application/octet-stream',
'Content-Length: 13',
'Expect: ',
'Transfer-Encoding: '
],
NOPROGRESS: false,
PROXY: '',
TIMEOUT_MS: 0,
UPLOAD: 1,
URL: 'http://localhost/',
USERAGENT: `insomnia/${getAppVersion()}`,
VERBOSE: true
}
});
});
it('sends multipart form data', async () => {
const workspace = await models.workspace.create();
const settings = await models.settings.create();
await models.cookieJar.create({parentId: workspace._id});
const fileName = pathResolve(pathJoin(__dirname, './testfile.txt'));
const request = Object.assign(models.request.init(), {
_id: 'req_123',
parentId: workspace._id,
headers: [{name: 'Content-Type', value: 'multipart/form-data'}],
url: 'http://localhost',
method: 'POST',
body: {
mimeType: CONTENT_TYPE_FORM_DATA,
params: [
// Should ignore value and send the file since type is set to file
{name: 'foo', fileName: fileName, value: 'bar', type: 'file'},
// Some extra params
{name: 'a', value: 'AA'},
{name: 'baz', value: 'qux', disabled: true}
]
}
});
const renderedRequest = await getRenderedRequest(request);
const response = await networkUtils._actuallySend(
renderedRequest,
workspace,
settings
);
const body = JSON.parse(Buffer.from(response.body, 'base64'));
expect(body).toEqual({
options: {
COOKIEFILE: '',
CUSTOMREQUEST: 'POST',
ENCODING: '',
FOLLOWLOCATION: true,
HTTPHEADER: [
'Content-Type: multipart/form-data',
'Expect: ',
'Transfer-Encoding: '
],
HTTPPOST: [
{file: fileName, name: 'foo', type: 'text/plain'},
{contents: 'AA', name: 'a'}
],
NOPROGRESS: false,
PROXY: '',
TIMEOUT_MS: 0,
URL: 'http://localhost/',
USERAGENT: `insomnia/${getAppVersion()}`,
VERBOSE: true
}
});
});
});
// describe('actuallySend()', () => {
// beforeEach(() => db.init(models.types(), {inMemoryOnly: true}, true));
//
// it('sends a generic request', async () => {
// let mock;
//
// const workspace = await models.workspace.create();
// const settings = await models.settings.create();
// const cookies = [{
// creation: new Date('2016-10-05T04:40:49.505Z'),
// key: 'foo',
// value: 'barrrrr',
// expires: new Date('2096-10-12T04:40:49.000Z'),
// domain: 'notlocalhost',
// path: '/',
// hostOnly: true,
// lastAccessed: new Date('2096-10-05T04:40:49.505Z')
// }, {
// creation: new Date('2016-10-05T04:40:49.505Z'),
// key: 'foo',
// value: 'barrrrr',
// expires: new Date('2096-10-12T04:40:49.000Z'),
// domain: 'localhost',
// path: '/',
// hostOnly: true,
// lastAccessed: new Date('2096-10-05T04:40:49.505Z')
// }];
//
// await models.cookieJar.create({
// parentId: workspace._id,
// cookies
// });
//
// mock = nock('http://localhost')
// .matchHeader('Content-Type', 'application/json')
// .matchHeader('Authorization', 'Basic dXNlcjpwYXNz')
// .matchHeader('Accept', '*/*')
// .matchHeader('User-Agent', `insomnia/${getAppVersion()}`)
// .matchHeader('Cookie', 'foo=barrrrr')
// .post('/', 'foo=bar')
// .query({'foo bar': 'hello&world'})
// .reply(200, 'response body')
// .log(console.log);
//
// const request = Object.assign(models.request.init(), {
// _id: 'req_123',
// parentId: workspace._id,
// headers: [{name: 'Content-Type', value: 'application/json'}],
// parameters: [{name: 'foo bar', value: 'hello&world'}],
// method: 'POST',
// body: {
// mimeType: CONTENT_TYPE_FORM_URLENCODED,
// params: [{name: 'foo', value: 'bar'}]
// },
// url: 'http://localhost',
// authentication: {
// type: AUTH_BASIC,
// username: 'user',
// password: 'pass'
// }
// });
//
// const renderedRequest = await getRenderedRequest(request);
// const response = await networkUtils._actuallySend(
// renderedRequest,
// workspace,
// settings
// );
//
// expect(mock.basePath).toBe('http://localhost:80');
// expect(response.error).toBe(undefined);
// expect(response.url).toBe('http://localhost/?foo%20bar=hello%26world');
// expect(response.body).toBe(new Buffer('response body').toString('base64'));
// expect(response.statusCode).toBe(200);
// });
//
// it('skips sending and storing cookies with setting', async () => {
// let mock;
//
// const workspace = await models.workspace.create();
// const settings = await models.settings.create();
// const cookies = [{
// creation: new Date('2016-10-05T04:40:49.505Z'),
// key: 'foo',
// value: 'barrrrr',
// expires: new Date('2096-10-12T04:40:49.000Z'),
// domain: 'notlocalhost',
// path: '/',
// hostOnly: true,
// lastAccessed: new Date('2096-10-05T04:40:49.505Z')
// }, {
// creation: new Date('2016-10-05T04:40:49.505Z'),
// key: 'foo',
// value: 'barrrrr',
// expires: new Date('2096-10-12T04:40:49.000Z'),
// domain: 'localhost',
// path: '/',
// hostOnly: true,
// lastAccessed: new Date('2096-10-05T04:40:49.505Z')
// }];
//
// await models.cookieJar.create({
// parentId: workspace._id,
// cookies
// });
//
// mock = nock('http://localhost')
// .matchHeader('Content-Type', 'application/json')
// .matchHeader('Authorization', 'Basic dXNlcjpwYXNz')
// .matchHeader('Accept', '*/*')
// .matchHeader('User-Agent', `insomnia/${getAppVersion()}`)
// .post('/', 'foo=bar')
// .query({'foo bar': 'hello&world'})
// .reply(200, 'response body', {
// 'Set-Cookie': 'foo=bar; expires=Tue, 27-Mar-38 22:54:51 GMT; path=/; HttpOnly'
// })
// .log(console.log);
//
// const request = Object.assign(models.request.init(), {
// _id: 'req_123',
// parentId: workspace._id,
// headers: [{name: 'Content-Type', value: 'application/json'}],
// parameters: [{name: 'foo bar', value: 'hello&world'}],
// method: 'POST',
// body: {
// mimeType: CONTENT_TYPE_FORM_URLENCODED,
// params: [{name: 'foo', value: 'bar'}]
// },
// url: 'http://localhost',
// authentication: {
// type: AUTH_BASIC,
// username: 'user',
// password: 'pass'
// },
// settingStoreCookies: false,
// settingSendCookies: false
// });
//
// const renderedRequest = await getRenderedRequest(request);
// const response = await networkUtils._actuallySend(
// renderedRequest,
// workspace,
// settings
// );
//
// expect(mock.basePath).toBe('http://localhost:80');
// expect(response.error).toBe(undefined);
// expect(response.url).toBe('http://localhost/?foo%20bar=hello%26world');
// expect(response.body).toBe(new Buffer('response body').toString('base64'));
// expect(response.statusCode).toBe(200);
// });
//
// it('sends a file', async () => {
// let mock;
//
// const workspace = await models.workspace.create();
// const settings = await models.settings.create();
// await models.cookieJar.create({parentId: workspace._id});
//
// mock = nock('http://localhost')
// .matchHeader('Content-Type', 'application/octet-stream')
// .matchHeader('Accept', '*/*')
// .matchHeader('User-Agent', `insomnia/${getAppVersion()}`)
// .post('/', 'Hello World!')
// .reply(200, 'response body')
// .log(console.log);
//
// const request = Object.assign(models.request.init(), {
// _id: 'req_123',
// parentId: workspace._id,
// headers: [{name: 'Content-Type', value: 'application/octet-stream'}],
// url: 'http://localhost',
// method: 'POST',
// body: {
// mimeType: CONTENT_TYPE_FILE,
// fileName: pathResolve(pathJoin(__dirname, './testfile.txt')) // Let's send ourselves
// }
// });
//
// const renderedRequest = await getRenderedRequest(request);
// const response = await networkUtils._actuallySend(
// renderedRequest,
// workspace,
// settings
// );
//
// expect(mock.basePath).toBe('http://localhost:80');
// expect(response.error).toBe(undefined);
// expect(response.url).toBe('http://localhost/');
// expect(response.body).toBe(new Buffer('response body').toString('base64'));
// expect(response.statusCode).toBe(200);
// });
//
// it('sends multipart form data', async () => {
// let mock;
//
// const workspace = await models.workspace.create();
// const settings = await models.settings.create();
// await models.cookieJar.create({parentId: workspace._id});
// const fileName = pathResolve(pathJoin(__dirname, './testfile.txt'));
// let requestBody = 'n/a';
// mock = nock('http://localhost')
// .matchHeader('Content-Type', /^multipart\/form-data/)
// .matchHeader('Accept', '*/*')
// .matchHeader('User-Agent', `insomnia/${getAppVersion()}`)
// .post('/', body => {
// requestBody = body;
// return true;
// })
// .reply(200, 'response body')
// .log(console.log);
//
// const request = Object.assign(models.request.init(), {
// _id: 'req_123',
// parentId: workspace._id,
// headers: [{name: 'Content-Type', value: 'multipart/form-data'}],
// url: 'http://localhost',
// method: 'POST',
// body: {
// mimeType: CONTENT_TYPE_FORM_DATA,
// params: [
// // Should ignore value and send the file since type is set to file
// {name: 'foo', fileName: fileName, value: 'bar', type: 'file'},
//
// // Some extra params
// {name: 'a', value: 'AA'},
// {name: 'baz', value: 'qux', disabled: true}
// ]
// }
// });
//
// const renderedRequest = await getRenderedRequest(request);
// const response = await networkUtils._actuallySend(
// renderedRequest,
// workspace,
// settings
// );
//
// expect(mock.basePath).toBe('http://localhost:80');
// expect(response.error).toBe(undefined);
// expect(response.url).toBe('http://localhost/');
// expect(response.body).toBe(new Buffer('response body').toString('base64'));
// expect(response.statusCode).toBe(200);
//
// const lines = requestBody.split(/\r\n/);
// expect(lines[0]).toMatch(/^----------------------------\d{24}/);
// expect(lines[1]).toBe('Content-Disposition: form-data; name="foo"; filename="testfile.txt"');
// expect(lines[2]).toBe('Content-Type: text/plain');
// expect(lines[3]).toBe('');
// expect(lines[4]).toBe('Hello World!\n');
// expect(lines[5]).toMatch(/^----------------------------\d{24}/);
// expect(lines[6]).toBe('Content-Disposition: form-data; name="a"');
// expect(lines[7]).toBe('');
// expect(lines[8]).toBe('AA');
// expect(lines[9]).toMatch(/^----------------------------\d{24}--/);
// expect(lines[10]).toBe('');
// expect(lines.length).toBe(11);
// });
// });

View File

@ -188,9 +188,11 @@ export function _actuallySend (renderedRequest, workspace, settings) {
setOpt(Curl.option.CAINFO, fullCAPath);
}
// Set cookies
// Enable cookie handling (this is required)
setOpt(Curl.option.COOKIEFILE, '');
// Set cookies from jar
if (renderedRequest.settingSendCookies) {
setOpt(Curl.option.COOKIEFILE, ''); // Enable cookies
const cookies = renderedRequest.cookieJar.cookies || [];
for (const cookie of cookies) {
let expiresTimestamp = 0;
@ -298,7 +300,8 @@ export function _actuallySend (renderedRequest, workspace, settings) {
} else if (renderedRequest.body.mimeType === CONTENT_TYPE_FORM_DATA) {
const data = renderedRequest.body.params.map(param => {
if (param.type === 'file' && param.fileName) {
return {name: param.name, file: param.fileName, type: mimes.lookup(param.fileName)};
const type = mimes.lookup(param.fileName) || 'application/octet-stream';
return {name: param.name, file: param.fileName, type};
} else {
return {name: param.name, contents: param.value};
}
@ -411,8 +414,8 @@ export function _actuallySend (renderedRequest, workspace, settings) {
const contentType = contentTypeHeader ? contentTypeHeader.value : '';
// Update Cookie Jar
const cookieStrings = curl.getInfo(Curl.info.COOKIELIST);
if (renderedRequest.settingStoreCookies) {
const cookieStrings = curl.getInfo(Curl.info.COOKIELIST);
const cookies = cookieStrings.map(str => {
// 0 1 2 3 4 5 6
// [#HttpOnly_.hostname, includeSubdomains, path, secure, expiry, name, value]

View File

@ -26,7 +26,6 @@
"build:copy": "cp -r ./app/package.json ./app/static ./app/icons/* ./build/",
"build:install": "cd build && npm install",
"build": "npm run build:clean && npm run build:renderer && npm run build:main && npm run build:copy && npm run build:install",
"rebuild": "electron-rebuild -f -w node-libcurl",
"package:mac": "rm -rf dist/mac && node node_modules/electron-builder/out/cli/build-cli.js --publish=never --x64 --mac",
"package:win": "rm -rf dist/win* && node node_modules/electron-builder/out/cli/build-cli.js --publish=never --x64 --win",
"package:linux": "rm -rf dist/linux && rm -f dist/*.AppImage && rm -f dist/*.deb && node node_modules/electron-builder/out/cli/build-cli.js --publish=never --x64 --linux",
@ -34,8 +33,7 @@
"build-n-package": "npm run build && npm run package",
"build-n-package:win": "npm run build && npm run package:win",
"build-n-package:mac": "npm run build && npm run package:mac",
"build-n-package:linux": "npm run build && npm run package:linux",
"sentry": "bash scripts/sentry-release.sh"
"build-n-package:linux": "npm run build && npm run package:linux"
},
"jest": {
"setupFiles": [
@ -172,7 +170,6 @@
"jest": "~19.0.2",
"less": "~2.7.2",
"less-loader": "~2.2.3",
"nock": "~9.0.2",
"react-hot-loader": "~3.0.0-beta.6",
"redux-mock-store": "~1.0.2",
"style-loader": "~0.13.2",