[Laszlo-checkins] r8635 - in openlaszlo/trunk: WEB-INF/lps/lfc/data WEB-INF/lps/lfc/kernel/swf WEB-INF/lps/server/src/org/openlaszlo/data demos/vacation-survey test/data test/lfc/data

hqm@openlaszlo.org hqm at openlaszlo.org
Fri Apr 11 12:23:13 PDT 2008


Author: hqm
Date: 2008-04-11 12:23:04 -0700 (Fri, 11 Apr 2008)
New Revision: 8635

Added:
   openlaszlo/trunk/test/lfc/data/testgetmethod.lzx
   openlaszlo/trunk/test/lfc/data/testgetmethodsolo.lzx
   openlaszlo/trunk/test/lfc/data/testpostmethod.lzx
   openlaszlo/trunk/test/lfc/data/testpostmethodsolo.lzx
Modified:
   openlaszlo/trunk/WEB-INF/lps/lfc/data/LzDataset.lzs
   openlaszlo/trunk/WEB-INF/lps/lfc/data/LzHTTPDataProvider.lzs
   openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf/LzHTTPLoader.as
   openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf/LzLoadQueue.as
   openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf/LzLoader.lzs
   openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/data/HTTPDataSource.java
   openlaszlo/trunk/demos/vacation-survey/vacation-survey.lzx
   openlaszlo/trunk/test/data/data-url.lzx
   openlaszlo/trunk/test/lfc/data/alldata.lzx
Log:
Change 20080411-hqm-4 by hqm at badtzmaru.home on 2008-04-11 15:22:41 EDT
    in /Users/hqm/openlaszlo/trunk5
    for http://svn.openlaszlo.org/openlaszlo/trunk

Summary:  fix for XML RPC, and some other brain damage in data loader

New Features:

Bugs Fixed: LPP-5481

Technical Reviewer: max
QA Reviewer: pbr
Doc Reviewer: (pending)

Documentation:

Release Notes:

Details:

+ A while back we discovered that that data loading API would not let
you POST data to a url while also supporting an independent query
string in the URL.

So I had made some fixes for that, both in SOLO and proxied mode.  In
proxied mode I moved the place where the POST payload was stored out
of the "url" arg.

That caused some trouble because there is older code in
XMLRPCDataSource.java which expects to be able to stick
"lzpostbody=DATA" into the url and call the
HTTPDataSource.getHTTPData() method, which no longer expects to see
that data there.

I fixed this by putting back the code to look for the "lzpostbody" arg
inside the URL as well as in the proxy request parameters.

Sorry this is so baroque. The main idea going forward is that we have
the LzHTTPLoader API which looks like the javascript XMLHTTPRequest.
Everything in LzHTTPDataProvider is geared to talk to that API; a URL
with query args, and an optional POST content string.

The SWF kernel loader code has to then unpack that and make it work
with the brain-dead Flash LoadVars HTTP API as much as possible, in
solo and proxied mode.


Tests:

test/lfc/data/alldata.lzx, in dhtml and swf
demos/amazon
XMLRPC test case in bug report



Modified: openlaszlo/trunk/WEB-INF/lps/lfc/data/LzDataset.lzs
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/lfc/data/LzDataset.lzs	2008-04-11 19:11:17 UTC (rev 8634)
+++ openlaszlo/trunk/WEB-INF/lps/lfc/data/LzDataset.lzs	2008-04-11 19:23:04 UTC (rev 8635)
@@ -200,7 +200,7 @@
   * '__lzbc__=1204685840777'.  This is to prevent client caching.
   * @type Boolean
   */
