Compare commits

...

16 Commits

Author SHA1 Message Date
dbe999eea7 1.1.6 2018-07-19 23:22:19 +02:00
31b326cf51 update the way requests are ended 2018-07-19 23:22:11 +02:00
0c03763281 1.1.5 2018-07-19 23:13:17 +02:00
21e85062f7 fix(path resolution): now correctly looking in cwd 2018-07-19 23:13:16 +02:00
33670bb4d5 1.1.4 2018-07-19 22:51:22 +02:00
6893e1f460 fix(build): coverage treshold 2018-07-19 22:51:22 +02:00
3a1943417b 1.1.3 2018-07-19 22:36:46 +02:00
8e6834da02 fix(core): export formData 2018-07-19 22:36:45 +02:00
7d78890e14 1.1.2 2018-07-19 16:16:08 +02:00
5c413947a4 add formData capability 2018-07-19 16:16:02 +02:00
5de63a1ef3 1.1.1 2018-07-16 23:51:32 +02:00
ee7fa87b25 fix(ci): update tests 2018-07-16 23:51:31 +02:00
4b65674fb2 1.1.0 2018-07-16 23:49:36 +02:00
14f48c99d0 feat(noe supports unix socks): update 2018-07-16 23:49:35 +02:00
e9f1d5697f 1.0.19 2018-07-16 23:39:26 +02:00
b4a9d1aa0c fix(core): update 2018-07-16 23:39:25 +02:00
8 changed files with 232 additions and 67 deletions

View File

