1106Svbart@nginx.com 2106Svbart@nginx.com /* 3106Svbart@nginx.com * Copyright (C) Igor Sysoev 4106Svbart@nginx.com * Copyright (C) Valentin V. Bartenev 5106Svbart@nginx.com * Copyright (C) NGINX, Inc. 6106Svbart@nginx.com */ 7106Svbart@nginx.com 8106Svbart@nginx.com #include <nxt_main.h> 9106Svbart@nginx.com #include <nxt_conf.h> 10*1439Svbart@nginx.com 11*1439Svbart@nginx.com #include <float.h> 12106Svbart@nginx.com #include <math.h> 13106Svbart@nginx.com 14106Svbart@nginx.com 15106Svbart@nginx.com #define NXT_CONF_MAX_SHORT_STRING 14 16*1439Svbart@nginx.com #define NXT_CONF_MAX_NUMBER_LEN 14 17172Svbart@nginx.com #define NXT_CONF_MAX_STRING NXT_INT32_T_MAX 18106Svbart@nginx.com 191174Svbart@nginx.com #define NXT_CONF_MAX_TOKEN_LEN 256 201174Svbart@nginx.com 21106Svbart@nginx.com 22106Svbart@nginx.com typedef enum { 23116Svbart@nginx.com NXT_CONF_VALUE_NULL = 0, 24116Svbart@nginx.com NXT_CONF_VALUE_BOOLEAN, 25116Svbart@nginx.com NXT_CONF_VALUE_INTEGER, 26116Svbart@nginx.com NXT_CONF_VALUE_NUMBER, 27116Svbart@nginx.com NXT_CONF_VALUE_SHORT_STRING, 28116Svbart@nginx.com NXT_CONF_VALUE_STRING, 29116Svbart@nginx.com NXT_CONF_VALUE_ARRAY, 30116Svbart@nginx.com NXT_CONF_VALUE_OBJECT, 31116Svbart@nginx.com } nxt_conf_value_type_t; 32106Svbart@nginx.com 33106Svbart@nginx.com 34106Svbart@nginx.com typedef enum { 35106Svbart@nginx.com NXT_CONF_OP_PASS = 0, 36106Svbart@nginx.com NXT_CONF_OP_CREATE, 37106Svbart@nginx.com NXT_CONF_OP_REPLACE, 38106Svbart@nginx.com NXT_CONF_OP_DELETE, 39106Svbart@nginx.com } nxt_conf_op_action_t; 40106Svbart@nginx.com 41106Svbart@nginx.com 42106Svbart@nginx.com typedef struct nxt_conf_array_s nxt_conf_array_t; 43106Svbart@nginx.com typedef struct nxt_conf_object_s nxt_conf_object_t; 44106Svbart@nginx.com 45106Svbart@nginx.com 46180Smax.romanov@nginx.com struct nxt_conf_value_s { 47187Smax.romanov@nginx.com union { 48171Svbart@nginx.com uint8_t boolean; /* 1 bit. */ 49*1439Svbart@nginx.com u_char number[NXT_CONF_MAX_NUMBER_LEN + 1];; 50173Svbart@nginx.com 51173Svbart@nginx.com struct { 52208Svbart@nginx.com u_char start[NXT_CONF_MAX_SHORT_STRING]; 53173Svbart@nginx.com uint8_t length; 54173Svbart@nginx.com } str; 55172Svbart@nginx.com 56187Smax.romanov@nginx.com struct { 57172Svbart@nginx.com u_char *start; 58172Svbart@nginx.com uint32_t length; 59187Smax.romanov@nginx.com } nxt_packed string; 60172Svbart@nginx.com 61106Svbart@nginx.com nxt_conf_array_t *array; 62106Svbart@nginx.com nxt_conf_object_t *object; 63187Smax.romanov@nginx.com } nxt_packed u; 64106Svbart@nginx.com 65171Svbart@nginx.com uint8_t type; /* 3 bits. */ 66180Smax.romanov@nginx.com } nxt_aligned(8); 67106Svbart@nginx.com 68106Svbart@nginx.com 69106Svbart@nginx.com struct nxt_conf_array_s { 70106Svbart@nginx.com nxt_uint_t count; 71106Svbart@nginx.com nxt_conf_value_t elements[]; 72106Svbart@nginx.com }; 73106Svbart@nginx.com 74106Svbart@nginx.com 75106Svbart@nginx.com typedef struct { 76106Svbart@nginx.com nxt_conf_value_t name; 77106Svbart@nginx.com nxt_conf_value_t value; 78106Svbart@nginx.com } nxt_conf_object_member_t; 79106Svbart@nginx.com 80106Svbart@nginx.com 81106Svbart@nginx.com struct nxt_conf_object_s { 82106Svbart@nginx.com nxt_uint_t count; 83106Svbart@nginx.com nxt_conf_object_member_t members[]; 84106Svbart@nginx.com }; 85106Svbart@nginx.com 86106Svbart@nginx.com 87106Svbart@nginx.com struct nxt_conf_op_s { 88106Svbart@nginx.com uint32_t index; 89106Svbart@nginx.com uint32_t action; /* nxt_conf_op_action_t */ 90106Svbart@nginx.com void *ctx; 91106Svbart@nginx.com }; 92106Svbart@nginx.com 93106Svbart@nginx.com 941174Svbart@nginx.com typedef struct { 951174Svbart@nginx.com u_char *start; 961174Svbart@nginx.com u_char *end; 971174Svbart@nginx.com nxt_bool_t last; 981174Svbart@nginx.com u_char buf[NXT_CONF_MAX_TOKEN_LEN]; 991174Svbart@nginx.com } nxt_conf_path_parse_t; 1001174Svbart@nginx.com 1011174Svbart@nginx.com 1021174Svbart@nginx.com static nxt_int_t nxt_conf_path_next_token(nxt_conf_path_parse_t *parse, 1031174Svbart@nginx.com nxt_str_t *token); 1041174Svbart@nginx.com 105106Svbart@nginx.com static u_char *nxt_conf_json_skip_space(u_char *start, u_char *end); 106106Svbart@nginx.com static u_char *nxt_conf_json_parse_value(nxt_mp_t *mp, nxt_conf_value_t *value, 107208Svbart@nginx.com u_char *start, u_char *end, nxt_conf_json_error_t *error); 108106Svbart@nginx.com static u_char *nxt_conf_json_parse_object(nxt_mp_t *mp, nxt_conf_value_t *value, 109208Svbart@nginx.com u_char *start, u_char *end, nxt_conf_json_error_t *error); 110106Svbart@nginx.com static nxt_int_t nxt_conf_object_hash_add(nxt_mp_t *mp, 111106Svbart@nginx.com nxt_lvlhsh_t *lvlhsh, nxt_conf_object_member_t *member); 112106Svbart@nginx.com static nxt_int_t nxt_conf_object_hash_test(nxt_lvlhsh_query_t *lhq, 113106Svbart@nginx.com void *data); 114106Svbart@nginx.com static void *nxt_conf_object_hash_alloc(void *data, size_t size); 115106Svbart@nginx.com static void nxt_conf_object_hash_free(void *data, void *p); 116106Svbart@nginx.com static u_char *nxt_conf_json_parse_array(nxt_mp_t *mp, nxt_conf_value_t *value, 117208Svbart@nginx.com u_char *start, u_char *end, nxt_conf_json_error_t *error); 118106Svbart@nginx.com static u_char *nxt_conf_json_parse_string(nxt_mp_t *mp, nxt_conf_value_t *value, 119208Svbart@nginx.com u_char *start, u_char *end, nxt_conf_json_error_t *error); 120106Svbart@nginx.com static u_char *nxt_conf_json_parse_number(nxt_mp_t *mp, nxt_conf_value_t *value, 121208Svbart@nginx.com u_char *start, u_char *end, nxt_conf_json_error_t *error); 122208Svbart@nginx.com static void nxt_conf_json_parse_error(nxt_conf_json_error_t *error, u_char *pos, 123208Svbart@nginx.com const char *detail); 124106Svbart@nginx.com 125106Svbart@nginx.com static nxt_int_t nxt_conf_copy_value(nxt_mp_t *mp, nxt_conf_op_t *op, 126106Svbart@nginx.com nxt_conf_value_t *dst, nxt_conf_value_t *src); 1271048Svbart@nginx.com static nxt_int_t nxt_conf_copy_array(nxt_mp_t *mp, nxt_conf_op_t *op, 1281048Svbart@nginx.com nxt_conf_value_t *dst, nxt_conf_value_t *src); 129106Svbart@nginx.com static nxt_int_t nxt_conf_copy_object(nxt_mp_t *mp, nxt_conf_op_t *op, 130106Svbart@nginx.com nxt_conf_value_t *dst, nxt_conf_value_t *src); 131106Svbart@nginx.com 132106Svbart@nginx.com static size_t nxt_conf_json_string_length(nxt_conf_value_t *value); 133106Svbart@nginx.com static u_char *nxt_conf_json_print_string(u_char *p, nxt_conf_value_t *value); 134106Svbart@nginx.com static size_t nxt_conf_json_array_length(nxt_conf_value_t *value, 135106Svbart@nginx.com nxt_conf_json_pretty_t *pretty); 136106Svbart@nginx.com static u_char *nxt_conf_json_print_array(u_char *p, nxt_conf_value_t *value, 137106Svbart@nginx.com nxt_conf_json_pretty_t *pretty); 138106Svbart@nginx.com static size_t nxt_conf_json_object_length(nxt_conf_value_t *value, 139106Svbart@nginx.com nxt_conf_json_pretty_t *pretty); 140106Svbart@nginx.com static u_char *nxt_conf_json_print_object(u_char *p, nxt_conf_value_t *value, 141106Svbart@nginx.com nxt_conf_json_pretty_t *pretty); 142106Svbart@nginx.com 143106Svbart@nginx.com static size_t nxt_conf_json_escape_length(u_char *p, size_t size); 144106Svbart@nginx.com static u_char *nxt_conf_json_escape(u_char *dst, u_char *src, size_t size); 145106Svbart@nginx.com 146106Svbart@nginx.com 147106Svbart@nginx.com #define nxt_conf_json_newline(p) \ 148106Svbart@nginx.com ((p)[0] = '\r', (p)[1] = '\n', (p) + 2) 149106Svbart@nginx.com 150106Svbart@nginx.com 151106Svbart@nginx.com nxt_inline u_char * 152106Svbart@nginx.com nxt_conf_json_indentation(u_char *p, uint32_t level) 153106Svbart@nginx.com { 154106Svbart@nginx.com while (level) { 155106Svbart@nginx.com *p++ = '\t'; 156106Svbart@nginx.com level--; 157106Svbart@nginx.com } 158106Svbart@nginx.com 159106Svbart@nginx.com return p; 160106Svbart@nginx.com } 161106Svbart@nginx.com 162106Svbart@nginx.com 163121Svbart@nginx.com void 164106Svbart@nginx.com nxt_conf_get_string(nxt_conf_value_t *value, nxt_str_t *str) 165106Svbart@nginx.com { 166116Svbart@nginx.com if (value->type == NXT_CONF_VALUE_SHORT_STRING) { 167173Svbart@nginx.com str->length = value->u.str.length; 168173Svbart@nginx.com str->start = value->u.str.start; 169106Svbart@nginx.com 170106Svbart@nginx.com } else { 171172Svbart@nginx.com str->length = value->u.string.length; 172172Svbart@nginx.com str->start = value->u.string.start; 173106Svbart@nginx.com } 174106Svbart@nginx.com } 175106Svbart@nginx.com 176106Svbart@nginx.com 177773Svbart@nginx.com void 178773Svbart@nginx.com nxt_conf_set_string(nxt_conf_value_t *value, nxt_str_t *str) 179773Svbart@nginx.com { 180773Svbart@nginx.com if (str->length > NXT_CONF_MAX_SHORT_STRING) { 181773Svbart@nginx.com value->type = NXT_CONF_VALUE_STRING; 182773Svbart@nginx.com value->u.string.length = str->length; 183773Svbart@nginx.com value->u.string.start = str->start; 184773Svbart@nginx.com 185773Svbart@nginx.com } else { 186773Svbart@nginx.com value->type = NXT_CONF_VALUE_SHORT_STRING; 187773Svbart@nginx.com value->u.str.length = str->length; 188773Svbart@nginx.com 189773Svbart@nginx.com nxt_memcpy(value->u.str.start, str->start, str->length); 190773Svbart@nginx.com } 191773Svbart@nginx.com } 192773Svbart@nginx.com 193773Svbart@nginx.com 194774Svbart@nginx.com nxt_int_t 195774Svbart@nginx.com nxt_conf_set_string_dup(nxt_conf_value_t *value, nxt_mp_t *mp, nxt_str_t *str) 196774Svbart@nginx.com { 197774Svbart@nginx.com nxt_str_t tmp, *ptr; 198774Svbart@nginx.com 199774Svbart@nginx.com if (str->length > NXT_CONF_MAX_SHORT_STRING) { 200774Svbart@nginx.com value->type = NXT_CONF_VALUE_STRING; 201774Svbart@nginx.com 202774Svbart@nginx.com ptr = nxt_str_dup(mp, &tmp, str); 203774Svbart@nginx.com if (nxt_slow_path(ptr == NULL)) { 204774Svbart@nginx.com return NXT_ERROR; 205774Svbart@nginx.com } 206774Svbart@nginx.com 207774Svbart@nginx.com value->u.string.length = tmp.length; 208774Svbart@nginx.com value->u.string.start = tmp.start; 209774Svbart@nginx.com 210774Svbart@nginx.com } else { 211774Svbart@nginx.com value->type = NXT_CONF_VALUE_SHORT_STRING; 212774Svbart@nginx.com value->u.str.length = str->length; 213774Svbart@nginx.com 214774Svbart@nginx.com nxt_memcpy(value->u.str.start, str->start, str->length); 215774Svbart@nginx.com } 216774Svbart@nginx.com 217774Svbart@nginx.com return NXT_OK; 218774Svbart@nginx.com } 219774Svbart@nginx.com 220774Svbart@nginx.com 221*1439Svbart@nginx.com double 222*1439Svbart@nginx.com nxt_conf_get_number(nxt_conf_value_t *value) 223507Smax.romanov@nginx.com { 224*1439Svbart@nginx.com return nxt_strtod(value->u.number, NULL); 225507Smax.romanov@nginx.com } 226507Smax.romanov@nginx.com 227507Smax.romanov@nginx.com 2281236St.nateldemoura@f5.com uint8_t 2291236St.nateldemoura@f5.com nxt_conf_get_boolean(nxt_conf_value_t *value) 2301236St.nateldemoura@f5.com { 2311236St.nateldemoura@f5.com return value->u.boolean; 2321236St.nateldemoura@f5.com } 2331236St.nateldemoura@f5.com 2341236St.nateldemoura@f5.com 235116Svbart@nginx.com nxt_uint_t 236121Svbart@nginx.com nxt_conf_object_members_count(nxt_conf_value_t *value) 237121Svbart@nginx.com { 238121Svbart@nginx.com return value->u.object->count; 239121Svbart@nginx.com } 240121Svbart@nginx.com 241121Svbart@nginx.com 242121Svbart@nginx.com nxt_conf_value_t * 243121Svbart@nginx.com nxt_conf_create_object(nxt_mp_t *mp, nxt_uint_t count) 244121Svbart@nginx.com { 245121Svbart@nginx.com size_t size; 246121Svbart@nginx.com nxt_conf_value_t *value; 247121Svbart@nginx.com 248121Svbart@nginx.com size = sizeof(nxt_conf_value_t) 249121Svbart@nginx.com + sizeof(nxt_conf_object_t) 250121Svbart@nginx.com + count * sizeof(nxt_conf_object_member_t); 251121Svbart@nginx.com 252121Svbart@nginx.com value = nxt_mp_get(mp, size); 253121Svbart@nginx.com if (nxt_slow_path(value == NULL)) { 254121Svbart@nginx.com return NULL; 255121Svbart@nginx.com } 256121Svbart@nginx.com 257121Svbart@nginx.com value->u.object = nxt_pointer_to(value, sizeof(nxt_conf_value_t)); 258121Svbart@nginx.com value->u.object->count = count; 259121Svbart@nginx.com 260121Svbart@nginx.com value->type = NXT_CONF_VALUE_OBJECT; 261121Svbart@nginx.com 262121Svbart@nginx.com return value; 263121Svbart@nginx.com } 264121Svbart@nginx.com 265121Svbart@nginx.com 266208Svbart@nginx.com void 267208Svbart@nginx.com nxt_conf_set_member(nxt_conf_value_t *object, nxt_str_t *name, 268172Svbart@nginx.com nxt_conf_value_t *value, uint32_t index) 269121Svbart@nginx.com { 270121Svbart@nginx.com nxt_conf_object_member_t *member; 271121Svbart@nginx.com 272121Svbart@nginx.com member = &object->u.object->members[index]; 273773Svbart@nginx.com 274773Svbart@nginx.com nxt_conf_set_string(&member->name, name); 275121Svbart@nginx.com 276121Svbart@nginx.com member->value = *value; 277208Svbart@nginx.com } 278208Svbart@nginx.com 279208Svbart@nginx.com 280208Svbart@nginx.com void 281208Svbart@nginx.com nxt_conf_set_member_string(nxt_conf_value_t *object, nxt_str_t *name, 282208Svbart@nginx.com nxt_str_t *value, uint32_t index) 283208Svbart@nginx.com { 284208Svbart@nginx.com nxt_conf_object_member_t *member; 285208Svbart@nginx.com 286208Svbart@nginx.com member = &object->u.object->members[index]; 287773Svbart@nginx.com 288773Svbart@nginx.com nxt_conf_set_string(&member->name, name); 289773Svbart@nginx.com 290773Svbart@nginx.com nxt_conf_set_string(&member->value, value); 291208Svbart@nginx.com } 292208Svbart@nginx.com 293208Svbart@nginx.com 294774Svbart@nginx.com nxt_int_t 295774Svbart@nginx.com nxt_conf_set_member_string_dup(nxt_conf_value_t *object, nxt_mp_t *mp, 296774Svbart@nginx.com nxt_str_t *name, nxt_str_t *value, uint32_t index) 297774Svbart@nginx.com { 298774Svbart@nginx.com nxt_conf_object_member_t *member; 299774Svbart@nginx.com 300774Svbart@nginx.com member = &object->u.object->members[index]; 301774Svbart@nginx.com 302774Svbart@nginx.com nxt_conf_set_string(&member->name, name); 303774Svbart@nginx.com 304774Svbart@nginx.com return nxt_conf_set_string_dup(&member->value, mp, value); 305774Svbart@nginx.com } 306774Svbart@nginx.com 307774Svbart@nginx.com 308208Svbart@nginx.com void 309208Svbart@nginx.com nxt_conf_set_member_integer(nxt_conf_value_t *object, nxt_str_t *name, 310208Svbart@nginx.com int64_t value, uint32_t index) 311208Svbart@nginx.com { 312*1439Svbart@nginx.com u_char *p, *end; 313208Svbart@nginx.com nxt_conf_object_member_t *member; 314208Svbart@nginx.com 315208Svbart@nginx.com member = &object->u.object->members[index]; 316773Svbart@nginx.com 317773Svbart@nginx.com nxt_conf_set_string(&member->name, name); 318208Svbart@nginx.com 319*1439Svbart@nginx.com p = member->value.u.number; 320*1439Svbart@nginx.com end = p + NXT_CONF_MAX_NUMBER_LEN; 321*1439Svbart@nginx.com 322*1439Svbart@nginx.com end = nxt_sprintf(p, end, "%L", value); 323*1439Svbart@nginx.com *end = '\0'; 324*1439Svbart@nginx.com 325208Svbart@nginx.com member->value.type = NXT_CONF_VALUE_INTEGER; 326121Svbart@nginx.com } 327121Svbart@nginx.com 328121Svbart@nginx.com 329774Svbart@nginx.com void 330774Svbart@nginx.com nxt_conf_set_member_null(nxt_conf_value_t *object, nxt_str_t *name, 331774Svbart@nginx.com uint32_t index) 332774Svbart@nginx.com { 333774Svbart@nginx.com nxt_conf_object_member_t *member; 334774Svbart@nginx.com 335774Svbart@nginx.com member = &object->u.object->members[index]; 336774Svbart@nginx.com 337774Svbart@nginx.com nxt_conf_set_string(&member->name, name); 338774Svbart@nginx.com 339774Svbart@nginx.com member->value.type = NXT_CONF_VALUE_NULL; 340774Svbart@nginx.com } 341774Svbart@nginx.com 342774Svbart@nginx.com 343774Svbart@nginx.com nxt_conf_value_t * 344774Svbart@nginx.com nxt_conf_create_array(nxt_mp_t *mp, nxt_uint_t count) 345774Svbart@nginx.com { 346774Svbart@nginx.com size_t size; 347774Svbart@nginx.com nxt_conf_value_t *value; 348774Svbart@nginx.com 349774Svbart@nginx.com size = sizeof(nxt_conf_value_t) 350774Svbart@nginx.com + sizeof(nxt_conf_array_t) 351774Svbart@nginx.com + count * sizeof(nxt_conf_value_t); 352774Svbart@nginx.com 353774Svbart@nginx.com value = nxt_mp_get(mp, size); 354774Svbart@nginx.com if (nxt_slow_path(value == NULL)) { 355774Svbart@nginx.com return NULL; 356774Svbart@nginx.com } 357774Svbart@nginx.com 358774Svbart@nginx.com value->u.array = nxt_pointer_to(value, sizeof(nxt_conf_value_t)); 359774Svbart@nginx.com value->u.array->count = count; 360774Svbart@nginx.com 361774Svbart@nginx.com value->type = NXT_CONF_VALUE_ARRAY; 362774Svbart@nginx.com 363774Svbart@nginx.com return value; 364774Svbart@nginx.com } 365774Svbart@nginx.com 366774Svbart@nginx.com 367774Svbart@nginx.com void 368774Svbart@nginx.com nxt_conf_set_element(nxt_conf_value_t *array, nxt_uint_t index, 369774Svbart@nginx.com nxt_conf_value_t *value) 370774Svbart@nginx.com { 371774Svbart@nginx.com array->u.array->elements[index] = *value; 372774Svbart@nginx.com } 373774Svbart@nginx.com 374774Svbart@nginx.com 375774Svbart@nginx.com nxt_int_t 376774Svbart@nginx.com nxt_conf_set_element_string_dup(nxt_conf_value_t *array, nxt_mp_t *mp, 377774Svbart@nginx.com nxt_uint_t index, nxt_str_t *value) 378774Svbart@nginx.com { 379774Svbart@nginx.com nxt_conf_value_t *element; 380774Svbart@nginx.com 381774Svbart@nginx.com element = &array->u.array->elements[index]; 382774Svbart@nginx.com 383774Svbart@nginx.com return nxt_conf_set_string_dup(element, mp, value); 384774Svbart@nginx.com } 385774Svbart@nginx.com 386774Svbart@nginx.com 387121Svbart@nginx.com nxt_uint_t 388961Sigor@sysoev.ru nxt_conf_array_elements_count(nxt_conf_value_t *value) 389961Sigor@sysoev.ru { 390961Sigor@sysoev.ru return value->u.array->count; 391961Sigor@sysoev.ru } 392961Sigor@sysoev.ru 393961Sigor@sysoev.ru 394961Sigor@sysoev.ru nxt_uint_t 395116Svbart@nginx.com nxt_conf_type(nxt_conf_value_t *value) 396116Svbart@nginx.com { 397116Svbart@nginx.com switch (value->type) { 398116Svbart@nginx.com 399116Svbart@nginx.com case NXT_CONF_VALUE_NULL: 400116Svbart@nginx.com return NXT_CONF_NULL; 401116Svbart@nginx.com 402116Svbart@nginx.com case NXT_CONF_VALUE_BOOLEAN: 403116Svbart@nginx.com return NXT_CONF_BOOLEAN; 404116Svbart@nginx.com 405116Svbart@nginx.com case NXT_CONF_VALUE_INTEGER: 406116Svbart@nginx.com return NXT_CONF_INTEGER; 407116Svbart@nginx.com 408116Svbart@nginx.com case NXT_CONF_VALUE_NUMBER: 409116Svbart@nginx.com return NXT_CONF_NUMBER; 410116Svbart@nginx.com 411116Svbart@nginx.com case NXT_CONF_VALUE_SHORT_STRING: 412116Svbart@nginx.com case NXT_CONF_VALUE_STRING: 413116Svbart@nginx.com return NXT_CONF_STRING; 414116Svbart@nginx.com 415116Svbart@nginx.com case NXT_CONF_VALUE_ARRAY: 416116Svbart@nginx.com return NXT_CONF_ARRAY; 417116Svbart@nginx.com 418116Svbart@nginx.com case NXT_CONF_VALUE_OBJECT: 419116Svbart@nginx.com return NXT_CONF_OBJECT; 420116Svbart@nginx.com } 421116Svbart@nginx.com 422116Svbart@nginx.com nxt_unreachable(); 423116Svbart@nginx.com 424116Svbart@nginx.com return 0; 425116Svbart@nginx.com } 426116Svbart@nginx.com 427116Svbart@nginx.com 428106Svbart@nginx.com nxt_conf_value_t * 429106Svbart@nginx.com nxt_conf_get_path(nxt_conf_value_t *value, nxt_str_t *path) 430106Svbart@nginx.com { 431106Svbart@nginx.com nxt_str_t token; 4321174Svbart@nginx.com nxt_int_t ret, index; 433106Svbart@nginx.com nxt_conf_path_parse_t parse; 434106Svbart@nginx.com 435106Svbart@nginx.com parse.start = path->start; 436106Svbart@nginx.com parse.end = path->start + path->length; 437106Svbart@nginx.com parse.last = 0; 438106Svbart@nginx.com 439106Svbart@nginx.com do { 4401174Svbart@nginx.com ret = nxt_conf_path_next_token(&parse, &token); 4411174Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 4421174Svbart@nginx.com return NULL; 4431174Svbart@nginx.com } 444106Svbart@nginx.com 445106Svbart@nginx.com if (token.length == 0) { 446106Svbart@nginx.com 447106Svbart@nginx.com if (parse.last) { 448106Svbart@nginx.com break; 449106Svbart@nginx.com } 450106Svbart@nginx.com 451106Svbart@nginx.com return NULL; 452106Svbart@nginx.com } 453106Svbart@nginx.com 454775Svbart@nginx.com switch (value->type) { 455775Svbart@nginx.com 456775Svbart@nginx.com case NXT_CONF_VALUE_OBJECT: 457775Svbart@nginx.com value = nxt_conf_get_object_member(value, &token, NULL); 458775Svbart@nginx.com break; 459775Svbart@nginx.com 460775Svbart@nginx.com case NXT_CONF_VALUE_ARRAY: 461775Svbart@nginx.com index = nxt_int_parse(token.start, token.length); 462775Svbart@nginx.com 463775Svbart@nginx.com if (index < 0 || index > NXT_INT32_T_MAX) { 464775Svbart@nginx.com return NULL; 465775Svbart@nginx.com } 466775Svbart@nginx.com 467775Svbart@nginx.com value = nxt_conf_get_array_element(value, index); 468775Svbart@nginx.com break; 469775Svbart@nginx.com 470775Svbart@nginx.com default: 471775Svbart@nginx.com return NULL; 472775Svbart@nginx.com } 473106Svbart@nginx.com 474106Svbart@nginx.com if (value == NULL) { 475106Svbart@nginx.com return NULL; 476106Svbart@nginx.com } 477106Svbart@nginx.com 478106Svbart@nginx.com } while (parse.last == 0); 479106Svbart@nginx.com 480106Svbart@nginx.com return value; 481106Svbart@nginx.com } 482106Svbart@nginx.com 483106Svbart@nginx.com 4841174Svbart@nginx.com static nxt_int_t 485106Svbart@nginx.com nxt_conf_path_next_token(nxt_conf_path_parse_t *parse, nxt_str_t *token) 486106Svbart@nginx.com { 4871174Svbart@nginx.com u_char *p, *start, *end; 4881174Svbart@nginx.com size_t length; 4891174Svbart@nginx.com 4901174Svbart@nginx.com start = parse->start + 1; 4911174Svbart@nginx.com 4921174Svbart@nginx.com p = start; 4931174Svbart@nginx.com 4941174Svbart@nginx.com while (p < parse->end && *p != '/') { 495106Svbart@nginx.com p++; 496106Svbart@nginx.com } 497106Svbart@nginx.com 498106Svbart@nginx.com parse->start = p; 4991174Svbart@nginx.com parse->last = (p >= parse->end); 5001174Svbart@nginx.com 5011174Svbart@nginx.com length = p - start; 5021174Svbart@nginx.com 5031174Svbart@nginx.com if (nxt_slow_path(length > NXT_CONF_MAX_TOKEN_LEN)) { 5041174Svbart@nginx.com return NXT_ERROR; 5051174Svbart@nginx.com } 5061174Svbart@nginx.com 5071174Svbart@nginx.com end = nxt_decode_uri(parse->buf, start, length); 5081174Svbart@nginx.com if (nxt_slow_path(end == NULL)) { 5091174Svbart@nginx.com return NXT_ERROR; 5101174Svbart@nginx.com } 5111174Svbart@nginx.com 5121174Svbart@nginx.com token->length = end - parse->buf; 5131174Svbart@nginx.com token->start = parse->buf; 5141174Svbart@nginx.com 5151174Svbart@nginx.com return NXT_OK; 516106Svbart@nginx.com } 517106Svbart@nginx.com 518106Svbart@nginx.com 519106Svbart@nginx.com nxt_conf_value_t * 520106Svbart@nginx.com nxt_conf_get_object_member(nxt_conf_value_t *value, nxt_str_t *name, 521106Svbart@nginx.com uint32_t *index) 522106Svbart@nginx.com { 523106Svbart@nginx.com nxt_str_t str; 524106Svbart@nginx.com nxt_uint_t n; 525106Svbart@nginx.com nxt_conf_object_t *object; 526106Svbart@nginx.com nxt_conf_object_member_t *member; 527106Svbart@nginx.com 528116Svbart@nginx.com if (value->type != NXT_CONF_VALUE_OBJECT) { 529106Svbart@nginx.com return NULL; 530106Svbart@nginx.com } 531106Svbart@nginx.com 532106Svbart@nginx.com object = value->u.object; 533106Svbart@nginx.com 534106Svbart@nginx.com for (n = 0; n < object->count; n++) { 535106Svbart@nginx.com member = &object->members[n]; 536106Svbart@nginx.com 537106Svbart@nginx.com nxt_conf_get_string(&member->name, &str); 538106Svbart@nginx.com 539106Svbart@nginx.com if (nxt_strstr_eq(&str, name)) { 540106Svbart@nginx.com 541106Svbart@nginx.com if (index != NULL) { 542106Svbart@nginx.com *index = n; 543106Svbart@nginx.com } 544106Svbart@nginx.com 545106Svbart@nginx.com return &member->value; 546106Svbart@nginx.com } 547106Svbart@nginx.com } 548106Svbart@nginx.com 549106Svbart@nginx.com return NULL; 550106Svbart@nginx.com } 551106Svbart@nginx.com 552106Svbart@nginx.com 553106Svbart@nginx.com nxt_int_t 554213Svbart@nginx.com nxt_conf_map_object(nxt_mp_t *mp, nxt_conf_value_t *value, nxt_conf_map_t *map, 555213Svbart@nginx.com nxt_uint_t n, void *data) 556106Svbart@nginx.com { 557*1439Svbart@nginx.com double num; 558213Svbart@nginx.com nxt_str_t str, *s; 559106Svbart@nginx.com nxt_uint_t i; 560106Svbart@nginx.com nxt_conf_value_t *v; 561106Svbart@nginx.com 562106Svbart@nginx.com union { 563111Sigor@sysoev.ru uint8_t ui8; 564111Sigor@sysoev.ru int32_t i32; 565111Sigor@sysoev.ru int64_t i64; 566839Svbart@nginx.com int i; 567111Sigor@sysoev.ru ssize_t size; 568111Sigor@sysoev.ru off_t off; 569111Sigor@sysoev.ru nxt_msec_t msec; 570111Sigor@sysoev.ru double dbl; 571111Sigor@sysoev.ru nxt_str_t str; 572213Svbart@nginx.com char *cstrz; 573111Sigor@sysoev.ru void *v; 574106Svbart@nginx.com } *ptr; 575106Svbart@nginx.com 576136Svbart@nginx.com for (i = 0; i < n; i++) { 577106Svbart@nginx.com 578106Svbart@nginx.com v = nxt_conf_get_object_member(value, &map[i].name, NULL); 579106Svbart@nginx.com 580116Svbart@nginx.com if (v == NULL || v->type == NXT_CONF_VALUE_NULL) { 581106Svbart@nginx.com continue; 582106Svbart@nginx.com } 583106Svbart@nginx.com 584106Svbart@nginx.com ptr = nxt_pointer_to(data, map[i].offset); 585106Svbart@nginx.com 586106Svbart@nginx.com switch (map[i].type) { 587106Svbart@nginx.com 588106Svbart@nginx.com case NXT_CONF_MAP_INT8: 589106Svbart@nginx.com 590136Svbart@nginx.com if (v->type == NXT_CONF_VALUE_BOOLEAN) { 591136Svbart@nginx.com ptr->ui8 = v->u.boolean; 592106Svbart@nginx.com } 593106Svbart@nginx.com 594106Svbart@nginx.com break; 595106Svbart@nginx.com 596106Svbart@nginx.com case NXT_CONF_MAP_INT32: 597106Svbart@nginx.com case NXT_CONF_MAP_INT64: 598106Svbart@nginx.com case NXT_CONF_MAP_INT: 599106Svbart@nginx.com case NXT_CONF_MAP_SIZE: 600106Svbart@nginx.com case NXT_CONF_MAP_OFF: 601111Sigor@sysoev.ru case NXT_CONF_MAP_MSEC: 602106Svbart@nginx.com 603116Svbart@nginx.com if (v->type != NXT_CONF_VALUE_INTEGER) { 604136Svbart@nginx.com break; 605106Svbart@nginx.com } 606106Svbart@nginx.com 607*1439Svbart@nginx.com num = nxt_strtod(v->u.number, NULL); 608*1439Svbart@nginx.com 609106Svbart@nginx.com switch (map[i].type) { 610106Svbart@nginx.com 611106Svbart@nginx.com case NXT_CONF_MAP_INT32: 612*1439Svbart@nginx.com ptr->i32 = num; 613106Svbart@nginx.com break; 614106Svbart@nginx.com 615106Svbart@nginx.com case NXT_CONF_MAP_INT64: 616*1439Svbart@nginx.com ptr->i64 = num; 617106Svbart@nginx.com break; 618106Svbart@nginx.com 619106Svbart@nginx.com case NXT_CONF_MAP_INT: 620*1439Svbart@nginx.com ptr->i = num; 621106Svbart@nginx.com break; 622106Svbart@nginx.com 623106Svbart@nginx.com case NXT_CONF_MAP_SIZE: 624*1439Svbart@nginx.com ptr->size = num; 625106Svbart@nginx.com break; 626106Svbart@nginx.com 627106Svbart@nginx.com case NXT_CONF_MAP_OFF: 628*1439Svbart@nginx.com ptr->off = num; 629106Svbart@nginx.com break; 630106Svbart@nginx.com 631111Sigor@sysoev.ru case NXT_CONF_MAP_MSEC: 632*1439Svbart@nginx.com ptr->msec = (nxt_msec_t) num * 1000; 633111Sigor@sysoev.ru break; 634111Sigor@sysoev.ru 635106Svbart@nginx.com default: 636106Svbart@nginx.com nxt_unreachable(); 637106Svbart@nginx.com } 638106Svbart@nginx.com 639106Svbart@nginx.com break; 640106Svbart@nginx.com 641106Svbart@nginx.com case NXT_CONF_MAP_DOUBLE: 642106Svbart@nginx.com 643116Svbart@nginx.com if (v->type == NXT_CONF_VALUE_NUMBER) { 644*1439Svbart@nginx.com ptr->dbl = nxt_strtod(v->u.number, NULL); 645106Svbart@nginx.com } 646106Svbart@nginx.com 647106Svbart@nginx.com break; 648106Svbart@nginx.com 649106Svbart@nginx.com case NXT_CONF_MAP_STR: 650213Svbart@nginx.com case NXT_CONF_MAP_STR_COPY: 651213Svbart@nginx.com case NXT_CONF_MAP_CSTRZ: 652213Svbart@nginx.com 653213Svbart@nginx.com if (v->type != NXT_CONF_VALUE_SHORT_STRING 654213Svbart@nginx.com && v->type != NXT_CONF_VALUE_STRING) 655106Svbart@nginx.com { 656213Svbart@nginx.com break; 657213Svbart@nginx.com } 658213Svbart@nginx.com 659213Svbart@nginx.com nxt_conf_get_string(v, &str); 660213Svbart@nginx.com 661213Svbart@nginx.com switch (map[i].type) { 662213Svbart@nginx.com 663213Svbart@nginx.com case NXT_CONF_MAP_STR: 664213Svbart@nginx.com ptr->str = str; 665213Svbart@nginx.com break; 666213Svbart@nginx.com 667213Svbart@nginx.com case NXT_CONF_MAP_STR_COPY: 668213Svbart@nginx.com 669213Svbart@nginx.com s = nxt_str_dup(mp, &ptr->str, &str); 670213Svbart@nginx.com 671213Svbart@nginx.com if (nxt_slow_path(s == NULL)) { 672213Svbart@nginx.com return NXT_ERROR; 673213Svbart@nginx.com } 674213Svbart@nginx.com 675213Svbart@nginx.com break; 676213Svbart@nginx.com 677213Svbart@nginx.com case NXT_CONF_MAP_CSTRZ: 678213Svbart@nginx.com 679213Svbart@nginx.com ptr->cstrz = nxt_str_cstrz(mp, &str); 680213Svbart@nginx.com 681213Svbart@nginx.com if (nxt_slow_path(ptr->cstrz == NULL)) { 682213Svbart@nginx.com return NXT_ERROR; 683213Svbart@nginx.com } 684213Svbart@nginx.com 685213Svbart@nginx.com break; 686213Svbart@nginx.com 687213Svbart@nginx.com default: 688213Svbart@nginx.com nxt_unreachable(); 689106Svbart@nginx.com } 690106Svbart@nginx.com 691106Svbart@nginx.com break; 692106Svbart@nginx.com 693106Svbart@nginx.com case NXT_CONF_MAP_PTR: 694106Svbart@nginx.com 695106Svbart@nginx.com ptr->v = v; 696106Svbart@nginx.com 697106Svbart@nginx.com break; 698106Svbart@nginx.com } 699106Svbart@nginx.com } 700106Svbart@nginx.com 701106Svbart@nginx.com return NXT_OK; 702106Svbart@nginx.com } 703106Svbart@nginx.com 704106Svbart@nginx.com 705106Svbart@nginx.com nxt_conf_value_t * 706106Svbart@nginx.com nxt_conf_next_object_member(nxt_conf_value_t *value, nxt_str_t *name, 707106Svbart@nginx.com uint32_t *next) 708106Svbart@nginx.com { 709106Svbart@nginx.com uint32_t n; 710106Svbart@nginx.com nxt_conf_object_t *object; 711106Svbart@nginx.com nxt_conf_object_member_t *member; 712106Svbart@nginx.com 713116Svbart@nginx.com if (value->type != NXT_CONF_VALUE_OBJECT) { 714106Svbart@nginx.com return NULL; 715106Svbart@nginx.com } 716106Svbart@nginx.com 717106Svbart@nginx.com n = *next; 718106Svbart@nginx.com object = value->u.object; 719106Svbart@nginx.com 720106Svbart@nginx.com if (n >= object->count) { 721106Svbart@nginx.com return NULL; 722106Svbart@nginx.com } 723106Svbart@nginx.com 724106Svbart@nginx.com member = &object->members[n]; 725106Svbart@nginx.com *next = n + 1; 726106Svbart@nginx.com 727106Svbart@nginx.com nxt_conf_get_string(&member->name, name); 728106Svbart@nginx.com 729106Svbart@nginx.com return &member->value; 730106Svbart@nginx.com } 731106Svbart@nginx.com 732106Svbart@nginx.com 733214Svbart@nginx.com nxt_conf_value_t * 734214Svbart@nginx.com nxt_conf_get_array_element(nxt_conf_value_t *value, uint32_t index) 735214Svbart@nginx.com { 736214Svbart@nginx.com nxt_conf_array_t *array; 737214Svbart@nginx.com 738214Svbart@nginx.com if (value->type != NXT_CONF_VALUE_ARRAY) { 739214Svbart@nginx.com return NULL; 740214Svbart@nginx.com } 741214Svbart@nginx.com 742214Svbart@nginx.com array = value->u.array; 743214Svbart@nginx.com 744214Svbart@nginx.com if (index >= array->count) { 745214Svbart@nginx.com return NULL; 746214Svbart@nginx.com } 747214Svbart@nginx.com 748214Svbart@nginx.com return &array->elements[index]; 749214Svbart@nginx.com } 750214Svbart@nginx.com 751214Svbart@nginx.com 752962Sigor@sysoev.ru void 753962Sigor@sysoev.ru nxt_conf_array_qsort(nxt_conf_value_t *value, 754962Sigor@sysoev.ru int (*compare)(const void *, const void *)) 755962Sigor@sysoev.ru { 756962Sigor@sysoev.ru nxt_conf_array_t *array; 757962Sigor@sysoev.ru 758962Sigor@sysoev.ru if (value->type != NXT_CONF_VALUE_ARRAY) { 759962Sigor@sysoev.ru return; 760962Sigor@sysoev.ru } 761962Sigor@sysoev.ru 762962Sigor@sysoev.ru array = value->u.array; 763962Sigor@sysoev.ru 764962Sigor@sysoev.ru nxt_qsort(array->elements, array->count, sizeof(nxt_conf_value_t), compare); 765962Sigor@sysoev.ru } 766962Sigor@sysoev.ru 767962Sigor@sysoev.ru 7681049Svbart@nginx.com nxt_conf_op_ret_t 769106Svbart@nginx.com nxt_conf_op_compile(nxt_mp_t *mp, nxt_conf_op_t **ops, nxt_conf_value_t *root, 7701049Svbart@nginx.com nxt_str_t *path, nxt_conf_value_t *value, nxt_bool_t add) 771106Svbart@nginx.com { 772106Svbart@nginx.com nxt_str_t token; 7731174Svbart@nginx.com nxt_int_t ret, index; 774106Svbart@nginx.com nxt_conf_op_t *op, **parent; 7751047Svbart@nginx.com nxt_conf_value_t *node; 776106Svbart@nginx.com nxt_conf_path_parse_t parse; 777106Svbart@nginx.com nxt_conf_object_member_t *member; 778106Svbart@nginx.com 779106Svbart@nginx.com parse.start = path->start; 780106Svbart@nginx.com parse.end = path->start + path->length; 781106Svbart@nginx.com parse.last = 0; 782106Svbart@nginx.com 783106Svbart@nginx.com parent = ops; 784106Svbart@nginx.com 785106Svbart@nginx.com for ( ;; ) { 786106Svbart@nginx.com op = nxt_mp_zget(mp, sizeof(nxt_conf_op_t)); 787106Svbart@nginx.com if (nxt_slow_path(op == NULL)) { 7881049Svbart@nginx.com return NXT_CONF_OP_ERROR; 789106Svbart@nginx.com } 790106Svbart@nginx.com 791106Svbart@nginx.com *parent = op; 792106Svbart@nginx.com parent = (nxt_conf_op_t **) &op->ctx; 793106Svbart@nginx.com 7941174Svbart@nginx.com ret = nxt_conf_path_next_token(&parse, &token); 7951174Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 7961174Svbart@nginx.com return NXT_CONF_OP_ERROR; 7971174Svbart@nginx.com } 798106Svbart@nginx.com 7991048Svbart@nginx.com switch (root->type) { 8001048Svbart@nginx.com 8011048Svbart@nginx.com case NXT_CONF_VALUE_OBJECT: 8021048Svbart@nginx.com node = nxt_conf_get_object_member(root, &token, &op->index); 8031048Svbart@nginx.com break; 8041048Svbart@nginx.com 8051048Svbart@nginx.com case NXT_CONF_VALUE_ARRAY: 8061048Svbart@nginx.com index = nxt_int_parse(token.start, token.length); 8071048Svbart@nginx.com 8081048Svbart@nginx.com if (index < 0 || index > NXT_INT32_T_MAX) { 8091049Svbart@nginx.com return NXT_CONF_OP_NOT_FOUND; 8101048Svbart@nginx.com } 8111048Svbart@nginx.com 8121048Svbart@nginx.com op->index = index; 8131048Svbart@nginx.com 8141048Svbart@nginx.com node = nxt_conf_get_array_element(root, index); 8151048Svbart@nginx.com break; 8161048Svbart@nginx.com 8171048Svbart@nginx.com default: 8181048Svbart@nginx.com node = NULL; 8191048Svbart@nginx.com } 820106Svbart@nginx.com 821106Svbart@nginx.com if (parse.last) { 822106Svbart@nginx.com break; 823106Svbart@nginx.com } 824106Svbart@nginx.com 8251047Svbart@nginx.com if (node == NULL) { 8261049Svbart@nginx.com return NXT_CONF_OP_NOT_FOUND; 827106Svbart@nginx.com } 828106Svbart@nginx.com 829106Svbart@nginx.com op->action = NXT_CONF_OP_PASS; 8301047Svbart@nginx.com root = node; 831106Svbart@nginx.com } 832106Svbart@nginx.com 833106Svbart@nginx.com if (value == NULL) { 834106Svbart@nginx.com 8351047Svbart@nginx.com if (node == NULL) { 8361049Svbart@nginx.com return NXT_CONF_OP_NOT_FOUND; 837106Svbart@nginx.com } 838106Svbart@nginx.com 839106Svbart@nginx.com op->action = NXT_CONF_OP_DELETE; 840106Svbart@nginx.com 8411049Svbart@nginx.com return NXT_CONF_OP_OK; 8421049Svbart@nginx.com } 8431049Svbart@nginx.com 8441049Svbart@nginx.com if (add) { 8451049Svbart@nginx.com if (node == NULL) { 8461049Svbart@nginx.com return NXT_CONF_OP_NOT_FOUND; 8471049Svbart@nginx.com } 8481049Svbart@nginx.com 8491049Svbart@nginx.com if (node->type != NXT_CONF_VALUE_ARRAY) { 8501049Svbart@nginx.com return NXT_CONF_OP_NOT_ALLOWED; 8511049Svbart@nginx.com } 8521049Svbart@nginx.com 8531049Svbart@nginx.com op->action = NXT_CONF_OP_PASS; 8541049Svbart@nginx.com 8551049Svbart@nginx.com op = nxt_mp_zget(mp, sizeof(nxt_conf_op_t)); 8561049Svbart@nginx.com if (nxt_slow_path(op == NULL)) { 8571049Svbart@nginx.com return NXT_CONF_OP_ERROR; 8581049Svbart@nginx.com } 8591049Svbart@nginx.com 8601049Svbart@nginx.com *parent = op; 8611049Svbart@nginx.com 8621049Svbart@nginx.com op->index = node->u.array->count; 8631049Svbart@nginx.com op->action = NXT_CONF_OP_CREATE; 8641049Svbart@nginx.com op->ctx = value; 8651049Svbart@nginx.com 8661049Svbart@nginx.com return NXT_CONF_OP_OK; 867106Svbart@nginx.com } 868106Svbart@nginx.com 8691048Svbart@nginx.com if (node != NULL) { 8701048Svbart@nginx.com op->action = NXT_CONF_OP_REPLACE; 8711048Svbart@nginx.com op->ctx = value; 8721048Svbart@nginx.com 8731049Svbart@nginx.com return NXT_CONF_OP_OK; 8741048Svbart@nginx.com } 8751048Svbart@nginx.com 8761048Svbart@nginx.com op->action = NXT_CONF_OP_CREATE; 8771048Svbart@nginx.com 8781048Svbart@nginx.com if (root->type == NXT_CONF_VALUE_ARRAY) { 8791048Svbart@nginx.com if (op->index > root->u.array->count) { 8801049Svbart@nginx.com return NXT_CONF_OP_NOT_FOUND; 8811048Svbart@nginx.com } 8821048Svbart@nginx.com 8831048Svbart@nginx.com op->ctx = value; 8841048Svbart@nginx.com 8851048Svbart@nginx.com } else { 886106Svbart@nginx.com member = nxt_mp_zget(mp, sizeof(nxt_conf_object_member_t)); 887106Svbart@nginx.com if (nxt_slow_path(member == NULL)) { 8881049Svbart@nginx.com return NXT_CONF_OP_ERROR; 889106Svbart@nginx.com } 890106Svbart@nginx.com 8911174Svbart@nginx.com ret = nxt_conf_set_string_dup(&member->name, mp, &token); 8921174Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 8931174Svbart@nginx.com return NXT_CONF_OP_ERROR; 8941174Svbart@nginx.com } 895106Svbart@nginx.com 896106Svbart@nginx.com member->value = *value; 897106Svbart@nginx.com 8981047Svbart@nginx.com op->index = root->u.object->count; 899106Svbart@nginx.com op->ctx = member; 900106Svbart@nginx.com } 901106Svbart@nginx.com 9021049Svbart@nginx.com return NXT_CONF_OP_OK; 903106Svbart@nginx.com } 904106Svbart@nginx.com 905106Svbart@nginx.com 906106Svbart@nginx.com nxt_conf_value_t * 907106Svbart@nginx.com nxt_conf_clone(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *value) 908106Svbart@nginx.com { 909106Svbart@nginx.com nxt_int_t rc; 910106Svbart@nginx.com nxt_conf_value_t *copy; 911106Svbart@nginx.com 912106Svbart@nginx.com copy = nxt_mp_get(mp, sizeof(nxt_conf_value_t)); 913106Svbart@nginx.com if (nxt_slow_path(copy == NULL)) { 914106Svbart@nginx.com return NULL; 915106Svbart@nginx.com } 916106Svbart@nginx.com 917106Svbart@nginx.com rc = nxt_conf_copy_value(mp, op, copy, value); 918106Svbart@nginx.com 919106Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 920106Svbart@nginx.com return NULL; 921106Svbart@nginx.com } 922106Svbart@nginx.com 923106Svbart@nginx.com return copy; 924106Svbart@nginx.com } 925106Svbart@nginx.com 926106Svbart@nginx.com 927106Svbart@nginx.com static nxt_int_t 928106Svbart@nginx.com nxt_conf_copy_value(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *dst, 929106Svbart@nginx.com nxt_conf_value_t *src) 930106Svbart@nginx.com { 9311048Svbart@nginx.com if (op != NULL 9321048Svbart@nginx.com && src->type != NXT_CONF_VALUE_ARRAY 9331048Svbart@nginx.com && src->type != NXT_CONF_VALUE_OBJECT) 9341048Svbart@nginx.com { 935106Svbart@nginx.com return NXT_ERROR; 936106Svbart@nginx.com } 937106Svbart@nginx.com 938106Svbart@nginx.com switch (src->type) { 939106Svbart@nginx.com 940116Svbart@nginx.com case NXT_CONF_VALUE_STRING: 941106Svbart@nginx.com 942172Svbart@nginx.com dst->u.string.start = nxt_mp_nget(mp, src->u.string.length); 943172Svbart@nginx.com if (nxt_slow_path(dst->u.string.start == NULL)) { 944106Svbart@nginx.com return NXT_ERROR; 945106Svbart@nginx.com } 946106Svbart@nginx.com 947172Svbart@nginx.com nxt_memcpy(dst->u.string.start, src->u.string.start, 948172Svbart@nginx.com src->u.string.length); 949172Svbart@nginx.com 950172Svbart@nginx.com dst->u.string.length = src->u.string.length; 951172Svbart@nginx.com 952106Svbart@nginx.com break; 953106Svbart@nginx.com 954116Svbart@nginx.com case NXT_CONF_VALUE_ARRAY: 9551048Svbart@nginx.com return nxt_conf_copy_array(mp, op, dst, src); 956106Svbart@nginx.com 957116Svbart@nginx.com case NXT_CONF_VALUE_OBJECT: 958106Svbart@nginx.com return nxt_conf_copy_object(mp, op, dst, src); 959106Svbart@nginx.com 960106Svbart@nginx.com default: 961106Svbart@nginx.com dst->u = src->u; 962106Svbart@nginx.com } 963106Svbart@nginx.com 9641048Svbart@nginx.com dst->type = src->type; 9651048Svbart@nginx.com 9661048Svbart@nginx.com return NXT_OK; 9671048Svbart@nginx.com } 9681048Svbart@nginx.com 9691048Svbart@nginx.com 9701048Svbart@nginx.com static nxt_int_t 9711048Svbart@nginx.com nxt_conf_copy_array(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *dst, 9721048Svbart@nginx.com nxt_conf_value_t *src) 9731048Svbart@nginx.com { 9741048Svbart@nginx.com size_t size; 9751048Svbart@nginx.com nxt_int_t rc; 9761048Svbart@nginx.com nxt_uint_t s, d, count, index; 9771048Svbart@nginx.com nxt_conf_op_t *pass_op; 9781048Svbart@nginx.com nxt_conf_value_t *value; 9791048Svbart@nginx.com 9801048Svbart@nginx.com count = src->u.array->count; 9811048Svbart@nginx.com 9821048Svbart@nginx.com if (op != NULL) { 9831048Svbart@nginx.com if (op->action == NXT_CONF_OP_CREATE) { 9841048Svbart@nginx.com count++; 9851048Svbart@nginx.com 9861048Svbart@nginx.com } else if (op->action == NXT_CONF_OP_DELETE) { 9871048Svbart@nginx.com count--; 9881048Svbart@nginx.com } 9891048Svbart@nginx.com } 9901048Svbart@nginx.com 9911048Svbart@nginx.com size = sizeof(nxt_conf_array_t) + count * sizeof(nxt_conf_value_t); 9921048Svbart@nginx.com 9931048Svbart@nginx.com dst->u.array = nxt_mp_get(mp, size); 9941048Svbart@nginx.com if (nxt_slow_path(dst->u.array == NULL)) { 9951048Svbart@nginx.com return NXT_ERROR; 9961048Svbart@nginx.com } 9971048Svbart@nginx.com 9981048Svbart@nginx.com dst->u.array->count = count; 9991048Svbart@nginx.com 10001048Svbart@nginx.com s = 0; 10011048Svbart@nginx.com d = 0; 10021048Svbart@nginx.com 10031048Svbart@nginx.com pass_op = NULL; 10041048Svbart@nginx.com 10051048Svbart@nginx.com /* 10061048Svbart@nginx.com * This initialization is needed only to 10071048Svbart@nginx.com * suppress a warning on GCC 4.8 and older. 10081048Svbart@nginx.com */ 10091048Svbart@nginx.com index = 0; 10101048Svbart@nginx.com 10111048Svbart@nginx.com do { 10121048Svbart@nginx.com if (pass_op == NULL) { 10131048Svbart@nginx.com index = (op == NULL) ? src->u.array->count : op->index; 10141048Svbart@nginx.com } 10151048Svbart@nginx.com 10161048Svbart@nginx.com while (s != index) { 10171048Svbart@nginx.com rc = nxt_conf_copy_value(mp, pass_op, &dst->u.array->elements[d], 10181048Svbart@nginx.com &src->u.array->elements[s]); 10191048Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 10201048Svbart@nginx.com return NXT_ERROR; 10211048Svbart@nginx.com } 10221048Svbart@nginx.com 10231048Svbart@nginx.com s++; 10241048Svbart@nginx.com d++; 10251048Svbart@nginx.com } 10261048Svbart@nginx.com 10271048Svbart@nginx.com if (pass_op != NULL) { 10281048Svbart@nginx.com pass_op = NULL; 10291048Svbart@nginx.com continue; 10301048Svbart@nginx.com } 10311048Svbart@nginx.com 10321048Svbart@nginx.com if (op != NULL) { 10331048Svbart@nginx.com switch (op->action) { 10341048Svbart@nginx.com case NXT_CONF_OP_PASS: 10351048Svbart@nginx.com pass_op = op->ctx; 10361048Svbart@nginx.com index++; 10371048Svbart@nginx.com break; 10381048Svbart@nginx.com 10391048Svbart@nginx.com case NXT_CONF_OP_CREATE: 10401048Svbart@nginx.com value = op->ctx; 10411048Svbart@nginx.com dst->u.array->elements[d] = *value; 10421048Svbart@nginx.com 10431048Svbart@nginx.com d++; 10441048Svbart@nginx.com break; 10451048Svbart@nginx.com 10461048Svbart@nginx.com case NXT_CONF_OP_REPLACE: 10471048Svbart@nginx.com value = op->ctx; 10481048Svbart@nginx.com dst->u.array->elements[d] = *value; 10491048Svbart@nginx.com 10501048Svbart@nginx.com s++; 10511048Svbart@nginx.com d++; 10521048Svbart@nginx.com break; 10531048Svbart@nginx.com 10541048Svbart@nginx.com case NXT_CONF_OP_DELETE: 10551048Svbart@nginx.com s++; 10561048Svbart@nginx.com break; 10571048Svbart@nginx.com } 10581048Svbart@nginx.com 10591048Svbart@nginx.com op = NULL; 10601048Svbart@nginx.com } 10611048Svbart@nginx.com 10621048Svbart@nginx.com } while (d != count); 10631048Svbart@nginx.com 10641048Svbart@nginx.com dst->type = src->type; 10651048Svbart@nginx.com 1066106Svbart@nginx.com return NXT_OK; 1067106Svbart@nginx.com } 1068106Svbart@nginx.com 1069106Svbart@nginx.com 1070106Svbart@nginx.com static nxt_int_t 1071106Svbart@nginx.com nxt_conf_copy_object(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *dst, 1072106Svbart@nginx.com nxt_conf_value_t *src) 1073106Svbart@nginx.com { 1074106Svbart@nginx.com size_t size; 1075106Svbart@nginx.com nxt_int_t rc; 1076106Svbart@nginx.com nxt_uint_t s, d, count, index; 1077106Svbart@nginx.com nxt_conf_op_t *pass_op; 1078106Svbart@nginx.com nxt_conf_value_t *value; 1079106Svbart@nginx.com nxt_conf_object_member_t *member; 1080106Svbart@nginx.com 1081106Svbart@nginx.com count = src->u.object->count; 1082106Svbart@nginx.com 1083106Svbart@nginx.com if (op != NULL) { 1084106Svbart@nginx.com if (op->action == NXT_CONF_OP_CREATE) { 1085106Svbart@nginx.com count++; 1086106Svbart@nginx.com 1087106Svbart@nginx.com } else if (op->action == NXT_CONF_OP_DELETE) { 1088106Svbart@nginx.com count--; 1089106Svbart@nginx.com } 1090106Svbart@nginx.com } 1091106Svbart@nginx.com 1092106Svbart@nginx.com size = sizeof(nxt_conf_object_t) 1093106Svbart@nginx.com + count * sizeof(nxt_conf_object_member_t); 1094106Svbart@nginx.com 1095106Svbart@nginx.com dst->u.object = nxt_mp_get(mp, size); 1096106Svbart@nginx.com if (nxt_slow_path(dst->u.object == NULL)) { 1097106Svbart@nginx.com return NXT_ERROR; 1098106Svbart@nginx.com } 1099106Svbart@nginx.com 1100106Svbart@nginx.com dst->u.object->count = count; 1101106Svbart@nginx.com 1102106Svbart@nginx.com s = 0; 1103106Svbart@nginx.com d = 0; 1104106Svbart@nginx.com 1105106Svbart@nginx.com pass_op = NULL; 1106106Svbart@nginx.com 1107106Svbart@nginx.com /* 1108106Svbart@nginx.com * This initialization is needed only to 1109106Svbart@nginx.com * suppress a warning on GCC 4.8 and older. 1110106Svbart@nginx.com */ 1111106Svbart@nginx.com index = 0; 1112106Svbart@nginx.com 1113106Svbart@nginx.com do { 1114106Svbart@nginx.com if (pass_op == NULL) { 11151047Svbart@nginx.com index = (op == NULL) ? src->u.object->count : op->index; 1116106Svbart@nginx.com } 1117106Svbart@nginx.com 1118106Svbart@nginx.com while (s != index) { 1119106Svbart@nginx.com rc = nxt_conf_copy_value(mp, NULL, 1120106Svbart@nginx.com &dst->u.object->members[d].name, 1121106Svbart@nginx.com &src->u.object->members[s].name); 1122106Svbart@nginx.com 1123106Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 1124106Svbart@nginx.com return NXT_ERROR; 1125106Svbart@nginx.com } 1126106Svbart@nginx.com 1127106Svbart@nginx.com rc = nxt_conf_copy_value(mp, pass_op, 1128106Svbart@nginx.com &dst->u.object->members[d].value, 1129106Svbart@nginx.com &src->u.object->members[s].value); 1130106Svbart@nginx.com 1131106Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 1132106Svbart@nginx.com return NXT_ERROR; 1133106Svbart@nginx.com } 1134106Svbart@nginx.com 1135106Svbart@nginx.com s++; 1136106Svbart@nginx.com d++; 1137106Svbart@nginx.com } 1138106Svbart@nginx.com 1139106Svbart@nginx.com if (pass_op != NULL) { 1140106Svbart@nginx.com pass_op = NULL; 1141106Svbart@nginx.com continue; 1142106Svbart@nginx.com } 1143106Svbart@nginx.com 1144106Svbart@nginx.com if (op != NULL) { 1145106Svbart@nginx.com switch (op->action) { 1146106Svbart@nginx.com case NXT_CONF_OP_PASS: 1147106Svbart@nginx.com pass_op = op->ctx; 1148106Svbart@nginx.com index++; 1149106Svbart@nginx.com break; 1150106Svbart@nginx.com 1151106Svbart@nginx.com case NXT_CONF_OP_CREATE: 1152106Svbart@nginx.com member = op->ctx; 1153106Svbart@nginx.com 1154106Svbart@nginx.com rc = nxt_conf_copy_value(mp, NULL, 1155106Svbart@nginx.com &dst->u.object->members[d].name, 1156106Svbart@nginx.com &member->name); 1157106Svbart@nginx.com 1158106Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 1159106Svbart@nginx.com return NXT_ERROR; 1160106Svbart@nginx.com } 1161106Svbart@nginx.com 1162106Svbart@nginx.com dst->u.object->members[d].value = member->value; 1163106Svbart@nginx.com 1164106Svbart@nginx.com d++; 1165106Svbart@nginx.com break; 1166106Svbart@nginx.com 1167106Svbart@nginx.com case NXT_CONF_OP_REPLACE: 1168106Svbart@nginx.com rc = nxt_conf_copy_value(mp, NULL, 1169106Svbart@nginx.com &dst->u.object->members[d].name, 1170106Svbart@nginx.com &src->u.object->members[s].name); 1171106Svbart@nginx.com 1172106Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 1173106Svbart@nginx.com return NXT_ERROR; 1174106Svbart@nginx.com } 1175106Svbart@nginx.com 1176106Svbart@nginx.com value = op->ctx; 1177106Svbart@nginx.com 1178106Svbart@nginx.com dst->u.object->members[d].value = *value; 1179106Svbart@nginx.com 1180106Svbart@nginx.com s++; 1181106Svbart@nginx.com d++; 1182106Svbart@nginx.com break; 1183106Svbart@nginx.com 1184106Svbart@nginx.com case NXT_CONF_OP_DELETE: 1185106Svbart@nginx.com s++; 1186106Svbart@nginx.com break; 1187106Svbart@nginx.com } 1188106Svbart@nginx.com 11891046Svbart@nginx.com op = NULL; 1190106Svbart@nginx.com } 1191106Svbart@nginx.com 1192106Svbart@nginx.com } while (d != count); 1193106Svbart@nginx.com 1194106Svbart@nginx.com dst->type = src->type; 1195106Svbart@nginx.com 1196106Svbart@nginx.com return NXT_OK; 1197106Svbart@nginx.com } 1198106Svbart@nginx.com 1199106Svbart@nginx.com 1200106Svbart@nginx.com nxt_conf_value_t * 1201208Svbart@nginx.com nxt_conf_json_parse(nxt_mp_t *mp, u_char *start, u_char *end, 1202208Svbart@nginx.com nxt_conf_json_error_t *error) 1203106Svbart@nginx.com { 1204106Svbart@nginx.com u_char *p; 1205106Svbart@nginx.com nxt_conf_value_t *value; 1206106Svbart@nginx.com 1207106Svbart@nginx.com value = nxt_mp_get(mp, sizeof(nxt_conf_value_t)); 1208106Svbart@nginx.com if (nxt_slow_path(value == NULL)) { 1209106Svbart@nginx.com return NULL; 1210106Svbart@nginx.com } 1211106Svbart@nginx.com 1212106Svbart@nginx.com p = nxt_conf_json_skip_space(start, end); 1213106Svbart@nginx.com 1214106Svbart@nginx.com if (nxt_slow_path(p == end)) { 1215208Svbart@nginx.com 1216208Svbart@nginx.com nxt_conf_json_parse_error(error, start, 1217311Snick@nginx.com "An empty JSON payload isn't allowed. It must be either a literal " 1218311Snick@nginx.com "(null, true, or false), a number, a string (in double quotes " 1219311Snick@nginx.com "\"\"), an array (with brackets []), or an object (with braces {})." 1220208Svbart@nginx.com ); 1221208Svbart@nginx.com 1222106Svbart@nginx.com return NULL; 1223106Svbart@nginx.com } 1224106Svbart@nginx.com 1225208Svbart@nginx.com p = nxt_conf_json_parse_value(mp, value, p, end, error); 1226106Svbart@nginx.com 1227106Svbart@nginx.com if (nxt_slow_path(p == NULL)) { 1228106Svbart@nginx.com return NULL; 1229106Svbart@nginx.com } 1230106Svbart@nginx.com 1231106Svbart@nginx.com p = nxt_conf_json_skip_space(p, end); 1232106Svbart@nginx.com 1233106Svbart@nginx.com if (nxt_slow_path(p != end)) { 1234208Svbart@nginx.com 1235208Svbart@nginx.com nxt_conf_json_parse_error(error, p, 1236311Snick@nginx.com "Unexpected character after the end of a valid JSON value." 1237208Svbart@nginx.com ); 1238208Svbart@nginx.com 1239106Svbart@nginx.com return NULL; 1240106Svbart@nginx.com } 1241106Svbart@nginx.com 1242106Svbart@nginx.com return value; 1243106Svbart@nginx.com } 1244106Svbart@nginx.com 1245106Svbart@nginx.com 1246106Svbart@nginx.com static u_char * 1247106Svbart@nginx.com nxt_conf_json_skip_space(u_char *start, u_char *end) 1248106Svbart@nginx.com { 12491363Svbart@nginx.com u_char *p, ch; 12501363Svbart@nginx.com 12511363Svbart@nginx.com enum { 12521363Svbart@nginx.com sw_normal = 0, 12531363Svbart@nginx.com sw_after_slash, 12541363Svbart@nginx.com sw_single_comment, 12551363Svbart@nginx.com sw_multi_comment, 12561363Svbart@nginx.com sw_after_asterisk, 12571363Svbart@nginx.com } state; 12581363Svbart@nginx.com 12591363Svbart@nginx.com state = sw_normal; 1260106Svbart@nginx.com 1261106Svbart@nginx.com for (p = start; nxt_fast_path(p != end); p++) { 12621363Svbart@nginx.com ch = *p; 12631363Svbart@nginx.com 12641363Svbart@nginx.com switch (state) { 12651363Svbart@nginx.com 12661363Svbart@nginx.com case sw_normal: 12671363Svbart@nginx.com switch (ch) { 12681363Svbart@nginx.com case ' ': 12691363Svbart@nginx.com case '\t': 12701363Svbart@nginx.com case '\n': 12711363Svbart@nginx.com case '\r': 12721363Svbart@nginx.com continue; 12731363Svbart@nginx.com case '/': 12741425Svbart@nginx.com start = p; 12751363Svbart@nginx.com state = sw_after_slash; 12761363Svbart@nginx.com continue; 12771363Svbart@nginx.com } 12781363Svbart@nginx.com 12791363Svbart@nginx.com break; 12801363Svbart@nginx.com 12811363Svbart@nginx.com case sw_after_slash: 12821363Svbart@nginx.com switch (ch) { 12831363Svbart@nginx.com case '/': 12841363Svbart@nginx.com state = sw_single_comment; 12851363Svbart@nginx.com continue; 12861363Svbart@nginx.com case '*': 12871363Svbart@nginx.com state = sw_multi_comment; 12881363Svbart@nginx.com continue; 12891363Svbart@nginx.com } 12901363Svbart@nginx.com 12911363Svbart@nginx.com break; 12921363Svbart@nginx.com 12931363Svbart@nginx.com case sw_single_comment: 12941363Svbart@nginx.com if (ch == '\n') { 12951363Svbart@nginx.com state = sw_normal; 12961363Svbart@nginx.com } 12971363Svbart@nginx.com 12981363Svbart@nginx.com continue; 12991363Svbart@nginx.com 13001363Svbart@nginx.com case sw_multi_comment: 13011363Svbart@nginx.com if (ch == '*') { 13021363Svbart@nginx.com state = sw_after_asterisk; 13031363Svbart@nginx.com } 13041363Svbart@nginx.com 13051363Svbart@nginx.com continue; 13061363Svbart@nginx.com 13071363Svbart@nginx.com case sw_after_asterisk: 13081363Svbart@nginx.com switch (ch) { 13091363Svbart@nginx.com case '/': 13101363Svbart@nginx.com state = sw_normal; 13111363Svbart@nginx.com continue; 13121363Svbart@nginx.com case '*': 13131363Svbart@nginx.com continue; 13141363Svbart@nginx.com } 13151363Svbart@nginx.com 13161363Svbart@nginx.com state = sw_multi_comment; 1317106Svbart@nginx.com continue; 1318106Svbart@nginx.com } 1319106Svbart@nginx.com 1320106Svbart@nginx.com break; 1321106Svbart@nginx.com } 1322106Svbart@nginx.com 13231425Svbart@nginx.com if (nxt_slow_path(state != sw_normal)) { 13241425Svbart@nginx.com return start; 13251425Svbart@nginx.com } 13261425Svbart@nginx.com 1327106Svbart@nginx.com return p; 1328106Svbart@nginx.com } 1329106Svbart@nginx.com 1330106Svbart@nginx.com 1331106Svbart@nginx.com static u_char * 1332106Svbart@nginx.com nxt_conf_json_parse_value(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start, 1333208Svbart@nginx.com u_char *end, nxt_conf_json_error_t *error) 1334106Svbart@nginx.com { 1335208Svbart@nginx.com u_char ch, *p; 1336106Svbart@nginx.com 1337106Svbart@nginx.com ch = *start; 1338106Svbart@nginx.com 1339106Svbart@nginx.com switch (ch) { 1340106Svbart@nginx.com case '{': 1341208Svbart@nginx.com return nxt_conf_json_parse_object(mp, value, start, end, error); 1342106Svbart@nginx.com 1343106Svbart@nginx.com case '[': 1344208Svbart@nginx.com return nxt_conf_json_parse_array(mp, value, start, end, error); 1345106Svbart@nginx.com 1346106Svbart@nginx.com case '"': 1347208Svbart@nginx.com return nxt_conf_json_parse_string(mp, value, start, end, error); 1348106Svbart@nginx.com 1349106Svbart@nginx.com case 't': 1350106Svbart@nginx.com if (nxt_fast_path(end - start >= 4 1351106Svbart@nginx.com && nxt_memcmp(start, "true", 4) == 0)) 1352106Svbart@nginx.com { 1353106Svbart@nginx.com value->u.boolean = 1; 1354116Svbart@nginx.com value->type = NXT_CONF_VALUE_BOOLEAN; 1355106Svbart@nginx.com 1356106Svbart@nginx.com return start + 4; 1357106Svbart@nginx.com } 1358106Svbart@nginx.com 1359208Svbart@nginx.com goto error; 1360106Svbart@nginx.com 1361106Svbart@nginx.com case 'f': 1362106Svbart@nginx.com if (nxt_fast_path(end - start >= 5 1363106Svbart@nginx.com && nxt_memcmp(start, "false", 5) == 0)) 1364106Svbart@nginx.com { 1365106Svbart@nginx.com value->u.boolean = 0; 1366116Svbart@nginx.com value->type = NXT_CONF_VALUE_BOOLEAN; 1367106Svbart@nginx.com 1368106Svbart@nginx.com return start + 5; 1369106Svbart@nginx.com } 1370106Svbart@nginx.com 1371208Svbart@nginx.com goto error; 1372106Svbart@nginx.com 1373106Svbart@nginx.com case 'n': 1374106Svbart@nginx.com if (nxt_fast_path(end - start >= 4 1375106Svbart@nginx.com && nxt_memcmp(start, "null", 4) == 0)) 1376106Svbart@nginx.com { 1377116Svbart@nginx.com value->type = NXT_CONF_VALUE_NULL; 1378106Svbart@nginx.com return start + 4; 1379106Svbart@nginx.com } 1380106Svbart@nginx.com 1381208Svbart@nginx.com goto error; 1382208Svbart@nginx.com 1383208Svbart@nginx.com case '-': 1384208Svbart@nginx.com if (nxt_fast_path(end - start > 1)) { 1385208Svbart@nginx.com ch = start[1]; 1386208Svbart@nginx.com break; 1387208Svbart@nginx.com } 1388208Svbart@nginx.com 1389208Svbart@nginx.com goto error; 1390106Svbart@nginx.com } 1391106Svbart@nginx.com 1392208Svbart@nginx.com if (nxt_fast_path((ch - '0') <= 9)) { 1393208Svbart@nginx.com p = nxt_conf_json_parse_number(mp, value, start, end, error); 1394208Svbart@nginx.com 1395383Svbart@nginx.com if (nxt_slow_path(p == NULL)) { 1396383Svbart@nginx.com return NULL; 1397383Svbart@nginx.com } 1398383Svbart@nginx.com 1399208Svbart@nginx.com if (p == end) { 1400208Svbart@nginx.com return end; 1401208Svbart@nginx.com } 1402208Svbart@nginx.com 1403208Svbart@nginx.com switch (*p) { 1404208Svbart@nginx.com case ' ': 1405208Svbart@nginx.com case '\t': 1406208Svbart@nginx.com case '\r': 1407208Svbart@nginx.com case '\n': 1408208Svbart@nginx.com case ',': 1409208Svbart@nginx.com case '}': 1410208Svbart@nginx.com case ']': 1411208Svbart@nginx.com case '{': 1412208Svbart@nginx.com case '[': 1413208Svbart@nginx.com case '"': 14141363Svbart@nginx.com case '/': 1415208Svbart@nginx.com return p; 1416208Svbart@nginx.com } 1417106Svbart@nginx.com } 1418106Svbart@nginx.com 1419208Svbart@nginx.com error: 1420208Svbart@nginx.com 1421208Svbart@nginx.com nxt_conf_json_parse_error(error, start, 1422311Snick@nginx.com "A valid JSON value is expected here. It must be either a literal " 1423311Snick@nginx.com "(null, true, or false), a number, a string (in double quotes \"\"), " 1424311Snick@nginx.com "an array (with brackets []), or an object (with braces {})." 1425208Svbart@nginx.com ); 1426208Svbart@nginx.com 1427106Svbart@nginx.com return NULL; 1428106Svbart@nginx.com } 1429106Svbart@nginx.com 1430106Svbart@nginx.com 1431106Svbart@nginx.com static const nxt_lvlhsh_proto_t nxt_conf_object_hash_proto 1432106Svbart@nginx.com nxt_aligned(64) = 1433106Svbart@nginx.com { 1434106Svbart@nginx.com NXT_LVLHSH_DEFAULT, 1435106Svbart@nginx.com nxt_conf_object_hash_test, 1436106Svbart@nginx.com nxt_conf_object_hash_alloc, 1437106Svbart@nginx.com nxt_conf_object_hash_free, 1438106Svbart@nginx.com }; 1439106Svbart@nginx.com 1440106Svbart@nginx.com 1441106Svbart@nginx.com static u_char * 1442106Svbart@nginx.com nxt_conf_json_parse_object(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start, 1443208Svbart@nginx.com u_char *end, nxt_conf_json_error_t *error) 1444106Svbart@nginx.com { 1445208Svbart@nginx.com u_char *p, *name; 1446106Svbart@nginx.com nxt_mp_t *mp_temp; 1447106Svbart@nginx.com nxt_int_t rc; 1448106Svbart@nginx.com nxt_uint_t count; 1449106Svbart@nginx.com nxt_lvlhsh_t hash; 1450106Svbart@nginx.com nxt_lvlhsh_each_t lhe; 1451106Svbart@nginx.com nxt_conf_object_t *object; 1452106Svbart@nginx.com nxt_conf_object_member_t *member, *element; 1453106Svbart@nginx.com 1454106Svbart@nginx.com mp_temp = nxt_mp_create(1024, 128, 256, 32); 1455106Svbart@nginx.com if (nxt_slow_path(mp_temp == NULL)) { 1456106Svbart@nginx.com return NULL; 1457106Svbart@nginx.com } 1458106Svbart@nginx.com 1459106Svbart@nginx.com nxt_lvlhsh_init(&hash); 1460106Svbart@nginx.com 1461106Svbart@nginx.com count = 0; 1462130Svbart@nginx.com p = start; 1463130Svbart@nginx.com 1464130Svbart@nginx.com for ( ;; ) { 1465130Svbart@nginx.com p = nxt_conf_json_skip_space(p + 1, end); 1466130Svbart@nginx.com 1467130Svbart@nginx.com if (nxt_slow_path(p == end)) { 1468208Svbart@nginx.com 1469208Svbart@nginx.com nxt_conf_json_parse_error(error, p, 1470311Snick@nginx.com "Unexpected end of JSON payload. There's an object without " 1471311Snick@nginx.com "a closing brace (})." 1472208Svbart@nginx.com ); 1473208Svbart@nginx.com 1474130Svbart@nginx.com goto error; 1475130Svbart@nginx.com } 1476130Svbart@nginx.com 1477130Svbart@nginx.com if (*p != '"') { 1478130Svbart@nginx.com if (nxt_fast_path(*p == '}')) { 1479106Svbart@nginx.com break; 1480106Svbart@nginx.com } 1481106Svbart@nginx.com 1482208Svbart@nginx.com nxt_conf_json_parse_error(error, p, 1483208Svbart@nginx.com "A double quote (\") is expected here. There must be a valid " 1484208Svbart@nginx.com "JSON object member starts with a name, which is a string " 1485208Svbart@nginx.com "enclosed in double quotes." 1486208Svbart@nginx.com ); 1487208Svbart@nginx.com 1488130Svbart@nginx.com goto error; 1489130Svbart@nginx.com } 1490130Svbart@nginx.com 1491208Svbart@nginx.com name = p; 1492208Svbart@nginx.com 1493130Svbart@nginx.com count++; 1494130Svbart@nginx.com 1495130Svbart@nginx.com member = nxt_mp_get(mp_temp, sizeof(nxt_conf_object_member_t)); 1496130Svbart@nginx.com if (nxt_slow_path(member == NULL)) { 1497130Svbart@nginx.com goto error; 1498130Svbart@nginx.com } 1499130Svbart@nginx.com 1500208Svbart@nginx.com p = nxt_conf_json_parse_string(mp, &member->name, p, end, error); 1501130Svbart@nginx.com 1502130Svbart@nginx.com if (nxt_slow_path(p == NULL)) { 1503130Svbart@nginx.com goto error; 1504130Svbart@nginx.com } 1505130Svbart@nginx.com 1506130Svbart@nginx.com rc = nxt_conf_object_hash_add(mp_temp, &hash, member); 1507130Svbart@nginx.com 1508130Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 1509208Svbart@nginx.com 1510208Svbart@nginx.com if (rc == NXT_DECLINED) { 1511208Svbart@nginx.com nxt_conf_json_parse_error(error, name, 1512208Svbart@nginx.com "Duplicate object member. All JSON object members must " 1513208Svbart@nginx.com "have unique names." 1514208Svbart@nginx.com ); 1515208Svbart@nginx.com } 1516208Svbart@nginx.com 1517130Svbart@nginx.com goto error; 1518130Svbart@nginx.com } 1519130Svbart@nginx.com 1520130Svbart@nginx.com p = nxt_conf_json_skip_space(p, end); 1521130Svbart@nginx.com 1522208Svbart@nginx.com if (nxt_slow_path(p == end)) { 1523208Svbart@nginx.com 1524208Svbart@nginx.com nxt_conf_json_parse_error(error, p, 1525311Snick@nginx.com "Unexpected end of JSON payload. There's an object member " 1526311Snick@nginx.com "without a value." 1527208Svbart@nginx.com ); 1528208Svbart@nginx.com 1529208Svbart@nginx.com goto error; 1530208Svbart@nginx.com } 1531208Svbart@nginx.com 1532208Svbart@nginx.com if (nxt_slow_path(*p != ':')) { 1533208Svbart@nginx.com 1534208Svbart@nginx.com nxt_conf_json_parse_error(error, p, 1535311Snick@nginx.com "A colon (:) is expected here. There must be a colon after " 1536311Snick@nginx.com "a JSON member name." 1537208Svbart@nginx.com ); 1538208Svbart@nginx.com 1539130Svbart@nginx.com goto error; 1540130Svbart@nginx.com } 1541130Svbart@nginx.com 1542130Svbart@nginx.com p = nxt_conf_json_skip_space(p + 1, end); 1543130Svbart@nginx.com 1544130Svbart@nginx.com if (nxt_slow_path(p == end)) { 1545208Svbart@nginx.com 1546208Svbart@nginx.com nxt_conf_json_parse_error(error, p, 1547311Snick@nginx.com "Unexpected end of JSON payload. There's an object member " 1548311Snick@nginx.com "without a value." 1549208Svbart@nginx.com ); 1550208Svbart@nginx.com 1551130Svbart@nginx.com goto error; 1552130Svbart@nginx.com } 1553130Svbart@nginx.com 1554208Svbart@nginx.com p = nxt_conf_json_parse_value(mp, &member->value, p, end, error); 1555130Svbart@nginx.com 1556130Svbart@nginx.com if (nxt_slow_path(p == NULL)) { 1557130Svbart@nginx.com goto error; 1558130Svbart@nginx.com } 1559130Svbart@nginx.com 1560130Svbart@nginx.com p = nxt_conf_json_skip_space(p, end); 1561130Svbart@nginx.com 1562130Svbart@nginx.com if (nxt_slow_path(p == end)) { 1563208Svbart@nginx.com 1564208Svbart@nginx.com nxt_conf_json_parse_error(error, p, 1565311Snick@nginx.com "Unexpected end of JSON payload. There's an object without " 1566311Snick@nginx.com "a closing brace (})." 1567208Svbart@nginx.com ); 1568208Svbart@nginx.com 1569130Svbart@nginx.com goto error; 1570130Svbart@nginx.com } 1571130Svbart@nginx.com 1572130Svbart@nginx.com if (*p != ',') { 1573130Svbart@nginx.com if (nxt_fast_path(*p == '}')) { 1574130Svbart@nginx.com break; 1575106Svbart@nginx.com } 1576106Svbart@nginx.com 1577208Svbart@nginx.com nxt_conf_json_parse_error(error, p, 1578311Snick@nginx.com "Either a closing brace (}) or a comma (,) is expected here. " 1579311Snick@nginx.com "Each JSON object must be enclosed in braces and its members " 1580311Snick@nginx.com "must be separated by commas." 1581208Svbart@nginx.com ); 1582208Svbart@nginx.com 1583130Svbart@nginx.com goto error; 1584106Svbart@nginx.com } 1585106Svbart@nginx.com } 1586106Svbart@nginx.com 1587106Svbart@nginx.com object = nxt_mp_get(mp, sizeof(nxt_conf_object_t) 1588106Svbart@nginx.com + count * sizeof(nxt_conf_object_member_t)); 1589106Svbart@nginx.com if (nxt_slow_path(object == NULL)) { 1590106Svbart@nginx.com goto error; 1591106Svbart@nginx.com } 1592106Svbart@nginx.com 1593106Svbart@nginx.com value->u.object = object; 1594116Svbart@nginx.com value->type = NXT_CONF_VALUE_OBJECT; 1595106Svbart@nginx.com 1596106Svbart@nginx.com object->count = count; 1597106Svbart@nginx.com member = object->members; 1598106Svbart@nginx.com 1599598Sigor@sysoev.ru nxt_lvlhsh_each_init(&lhe, &nxt_conf_object_hash_proto); 1600106Svbart@nginx.com 1601106Svbart@nginx.com for ( ;; ) { 1602106Svbart@nginx.com element = nxt_lvlhsh_each(&hash, &lhe); 1603106Svbart@nginx.com 1604106Svbart@nginx.com if (element == NULL) { 1605106Svbart@nginx.com break; 1606106Svbart@nginx.com } 1607106Svbart@nginx.com 1608106Svbart@nginx.com *member++ = *element; 1609106Svbart@nginx.com } 1610106Svbart@nginx.com 1611106Svbart@nginx.com nxt_mp_destroy(mp_temp); 1612106Svbart@nginx.com 1613106Svbart@nginx.com return p + 1; 1614106Svbart@nginx.com 1615106Svbart@nginx.com error: 1616106Svbart@nginx.com 1617106Svbart@nginx.com nxt_mp_destroy(mp_temp); 1618106Svbart@nginx.com return NULL; 1619106Svbart@nginx.com } 1620106Svbart@nginx.com 1621106Svbart@nginx.com 1622106Svbart@nginx.com static nxt_int_t 1623106Svbart@nginx.com nxt_conf_object_hash_add(nxt_mp_t *mp, nxt_lvlhsh_t *lvlhsh, 1624106Svbart@nginx.com nxt_conf_object_member_t *member) 1625106Svbart@nginx.com { 1626106Svbart@nginx.com nxt_lvlhsh_query_t lhq; 1627106Svbart@nginx.com 1628106Svbart@nginx.com nxt_conf_get_string(&member->name, &lhq.key); 1629106Svbart@nginx.com 1630106Svbart@nginx.com lhq.key_hash = nxt_djb_hash(lhq.key.start, lhq.key.length); 1631106Svbart@nginx.com lhq.replace = 0; 1632106Svbart@nginx.com lhq.value = member; 1633106Svbart@nginx.com lhq.proto = &nxt_conf_object_hash_proto; 1634106Svbart@nginx.com lhq.pool = mp; 1635106Svbart@nginx.com 1636106Svbart@nginx.com return nxt_lvlhsh_insert(lvlhsh, &lhq); 1637106Svbart@nginx.com } 1638106Svbart@nginx.com 1639106Svbart@nginx.com 1640106Svbart@nginx.com static nxt_int_t 1641106Svbart@nginx.com nxt_conf_object_hash_test(nxt_lvlhsh_query_t *lhq, void *data) 1642106Svbart@nginx.com { 1643106Svbart@nginx.com nxt_str_t str; 1644106Svbart@nginx.com nxt_conf_object_member_t *member; 1645106Svbart@nginx.com 1646106Svbart@nginx.com member = data; 1647106Svbart@nginx.com 1648106Svbart@nginx.com nxt_conf_get_string(&member->name, &str); 1649106Svbart@nginx.com 1650208Svbart@nginx.com return nxt_strstr_eq(&lhq->key, &str) ? NXT_OK : NXT_DECLINED; 1651106Svbart@nginx.com } 1652106Svbart@nginx.com 1653106Svbart@nginx.com 1654106Svbart@nginx.com static void * 1655106Svbart@nginx.com nxt_conf_object_hash_alloc(void *data, size_t size) 1656106Svbart@nginx.com { 1657106Svbart@nginx.com return nxt_mp_align(data, size, size); 1658106Svbart@nginx.com } 1659106Svbart@nginx.com 1660106Svbart@nginx.com 1661106Svbart@nginx.com static void 1662106Svbart@nginx.com nxt_conf_object_hash_free(void *data, void *p) 1663106Svbart@nginx.com { 1664106Svbart@nginx.com nxt_mp_free(data, p); 1665106Svbart@nginx.com } 1666106Svbart@nginx.com 1667106Svbart@nginx.com 1668106Svbart@nginx.com static u_char * 1669106Svbart@nginx.com nxt_conf_json_parse_array(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start, 1670208Svbart@nginx.com u_char *end, nxt_conf_json_error_t *error) 1671106Svbart@nginx.com { 1672106Svbart@nginx.com u_char *p; 1673106Svbart@nginx.com nxt_mp_t *mp_temp; 1674106Svbart@nginx.com nxt_uint_t count; 1675106Svbart@nginx.com nxt_list_t *list; 1676106Svbart@nginx.com nxt_conf_array_t *array; 1677106Svbart@nginx.com nxt_conf_value_t *element; 1678106Svbart@nginx.com 1679106Svbart@nginx.com mp_temp = nxt_mp_create(1024, 128, 256, 32); 1680106Svbart@nginx.com if (nxt_slow_path(mp_temp == NULL)) { 1681106Svbart@nginx.com return NULL; 1682106Svbart@nginx.com } 1683106Svbart@nginx.com 1684106Svbart@nginx.com list = nxt_list_create(mp_temp, 8, sizeof(nxt_conf_value_t)); 1685106Svbart@nginx.com if (nxt_slow_path(list == NULL)) { 1686106Svbart@nginx.com goto error; 1687106Svbart@nginx.com } 1688106Svbart@nginx.com 1689106Svbart@nginx.com count = 0; 1690130Svbart@nginx.com p = start; 1691130Svbart@nginx.com 1692130Svbart@nginx.com for ( ;; ) { 1693130Svbart@nginx.com p = nxt_conf_json_skip_space(p + 1, end); 1694130Svbart@nginx.com 1695130Svbart@nginx.com if (nxt_slow_path(p == end)) { 1696208Svbart@nginx.com 1697208Svbart@nginx.com nxt_conf_json_parse_error(error, p, 1698311Snick@nginx.com "Unexpected end of JSON payload. There's an array without " 1699311Snick@nginx.com "a closing bracket (])." 1700208Svbart@nginx.com ); 1701208Svbart@nginx.com 1702130Svbart@nginx.com goto error; 1703130Svbart@nginx.com } 1704130Svbart@nginx.com 1705130Svbart@nginx.com if (*p == ']') { 1706130Svbart@nginx.com break; 1707130Svbart@nginx.com } 1708130Svbart@nginx.com 1709130Svbart@nginx.com count++; 1710130Svbart@nginx.com 1711130Svbart@nginx.com element = nxt_list_add(list); 1712130Svbart@nginx.com if (nxt_slow_path(element == NULL)) { 1713130Svbart@nginx.com goto error; 1714130Svbart@nginx.com } 1715130Svbart@nginx.com 1716208Svbart@nginx.com p = nxt_conf_json_parse_value(mp, element, p, end, error); 1717130Svbart@nginx.com 1718130Svbart@nginx.com if (nxt_slow_path(p == NULL)) { 1719130Svbart@nginx.com goto error; 1720130Svbart@nginx.com } 1721130Svbart@nginx.com 1722130Svbart@nginx.com p = nxt_conf_json_skip_space(p, end); 1723130Svbart@nginx.com 1724130Svbart@nginx.com if (nxt_slow_path(p == end)) { 1725208Svbart@nginx.com 1726208Svbart@nginx.com nxt_conf_json_parse_error(error, p, 1727311Snick@nginx.com "Unexpected end of JSON payload. There's an array without " 1728311Snick@nginx.com "a closing bracket (])." 1729208Svbart@nginx.com ); 1730208Svbart@nginx.com 1731130Svbart@nginx.com goto error; 1732130Svbart@nginx.com } 1733130Svbart@nginx.com 1734130Svbart@nginx.com if (*p != ',') { 1735130Svbart@nginx.com if (nxt_fast_path(*p == ']')) { 1736106Svbart@nginx.com break; 1737106Svbart@nginx.com } 1738106Svbart@nginx.com 1739208Svbart@nginx.com nxt_conf_json_parse_error(error, p, 1740311Snick@nginx.com "Either a closing bracket (]) or a comma (,) is expected " 1741311Snick@nginx.com "here. Each array must be enclosed in brackets and its " 1742311Snick@nginx.com "members must be separated by commas." 1743208Svbart@nginx.com ); 1744208Svbart@nginx.com 1745130Svbart@nginx.com goto error; 1746106Svbart@nginx.com } 1747106Svbart@nginx.com } 1748106Svbart@nginx.com 1749106Svbart@nginx.com array = nxt_mp_get(mp, sizeof(nxt_conf_array_t) 1750106Svbart@nginx.com + count * sizeof(nxt_conf_value_t)); 1751106Svbart@nginx.com if (nxt_slow_path(array == NULL)) { 1752106Svbart@nginx.com goto error; 1753106Svbart@nginx.com } 1754106Svbart@nginx.com 1755106Svbart@nginx.com value->u.array = array; 1756116Svbart@nginx.com value->type = NXT_CONF_VALUE_ARRAY; 1757106Svbart@nginx.com 1758106Svbart@nginx.com array->count = count; 1759106Svbart@nginx.com element = array->elements; 1760106Svbart@nginx.com 1761106Svbart@nginx.com nxt_list_each(value, list) { 1762106Svbart@nginx.com *element++ = *value; 1763106Svbart@nginx.com } nxt_list_loop; 1764106Svbart@nginx.com 1765106Svbart@nginx.com nxt_mp_destroy(mp_temp); 1766106Svbart@nginx.com 1767106Svbart@nginx.com return p + 1; 1768106Svbart@nginx.com 1769106Svbart@nginx.com error: 1770106Svbart@nginx.com 1771106Svbart@nginx.com nxt_mp_destroy(mp_temp); 1772106Svbart@nginx.com return NULL; 1773106Svbart@nginx.com } 1774106Svbart@nginx.com 1775106Svbart@nginx.com 1776106Svbart@nginx.com static u_char * 1777106Svbart@nginx.com nxt_conf_json_parse_string(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start, 1778208Svbart@nginx.com u_char *end, nxt_conf_json_error_t *error) 1779106Svbart@nginx.com { 1780106Svbart@nginx.com u_char *p, ch, *last, *s; 1781106Svbart@nginx.com size_t size, surplus; 1782106Svbart@nginx.com uint32_t utf, utf_high; 1783106Svbart@nginx.com nxt_uint_t i; 1784106Svbart@nginx.com enum { 1785106Svbart@nginx.com sw_usual = 0, 1786106Svbart@nginx.com sw_escape, 1787106Svbart@nginx.com sw_encoded1, 1788106Svbart@nginx.com sw_encoded2, 1789106Svbart@nginx.com sw_encoded3, 1790106Svbart@nginx.com sw_encoded4, 1791106Svbart@nginx.com } state; 1792106Svbart@nginx.com 1793106Svbart@nginx.com start++; 1794106Svbart@nginx.com 1795106Svbart@nginx.com state = 0; 1796106Svbart@nginx.com surplus = 0; 1797106Svbart@nginx.com 1798106Svbart@nginx.com for (p = start; nxt_fast_path(p != end); p++) { 1799106Svbart@nginx.com ch = *p; 1800106Svbart@nginx.com 1801106Svbart@nginx.com switch (state) { 1802106Svbart@nginx.com 1803106Svbart@nginx.com case sw_usual: 1804106Svbart@nginx.com 1805106Svbart@nginx.com if (ch == '"') { 1806106Svbart@nginx.com break; 1807106Svbart@nginx.com } 1808106Svbart@nginx.com 1809106Svbart@nginx.com if (ch == '\\') { 1810106Svbart@nginx.com state = sw_escape; 1811106Svbart@nginx.com continue; 1812106Svbart@nginx.com } 1813106Svbart@nginx.com 1814106Svbart@nginx.com if (nxt_fast_path(ch >= ' ')) { 1815106Svbart@nginx.com continue; 1816106Svbart@nginx.com } 1817106Svbart@nginx.com 1818208Svbart@nginx.com nxt_conf_json_parse_error(error, p, 1819311Snick@nginx.com "Unexpected character. All control characters in a JSON " 1820311Snick@nginx.com "string must be escaped." 1821208Svbart@nginx.com ); 1822208Svbart@nginx.com 1823106Svbart@nginx.com return NULL; 1824106Svbart@nginx.com 1825106Svbart@nginx.com case sw_escape: 1826106Svbart@nginx.com 1827106Svbart@nginx.com switch (ch) { 1828106Svbart@nginx.com case '"': 1829106Svbart@nginx.com case '\\': 1830106Svbart@nginx.com case '/': 1831106Svbart@nginx.com case 'n': 1832106Svbart@nginx.com case 'r': 1833106Svbart@nginx.com case 't': 1834106Svbart@nginx.com case 'b': 1835106Svbart@nginx.com case 'f': 1836106Svbart@nginx.com surplus++; 1837106Svbart@nginx.com state = sw_usual; 1838106Svbart@nginx.com continue; 1839106Svbart@nginx.com 1840106Svbart@nginx.com case 'u': 1841106Svbart@nginx.com /* 1842106Svbart@nginx.com * Basic unicode 6 bytes "\uXXXX" in JSON 1843106Svbart@nginx.com * and up to 3 bytes in UTF-8. 1844106Svbart@nginx.com * 1845106Svbart@nginx.com * Surrogate pair: 12 bytes "\uXXXX\uXXXX" in JSON 1846106Svbart@nginx.com * and 3 or 4 bytes in UTF-8. 1847106Svbart@nginx.com */ 1848106Svbart@nginx.com surplus += 3; 1849106Svbart@nginx.com state = sw_encoded1; 1850106Svbart@nginx.com continue; 1851106Svbart@nginx.com } 1852106Svbart@nginx.com 1853208Svbart@nginx.com nxt_conf_json_parse_error(error, p - 1, 1854311Snick@nginx.com "Unexpected backslash. A literal backslash in a JSON string " 1855311Snick@nginx.com "must be escaped with a second backslash (\\\\)." 1856208Svbart@nginx.com ); 1857208Svbart@nginx.com 1858106Svbart@nginx.com return NULL; 1859106Svbart@nginx.com 1860106Svbart@nginx.com case sw_encoded1: 1861106Svbart@nginx.com case sw_encoded2: 1862106Svbart@nginx.com case sw_encoded3: 1863106Svbart@nginx.com case sw_encoded4: 1864106Svbart@nginx.com 1865106Svbart@nginx.com if (nxt_fast_path((ch >= '0' && ch <= '9') 1866202Svbart@nginx.com || (ch >= 'A' && ch <= 'F') 1867202Svbart@nginx.com || (ch >= 'a' && ch <= 'f'))) 1868106Svbart@nginx.com { 1869106Svbart@nginx.com state = (state == sw_encoded4) ? sw_usual : state + 1; 1870106Svbart@nginx.com continue; 1871106Svbart@nginx.com } 1872106Svbart@nginx.com 1873208Svbart@nginx.com nxt_conf_json_parse_error(error, p, 1874311Snick@nginx.com "Invalid escape sequence. An escape sequence in a JSON " 1875311Snick@nginx.com "string must start with a backslash, followed by the lowercase " 1876311Snick@nginx.com "letter u, followed by four hexadecimal digits (\\uXXXX)." 1877208Svbart@nginx.com ); 1878208Svbart@nginx.com 1879106Svbart@nginx.com return NULL; 1880106Svbart@nginx.com } 1881106Svbart@nginx.com 1882106Svbart@nginx.com break; 1883106Svbart@nginx.com } 1884106Svbart@nginx.com 1885106Svbart@nginx.com if (nxt_slow_path(p == end)) { 1886208Svbart@nginx.com 1887208Svbart@nginx.com nxt_conf_json_parse_error(error, p, 1888311Snick@nginx.com "Unexpected end of JSON payload. There's a string without " 1889311Snick@nginx.com "a final double quote (\")." 1890208Svbart@nginx.com ); 1891208Svbart@nginx.com 1892106Svbart@nginx.com return NULL; 1893106Svbart@nginx.com } 1894106Svbart@nginx.com 1895106Svbart@nginx.com /* Points to the ending quote mark. */ 1896106Svbart@nginx.com last = p; 1897106Svbart@nginx.com 1898106Svbart@nginx.com size = last - start - surplus; 1899106Svbart@nginx.com 1900106Svbart@nginx.com if (size > NXT_CONF_MAX_SHORT_STRING) { 1901172Svbart@nginx.com 1902172Svbart@nginx.com if (nxt_slow_path(size > NXT_CONF_MAX_STRING)) { 1903208Svbart@nginx.com 1904208Svbart@nginx.com nxt_conf_json_parse_error(error, start, 1905311Snick@nginx.com "The string is too long. Such a long JSON string value " 1906311Snick@nginx.com "is not supported." 1907208Svbart@nginx.com ); 1908208Svbart@nginx.com 1909106Svbart@nginx.com return NULL; 1910106Svbart@nginx.com } 1911106Svbart@nginx.com 1912172Svbart@nginx.com value->type = NXT_CONF_VALUE_STRING; 1913172Svbart@nginx.com 1914172Svbart@nginx.com value->u.string.start = nxt_mp_nget(mp, size); 1915172Svbart@nginx.com if (nxt_slow_path(value->u.string.start == NULL)) { 1916172Svbart@nginx.com return NULL; 1917172Svbart@nginx.com } 1918172Svbart@nginx.com 1919172Svbart@nginx.com value->u.string.length = size; 1920172Svbart@nginx.com 1921172Svbart@nginx.com s = value->u.string.start; 1922106Svbart@nginx.com 1923106Svbart@nginx.com } else { 1924116Svbart@nginx.com value->type = NXT_CONF_VALUE_SHORT_STRING; 1925173Svbart@nginx.com value->u.str.length = size; 1926173Svbart@nginx.com 1927173Svbart@nginx.com s = value->u.str.start; 1928106Svbart@nginx.com } 1929106Svbart@nginx.com 1930106Svbart@nginx.com if (surplus == 0) { 1931106Svbart@nginx.com nxt_memcpy(s, start, size); 1932106Svbart@nginx.com return last + 1; 1933106Svbart@nginx.com } 1934106Svbart@nginx.com 1935106Svbart@nginx.com p = start; 1936106Svbart@nginx.com 1937106Svbart@nginx.com do { 1938106Svbart@nginx.com ch = *p++; 1939106Svbart@nginx.com 1940106Svbart@nginx.com if (ch != '\\') { 1941106Svbart@nginx.com *s++ = ch; 1942106Svbart@nginx.com continue; 1943106Svbart@nginx.com } 1944106Svbart@nginx.com 1945106Svbart@nginx.com ch = *p++; 1946106Svbart@nginx.com 1947106Svbart@nginx.com switch (ch) { 1948106Svbart@nginx.com case '"': 1949106Svbart@nginx.com case '\\': 1950106Svbart@nginx.com case '/': 1951106Svbart@nginx.com *s++ = ch; 1952106Svbart@nginx.com continue; 1953106Svbart@nginx.com 1954106Svbart@nginx.com case 'n': 1955106Svbart@nginx.com *s++ = '\n'; 1956106Svbart@nginx.com continue; 1957106Svbart@nginx.com 1958106Svbart@nginx.com case 'r': 1959106Svbart@nginx.com *s++ = '\r'; 1960106Svbart@nginx.com continue; 1961106Svbart@nginx.com 1962106Svbart@nginx.com case 't': 1963106Svbart@nginx.com *s++ = '\t'; 1964106Svbart@nginx.com continue; 1965106Svbart@nginx.com 1966106Svbart@nginx.com case 'b': 1967106Svbart@nginx.com *s++ = '\b'; 1968106Svbart@nginx.com continue; 1969106Svbart@nginx.com 1970106Svbart@nginx.com case 'f': 1971106Svbart@nginx.com *s++ = '\f'; 1972106Svbart@nginx.com continue; 1973106Svbart@nginx.com } 1974106Svbart@nginx.com 1975106Svbart@nginx.com utf = 0; 1976106Svbart@nginx.com utf_high = 0; 1977106Svbart@nginx.com 1978106Svbart@nginx.com for ( ;; ) { 1979106Svbart@nginx.com for (i = 0; i < 4; i++) { 1980202Svbart@nginx.com utf = (utf << 4) | (p[i] >= 'A' ? 10 + ((p[i] & ~0x20) - 'A') 1981202Svbart@nginx.com : p[i] - '0'); 1982106Svbart@nginx.com } 1983106Svbart@nginx.com 1984106Svbart@nginx.com p += 4; 1985106Svbart@nginx.com 1986207Svbart@nginx.com if (utf_high != 0) { 1987611Svbart@nginx.com if (nxt_slow_path(utf < 0xDC00 || utf > 0xDFFF)) { 1988208Svbart@nginx.com 1989208Svbart@nginx.com nxt_conf_json_parse_error(error, p - 12, 1990311Snick@nginx.com "Invalid JSON encoding sequence. This 12-byte " 1991311Snick@nginx.com "sequence composes an illegal UTF-16 surrogate pair." 1992208Svbart@nginx.com ); 1993208Svbart@nginx.com 1994207Svbart@nginx.com return NULL; 1995207Svbart@nginx.com } 1996207Svbart@nginx.com 1997611Svbart@nginx.com utf = ((utf_high - 0xD800) << 10) + (utf - 0xDC00) + 0x10000; 1998207Svbart@nginx.com 1999106Svbart@nginx.com break; 2000106Svbart@nginx.com } 2001106Svbart@nginx.com 2002611Svbart@nginx.com if (utf < 0xD800 || utf > 0xDFFF) { 2003106Svbart@nginx.com break; 2004106Svbart@nginx.com } 2005106Svbart@nginx.com 2006611Svbart@nginx.com if (utf > 0xDBFF || p[0] != '\\' || p[1] != 'u') { 2007208Svbart@nginx.com 2008208Svbart@nginx.com nxt_conf_json_parse_error(error, p - 6, 2009311Snick@nginx.com "Invalid JSON encoding sequence. This 6-byte sequence " 2010311Snick@nginx.com "does not represent a valid UTF character." 2011208Svbart@nginx.com ); 2012208Svbart@nginx.com 2013207Svbart@nginx.com return NULL; 2014207Svbart@nginx.com } 2015207Svbart@nginx.com 2016106Svbart@nginx.com p += 2; 2017207Svbart@nginx.com 2018207Svbart@nginx.com utf_high = utf; 2019207Svbart@nginx.com utf = 0; 2020106Svbart@nginx.com } 2021106Svbart@nginx.com 2022106Svbart@nginx.com s = nxt_utf8_encode(s, utf); 2023106Svbart@nginx.com 2024106Svbart@nginx.com } while (p != last); 2025106Svbart@nginx.com 2026106Svbart@nginx.com if (size > NXT_CONF_MAX_SHORT_STRING) { 2027172Svbart@nginx.com value->u.string.length = s - value->u.string.start; 2028106Svbart@nginx.com 2029106Svbart@nginx.com } else { 2030173Svbart@nginx.com value->u.str.length = s - value->u.str.start; 2031106Svbart@nginx.com } 2032106Svbart@nginx.com 2033106Svbart@nginx.com return last + 1; 2034106Svbart@nginx.com } 2035106Svbart@nginx.com 2036106Svbart@nginx.com 2037106Svbart@nginx.com static u_char * 2038106Svbart@nginx.com nxt_conf_json_parse_number(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start, 2039208Svbart@nginx.com u_char *end, nxt_conf_json_error_t *error) 2040106Svbart@nginx.com { 2041*1439Svbart@nginx.com u_char *p, *s, ch, c, *dot_pos; 2042*1439Svbart@nginx.com size_t size; 2043*1439Svbart@nginx.com double num; 2044*1439Svbart@nginx.com 2045*1439Svbart@nginx.com s = start; 2046*1439Svbart@nginx.com ch = *s; 2047106Svbart@nginx.com 2048106Svbart@nginx.com if (ch == '-') { 2049*1439Svbart@nginx.com s++; 2050106Svbart@nginx.com } 2051106Svbart@nginx.com 2052*1439Svbart@nginx.com dot_pos = NULL; 2053*1439Svbart@nginx.com 2054*1439Svbart@nginx.com for (p = s; nxt_fast_path(p != end); p++) { 2055106Svbart@nginx.com ch = *p; 2056106Svbart@nginx.com 2057106Svbart@nginx.com /* Values below '0' become >= 208. */ 2058*1439Svbart@nginx.com c = ch - '0'; 2059*1439Svbart@nginx.com 2060*1439Svbart@nginx.com if (c > 9) { 2061*1439Svbart@nginx.com if (ch == '.' && nxt_fast_path(dot_pos == NULL)) { 2062*1439Svbart@nginx.com dot_pos = p; 2063*1439Svbart@nginx.com continue; 2064*1439Svbart@nginx.com } 2065*1439Svbart@nginx.com 2066106Svbart@nginx.com break; 2067106Svbart@nginx.com } 2068*1439Svbart@nginx.com } 2069*1439Svbart@nginx.com 2070*1439Svbart@nginx.com if (dot_pos != NULL) { 2071*1439Svbart@nginx.com if (nxt_slow_path(p - dot_pos <= 1)) { 2072*1439Svbart@nginx.com nxt_conf_json_parse_error(error, s, 2073*1439Svbart@nginx.com "The number is invalid. A fraction part in JSON numbers " 2074*1439Svbart@nginx.com "must contain at least one digit." 2075208Svbart@nginx.com ); 2076208Svbart@nginx.com 2077208Svbart@nginx.com return NULL; 2078106Svbart@nginx.com } 2079106Svbart@nginx.com 2080*1439Svbart@nginx.com } else { 2081*1439Svbart@nginx.com dot_pos = p; 2082106Svbart@nginx.com } 2083106Svbart@nginx.com 2084*1439Svbart@nginx.com if (nxt_slow_path(dot_pos - s > 1 && *start == '0')) { 2085*1439Svbart@nginx.com nxt_conf_json_parse_error(error, s, 2086311Snick@nginx.com "The number is invalid. Leading zeros are not allowed in JSON " 2087311Snick@nginx.com "numbers." 2088208Svbart@nginx.com ); 2089208Svbart@nginx.com 2090106Svbart@nginx.com return NULL; 2091106Svbart@nginx.com } 2092106Svbart@nginx.com 2093*1439Svbart@nginx.com if (ch == 'e' || ch == 'E') { 2094*1439Svbart@nginx.com p++; 2095*1439Svbart@nginx.com s = p; 2096*1439Svbart@nginx.com 2097*1439Svbart@nginx.com if (nxt_fast_path(s != end)) { 2098*1439Svbart@nginx.com ch = *s; 2099*1439Svbart@nginx.com 2100*1439Svbart@nginx.com if (ch == '-' || ch == '+') { 2101*1439Svbart@nginx.com s++; 2102*1439Svbart@nginx.com } 2103*1439Svbart@nginx.com 2104*1439Svbart@nginx.com for (p = s; nxt_fast_path(p != end); p++) { 2105*1439Svbart@nginx.com ch = *p; 2106*1439Svbart@nginx.com 2107*1439Svbart@nginx.com /* Values below '0' become >= 208. */ 2108*1439Svbart@nginx.com c = ch - '0'; 2109*1439Svbart@nginx.com 2110*1439Svbart@nginx.com if (c > 9) { 2111*1439Svbart@nginx.com break; 2112*1439Svbart@nginx.com } 2113*1439Svbart@nginx.com } 2114106Svbart@nginx.com } 2115106Svbart@nginx.com 2116*1439Svbart@nginx.com if (nxt_slow_path(p == s)) { 2117*1439Svbart@nginx.com nxt_conf_json_parse_error(error, start, 2118*1439Svbart@nginx.com "The number is invalid. An exponent part in JSON numbers " 2119*1439Svbart@nginx.com "must contain at least one digit." 2120*1439Svbart@nginx.com ); 2121*1439Svbart@nginx.com 2122106Svbart@nginx.com return NULL; 2123106Svbart@nginx.com } 2124106Svbart@nginx.com } 2125106Svbart@nginx.com 2126*1439Svbart@nginx.com size = p - start; 2127*1439Svbart@nginx.com 2128*1439Svbart@nginx.com if (size > NXT_CONF_MAX_NUMBER_LEN) { 2129*1439Svbart@nginx.com nxt_conf_json_parse_error(error, start, 2130*1439Svbart@nginx.com "The number is too long. Such a long JSON number value " 2131*1439Svbart@nginx.com "is not supported." 2132*1439Svbart@nginx.com ); 2133*1439Svbart@nginx.com 2134106Svbart@nginx.com return NULL; 2135106Svbart@nginx.com } 2136106Svbart@nginx.com 2137*1439Svbart@nginx.com nxt_memcpy(value->u.number, start, size); 2138*1439Svbart@nginx.com value->u.number[size] = '\0'; 2139*1439Svbart@nginx.com 2140*1439Svbart@nginx.com nxt_errno = 0; 2141*1439Svbart@nginx.com end = NULL; 2142*1439Svbart@nginx.com 2143*1439Svbart@nginx.com num = nxt_strtod(value->u.number, &end); 2144*1439Svbart@nginx.com 2145*1439Svbart@nginx.com if (nxt_slow_path(nxt_errno == NXT_ERANGE || fabs(num) > NXT_INT64_T_MAX)) { 2146*1439Svbart@nginx.com nxt_conf_json_parse_error(error, start, 2147*1439Svbart@nginx.com "The number is out of representable range. Such JSON number " 2148*1439Svbart@nginx.com "value is not supported." 2149*1439Svbart@nginx.com ); 2150*1439Svbart@nginx.com 2151*1439Svbart@nginx.com return NULL; 2152106Svbart@nginx.com } 2153106Svbart@nginx.com 2154*1439Svbart@nginx.com if (nxt_slow_path(end == NULL || *end != '\0')) { 2155*1439Svbart@nginx.com nxt_thread_log_alert("strtod(\"%s\", %s) failed %E", value->u.number, 2156*1439Svbart@nginx.com end == NULL ? (u_char *) "NULL" : end, nxt_errno); 2157*1439Svbart@nginx.com return NULL; 2158106Svbart@nginx.com } 2159*1439Svbart@nginx.com 2160*1439Svbart@nginx.com value->type = (num == trunc(num)) ? NXT_CONF_VALUE_INTEGER 2161*1439Svbart@nginx.com : NXT_CONF_VALUE_NUMBER; 2162*1439Svbart@nginx.com 2163*1439Svbart@nginx.com return p; 2164106Svbart@nginx.com } 2165106Svbart@nginx.com 2166106Svbart@nginx.com 2167208Svbart@nginx.com static void 2168208Svbart@nginx.com nxt_conf_json_parse_error(nxt_conf_json_error_t *error, u_char *pos, 2169208Svbart@nginx.com const char *detail) 2170208Svbart@nginx.com { 2171208Svbart@nginx.com if (error == NULL) { 2172208Svbart@nginx.com return; 2173208Svbart@nginx.com } 2174208Svbart@nginx.com 2175208Svbart@nginx.com error->pos = pos; 2176208Svbart@nginx.com error->detail = (u_char *) detail; 2177208Svbart@nginx.com } 2178208Svbart@nginx.com 2179208Svbart@nginx.com 2180106Svbart@nginx.com size_t 2181106Svbart@nginx.com nxt_conf_json_length(nxt_conf_value_t *value, nxt_conf_json_pretty_t *pretty) 2182106Svbart@nginx.com { 2183106Svbart@nginx.com switch (value->type) { 2184106Svbart@nginx.com 2185116Svbart@nginx.com case NXT_CONF_VALUE_NULL: 2186703Svbart@nginx.com return nxt_length("null"); 2187106Svbart@nginx.com 2188116Svbart@nginx.com case NXT_CONF_VALUE_BOOLEAN: 2189703Svbart@nginx.com return value->u.boolean ? nxt_length("true") : nxt_length("false"); 2190106Svbart@nginx.com 2191116Svbart@nginx.com case NXT_CONF_VALUE_INTEGER: 2192116Svbart@nginx.com case NXT_CONF_VALUE_NUMBER: 2193*1439Svbart@nginx.com return nxt_strlen(value->u.number); 2194106Svbart@nginx.com 2195116Svbart@nginx.com case NXT_CONF_VALUE_SHORT_STRING: 2196116Svbart@nginx.com case NXT_CONF_VALUE_STRING: 2197106Svbart@nginx.com return nxt_conf_json_string_length(value); 2198106Svbart@nginx.com 2199116Svbart@nginx.com case NXT_CONF_VALUE_ARRAY: 2200106Svbart@nginx.com return nxt_conf_json_array_length(value, pretty); 2201106Svbart@nginx.com 2202116Svbart@nginx.com case NXT_CONF_VALUE_OBJECT: 2203106Svbart@nginx.com return nxt_conf_json_object_length(value, pretty); 2204106Svbart@nginx.com } 2205106Svbart@nginx.com 2206106Svbart@nginx.com nxt_unreachable(); 2207106Svbart@nginx.com 2208106Svbart@nginx.com return 0; 2209106Svbart@nginx.com } 2210106Svbart@nginx.com 2211106Svbart@nginx.com 2212106Svbart@nginx.com u_char * 2213106Svbart@nginx.com nxt_conf_json_print(u_char *p, nxt_conf_value_t *value, 2214106Svbart@nginx.com nxt_conf_json_pretty_t *pretty) 2215106Svbart@nginx.com { 2216106Svbart@nginx.com switch (value->type) { 2217106Svbart@nginx.com 2218116Svbart@nginx.com case NXT_CONF_VALUE_NULL: 2219106Svbart@nginx.com return nxt_cpymem(p, "null", 4); 2220106Svbart@nginx.com 2221116Svbart@nginx.com case NXT_CONF_VALUE_BOOLEAN: 2222106Svbart@nginx.com return value->u.boolean ? nxt_cpymem(p, "true", 4) 2223106Svbart@nginx.com : nxt_cpymem(p, "false", 5); 2224106Svbart@nginx.com 2225116Svbart@nginx.com case NXT_CONF_VALUE_INTEGER: 2226116Svbart@nginx.com case NXT_CONF_VALUE_NUMBER: 2227*1439Svbart@nginx.com return nxt_cpystr(p, value->u.number); 2228106Svbart@nginx.com 2229116Svbart@nginx.com case NXT_CONF_VALUE_SHORT_STRING: 2230116Svbart@nginx.com case NXT_CONF_VALUE_STRING: 2231106Svbart@nginx.com return nxt_conf_json_print_string(p, value); 2232106Svbart@nginx.com 2233116Svbart@nginx.com case NXT_CONF_VALUE_ARRAY: 2234106Svbart@nginx.com return nxt_conf_json_print_array(p, value, pretty); 2235106Svbart@nginx.com 2236116Svbart@nginx.com case NXT_CONF_VALUE_OBJECT: 2237106Svbart@nginx.com return nxt_conf_json_print_object(p, value, pretty); 2238106Svbart@nginx.com } 2239106Svbart@nginx.com 2240106Svbart@nginx.com nxt_unreachable(); 2241106Svbart@nginx.com 2242106Svbart@nginx.com return p; 2243106Svbart@nginx.com } 2244106Svbart@nginx.com 2245106Svbart@nginx.com 2246106Svbart@nginx.com static size_t 2247106Svbart@nginx.com nxt_conf_json_string_length(nxt_conf_value_t *value) 2248106Svbart@nginx.com { 2249106Svbart@nginx.com nxt_str_t str; 2250106Svbart@nginx.com 2251106Svbart@nginx.com nxt_conf_get_string(value, &str); 2252106Svbart@nginx.com 2253106Svbart@nginx.com return 2 + nxt_conf_json_escape_length(str.start, str.length); 2254106Svbart@nginx.com } 2255106Svbart@nginx.com 2256106Svbart@nginx.com 2257106Svbart@nginx.com static u_char * 2258106Svbart@nginx.com nxt_conf_json_print_string(u_char *p, nxt_conf_value_t *value) 2259106Svbart@nginx.com { 2260106Svbart@nginx.com nxt_str_t str; 2261106Svbart@nginx.com 2262106Svbart@nginx.com nxt_conf_get_string(value, &str); 2263106Svbart@nginx.com 2264106Svbart@nginx.com *p++ = '"'; 2265106Svbart@nginx.com 2266106Svbart@nginx.com p = nxt_conf_json_escape(p, str.start, str.length); 2267106Svbart@nginx.com 2268106Svbart@nginx.com *p++ = '"'; 2269106Svbart@nginx.com 2270106Svbart@nginx.com return p; 2271106Svbart@nginx.com } 2272106Svbart@nginx.com 2273106Svbart@nginx.com 2274106Svbart@nginx.com static size_t 2275106Svbart@nginx.com nxt_conf_json_array_length(nxt_conf_value_t *value, 2276106Svbart@nginx.com nxt_conf_json_pretty_t *pretty) 2277106Svbart@nginx.com { 2278106Svbart@nginx.com size_t len; 2279106Svbart@nginx.com nxt_uint_t n; 2280106Svbart@nginx.com nxt_conf_array_t *array; 2281106Svbart@nginx.com 2282106Svbart@nginx.com array = value->u.array; 2283106Svbart@nginx.com 2284106Svbart@nginx.com /* [] */ 2285106Svbart@nginx.com len = 2; 2286106Svbart@nginx.com 2287106Svbart@nginx.com if (pretty != NULL) { 2288106Svbart@nginx.com pretty->level++; 2289106Svbart@nginx.com } 2290106Svbart@nginx.com 2291106Svbart@nginx.com value = array->elements; 2292106Svbart@nginx.com 2293106Svbart@nginx.com for (n = 0; n < array->count; n++) { 2294106Svbart@nginx.com len += nxt_conf_json_length(&value[n], pretty); 2295106Svbart@nginx.com 2296106Svbart@nginx.com if (pretty != NULL) { 2297106Svbart@nginx.com /* Indentation and new line. */ 2298106Svbart@nginx.com len += pretty->level + 2; 2299106Svbart@nginx.com } 2300106Svbart@nginx.com } 2301106Svbart@nginx.com 2302106Svbart@nginx.com if (pretty != NULL) { 2303106Svbart@nginx.com pretty->level--; 2304106Svbart@nginx.com 2305106Svbart@nginx.com if (n != 0) { 2306106Svbart@nginx.com /* Indentation and new line. */ 2307106Svbart@nginx.com len += pretty->level + 2; 2308106Svbart@nginx.com } 2309106Svbart@nginx.com } 2310106Svbart@nginx.com 2311106Svbart@nginx.com /* Reserve space for "n" commas. */ 2312106Svbart@nginx.com return len + n; 2313106Svbart@nginx.com } 2314106Svbart@nginx.com 2315106Svbart@nginx.com 2316106Svbart@nginx.com static u_char * 2317106Svbart@nginx.com nxt_conf_json_print_array(u_char *p, nxt_conf_value_t *value, 2318106Svbart@nginx.com nxt_conf_json_pretty_t *pretty) 2319106Svbart@nginx.com { 2320106Svbart@nginx.com nxt_uint_t n; 2321106Svbart@nginx.com nxt_conf_array_t *array; 2322106Svbart@nginx.com 2323106Svbart@nginx.com array = value->u.array; 2324106Svbart@nginx.com 2325106Svbart@nginx.com *p++ = '['; 2326106Svbart@nginx.com 2327106Svbart@nginx.com if (array->count != 0) { 2328106Svbart@nginx.com value = array->elements; 2329106Svbart@nginx.com 2330106Svbart@nginx.com if (pretty != NULL) { 2331106Svbart@nginx.com p = nxt_conf_json_newline(p); 2332106Svbart@nginx.com 2333106Svbart@nginx.com pretty->level++; 2334106Svbart@nginx.com p = nxt_conf_json_indentation(p, pretty->level); 2335106Svbart@nginx.com } 2336106Svbart@nginx.com 2337106Svbart@nginx.com p = nxt_conf_json_print(p, &value[0], pretty); 2338106Svbart@nginx.com 2339106Svbart@nginx.com for (n = 1; n < array->count; n++) { 2340106Svbart@nginx.com *p++ = ','; 2341106Svbart@nginx.com 2342106Svbart@nginx.com if (pretty != NULL) { 2343106Svbart@nginx.com p = nxt_conf_json_newline(p); 2344106Svbart@nginx.com p = nxt_conf_json_indentation(p, pretty->level); 2345106Svbart@nginx.com 2346106Svbart@nginx.com pretty->more_space = 0; 2347106Svbart@nginx.com } 2348106Svbart@nginx.com 2349106Svbart@nginx.com p = nxt_conf_json_print(p, &value[n], pretty); 2350106Svbart@nginx.com } 2351106Svbart@nginx.com 2352106Svbart@nginx.com if (pretty != NULL) { 2353106Svbart@nginx.com p = nxt_conf_json_newline(p); 2354106Svbart@nginx.com 2355106Svbart@nginx.com pretty->level--; 2356106Svbart@nginx.com p = nxt_conf_json_indentation(p, pretty->level); 2357106Svbart@nginx.com 2358106Svbart@nginx.com pretty->more_space = 1; 2359106Svbart@nginx.com } 2360106Svbart@nginx.com } 2361106Svbart@nginx.com 2362106Svbart@nginx.com *p++ = ']'; 2363106Svbart@nginx.com 2364106Svbart@nginx.com return p; 2365106Svbart@nginx.com } 2366106Svbart@nginx.com 2367106Svbart@nginx.com 2368106Svbart@nginx.com static size_t 2369106Svbart@nginx.com nxt_conf_json_object_length(nxt_conf_value_t *value, 2370106Svbart@nginx.com nxt_conf_json_pretty_t *pretty) 2371106Svbart@nginx.com { 2372106Svbart@nginx.com size_t len; 2373106Svbart@nginx.com nxt_uint_t n; 2374106Svbart@nginx.com nxt_conf_object_t *object; 2375106Svbart@nginx.com nxt_conf_object_member_t *member; 2376106Svbart@nginx.com 2377106Svbart@nginx.com object = value->u.object; 2378106Svbart@nginx.com 2379106Svbart@nginx.com /* {} */ 2380106Svbart@nginx.com len = 2; 2381106Svbart@nginx.com 2382106Svbart@nginx.com if (pretty != NULL) { 2383106Svbart@nginx.com pretty->level++; 2384106Svbart@nginx.com } 2385106Svbart@nginx.com 2386106Svbart@nginx.com member = object->members; 2387106Svbart@nginx.com 2388106Svbart@nginx.com for (n = 0; n < object->count; n++) { 2389106Svbart@nginx.com len += nxt_conf_json_string_length(&member[n].name) + 1 2390106Svbart@nginx.com + nxt_conf_json_length(&member[n].value, pretty) + 1; 2391106Svbart@nginx.com 2392106Svbart@nginx.com if (pretty != NULL) { 2393106Svbart@nginx.com /* 2394106Svbart@nginx.com * Indentation, space after ":", new line, and possible 2395106Svbart@nginx.com * additional empty line between non-empty objects. 2396106Svbart@nginx.com */ 2397106Svbart@nginx.com len += pretty->level + 1 + 2 + 2; 2398106Svbart@nginx.com } 2399106Svbart@nginx.com } 2400106Svbart@nginx.com 2401106Svbart@nginx.com if (pretty != NULL) { 2402106Svbart@nginx.com pretty->level--; 2403106Svbart@nginx.com 2404106Svbart@nginx.com /* Indentation and new line. */ 2405106Svbart@nginx.com len += pretty->level + 2; 2406106Svbart@nginx.com } 2407106Svbart@nginx.com 2408106Svbart@nginx.com return len; 2409106Svbart@nginx.com } 2410106Svbart@nginx.com 2411106Svbart@nginx.com 2412106Svbart@nginx.com static u_char * 2413106Svbart@nginx.com nxt_conf_json_print_object(u_char *p, nxt_conf_value_t *value, 2414106Svbart@nginx.com nxt_conf_json_pretty_t *pretty) 2415106Svbart@nginx.com { 2416106Svbart@nginx.com nxt_uint_t n; 2417106Svbart@nginx.com nxt_conf_object_t *object; 2418106Svbart@nginx.com nxt_conf_object_member_t *member; 2419106Svbart@nginx.com 2420106Svbart@nginx.com object = value->u.object; 2421106Svbart@nginx.com 2422106Svbart@nginx.com *p++ = '{'; 2423106Svbart@nginx.com 2424106Svbart@nginx.com if (object->count != 0) { 2425106Svbart@nginx.com 2426106Svbart@nginx.com if (pretty != NULL) { 2427106Svbart@nginx.com p = nxt_conf_json_newline(p); 2428106Svbart@nginx.com pretty->level++; 2429106Svbart@nginx.com } 2430106Svbart@nginx.com 2431106Svbart@nginx.com member = object->members; 2432106Svbart@nginx.com 2433106Svbart@nginx.com n = 0; 2434106Svbart@nginx.com 2435106Svbart@nginx.com for ( ;; ) { 2436106Svbart@nginx.com if (pretty != NULL) { 2437106Svbart@nginx.com p = nxt_conf_json_indentation(p, pretty->level); 2438106Svbart@nginx.com } 2439106Svbart@nginx.com 2440106Svbart@nginx.com p = nxt_conf_json_print_string(p, &member[n].name); 2441106Svbart@nginx.com 2442106Svbart@nginx.com *p++ = ':'; 2443106Svbart@nginx.com 2444106Svbart@nginx.com if (pretty != NULL) { 2445106Svbart@nginx.com *p++ = ' '; 2446106Svbart@nginx.com } 2447106Svbart@nginx.com 2448106Svbart@nginx.com p = nxt_conf_json_print(p, &member[n].value, pretty); 2449106Svbart@nginx.com 2450106Svbart@nginx.com n++; 2451106Svbart@nginx.com 2452106Svbart@nginx.com if (n == object->count) { 2453106Svbart@nginx.com break; 2454106Svbart@nginx.com } 2455106Svbart@nginx.com 2456106Svbart@nginx.com *p++ = ','; 2457106Svbart@nginx.com 2458106Svbart@nginx.com if (pretty != NULL) { 2459106Svbart@nginx.com p = nxt_conf_json_newline(p); 2460106Svbart@nginx.com 2461106Svbart@nginx.com if (pretty->more_space) { 2462106Svbart@nginx.com pretty->more_space = 0; 2463106Svbart@nginx.com p = nxt_conf_json_newline(p); 2464106Svbart@nginx.com } 2465106Svbart@nginx.com } 2466106Svbart@nginx.com } 2467106Svbart@nginx.com 2468106Svbart@nginx.com if (pretty != NULL) { 2469106Svbart@nginx.com p = nxt_conf_json_newline(p); 2470106Svbart@nginx.com 2471106Svbart@nginx.com pretty->level--; 2472106Svbart@nginx.com p = nxt_conf_json_indentation(p, pretty->level); 2473106Svbart@nginx.com 2474106Svbart@nginx.com pretty->more_space = 1; 2475106Svbart@nginx.com } 2476106Svbart@nginx.com } 2477106Svbart@nginx.com 2478106Svbart@nginx.com *p++ = '}'; 2479106Svbart@nginx.com 2480106Svbart@nginx.com return p; 2481106Svbart@nginx.com } 2482106Svbart@nginx.com 2483106Svbart@nginx.com 2484106Svbart@nginx.com static size_t 2485106Svbart@nginx.com nxt_conf_json_escape_length(u_char *p, size_t size) 2486106Svbart@nginx.com { 2487106Svbart@nginx.com u_char ch; 2488106Svbart@nginx.com size_t len; 2489106Svbart@nginx.com 2490106Svbart@nginx.com len = size; 2491106Svbart@nginx.com 2492106Svbart@nginx.com while (size) { 2493106Svbart@nginx.com ch = *p++; 2494106Svbart@nginx.com 2495106Svbart@nginx.com if (ch == '\\' || ch == '"') { 2496106Svbart@nginx.com len++; 2497106Svbart@nginx.com 2498611Svbart@nginx.com } else if (ch <= 0x1F) { 2499106Svbart@nginx.com 2500106Svbart@nginx.com switch (ch) { 2501106Svbart@nginx.com case '\n': 2502106Svbart@nginx.com case '\r': 2503106Svbart@nginx.com case '\t': 2504106Svbart@nginx.com case '\b': 2505106Svbart@nginx.com case '\f': 2506106Svbart@nginx.com len++; 2507106Svbart@nginx.com break; 2508106Svbart@nginx.com 2509106Svbart@nginx.com default: 2510106Svbart@nginx.com len += sizeof("\\u001F") - 2; 2511106Svbart@nginx.com } 2512106Svbart@nginx.com } 2513106Svbart@nginx.com 2514106Svbart@nginx.com size--; 2515106Svbart@nginx.com } 2516106Svbart@nginx.com 2517106Svbart@nginx.com return len; 2518106Svbart@nginx.com } 2519106Svbart@nginx.com 2520106Svbart@nginx.com 2521106Svbart@nginx.com static u_char * 2522106Svbart@nginx.com nxt_conf_json_escape(u_char *dst, u_char *src, size_t size) 2523106Svbart@nginx.com { 2524106Svbart@nginx.com u_char ch; 2525106Svbart@nginx.com 2526106Svbart@nginx.com while (size) { 2527106Svbart@nginx.com ch = *src++; 2528106Svbart@nginx.com 2529611Svbart@nginx.com if (ch > 0x1F) { 2530106Svbart@nginx.com 2531106Svbart@nginx.com if (ch == '\\' || ch == '"') { 2532106Svbart@nginx.com *dst++ = '\\'; 2533106Svbart@nginx.com } 2534106Svbart@nginx.com 2535106Svbart@nginx.com *dst++ = ch; 2536106Svbart@nginx.com 2537106Svbart@nginx.com } else { 2538106Svbart@nginx.com *dst++ = '\\'; 2539106Svbart@nginx.com 2540106Svbart@nginx.com switch (ch) { 2541106Svbart@nginx.com case '\n': 2542106Svbart@nginx.com *dst++ = 'n'; 2543106Svbart@nginx.com break; 2544106Svbart@nginx.com 2545106Svbart@nginx.com case '\r': 2546106Svbart@nginx.com *dst++ = 'r'; 2547106Svbart@nginx.com break; 2548106Svbart@nginx.com 2549106Svbart@nginx.com case '\t': 2550106Svbart@nginx.com *dst++ = 't'; 2551106Svbart@nginx.com break; 2552106Svbart@nginx.com 2553106Svbart@nginx.com case '\b': 2554106Svbart@nginx.com *dst++ = 'b'; 2555106Svbart@nginx.com break; 2556106Svbart@nginx.com 2557106Svbart@nginx.com case '\f': 2558106Svbart@nginx.com *dst++ = 'f'; 2559106Svbart@nginx.com break; 2560106Svbart@nginx.com 2561106Svbart@nginx.com default: 2562106Svbart@nginx.com *dst++ = 'u'; *dst++ = '0'; *dst++ = '0'; 2563106Svbart@nginx.com *dst++ = '0' + (ch >> 4); 2564106Svbart@nginx.com 2565611Svbart@nginx.com ch &= 0xF; 2566106Svbart@nginx.com 2567106Svbart@nginx.com *dst++ = (ch < 10) ? ('0' + ch) : ('A' + ch - 10); 2568106Svbart@nginx.com } 2569106Svbart@nginx.com } 2570106Svbart@nginx.com 2571106Svbart@nginx.com size--; 2572106Svbart@nginx.com } 2573106Svbart@nginx.com 2574106Svbart@nginx.com return dst; 2575106Svbart@nginx.com } 2576208Svbart@nginx.com 2577208Svbart@nginx.com 2578208Svbart@nginx.com void 2579208Svbart@nginx.com nxt_conf_json_position(u_char *start, u_char *pos, nxt_uint_t *line, 2580208Svbart@nginx.com nxt_uint_t *column) 2581208Svbart@nginx.com { 2582208Svbart@nginx.com u_char *p; 2583208Svbart@nginx.com ssize_t symbols; 2584208Svbart@nginx.com nxt_uint_t lines; 2585208Svbart@nginx.com 2586208Svbart@nginx.com lines = 1; 2587208Svbart@nginx.com 2588208Svbart@nginx.com for (p = start; p != pos; p++) { 2589208Svbart@nginx.com 2590208Svbart@nginx.com if (*p != '\n') { 2591208Svbart@nginx.com continue; 2592208Svbart@nginx.com } 2593208Svbart@nginx.com 2594208Svbart@nginx.com lines++; 2595208Svbart@nginx.com start = p + 1; 2596208Svbart@nginx.com } 2597208Svbart@nginx.com 2598208Svbart@nginx.com symbols = nxt_utf8_length(start, p - start); 2599208Svbart@nginx.com 2600208Svbart@nginx.com if (symbols != -1) { 2601208Svbart@nginx.com *line = lines; 2602208Svbart@nginx.com *column = 1 + symbols; 2603208Svbart@nginx.com } 2604208Svbart@nginx.com } 2605