src/core/ngx_json_parse.c - nginx-1.31.9 nginx/ @ 2a3a19c6f

Functions defined

Macros defined

Source code


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


  5. /*
  6. * JSON parser. RFC 8259 for the JSON grammar.

  7. * Site http://json.org/ may be useful too.
  8. */


  9. #include <ngx_config.h>
  10. #include <ngx_core.h>
  11. #include <ngx_json_parse.h>


  12. ‌#define NGX_JSON_NOT_SKIPPING  (ngx_uint_t) -1
  13. ‌#define ngx_json_skipping(d)   ((d) != NGX_JSON_NOT_SKIPPING)
  14. ‌#define ngx_json_ws(c)  ((c) == ' ' || (c) == '\t' || (c) == CR || (c) == LF)


  15. static ngx_inline ngx_int_t ngx_json_end_number(ngx_json_ctx_t *ctx,
  16.     u_char *start, u_char *end, ngx_json_state_e *state);
  17. static ngx_inline ngx_int_t ngx_json_emit(ngx_json_ctx_t *ctx,
  18.     ngx_json_event_e event, u_char *data, size_t len);
  19. static ngx_inline ngx_json_state_e ngx_json_after_value(ngx_json_ctx_t *ctx);
  20. static ngx_inline ngx_int_t ngx_json_close(ngx_json_ctx_t *ctx,
  21.     ngx_json_event_e event, ngx_json_state_e *state, u_char *p);
  22. static ngx_int_t ngx_json_push_state(ngx_json_ctx_t *ctx,
  23.     ngx_json_container_e container);


  24. void
  25. ‌ngx_json_ctx_init(ngx_json_ctx_t *ctx, ngx_pool_t *pool)
  26. {
  27.     ctx->state = ngx_json_start;
  28.     ctx->pool = pool;
  29.     ctx->handler = NULL;
  30.     ctx->data = NULL;
  31.     ctx->codepoint = 0;
  32.     ctx->hex_left = 0;

  33.     ctx->depth = 0;
  34.     ctx->skip_until_depth = NGX_JSON_NOT_SKIPPING;
  35.     ctx->max_depth = NGX_JSON_DEFAULT_MAX_DEPTH;

  36.     /* stack is allocated lazily on first push, sized to max_depth */

  37.     ctx->stack = NULL;

  38.     ctx->in_key = 0;
  39.     ctx->escaped = 0;
  40. }


  41. ngx_int_t
  42. ‌ngx_json_parse_ctx(ngx_json_ctx_t *ctx, u_char *data, size_t len)
  43. {
  44.     u_char            *p, *last, *start;
  45.     ngx_int_t          rc, hd;
  46.     ngx_uint_t         skip_depth;
  47.     ngx_json_event_e   event;
  48.     ngx_json_state_e   state;

  49.     if (len == 0) {
  50.         return NGX_DECLINED;
  51.     }

  52.     if (data == NULL) {
  53.         return NGX_ERROR;
  54.     }

  55.     if (ctx->state == ngx_json_done) {
  56.         return NGX_DECLINED;
  57.     }

  58.     last = data + len;
  59.     state = ctx->state;
  60.     skip_depth = ctx->skip_until_depth;
  61.     start = NULL;

  62.     for (p = data; p < last; p++) {

  63.         /* skipping suppresses emission only; the machine still validates */

  64.         if (ngx_json_skipping(skip_depth) && ctx->depth <= skip_depth
  65.             && (state == ngx_json_object_value_separator
  66.                 || state == ngx_json_array_value_separator
  67.                 || state == ngx_json_done))
  68.         {
  69.             skip_depth = NGX_JSON_NOT_SKIPPING;
  70.             ctx->skip_until_depth = NGX_JSON_NOT_SKIPPING;
  71.             p--;

  72.             continue;
  73.         }

  74.         switch (state) {

  75.         case ngx_json_start:
  76.             if (ngx_json_ws(*p)) {
  77.                 break;
  78.             }

  79.             p--;
  80.             state = ngx_json_value;
  81.             break;

  82.         case ngx_json_object:
  83.             if (ngx_json_ws(*p)) {
  84.                 break;
  85.             }

  86.             if (*p == '}') {
  87.                 rc = ngx_json_close(ctx, NGX_JSON_OBJECT_CLOSE, &state, p);
  88.                 if (rc != NGX_OK) {
  89.                     return rc;
  90.                 }

  91.                 break;
  92.             }

  93.             /* fall through */

  94.         case ngx_json_object_next:
  95.             if (ngx_json_ws(*p)) {
  96.                 break;
  97.             }

  98.             if (*p == '"') {
  99.                 ctx->in_key = 1;
  100.                 ctx->escaped = 0;
  101.                 start = p + 1;
  102.                 state = ngx_json_string;
  103.                 break;
  104.             }

  105.             return NGX_DECLINED;

  106.         case ngx_json_object_name_separator:
  107.             if (ngx_json_ws(*p)) {
  108.                 break;
  109.             }

  110.             if (*p == ':') {
  111.                 state = ngx_json_value;
  112.                 break;
  113.             }

  114.             return NGX_DECLINED;

  115.         case ngx_json_object_value_separator:
  116.             if (ngx_json_ws(*p)) {
  117.                 break;
  118.             }

  119.             if (*p == ',') {
  120.                 state = ngx_json_object_next;
  121.                 break;
  122.             }

  123.             if (*p == '}') {
  124.                 rc = ngx_json_close(ctx, NGX_JSON_OBJECT_CLOSE, &state, p);
  125.                 if (rc != NGX_OK) {
  126.                     return rc;
  127.                 }

  128.                 break;
  129.             }

  130.             return NGX_DECLINED;

  131.         case ngx_json_array_value_separator:
  132.             if (ngx_json_ws(*p)) {
  133.                 break;
  134.             }

  135.             if (*p == ',') {
  136.                 state = ngx_json_value;
  137.                 break;
  138.             }

  139.             if (*p == ']') {
  140.                 rc = ngx_json_close(ctx, NGX_JSON_ARRAY_CLOSE, &state, p);
  141.                 if (rc != NGX_OK) {
  142.                     return rc;
  143.                 }

  144.                 break;
  145.             }

  146.             return NGX_DECLINED;

  147.         case ngx_json_array:
  148.             if (ngx_json_ws(*p)) {
  149.                 break;
  150.             }

  151.             if (*p == ']') {
  152.                 rc = ngx_json_close(ctx, NGX_JSON_ARRAY_CLOSE, &state, p);
  153.                 if (rc != NGX_OK) {
  154.                     return rc;
  155.                 }

  156.                 break;
  157.             }

  158.             /* fall through */

  159.         case ngx_json_value:
  160.             if (ngx_json_ws(*p)) {
  161.                 break;
  162.             }

  163.             start = p;

  164.             if (*p == '"') {
  165.                 ctx->in_key = 0;
  166.                 ctx->escaped = 0;
  167.                 start = p + 1;
  168.                 state = ngx_json_string;
  169.                 break;
  170.             }

  171.             if (*p == '{') {
  172.                 rc = ngx_json_emit(ctx, NGX_JSON_OBJECT_OPEN, p, 1);
  173.                 if (rc != NGX_OK) {
  174.                     return rc;
  175.                 }

  176.                 rc = ngx_json_push_state(ctx, ngx_json_ctx_object);
  177.                 if (rc != NGX_OK) {
  178.                     return rc;
  179.                 }

  180.                 state = ngx_json_object;
  181.                 break;
  182.             }

  183.             if (*p == '[') {
  184.                 rc = ngx_json_emit(ctx, NGX_JSON_ARRAY_OPEN, p, 1);
  185.                 if (rc != NGX_OK) {
  186.                     return rc;
  187.                 }

  188.                 rc = ngx_json_push_state(ctx, ngx_json_ctx_array);
  189.                 if (rc != NGX_OK) {
  190.                     return rc;
  191.                 }

  192.                 state = ngx_json_array;
  193.                 break;
  194.             }

  195.             if (*p == '-') {
  196.                 state = ngx_json_number_minus;
  197.                 break;
  198.             }

  199.             if (*p == '0') {
  200.                 state = ngx_json_number_int_zero;
  201.                 break;
  202.             }

  203.             if (*p >= '1' && *p <= '9') {
  204.                 state = ngx_json_number_int;
  205.                 break;
  206.             }

  207.             if (*p == 't') {
  208.                 state = ngx_json_true_t;
  209.                 break;
  210.             }

  211.             if (*p == 'f') {
  212.                 state = ngx_json_false_f;
  213.                 break;
  214.             }

  215.             if (*p == 'n') {
  216.                 state = ngx_json_null_n;
  217.                 break;
  218.             }

  219.             return NGX_DECLINED;

  220.         case ngx_json_string:
  221.             if (*p == '"') {

  222.                 if (ctx->in_key) {
  223.                     event = ctx->escaped ? NGX_JSON_KEY_ESCAPED
  224.                                          : NGX_JSON_KEY;

  225.                     rc = ngx_json_emit(ctx, event, start, p - start);
  226.                     if (rc != NGX_OK) {
  227.                         return rc;
  228.                     }

  229.                     ctx->in_key = 0;
  230.                     state = ngx_json_object_name_separator;

  231.                 } else {
  232.                     event = ctx->escaped ? NGX_JSON_VALUE_STRING_ESCAPED
  233.                                          : NGX_JSON_VALUE_STRING;

  234.                     rc = ngx_json_emit(ctx, event, start, p - start);
  235.                     if (rc != NGX_OK) {
  236.                         return rc;
  237.                     }

  238.                     state = ngx_json_after_value(ctx);
  239.                 }

  240.                 break;
  241.             }

  242.             if (*p == '\\') {
  243.                 ctx->escaped = 1;
  244.                 state = ngx_json_escaped;
  245.                 break;
  246.             }

  247.             if (*p < ' ') {
  248.                 return NGX_DECLINED;
  249.             }

  250.             break;

  251.         case ngx_json_escaped:
  252.             if (*p == '"' || *p == '\\' || *p == '/' || *p == 'b'
  253.                 || *p == 'f' || *p == 'n' || *p == 'r' || *p == 't')
  254.             {
  255.                 state = ngx_json_string;
  256.                 break;
  257.             }

  258.             if (*p == 'u') {
  259.                 ctx->codepoint = 0;
  260.                 ctx->hex_left = 4;
  261.                 state = ngx_json_escaped_hex;
  262.                 break;
  263.             }

  264.             return NGX_DECLINED;

  265.         case ngx_json_escaped_hex:

  266.             /* accumulate the four hex digits of the first \uXXXX escape */

  267.             hd = ngx_json_hex_digit(*p);
  268.             if (hd == NGX_ERROR) {
  269.                 return NGX_DECLINED;
  270.             }

  271.             ctx->codepoint = (ctx->codepoint << 4) | (uint32_t) hd;

  272.             if (--ctx->hex_left > 0) {
  273.                 break;
  274.             }

  275.             if (ctx->codepoint >= 0xD800 && ctx->codepoint <= 0xDBFF) {
  276.                 /* high surrogate - must be followed by \uDC00..\uDFFF */
  277.                 state = ngx_json_surrogate_start;
  278.                 break;
  279.             }

  280.             if (ctx->codepoint >= 0xDC00 && ctx->codepoint <= 0xDFFF) {
  281.                 /* lone low surrogate */
  282.                 return NGX_DECLINED;
  283.             }

  284.             state = ngx_json_string;
  285.             break;

  286.         case ngx_json_surrogate_start:
  287.             if (*p == '\\') {
  288.                 state = ngx_json_surrogate_u;
  289.                 break;
  290.             }

  291.             /* high surrogate not followed by \uXXXX */
  292.             return NGX_DECLINED;

  293.         case ngx_json_surrogate_u:
  294.             if (*p == 'u') {
  295.                 ctx->codepoint = 0;
  296.                 ctx->hex_left = 4;
  297.                 state = ngx_json_surrogate_hex;
  298.                 break;
  299.             }

  300.             /* high surrogate followed by non-\u escape */
  301.             return NGX_DECLINED;

  302.         case ngx_json_surrogate_hex:

  303.             /* accumulate the four hex digits of the low \uXXXX escape */

  304.             hd = ngx_json_hex_digit(*p);
  305.             if (hd == NGX_ERROR) {
  306.                 return NGX_DECLINED;
  307.             }

  308.             ctx->codepoint = (ctx->codepoint << 4) | (uint32_t) hd;

  309.             if (--ctx->hex_left > 0) {
  310.                 break;
  311.             }

  312.             if (ctx->codepoint >= 0xDC00 && ctx->codepoint <= 0xDFFF) {
  313.                 /* valid surrogate pair */
  314.                 state = ngx_json_string;
  315.                 break;
  316.             }

  317.             /* high surrogate not followed by low surrogate */
  318.             return NGX_DECLINED;

  319.         case ngx_json_number_minus:
  320.             if (*p >= '1' && *p <= '9') {
  321.                 state = ngx_json_number_int;
  322.                 break;
  323.             }

  324.             if (*p == '0') {
  325.                 state = ngx_json_number_int_zero;
  326.                 break;
  327.             }

  328.             return NGX_DECLINED;

  329.         case ngx_json_number_int_zero:
  330.             if (*p == '.') {
  331.                 state = ngx_json_number_frac;
  332.                 break;
  333.             }

  334.             if (*p == 'e' || *p == 'E') {
  335.                 /* No sense, but permitted by RFC */
  336.                 state = ngx_json_number_exp;
  337.                 break;
  338.             }

  339.             p--;

  340.             rc = ngx_json_end_number(ctx, start, p + 1, &state);
  341.             if (rc != NGX_OK) {
  342.                 return rc;
  343.             }

  344.             break;

  345.         case ngx_json_number_int:
  346.             if (*p >= '0' && *p <= '9') {
  347.                 break;
  348.             }

  349.             if (*p == '.') {
  350.                 state = ngx_json_number_frac;
  351.                 break;
  352.             }

  353.             if (*p == 'e' || *p == 'E') {
  354.                 /* No sense, but permitted by RFC */
  355.                 state = ngx_json_number_exp;
  356.                 break;
  357.             }

  358.             p--;

  359.             rc = ngx_json_end_number(ctx, start, p + 1, &state);
  360.             if (rc!= NGX_OK) {
  361.                 return rc;
  362.             }

  363.             break;

  364.         case ngx_json_number_frac:
  365.             if (*p >= '0' && *p <= '9') {
  366.                 state = ngx_json_number_frac_digit;
  367.                 break;
  368.             }

  369.             return NGX_DECLINED;

  370.         case ngx_json_number_frac_digit:
  371.             if (*p >= '0' && *p <= '9') {
  372.                 break;
  373.             }

  374.             if (*p == 'e' || *p == 'E') {
  375.                 state = ngx_json_number_exp;
  376.                 break;
  377.             }

  378.             p--;

  379.             rc = ngx_json_end_number(ctx, start, p + 1, &state);
  380.             if (rc != NGX_OK) {
  381.                 return rc;
  382.             }

  383.             break;

  384.         case ngx_json_number_exp:
  385.             if (*p == '-' || *p == '+') {
  386.                 state = ngx_json_number_exp_plusminus;
  387.                 break;
  388.             }

  389.             if (*p >= '0' && *p <= '9') {
  390.                 state = ngx_json_number_exp_digit;
  391.                 break;
  392.             }

  393.             return NGX_DECLINED;

  394.         case ngx_json_number_exp_plusminus:
  395.             if (*p >= '0' && *p <= '9') {
  396.                 state = ngx_json_number_exp_digit;
  397.                 break;
  398.             }

  399.             return NGX_DECLINED;

  400.         case ngx_json_number_exp_digit:
  401.             if (*p >= '0' && *p <= '9') {
  402.                 break;
  403.             }

  404.             p--;

  405.             rc = ngx_json_end_number(ctx, start, p + 1, &state);
  406.             if (rc != NGX_OK) {
  407.                 return rc;
  408.             }

  409.             break;

  410.         case ngx_json_true_t:
  411.             if (*p == 'r') {
  412.                 state = ngx_json_true_tr;
  413.                 break;
  414.             }

  415.             return NGX_DECLINED;

  416.         case ngx_json_true_tr:
  417.             if (*p == 'u') {
  418.                 state = ngx_json_true_tru;
  419.                 break;
  420.             }

  421.             return NGX_DECLINED;

  422.         case ngx_json_true_tru:
  423.             if (*p == 'e') {
  424.                 rc = ngx_json_emit(ctx, NGX_JSON_VALUE_BOOL, start,
  425.                                   p + 1 - start);
  426.                 if (rc != NGX_OK) {
  427.                     return rc;
  428.                 }

  429.                 state = ngx_json_after_value(ctx);
  430.                 break;
  431.             }

  432.             return NGX_DECLINED;

  433.         case ngx_json_false_f:
  434.             if (*p == 'a') {
  435.                 state = ngx_json_false_fa;
  436.                 break;
  437.             }

  438.             return NGX_DECLINED;

  439.         case ngx_json_false_fa:
  440.             if (*p == 'l') {
  441.                 state = ngx_json_false_fal;
  442.                 break;
  443.             }

  444.             return NGX_DECLINED;

  445.         case ngx_json_false_fal:
  446.             if (*p == 's') {
  447.                 state = ngx_json_false_fals;
  448.                 break;
  449.             }

  450.             return NGX_DECLINED;

  451.         case ngx_json_false_fals:
  452.             if (*p == 'e') {
  453.                 rc = ngx_json_emit(ctx, NGX_JSON_VALUE_BOOL, start,
  454.                                   p + 1 - start);
  455.                 if (rc != NGX_OK) {
  456.                     return rc;
  457.                 }

  458.                 state = ngx_json_after_value(ctx);
  459.                 break;
  460.             }

  461.             return NGX_DECLINED;

  462.         case ngx_json_null_n:
  463.             if (*p == 'u') {
  464.                 state = ngx_json_null_nu;
  465.                 break;
  466.             }

  467.             return NGX_DECLINED;

  468.         case ngx_json_null_nu:
  469.             if (*p == 'l') {
  470.                 state = ngx_json_null_nul;
  471.                 break;
  472.             }

  473.             return NGX_DECLINED;

  474.         case ngx_json_null_nul:
  475.             if (*p == 'l') {
  476.                 rc = ngx_json_emit(ctx, NGX_JSON_VALUE_NULL, start,
  477.                                   p + 1 - start);
  478.                 if (rc != NGX_OK) {
  479.                     return rc;
  480.                 }

  481.                 state = ngx_json_after_value(ctx);
  482.                 break;
  483.             }

  484.             return NGX_DECLINED;

  485.         case ngx_json_done:
  486.             if (ngx_json_ws(*p)) {
  487.                 break;
  488.             }

  489.             return NGX_DECLINED;
  490.         }

  491.         skip_depth = ctx->skip_until_depth;
  492.     }

  493.     /* a bare top-level number is not self-delimited; emit it at end of input */

  494.     if (ctx->depth == 0
  495.         && (state == ngx_json_number_int_zero
  496.             || state == ngx_json_number_int
  497.             || state == ngx_json_number_frac_digit
  498.             || state == ngx_json_number_exp_digit))
  499.     {
  500.         rc = ngx_json_emit(ctx, NGX_JSON_VALUE_NUMBER, start, last - start);
  501.         if (rc != NGX_OK) {
  502.             return rc;
  503.         }

  504.         state = ngx_json_done;
  505.     }

  506.     ctx->state = state;

  507.     if (state == ngx_json_done) {
  508.         return NGX_OK;
  509.     }

  510.     return NGX_DECLINED;
  511. }


  512. ngx_int_t
  513. ‌ngx_json_parse(ngx_pool_t *pool, ngx_str_t *json, ngx_json_handler_pt handler,
  514.     void *data)
  515. {
  516.     ngx_json_ctx_t  jctx;

  517.     ngx_json_ctx_init(&jctx, pool);

  518.     jctx.data = data;
  519.     jctx.handler = handler;

  520.     return ngx_json_parse_ctx(&jctx, json->data, json->len);
  521. }


  522. static ngx_inline ngx_int_t
  523. ‌ngx_json_end_number(ngx_json_ctx_t *ctx, u_char *start, u_char *end,
  524.     ngx_json_state_e *state)
  525. {
  526.     ngx_int_t  rc;

  527.     rc = ngx_json_emit(ctx, NGX_JSON_VALUE_NUMBER, start, end - start);
  528.     if (rc != NGX_OK) {
  529.         return rc;
  530.     }

  531.     *state = ngx_json_after_value(ctx);

  532.     return NGX_OK;
  533. }


  534. static ngx_inline ngx_int_t
  535. ‌ngx_json_emit(ngx_json_ctx_t *ctx, ngx_json_event_e event, u_char *data,
  536.     size_t len)
  537. {
  538.     ngx_int_t  rc;
  539.     ngx_str_t  token;

  540.     if (ngx_json_skipping(ctx->skip_until_depth)) {
  541.         return NGX_OK;
  542.     }

  543.     if (ctx->handler == NULL) {
  544.         return NGX_OK;
  545.     }

  546.     token.data = data;
  547.     token.len = len;
  548.     rc = ctx->handler(ctx, event, &token);

  549.     if (rc == NGX_JSON_SKIP) {

  550.         /*
  551.          * NGX_JSON_SKIP prunes the rest of the current container.  It is
  552.          * honoured only where it is meaningful:
  553.          *
  554.          *   - OBJECT_OPEN / ARRAY_OPEN: skip the whole container;
  555.          *   - a scalar VALUE_* that is an array element: skip the rest of
  556.          *     that array.
  557.          *
  558.          * A skip requested on a CLOSE, or on an object member value, is
  559.          * ignored: object members are navigated by KEY (use a KEY skip),
  560.          * and a CLOSE fires after the container is already complete.
  561.          */

  562.         switch (event) {

  563.         case NGX_JSON_KEY:
  564.         case NGX_JSON_KEY_ESCAPED:
  565.         case NGX_JSON_OBJECT_OPEN:
  566.         case NGX_JSON_ARRAY_OPEN:
  567.             ctx->skip_until_depth = ctx->depth;
  568.             break;

  569.         case NGX_JSON_VALUE_STRING:
  570.         case NGX_JSON_VALUE_STRING_ESCAPED:
  571.         case NGX_JSON_VALUE_NUMBER:
  572.         case NGX_JSON_VALUE_BOOL:
  573.         case NGX_JSON_VALUE_NULL:
  574.             if (ctx->depth > 0
  575.                 && ctx->stack[ctx->depth - 1] == ngx_json_ctx_array
  576.             ) {
  577.                 ctx->skip_until_depth = ctx->depth - 1;
  578.             }
  579.             break;

  580.         default:
  581.             break;
  582.         }

  583.         return NGX_OK;
  584.     }

  585.     return rc;
  586. }


  587. static ngx_inline ngx_json_state_e
  588. ‌ngx_json_after_value(ngx_json_ctx_t *ctx)
  589. {
  590.     if (ctx->depth == 0) {
  591.         return ngx_json_done;
  592.     }

  593.     if (ctx->stack[ctx->depth - 1] == ngx_json_ctx_object) {
  594.         return ngx_json_object_value_separator;
  595.     }

  596.     return ngx_json_array_value_separator;
  597. }


  598. static ngx_inline ngx_int_t
  599. ‌ngx_json_close(ngx_json_ctx_t *ctx, ngx_json_event_e event,
  600.     ngx_json_state_e *state, u_char *p)
  601. {
  602.     ngx_int_t  rc;

  603.     ctx->depth--;

  604.     rc = ngx_json_emit(ctx, event, p, 1);
  605.     if (rc != NGX_OK) {
  606.         return rc;
  607.     }

  608.     *state = ngx_json_after_value(ctx);

  609.     return NGX_OK;
  610. }


  611. static ngx_int_t
  612. ‌ngx_json_push_state(ngx_json_ctx_t *ctx, ngx_json_container_e container)
  613. {
  614.     ngx_json_container_e  *stack;

  615.     if (ctx->depth >= ctx->max_depth) {
  616.         return NGX_DECLINED;
  617.     }

  618.     if (ctx->stack == NULL) {
  619.         stack = ngx_palloc(ctx->pool,
  620.                            ctx->max_depth * sizeof(ngx_json_container_e));
  621.         if (stack == NULL) {
  622.             return NGX_ERROR;
  623.         }

  624.         ctx->stack = stack;
  625.     }

  626.     ctx->stack[ctx->depth] = container;
  627.     ctx->depth++;

  628.     return NGX_OK;
  629. }