function makeRequest(params, callback) {
    const { hostname, port, method, queryObj, headers, path,
            authCredentials, requestBody, jsonResponse,
            urlForSignature } = params;
    const options = {
        hostname,
        port,
        method,
        headers,
        path: path || '/',
        rejectUnauthorized: false,
    };
    const qs = querystring.stringify(queryObj);

    if (params.GCP && authCredentials) {
        const gcpPath = queryObj ? `${options.path}?${qs}` : options.path;
        const getAuthObject = {
            endpoint: { host: hostname },
            method,
            path: gcpPath || '/',
            headers,
        };
        const signer = new GcpSigner(getAuthObject);
        signer.addAuthorization(authCredentials, new Date());
        Object.assign(options.headers, {
            Authorization: getAuthObject.headers.Authorization,
            Date: getAuthObject.headers['x-goog-date'],
        });
    }

    const req = transport.request(options, res => {
        const body = [];
        res.on('data', chunk => {
            body.push(chunk);
        });
        res.on('error', err => {
            process.stdout.write('err receiving response');
            return callback(err);
        });
        res.on('end', () => {
            const total = body.join('');
            const data = {
                headers: res.headers,
                statusCode: res.statusCode,
                body: total,
            };
            const err = _parseError(total, res.statusCode, jsonResponse);
            if (err) {
                err.statusCode = res.statusCode;
            }
            return callback(err, data);
        });
    });
    req.on('error', err => {
        process.stdout.write('err sending request');
        return callback(err);
    });
    // generate v4 headers if authentication credentials are provided
    const savedPath = req.path;
    const encodedPath = urlForSignature || req.path;
    // decode path because signing code re-encodes it
    req.path = _decodeURI(encodedPath);
    if (authCredentials && !params.GCP) {
        auth.client.generateV4Headers(req, queryObj || '',
            authCredentials.accessKey, authCredentials.secretKey, 's3', undefined, undefined, requestBody);
    }
    // restore original URL-encoded path
    req.path = savedPath;
    if (queryObj) {
        req.path = `${options.path}?${qs}`;
    }
    if (requestBody) {
        req.write(requestBody);
    }
    req.end();
}
makeRequest - utility function to generate a request
@param {object} params - params for making request
@param {string} params.hostname - request hostname
@param {number} [params.port] - request port
@param {string} params.method - request method
@param {object} [params.queryObj] - query fields and their string values
@param {object} [params.headers] - headers and their string values
@param {string} [params.path] - URL-encoded request path
@param {object} [params.authCredentials] - authentication credentials
@param {string} params.authCredentials.accessKey - access key
@param {string} params.authCredentials.secretKey - secret key
@param {boolean} params.GCP - flag to setup for GCP request
@param {string} [params.requestBody] - request body contents
@param {string} [params.urlForSignature] - the url to use when signing the
  request
@param {boolean} [params.jsonResponse] - if true, response is
  expected to be received in JSON format (including errors)
@param {function} callback - with error and response parameters
@return {undefined} - and call callback