NAME
YATT::Lite::WebMVC0::SiteApp - PSGI Handler for yatt
SYNOPSIS
# In app.psgi
use FindBin;
use YATT::Lite::WebMVC0::SiteApp -as_base;
use YATT::Lite qw/Entity *CON/;
return do {
my $site = MY->new(doc_root => "$FindBin::Bin/html");
#----- You can define entities here. ----
Entity session => sub {
my ($this, $key) = @_;
my $sess = $CON->get_session
or return;
$sess->param($key);
};
if (YATT::Lite::Factory->want_object) {
# When app.psgi is loaded from yatt support scripts(eg. yatt lint),
# return bare object, not app.
$site;
} else {
# Otherwise, normal PSGI. You can use Plack::Builder and/or middleware.
$site->to_app;
}
};
DESCRIPTION
SiteApp is Site + PSGI adapter: it inherits the public facade API of YATT::Lite::Site (load, request, render_file...) and adds to_app/call for the web.
SiteApp is a Factory of DirApp, which is a web specific subclass of YATT::Lite.
SiteApp takes a template directory tree at startup and becomes a PSGI application.
When SiteApp called for incoming request, it first determins a sub-directory for the request. Then SiteApp looks for DirApp from own cache, load/build it when necessary, and finally invoke DirApp to handle do rest of work.
CONFIGS
SiteApp accepts YATT::Lite::Object style configurations.
doc_root
Document root of this PSGI application. *.yatt should be placed under this. Usually, $FindBin::Bin/html
app_ns
Namespace of per-directory YATT::Lite class. Default is MyYATT. This will also be used as a base class of each YATT::Lite instances. This class will be loaded at startup (but can be missing). If it exists, it must be a subclass of YATT::Lite.
app_root
The application directory where app.psgi lives in. Sometime omissible, but recommended to set as $FindBin::Bin.
app_base
Base DirApp for all DirApp under doc_root. A.k.a inheritance of app-directory. Omissible. Usually, $FindBin::Bin/ytmpl.
site_prefix
If your app.psgi is located under subpath, specify this. You can refer this from *.yatt via &yatt:site_prefix();.
header_charset
Default charset for HTTP response headers. Default is utf-8.
tmpl_encoding, output_encoding
Encoding of *.yatt and HTTP response body, respectively.
XXX: should note about widechars....
no_nested_query
By default, yatt turns specific parameters into hashes/arrays like PHP and Ruby on Rails. This feature is useful(I hope), but is experimental. So if you don't want this feature, turn this config on.
mkquery_with_body_params
(Compatibility option) Before GH-259, url reproducing APIs ($CON->mkquery($CON), $CON->current_path($CON), $CON->mkurl(undef, $CON)...) reproduced POST body parameters too. Since POST is often chosen exactly to keep parameters out of access logs, they now reproduce only QUERY_STRING-derived parameters when the request has a body. Set this option to 1 to restore the old merged behavior.
pagevars
Package name of the pagevars module, which defines per-page compile-time constants for templates. See YATT::Lite::PageConsts.
argmacro
Hash of argmacro name to the Perl module which defines it, like {enum => 'MyApp::ArgMacro::Enum'}. Templates can use them as %enum; without <!yatt:argmacro>.
To register them in a namespace, give a list of hashes, each optionally paired with a namespace, like [[myorg => {enum => 'MyApp::ArgMacro::Enum'}], {...}]. Then templates use it as %myorg:enum;. See "REGISTRATION" in YATT::Lite::ArgMacro.
psgi_static
Requests other than *.yatt, *.ytmpl, *.ydo are passed to this PSGI app. Default is:
Plack::App::File->new(root => $self->{doc_root})->to_app
backend
Room for your Model instance. If it is given and it has startup method is implemented, $backend->startup($siteapp, @all_dirapps) will be called when prepare_app.
allow_debug_from
List of client addresses which may see developer-only error output: the error_trace widget of the shipped ytmpl/error.ytmpl (backtrace, source lines and frame arguments) and, under runas_fcgi, the raw exception text. Anything else gets the public error page. Templates can ask the same question with &yatt:is_debug_allowed_ip();.
Default is ['127.0.0.1', '::1']: the loopback client only. Giving this option replaces the default, so list the loopback addresses too if you still want them.
Each entry is compared with the client address as a whole string, exactly. (Earlier versions anchored this check only at the start, so 127.0.0.1 also matched 127.0.0.100.) For CIDR ranges, IPv6 normalization and IPv4-mapped IPv6 addresses, use YATT::Lite::WebMVC0::Partial::StrictIPMatch.
The client address is REMOTE_ADDR, unless "trusted_proxies" says otherwise.
trusted_proxies
List of addresses of the reverse proxies in front of this app. When REMOTE_ADDR is one of them, the client address (for "allow_debug_from") is taken from the headers the proxy added: X-Real-IP, then X-Client-IP, then X-Forwarded-For, whose entries are read from the right, skipping other trusted proxies, so that a value the client itself planted at the left is not used. Entries are matched like "allow_debug_from" (exact string by default, CIDR with YATT::Lite::WebMVC0::Partial::StrictIPMatch).
Compatibility note: before this option existed, those headers were believed from any peer, so a remote client could send X-Real-IP: 127.0.0.1 and pass allow_debug_from. Now they are ignored unless trusted_proxies is set. If your app runs behind a proxy and you rely on allow_debug_from for addresses other than the proxy itself, add the proxy here:
trusted_proxies => ['10.0.0.1'],
Alternatively, keep this option unset and let Plack::Middleware::ReverseProxy rewrite REMOTE_ADDR, enabled only for connections from the proxy:
enable_if { $_[0]->{REMOTE_ADDR} eq '10.0.0.1' } 'ReverseProxy';
X-Forwarded-Proto is not affected by this option: it is still honoured from any peer for URL building and the Secure cookie attribute.
METHODS
call($env)
PSGI entry function. SiteApp uses $env as following:
- PATH_TRANSLATED, REDIRECT_STATUS
-
If
$env->{REDIRECT_STATUS}is200and has non empty$env->{PATH_TRANSLATED}, yatt tries to serve specified path. - PATH_INFO
-
Otherwise, yatt examines
$env->{PATH_INFO}under doc_root and app_base, in this order.
Return value of actions
If an action (*.ydo, <!yatt:action> or mount_action) returns a PSGI response, it is used as the response instead of the connection buffer. Both forms of PSGI response are accepted:
- ARRAY -
[$status, \@headers, \@body] - CODE - delayed response / streaming
-
return sub { my ($responder) = @_; my $writer = $responder->([200, ['Content-Type', "text/html"]]); $writer->write('....'); $writer->close; };
These are equivalent to $CON->raise_response($response).
Note for CODE responses: the callback is invoked by the PSGI server after call($env) has returned. At that time, dynamically scoped variables such as $SYS and $YATT are no longer set up. ($CON is fine, because actions receive it as an argument and capture it lexically.) If you need them in the callback, copy them into lexical variables before returning the callback:
my ($sys, $yatt) = ($SYS, $YATT);
return sub { ... uses $sys, $yatt ... };
prepare_app
PSGI startup hook.
render($path_info, $args)
Aid for batch execution.
make_connection($parent_fh, @config)
Build helper for YATT::Lite::WebMVC0::Connection object. $parent_fh can be undef. If specified, $con->flush will flush buffered contents to $parent_fh.
HOOKS
before_dirhandler($dirapp, $connection, $filename)
ENTITY FUNCTIONS
SiteApp registers following entity functions (usable in every template as &yatt:NAME(ARGS);). This section covers URL-related ones. Most of them delegate to the same-named method of $CON.
URL builders
Recommended way to build app-internal links. *_path returns a path, *_url returns an absolute url, and both respect the mount point of the site. See "URL BUILDING METHODS" in YATT::Lite::WebMVC0::Connection for details.
<a href="&yatt:site_path(/admin/);">admin</a>
<a href="&yatt:site_path(/list,[page,2]);">page 2</a>
<a href="&yatt:current_path([page,2]);">page 2 of this page</a>
&yatt:site_url(/confirm); (absolute; for emails etc.)
&yatt:current_url();
- &yatt:site_path(PATH,QUERY);
- &yatt:site_url(PATH,QUERY);
- &yatt:current_path(QUERY);
- &yatt:current_url(QUERY);
-
QUERY is optional and must be
[key,value,...]array form.
Redirect
- &yatt:raise_redirect(URL);
- &yatt:redirect(URL);
-
Same as
$CON->raise_redirect. Html made so far is discarded and the rendering stops there. See "REDIRECT" in YATT::Lite::WebMVC0::Connection.
Debugging
- &yatt:is_debug_allowed_ip();
- &yatt:is_debug_allowed_ip(ADDRESS);
-
True if the client address (or the given ADDRESS) is listed in "allow_debug_from". Without an argument the client address is decided by "trusted_proxies". The shipped ytmpl/error.ytmpl uses this to choose between the developer trace and the public error page.
Location inspection
These entities answer where this page is served. As a general rule, lowercase entities return yatt-normalized values and are recommended; UPPERCASE ones return raw PSGI env values as-is (mainly for debugging).
Suppose the app is deployed at /myapp via Apache Action + AddHandler (so raw SCRIPT_NAME contains the handler script path) behind a reverse proxy which sets X-Forwarded-Proto: https, and https://example.com/myapp/auth/test?q=1 is served by auth/test.yatt:
&yatt:script_name(); /myapp
&yatt:SCRIPT_NAME(); /myapp/cgi-bin/runplack.cgi
&yatt:script_dir(); /myapp/
&yatt:script_uri(); https://example.com/myapp/auth/test
&yatt:SCRIPT_URI(); http://example.com/myapp/auth/test
&yatt:script_url(); /myapp/auth/test
&yatt:SCRIPT_URL(); /myapp/auth/test
&yatt:dir_location(); /myapp/auth/
&yatt:file_location(); /myapp/auth/test
&yatt:page_location(); /myapp/auth/test
&yatt:absrequest(); /auth/test
&yatt:abspath(); /auth/test.yatt
&yatt:request_uri(); /myapp/auth/test?q=1
&yatt:path_info(); /auth/test
- &yatt:script_name();
-
The mount point of the site, without trailing
/($env->{'yatt.script_name'}- normalizedSCRIPT_NAME; handler artifacts of Apache Action mapping are trimmed). The most basic building block for path abstraction. Note: this usually equals to&yatt:site_prefix();(explicit "site_prefix" config wins if given). - &yatt:script_dir();
-
script_name+/. - &yatt:script_uri();
-
Absolute url of the current page. Unlike raw
SCRIPT_URI, this respectsX-Forwarded-Proto(GH-205). - &yatt:script_url();
-
Path-only version of
script_uri. - &yatt:dir_location(); &yatt:file_location(); &yatt:page_location();
-
Mount-prefix aware location of the current directory / page.
file_locationfollows how the request spelled the file name (with/without extension), whilepage_locationis always the canonical (extension-less) form. Both omit the file name for index.yatt requests. See "LOCATION INSPECTION METHODS" in YATT::Lite::WebMVC0::Connection. - &yatt:abspath();
-
location+file(physical file name), without mount prefix. - &yatt:absrequest();
-
REQUEST_URIminusscript_name, query string stripped. SinceREQUEST_URItypically does not contain index.yatt, this is not suitable to get the physical file name. - &yatt:is_current_file(PATH); &yatt:is_current_page(PAGE);
-
Current page predicates, useful for navigation highlighting.
- &yatt:path_info(); &yatt:request_uri(); &yatt:script_filename();
-
Raw
PATH_INFO/REQUEST_URI/SCRIPT_FILENAME.
SEE ALSO
YATT::Lite::WebMVC0::Connection, YATT::Lite::WebMVC0::DirApp, YATT::Lite