/** * 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; });