-var clientcacheable = true;
+var clientcacheable = false;
 
 /** A string to be appended to the request that
   * the dataset makes. 
@@ -683,14 +683,28 @@
         dreq.queryparams = this.params;
     }
 
-    // Support for 'lzpostbody'
-    var lzpostbody = null;
-    if (dreq.queryparams) {
-        lzpostbody = dreq.queryparams.getValue('lzpostbody');
+    // Support for 'lzpostbody'.  If this is a POST, set
+    // the DataRequest.postbody field to the lzpostbody value.
+    // 
+    if (this.querytype.toUpperCase() == "POST") {
+        var lzpostbody = null;
+        if (dreq.queryparams) {
+            lzpostbody = dreq.queryparams.getValue('lzpostbody');
+        }
+        // If there is a lzpostbody query arg, we are going to remove
+        // it from the query args, and set it as the dreq.postbody
+        // arg.  Note: In SOLO mode, the DHTML runtime can actually
+        // support raw POST via the XMLHTTPRequest API.
+        //
+        // The Flash swf8 native API has no way to support POST of
+        // arbitrary raw data in SOLO mode; the best we can do is to
+        // send a list of url-encoded key=value pairs.
+        // 
+        if (lzpostbody != null) { 
+            dreq.postbody = lzpostbody;
+            dreq.queryparams.remove('lzpostbody');
+        }
     }
-    if (lzpostbody != null) { 
-        dreq.postbody = lzpostbody;
-    }
 
     dreq.proxied            = this.isProxied();
 

Modified: openlaszlo/trunk/WEB-INF/lps/lfc/data/LzHTTPDataProvider.lzs
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/lfc/data/LzHTTPDataProvider.lzs	2008-04-11 19:11:17 UTC (rev 8634)
+++ openlaszlo/trunk/WEB-INF/lps/lfc/data/LzHTTPDataProvider.lzs	2008-04-11 19:23:04 UTC (rev 8635)
@@ -160,50 +160,52 @@
             postbody = q;
         }
 
+        var lzurl = new LzURL(dreq.src);
+
+        // For GET requests, merge in params data with URL query 
+        if (dreq.method == "GET") {
+            if (lzurl.query != null) {
+                lzurl.query = lzurl.query + "&" + postbody;
+            } else {
+                lzurl.query = postbody;
+            }
+            postbody = null;
+        }
+
+
         // [LPP-5368] If this is a SOLO POST request, with an empty
         // POST body, put the 'cache-breaking' arg into this post
         // body. This prevents the case of an empty POST body, which
         // would cause the Flash player to turn it into a GET request.
+        //
+        // We are going to go ahead and do this for all platforms, not
+        // just SWF, in order to make things more consistent for the
+        // app developer; they will get this magic arg added across
+        // all platforms.
         if (!proxied && (dreq.method == "POST") && (postbody == null || postbody == ''))  {
             postbody = cachebreak;
         }
 
-        var lzurl = new LzURL(dreq.src);
-        
-        // For GET requests, merge in params data with URL query 
-        if (dreq.method == "GET") {
-            if (postbody != null) {
-                if (lzurl.query != null) {
-                    lzurl.query = lzurl.query + "&" + postbody;
-                } else {
-                    lzurl.query = postbody;
-                }
-                postbody = null;
-            }
-        }
-
         // convert url back to string
         var url = lzurl.toString();
         if (proxied) {
             // TODO [hqm 2007-08-03] make the API for makeProxiedURL take an explicit host arg,
             // so we can set the proxy from user code
             url = tloader.makeProxiedURL(url, dreq.method, "xmldata" , headers, postbody);
+
             // We need to move the proxy string query data to the
-            // postbody, can't leave it in the URL string, it could be
-            // arbitrarily long.
+            // postbody; can't leave it in the URL string since it
+            // could be arbitrarily long.
             var marker = url.indexOf('?');
             var uquery = url.substring(marker+1, url.length);
             var url_noquery = url.substring(0,marker);
             url = url_noquery + '?' + cachebreak;
             postbody = uquery;
-            //Debug.write("proxied req url: ", url, ', postbody: ',postbody)
+
         }  else {
             // break the browser cache by adding a unique string to the url
             if (!dreq.clientcacheable) {
-                if (dreq.method == "POST") {
-                    //POST case:
-                    // cache break arg already added to post body
-                } else {
+                if (dreq.method == "GET") {
                     // GET case: add to url query portion
                     if (lzurl.query == null) {
                         lzurl.query = cachebreak;
@@ -217,7 +219,6 @@
         }
    
         dreq.status =  "loading";
-        //Debug.write("calling tloader.open", proxied ? "POST" : dreq.method, url, "dreq.method=", dreq.method);
         tloader.open ( proxied ? "POST" : dreq.method, url, /* username */ null, /* password */ null);
         tloader.send (/* content */ postbody);
     }

