Browse Source

#91 - fixed. #90 - fixed. #77 - url encoded. #51 - fixed.

tags/v2.5-rc1
V. Soshnikov 2 years ago
parent
commit
1f057360b6
56 changed files with 798 additions and 388 deletions
  1. 2
    0
      .gitignore
  2. 89
    5
      README.md
  3. 2
    14
      src/debug.h
  4. 263
    143
      src/ngx_http_tnt_handlers.c
  5. 19
    11
      src/ngx_http_tnt_handlers.h
  6. 187
    48
      src/ngx_http_tnt_module.c
  7. 1
    1
      src/ngx_http_tnt_version.h
  8. 31
    77
      src/tp_transcode.c
  9. 0
    4
      src/tp_transcode.h
  10. 3
    3
      t/auto.sh
  11. 0
    0
      t/basic_features.py
  12. 0
    0
      t/cases/batch.json
  13. BIN
      t/cases/batch.json.tmp
  14. 0
    0
      t/cases/escaped.json
  15. BIN
      t/cases/escaped.json.tmp
  16. 0
    0
      t/cases/expected
  17. 0
    0
      t/cases/param_w_tnt_name.json
  18. BIN
      t/cases/param_w_tnt_name.json.tmp
  19. 0
    0
      t/cases/param_wo_args.json
  20. BIN
      t/cases/param_wo_args.json.tmp
  21. 0
    0
      t/cases/param_wo_tnt_name.json
  22. BIN
      t/cases/param_wo_tnt_name.json.tmp
  23. 0
    0
      t/cases/regular.json
  24. BIN
      t/cases/regular.json.tmp
  25. 0
    0
      t/cases/regular_2.json
  26. BIN
      t/cases/regular_2.json.tmp
  27. 0
    0
      t/cases/without_id.json
  28. BIN
      t/cases/without_id.json.tmp
  29. 0
    0
      t/cases/without_method.json
  30. BIN
      t/cases/without_method.json.tmp
  31. 0
    0
      t/cases/without_method_2.json
  32. BIN
      t/cases/without_method_2.json.tmp
  33. 0
    0
      t/cases/without_params.json
  34. BIN
      t/cases/without_params.json.tmp
  35. 0
    0
      t/cases/wrong_args.json
  36. 0
    0
      t/cases/wrong_args.json.tmp
  37. 0
    0
      t/cases/wrong_args_2.json
  38. BIN
      t/cases/wrong_args_2.json.tmp
  39. 0
    0
      t/cases/wrong_args_3.json
  40. BIN
      t/cases/wrong_args_3.json.tmp
  41. 0
    0
      t/http_utils.py
  42. 1
    1
      t/lua.py
  43. 0
    0
      t/ngx_confs/nginx.dev.conf
  44. 0
    0
      t/ngx_confs/nginx.dev.dyn.conf
  45. 76
    48
      t/ngx_confs/tnt_server_test.conf
  46. 0
    0
      t/ngx_versions_list
  47. 15
    0
      t/parallel_clients.sh
  48. 13
    7
      t/run_all.sh
  49. 19
    3
      t/test.lua
  50. 0
    0
      t/tp_allowed.c
  51. 6
    6
      t/transcode.sh
  52. 1
    1
      t/v20_features.py
  53. 1
    1
      t/v23_features.py
  54. 1
    1
      t/v24_features.py
  55. 68
    0
      t/v26_features.py
  56. 0
    14
      test/parallel_clients.sh

+ 2
- 0
.gitignore View File

@@ -1,3 +1,5 @@
tp_allowed
__pycache__
test-root
nginx
*.dSYM

+ 89
- 5
README.md View File

