LCOV - code coverage report
Current view: top level - flamenco/rpcserver - fd_methods.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 217 0.0 %
Date: 2024-11-13 11:58:15 Functions: 0 7 0.0 %

          Line data    Source code
       1             : #include <stdio.h>
       2             : #include <stdlib.h>
       3             : #include <assert.h>
       4             : #include "fd_methods.h"
       5             : #include "fd_webserver.h"
       6             : #include "../../util/fd_util.h"
       7             : 
       8             : // Read the next json lexical token and report any error to the client
       9             : #define NEXT_TOKEN                                                      \
      10           0 :   do {                                                                  \
      11           0 :     prevpos = lex->pos;                                                 \
      12           0 :     prevtoken = lex->last_tok;                                          \
      13           0 :     token = json_lex_next_token(lex);                                   \
      14           0 :     if (token == JSON_TOKEN_ERROR) return 0;                            \
      15           0 :   } while (0)
      16             : 
      17             : #define UNNEXT_TOKEN                                                    \
      18           0 :   lex->pos = prevpos;                                                   \
      19           0 :   lex->last_tok = prevtoken;
      20             : 
      21             : // Report a json parsing syntax error
      22             : #define SYNTAX_ERROR(format, ...)                                       \
      23           0 :   do {                                                                  \
      24           0 :     json_lex_sprintf(lex, format, __VA_ARGS__);                         \
      25           0 :     return 0;                                                           \
      26           0 :   } while (0)
      27             : 
      28             : // Parse a generic json value. The values argument is used for storing
      29             : // leaf values for later access. path describes the path through the
      30             : // json syntax tree to this value.
      31             : int
      32           0 : json_values_parse(json_lex_state_t* lex, struct json_values* values, struct json_path* path) {
      33           0 :   ulong prevpos;
      34           0 :   long token;
      35           0 :   long prevtoken;
      36             : 
      37             :   // Prepare to update the path to include a new element
      38           0 :   if (path->len == JSON_MAX_PATH)
      39           0 :     SYNTAX_ERROR("json value is too nested at position %lu", lex->pos);
      40           0 :   uint* path_last = &path->elems[path->len ++];
      41             : 
      42           0 :   NEXT_TOKEN;
      43           0 :   switch (token) {
      44           0 :   case JSON_TOKEN_LBRACE: // Start a new json object
      45           0 :     do {
      46           0 :       NEXT_TOKEN;
      47           0 :       if (token == JSON_TOKEN_RBRACE)
      48           0 :         break;
      49           0 :       if (token != JSON_TOKEN_STRING)
      50           0 :         SYNTAX_ERROR("expected string key at position %lu", prevpos);
      51             :       // Translate the key string to a known keyword ID. We only allow
      52             :       // a predetermined set of keys.
      53           0 :       ulong key_sz;
      54           0 :       const char* key = json_lex_get_text(lex, &key_sz);
      55           0 :       long keyid = fd_webserver_json_keyword(key, key_sz);
      56           0 :       if (keyid == KEYW_UNKNOWN)
      57           0 :         SYNTAX_ERROR("unrecognized string key at position %lu", prevpos);
      58             :       // Append to the path
      59           0 :       *path_last = ((JSON_TOKEN_LBRACE<<16) | (uint)keyid);
      60             : 
      61           0 :       NEXT_TOKEN;
      62           0 :       if (token != JSON_TOKEN_COLON)
      63           0 :         SYNTAX_ERROR("expected colon at position %lu", prevpos);
      64             : 
      65             :       // Recursively parse the inner value
      66           0 :       if (!json_values_parse(lex, values, path))
      67           0 :         return 0;
      68             : 
      69           0 :       NEXT_TOKEN;
      70           0 :       if (token == JSON_TOKEN_RBRACE)
      71           0 :         break;
      72           0 :       if (token != JSON_TOKEN_COMMA)
      73           0 :         SYNTAX_ERROR("expected comma at position %lu", prevpos);
      74           0 :     } while(1);
      75           0 :     break;
      76             : 
      77           0 :   case JSON_TOKEN_LBRACKET: { // Start an array
      78           0 :     uint i = 0;
      79           0 :     do {
      80             :       // Append to the path
      81           0 :       *path_last = ((JSON_TOKEN_LBRACKET<<16) | i);
      82             :       // Recursively parse the array element
      83           0 :       if (!json_values_parse(lex, values, path))
      84           0 :         return 0;
      85             : 
      86           0 :       NEXT_TOKEN;
      87           0 :       if (token == JSON_TOKEN_RBRACKET)
      88           0 :         break;
      89           0 :       if (token != JSON_TOKEN_COMMA)
      90           0 :         SYNTAX_ERROR("expected comma at position %lu", prevpos);
      91             : 
      92           0 :       ++i;
      93           0 :     } while(1);
      94           0 :     break;
      95           0 :   }
      96             : 
      97           0 :   case JSON_TOKEN_STRING: {
      98             :     // Append to the path
      99           0 :     *path_last = (JSON_TOKEN_STRING<<16);
     100             :     // Store the leaf value in values, indexed by the current path
     101           0 :     ulong str_sz;
     102           0 :     const char* str = json_lex_get_text(lex, &str_sz);
     103           0 :     json_add_value(values, path, str, str_sz);
     104           0 :     break;
     105           0 :   }
     106             : 
     107           0 :   case JSON_TOKEN_INTEGER: {
     108             :     // Append to the path
     109           0 :     *path_last = (JSON_TOKEN_INTEGER<<16);
     110             :     // Store the leaf value in values, indexed by the current path
     111           0 :     long val = json_lex_as_int(lex);
     112           0 :     json_add_value(values, path, &val, sizeof(val));
     113           0 :     break;
     114           0 :   }
     115             : 
     116           0 :   case JSON_TOKEN_FLOAT: {
     117             :     // Append to the path
     118           0 :     *path_last = (JSON_TOKEN_FLOAT<<16);
     119             :     // Store the leaf value in values, indexed by the current path
     120           0 :     double val = json_lex_as_float(lex);
     121           0 :     json_add_value(values, path, &val, sizeof(val));
     122           0 :     break;
     123           0 :   }
     124             : 
     125           0 :   case JSON_TOKEN_BOOL:
     126             :     // Append to the path
     127           0 :     *path_last = (JSON_TOKEN_BOOL<<16);
     128             :     // Store the leaf value in values, indexed by the current path
     129           0 :     json_add_value(values, path, &lex->last_bool, sizeof(lex->last_bool));
     130           0 :     break;
     131             : 
     132           0 :   case JSON_TOKEN_NULL:
     133             :     // Append to the path
     134           0 :     *path_last = (JSON_TOKEN_NULL<<16);
     135             :     // Store the leaf value in values, indexed by the current path
     136           0 :     json_add_value(values, path, NULL, 0);
     137           0 :     break;
     138             : 
     139           0 :   case JSON_TOKEN_RBRACKET:
     140           0 :     if (prevtoken == JSON_TOKEN_LBRACKET) {
     141             :       /* Empty array */
     142           0 :       UNNEXT_TOKEN;
     143           0 :       break;
     144           0 :     }
     145           0 :     SYNTAX_ERROR("unexpected ']' at position %lu", prevpos);
     146           0 :     break;
     147             : 
     148           0 :   case JSON_TOKEN_RBRACE:
     149           0 :     if (prevtoken == JSON_TOKEN_LBRACE) {
     150             :       /* Empty object */
     151           0 :       UNNEXT_TOKEN;
     152           0 :       break;
     153           0 :     }
     154           0 :     SYNTAX_ERROR("unexpected '}' at position %lu", prevpos);
     155           0 :     break;
     156             : 
     157           0 :   default:
     158           0 :     SYNTAX_ERROR("expected json value at position %lu", prevpos);
     159           0 :   }
     160             : 
     161           0 :   path->len --;
     162           0 :   return 1;
     163           0 : }
     164             : 
     165             : // Initialize a json_values
     166           0 : void json_values_new(struct json_values* values) {
     167           0 :   values->num_values = 0;
     168           0 :   values->buf = values->buf_init;
     169           0 :   values->buf_sz = 0;
     170           0 :   values->buf_alloc = sizeof(values->buf_init);
     171           0 : }
     172             : 
     173             : // Destroy a json_values
     174           0 : void json_values_delete(struct json_values* values) {
     175           0 :   (void)values;
     176           0 : }
     177             : 
     178             : // Add a parsed value to a json_values
     179           0 : void json_add_value(struct json_values* values, struct json_path* path, const void* data, ulong data_sz) {
     180           0 :   if (values->num_values == JSON_MAX_PATHS) {
     181             :     // Ignore when we have too many values. In the actual requests
     182             :     // that we expect to handle, the number of values is modest.
     183           0 :     return;
     184           0 :   }
     185             : 
     186             :   // Get the new buffer size after we add the new data (plus null terminator)
     187           0 :   ulong new_buf_sz = values->buf_sz + data_sz + 1;
     188           0 :   new_buf_sz = ((new_buf_sz + 7UL) & ~7UL); // 8-byte align
     189           0 :   if (new_buf_sz > values->buf_alloc) {
     190             :     // Grow the allocation
     191           0 :     do {
     192           0 :       values->buf_alloc <<= 1;
     193           0 :     } while (new_buf_sz > values->buf_alloc);
     194           0 :     char* newbuf = (char*)fd_scratch_alloc(1, values->buf_alloc);
     195           0 :     fd_memcpy(newbuf, values->buf, values->buf_sz);
     196           0 :     values->buf = newbuf;
     197           0 :   }
     198             : 
     199             :   // Add a new value to the table
     200           0 :   uint i = values->num_values++;
     201           0 :   struct json_path* path2 = &values->values[i].path;
     202           0 :   uint len = path2->len = path->len;
     203           0 :   for (uint j = 0; j < len; ++j)
     204           0 :     path2->elems[j] = path->elems[j];
     205             :   // Copy out the data
     206           0 :   ulong off = values->values[i].data_offset = values->buf_sz;
     207           0 :   values->values[i].data_sz = data_sz;
     208           0 :   fd_memcpy(values->buf + off, data, data_sz);
     209           0 :   values->buf[off + data_sz] = '\0';
     210           0 :   values->buf_sz = new_buf_sz;
     211           0 : }
     212             : 
     213             : // Retrieve a value at a given path. A NULL is returned if the path
     214             : // isn't found
     215           0 : const void* json_get_value(struct json_values* values, const uint* path_elems, uint path_sz, ulong* data_sz) {
     216             :   // Loop through the values
     217           0 :   for (uint i = 0; i < values->num_values; ++i) {
     218             :     // Compare paths
     219           0 :     struct json_path* path = &values->values[i].path;
     220           0 :     if (path->len == path_sz) {
     221           0 :       for (uint j = 0; ; ++j) {
     222           0 :         if (j == path_sz) {
     223           0 :           *data_sz = values->values[i].data_sz;
     224           0 :           return values->buf + values->values[i].data_offset;
     225           0 :         }
     226           0 :         if (path->elems[j] != path_elems[j])
     227           0 :           break;
     228           0 :       }
     229           0 :     }
     230           0 :   }
     231             :   // Not found
     232           0 :   *data_sz = 0;
     233           0 :   return NULL;
     234           0 : }
     235             : 
     236           0 : const void* json_get_value_multi(struct json_values* values, const uint* path_elems, uint path_sz, ulong* data_sz, uint * pos) {
     237             :   // Loop through the values
     238           0 :   for (uint i = *pos; i < values->num_values; ++i) {
     239             :     // Compare paths
     240           0 :     struct json_path* path = &values->values[i].path;
     241           0 :     if (path->len == path_sz) {
     242           0 :       for (uint j = 0; ; ++j) {
     243           0 :         if (j == path_sz) {
     244           0 :           *data_sz = values->values[i].data_sz;
     245           0 :           *pos = j+1;
     246           0 :           return values->buf + values->values[i].data_offset;
     247           0 :         }
     248           0 :         if (path->elems[j] != path_elems[j])
     249           0 :           break;
     250           0 :       }
     251           0 :     }
     252           0 :   }
     253             :   // Not found
     254           0 :   *data_sz = 0;
     255           0 :   *pos = values->num_values;
     256           0 :   return NULL;
     257           0 : }
     258             : 
     259             : // Dump the values and paths to stdout
     260           0 : void json_values_printout(struct json_values* values) {
     261           0 :   for (uint i = 0; i < values->num_values; ++i) {
     262           0 :     struct json_path* path = &values->values[i].path;
     263           0 :     const char* data = values->buf + values->values[i].data_offset;
     264           0 :     ulong data_sz = values->values[i].data_sz;
     265           0 :     for (uint j = 0; j < path->len; ++j) {
     266           0 :       uint e = path->elems[j];
     267           0 :       switch (e >> 16U) {
     268           0 :       case JSON_TOKEN_LBRACE:
     269           0 :         printf(" (object|%s)", un_fd_webserver_json_keyword(e & 0xffffUL));
     270           0 :         break;
     271           0 :       case JSON_TOKEN_LBRACKET:
     272           0 :         printf(" (array|%lu)", e & 0xffffUL);
     273           0 :         break;
     274           0 :       case JSON_TOKEN_STRING:
     275           0 :         printf(" STRING \"");
     276           0 :         fwrite(data, 1, data_sz, stdout);
     277           0 :         printf("\"");
     278           0 :         break;
     279           0 :       case JSON_TOKEN_INTEGER:
     280           0 :         assert(data_sz == sizeof(long));
     281           0 :         printf(" INT %ld", *(long*)data);
     282           0 :         break;
     283           0 :       case JSON_TOKEN_FLOAT:
     284           0 :         assert(data_sz == sizeof(double));
     285           0 :         printf(" FLOAT %g", *(double*)data);
     286           0 :         break;
     287           0 :       case JSON_TOKEN_BOOL:
     288           0 :         assert(data_sz == sizeof(int));
     289           0 :         printf(" BOOL %d", *(int*)data);
     290           0 :         break;
     291           0 :       case JSON_TOKEN_NULL:
     292           0 :         printf(" NULL");
     293           0 :         break;
     294           0 :       }
     295           0 :     }
     296           0 :     printf("\n");
     297           0 :   }
     298           0 : }

Generated by: LCOV version 1.14