code wiki / (root) / nx_http_template_test.nx

nx_http_template_test.nx source

↩ module page · 169 lines · 6844 B

1// nx_http_template_test.nx -- smoke for typed-context templates. 2// 3// expect_exit: 0 4// 5// license_tier: ORIGINAL 6 7import "nx_syscalls_x86_64.nx" 8import "nx_http_template.nx" 9 10func bytes_eq(a: *u8, b: *u8, n: i64) -> i64 { 11 var i: i64 = 0 12 while i < n { 13 if a[i] != b[i] { return 0 } 14 i = i + 1 15 } 16 return 1 17} 18 19func bytes_contains(haystack: *u8, h_n: i64, needle: *u8, n_n: i64) -> i64 { 20 if n_n > h_n { return 0 } 21 var i: i64 = 0 22 while i <= h_n - n_n { 23 if bytes_eq(((haystack as i64) + i) as *u8, needle, n_n) == 1 { return 1 } 24 i = i + 1 25 } 26 return 0 27} 28 29// Helper: populate vars table with three entries. 30func setup_vars(vars: *NxTemplateVars) -> i64 { 31 let names: *u8 = sys_mmap(256) 32 let name_offs: *i64 = sys_mmap(64) as *i64 33 let name_lens: *i64 = sys_mmap(64) as *i64 34 let values: *u8 = sys_mmap(1024) 35 let value_offs: *i64 = sys_mmap(64) as *i64 36 let value_lens: *i64 = sys_mmap(64) as *i64 37 38 // "name" -> "Alice" 39 let n0: *u8 = "name" as *u8 40 var a: i64 = 0 41 while a < 4 { names[a] = n0[a]; a = a + 1 } 42 name_offs[0] = 0; name_lens[0] = 4 43 let v0: *u8 = "Alice" as *u8 44 var b: i64 = 0 45 while b < 5 { values[b] = v0[b]; b = b + 1 } 46 value_offs[0] = 0; value_lens[0] = 5 47 48 // "url" -> "/page?q=hello world" 49 let n1: *u8 = "url" as *u8 50 var c: i64 = 0 51 while c < 3 { names[4 + c] = n1[c]; c = c + 1 } 52 name_offs[1] = 4; name_lens[1] = 3 53 let v1: *u8 = "/page?q=hello world" as *u8 54 var d: i64 = 0 55 while d < 19 { values[5 + d] = v1[d]; d = d + 1 } 56 value_offs[1] = 5; value_lens[1] = 19 57 58 // "evil" -> "<script>alert(1)</script>" 59 let n2: *u8 = "evil" as *u8 60 var e: i64 = 0 61 while e < 4 { names[7 + e] = n2[e]; e = e + 1 } 62 name_offs[2] = 7; name_lens[2] = 4 63 let v2: *u8 = "<script>alert(1)</script>" as *u8 64 var f: i64 = 0 65 while f < 25 { values[24 + f] = v2[f]; f = f + 1 } 66 value_offs[2] = 24; value_lens[2] = 25 67 68 return nx_template_vars_init(vars, 69 names, name_offs, name_lens, 70 values, value_offs, value_lens, 71 3) 72} 73 74func main() -> i64 { 75 // ---- Verdict enum ---- 76 if nxt_verdict_is_valid(NXT_OK) != 1 { return 1 } 77 if nxt_verdict_is_valid(NXT_BAD_MODIFIER) != 1 { return 2 } 78 if nxt_verdict_is_valid(NXT_VERDICT_N) != 0 { return 3 } 79 if bytes_eq(nxt_verdict_name(NXT_OK), "OK" as *u8, 2) != 1 { return 4 } 80 if bytes_eq(nxt_verdict_name(NXT_BAD_TEMPLATE), "BAD_TEMPLATE" as *u8, 12) != 1 { return 5 } 81 82 // ---- Modifier -> ctx ---- 83 if nxt_modifier_to_ctx("text" as *u8, 4) != NXH_CTX_TEXT { return 10 } 84 if nxt_modifier_to_ctx("attr" as *u8, 4) != NXH_CTX_ATTR_DQ { return 11 } 85 if nxt_modifier_to_ctx("url" as *u8, 3) != NXH_CTX_URL { return 12 } 86 if nxt_modifier_to_ctx("raw" as *u8, 3) != NXH_CTX_RAW { return 13 } 87 if nxt_modifier_to_ctx("nope" as *u8, 4) != -1 { return 14 } 88 89 // ---- Init vars ---- 90 let vars: *NxTemplateVars = (sys_mmap(NX_TEMPLATE_VARS_BYTES)) as *NxTemplateVars 91 if setup_vars(vars) != NXT_OK { return 20 } 92 93 let out: *u8 = sys_mmap(2048) 94 let out_n: *i64 = sys_mmap(8) as *i64 95 96 // ---- Default TEXT context ---- 97 let tmpl1: *u8 = "Hello, {{ name }}!" as *u8 98 out_n[0] = 0 99 if nx_http_template_render(tmpl1, 18, vars, out, 2048, out_n) != NXT_OK { return 30 } 100 if out_n[0] != 13 { return 31 } 101 if bytes_eq(out, "Hello, Alice!" as *u8, 13) != 1 { return 32 } 102 103 // ---- XSS prevention via TEXT context ---- 104 let tmpl2: *u8 = "<p>{{ evil }}</p>" as *u8 105 out_n[0] = 0 106 if nx_http_template_render(tmpl2, 17, vars, out, 2048, out_n) != NXT_OK { return 40 } 107 // Substrate must have escaped < and > to &lt; / &gt; 108 if bytes_contains(out, out_n[0], "<script>" as *u8, 8) != 0 { return 41 } 109 if bytes_contains(out, out_n[0], "&lt;script&gt;" as *u8, 14) != 1 { return 42 } 110 111 // ---- URL context: spaces -> %20 ---- 112 let tmpl3: *u8 = "<a href=\"{{ url | url }}\">click</a>" as *u8 113 out_n[0] = 0 114 if nx_http_template_render(tmpl3, 35, vars, out, 2048, out_n) != NXT_OK { return 50 } 115 if bytes_contains(out, out_n[0], "hello%20world" as *u8, 13) != 1 { return 51 } 116 117 // ---- ATTR_DQ context: quote in value -> &quot; ---- 118 let n_evil: *u8 = "evil" as *u8 // value contains "..." with quotes around the JS 119 let tmpl4: *u8 = "<div class=\"{{ evil | attr }}\">x</div>" as *u8 120 out_n[0] = 0 121 if nx_http_template_render(tmpl4, 38, vars, out, 2048, out_n) != NXT_OK { return 60 } 122 // < and > and " should be encoded 123 if bytes_contains(out, out_n[0], "&lt;script&gt;" as *u8, 14) != 1 { return 61 } 124 125 // ---- RAW bypass (audited) ---- 126 let tmpl5: *u8 = "<p>{{ evil | raw }}</p>" as *u8 127 out_n[0] = 0 128 if nx_http_template_render(tmpl5, 23, vars, out, 2048, out_n) != NXT_OK { return 70 } 129 // RAW lets the value through unescaped (caller asserts safety). 130 if bytes_contains(out, out_n[0], "<script>" as *u8, 8) != 1 { return 71 } 131 132 // ---- BAD_MODIFIER ---- 133 let tmpl6: *u8 = "<p>{{ evil | onclick }}</p>" as *u8 134 out_n[0] = 0 135 if nx_http_template_render(tmpl6, 27, vars, out, 2048, out_n) != NXT_BAD_MODIFIER { return 80 } 136 137 // ---- VAR_NOT_FOUND ---- 138 let tmpl7: *u8 = "{{ undefined_var }}" as *u8 139 out_n[0] = 0 140 if nx_http_template_render(tmpl7, 19, vars, out, 2048, out_n) != NXT_VAR_NOT_FOUND { return 90 } 141 142 // ---- BAD_TEMPLATE (missing close `}}`) ---- 143 let tmpl8: *u8 = "{{ name" as *u8 144 out_n[0] = 0 145 if nx_http_template_render(tmpl8, 7, vars, out, 2048, out_n) != NXT_BAD_TEMPLATE { return 100 } 146 147 // ---- Multiple substitutions ---- 148 let tmpl9: *u8 = "Hi {{ name }}, see <a href=\"{{ url | url }}\">link</a>." as *u8 149 out_n[0] = 0 150 if nx_http_template_render(tmpl9, 54, vars, out, 2048, out_n) != NXT_OK { return 110 } 151 if bytes_contains(out, out_n[0], "Hi Alice" as *u8, 8) != 1 { return 111 } 152 if bytes_contains(out, out_n[0], "hello%20world" as *u8, 13) != 1 { return 112 } 153 154 // ---- Template with no vars (plain literal) ---- 155 let tmpl10: *u8 = "<h1>plain</h1>" as *u8 156 out_n[0] = 0 157 if nx_http_template_render(tmpl10, 14, vars, out, 2048, out_n) != NXT_OK { return 120 } 158 if out_n[0] != 14 { return 121 } 159 if bytes_eq(out, tmpl10, 14) != 1 { return 122 } 160 161 // ---- BAD_ARG paths ---- 162 out_n[0] = 0 163 if nx_http_template_render(0 as *u8, 10, vars, out, 2048, out_n) != NXT_BAD_ARG { return 130 } 164 if nx_http_template_render(tmpl1, 18, 0 as *NxTemplateVars, out, 2048, out_n) != NXT_BAD_ARG { return 131 } 165 if nx_http_template_render(tmpl1, 18, vars, 0 as *u8, 2048, out_n) != NXT_BAD_ARG { return 132 } 166 if nx_http_template_render(tmpl1, 18, vars, out, 0, out_n) != NXT_BAD_ARG { return 133 } 167 168 return 0 169}