Comparing versions 5 and 6.

HttpProxyInfotron

Right now for simplicity, we only allow one output terminal on the server side which is "response".

All messages are sent via POST by default and the message will be encoded as part of the content-body

Demos that use it

  • http.html

================

Input Terminals

================ * any terminal - <type:any>

================ Output Terminals ================ response - <type:any> %error - <type:object literal>

==================== Intrinsic Properties ====================

  • path_suffix - <type: string> (i.e. /index.html )
  • uri_suffix - <type: string> (i.e. api_key=12335 )
  • method - <type:string> (i.e. 'GET' or 'POST')
  • encoding - <type:string> (i.e. 'uri-form', 'xml' or 'json')

Seung Chan Lim ( slim@maya.com )


BLUEPRINT(
"~010B4D65537A854c52A8DB720FFC0D9CDD",
[
 ["", "", null]
],
[
 "response_out"
],
function(Class)
{ 
Class.prototype._onInit = function(props) {

var a = this.dom_node.getElementsByTagName("A")[0];


if (!a || a.rel != "rpc" || !a.href || !a.getAttribute("impl")) {

throw "This is a proxy infotron: an anchor tag of the format \

/*********************************************************************/
}

if (this.dom_node.getAttribute("is_proxy") != "true") {

    throw "This is a proxy infotron: you must specify is_proxy=\"true\"";
/*********************************************************************/
}



/*************************************************************************/

this._pool = [];
this._XH_IDS = ['MSXML2.XMLHTTP.5.0',
       'MSXML2.XMLHTTP.4.0',
       'MSXML2.XMLHTTP.3.0',
       'MSXML2.XMLHTTP',
       'Microsoft.XMLHTTP'];
this._content_only = props["suppresses_status"] || false;    
this._base_uri = this.dom_node.getElementsByTagName("A")[0].href || "/";
this._path_suffix = props["path_suffix"] || "";
this._uri_suffix = props["uri_suffix"] || "";
this._method = (props["method"] || "POST").toUpperCase();
this._encoding = (props["encoding"] || "json").toLowerCase();
this._use_eval = props["auto_evaluates_response"] || false;
this._accept = props["accept_header"] || "application/x-javascript";

}

Class.prototype._onMsgDelivery = function(iterm, msg)
{
var e;

if (iterm != "%startup") {
    var type;
    var url = this._createUrl(iterm);
    var s;

    // for now we expcet back javascript cuz it's
    // the simplest
    switch (this._encoding) {
    case "json": {
    s = this._toJson(msg);
    type = "application/x-javascript";

    if (this._method == "GET") {
        s = "msg=" + escape(s);
    }
    break;
    } 
    case "uri-form": {
    s = "";
    for (key in msg) {
        s += (escape(key) + "=" + escape(msg[key]) + "&");
    }
    break;
    }
    case "xml": {
    s = this._toXmlRpc(msg);
    type = "text/xml";

    if (this._method == "GET") {
        s = "msg=" + escape(s);
    }
    break;
    }
    default: {
    this.warning("unknown encoding [" + this._encoding + "] \

defaulting to JSON");

    s = this._toJson(msg);
    type = "application/x-javascript";

    if (this._method == "GET") {
        s = "msg=" + escape(s);
    }
    break;      
    }
    }

    switch (this._method) {
    case "POST": {
        this.onRequest(["POST", 
                url + ((this._uri_suffix) ? ('?' + this._uri_suffix) : ''), 
                        {"Content-type":type,
                 "accept" : this._accept}, 
                s]);
        break;
    }
    case "GET": {
        this.onRequest(["GET", 
                url + "?" + s + ((this._uri_suffix) ? this._uri_suffix: ''), 
                        {"accept" : this._accept}, 
                s]);
    break;
    }
    default: {
    break;
    }
    }
}
};

Class.prototype.onRequest = function(msg) 
{
var xh = this.getIdleClient();

var method = msg[0], uri = msg[1];

if (xh.object) {
    this.info(method + " --> " + uri);
    var hdrs = msg[2] || {};

    if (hdrs) {
    var key, low_key;

    for (key in hdrs) {
        low_key = key.toLowerCase();
        if (key != low_key) {
        hdrs[low_key] = hdrs[key];
        delete hdrs[key];
        }
    }
    }

    var content;

    if (method == "GET") {
    content = null;
    } else {
    try {
        content = msg[3] || "";
    } catch (e) {
        this.error(e, "Missing content?");

        return;
        /*********************************************************/
    }

    if (!hdrs || !hdrs["content-type"]) {
        // has header
        hdrs["content-type"] = "plain/text";
    }
    }


    try {
    xh.object.open(msg[0], msg[1], true);
    if (hdrs) {
        var val;
        for (name in hdrs) {
        val = hdrs[name];
        xh.object.setRequestHeader(name, val);
        }
    }

    xh.object.send(content);
    } catch (e) {
    this.error(e, "Possibly malformed request: " + msg);

    return;
    /*************************************************************/
    }
} else {
    this.error("Browser does not support XMLHTTP");
}
};

Class.prototype.onReadyStateChange = function(xh, req_id) 
{       
if (xh.readyState == 4) {
    var msg;

    if (this._content_only) {
    msg = xh.responseText;
    } else { 
    msg = [xh.status, xh.responseText];
    }

    if (this._use_eval) {
    try {
        eval("msg = " + msg);
    } catch (e) {
        alert(msg);
        this.error(e, 
               "Invalid JavaScript returned from server:");
        this.postMessage("%error", xh.responseText);
        //self.debug("---");
        return;
        /*********************************************************/
    }
    }

    //self.debug("GOOD " + msg);
    if (req_id != null) {
    this.postMessage("response_out", [req_id, msg]);
    } else {
    this.postMessage("response_out", msg);
    }
}
};

Class.prototype.getIdleClient = function() 
{
var xh;

for (var i = 0; i < this._pool.length; i ++ ) {
    if (this._pool[i][0] == "idle") {
    //debug("IDLE: #"+i);
    this._pool[i][0] = "busy";
    //debug(i + " --> busy");
    if (1) {// only Safari supports XMLHttp reuse
        delete this._pool[i][1];
        xh = this._createXmlHttpObj(i);
        this._pool[i][1] = xh;
    }

    return {object:this._pool[i][1], id : i};
    /*************************************************************/
    }
}

// create a new one
xh = this._createXmlHttpObj(this._pool.length);

if (xh) {       
    this._pool.push(['busy', xh, null]);

    return {object:xh, id:this._pool.length - 1};
    /*****************************************************************/
} else {
    this.error("Could not create a new XML HTTP Client");

    return null;
    /*****************************************************************/
}
};

Class.prototype._createXmlHttpObj = function(id) 
{
// create a new one
var xh = null;
var self = this;

try {
    xh = new XMLHttpRequest();
} catch (e) {
    var n = this._XH_IDS.length;

    for (var i = 0; i < n; i ++ ) {
    try {
        xh = new ActiveXObject(this._XH_IDS[i]);

        break;
    } catch (e) {

    }
    }
}

if (xh) {
    xh.onreadystatechange = function () { 

    var o = self._pool[id][1]
    try {
        self.onReadyStateChange(o, self._pool[id][2]);
    } catch (e) {
        self.warning(e);
    }
    if (o.readyState == 4) {
        self._pool[id][0] = "idle";
        //debug(id + " --> idle");
    }
    };

    return xh;
    /*****************************************************************/
} else {

    return null;
    /*****************************************************************/
}
};

/*************************************************************************/
Class.prototype._createUrl = function(iterm)
{

return this._base_uri + "/" + 
    escape(iterm) + this._path_suffix;
}

Class.prototype._toJson = function(obj)
{
// modified from http://www.crockford.com/JSON/js.html
// being used for GOOD not evil!!
var c, i, l, s = '', v;

switch (typeof(obj)) {
case 'object':
    if (obj) {
    if (obj.constructor == Array) {
        for (i = 0; i < obj.length; ++i) {
        v = this._toJson(obj[i]);
        if (s) {
            s += ',';
        }
        s += v;
        }
        return '[' + s + ']';
    } else if (typeof obj.toString != 'undefined') {
        for (i in obj) {
        v = obj[i];
        if (typeof v != 'undefined' && typeof v != 'function') {
            v = this._toJson(v);
            if (s) {
            s += ',';
            }
            s += this._toJson(i) + ':' + v;
        }
        }
        return '{' + s + '}';
    }
    }
    return 'null';
case 'number':
    return isFinite(obj) ? (new String(obj)) : 'null';
case 'string':
    l = obj.length;
    s = '"';
    for (i = 0; i < l; i += 1) {
    c = obj.charAt(i);
    if (c >= ' ') {
        if (c == '\\' || c == '"') {
        s += '\\';
        }
        s += c;
    } else {
        switch (c) {
        case '\b':
        s += '\\b';
        break;
        case '\f':
        s += '\\f';
        break;
        case '\n':
        s += '\\n';
        break;
        case '\r':
        s += '\\r';
        break;
        case '\t':
        s += '\\t';
        break;
        default:
        c = c.charCodeAt();
        s += '\\u00' + Math.floor(c / 16).toString(16) +
            (c % 16).toString(16);
        }
    }
    }
    return s + '"';
case 'boolean':
    return (new String(obj));
default:
    return 'null';
}
}



Class.prototype._toXmlRpc = function(js)
{
if (js && js.toXmlRpc) {

    return js.toXmlRpc();
    /*****************************************************************/
} else {
    var s;

    if (typeof(js) == typeof(1)) {
    // number
    if (parseInt(js) == parseFloat(js)) {
        // int
        s = "<int>" + js.toString() + "</int>";
    } else {
        s = "<double>" + js.toString() + "</double>";
    }
    } else if (typeof(js) == typeof("")) {
    // string
    // I have to escape &, <, and >... later.. -.-;
    s = "<string>" + js + "</string>";
    } else if (typeof(js) == typeof(true)) {
    // bool
    s = "<boolean>" + js.toString() + "</boolean>";
    }  else if (js == null) {
    s = "<struct><member><name>type</name><value>null</value></member></struct>"
    } else if (js.constructor == Date) {
    var y, m, d, h, mi, se;
    // date
    y = js.getFullYear();
    m = js.getMonth() + 1;
    d = js.getDate();
    h = js.getHours();
    mi = js.getMinutes();
    se = js.getSeconds();

    if (d < 10) {
        d = "0" + d;
    }
    if (m < 10) {
        m = "0" + m;
    }
    if (h < 10) {
        h = "0" + h;
    }
    if (mi < 10) {
        mi = "0" + mi;
    }
    if (se < 10) {
        se = "0" + se;
    }
    s = "<dateTime.iso8601>" + 
        ( new String(y) + new String(m) + new String(d) + 
          "T" + h + ":" + mi + ":" + se) + 
        "</dateTime.iso8601>";

    } else if (js.constructor == Array) {
    // array
    var i;

    s = "<array><data>";

    for (i = 0; i < js.length; i ++) {
        s += "<value>" + this._toXmlRpc(js[i]) + "</value>";
    }
    s += "</data></array>";
    } else if (typeof(js) == "object") {
    // object
    var key;

    s = "<struct>";

    for (key in js) {
        s += "<member><name>" + key + "</name><value>" +  
        this._toXmlRpc(js[key]) + "</value></member>";
    }
    s += "</struct>";
    }


    return s;
}
}

}, "Server Infotron Proxy");

History Key

  • New content
  • Removed content

Recent Versions

Choose two versions to compare, or click the link to view it.

  1. 6. about 1 year by slim
  2. 5. about 1 year by xexamedes
  3. 4. about 1 year by xexamedes
  4. 3. about 1 year by xexamedes
  5. 2. about 1 year by xexamedes
  6. 1. about 1 year by xexamedes