nginx/njs

Object prototype methods "hasOwnProperty" always return true in r.variables when "set" directive is used only inside some "location" block

Closed this issue · 3 comments

Abstract

If "location" block A defines a value name by "set" directive, and "location" block B does not define, Object prototype methods "hasOwnProperty" always return true in "location" block B with error log "using uninitialized [NAME] variable"


Detail

js_content directive can pass "module.function" which only accept one paramter (r: NginxHTTPRequest), but sometimes developer want to pass more paramters by location block with same "module.function". "set" directive may be used as this idea.

Suppose "location" block A defines a value name by set $aaa "111" and "location" block B does not define that, when js run Object.prototype.hasOwnProperty.call(r.variables, "aaa") in "location" block B, it always return true, and with a error log "using uninitialized 'aaa' variable". Because it alway returns true, code in "location" block B will get an empty string, that will make an unexpected logical code run.

This behavior should be consider as a bug.


Environment & Version:

CentOS 7
nginx.x86_64 1:1.25.2-1.el7.ngx
nginx-module-njs.x86_64 1:1.25.2+0.8.0-1.el7.ngx


Steps to reproduce:

nginx.conf:

server {
    listen       8765;
    server_name  localhost;
    

    js_import test from test.js;

    location /test_exists_value_a {
        set $exists_value_a "dddddddd";
        js_content test.exists_value_a;
    }

    location /test_not_exists_value_a {
        js_content test.exists_value_a;
    }

}

test.js:


function exists_value_a(r){

    let res = 0;
    if(Object.prototype.hasOwnProperty.call(r.variables, "exists_value_a")){
        res = 1;
    }

    r.return(200, JSON.stringify({
        "detect": res,
        //"exists_value_a": r.variables["exists_value_a"]
    }));

}



export default {exists_value_a};

curl:

curl -v "http://localhost:8765/test_not_exists_value_a"


What is expected?

value "detect" should be 0, no error log produce.


What is actually happening?

curl:

{"detect":1}

error log:

2023/09/05 11:50:05 [warn] 11703#11703: *3 using uninitialized "exists_value_a" variable, client: 127.0.0.1, server: localhost, request: "GET /test_not_exists_value_a HTTP/1.1", host: "localhost:8765"

Hi @HorseLuke,

Here we have situation similar to #667. The nginx variables are global and not local to a location.
set $exists_value_a "dddddddd" sets a value to $exists_value_a in location /test_exists_value_a, but the $exists_value_a exists globally once it defined anywhere and njs can reference it.

OK, got it. Closed as "by-design"?

To those who encounter same problem, now the solution is:

(1) define set with empty string in server block, this is a global define behavior, and solved trigger uninitialized error problem.
(2) check whether the value is empty or not in js_content, do not use hasOwnProperty check.

nginx.conf:

server {
    listen       8765;
    server_name  localhost;
    
    set $param_for_js_content "";

    js_import test from test.js;

    location /test_exists_value_a {
        set $param_for_js_content "dddddddd";
        js_content test.dorun;
    }

    location /test_not_exists_value_a {
        js_content test.dorun;
    }

}