src/core/ngx_json_parse.c - nginx-1.31.7 nginx/ @ 939334eff

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. }


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

  47.     if (len == 0) {
  48.         return NGX_DECLINED;
  49.     }

  50.     if (data == NULL) {
  51.         return NGX_ERROR;
  52.     }

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

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

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

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

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

  70.             continue;
  71.         }

  72.         switch (state) {

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

  77.             p--;
  78.             state = ngx_json_value;
  79.             break;

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

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

  89.                 break;
  90.             }

  91.             /* fall through */

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

  96.             if (*p == '"') {
  97.                 ctx->in_key = 1;
  98.                 start = p + 1;
  99.                 state = ngx_json_string;
  100.                 break;
  101.             }

  102.             return NGX_DECLINED;

  103.         case ngx_json_object_name_separator:
  104.             if (ngx_json_ws(*p)) {
  105.                 break;
  106.             }

  107.             if (*p == ':') {
  108.                 state = ngx_json_value;
  109.                 break;
  110.             }

  111.             return NGX_DECLINED;

  112.         case ngx_json_object_value_separator:
  113.             if (ngx_json_ws(*p)) {
  114.                 break;
  115.             }

  116.             if (*p == ',') {
  117.                 state = ngx_json_object_next;
  118.                 break;
  119.             }

  120.             if (*p == '}') {
  121.                 rc = ngx_json_close(ctx, NGX_JSON_OBJECT_CLOSE, &state, p);
  122.                 if (rc != NGX_OK) {
  123.                     return rc;
  124.                 }

  125.                 break;
  126.             }

  127.             return NGX_DECLINED;

  128.         case ngx_json_array_value_separator:
  129.             if (ngx_json_ws(*p)) {
  130.                 break;
  131.             }

  132.             if (*p == ',') {
  133.                 state = ngx_json_value;
  134.                 break;
  135.             }

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

  141.                 break;
  142.             }

  143.             return NGX_DECLINED;

  144.         case ngx_json_array:
  145.             if (ngx_json_ws(*p)) {
  146.                 break;
  147.             }

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

  153.                 break;
  154.             }

  155.             /* fall through */

  156.         case ngx_json_value:
  157.             if (ngx_json_ws(*p)) {
  158.                 break;
  159.             }

  160.             start = p;

  161.             if (*p == '"') {
  162.                 ctx->in_key = 0;
  163.                 start = p + 1;
  164.                 state = ngx_json_string;
  165.                 break;
  166.             }

  167.             if (*p == '{') {
  168.                 rc = ngx_json_emit(ctx, NGX_JSON_OBJECT_OPEN, p, 1);
  169.                 if (rc != NGX_OK) {
  170.                     return rc;
  171.                 }

  172.                 rc = ngx_json_push_state(ctx, ngx_json_ctx_object);
  173.                 if (rc != NGX_OK) {
  174.                     return rc;
  175.                 }

  176.                 state = ngx_json_object;
  177.                 break;
  178.             }

  179.             if (*p == '[') {
  180.                 rc = ngx_json_emit(ctx, NGX_JSON_ARRAY_OPEN, p, 1);
  181.                 if (rc != NGX_OK) {
  182.                     return rc;
  183.                 }

  184.                 rc = ngx_json_push_state(ctx, ngx_json_ctx_array);
  185.                 if (rc != NGX_OK) {
  186.                     return rc;
  187.                 }

  188.                 state = ngx_json_array;
  189.                 break;
  190.             }

  191.             if (*p == '-') {
  192.                 state = ngx_json_number_minus;
  193.                 break;
  194.             }

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

  199.             if (*p >= '1' && *p <= '9') {
  200.                 state = ngx_json_number_int;
  201.                 break;
  202.             }

  203.             if (*p == 't') {
  204.                 state = ngx_json_true_t;
  205.                 break;
  206.             }

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

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

  215.             return NGX_DECLINED;

  216.         case ngx_json_string:
  217.             if (*p == '"') {

  218.                 if (ctx->in_key) {
  219.                     rc = ngx_json_emit(ctx, NGX_JSON_KEY, start, p - start);
  220.                     if (rc != NGX_OK) {
  221.                         return rc;
  222.                     }

  223.                     ctx->in_key = 0;
  224.                     state = ngx_json_object_name_separator;

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

  231.                     state = ngx_json_after_value(ctx);
  232.                 }

  233.                 break;
  234.             }

  235.             if (*p == '\\') {
  236.                 state = ngx_json_escaped;
  237.                 break;
  238.             }

  239.             if (*p < ' ') {
  240.                 return NGX_DECLINED;
  241.             }

  242.             break;

  243.         case ngx_json_escaped:
  244.             if (*p == '"' || *p == '\\' || *p == '/' || *p == 'b'
  245.                 || *p == 'f' || *p == 'n' || *p == 'r' || *p == 't')
  246.             {
  247.                 state = ngx_json_string;
  248.                 break;
  249.             }

  250.             if (*p == 'u') {
  251.                 ctx->codepoint = 0;
  252.                 ctx->hex_left = 4;
  253.                 state = ngx_json_escaped_hex;
  254.                 break;
  255.             }

  256.             return NGX_DECLINED;

  257.         case ngx_json_escaped_hex:

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

  259.             hd = ngx_json_hex_digit(*p);
  260.             if (hd == NGX_ERROR) {
  261.                 return NGX_DECLINED;
  262.             }

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

  264.             if (--ctx->hex_left > 0) {
  265.                 break;
  266.             }

  267.             if (ctx->codepoint >= 0xD800 && ctx->codepoint <= 0xDBFF) {
  268.                 /* high surrogate - must be followed by \uDC00..\uDFFF */
  269.                 state = ngx_json_surrogate_start;
  270.                 break;
  271.             }

  272.             if (ctx->codepoint >= 0xDC00 && ctx->codepoint <= 0xDFFF) {
  273.                 /* lone low surrogate */
  274.                 return NGX_DECLINED;
  275.             }

  276.             state = ngx_json_string;
  277.             break;

  278.         case ngx_json_surrogate_start:
  279.             if (*p == '\\') {
  280.                 state = ngx_json_surrogate_u;
  281.                 break;
  282.             }

  283.             /* high surrogate not followed by \uXXXX */
  284.             return NGX_DECLINED;

  285.         case ngx_json_surrogate_u:
  286.             if (*p == 'u') {
  287.                 ctx->codepoint = 0;
  288.                 ctx->hex_left = 4;
  289.                 state = ngx_json_surrogate_hex;
  290.                 break;
  291.             }

  292.             /* high surrogate followed by non-\u escape */
  293.             return NGX_DECLINED;

  294.         case ngx_json_surrogate_hex:

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

  296.             hd = ngx_json_hex_digit(*p);
  297.             if (hd == NGX_ERROR) {
  298.                 return NGX_DECLINED;
  299.             }

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

  301.             if (--ctx->hex_left > 0) {
  302.                 break;
  303.             }

  304.             if (ctx->codepoint >= 0xDC00 && ctx->codepoint <= 0xDFFF) {
  305.                 /* valid surrogate pair */
  306.                 state = ngx_json_string;
  307.                 break;
  308.             }

  309.             /* high surrogate not followed by low surrogate */
  310.             return NGX_DECLINED;

  311.         case ngx_json_number_minus:
  312.             if (*p >= '1' && *p <= '9') {
  313.                 state = ngx_json_number_int;
  314.                 break;
  315.             }

  316.             if (*p == '0') {
  317.                 state = ngx_json_number_int_zero;
  318.                 break;
  319.             }

  320.             return NGX_DECLINED;

  321.         case ngx_json_number_int_zero:
  322.             if (*p == '.') {
  323.                 state = ngx_json_number_frac;
  324.                 break;
  325.             }

  326.             if (*p == 'e' || *p == 'E') {
  327.                 /* No sense, but permitted by RFC */
  328.                 state = ngx_json_number_exp;
  329.                 break;
  330.             }

  331.             p--;

  332.             rc = ngx_json_end_number(ctx, start, p + 1, &state);
  333.             if (rc != NGX_OK) {
  334.                 return rc;
  335.             }

  336.             break;

  337.         case ngx_json_number_int:
  338.             if (*p >= '0' && *p <= '9') {
  339.                 break;
  340.             }

  341.             if (*p == '.') {
  342.                 state = ngx_json_number_frac;
  343.                 break;
  344.             }

  345.             if (*p == 'e' || *p == 'E') {
  346.                 /* No sense, but permitted by RFC */
  347.                 state = ngx_json_number_exp;
  348.                 break;
  349.             }

  350.             p--;

  351.             rc = ngx_json_end_number(ctx, start, p + 1, &state);
  352.             if (rc!= NGX_OK) {
  353.                 return rc;
  354.             }

  355.             break;

  356.         case ngx_json_number_frac:
  357.             if (*p >= '0' && *p <= '9') {
  358.                 state = ngx_json_number_frac_digit;
  359.                 break;
  360.             }

  361.             return NGX_DECLINED;

  362.         case ngx_json_number_frac_digit:
  363.             if (*p >= '0' && *p <= '9') {
  364.                 break;
  365.             }

  366.             if (*p == 'e' || *p == 'E') {
  367.                 state = ngx_json_number_exp;
  368.                 break;
  369.             }

  370.             p--;

  371.             rc = ngx_json_end_number(ctx, start, p + 1, &state);
  372.             if (rc != NGX_OK) {
  373.                 return rc;
  374.             }

  375.             break;

  376.         case ngx_json_number_exp:
  377.             if (*p == '-' || *p == '+') {
  378.                 state = ngx_json_number_exp_plusminus;
  379.                 break;
  380.             }

  381.             if (*p >= '0' && *p <= '9') {
  382.                 state = ngx_json_number_exp_digit;
  383.                 break;
  384.             }

  385.             return NGX_DECLINED;

  386.         case ngx_json_number_exp_plusminus:
  387.             if (*p >= '0' && *p <= '9') {
  388.                 state = ngx_json_number_exp_digit;
  389.                 break;
  390.             }

  391.             return NGX_DECLINED;

  392.         case ngx_json_number_exp_digit:
  393.             if (*p >= '0' && *p <= '9') {
  394.                 break;
  395.             }

  396.             p--;

  397.             rc = ngx_json_end_number(ctx, start, p + 1, &state);
  398.             if (rc != NGX_OK) {
  399.                 return rc;
  400.             }

  401.             break;

  402.         case ngx_json_true_t:
  403.             if (*p == 'r') {
  404.                 state = ngx_json_true_tr;
  405.                 break;
  406.             }

  407.             return NGX_DECLINED;

  408.         case ngx_json_true_tr:
  409.             if (*p == 'u') {
  410.                 state = ngx_json_true_tru;
  411.                 break;
  412.             }

  413.             return NGX_DECLINED;

  414.         case ngx_json_true_tru:
  415.             if (*p == 'e') {
  416.                 rc = ngx_json_emit(ctx, NGX_JSON_VALUE_BOOL, start,
  417.                                   p + 1 - start);
  418.                 if (rc != NGX_OK) {
  419.                     return rc;
  420.                 }

  421.                 state = ngx_json_after_value(ctx);
  422.                 break;
  423.             }

  424.             return NGX_DECLINED;

  425.         case ngx_json_false_f:
  426.             if (*p == 'a') {
  427.                 state = ngx_json_false_fa;
  428.                 break;
  429.             }

  430.             return NGX_DECLINED;

  431.         case ngx_json_false_fa:
  432.             if (*p == 'l') {
  433.                 state = ngx_json_false_fal;
  434.                 break;
  435.             }

  436.             return NGX_DECLINED;

  437.         case ngx_json_false_fal:
  438.             if (*p == 's') {
  439.                 state = ngx_json_false_fals;
  440.                 break;
  441.             }

  442.             return NGX_DECLINED;

  443.         case ngx_json_false_fals:
  444.             if (*p == 'e') {
  445.                 rc = ngx_json_emit(ctx, NGX_JSON_VALUE_BOOL, start,
  446.                                   p + 1 - start);
  447.                 if (rc != NGX_OK) {
  448.                     return rc;
  449.                 }

  450.                 state = ngx_json_after_value(ctx);
  451.                 break;
  452.             }

  453.             return NGX_DECLINED;

  454.         case ngx_json_null_n:
  455.             if (*p == 'u') {
  456.                 state = ngx_json_null_nu;
  457.                 break;
  458.             }

  459.             return NGX_DECLINED;

  460.         case ngx_json_null_nu:
  461.             if (*p == 'l') {
  462.                 state = ngx_json_null_nul;
  463.                 break;
  464.             }

  465.             return NGX_DECLINED;

  466.         case ngx_json_null_nul:
  467.             if (*p == 'l') {
  468.                 rc = ngx_json_emit(ctx, NGX_JSON_VALUE_NULL, start,
  469.                                   p + 1 - start);
  470.                 if (rc != NGX_OK) {
  471.                     return rc;
  472.                 }

  473.                 state = ngx_json_after_value(ctx);
  474.                 break;
  475.             }

  476.             return NGX_DECLINED;

  477.         case ngx_json_done:
  478.             if (ngx_json_ws(*p)) {
  479.                 break;
  480.             }

  481.             return NGX_DECLINED;
  482.         }

  483.         skip_depth = ctx->skip_until_depth;
  484.     }

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

  486.     if (ctx->depth == 0
  487.         && (state == ngx_json_number_int_zero
  488.             || state == ngx_json_number_int
  489.             || state == ngx_json_number_frac_digit
  490.             || state == ngx_json_number_exp_digit))
  491.     {
  492.         rc = ngx_json_emit(ctx, NGX_JSON_VALUE_NUMBER, start, last - start);
  493.         if (rc != NGX_OK) {
  494.             return rc;
  495.         }

  496.         state = ngx_json_done;
  497.     }

  498.     ctx->state = state;

  499.     if (state == ngx_json_done) {
  500.         return NGX_OK;
  501.     }

  502.     return NGX_DECLINED;
  503. }


  504. ngx_int_t
  505. ‌ngx_json_parse(ngx_pool_t *pool, ngx_str_t *json, ngx_json_handler_pt handler,
  506.     void *data)
  507. {
  508.     ngx_json_ctx_t  jctx;

  509.     ngx_json_ctx_init(&jctx, pool);

  510.     jctx.data = data;
  511.     jctx.handler = handler;

  512.     return ngx_json_parse_ctx(&jctx, json->data, json->len);
  513. }


  514. static ngx_inline ngx_int_t
  515. ‌ngx_json_end_number(ngx_json_ctx_t *ctx, u_char *start, u_char *end,
  516.     ngx_json_state_e *state)
  517. {
  518.     ngx_int_t  rc;

  519.     rc = ngx_json_emit(ctx, NGX_JSON_VALUE_NUMBER, start, end - start);
  520.     if (rc != NGX_OK) {
  521.         return rc;
  522.     }

  523.     *state = ngx_json_after_value(ctx);

  524.     return NGX_OK;
  525. }


  526. static ngx_inline ngx_int_t
  527. ‌ngx_json_emit(ngx_json_ctx_t *ctx, ngx_json_event_e event, u_char *data,
  528.     size_t len)
  529. {
  530.     ngx_int_t  rc;
  531.     ngx_str_t  token;

  532.     if (ngx_json_skipping(ctx->skip_until_depth)) {
  533.         return NGX_OK;
  534.     }

  535.     if (ctx->handler == NULL) {
  536.         return NGX_OK;
  537.     }

  538.     token.data = data;
  539.     token.len = len;
  540.     rc = ctx->handler(ctx, event, &token);

  541.     if (rc == NGX_JSON_SKIP) {

  542.         /*
  543.          * NGX_JSON_SKIP prunes the rest of the current container.  It is
  544.          * honoured only where it is meaningful:
  545.          *
  546.          *   - OBJECT_OPEN / ARRAY_OPEN: skip the whole container;
  547.          *   - a scalar VALUE_* that is an array element: skip the rest of
  548.          *     that array.
  549.          *
  550.          * A skip requested on a CLOSE, or on an object member value, is
  551.          * ignored: object members are navigated by KEY (use a KEY skip),
  552.          * and a CLOSE fires after the container is already complete.
  553.          */

  554.         switch (event) {

  555.         case NGX_JSON_KEY:
  556.         case NGX_JSON_OBJECT_OPEN:
  557.         case NGX_JSON_ARRAY_OPEN:
  558.             ctx->skip_until_depth = ctx->depth;
  559.             break;

  560.         case NGX_JSON_VALUE_STRING:
  561.         case NGX_JSON_VALUE_NUMBER:
  562.         case NGX_JSON_VALUE_BOOL:
  563.         case NGX_JSON_VALUE_NULL:
  564.             if (ctx->depth > 0
  565.                 && ctx->stack[ctx->depth - 1] == ngx_json_ctx_array
  566.             ) {
  567.                 ctx->skip_until_depth = ctx->depth - 1;
  568.             }
  569.             break;

  570.         default:
  571.             break;
  572.         }

  573.         return NGX_OK;
  574.     }

  575.     return rc;
  576. }


  577. static ngx_inline ngx_json_state_e
  578. ‌ngx_json_after_value(ngx_json_ctx_t *ctx)
  579. {
  580.     if (ctx->depth == 0) {
  581.         return ngx_json_done;
  582.     }

  583.     if (ctx->stack[ctx->depth - 1] == ngx_json_ctx_object) {
  584.         return ngx_json_object_value_separator;
  585.     }

  586.     return ngx_json_array_value_separator;
  587. }


  588. static ngx_inline ngx_int_t
  589. ‌ngx_json_close(ngx_json_ctx_t *ctx, ngx_json_event_e event,
  590.     ngx_json_state_e *state, u_char *p)
  591. {
  592.     ngx_int_t  rc;

  593.     ctx->depth--;

  594.     rc = ngx_json_emit(ctx, event, p, 1);
  595.     if (rc != NGX_OK) {
  596.         return rc;
  597.     }

  598.     *state = ngx_json_after_value(ctx);

  599.     return NGX_OK;
  600. }


  601. static ngx_int_t
  602. ‌ngx_json_push_state(ngx_json_ctx_t *ctx, ngx_json_container_e container)
  603. {
  604.     ngx_json_container_e  *stack;

  605.     if (ctx->depth >= ctx->max_depth) {
  606.         return NGX_DECLINED;
  607.     }

  608.     if (ctx->stack == NULL) {
  609.         stack = ngx_palloc(ctx->pool,
  610.                            ctx->max_depth * sizeof(ngx_json_container_e));
  611.         if (stack == NULL) {
  612.             return NGX_ERROR;
  613.         }

  614.         ctx->stack = stack;
  615.     }

  616.     ctx->stack[ctx->depth] = container;
  617.     ctx->depth++;

  618.     return NGX_OK;
  619. }