ember-introjs
Version:
An Ember Component for intro.js
190 lines (171 loc) • 5.9 kB
JavaScript
/**
* HTTP Client using the JSGI standard objects
*/
({define:typeof define!="undefined"?define:function(deps, factory){module.exports = factory.apply(this, deps.slice(0,2).map(require).concat(require))}}).
define(["./promise", "./process", "require"],
function(promise, process, require){
var defer = promise.defer,
when = promise.when,
print = process.print,
request;
if(typeof XMLHttpRequest === "undefined"){
request = require("./engines/node/http-client").request;
}
else{
request = function(request){
var
scheme = request.scheme || "http",
serverName = request.serverName || request.hostname || "localhost",
serverPort = request.serverPort || request.port || 80,
xhr = new XMLHttpRequest();
xhr.open(request.method || "GET",
request.url || // allow request.url to shortcut creating a URL from all the various parts
(scheme + "://" + serverName + ":" + serverPort + request.pathInfo + (request.queryString ? '?' + request.queryString : '')), true);
for(var i in request.headers){
xhr.setRequestHeader(i, request.headers[i]);
}
var deferred = defer(),
response,
lastUpdate;
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 || xhr.readyState == 3){
if(!response){
response = {
body: [xhr.responseText],
status: xhr.status,
headers: {}
};
lastUpdate = xhr.responseText.length;
var headers = xhr.getAllResponseHeaders();
headers = headers.split(/\n/);
for(var i = 0; i < headers.length; i++){
var nameValue = headers[i].split(": ", 2);
if(nameValue){
var name = nameValue[0];
response.headers[name.toLowerCase()] = xhr.getResponseHeader(name);
}
}
}
else{
response.body = [xhr.responseText];
lastUpdate = xhr.responseText.length;
}
if(xhr.readyState == 4){
deferred.resolve(response);
}
else{
deferred.progress(response);
}
}
}
xhr.send(request.body && request.body.toString());
return deferred.promise;
}
}
// for back-compat
request.request = request;
// FIXME this way too naive
var isRedirect = request.isRedirect = function(response){
return [301,302,303,307].indexOf(response.status) >= 0;
}
request.Redirect = function(nextApp, maxRedirects){
maxRedirects = maxRedirects || 10;
return function(request){
var remaining = maxRedirects,
deferred = defer();
function next(){
when(nextApp(request), function(response) {
if(remaining--){
// TODO cache safe redirects when cache is added
if(isRedirect(response)){
request.url = response.headers.location;
next();
}else{
deferred.resolve(response);
}
}else{
if(isRedirect(response)) print("Maximum redirects reached")
deferred.resolve(response);
}
}, deferred.reject);
}
next();
return deferred.promise;
}
}
request.CookieJar = function(nextApp) {
var domainToCookies = {};
return function(req) {
var
querystring = require("./querystring"),
parseUri = require("./util/uri").parseUri;
if (req.url) {
var url = parseUri(req.url);
req.hostname = url.host;
req.port = url.port;
req.pathInfo = url.path;
req.authority = url.authority;
}
if (req.hostname && domainToCookies[req.hostname]) {
var cookieString = "";
req.headers["Cookie"] = domainToCookies[req.hostname].map(function(cookie) {
return querystring.toQueryString(cookie);
}).join(',');
}
return when(nextApp(req), function(response) {
var cookies;
if (response.headers["set-cookie"]) {
var path, domain = req.hostname + (req.port ? ":"+req.port : "");
if (Array.isArray(response.headers["set-cookie"])) {
cookies = [];
response.headers["set-cookie"].forEach(function(cookie) {
cookie = querystring.parseQuery(cookie, /[;,]/g);
if (cookie.Version !== undefined) { delete cookie.Version; }
if (cookie.Path !== undefined) { path = cookie.Path; delete cookie.Path; }
if (cookie.HttpOnly !== undefined) { delete cookie.HttpOnly; }
if (cookie.Domain !== undefined) { domain = cookie.Domain; delete cookie.Domain; }
cookies.push(cookie);
});
} else {
cookies = querystring.parseQuery(response.headers["set-cookie"], /[;,]/g);
if (cookies.Version !== undefined) { delete cookies.Version; }
if (cookies.Path !== undefined) { path = cookies.Path; delete cookies.Path; }
if (cookies.HttpOnly !== undefined) { delete cookies.HttpOnly; }
if (cookies.Domain !== undefined) { domain = cookies.Domain; delete cookies.Domain; }
cookies = [ cookies ];
}
for (var k in cookies) {
if (Array.isArray(cookies[k])) {
cookies[k] = cookies[k][0];
}
}
if (cookies) {
domainToCookies[req.hostname] = cookies;
}
}
return response;
});
};
};
// TODO request.Cache
// TODO request.CookieJar
request.Client = function(options) {
if (!(this instanceof request.Client)) return new request.Client(options);
options = options || {};
for (var key in options) {
this[key] = options[key];
}
this.request = request;
// turn on redirects by default
var redirects = "redirects" in this ? this.redirects : 20;
if (redirects) {
this.request = request.CookieJar(request.Redirect(this.request, typeof redirects === "number" && redirects));
}
var finalRequest = this.request;
this.request = function(options) {
if (typeof options === "string") options = {url: options};
return finalRequest(options);
}
}
return request;
});