You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
125 lines
3.4 KiB
125 lines
3.4 KiB
const url = require('url') |
|
const hyperquest = require('hyperquest') |
|
const bl = require('bl') |
|
const stringify = require('json-stringify-safe') |
|
|
|
function HttpError (message) { |
|
SyntaxError.call(this, message) |
|
Error.captureStackTrace(this, arguments.callee) |
|
} |
|
|
|
HttpError.prototype = Object.create(SyntaxError.prototype) |
|
HttpError.prototype.constructor = HttpError |
|
|
|
function collector (uri, options, callback) { |
|
var request = makeRequest(uri, options) |
|
var redirect = null |
|
var redirectCount = 0 |
|
|
|
return handle(request) |
|
|
|
function handle (request) { |
|
if (options.followRedirects) { |
|
request.on('response', (response) => { |
|
redirect = isRedirect(request.request, response) && response.headers.location |
|
}) |
|
} |
|
|
|
request.pipe(bl((err, data) => { |
|
if (redirect) { |
|
if (++redirectCount >= (typeof options.followRedirects === 'number' ? options.followRedirects : 10)) { |
|
return callback(new Error('Response was redirected too many times (' + redirectCount + ')')) |
|
} |
|
request = makeRequest(url.resolve(uri, redirect), options) |
|
redirect = null |
|
return handle(request) |
|
} |
|
|
|
if (err) { |
|
return callback(err) |
|
} |
|
|
|
if (!data.length) { |
|
return callback(null, null, request.response) |
|
} |
|
|
|
var ret, msg |
|
|
|
try { |
|
ret = JSON.parse(data.toString()) |
|
} catch (e) { |
|
msg = 'JSON parse error: ' + e.message |
|
err = request.response.statusCode >= 300 ? new HttpError(msg) : new SyntaxError(msg) |
|
|
|
err.statusCode = request.response.statusCode |
|
err.data = data |
|
err.response = request.response |
|
|
|
return callback(err) |
|
} |
|
|
|
callback(null, ret, request.response) |
|
})) |
|
|
|
return request |
|
} |
|
} |
|
|
|
function makeMethod (method, data) { |
|
function handler (uri, options, callback) { |
|
var defaultOptions = { method, headers: {} } |
|
if (typeof options === 'object') { |
|
options = Object.assign(defaultOptions, options) |
|
} else { |
|
callback = options |
|
options = defaultOptions |
|
} |
|
|
|
if (data && typeof options.headers['content-type'] !== 'string') { |
|
options.headers['content-type'] = 'application/json' |
|
} |
|
if (typeof options.headers['accept'] !== 'string') { |
|
options.headers['accept'] = 'application/json' |
|
} |
|
|
|
return collector(uri, options, callback) |
|
} |
|
|
|
function dataHandler (uri, data, options, callback) { |
|
var request = handler(uri, options, callback) |
|
|
|
if (typeof data.pipe === 'function') { |
|
data.pipe(request) |
|
} else { |
|
request.end(stringify(data)) |
|
} |
|
|
|
return request |
|
} |
|
|
|
return data ? dataHandler : handler |
|
} |
|
|
|
function makeRequest (uri, options) { |
|
return (options.hyperquest || hyperquest)(uri, options) |
|
} |
|
|
|
function isRedirect (request, response) { |
|
return request.method === 'GET' && |
|
response.headers.location && |
|
(response.statusCode === 301 || |
|
response.statusCode === 302 || |
|
response.statusCode === 307 || |
|
response.statusCode === 308 |
|
) |
|
} |
|
|
|
module.exports.get = makeMethod('GET', false) |
|
module.exports.post = makeMethod('POST', true) |
|
module.exports.put = makeMethod('PUT', true) |
|
module.exports.delete = function deleteHandler (uri, options, callback) { |
|
// behaves half-way between a data posting request and a GET |
|
// since https://github.com/substack/hyperquest/commit/9b130e101 |
|
return makeMethod('DELETE', false)(uri, options, callback).end() |
|
} |
|
module.exports.HttpError = HttpError
|
|
|