On Fri, Jul 31, 2009 at 6:04 PM, <[email protected]> wrote:
>
>
http://docs.google.com/Doc?docid=0AVWyIFBvIVXGZGZneGI3Z2tfNjVkbjV0OXdmaw&hl=en

Contents with commentary follow.

> 0. IntroductionThis proposes new behavior for the Caja cajoling service
> allowing greater flexibility for use with various module loading schemes.
> 1. Current situationThe current Caja cajoling service has a simple
> invocation syntax with all parameters on the URL:
>
> http://serviceDnsName/somePath?url=...&mime-type=...&transform=...
>
> The URL parameters it supports are as follows:
>
> *url*: The URL of the original code to retrieve and cajole.
>
> *mime-type*: The expected MIME type of the content to be found at url. We
> currently support application/javascript, to directly cajole Cajita or
> Valija code, or text/html, to cajole some HTML that may contain some
> scripts. When cajoling HTML, we always do so in Valija mode (and the
> programmer can restrict subsets of the code to Cajita using the "use
> strict,cajita" directive). Also, when cajoling HTML, we return HTML (with
> <script>s) to the client; when cajoling Cajita or Valija, we return
> JavaScript to the client.
>
> *transform*: The transformation desired. We currently support innocent,
> cajita and valija. It is (or *should* be) an error to ask for 
> cajitatransformation of
> text/html content.
>

If MIME type is omitted, it would be good to infer it from the extension in
the obvious manner. It would also be good to accept "application/ecmascript"
as synonymous with "application/javascript".

The "use ..." directive syntax settled by the ES5 spec implies that we
should accept "use cajita". To manage the transition, we should continue to
accept "use strict,cajita" as well.

If the transform is omitted, it should default to "valija".


>
> Concrete (heavily simplified) examples of requests and responses are:
>
> *Request:
> *...?url=http://x/aFile.html&mime-type=text/html
> *Response:*
> <p>Hello world, this is some HTML.</p>
> <script>
>   ___.loadModule({ /* the JavaScript goes here. */ });
> </script>
>
> *Request:*
> ...?url=http://x/aFile.js&mime-type=application/javascript
> *Response:*
>
> ___.loadModule({ /* The JavaScript goes here. */ });
>
>
>
> The problems we seek to solve here is that the way the responses are
> returned is rather rigid. Consider two possible consumers:
>
> 1. A <script src="..."> tag that refers to the cajoling service. The
> creator of this tag must use the cajita.js API to set up a module handler
> before creating the tag. But most importantly: *If a page has two such
> <script> tags pending, they will both be processed by the same module
> handler since we cannot guarantee which of the resulting HTTP requests will
> be fulfilled first.*
>

Your counter proposal does not alter this situation. Rather, it is
equivalent to merely registering a different new-module handler behavior and
should be expressed in this manner, as shown below.


>
> 2. An XMLHTTPRequest that obtains the result of the cajoling service. The
> invoker of this request likely considers the ___.loadModule() envelope a
> distraction that they must work around. For example, to eval() the result
> and capture the module in variable theModule, they might do:
>
> var theModule;
> var stringToEval =
>     "___ = { loadModule: function(m) { theModule = m; } };"
>     + returnResultFromXHR;
> eval(stringToEval);
>

To get the same effect non-kludgily within the current framework:


    ___.setNewModuleHandler(___.obtainNewModule);
    var theModule = eval(returnResultFromXHR);


>
> Furthermore:
>
> 3. The ___.loadModule() semantics are not convenient for the case where a
> module is being loaded by cajoled code and needs to be exposed to it.
>

Not directly. But a convenient semantics can as easily be built on it.

>
> 2. ProposalWe propose that the cajoling service support an additional
> parameter, a JSONP-style callback function that the client wants invoked by
> the returned script:
>
> *callback*: The name of a callback function to invoke with the result of
> the cajoling.
>
> Concrete (heavily simplified) examples of requests and responses are:
>
> *Request:
> *...?url=http://x/aFile.html&mime-type=text/html
> *Response:*
> <p>Hello world, this is some HTML.</p>
> <script>
>   ___.moduleOf({ /* the JavaScript goes here. */ });
> </script>
>
> *Request:*
> ...?url=http://x/aFile.html&callback=giveMeMyModule&mime-type=text/html
> *Response:*
> <p>Hello world, this is some HTML.</p>
> <script>
>   giveMeMyModule(___.moduleOf({ /* the JavaScript goes here. */ }));
> </script>
>
> *Request:*
> ...?url=http://x/aFile.js&mime-type=application/javascript
> *Response:*
>
> ___.moduleOf({ /* The JavaScript goes here. */ });
>
>
>  *Request:*
> ...?url=http://x/aFile.js&callback=giveMeMyModule
> &mime-type=application/javascript
> *Response:*
>
> giveMeMyModule(___.moduleOf({ /* The JavaScript goes here. */ }));
>
> In concert with this, cajita.js would deprecate ___.loadModule() and
> provide the following instead:
>
> *___.moduleFromObject(<moduleObject>)*: Given a raw module object literal,
> register debugging hooks; freeze the module object literal, wrap it in a
> simplified API, and return a "secure module" object. Also assign that secure
> module object to the "last module seen".
>
> *___.moduleFromText(<moduleText>)*: Give some text, check the signature of
> the text (if appropriate) and eval() it, yielding a raw module object
> literal. Then invoke ___.moduleFromObject() on the raw literal and return
> the result.
>
> *___.takeLastModule()*: Return and clear the last "secure module" object
> that was created.
>

