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