luci-base: dispatcher.uc: only flush HTTP headers after rendering output
authorJo-Philipp Wich <jo@mein.io>
Thu, 3 Nov 2022 10:13:30 +0000 (11:13 +0100)
committerJo-Philipp Wich <jo@mein.io>
Thu, 3 Nov 2022 10:17:55 +0000 (11:17 +0100)
Ensure to first completely render the action function before flushing HTTP
headers since the invoked action logic might modify the HTTP headers itself.

Fixes: e7afd0d327 ("luci-base: fix luci.http.close()")
Ref: https://github.com/openwrt/luci/commit/e7afd0d327bb35c502ca41a3c5e3ea098898fbd7#commitcomment-88736854
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
modules/luci-base/ucode/dispatcher.uc

index 8ac32c3d1d364d92d078a1b69721bc79e7e039ce..89ff39193939a1e9b065f18fca58add835da3c0f 100644 (file)
@@ -764,6 +764,13 @@ function rollback_pending() {
 
 let dispatch;
 
+function render_action(fn) {
+       const data = render(fn);
+
+       http.write_headers();
+       http.output(data);
+}
+
 function run_action(request_path, lang, tree, resolved, action) {
        switch (action?.type) {
        case 'template':
@@ -775,13 +782,12 @@ function run_action(request_path, lang, tree, resolved, action) {
                break;
 
        case 'call':
-               http.write_headers();
-               http.output(render(() => {
+               render_action(() => {
                        runtime.call(action.module, action.function,
                                ...(action.parameters ?? []),
                                ...resolved.ctx.request_args
                        );
-               }));
+               });
                break;
 
        case 'function':
@@ -790,33 +796,30 @@ function run_action(request_path, lang, tree, resolved, action) {
                assert(type(mod[action.function]) == 'function',
                        `Module '${action.module}' does not export function '${action.function}'`);
 
-               http.write_headers();
-               http.output(render(() => {
+               render_action(() => {
                        call(mod[action.function], mod, runtime.env,
                                ...(action.parameters ?? []),
                                ...resolved.ctx.request_args
                        );
-               }));
+               });
                break;
 
        case 'cbi':
-               http.write_headers();
-               http.output(render(() => {
+               render_action(() => {
                        runtime.call('luci.dispatcher', 'invoke_cbi_action',
                                action.path, null,
                                ...resolved.ctx.request_args
                        );
-               }));
+               });
                break;
 
        case 'form':
-               http.write_headers();
-               http.output(render(() => {
+               render_action(() => {
                        runtime.call('luci.dispatcher', 'invoke_form_action',
                                action.path,
                                ...resolved.ctx.request_args
                        );
-               }));
+               });
                break;
 
        case 'alias':