UNPKG

nodulator

Version:

Complete NodeJS Framework for Restfull APIs

175 lines (145 loc) 4.89 kB
/* * Copyright 2012-2014 the original author or authors * @license MIT, see LICENSE.txt for details * * @author Scott Andrews */ (function (define, global) { 'use strict'; define(function (require) { var when, UrlBuilder, normalizeHeaderName, responsePromise, client, headerSplitRE; when = require('when'); UrlBuilder = require('../UrlBuilder'); normalizeHeaderName = require('../util/normalizeHeaderName'); responsePromise = require('../util/responsePromise'); client = require('../client'); // according to the spec, the line break is '\r\n', but doesn't hold true in practice headerSplitRE = /[\r|\n]+/; function parseHeaders(raw) { // Note: Set-Cookie will be removed by the browser var headers = {}; if (!raw) { return headers; } raw.trim().split(headerSplitRE).forEach(function (header) { var boundary, name, value; boundary = header.indexOf(':'); name = normalizeHeaderName(header.substring(0, boundary).trim()); value = header.substring(boundary + 1).trim(); if (headers[name]) { if (Array.isArray(headers[name])) { // add to an existing array headers[name].push(value); } else { // convert single value to array headers[name] = [headers[name], value]; } } else { // new, single value headers[name] = value; } }); return headers; } function safeMixin(target, source) { Object.keys(source || {}).forEach(function (prop) { // make sure the property already exists as // IE 6 will blow up if we add a new prop if (source.hasOwnProperty(prop) && prop in target) { try { target[prop] = source[prop]; } catch (e) { // ignore, expected for some properties at some points in the request lifecycle } } }); return target; } return client(function xhr(request) { return responsePromise.promise(function (resolve, reject) { /*jshint maxcomplexity:20 */ var client, method, url, headers, entity, headerName, response, XMLHttpRequest; request = typeof request === 'string' ? { path: request } : request || {}; response = { request: request }; if (request.canceled) { response.error = 'precanceled'; reject(response); return; } entity = request.entity; request.method = request.method || (entity ? 'POST' : 'GET'); method = request.method; url = response.url = new UrlBuilder(request.path || '', request.params).build(); XMLHttpRequest = request.engine || global.XMLHttpRequest; if (!XMLHttpRequest) { reject({ request: request, url: url, error: 'xhr-not-available' }); return; } try { client = response.raw = new XMLHttpRequest(); // mixin extra request properties before and after opening the request as some properties require being set at different phases of the request safeMixin(client, request.mixin); client.open(method, url, true); safeMixin(client, request.mixin); headers = request.headers; for (headerName in headers) { /*jshint forin:false */ if (headerName === 'Content-Type' && headers[headerName] === 'multipart/form-data') { // XMLHttpRequest generates its own Content-Type header with the // appropriate multipart boundary when sending multipart/form-data. continue; } client.setRequestHeader(headerName, headers[headerName]); } request.canceled = false; request.cancel = function cancel() { request.canceled = true; client.abort(); reject(response); }; client.onreadystatechange = function (/* e */) { if (request.canceled) { return; } if (client.readyState === (XMLHttpRequest.DONE || 4)) { response.status = { code: client.status, text: client.statusText }; response.headers = parseHeaders(client.getAllResponseHeaders()); response.entity = client.responseText; if (response.status.code > 0) { // check status code as readystatechange fires before error event resolve(response); } else { // give the error callback a chance to fire before resolving // requests for file:// URLs do not have a status code setTimeout(function () { resolve(response); }, 0); } } }; try { client.onerror = function (/* e */) { response.error = 'loaderror'; reject(response); }; } catch (e) { // IE 6 will not support error handling } client.send(entity); } catch (e) { response.error = 'loaderror'; reject(response); } }); }); }); }( typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); }, typeof window !== 'undefined' ? window : void 0 // Boilerplate for AMD and Node ));