-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Request routing flow
Yurt Page edited this page Jan 9, 2024
·
1 revision
In general the request routing flow is:
- uhttpd (or another web server) invokes
/www/cgi-bin/luci
, passes request info via env vars & stdin (basic CGI interface) -
/www/cgi-bin/luci
instantiates theluci.sgi.cgi
class (sgi = Server Gateway Interface, a module to translate the server specific env to a common LuCI-internal HTTP request state) and invokes itsrun()
method. There might be others but not relevant for the basic logic flow -
luci.sgi.cgi
builds an HTTP request object from the provided information, loadsluci.dispatcher
and invokesluci.dispatcher.httpdispatch()
, passing the HTTP request context object as argument -
luci.dispatcher.httpdispatch()
parses the requested path, determines the preferred browser language and sets them in the global state along with the received HTTP request context, then proceeds inluci.dispatcher.dispatch()
-
luci.dispatcher.dispatch()
does several things:
- it parses all
/usr/share/luci/menu.d/
JSON files, assembles them into a global tree structure (refmenu_json()
)- checks uci and fs dependencies for all nodes (ref
check_depends()
) - does some cleanup and post-processing
- then caches the resulting tree structure on disk in
/tmp
. In case a fresh cache file is found, it is used instead and the JSON menu file processing is skipped
- checks uci and fs dependencies for all nodes (ref
- it resolves the requested node by looking up the determined path from the HTTP request context in the assembled menu tree structure (ref
resolve_page()
)- if no matching node is found it yields a 404 error
- if node dependencies are not fulfilled, it yields a 404 error
- if the node or any of its ancestors require a login (specify a non-empty
auth: {}
object in their JSON), then...- if a session ID can be determined using one of the specified methods then...
- if the session can be found (
ubus call session get '{ "ubus_rpc_session": "the_ID" }'
, refcheck_authentication()
) then continue - if the session can not be found or is expired, then...
- if the node or any of its ancestors specified
login: true
in theauth: { }
object then present an HTML login dialog (by rendering/usr/lib/lua/luci/view/sysauth.htm
) - if no node along the ancestor chain specifies
login: true
then yield a 403 error
- if the node or any of its ancestors specified
- if the session can be found (
- if a session ID can be determined using one of the specified methods then...
- it checks the acl dependencies along the ancestor chain
- if a node along the chain depends on an ACL which is not granted in the active session, then yield a 403 error
- if a node along the chain depends on an ACL for which the active session only has read but not write permission, then mark the node as readonly
- does CORS processing if the HTTP request type is
OPTIONS
and the page (or one of its ancestory hadcors: true
set - does setuid/setgid dropping if configured in the ancestor chain
- it evaluates the
action: { }
object of the resolved node- depending on the action (ref: Description of the JSON in menu.d and acl.d? - #4 by jow ) it either...
- executes a JavaScript view (type
view
) in/www/luci-static/resources/view/**.js
- this is the most common and preferred node action
- it is implemented by rendering a server side
/usr/lib/lua/luci/view/view.htm
template which in turn instantiates the/www/luci-static/resources/view/**.js
JS class from the rendered HTML code using theL.ui.instantiateView()
API.
- calls a class method (type
call
) - the method is responsible for producing HTTP output, setting status headers etc. If the mode encounters an exception, then yield a 500 error - renders a server side Lua template (type
template
) in/usr/lib/lua/luci/view/**.htm
according to the node action specification - this action type is deprecated/being faded out - renders an abstract CBI form (type
cbi
) in/usr/lib/lua/luci/model/cbi/**.lua
- this action type is deprecated/being faded out - renders a non-UCI CBI form (type
form
) in/usr/lib/lua/luci/model/cbi/**.lua
- this action type is deprecated/being faded out - executes a summary or detail sub-action (type
arcombine
) depending on whether an ID argument is present as last path segment - this action type is deprecated/being faded out - redirects or rewrites the request (types
alias
andrewrite
)
- executes a JavaScript view (type
- depending on the action (ref: Description of the JSON in menu.d and acl.d? - #4 by jow ) it either...
A typical JavaScript based view is composed of several requests though:
- The main request to access a LuCI URL produces a server-side rendered HTML page frame that includes JS code that...
- Requests the session-specific menu tree as JSON from the server and renders it locally into an HTML menu
- Requests various static resources such as
luci.js
, CSS files etc. - For the most common
view
action type, requests and instantiates the actual view.js
file which in turn...- produces markup and incrementally renders the content area of the server side rendered page frame
- optionally makes a number of ubus-rpc API requests to fetch more information from the server, e.g. to load uci config values or system runtime information
- in the specific example of
crontab.js
, the file contents are fetched via theL.fs.read()
JS API which in turn invokesubus call file read { "path": "..." }
via the HTTP-UBUS interface (not strictly part of LuCI) towardsrpcd
file module
The HTML page frame template is /usr/lib/lua/luci/view/view.htm
for JS based views, for other actions (CBI maps, server side Lua templates) it is other *.htm
templates including header.htm
and footer.htm
themselves
The header.htm
and footer.htm
templates in luci-base are just stubs including the theme specific header.htm
and footer.htm
Source https://forum.openwrt.org/t/redesigning-luci-openwrt/133469/6