SimpleHttpServer
, except SoyWeb serves a Soy file by rendering a template in the file as HTML.Unlike other templating languages like PHP and JSP, Soy gives users just enough programming logic to eliminate duplicate HTML across pages (using template calls and loops), but not so much programming power that business logic will leak into the template.
tasks.soy
, in a directory js
that defines three templates: the UI for a task list, the boilerplate for a demo page, and an instance of the task list on a demo page:{namespace tasks} /** * @param title * @param items */ {template .list} <h1>{$title}</h1> <div> {foreach $item in $items} <div class="{css task-item}"> <div style="margin-left: {$item.indent * 24}px"> {$item.name} </div> </div> {ifempty} <div class="{css tasks-complete}"> Nothing to do! </div> {/foreach} </div> {/template} /** * @param content */ {template .demoPage} <!doctype> <html> <head> <link rel="stylesheet" href="tasks.css"> </head> <body> {$content|noAutoescape} </body> </html> {/template} /** * This template will be rendered by SoyWeb when the user loads tasks.soy. * It deliberately includes dummy data so the designer can get a feel for how * the task list will appear with real data rather with minimal copy and paste. */ {template .soyweb} {call .demoPage} {param content} {call .list} {param title: 'Food Shopping' /} {param items: [ ['indent': 0, 'name': 'cheese' ], ['indent': 0, 'name': 'crackers' ], ['indent': 0, 'name': 'condiments' ], ['indent': 1, 'name': 'ketchup' ], ['indent': 1, 'name': 'mayo' ], ] /} {/call} {/param} {/call} {/template}To see how the rendered template looks using SoyWeb, run the following command:
java -jar plovr.jar soyweb --dir jsThen point your browser to
http://localhost:9811/tasks.html
to see the task list populated with the data specified by the .soyweb
template.Now creating another template with a different set of mock data is much less work, as js/tasks2.soy
can reuse the existing templates:
{namespace tasks2} /** * This template will be rendered by SoyWeb when the user loads tasks2.soy. * This makes it possible to see how an empty task list will be rendered. */ {template .soyweb} {call tasks.demoPage} {param content} {call tasks.list} {param title: 'Food Shopping' /} {param items: [] /} {/call} {/param} {/call} {/template}With SoyWeb is running, the rendered version of this template can be seen at
http://localhost:9811/tasks2.html
.--unsafe
option when starting SoyWeb. This makes it easier to see what your template will look like with different inputs. Consider the following Soy file, js/settings.soy
, for a settings page that shows a user whether or not he has granted an application access to Facebook:{namespace settings} /** * @param? accessToken */ {template .facebook} <div> {if $accessToken} You have granted access to Facebook. Your access token is <b>{$accessToken|id}</b>. {else} This application does not have access to Facebook. {sp} <button>Grant Access</button> {/if} </div> {/template} /** * Demo the settings UI using SoyWeb. */ {template .soyweb} <body> {call .facebook data="all" /} </body> {/template}Normally, if you loaded
settings.soy
with SoyWeb, accessToken
would be null
, so you would see the "This application does not have access to Facebook" UI. If you wanted to see the "You have granted access to Facebook" UI, then you would have to edit facebook.soy
to set {param accessToken: 'someToken' /}
in the .soyweb
template, and then reload the page.It would be much more convenient to be able to edit the query parameters of the URL to SoyWeb to toggle these parameters so that:
http://localhost:9811/settings.html?accessToken=someTokenwould show the "access granted" UI with whereas
http://localhost:9811/settings.html?accessToken=nullwould show the "no access" UI. Fortunately, SoyWeb makes this possible when the
--unsafe
option is specified as follows:java -jar plovr.jar soyweb --dir js --unsafeWhen specified, SoyWeb takes each query parameter and makes a best effort to convert it to the appropriate datatype, and then passes each name/value pair as a parameter to the
.soyweb
template when rendering it. Here are some examples of the types of conversions that SoyWeb will do for a query string:?option=true
becomes the pair {option: true}
?option=TRUE
becomes the pair {option: "TRUE"}
?option1=true&option2=false
becomes the pair {option1: true, option2: false}
, as multiple parameters may be defined in the query string.?option=null
becomes the pair {option: null}
?option=foo
becomes the pair {option: "foo"}
?option=%22foo%22
becomes the pair {option: "foo"}
?option=true&option=10
becomes the pair {option: 10}
because SoyWeb chooses the rightmost value for a repeated query parameter. This makes it easier to tack on a new value to the end of a URL to update it rather than finding the existing assignment and editing it.This option is disabled by default because it could enable a malicious user to to inject his own JavaScript into your page. For example, the user could construct the following URL that alerts gotcha when the user visits the page:
http://localhost:9811/settings.html?accessToken=%3Cscript%3Ealert('gotcha')%3C/script%3EThis particular exploit works because the author of
facebook.soy
used {$accessToken|id}
instead of {$accessToken}
, which disabled autoescaping for that variable. (Incidentally, Chrome refuses to run this JavaScript, noting: Refused to execute a JavaScript script. Source code of script found within request. in the developer tools console.)For this reason, this feature is disabled by default and is named --unsafe
to raise awareness of the security implications of enabling this option. Nevertheless, this is an effective feature for developing HTML UIs, as it makes it possible to view the interface in different states with little overhead. It is highly recommended for prototyping and for demoing to trusted users.
--dir
is the only required option: it specifies the directory of files to serve. No files in parent directories of --dir
will be served by SoyWeb.--unsafe
makes it possible to specify Soy parameters using query parameters from the URL. This parameter is named "unsafe" because it opens up the possibility for XSS attacks. This is not a sensible thing to do if SoyWeb is used in production, but it is incredibly useful when prototyping internally. See Setting template parameters with URL query parameters for details.--port
is the port on which SoyWeb will handle requests. The default is 9811 (which is one more than plovr's default port, 9810).--template
is the name of the template that SoyWeb will use in a .soy
file when it is requested. As shown in the example, the default value is soyweb
. Note that this template generally does not have any parameters unless it is intended to be used with --unsafe
such that parameter values will be supplied via the query string.--globals
refers to a JSON file containing a map of global variable names to values. If supplied, SoyWeb will supply these values as globals when rendering a template. See www-globals.js for an example of this.--static
if specified, disables SoyWeb's default serving behavior, which is to reload a template each time it is requested. This option is not generally recommended for use, though admittedly it is used to serve the static content on plovr.com.--noindexes
disables listing the files in a directory, much like the "-Indexes" directive in an Apache config.