@ -1,6 +1,6 @@
{ {
"npmts": { "npmts": {
"coverageTreshold": 60 "coverageTreshold": 50
}, },
"npmci": { "npmci": {
"npmGlobalTools": [ "npmGlobalTools": [

54
package-lock.json generated
View File

@ -1,6 +1,6 @@
{ {
"name": "@pushrocks/smartrequest", "name": "@pushrocks/smartrequest",
"version": "1.0.18", "version": "1.1.6",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
@ -102,6 +102,14 @@
"@types/chai": "*" "@types/chai": "*"
} }
}, },
"@types/form-data": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-2.2.1.tgz",
"integrity": "sha512-JAMFhOaHIciYVh8fb5/83nmuO/AHwmto+Hq7a9y8FzLDcC1KCU344XDOMEmahnrTFlHjgh4L0WJFczNIX2GxnQ==",
"requires": {
"@types/node": "*"
}
},
"@types/fs-extra": { "@types/fs-extra": {
"version": "5.0.4", "version": "5.0.4",
"resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-5.0.4.tgz", "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-5.0.4.tgz",
@ -114,8 +122,7 @@
"@types/node": { "@types/node": {
"version": "10.5.2", "version": "10.5.2",
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.5.2.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-10.5.2.tgz",
"integrity": "sha512-m9zXmifkZsMHZBOyxZWilMwmTlpC8x5Ty360JKTiXvlXZfBWYpsg9ZZvP/Ye+iZUh+Q+MxDLjItVTWIsfwz+8Q==", "integrity": "sha512-m9zXmifkZsMHZBOyxZWilMwmTlpC8x5Ty360JKTiXvlXZfBWYpsg9ZZvP/Ye+iZUh+Q+MxDLjItVTWIsfwz+8Q=="
"dev": true
}, },
"@types/vinyl": { "@types/vinyl": {
"version": "2.0.2", "version": "2.0.2",
@ -153,6 +160,11 @@
"integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==",
"dev": true "dev": true
}, },
"asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
},
"balanced-match": { "balanced-match": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
@ -255,6 +267,14 @@
"readable-stream": "^2.3.5" "readable-stream": "^2.3.5"
} }
}, },
"combined-stream": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz",
"integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=",
"requires": {
"delayed-stream": "~1.0.0"
}
},
"concat-map": { "concat-map": {
"version": "0.0.1", "version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@ -286,6 +306,11 @@
"object-keys": "^1.0.8" "object-keys": "^1.0.8"
} }
}, },
"delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
},
"diff": { "diff": {
"version": "3.5.0", "version": "3.5.0",
"resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
@ -354,6 +379,16 @@
"integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=",
"dev": true "dev": true
}, },
"form-data": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz",
"integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=",
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "1.0.6",
"mime-types": "^2.1.12"
}
},
"fs-extra": { "fs-extra": {
"version": "6.0.1", "version": "6.0.1",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.1.tgz", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.1.tgz",
@ -520,6 +555,19 @@
"integrity": "sha512-0Dab5btKVPhibSalc9QGXb559ED7G7iLjFXBaj9Wq8O3vorueR5K5jaE3hkG6ZQINyhA/JgG6Qk4qdFQjsYV6g==", "integrity": "sha512-0Dab5btKVPhibSalc9QGXb559ED7G7iLjFXBaj9Wq8O3vorueR5K5jaE3hkG6ZQINyhA/JgG6Qk4qdFQjsYV6g==",
"dev": true "dev": true
}, },
"mime-db": {
"version": "1.35.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.35.0.tgz",
"integrity": "sha512-JWT/IcCTsB0Io3AhWUMjRqucrHSPsSf2xKLaRldJVULioggvkJvggZ3VXNNSRkCddE6D+BUI4HEIZIA2OjwIvg=="
},
"mime-types": {
"version": "2.1.19",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.19.tgz",
"integrity": "sha512-P1tKYHVSZ6uFo26mtnve4HQFE3koh1UWVkp8YUC+ESBHe945xWSoXuHHiGarDqcEZ+whpCDnlNw5LON0kLo+sw==",
"requires": {
"mime-db": "~1.35.0"
}
},
"minimatch": { "minimatch": {
"version": "3.0.4", "version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",

View File

@ -1,6 +1,6 @@
{ {
"name": "@pushrocks/smartrequest", "name": "@pushrocks/smartrequest",
"version": "1.0.18", "version": "1.1.6",
"private": false, "private": false,
"description": "dropin replacement for request", "description": "dropin replacement for request",
"main": "dist/index.js", "main": "dist/index.js",
@ -23,7 +23,9 @@
}, },
"homepage": "https://gitlab.com/pushrocks/smartrequest#README", "homepage": "https://gitlab.com/pushrocks/smartrequest#README",
"dependencies": { "dependencies": {
"@pushrocks/smartpromise": "^2.0.5" "@pushrocks/smartpromise": "^2.0.5",
"@types/form-data": "^2.2.1",
"form-data": "^2.3.2"
}, },
"devDependencies": { "devDependencies": {
"@gitzone/tsrun": "^1.1.9", "@gitzone/tsrun": "^1.1.9",

View File

@ -22,8 +22,18 @@ tap.test('should post a JSON document over http', async () => {
.equal('fa4c6baa0812e5b5c80ed8885e55a8a6'); .equal('fa4c6baa0812e5b5c80ed8885e55a8a6');
}); });
tap.test('should deal with unix socks', async () => { tap.skip.test('should deal with unix socks', async () => {
await expect(smartrequest.request('http://unix:/var/run/docker.sock:/containers')) const socketResponse = await smartrequest.request('http://unix:/var/run/docker.sock:/containers/json', {
headers: {
"Content-Type": "application/json",
"Host": "docker.sock"
}
});
console.log(socketResponse.body);
}); });
tap.skip.test('should correctly upload a file using formData', async () => {
})
tap.start(); tap.start();

View File

@ -1,5 +1,6 @@
export { request, extendedIncomingMessage } from './smartrequest.request'; export { request, IExtendedIncomingMessage } from './smartrequest.request';
export { ISmartRequestOptions } from './smartrequest.interfaces'; export { ISmartRequestOptions } from './smartrequest.interfaces';
export * from './smartrequest.jsonrest'; export * from './smartrequest.jsonrest';
export * from './smartrequest.binaryrest'; export * from './smartrequest.binaryrest';
export * from './smartrequest.formdata';

View File

@ -0,0 +1,62 @@
import * as plugins from "./smartrequest.plugins";
import * as interfaces from "./smartrequest.interfaces";
import { request } from "./smartrequest.request";
/**
* the interfae for FormFieldData
*/
export interface IFormField {
name: string;
type: "string" | "filePath" | "Buffer";
payload: string;
}
/**
* retrieve the FormData headers in reliable way
* @param formDataArg
*/
const getFormDataHeaders = (formDataArg: plugins.formData) => {
const done = plugins.smartpromise.defer();
formDataArg.getLength((err, length) => {
if (err) {
done.reject(err);
}
const headers = Object.assign(
{ "Content-Length": length },
formDataArg.getHeaders()
);
done.resolve(headers);
});
return done.promise;
};
const appendFormField = async (
formDataArg: plugins.formData,
formDataField: IFormField
) => {
if (formDataField.type === "filePath") {
formDataArg.append("type", "image");
let fileData = plugins.fs.createReadStream(
plugins.path.join(process.cwd(), formDataField.payload)
);
formDataArg.append("media", fileData, "upload.pdf");
}
};
export const postFormData = async (
urlArg: string,
optionsArg: interfaces.ISmartRequestOptions = {},
payloadArg: IFormField[]
) => {
const form = new plugins.formData();
for (const formField of payloadArg) {
await appendFormField(form, formField);
}
const pipeLog: any = async (...args) => {
console.log(args);
};
const requestOptions = Object.assign({}, optionsArg, { requestBody: form });
// lets fire the actual request for sending the formdata
request(urlArg, requestOptions);
};

View File

@ -1,7 +1,10 @@
import * as url from 'url'; import * as formData from 'form-data';
import * as fs from 'fs';
import * as http from 'http'; import * as http from 'http';
import * as https from 'https'; import * as https from 'https';
import * as path from 'path';
import * as url from 'url';
import * as smartpromise from '@pushrocks/smartpromise'; import * as smartpromise from '@pushrocks/smartpromise';
export { url, http, https, smartpromise }; export {formData, http, https, fs, path, url, smartpromise };

View File

@ -1,85 +1,124 @@
import * as https from 'https'; import * as https from "https";
import * as plugins from './smartrequest.plugins'; import * as plugins from "./smartrequest.plugins";
import * as interfaces from './smartrequest.interfaces'; import * as interfaces from "./smartrequest.interfaces";
import { IncomingMessage } from 'http'; import { IncomingMessage } from "http";
export interface extendedIncomingMessage extends IncomingMessage { export interface IExtendedIncomingMessage extends IncomingMessage {
body: any; body: any;
} }
let buildResponse = (incomingMessageArg: IncomingMessage): Promise<extendedIncomingMessage> => { const buildUtf8Response = (
let done = plugins.smartpromise.defer<extendedIncomingMessage>(); incomingMessageArg: IncomingMessage
): Promise<IExtendedIncomingMessage> => {
let done = plugins.smartpromise.defer<IExtendedIncomingMessage>();
// Continuously update stream with data // Continuously update stream with data
let body = ''; let body = "";
incomingMessageArg.on('data', function(chunkArg) { incomingMessageArg.on("data", function(chunkArg) {
body += chunkArg; body += chunkArg;
}); });
incomingMessageArg.on('end', function() { incomingMessageArg.on("end", function() {
try { try {
(incomingMessageArg as extendedIncomingMessage).body = JSON.parse(body); (incomingMessageArg as IExtendedIncomingMessage).body = JSON.parse(body);
} catch (err) { } catch (err) {
(incomingMessageArg as extendedIncomingMessage).body = body; (incomingMessageArg as IExtendedIncomingMessage).body = body;
} }
done.resolve(incomingMessageArg as extendedIncomingMessage); done.resolve(incomingMessageArg as IExtendedIncomingMessage);
}); });
return done.promise; return done.promise;
}; };
/**
* determine wether a url is a unix sock
* @param urlArg
*/
const testForUnixSock = (urlArg: string): boolean => {
const unixRegex = /^(http:\/\/|https:\/\/|)unix:/;
return unixRegex.test(urlArg);
};
/**
* determine socketPath and path for unixsock
*/
const parseSocketPathAndRoute = (stringToParseArg: string) => {
const parseRegex = /(.*):(.*)/;
const result = parseRegex.exec(stringToParseArg);
return {
socketPath: result[1],
path: result[2]
}
}
export let request = async ( export let request = async (
domainArg: string, domainArg: string,
optionsArg: interfaces.ISmartRequestOptions = {}, optionsArg: interfaces.ISmartRequestOptions = {},
streamArg: boolean = false streamArg: boolean = false
): Promise<extendedIncomingMessage> => { ): Promise<IExtendedIncomingMessage> => {
let done = plugins.smartpromise.defer<any>(); let done = plugins.smartpromise.defer<any>();
// parse url
let parsedUrl: plugins.url.Url; let parsedUrl: plugins.url.Url;
if (domainArg) { parsedUrl = plugins.url.parse(domainArg);
parsedUrl = plugins.url.parse(domainArg); optionsArg.hostname = parsedUrl.hostname;
optionsArg.hostname = parsedUrl.hostname; if (parsedUrl.port) {
if (parsedUrl.port) { optionsArg.port = parseInt(parsedUrl.port);
optionsArg.port = parseInt(parsedUrl.port);
}
optionsArg.path = parsedUrl.path;
} }
if (!parsedUrl || parsedUrl.protocol === 'https:') { optionsArg.path = parsedUrl.path;
let request = plugins.https.request(optionsArg, response => {
if (streamArg) { // determine if unixsock
done.resolve(response); if(testForUnixSock(domainArg)) {
} else { const detailedUnixPath = parseSocketPathAndRoute(optionsArg.path)
buildResponse(response).then(done.resolve); optionsArg.socketPath = detailedUnixPath.socketPath;
} optionsArg.path = detailedUnixPath.path;
}); }
if (optionsArg.requestBody) {
if (typeof optionsArg.requestBody !== 'string') { // lets determine the request module to use
optionsArg.requestBody = JSON.stringify(optionsArg.requestBody); const requestModule = (() => {
} if (parsedUrl.protocol === "https:") {
request.write(optionsArg.requestBody); return plugins.https;
} else if (parsedUrl.protocol === "http:") {
return plugins.http;
} else {
throw new Error(`unsupported protocol: ${parsedUrl.protocol}`);
} }
request.on('error', e => { })() as typeof plugins.https;
console.error(e);
});
request.end(); // lets perform the actual request
} else if (parsedUrl.protocol === 'http:') { let request = requestModule.request(optionsArg);
let request = plugins.http.request(optionsArg, response => {
if (streamArg) { // lets write the requestBody
done.resolve(response); if (optionsArg.requestBody) {
} else { if (
buildResponse(response).then(done.resolve); typeof optionsArg.requestBody !== "string"
} && !(optionsArg.requestBody instanceof plugins.formData)
}); ) {
if (optionsArg.requestBody) { optionsArg.requestBody = JSON.stringify(optionsArg.requestBody);
if (typeof optionsArg.requestBody !== 'string') {
optionsArg.requestBody = JSON.stringify(optionsArg.requestBody);
}
request.write(optionsArg.requestBody); request.write(optionsArg.requestBody);
request.end();
} else if (optionsArg.requestBody instanceof plugins.formData) {
optionsArg.requestBody.pipe(request);
} }
request.on('error', e => {
console.error(e);
});
request.end();
} else { } else {
throw new Error(`unsupported protocol: ${parsedUrl.protocol}`); request.end();
} }
return done.promise;
// lets handle an error
request.on("error", e => {
console.error(e);
});
// lets handle the response
request.on("response", async response => {
if (streamArg) {
done.resolve(response);
} else {
const builtResponse = await buildUtf8Response(response)
done.resolve(builtResponse);
}
});
const result = await done.promise;
return result;
}; };