/src/unit/src/nxt_http_variables.c
Line | Count | Source (jump to first uncovered line) |
1 | | |
2 | | /* |
3 | | * Copyright (C) NGINX, Inc. |
4 | | */ |
5 | | |
6 | | #include <nxt_router.h> |
7 | | #include <nxt_http.h> |
8 | | |
9 | | |
10 | | static nxt_int_t nxt_http_var_dollar(nxt_task_t *task, nxt_str_t *str, |
11 | | void *ctx, uint16_t field); |
12 | | static nxt_int_t nxt_http_var_request_time(nxt_task_t *task, nxt_str_t *str, |
13 | | void *ctx, uint16_t field); |
14 | | static nxt_int_t nxt_http_var_method(nxt_task_t *task, nxt_str_t *str, |
15 | | void *ctx, uint16_t field); |
16 | | static nxt_int_t nxt_http_var_request_uri(nxt_task_t *task, nxt_str_t *str, |
17 | | void *ctx, uint16_t field); |
18 | | static nxt_int_t nxt_http_var_uri(nxt_task_t *task, nxt_str_t *str, void *ctx, |
19 | | uint16_t field); |
20 | | static nxt_int_t nxt_http_var_host(nxt_task_t *task, nxt_str_t *str, void *ctx, |
21 | | uint16_t field); |
22 | | static nxt_int_t nxt_http_var_remote_addr(nxt_task_t *task, nxt_str_t *str, |
23 | | void *ctx, uint16_t field); |
24 | | static nxt_int_t nxt_http_var_time_local(nxt_task_t *task, nxt_str_t *str, |
25 | | void *ctx, uint16_t field); |
26 | | static u_char *nxt_http_log_date(u_char *buf, nxt_realtime_t *now, |
27 | | struct tm *tm, size_t size, const char *format); |
28 | | static nxt_int_t nxt_http_var_request_line(nxt_task_t *task, nxt_str_t *str, |
29 | | void *ctx, uint16_t field); |
30 | | static nxt_int_t nxt_http_var_status(nxt_task_t *task, nxt_str_t *str, |
31 | | void *ctx, uint16_t field); |
32 | | static nxt_int_t nxt_http_var_body_bytes_sent(nxt_task_t *task, nxt_str_t *str, |
33 | | void *ctx, uint16_t field); |
34 | | static nxt_int_t nxt_http_var_referer(nxt_task_t *task, nxt_str_t *str, |
35 | | void *ctx, uint16_t field); |
36 | | static nxt_int_t nxt_http_var_user_agent(nxt_task_t *task, nxt_str_t *str, |
37 | | void *ctx, uint16_t field); |
38 | | static nxt_int_t nxt_http_var_arg(nxt_task_t *task, nxt_str_t *str, void *ctx, |
39 | | uint16_t field); |
40 | | static nxt_int_t nxt_http_var_header(nxt_task_t *task, nxt_str_t *str, |
41 | | void *ctx, uint16_t field); |
42 | | static nxt_int_t nxt_http_var_cookie(nxt_task_t *task, nxt_str_t *str, |
43 | | void *ctx, uint16_t field); |
44 | | |
45 | | |
46 | | static nxt_var_decl_t nxt_http_vars[] = { |
47 | | { |
48 | | .name = nxt_string("dollar"), |
49 | | .handler = nxt_http_var_dollar, |
50 | | }, { |
51 | | .name = nxt_string("request_time"), |
52 | | .handler = nxt_http_var_request_time, |
53 | | }, { |
54 | | .name = nxt_string("method"), |
55 | | .handler = nxt_http_var_method, |
56 | | }, { |
57 | | .name = nxt_string("request_uri"), |
58 | | .handler = nxt_http_var_request_uri, |
59 | | }, { |
60 | | .name = nxt_string("uri"), |
61 | | .handler = nxt_http_var_uri, |
62 | | }, { |
63 | | .name = nxt_string("host"), |
64 | | .handler = nxt_http_var_host, |
65 | | }, { |
66 | | .name = nxt_string("remote_addr"), |
67 | | .handler = nxt_http_var_remote_addr, |
68 | | }, { |
69 | | .name = nxt_string("time_local"), |
70 | | .handler = nxt_http_var_time_local, |
71 | | }, { |
72 | | .name = nxt_string("request_line"), |
73 | | .handler = nxt_http_var_request_line, |
74 | | }, { |
75 | | .name = nxt_string("status"), |
76 | | .handler = nxt_http_var_status, |
77 | | }, { |
78 | | .name = nxt_string("body_bytes_sent"), |
79 | | .handler = nxt_http_var_body_bytes_sent, |
80 | | }, { |
81 | | .name = nxt_string("header_referer"), |
82 | | .handler = nxt_http_var_referer, |
83 | | }, { |
84 | | .name = nxt_string("header_user_agent"), |
85 | | .handler = nxt_http_var_user_agent, |
86 | | }, { |
87 | | .name = nxt_string("arg"), |
88 | | .handler = nxt_http_var_arg, |
89 | | .field_hash = nxt_http_argument_hash, |
90 | | }, { |
91 | | .name = nxt_string("header"), |
92 | | .handler = nxt_http_var_header, |
93 | | .field_hash = nxt_http_header_hash, |
94 | | }, { |
95 | | .name = nxt_string("cookie"), |
96 | | .handler = nxt_http_var_cookie, |
97 | | .field_hash = nxt_http_cookie_hash, |
98 | | }, |
99 | | }; |
100 | | |
101 | | |
102 | | nxt_int_t |
103 | | nxt_http_register_variables(void) |
104 | 0 | { |
105 | 0 | return nxt_var_register(nxt_http_vars, nxt_nitems(nxt_http_vars)); |
106 | 0 | } |
107 | | |
108 | | |
109 | | static nxt_int_t |
110 | | nxt_http_var_dollar(nxt_task_t *task, nxt_str_t *str, void *ctx, uint16_t field) |
111 | 0 | { |
112 | 0 | nxt_str_set(str, "$"); |
113 | |
|
114 | 0 | return NXT_OK; |
115 | 0 | } |
116 | | |
117 | | |
118 | | static nxt_int_t |
119 | | nxt_http_var_request_time(nxt_task_t *task, nxt_str_t *str, void *ctx, |
120 | | uint16_t field) |
121 | 0 | { |
122 | 0 | u_char *p; |
123 | 0 | nxt_msec_t ms; |
124 | 0 | nxt_nsec_t now; |
125 | 0 | nxt_http_request_t *r; |
126 | |
|
127 | 0 | r = ctx; |
128 | |
|
129 | 0 | now = nxt_thread_monotonic_time(task->thread); |
130 | 0 | ms = (now - r->start_time) / 1000000; |
131 | |
|
132 | 0 | str->start = nxt_mp_nget(r->mem_pool, NXT_TIME_T_LEN + 4); |
133 | 0 | if (nxt_slow_path(str->start == NULL)) { |
134 | 0 | return NXT_ERROR; |
135 | 0 | } |
136 | | |
137 | 0 | p = nxt_sprintf(str->start, str->start + NXT_TIME_T_LEN, "%T.%03M", |
138 | 0 | (nxt_time_t) ms / 1000, ms % 1000); |
139 | |
|
140 | 0 | str->length = p - str->start; |
141 | |
|
142 | 0 | return NXT_OK; |
143 | 0 | } |
144 | | |
145 | | |
146 | | static nxt_int_t |
147 | | nxt_http_var_method(nxt_task_t *task, nxt_str_t *str, void *ctx, uint16_t field) |
148 | 0 | { |
149 | 0 | nxt_http_request_t *r; |
150 | |
|
151 | 0 | r = ctx; |
152 | |
|
153 | 0 | *str = *r->method; |
154 | |
|
155 | 0 | return NXT_OK; |
156 | 0 | } |
157 | | |
158 | | |
159 | | static nxt_int_t |
160 | | nxt_http_var_request_uri(nxt_task_t *task, nxt_str_t *str, void *ctx, |
161 | | uint16_t field) |
162 | 0 | { |
163 | 0 | nxt_http_request_t *r; |
164 | |
|
165 | 0 | r = ctx; |
166 | |
|
167 | 0 | *str = r->target; |
168 | |
|
169 | 0 | return NXT_OK; |
170 | 0 | } |
171 | | |
172 | | |
173 | | static nxt_int_t |
174 | | nxt_http_var_uri(nxt_task_t *task, nxt_str_t *str, void *ctx, uint16_t field) |
175 | 0 | { |
176 | 0 | nxt_http_request_t *r; |
177 | |
|
178 | 0 | r = ctx; |
179 | |
|
180 | 0 | *str = *r->path; |
181 | |
|
182 | 0 | return NXT_OK; |
183 | 0 | } |
184 | | |
185 | | |
186 | | static nxt_int_t |
187 | | nxt_http_var_host(nxt_task_t *task, nxt_str_t *str, void *ctx, uint16_t field) |
188 | 0 | { |
189 | 0 | nxt_http_request_t *r; |
190 | |
|
191 | 0 | r = ctx; |
192 | |
|
193 | 0 | *str = r->host; |
194 | |
|
195 | 0 | return NXT_OK; |
196 | 0 | } |
197 | | |
198 | | |
199 | | static nxt_int_t |
200 | | nxt_http_var_remote_addr(nxt_task_t *task, nxt_str_t *str, void *ctx, |
201 | | uint16_t field) |
202 | 0 | { |
203 | 0 | nxt_http_request_t *r; |
204 | |
|
205 | 0 | r = ctx; |
206 | |
|
207 | 0 | str->length = r->remote->address_length; |
208 | 0 | str->start = nxt_sockaddr_address(r->remote); |
209 | |
|
210 | 0 | return NXT_OK; |
211 | 0 | } |
212 | | |
213 | | |
214 | | static nxt_int_t |
215 | | nxt_http_var_time_local(nxt_task_t *task, nxt_str_t *str, void *ctx, |
216 | | uint16_t field) |
217 | 0 | { |
218 | 0 | nxt_http_request_t *r; |
219 | |
|
220 | 0 | static nxt_time_string_t date_cache = { |
221 | 0 | (nxt_atomic_uint_t) -1, |
222 | 0 | nxt_http_log_date, |
223 | 0 | "%02d/%s/%4d:%02d:%02d:%02d %c%02d%02d", |
224 | 0 | nxt_length("31/Dec/1986:19:40:00 +0300"), |
225 | 0 | NXT_THREAD_TIME_LOCAL, |
226 | 0 | NXT_THREAD_TIME_SEC, |
227 | 0 | }; |
228 | |
|
229 | 0 | r = ctx; |
230 | |
|
231 | 0 | str->length = date_cache.size; |
232 | |
|
233 | 0 | str->start = nxt_mp_nget(r->mem_pool, str->length); |
234 | 0 | if (nxt_slow_path(str->start == NULL)) { |
235 | 0 | return NXT_ERROR; |
236 | 0 | } |
237 | | |
238 | 0 | str->length = nxt_thread_time_string(task->thread, &date_cache, str->start) |
239 | 0 | - str->start; |
240 | |
|
241 | 0 | return NXT_OK; |
242 | 0 | } |
243 | | |
244 | | |
245 | | static u_char * |
246 | | nxt_http_log_date(u_char *buf, nxt_realtime_t *now, struct tm *tm, |
247 | | size_t size, const char *format) |
248 | 0 | { |
249 | 0 | u_char sign; |
250 | 0 | time_t gmtoff; |
251 | |
|
252 | 0 | static const char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", |
253 | 0 | "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; |
254 | |
|
255 | 0 | gmtoff = nxt_timezone(tm) / 60; |
256 | |
|
257 | 0 | if (gmtoff < 0) { |
258 | 0 | gmtoff = -gmtoff; |
259 | 0 | sign = '-'; |
260 | |
|
261 | 0 | } else { |
262 | 0 | sign = '+'; |
263 | 0 | } |
264 | |
|
265 | 0 | return nxt_sprintf(buf, buf + size, format, |
266 | 0 | tm->tm_mday, month[tm->tm_mon], tm->tm_year + 1900, |
267 | 0 | tm->tm_hour, tm->tm_min, tm->tm_sec, |
268 | 0 | sign, gmtoff / 60, gmtoff % 60); |
269 | 0 | } |
270 | | |
271 | | |
272 | | static nxt_int_t |
273 | | nxt_http_var_request_line(nxt_task_t *task, nxt_str_t *str, void *ctx, |
274 | | uint16_t field) |
275 | 0 | { |
276 | 0 | size_t length; |
277 | 0 | u_char *p, *start; |
278 | 0 | nxt_http_request_t *r; |
279 | |
|
280 | 0 | r = ctx; |
281 | |
|
282 | 0 | length = r->method->length + 1 + r->target.length + 1 + r->version.length; |
283 | |
|
284 | 0 | start = nxt_mp_nget(r->mem_pool, length); |
285 | 0 | if (nxt_slow_path(start == NULL)) { |
286 | 0 | return NXT_ERROR; |
287 | 0 | } |
288 | | |
289 | 0 | p = start; |
290 | |
|
291 | 0 | if (r->method->length != 0) { |
292 | 0 | p = nxt_cpymem(p, r->method->start, r->method->length); |
293 | |
|
294 | 0 | if (r->target.length != 0) { |
295 | 0 | *p++ = ' '; |
296 | 0 | p = nxt_cpymem(p, r->target.start, r->target.length); |
297 | |
|
298 | 0 | if (r->version.length != 0) { |
299 | 0 | *p++ = ' '; |
300 | 0 | p = nxt_cpymem(p, r->version.start, r->version.length); |
301 | 0 | } |
302 | 0 | } |
303 | |
|
304 | 0 | } else { |
305 | 0 | *p++ = '-'; |
306 | 0 | } |
307 | |
|
308 | 0 | str->start = start; |
309 | 0 | str->length = p - start; |
310 | |
|
311 | 0 | return NXT_OK; |
312 | 0 | } |
313 | | |
314 | | |
315 | | static nxt_int_t |
316 | | nxt_http_var_body_bytes_sent(nxt_task_t *task, nxt_str_t *str, void *ctx, |
317 | | uint16_t field) |
318 | 0 | { |
319 | 0 | nxt_off_t bytes; |
320 | 0 | nxt_http_request_t *r; |
321 | |
|
322 | 0 | r = ctx; |
323 | |
|
324 | 0 | str->start = nxt_mp_nget(r->mem_pool, NXT_OFF_T_LEN); |
325 | 0 | if (nxt_slow_path(str->start == NULL)) { |
326 | 0 | return NXT_ERROR; |
327 | 0 | } |
328 | | |
329 | 0 | bytes = nxt_http_proto[r->protocol].body_bytes_sent(task, r->proto); |
330 | |
|
331 | 0 | str->length = nxt_sprintf(str->start, str->start + NXT_OFF_T_LEN, "%O", |
332 | 0 | bytes) - str->start; |
333 | |
|
334 | 0 | return NXT_OK; |
335 | 0 | } |
336 | | |
337 | | |
338 | | static nxt_int_t |
339 | | nxt_http_var_status(nxt_task_t *task, nxt_str_t *str, void *ctx, uint16_t field) |
340 | 0 | { |
341 | 0 | nxt_http_request_t *r; |
342 | |
|
343 | 0 | r = ctx; |
344 | |
|
345 | 0 | str->start = nxt_mp_nget(r->mem_pool, 3); |
346 | 0 | if (nxt_slow_path(str->start == NULL)) { |
347 | 0 | return NXT_ERROR; |
348 | 0 | } |
349 | | |
350 | 0 | str->length = nxt_sprintf(str->start, str->start + 3, "%03d", r->status) |
351 | 0 | - str->start; |
352 | |
|
353 | 0 | return NXT_OK; |
354 | 0 | } |
355 | | |
356 | | |
357 | | static nxt_int_t |
358 | | nxt_http_var_referer(nxt_task_t *task, nxt_str_t *str, void *ctx, |
359 | | uint16_t field) |
360 | 0 | { |
361 | 0 | nxt_http_request_t *r; |
362 | |
|
363 | 0 | r = ctx; |
364 | |
|
365 | 0 | if (r->referer != NULL) { |
366 | 0 | str->start = r->referer->value; |
367 | 0 | str->length = r->referer->value_length; |
368 | |
|
369 | 0 | } else { |
370 | 0 | nxt_str_null(str); |
371 | 0 | } |
372 | |
|
373 | 0 | return NXT_OK; |
374 | 0 | } |
375 | | |
376 | | |
377 | | static nxt_int_t |
378 | | nxt_http_var_user_agent(nxt_task_t *task, nxt_str_t *str, void *ctx, |
379 | | uint16_t field) |
380 | 0 | { |
381 | 0 | nxt_http_request_t *r; |
382 | |
|
383 | 0 | r = ctx; |
384 | |
|
385 | 0 | if (r->user_agent != NULL) { |
386 | 0 | str->start = r->user_agent->value; |
387 | 0 | str->length = r->user_agent->value_length; |
388 | |
|
389 | 0 | } else { |
390 | 0 | nxt_str_null(str); |
391 | 0 | } |
392 | |
|
393 | 0 | return NXT_OK; |
394 | 0 | } |
395 | | |
396 | | |
397 | | static nxt_int_t |
398 | | nxt_http_var_arg(nxt_task_t *task, nxt_str_t *str, void *ctx, uint16_t field) |
399 | 0 | { |
400 | 0 | nxt_array_t *args; |
401 | 0 | nxt_var_field_t *vf; |
402 | 0 | nxt_router_conf_t *rtcf; |
403 | 0 | nxt_http_request_t *r; |
404 | 0 | nxt_http_name_value_t *nv, *start; |
405 | |
|
406 | 0 | r = ctx; |
407 | |
|
408 | 0 | rtcf = r->conf->socket_conf->router_conf; |
409 | |
|
410 | 0 | vf = nxt_var_field_get(rtcf->tstr_state->var_fields, field); |
411 | |
|
412 | 0 | args = nxt_http_arguments_parse(r); |
413 | 0 | if (nxt_slow_path(args == NULL)) { |
414 | 0 | return NXT_ERROR; |
415 | 0 | } |
416 | | |
417 | 0 | start = args->elts; |
418 | 0 | nv = start + args->nelts - 1; |
419 | |
|
420 | 0 | while (nv >= start) { |
421 | |
|
422 | 0 | if (vf->hash == nv->hash |
423 | 0 | && vf->name.length == nv->name_length |
424 | 0 | && memcmp(vf->name.start, nv->name, nv->name_length) == 0) |
425 | 0 | { |
426 | 0 | str->start = nv->value; |
427 | 0 | str->length = nv->value_length; |
428 | |
|
429 | 0 | return NXT_OK; |
430 | 0 | } |
431 | | |
432 | 0 | nv--; |
433 | 0 | } |
434 | | |
435 | 0 | nxt_str_null(str); |
436 | |
|
437 | 0 | return NXT_OK; |
438 | 0 | } |
439 | | |
440 | | |
441 | | static nxt_int_t |
442 | | nxt_http_var_header(nxt_task_t *task, nxt_str_t *str, void *ctx, uint16_t field) |
443 | 0 | { |
444 | 0 | nxt_var_field_t *vf; |
445 | 0 | nxt_http_field_t *f; |
446 | 0 | nxt_router_conf_t *rtcf; |
447 | 0 | nxt_http_request_t *r; |
448 | |
|
449 | 0 | r = ctx; |
450 | |
|
451 | 0 | rtcf = r->conf->socket_conf->router_conf; |
452 | |
|
453 | 0 | vf = nxt_var_field_get(rtcf->tstr_state->var_fields, field); |
454 | |
|
455 | 0 | nxt_list_each(f, r->fields) { |
456 | |
|
457 | 0 | if (vf->hash == f->hash |
458 | 0 | && vf->name.length == f->name_length |
459 | 0 | && nxt_strncasecmp(vf->name.start, f->name, f->name_length) == 0) |
460 | 0 | { |
461 | 0 | str->start = f->value; |
462 | 0 | str->length = f->value_length; |
463 | |
|
464 | 0 | return NXT_OK; |
465 | 0 | } |
466 | |
|
467 | 0 | } nxt_list_loop; |
468 | | |
469 | 0 | nxt_str_null(str); |
470 | |
|
471 | 0 | return NXT_OK; |
472 | 0 | } |
473 | | |
474 | | |
475 | | static nxt_int_t |
476 | | nxt_http_var_cookie(nxt_task_t *task, nxt_str_t *str, void *ctx, uint16_t field) |
477 | 0 | { |
478 | 0 | nxt_array_t *cookies; |
479 | 0 | nxt_var_field_t *vf; |
480 | 0 | nxt_router_conf_t *rtcf; |
481 | 0 | nxt_http_request_t *r; |
482 | 0 | nxt_http_name_value_t *nv, *end; |
483 | |
|
484 | 0 | r = ctx; |
485 | |
|
486 | 0 | rtcf = r->conf->socket_conf->router_conf; |
487 | |
|
488 | 0 | vf = nxt_var_field_get(rtcf->tstr_state->var_fields, field); |
489 | |
|
490 | 0 | cookies = nxt_http_cookies_parse(r); |
491 | 0 | if (nxt_slow_path(cookies == NULL)) { |
492 | 0 | return NXT_ERROR; |
493 | 0 | } |
494 | | |
495 | 0 | nv = cookies->elts; |
496 | 0 | end = nv + cookies->nelts; |
497 | |
|
498 | 0 | while (nv < end) { |
499 | |
|
500 | 0 | if (vf->hash == nv->hash |
501 | 0 | && vf->name.length == nv->name_length |
502 | 0 | && memcmp(vf->name.start, nv->name, nv->name_length) == 0) |
503 | 0 | { |
504 | 0 | str->start = nv->value; |
505 | 0 | str->length = nv->value_length; |
506 | |
|
507 | 0 | return NXT_OK; |
508 | 0 | } |
509 | | |
510 | 0 | nv++; |
511 | 0 | } |
512 | | |
513 | 0 | nxt_str_null(str); |
514 | |
|
515 | 0 | return NXT_OK; |
516 | 0 | } |