src/http/modules/ngx_http_json_module.c - nginx-1.31.7 nginx/ @ 939334eff

Global variables defined

Data types defined

Functions defined

Macros defined

Source code


  1. /*
  2. * Copyright (C) Nginx, Inc.
  3. */


  4. #include <ngx_config.h>
  5. #include <ngx_core.h>
  6. #include <ngx_http.h>
  7. #include <ngx_json_parse.h>


  8. ‌#define NGX_HTTP_JSON_DEFAULT_MAX_DEPTH       32

  9. ‌typedef struct {
  10.     ngx_uint_t                     is_index;
  11.     ngx_str_t                      key;
  12.     ngx_uint_t                     index;
  13. ‌} ngx_http_json_seg_t;


  14. ‌typedef struct ngx_http_json_node_s  ngx_http_json_node_t;


  15. ‌struct ngx_http_json_node_s {
  16.     ngx_http_json_seg_t            seg;
  17.     ngx_array_t                   *children;  /* ngx_http_json_node_t */
  18.     ngx_uint_t                    *dests;
  19.     ngx_uint_t                     ndests;
  20. };


  21. ‌typedef struct {
  22.     ngx_int_t                      index;
  23.     ngx_http_json_node_t          *root;
  24. ‌} ngx_http_json_source_t;


  25. ‌typedef struct {
  26.     ngx_uint_t                     source_index;
  27. ‌} ngx_http_json_variable_t;


  28. ‌typedef struct {
  29.     ngx_uint_t                     index;
  30.     u_char                        *start;
  31.     ngx_http_json_node_t          *node;
  32.     ngx_uint_t                     is_array;
  33. ‌} ngx_http_json_frame_t;


  34. ‌typedef struct {
  35.     ngx_int_t                      max_depth;
  36.     ngx_array_t                   *sources;
  37.     ngx_array_t                   *variables;
  38. ‌} ngx_http_json_main_conf_t;


  39. ‌typedef struct {
  40.     ngx_http_request_t            *r;
  41.     ngx_http_variable_value_t     *values;
  42.     ngx_array_t                    stack;
  43.     ngx_str_t                      current_key;
  44.     ngx_http_json_node_t          *current_node;
  45.     ngx_http_json_node_t          *root;
  46. ‌} ngx_http_json_state_t;


  47. static char *ngx_http_json_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
  48. static ngx_int_t ngx_http_json_variable(ngx_http_request_t *r,
  49.     ngx_http_variable_value_t *v, uintptr_t data);
  50. static void ngx_http_json_reset(ngx_http_variable_value_t *values,
  51.     ngx_http_json_main_conf_t *jmcf, ngx_uint_t source_index);
  52. static char *ngx_http_json_insert_path(ngx_conf_t *cf,
  53.     ngx_http_json_node_t *root, ngx_uint_t dest, ngx_str_t *path);
  54. static ngx_http_json_node_t *ngx_http_json_child(ngx_conf_t *cf,
  55.     ngx_http_json_node_t *parent, ngx_http_json_seg_t *seg);
  56. static ngx_int_t ngx_http_json_handler(ngx_json_ctx_t *ctx,
  57.     ngx_json_event_e event, ngx_str_t *token);
  58. static void ngx_http_json_inc_index(ngx_http_json_state_t *state);
  59. static ngx_http_json_node_t *ngx_http_json_lookup_key(
  60.     ngx_http_json_node_t *parent, ngx_str_t *key);
  61. static ngx_http_json_node_t *ngx_http_json_lookup_index(
  62.     ngx_http_json_node_t *parent, ngx_uint_t index);
  63. static ngx_int_t ngx_http_json_store(ngx_http_json_state_t *state,
  64.     ngx_http_json_node_t *node, ngx_str_t *value, ngx_uint_t unescape);
  65. static ngx_int_t ngx_http_json_push(ngx_http_json_state_t *state,
  66.     ngx_json_event_e event, u_char *start, ngx_http_json_node_t *node);
  67. static void *ngx_http_json_create_main_conf(ngx_conf_t *cf);
  68. static char *ngx_http_json_init_main_conf(ngx_conf_t *cf, void *conf);


  69. ‌static ngx_conf_num_bounds_t  ngx_http_json_max_depth_bounds = {
  70.     ngx_conf_check_num_bounds, 1, 256
  71. };


  72. ‌static ngx_command_t  ngx_http_json_commands[] = {

  73.     { ngx_string("json_set"),
  74.       NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE3,
  75.       ngx_http_json_set,
  76.       NGX_HTTP_MAIN_CONF_OFFSET,
  77.       0,
  78.       NULL },

  79.     { ngx_string("json_max_depth"),
  80.       NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
  81.       ngx_conf_set_num_slot,
  82.       NGX_HTTP_MAIN_CONF_OFFSET,
  83.       offsetof(ngx_http_json_main_conf_t, max_depth),
  84.       &ngx_http_json_max_depth_bounds },

  85.       ngx_null_command
  86. };


  87. ‌static ngx_http_module_t  ngx_http_json_module_ctx = {
  88.     NULL,                            /* preconfiguration */
  89.     NULL,                            /* postconfiguration */

  90.     ngx_http_json_create_main_conf,  /* create main configuration */
  91.     ngx_http_json_init_main_conf,    /* init main configuration */

  92.     NULL,                            /* create server configuration */
  93.     NULL,                            /* merge server configuration */

  94.     NULL,                            /* create location configuration */
  95.     NULL                             /* merge location configuration */
  96. };


  97. ‌ngx_module_t  ngx_http_json_module = {
  98.     NGX_MODULE_V1,
  99.     &ngx_http_json_module_ctx,       /* module context */
  100.     ngx_http_json_commands,          /* module directives */
  101.     NGX_HTTP_MODULE,                 /* module type */
  102.     NULL,                            /* init master */
  103.     NULL,                            /* init module */
  104.     NULL,                            /* init process */
  105.     NULL,                            /* init thread */
  106.     NULL,                            /* exit thread */
  107.     NULL,                            /* exit process */
  108.     NULL,                            /* exit master */
  109.     NGX_MODULE_V1_PADDING
  110. };


  111. static char *
  112. ‌ngx_http_json_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  113. {
  114.     ngx_http_json_main_conf_t  *jmcf = conf;

  115.     ngx_str_t                 *value, name, source;
  116.     ngx_int_t                  sindex;
  117.     ngx_uint_t                 i, oi, si;
  118.     ngx_http_variable_t       *var;
  119.     ngx_http_json_source_t    *src, *srcs;
  120.     ngx_http_json_variable_t  *jv;

  121.     value = cf->args->elts;

  122.     name = value[1];

  123.     if (name.data[0] != '$') {
  124.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  125.                            "invalid variable name \"%V\"", &name);
  126.         return NGX_CONF_ERROR;
  127.     }

  128.     name.len--;
  129.     name.data++;

  130.     var = ngx_http_add_variable(cf, &name, NGX_HTTP_VAR_CHANGEABLE);
  131.     if (var == NULL) {
  132.         return NGX_CONF_ERROR;
  133.     }

  134.     if (var->get_handler == ngx_http_json_variable) {
  135.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  136.                            "json_set variable \"%V\" is already defined",
  137.                            &name);
  138.         return NGX_CONF_ERROR;
  139.     }

  140.     source = value[2];

  141.     if (source.data[0] != '$') {
  142.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  143.                            "invalid variable name \"%V\"", &source);
  144.         return NGX_CONF_ERROR;
  145.     }

  146.     source.len--;
  147.     source.data++;

  148.     sindex = ngx_http_get_variable_index(cf, &source);
  149.     if (sindex == NGX_ERROR) {
  150.         return NGX_CONF_ERROR;
  151.     }

  152.     if (jmcf->sources == NULL) {
  153.         jmcf->sources = ngx_array_create(cf->pool, 4,
  154.                                          sizeof(ngx_http_json_source_t));
  155.         if (jmcf->sources == NULL) {
  156.             return NGX_CONF_ERROR;
  157.         }
  158.     }

  159.     srcs = jmcf->sources->elts;
  160.     si = jmcf->sources->nelts;

  161.     for (i = 0; i < jmcf->sources->nelts; i++) {
  162.         if (srcs[i].index == sindex) {
  163.             si = i;
  164.             break;
  165.         }
  166.     }

  167.     if (si == jmcf->sources->nelts) {
  168.         src = ngx_array_push(jmcf->sources);
  169.         if (src == NULL) {
  170.             return NGX_CONF_ERROR;
  171.         }

  172.         src->index = sindex;

  173.         src->root = ngx_pcalloc(cf->pool, sizeof(ngx_http_json_node_t));
  174.         if (src->root == NULL) {
  175.             return NGX_CONF_ERROR;
  176.         }

  177.     } else {
  178.         src = &srcs[si];
  179.     }

  180.     if (jmcf->variables == NULL) {
  181.         jmcf->variables = ngx_array_create(cf->pool, 4,
  182.                                            sizeof(ngx_http_json_variable_t));
  183.         if (jmcf->variables == NULL) {
  184.             return NGX_CONF_ERROR;
  185.         }
  186.     }

  187.     oi = jmcf->variables->nelts;

  188.     jv = ngx_array_push(jmcf->variables);
  189.     if (jv == NULL) {
  190.         return NGX_CONF_ERROR;
  191.     }

  192.     jv->source_index = si;

  193.     if (ngx_http_json_insert_path(cf, src->root, oi, &value[3])
  194.         != NGX_CONF_OK)
  195.     {
  196.         return NGX_CONF_ERROR;
  197.     }

  198.     var->get_handler = ngx_http_json_variable;
  199.     var->data = (uintptr_t) oi;

  200.     return NGX_CONF_OK;
  201. }


  202. static ngx_int_t
  203. ‌ngx_http_json_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v,
  204.     uintptr_t data)
  205. {
  206.     ngx_int_t                   rc;
  207.     ngx_uint_t                  oi, si;
  208.     ngx_json_ctx_t              jctx;
  209.     ngx_http_json_state_t       state;
  210.     ngx_http_json_source_t     *src, *srcs;
  211.     ngx_http_json_variable_t   *jv;
  212.     ngx_http_variable_value_t  *cached, *values, *vv;
  213.     ngx_http_json_main_conf_t  *jmcf;

  214.     oi = (ngx_uint_t) data;

  215.     jmcf = ngx_http_get_module_main_conf(r, ngx_http_json_module);

  216.     if (jmcf->variables == NULL || oi >= jmcf->variables->nelts) {
  217.         v->not_found = 1;
  218.         return NGX_OK;
  219.     }

  220.     values = ngx_http_get_module_ctx(r, ngx_http_json_module);

  221.     if (values == NULL) {
  222.         values = ngx_pcalloc(r->pool, jmcf->variables->nelts
  223.                              * sizeof(ngx_http_variable_value_t));
  224.         if (values == NULL) {
  225.             return NGX_ERROR;
  226.         }

  227.         ngx_http_set_ctx(r, values, ngx_http_json_module);
  228.     }

  229.     cached = &values[oi];

  230.     if (cached->valid || cached->not_found) {
  231.         *v = *cached;
  232.         return NGX_OK;
  233.     }

  234.     jv = jmcf->variables->elts;
  235.     si = jv[oi].source_index;

  236.     srcs = jmcf->sources->elts;
  237.     src = &srcs[si];

  238.     vv = ngx_http_get_flushed_variable(r, (ngx_uint_t) src->index);

  239.     if (vv == NULL) {
  240.         return NGX_ERROR;
  241.     }

  242.     ngx_http_json_reset(values, jmcf, si);

  243.     if (vv->not_found || vv->len == 0) {
  244.         *v = *cached;
  245.         return NGX_OK;
  246.     }

  247.     ngx_memzero(&state, sizeof(ngx_http_json_state_t));

  248.     state.r = r;
  249.     state.values = values;
  250.     state.root = src->root;

  251.     if (ngx_array_init(&state.stack, r->pool, 8, sizeof(ngx_http_json_frame_t))
  252.         != NGX_OK)
  253.     {
  254.         return NGX_ERROR;
  255.     }

  256.     ngx_json_ctx_init(&jctx, r->pool);

  257.     jctx.handler = ngx_http_json_handler;
  258.     jctx.data = &state;
  259.     jctx.max_depth = jmcf->max_depth;

  260.     rc = ngx_json_parse_ctx(&jctx, vv->data, vv->len);

  261.     if (rc == NGX_OK) {
  262.         *v = *cached;
  263.         return NGX_OK;
  264.     }

  265.     ngx_http_json_reset(values, jmcf, si);

  266.     if (rc == NGX_DECLINED) {
  267.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  268.                        "json_set: invalid JSON source");
  269.     }

  270.     if (rc == NGX_ERROR) {
  271.         return NGX_ERROR;
  272.     }

  273.     *v = *cached;

  274.     return NGX_OK;
  275. }


  276. static void
  277. ‌ngx_http_json_reset(ngx_http_variable_value_t *values,
  278.     ngx_http_json_main_conf_t *jmcf, ngx_uint_t source_index)
  279. {
  280.     ngx_uint_t                 i;
  281.     ngx_http_json_variable_t  *jv;

  282.     jv = jmcf->variables->elts;

  283.     for (i = 0; i < jmcf->variables->nelts; i++) {
  284.         if (jv[i].source_index != source_index) {
  285.             continue;
  286.         }

  287.         values[i].valid = 0;
  288.         values[i].not_found = 1;
  289.     }
  290. }


  291. static char *
  292. ‌ngx_http_json_insert_path(ngx_conf_t *cf, ngx_http_json_node_t *root,
  293.     ngx_uint_t dest, ngx_str_t *path)
  294. {
  295.     u_char                *p, *last, *start, *dst;
  296.     ngx_int_t              index;
  297.     ngx_uint_t            *term;
  298.     ngx_http_json_seg_t    seg;
  299.     ngx_http_json_node_t  *node;
  300. ‌    enum {
  301.         sw_start = 0,
  302.         sw_key,
  303.         sw_dot,
  304.         sw_bracket,
  305.         sw_index,
  306.         sw_quoted,
  307.         sw_quoted_escape,
  308.         sw_quoted_close,
  309.         sw_after_bracket
  310.     } state;

  311.     if (path->len == 0) {
  312.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "empty json_set path");
  313.         return NGX_CONF_ERROR;
  314.     }

  315.     node = root;
  316.     start = NULL;

  317.     last = path->data + path->len;
  318.     state = sw_start;

  319.     for (p = path->data; p < last; p++) {

  320.         switch (state) {

  321.         case sw_start:

  322.             if (*p == '[') {
  323.                 state = sw_bracket;
  324.                 break;
  325.             }

  326.             if (*p == '.' || *p == '$') {
  327.                 goto invalid;
  328.             }

  329.             start = p;
  330.             state = sw_key;
  331.             break;

  332.         case sw_key:

  333.             if (*p == '.' || *p == '[') {

  334.                 seg.is_index = 0;
  335.                 seg.key.data = start;
  336.                 seg.key.len = p - start;
  337.                 seg.index = 0;

  338.                 node = ngx_http_json_child(cf, node, &seg);
  339.                 if (node == NULL) {
  340.                     return NGX_CONF_ERROR;
  341.                 }

  342.                 state = (*p == '.') ? sw_dot : sw_bracket;
  343.             }

  344.             break;

  345.         case sw_dot:

  346.             if (*p == '.' || *p == '[' || *p == '$') {
  347.                 goto invalid;
  348.             }

  349.             start = p;
  350.             state = sw_key;
  351.             break;

  352.         case sw_bracket:

  353.             if (*p == '"') {
  354.                 start = p + 1;
  355.                 state = sw_quoted;
  356.                 break;
  357.             }

  358.             if (*p >= '0' && *p <= '9') {
  359.                 start = p;
  360.                 state = sw_index;
  361.                 break;
  362.             }

  363.             goto invalid;

  364.         case sw_index:

  365.             if (*p >= '0' && *p <= '9') {
  366.                 break;
  367.             }

  368.             if (*p != ']') {
  369.                 goto invalid;
  370.             }

  371.             index = ngx_atoi(start, p - start);
  372.             if (index == NGX_ERROR) {
  373.                 goto invalid;
  374.             }

  375.             seg.is_index = 1;
  376.             seg.index = index;
  377.             ngx_str_null(&seg.key);

  378.             node = ngx_http_json_child(cf, node, &seg);
  379.             if (node == NULL) {
  380.                 return NGX_CONF_ERROR;
  381.             }

  382.             state = sw_after_bracket;
  383.             break;

  384.         case sw_quoted:

  385.             if (*p == '\\') {
  386.                 state = sw_quoted_escape;
  387.                 break;
  388.             }

  389.             if (*p == '"') {

  390.                 dst = ngx_pnalloc(cf->pool, (size_t) (p - start));
  391.                 if (dst == NULL) {
  392.                     return NGX_CONF_ERROR;
  393.                 }

  394.                 ngx_memcpy(dst, start, p - start);

  395.                 seg.is_index = 0;
  396.                 seg.key.data = dst;
  397.                 seg.key.len = p - start;
  398.                 seg.index = 0;

  399.                 if (ngx_json_unescape_string(&seg.key) != NGX_OK) {
  400.                     goto invalid;
  401.                 }

  402.                 node = ngx_http_json_child(cf, node, &seg);
  403.                 if (node == NULL) {
  404.                     return NGX_CONF_ERROR;
  405.                 }

  406.                 state = sw_quoted_close;
  407.             }

  408.             break;

  409.         case sw_quoted_escape:

  410.             state = sw_quoted;
  411.             break;

  412.         case sw_quoted_close:

  413.             if (*p != ']') {
  414.                 goto invalid;
  415.             }

  416.             state = sw_after_bracket;
  417.             break;

  418.         case sw_after_bracket:

  419.             if (*p == '.') {
  420.                 state = sw_dot;
  421.                 break;
  422.             }

  423.             if (*p == '[') {
  424.                 state = sw_bracket;
  425.                 break;
  426.             }

  427.             goto invalid;
  428.         }
  429.     }

  430.     switch (state) {

  431.     case sw_key:

  432.         seg.is_index = 0;
  433.         seg.key.data = start;
  434.         seg.key.len = last - start;
  435.         seg.index = 0;

  436.         node = ngx_http_json_child(cf, node, &seg);
  437.         if (node == NULL) {
  438.             return NGX_CONF_ERROR;
  439.         }

  440.         break;

  441.     case sw_after_bracket:
  442.         break;

  443.     default:
  444.         goto invalid;
  445.     }

  446.     term = ngx_palloc(cf->pool, (node->ndests + 1) * sizeof(ngx_uint_t));
  447.     if (term == NULL) {
  448.         return NGX_CONF_ERROR;
  449.     }

  450.     if (node->ndests) {
  451.         ngx_memcpy(term, node->dests, node->ndests * sizeof(ngx_uint_t));
  452.     }

  453.     term[node->ndests] = dest;
  454.     node->dests = term;
  455.     node->ndests++;

  456.     return NGX_CONF_OK;

  457. invalid:

  458.     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  459.                        "invalid json_set path \"%V\"", path);
  460.     return NGX_CONF_ERROR;
  461. }


  462. static ngx_http_json_node_t *
  463. ‌ngx_http_json_child(ngx_conf_t *cf, ngx_http_json_node_t *parent,
  464.     ngx_http_json_seg_t *seg)
  465. {
  466.     ngx_uint_t             i;
  467.     ngx_http_json_seg_t   *cseg;
  468.     ngx_http_json_node_t  *child, *elts;

  469.     if (parent->children != NULL) {
  470.         elts = parent->children->elts;

  471.         for (i = 0; i < parent->children->nelts; i++) {
  472.             child = &elts[i];
  473.             cseg = &child->seg;

  474.             if (seg->is_index) {
  475.                 if (cseg->is_index && cseg->index == seg->index) {
  476.                     return child;
  477.                 }

  478.             } else {
  479.                 if (!cseg->is_index
  480.                     && cseg->key.len == seg->key.len
  481.                     && ngx_memcmp(cseg->key.data, seg->key.data, seg->key.len)
  482.                        == 0)
  483.                 {
  484.                     return child;
  485.                 }
  486.             }
  487.         }

  488.     } else {
  489.         parent->children = ngx_array_create(cf->pool, 1,
  490.                                             sizeof(ngx_http_json_node_t));
  491.         if (parent->children == NULL) {
  492.             return NULL;
  493.         }
  494.     }

  495.     child = ngx_array_push(parent->children);
  496.     if (child == NULL) {
  497.         return NULL;
  498.     }

  499.     ngx_memzero(child, sizeof(ngx_http_json_node_t));

  500.     child->seg = *seg;

  501.     return child;
  502. }


  503. static ngx_int_t
  504. ‌ngx_http_json_handler(ngx_json_ctx_t *ctx, ngx_json_event_e event,
  505.     ngx_str_t *token)
  506. {
  507.     ngx_str_t               slice, value;
  508.     ngx_uint_t              is_member;
  509.     ngx_http_json_node_t   *node;
  510.     ngx_http_json_state_t  *state;
  511.     ngx_http_json_frame_t  *top;

  512.     state = ctx->data;

  513.     top = NULL;
  514.     if (state->stack.nelts) {
  515.         top = (ngx_http_json_frame_t *) state->stack.elts
  516.               + state->stack.nelts - 1;
  517.     }

  518.     switch (event) {

  519.     case NGX_JSON_OBJECT_OPEN:
  520.     case NGX_JSON_ARRAY_OPEN:

  521.         if (state->stack.nelts == 0) {

  522.             ngx_str_null(&state->current_key);
  523.             state->current_node = NULL;

  524.             return ngx_http_json_push(state, event, token->data, state->root);
  525.         }

  526.         is_member = (state->current_key.data != NULL);
  527.         ngx_str_null(&state->current_key);

  528.         if (is_member) {

  529.             node = state->current_node;
  530.             state->current_node = NULL;

  531.         } else {

  532.             node = ngx_http_json_lookup_index(top->node, top->index);

  533.             ngx_http_json_inc_index(state);

  534.             if (node == NULL) {
  535.                 return NGX_JSON_SKIP;
  536.             }
  537.         }

  538.         return ngx_http_json_push(state, event, token->data, node);

  539.     case NGX_JSON_OBJECT_CLOSE:
  540.     case NGX_JSON_ARRAY_CLOSE:

  541.         if (top != NULL) {

  542.             if (top->node->ndests > 0) {
  543.                 slice.data = top->start;
  544.                 slice.len = token->data - top->start + 1;

  545.                 if (ngx_http_json_store(state, top->node, &slice, 0)
  546.                     != NGX_OK)
  547.                 {
  548.                     return NGX_ERROR;
  549.                 }
  550.             }

  551.             state->stack.nelts--;
  552.         }

  553.         break;

  554.     case NGX_JSON_KEY:

  555.         if (ngx_strlchr(token->data, token->data + token->len, '\\') == NULL) {
  556.             state->current_key = *token;

  557.         } else {
  558.             state->current_key.data = ngx_pstrdup(ctx->pool, token);
  559.             if (state->current_key.data == NULL) {
  560.                 return NGX_ERROR;
  561.             }

  562.             state->current_key.len = token->len;

  563.             if (ngx_json_unescape_string(&state->current_key) != NGX_OK) {
  564.                 return NGX_ERROR;
  565.             }
  566.         }

  567.         node = ngx_http_json_lookup_key(top->node, &state->current_key);
  568.         if (node == NULL) {
  569.             ngx_str_null(&state->current_key);
  570.             state->current_node = NULL;
  571.             return NGX_JSON_SKIP;
  572.         }

  573.         state->current_node = node;

  574.         break;

  575.     case NGX_JSON_VALUE_STRING:
  576.     case NGX_JSON_VALUE_NUMBER:
  577.     case NGX_JSON_VALUE_BOOL:
  578.     case NGX_JSON_VALUE_NULL:

  579.         if (top == NULL) {
  580.             ngx_str_null(&state->current_key);
  581.             state->current_node = NULL;
  582.             break;
  583.         }

  584.         is_member = (state->current_key.data != NULL);
  585.         ngx_str_null(&state->current_key);

  586.         if (is_member) {

  587.             node = state->current_node;
  588.             state->current_node = NULL;

  589.         } else {

  590.             node = ngx_http_json_lookup_index(top->node, top->index);

  591.             ngx_http_json_inc_index(state);
  592.         }

  593.         if (node != NULL && node->ndests > 0) {

  594.             value = *token;

  595.             if (ngx_http_json_store(state, node, &value,
  596.                                           event == NGX_JSON_VALUE_STRING)
  597.                 != NGX_OK)
  598.             {
  599.                 return NGX_ERROR;
  600.             }
  601.         }

  602.         break;
  603.     }

  604.     return NGX_OK;
  605. }


  606. static void
  607. ‌ngx_http_json_inc_index(ngx_http_json_state_t *state)
  608. {
  609.     ngx_http_json_frame_t  *top;

  610.     if (state->stack.nelts == 0) {
  611.         return;
  612.     }

  613.     top = state->stack.elts;
  614.     top += state->stack.nelts - 1;

  615.     if (top->is_array) {
  616.         top->index++;
  617.     }
  618. }


  619. static ngx_http_json_node_t *
  620. ‌ngx_http_json_lookup_key(ngx_http_json_node_t *parent, ngx_str_t *key)
  621. {
  622.     ngx_uint_t             i;
  623.     ngx_http_json_seg_t   *seg;
  624.     ngx_http_json_node_t  *child, *elts;

  625.     if (parent->children == NULL) {
  626.         return NULL;
  627.     }

  628.     elts = parent->children->elts;

  629.     for (i = 0; i < parent->children->nelts; i++) {
  630.         child = &elts[i];
  631.         seg = &child->seg;

  632.         if (!seg->is_index
  633.             && seg->key.len == key->len
  634.             && ngx_memcmp(seg->key.data, key->data, key->len) == 0)
  635.         {
  636.             return child;
  637.         }
  638.     }

  639.     return NULL;
  640. }


  641. static ngx_http_json_node_t *
  642. ‌ngx_http_json_lookup_index(ngx_http_json_node_t *parent, ngx_uint_t index)
  643. {
  644.     ngx_uint_t             i;
  645.     ngx_http_json_seg_t   *seg;
  646.     ngx_http_json_node_t  *child, *elts;

  647.     if (parent->children == NULL) {
  648.         return NULL;
  649.     }

  650.     elts = parent->children->elts;

  651.     for (i = 0; i < parent->children->nelts; i++) {
  652.         child = &elts[i];
  653.         seg = &child->seg;

  654.         if (seg->is_index && seg->index == index) {
  655.             return child;
  656.         }
  657.     }

  658.     return NULL;
  659. }


  660. static ngx_int_t
  661. ‌ngx_http_json_store(ngx_http_json_state_t *state, ngx_http_json_node_t *node,
  662.     ngx_str_t *value, ngx_uint_t unescape)
  663. {
  664.     ngx_str_t                   val;
  665.     ngx_uint_t                  i;
  666.     ngx_http_variable_value_t  *slot;

  667.     if (value->len == 0) {
  668.         val.len = 0;
  669.         val.data = (u_char *) "";

  670.     } else {
  671.         val.data = ngx_pstrdup(state->r->pool, value);
  672.         if (val.data == NULL) {
  673.             return NGX_ERROR;
  674.         }

  675.         val.len = value->len;

  676.         if (unescape && ngx_json_unescape_string(&val) != NGX_OK) {
  677.             return NGX_ERROR;
  678.         }
  679.     }

  680.     for (i = 0; i < node->ndests; i++) {
  681.         slot = &state->values[node->dests[i]];
  682.         slot->valid = 1;
  683.         slot->not_found = 0;
  684.         slot->no_cacheable = 0;
  685.         slot->escape = 0;
  686.         slot->len = val.len;
  687.         slot->data = val.data;
  688.     }

  689.     return NGX_OK;
  690. }


  691. static ngx_int_t
  692. ‌ngx_http_json_push(ngx_http_json_state_t *state, ngx_json_event_e event,
  693.     u_char *start, ngx_http_json_node_t *node)
  694. {
  695.     ngx_http_json_frame_t  *frame;

  696.     frame = ngx_array_push(&state->stack);
  697.     if (frame == NULL) {
  698.         return NGX_ERROR;
  699.     }

  700.     frame->index = 0;
  701.     frame->start = start;
  702.     frame->is_array = (event == NGX_JSON_ARRAY_OPEN);
  703.     frame->node = node;

  704.     return NGX_OK;
  705. }


  706. static void *
  707. ‌ngx_http_json_create_main_conf(ngx_conf_t *cf)
  708. {
  709.     ngx_http_json_main_conf_t  *jmcf;

  710.     jmcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_json_main_conf_t));
  711.     if (jmcf == NULL) {
  712.         return NULL;
  713.     }

  714.     jmcf->max_depth = NGX_CONF_UNSET;

  715.     return jmcf;
  716. }


  717. static char *
  718. ‌ngx_http_json_init_main_conf(ngx_conf_t *cf, void *conf)
  719. {
  720.     ngx_http_json_main_conf_t  *jmcf = conf;

  721.     ngx_conf_init_value(jmcf->max_depth, NGX_HTTP_JSON_DEFAULT_MAX_DEPTH);

  722.     return NGX_CONF_OK;
  723. }