Modified: openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf/LzHTTPLoader.as
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf/LzHTTPLoader.as	2008-04-11 19:11:17 UTC (rev 8634)
+++ openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf/LzHTTPLoader.as	2008-04-11 19:23:04 UTC (rev 8635)
@@ -157,7 +157,6 @@
 }
 
 LzHTTPLoader.prototype.send = function (content) {
-    //Debug.write('LzHTTPLoader.prototype.send', this, this.lzloader);
     this.xmlrequestobj.rawpostbody = content;
     this.lzloader.setHeaders(this.requestheaders);
     this.lzloader.requestDirectXML( this.xmlrequestobj );
@@ -219,7 +218,6 @@
         sep = "&";
     }
 
-    //Debug.write('makeProxiedURL url:',url, 'reqtype:', reqtype,' proxyurl:', proxyurl);
     return proxyurl;
 }
 

Modified: openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf/LzLoadQueue.as
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf/LzLoadQueue.as	2008-04-11 19:11:17 UTC (rev 8634)
+++ openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf/LzLoadQueue.as	2008-04-11 19:23:04 UTC (rev 8635)
@@ -111,7 +111,6 @@
             return;
         }
 
-      //Debug.write("LzLoadQueue.XMLOnDataHandler success", this, this.loader);
       // Create a queue containing one root node, myself, and convert it and all children to
       // LzDataNodes.
 
