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> 10106Svbart@nginx.com #if 0 11106Svbart@nginx.com #include <math.h> 12106Svbart@nginx.com #include <float.h> 13106Svbart@nginx.com #endif 14106Svbart@nginx.com 15106Svbart@nginx.com 16106Svbart@nginx.com #define NXT_CONF_MAX_SHORT_STRING 14 17172Svbart@nginx.com #define NXT_CONF_MAX_STRING NXT_INT32_T_MAX 18106Svbart@nginx.com 19*1174Svbart@nginx.com #define NXT_CONF_MAX_TOKEN_LEN 256 20*1174Svbart@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. */ 49106Svbart@nginx.com int64_t integer; 50106Svbart@nginx.com double number; 51173Svbart@nginx.com 52173Svbart@nginx.com struct { 53208Svbart@nginx.com u_char start[NXT_CONF_MAX_SHORT_STRING]; 54173Svbart@nginx.com uint8_t length; 55173Svbart@nginx.com } str; 56172Svbart@nginx.com 57187Smax.romanov@nginx.com struct { 58172Svbart@nginx.com u_char *start; 59172Svbart@nginx.com uint32_t length; 60187Smax.romanov@nginx.com } nxt_packed string; 61172Svbart@nginx.com 62106Svbart@nginx.com nxt_conf_array_t *array; 63106Svbart@nginx.com nxt_conf_object_t *object; 64187Smax.romanov@nginx.com } nxt_packed u; 65106Svbart@nginx.com 66171Svbart@nginx.com uint8_t type; /* 3 bits. */ 67180Smax.romanov@nginx.com } nxt_aligned(8); 68106Svbart@nginx.com 69106Svbart@nginx.com 70106Svbart@nginx.com struct nxt_conf_array_s { 71106Svbart@nginx.com nxt_uint_t count; 72106Svbart@nginx.com nxt_conf_value_t elements[]; 73106Svbart@nginx.com }; 74106Svbart@nginx.com 75106Svbart@nginx.com 76106Svbart@nginx.com typedef struct { 77106Svbart@nginx.com nxt_conf_value_t name; 78106Svbart@nginx.com nxt_conf_value_t value; 79106Svbart@nginx.com } nxt_conf_object_member_t; 80106Svbart@nginx.com 81106Svbart@nginx.com 82106Svbart@nginx.com struct nxt_conf_object_s { 83106Svbart@nginx.com nxt_uint_t count; 84106Svbart@nginx.com nxt_conf_object_member_t members[]; 85106Svbart@nginx.com }; 86106Svbart@nginx.com 87106Svbart@nginx.com 88106Svbart@nginx.com struct nxt_conf_op_s { 89106Svbart@nginx.com uint32_t index; 90106Svbart@nginx.com uint32_t action; /* nxt_conf_op_action_t */ 91106Svbart@nginx.com void *ctx; 92106Svbart@nginx.com }; 93106Svbart@nginx.com 94106Svbart@nginx.com 95*1174Svbart@nginx.com typedef struct { 96*1174Svbart@nginx.com u_char *start; 97*1174Svbart@nginx.com u_char *end; 98*1174Svbart@nginx.com nxt_bool_t last; 99*1174Svbart@nginx.com u_char buf[NXT_CONF_MAX_TOKEN_LEN]; 100*1174Svbart@nginx.com } nxt_conf_path_parse_t; 101*1174Svbart@nginx.com 102*1174Svbart@nginx.com 103*1174Svbart@nginx.com static nxt_int_t nxt_conf_path_next_token(nxt_conf_path_parse_t *parse, 104*1174Svbart@nginx.com nxt_str_t *token); 105*1174Svbart@nginx.com 106106Svbart@nginx.com static u_char *nxt_conf_json_skip_space(u_char *start, u_char *end); 107106Svbart@nginx.com static u_char *nxt_conf_json_parse_value(nxt_mp_t *mp, nxt_conf_value_t *value, 108208Svbart@nginx.com u_char *start, u_char *end, nxt_conf_json_error_t *error); 109106Svbart@nginx.com static u_char *nxt_conf_json_parse_object(nxt_mp_t *mp, nxt_conf_value_t *value, 110208Svbart@nginx.com u_char *start, u_char *end, nxt_conf_json_error_t *error); 111106Svbart@nginx.com static nxt_int_t nxt_conf_object_hash_add(nxt_mp_t *mp, 112106Svbart@nginx.com nxt_lvlhsh_t *lvlhsh, nxt_conf_object_member_t *member); 113106Svbart@nginx.com static nxt_int_t nxt_conf_object_hash_test(nxt_lvlhsh_query_t *lhq, 114106Svbart@nginx.com void *data); 115106Svbart@nginx.com static void *nxt_conf_object_hash_alloc(void *data, size_t size); 116106Svbart@nginx.com static void nxt_conf_object_hash_free(void *data, void *p); 117106Svbart@nginx.com static u_char *nxt_conf_json_parse_array(nxt_mp_t *mp, nxt_conf_value_t *value, 118208Svbart@nginx.com u_char *start, u_char *end, nxt_conf_json_error_t *error); 119106Svbart@nginx.com static u_char *nxt_conf_json_parse_string(nxt_mp_t *mp, nxt_conf_value_t *value, 120208Svbart@nginx.com u_char *start, u_char *end, nxt_conf_json_error_t *error); 121106Svbart@nginx.com static u_char *nxt_conf_json_parse_number(nxt_mp_t *mp, nxt_conf_value_t *value, 122208Svbart@nginx.com u_char *start, u_char *end, nxt_conf_json_error_t *error); 123208Svbart@nginx.com static void nxt_conf_json_parse_error(nxt_conf_json_error_t *error, u_char *pos, 124208Svbart@nginx.com const char *detail); 125106Svbart@nginx.com 126106Svbart@nginx.com static nxt_int_t nxt_conf_copy_value(nxt_mp_t *mp, nxt_conf_op_t *op, 127106Svbart@nginx.com nxt_conf_value_t *dst, nxt_conf_value_t *src); 1281048Svbart@nginx.com static nxt_int_t nxt_conf_copy_array(nxt_mp_t *mp, nxt_conf_op_t *op, 1291048Svbart@nginx.com nxt_conf_value_t *dst, nxt_conf_value_t *src); 130106Svbart@nginx.com static nxt_int_t nxt_conf_copy_object(nxt_mp_t *mp, nxt_conf_op_t *op, 131106Svbart@nginx.com nxt_conf_value_t *dst, nxt_conf_value_t *src); 132106Svbart@nginx.com 133106Svbart@nginx.com static size_t nxt_conf_json_integer_length(nxt_conf_value_t *value); 134106Svbart@nginx.com static u_char *nxt_conf_json_print_integer(u_char *p, nxt_conf_value_t *value); 135106Svbart@nginx.com static size_t nxt_conf_json_string_length(nxt_conf_value_t *value); 136106Svbart@nginx.com static u_char *nxt_conf_json_print_string(u_char *p, nxt_conf_value_t *value); 137106Svbart@nginx.com static size_t nxt_conf_json_array_length(nxt_conf_value_t *value, 138106Svbart@nginx.com nxt_conf_json_pretty_t *pretty); 139106Svbart@nginx.com static u_char *nxt_conf_json_print_array(u_char *p, nxt_conf_value_t *value, 140106Svbart@nginx.com nxt_conf_json_pretty_t *pretty); 141106Svbart@nginx.com static size_t nxt_conf_json_object_length(nxt_conf_value_t *value, 142106Svbart@nginx.com nxt_conf_json_pretty_t *pretty); 143106Svbart@nginx.com static u_char *nxt_conf_json_print_object(u_char *p, nxt_conf_value_t *value, 144106Svbart@nginx.com nxt_conf_json_pretty_t *pretty); 145106Svbart@nginx.com 146106Svbart@nginx.com static size_t nxt_conf_json_escape_length(u_char *p, size_t size); 147106Svbart@nginx.com static u_char *nxt_conf_json_escape(u_char *dst, u_char *src, size_t size); 148106Svbart@nginx.com 149106Svbart@nginx.com 150106Svbart@nginx.com #define nxt_conf_json_newline(p) \ 151106Svbart@nginx.com ((p)[0] = '\r', (p)[1] = '\n', (p) + 2) 152106Svbart@nginx.com 153106Svbart@nginx.com 154106Svbart@nginx.com nxt_inline u_char * 155106Svbart@nginx.com nxt_conf_json_indentation(u_char *p, uint32_t level) 156106Svbart@nginx.com { 157106Svbart@nginx.com while (level) { 158106Svbart@nginx.com *p++ = '\t'; 159106Svbart@nginx.com level--; 160106Svbart@nginx.com } 161106Svbart@nginx.com 162106Svbart@nginx.com return p; 163106Svbart@nginx.com } 164106Svbart@nginx.com 165106Svbart@nginx.com 166121Svbart@nginx.com void 167106Svbart@nginx.com nxt_conf_get_string(nxt_conf_value_t *value, nxt_str_t *str) 168106Svbart@nginx.com { 169116Svbart@nginx.com if (value->type == NXT_CONF_VALUE_SHORT_STRING) { 170173Svbart@nginx.com str->length = value->u.str.length; 171173Svbart@nginx.com str->start = value->u.str.start; 172106Svbart@nginx.com 173106Svbart@nginx.com } else { 174172Svbart@nginx.com str->length = value->u.string.length; 175172Svbart@nginx.com str->start = value->u.string.start; 176106Svbart@nginx.com } 177106Svbart@nginx.com } 178106Svbart@nginx.com 179106Svbart@nginx.com 180773Svbart@nginx.com void 181773Svbart@nginx.com nxt_conf_set_string(nxt_conf_value_t *value, nxt_str_t *str) 182773Svbart@nginx.com { 183773Svbart@nginx.com if (str->length > NXT_CONF_MAX_SHORT_STRING) { 184773Svbart@nginx.com value->type = NXT_CONF_VALUE_STRING; 185773Svbart@nginx.com value->u.string.length = str->length; 186773Svbart@nginx.com value->u.string.start = str->start; 187773Svbart@nginx.com 188773Svbart@nginx.com } else { 189773Svbart@nginx.com value->type = NXT_CONF_VALUE_SHORT_STRING; 190773Svbart@nginx.com value->u.str.length = str->length; 191773Svbart@nginx.com 192773Svbart@nginx.com nxt_memcpy(value->u.str.start, str->start, str->length); 193773Svbart@nginx.com } 194773Svbart@nginx.com } 195773Svbart@nginx.com 196773Svbart@nginx.com 197774Svbart@nginx.com nxt_int_t 198774Svbart@nginx.com nxt_conf_set_string_dup(nxt_conf_value_t *value, nxt_mp_t *mp, nxt_str_t *str) 199774Svbart@nginx.com { 200774Svbart@nginx.com nxt_str_t tmp, *ptr; 201774Svbart@nginx.com 202774Svbart@nginx.com if (str->length > NXT_CONF_MAX_SHORT_STRING) { 203774Svbart@nginx.com value->type = NXT_CONF_VALUE_STRING; 204774Svbart@nginx.com 205774Svbart@nginx.com ptr = nxt_str_dup(mp, &tmp, str); 206774Svbart@nginx.com if (nxt_slow_path(ptr == NULL)) { 207774Svbart@nginx.com return NXT_ERROR; 208774Svbart@nginx.com } 209774Svbart@nginx.com 210774Svbart@nginx.com value->u.string.length = tmp.length; 211774Svbart@nginx.com value->u.string.start = tmp.start; 212774Svbart@nginx.com 213774Svbart@nginx.com } else { 214774Svbart@nginx.com value->type = NXT_CONF_VALUE_SHORT_STRING; 215774Svbart@nginx.com value->u.str.length = str->length; 216774Svbart@nginx.com 217774Svbart@nginx.com nxt_memcpy(value->u.str.start, str->start, str->length); 218774Svbart@nginx.com } 219774Svbart@nginx.com 220774Svbart@nginx.com return NXT_OK; 221774Svbart@nginx.com } 222774Svbart@nginx.com 223774Svbart@nginx.com 224507Smax.romanov@nginx.com int64_t 225507Smax.romanov@nginx.com nxt_conf_get_integer(nxt_conf_value_t *value) 226507Smax.romanov@nginx.com { 227507Smax.romanov@nginx.com return value->u.integer; 228507Smax.romanov@nginx.com } 229507Smax.romanov@nginx.com 230507Smax.romanov@nginx.com 231116Svbart@nginx.com nxt_uint_t 232121Svbart@nginx.com nxt_conf_object_members_count(nxt_conf_value_t *value) 233121Svbart@nginx.com { 234121Svbart@nginx.com return value->u.object->count; 235121Svbart@nginx.com } 236121Svbart@nginx.com 237121Svbart@nginx.com 238121Svbart@nginx.com nxt_conf_value_t * 239121Svbart@nginx.com nxt_conf_create_object(nxt_mp_t *mp, nxt_uint_t count) 240121Svbart@nginx.com { 241121Svbart@nginx.com size_t size; 242121Svbart@nginx.com nxt_conf_value_t *value; 243121Svbart@nginx.com 244121Svbart@nginx.com size = sizeof(nxt_conf_value_t) 245121Svbart@nginx.com + sizeof(nxt_conf_object_t) 246121Svbart@nginx.com + count * sizeof(nxt_conf_object_member_t); 247121Svbart@nginx.com 248121Svbart@nginx.com value = nxt_mp_get(mp, size); 249121Svbart@nginx.com if (nxt_slow_path(value == NULL)) { 250121Svbart@nginx.com return NULL; 251121Svbart@nginx.com } 252121Svbart@nginx.com 253121Svbart@nginx.com value->u.object = nxt_pointer_to(value, sizeof(nxt_conf_value_t)); 254121Svbart@nginx.com value->u.object->count = count; 255121Svbart@nginx.com 256121Svbart@nginx.com value->type = NXT_CONF_VALUE_OBJECT; 257121Svbart@nginx.com 258121Svbart@nginx.com return value; 259121Svbart@nginx.com } 260121Svbart@nginx.com 261121Svbart@nginx.com 262208Svbart@nginx.com void 263208Svbart@nginx.com nxt_conf_set_member(nxt_conf_value_t *object, nxt_str_t *name, 264172Svbart@nginx.com nxt_conf_value_t *value, uint32_t index) 265121Svbart@nginx.com { 266121Svbart@nginx.com nxt_conf_object_member_t *member; 267121Svbart@nginx.com 268121Svbart@nginx.com member = &object->u.object->members[index]; 269773Svbart@nginx.com 270773Svbart@nginx.com nxt_conf_set_string(&member->name, name); 271121Svbart@nginx.com 272121Svbart@nginx.com member->value = *value; 273208Svbart@nginx.com } 274208Svbart@nginx.com 275208Svbart@nginx.com 276208Svbart@nginx.com void 277208Svbart@nginx.com nxt_conf_set_member_string(nxt_conf_value_t *object, nxt_str_t *name, 278208Svbart@nginx.com nxt_str_t *value, uint32_t index) 279208Svbart@nginx.com { 280208Svbart@nginx.com nxt_conf_object_member_t *member; 281208Svbart@nginx.com 282208Svbart@nginx.com member = &object->u.object->members[index]; 283773Svbart@nginx.com 284773Svbart@nginx.com nxt_conf_set_string(&member->name, name); 285773Svbart@nginx.com 286773Svbart@nginx.com nxt_conf_set_string(&member->value, value); 287208Svbart@nginx.com } 288208Svbart@nginx.com 289208Svbart@nginx.com 290774Svbart@nginx.com nxt_int_t 291774Svbart@nginx.com nxt_conf_set_member_string_dup(nxt_conf_value_t *object, nxt_mp_t *mp, 292774Svbart@nginx.com nxt_str_t *name, nxt_str_t *value, uint32_t index) 293774Svbart@nginx.com { 294774Svbart@nginx.com nxt_conf_object_member_t *member; 295774Svbart@nginx.com 296774Svbart@nginx.com member = &object->u.object->members[index]; 297774Svbart@nginx.com 298774Svbart@nginx.com nxt_conf_set_string(&member->name, name); 299774Svbart@nginx.com 300774Svbart@nginx.com return nxt_conf_set_string_dup(&member->value, mp, value); 301774Svbart@nginx.com } 302774Svbart@nginx.com 303774Svbart@nginx.com 304208Svbart@nginx.com void 305208Svbart@nginx.com nxt_conf_set_member_integer(nxt_conf_value_t *object, nxt_str_t *name, 306208Svbart@nginx.com int64_t value, uint32_t index) 307208Svbart@nginx.com { 308208Svbart@nginx.com nxt_conf_object_member_t *member; 309208Svbart@nginx.com 310208Svbart@nginx.com member = &object->u.object->members[index]; 311773Svbart@nginx.com 312773Svbart@nginx.com nxt_conf_set_string(&member->name, name); 313208Svbart@nginx.com 314208Svbart@nginx.com member->value.u.integer = value; 315208Svbart@nginx.com member->value.type = NXT_CONF_VALUE_INTEGER; 316121Svbart@nginx.com } 317121Svbart@nginx.com 318121Svbart@nginx.com 319774Svbart@nginx.com void 320774Svbart@nginx.com nxt_conf_set_member_null(nxt_conf_value_t *object, nxt_str_t *name, 321774Svbart@nginx.com uint32_t index) 322774Svbart@nginx.com { 323774Svbart@nginx.com nxt_conf_object_member_t *member; 324774Svbart@nginx.com 325774Svbart@nginx.com member = &object->u.object->members[index]; 326774Svbart@nginx.com 327774Svbart@nginx.com nxt_conf_set_string(&member->name, name); 328774Svbart@nginx.com 329774Svbart@nginx.com member->value.type = NXT_CONF_VALUE_NULL; 330774Svbart@nginx.com } 331774Svbart@nginx.com 332774Svbart@nginx.com 333774Svbart@nginx.com nxt_conf_value_t * 334774Svbart@nginx.com nxt_conf_create_array(nxt_mp_t *mp, nxt_uint_t count) 335774Svbart@nginx.com { 336774Svbart@nginx.com size_t size; 337774Svbart@nginx.com nxt_conf_value_t *value; 338774Svbart@nginx.com 339774Svbart@nginx.com size = sizeof(nxt_conf_value_t) 340774Svbart@nginx.com + sizeof(nxt_conf_array_t) 341774Svbart@nginx.com + count * sizeof(nxt_conf_value_t); 342774Svbart@nginx.com 343774Svbart@nginx.com value = nxt_mp_get(mp, size); 344774Svbart@nginx.com if (nxt_slow_path(value == NULL)) { 345774Svbart@nginx.com return NULL; 346774Svbart@nginx.com } 347774Svbart@nginx.com 348774Svbart@nginx.com value->u.array = nxt_pointer_to(value, sizeof(nxt_conf_value_t)); 349774Svbart@nginx.com value->u.array->count = count; 350774Svbart@nginx.com 351774Svbart@nginx.com value->type = NXT_CONF_VALUE_ARRAY; 352774Svbart@nginx.com 353774Svbart@nginx.com return value; 354774Svbart@nginx.com } 355774Svbart@nginx.com 356774Svbart@nginx.com 357774Svbart@nginx.com void 358774Svbart@nginx.com nxt_conf_set_element(nxt_conf_value_t *array, nxt_uint_t index, 359774Svbart@nginx.com nxt_conf_value_t *value) 360774Svbart@nginx.com { 361774Svbart@nginx.com array->u.array->elements[index] = *value; 362774Svbart@nginx.com } 363774Svbart@nginx.com 364774Svbart@nginx.com 365774Svbart@nginx.com nxt_int_t 366774Svbart@nginx.com nxt_conf_set_element_string_dup(nxt_conf_value_t *array, nxt_mp_t *mp, 367774Svbart@nginx.com nxt_uint_t index, nxt_str_t *value) 368774Svbart@nginx.com { 369774Svbart@nginx.com nxt_conf_value_t *element; 370774Svbart@nginx.com 371774Svbart@nginx.com element = &array->u.array->elements[index]; 372774Svbart@nginx.com 373774Svbart@nginx.com return nxt_conf_set_string_dup(element, mp, value); 374774Svbart@nginx.com } 375774Svbart@nginx.com 376774Svbart@nginx.com 377121Svbart@nginx.com nxt_uint_t 378961Sigor@sysoev.ru nxt_conf_array_elements_count(nxt_conf_value_t *value) 379961Sigor@sysoev.ru { 380961Sigor@sysoev.ru return value->u.array->count; 381961Sigor@sysoev.ru } 382961Sigor@sysoev.ru 383961Sigor@sysoev.ru 384961Sigor@sysoev.ru nxt_uint_t 385116Svbart@nginx.com nxt_conf_type(nxt_conf_value_t *value) 386116Svbart@nginx.com { 387116Svbart@nginx.com switch (value->type) { 388116Svbart@nginx.com 389116Svbart@nginx.com case NXT_CONF_VALUE_NULL: 390116Svbart@nginx.com return NXT_CONF_NULL; 391116Svbart@nginx.com 392116Svbart@nginx.com case NXT_CONF_VALUE_BOOLEAN: 393116Svbart@nginx.com return NXT_CONF_BOOLEAN; 394116Svbart@nginx.com 395116Svbart@nginx.com case NXT_CONF_VALUE_INTEGER: 396116Svbart@nginx.com return NXT_CONF_INTEGER; 397116Svbart@nginx.com 398116Svbart@nginx.com case NXT_CONF_VALUE_NUMBER: 399116Svbart@nginx.com return NXT_CONF_NUMBER; 400116Svbart@nginx.com 401116Svbart@nginx.com case NXT_CONF_VALUE_SHORT_STRING: 402116Svbart@nginx.com case NXT_CONF_VALUE_STRING: 403116Svbart@nginx.com return NXT_CONF_STRING; 404116Svbart@nginx.com 405116Svbart@nginx.com case NXT_CONF_VALUE_ARRAY: 406116Svbart@nginx.com return NXT_CONF_ARRAY; 407116Svbart@nginx.com 408116Svbart@nginx.com case NXT_CONF_VALUE_OBJECT: 409116Svbart@nginx.com return NXT_CONF_OBJECT; 410116Svbart@nginx.com } 411116Svbart@nginx.com 412116Svbart@nginx.com nxt_unreachable(); 413116Svbart@nginx.com 414116Svbart@nginx.com return 0; 415116Svbart@nginx.com } 416116Svbart@nginx.com 417116Svbart@nginx.com 418106Svbart@nginx.com nxt_conf_value_t * 419106Svbart@nginx.com nxt_conf_get_path(nxt_conf_value_t *value, nxt_str_t *path) 420106Svbart@nginx.com { 421106Svbart@nginx.com nxt_str_t token; 422*1174Svbart@nginx.com nxt_int_t ret, index; 423106Svbart@nginx.com nxt_conf_path_parse_t parse; 424106Svbart@nginx.com 425106Svbart@nginx.com parse.start = path->start; 426106Svbart@nginx.com parse.end = path->start + path->length; 427106Svbart@nginx.com parse.last = 0; 428106Svbart@nginx.com 429106Svbart@nginx.com do { 430*1174Svbart@nginx.com ret = nxt_conf_path_next_token(&parse, &token); 431*1174Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 432*1174Svbart@nginx.com return NULL; 433*1174Svbart@nginx.com } 434106Svbart@nginx.com 435106Svbart@nginx.com if (token.length == 0) { 436106Svbart@nginx.com 437106Svbart@nginx.com if (parse.last) { 438106Svbart@nginx.com break; 439106Svbart@nginx.com } 440106Svbart@nginx.com 441106Svbart@nginx.com return NULL; 442106Svbart@nginx.com } 443106Svbart@nginx.com 444775Svbart@nginx.com switch (value->type) { 445775Svbart@nginx.com 446775Svbart@nginx.com case NXT_CONF_VALUE_OBJECT: 447775Svbart@nginx.com value = nxt_conf_get_object_member(value, &token, NULL); 448775Svbart@nginx.com break; 449775Svbart@nginx.com 450775Svbart@nginx.com case NXT_CONF_VALUE_ARRAY: 451775Svbart@nginx.com index = nxt_int_parse(token.start, token.length); 452775Svbart@nginx.com 453775Svbart@nginx.com if (index < 0 || index > NXT_INT32_T_MAX) { 454775Svbart@nginx.com return NULL; 455775Svbart@nginx.com } 456775Svbart@nginx.com 457775Svbart@nginx.com value = nxt_conf_get_array_element(value, index); 458775Svbart@nginx.com break; 459775Svbart@nginx.com 460775Svbart@nginx.com default: 461775Svbart@nginx.com return NULL; 462775Svbart@nginx.com } 463106Svbart@nginx.com 464106Svbart@nginx.com if (value == NULL) { 465106Svbart@nginx.com return NULL; 466106Svbart@nginx.com } 467106Svbart@nginx.com 468106Svbart@nginx.com } while (parse.last == 0); 469106Svbart@nginx.com 470106Svbart@nginx.com return value; 471106Svbart@nginx.com } 472106Svbart@nginx.com 473106Svbart@nginx.com 474*1174Svbart@nginx.com static nxt_int_t 475106Svbart@nginx.com nxt_conf_path_next_token(nxt_conf_path_parse_t *parse, nxt_str_t *token) 476106Svbart@nginx.com { 477*1174Svbart@nginx.com u_char *p, *start, *end; 478*1174Svbart@nginx.com size_t length; 479*1174Svbart@nginx.com 480*1174Svbart@nginx.com start = parse->start + 1; 481*1174Svbart@nginx.com 482*1174Svbart@nginx.com p = start; 483*1174Svbart@nginx.com 484*1174Svbart@nginx.com while (p < parse->end && *p != '/') { 485106Svbart@nginx.com p++; 486106Svbart@nginx.com } 487106Svbart@nginx.com 488106Svbart@nginx.com parse->start = p; 489*1174Svbart@nginx.com parse->last = (p >= parse->end); 490*1174Svbart@nginx.com 491*1174Svbart@nginx.com length = p - start; 492*1174Svbart@nginx.com 493*1174Svbart@nginx.com if (nxt_slow_path(length > NXT_CONF_MAX_TOKEN_LEN)) { 494*1174Svbart@nginx.com return NXT_ERROR; 495*1174Svbart@nginx.com } 496*1174Svbart@nginx.com 497*1174Svbart@nginx.com end = nxt_decode_uri(parse->buf, start, length); 498*1174Svbart@nginx.com if (nxt_slow_path(end == NULL)) { 499*1174Svbart@nginx.com return NXT_ERROR; 500*1174Svbart@nginx.com } 501*1174Svbart@nginx.com 502*1174Svbart@nginx.com token->length = end - parse->buf; 503*1174Svbart@nginx.com token->start = parse->buf; 504*1174Svbart@nginx.com 505*1174Svbart@nginx.com return NXT_OK; 506106Svbart@nginx.com } 507106Svbart@nginx.com 508106Svbart@nginx.com 509106Svbart@nginx.com nxt_conf_value_t * 510106Svbart@nginx.com nxt_conf_get_object_member(nxt_conf_value_t *value, nxt_str_t *name, 511106Svbart@nginx.com uint32_t *index) 512106Svbart@nginx.com { 513106Svbart@nginx.com nxt_str_t str; 514106Svbart@nginx.com nxt_uint_t n; 515106Svbart@nginx.com nxt_conf_object_t *object; 516106Svbart@nginx.com nxt_conf_object_member_t *member; 517106Svbart@nginx.com 518116Svbart@nginx.com if (value->type != NXT_CONF_VALUE_OBJECT) { 519106Svbart@nginx.com return NULL; 520106Svbart@nginx.com } 521106Svbart@nginx.com 522106Svbart@nginx.com object = value->u.object; 523106Svbart@nginx.com 524106Svbart@nginx.com for (n = 0; n < object->count; n++) { 525106Svbart@nginx.com member = &object->members[n]; 526106Svbart@nginx.com 527106Svbart@nginx.com nxt_conf_get_string(&member->name, &str); 528106Svbart@nginx.com 529106Svbart@nginx.com if (nxt_strstr_eq(&str, name)) { 530106Svbart@nginx.com 531106Svbart@nginx.com if (index != NULL) { 532106Svbart@nginx.com *index = n; 533106Svbart@nginx.com } 534106Svbart@nginx.com 535106Svbart@nginx.com return &member->value; 536106Svbart@nginx.com } 537106Svbart@nginx.com } 538106Svbart@nginx.com 539106Svbart@nginx.com return NULL; 540106Svbart@nginx.com } 541106Svbart@nginx.com 542106Svbart@nginx.com 543106Svbart@nginx.com nxt_int_t 544213Svbart@nginx.com nxt_conf_map_object(nxt_mp_t *mp, nxt_conf_value_t *value, nxt_conf_map_t *map, 545213Svbart@nginx.com nxt_uint_t n, void *data) 546106Svbart@nginx.com { 547213Svbart@nginx.com nxt_str_t str, *s; 548106Svbart@nginx.com nxt_uint_t i; 549106Svbart@nginx.com nxt_conf_value_t *v; 550106Svbart@nginx.com 551106Svbart@nginx.com union { 552111Sigor@sysoev.ru uint8_t ui8; 553111Sigor@sysoev.ru int32_t i32; 554111Sigor@sysoev.ru int64_t i64; 555839Svbart@nginx.com int i; 556111Sigor@sysoev.ru ssize_t size; 557111Sigor@sysoev.ru off_t off; 558111Sigor@sysoev.ru nxt_msec_t msec; 559111Sigor@sysoev.ru double dbl; 560111Sigor@sysoev.ru nxt_str_t str; 561213Svbart@nginx.com char *cstrz; 562111Sigor@sysoev.ru void *v; 563106Svbart@nginx.com } *ptr; 564106Svbart@nginx.com 565136Svbart@nginx.com for (i = 0; i < n; i++) { 566106Svbart@nginx.com 567106Svbart@nginx.com v = nxt_conf_get_object_member(value, &map[i].name, NULL); 568106Svbart@nginx.com 569116Svbart@nginx.com if (v == NULL || v->type == NXT_CONF_VALUE_NULL) { 570106Svbart@nginx.com continue; 571106Svbart@nginx.com } 572106Svbart@nginx.com 573106Svbart@nginx.com ptr = nxt_pointer_to(data, map[i].offset); 574106Svbart@nginx.com 575106Svbart@nginx.com switch (map[i].type) { 576106Svbart@nginx.com 577106Svbart@nginx.com case NXT_CONF_MAP_INT8: 578106Svbart@nginx.com 579136Svbart@nginx.com if (v->type == NXT_CONF_VALUE_BOOLEAN) { 580136Svbart@nginx.com ptr->ui8 = v->u.boolean; 581106Svbart@nginx.com } 582106Svbart@nginx.com 583106Svbart@nginx.com break; 584106Svbart@nginx.com 585106Svbart@nginx.com case NXT_CONF_MAP_INT32: 586106Svbart@nginx.com case NXT_CONF_MAP_INT64: 587106Svbart@nginx.com case NXT_CONF_MAP_INT: 588106Svbart@nginx.com case NXT_CONF_MAP_SIZE: 589106Svbart@nginx.com case NXT_CONF_MAP_OFF: 590111Sigor@sysoev.ru case NXT_CONF_MAP_MSEC: 591106Svbart@nginx.com 592116Svbart@nginx.com if (v->type != NXT_CONF_VALUE_INTEGER) { 593136Svbart@nginx.com break; 594106Svbart@nginx.com } 595106Svbart@nginx.com 596106Svbart@nginx.com switch (map[i].type) { 597106Svbart@nginx.com 598106Svbart@nginx.com case NXT_CONF_MAP_INT32: 599120Svbart@nginx.com ptr->i32 = v->u.integer; 600106Svbart@nginx.com break; 601106Svbart@nginx.com 602106Svbart@nginx.com case NXT_CONF_MAP_INT64: 603106Svbart@nginx.com ptr->i64 = v->u.integer; 604106Svbart@nginx.com break; 605106Svbart@nginx.com 606106Svbart@nginx.com case NXT_CONF_MAP_INT: 607106Svbart@nginx.com ptr->i = v->u.integer; 608106Svbart@nginx.com break; 609106Svbart@nginx.com 610106Svbart@nginx.com case NXT_CONF_MAP_SIZE: 611106Svbart@nginx.com ptr->size = v->u.integer; 612106Svbart@nginx.com break; 613106Svbart@nginx.com 614106Svbart@nginx.com case NXT_CONF_MAP_OFF: 615106Svbart@nginx.com ptr->off = v->u.integer; 616106Svbart@nginx.com break; 617106Svbart@nginx.com 618111Sigor@sysoev.ru case NXT_CONF_MAP_MSEC: 619318Smax.romanov@nginx.com ptr->msec = v->u.integer * 1000; 620111Sigor@sysoev.ru break; 621111Sigor@sysoev.ru 622106Svbart@nginx.com default: 623106Svbart@nginx.com nxt_unreachable(); 624106Svbart@nginx.com } 625106Svbart@nginx.com 626106Svbart@nginx.com break; 627106Svbart@nginx.com 628106Svbart@nginx.com case NXT_CONF_MAP_DOUBLE: 629106Svbart@nginx.com 630116Svbart@nginx.com if (v->type == NXT_CONF_VALUE_NUMBER) { 631106Svbart@nginx.com ptr->dbl = v->u.number; 632106Svbart@nginx.com 633116Svbart@nginx.com } else if (v->type == NXT_CONF_VALUE_INTEGER) { 634106Svbart@nginx.com ptr->dbl = v->u.integer; 635106Svbart@nginx.com 636106Svbart@nginx.com } 637106Svbart@nginx.com 638106Svbart@nginx.com break; 639106Svbart@nginx.com 640106Svbart@nginx.com case NXT_CONF_MAP_STR: 641213Svbart@nginx.com case NXT_CONF_MAP_STR_COPY: 642213Svbart@nginx.com case NXT_CONF_MAP_CSTRZ: 643213Svbart@nginx.com 644213Svbart@nginx.com if (v->type != NXT_CONF_VALUE_SHORT_STRING 645213Svbart@nginx.com && v->type != NXT_CONF_VALUE_STRING) 646106Svbart@nginx.com { 647213Svbart@nginx.com break; 648213Svbart@nginx.com } 649213Svbart@nginx.com 650213Svbart@nginx.com nxt_conf_get_string(v, &str); 651213Svbart@nginx.com 652213Svbart@nginx.com switch (map[i].type) { 653213Svbart@nginx.com 654213Svbart@nginx.com case NXT_CONF_MAP_STR: 655213Svbart@nginx.com ptr->str = str; 656213Svbart@nginx.com break; 657213Svbart@nginx.com 658213Svbart@nginx.com case NXT_CONF_MAP_STR_COPY: 659213Svbart@nginx.com 660213Svbart@nginx.com s = nxt_str_dup(mp, &ptr->str, &str); 661213Svbart@nginx.com 662213Svbart@nginx.com if (nxt_slow_path(s == NULL)) { 663213Svbart@nginx.com return NXT_ERROR; 664213Svbart@nginx.com } 665213Svbart@nginx.com 666213Svbart@nginx.com break; 667213Svbart@nginx.com 668213Svbart@nginx.com case NXT_CONF_MAP_CSTRZ: 669213Svbart@nginx.com 670213Svbart@nginx.com ptr->cstrz = nxt_str_cstrz(mp, &str); 671213Svbart@nginx.com 672213Svbart@nginx.com if (nxt_slow_path(ptr->cstrz == NULL)) { 673213Svbart@nginx.com return NXT_ERROR; 674213Svbart@nginx.com } 675213Svbart@nginx.com 676213Svbart@nginx.com break; 677213Svbart@nginx.com 678213Svbart@nginx.com default: 679213Svbart@nginx.com nxt_unreachable(); 680106Svbart@nginx.com } 681106Svbart@nginx.com 682106Svbart@nginx.com break; 683106Svbart@nginx.com 684106Svbart@nginx.com case NXT_CONF_MAP_PTR: 685106Svbart@nginx.com 686106Svbart@nginx.com ptr->v = v; 687106Svbart@nginx.com 688106Svbart@nginx.com break; 689106Svbart@nginx.com } 690106Svbart@nginx.com } 691106Svbart@nginx.com 692106Svbart@nginx.com return NXT_OK; 693106Svbart@nginx.com } 694106Svbart@nginx.com 695106Svbart@nginx.com 696106Svbart@nginx.com nxt_conf_value_t * 697106Svbart@nginx.com nxt_conf_next_object_member(nxt_conf_value_t *value, nxt_str_t *name, 698106Svbart@nginx.com uint32_t *next) 699106Svbart@nginx.com { 700106Svbart@nginx.com uint32_t n; 701106Svbart@nginx.com nxt_conf_object_t *object; 702106Svbart@nginx.com nxt_conf_object_member_t *member; 703106Svbart@nginx.com 704116Svbart@nginx.com if (value->type != NXT_CONF_VALUE_OBJECT) { 705106Svbart@nginx.com return NULL; 706106Svbart@nginx.com } 707106Svbart@nginx.com 708106Svbart@nginx.com n = *next; 709106Svbart@nginx.com object = value->u.object; 710106Svbart@nginx.com 711106Svbart@nginx.com if (n >= object->count) { 712106Svbart@nginx.com return NULL; 713106Svbart@nginx.com } 714106Svbart@nginx.com 715106Svbart@nginx.com member = &object->members[n]; 716106Svbart@nginx.com *next = n + 1; 717106Svbart@nginx.com 718106Svbart@nginx.com nxt_conf_get_string(&member->name, name); 719106Svbart@nginx.com 720106Svbart@nginx.com return &member->value; 721106Svbart@nginx.com } 722106Svbart@nginx.com 723106Svbart@nginx.com 724214Svbart@nginx.com nxt_conf_value_t * 725214Svbart@nginx.com nxt_conf_get_array_element(nxt_conf_value_t *value, uint32_t index) 726214Svbart@nginx.com { 727214Svbart@nginx.com nxt_conf_array_t *array; 728214Svbart@nginx.com 729214Svbart@nginx.com if (value->type != NXT_CONF_VALUE_ARRAY) { 730214Svbart@nginx.com return NULL; 731214Svbart@nginx.com } 732214Svbart@nginx.com 733214Svbart@nginx.com array = value->u.array; 734214Svbart@nginx.com 735214Svbart@nginx.com if (index >= array->count) { 736214Svbart@nginx.com return NULL; 737214Svbart@nginx.com } 738214Svbart@nginx.com 739214Svbart@nginx.com return &array->elements[index]; 740214Svbart@nginx.com } 741214Svbart@nginx.com 742214Svbart@nginx.com 743962Sigor@sysoev.ru void 744962Sigor@sysoev.ru nxt_conf_array_qsort(nxt_conf_value_t *value, 745962Sigor@sysoev.ru int (*compare)(const void *, const void *)) 746962Sigor@sysoev.ru { 747962Sigor@sysoev.ru nxt_conf_array_t *array; 748962Sigor@sysoev.ru 749962Sigor@sysoev.ru if (value->type != NXT_CONF_VALUE_ARRAY) { 750962Sigor@sysoev.ru return; 751962Sigor@sysoev.ru } 752962Sigor@sysoev.ru 753962Sigor@sysoev.ru array = value->u.array; 754962Sigor@sysoev.ru 755962Sigor@sysoev.ru nxt_qsort(array->elements, array->count, sizeof(nxt_conf_value_t), compare); 756962Sigor@sysoev.ru } 757962Sigor@sysoev.ru 758962Sigor@sysoev.ru 7591049Svbart@nginx.com nxt_conf_op_ret_t 760106Svbart@nginx.com nxt_conf_op_compile(nxt_mp_t *mp, nxt_conf_op_t **ops, nxt_conf_value_t *root, 7611049Svbart@nginx.com nxt_str_t *path, nxt_conf_value_t *value, nxt_bool_t add) 762106Svbart@nginx.com { 763106Svbart@nginx.com nxt_str_t token; 764*1174Svbart@nginx.com nxt_int_t ret, index; 765106Svbart@nginx.com nxt_conf_op_t *op, **parent; 7661047Svbart@nginx.com nxt_conf_value_t *node; 767106Svbart@nginx.com nxt_conf_path_parse_t parse; 768106Svbart@nginx.com nxt_conf_object_member_t *member; 769106Svbart@nginx.com 770106Svbart@nginx.com parse.start = path->start; 771106Svbart@nginx.com parse.end = path->start + path->length; 772106Svbart@nginx.com parse.last = 0; 773106Svbart@nginx.com 774106Svbart@nginx.com parent = ops; 775106Svbart@nginx.com 776106Svbart@nginx.com for ( ;; ) { 777106Svbart@nginx.com op = nxt_mp_zget(mp, sizeof(nxt_conf_op_t)); 778106Svbart@nginx.com if (nxt_slow_path(op == NULL)) { 7791049Svbart@nginx.com return NXT_CONF_OP_ERROR; 780106Svbart@nginx.com } 781106Svbart@nginx.com 782106Svbart@nginx.com *parent = op; 783106Svbart@nginx.com parent = (nxt_conf_op_t **) &op->ctx; 784106Svbart@nginx.com 785*1174Svbart@nginx.com ret = nxt_conf_path_next_token(&parse, &token); 786*1174Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 787*1174Svbart@nginx.com return NXT_CONF_OP_ERROR; 788*1174Svbart@nginx.com } 789106Svbart@nginx.com 7901048Svbart@nginx.com switch (root->type) { 7911048Svbart@nginx.com 7921048Svbart@nginx.com case NXT_CONF_VALUE_OBJECT: 7931048Svbart@nginx.com node = nxt_conf_get_object_member(root, &token, &op->index); 7941048Svbart@nginx.com break; 7951048Svbart@nginx.com 7961048Svbart@nginx.com case NXT_CONF_VALUE_ARRAY: 7971048Svbart@nginx.com index = nxt_int_parse(token.start, token.length); 7981048Svbart@nginx.com 7991048Svbart@nginx.com if (index < 0 || index > NXT_INT32_T_MAX) { 8001049Svbart@nginx.com return NXT_CONF_OP_NOT_FOUND; 8011048Svbart@nginx.com } 8021048Svbart@nginx.com 8031048Svbart@nginx.com op->index = index; 8041048Svbart@nginx.com 8051048Svbart@nginx.com node = nxt_conf_get_array_element(root, index); 8061048Svbart@nginx.com break; 8071048Svbart@nginx.com 8081048Svbart@nginx.com default: 8091048Svbart@nginx.com node = NULL; 8101048Svbart@nginx.com } 811106Svbart@nginx.com 812106Svbart@nginx.com if (parse.last) { 813106Svbart@nginx.com break; 814106Svbart@nginx.com } 815106Svbart@nginx.com 8161047Svbart@nginx.com if (node == NULL) { 8171049Svbart@nginx.com return NXT_CONF_OP_NOT_FOUND; 818106Svbart@nginx.com } 819106Svbart@nginx.com 820106Svbart@nginx.com op->action = NXT_CONF_OP_PASS; 8211047Svbart@nginx.com root = node; 822106Svbart@nginx.com } 823106Svbart@nginx.com 824106Svbart@nginx.com if (value == NULL) { 825106Svbart@nginx.com 8261047Svbart@nginx.com if (node == NULL) { 8271049Svbart@nginx.com return NXT_CONF_OP_NOT_FOUND; 828106Svbart@nginx.com } 829106Svbart@nginx.com 830106Svbart@nginx.com op->action = NXT_CONF_OP_DELETE; 831106Svbart@nginx.com 8321049Svbart@nginx.com return NXT_CONF_OP_OK; 8331049Svbart@nginx.com } 8341049Svbart@nginx.com 8351049Svbart@nginx.com if (add) { 8361049Svbart@nginx.com if (node == NULL) { 8371049Svbart@nginx.com return NXT_CONF_OP_NOT_FOUND; 8381049Svbart@nginx.com } 8391049Svbart@nginx.com 8401049Svbart@nginx.com if (node->type != NXT_CONF_VALUE_ARRAY) { 8411049Svbart@nginx.com return NXT_CONF_OP_NOT_ALLOWED; 8421049Svbart@nginx.com } 8431049Svbart@nginx.com 8441049Svbart@nginx.com op->action = NXT_CONF_OP_PASS; 8451049Svbart@nginx.com 8461049Svbart@nginx.com op = nxt_mp_zget(mp, sizeof(nxt_conf_op_t)); 8471049Svbart@nginx.com if (nxt_slow_path(op == NULL)) { 8481049Svbart@nginx.com return NXT_CONF_OP_ERROR; 8491049Svbart@nginx.com } 8501049Svbart@nginx.com 8511049Svbart@nginx.com *parent = op; 8521049Svbart@nginx.com 8531049Svbart@nginx.com op->index = node->u.array->count; 8541049Svbart@nginx.com op->action = NXT_CONF_OP_CREATE; 8551049Svbart@nginx.com op->ctx = value; 8561049Svbart@nginx.com 8571049Svbart@nginx.com return NXT_CONF_OP_OK; 858106Svbart@nginx.com } 859106Svbart@nginx.com 8601048Svbart@nginx.com if (node != NULL) { 8611048Svbart@nginx.com op->action = NXT_CONF_OP_REPLACE; 8621048Svbart@nginx.com op->ctx = value; 8631048Svbart@nginx.com 8641049Svbart@nginx.com return NXT_CONF_OP_OK; 8651048Svbart@nginx.com } 8661048Svbart@nginx.com 8671048Svbart@nginx.com op->action = NXT_CONF_OP_CREATE; 8681048Svbart@nginx.com 8691048Svbart@nginx.com if (root->type == NXT_CONF_VALUE_ARRAY) { 8701048Svbart@nginx.com if (op->index > root->u.array->count) { 8711049Svbart@nginx.com return NXT_CONF_OP_NOT_FOUND; 8721048Svbart@nginx.com } 8731048Svbart@nginx.com 8741048Svbart@nginx.com op->ctx = value; 8751048Svbart@nginx.com 8761048Svbart@nginx.com } else { 877106Svbart@nginx.com member = nxt_mp_zget(mp, sizeof(nxt_conf_object_member_t)); 878106Svbart@nginx.com if (nxt_slow_path(member == NULL)) { 8791049Svbart@nginx.com return NXT_CONF_OP_ERROR; 880106Svbart@nginx.com } 881106Svbart@nginx.com 882*1174Svbart@nginx.com ret = nxt_conf_set_string_dup(&member->name, mp, &token); 883*1174Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 884*1174Svbart@nginx.com return NXT_CONF_OP_ERROR; 885*1174Svbart@nginx.com } 886106Svbart@nginx.com 887106Svbart@nginx.com member->value = *value; 888106Svbart@nginx.com 8891047Svbart@nginx.com op->index = root->u.object->count; 890106Svbart@nginx.com op->ctx = member; 891106Svbart@nginx.com } 892106Svbart@nginx.com 8931049Svbart@nginx.com return NXT_CONF_OP_OK; 894106Svbart@nginx.com } 895106Svbart@nginx.com 896106Svbart@nginx.com 897106Svbart@nginx.com nxt_conf_value_t * 898106Svbart@nginx.com nxt_conf_clone(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *value) 899106Svbart@nginx.com { 900106Svbart@nginx.com nxt_int_t rc; 901106Svbart@nginx.com nxt_conf_value_t *copy; 902106Svbart@nginx.com 903106Svbart@nginx.com copy = nxt_mp_get(mp, sizeof(nxt_conf_value_t)); 904106Svbart@nginx.com if (nxt_slow_path(copy == NULL)) { 905106Svbart@nginx.com return NULL; 906106Svbart@nginx.com } 907106Svbart@nginx.com 908106Svbart@nginx.com rc = nxt_conf_copy_value(mp, op, copy, value); 909106Svbart@nginx.com 910106Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 911106Svbart@nginx.com return NULL; 912106Svbart@nginx.com } 913106Svbart@nginx.com 914106Svbart@nginx.com return copy; 915106Svbart@nginx.com } 916106Svbart@nginx.com 917106Svbart@nginx.com 918106Svbart@nginx.com static nxt_int_t 919106Svbart@nginx.com nxt_conf_copy_value(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *dst, 920106Svbart@nginx.com nxt_conf_value_t *src) 921106Svbart@nginx.com { 9221048Svbart@nginx.com if (op != NULL 9231048Svbart@nginx.com && src->type != NXT_CONF_VALUE_ARRAY 9241048Svbart@nginx.com && src->type != NXT_CONF_VALUE_OBJECT) 9251048Svbart@nginx.com { 926106Svbart@nginx.com return NXT_ERROR; 927106Svbart@nginx.com } 928106Svbart@nginx.com 929106Svbart@nginx.com switch (src->type) { 930106Svbart@nginx.com 931116Svbart@nginx.com case NXT_CONF_VALUE_STRING: 932106Svbart@nginx.com 933172Svbart@nginx.com dst->u.string.start = nxt_mp_nget(mp, src->u.string.length); 934172Svbart@nginx.com if (nxt_slow_path(dst->u.string.start == NULL)) { 935106Svbart@nginx.com return NXT_ERROR; 936106Svbart@nginx.com } 937106Svbart@nginx.com 938172Svbart@nginx.com nxt_memcpy(dst->u.string.start, src->u.string.start, 939172Svbart@nginx.com src->u.string.length); 940172Svbart@nginx.com 941172Svbart@nginx.com dst->u.string.length = src->u.string.length; 942172Svbart@nginx.com 943106Svbart@nginx.com break; 944106Svbart@nginx.com 945116Svbart@nginx.com case NXT_CONF_VALUE_ARRAY: 9461048Svbart@nginx.com return nxt_conf_copy_array(mp, op, dst, src); 947106Svbart@nginx.com 948116Svbart@nginx.com case NXT_CONF_VALUE_OBJECT: 949106Svbart@nginx.com return nxt_conf_copy_object(mp, op, dst, src); 950106Svbart@nginx.com 951106Svbart@nginx.com default: 952106Svbart@nginx.com dst->u = src->u; 953106Svbart@nginx.com } 954106Svbart@nginx.com 9551048Svbart@nginx.com dst->type = src->type; 9561048Svbart@nginx.com 9571048Svbart@nginx.com return NXT_OK; 9581048Svbart@nginx.com } 9591048Svbart@nginx.com 9601048Svbart@nginx.com 9611048Svbart@nginx.com static nxt_int_t 9621048Svbart@nginx.com nxt_conf_copy_array(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *dst, 9631048Svbart@nginx.com nxt_conf_value_t *src) 9641048Svbart@nginx.com { 9651048Svbart@nginx.com size_t size; 9661048Svbart@nginx.com nxt_int_t rc; 9671048Svbart@nginx.com nxt_uint_t s, d, count, index; 9681048Svbart@nginx.com nxt_conf_op_t *pass_op; 9691048Svbart@nginx.com nxt_conf_value_t *value; 9701048Svbart@nginx.com 9711048Svbart@nginx.com count = src->u.array->count; 9721048Svbart@nginx.com 9731048Svbart@nginx.com if (op != NULL) { 9741048Svbart@nginx.com if (op->action == NXT_CONF_OP_CREATE) { 9751048Svbart@nginx.com count++; 9761048Svbart@nginx.com 9771048Svbart@nginx.com } else if (op->action == NXT_CONF_OP_DELETE) { 9781048Svbart@nginx.com count--; 9791048Svbart@nginx.com } 9801048Svbart@nginx.com } 9811048Svbart@nginx.com 9821048Svbart@nginx.com size = sizeof(nxt_conf_array_t) + count * sizeof(nxt_conf_value_t); 9831048Svbart@nginx.com 9841048Svbart@nginx.com dst->u.array = nxt_mp_get(mp, size); 9851048Svbart@nginx.com if (nxt_slow_path(dst->u.array == NULL)) { 9861048Svbart@nginx.com return NXT_ERROR; 9871048Svbart@nginx.com } 9881048Svbart@nginx.com 9891048Svbart@nginx.com dst->u.array->count = count; 9901048Svbart@nginx.com 9911048Svbart@nginx.com s = 0; 9921048Svbart@nginx.com d = 0; 9931048Svbart@nginx.com 9941048Svbart@nginx.com pass_op = NULL; 9951048Svbart@nginx.com 9961048Svbart@nginx.com /* 9971048Svbart@nginx.com * This initialization is needed only to 9981048Svbart@nginx.com * suppress a warning on GCC 4.8 and older. 9991048Svbart@nginx.com */ 10001048Svbart@nginx.com index = 0; 10011048Svbart@nginx.com 10021048Svbart@nginx.com do { 10031048Svbart@nginx.com if (pass_op == NULL) { 10041048Svbart@nginx.com index = (op == NULL) ? src->u.array->count : op->index; 10051048Svbart@nginx.com } 10061048Svbart@nginx.com 10071048Svbart@nginx.com while (s != index) { 10081048Svbart@nginx.com rc = nxt_conf_copy_value(mp, pass_op, &dst->u.array->elements[d], 10091048Svbart@nginx.com &src->u.array->elements[s]); 10101048Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 10111048Svbart@nginx.com return NXT_ERROR; 10121048Svbart@nginx.com } 10131048Svbart@nginx.com 10141048Svbart@nginx.com s++; 10151048Svbart@nginx.com d++; 10161048Svbart@nginx.com } 10171048Svbart@nginx.com 10181048Svbart@nginx.com if (pass_op != NULL) { 10191048Svbart@nginx.com pass_op = NULL; 10201048Svbart@nginx.com continue; 10211048Svbart@nginx.com } 10221048Svbart@nginx.com 10231048Svbart@nginx.com if (op != NULL) { 10241048Svbart@nginx.com switch (op->action) { 10251048Svbart@nginx.com case NXT_CONF_OP_PASS: 10261048Svbart@nginx.com pass_op = op->ctx; 10271048Svbart@nginx.com index++; 10281048Svbart@nginx.com break; 10291048Svbart@nginx.com 10301048Svbart@nginx.com case NXT_CONF_OP_CREATE: 10311048Svbart@nginx.com value = op->ctx; 10321048Svbart@nginx.com dst->u.array->elements[d] = *value; 10331048Svbart@nginx.com 10341048Svbart@nginx.com d++; 10351048Svbart@nginx.com break; 10361048Svbart@nginx.com 10371048Svbart@nginx.com case NXT_CONF_OP_REPLACE: 10381048Svbart@nginx.com value = op->ctx; 10391048Svbart@nginx.com dst->u.array->elements[d] = *value; 10401048Svbart@nginx.com 10411048Svbart@nginx.com s++; 10421048Svbart@nginx.com d++; 10431048Svbart@nginx.com break; 10441048Svbart@nginx.com 10451048Svbart@nginx.com case NXT_CONF_OP_DELETE: 10461048Svbart@nginx.com s++; 10471048Svbart@nginx.com break; 10481048Svbart@nginx.com } 10491048Svbart@nginx.com 10501048Svbart@nginx.com op = NULL; 10511048Svbart@nginx.com } 10521048Svbart@nginx.com 10531048Svbart@nginx.com } while (d != count); 10541048Svbart@nginx.com 10551048Svbart@nginx.com dst->type = src->type; 10561048Svbart@nginx.com 1057106Svbart@nginx.com return NXT_OK; 1058106Svbart@nginx.com } 1059106Svbart@nginx.com 1060106Svbart@nginx.com 1061106Svbart@nginx.com static nxt_int_t 1062106Svbart@nginx.com nxt_conf_copy_object(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *dst, 1063106Svbart@nginx.com nxt_conf_value_t *src) 1064106Svbart@nginx.com { 1065106Svbart@nginx.com size_t size; 1066106Svbart@nginx.com nxt_int_t rc; 1067106Svbart@nginx.com nxt_uint_t s, d, count, index; 1068106Svbart@nginx.com nxt_conf_op_t *pass_op; 1069106Svbart@nginx.com nxt_conf_value_t *value; 1070106Svbart@nginx.com nxt_conf_object_member_t *member; 1071106Svbart@nginx.com 1072106Svbart@nginx.com count = src->u.object->count; 1073106Svbart@nginx.com 1074106Svbart@nginx.com if (op != NULL) { 1075106Svbart@nginx.com if (op->action == NXT_CONF_OP_CREATE) { 1076106Svbart@nginx.com count++; 1077106Svbart@nginx.com 1078106Svbart@nginx.com } else if (op->action == NXT_CONF_OP_DELETE) { 1079106Svbart@nginx.com count--; 1080106Svbart@nginx.com } 1081106Svbart@nginx.com } 1082106Svbart@nginx.com 1083106Svbart@nginx.com size = sizeof(nxt_conf_object_t) 1084106Svbart@nginx.com + count * sizeof(nxt_conf_object_member_t); 1085106Svbart@nginx.com 1086106Svbart@nginx.com dst->u.object = nxt_mp_get(mp, size); 1087106Svbart@nginx.com if (nxt_slow_path(dst->u.object == NULL)) { 1088106Svbart@nginx.com return NXT_ERROR; 1089106Svbart@nginx.com } 1090106Svbart@nginx.com 1091106Svbart@nginx.com dst->u.object->count = count; 1092106Svbart@nginx.com 1093106Svbart@nginx.com s = 0; 1094106Svbart@nginx.com d = 0; 1095106Svbart@nginx.com 1096106Svbart@nginx.com pass_op = NULL; 1097106Svbart@nginx.com 1098106Svbart@nginx.com /* 1099106Svbart@nginx.com * This initialization is needed only to 1100106Svbart@nginx.com * suppress a warning on GCC 4.8 and older. 1101106Svbart@nginx.com */ 1102106Svbart@nginx.com index = 0; 1103106Svbart@nginx.com 1104106Svbart@nginx.com do { 1105106Svbart@nginx.com if (pass_op == NULL) { 11061047Svbart@nginx.com index = (op == NULL) ? src->u.object->count : op->index; 1107106Svbart@nginx.com } 1108106Svbart@nginx.com 1109106Svbart@nginx.com while (s != index) { 1110106Svbart@nginx.com rc = nxt_conf_copy_value(mp, NULL, 1111106Svbart@nginx.com &dst->u.object->members[d].name, 1112106Svbart@nginx.com &src->u.object->members[s].name); 1113106Svbart@nginx.com 1114106Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 1115106Svbart@nginx.com return NXT_ERROR; 1116106Svbart@nginx.com } 1117106Svbart@nginx.com 1118106Svbart@nginx.com rc = nxt_conf_copy_value(mp, pass_op, 1119106Svbart@nginx.com &dst->u.object->members[d].value, 1120106Svbart@nginx.com &src->u.object->members[s].value); 1121106Svbart@nginx.com 1122106Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 1123106Svbart@nginx.com return NXT_ERROR; 1124106Svbart@nginx.com } 1125106Svbart@nginx.com 1126106Svbart@nginx.com s++; 1127106Svbart@nginx.com d++; 1128106Svbart@nginx.com } 1129106Svbart@nginx.com 1130106Svbart@nginx.com if (pass_op != NULL) { 1131106Svbart@nginx.com pass_op = NULL; 1132106Svbart@nginx.com continue; 1133106Svbart@nginx.com } 1134106Svbart@nginx.com 1135106Svbart@nginx.com if (op != NULL) { 1136106Svbart@nginx.com switch (op->action) { 1137106Svbart@nginx.com case NXT_CONF_OP_PASS: 1138106Svbart@nginx.com pass_op = op->ctx; 1139106Svbart@nginx.com index++; 1140106Svbart@nginx.com break; 1141106Svbart@nginx.com 1142106Svbart@nginx.com case NXT_CONF_OP_CREATE: 1143106Svbart@nginx.com member = op->ctx; 1144106Svbart@nginx.com 1145106Svbart@nginx.com rc = nxt_conf_copy_value(mp, NULL, 1146106Svbart@nginx.com &dst->u.object->members[d].name, 1147106Svbart@nginx.com &member->name); 1148106Svbart@nginx.com 1149106Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 1150106Svbart@nginx.com return NXT_ERROR; 1151106Svbart@nginx.com } 1152106Svbart@nginx.com 1153106Svbart@nginx.com dst->u.object->members[d].value = member->value; 1154106Svbart@nginx.com 1155106Svbart@nginx.com d++; 1156106Svbart@nginx.com break; 1157106Svbart@nginx.com 1158106Svbart@nginx.com case NXT_CONF_OP_REPLACE: 1159106Svbart@nginx.com rc = nxt_conf_copy_value(mp, NULL, 1160106Svbart@nginx.com &dst->u.object->members[d].name, 1161106Svbart@nginx.com &src->u.object->members[s].name); 1162106Svbart@nginx.com 1163106Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 1164106Svbart@nginx.com return NXT_ERROR; 1165106Svbart@nginx.com } 1166106Svbart@nginx.com 1167106Svbart@nginx.com value = op->ctx; 1168106Svbart@nginx.com 1169106Svbart@nginx.com dst->u.object->members[d].value = *value; 1170106Svbart@nginx.com 1171106Svbart@nginx.com s++; 1172106Svbart@nginx.com d++; 1173106Svbart@nginx.com break; 1174106Svbart@nginx.com 1175106Svbart@nginx.com case NXT_CONF_OP_DELETE: 1176106Svbart@nginx.com s++; 1177106Svbart@nginx.com break; 1178106Svbart@nginx.com } 1179106Svbart@nginx.com 11801046Svbart@nginx.com op = NULL; 1181106Svbart@nginx.com } 1182106Svbart@nginx.com 1183106Svbart@nginx.com } while (d != count); 1184106Svbart@nginx.com 1185106Svbart@nginx.com dst->type = src->type; 1186106Svbart@nginx.com 1187106Svbart@nginx.com return NXT_OK; 1188106Svbart@nginx.com } 1189106Svbart@nginx.com 1190106Svbart@nginx.com 1191106Svbart@nginx.com nxt_conf_value_t * 1192208Svbart@nginx.com nxt_conf_json_parse(nxt_mp_t *mp, u_char *start, u_char *end, 1193208Svbart@nginx.com nxt_conf_json_error_t *error) 1194106Svbart@nginx.com { 1195106Svbart@nginx.com u_char *p; 1196106Svbart@nginx.com nxt_conf_value_t *value; 1197106Svbart@nginx.com 1198106Svbart@nginx.com value = nxt_mp_get(mp, sizeof(nxt_conf_value_t)); 1199106Svbart@nginx.com if (nxt_slow_path(value == NULL)) { 1200106Svbart@nginx.com return NULL; 1201106Svbart@nginx.com } 1202106Svbart@nginx.com 1203106Svbart@nginx.com p = nxt_conf_json_skip_space(start, end); 1204106Svbart@nginx.com 1205106Svbart@nginx.com if (nxt_slow_path(p == end)) { 1206208Svbart@nginx.com 1207208Svbart@nginx.com nxt_conf_json_parse_error(error, start, 1208311Snick@nginx.com "An empty JSON payload isn't allowed. It must be either a literal " 1209311Snick@nginx.com "(null, true, or false), a number, a string (in double quotes " 1210311Snick@nginx.com "\"\"), an array (with brackets []), or an object (with braces {})." 1211208Svbart@nginx.com ); 1212208Svbart@nginx.com 1213106Svbart@nginx.com return NULL; 1214106Svbart@nginx.com } 1215106Svbart@nginx.com 1216208Svbart@nginx.com p = nxt_conf_json_parse_value(mp, value, p, end, error); 1217106Svbart@nginx.com 1218106Svbart@nginx.com if (nxt_slow_path(p == NULL)) { 1219106Svbart@nginx.com return NULL; 1220106Svbart@nginx.com } 1221106Svbart@nginx.com 1222106Svbart@nginx.com p = nxt_conf_json_skip_space(p, end); 1223106Svbart@nginx.com 1224106Svbart@nginx.com if (nxt_slow_path(p != end)) { 1225208Svbart@nginx.com 1226208Svbart@nginx.com nxt_conf_json_parse_error(error, p, 1227311Snick@nginx.com "Unexpected character after the end of a valid JSON value." 1228208Svbart@nginx.com ); 1229208Svbart@nginx.com 1230106Svbart@nginx.com return NULL; 1231106Svbart@nginx.com } 1232106Svbart@nginx.com 1233106Svbart@nginx.com return value; 1234106Svbart@nginx.com } 1235106Svbart@nginx.com 1236106Svbart@nginx.com 1237106Svbart@nginx.com static u_char * 1238106Svbart@nginx.com nxt_conf_json_skip_space(u_char *start, u_char *end) 1239106Svbart@nginx.com { 1240106Svbart@nginx.com u_char *p; 1241106Svbart@nginx.com 1242106Svbart@nginx.com for (p = start; nxt_fast_path(p != end); p++) { 1243106Svbart@nginx.com 1244106Svbart@nginx.com switch (*p) { 1245106Svbart@nginx.com case ' ': 1246106Svbart@nginx.com case '\t': 1247106Svbart@nginx.com case '\r': 1248106Svbart@nginx.com case '\n': 1249106Svbart@nginx.com continue; 1250106Svbart@nginx.com } 1251106Svbart@nginx.com 1252106Svbart@nginx.com break; 1253106Svbart@nginx.com } 1254106Svbart@nginx.com 1255106Svbart@nginx.com return p; 1256106Svbart@nginx.com } 1257106Svbart@nginx.com 1258106Svbart@nginx.com 1259106Svbart@nginx.com static u_char * 1260106Svbart@nginx.com nxt_conf_json_parse_value(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start, 1261208Svbart@nginx.com u_char *end, nxt_conf_json_error_t *error) 1262106Svbart@nginx.com { 1263208Svbart@nginx.com u_char ch, *p; 1264106Svbart@nginx.com 1265106Svbart@nginx.com ch = *start; 1266106Svbart@nginx.com 1267106Svbart@nginx.com switch (ch) { 1268106Svbart@nginx.com case '{': 1269208Svbart@nginx.com return nxt_conf_json_parse_object(mp, value, start, end, error); 1270106Svbart@nginx.com 1271106Svbart@nginx.com case '[': 1272208Svbart@nginx.com return nxt_conf_json_parse_array(mp, value, start, end, error); 1273106Svbart@nginx.com 1274106Svbart@nginx.com case '"': 1275208Svbart@nginx.com return nxt_conf_json_parse_string(mp, value, start, end, error); 1276106Svbart@nginx.com 1277106Svbart@nginx.com case 't': 1278106Svbart@nginx.com if (nxt_fast_path(end - start >= 4 1279106Svbart@nginx.com && nxt_memcmp(start, "true", 4) == 0)) 1280106Svbart@nginx.com { 1281106Svbart@nginx.com value->u.boolean = 1; 1282116Svbart@nginx.com value->type = NXT_CONF_VALUE_BOOLEAN; 1283106Svbart@nginx.com 1284106Svbart@nginx.com return start + 4; 1285106Svbart@nginx.com } 1286106Svbart@nginx.com 1287208Svbart@nginx.com goto error; 1288106Svbart@nginx.com 1289106Svbart@nginx.com case 'f': 1290106Svbart@nginx.com if (nxt_fast_path(end - start >= 5 1291106Svbart@nginx.com && nxt_memcmp(start, "false", 5) == 0)) 1292106Svbart@nginx.com { 1293106Svbart@nginx.com value->u.boolean = 0; 1294116Svbart@nginx.com value->type = NXT_CONF_VALUE_BOOLEAN; 1295106Svbart@nginx.com 1296106Svbart@nginx.com return start + 5; 1297106Svbart@nginx.com } 1298106Svbart@nginx.com 1299208Svbart@nginx.com goto error; 1300106Svbart@nginx.com 1301106Svbart@nginx.com case 'n': 1302106Svbart@nginx.com if (nxt_fast_path(end - start >= 4 1303106Svbart@nginx.com && nxt_memcmp(start, "null", 4) == 0)) 1304106Svbart@nginx.com { 1305116Svbart@nginx.com value->type = NXT_CONF_VALUE_NULL; 1306106Svbart@nginx.com return start + 4; 1307106Svbart@nginx.com } 1308106Svbart@nginx.com 1309208Svbart@nginx.com goto error; 1310208Svbart@nginx.com 1311208Svbart@nginx.com case '-': 1312208Svbart@nginx.com if (nxt_fast_path(end - start > 1)) { 1313208Svbart@nginx.com ch = start[1]; 1314208Svbart@nginx.com break; 1315208Svbart@nginx.com } 1316208Svbart@nginx.com 1317208Svbart@nginx.com goto error; 1318106Svbart@nginx.com } 1319106Svbart@nginx.com 1320208Svbart@nginx.com if (nxt_fast_path((ch - '0') <= 9)) { 1321208Svbart@nginx.com p = nxt_conf_json_parse_number(mp, value, start, end, error); 1322208Svbart@nginx.com 1323383Svbart@nginx.com if (nxt_slow_path(p == NULL)) { 1324383Svbart@nginx.com return NULL; 1325383Svbart@nginx.com } 1326383Svbart@nginx.com 1327208Svbart@nginx.com if (p == end) { 1328208Svbart@nginx.com return end; 1329208Svbart@nginx.com } 1330208Svbart@nginx.com 1331208Svbart@nginx.com switch (*p) { 1332208Svbart@nginx.com case ' ': 1333208Svbart@nginx.com case '\t': 1334208Svbart@nginx.com case '\r': 1335208Svbart@nginx.com case '\n': 1336208Svbart@nginx.com case ',': 1337208Svbart@nginx.com case '}': 1338208Svbart@nginx.com case ']': 1339208Svbart@nginx.com case '{': 1340208Svbart@nginx.com case '[': 1341208Svbart@nginx.com case '"': 1342208Svbart@nginx.com return p; 1343208Svbart@nginx.com } 1344106Svbart@nginx.com } 1345106Svbart@nginx.com 1346208Svbart@nginx.com error: 1347208Svbart@nginx.com 1348208Svbart@nginx.com nxt_conf_json_parse_error(error, start, 1349311Snick@nginx.com "A valid JSON value is expected here. It must be either a literal " 1350311Snick@nginx.com "(null, true, or false), a number, a string (in double quotes \"\"), " 1351311Snick@nginx.com "an array (with brackets []), or an object (with braces {})." 1352208Svbart@nginx.com ); 1353208Svbart@nginx.com 1354106Svbart@nginx.com return NULL; 1355106Svbart@nginx.com } 1356106Svbart@nginx.com 1357106Svbart@nginx.com 1358106Svbart@nginx.com static const nxt_lvlhsh_proto_t nxt_conf_object_hash_proto 1359106Svbart@nginx.com nxt_aligned(64) = 1360106Svbart@nginx.com { 1361106Svbart@nginx.com NXT_LVLHSH_DEFAULT, 1362106Svbart@nginx.com nxt_conf_object_hash_test, 1363106Svbart@nginx.com nxt_conf_object_hash_alloc, 1364106Svbart@nginx.com nxt_conf_object_hash_free, 1365106Svbart@nginx.com }; 1366106Svbart@nginx.com 1367106Svbart@nginx.com 1368106Svbart@nginx.com static u_char * 1369106Svbart@nginx.com nxt_conf_json_parse_object(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start, 1370208Svbart@nginx.com u_char *end, nxt_conf_json_error_t *error) 1371106Svbart@nginx.com { 1372208Svbart@nginx.com u_char *p, *name; 1373106Svbart@nginx.com nxt_mp_t *mp_temp; 1374106Svbart@nginx.com nxt_int_t rc; 1375106Svbart@nginx.com nxt_uint_t count; 1376106Svbart@nginx.com nxt_lvlhsh_t hash; 1377106Svbart@nginx.com nxt_lvlhsh_each_t lhe; 1378106Svbart@nginx.com nxt_conf_object_t *object; 1379106Svbart@nginx.com nxt_conf_object_member_t *member, *element; 1380106Svbart@nginx.com 1381106Svbart@nginx.com mp_temp = nxt_mp_create(1024, 128, 256, 32); 1382106Svbart@nginx.com if (nxt_slow_path(mp_temp == NULL)) { 1383106Svbart@nginx.com return NULL; 1384106Svbart@nginx.com } 1385106Svbart@nginx.com 1386106Svbart@nginx.com nxt_lvlhsh_init(&hash); 1387106Svbart@nginx.com 1388106Svbart@nginx.com count = 0; 1389130Svbart@nginx.com p = start; 1390130Svbart@nginx.com 1391130Svbart@nginx.com for ( ;; ) { 1392130Svbart@nginx.com p = nxt_conf_json_skip_space(p + 1, end); 1393130Svbart@nginx.com 1394130Svbart@nginx.com if (nxt_slow_path(p == end)) { 1395208Svbart@nginx.com 1396208Svbart@nginx.com nxt_conf_json_parse_error(error, p, 1397311Snick@nginx.com "Unexpected end of JSON payload. There's an object without " 1398311Snick@nginx.com "a closing brace (})." 1399208Svbart@nginx.com ); 1400208Svbart@nginx.com 1401130Svbart@nginx.com goto error; 1402130Svbart@nginx.com } 1403130Svbart@nginx.com 1404130Svbart@nginx.com if (*p != '"') { 1405130Svbart@nginx.com if (nxt_fast_path(*p == '}')) { 1406106Svbart@nginx.com break; 1407106Svbart@nginx.com } 1408106Svbart@nginx.com 1409208Svbart@nginx.com nxt_conf_json_parse_error(error, p, 1410208Svbart@nginx.com "A double quote (\") is expected here. There must be a valid " 1411208Svbart@nginx.com "JSON object member starts with a name, which is a string " 1412208Svbart@nginx.com "enclosed in double quotes." 1413208Svbart@nginx.com ); 1414208Svbart@nginx.com 1415130Svbart@nginx.com goto error; 1416130Svbart@nginx.com } 1417130Svbart@nginx.com 1418208Svbart@nginx.com name = p; 1419208Svbart@nginx.com 1420130Svbart@nginx.com count++; 1421130Svbart@nginx.com 1422130Svbart@nginx.com member = nxt_mp_get(mp_temp, sizeof(nxt_conf_object_member_t)); 1423130Svbart@nginx.com if (nxt_slow_path(member == NULL)) { 1424130Svbart@nginx.com goto error; 1425130Svbart@nginx.com } 1426130Svbart@nginx.com 1427208Svbart@nginx.com p = nxt_conf_json_parse_string(mp, &member->name, p, end, error); 1428130Svbart@nginx.com 1429130Svbart@nginx.com if (nxt_slow_path(p == NULL)) { 1430130Svbart@nginx.com goto error; 1431130Svbart@nginx.com } 1432130Svbart@nginx.com 1433130Svbart@nginx.com rc = nxt_conf_object_hash_add(mp_temp, &hash, member); 1434130Svbart@nginx.com 1435130Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 1436208Svbart@nginx.com 1437208Svbart@nginx.com if (rc == NXT_DECLINED) { 1438208Svbart@nginx.com nxt_conf_json_parse_error(error, name, 1439208Svbart@nginx.com "Duplicate object member. All JSON object members must " 1440208Svbart@nginx.com "have unique names." 1441208Svbart@nginx.com ); 1442208Svbart@nginx.com } 1443208Svbart@nginx.com 1444130Svbart@nginx.com goto error; 1445130Svbart@nginx.com } 1446130Svbart@nginx.com 1447130Svbart@nginx.com p = nxt_conf_json_skip_space(p, end); 1448130Svbart@nginx.com 1449208Svbart@nginx.com if (nxt_slow_path(p == end)) { 1450208Svbart@nginx.com 1451208Svbart@nginx.com nxt_conf_json_parse_error(error, p, 1452311Snick@nginx.com "Unexpected end of JSON payload. There's an object member " 1453311Snick@nginx.com "without a value." 1454208Svbart@nginx.com ); 1455208Svbart@nginx.com 1456208Svbart@nginx.com goto error; 1457208Svbart@nginx.com } 1458208Svbart@nginx.com 1459208Svbart@nginx.com if (nxt_slow_path(*p != ':')) { 1460208Svbart@nginx.com 1461208Svbart@nginx.com nxt_conf_json_parse_error(error, p, 1462311Snick@nginx.com "A colon (:) is expected here. There must be a colon after " 1463311Snick@nginx.com "a JSON member name." 1464208Svbart@nginx.com ); 1465208Svbart@nginx.com 1466130Svbart@nginx.com goto error; 1467130Svbart@nginx.com } 1468130Svbart@nginx.com 1469130Svbart@nginx.com p = nxt_conf_json_skip_space(p + 1, end); 1470130Svbart@nginx.com 1471130Svbart@nginx.com if (nxt_slow_path(p == end)) { 1472208Svbart@nginx.com 1473208Svbart@nginx.com nxt_conf_json_parse_error(error, p, 1474311Snick@nginx.com "Unexpected end of JSON payload. There's an object member " 1475311Snick@nginx.com "without a value." 1476208Svbart@nginx.com ); 1477208Svbart@nginx.com 1478130Svbart@nginx.com goto error; 1479130Svbart@nginx.com } 1480130Svbart@nginx.com 1481208Svbart@nginx.com p = nxt_conf_json_parse_value(mp, &member->value, p, end, error); 1482130Svbart@nginx.com 1483130Svbart@nginx.com if (nxt_slow_path(p == NULL)) { 1484130Svbart@nginx.com goto error; 1485130Svbart@nginx.com } 1486130Svbart@nginx.com 1487130Svbart@nginx.com p = nxt_conf_json_skip_space(p, end); 1488130Svbart@nginx.com 1489130Svbart@nginx.com if (nxt_slow_path(p == end)) { 1490208Svbart@nginx.com 1491208Svbart@nginx.com nxt_conf_json_parse_error(error, p, 1492311Snick@nginx.com "Unexpected end of JSON payload. There's an object without " 1493311Snick@nginx.com "a closing brace (})." 1494208Svbart@nginx.com ); 1495208Svbart@nginx.com 1496130Svbart@nginx.com goto error; 1497130Svbart@nginx.com } 1498130Svbart@nginx.com 1499130Svbart@nginx.com if (*p != ',') { 1500130Svbart@nginx.com if (nxt_fast_path(*p == '}')) { 1501130Svbart@nginx.com break; 1502106Svbart@nginx.com } 1503106Svbart@nginx.com 1504208Svbart@nginx.com nxt_conf_json_parse_error(error, p, 1505311Snick@nginx.com "Either a closing brace (}) or a comma (,) is expected here. " 1506311Snick@nginx.com "Each JSON object must be enclosed in braces and its members " 1507311Snick@nginx.com "must be separated by commas." 1508208Svbart@nginx.com ); 1509208Svbart@nginx.com 1510130Svbart@nginx.com goto error; 1511106Svbart@nginx.com } 1512106Svbart@nginx.com } 1513106Svbart@nginx.com 1514106Svbart@nginx.com object = nxt_mp_get(mp, sizeof(nxt_conf_object_t) 1515106Svbart@nginx.com + count * sizeof(nxt_conf_object_member_t)); 1516106Svbart@nginx.com if (nxt_slow_path(object == NULL)) { 1517106Svbart@nginx.com goto error; 1518106Svbart@nginx.com } 1519106Svbart@nginx.com 1520106Svbart@nginx.com value->u.object = object; 1521116Svbart@nginx.com value->type = NXT_CONF_VALUE_OBJECT; 1522106Svbart@nginx.com 1523106Svbart@nginx.com object->count = count; 1524106Svbart@nginx.com member = object->members; 1525106Svbart@nginx.com 1526598Sigor@sysoev.ru nxt_lvlhsh_each_init(&lhe, &nxt_conf_object_hash_proto); 1527106Svbart@nginx.com 1528106Svbart@nginx.com for ( ;; ) { 1529106Svbart@nginx.com element = nxt_lvlhsh_each(&hash, &lhe); 1530106Svbart@nginx.com 1531106Svbart@nginx.com if (element == NULL) { 1532106Svbart@nginx.com break; 1533106Svbart@nginx.com } 1534106Svbart@nginx.com 1535106Svbart@nginx.com *member++ = *element; 1536106Svbart@nginx.com } 1537106Svbart@nginx.com 1538106Svbart@nginx.com nxt_mp_destroy(mp_temp); 1539106Svbart@nginx.com 1540106Svbart@nginx.com return p + 1; 1541106Svbart@nginx.com 1542106Svbart@nginx.com error: 1543106Svbart@nginx.com 1544106Svbart@nginx.com nxt_mp_destroy(mp_temp); 1545106Svbart@nginx.com return NULL; 1546106Svbart@nginx.com } 1547106Svbart@nginx.com 1548106Svbart@nginx.com 1549106Svbart@nginx.com static nxt_int_t 1550106Svbart@nginx.com nxt_conf_object_hash_add(nxt_mp_t *mp, nxt_lvlhsh_t *lvlhsh, 1551106Svbart@nginx.com nxt_conf_object_member_t *member) 1552106Svbart@nginx.com { 1553106Svbart@nginx.com nxt_lvlhsh_query_t lhq; 1554106Svbart@nginx.com 1555106Svbart@nginx.com nxt_conf_get_string(&member->name, &lhq.key); 1556106Svbart@nginx.com 1557106Svbart@nginx.com lhq.key_hash = nxt_djb_hash(lhq.key.start, lhq.key.length); 1558106Svbart@nginx.com lhq.replace = 0; 1559106Svbart@nginx.com lhq.value = member; 1560106Svbart@nginx.com lhq.proto = &nxt_conf_object_hash_proto; 1561106Svbart@nginx.com lhq.pool = mp; 1562106Svbart@nginx.com 1563106Svbart@nginx.com return nxt_lvlhsh_insert(lvlhsh, &lhq); 1564106Svbart@nginx.com } 1565106Svbart@nginx.com 1566106Svbart@nginx.com 1567106Svbart@nginx.com static nxt_int_t 1568106Svbart@nginx.com nxt_conf_object_hash_test(nxt_lvlhsh_query_t *lhq, void *data) 1569106Svbart@nginx.com { 1570106Svbart@nginx.com nxt_str_t str; 1571106Svbart@nginx.com nxt_conf_object_member_t *member; 1572106Svbart@nginx.com 1573106Svbart@nginx.com member = data; 1574106Svbart@nginx.com 1575106Svbart@nginx.com nxt_conf_get_string(&member->name, &str); 1576106Svbart@nginx.com 1577208Svbart@nginx.com return nxt_strstr_eq(&lhq->key, &str) ? NXT_OK : NXT_DECLINED; 1578106Svbart@nginx.com } 1579106Svbart@nginx.com 1580106Svbart@nginx.com 1581106Svbart@nginx.com static void * 1582106Svbart@nginx.com nxt_conf_object_hash_alloc(void *data, size_t size) 1583106Svbart@nginx.com { 1584106Svbart@nginx.com return nxt_mp_align(data, size, size); 1585106Svbart@nginx.com } 1586106Svbart@nginx.com 1587106Svbart@nginx.com 1588106Svbart@nginx.com static void 1589106Svbart@nginx.com nxt_conf_object_hash_free(void *data, void *p) 1590106Svbart@nginx.com { 1591106Svbart@nginx.com nxt_mp_free(data, p); 1592106Svbart@nginx.com } 1593106Svbart@nginx.com 1594106Svbart@nginx.com 1595106Svbart@nginx.com static u_char * 1596106Svbart@nginx.com nxt_conf_json_parse_array(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start, 1597208Svbart@nginx.com u_char *end, nxt_conf_json_error_t *error) 1598106Svbart@nginx.com { 1599106Svbart@nginx.com u_char *p; 1600106Svbart@nginx.com nxt_mp_t *mp_temp; 1601106Svbart@nginx.com nxt_uint_t count; 1602106Svbart@nginx.com nxt_list_t *list; 1603106Svbart@nginx.com nxt_conf_array_t *array; 1604106Svbart@nginx.com nxt_conf_value_t *element; 1605106Svbart@nginx.com 1606106Svbart@nginx.com mp_temp = nxt_mp_create(1024, 128, 256, 32); 1607106Svbart@nginx.com if (nxt_slow_path(mp_temp == NULL)) { 1608106Svbart@nginx.com return NULL; 1609106Svbart@nginx.com } 1610106Svbart@nginx.com 1611106Svbart@nginx.com list = nxt_list_create(mp_temp, 8, sizeof(nxt_conf_value_t)); 1612106Svbart@nginx.com if (nxt_slow_path(list == NULL)) { 1613106Svbart@nginx.com goto error; 1614106Svbart@nginx.com } 1615106Svbart@nginx.com 1616106Svbart@nginx.com count = 0; 1617130Svbart@nginx.com p = start; 1618130Svbart@nginx.com 1619130Svbart@nginx.com for ( ;; ) { 1620130Svbart@nginx.com p = nxt_conf_json_skip_space(p + 1, end); 1621130Svbart@nginx.com 1622130Svbart@nginx.com if (nxt_slow_path(p == end)) { 1623208Svbart@nginx.com 1624208Svbart@nginx.com nxt_conf_json_parse_error(error, p, 1625311Snick@nginx.com "Unexpected end of JSON payload. There's an array without " 1626311Snick@nginx.com "a closing bracket (])." 1627208Svbart@nginx.com ); 1628208Svbart@nginx.com 1629130Svbart@nginx.com goto error; 1630130Svbart@nginx.com } 1631130Svbart@nginx.com 1632130Svbart@nginx.com if (*p == ']') { 1633130Svbart@nginx.com break; 1634130Svbart@nginx.com } 1635130Svbart@nginx.com 1636130Svbart@nginx.com count++; 1637130Svbart@nginx.com 1638130Svbart@nginx.com element = nxt_list_add(list); 1639130Svbart@nginx.com if (nxt_slow_path(element == NULL)) { 1640130Svbart@nginx.com goto error; 1641130Svbart@nginx.com } 1642130Svbart@nginx.com 1643208Svbart@nginx.com p = nxt_conf_json_parse_value(mp, element, p, end, error); 1644130Svbart@nginx.com 1645130Svbart@nginx.com if (nxt_slow_path(p == NULL)) { 1646130Svbart@nginx.com goto error; 1647130Svbart@nginx.com } 1648130Svbart@nginx.com 1649130Svbart@nginx.com p = nxt_conf_json_skip_space(p, end); 1650130Svbart@nginx.com 1651130Svbart@nginx.com if (nxt_slow_path(p == end)) { 1652208Svbart@nginx.com 1653208Svbart@nginx.com nxt_conf_json_parse_error(error, p, 1654311Snick@nginx.com "Unexpected end of JSON payload. There's an array without " 1655311Snick@nginx.com "a closing bracket (])." 1656208Svbart@nginx.com ); 1657208Svbart@nginx.com 1658130Svbart@nginx.com goto error; 1659130Svbart@nginx.com } 1660130Svbart@nginx.com 1661130Svbart@nginx.com if (*p != ',') { 1662130Svbart@nginx.com if (nxt_fast_path(*p == ']')) { 1663106Svbart@nginx.com break; 1664106Svbart@nginx.com } 1665106Svbart@nginx.com 1666208Svbart@nginx.com nxt_conf_json_parse_error(error, p, 1667311Snick@nginx.com "Either a closing bracket (]) or a comma (,) is expected " 1668311Snick@nginx.com "here. Each array must be enclosed in brackets and its " 1669311Snick@nginx.com "members must be separated by commas." 1670208Svbart@nginx.com ); 1671208Svbart@nginx.com 1672130Svbart@nginx.com goto error; 1673106Svbart@nginx.com } 1674106Svbart@nginx.com } 1675106Svbart@nginx.com 1676106Svbart@nginx.com array = nxt_mp_get(mp, sizeof(nxt_conf_array_t) 1677106Svbart@nginx.com + count * sizeof(nxt_conf_value_t)); 1678106Svbart@nginx.com if (nxt_slow_path(array == NULL)) { 1679106Svbart@nginx.com goto error; 1680106Svbart@nginx.com } 1681106Svbart@nginx.com 1682106Svbart@nginx.com value->u.array = array; 1683116Svbart@nginx.com value->type = NXT_CONF_VALUE_ARRAY; 1684106Svbart@nginx.com 1685106Svbart@nginx.com array->count = count; 1686106Svbart@nginx.com element = array->elements; 1687106Svbart@nginx.com 1688106Svbart@nginx.com nxt_list_each(value, list) { 1689106Svbart@nginx.com *element++ = *value; 1690106Svbart@nginx.com } nxt_list_loop; 1691106Svbart@nginx.com 1692106Svbart@nginx.com nxt_mp_destroy(mp_temp); 1693106Svbart@nginx.com 1694106Svbart@nginx.com return p + 1; 1695106Svbart@nginx.com 1696106Svbart@nginx.com error: 1697106Svbart@nginx.com 1698106Svbart@nginx.com nxt_mp_destroy(mp_temp); 1699106Svbart@nginx.com return NULL; 1700106Svbart@nginx.com } 1701106Svbart@nginx.com 1702106Svbart@nginx.com 1703106Svbart@nginx.com static u_char * 1704106Svbart@nginx.com nxt_conf_json_parse_string(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start, 1705208Svbart@nginx.com u_char *end, nxt_conf_json_error_t *error) 1706106Svbart@nginx.com { 1707106Svbart@nginx.com u_char *p, ch, *last, *s; 1708106Svbart@nginx.com size_t size, surplus; 1709106Svbart@nginx.com uint32_t utf, utf_high; 1710106Svbart@nginx.com nxt_uint_t i; 1711106Svbart@nginx.com enum { 1712106Svbart@nginx.com sw_usual = 0, 1713106Svbart@nginx.com sw_escape, 1714106Svbart@nginx.com sw_encoded1, 1715106Svbart@nginx.com sw_encoded2, 1716106Svbart@nginx.com sw_encoded3, 1717106Svbart@nginx.com sw_encoded4, 1718106Svbart@nginx.com } state; 1719106Svbart@nginx.com 1720106Svbart@nginx.com start++; 1721106Svbart@nginx.com 1722106Svbart@nginx.com state = 0; 1723106Svbart@nginx.com surplus = 0; 1724106Svbart@nginx.com 1725106Svbart@nginx.com for (p = start; nxt_fast_path(p != end); p++) { 1726106Svbart@nginx.com ch = *p; 1727106Svbart@nginx.com 1728106Svbart@nginx.com switch (state) { 1729106Svbart@nginx.com 1730106Svbart@nginx.com case sw_usual: 1731106Svbart@nginx.com 1732106Svbart@nginx.com if (ch == '"') { 1733106Svbart@nginx.com break; 1734106Svbart@nginx.com } 1735106Svbart@nginx.com 1736106Svbart@nginx.com if (ch == '\\') { 1737106Svbart@nginx.com state = sw_escape; 1738106Svbart@nginx.com continue; 1739106Svbart@nginx.com } 1740106Svbart@nginx.com 1741106Svbart@nginx.com if (nxt_fast_path(ch >= ' ')) { 1742106Svbart@nginx.com continue; 1743106Svbart@nginx.com } 1744106Svbart@nginx.com 1745208Svbart@nginx.com nxt_conf_json_parse_error(error, p, 1746311Snick@nginx.com "Unexpected character. All control characters in a JSON " 1747311Snick@nginx.com "string must be escaped." 1748208Svbart@nginx.com ); 1749208Svbart@nginx.com 1750106Svbart@nginx.com return NULL; 1751106Svbart@nginx.com 1752106Svbart@nginx.com case sw_escape: 1753106Svbart@nginx.com 1754106Svbart@nginx.com switch (ch) { 1755106Svbart@nginx.com case '"': 1756106Svbart@nginx.com case '\\': 1757106Svbart@nginx.com case '/': 1758106Svbart@nginx.com case 'n': 1759106Svbart@nginx.com case 'r': 1760106Svbart@nginx.com case 't': 1761106Svbart@nginx.com case 'b': 1762106Svbart@nginx.com case 'f': 1763106Svbart@nginx.com surplus++; 1764106Svbart@nginx.com state = sw_usual; 1765106Svbart@nginx.com continue; 1766106Svbart@nginx.com 1767106Svbart@nginx.com case 'u': 1768106Svbart@nginx.com /* 1769106Svbart@nginx.com * Basic unicode 6 bytes "\uXXXX" in JSON 1770106Svbart@nginx.com * and up to 3 bytes in UTF-8. 1771106Svbart@nginx.com * 1772106Svbart@nginx.com * Surrogate pair: 12 bytes "\uXXXX\uXXXX" in JSON 1773106Svbart@nginx.com * and 3 or 4 bytes in UTF-8. 1774106Svbart@nginx.com */ 1775106Svbart@nginx.com surplus += 3; 1776106Svbart@nginx.com state = sw_encoded1; 1777106Svbart@nginx.com continue; 1778106Svbart@nginx.com } 1779106Svbart@nginx.com 1780208Svbart@nginx.com nxt_conf_json_parse_error(error, p - 1, 1781311Snick@nginx.com "Unexpected backslash. A literal backslash in a JSON string " 1782311Snick@nginx.com "must be escaped with a second backslash (\\\\)." 1783208Svbart@nginx.com ); 1784208Svbart@nginx.com 1785106Svbart@nginx.com return NULL; 1786106Svbart@nginx.com 1787106Svbart@nginx.com case sw_encoded1: 1788106Svbart@nginx.com case sw_encoded2: 1789106Svbart@nginx.com case sw_encoded3: 1790106Svbart@nginx.com case sw_encoded4: 1791106Svbart@nginx.com 1792106Svbart@nginx.com if (nxt_fast_path((ch >= '0' && ch <= '9') 1793202Svbart@nginx.com || (ch >= 'A' && ch <= 'F') 1794202Svbart@nginx.com || (ch >= 'a' && ch <= 'f'))) 1795106Svbart@nginx.com { 1796106Svbart@nginx.com state = (state == sw_encoded4) ? sw_usual : state + 1; 1797106Svbart@nginx.com continue; 1798106Svbart@nginx.com } 1799106Svbart@nginx.com 1800208Svbart@nginx.com nxt_conf_json_parse_error(error, p, 1801311Snick@nginx.com "Invalid escape sequence. An escape sequence in a JSON " 1802311Snick@nginx.com "string must start with a backslash, followed by the lowercase " 1803311Snick@nginx.com "letter u, followed by four hexadecimal digits (\\uXXXX)." 1804208Svbart@nginx.com ); 1805208Svbart@nginx.com 1806106Svbart@nginx.com return NULL; 1807106Svbart@nginx.com } 1808106Svbart@nginx.com 1809106Svbart@nginx.com break; 1810106Svbart@nginx.com } 1811106Svbart@nginx.com 1812106Svbart@nginx.com if (nxt_slow_path(p == end)) { 1813208Svbart@nginx.com 1814208Svbart@nginx.com nxt_conf_json_parse_error(error, p, 1815311Snick@nginx.com "Unexpected end of JSON payload. There's a string without " 1816311Snick@nginx.com "a final double quote (\")." 1817208Svbart@nginx.com ); 1818208Svbart@nginx.com 1819106Svbart@nginx.com return NULL; 1820106Svbart@nginx.com } 1821106Svbart@nginx.com 1822106Svbart@nginx.com /* Points to the ending quote mark. */ 1823106Svbart@nginx.com last = p; 1824106Svbart@nginx.com 1825106Svbart@nginx.com size = last - start - surplus; 1826106Svbart@nginx.com 1827106Svbart@nginx.com if (size > NXT_CONF_MAX_SHORT_STRING) { 1828172Svbart@nginx.com 1829172Svbart@nginx.com if (nxt_slow_path(size > NXT_CONF_MAX_STRING)) { 1830208Svbart@nginx.com 1831208Svbart@nginx.com nxt_conf_json_parse_error(error, start, 1832311Snick@nginx.com "The string is too long. Such a long JSON string value " 1833311Snick@nginx.com "is not supported." 1834208Svbart@nginx.com ); 1835208Svbart@nginx.com 1836106Svbart@nginx.com return NULL; 1837106Svbart@nginx.com } 1838106Svbart@nginx.com 1839172Svbart@nginx.com value->type = NXT_CONF_VALUE_STRING; 1840172Svbart@nginx.com 1841172Svbart@nginx.com value->u.string.start = nxt_mp_nget(mp, size); 1842172Svbart@nginx.com if (nxt_slow_path(value->u.string.start == NULL)) { 1843172Svbart@nginx.com return NULL; 1844172Svbart@nginx.com } 1845172Svbart@nginx.com 1846172Svbart@nginx.com value->u.string.length = size; 1847172Svbart@nginx.com 1848172Svbart@nginx.com s = value->u.string.start; 1849106Svbart@nginx.com 1850106Svbart@nginx.com } else { 1851116Svbart@nginx.com value->type = NXT_CONF_VALUE_SHORT_STRING; 1852173Svbart@nginx.com value->u.str.length = size; 1853173Svbart@nginx.com 1854173Svbart@nginx.com s = value->u.str.start; 1855106Svbart@nginx.com } 1856106Svbart@nginx.com 1857106Svbart@nginx.com if (surplus == 0) { 1858106Svbart@nginx.com nxt_memcpy(s, start, size); 1859106Svbart@nginx.com return last + 1; 1860106Svbart@nginx.com } 1861106Svbart@nginx.com 1862106Svbart@nginx.com p = start; 1863106Svbart@nginx.com 1864106Svbart@nginx.com do { 1865106Svbart@nginx.com ch = *p++; 1866106Svbart@nginx.com 1867106Svbart@nginx.com if (ch != '\\') { 1868106Svbart@nginx.com *s++ = ch; 1869106Svbart@nginx.com continue; 1870106Svbart@nginx.com } 1871106Svbart@nginx.com 1872106Svbart@nginx.com ch = *p++; 1873106Svbart@nginx.com 1874106Svbart@nginx.com switch (ch) { 1875106Svbart@nginx.com case '"': 1876106Svbart@nginx.com case '\\': 1877106Svbart@nginx.com case '/': 1878106Svbart@nginx.com *s++ = ch; 1879106Svbart@nginx.com continue; 1880106Svbart@nginx.com 1881106Svbart@nginx.com case 'n': 1882106Svbart@nginx.com *s++ = '\n'; 1883106Svbart@nginx.com continue; 1884106Svbart@nginx.com 1885106Svbart@nginx.com case 'r': 1886106Svbart@nginx.com *s++ = '\r'; 1887106Svbart@nginx.com continue; 1888106Svbart@nginx.com 1889106Svbart@nginx.com case 't': 1890106Svbart@nginx.com *s++ = '\t'; 1891106Svbart@nginx.com continue; 1892106Svbart@nginx.com 1893106Svbart@nginx.com case 'b': 1894106Svbart@nginx.com *s++ = '\b'; 1895106Svbart@nginx.com continue; 1896106Svbart@nginx.com 1897106Svbart@nginx.com case 'f': 1898106Svbart@nginx.com *s++ = '\f'; 1899106Svbart@nginx.com continue; 1900106Svbart@nginx.com } 1901106Svbart@nginx.com 1902106Svbart@nginx.com utf = 0; 1903106Svbart@nginx.com utf_high = 0; 1904106Svbart@nginx.com 1905106Svbart@nginx.com for ( ;; ) { 1906106Svbart@nginx.com for (i = 0; i < 4; i++) { 1907202Svbart@nginx.com utf = (utf << 4) | (p[i] >= 'A' ? 10 + ((p[i] & ~0x20) - 'A') 1908202Svbart@nginx.com : p[i] - '0'); 1909106Svbart@nginx.com } 1910106Svbart@nginx.com 1911106Svbart@nginx.com p += 4; 1912106Svbart@nginx.com 1913207Svbart@nginx.com if (utf_high != 0) { 1914611Svbart@nginx.com if (nxt_slow_path(utf < 0xDC00 || utf > 0xDFFF)) { 1915208Svbart@nginx.com 1916208Svbart@nginx.com nxt_conf_json_parse_error(error, p - 12, 1917311Snick@nginx.com "Invalid JSON encoding sequence. This 12-byte " 1918311Snick@nginx.com "sequence composes an illegal UTF-16 surrogate pair." 1919208Svbart@nginx.com ); 1920208Svbart@nginx.com 1921207Svbart@nginx.com return NULL; 1922207Svbart@nginx.com } 1923207Svbart@nginx.com 1924611Svbart@nginx.com utf = ((utf_high - 0xD800) << 10) + (utf - 0xDC00) + 0x10000; 1925207Svbart@nginx.com 1926106Svbart@nginx.com break; 1927106Svbart@nginx.com } 1928106Svbart@nginx.com 1929611Svbart@nginx.com if (utf < 0xD800 || utf > 0xDFFF) { 1930106Svbart@nginx.com break; 1931106Svbart@nginx.com } 1932106Svbart@nginx.com 1933611Svbart@nginx.com if (utf > 0xDBFF || p[0] != '\\' || p[1] != 'u') { 1934208Svbart@nginx.com 1935208Svbart@nginx.com nxt_conf_json_parse_error(error, p - 6, 1936311Snick@nginx.com "Invalid JSON encoding sequence. This 6-byte sequence " 1937311Snick@nginx.com "does not represent a valid UTF character." 1938208Svbart@nginx.com ); 1939208Svbart@nginx.com 1940207Svbart@nginx.com return NULL; 1941207Svbart@nginx.com } 1942207Svbart@nginx.com 1943106Svbart@nginx.com p += 2; 1944207Svbart@nginx.com 1945207Svbart@nginx.com utf_high = utf; 1946207Svbart@nginx.com utf = 0; 1947106Svbart@nginx.com } 1948106Svbart@nginx.com 1949106Svbart@nginx.com s = nxt_utf8_encode(s, utf); 1950106Svbart@nginx.com 1951106Svbart@nginx.com } while (p != last); 1952106Svbart@nginx.com 1953106Svbart@nginx.com if (size > NXT_CONF_MAX_SHORT_STRING) { 1954172Svbart@nginx.com value->u.string.length = s - value->u.string.start; 1955106Svbart@nginx.com 1956106Svbart@nginx.com } else { 1957173Svbart@nginx.com value->u.str.length = s - value->u.str.start; 1958106Svbart@nginx.com } 1959106Svbart@nginx.com 1960106Svbart@nginx.com return last + 1; 1961106Svbart@nginx.com } 1962106Svbart@nginx.com 1963106Svbart@nginx.com 1964106Svbart@nginx.com static u_char * 1965106Svbart@nginx.com nxt_conf_json_parse_number(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start, 1966208Svbart@nginx.com u_char *end, nxt_conf_json_error_t *error) 1967106Svbart@nginx.com { 1968106Svbart@nginx.com u_char *p, ch; 1969106Svbart@nginx.com uint64_t integer; 1970106Svbart@nginx.com nxt_int_t sign; 1971106Svbart@nginx.com #if 0 1972106Svbart@nginx.com uint64_t frac, power 1973106Svbart@nginx.com nxt_int_t e, negative; 1974106Svbart@nginx.com #endif 1975106Svbart@nginx.com 1976106Svbart@nginx.com static const uint64_t cutoff = NXT_INT64_T_MAX / 10; 1977106Svbart@nginx.com static const uint64_t cutlim = NXT_INT64_T_MAX % 10; 1978106Svbart@nginx.com 1979106Svbart@nginx.com ch = *start; 1980106Svbart@nginx.com 1981106Svbart@nginx.com if (ch == '-') { 1982106Svbart@nginx.com sign = -1; 1983106Svbart@nginx.com start++; 1984106Svbart@nginx.com 1985106Svbart@nginx.com } else { 1986106Svbart@nginx.com sign = 1; 1987106Svbart@nginx.com } 1988106Svbart@nginx.com 1989106Svbart@nginx.com integer = 0; 1990106Svbart@nginx.com 1991106Svbart@nginx.com for (p = start; nxt_fast_path(p != end); p++) { 1992106Svbart@nginx.com ch = *p; 1993106Svbart@nginx.com 1994106Svbart@nginx.com /* Values below '0' become >= 208. */ 1995106Svbart@nginx.com ch = ch - '0'; 1996106Svbart@nginx.com 1997106Svbart@nginx.com if (ch > 9) { 1998106Svbart@nginx.com break; 1999106Svbart@nginx.com } 2000106Svbart@nginx.com 2001106Svbart@nginx.com if (nxt_slow_path(integer >= cutoff 2002106Svbart@nginx.com && (integer > cutoff || ch > cutlim))) 2003106Svbart@nginx.com { 2004208Svbart@nginx.com nxt_conf_json_parse_error(error, start, 2005311Snick@nginx.com "The integer is too large. Such a large JSON integer value " 2006311Snick@nginx.com "is not supported." 2007208Svbart@nginx.com ); 2008208Svbart@nginx.com 2009208Svbart@nginx.com return NULL; 2010106Svbart@nginx.com } 2011106Svbart@nginx.com 2012106Svbart@nginx.com integer = integer * 10 + ch; 2013106Svbart@nginx.com } 2014106Svbart@nginx.com 2015208Svbart@nginx.com if (nxt_slow_path(p - start > 1 && *start == '0')) { 2016208Svbart@nginx.com 2017208Svbart@nginx.com nxt_conf_json_parse_error(error, start, 2018311Snick@nginx.com "The number is invalid. Leading zeros are not allowed in JSON " 2019311Snick@nginx.com "numbers." 2020208Svbart@nginx.com ); 2021208Svbart@nginx.com 2022106Svbart@nginx.com return NULL; 2023106Svbart@nginx.com } 2024106Svbart@nginx.com 2025106Svbart@nginx.com if (ch != '.') { 2026116Svbart@nginx.com value->type = NXT_CONF_VALUE_INTEGER; 2027106Svbart@nginx.com value->u.integer = sign * integer; 2028106Svbart@nginx.com return p; 2029106Svbart@nginx.com } 2030106Svbart@nginx.com 2031106Svbart@nginx.com #if 0 2032106Svbart@nginx.com start = p + 1; 2033106Svbart@nginx.com 2034106Svbart@nginx.com frac = 0; 2035106Svbart@nginx.com power = 1; 2036106Svbart@nginx.com 2037106Svbart@nginx.com for (p = start; nxt_fast_path(p != end); p++) { 2038106Svbart@nginx.com ch = *p; 2039106Svbart@nginx.com 2040106Svbart@nginx.com /* Values below '0' become >= 208. */ 2041106Svbart@nginx.com ch = ch - '0'; 2042106Svbart@nginx.com 2043106Svbart@nginx.com if (ch > 9) { 2044106Svbart@nginx.com break; 2045106Svbart@nginx.com } 2046106Svbart@nginx.com 2047106Svbart@nginx.com if (nxt_slow_path((frac >= cutoff && (frac > cutoff || ch > cutlim)) 2048106Svbart@nginx.com || power > cutoff)) 2049106Svbart@nginx.com { 2050106Svbart@nginx.com return NULL; 2051106Svbart@nginx.com } 2052106Svbart@nginx.com 2053106Svbart@nginx.com frac = frac * 10 + ch; 2054106Svbart@nginx.com power *= 10; 2055106Svbart@nginx.com } 2056106Svbart@nginx.com 2057106Svbart@nginx.com if (nxt_slow_path(p == start)) { 2058106Svbart@nginx.com return NULL; 2059106Svbart@nginx.com } 2060106Svbart@nginx.com 2061116Svbart@nginx.com value->type = NXT_CONF_VALUE_NUMBER; 2062106Svbart@nginx.com value->u.number = integer + (double) frac / power; 2063106Svbart@nginx.com 2064106Svbart@nginx.com value->u.number = copysign(value->u.number, sign); 2065106Svbart@nginx.com 2066106Svbart@nginx.com if (ch == 'e' || ch == 'E') { 2067106Svbart@nginx.com start = p + 1; 2068106Svbart@nginx.com 2069106Svbart@nginx.com ch = *start; 2070106Svbart@nginx.com 2071106Svbart@nginx.com if (ch == '-' || ch == '+') { 2072106Svbart@nginx.com start++; 2073106Svbart@nginx.com } 2074106Svbart@nginx.com 2075106Svbart@nginx.com negative = (ch == '-') ? 1 : 0; 2076106Svbart@nginx.com e = 0; 2077106Svbart@nginx.com 2078106Svbart@nginx.com for (p = start; nxt_fast_path(p != end); p++) { 2079106Svbart@nginx.com ch = *p; 2080106Svbart@nginx.com 2081106Svbart@nginx.com /* Values below '0' become >= 208. */ 2082106Svbart@nginx.com ch = ch - '0'; 2083106Svbart@nginx.com 2084106Svbart@nginx.com if (ch > 9) { 2085106Svbart@nginx.com break; 2086106Svbart@nginx.com } 2087106Svbart@nginx.com 2088106Svbart@nginx.com e = e * 10 + ch; 2089106Svbart@nginx.com 2090106Svbart@nginx.com if (nxt_slow_path(e > DBL_MAX_10_EXP)) { 2091106Svbart@nginx.com return NULL; 2092106Svbart@nginx.com } 2093106Svbart@nginx.com } 2094106Svbart@nginx.com 2095106Svbart@nginx.com if (nxt_slow_path(p == start)) { 2096106Svbart@nginx.com return NULL; 2097106Svbart@nginx.com } 2098106Svbart@nginx.com 2099106Svbart@nginx.com if (negative) { 2100106Svbart@nginx.com value->u.number /= exp10(e); 2101106Svbart@nginx.com 2102106Svbart@nginx.com } else { 2103106Svbart@nginx.com value->u.number *= exp10(e); 2104106Svbart@nginx.com } 2105106Svbart@nginx.com } 2106106Svbart@nginx.com 2107106Svbart@nginx.com if (nxt_fast_path(isfinite(value->u.number))) { 2108106Svbart@nginx.com return p; 2109106Svbart@nginx.com } 2110208Svbart@nginx.com #else 2111208Svbart@nginx.com 2112208Svbart@nginx.com nxt_conf_json_parse_error(error, start, 2113311Snick@nginx.com "The number is not an integer. JSON numbers with decimals and " 2114311Snick@nginx.com "exponents are not supported." 2115208Svbart@nginx.com ); 2116208Svbart@nginx.com 2117106Svbart@nginx.com #endif 2118106Svbart@nginx.com 2119106Svbart@nginx.com return NULL; 2120106Svbart@nginx.com } 2121106Svbart@nginx.com 2122106Svbart@nginx.com 2123208Svbart@nginx.com static void 2124208Svbart@nginx.com nxt_conf_json_parse_error(nxt_conf_json_error_t *error, u_char *pos, 2125208Svbart@nginx.com const char *detail) 2126208Svbart@nginx.com { 2127208Svbart@nginx.com if (error == NULL) { 2128208Svbart@nginx.com return; 2129208Svbart@nginx.com } 2130208Svbart@nginx.com 2131208Svbart@nginx.com error->pos = pos; 2132208Svbart@nginx.com error->detail = (u_char *) detail; 2133208Svbart@nginx.com } 2134208Svbart@nginx.com 2135208Svbart@nginx.com 2136106Svbart@nginx.com size_t 2137106Svbart@nginx.com nxt_conf_json_length(nxt_conf_value_t *value, nxt_conf_json_pretty_t *pretty) 2138106Svbart@nginx.com { 2139106Svbart@nginx.com switch (value->type) { 2140106Svbart@nginx.com 2141116Svbart@nginx.com case NXT_CONF_VALUE_NULL: 2142703Svbart@nginx.com return nxt_length("null"); 2143106Svbart@nginx.com 2144116Svbart@nginx.com case NXT_CONF_VALUE_BOOLEAN: 2145703Svbart@nginx.com return value->u.boolean ? nxt_length("true") : nxt_length("false"); 2146106Svbart@nginx.com 2147116Svbart@nginx.com case NXT_CONF_VALUE_INTEGER: 2148106Svbart@nginx.com return nxt_conf_json_integer_length(value); 2149106Svbart@nginx.com 2150116Svbart@nginx.com case NXT_CONF_VALUE_NUMBER: 2151106Svbart@nginx.com /* TODO */ 2152106Svbart@nginx.com return 0; 2153106Svbart@nginx.com 2154116Svbart@nginx.com case NXT_CONF_VALUE_SHORT_STRING: 2155116Svbart@nginx.com case NXT_CONF_VALUE_STRING: 2156106Svbart@nginx.com return nxt_conf_json_string_length(value); 2157106Svbart@nginx.com 2158116Svbart@nginx.com case NXT_CONF_VALUE_ARRAY: 2159106Svbart@nginx.com return nxt_conf_json_array_length(value, pretty); 2160106Svbart@nginx.com 2161116Svbart@nginx.com case NXT_CONF_VALUE_OBJECT: 2162106Svbart@nginx.com return nxt_conf_json_object_length(value, pretty); 2163106Svbart@nginx.com } 2164106Svbart@nginx.com 2165106Svbart@nginx.com nxt_unreachable(); 2166106Svbart@nginx.com 2167106Svbart@nginx.com return 0; 2168106Svbart@nginx.com } 2169106Svbart@nginx.com 2170106Svbart@nginx.com 2171106Svbart@nginx.com u_char * 2172106Svbart@nginx.com nxt_conf_json_print(u_char *p, nxt_conf_value_t *value, 2173106Svbart@nginx.com nxt_conf_json_pretty_t *pretty) 2174106Svbart@nginx.com { 2175106Svbart@nginx.com switch (value->type) { 2176106Svbart@nginx.com 2177116Svbart@nginx.com case NXT_CONF_VALUE_NULL: 2178106Svbart@nginx.com return nxt_cpymem(p, "null", 4); 2179106Svbart@nginx.com 2180116Svbart@nginx.com case NXT_CONF_VALUE_BOOLEAN: 2181106Svbart@nginx.com return value->u.boolean ? nxt_cpymem(p, "true", 4) 2182106Svbart@nginx.com : nxt_cpymem(p, "false", 5); 2183106Svbart@nginx.com 2184116Svbart@nginx.com case NXT_CONF_VALUE_INTEGER: 2185106Svbart@nginx.com return nxt_conf_json_print_integer(p, value); 2186106Svbart@nginx.com 2187116Svbart@nginx.com case NXT_CONF_VALUE_NUMBER: 2188106Svbart@nginx.com /* TODO */ 2189106Svbart@nginx.com return p; 2190106Svbart@nginx.com 2191116Svbart@nginx.com case NXT_CONF_VALUE_SHORT_STRING: 2192116Svbart@nginx.com case NXT_CONF_VALUE_STRING: 2193106Svbart@nginx.com return nxt_conf_json_print_string(p, value); 2194106Svbart@nginx.com 2195116Svbart@nginx.com case NXT_CONF_VALUE_ARRAY: 2196106Svbart@nginx.com return nxt_conf_json_print_array(p, value, pretty); 2197106Svbart@nginx.com 2198116Svbart@nginx.com case NXT_CONF_VALUE_OBJECT: 2199106Svbart@nginx.com return nxt_conf_json_print_object(p, value, pretty); 2200106Svbart@nginx.com } 2201106Svbart@nginx.com 2202106Svbart@nginx.com nxt_unreachable(); 2203106Svbart@nginx.com 2204106Svbart@nginx.com return p; 2205106Svbart@nginx.com } 2206106Svbart@nginx.com 2207106Svbart@nginx.com 2208106Svbart@nginx.com static size_t 2209106Svbart@nginx.com nxt_conf_json_integer_length(nxt_conf_value_t *value) 2210106Svbart@nginx.com { 2211106Svbart@nginx.com int64_t num; 2212106Svbart@nginx.com 2213106Svbart@nginx.com num = llabs(value->u.integer); 2214106Svbart@nginx.com 2215106Svbart@nginx.com if (num <= 9999) { 2216703Svbart@nginx.com return nxt_length("-9999"); 2217106Svbart@nginx.com } 2218106Svbart@nginx.com 2219210Svbart@nginx.com if (num <= 99999999999LL) { 2220703Svbart@nginx.com return nxt_length("-99999999999"); 2221106Svbart@nginx.com } 2222106Svbart@nginx.com 2223106Svbart@nginx.com return NXT_INT64_T_LEN; 2224106Svbart@nginx.com } 2225106Svbart@nginx.com 2226106Svbart@nginx.com 2227106Svbart@nginx.com static u_char * 2228106Svbart@nginx.com nxt_conf_json_print_integer(u_char *p, nxt_conf_value_t *value) 2229106Svbart@nginx.com { 2230106Svbart@nginx.com return nxt_sprintf(p, p + NXT_INT64_T_LEN, "%L", value->u.integer); 2231106Svbart@nginx.com } 2232106Svbart@nginx.com 2233106Svbart@nginx.com 2234106Svbart@nginx.com static size_t 2235106Svbart@nginx.com nxt_conf_json_string_length(nxt_conf_value_t *value) 2236106Svbart@nginx.com { 2237106Svbart@nginx.com nxt_str_t str; 2238106Svbart@nginx.com 2239106Svbart@nginx.com nxt_conf_get_string(value, &str); 2240106Svbart@nginx.com 2241106Svbart@nginx.com return 2 + nxt_conf_json_escape_length(str.start, str.length); 2242106Svbart@nginx.com } 2243106Svbart@nginx.com 2244106Svbart@nginx.com 2245106Svbart@nginx.com static u_char * 2246106Svbart@nginx.com nxt_conf_json_print_string(u_char *p, nxt_conf_value_t *value) 2247106Svbart@nginx.com { 2248106Svbart@nginx.com nxt_str_t str; 2249106Svbart@nginx.com 2250106Svbart@nginx.com nxt_conf_get_string(value, &str); 2251106Svbart@nginx.com 2252106Svbart@nginx.com *p++ = '"'; 2253106Svbart@nginx.com 2254106Svbart@nginx.com p = nxt_conf_json_escape(p, str.start, str.length); 2255106Svbart@nginx.com 2256106Svbart@nginx.com *p++ = '"'; 2257106Svbart@nginx.com 2258106Svbart@nginx.com return p; 2259106Svbart@nginx.com } 2260106Svbart@nginx.com 2261106Svbart@nginx.com 2262106Svbart@nginx.com static size_t 2263106Svbart@nginx.com nxt_conf_json_array_length(nxt_conf_value_t *value, 2264106Svbart@nginx.com nxt_conf_json_pretty_t *pretty) 2265106Svbart@nginx.com { 2266106Svbart@nginx.com size_t len; 2267106Svbart@nginx.com nxt_uint_t n; 2268106Svbart@nginx.com nxt_conf_array_t *array; 2269106Svbart@nginx.com 2270106Svbart@nginx.com array = value->u.array; 2271106Svbart@nginx.com 2272106Svbart@nginx.com /* [] */ 2273106Svbart@nginx.com len = 2; 2274106Svbart@nginx.com 2275106Svbart@nginx.com if (pretty != NULL) { 2276106Svbart@nginx.com pretty->level++; 2277106Svbart@nginx.com } 2278106Svbart@nginx.com 2279106Svbart@nginx.com value = array->elements; 2280106Svbart@nginx.com 2281106Svbart@nginx.com for (n = 0; n < array->count; n++) { 2282106Svbart@nginx.com len += nxt_conf_json_length(&value[n], pretty); 2283106Svbart@nginx.com 2284106Svbart@nginx.com if (pretty != NULL) { 2285106Svbart@nginx.com /* Indentation and new line. */ 2286106Svbart@nginx.com len += pretty->level + 2; 2287106Svbart@nginx.com } 2288106Svbart@nginx.com } 2289106Svbart@nginx.com 2290106Svbart@nginx.com if (pretty != NULL) { 2291106Svbart@nginx.com pretty->level--; 2292106Svbart@nginx.com 2293106Svbart@nginx.com if (n != 0) { 2294106Svbart@nginx.com /* Indentation and new line. */ 2295106Svbart@nginx.com len += pretty->level + 2; 2296106Svbart@nginx.com } 2297106Svbart@nginx.com } 2298106Svbart@nginx.com 2299106Svbart@nginx.com /* Reserve space for "n" commas. */ 2300106Svbart@nginx.com return len + n; 2301106Svbart@nginx.com } 2302106Svbart@nginx.com 2303106Svbart@nginx.com 2304106Svbart@nginx.com static u_char * 2305106Svbart@nginx.com nxt_conf_json_print_array(u_char *p, nxt_conf_value_t *value, 2306106Svbart@nginx.com nxt_conf_json_pretty_t *pretty) 2307106Svbart@nginx.com { 2308106Svbart@nginx.com nxt_uint_t n; 2309106Svbart@nginx.com nxt_conf_array_t *array; 2310106Svbart@nginx.com 2311106Svbart@nginx.com array = value->u.array; 2312106Svbart@nginx.com 2313106Svbart@nginx.com *p++ = '['; 2314106Svbart@nginx.com 2315106Svbart@nginx.com if (array->count != 0) { 2316106Svbart@nginx.com value = array->elements; 2317106Svbart@nginx.com 2318106Svbart@nginx.com if (pretty != NULL) { 2319106Svbart@nginx.com p = nxt_conf_json_newline(p); 2320106Svbart@nginx.com 2321106Svbart@nginx.com pretty->level++; 2322106Svbart@nginx.com p = nxt_conf_json_indentation(p, pretty->level); 2323106Svbart@nginx.com } 2324106Svbart@nginx.com 2325106Svbart@nginx.com p = nxt_conf_json_print(p, &value[0], pretty); 2326106Svbart@nginx.com 2327106Svbart@nginx.com for (n = 1; n < array->count; n++) { 2328106Svbart@nginx.com *p++ = ','; 2329106Svbart@nginx.com 2330106Svbart@nginx.com if (pretty != NULL) { 2331106Svbart@nginx.com p = nxt_conf_json_newline(p); 2332106Svbart@nginx.com p = nxt_conf_json_indentation(p, pretty->level); 2333106Svbart@nginx.com 2334106Svbart@nginx.com pretty->more_space = 0; 2335106Svbart@nginx.com } 2336106Svbart@nginx.com 2337106Svbart@nginx.com p = nxt_conf_json_print(p, &value[n], pretty); 2338106Svbart@nginx.com } 2339106Svbart@nginx.com 2340106Svbart@nginx.com if (pretty != NULL) { 2341106Svbart@nginx.com p = nxt_conf_json_newline(p); 2342106Svbart@nginx.com 2343106Svbart@nginx.com pretty->level--; 2344106Svbart@nginx.com p = nxt_conf_json_indentation(p, pretty->level); 2345106Svbart@nginx.com 2346106Svbart@nginx.com pretty->more_space = 1; 2347106Svbart@nginx.com } 2348106Svbart@nginx.com } 2349106Svbart@nginx.com 2350106Svbart@nginx.com *p++ = ']'; 2351106Svbart@nginx.com 2352106Svbart@nginx.com return p; 2353106Svbart@nginx.com } 2354106Svbart@nginx.com 2355106Svbart@nginx.com 2356106Svbart@nginx.com static size_t 2357106Svbart@nginx.com nxt_conf_json_object_length(nxt_conf_value_t *value, 2358106Svbart@nginx.com nxt_conf_json_pretty_t *pretty) 2359106Svbart@nginx.com { 2360106Svbart@nginx.com size_t len; 2361106Svbart@nginx.com nxt_uint_t n; 2362106Svbart@nginx.com nxt_conf_object_t *object; 2363106Svbart@nginx.com nxt_conf_object_member_t *member; 2364106Svbart@nginx.com 2365106Svbart@nginx.com object = value->u.object; 2366106Svbart@nginx.com 2367106Svbart@nginx.com /* {} */ 2368106Svbart@nginx.com len = 2; 2369106Svbart@nginx.com 2370106Svbart@nginx.com if (pretty != NULL) { 2371106Svbart@nginx.com pretty->level++; 2372106Svbart@nginx.com } 2373106Svbart@nginx.com 2374106Svbart@nginx.com member = object->members; 2375106Svbart@nginx.com 2376106Svbart@nginx.com for (n = 0; n < object->count; n++) { 2377106Svbart@nginx.com len += nxt_conf_json_string_length(&member[n].name) + 1 2378106Svbart@nginx.com + nxt_conf_json_length(&member[n].value, pretty) + 1; 2379106Svbart@nginx.com 2380106Svbart@nginx.com if (pretty != NULL) { 2381106Svbart@nginx.com /* 2382106Svbart@nginx.com * Indentation, space after ":", new line, and possible 2383106Svbart@nginx.com * additional empty line between non-empty objects. 2384106Svbart@nginx.com */ 2385106Svbart@nginx.com len += pretty->level + 1 + 2 + 2; 2386106Svbart@nginx.com } 2387106Svbart@nginx.com } 2388106Svbart@nginx.com 2389106Svbart@nginx.com if (pretty != NULL) { 2390106Svbart@nginx.com pretty->level--; 2391106Svbart@nginx.com 2392106Svbart@nginx.com /* Indentation and new line. */ 2393106Svbart@nginx.com len += pretty->level + 2; 2394106Svbart@nginx.com } 2395106Svbart@nginx.com 2396106Svbart@nginx.com return len; 2397106Svbart@nginx.com } 2398106Svbart@nginx.com 2399106Svbart@nginx.com 2400106Svbart@nginx.com static u_char * 2401106Svbart@nginx.com nxt_conf_json_print_object(u_char *p, nxt_conf_value_t *value, 2402106Svbart@nginx.com nxt_conf_json_pretty_t *pretty) 2403106Svbart@nginx.com { 2404106Svbart@nginx.com nxt_uint_t n; 2405106Svbart@nginx.com nxt_conf_object_t *object; 2406106Svbart@nginx.com nxt_conf_object_member_t *member; 2407106Svbart@nginx.com 2408106Svbart@nginx.com object = value->u.object; 2409106Svbart@nginx.com 2410106Svbart@nginx.com *p++ = '{'; 2411106Svbart@nginx.com 2412106Svbart@nginx.com if (object->count != 0) { 2413106Svbart@nginx.com 2414106Svbart@nginx.com if (pretty != NULL) { 2415106Svbart@nginx.com p = nxt_conf_json_newline(p); 2416106Svbart@nginx.com pretty->level++; 2417106Svbart@nginx.com } 2418106Svbart@nginx.com 2419106Svbart@nginx.com member = object->members; 2420106Svbart@nginx.com 2421106Svbart@nginx.com n = 0; 2422106Svbart@nginx.com 2423106Svbart@nginx.com for ( ;; ) { 2424106Svbart@nginx.com if (pretty != NULL) { 2425106Svbart@nginx.com p = nxt_conf_json_indentation(p, pretty->level); 2426106Svbart@nginx.com } 2427106Svbart@nginx.com 2428106Svbart@nginx.com p = nxt_conf_json_print_string(p, &member[n].name); 2429106Svbart@nginx.com 2430106Svbart@nginx.com *p++ = ':'; 2431106Svbart@nginx.com 2432106Svbart@nginx.com if (pretty != NULL) { 2433106Svbart@nginx.com *p++ = ' '; 2434106Svbart@nginx.com } 2435106Svbart@nginx.com 2436106Svbart@nginx.com p = nxt_conf_json_print(p, &member[n].value, pretty); 2437106Svbart@nginx.com 2438106Svbart@nginx.com n++; 2439106Svbart@nginx.com 2440106Svbart@nginx.com if (n == object->count) { 2441106Svbart@nginx.com break; 2442106Svbart@nginx.com } 2443106Svbart@nginx.com 2444106Svbart@nginx.com *p++ = ','; 2445106Svbart@nginx.com 2446106Svbart@nginx.com if (pretty != NULL) { 2447106Svbart@nginx.com p = nxt_conf_json_newline(p); 2448106Svbart@nginx.com 2449106Svbart@nginx.com if (pretty->more_space) { 2450106Svbart@nginx.com pretty->more_space = 0; 2451106Svbart@nginx.com p = nxt_conf_json_newline(p); 2452106Svbart@nginx.com } 2453106Svbart@nginx.com } 2454106Svbart@nginx.com } 2455106Svbart@nginx.com 2456106Svbart@nginx.com if (pretty != NULL) { 2457106Svbart@nginx.com p = nxt_conf_json_newline(p); 2458106Svbart@nginx.com 2459106Svbart@nginx.com pretty->level--; 2460106Svbart@nginx.com p = nxt_conf_json_indentation(p, pretty->level); 2461106Svbart@nginx.com 2462106Svbart@nginx.com pretty->more_space = 1; 2463106Svbart@nginx.com } 2464106Svbart@nginx.com } 2465106Svbart@nginx.com 2466106Svbart@nginx.com *p++ = '}'; 2467106Svbart@nginx.com 2468106Svbart@nginx.com return p; 2469106Svbart@nginx.com } 2470106Svbart@nginx.com 2471106Svbart@nginx.com 2472106Svbart@nginx.com static size_t 2473106Svbart@nginx.com nxt_conf_json_escape_length(u_char *p, size_t size) 2474106Svbart@nginx.com { 2475106Svbart@nginx.com u_char ch; 2476106Svbart@nginx.com size_t len; 2477106Svbart@nginx.com 2478106Svbart@nginx.com len = size; 2479106Svbart@nginx.com 2480106Svbart@nginx.com while (size) { 2481106Svbart@nginx.com ch = *p++; 2482106Svbart@nginx.com 2483106Svbart@nginx.com if (ch == '\\' || ch == '"') { 2484106Svbart@nginx.com len++; 2485106Svbart@nginx.com 2486611Svbart@nginx.com } else if (ch <= 0x1F) { 2487106Svbart@nginx.com 2488106Svbart@nginx.com switch (ch) { 2489106Svbart@nginx.com case '\n': 2490106Svbart@nginx.com case '\r': 2491106Svbart@nginx.com case '\t': 2492106Svbart@nginx.com case '\b': 2493106Svbart@nginx.com case '\f': 2494106Svbart@nginx.com len++; 2495106Svbart@nginx.com break; 2496106Svbart@nginx.com 2497106Svbart@nginx.com default: 2498106Svbart@nginx.com len += sizeof("\\u001F") - 2; 2499106Svbart@nginx.com } 2500106Svbart@nginx.com } 2501106Svbart@nginx.com 2502106Svbart@nginx.com size--; 2503106Svbart@nginx.com } 2504106Svbart@nginx.com 2505106Svbart@nginx.com return len; 2506106Svbart@nginx.com } 2507106Svbart@nginx.com 2508106Svbart@nginx.com 2509106Svbart@nginx.com static u_char * 2510106Svbart@nginx.com nxt_conf_json_escape(u_char *dst, u_char *src, size_t size) 2511106Svbart@nginx.com { 2512106Svbart@nginx.com u_char ch; 2513106Svbart@nginx.com 2514106Svbart@nginx.com while (size) { 2515106Svbart@nginx.com ch = *src++; 2516106Svbart@nginx.com 2517611Svbart@nginx.com if (ch > 0x1F) { 2518106Svbart@nginx.com 2519106Svbart@nginx.com if (ch == '\\' || ch == '"') { 2520106Svbart@nginx.com *dst++ = '\\'; 2521106Svbart@nginx.com } 2522106Svbart@nginx.com 2523106Svbart@nginx.com *dst++ = ch; 2524106Svbart@nginx.com 2525106Svbart@nginx.com } else { 2526106Svbart@nginx.com *dst++ = '\\'; 2527106Svbart@nginx.com 2528106Svbart@nginx.com switch (ch) { 2529106Svbart@nginx.com case '\n': 2530106Svbart@nginx.com *dst++ = 'n'; 2531106Svbart@nginx.com break; 2532106Svbart@nginx.com 2533106Svbart@nginx.com case '\r': 2534106Svbart@nginx.com *dst++ = 'r'; 2535106Svbart@nginx.com break; 2536106Svbart@nginx.com 2537106Svbart@nginx.com case '\t': 2538106Svbart@nginx.com *dst++ = 't'; 2539106Svbart@nginx.com break; 2540106Svbart@nginx.com 2541106Svbart@nginx.com case '\b': 2542106Svbart@nginx.com *dst++ = 'b'; 2543106Svbart@nginx.com break; 2544106Svbart@nginx.com 2545106Svbart@nginx.com case '\f': 2546106Svbart@nginx.com *dst++ = 'f'; 2547106Svbart@nginx.com break; 2548106Svbart@nginx.com 2549106Svbart@nginx.com default: 2550106Svbart@nginx.com *dst++ = 'u'; *dst++ = '0'; *dst++ = '0'; 2551106Svbart@nginx.com *dst++ = '0' + (ch >> 4); 2552106Svbart@nginx.com 2553611Svbart@nginx.com ch &= 0xF; 2554106Svbart@nginx.com 2555106Svbart@nginx.com *dst++ = (ch < 10) ? ('0' + ch) : ('A' + ch - 10); 2556106Svbart@nginx.com } 2557106Svbart@nginx.com } 2558106Svbart@nginx.com 2559106Svbart@nginx.com size--; 2560106Svbart@nginx.com } 2561106Svbart@nginx.com 2562106Svbart@nginx.com return dst; 2563106Svbart@nginx.com } 2564208Svbart@nginx.com 2565208Svbart@nginx.com 2566208Svbart@nginx.com void 2567208Svbart@nginx.com nxt_conf_json_position(u_char *start, u_char *pos, nxt_uint_t *line, 2568208Svbart@nginx.com nxt_uint_t *column) 2569208Svbart@nginx.com { 2570208Svbart@nginx.com u_char *p; 2571208Svbart@nginx.com ssize_t symbols; 2572208Svbart@nginx.com nxt_uint_t lines; 2573208Svbart@nginx.com 2574208Svbart@nginx.com lines = 1; 2575208Svbart@nginx.com 2576208Svbart@nginx.com for (p = start; p != pos; p++) { 2577208Svbart@nginx.com 2578208Svbart@nginx.com if (*p != '\n') { 2579208Svbart@nginx.com continue; 2580208Svbart@nginx.com } 2581208Svbart@nginx.com 2582208Svbart@nginx.com lines++; 2583208Svbart@nginx.com start = p + 1; 2584208Svbart@nginx.com } 2585208Svbart@nginx.com 2586208Svbart@nginx.com symbols = nxt_utf8_length(start, p - start); 2587208Svbart@nginx.com 2588208Svbart@nginx.com if (symbols != -1) { 2589208Svbart@nginx.com *line = lines; 2590208Svbart@nginx.com *column = 1 + symbols; 2591208Svbart@nginx.com } 2592208Svbart@nginx.com } 2593