| "use strict"; |
| |
| var request = require('request'); |
| |
| var buffer = require('./buffer'); |
| var errors = require('./errors'); |
| var utils = require('../utils'); |
| |
| function ajax(options, adapterCallback) { |
| |
| var requestCompleted = false; |
| var callback = utils.getArguments(function (args) { |
| if (requestCompleted) { |
| return; |
| } |
| adapterCallback.apply(this, args); |
| requestCompleted = true; |
| }); |
| |
| if (typeof options === "function") { |
| callback = options; |
| options = {}; |
| } |
| |
| options = utils.clone(options); |
| |
| var defaultOptions = { |
| method : "GET", |
| headers: {}, |
| json: true, |
| processData: true, |
| timeout: 10000, |
| cache: false |
| }; |
| |
| options = utils.extend(true, defaultOptions, options); |
| |
| |
| function onSuccess(obj, resp, cb) { |
| if (!options.binary && !options.json && options.processData && |
| typeof obj !== 'string') { |
| obj = JSON.stringify(obj); |
| } else if (!options.binary && options.json && typeof obj === 'string') { |
| try { |
| obj = JSON.parse(obj); |
| } catch (e) { |
| // Probably a malformed JSON from server |
| return cb(e); |
| } |
| } |
| if (Array.isArray(obj)) { |
| obj = obj.map(function (v) { |
| if (v.error || v.missing) { |
| return errors.generateErrorFromResponse(v); |
| } else { |
| return v; |
| } |
| }); |
| } |
| cb(null, obj, resp); |
| } |
| |
| function onError(err, cb) { |
| var errParsed, errObj; |
| if (err.code && err.status) { |
| var err2 = new Error(err.message || err.code); |
| err2.status = err.status; |
| return cb(err2); |
| } |
| try { |
| errParsed = JSON.parse(err.responseText); |
| //would prefer not to have a try/catch clause |
| errObj = errors.generateErrorFromResponse(errParsed); |
| } catch (e) { |
| errObj = errors.generateErrorFromResponse(err); |
| } |
| cb(errObj); |
| } |
| |
| |
| if (options.json) { |
| if (!options.binary) { |
| options.headers.Accept = 'application/json'; |
| } |
| options.headers['Content-Type'] = options.headers['Content-Type'] || |
| 'application/json'; |
| } |
| |
| if (options.binary) { |
| options.encoding = null; |
| options.json = false; |
| } |
| |
| if (!options.processData) { |
| options.json = false; |
| } |
| |
| function defaultBody(data) { |
| if (process.browser) { |
| return ''; |
| } |
| return new buffer('', 'binary'); |
| } |
| |
| return request(options, function (err, response, body) { |
| if (err) { |
| err.status = response ? response.statusCode : 400; |
| return onError(err, callback); |
| } |
| |
| var error; |
| var content_type = response.headers && response.headers['content-type']; |
| var data = body || defaultBody(); |
| |
| // CouchDB doesn't always return the right content-type for JSON data, so |
| // we check for ^{ and }$ (ignoring leading/trailing whitespace) |
| if (!options.binary && (options.json || !options.processData) && |
| typeof data !== 'object' && |
| (/json/.test(content_type) || |
| (/^[\s]*\{/.test(data) && /\}[\s]*$/.test(data)))) { |
| data = JSON.parse(data); |
| } |
| |
| if (response.statusCode >= 200 && response.statusCode < 300) { |
| onSuccess(data, response, callback); |
| } else { |
| if (options.binary) { |
| data = JSON.parse(data.toString()); |
| } |
| error = errors.generateErrorFromResponse(data); |
| error.status = response.statusCode; |
| callback(error); |
| } |
| }); |
| } |
| |
| module.exports = ajax; |