@@ -424,9 +423,9 @@
 LzLoadQueue.loadXML = function (loadobj) {
     // Set the onData handler to intercept returning data
     loadobj.onData = LzLoadQueue.XMLOnDataHandler;
+
     var dopost = (loadobj.reqtype.toUpperCase() == 'POST');
-    
-    //
+
     /*
       [1] If request is PROXIED, send the URL as given, with query string stripped off,
       parsed, and each arg is set as a property on the LoadVar object.
@@ -481,16 +480,17 @@
 
     if (loadobj.proxied) {
         // PROXY request: proxy parameters have been stored on
-        // rawpostbody, get them out and attach them to the LoadVars
+        // rawpostbody, get them out and append them to the LoadVars
         // obj, to POST to LPS proxy server.
 
-        var lzpostbody = loadobj.rawpostbody;
+        var content = loadobj.rawpostbody;
         // Copy the postbody data onto the LoadVars, it will be POST'ed
-        var pdata = LzParam.parseQueryString(lzpostbody);
+        var pdata = LzParam.parseQueryString(content);
         for ( var key in pdata) {
             lvar[key] = pdata[key];
         }
 
+
         lvar.sendAndLoad(reqstr , loadobj, "POST" );
     } else {
         // SOLO request:
@@ -499,28 +499,26 @@
         var header;
         var headers = loadobj.loader.requestheaders;
 
-        if (!dopost) {
-            // For a GET request, all query args have been placed on
-            // the lvar object already.
+        if (dopost) {
             for ( header in headers) {
                 lvar.addRequestHeader(header, headers[header]);
             }
-            //Debug.write("GET", reqstr);
-            lvar.sendAndLoad(reqstr , loadobj, "GET" );
-        } else {
-            //Debug.write("POST", reqstr);
+
             var lzpostbody = loadobj.rawpostbody;
             // Copy the postbody data onto the LoadVars, it will be POST'ed
             var pdata = LzParam.parseQueryString(lzpostbody);
             for ( var key in pdata) {
                 lvar[key] = pdata[key];
             }
-            
+
+            lvar.sendAndLoad(reqstr , loadobj , "POST");
+        } else {
+            // For a GET request, all query args have been placed on
+            // the lvar object already.
             for ( header in headers) {
                 lvar.addRequestHeader(header, headers[header]);
             }
-            //Debug.write("POST", reqstr);
-            lvar.sendAndLoad(reqstr , loadobj , "POST");
+            lvar.sendAndLoad(reqstr , loadobj, "GET" );
         }
     }
 }

Modified: openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf/LzLoader.lzs
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf/LzLoader.lzs	2008-04-11 19:11:17 UTC (rev 8634)
+++ openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf/LzLoader.lzs	2008-04-11 19:23:04 UTC (rev 8635)
@@ -502,8 +502,11 @@
     this.copyQueue = {ptr: 0, q: queue, xmlobj: xmlnode};
     this.trimwhitespace = xmlnode.trimwhitespace;
     this.nsprefix       = xmlnode.nsprefix; 
-    this.queuedCopyFlashXML_internal();
-    this.startCopyTask();
+    var done = this.queuedCopyFlashXML_internal();
+    // If the copy wasn't completed in this quanta, start a task to finish it.
+    if (!done) {
+        this.startCopyTask();
+    }
 }
 
 var copyLoopsPerFrame = 1000;
@@ -520,7 +523,6 @@
     var nsprefix = this.nsprefix;
     var trimwhitespace = this.trimwhitespace;
     var ptr = this.copyQueue.ptr;
-    //    Debug.write("enter queuedCopyFlashXML_internal", ptr);
     var q = this.copyQueue.q;
     var iter = 0;
     var maxiter = this.copyLoopsPerFrame;
@@ -619,14 +621,16 @@
     this.copyQueue.ptr = ptr;
     //Debug.write("leaving queuedCopyFlashXML_internal main loop", ptr, iter);
     if (ptr >= q.length) {
-        //Debug.write("entering queuedCopyFlashXML_internal post-copy cleanup", ptr, q.length);
         // If we get here, we're finished with the tree copy.
         // Unregister the idle loop handler
         var xmlobj = this.copyQueue.xmlobj;
         this.removeCopyTask();
         // Proceed with getting this dataset returned to the customer
-        //Debug.write("calling loader.returnData root node");
         xmlobj.loader.returnData(xmlobj, this.lfcrootnode.childNodes[0].childNodes[0]);
+        // Indicate that we finished it all in one go, no need to queue more copy tasks
+        return true;
+    } else {
+        return false;
     }
 }
 

Modified: openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/data/HTTPDataSource.java
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/data/HTTPDataSource.java	2008-04-11 19:11:17 UTC (rev 8634)
+++ openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/data/HTTPDataSource.java	2008-04-11 19:23:04 UTC (rev 8635)
@@ -422,34 +422,41 @@
     
             boolean hasQuery = (query != null && query.length() > 0);
     
-            if (isPost) {
-                String postbody = req.getParameter("lzpostbody");
-                // If there is a lzpostbody arg, use it as the POST request body,
-                // and copy the query arg from the client-supplied URL to the proxy request URL
-                if (postbody != null) {
-                    ((EntityEnclosingMethod)request).setRequestBody(postbody);
-                    request.setQueryString(query);
-                } else if (hasQuery) {
-                    StringTokenizer st = new StringTokenizer(query, "&");
-                    while (st.hasMoreTokens()) {
-                        String it = st.nextToken();
-                        int i = it.indexOf("=");
-                        if (i > 0) {
-                            String n = it.substring(0, i);
-                            String v = it.substring(i + 1, it.length());
-                            // POST encodes values during request
-                            ((PostMethod)request).addParameter(n, URLDecoder.decode(v, "UTF-8"));
-                        } else {
-                            mLogger.warn(
-                                /* (non-Javadoc)
-                                 * @i18n.test
-                                 * @org-mes="ignoring bad token (missing '=' char) in query string: " + p[0]
-                                 */
-                                org.openlaszlo.i18n.LaszloMessages.getMessage(
-                                    HTTPDataSource.class.getName(),"051018-429", new Object[] {it})
-                                         );
+            String rawcontent = null; 
+            // Newer rawpost protocol puts lzpostbody as a separate
+            // top level query arg in the request.
+            rawcontent = req.getParameter("lzpostbody");
+
+             if (isPost) {
+                    // Older rawpost protocol put the "lzpostbody" arg
+                    // embedded in the "url" args's query args
+                    if (rawcontent == null && hasQuery) {
+                        rawcontent = findQueryArg ("lzpostbody", query);
+                    }
+                    if (rawcontent != null) {
+                        // Get the unescaped query string
+                        ((EntityEnclosingMethod)request).setRequestBody(rawcontent);
+                    } else if (hasQuery) {
+                        StringTokenizer st = new StringTokenizer(query, "&");
+                        while (st.hasMoreTokens()) {
+                            String it = st.nextToken();
+                            int i = it.indexOf("=");
+                            if (i > 0) {
+                                String n = it.substring(0, i);
+                                String v = it.substring(i + 1, it.length());
+                                // POST encodes values during request
+                                ((PostMethod)request).addParameter(n, URLDecoder.decode(v, "UTF-8"));
+                            } else {
+                                mLogger.warn(
+                                    /* (non-Javadoc)
+                                     * @i18n.test
+                                     * @org-mes="ignoring bad token (missing '=' char) in query string: " + p[0]
+                                     */
+                                    org.openlaszlo.i18n.LaszloMessages.getMessage(
+                                        HTTPDataSource.class.getName(),"051018-429", new Object[] {it})
+                                             );
+                            }
                         }
-                    }
                 }
             } else {   
                 // This call takes an encoded (escaped) query string
@@ -627,6 +634,23 @@
         return mMaxConnectionsPerHost;
     }
 
