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