1
2 /*
3 * Copyright (C) NGINX, Inc.
4 */
5
6 #include <nxt_router.h>
7 #include <nxt_http.h>
8 #include <njs.h>
9
10
11 static njs_int_t nxt_http_js_ext_uri(njs_vm_t *vm, njs_object_prop_t *prop,
12 njs_value_t *value, njs_value_t *setval, njs_value_t *retval);
13 static njs_int_t nxt_http_js_ext_host(njs_vm_t *vm, njs_object_prop_t *prop,
14 njs_value_t *value, njs_value_t *setval, njs_value_t *retval);
15 static njs_int_t nxt_http_js_ext_remote_addr(njs_vm_t *vm,
16 njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval,
17 njs_value_t *retval);
18 static njs_int_t nxt_http_js_ext_get_args(njs_vm_t *vm,
19 njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval,
20 njs_value_t *retval);
21 static njs_int_t nxt_http_js_ext_get_header(njs_vm_t *vm,
22 njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval,
23 njs_value_t *retval);
24 static njs_int_t nxt_http_js_ext_keys_header(njs_vm_t *vm,
25 njs_value_t *value, njs_value_t *keys);
26 static njs_int_t nxt_http_js_ext_get_cookie(njs_vm_t *vm,
27 njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval,
28 njs_value_t *retval);
29 static njs_int_t nxt_http_js_ext_keys_cookie(njs_vm_t *vm, njs_value_t *value,
30 njs_value_t *keys);
31 static njs_int_t nxt_http_js_ext_get_var(njs_vm_t *vm, njs_object_prop_t *prop,
32 njs_value_t *value, njs_value_t *setval, njs_value_t *retval);
33
34
35 static njs_external_t nxt_http_js_proto[] = {
36 {
37 .flags = NJS_EXTERN_PROPERTY,
38 .name.string = njs_str("uri"),
39 .enumerable = 1,
40 .u.property = {
41 .handler = nxt_http_js_ext_uri,
42 }
43 },
44
45 {
46 .flags = NJS_EXTERN_PROPERTY,
47 .name.string = njs_str("host"),
48 .enumerable = 1,
49 .u.property = {
50 .handler = nxt_http_js_ext_host,
51 }
52 },
53
54 {
55 .flags = NJS_EXTERN_PROPERTY,
56 .name.string = njs_str("remoteAddr"),
57 .enumerable = 1,
58 .u.property = {
59 .handler = nxt_http_js_ext_remote_addr,
60 }
61 },
62
63 {
64 .flags = NJS_EXTERN_PROPERTY,
65 .name.string = njs_str("args"),
66 .enumerable = 1,
67 .u.property = {
68 .handler = nxt_http_js_ext_get_args,
69 }
70 },
71
72 {
73 .flags = NJS_EXTERN_OBJECT,
74 .name.string = njs_str("headers"),
75 .enumerable = 1,
76 .u.object = {
77 .enumerable = 1,
78 .prop_handler = nxt_http_js_ext_get_header,
79 .keys = nxt_http_js_ext_keys_header,
80 }
81 },
82
83 {
84 .flags = NJS_EXTERN_OBJECT,
85 .name.string = njs_str("cookies"),
86 .enumerable = 1,
87 .u.object = {
88 .enumerable = 1,
89 .prop_handler = nxt_http_js_ext_get_cookie,
90 .keys = nxt_http_js_ext_keys_cookie,
91 }
92 },
93
94 {
95 .flags = NJS_EXTERN_OBJECT,
96 .name.string = njs_str("vars"),
97 .u.object = {
98 .prop_handler = nxt_http_js_ext_get_var,
99 }
100 },
101 };
102
103
104 void
nxt_http_register_js_proto(nxt_js_conf_t * jcf)105 nxt_http_register_js_proto(nxt_js_conf_t *jcf)
106 {
107 nxt_js_set_proto(jcf, nxt_http_js_proto, njs_nitems(nxt_http_js_proto));
108 }
109
110
111 static njs_int_t
nxt_http_js_ext_uri(njs_vm_t * vm,njs_object_prop_t * prop,njs_value_t * value,njs_value_t * setval,njs_value_t * retval)112 nxt_http_js_ext_uri(njs_vm_t *vm, njs_object_prop_t *prop,
113 njs_value_t *value, njs_value_t *setval, njs_value_t *retval)
114 {
115 nxt_http_request_t *r;
116
117 r = njs_vm_external(vm, nxt_js_proto_id, value);
118 if (r == NULL) {
119 njs_value_undefined_set(retval);
120 return NJS_DECLINED;
121 }
122
123 return njs_vm_value_string_set(vm, retval, r->path->start, r->path->length);
124 }
125
126
127 static njs_int_t
nxt_http_js_ext_host(njs_vm_t * vm,njs_object_prop_t * prop,njs_value_t * value,njs_value_t * setval,njs_value_t * retval)128 nxt_http_js_ext_host(njs_vm_t *vm, njs_object_prop_t *prop,
129 njs_value_t *value, njs_value_t *setval, njs_value_t *retval)
130 {
131 nxt_http_request_t *r;
132
133 r = njs_vm_external(vm, nxt_js_proto_id, value);
134 if (r == NULL) {
135 njs_value_undefined_set(retval);
136 return NJS_DECLINED;
137 }
138
139 return njs_vm_value_string_set(vm, retval, r->host.start, r->host.length);
140 }
141
142
143 static njs_int_t
nxt_http_js_ext_remote_addr(njs_vm_t * vm,njs_object_prop_t * prop,njs_value_t * value,njs_value_t * setval,njs_value_t * retval)144 nxt_http_js_ext_remote_addr(njs_vm_t *vm, njs_object_prop_t *prop,
145 njs_value_t *value, njs_value_t *setval, njs_value_t *retval)
146 {
147 nxt_http_request_t *r;
148
149 r = njs_vm_external(vm, nxt_js_proto_id, value);
150 if (r == NULL) {
151 njs_value_undefined_set(retval);
152 return NJS_DECLINED;
153 }
154
155 return njs_vm_value_string_set(vm, retval,
156 nxt_sockaddr_address(r->remote),
157 r->remote->address_length);
158 }
159
160
161 static njs_int_t
nxt_http_js_ext_get_args(njs_vm_t * vm,njs_object_prop_t * prop,njs_value_t * value,njs_value_t * setval,njs_value_t * retval)162 nxt_http_js_ext_get_args(njs_vm_t *vm, njs_object_prop_t *prop,
163 njs_value_t *value, njs_value_t *setval, njs_value_t *retval)
164 {
165 njs_int_t ret;
166 njs_value_t *args;
167 njs_opaque_value_t val;
168 nxt_http_request_t *r;
169
170 r = njs_vm_external(vm, nxt_js_proto_id, value);
171 if (r == NULL) {
172 njs_value_undefined_set(retval);
173 return NJS_DECLINED;
174 }
175
176 args = njs_value_arg(&val);
177
178 ret = njs_vm_query_string_parse(vm, r->args->start,
179 r->args->start + r->args->length, args);
180
181 if (ret == NJS_ERROR) {
182 return NJS_ERROR;
183 }
184
185 njs_value_assign(retval, args);
186
187 return NJS_OK;
188 }
189
190
191 static njs_int_t
nxt_http_js_ext_get_header(njs_vm_t * vm,njs_object_prop_t * prop,njs_value_t * value,njs_value_t * setval,njs_value_t * retval)192 nxt_http_js_ext_get_header(njs_vm_t *vm, njs_object_prop_t *prop,
193 njs_value_t *value, njs_value_t *setval, njs_value_t *retval)
194 {
195 njs_int_t rc;
196 njs_str_t key;
197 nxt_http_field_t *f;
198 nxt_http_request_t *r;
199
200 r = njs_vm_external(vm, nxt_js_proto_id, value);
201 if (r == NULL) {
202 njs_value_undefined_set(retval);
203 return NJS_DECLINED;
204 }
205
206 rc = njs_vm_prop_name(vm, prop, &key);
207 if (rc != NJS_OK) {
208 njs_value_undefined_set(retval);
209 return NJS_DECLINED;
210 }
211
212 nxt_list_each(f, r->fields) {
213
214 if (key.length == f->name_length
215 && memcmp(key.start, f->name, f->name_length) == 0)
216 {
217 return njs_vm_value_string_set(vm, retval, f->value,
218 f->value_length);
219 }
220
221 } nxt_list_loop;
222
223 njs_value_undefined_set(retval);
224
225 return NJS_DECLINED;
226 }
227
228
229 static njs_int_t
nxt_http_js_ext_keys_header(njs_vm_t * vm,njs_value_t * value,njs_value_t * keys)230 nxt_http_js_ext_keys_header(njs_vm_t *vm, njs_value_t *value, njs_value_t *keys)
231 {
232 njs_int_t rc;
233 nxt_http_field_t *f;
234 nxt_http_request_t *r;
235
236 rc = njs_vm_array_alloc(vm, keys, 4);
237 if (rc != NJS_OK) {
238 return NJS_ERROR;
239 }
240
241 r = njs_vm_external(vm, nxt_js_proto_id, value);
242 if (r == NULL) {
243 return NJS_OK;
244 }
245
246 nxt_list_each(f, r->fields) {
247
248 value = njs_vm_array_push(vm, keys);
249 if (value == NULL) {
250 return NJS_ERROR;
251 }
252
253 rc = njs_vm_value_string_set(vm, value, f->name, f->name_length);
254 if (rc != NJS_OK) {
255 return NJS_ERROR;
256 }
257
258 } nxt_list_loop;
259
260 return NJS_OK;
261 }
262
263
264 static njs_int_t
nxt_http_js_ext_get_cookie(njs_vm_t * vm,njs_object_prop_t * prop,njs_value_t * value,njs_value_t * setval,njs_value_t * retval)265 nxt_http_js_ext_get_cookie(njs_vm_t *vm, njs_object_prop_t *prop,
266 njs_value_t *value, njs_value_t *setval, njs_value_t *retval)
267 {
268 njs_int_t rc;
269 njs_str_t key;
270 nxt_array_t *cookies;
271 nxt_http_request_t *r;
272 nxt_http_name_value_t *nv, *start, *end;
273
274 r = njs_vm_external(vm, nxt_js_proto_id, value);
275 if (r == NULL) {
276 njs_value_undefined_set(retval);
277 return NJS_DECLINED;
278 }
279
280 rc = njs_vm_prop_name(vm, prop, &key);
281 if (rc != NJS_OK) {
282 njs_value_undefined_set(retval);
283 return NJS_DECLINED;
284 }
285
286 cookies = nxt_http_cookies_parse(r);
287 if (nxt_slow_path(cookies == NULL)) {
288 return NJS_ERROR;
289 }
290
291 start = cookies->elts;
292 end = start + cookies->nelts;
293
294 for (nv = start; nv < end; nv++) {
295
296 if (key.length == nv->name_length
297 && memcmp(key.start, nv->name, nv->name_length) == 0)
298 {
299 return njs_vm_value_string_set(vm, retval, nv->value,
300 nv->value_length);
301 }
302 }
303
304 njs_value_undefined_set(retval);
305
306 return NJS_DECLINED;
307 }
308
309
310 static njs_int_t
nxt_http_js_ext_keys_cookie(njs_vm_t * vm,njs_value_t * value,njs_value_t * keys)311 nxt_http_js_ext_keys_cookie(njs_vm_t *vm, njs_value_t *value, njs_value_t *keys)
312 {
313 njs_int_t rc;
314 nxt_array_t *cookies;
315 nxt_http_request_t *r;
316 nxt_http_name_value_t *nv, *start, *end;
317
318 rc = njs_vm_array_alloc(vm, keys, 4);
319 if (rc != NJS_OK) {
320 return NJS_ERROR;
321 }
322
323 r = njs_vm_external(vm, nxt_js_proto_id, value);
324 if (r == NULL) {
325 return NJS_OK;
326 }
327
328 cookies = nxt_http_cookies_parse(r);
329 if (nxt_slow_path(cookies == NULL)) {
330 return NJS_ERROR;
331 }
332
333 start = cookies->elts;
334 end = start + cookies->nelts;
335
336 for (nv = start; nv < end; nv++) {
337
338 value = njs_vm_array_push(vm, keys);
339 if (value == NULL) {
340 return NJS_ERROR;
341 }
342
343 rc = njs_vm_value_string_set(vm, value, nv->name, nv->name_length);
344 if (rc != NJS_OK) {
345 return NJS_ERROR;
346 }
347 }
348
349 return NJS_OK;
350 }
351
352
353 static njs_int_t
nxt_http_js_ext_get_var(njs_vm_t * vm,njs_object_prop_t * prop,njs_value_t * value,njs_value_t * setval,njs_value_t * retval)354 nxt_http_js_ext_get_var(njs_vm_t *vm, njs_object_prop_t *prop,
355 njs_value_t *value, njs_value_t *setval, njs_value_t *retval)
356 {
357 njs_int_t rc;
358 njs_str_t key;
359 nxt_str_t name, *vv;
360 nxt_router_conf_t *rtcf;
361 nxt_http_request_t *r;
362
363 r = njs_vm_external(vm, nxt_js_proto_id, value);
364 if (r == NULL) {
365 njs_value_undefined_set(retval);
366 return NJS_DECLINED;
367 }
368
369 rc = njs_vm_prop_name(vm, prop, &key);
370 if (rc != NJS_OK) {
371 njs_value_undefined_set(retval);
372 return NJS_DECLINED;
373 }
374
375 rtcf = r->conf->socket_conf->router_conf;
376
377 name.start = key.start;
378 name.length = key.length;
379
380 vv = nxt_var_get(&r->task, rtcf->tstr_state, &r->tstr_cache.var, &name, r);
381
382 if (vv != NULL) {
383 return njs_vm_value_string_set(vm, retval, vv->start, vv->length);
384 }
385
386 njs_value_undefined_set(retval);
387
388 return NJS_DECLINED;
389 }
390