Line data Source code
1 :
2 : /*
3 : * Copyright (C) Xiaozhe Wang (chaoslawful)
4 : * Copyright (C) Yichun Zhang (agentzh)
5 : */
6 :
7 :
8 : #ifndef DDEBUG
9 : #define DDEBUG 0
10 : #endif
11 : #include "ddebug.h"
12 :
13 :
14 : #include "ngx_http_lua_args.h"
15 : #include "ngx_http_lua_util.h"
16 :
17 :
18 : static int ngx_http_lua_ngx_req_set_uri_args(lua_State *L);
19 : static int ngx_http_lua_ngx_req_get_uri_args(lua_State *L);
20 : static int ngx_http_lua_ngx_req_get_post_args(lua_State *L);
21 :
22 :
23 : static int
24 0 : ngx_http_lua_ngx_req_set_uri_args(lua_State *L)
25 : {
26 : ngx_http_request_t *r;
27 : ngx_str_t args;
28 : const char *msg;
29 : size_t len;
30 : u_char *p;
31 :
32 0 : if (lua_gettop(L) != 1) {
33 0 : return luaL_error(L, "expecting 1 argument but seen %d",
34 : lua_gettop(L));
35 : }
36 :
37 0 : r = ngx_http_lua_get_req(L);
38 0 : if (r == NULL) {
39 0 : return luaL_error(L, "no request object found");
40 : }
41 :
42 0 : ngx_http_lua_check_fake_request(L, r);
43 :
44 0 : switch (lua_type(L, 1)) {
45 0 : case LUA_TNUMBER:
46 : case LUA_TSTRING:
47 0 : p = (u_char *) lua_tolstring(L, 1, &len);
48 :
49 0 : args.data = ngx_palloc(r->pool, len);
50 0 : if (args.data == NULL) {
51 0 : return luaL_error(L, "no memory");
52 : }
53 :
54 0 : ngx_memcpy(args.data, p, len);
55 :
56 0 : args.len = len;
57 0 : break;
58 :
59 0 : case LUA_TTABLE:
60 0 : ngx_http_lua_process_args_option(r, L, 1, &args);
61 :
62 : dd("args: %.*s", (int) args.len, args.data);
63 :
64 0 : break;
65 :
66 0 : default:
67 0 : msg = lua_pushfstring(L, "string, number, or table expected, "
68 : "but got %s", luaL_typename(L, 2));
69 0 : return luaL_argerror(L, 1, msg);
70 : }
71 :
72 : dd("args: %.*s", (int) args.len, args.data);
73 :
74 0 : r->args.data = args.data;
75 0 : r->args.len = args.len;
76 :
77 0 : r->valid_unparsed_uri = 0;
78 :
79 0 : return 0;
80 : }
81 :
82 :
83 : static int
84 0 : ngx_http_lua_ngx_req_get_uri_args(lua_State *L)
85 : {
86 : ngx_http_request_t *r;
87 : u_char *buf;
88 : u_char *last;
89 : int retval;
90 : int n;
91 : int max;
92 :
93 0 : n = lua_gettop(L);
94 :
95 0 : if (n != 0 && n != 1) {
96 0 : return luaL_error(L, "expecting 0 or 1 arguments but seen %d", n);
97 : }
98 :
99 0 : if (n == 1) {
100 0 : max = luaL_checkinteger(L, 1);
101 0 : lua_pop(L, 1);
102 :
103 : } else {
104 0 : max = NGX_HTTP_LUA_MAX_ARGS;
105 : }
106 :
107 0 : r = ngx_http_lua_get_req(L);
108 0 : if (r == NULL) {
109 0 : return luaL_error(L, "no request object found");
110 : }
111 :
112 0 : ngx_http_lua_check_fake_request(L, r);
113 :
114 0 : if (r->args.len == 0) {
115 0 : lua_createtable(L, 0, 0);
116 0 : return 1;
117 : }
118 :
119 : /* we copy r->args over to buf to simplify
120 : * unescaping query arg keys and values */
121 :
122 0 : buf = ngx_palloc(r->pool, r->args.len);
123 0 : if (buf == NULL) {
124 0 : return luaL_error(L, "no memory");
125 : }
126 :
127 0 : lua_createtable(L, 0, 4);
128 :
129 0 : ngx_memcpy(buf, r->args.data, r->args.len);
130 :
131 0 : last = buf + r->args.len;
132 :
133 0 : retval = ngx_http_lua_parse_args(L, buf, last, max);
134 :
135 0 : ngx_pfree(r->pool, buf);
136 :
137 0 : return retval;
138 : }
139 :
140 :
141 : static int
142 0 : ngx_http_lua_ngx_req_get_post_args(lua_State *L)
143 : {
144 : ngx_http_request_t *r;
145 : u_char *buf;
146 : int retval;
147 : size_t len;
148 : ngx_chain_t *cl;
149 : u_char *p;
150 : u_char *last;
151 : int n;
152 : int max;
153 :
154 0 : n = lua_gettop(L);
155 :
156 0 : if (n != 0 && n != 1) {
157 0 : return luaL_error(L, "expecting 0 or 1 arguments but seen %d", n);
158 : }
159 :
160 0 : if (n == 1) {
161 0 : max = luaL_checkinteger(L, 1);
162 0 : lua_pop(L, 1);
163 :
164 : } else {
165 0 : max = NGX_HTTP_LUA_MAX_ARGS;
166 : }
167 :
168 0 : r = ngx_http_lua_get_req(L);
169 0 : if (r == NULL) {
170 0 : return luaL_error(L, "no request object found");
171 : }
172 :
173 0 : ngx_http_lua_check_fake_request(L, r);
174 :
175 0 : if (r->discard_body) {
176 0 : lua_createtable(L, 0, 0);
177 0 : return 1;
178 : }
179 :
180 0 : if (r->request_body == NULL) {
181 0 : return luaL_error(L, "no request body found; "
182 : "maybe you should turn on lua_need_request_body?");
183 : }
184 :
185 0 : if (r->request_body->temp_file) {
186 0 : lua_pushnil(L);
187 0 : lua_pushliteral(L, "request body in temp file not supported");
188 0 : return 2;
189 : }
190 :
191 0 : if (r->request_body->bufs == NULL) {
192 0 : lua_createtable(L, 0, 0);
193 0 : return 1;
194 : }
195 :
196 : /* we copy r->request_body->bufs over to buf to simplify
197 : * unescaping query arg keys and values */
198 :
199 0 : len = 0;
200 0 : for (cl = r->request_body->bufs; cl; cl = cl->next) {
201 0 : len += cl->buf->last - cl->buf->pos;
202 : }
203 :
204 : dd("post body length: %d", (int) len);
205 :
206 0 : if (len == 0) {
207 0 : lua_createtable(L, 0, 0);
208 0 : return 1;
209 : }
210 :
211 0 : buf = ngx_palloc(r->pool, len);
212 0 : if (buf == NULL) {
213 0 : return luaL_error(L, "no memory");
214 : }
215 :
216 0 : lua_createtable(L, 0, 4);
217 :
218 0 : p = buf;
219 0 : for (cl = r->request_body->bufs; cl; cl = cl->next) {
220 0 : p = ngx_copy(p, cl->buf->pos, cl->buf->last - cl->buf->pos);
221 : }
222 :
223 : dd("post body: %.*s", (int) len, buf);
224 :
225 0 : last = buf + len;
226 :
227 0 : retval = ngx_http_lua_parse_args(L, buf, last, max);
228 :
229 0 : ngx_pfree(r->pool, buf);
230 :
231 0 : return retval;
232 : }
233 :
234 :
235 : int
236 0 : ngx_http_lua_parse_args(lua_State *L, u_char *buf, u_char *last, int max)
237 : {
238 : u_char *p, *q;
239 : u_char *src, *dst;
240 : unsigned parsing_value;
241 : size_t len;
242 0 : int count = 0;
243 : int top;
244 :
245 0 : top = lua_gettop(L);
246 :
247 0 : p = buf;
248 :
249 0 : parsing_value = 0;
250 0 : q = p;
251 :
252 0 : while (p != last) {
253 0 : if (*p == '=' && ! parsing_value) {
254 : /* key data is between p and q */
255 :
256 0 : src = q; dst = q;
257 :
258 0 : ngx_http_lua_unescape_uri(&dst, &src, p - q,
259 : NGX_UNESCAPE_URI_COMPONENT);
260 :
261 : dd("pushing key %.*s", (int) (dst - q), q);
262 :
263 : /* push the key */
264 0 : lua_pushlstring(L, (char *) q, dst - q);
265 :
266 : /* skip the current '=' char */
267 0 : p++;
268 :
269 0 : q = p;
270 0 : parsing_value = 1;
271 :
272 0 : } else if (*p == '&') {
273 : /* reached the end of a key or a value, just save it */
274 0 : src = q; dst = q;
275 :
276 0 : ngx_http_lua_unescape_uri(&dst, &src, p - q,
277 : NGX_UNESCAPE_URI_COMPONENT);
278 :
279 : dd("pushing key or value %.*s", (int) (dst - q), q);
280 :
281 : /* push the value or key */
282 0 : lua_pushlstring(L, (char *) q, dst - q);
283 :
284 : /* skip the current '&' char */
285 0 : p++;
286 :
287 0 : q = p;
288 :
289 0 : if (parsing_value) {
290 : /* end of the current pair's value */
291 0 : parsing_value = 0;
292 :
293 : } else {
294 : /* the current parsing pair takes no value,
295 : * just push the value "true" */
296 : dd("pushing boolean true");
297 :
298 0 : lua_pushboolean(L, 1);
299 : }
300 :
301 0 : (void) lua_tolstring(L, -2, &len);
302 :
303 0 : if (len == 0) {
304 : /* ignore empty string key pairs */
305 : dd("popping key and value...");
306 0 : lua_pop(L, 2);
307 :
308 : } else {
309 : dd("setting table...");
310 0 : ngx_http_lua_set_multi_value_table(L, top);
311 : }
312 :
313 0 : if (max > 0 && ++count == max) {
314 0 : ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
315 : "lua hit query args limit %d", max);
316 :
317 0 : return 1;
318 : }
319 :
320 : } else {
321 0 : p++;
322 : }
323 : }
324 :
325 0 : if (p != q || parsing_value) {
326 0 : src = q; dst = q;
327 :
328 0 : ngx_http_lua_unescape_uri(&dst, &src, p - q,
329 : NGX_UNESCAPE_URI_COMPONENT);
330 :
331 : dd("pushing key or value %.*s", (int) (dst - q), q);
332 :
333 0 : lua_pushlstring(L, (char *) q, dst - q);
334 :
335 0 : if (!parsing_value) {
336 : dd("pushing boolean true...");
337 0 : lua_pushboolean(L, 1);
338 : }
339 :
340 0 : (void) lua_tolstring(L, -2, &len);
341 :
342 0 : if (len == 0) {
343 : /* ignore empty string key pairs */
344 : dd("popping key and value...");
345 0 : lua_pop(L, 2);
346 :
347 : } else {
348 : dd("setting table...");
349 0 : ngx_http_lua_set_multi_value_table(L, top);
350 : }
351 : }
352 :
353 : dd("gettop: %d", lua_gettop(L));
354 : dd("type: %s", lua_typename(L, lua_type(L, 1)));
355 :
356 0 : if (lua_gettop(L) != top) {
357 0 : return luaL_error(L, "internal error: stack in bad state");
358 : }
359 :
360 0 : return 1;
361 : }
362 :
363 :
364 : void
365 18 : ngx_http_lua_inject_req_args_api(lua_State *L)
366 : {
367 18 : lua_pushcfunction(L, ngx_http_lua_ngx_req_set_uri_args);
368 18 : lua_setfield(L, -2, "set_uri_args");
369 :
370 18 : lua_pushcfunction(L, ngx_http_lua_ngx_req_get_uri_args);
371 18 : lua_setfield(L, -2, "get_uri_args");
372 :
373 18 : lua_pushcfunction(L, ngx_http_lua_ngx_req_get_uri_args);
374 18 : lua_setfield(L, -2, "get_query_args"); /* deprecated */
375 :
376 18 : lua_pushcfunction(L, ngx_http_lua_ngx_req_get_post_args);
377 18 : lua_setfield(L, -2, "get_post_args");
378 18 : }
379 :
380 :
381 : #ifndef NGX_LUA_NO_FFI_API
382 : size_t
383 0 : ngx_http_lua_ffi_req_get_querystring_len(ngx_http_request_t *r)
384 : {
385 0 : return r->args.len;
386 : }
387 :
388 :
389 : int
390 0 : ngx_http_lua_ffi_req_get_uri_args_count(ngx_http_request_t *r, int max)
391 : {
392 : int count;
393 : u_char *p, *last;
394 :
395 0 : if (r->connection->fd == (ngx_socket_t) -1) {
396 0 : return NGX_HTTP_LUA_FFI_BAD_CONTEXT;
397 : }
398 :
399 0 : if (max < 0) {
400 0 : max = NGX_HTTP_LUA_MAX_ARGS;
401 : }
402 :
403 0 : last = r->args.data + r->args.len;
404 0 : count = 0;
405 :
406 0 : for (p = r->args.data; p != last; p++) {
407 0 : if (*p == '&') {
408 0 : if (count == 0) {
409 0 : count += 2;
410 :
411 : } else {
412 0 : count++;
413 : }
414 : }
415 : }
416 :
417 0 : if (count) {
418 0 : if (max > 0 && count > max) {
419 0 : count = max;
420 0 : ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
421 : "lua hit query args limit %d", max);
422 : }
423 :
424 0 : return count;
425 : }
426 :
427 0 : if (r->args.len) {
428 0 : return 1;
429 : }
430 :
431 0 : return 0;
432 : }
433 :
434 :
435 : int
436 0 : ngx_http_lua_ffi_req_get_uri_args(ngx_http_request_t *r, u_char *buf,
437 : ngx_http_lua_ffi_table_elt_t *out, int count)
438 : {
439 0 : int i, parsing_value = 0;
440 : u_char *last, *p, *q;
441 : u_char *src, *dst;
442 :
443 0 : if (count <= 0) {
444 0 : return NGX_OK;
445 : }
446 :
447 0 : ngx_memcpy(buf, r->args.data, r->args.len);
448 :
449 0 : i = 0;
450 0 : last = buf + r->args.len;
451 0 : p = buf;
452 0 : q = p;
453 :
454 0 : while (p != last) {
455 0 : if (*p == '=' && !parsing_value) {
456 : /* key data is between p and q */
457 :
458 0 : src = q; dst = q;
459 :
460 0 : ngx_http_lua_unescape_uri(&dst, &src, p - q,
461 : NGX_UNESCAPE_URI_COMPONENT);
462 :
463 : dd("saving key %.*s", (int) (dst - q), q);
464 :
465 0 : out[i].key.data = q;
466 0 : out[i].key.len = (int) (dst - q);
467 :
468 : /* skip the current '=' char */
469 0 : p++;
470 :
471 0 : q = p;
472 0 : parsing_value = 1;
473 :
474 0 : } else if (*p == '&') {
475 : /* reached the end of a key or a value, just save it */
476 0 : src = q; dst = q;
477 :
478 0 : ngx_http_lua_unescape_uri(&dst, &src, p - q,
479 : NGX_UNESCAPE_URI_COMPONENT);
480 :
481 : dd("pushing key or value %.*s", (int) (dst - q), q);
482 :
483 0 : if (parsing_value) {
484 : /* end of the current pair's value */
485 0 : parsing_value = 0;
486 :
487 0 : if (out[i].key.len) {
488 0 : out[i].value.data = q;
489 0 : out[i].value.len = (int) (dst - q);
490 0 : i++;
491 : }
492 :
493 : } else {
494 : /* the current parsing pair takes no value,
495 : * just push the value "true" */
496 : dd("pushing boolean true");
497 :
498 0 : if (dst - q) {
499 0 : out[i].key.data = q;
500 0 : out[i].key.len = (int) (dst - q);
501 0 : out[i].value.len = -1;
502 0 : i++;
503 : }
504 : }
505 :
506 0 : if (i == count) {
507 0 : return i;
508 : }
509 :
510 : /* skip the current '&' char */
511 0 : p++;
512 :
513 0 : q = p;
514 :
515 : } else {
516 0 : p++;
517 : }
518 : }
519 :
520 0 : if (p != q || parsing_value) {
521 0 : src = q; dst = q;
522 :
523 0 : ngx_http_lua_unescape_uri(&dst, &src, p - q,
524 : NGX_UNESCAPE_URI_COMPONENT);
525 :
526 : dd("pushing key or value %.*s", (int) (dst - q), q);
527 :
528 0 : if (parsing_value) {
529 0 : if (out[i].key.len) {
530 0 : out[i].value.data = q;
531 0 : out[i].value.len = (int) (dst - q);
532 0 : i++;
533 : }
534 :
535 : } else {
536 0 : if (dst - q) {
537 0 : out[i].key.data = q;
538 0 : out[i].key.len = (int) (dst - q);
539 0 : out[i].value.len = (int) -1;
540 0 : i++;
541 : }
542 : }
543 : }
544 :
545 0 : return i;
546 : }
547 : #endif /* NGX_LUA_NO_FFI_API */
548 :
549 :
550 : /* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|