+    // Extract a urlencoded query arg value
+    static String findQueryArg (String argname, String query) throws UnsupportedEncodingException {
+        StringTokenizer st = new StringTokenizer(query, "&");
+        while (st.hasMoreTokens()) {
+            String it = st.nextToken();
+            int i = it.indexOf("=");
+            if (i > 0) {
+                String n = it.substring(0, i);
+                String v = it.substring(i + 1, it.length());
+                if (argname.equals(n)) {
+                    return URLDecoder.decode(v, "UTF-8");
+                }
+            }
+        }
+        return null;
+    }
+
     public static void main(String args[]) {
 
         HTTPDataSource ds = new HTTPDataSource();
@@ -663,4 +687,7 @@
             e.printStackTrace();
         }
     }
+
+
+
 }

Modified: openlaszlo/trunk/demos/vacation-survey/vacation-survey.lzx
===================================================================
--- openlaszlo/trunk/demos/vacation-survey/vacation-survey.lzx	2008-04-11 19:11:17 UTC (rev 8634)
+++ openlaszlo/trunk/demos/vacation-survey/vacation-survey.lzx	2008-04-11 19:23:04 UTC (rev 8635)
@@ -1,6 +1,6 @@
 <!-- vacation-survey.lzx -->
 
-<canvas width="457" height="206" bgcolor="0xeaeaea" title="Vacation Survey" proxied="true">
+<canvas width="457" height="206" bgcolor="0xeaeaea" title="Vacation Survey" >
 
     <!-- [2006-9-25 jgrandy] (LPP-2755) commented out  <splash/> -->
 
@@ -8,7 +8,7 @@
 
     <debug x="250"/>
 
