UNPKG

azure

Version:
208 lines (188 loc) 6.59 kB
// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. 'use strict'; const request = require('request'); const through = require('through'); const duplexer = require('duplexer'); const Constants = require('./constants'); const utils = require('./utils'); const HttpVerbs = Constants.HttpConstants.HttpVerbs; // // Request pipelines are functions that allow you to // add filters to modify requests and responses // before / after the actual HTTP request. // /** * * create a new http client pipeline that ends with a call to the * request library using the given sink function to actually make * the http request. * * @return function(request, callback) - function to make a request. * */ exports.createWithSink = function(sink) { let pipeline = sink; // The function that actually runs the pipeline. It starts simple function runFilteredRequest(options, callback) { return pipeline(options, callback); } function makeFilteredPipeline(filter) { let currentPipeline = pipeline; return function (options, callback) { return filter(options, currentPipeline, callback); }; } // Add 'add' method so we can add filters. runFilteredRequest.add = function add() { let argumentList = utils.objectValues(arguments); argumentList.forEach((filter) => { pipeline = makeFilteredPipeline(filter); }); }; // Add verb specific helper methods let verbs = Object.keys(HttpVerbs); verbs.forEach((method) => { runFilteredRequest[method] = ((m) => { return (options, callback) => { options.method = m; return pipeline(options, callback); }; })(method); }); // If user passed any other parameters, assume they're filters // and add them. for(let i = 1; i < arguments.length; ++i) { runFilteredRequest.add(arguments[i]); } return runFilteredRequest; }; /** * This function acts as the final sink for a request, actually * going out over the wire. * * @param {Object} [requestOptions] - The request options * {@link https://github.com/request/request#requestoptions-callback Options doc} * * @private * @param options The request to perform * @param callback function(err, result, response, body) callback function that * will be called at completion of the request. */ exports.requestLibrarySink = function requestLibrarySink (requestOptions) { return (options, callback) => { let defaultRequest = request.defaults(requestOptions); let requestStream, bodyStream, requestHeaderStream; if (options.headersOnly) { requestHeaderStream = defaultRequest(options); requestHeaderStream.on('error', (err) => { return callback(err); }); requestHeaderStream.on('response', (response) => { requestHeaderStream.on('end', () => { return callback(null, response); }); }); return requestHeaderStream; } else if (options.streamedResponse) { if (options.body && typeof options.body.pipe === 'function') { bodyStream = options.body; options.body = null; requestStream = bodyStream.pipe(defaultRequest(options)); } else { requestStream = defaultRequest(options); } requestStream.on('error', (err) => { return callback(err); }); requestStream.on('response', (response) => { return callback(null, response); }); return requestStream; } else if (options.body && typeof options.body.pipe === 'function') { bodyStream = options.body; options.body = null; return bodyStream.pipe(defaultRequest(options, (err, response, body) => { if (err) { return callback(err); } return callback(null, response, body); })); } else { return defaultRequest(options, (err, response, body) => { if (err) { return callback(err); } return callback(null, response, body); }); } }; }; /** * * create a new http client pipeline that ends with a call to the * request library. * * @param {Object} [requestOptions] - The request options * {@link https://github.com/request/request#requestoptions-callback Options doc} * * @return function(request, callback) - function to make a request. * */ exports.create = function (requestOptions) { return function () { if (arguments.length === 0) { return exports.createWithSink(exports.requestLibrarySink(requestOptions)); } // User passed filters to add to the pipeline. // build up appropriate arguments and call exports.createWithSink return exports.createWithSink.apply(null, [exports.requestLibrarySink(requestOptions)].concat(utils.objectValues(arguments))); }; }; /** * Create a new filter that's a combination of all the filters * given on the arguments list. * * @param {varargs} filters to run. First filter in the list is closest to * the sink, so last to run before the request, first to run on the response: * exactly the same as if you called pipeline.add or passed the list to * pipeline.create. * * @return the new filter. */ exports.createCompositeFilter = function createCompositeFilter() { let filter = arguments[0]; function makePairedFilter(filterA, filterB) { return (options, next, callback) => { function callFilterA(o, cb) { return filterA(o, next, cb); } return filterB(options, callFilterA, callback); }; } for(let i = 1; i < arguments.length; ++i) { filter = makePairedFilter(filter, arguments[i]); } return filter; }; /** * Creates an interim stream which can be returned to the * caller synchronously, so that async operations can still * hook up to the streaming output afterwards. Used when * filters need to do async work before they can call the rest * of the pipeline. * * @param setPipe function(input, output) * this function is invoked synchronously, to pass the two * underlying streams. input should be piped to the result of * the next filter. The result of next should be piped to output. * It's common to pause the input stream to prevent data loss * before actually returning the real stream to hook up to. * * @returns a duplex stream that writes to the input stream and * produces data from the output stream. */ exports.interimStream = function(setPipes) { let input = through(); let output = through(); let duplex = duplexer(input, output); setPipes(input, output); return duplex; }; exports = module.exports;