I don't understand why renaming "loadModule" into "giveMeMyModule",
"moduleOf", "moduleFromObject" improves anything. The behavior of
"loadModule" is merely:

  /**
   * A module is an object literal containing metadata and an
   * <code>instantiate</code> member, which is a plugin-maker function.
   * <p>
   * loadModule(module) marks module's <code>instantiate</code> member as a
   * func, freezes the module, asks the current new-module-handler to handle
it
   * (thereby notifying the handler), and returns the new module.
   */
  function loadModule(module) {
    freeze(module);
    markFuncFreeze(module.instantiate);
    return callPub(myNewModuleHandler, 'handle', [module]);
  }


By design, this is already customizable by registering a new-module handler.
AFAICT, all the behaviors your propose can be expressed as new-module
handlers. What all this suggests is that we should replace the current
definition of obtainNewModule in cajita.js with:

      var lastSecureModule = null;
      var obtainNewModule = freeze({
        handle: ___.markFuncFreeze(function(newModule) {
          lastSecureModule = asSecureModule(newModule);
          return newModule.
        })
      });

      var takeLastModule = markFuncFreeze(function() {
        try { return lastSecureModule; } finally { lastSecureModule = null;
}
      }),

and then add

      takeLastModule: takeLastModule,

to the members of "___".


Where asSecureModule(newModule) does the "register debugging hooks" and
"wrap it in a simplified API" that you have in mind. Note that loadModule
already "freeze[s] the module object literal" so obtainNewModule doesn't
need to. I will assume the above changes in my comments below.



>
> A "secure module" object is a "maker function" suitable for direct exposure
> to either cajoled or un-cajoled code. Invoking this with an object literal
> containing named parameters results in an instance of the module:
>
> var myInstance = aSecureModule({ arg0: v0, arg1: v1, ... });
>

So, ignoring debugging hooks, is the following an adequate asSecureModule()
function?

    function asSecureModule(newModule) {
      return ___.markFuncFreeze(function(IMPORTS___) {
        return newModule.instantiate(___, IMPORTS___);
      });
    }




>
> 3. Examples using the proposed API3.1. Loading cajoled code into a
> pre-composed HTML page<p>Hello world, this is HTML</p>
>
> <script src="cajita.js"></script>
> <script src="domita.js"></script>
> <!-- ... -->
>
> <script src="
> http://cajoler/?url=http://x/aFile.js&mime-type=application/javascript
> "></script>
> <script>
>   var theModule = ___.takeLastModule();
>   var theInstance = theModule({ arg0: v0, arg1: v1, ... });
> </script>
>

If you simply precede the import of aFile with

      <script>___.setNewModuleHandler(___.obtainNewModule);</script>

the rest of that page will work as is.


>
> 3.2. Loading cajoled code dynamically via a <script> tag
> <p>Hello world, this is HTML</p>
>
> <script src="cajita.js"></script>
> <script src="domita.js"></script>
> <!-- ... -->
>
> <script>
>   var theNode = document.createElement('script');
>   theNode.setAttribute(
>     'src',
>     'http://cajoler/?url=http://x/aFile.js&callback=getModule
> &mime-type=application/javascript');
>
>   window.getModule = function(theModule) {
>     /* invoked asynchronously when the <script> loads */
>     var theInstance = theModule({ arg0: v0, arg1: v1, ... });
>   };
>
>   document.getElementsByTagName('head')[0].appendChild(theNode);
> </script>
>

Are later inline scripts invoked after previous <script src="..."> have been
evaluated? If so, then the JSONP trick above isn't necessary. If not, then
this JSONP trick does work but creates a bad namespace management problem.
Where do these names come from and how are they gc'ed?


>
> 3.3. Loading cajoled code via an XMLHttpRequest<p>Hello world, this is
> HTML</p>
>
> <script src="cajita.js"></script>
> <script src="domita.js"></script>
> <!-- ... -->
>
> <script>
>   var xhr = new XMLHttpRequest();
>   /* Note no callback parameter */
>   xhr.open('
> http://cajoler/?url=http://x/aFile.js&&mime-type=application/javascript');
>   xhr.onreadystatechange = function () {
>     /* ... check status, etc. */
>     var theModule = eval(xhr.responseText);
>     var theInstance = theModule({ arg0: v0, arg1: v1, ... });
>   };
>   xhr.send(...);
> </script>
>

    xhr.onreadystatechange = function() {
      ___.setNewModuleHandler(___.obtainNewModule);
      var theInstance = eval(xhr.responseText)(___, { arg0: v0, arg1: v1,
... });
    };
  Edit this page (if you have
permission)<http://docs.google.com/Doc?tab=edit&dr=true&id=dfgxb7gk_65dn5t9wfk>
|
 Google Docs -- Web word processing, presentations and
spreadsheets.<http://docs.google.com/>



this works even with the current ___.obtainNewModule.

-- 
   Cheers,
   --MarkM

Reply via email to