-    <dataset name="surveydataset" type="http" src="http:survey.jsp"/>
+    <dataset name="surveydataset" type="http" src="http:survey.jsp" querytype="post"/>
 
     <node id="resultdata">
         <attribute name="hawaii" 

Modified: openlaszlo/trunk/test/data/data-url.lzx
===================================================================
--- openlaszlo/trunk/test/data/data-url.lzx	2008-04-11 19:11:17 UTC (rev 8634)
+++ openlaszlo/trunk/test/data/data-url.lzx	2008-04-11 19:23:04 UTC (rev 8635)
@@ -1,15 +1,13 @@
 <canvas debug="true" height="600" >
-    <font src="helmetr.ttf" name="helvet" />
-    <debug y="130" height="400" width="400" fontsize="14" font="helvet" />
+    <debug y="130" height="460" width="1200" fontsize="14" />
     <simplelayout/>
-    <datasource timeout="3000" >
-        <dataset name="myds"
-            ontimeout="Debug.write(this.name + ': timed out')"
-            onerror="Debug.write(this.name + ': error')"
-            ondata="Debug.write('Response: ' + this.getPointer().serialize())" >
-        </dataset>
-    </datasource>
 
+    <dataset name="myds" type="http"
+             ontimeout="Debug.write(this.name + ': timed out')"
+             onerror="Debug.write(this.name + ': error')"
+             ondata="Debug.write('Response: ' + this.getPointer().serialize())" >
+    </dataset>
+
     <view>
         <simplelayout axis="x" spacing="2"/>
         <text>Type url:</text>
@@ -32,7 +30,7 @@
 
         <method name="doit">
             Debug.write("Requesting: " + url.getText()); 
-            var ds = canvas.datasets['myds'];
+            var ds = myds;
 
             ds.setSrc(url.getText());
 

Modified: openlaszlo/trunk/test/lfc/data/alldata.lzx
===================================================================
--- openlaszlo/trunk/test/lfc/data/alldata.lzx	2008-04-11 19:11:17 UTC (rev 8634)
+++ openlaszlo/trunk/test/lfc/data/alldata.lzx	2008-04-11 19:23:04 UTC (rev 8635)
@@ -16,6 +16,10 @@
     <include href="namespace.lzx"/>
     <include href="namespace-solo.lzx"/>
     <include href="whitespace.lzx"/>
+    <include href="testgetmethod.lzx"/>
+    <include href="testgetmethodsolo.lzx"/>
+    <include href="testpostmethod.lzx"/>
+    <include href="testpostmethodsolo.lzx"/>
     <include href="testsetheaders.lzx"/>
     <include href="testsetheaders-solo.lzx"/>
     <include href="testrawpost.lzx"/>
@@ -38,6 +42,10 @@
         <TestNamespaceSOLO/>
         <TestTrimWhitespace/>
         <TestSendHeaders/>
+        <TestGetMethod/>
+        <TestPOSTMethod/>
+        <TestGetMethodSOLO/>
+        <TestPOSTMethodSOLO/>
         <TestSetHeaders/>
         <TestSetHeadersSOLO/>
         <TestRawPost/>

Added: openlaszlo/trunk/test/lfc/data/testgetmethod.lzx


Property changes on: openlaszlo/trunk/test/lfc/data/testgetmethod.lzx
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:eol-style
   + native

Added: openlaszlo/trunk/test/lfc/data/testgetmethodsolo.lzx


Property changes on: openlaszlo/trunk/test/lfc/data/testgetmethodsolo.lzx
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:eol-style
   + native

Added: openlaszlo/trunk/test/lfc/data/testpostmethod.lzx


Property changes on: openlaszlo/trunk/test/lfc/data/testpostmethod.lzx
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:eol-style
   + native

Added: openlaszlo/trunk/test/lfc/data/testpostmethodsolo.lzx


Property changes on: openlaszlo/trunk/test/lfc/data/testpostmethodsolo.lzx
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:eol-style
   + native



More information about the Laszlo-checkins mailing list