@@ -48,6 +48,7 @@ Tarantool - https://hub.docker.com/r/tarantool/tarantool
* [tnt_pass_http_request](#tnt_pass_http_request)
* [tnt_pass_http_request_buffer_size](#tnt_pass_http_request_buffer_size)
* [tnt_method](#tnt_method)
* [tnt_set_header](#tnt_set_header)
* [tnt_send_timeout](#tnt_send_timeout)
* [tnt_read_timeout](#tnt_read_timeout)
* [tnt_buffer_size](#tnt_buffer_size)
@@ -480,7 +481,7 @@ Example
tnt_pass_http_request
------------------
**syntax:** *tnt_pass_http_request [on|off|parse_args|unescape|pass_body|pass_headers_out]*
**syntax:** *tnt_pass_http_request [on|off|parse_args|unescape|pass_body|pass_headers_out|parse_urlencoded]*
**default:** *off*
@@ -519,6 +520,7 @@ Examples #1
req.body -- request body, type string
end
```
Examples #2 (pass_headers_out)
```nginx
location @tnt {
@@ -543,6 +545,24 @@ Examples #2 (pass_headers_out)
end
```
Examples #3 (parse_urlencoded)
```nginx
location /tnt {
tnt_http_rest_methods post;
tnt_pass_http_request on parse_urlencoded;
tnt_method tarantool_stored_procedure_name;
tnt_pass 127.0.0.1:9999;
}
```
```lua
function tarantool_stored_procedure_name(req, ...)
req.headers -- a lua table
req.query -- a string
req.body -- a lua table with url encoded args
return true
end
```
```bash
# Call tarantool_stored_procedure_name()
$> wget NGINX_HOST/tarantool_stored_procedure_name/some/mega/path?q=1
@@ -551,7 +571,7 @@ Examples #2 (pass_headers_out)
[Back to content](#content)
tnt_pass_http_request_buffer_size
------------------------
---------------------------------
**syntax:** *tnt_pass_http_request_buffer_size SIZE*
**default:** *4k, 8k*
@@ -563,14 +583,14 @@ Specify the size of the buffer used for `tnt_pass_http_request`.
[Back to content](#content)
tnt_method
-----------
----------
**syntax:** *tnt_method STR*
**default:** *no*
**context:** *location, location if*
Specify the Tarantool call method.
Specify the Tarantool call method. It can take a nginx's variable.
Examples
```nginx
@@ -584,6 +604,18 @@ Examples
tnt_pass_http_request on;
tnt_pass 127.0.0.1:9999;
}
location ~ /api/([-_a-zA-Z0-9/]+)/ {
# Also tnt_pass_http_request can mix with JSON communication [[
tnt_http_rest_methods get;
tnt_method $1;
#]]
# [on|of]
tnt_pass_http_request on;
tnt_pass 127.0.0.1:9999;
}
```
```lua
function tarantool_stored_procedure_name(req, ...)
@@ -591,6 +623,12 @@ Examples
req.query -- string
return { 'OK' }
end
function call(req, ...)
req.headers -- lua table
req.query -- string
return req, ...
end
```
```bash
# OK Call tarantool_stored_procedure_name()
@@ -598,12 +636,58 @@ Examples
# Error Call tarantool_stored_procedure_XXX()
$> wget NGINX_HOST/tarantool_stored_procedure_XXX/some/mega/path?q=1
# OK Call api_function
$> wget NGINX_HOST/api/call/path?q=1
```
[Back to content](#content)
tnt_set_header
--------------
**syntax:** *tnt_set_header STR STR*
**default:** *no*
**context:** *location, location if*
Allows redefining or appending fields to the request header passed to the
tarantool proxied server. The value can contain text, variables, and their combinations.
Examples
```nginx
location tnt {
# Also tnt_pass_http_request can mix with JSON communication [[
tnt_http_rest_methods get;
tnt_method tarantool_stored_procedure_name;
#]]
tnt_set_header X-Host $host;
tnt_set_header X-GEO-COUNTRY $geoip_country_code;
# [on|of]
tnt_pass_http_request on;
tnt_pass 127.0.0.1:9999;
}
```
```lua
function tarantool_stored_procedure_name(req, ...)
req.headers['X-Host'] -- a hostname
req.headers['X-GEO-COUNTRY'] -- a geo country
return { 'OK' }
end
```
```bash
# OK Call tarantool_stored_procedure_name()
$> wget NGINX_HOST/tarantool_stored_procedure_name/some/mega/path?q=1
```
[Back to content](#content)
tnt_send_timeout
-------------------
----------------
**syntax:** *tnt_send_timeout TIME*
**default:** *60s*

+ 2
- 14
src/debug.h View File

@@ -26,7 +26,7 @@
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* Copyright (C) 2015-2016 Tarantool AUTHORS:
* Copyright (C) 2015-2017 Tarantool AUTHORS:
* please see AUTHORS file.
*/

@@ -71,19 +71,7 @@ dd(const char* fmt, ...) { }

static inline const u_char*
get_str_safe(const u_char *str) {
return (str ? str : (const u_char *)"NULL");
return (str ? str : (const u_char *) "NULL");
}

#if (NGX_HAVE_VARIADIC_MACROS)
# define log_crit(log, ...) \
ngx_log_error_core(NGX_LOG_CRIT, (log), 0, __VA_ARGS__)
# define crit(...) log_crit(r->connection->log, __VA_ARGS__)
# else
/** TODO
* Need I add some warn message?
*/
static inline void
crit(...) {}
#endif /* NGX_HAVE_VARIADIC_MACROS */

#endif

+ 263
- 143
src/ngx_http_tnt_handlers.c View File

@@ -26,7 +26,7 @@
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* Copyright (C) 2015-2016 Tarantool AUTHORS:
* Copyright (C) 2015-2017 Tarantool AUTHORS:
* please see AUTHORS file.
*/

@@ -195,6 +195,7 @@ ngx_http_tnt_send_once(ngx_http_request_t *r,
{
tp_transcode_t tc;
size_t complete_msg_size;

tp_transcode_init_args_t args = {
.output = (char *) out_chain->buf->start,
.output_size = out_chain->buf->end - out_chain->buf->start,
@@ -381,23 +382,26 @@ ngx_http_tnt_encode_str_map_item(ngx_http_request_t *r,
return NGX_OK;
}


static inline ngx_int_t
ngx_http_tnt_encode_query_args(
ngx_http_request_t *r,
ngx_http_tnt_loc_conf_t *tlcf,
struct tp *tp,
ngx_uint_t *args_items)
ngx_http_tnt_encode_query_args(ngx_http_request_t *r,
ngx_http_tnt_loc_conf_t *tlcf,
struct tp *tp,
ngx_str_t *args,
ngx_uint_t *args_items)
{
u_char *arg_begin, *end;
u_char *arg_begin, *end;
ngx_http_tnt_next_arg_t arg;

if (r->args.len == 0) {
if (args->len == 0) {
return NGX_OK;
}

arg_begin = r->args.data;
end = arg_begin + r->args.len;
arg_begin = args->data;
end = arg_begin + args->len;

ngx_http_tnt_next_arg_t arg = { .it = arg_begin, .value = NULL };
arg.it = arg_begin;
arg.value = NULL;

for (; arg.it < end; ) {

@@ -425,171 +429,270 @@ ngx_http_tnt_encode_query_args(
}


static inline ngx_int_t
ngx_http_tnt_encode_urlencoded_body(ngx_http_request_t *r,
ngx_http_tnt_loc_conf_t *tlcf,
struct tp *tp,
ngx_buf_t *b,
ngx_uint_t *args_items)
{
ngx_str_t args;

if (b->start == b->last) {
return NGX_OK;
}

args.data = b->start;
args.len = (size_t) (b->last - b->start);

return ngx_http_tnt_encode_query_args(r, tlcf, tp, &args, args_items);
}


static inline ngx_int_t
ngx_http_tnt_get_request_data(ngx_http_request_t *r,
ngx_http_tnt_loc_conf_t *tlcf,
struct tp *tp)
{
char *root_map_place;
char *map_place;
size_t root_items;
size_t map_items;
ngx_buf_t *b;
ngx_chain_t *body;
char *p;
/** TODO:
* This function should be part of tp_transcode.{c,h}. It's very
* strange have this function here, so the best way is piece by piece
* move a functionality ...
*
* Also it would be nice to tie nginx structures with tp_transcode
*/
char *root_map_place;
char *map_place;
size_t root_items;
size_t map_items;
ngx_buf_t *b;
ngx_chain_t *body;
char *p;
ngx_buf_t unparsed_body;
ngx_http_tnt_ctx_t *ctx;

ctx = ngx_http_get_module_ctx(r, ngx_http_tnt_module);

root_items = 0;
root_map_place = tp->p;
tp_add(tp, 1 + sizeof(uint32_t));

/** Encode protocol
*/
if (tp_add(tp, 1 + sizeof(uint32_t)) == NULL) {
goto oom_cant_encode;
}

/** Encode protocol */
++root_items;

if (!tp_encode_str_map_item(tp,
if (tp_encode_str_map_item(tp,
"proto", sizeof("proto") - 1,
(const char*) r->http_protocol.data,
r->http_protocol.len))
r->http_protocol.len) == NULL)
{
return NGX_ERROR;
goto oom_cant_encode;
}

/** Encode method
*/
/** Encode method */
++root_items;

if (!tp_encode_str_map_item(tp,
if (tp_encode_str_map_item(tp,
"method", sizeof("method") - 1,
(const char *) r->method_name.data,
r->method_name.len))
r->method_name.len) == NULL)
{
return NGX_ERROR;
goto oom_cant_encode;
}

/** Encode raw uri
*/
/** Encode raw uri */
++root_items;

if (ngx_http_tnt_encode_str_map_item(r, tlcf, tp,
(u_char *)"uri", sizeof("uri") - 1,
(u_char *) "uri", sizeof("uri") - 1,
r->unparsed_uri.data,
r->unparsed_uri.len) == NGX_ERROR)
{
return NGX_ERROR;
goto oom_cant_encode;
}

/** Encode query args
*/
/** Encode query args */
if (tlcf->pass_http_request & NGX_TNT_CONF_PARSE_ARGS) {

++root_items;

if (!tp_encode_str(tp, "args", sizeof("args") - 1)) {
return NGX_ERROR;
if (tp_encode_str(tp, "args", sizeof("args") - 1) == NULL) {
goto oom_cant_encode;
}

map_place = tp->p;
if (!tp_add(tp, 1 + sizeof(uint32_t))) {
return NGX_ERROR;
if (tp_add(tp, 1 + sizeof(uint32_t)) == NULL) {
goto oom_cant_encode;
}

map_items = 0;

if (ngx_http_tnt_encode_query_args(
r, tlcf, tp, &map_items) == NGX_ERROR)
r, tlcf, tp, &r->args, &map_items) == NGX_ERROR)
{
return NGX_ERROR;
goto oom_cant_encode;
}

*(map_place++) = 0xdf;
*(uint32_t *) map_place = mp_bswap_u32(map_items);
}

/** Encode http headers
*/
/** Encode http headers */
++root_items;

if (!tp_encode_str(tp, "headers", sizeof("headers") - 1)) {
return NGX_ERROR;
if (tp_encode_str(tp, "headers", sizeof("headers") - 1) == NULL) {
goto oom_cant_encode_headers;
}

map_items = 0;
map_place = tp->p;

if (!tp_add(tp, 1 + sizeof(uint32_t))) {
return NGX_ERROR;
if (tp_add(tp, 1 + sizeof(uint32_t)) == NULL) {
goto oom_cant_encode_headers;
}

// XXX set_header
#if 0
ngx_http_script_flush_no_cacheable_variables(r, tlcf->headers.flushes);
#endif

if (ngx_http_tnt_copy_headers(tp, &r->headers_in.headers, &map_items) ==
NGX_ERROR)
{
return NGX_ERROR;
goto oom_cant_encode_headers;
}

if ((tlcf->pass_http_request & NGX_TNT_CONF_PASS_HEADERS_OUT) &&
(ngx_http_tnt_copy_headers(tp, &r->headers_out.headers, &map_items) ==
NGX_ERROR) )
{
return NGX_ERROR;
goto oom_cant_encode_headers;
}

*(map_place++) = 0xdf;
*(uint32_t *) map_place = mp_bswap_u32(map_items);

/* Encode body
*/
if ((tlcf->pass_http_request & NGX_TNT_CONF_PASS_BODY) &&
/** Encode body */
if ((tlcf->pass_http_request & NGX_TNT_CONF_PASS_BODY ||
tlcf->pass_http_request & NGX_TNT_CONF_PARSE_URLENCODED) &&
r->headers_in.content_length_n > 0 &&
r->upstream->request_bufs)
{
++root_items;

if (!tp_encode_str(tp, "body", sizeof("body") - 1)) {
return NGX_ERROR;
if (tp_encode_str(tp, "body", sizeof("body") - 1) == NULL) {
goto oom_cant_encode_body;
}

int sz = mp_sizeof_str(r->headers_in.content_length_n);
if (tp_ensure(tp, sz) == -1) {
return NGX_ERROR;
}
/** Encode urlencoded body as map - body = { K = V, .. } */
if (tlcf->pass_http_request & NGX_TNT_CONF_PARSE_URLENCODED) {

p = mp_encode_strl(tp->p, r->headers_in.content_length_n);
for (body = r->upstream->request_bufs; body; body = body->next) {
map_place = tp->p;

b = body->buf;
if (tp_add(tp, 1 + sizeof(uint32_t)) == NULL) {
goto oom_cant_encode_body;
}

if (b->in_file) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"tnt: in-file buffer found. aborted. "
"consider increasing your 'client_body_buffer_size' "
"setting");
ngx_memset(&unparsed_body, 0, sizeof(ngx_buf_t));
unparsed_body.pos = ngx_pnalloc(r->pool,
sizeof(u_char) * r->headers_in.content_length_n + 1);
if (unparsed_body.pos == NULL) {
return NGX_ERROR;
}
unparsed_body.last = unparsed_body.pos;
unparsed_body.start = unparsed_body.pos;
unparsed_body.end = unparsed_body.pos +
r->headers_in.content_length_n + 1;

for (body = r->upstream->request_bufs; body; body = body->next) {

b = body->buf;

if (b->in_file) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"tnt: in-file buffer found. aborted. "
"consider increasing your 'client_body_buffer_size' "
"setting");
return NGX_ERROR;
}

unparsed_body.last = ngx_copy(unparsed_body.last,
b->pos, b->last - b->pos);
}

map_items = 0;

if (ngx_http_tnt_encode_urlencoded_body(r, tlcf, tp,
&unparsed_body, &map_items) != NGX_OK)
{
goto oom_cant_encode_body;
}

*(map_place++) = 0xdf;
*(uint32_t *) map_place = mp_bswap_u32(map_items);

p = (char *) ngx_copy(p, b->pos, b->last - b->pos);
}
/** Unknown body type - encode as mp string
*/
else {

if (!tp_add(tp, sz)) {
return NGX_ERROR;
}
int sz = mp_sizeof_str(r->headers_in.content_length_n);
if (tp_ensure(tp, sz) == -1) {
goto oom_cant_encode_body;
}

p = mp_encode_strl(tp->p, r->headers_in.content_length_n);

for (body = r->upstream->request_bufs; body; body = body->next) {

b = body->buf;

if (b->in_file) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"tnt: in-file buffer found. aborted. "
"consider increasing your 'client_body_buffer_size' "
"setting");
return NGX_ERROR;
}

p = (char *) ngx_copy(p, b->pos, b->last - b->pos);
}

if (tp_add(tp, sz) == NULL) {
goto oom_cant_encode_body;
}
}
}

*(root_map_place++) = 0xdf;
*(uint32_t *) root_map_place = mp_bswap_u32(root_items);

return NGX_OK;

oom_cant_encode:
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"tnt: can't encode uri, schema etc. "
"aborted. consider increasing your "
"'tnt_pass_http_request_buffer_size' setting");
return NGX_ERROR;

oom_cant_encode_headers:
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"tnt: can't encode HTTP headers. "
"aborted. consider increasing your "
"'tnt_pass_http_request_buffer_size' setting");
return NGX_ERROR;

oom_cant_encode_body:

ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"tnt: can't encode body. aborted. consider increasing your "
"'tnt_pass_http_request_buffer_size' setting");
return NGX_ERROR;
}


static inline ngx_buf_t *
ngx_http_tnt_get_request_data_map(
ngx_http_request_t *r,
ngx_http_tnt_loc_conf_t *tlcf)
ngx_http_tnt_get_request_data_map(ngx_http_request_t *r,
ngx_http_tnt_loc_conf_t *tlcf)
{
ngx_int_t rc;
struct tp tp;
@@ -597,8 +700,10 @@ ngx_http_tnt_get_request_data_map(

b = ngx_create_temp_buf(r->pool, tlcf->pass_http_request_buffer_size);
if (b == NULL) {
crit("[BUG?] ngx_http_tnt_get_request_data_map - "
"failed to allocate output buffer, size");
ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0,
"ngx_http_tnt_get_request_data_map can't allocate "
"output buffer with size = %d",
(int) tlcf->pass_http_request_buffer_size);
return NULL;
}

@@ -607,7 +712,7 @@ ngx_http_tnt_get_request_data_map(

b->pos = b->start;

tp_init(&tp, (char *)b->start, b->end - b->start, NULL, NULL);
tp_init(&tp, (char *) b->start, b->end - b->start, NULL, NULL);
tp.size = tp.p;

rc = ngx_http_tnt_get_request_data(r, tlcf, &tp);
@@ -615,7 +720,7 @@ ngx_http_tnt_get_request_data_map(
return NULL;
}

b->last = (u_char *)tp.p;
b->last = (u_char *) tp.p;

return b;
}
@@ -668,7 +773,7 @@ ngx_int_t ngx_http_tnt_init_handlers(ngx_http_request_t *r,
ngx_http_upstream_t *u,
ngx_http_tnt_loc_conf_t *tlcf)
{
ngx_http_tnt_ctx_t *ctx;
ngx_http_tnt_ctx_t *ctx;

ctx = ngx_http_tnt_create_ctx(r);
if (ctx == NULL) {
@@ -684,18 +789,15 @@ ngx_int_t ngx_http_tnt_init_handlers(ngx_http_request_t *r,
u->abort_request = ngx_http_tnt_abort_request;
u->finalize_request = ngx_http_tnt_finalize_request;

/** Default */
u->create_request = ngx_http_tnt_query_handler;

if (tlcf->pass_http_request & NGX_TNT_CONF_PASS_BODY) {
dd("NGX_TNT_CONF_PASS_BODY");
u->create_request = ngx_http_tnt_query_handler;
} else {
return NGX_OK;
}

if (r->headers_in.content_length_n > 0) {
dd("ngx_http_tnt_body_json_handler");
u->create_request = ngx_http_tnt_body_json_handler;
} else {
dd("ngx_http_tnt_query_handler");
u->create_request = ngx_http_tnt_query_handler;
}
if (r->headers_in.content_length_n > 0) {
u->create_request = ngx_http_tnt_body_handler;
}

return NGX_OK;
@@ -703,15 +805,16 @@ ngx_int_t ngx_http_tnt_init_handlers(ngx_http_request_t *r,


ngx_int_t
ngx_http_tnt_body_json_handler(ngx_http_request_t *r)
ngx_http_tnt_body_handler(ngx_http_request_t *r)
{
ngx_buf_t *b, *request_b = NULL;
ngx_chain_t *body;
size_t complete_msg_size;
tp_transcode_t tc;
ngx_http_tnt_ctx_t *ctx;
ngx_chain_t *out_chain;
ngx_http_tnt_loc_conf_t *tlcf;
ngx_buf_t *b, *request_b = NULL;
ngx_chain_t *body;
size_t complete_msg_size;
tp_transcode_t tc;
ngx_http_tnt_ctx_t *ctx;
ngx_chain_t *out_chain;
ngx_http_tnt_loc_conf_t *tlcf;
const ngx_http_tnt_error_t *e;

ctx = ngx_http_get_module_ctx(r, ngx_http_tnt_module);

@@ -732,9 +835,10 @@ ngx_http_tnt_body_json_handler(ngx_http_request_t *r)
out_chain->buf = ngx_create_temp_buf(r->pool,
ngx_http_tnt_get_output_size(r, ctx, tlcf, request_b));
if (out_chain->buf == NULL) {
crit("[BUG?] ngx_http_tnt_body_json_handler -- "
"failed to allocate output buffer, size %ui",
(r->headers_in.content_length_n + 1) * tlcf->in_multiplier);
ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0,
"ngx_http_tnt_body_handler -- "
"failed to allocate output buffer, size %ui",
(r->headers_in.content_length_n + 1) * tlcf->in_multiplier);
return NGX_ERROR;
}

@@ -747,7 +851,7 @@ ngx_http_tnt_body_json_handler(ngx_http_request_t *r)
out_chain->buf->last_in_chain = 1;

/**
* Conv. input json to Tarantool message [
* Conv. input (json, x-url-encoded) into Tarantool's message [
*/
tp_transcode_init_args_t args = {
.output = (char *) out_chain->buf->start,
@@ -759,49 +863,61 @@ ngx_http_tnt_body_json_handler(ngx_http_request_t *r)
};

if (tp_transcode_init(&tc, &args) == TP_TRANSCODE_ERROR) {
crit("[BUG] failed to call tp_transcode_init(input)");
ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0,
"[BUG] failed to call tp_transcode_init(input)");
return NGX_ERROR;
}

/**
* Bind extra data e.g. http headers, uri ...
*/
/** Bind extra data e.g. http headers, uri etc */
if (request_b != NULL) {
tp_transcode_bind_data(&tc,
(const char *) request_b->start,
(const char *) request_b->last);
tp_transcode_bind_data(&tc, (const char *) request_b->start,
(const char *) request_b->last);
}

/** Parse url-encoded*/
if (tlcf->pass_http_request & NGX_TNT_CONF_PARSE_URLENCODED) {

if (tp_transcode(&tc, "{\"params\":[]}", sizeof("{\"params\":[]}") - 1)
== TP_TRANSCODE_ERROR)
{
ctx->state = INPUT_JSON_PARSE_FAILED;
goto read_input_done;
}
}

for (body = r->upstream->request_bufs; body; body = body->next) {
/** Parse JSON*/
else {

if (body->buf->in_file) {
for (body = r->upstream->request_bufs; body; body = body->next) {

ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"tnt: in-file buffer found. aborted. "
"consider increasing your 'client_body_buffer_size' "
"setting");

const ngx_http_tnt_error_t *e = get_error_text(REQUEST_TOO_LARGE);
ctx->in_err = ngx_http_tnt_set_err(r,
e->code,
e->msg.data, e->msg.len);
if (ctx->in_err == NULL) {
goto error_exit;
}
if (body->buf->in_file) {

ctx->state = INPUT_TO_LARGE;
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"tnt: in-file buffer found. aborted. "
"consider increasing your 'client_body_buffer_size' "
"setting");

goto read_input_done;
e = get_error_text(REQUEST_TOO_LARGE);
ctx->in_err = ngx_http_tnt_set_err(r, e->code,
e->msg.data, e->msg.len);
if (ctx->in_err == NULL) {
goto error_exit;
}

} else {
b = body->buf;
}
ctx->state = INPUT_TO_LARGE;
goto read_input_done;

if (tp_transcode(&tc, (char *)b->pos, b->last - b->pos)
== TP_TRANSCODE_ERROR)
{
ctx->state = INPUT_JSON_PARSE_FAILED;
goto read_input_done;
} else {
b = body->buf;
}

if (tp_transcode(&tc, (char *) b->pos, b->last - b->pos)
== TP_TRANSCODE_ERROR)
{
ctx->state = INPUT_JSON_PARSE_FAILED;
goto read_input_done;
}
}
}

@@ -925,19 +1041,22 @@ ngx_http_tnt_query_handler(ngx_http_request_t *r)
buf = out_chain->buf;
tp_init(&tp, (char *)buf->start, buf->end - buf->start, NULL, NULL);

if (!tp_call_nargs(&tp,
(const char *)ctx->preset_method,
(size_t)ctx->preset_method_len, 1))
if (!tp_call_nargs(&tp, (const char *) ctx->preset_method,
(size_t) ctx->preset_method_len, 1))
{
err = get_error_text(HTTP_REQUEST_TOO_LARGE);
crit("ngx_http_tnt_query_handler - %s", get_str_safe(err->msg.data));
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"ngx_http_tnt_query_handler - %s",
get_str_safe(err->msg.data));
return NGX_ERROR;
}

rc = ngx_http_tnt_get_request_data(r, tlcf, &tp);
if (rc != NGX_OK) {
err = get_error_text(HTTP_REQUEST_TOO_LARGE);
crit("ngx_http_tnt_query_handler - %s", get_str_safe(err->msg.data));
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"ngx_http_tnt_query_handler - %s",
get_str_safe(err->msg.data));
return rc;
}

@@ -1008,7 +1127,8 @@ ngx_http_tnt_process_header(ngx_http_request_t *r)
case INPUT_EMPTY:
return ngx_http_tnt_output_err(r, ctx, NGX_HTTP_BAD_REQUEST);
default:
crit("[BUG] unexpected ctx->stage(%i)", ctx->state);
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"[BUG] unexpected ctx->stage(%i)", ctx->state);
return NGX_ERROR;
}

@@ -1077,8 +1197,7 @@ ngx_http_tnt_set_err(ngx_http_request_t *r,
return b;
}

/**
*/

static const ngx_http_tnt_error_t errors[] = {

{ ngx_string("Request too large, consider increasing your "
@@ -1096,6 +1215,7 @@ static const ngx_http_tnt_error_t errors[] = {
}
};


const ngx_http_tnt_error_t *
get_error_text(int type)
{

+ 19
- 11
src/ngx_http_tnt_handlers.h View File

@@ -45,14 +45,19 @@ typedef enum ngx_tnt_conf_states {
NGX_TNT_CONF_UNESCAPE = 8,
NGX_TNT_CONF_PASS_BODY = 16,
NGX_TNT_CONF_PASS_HEADERS_OUT = 32,
NGX_TNT_CONF_PARSE_URLENCODED = 64,
} ngx_tnt_conf_states_e;

typedef struct {
ngx_array_t *flushes;
ngx_array_t *lengths;
ngx_array_t *values;
ngx_hash_t hash;
} ngx_http_tnt_headers_t;
typedef struct ngx_http_tnt_header_val_s ngx_http_tnt_header_val_t;

typedef ngx_int_t (*ngx_http_set_header_pt)(ngx_http_request_t *r,
ngx_http_tnt_header_val_t *hv, ngx_str_t *value);

struct ngx_http_tnt_header_val_s {
ngx_http_complex_value_t value;
ngx_str_t key;
ngx_http_set_header_pt handler;
};

/** The structure hold the nginx location variables, e.g. loc_conf.
*/
@@ -68,7 +73,8 @@ typedef struct {
* If this is set then tp_transcode use only this method name and
* tp_transcode will ignore the method name from the json or/and uri
*/
ngx_str_t method;
ngx_http_complex_value_t *method_ccv;
ngx_str_t method;

/** This is max allowed size of query + headers + body, the size in bytes
*/
@@ -113,9 +119,7 @@ typedef struct {
*/
ngx_uint_t pure_result;

ngx_array_t *headers_source;

ngx_http_tnt_headers_t headers;
ngx_array_t *headers;

} ngx_http_tnt_loc_conf_t;

@@ -167,6 +171,10 @@ typedef struct ngx_http_tnt_ctx {
*/
ngx_int_t greeting:1;

/**
*/
ngx_int_t url_encoded_body:1;

/** The preset method and its length
*/
u_char preset_method[128];
@@ -182,7 +190,7 @@ ngx_int_t ngx_http_tnt_init_handlers(ngx_http_request_t *r,

/** Request handlers [
*/
ngx_int_t ngx_http_tnt_body_json_handler(ngx_http_request_t *r);
ngx_int_t ngx_http_tnt_body_handler(ngx_http_request_t *r);
ngx_int_t ngx_http_tnt_query_handler(ngx_http_request_t *r);
/* ] */


+ 187
- 48
src/ngx_http_tnt_module.c View File

@@ -37,48 +37,34 @@
#include <ngx_http_tnt_version.h>
#include <ngx_http_tnt_handlers.h>

/** Filters
*/

/** Filters */
static ngx_int_t ngx_http_tnt_filter_init(void *data);

static ngx_int_t ngx_http_tnt_send_reply(
ngx_http_request_t *r,
ngx_http_upstream_t *u,
ngx_http_tnt_ctx_t *ctx);

static ngx_int_t ngx_http_tnt_filter_reply(
ngx_http_request_t *r,
ngx_http_upstream_t *u,
ngx_buf_t *b);

static ngx_int_t ngx_http_tnt_send_reply(ngx_http_request_t *r,
ngx_http_upstream_t *u, ngx_http_tnt_ctx_t *ctx);
static ngx_int_t ngx_http_tnt_filter_reply(ngx_http_request_t *r,
ngx_http_upstream_t *u, ngx_buf_t *b);
static ngx_int_t ngx_http_tnt_filter(void *data, ssize_t bytes);

/** Other functions and utils
*/
static inline ngx_buf_t * ngx_http_tnt_create_mem_buf(
ngx_http_request_t *r,
ngx_http_upstream_t *u,
size_t size);

static inline ngx_int_t ngx_http_tnt_output(
ngx_http_request_t *r,
ngx_http_upstream_t *u,
ngx_buf_t *b);
/** Other functions */
static inline ngx_buf_t * ngx_http_tnt_create_mem_buf(ngx_http_request_t *r,
ngx_http_upstream_t *u, size_t size);
static inline ngx_int_t ngx_http_tnt_output(ngx_http_request_t *r,
ngx_http_upstream_t *u, ngx_buf_t *b);

/** Confs
*/
/** Nginx handlers */
static ngx_int_t ngx_http_tnt_preconfiguration(ngx_conf_t *cf);
static void *ngx_http_tnt_create_loc_conf(ngx_conf_t *cf);
static char *ngx_http_tnt_merge_loc_conf(
ngx_conf_t *cf,
void *parent,
static char *ngx_http_tnt_merge_loc_conf(ngx_conf_t *cf, void *parent,
void *child);

static char *ngx_http_tnt_pass(
ngx_conf_t *cf,
ngx_command_t *cmd,
static char * ngx_http_tnt_method(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static char * ngx_http_tnt_headers_add(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static ngx_int_t ngx_http_tnt_add_header_in(ngx_http_request_t *r,
ngx_http_tnt_header_val_t *hv, ngx_str_t *value);
static ngx_int_t ngx_http_tnt_process_headers(ngx_http_request_t *r,
ngx_http_tnt_loc_conf_t *tlcf);
static char *ngx_http_tnt_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);

static ngx_conf_bitmask_t ngx_http_tnt_next_upstream_masks[] = {
{ ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR },
@@ -95,6 +81,7 @@ static ngx_conf_bitmask_t ngx_http_tnt_pass_http_request_masks[] = {
{ ngx_string("unescape"), NGX_TNT_CONF_UNESCAPE },
{ ngx_string("pass_body"), NGX_TNT_CONF_PASS_BODY },
{ ngx_string("pass_headers_out"), NGX_TNT_CONF_PASS_HEADERS_OUT },
{ ngx_string("parse_urlencoded"), NGX_TNT_CONF_PARSE_URLENCODED },
{ ngx_null_string, 0 }
};

@@ -188,9 +175,9 @@ static ngx_command_t ngx_http_tnt_commands[] = {

{ ngx_string("tnt_method"),
NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1,
ngx_conf_set_str_slot,
ngx_http_tnt_method,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_tnt_loc_conf_t, method),
0,
NULL },

{ ngx_string("tnt_pass_http_request_buffer_size"),
@@ -231,9 +218,9 @@ static ngx_command_t ngx_http_tnt_commands[] = {

{ ngx_string("tnt_set_header"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
ngx_conf_set_keyval_slot,
ngx_http_tnt_headers_add,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_tnt_loc_conf_t, headers_source),
0,
NULL },

ngx_null_command
@@ -282,6 +269,19 @@ ngx_http_tnt_handler(ngx_http_request_t *r)

tlcf = ngx_http_get_module_loc_conf(r, ngx_http_tnt_module);

if (tlcf->method_ccv != NULL) {

if (ngx_http_complex_value(r, tlcf->method_ccv, &tlcf->method)
!= NGX_OK)
{
return NGX_ERROR;
}
}

if (ngx_http_tnt_process_headers(r, tlcf) != NGX_OK) {
return NGX_ERROR;
}

if ((!tlcf->method.len && r->uri.len <= 1 /* i.e '/' */) ||
!(r->method & ngx_http_tnt_allowed_methods))
{
@@ -444,7 +444,9 @@ ngx_http_tnt_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)

ngx_conf_merge_size_value(conf->out_multiplier, prev->out_multiplier, 2);

ngx_conf_merge_str_value(conf->method, prev->method, "");
if (conf->method_ccv == NULL) {
conf->method_ccv = prev->method_ccv;
}

ngx_conf_merge_size_value(conf->pass_http_request_buffer_size,
prev->pass_http_request_buffer_size, 4096*2);
@@ -465,15 +467,148 @@ ngx_http_tnt_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_bitmask_value(conf->pure_result, prev->pure_result,
NGX_TNT_CONF_OFF);

if (conf->headers_source == NULL) {
if (conf->headers == NULL) {
conf->headers = prev->headers;
conf->headers_source = prev->headers_source;
}

return NGX_CONF_OK;
}


static char *
ngx_http_tnt_method(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_tnt_loc_conf_t *tlcf = conf;

ngx_http_compile_complex_value_t ccv;
ngx_str_t *value;
ngx_http_complex_value_t cv;

ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
value = cf->args->elts;

ccv.cf = cf;
ccv.value = &value[1];
ccv.complex_value = &cv;

if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
return NGX_CONF_ERROR;
}

tlcf->method_ccv = ngx_palloc(cf->pool, sizeof(ngx_http_complex_value_t));
if (tlcf->method_ccv == NULL) {
return NGX_CONF_ERROR;
}

*tlcf->method_ccv = cv;

return NGX_CONF_OK;
}


static char *
ngx_http_tnt_headers_add(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_tnt_loc_conf_t *tlcf = conf;

ngx_str_t *value;
ngx_http_tnt_header_val_t *hv;
ngx_http_compile_complex_value_t ccv;

value = cf->args->elts;

if (tlcf->headers == NULL) {

tlcf->headers = ngx_array_create(cf->pool, 1,
sizeof(ngx_http_tnt_header_val_t));
if (tlcf->headers == NULL) {
return NGX_CONF_ERROR;
}
}

hv = ngx_array_push(tlcf->headers);
if (hv == NULL) {
return NGX_CONF_ERROR;
}

hv->key = value[1];
hv->handler = ngx_http_tnt_add_header_in;

if (value[2].len == 0) {
ngx_memzero(&hv->value, sizeof(ngx_http_complex_value_t));

} else {
ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));

ccv.cf = cf;
ccv.value = &value[2];
ccv.complex_value = &hv->value;

if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
return NGX_CONF_ERROR;
}
}

if (cf->args->nelts == 3) {
return NGX_CONF_OK;
}

return NGX_CONF_OK;
}


static ngx_int_t
ngx_http_tnt_add_header_in(ngx_http_request_t *r,
ngx_http_tnt_header_val_t *hv,
ngx_str_t *value)
{
ngx_table_elt_t *h;

if (value->len) {

h = ngx_list_push(&r->headers_in.headers);
if (h == NULL) {
return NGX_ERROR;
}

h->hash = 1;
h->key = hv->key;
h->value = *value;
}

return NGX_OK;
}


static ngx_int_t
ngx_http_tnt_process_headers(ngx_http_request_t *r,
ngx_http_tnt_loc_conf_t *tlcf)
{
ngx_uint_t i;
ngx_str_t value;
ngx_http_tnt_header_val_t *h;

if (tlcf->headers == NULL) {
return NGX_OK;
}

h = tlcf->headers->elts;

for (i = 0; i < tlcf->headers->nelts; i++) {

if (ngx_http_complex_value(r, &h[i].value, &value) != NGX_OK) {
return NGX_ERROR;
}

if (h[i].handler(r, &h[i], &value) != NGX_OK) {
return NGX_ERROR;
}
}

return NGX_OK;
}


static char *
ngx_http_tnt_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
@@ -574,7 +709,8 @@ ngx_http_tnt_send_reply(ngx_http_request_t *r,

rc = tp_transcode_init(&tc, &args);
if (rc == TP_TRANSCODE_ERROR) {
crit("[BUG] failed to call tp_transcode_init(output)");
ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0,
"[BUG] failed to call tp_transcode_init(output)");
return NGX_ERROR;
}

@@ -589,7 +725,9 @@ ngx_http_tnt_send_reply(ngx_http_request_t *r,
size_t complete_msg_size = 0;
rc = tp_transcode_complete(&tc, &complete_msg_size);
if (rc == TP_TRANSCODE_ERROR) {
crit("[BUG] failed to complete output transcoding. UNKNOWN ERROR");
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"[BUG] failed to complete output transcoding. "
"UNKNOWN ERROR");
goto error_exit;
}

@@ -612,9 +750,9 @@ ngx_http_tnt_send_reply(ngx_http_request_t *r,
/* Transcoder down
*/
else {
crit("[BUG] failed to transcode output. errcode: '%d', errmsg: '%s'",
tc.errcode,
get_str_safe((const u_char *)tc.errmsg));
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"[BUG] failed to transcode output. errcode: '%d', errmsg: '%s'",
tc.errcode, get_str_safe((const u_char *) tc.errmsg));
goto error_exit;
}

@@ -684,8 +822,9 @@ ngx_http_tnt_filter_reply(ngx_http_request_t *r,
ctx->payload_size = tp_read_payload((char *)&ctx->payload.mem[0],
(char *)ctx->payload.e);
if (ctx->payload_size <= 0) {
crit("[BUG] tp_read_payload failed, ret:%i",
(int)ctx->payload_size);
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"[BUG] tp_read_payload failed, ret:%i",
(int) ctx->payload_size);
return NGX_ERROR;
}


+ 1
- 1
src/ngx_http_tnt_version.h View File

@@ -33,6 +33,6 @@
#ifndef NGX_HTTP_TNT_VERSION_H
#define NGX_HTTP_TNT_VERSION_H 1

#define NGX_HTTP_TNT_MODULE_VERSION_STRING "v2.4.6-rc1"
#define NGX_HTTP_TNT_MODULE_VERSION_STRING "v2.4.6-rc1-23-g5ef7528-dirty"

#endif

+ 31
- 77
src/tp_transcode.c View File

@@ -47,20 +47,11 @@
#include <stdint.h>
#include <inttypes.h>

#if 0
#define dd(...) fprintf(stderr, __VA_ARGS__)
#else
#define dd(...)
#endif

#define ALLOC(ctx_, size) \
(ctx_)->tc->mf.alloc((ctx_)->tc->mf.ctx, (size))
#define REALLOC(ctx_, mem, size) \
(ctx_)->tc->mf.realloc((ctx_)->tc->mf.ctx, (mem), (size))
#define FREE(ctx_, mem) \
(ctx_)->tc->mf.free((ctx_)->tc->mf.ctx, (mem))

enum type { TYPE_MAP = 1, TYPE_ARRAY = 2, TYPE_KEY = 4 };
enum type {
TYPE_MAP = 1,
TYPE_ARRAY = 2,
TYPE_KEY = 4
};

static inline void
say_error_(tp_transcode_t *t, int code, const char *e, size_t len)
@@ -91,11 +82,28 @@ say_error_(tp_transcode_t *t, int code, const char *e, size_t len)

#define say_wrong_params(ctx) \
say_error((ctx), -32700, \
"'params' _must_ be array, 'params' _may_ be empty array")
"'params' _must_ be array, 'params' _may_ be an empty array")

#define say_invalid_json(ctx) \
say_error((ctx), -32700, "invalid json")

#define ALLOC(ctx_, size) \
(ctx_)->tc->mf.alloc((ctx_)->tc->mf.ctx, (size))
#define REALLOC(ctx_, mem, size) \
(ctx_)->tc->mf.realloc((ctx_)->tc->mf.ctx, (mem), (size))
#define FREE(ctx_, mem) \
(ctx_)->tc->mf.free((ctx_)->tc->mf.ctx, (mem))

#if 0
# define dd(...) do { \
fprintf(stderr, "tnt *** "); \
fprintf(stderr, __VA_ARGS__); \
fprintf(stderr, " at %s line %d.\n", __FILE__, __LINE__); \
} while(0)
#else
# define dd(...)
#endif

/*
* CODEC - YAJL_JSON_RPC
*/
@@ -773,7 +781,7 @@ yajl_json2tp_transcode(void *ctx, const char *input, size_t input_size)
static enum tt_result
yajl_json2tp_complete(void *ctx, size_t *complete_msg_size)
{
yajl_ctx_t *s_ctx = (yajl_ctx_t *)ctx;
yajl_ctx_t *s_ctx = (yajl_ctx_t *) ctx;

const yajl_status stat = yajl_complete_parse(s_ctx->hand);

@@ -792,56 +800,6 @@ yajl_json2tp_complete(void *ctx, size_t *complete_msg_size)
return TP_TRANSCODE_ERROR;
}


/**
* CODEC - uri query to Tarantool message
*/

typedef struct query2tp_ctx {
char *pos;
char *end;
tp_transcode_t *tc;
} query2tp_ctx_t;

static void*
query2tp_create(tp_transcode_t *tc, char *output, size_t output_size)
{
query2tp_ctx_t *ctx = tc->mf.alloc(tc->mf.ctx, sizeof(query2tp_ctx_t));
if (unlikely(!ctx))
return NULL;

ctx->pos = output;
ctx->end = output + output_size;
ctx->tc = tc;

return ctx;
}

static void
query2tp_free(void *ctx_)
{
if (unlikely(!ctx_))
return;
query2tp_ctx_t *ctx = ctx_;
tp_transcode_t * tc = ctx->tc;
tc->mf.free(tc->mf.ctx, ctx);
}

enum tt_result
query2tp_transcode(void *ctx, const char *in, size_t in_size)
{
(void)ctx, (void)in, (void)in_size;
return 0;
}

enum tt_result
query2tp_complete(void *ctx, size_t *cmpl_msg_size)
{
(void)ctx, (void)cmpl_msg_size;
return 0;
}


/**
* CODEC - Tarantool message to JSON RPC
*/
@@ -1144,7 +1102,7 @@ tp2json_transcode(void *ctx_, const char *in, size_t in_size)
const char *it = in, *end = in + in_size;

/* TODO
* Need add tarantool message structure check like in tp_reply
* I have to add tarantool message check like tp_reply does
*/

/* Message len */
@@ -1201,11 +1159,6 @@ tp_codec_t codecs[TP_CODEC_MAX] = {
&yajl_json2tp_complete,
&yajl_json2tp_free),

CODEC(&query2tp_create,
&query2tp_transcode,
&query2tp_complete,
&query2tp_free),

CODEC(&tp2json_create,
&tp_reply2json_transcode,
&tp2json_complete,
@@ -1214,7 +1167,7 @@ tp_codec_t codecs[TP_CODEC_MAX] = {
CODEC(&tp2json_create,
&tp2json_transcode,
&tp2json_complete,
&tp2json_free)
&tp2json_free),

};
#undef CODEC
@@ -1226,22 +1179,23 @@ tp_codec_t codecs[TP_CODEC_MAX] = {
static void *
def_alloc(void *ctx, size_t s)
{
(void)ctx;
(void) ctx;
return malloc(s);
}

static void *
def_realloc(void *ctx, void *m, size_t s)
{
(void)ctx;
(void) ctx;
return realloc(m, s);
}

static void
def_free(void *ctx, void *m)
{
(void)ctx;
free(m);
(void) ctx;
if (m)
free(m);
}

enum tt_result

+ 0
- 4
src/tp_transcode.h View File

@@ -74,10 +74,6 @@ enum tp_codec_type {
*/
YAJL_JSON_TO_TP = 0,

/**
*/
QUERY_TO_TP,

/** Tarantool reply message to JSON
*/
TP_REPLY_TO_JSON,

test/auto.sh → t/auto.sh View File

@@ -2,7 +2,7 @@

set -x -e

for ver_tag in `cat test/ngx_versions_list`; do
for ver_tag in `cat t/ngx_versions_list`; do

# Checkout nginx version via tag
cd nginx
@@ -21,9 +21,9 @@ for ver_tag in `cat test/ngx_versions_list`; do
echo "[+] Start testing $ver_tag"
./nginx/objs/nginx 2> /dev/null &
nginx_pid=$!
tarantool test/test.lua 2> /dev/null &
tarantool t/test.lua 2> /dev/null &
tnt_pid=$!
./test/run_all.sh
./t/run_all.sh
for pid in $nginx_pid $tnt_pid; do
echo "[+] Terminating $pid"
kill -s TERM $pid

test/basic_features.py → t/basic_features.py View File


test/cases/batch.json → t/cases/batch.json View File


BIN
t/cases/batch.json.tmp View File


test/cases/escaped.json → t/cases/escaped.json View File


BIN
t/cases/escaped.json.tmp View File


test/cases/expected → t/cases/expected View File


test/cases/param_w_tnt_name.json → t/cases/param_w_tnt_name.json View File


BIN
t/cases/param_w_tnt_name.json.tmp View File


test/cases/param_wo_args.json → t/cases/param_wo_args.json View File


BIN
t/cases/param_wo_args.json.tmp View File


test/cases/param_wo_tnt_name.json → t/cases/param_wo_tnt_name.json View File


BIN
t/cases/param_wo_tnt_name.json.tmp View File


test/cases/regular.json → t/cases/regular.json View File


BIN
t/cases/regular.json.tmp View File


test/cases/regular_2.json → t/cases/regular_2.json View File


BIN
t/cases/regular_2.json.tmp View File


test/cases/without_id.json → t/cases/without_id.json View File


BIN
t/cases/without_id.json.tmp View File


test/cases/without_method.json → t/cases/without_method.json View File


BIN
t/cases/without_method.json.tmp View File


test/cases/without_method_2.json → t/cases/without_method_2.json View File


BIN
t/cases/without_method_2.json.tmp View File


test/cases/without_params.json → t/cases/without_params.json View File


BIN
t/cases/without_params.json.tmp View File


test/cases/wrong_args.json → t/cases/wrong_args.json View File


+ 0
- 0
t/cases/wrong_args.json.tmp View File


test/cases/wrong_args_2.json → t/cases/wrong_args_2.json View File


BIN
t/cases/wrong_args_2.json.tmp View File


test/cases/wrong_args_3.json → t/cases/wrong_args_3.json View File


BIN
t/cases/wrong_args_3.json.tmp View File


test/http_utils.py → t/http_utils.py View File


test/lua.py → t/lua.py View File

@@ -3,7 +3,7 @@

import sys
import time
sys.path.append('./test')
sys.path.append('./t')
from http_utils import *

VERBOSE = False

test/ngx_confs/nginx.dev.conf → t/ngx_confs/nginx.dev.conf View File


test/ngx_confs/nginx.dev.dyn.conf → t/ngx_confs/nginx.dev.dyn.conf View File


test/ngx_confs/tnt_server_test.conf → t/ngx_confs/tnt_server_test.conf View File

@@ -209,54 +209,54 @@ http {
tnt_pass tnt;
}

location /lua {
lua_need_request_body on;
rewrite_by_lua '
local cjson = require("cjson")
local map = {
GET = ngx.HTTP_GET,
POST = ngx.HTTP_POST,
PUT = ngx.HTTP_PUT,
-- ...
}
local res = ngx.location.capture("/tnt_proxy", {
args = ngx.var.args,
method = map[ngx.var.request_method],
body = ngx.body
})
if res.status == ngx.HTTP_OK then
local answ = cjson.decode(res.body)
-- Read reply
local result = answ["result"]
if result ~= nil then
ngx.status = result[1]["ngx"][1]
for k, v in pairs(result[1]["ngx"][2]) do
ngx.header[k] = v
end
table.remove(result, 1)
ngx.say(cjson.encode(result))
else
ngx.status = 502
ngx.say(res.body)
end
-- Finalize execution
ngx.exit(ngx.OK)
else
ngx.status = 502
ngx.say("Tarantool does not work")
end
';
}
# location /lua {
#
# lua_need_request_body on;
#
# rewrite_by_lua '
#
# local cjson = require("cjson")
#
# local map = {
# GET = ngx.HTTP_GET,
# POST = ngx.HTTP_POST,
# PUT = ngx.HTTP_PUT,
# -- ...
# }
#
# local res = ngx.location.capture("/tnt_proxy", {
# args = ngx.var.args,
# method = map[ngx.var.request_method],
# body = ngx.body
# })
#
# if res.status == ngx.HTTP_OK then
# local answ = cjson.decode(res.body)
#
# -- Read reply
# local result = answ["result"]
#
# if result ~= nil then
# ngx.status = result[1]["ngx"][1]
# for k, v in pairs(result[1]["ngx"][2]) do
# ngx.header[k] = v
# end
#
# table.remove(result, 1)
# ngx.say(cjson.encode(result))
# else
# ngx.status = 502
# ngx.say(res.body)
# end
#
# -- Finalize execution
# ngx.exit(ngx.OK)
# else
# ngx.status = 502
# ngx.say("Tarantool does not work")
# end
# ';
# }

location /echo_big {
tnt_pass_http_request_buffer_size 1m;
@@ -266,5 +266,33 @@ http {
tnt_http_methods all;
tnt_pass tnt;
}

location /url_encoded {
tnt_pass_http_request_buffer_size 1m;
tnt_pass_http_request on parse_args parse_urlencoded;
tnt_http_rest_methods get post;
tnt_http_methods get post;
tnt_pass tnt;
}

location ~ /method_ccv/([-_a-zA-Z0-9/]+)/ {
tnt_method $1;
tnt_pass_http_request_buffer_size 1m;
tnt_http_rest_methods get;
tnt_http_methods get;
tnt_pass tnt;
}

location /headers_ccv {
tnt_method method_1;
tnt_set_header 'X-host' $host;
tnt_set_header 'X-Str' 'str';
tnt_set_header 'X-Uri' $uri;
tnt_pass_http_request_buffer_size 1m;
tnt_http_rest_methods get;
tnt_http_methods get;
tnt_pass tnt;
}

}
}

test/ngx_versions_list → t/ngx_versions_list View File


+ 15
- 0
t/parallel_clients.sh View File

@@ -0,0 +1,15 @@
#!/bin/bash

for i in {1..10}; do
./t/basic_features.py &
./t/v20_features.py &
./t/v23_features.py &
./t/v24_features.py &
# ./t/lua.py &
./t/v26_features.py &
done

for i in `jobs -p`; do
wait $i
done


test/run_all.sh → t/run_all.sh View File

@@ -2,7 +2,7 @@

set -e #-x

WORK_DIR=$PWD/test
WORK_DIR=$PWD/t
NGINX_PREFIX=$PWD/test-root

## Tests
@@ -22,8 +22,11 @@ for i in {1..10}; do
$WORK_DIR/v24_features.py 1> /dev/null || (
echo "[-] $WORK_DIR/v24_features.py failed" && exit 1
)
$WORK_DIR/lua.py 1> /dev/null || (
echo "[-] $WORK_DIR/lua.py failed" && exit 1
# $WORK_DIR/lua.py 1> /dev/null || (
# echo "[-] $WORK_DIR/lua.py failed" && exit 1
# )
$WORK_DIR/v26_features.py 1> /dev/null || (
echo "[-] $WORK_DIR/v24_features.py failed" && exit 1
)
done

@@ -44,10 +47,13 @@ for i in {1..3}; do
`$WORK_DIR/v24_features.py 1> /dev/null || (
echo "[-] $WORK_DIR/v24_features.py failed" && exit 1
)` &
clients_pids="$clients_pids $!"
`$WORK_DIR/lua.py 1> /dev/null || (
echo "[-] $WORK_DIR/lua.py failed" && exit 1
)` &
# clients_pids="$clients_pids $!"
# `$WORK_DIR/lua.py 1> /dev/null || (
# echo "[-] $WORK_DIR/lua.py failed" && exit 1
# )` &
$WORK_DIR/v26_features.py 1> /dev/null || (
echo "[-] $WORK_DIR/v24_features.py failed" && exit 1
)
clients_pids="$clients_pids $!"
done
for job in $clients_pids; do

test/test.lua → t/test.lua View File

@@ -160,11 +160,27 @@ function tnt_proxy(req, ...)
-- out
end

function url_encoded(req, ...)
return req, ...
end

function method_1(req)
return req
end

function method_2(req)
return req
end

function method_3(req)
return req
end

-- CFG
box.cfg {
log_level = 5;
listen = 9999;
wal_mode = 'none';
log_level = 5,
listen = 9999,
wal_mode = 'none',
}

box.once('gr', function()

test/tp_allowed.c → t/tp_allowed.c View File


test/transcode.sh → t/transcode.sh View File

@@ -14,23 +14,23 @@ do_trasncode() {
fi

if [[ x"$DUMP_RESULT_ONLY" = x"yes" ]]; then
echo "$name -> $result" >> ${PWD}/test/cases/tc.out
echo "$name -> $result" >> ${PWD}/t/cases/tc.out
return;
fi
}

####
echo "[+] Testing ..."
rm -f ${PWD}/test/cases/tc.out > /dev/null
rm -f ${PWD}/t/cases/tc.out > /dev/null
if [[ x"$TRANSCODE_OFF" != x"yes" ]]; then
for _case in `ls ${PWD}/test/cases/*json`; do
for _case in `ls ${PWD}/t/cases/*json`; do
do_trasncode $_case
done
fi

cat ${PWD}/test/cases/tc.out | sort > ${PWD}/test/cases/tc.out.sorted
diff_result=`diff ${PWD}/test/cases/tc.out.sorted \
${PWD}/test/cases/expected`
cat ${PWD}/t/cases/tc.out | sort > ${PWD}/t/cases/tc.out.sorted
diff_result=`diff ${PWD}/t/cases/tc.out.sorted \
${PWD}/t/cases/expected`
if [[ ! x"$diff_result" = x'' ]]; then
echo "[-] $diff_result"
exit 1

test/v20_features.py → t/v20_features.py View File

@@ -1,7 +1,7 @@
#!/usr/bin/python

import sys
sys.path.append('./test')
sys.path.append('./t')
from http_utils import *

big_args_in = {}

test/v23_features.py → t/v23_features.py View File

@@ -2,7 +2,7 @@
# -_- encoding: utf8 -_-

import sys
sys.path.append('./test')
sys.path.append('./t')
from http_utils import *

# =============

test/v24_features.py → t/v24_features.py View File

@@ -3,7 +3,7 @@

import sys
import time
sys.path.append('./test')
sys.path.append('./t')
from http_utils import *

# =============

+ 68
- 0
t/v26_features.py View File

@@ -0,0 +1,68 @@
#!/usr/bin/python
# -_- encoding: utf8 -_-

import sys
import time
sys.path.append('./t')
from http_utils import *


default_headers = {"Content-Type": "application/x-www-form-urlencoded"}
preset_method_location = BASE_URL + '/url_encoded'


print ('[+] Post form - 0 param')
rc, out = post_form(preset_method_location, default_headers)
assert rc == 200, "rc != 200"
assert len(out['result']) == 1, "len(result) != 1"
assert out['result'][0]["headers"]["Content-Type"] == \
default_headers["Content-Type"], "Content-Type not equals"
print ('[+] OK')


print ('[+] Post form - 1 param')
rc, out = post_form(preset_method_location, {"a": "b"}, default_headers)
assert rc == 200, "rc != 200"
assert len(out['result']) == 1, "len(result) != 1"
assert out['result'][0]["headers"]["Content-Type"] == \
default_headers["Content-Type"], "Content-Type not equals"
assert out['result'][0]['body'] == {"a": "b"}, "not expected result"
print ('[+] OK')


print ('[+] Post form - N param')
args = {}
for i in range(1, 1000):
args['a' + str(i)] = str(i)
rc, out = post_form(preset_method_location, args, default_headers)
assert rc == 200, "rc != 200"
assert rc == 200, "rc != 200"
assert len(out['result']) == 1, "len(result) != 1"
assert out['result'][0]["headers"]["Content-Type"] == \
default_headers["Content-Type"], "Content-Type not equals"
assert out['result'][0]['body'] == args, "not expected result"
print ('[+] OK')


print ('[+] Method ccv')
for m in {"method_1", "method_2", "method_3"}:
preset_method_location = BASE_URL + '/method_ccv/' + m + '/comming'
rc, out = get(preset_method_location, None, None)
assert rc == 200, "rc != 200"
assert out['result'][0]['uri'] == '/method_ccv/' + m + '/comming', \
'not expected URL'
print ('[+] OK')


print ('[+] Headers ccv')
preset_method_location = BASE_URL + '/headers_ccv'
rc, out = get(preset_method_location, None, None)
assert rc == 200, "rc != 200"
assert out['result'][0]['headers']['Host'] == '0.0.0.0:8081', \
'not expected host'
assert out['result'][0]['headers']['X-Str'] == 'str', \
'X-Str is not expected'
assert out['result'][0]['headers']['X-Uri'] == '/headers_ccv', \
'X-Uri is not expected'
print ('[+] OK')


+ 0
- 14
test/parallel_clients.sh View File

@@ -1,14 +0,0 @@
#!/bin/bash

for i in {1..10}; do
./test/basic_features.py &
./test/v20_features.py &
./test/v23_features.py &
./test/v24_features.py &
./test/lua.py &
done

for i in `jobs -p`; do
wait $i
done


Loading…
Cancel
Save