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 19106Svbart@nginx.com 20106Svbart@nginx.com typedef enum { 21116Svbart@nginx.com NXT_CONF_VALUE_NULL = 0, 22116Svbart@nginx.com NXT_CONF_VALUE_BOOLEAN, 23116Svbart@nginx.com NXT_CONF_VALUE_INTEGER, 24116Svbart@nginx.com NXT_CONF_VALUE_NUMBER, 25116Svbart@nginx.com NXT_CONF_VALUE_SHORT_STRING, 26116Svbart@nginx.com NXT_CONF_VALUE_STRING, 27116Svbart@nginx.com NXT_CONF_VALUE_ARRAY, 28116Svbart@nginx.com NXT_CONF_VALUE_OBJECT, 29116Svbart@nginx.com } nxt_conf_value_type_t; 30106Svbart@nginx.com 31106Svbart@nginx.com 32106Svbart@nginx.com typedef enum { 33106Svbart@nginx.com NXT_CONF_OP_PASS = 0, 34106Svbart@nginx.com NXT_CONF_OP_CREATE, 35106Svbart@nginx.com NXT_CONF_OP_REPLACE, 36106Svbart@nginx.com NXT_CONF_OP_DELETE, 37106Svbart@nginx.com } nxt_conf_op_action_t; 38106Svbart@nginx.com 39106Svbart@nginx.com 40106Svbart@nginx.com typedef struct nxt_conf_array_s nxt_conf_array_t; 41106Svbart@nginx.com typedef struct nxt_conf_object_s nxt_conf_object_t; 42106Svbart@nginx.com 43106Svbart@nginx.com 44180Smax.romanov@nginx.com struct nxt_conf_value_s { 45187Smax.romanov@nginx.com union { 46171Svbart@nginx.com uint8_t boolean; /* 1 bit. */ 47106Svbart@nginx.com int64_t integer; 48106Svbart@nginx.com double number; 49173Svbart@nginx.com 50173Svbart@nginx.com struct { 51208Svbart@nginx.com u_char start[NXT_CONF_MAX_SHORT_STRING]; 52173Svbart@nginx.com uint8_t length; 53173Svbart@nginx.com } str; 54172Svbart@nginx.com 55187Smax.romanov@nginx.com struct { 56172Svbart@nginx.com u_char *start; 57172Svbart@nginx.com uint32_t length; 58187Smax.romanov@nginx.com } nxt_packed string; 59172Svbart@nginx.com 60106Svbart@nginx.com nxt_conf_array_t *array; 61106Svbart@nginx.com nxt_conf_object_t *object; 62187Smax.romanov@nginx.com } nxt_packed u; 63106Svbart@nginx.com 64171Svbart@nginx.com uint8_t type; /* 3 bits. */ 65180Smax.romanov@nginx.com } nxt_aligned(8); 66106Svbart@nginx.com 67106Svbart@nginx.com 68106Svbart@nginx.com struct nxt_conf_array_s { 69106Svbart@nginx.com nxt_uint_t count; 70106Svbart@nginx.com nxt_conf_value_t elements[]; 71106Svbart@nginx.com }; 72106Svbart@nginx.com 73106Svbart@nginx.com 74106Svbart@nginx.com typedef struct { 75106Svbart@nginx.com nxt_conf_value_t name; 76106Svbart@nginx.com nxt_conf_value_t value; 77106Svbart@nginx.com } nxt_conf_object_member_t; 78106Svbart@nginx.com 79106Svbart@nginx.com 80106Svbart@nginx.com struct nxt_conf_object_s { 81106Svbart@nginx.com nxt_uint_t count; 82106Svbart@nginx.com nxt_conf_object_member_t members[]; 83106Svbart@nginx.com }; 84106Svbart@nginx.com 85106Svbart@nginx.com 86106Svbart@nginx.com struct nxt_conf_op_s { 87106Svbart@nginx.com uint32_t index; 88106Svbart@nginx.com uint32_t action; /* nxt_conf_op_action_t */ 89106Svbart@nginx.com void *ctx; 90106Svbart@nginx.com nxt_conf_op_t *next; 91106Svbart@nginx.com }; 92106Svbart@nginx.com 93106Svbart@nginx.com 94106Svbart@nginx.com static u_char *nxt_conf_json_skip_space(u_char *start, u_char *end); 95106Svbart@nginx.com static u_char *nxt_conf_json_parse_value(nxt_mp_t *mp, nxt_conf_value_t *value, 96208Svbart@nginx.com u_char *start, u_char *end, nxt_conf_json_error_t *error); 97106Svbart@nginx.com static u_char *nxt_conf_json_parse_object(nxt_mp_t *mp, nxt_conf_value_t *value, 98208Svbart@nginx.com u_char *start, u_char *end, nxt_conf_json_error_t *error); 99106Svbart@nginx.com static nxt_int_t nxt_conf_object_hash_add(nxt_mp_t *mp, 100106Svbart@nginx.com nxt_lvlhsh_t *lvlhsh, nxt_conf_object_member_t *member); 101106Svbart@nginx.com static nxt_int_t nxt_conf_object_hash_test(nxt_lvlhsh_query_t *lhq, 102106Svbart@nginx.com void *data); 103106Svbart@nginx.com static void *nxt_conf_object_hash_alloc(void *data, size_t size); 104106Svbart@nginx.com static void nxt_conf_object_hash_free(void *data, void *p); 105106Svbart@nginx.com static u_char *nxt_conf_json_parse_array(nxt_mp_t *mp, nxt_conf_value_t *value, 106208Svbart@nginx.com u_char *start, u_char *end, nxt_conf_json_error_t *error); 107106Svbart@nginx.com static u_char *nxt_conf_json_parse_string(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_number(nxt_mp_t *mp, nxt_conf_value_t *value, 110208Svbart@nginx.com u_char *start, u_char *end, nxt_conf_json_error_t *error); 111208Svbart@nginx.com static void nxt_conf_json_parse_error(nxt_conf_json_error_t *error, u_char *pos, 112208Svbart@nginx.com const char *detail); 113106Svbart@nginx.com 114106Svbart@nginx.com static nxt_int_t nxt_conf_copy_value(nxt_mp_t *mp, nxt_conf_op_t *op, 115106Svbart@nginx.com nxt_conf_value_t *dst, nxt_conf_value_t *src); 116106Svbart@nginx.com static nxt_int_t nxt_conf_copy_object(nxt_mp_t *mp, nxt_conf_op_t *op, 117106Svbart@nginx.com nxt_conf_value_t *dst, nxt_conf_value_t *src); 118106Svbart@nginx.com 119106Svbart@nginx.com static size_t nxt_conf_json_integer_length(nxt_conf_value_t *value); 120106Svbart@nginx.com static u_char *nxt_conf_json_print_integer(u_char *p, nxt_conf_value_t *value); 121106Svbart@nginx.com static size_t nxt_conf_json_string_length(nxt_conf_value_t *value); 122106Svbart@nginx.com static u_char *nxt_conf_json_print_string(u_char *p, nxt_conf_value_t *value); 123106Svbart@nginx.com static size_t nxt_conf_json_array_length(nxt_conf_value_t *value, 124106Svbart@nginx.com nxt_conf_json_pretty_t *pretty); 125106Svbart@nginx.com static u_char *nxt_conf_json_print_array(u_char *p, nxt_conf_value_t *value, 126106Svbart@nginx.com nxt_conf_json_pretty_t *pretty); 127106Svbart@nginx.com static size_t nxt_conf_json_object_length(nxt_conf_value_t *value, 128106Svbart@nginx.com nxt_conf_json_pretty_t *pretty); 129106Svbart@nginx.com static u_char *nxt_conf_json_print_object(u_char *p, nxt_conf_value_t *value, 130106Svbart@nginx.com nxt_conf_json_pretty_t *pretty); 131106Svbart@nginx.com 132106Svbart@nginx.com static size_t nxt_conf_json_escape_length(u_char *p, size_t size); 133106Svbart@nginx.com static u_char *nxt_conf_json_escape(u_char *dst, u_char *src, size_t size); 134106Svbart@nginx.com 135106Svbart@nginx.com 136106Svbart@nginx.com #define nxt_conf_json_newline(p) \ 137106Svbart@nginx.com ((p)[0] = '\r', (p)[1] = '\n', (p) + 2) 138106Svbart@nginx.com 139106Svbart@nginx.com 140106Svbart@nginx.com nxt_inline u_char * 141106Svbart@nginx.com nxt_conf_json_indentation(u_char *p, uint32_t level) 142106Svbart@nginx.com { 143106Svbart@nginx.com while (level) { 144106Svbart@nginx.com *p++ = '\t'; 145106Svbart@nginx.com level--; 146106Svbart@nginx.com } 147106Svbart@nginx.com 148106Svbart@nginx.com return p; 149106Svbart@nginx.com } 150106Svbart@nginx.com 151106Svbart@nginx.com 152121Svbart@nginx.com void 153106Svbart@nginx.com nxt_conf_get_string(nxt_conf_value_t *value, nxt_str_t *str) 154106Svbart@nginx.com { 155116Svbart@nginx.com if (value->type == NXT_CONF_VALUE_SHORT_STRING) { 156173Svbart@nginx.com str->length = value->u.str.length; 157173Svbart@nginx.com str->start = value->u.str.start; 158106Svbart@nginx.com 159106Svbart@nginx.com } else { 160172Svbart@nginx.com str->length = value->u.string.length; 161172Svbart@nginx.com str->start = value->u.string.start; 162106Svbart@nginx.com } 163106Svbart@nginx.com } 164106Svbart@nginx.com 165106Svbart@nginx.com 166*507Smax.romanov@nginx.com int64_t 167*507Smax.romanov@nginx.com nxt_conf_get_integer(nxt_conf_value_t *value) 168*507Smax.romanov@nginx.com { 169*507Smax.romanov@nginx.com return value->u.integer; 170*507Smax.romanov@nginx.com } 171*507Smax.romanov@nginx.com 172*507Smax.romanov@nginx.com 173116Svbart@nginx.com nxt_uint_t 174121Svbart@nginx.com nxt_conf_object_members_count(nxt_conf_value_t *value) 175121Svbart@nginx.com { 176121Svbart@nginx.com return value->u.object->count; 177121Svbart@nginx.com } 178121Svbart@nginx.com 179121Svbart@nginx.com 180121Svbart@nginx.com nxt_conf_value_t * 181121Svbart@nginx.com nxt_conf_create_object(nxt_mp_t *mp, nxt_uint_t count) 182121Svbart@nginx.com { 183121Svbart@nginx.com size_t size; 184121Svbart@nginx.com nxt_conf_value_t *value; 185121Svbart@nginx.com 186121Svbart@nginx.com size = sizeof(nxt_conf_value_t) 187121Svbart@nginx.com + sizeof(nxt_conf_object_t) 188121Svbart@nginx.com + count * sizeof(nxt_conf_object_member_t); 189121Svbart@nginx.com 190121Svbart@nginx.com value = nxt_mp_get(mp, size); 191121Svbart@nginx.com if (nxt_slow_path(value == NULL)) { 192121Svbart@nginx.com return NULL; 193121Svbart@nginx.com } 194121Svbart@nginx.com 195121Svbart@nginx.com value->u.object = nxt_pointer_to(value, sizeof(nxt_conf_value_t)); 196121Svbart@nginx.com value->u.object->count = count; 197121Svbart@nginx.com 198121Svbart@nginx.com value->type = NXT_CONF_VALUE_OBJECT; 199121Svbart@nginx.com 200121Svbart@nginx.com return value; 201121Svbart@nginx.com } 202121Svbart@nginx.com 203121Svbart@nginx.com 204208Svbart@nginx.com void 205208Svbart@nginx.com nxt_conf_set_member(nxt_conf_value_t *object, nxt_str_t *name, 206172Svbart@nginx.com nxt_conf_value_t *value, uint32_t index) 207121Svbart@nginx.com { 208121Svbart@nginx.com nxt_conf_value_t *name_value; 209121Svbart@nginx.com nxt_conf_object_member_t *member; 210121Svbart@nginx.com 211121Svbart@nginx.com member = &object->u.object->members[index]; 212121Svbart@nginx.com name_value = &member->name; 213121Svbart@nginx.com 214121Svbart@nginx.com if (name->length > NXT_CONF_MAX_SHORT_STRING) { 215121Svbart@nginx.com name_value->type = NXT_CONF_VALUE_STRING; 216172Svbart@nginx.com name_value->u.string.length = name->length; 217172Svbart@nginx.com name_value->u.string.start = name->start; 218121Svbart@nginx.com 219121Svbart@nginx.com } else { 220121Svbart@nginx.com name_value->type = NXT_CONF_VALUE_SHORT_STRING; 221173Svbart@nginx.com name_value->u.str.length = name->length; 222173Svbart@nginx.com 223173Svbart@nginx.com nxt_memcpy(name_value->u.str.start, name->start, name->length); 224121Svbart@nginx.com } 225121Svbart@nginx.com 226121Svbart@nginx.com member->value = *value; 227208Svbart@nginx.com } 228208Svbart@nginx.com 229208Svbart@nginx.com 230208Svbart@nginx.com void 231208Svbart@nginx.com nxt_conf_set_member_string(nxt_conf_value_t *object, nxt_str_t *name, 232208Svbart@nginx.com nxt_str_t *value, uint32_t index) 233208Svbart@nginx.com { 234208Svbart@nginx.com nxt_conf_value_t *set; 235208Svbart@nginx.com nxt_conf_object_member_t *member; 236208Svbart@nginx.com 237208Svbart@nginx.com member = &object->u.object->members[index]; 238208Svbart@nginx.com set = &member->name; 239208Svbart@nginx.com 240208Svbart@nginx.com if (name->length > NXT_CONF_MAX_SHORT_STRING) { 241208Svbart@nginx.com set->type = NXT_CONF_VALUE_STRING; 242208Svbart@nginx.com set->u.string.length = name->length; 243208Svbart@nginx.com set->u.string.start = name->start; 244208Svbart@nginx.com 245208Svbart@nginx.com } else { 246208Svbart@nginx.com set->type = NXT_CONF_VALUE_SHORT_STRING; 247208Svbart@nginx.com set->u.str.length = name->length; 248208Svbart@nginx.com 249208Svbart@nginx.com nxt_memcpy(set->u.str.start, name->start, name->length); 250208Svbart@nginx.com } 251208Svbart@nginx.com 252208Svbart@nginx.com set = &member->value; 253208Svbart@nginx.com 254208Svbart@nginx.com if (value->length > NXT_CONF_MAX_SHORT_STRING) { 255208Svbart@nginx.com set->type = NXT_CONF_VALUE_STRING; 256208Svbart@nginx.com set->u.string.length = value->length; 257208Svbart@nginx.com set->u.string.start = value->start; 258208Svbart@nginx.com 259208Svbart@nginx.com } else { 260208Svbart@nginx.com set->type = NXT_CONF_VALUE_SHORT_STRING; 261208Svbart@nginx.com set->u.str.length = value->length; 262208Svbart@nginx.com 263208Svbart@nginx.com nxt_memcpy(set->u.str.start, value->start, value->length); 264208Svbart@nginx.com } 265208Svbart@nginx.com } 266208Svbart@nginx.com 267208Svbart@nginx.com 268208Svbart@nginx.com void 269208Svbart@nginx.com nxt_conf_set_member_integer(nxt_conf_value_t *object, nxt_str_t *name, 270208Svbart@nginx.com int64_t value, uint32_t index) 271208Svbart@nginx.com { 272208Svbart@nginx.com nxt_conf_value_t *name_value; 273208Svbart@nginx.com nxt_conf_object_member_t *member; 274208Svbart@nginx.com 275208Svbart@nginx.com member = &object->u.object->members[index]; 276208Svbart@nginx.com name_value = &member->name; 277208Svbart@nginx.com 278208Svbart@nginx.com if (name->length > NXT_CONF_MAX_SHORT_STRING) { 279208Svbart@nginx.com name_value->type = NXT_CONF_VALUE_STRING; 280208Svbart@nginx.com name_value->u.string.length = name->length; 281208Svbart@nginx.com name_value->u.string.start = name->start; 282208Svbart@nginx.com 283208Svbart@nginx.com } else { 284208Svbart@nginx.com name_value->type = NXT_CONF_VALUE_SHORT_STRING; 285208Svbart@nginx.com name_value->u.str.length = name->length; 286208Svbart@nginx.com 287208Svbart@nginx.com nxt_memcpy(name_value->u.str.start, name->start, name->length); 288208Svbart@nginx.com } 289208Svbart@nginx.com 290208Svbart@nginx.com member->value.u.integer = value; 291208Svbart@nginx.com member->value.type = NXT_CONF_VALUE_INTEGER; 292121Svbart@nginx.com } 293121Svbart@nginx.com 294121Svbart@nginx.com 295121Svbart@nginx.com nxt_uint_t 296116Svbart@nginx.com nxt_conf_type(nxt_conf_value_t *value) 297116Svbart@nginx.com { 298116Svbart@nginx.com switch (value->type) { 299116Svbart@nginx.com 300116Svbart@nginx.com case NXT_CONF_VALUE_NULL: 301116Svbart@nginx.com return NXT_CONF_NULL; 302116Svbart@nginx.com 303116Svbart@nginx.com case NXT_CONF_VALUE_BOOLEAN: 304116Svbart@nginx.com return NXT_CONF_BOOLEAN; 305116Svbart@nginx.com 306116Svbart@nginx.com case NXT_CONF_VALUE_INTEGER: 307116Svbart@nginx.com return NXT_CONF_INTEGER; 308116Svbart@nginx.com 309116Svbart@nginx.com case NXT_CONF_VALUE_NUMBER: 310116Svbart@nginx.com return NXT_CONF_NUMBER; 311116Svbart@nginx.com 312116Svbart@nginx.com case NXT_CONF_VALUE_SHORT_STRING: 313116Svbart@nginx.com case NXT_CONF_VALUE_STRING: 314116Svbart@nginx.com return NXT_CONF_STRING; 315116Svbart@nginx.com 316116Svbart@nginx.com case NXT_CONF_VALUE_ARRAY: 317116Svbart@nginx.com return NXT_CONF_ARRAY; 318116Svbart@nginx.com 319116Svbart@nginx.com case NXT_CONF_VALUE_OBJECT: 320116Svbart@nginx.com return NXT_CONF_OBJECT; 321116Svbart@nginx.com } 322116Svbart@nginx.com 323116Svbart@nginx.com nxt_unreachable(); 324116Svbart@nginx.com 325116Svbart@nginx.com return 0; 326116Svbart@nginx.com } 327116Svbart@nginx.com 328116Svbart@nginx.com 329106Svbart@nginx.com typedef struct { 330106Svbart@nginx.com u_char *start; 331106Svbart@nginx.com u_char *end; 332106Svbart@nginx.com nxt_bool_t last; 333106Svbart@nginx.com } nxt_conf_path_parse_t; 334106Svbart@nginx.com 335106Svbart@nginx.com 336106Svbart@nginx.com static void nxt_conf_path_next_token(nxt_conf_path_parse_t *parse, 337106Svbart@nginx.com nxt_str_t *token); 338106Svbart@nginx.com 339106Svbart@nginx.com 340106Svbart@nginx.com nxt_conf_value_t * 341106Svbart@nginx.com nxt_conf_get_path(nxt_conf_value_t *value, nxt_str_t *path) 342106Svbart@nginx.com { 343106Svbart@nginx.com nxt_str_t token; 344106Svbart@nginx.com nxt_conf_path_parse_t parse; 345106Svbart@nginx.com 346106Svbart@nginx.com parse.start = path->start; 347106Svbart@nginx.com parse.end = path->start + path->length; 348106Svbart@nginx.com parse.last = 0; 349106Svbart@nginx.com 350106Svbart@nginx.com do { 351106Svbart@nginx.com nxt_conf_path_next_token(&parse, &token); 352106Svbart@nginx.com 353106Svbart@nginx.com if (token.length == 0) { 354106Svbart@nginx.com 355106Svbart@nginx.com if (parse.last) { 356106Svbart@nginx.com break; 357106Svbart@nginx.com } 358106Svbart@nginx.com 359106Svbart@nginx.com return NULL; 360106Svbart@nginx.com } 361106Svbart@nginx.com 362106Svbart@nginx.com value = nxt_conf_get_object_member(value, &token, NULL); 363106Svbart@nginx.com 364106Svbart@nginx.com if (value == NULL) { 365106Svbart@nginx.com return NULL; 366106Svbart@nginx.com } 367106Svbart@nginx.com 368106Svbart@nginx.com } while (parse.last == 0); 369106Svbart@nginx.com 370106Svbart@nginx.com return value; 371106Svbart@nginx.com } 372106Svbart@nginx.com 373106Svbart@nginx.com 374106Svbart@nginx.com static void 375106Svbart@nginx.com nxt_conf_path_next_token(nxt_conf_path_parse_t *parse, nxt_str_t *token) 376106Svbart@nginx.com { 377106Svbart@nginx.com u_char *p, *end; 378106Svbart@nginx.com 379106Svbart@nginx.com end = parse->end; 380106Svbart@nginx.com p = parse->start + 1; 381106Svbart@nginx.com 382106Svbart@nginx.com token->start = p; 383106Svbart@nginx.com 384106Svbart@nginx.com while (p < end && *p != '/') { 385106Svbart@nginx.com p++; 386106Svbart@nginx.com } 387106Svbart@nginx.com 388106Svbart@nginx.com parse->start = p; 389106Svbart@nginx.com parse->last = (p >= end); 390106Svbart@nginx.com 391106Svbart@nginx.com token->length = p - token->start; 392106Svbart@nginx.com } 393106Svbart@nginx.com 394106Svbart@nginx.com 395106Svbart@nginx.com nxt_conf_value_t * 396106Svbart@nginx.com nxt_conf_get_object_member(nxt_conf_value_t *value, nxt_str_t *name, 397106Svbart@nginx.com uint32_t *index) 398106Svbart@nginx.com { 399106Svbart@nginx.com nxt_str_t str; 400106Svbart@nginx.com nxt_uint_t n; 401106Svbart@nginx.com nxt_conf_object_t *object; 402106Svbart@nginx.com nxt_conf_object_member_t *member; 403106Svbart@nginx.com 404116Svbart@nginx.com if (value->type != NXT_CONF_VALUE_OBJECT) { 405106Svbart@nginx.com return NULL; 406106Svbart@nginx.com } 407106Svbart@nginx.com 408106Svbart@nginx.com object = value->u.object; 409106Svbart@nginx.com 410106Svbart@nginx.com for (n = 0; n < object->count; n++) { 411106Svbart@nginx.com member = &object->members[n]; 412106Svbart@nginx.com 413106Svbart@nginx.com nxt_conf_get_string(&member->name, &str); 414106Svbart@nginx.com 415106Svbart@nginx.com if (nxt_strstr_eq(&str, name)) { 416106Svbart@nginx.com 417106Svbart@nginx.com if (index != NULL) { 418106Svbart@nginx.com *index = n; 419106Svbart@nginx.com } 420106Svbart@nginx.com 421106Svbart@nginx.com return &member->value; 422106Svbart@nginx.com } 423106Svbart@nginx.com } 424106Svbart@nginx.com 425106Svbart@nginx.com return NULL; 426106Svbart@nginx.com } 427106Svbart@nginx.com 428106Svbart@nginx.com 429106Svbart@nginx.com nxt_int_t 430213Svbart@nginx.com nxt_conf_map_object(nxt_mp_t *mp, nxt_conf_value_t *value, nxt_conf_map_t *map, 431213Svbart@nginx.com nxt_uint_t n, void *data) 432106Svbart@nginx.com { 433213Svbart@nginx.com nxt_str_t str, *s; 434106Svbart@nginx.com nxt_uint_t i; 435106Svbart@nginx.com nxt_conf_value_t *v; 436106Svbart@nginx.com 437106Svbart@nginx.com union { 438111Sigor@sysoev.ru uint8_t ui8; 439111Sigor@sysoev.ru int32_t i32; 440111Sigor@sysoev.ru int64_t i64; 441111Sigor@sysoev.ru nxt_int_t i; 442111Sigor@sysoev.ru ssize_t size; 443111Sigor@sysoev.ru off_t off; 444111Sigor@sysoev.ru nxt_msec_t msec; 445111Sigor@sysoev.ru double dbl; 446111Sigor@sysoev.ru nxt_str_t str; 447213Svbart@nginx.com char *cstrz; 448111Sigor@sysoev.ru void *v; 449106Svbart@nginx.com } *ptr; 450106Svbart@nginx.com 451136Svbart@nginx.com for (i = 0; i < n; i++) { 452106Svbart@nginx.com 453106Svbart@nginx.com v = nxt_conf_get_object_member(value, &map[i].name, NULL); 454106Svbart@nginx.com 455116Svbart@nginx.com if (v == NULL || v->type == NXT_CONF_VALUE_NULL) { 456106Svbart@nginx.com continue; 457106Svbart@nginx.com } 458106Svbart@nginx.com 459106Svbart@nginx.com ptr = nxt_pointer_to(data, map[i].offset); 460106Svbart@nginx.com 461106Svbart@nginx.com switch (map[i].type) { 462106Svbart@nginx.com 463106Svbart@nginx.com case NXT_CONF_MAP_INT8: 464106Svbart@nginx.com 465136Svbart@nginx.com if (v->type == NXT_CONF_VALUE_BOOLEAN) { 466136Svbart@nginx.com ptr->ui8 = v->u.boolean; 467106Svbart@nginx.com } 468106Svbart@nginx.com 469106Svbart@nginx.com break; 470106Svbart@nginx.com 471106Svbart@nginx.com case NXT_CONF_MAP_INT32: 472106Svbart@nginx.com case NXT_CONF_MAP_INT64: 473106Svbart@nginx.com case NXT_CONF_MAP_INT: 474106Svbart@nginx.com case NXT_CONF_MAP_SIZE: 475106Svbart@nginx.com case NXT_CONF_MAP_OFF: 476111Sigor@sysoev.ru case NXT_CONF_MAP_MSEC: 477106Svbart@nginx.com 478116Svbart@nginx.com if (v->type != NXT_CONF_VALUE_INTEGER) { 479136Svbart@nginx.com break; 480106Svbart@nginx.com } 481106Svbart@nginx.com 482106Svbart@nginx.com switch (map[i].type) { 483106Svbart@nginx.com 484106Svbart@nginx.com case NXT_CONF_MAP_INT32: 485120Svbart@nginx.com ptr->i32 = v->u.integer; 486106Svbart@nginx.com break; 487106Svbart@nginx.com 488106Svbart@nginx.com case NXT_CONF_MAP_INT64: 489106Svbart@nginx.com ptr->i64 = v->u.integer; 490106Svbart@nginx.com break; 491106Svbart@nginx.com 492106Svbart@nginx.com case NXT_CONF_MAP_INT: 493106Svbart@nginx.com ptr->i = v->u.integer; 494106Svbart@nginx.com break; 495106Svbart@nginx.com 496106Svbart@nginx.com case NXT_CONF_MAP_SIZE: 497106Svbart@nginx.com ptr->size = v->u.integer; 498106Svbart@nginx.com break; 499106Svbart@nginx.com 500106Svbart@nginx.com case NXT_CONF_MAP_OFF: 501106Svbart@nginx.com ptr->off = v->u.integer; 502106Svbart@nginx.com break; 503106Svbart@nginx.com 504111Sigor@sysoev.ru case NXT_CONF_MAP_MSEC: 505318Smax.romanov@nginx.com ptr->msec = v->u.integer * 1000; 506111Sigor@sysoev.ru break; 507111Sigor@sysoev.ru 508106Svbart@nginx.com default: 509106Svbart@nginx.com nxt_unreachable(); 510106Svbart@nginx.com } 511106Svbart@nginx.com 512106Svbart@nginx.com break; 513106Svbart@nginx.com 514106Svbart@nginx.com case NXT_CONF_MAP_DOUBLE: 515106Svbart@nginx.com 516116Svbart@nginx.com if (v->type == NXT_CONF_VALUE_NUMBER) { 517106Svbart@nginx.com ptr->dbl = v->u.number; 518106Svbart@nginx.com 519116Svbart@nginx.com } else if (v->type == NXT_CONF_VALUE_INTEGER) { 520106Svbart@nginx.com ptr->dbl = v->u.integer; 521106Svbart@nginx.com 522106Svbart@nginx.com } 523106Svbart@nginx.com 524106Svbart@nginx.com break; 525106Svbart@nginx.com 526106Svbart@nginx.com case NXT_CONF_MAP_STR: 527213Svbart@nginx.com case NXT_CONF_MAP_STR_COPY: 528213Svbart@nginx.com case NXT_CONF_MAP_CSTRZ: 529213Svbart@nginx.com 530213Svbart@nginx.com if (v->type != NXT_CONF_VALUE_SHORT_STRING 531213Svbart@nginx.com && v->type != NXT_CONF_VALUE_STRING) 532106Svbart@nginx.com { 533213Svbart@nginx.com break; 534213Svbart@nginx.com } 535213Svbart@nginx.com 536213Svbart@nginx.com nxt_conf_get_string(v, &str); 537213Svbart@nginx.com 538213Svbart@nginx.com switch (map[i].type) { 539213Svbart@nginx.com 540213Svbart@nginx.com case NXT_CONF_MAP_STR: 541213Svbart@nginx.com ptr->str = str; 542213Svbart@nginx.com break; 543213Svbart@nginx.com 544213Svbart@nginx.com case NXT_CONF_MAP_STR_COPY: 545213Svbart@nginx.com 546213Svbart@nginx.com s = nxt_str_dup(mp, &ptr->str, &str); 547213Svbart@nginx.com 548213Svbart@nginx.com if (nxt_slow_path(s == NULL)) { 549213Svbart@nginx.com return NXT_ERROR; 550213Svbart@nginx.com } 551213Svbart@nginx.com 552213Svbart@nginx.com break; 553213Svbart@nginx.com 554213Svbart@nginx.com case NXT_CONF_MAP_CSTRZ: 555213Svbart@nginx.com 556213Svbart@nginx.com ptr->cstrz = nxt_str_cstrz(mp, &str); 557213Svbart@nginx.com 558213Svbart@nginx.com if (nxt_slow_path(ptr->cstrz == NULL)) { 559213Svbart@nginx.com return NXT_ERROR; 560213Svbart@nginx.com } 561213Svbart@nginx.com 562213Svbart@nginx.com break; 563213Svbart@nginx.com 564213Svbart@nginx.com default: 565213Svbart@nginx.com nxt_unreachable(); 566106Svbart@nginx.com } 567106Svbart@nginx.com 568106Svbart@nginx.com break; 569106Svbart@nginx.com 570106Svbart@nginx.com case NXT_CONF_MAP_PTR: 571106Svbart@nginx.com 572106Svbart@nginx.com ptr->v = v; 573106Svbart@nginx.com 574106Svbart@nginx.com break; 575106Svbart@nginx.com } 576106Svbart@nginx.com } 577106Svbart@nginx.com 578106Svbart@nginx.com return NXT_OK; 579106Svbart@nginx.com } 580106Svbart@nginx.com 581106Svbart@nginx.com 582106Svbart@nginx.com nxt_conf_value_t * 583106Svbart@nginx.com nxt_conf_next_object_member(nxt_conf_value_t *value, nxt_str_t *name, 584106Svbart@nginx.com uint32_t *next) 585106Svbart@nginx.com { 586106Svbart@nginx.com uint32_t n; 587106Svbart@nginx.com nxt_conf_object_t *object; 588106Svbart@nginx.com nxt_conf_object_member_t *member; 589106Svbart@nginx.com 590116Svbart@nginx.com if (value->type != NXT_CONF_VALUE_OBJECT) { 591106Svbart@nginx.com return NULL; 592106Svbart@nginx.com } 593106Svbart@nginx.com 594106Svbart@nginx.com n = *next; 595106Svbart@nginx.com object = value->u.object; 596106Svbart@nginx.com 597106Svbart@nginx.com if (n >= object->count) { 598106Svbart@nginx.com return NULL; 599106Svbart@nginx.com } 600106Svbart@nginx.com 601106Svbart@nginx.com member = &object->members[n]; 602106Svbart@nginx.com *next = n + 1; 603106Svbart@nginx.com 604106Svbart@nginx.com nxt_conf_get_string(&member->name, name); 605106Svbart@nginx.com 606106Svbart@nginx.com return &member->value; 607106Svbart@nginx.com } 608106Svbart@nginx.com 609106Svbart@nginx.com 610214Svbart@nginx.com nxt_conf_value_t * 611214Svbart@nginx.com nxt_conf_get_array_element(nxt_conf_value_t *value, uint32_t index) 612214Svbart@nginx.com { 613214Svbart@nginx.com nxt_conf_array_t *array; 614214Svbart@nginx.com 615214Svbart@nginx.com if (value->type != NXT_CONF_VALUE_ARRAY) { 616214Svbart@nginx.com return NULL; 617214Svbart@nginx.com } 618214Svbart@nginx.com 619214Svbart@nginx.com array = value->u.array; 620214Svbart@nginx.com 621214Svbart@nginx.com if (index >= array->count) { 622214Svbart@nginx.com return NULL; 623214Svbart@nginx.com } 624214Svbart@nginx.com 625214Svbart@nginx.com return &array->elements[index]; 626214Svbart@nginx.com } 627214Svbart@nginx.com 628214Svbart@nginx.com 629106Svbart@nginx.com nxt_int_t 630106Svbart@nginx.com nxt_conf_op_compile(nxt_mp_t *mp, nxt_conf_op_t **ops, nxt_conf_value_t *root, 631106Svbart@nginx.com nxt_str_t *path, nxt_conf_value_t *value) 632106Svbart@nginx.com { 633106Svbart@nginx.com nxt_str_t token; 634106Svbart@nginx.com nxt_conf_op_t *op, **parent; 635106Svbart@nginx.com nxt_conf_path_parse_t parse; 636106Svbart@nginx.com nxt_conf_object_member_t *member; 637106Svbart@nginx.com 638106Svbart@nginx.com parse.start = path->start; 639106Svbart@nginx.com parse.end = path->start + path->length; 640106Svbart@nginx.com parse.last = 0; 641106Svbart@nginx.com 642106Svbart@nginx.com parent = ops; 643106Svbart@nginx.com 644106Svbart@nginx.com for ( ;; ) { 645106Svbart@nginx.com op = nxt_mp_zget(mp, sizeof(nxt_conf_op_t)); 646106Svbart@nginx.com if (nxt_slow_path(op == NULL)) { 647106Svbart@nginx.com return NXT_ERROR; 648106Svbart@nginx.com } 649106Svbart@nginx.com 650106Svbart@nginx.com *parent = op; 651106Svbart@nginx.com parent = (nxt_conf_op_t **) &op->ctx; 652106Svbart@nginx.com 653106Svbart@nginx.com nxt_conf_path_next_token(&parse, &token); 654106Svbart@nginx.com 655106Svbart@nginx.com root = nxt_conf_get_object_member(root, &token, &op->index); 656106Svbart@nginx.com 657106Svbart@nginx.com if (parse.last) { 658106Svbart@nginx.com break; 659106Svbart@nginx.com } 660106Svbart@nginx.com 661106Svbart@nginx.com if (root == NULL) { 662106Svbart@nginx.com return NXT_DECLINED; 663106Svbart@nginx.com } 664106Svbart@nginx.com 665106Svbart@nginx.com op->action = NXT_CONF_OP_PASS; 666106Svbart@nginx.com } 667106Svbart@nginx.com 668106Svbart@nginx.com if (value == NULL) { 669106Svbart@nginx.com 670106Svbart@nginx.com if (root == NULL) { 671106Svbart@nginx.com return NXT_DECLINED; 672106Svbart@nginx.com } 673106Svbart@nginx.com 674106Svbart@nginx.com op->action = NXT_CONF_OP_DELETE; 675106Svbart@nginx.com 676106Svbart@nginx.com return NXT_OK; 677106Svbart@nginx.com } 678106Svbart@nginx.com 679106Svbart@nginx.com if (root == NULL) { 680106Svbart@nginx.com 681106Svbart@nginx.com member = nxt_mp_zget(mp, sizeof(nxt_conf_object_member_t)); 682106Svbart@nginx.com if (nxt_slow_path(member == NULL)) { 683106Svbart@nginx.com return NXT_ERROR; 684106Svbart@nginx.com } 685106Svbart@nginx.com 686106Svbart@nginx.com if (token.length > NXT_CONF_MAX_SHORT_STRING) { 687172Svbart@nginx.com member->name.u.string.length = token.length; 688172Svbart@nginx.com member->name.u.string.start = token.start; 689172Svbart@nginx.com 690116Svbart@nginx.com member->name.type = NXT_CONF_VALUE_STRING; 691106Svbart@nginx.com 692106Svbart@nginx.com } else { 693173Svbart@nginx.com member->name.u.str.length = token.length; 694173Svbart@nginx.com nxt_memcpy(member->name.u.str.start, token.start, token.length); 695106Svbart@nginx.com 696116Svbart@nginx.com member->name.type = NXT_CONF_VALUE_SHORT_STRING; 697106Svbart@nginx.com } 698106Svbart@nginx.com 699106Svbart@nginx.com member->value = *value; 700106Svbart@nginx.com 701106Svbart@nginx.com op->action = NXT_CONF_OP_CREATE; 702106Svbart@nginx.com op->ctx = member; 703106Svbart@nginx.com 704106Svbart@nginx.com } else { 705106Svbart@nginx.com op->action = NXT_CONF_OP_REPLACE; 706106Svbart@nginx.com op->ctx = value; 707106Svbart@nginx.com } 708106Svbart@nginx.com 709106Svbart@nginx.com return NXT_OK; 710106Svbart@nginx.com } 711106Svbart@nginx.com 712106Svbart@nginx.com 713106Svbart@nginx.com nxt_conf_value_t * 714106Svbart@nginx.com nxt_conf_clone(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *value) 715106Svbart@nginx.com { 716106Svbart@nginx.com nxt_int_t rc; 717106Svbart@nginx.com nxt_conf_value_t *copy; 718106Svbart@nginx.com 719106Svbart@nginx.com copy = nxt_mp_get(mp, sizeof(nxt_conf_value_t)); 720106Svbart@nginx.com if (nxt_slow_path(copy == NULL)) { 721106Svbart@nginx.com return NULL; 722106Svbart@nginx.com } 723106Svbart@nginx.com 724106Svbart@nginx.com rc = nxt_conf_copy_value(mp, op, copy, value); 725106Svbart@nginx.com 726106Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 727106Svbart@nginx.com return NULL; 728106Svbart@nginx.com } 729106Svbart@nginx.com 730106Svbart@nginx.com return copy; 731106Svbart@nginx.com } 732106Svbart@nginx.com 733106Svbart@nginx.com 734106Svbart@nginx.com static nxt_int_t 735106Svbart@nginx.com nxt_conf_copy_value(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *dst, 736106Svbart@nginx.com nxt_conf_value_t *src) 737106Svbart@nginx.com { 738106Svbart@nginx.com size_t size; 739106Svbart@nginx.com nxt_int_t rc; 740106Svbart@nginx.com nxt_uint_t n; 741106Svbart@nginx.com 742116Svbart@nginx.com if (op != NULL && src->type != NXT_CONF_VALUE_OBJECT) { 743106Svbart@nginx.com return NXT_ERROR; 744106Svbart@nginx.com } 745106Svbart@nginx.com 746106Svbart@nginx.com dst->type = src->type; 747106Svbart@nginx.com 748106Svbart@nginx.com switch (src->type) { 749106Svbart@nginx.com 750116Svbart@nginx.com case NXT_CONF_VALUE_STRING: 751106Svbart@nginx.com 752172Svbart@nginx.com dst->u.string.start = nxt_mp_nget(mp, src->u.string.length); 753172Svbart@nginx.com if (nxt_slow_path(dst->u.string.start == NULL)) { 754106Svbart@nginx.com return NXT_ERROR; 755106Svbart@nginx.com } 756106Svbart@nginx.com 757172Svbart@nginx.com nxt_memcpy(dst->u.string.start, src->u.string.start, 758172Svbart@nginx.com src->u.string.length); 759172Svbart@nginx.com 760172Svbart@nginx.com dst->u.string.length = src->u.string.length; 761172Svbart@nginx.com 762106Svbart@nginx.com break; 763106Svbart@nginx.com 764116Svbart@nginx.com case NXT_CONF_VALUE_ARRAY: 765106Svbart@nginx.com 766106Svbart@nginx.com size = sizeof(nxt_conf_array_t) 767106Svbart@nginx.com + src->u.array->count * sizeof(nxt_conf_value_t); 768106Svbart@nginx.com 769106Svbart@nginx.com dst->u.array = nxt_mp_get(mp, size); 770106Svbart@nginx.com if (nxt_slow_path(dst->u.array == NULL)) { 771106Svbart@nginx.com return NXT_ERROR; 772106Svbart@nginx.com } 773106Svbart@nginx.com 774106Svbart@nginx.com dst->u.array->count = src->u.array->count; 775106Svbart@nginx.com 776106Svbart@nginx.com for (n = 0; n < src->u.array->count; n++) { 777106Svbart@nginx.com rc = nxt_conf_copy_value(mp, NULL, &dst->u.array->elements[n], 778106Svbart@nginx.com &src->u.array->elements[n]); 779106Svbart@nginx.com 780106Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 781106Svbart@nginx.com return NXT_ERROR; 782106Svbart@nginx.com } 783106Svbart@nginx.com } 784106Svbart@nginx.com 785106Svbart@nginx.com break; 786106Svbart@nginx.com 787116Svbart@nginx.com case NXT_CONF_VALUE_OBJECT: 788106Svbart@nginx.com return nxt_conf_copy_object(mp, op, dst, src); 789106Svbart@nginx.com 790106Svbart@nginx.com default: 791106Svbart@nginx.com dst->u = src->u; 792106Svbart@nginx.com } 793106Svbart@nginx.com 794106Svbart@nginx.com return NXT_OK; 795106Svbart@nginx.com } 796106Svbart@nginx.com 797106Svbart@nginx.com 798106Svbart@nginx.com static nxt_int_t 799106Svbart@nginx.com nxt_conf_copy_object(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *dst, 800106Svbart@nginx.com nxt_conf_value_t *src) 801106Svbart@nginx.com { 802106Svbart@nginx.com size_t size; 803106Svbart@nginx.com nxt_int_t rc; 804106Svbart@nginx.com nxt_uint_t s, d, count, index; 805106Svbart@nginx.com nxt_conf_op_t *pass_op; 806106Svbart@nginx.com nxt_conf_value_t *value; 807106Svbart@nginx.com nxt_conf_object_member_t *member; 808106Svbart@nginx.com 809106Svbart@nginx.com count = src->u.object->count; 810106Svbart@nginx.com 811106Svbart@nginx.com if (op != NULL) { 812106Svbart@nginx.com if (op->action == NXT_CONF_OP_CREATE) { 813106Svbart@nginx.com count++; 814106Svbart@nginx.com 815106Svbart@nginx.com } else if (op->action == NXT_CONF_OP_DELETE) { 816106Svbart@nginx.com count--; 817106Svbart@nginx.com } 818106Svbart@nginx.com } 819106Svbart@nginx.com 820106Svbart@nginx.com size = sizeof(nxt_conf_object_t) 821106Svbart@nginx.com + count * sizeof(nxt_conf_object_member_t); 822106Svbart@nginx.com 823106Svbart@nginx.com dst->u.object = nxt_mp_get(mp, size); 824106Svbart@nginx.com if (nxt_slow_path(dst->u.object == NULL)) { 825106Svbart@nginx.com return NXT_ERROR; 826106Svbart@nginx.com } 827106Svbart@nginx.com 828106Svbart@nginx.com dst->u.object->count = count; 829106Svbart@nginx.com 830106Svbart@nginx.com s = 0; 831106Svbart@nginx.com d = 0; 832106Svbart@nginx.com 833106Svbart@nginx.com pass_op = NULL; 834106Svbart@nginx.com 835106Svbart@nginx.com /* 836106Svbart@nginx.com * This initialization is needed only to 837106Svbart@nginx.com * suppress a warning on GCC 4.8 and older. 838106Svbart@nginx.com */ 839106Svbart@nginx.com index = 0; 840106Svbart@nginx.com 841106Svbart@nginx.com do { 842106Svbart@nginx.com if (pass_op == NULL) { 843106Svbart@nginx.com index = (op == NULL || op->action == NXT_CONF_OP_CREATE) 844106Svbart@nginx.com ? src->u.object->count 845106Svbart@nginx.com : op->index; 846106Svbart@nginx.com } 847106Svbart@nginx.com 848106Svbart@nginx.com while (s != index) { 849106Svbart@nginx.com rc = nxt_conf_copy_value(mp, NULL, 850106Svbart@nginx.com &dst->u.object->members[d].name, 851106Svbart@nginx.com &src->u.object->members[s].name); 852106Svbart@nginx.com 853106Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 854106Svbart@nginx.com return NXT_ERROR; 855106Svbart@nginx.com } 856106Svbart@nginx.com 857106Svbart@nginx.com rc = nxt_conf_copy_value(mp, pass_op, 858106Svbart@nginx.com &dst->u.object->members[d].value, 859106Svbart@nginx.com &src->u.object->members[s].value); 860106Svbart@nginx.com 861106Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 862106Svbart@nginx.com return NXT_ERROR; 863106Svbart@nginx.com } 864106Svbart@nginx.com 865106Svbart@nginx.com s++; 866106Svbart@nginx.com d++; 867106Svbart@nginx.com } 868106Svbart@nginx.com 869106Svbart@nginx.com if (pass_op != NULL) { 870106Svbart@nginx.com pass_op = NULL; 871106Svbart@nginx.com continue; 872106Svbart@nginx.com } 873106Svbart@nginx.com 874106Svbart@nginx.com if (op != NULL) { 875106Svbart@nginx.com switch (op->action) { 876106Svbart@nginx.com case NXT_CONF_OP_PASS: 877106Svbart@nginx.com pass_op = op->ctx; 878106Svbart@nginx.com index++; 879106Svbart@nginx.com break; 880106Svbart@nginx.com 881106Svbart@nginx.com case NXT_CONF_OP_CREATE: 882106Svbart@nginx.com member = op->ctx; 883106Svbart@nginx.com 884106Svbart@nginx.com rc = nxt_conf_copy_value(mp, NULL, 885106Svbart@nginx.com &dst->u.object->members[d].name, 886106Svbart@nginx.com &member->name); 887106Svbart@nginx.com 888106Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 889106Svbart@nginx.com return NXT_ERROR; 890106Svbart@nginx.com } 891106Svbart@nginx.com 892106Svbart@nginx.com dst->u.object->members[d].value = member->value; 893106Svbart@nginx.com 894106Svbart@nginx.com d++; 895106Svbart@nginx.com break; 896106Svbart@nginx.com 897106Svbart@nginx.com case NXT_CONF_OP_REPLACE: 898106Svbart@nginx.com rc = nxt_conf_copy_value(mp, NULL, 899106Svbart@nginx.com &dst->u.object->members[d].name, 900106Svbart@nginx.com &src->u.object->members[s].name); 901106Svbart@nginx.com 902106Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 903106Svbart@nginx.com return NXT_ERROR; 904106Svbart@nginx.com } 905106Svbart@nginx.com 906106Svbart@nginx.com value = op->ctx; 907106Svbart@nginx.com 908106Svbart@nginx.com dst->u.object->members[d].value = *value; 909106Svbart@nginx.com 910106Svbart@nginx.com s++; 911106Svbart@nginx.com d++; 912106Svbart@nginx.com break; 913106Svbart@nginx.com 914106Svbart@nginx.com case NXT_CONF_OP_DELETE: 915106Svbart@nginx.com s++; 916106Svbart@nginx.com break; 917106Svbart@nginx.com } 918106Svbart@nginx.com 919106Svbart@nginx.com op = op->next; 920106Svbart@nginx.com } 921106Svbart@nginx.com 922106Svbart@nginx.com } while (d != count); 923106Svbart@nginx.com 924106Svbart@nginx.com dst->type = src->type; 925106Svbart@nginx.com 926106Svbart@nginx.com return NXT_OK; 927106Svbart@nginx.com } 928106Svbart@nginx.com 929106Svbart@nginx.com 930106Svbart@nginx.com nxt_conf_value_t * 931208Svbart@nginx.com nxt_conf_json_parse(nxt_mp_t *mp, u_char *start, u_char *end, 932208Svbart@nginx.com nxt_conf_json_error_t *error) 933106Svbart@nginx.com { 934106Svbart@nginx.com u_char *p; 935106Svbart@nginx.com nxt_conf_value_t *value; 936106Svbart@nginx.com 937106Svbart@nginx.com value = nxt_mp_get(mp, sizeof(nxt_conf_value_t)); 938106Svbart@nginx.com if (nxt_slow_path(value == NULL)) { 939106Svbart@nginx.com return NULL; 940106Svbart@nginx.com } 941106Svbart@nginx.com 942106Svbart@nginx.com p = nxt_conf_json_skip_space(start, end); 943106Svbart@nginx.com 944106Svbart@nginx.com if (nxt_slow_path(p == end)) { 945208Svbart@nginx.com 946208Svbart@nginx.com nxt_conf_json_parse_error(error, start, 947311Snick@nginx.com "An empty JSON payload isn't allowed. It must be either a literal " 948311Snick@nginx.com "(null, true, or false), a number, a string (in double quotes " 949311Snick@nginx.com "\"\"), an array (with brackets []), or an object (with braces {})." 950208Svbart@nginx.com ); 951208Svbart@nginx.com 952106Svbart@nginx.com return NULL; 953106Svbart@nginx.com } 954106Svbart@nginx.com 955208Svbart@nginx.com p = nxt_conf_json_parse_value(mp, value, p, end, error); 956106Svbart@nginx.com 957106Svbart@nginx.com if (nxt_slow_path(p == NULL)) { 958106Svbart@nginx.com return NULL; 959106Svbart@nginx.com } 960106Svbart@nginx.com 961106Svbart@nginx.com p = nxt_conf_json_skip_space(p, end); 962106Svbart@nginx.com 963106Svbart@nginx.com if (nxt_slow_path(p != end)) { 964208Svbart@nginx.com 965208Svbart@nginx.com nxt_conf_json_parse_error(error, p, 966311Snick@nginx.com "Unexpected character after the end of a valid JSON value." 967208Svbart@nginx.com ); 968208Svbart@nginx.com 969106Svbart@nginx.com return NULL; 970106Svbart@nginx.com } 971106Svbart@nginx.com 972106Svbart@nginx.com return value; 973106Svbart@nginx.com } 974106Svbart@nginx.com 975106Svbart@nginx.com 976106Svbart@nginx.com static u_char * 977106Svbart@nginx.com nxt_conf_json_skip_space(u_char *start, u_char *end) 978106Svbart@nginx.com { 979106Svbart@nginx.com u_char *p; 980106Svbart@nginx.com 981106Svbart@nginx.com for (p = start; nxt_fast_path(p != end); p++) { 982106Svbart@nginx.com 983106Svbart@nginx.com switch (*p) { 984106Svbart@nginx.com case ' ': 985106Svbart@nginx.com case '\t': 986106Svbart@nginx.com case '\r': 987106Svbart@nginx.com case '\n': 988106Svbart@nginx.com continue; 989106Svbart@nginx.com } 990106Svbart@nginx.com 991106Svbart@nginx.com break; 992106Svbart@nginx.com } 993106Svbart@nginx.com 994106Svbart@nginx.com return p; 995106Svbart@nginx.com } 996106Svbart@nginx.com 997106Svbart@nginx.com 998106Svbart@nginx.com static u_char * 999106Svbart@nginx.com nxt_conf_json_parse_value(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start, 1000208Svbart@nginx.com u_char *end, nxt_conf_json_error_t *error) 1001106Svbart@nginx.com { 1002208Svbart@nginx.com u_char ch, *p; 1003106Svbart@nginx.com 1004106Svbart@nginx.com ch = *start; 1005106Svbart@nginx.com 1006106Svbart@nginx.com switch (ch) { 1007106Svbart@nginx.com case '{': 1008208Svbart@nginx.com return nxt_conf_json_parse_object(mp, value, start, end, error); 1009106Svbart@nginx.com 1010106Svbart@nginx.com case '[': 1011208Svbart@nginx.com return nxt_conf_json_parse_array(mp, value, start, end, error); 1012106Svbart@nginx.com 1013106Svbart@nginx.com case '"': 1014208Svbart@nginx.com return nxt_conf_json_parse_string(mp, value, start, end, error); 1015106Svbart@nginx.com 1016106Svbart@nginx.com case 't': 1017106Svbart@nginx.com if (nxt_fast_path(end - start >= 4 1018106Svbart@nginx.com && nxt_memcmp(start, "true", 4) == 0)) 1019106Svbart@nginx.com { 1020106Svbart@nginx.com value->u.boolean = 1; 1021116Svbart@nginx.com value->type = NXT_CONF_VALUE_BOOLEAN; 1022106Svbart@nginx.com 1023106Svbart@nginx.com return start + 4; 1024106Svbart@nginx.com } 1025106Svbart@nginx.com 1026208Svbart@nginx.com goto error; 1027106Svbart@nginx.com 1028106Svbart@nginx.com case 'f': 1029106Svbart@nginx.com if (nxt_fast_path(end - start >= 5 1030106Svbart@nginx.com && nxt_memcmp(start, "false", 5) == 0)) 1031106Svbart@nginx.com { 1032106Svbart@nginx.com value->u.boolean = 0; 1033116Svbart@nginx.com value->type = NXT_CONF_VALUE_BOOLEAN; 1034106Svbart@nginx.com 1035106Svbart@nginx.com return start + 5; 1036106Svbart@nginx.com } 1037106Svbart@nginx.com 1038208Svbart@nginx.com goto error; 1039106Svbart@nginx.com 1040106Svbart@nginx.com case 'n': 1041106Svbart@nginx.com if (nxt_fast_path(end - start >= 4 1042106Svbart@nginx.com && nxt_memcmp(start, "null", 4) == 0)) 1043106Svbart@nginx.com { 1044116Svbart@nginx.com value->type = NXT_CONF_VALUE_NULL; 1045106Svbart@nginx.com return start + 4; 1046106Svbart@nginx.com } 1047106Svbart@nginx.com 1048208Svbart@nginx.com goto error; 1049208Svbart@nginx.com 1050208Svbart@nginx.com case '-': 1051208Svbart@nginx.com if (nxt_fast_path(end - start > 1)) { 1052208Svbart@nginx.com ch = start[1]; 1053208Svbart@nginx.com break; 1054208Svbart@nginx.com } 1055208Svbart@nginx.com 1056208Svbart@nginx.com goto error; 1057106Svbart@nginx.com } 1058106Svbart@nginx.com 1059208Svbart@nginx.com if (nxt_fast_path((ch - '0') <= 9)) { 1060208Svbart@nginx.com p = nxt_conf_json_parse_number(mp, value, start, end, error); 1061208Svbart@nginx.com 1062383Svbart@nginx.com if (nxt_slow_path(p == NULL)) { 1063383Svbart@nginx.com return NULL; 1064383Svbart@nginx.com } 1065383Svbart@nginx.com 1066208Svbart@nginx.com if (p == end) { 1067208Svbart@nginx.com return end; 1068208Svbart@nginx.com } 1069208Svbart@nginx.com 1070208Svbart@nginx.com switch (*p) { 1071208Svbart@nginx.com case ' ': 1072208Svbart@nginx.com case '\t': 1073208Svbart@nginx.com case '\r': 1074208Svbart@nginx.com case '\n': 1075208Svbart@nginx.com case ',': 1076208Svbart@nginx.com case '}': 1077208Svbart@nginx.com case ']': 1078208Svbart@nginx.com case '{': 1079208Svbart@nginx.com case '[': 1080208Svbart@nginx.com case '"': 1081208Svbart@nginx.com return p; 1082208Svbart@nginx.com } 1083106Svbart@nginx.com } 1084106Svbart@nginx.com 1085208Svbart@nginx.com error: 1086208Svbart@nginx.com 1087208Svbart@nginx.com nxt_conf_json_parse_error(error, start, 1088311Snick@nginx.com "A valid JSON value is expected here. It must be either a literal " 1089311Snick@nginx.com "(null, true, or false), a number, a string (in double quotes \"\"), " 1090311Snick@nginx.com "an array (with brackets []), or an object (with braces {})." 1091208Svbart@nginx.com ); 1092208Svbart@nginx.com 1093106Svbart@nginx.com return NULL; 1094106Svbart@nginx.com } 1095106Svbart@nginx.com 1096106Svbart@nginx.com 1097106Svbart@nginx.com static const nxt_lvlhsh_proto_t nxt_conf_object_hash_proto 1098106Svbart@nginx.com nxt_aligned(64) = 1099106Svbart@nginx.com { 1100106Svbart@nginx.com NXT_LVLHSH_DEFAULT, 1101106Svbart@nginx.com nxt_conf_object_hash_test, 1102106Svbart@nginx.com nxt_conf_object_hash_alloc, 1103106Svbart@nginx.com nxt_conf_object_hash_free, 1104106Svbart@nginx.com }; 1105106Svbart@nginx.com 1106106Svbart@nginx.com 1107106Svbart@nginx.com static u_char * 1108106Svbart@nginx.com nxt_conf_json_parse_object(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start, 1109208Svbart@nginx.com u_char *end, nxt_conf_json_error_t *error) 1110106Svbart@nginx.com { 1111208Svbart@nginx.com u_char *p, *name; 1112106Svbart@nginx.com nxt_mp_t *mp_temp; 1113106Svbart@nginx.com nxt_int_t rc; 1114106Svbart@nginx.com nxt_uint_t count; 1115106Svbart@nginx.com nxt_lvlhsh_t hash; 1116106Svbart@nginx.com nxt_lvlhsh_each_t lhe; 1117106Svbart@nginx.com nxt_conf_object_t *object; 1118106Svbart@nginx.com nxt_conf_object_member_t *member, *element; 1119106Svbart@nginx.com 1120106Svbart@nginx.com mp_temp = nxt_mp_create(1024, 128, 256, 32); 1121106Svbart@nginx.com if (nxt_slow_path(mp_temp == NULL)) { 1122106Svbart@nginx.com return NULL; 1123106Svbart@nginx.com } 1124106Svbart@nginx.com 1125106Svbart@nginx.com nxt_lvlhsh_init(&hash); 1126106Svbart@nginx.com 1127106Svbart@nginx.com count = 0; 1128130Svbart@nginx.com p = start; 1129130Svbart@nginx.com 1130130Svbart@nginx.com for ( ;; ) { 1131130Svbart@nginx.com p = nxt_conf_json_skip_space(p + 1, end); 1132130Svbart@nginx.com 1133130Svbart@nginx.com if (nxt_slow_path(p == end)) { 1134208Svbart@nginx.com 1135208Svbart@nginx.com nxt_conf_json_parse_error(error, p, 1136311Snick@nginx.com "Unexpected end of JSON payload. There's an object without " 1137311Snick@nginx.com "a closing brace (})." 1138208Svbart@nginx.com ); 1139208Svbart@nginx.com 1140130Svbart@nginx.com goto error; 1141130Svbart@nginx.com } 1142130Svbart@nginx.com 1143130Svbart@nginx.com if (*p != '"') { 1144130Svbart@nginx.com if (nxt_fast_path(*p == '}')) { 1145106Svbart@nginx.com break; 1146106Svbart@nginx.com } 1147106Svbart@nginx.com 1148208Svbart@nginx.com nxt_conf_json_parse_error(error, p, 1149208Svbart@nginx.com "A double quote (\") is expected here. There must be a valid " 1150208Svbart@nginx.com "JSON object member starts with a name, which is a string " 1151208Svbart@nginx.com "enclosed in double quotes." 1152208Svbart@nginx.com ); 1153208Svbart@nginx.com 1154130Svbart@nginx.com goto error; 1155130Svbart@nginx.com } 1156130Svbart@nginx.com 1157208Svbart@nginx.com name = p; 1158208Svbart@nginx.com 1159130Svbart@nginx.com count++; 1160130Svbart@nginx.com 1161130Svbart@nginx.com member = nxt_mp_get(mp_temp, sizeof(nxt_conf_object_member_t)); 1162130Svbart@nginx.com if (nxt_slow_path(member == NULL)) { 1163130Svbart@nginx.com goto error; 1164130Svbart@nginx.com } 1165130Svbart@nginx.com 1166208Svbart@nginx.com p = nxt_conf_json_parse_string(mp, &member->name, p, end, error); 1167130Svbart@nginx.com 1168130Svbart@nginx.com if (nxt_slow_path(p == NULL)) { 1169130Svbart@nginx.com goto error; 1170130Svbart@nginx.com } 1171130Svbart@nginx.com 1172130Svbart@nginx.com rc = nxt_conf_object_hash_add(mp_temp, &hash, member); 1173130Svbart@nginx.com 1174130Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 1175208Svbart@nginx.com 1176208Svbart@nginx.com if (rc == NXT_DECLINED) { 1177208Svbart@nginx.com nxt_conf_json_parse_error(error, name, 1178208Svbart@nginx.com "Duplicate object member. All JSON object members must " 1179208Svbart@nginx.com "have unique names." 1180208Svbart@nginx.com ); 1181208Svbart@nginx.com } 1182208Svbart@nginx.com 1183130Svbart@nginx.com goto error; 1184130Svbart@nginx.com } 1185130Svbart@nginx.com 1186130Svbart@nginx.com p = nxt_conf_json_skip_space(p, end); 1187130Svbart@nginx.com 1188208Svbart@nginx.com if (nxt_slow_path(p == end)) { 1189208Svbart@nginx.com 1190208Svbart@nginx.com nxt_conf_json_parse_error(error, p, 1191311Snick@nginx.com "Unexpected end of JSON payload. There's an object member " 1192311Snick@nginx.com "without a value." 1193208Svbart@nginx.com ); 1194208Svbart@nginx.com 1195208Svbart@nginx.com goto error; 1196208Svbart@nginx.com } 1197208Svbart@nginx.com 1198208Svbart@nginx.com if (nxt_slow_path(*p != ':')) { 1199208Svbart@nginx.com 1200208Svbart@nginx.com nxt_conf_json_parse_error(error, p, 1201311Snick@nginx.com "A colon (:) is expected here. There must be a colon after " 1202311Snick@nginx.com "a JSON member name." 1203208Svbart@nginx.com ); 1204208Svbart@nginx.com 1205130Svbart@nginx.com goto error; 1206130Svbart@nginx.com } 1207130Svbart@nginx.com 1208130Svbart@nginx.com p = nxt_conf_json_skip_space(p + 1, end); 1209130Svbart@nginx.com 1210130Svbart@nginx.com if (nxt_slow_path(p == end)) { 1211208Svbart@nginx.com 1212208Svbart@nginx.com nxt_conf_json_parse_error(error, p, 1213311Snick@nginx.com "Unexpected end of JSON payload. There's an object member " 1214311Snick@nginx.com "without a value." 1215208Svbart@nginx.com ); 1216208Svbart@nginx.com 1217130Svbart@nginx.com goto error; 1218130Svbart@nginx.com } 1219130Svbart@nginx.com 1220208Svbart@nginx.com p = nxt_conf_json_parse_value(mp, &member->value, p, end, error); 1221130Svbart@nginx.com 1222130Svbart@nginx.com if (nxt_slow_path(p == NULL)) { 1223130Svbart@nginx.com goto error; 1224130Svbart@nginx.com } 1225130Svbart@nginx.com 1226130Svbart@nginx.com p = nxt_conf_json_skip_space(p, end); 1227130Svbart@nginx.com 1228130Svbart@nginx.com if (nxt_slow_path(p == end)) { 1229208Svbart@nginx.com 1230208Svbart@nginx.com nxt_conf_json_parse_error(error, p, 1231311Snick@nginx.com "Unexpected end of JSON payload. There's an object without " 1232311Snick@nginx.com "a closing brace (})." 1233208Svbart@nginx.com ); 1234208Svbart@nginx.com 1235130Svbart@nginx.com goto error; 1236130Svbart@nginx.com } 1237130Svbart@nginx.com 1238130Svbart@nginx.com if (*p != ',') { 1239130Svbart@nginx.com if (nxt_fast_path(*p == '}')) { 1240130Svbart@nginx.com break; 1241106Svbart@nginx.com } 1242106Svbart@nginx.com 1243208Svbart@nginx.com nxt_conf_json_parse_error(error, p, 1244311Snick@nginx.com "Either a closing brace (}) or a comma (,) is expected here. " 1245311Snick@nginx.com "Each JSON object must be enclosed in braces and its members " 1246311Snick@nginx.com "must be separated by commas." 1247208Svbart@nginx.com ); 1248208Svbart@nginx.com 1249130Svbart@nginx.com goto error; 1250106Svbart@nginx.com } 1251106Svbart@nginx.com } 1252106Svbart@nginx.com 1253106Svbart@nginx.com object = nxt_mp_get(mp, sizeof(nxt_conf_object_t) 1254106Svbart@nginx.com + count * sizeof(nxt_conf_object_member_t)); 1255106Svbart@nginx.com if (nxt_slow_path(object == NULL)) { 1256106Svbart@nginx.com goto error; 1257106Svbart@nginx.com } 1258106Svbart@nginx.com 1259106Svbart@nginx.com value->u.object = object; 1260116Svbart@nginx.com value->type = NXT_CONF_VALUE_OBJECT; 1261106Svbart@nginx.com 1262106Svbart@nginx.com object->count = count; 1263106Svbart@nginx.com member = object->members; 1264106Svbart@nginx.com 1265106Svbart@nginx.com nxt_memzero(&lhe, sizeof(nxt_lvlhsh_each_t)); 1266106Svbart@nginx.com lhe.proto = &nxt_conf_object_hash_proto; 1267106Svbart@nginx.com 1268106Svbart@nginx.com for ( ;; ) { 1269106Svbart@nginx.com element = nxt_lvlhsh_each(&hash, &lhe); 1270106Svbart@nginx.com 1271106Svbart@nginx.com if (element == NULL) { 1272106Svbart@nginx.com break; 1273106Svbart@nginx.com } 1274106Svbart@nginx.com 1275106Svbart@nginx.com *member++ = *element; 1276106Svbart@nginx.com } 1277106Svbart@nginx.com 1278106Svbart@nginx.com nxt_mp_destroy(mp_temp); 1279106Svbart@nginx.com 1280106Svbart@nginx.com return p + 1; 1281106Svbart@nginx.com 1282106Svbart@nginx.com error: 1283106Svbart@nginx.com 1284106Svbart@nginx.com nxt_mp_destroy(mp_temp); 1285106Svbart@nginx.com return NULL; 1286106Svbart@nginx.com } 1287106Svbart@nginx.com 1288106Svbart@nginx.com 1289106Svbart@nginx.com static nxt_int_t 1290106Svbart@nginx.com nxt_conf_object_hash_add(nxt_mp_t *mp, nxt_lvlhsh_t *lvlhsh, 1291106Svbart@nginx.com nxt_conf_object_member_t *member) 1292106Svbart@nginx.com { 1293106Svbart@nginx.com nxt_lvlhsh_query_t lhq; 1294106Svbart@nginx.com 1295106Svbart@nginx.com nxt_conf_get_string(&member->name, &lhq.key); 1296106Svbart@nginx.com 1297106Svbart@nginx.com lhq.key_hash = nxt_djb_hash(lhq.key.start, lhq.key.length); 1298106Svbart@nginx.com lhq.replace = 0; 1299106Svbart@nginx.com lhq.value = member; 1300106Svbart@nginx.com lhq.proto = &nxt_conf_object_hash_proto; 1301106Svbart@nginx.com lhq.pool = mp; 1302106Svbart@nginx.com 1303106Svbart@nginx.com return nxt_lvlhsh_insert(lvlhsh, &lhq); 1304106Svbart@nginx.com } 1305106Svbart@nginx.com 1306106Svbart@nginx.com 1307106Svbart@nginx.com static nxt_int_t 1308106Svbart@nginx.com nxt_conf_object_hash_test(nxt_lvlhsh_query_t *lhq, void *data) 1309106Svbart@nginx.com { 1310106Svbart@nginx.com nxt_str_t str; 1311106Svbart@nginx.com nxt_conf_object_member_t *member; 1312106Svbart@nginx.com 1313106Svbart@nginx.com member = data; 1314106Svbart@nginx.com 1315106Svbart@nginx.com nxt_conf_get_string(&member->name, &str); 1316106Svbart@nginx.com 1317208Svbart@nginx.com return nxt_strstr_eq(&lhq->key, &str) ? NXT_OK : NXT_DECLINED; 1318106Svbart@nginx.com } 1319106Svbart@nginx.com 1320106Svbart@nginx.com 1321106Svbart@nginx.com static void * 1322106Svbart@nginx.com nxt_conf_object_hash_alloc(void *data, size_t size) 1323106Svbart@nginx.com { 1324106Svbart@nginx.com return nxt_mp_align(data, size, size); 1325106Svbart@nginx.com } 1326106Svbart@nginx.com 1327106Svbart@nginx.com 1328106Svbart@nginx.com static void 1329106Svbart@nginx.com nxt_conf_object_hash_free(void *data, void *p) 1330106Svbart@nginx.com { 1331106Svbart@nginx.com nxt_mp_free(data, p); 1332106Svbart@nginx.com } 1333106Svbart@nginx.com 1334106Svbart@nginx.com 1335106Svbart@nginx.com static u_char * 1336106Svbart@nginx.com nxt_conf_json_parse_array(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start, 1337208Svbart@nginx.com u_char *end, nxt_conf_json_error_t *error) 1338106Svbart@nginx.com { 1339106Svbart@nginx.com u_char *p; 1340106Svbart@nginx.com nxt_mp_t *mp_temp; 1341106Svbart@nginx.com nxt_uint_t count; 1342106Svbart@nginx.com nxt_list_t *list; 1343106Svbart@nginx.com nxt_conf_array_t *array; 1344106Svbart@nginx.com nxt_conf_value_t *element; 1345106Svbart@nginx.com 1346106Svbart@nginx.com mp_temp = nxt_mp_create(1024, 128, 256, 32); 1347106Svbart@nginx.com if (nxt_slow_path(mp_temp == NULL)) { 1348106Svbart@nginx.com return NULL; 1349106Svbart@nginx.com } 1350106Svbart@nginx.com 1351106Svbart@nginx.com list = nxt_list_create(mp_temp, 8, sizeof(nxt_conf_value_t)); 1352106Svbart@nginx.com if (nxt_slow_path(list == NULL)) { 1353106Svbart@nginx.com goto error; 1354106Svbart@nginx.com } 1355106Svbart@nginx.com 1356106Svbart@nginx.com count = 0; 1357130Svbart@nginx.com p = start; 1358130Svbart@nginx.com 1359130Svbart@nginx.com for ( ;; ) { 1360130Svbart@nginx.com p = nxt_conf_json_skip_space(p + 1, end); 1361130Svbart@nginx.com 1362130Svbart@nginx.com if (nxt_slow_path(p == end)) { 1363208Svbart@nginx.com 1364208Svbart@nginx.com nxt_conf_json_parse_error(error, p, 1365311Snick@nginx.com "Unexpected end of JSON payload. There's an array without " 1366311Snick@nginx.com "a closing bracket (])." 1367208Svbart@nginx.com ); 1368208Svbart@nginx.com 1369130Svbart@nginx.com goto error; 1370130Svbart@nginx.com } 1371130Svbart@nginx.com 1372130Svbart@nginx.com if (*p == ']') { 1373130Svbart@nginx.com break; 1374130Svbart@nginx.com } 1375130Svbart@nginx.com 1376130Svbart@nginx.com count++; 1377130Svbart@nginx.com 1378130Svbart@nginx.com element = nxt_list_add(list); 1379130Svbart@nginx.com if (nxt_slow_path(element == NULL)) { 1380130Svbart@nginx.com goto error; 1381130Svbart@nginx.com } 1382130Svbart@nginx.com 1383208Svbart@nginx.com p = nxt_conf_json_parse_value(mp, element, p, end, error); 1384130Svbart@nginx.com 1385130Svbart@nginx.com if (nxt_slow_path(p == NULL)) { 1386130Svbart@nginx.com goto error; 1387130Svbart@nginx.com } 1388130Svbart@nginx.com 1389130Svbart@nginx.com p = nxt_conf_json_skip_space(p, end); 1390130Svbart@nginx.com 1391130Svbart@nginx.com if (nxt_slow_path(p == end)) { 1392208Svbart@nginx.com 1393208Svbart@nginx.com nxt_conf_json_parse_error(error, p, 1394311Snick@nginx.com "Unexpected end of JSON payload. There's an array without " 1395311Snick@nginx.com "a closing bracket (])." 1396208Svbart@nginx.com ); 1397208Svbart@nginx.com 1398130Svbart@nginx.com goto error; 1399130Svbart@nginx.com } 1400130Svbart@nginx.com 1401130Svbart@nginx.com if (*p != ',') { 1402130Svbart@nginx.com if (nxt_fast_path(*p == ']')) { 1403106Svbart@nginx.com break; 1404106Svbart@nginx.com } 1405106Svbart@nginx.com 1406208Svbart@nginx.com nxt_conf_json_parse_error(error, p, 1407311Snick@nginx.com "Either a closing bracket (]) or a comma (,) is expected " 1408311Snick@nginx.com "here. Each array must be enclosed in brackets and its " 1409311Snick@nginx.com "members must be separated by commas." 1410208Svbart@nginx.com ); 1411208Svbart@nginx.com 1412130Svbart@nginx.com goto error; 1413106Svbart@nginx.com } 1414106Svbart@nginx.com } 1415106Svbart@nginx.com 1416106Svbart@nginx.com array = nxt_mp_get(mp, sizeof(nxt_conf_array_t) 1417106Svbart@nginx.com + count * sizeof(nxt_conf_value_t)); 1418106Svbart@nginx.com if (nxt_slow_path(array == NULL)) { 1419106Svbart@nginx.com goto error; 1420106Svbart@nginx.com } 1421106Svbart@nginx.com 1422106Svbart@nginx.com value->u.array = array; 1423116Svbart@nginx.com value->type = NXT_CONF_VALUE_ARRAY; 1424106Svbart@nginx.com 1425106Svbart@nginx.com array->count = count; 1426106Svbart@nginx.com element = array->elements; 1427106Svbart@nginx.com 1428106Svbart@nginx.com nxt_list_each(value, list) { 1429106Svbart@nginx.com *element++ = *value; 1430106Svbart@nginx.com } nxt_list_loop; 1431106Svbart@nginx.com 1432106Svbart@nginx.com nxt_mp_destroy(mp_temp); 1433106Svbart@nginx.com 1434106Svbart@nginx.com return p + 1; 1435106Svbart@nginx.com 1436106Svbart@nginx.com error: 1437106Svbart@nginx.com 1438106Svbart@nginx.com nxt_mp_destroy(mp_temp); 1439106Svbart@nginx.com return NULL; 1440106Svbart@nginx.com } 1441106Svbart@nginx.com 1442106Svbart@nginx.com 1443106Svbart@nginx.com static u_char * 1444106Svbart@nginx.com nxt_conf_json_parse_string(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start, 1445208Svbart@nginx.com u_char *end, nxt_conf_json_error_t *error) 1446106Svbart@nginx.com { 1447106Svbart@nginx.com u_char *p, ch, *last, *s; 1448106Svbart@nginx.com size_t size, surplus; 1449106Svbart@nginx.com uint32_t utf, utf_high; 1450106Svbart@nginx.com nxt_uint_t i; 1451106Svbart@nginx.com enum { 1452106Svbart@nginx.com sw_usual = 0, 1453106Svbart@nginx.com sw_escape, 1454106Svbart@nginx.com sw_encoded1, 1455106Svbart@nginx.com sw_encoded2, 1456106Svbart@nginx.com sw_encoded3, 1457106Svbart@nginx.com sw_encoded4, 1458106Svbart@nginx.com } state; 1459106Svbart@nginx.com 1460106Svbart@nginx.com start++; 1461106Svbart@nginx.com 1462106Svbart@nginx.com state = 0; 1463106Svbart@nginx.com surplus = 0; 1464106Svbart@nginx.com 1465106Svbart@nginx.com for (p = start; nxt_fast_path(p != end); p++) { 1466106Svbart@nginx.com ch = *p; 1467106Svbart@nginx.com 1468106Svbart@nginx.com switch (state) { 1469106Svbart@nginx.com 1470106Svbart@nginx.com case sw_usual: 1471106Svbart@nginx.com 1472106Svbart@nginx.com if (ch == '"') { 1473106Svbart@nginx.com break; 1474106Svbart@nginx.com } 1475106Svbart@nginx.com 1476106Svbart@nginx.com if (ch == '\\') { 1477106Svbart@nginx.com state = sw_escape; 1478106Svbart@nginx.com continue; 1479106Svbart@nginx.com } 1480106Svbart@nginx.com 1481106Svbart@nginx.com if (nxt_fast_path(ch >= ' ')) { 1482106Svbart@nginx.com continue; 1483106Svbart@nginx.com } 1484106Svbart@nginx.com 1485208Svbart@nginx.com nxt_conf_json_parse_error(error, p, 1486311Snick@nginx.com "Unexpected character. All control characters in a JSON " 1487311Snick@nginx.com "string must be escaped." 1488208Svbart@nginx.com ); 1489208Svbart@nginx.com 1490106Svbart@nginx.com return NULL; 1491106Svbart@nginx.com 1492106Svbart@nginx.com case sw_escape: 1493106Svbart@nginx.com 1494106Svbart@nginx.com switch (ch) { 1495106Svbart@nginx.com case '"': 1496106Svbart@nginx.com case '\\': 1497106Svbart@nginx.com case '/': 1498106Svbart@nginx.com case 'n': 1499106Svbart@nginx.com case 'r': 1500106Svbart@nginx.com case 't': 1501106Svbart@nginx.com case 'b': 1502106Svbart@nginx.com case 'f': 1503106Svbart@nginx.com surplus++; 1504106Svbart@nginx.com state = sw_usual; 1505106Svbart@nginx.com continue; 1506106Svbart@nginx.com 1507106Svbart@nginx.com case 'u': 1508106Svbart@nginx.com /* 1509106Svbart@nginx.com * Basic unicode 6 bytes "\uXXXX" in JSON 1510106Svbart@nginx.com * and up to 3 bytes in UTF-8. 1511106Svbart@nginx.com * 1512106Svbart@nginx.com * Surrogate pair: 12 bytes "\uXXXX\uXXXX" in JSON 1513106Svbart@nginx.com * and 3 or 4 bytes in UTF-8. 1514106Svbart@nginx.com */ 1515106Svbart@nginx.com surplus += 3; 1516106Svbart@nginx.com state = sw_encoded1; 1517106Svbart@nginx.com continue; 1518106Svbart@nginx.com } 1519106Svbart@nginx.com 1520208Svbart@nginx.com nxt_conf_json_parse_error(error, p - 1, 1521311Snick@nginx.com "Unexpected backslash. A literal backslash in a JSON string " 1522311Snick@nginx.com "must be escaped with a second backslash (\\\\)." 1523208Svbart@nginx.com ); 1524208Svbart@nginx.com 1525106Svbart@nginx.com return NULL; 1526106Svbart@nginx.com 1527106Svbart@nginx.com case sw_encoded1: 1528106Svbart@nginx.com case sw_encoded2: 1529106Svbart@nginx.com case sw_encoded3: 1530106Svbart@nginx.com case sw_encoded4: 1531106Svbart@nginx.com 1532106Svbart@nginx.com if (nxt_fast_path((ch >= '0' && ch <= '9') 1533202Svbart@nginx.com || (ch >= 'A' && ch <= 'F') 1534202Svbart@nginx.com || (ch >= 'a' && ch <= 'f'))) 1535106Svbart@nginx.com { 1536106Svbart@nginx.com state = (state == sw_encoded4) ? sw_usual : state + 1; 1537106Svbart@nginx.com continue; 1538106Svbart@nginx.com } 1539106Svbart@nginx.com 1540208Svbart@nginx.com nxt_conf_json_parse_error(error, p, 1541311Snick@nginx.com "Invalid escape sequence. An escape sequence in a JSON " 1542311Snick@nginx.com "string must start with a backslash, followed by the lowercase " 1543311Snick@nginx.com "letter u, followed by four hexadecimal digits (\\uXXXX)." 1544208Svbart@nginx.com ); 1545208Svbart@nginx.com 1546106Svbart@nginx.com return NULL; 1547106Svbart@nginx.com } 1548106Svbart@nginx.com 1549106Svbart@nginx.com break; 1550106Svbart@nginx.com } 1551106Svbart@nginx.com 1552106Svbart@nginx.com if (nxt_slow_path(p == end)) { 1553208Svbart@nginx.com 1554208Svbart@nginx.com nxt_conf_json_parse_error(error, p, 1555311Snick@nginx.com "Unexpected end of JSON payload. There's a string without " 1556311Snick@nginx.com "a final double quote (\")." 1557208Svbart@nginx.com ); 1558208Svbart@nginx.com 1559106Svbart@nginx.com return NULL; 1560106Svbart@nginx.com } 1561106Svbart@nginx.com 1562106Svbart@nginx.com /* Points to the ending quote mark. */ 1563106Svbart@nginx.com last = p; 1564106Svbart@nginx.com 1565106Svbart@nginx.com size = last - start - surplus; 1566106Svbart@nginx.com 1567106Svbart@nginx.com if (size > NXT_CONF_MAX_SHORT_STRING) { 1568172Svbart@nginx.com 1569172Svbart@nginx.com if (nxt_slow_path(size > NXT_CONF_MAX_STRING)) { 1570208Svbart@nginx.com 1571208Svbart@nginx.com nxt_conf_json_parse_error(error, start, 1572311Snick@nginx.com "The string is too long. Such a long JSON string value " 1573311Snick@nginx.com "is not supported." 1574208Svbart@nginx.com ); 1575208Svbart@nginx.com 1576106Svbart@nginx.com return NULL; 1577106Svbart@nginx.com } 1578106Svbart@nginx.com 1579172Svbart@nginx.com value->type = NXT_CONF_VALUE_STRING; 1580172Svbart@nginx.com 1581172Svbart@nginx.com value->u.string.start = nxt_mp_nget(mp, size); 1582172Svbart@nginx.com if (nxt_slow_path(value->u.string.start == NULL)) { 1583172Svbart@nginx.com return NULL; 1584172Svbart@nginx.com } 1585172Svbart@nginx.com 1586172Svbart@nginx.com value->u.string.length = size; 1587172Svbart@nginx.com 1588172Svbart@nginx.com s = value->u.string.start; 1589106Svbart@nginx.com 1590106Svbart@nginx.com } else { 1591116Svbart@nginx.com value->type = NXT_CONF_VALUE_SHORT_STRING; 1592173Svbart@nginx.com value->u.str.length = size; 1593173Svbart@nginx.com 1594173Svbart@nginx.com s = value->u.str.start; 1595106Svbart@nginx.com } 1596106Svbart@nginx.com 1597106Svbart@nginx.com if (surplus == 0) { 1598106Svbart@nginx.com nxt_memcpy(s, start, size); 1599106Svbart@nginx.com return last + 1; 1600106Svbart@nginx.com } 1601106Svbart@nginx.com 1602106Svbart@nginx.com p = start; 1603106Svbart@nginx.com 1604106Svbart@nginx.com do { 1605106Svbart@nginx.com ch = *p++; 1606106Svbart@nginx.com 1607106Svbart@nginx.com if (ch != '\\') { 1608106Svbart@nginx.com *s++ = ch; 1609106Svbart@nginx.com continue; 1610106Svbart@nginx.com } 1611106Svbart@nginx.com 1612106Svbart@nginx.com ch = *p++; 1613106Svbart@nginx.com 1614106Svbart@nginx.com switch (ch) { 1615106Svbart@nginx.com case '"': 1616106Svbart@nginx.com case '\\': 1617106Svbart@nginx.com case '/': 1618106Svbart@nginx.com *s++ = ch; 1619106Svbart@nginx.com continue; 1620106Svbart@nginx.com 1621106Svbart@nginx.com case 'n': 1622106Svbart@nginx.com *s++ = '\n'; 1623106Svbart@nginx.com continue; 1624106Svbart@nginx.com 1625106Svbart@nginx.com case 'r': 1626106Svbart@nginx.com *s++ = '\r'; 1627106Svbart@nginx.com continue; 1628106Svbart@nginx.com 1629106Svbart@nginx.com case 't': 1630106Svbart@nginx.com *s++ = '\t'; 1631106Svbart@nginx.com continue; 1632106Svbart@nginx.com 1633106Svbart@nginx.com case 'b': 1634106Svbart@nginx.com *s++ = '\b'; 1635106Svbart@nginx.com continue; 1636106Svbart@nginx.com 1637106Svbart@nginx.com case 'f': 1638106Svbart@nginx.com *s++ = '\f'; 1639106Svbart@nginx.com continue; 1640106Svbart@nginx.com } 1641106Svbart@nginx.com 1642106Svbart@nginx.com utf = 0; 1643106Svbart@nginx.com utf_high = 0; 1644106Svbart@nginx.com 1645106Svbart@nginx.com for ( ;; ) { 1646106Svbart@nginx.com for (i = 0; i < 4; i++) { 1647202Svbart@nginx.com utf = (utf << 4) | (p[i] >= 'A' ? 10 + ((p[i] & ~0x20) - 'A') 1648202Svbart@nginx.com : p[i] - '0'); 1649106Svbart@nginx.com } 1650106Svbart@nginx.com 1651106Svbart@nginx.com p += 4; 1652106Svbart@nginx.com 1653207Svbart@nginx.com if (utf_high != 0) { 1654207Svbart@nginx.com if (nxt_slow_path(utf < 0xdc00 || utf > 0xdfff)) { 1655208Svbart@nginx.com 1656208Svbart@nginx.com nxt_conf_json_parse_error(error, p - 12, 1657311Snick@nginx.com "Invalid JSON encoding sequence. This 12-byte " 1658311Snick@nginx.com "sequence composes an illegal UTF-16 surrogate pair." 1659208Svbart@nginx.com ); 1660208Svbart@nginx.com 1661207Svbart@nginx.com return NULL; 1662207Svbart@nginx.com } 1663207Svbart@nginx.com 1664207Svbart@nginx.com utf = ((utf_high - 0xd800) << 10) + (utf - 0xdc00) + 0x10000; 1665207Svbart@nginx.com 1666106Svbart@nginx.com break; 1667106Svbart@nginx.com } 1668106Svbart@nginx.com 1669207Svbart@nginx.com if (utf < 0xd800 || utf > 0xdfff) { 1670106Svbart@nginx.com break; 1671106Svbart@nginx.com } 1672106Svbart@nginx.com 1673207Svbart@nginx.com if (utf > 0xdbff || p[0] != '\\' || p[1] != 'u') { 1674208Svbart@nginx.com 1675208Svbart@nginx.com nxt_conf_json_parse_error(error, p - 6, 1676311Snick@nginx.com "Invalid JSON encoding sequence. This 6-byte sequence " 1677311Snick@nginx.com "does not represent a valid UTF character." 1678208Svbart@nginx.com ); 1679208Svbart@nginx.com 1680207Svbart@nginx.com return NULL; 1681207Svbart@nginx.com } 1682207Svbart@nginx.com 1683106Svbart@nginx.com p += 2; 1684207Svbart@nginx.com 1685207Svbart@nginx.com utf_high = utf; 1686207Svbart@nginx.com utf = 0; 1687106Svbart@nginx.com } 1688106Svbart@nginx.com 1689106Svbart@nginx.com s = nxt_utf8_encode(s, utf); 1690106Svbart@nginx.com 1691106Svbart@nginx.com } while (p != last); 1692106Svbart@nginx.com 1693106Svbart@nginx.com if (size > NXT_CONF_MAX_SHORT_STRING) { 1694172Svbart@nginx.com value->u.string.length = s - value->u.string.start; 1695106Svbart@nginx.com 1696106Svbart@nginx.com } else { 1697173Svbart@nginx.com value->u.str.length = s - value->u.str.start; 1698106Svbart@nginx.com } 1699106Svbart@nginx.com 1700106Svbart@nginx.com return last + 1; 1701106Svbart@nginx.com } 1702106Svbart@nginx.com 1703106Svbart@nginx.com 1704106Svbart@nginx.com static u_char * 1705106Svbart@nginx.com nxt_conf_json_parse_number(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start, 1706208Svbart@nginx.com u_char *end, nxt_conf_json_error_t *error) 1707106Svbart@nginx.com { 1708106Svbart@nginx.com u_char *p, ch; 1709106Svbart@nginx.com uint64_t integer; 1710106Svbart@nginx.com nxt_int_t sign; 1711106Svbart@nginx.com #if 0 1712106Svbart@nginx.com uint64_t frac, power 1713106Svbart@nginx.com nxt_int_t e, negative; 1714106Svbart@nginx.com #endif 1715106Svbart@nginx.com 1716106Svbart@nginx.com static const uint64_t cutoff = NXT_INT64_T_MAX / 10; 1717106Svbart@nginx.com static const uint64_t cutlim = NXT_INT64_T_MAX % 10; 1718106Svbart@nginx.com 1719106Svbart@nginx.com ch = *start; 1720106Svbart@nginx.com 1721106Svbart@nginx.com if (ch == '-') { 1722106Svbart@nginx.com sign = -1; 1723106Svbart@nginx.com start++; 1724106Svbart@nginx.com 1725106Svbart@nginx.com } else { 1726106Svbart@nginx.com sign = 1; 1727106Svbart@nginx.com } 1728106Svbart@nginx.com 1729106Svbart@nginx.com integer = 0; 1730106Svbart@nginx.com 1731106Svbart@nginx.com for (p = start; nxt_fast_path(p != end); p++) { 1732106Svbart@nginx.com ch = *p; 1733106Svbart@nginx.com 1734106Svbart@nginx.com /* Values below '0' become >= 208. */ 1735106Svbart@nginx.com ch = ch - '0'; 1736106Svbart@nginx.com 1737106Svbart@nginx.com if (ch > 9) { 1738106Svbart@nginx.com break; 1739106Svbart@nginx.com } 1740106Svbart@nginx.com 1741106Svbart@nginx.com if (nxt_slow_path(integer >= cutoff 1742106Svbart@nginx.com && (integer > cutoff || ch > cutlim))) 1743106Svbart@nginx.com { 1744208Svbart@nginx.com nxt_conf_json_parse_error(error, start, 1745311Snick@nginx.com "The integer is too large. Such a large JSON integer value " 1746311Snick@nginx.com "is not supported." 1747208Svbart@nginx.com ); 1748208Svbart@nginx.com 1749208Svbart@nginx.com return NULL; 1750106Svbart@nginx.com } 1751106Svbart@nginx.com 1752106Svbart@nginx.com integer = integer * 10 + ch; 1753106Svbart@nginx.com } 1754106Svbart@nginx.com 1755208Svbart@nginx.com if (nxt_slow_path(p - start > 1 && *start == '0')) { 1756208Svbart@nginx.com 1757208Svbart@nginx.com nxt_conf_json_parse_error(error, start, 1758311Snick@nginx.com "The number is invalid. Leading zeros are not allowed in JSON " 1759311Snick@nginx.com "numbers." 1760208Svbart@nginx.com ); 1761208Svbart@nginx.com 1762106Svbart@nginx.com return NULL; 1763106Svbart@nginx.com } 1764106Svbart@nginx.com 1765106Svbart@nginx.com if (ch != '.') { 1766116Svbart@nginx.com value->type = NXT_CONF_VALUE_INTEGER; 1767106Svbart@nginx.com value->u.integer = sign * integer; 1768106Svbart@nginx.com return p; 1769106Svbart@nginx.com } 1770106Svbart@nginx.com 1771106Svbart@nginx.com #if 0 1772106Svbart@nginx.com start = p + 1; 1773106Svbart@nginx.com 1774106Svbart@nginx.com frac = 0; 1775106Svbart@nginx.com power = 1; 1776106Svbart@nginx.com 1777106Svbart@nginx.com for (p = start; nxt_fast_path(p != end); p++) { 1778106Svbart@nginx.com ch = *p; 1779106Svbart@nginx.com 1780106Svbart@nginx.com /* Values below '0' become >= 208. */ 1781106Svbart@nginx.com ch = ch - '0'; 1782106Svbart@nginx.com 1783106Svbart@nginx.com if (ch > 9) { 1784106Svbart@nginx.com break; 1785106Svbart@nginx.com } 1786106Svbart@nginx.com 1787106Svbart@nginx.com if (nxt_slow_path((frac >= cutoff && (frac > cutoff || ch > cutlim)) 1788106Svbart@nginx.com || power > cutoff)) 1789106Svbart@nginx.com { 1790106Svbart@nginx.com return NULL; 1791106Svbart@nginx.com } 1792106Svbart@nginx.com 1793106Svbart@nginx.com frac = frac * 10 + ch; 1794106Svbart@nginx.com power *= 10; 1795106Svbart@nginx.com } 1796106Svbart@nginx.com 1797106Svbart@nginx.com if (nxt_slow_path(p == start)) { 1798106Svbart@nginx.com return NULL; 1799106Svbart@nginx.com } 1800106Svbart@nginx.com 1801116Svbart@nginx.com value->type = NXT_CONF_VALUE_NUMBER; 1802106Svbart@nginx.com value->u.number = integer + (double) frac / power; 1803106Svbart@nginx.com 1804106Svbart@nginx.com value->u.number = copysign(value->u.number, sign); 1805106Svbart@nginx.com 1806106Svbart@nginx.com if (ch == 'e' || ch == 'E') { 1807106Svbart@nginx.com start = p + 1; 1808106Svbart@nginx.com 1809106Svbart@nginx.com ch = *start; 1810106Svbart@nginx.com 1811106Svbart@nginx.com if (ch == '-' || ch == '+') { 1812106Svbart@nginx.com start++; 1813106Svbart@nginx.com } 1814106Svbart@nginx.com 1815106Svbart@nginx.com negative = (ch == '-') ? 1 : 0; 1816106Svbart@nginx.com e = 0; 1817106Svbart@nginx.com 1818106Svbart@nginx.com for (p = start; nxt_fast_path(p != end); p++) { 1819106Svbart@nginx.com ch = *p; 1820106Svbart@nginx.com 1821106Svbart@nginx.com /* Values below '0' become >= 208. */ 1822106Svbart@nginx.com ch = ch - '0'; 1823106Svbart@nginx.com 1824106Svbart@nginx.com if (ch > 9) { 1825106Svbart@nginx.com break; 1826106Svbart@nginx.com } 1827106Svbart@nginx.com 1828106Svbart@nginx.com e = e * 10 + ch; 1829106Svbart@nginx.com 1830106Svbart@nginx.com if (nxt_slow_path(e > DBL_MAX_10_EXP)) { 1831106Svbart@nginx.com return NULL; 1832106Svbart@nginx.com } 1833106Svbart@nginx.com } 1834106Svbart@nginx.com 1835106Svbart@nginx.com if (nxt_slow_path(p == start)) { 1836106Svbart@nginx.com return NULL; 1837106Svbart@nginx.com } 1838106Svbart@nginx.com 1839106Svbart@nginx.com if (negative) { 1840106Svbart@nginx.com value->u.number /= exp10(e); 1841106Svbart@nginx.com 1842106Svbart@nginx.com } else { 1843106Svbart@nginx.com value->u.number *= exp10(e); 1844106Svbart@nginx.com } 1845106Svbart@nginx.com } 1846106Svbart@nginx.com 1847106Svbart@nginx.com if (nxt_fast_path(isfinite(value->u.number))) { 1848106Svbart@nginx.com return p; 1849106Svbart@nginx.com } 1850208Svbart@nginx.com #else 1851208Svbart@nginx.com 1852208Svbart@nginx.com nxt_conf_json_parse_error(error, start, 1853311Snick@nginx.com "The number is not an integer. JSON numbers with decimals and " 1854311Snick@nginx.com "exponents are not supported." 1855208Svbart@nginx.com ); 1856208Svbart@nginx.com 1857106Svbart@nginx.com #endif 1858106Svbart@nginx.com 1859106Svbart@nginx.com return NULL; 1860106Svbart@nginx.com } 1861106Svbart@nginx.com 1862106Svbart@nginx.com 1863208Svbart@nginx.com static void 1864208Svbart@nginx.com nxt_conf_json_parse_error(nxt_conf_json_error_t *error, u_char *pos, 1865208Svbart@nginx.com const char *detail) 1866208Svbart@nginx.com { 1867208Svbart@nginx.com if (error == NULL) { 1868208Svbart@nginx.com return; 1869208Svbart@nginx.com } 1870208Svbart@nginx.com 1871208Svbart@nginx.com error->pos = pos; 1872208Svbart@nginx.com error->detail = (u_char *) detail; 1873208Svbart@nginx.com } 1874208Svbart@nginx.com 1875208Svbart@nginx.com 1876106Svbart@nginx.com size_t 1877106Svbart@nginx.com nxt_conf_json_length(nxt_conf_value_t *value, nxt_conf_json_pretty_t *pretty) 1878106Svbart@nginx.com { 1879106Svbart@nginx.com switch (value->type) { 1880106Svbart@nginx.com 1881116Svbart@nginx.com case NXT_CONF_VALUE_NULL: 1882106Svbart@nginx.com return sizeof("null") - 1; 1883106Svbart@nginx.com 1884116Svbart@nginx.com case NXT_CONF_VALUE_BOOLEAN: 1885106Svbart@nginx.com return value->u.boolean ? sizeof("true") - 1 : sizeof("false") - 1; 1886106Svbart@nginx.com 1887116Svbart@nginx.com case NXT_CONF_VALUE_INTEGER: 1888106Svbart@nginx.com return nxt_conf_json_integer_length(value); 1889106Svbart@nginx.com 1890116Svbart@nginx.com case NXT_CONF_VALUE_NUMBER: 1891106Svbart@nginx.com /* TODO */ 1892106Svbart@nginx.com return 0; 1893106Svbart@nginx.com 1894116Svbart@nginx.com case NXT_CONF_VALUE_SHORT_STRING: 1895116Svbart@nginx.com case NXT_CONF_VALUE_STRING: 1896106Svbart@nginx.com return nxt_conf_json_string_length(value); 1897106Svbart@nginx.com 1898116Svbart@nginx.com case NXT_CONF_VALUE_ARRAY: 1899106Svbart@nginx.com return nxt_conf_json_array_length(value, pretty); 1900106Svbart@nginx.com 1901116Svbart@nginx.com case NXT_CONF_VALUE_OBJECT: 1902106Svbart@nginx.com return nxt_conf_json_object_length(value, pretty); 1903106Svbart@nginx.com } 1904106Svbart@nginx.com 1905106Svbart@nginx.com nxt_unreachable(); 1906106Svbart@nginx.com 1907106Svbart@nginx.com return 0; 1908106Svbart@nginx.com } 1909106Svbart@nginx.com 1910106Svbart@nginx.com 1911106Svbart@nginx.com u_char * 1912106Svbart@nginx.com nxt_conf_json_print(u_char *p, nxt_conf_value_t *value, 1913106Svbart@nginx.com nxt_conf_json_pretty_t *pretty) 1914106Svbart@nginx.com { 1915106Svbart@nginx.com switch (value->type) { 1916106Svbart@nginx.com 1917116Svbart@nginx.com case NXT_CONF_VALUE_NULL: 1918106Svbart@nginx.com return nxt_cpymem(p, "null", 4); 1919106Svbart@nginx.com 1920116Svbart@nginx.com case NXT_CONF_VALUE_BOOLEAN: 1921106Svbart@nginx.com return value->u.boolean ? nxt_cpymem(p, "true", 4) 1922106Svbart@nginx.com : nxt_cpymem(p, "false", 5); 1923106Svbart@nginx.com 1924116Svbart@nginx.com case NXT_CONF_VALUE_INTEGER: 1925106Svbart@nginx.com return nxt_conf_json_print_integer(p, value); 1926106Svbart@nginx.com 1927116Svbart@nginx.com case NXT_CONF_VALUE_NUMBER: 1928106Svbart@nginx.com /* TODO */ 1929106Svbart@nginx.com return p; 1930106Svbart@nginx.com 1931116Svbart@nginx.com case NXT_CONF_VALUE_SHORT_STRING: 1932116Svbart@nginx.com case NXT_CONF_VALUE_STRING: 1933106Svbart@nginx.com return nxt_conf_json_print_string(p, value); 1934106Svbart@nginx.com 1935116Svbart@nginx.com case NXT_CONF_VALUE_ARRAY: 1936106Svbart@nginx.com return nxt_conf_json_print_array(p, value, pretty); 1937106Svbart@nginx.com 1938116Svbart@nginx.com case NXT_CONF_VALUE_OBJECT: 1939106Svbart@nginx.com return nxt_conf_json_print_object(p, value, pretty); 1940106Svbart@nginx.com } 1941106Svbart@nginx.com 1942106Svbart@nginx.com nxt_unreachable(); 1943106Svbart@nginx.com 1944106Svbart@nginx.com return p; 1945106Svbart@nginx.com } 1946106Svbart@nginx.com 1947106Svbart@nginx.com 1948106Svbart@nginx.com static size_t 1949106Svbart@nginx.com nxt_conf_json_integer_length(nxt_conf_value_t *value) 1950106Svbart@nginx.com { 1951106Svbart@nginx.com int64_t num; 1952106Svbart@nginx.com 1953106Svbart@nginx.com num = llabs(value->u.integer); 1954106Svbart@nginx.com 1955106Svbart@nginx.com if (num <= 9999) { 1956106Svbart@nginx.com return sizeof("-9999") - 1; 1957106Svbart@nginx.com } 1958106Svbart@nginx.com 1959210Svbart@nginx.com if (num <= 99999999999LL) { 1960106Svbart@nginx.com return sizeof("-99999999999") - 1; 1961106Svbart@nginx.com } 1962106Svbart@nginx.com 1963106Svbart@nginx.com return NXT_INT64_T_LEN; 1964106Svbart@nginx.com } 1965106Svbart@nginx.com 1966106Svbart@nginx.com 1967106Svbart@nginx.com static u_char * 1968106Svbart@nginx.com nxt_conf_json_print_integer(u_char *p, nxt_conf_value_t *value) 1969106Svbart@nginx.com { 1970106Svbart@nginx.com return nxt_sprintf(p, p + NXT_INT64_T_LEN, "%L", value->u.integer); 1971106Svbart@nginx.com } 1972106Svbart@nginx.com 1973106Svbart@nginx.com 1974106Svbart@nginx.com static size_t 1975106Svbart@nginx.com nxt_conf_json_string_length(nxt_conf_value_t *value) 1976106Svbart@nginx.com { 1977106Svbart@nginx.com nxt_str_t str; 1978106Svbart@nginx.com 1979106Svbart@nginx.com nxt_conf_get_string(value, &str); 1980106Svbart@nginx.com 1981106Svbart@nginx.com return 2 + nxt_conf_json_escape_length(str.start, str.length); 1982106Svbart@nginx.com } 1983106Svbart@nginx.com 1984106Svbart@nginx.com 1985106Svbart@nginx.com static u_char * 1986106Svbart@nginx.com nxt_conf_json_print_string(u_char *p, nxt_conf_value_t *value) 1987106Svbart@nginx.com { 1988106Svbart@nginx.com nxt_str_t str; 1989106Svbart@nginx.com 1990106Svbart@nginx.com nxt_conf_get_string(value, &str); 1991106Svbart@nginx.com 1992106Svbart@nginx.com *p++ = '"'; 1993106Svbart@nginx.com 1994106Svbart@nginx.com p = nxt_conf_json_escape(p, str.start, str.length); 1995106Svbart@nginx.com 1996106Svbart@nginx.com *p++ = '"'; 1997106Svbart@nginx.com 1998106Svbart@nginx.com return p; 1999106Svbart@nginx.com } 2000106Svbart@nginx.com 2001106Svbart@nginx.com 2002106Svbart@nginx.com static size_t 2003106Svbart@nginx.com nxt_conf_json_array_length(nxt_conf_value_t *value, 2004106Svbart@nginx.com nxt_conf_json_pretty_t *pretty) 2005106Svbart@nginx.com { 2006106Svbart@nginx.com size_t len; 2007106Svbart@nginx.com nxt_uint_t n; 2008106Svbart@nginx.com nxt_conf_array_t *array; 2009106Svbart@nginx.com 2010106Svbart@nginx.com array = value->u.array; 2011106Svbart@nginx.com 2012106Svbart@nginx.com /* [] */ 2013106Svbart@nginx.com len = 2; 2014106Svbart@nginx.com 2015106Svbart@nginx.com if (pretty != NULL) { 2016106Svbart@nginx.com pretty->level++; 2017106Svbart@nginx.com } 2018106Svbart@nginx.com 2019106Svbart@nginx.com value = array->elements; 2020106Svbart@nginx.com 2021106Svbart@nginx.com for (n = 0; n < array->count; n++) { 2022106Svbart@nginx.com len += nxt_conf_json_length(&value[n], pretty); 2023106Svbart@nginx.com 2024106Svbart@nginx.com if (pretty != NULL) { 2025106Svbart@nginx.com /* Indentation and new line. */ 2026106Svbart@nginx.com len += pretty->level + 2; 2027106Svbart@nginx.com } 2028106Svbart@nginx.com } 2029106Svbart@nginx.com 2030106Svbart@nginx.com if (pretty != NULL) { 2031106Svbart@nginx.com pretty->level--; 2032106Svbart@nginx.com 2033106Svbart@nginx.com if (n != 0) { 2034106Svbart@nginx.com /* Indentation and new line. */ 2035106Svbart@nginx.com len += pretty->level + 2; 2036106Svbart@nginx.com } 2037106Svbart@nginx.com } 2038106Svbart@nginx.com 2039106Svbart@nginx.com /* Reserve space for "n" commas. */ 2040106Svbart@nginx.com return len + n; 2041106Svbart@nginx.com } 2042106Svbart@nginx.com 2043106Svbart@nginx.com 2044106Svbart@nginx.com static u_char * 2045106Svbart@nginx.com nxt_conf_json_print_array(u_char *p, nxt_conf_value_t *value, 2046106Svbart@nginx.com nxt_conf_json_pretty_t *pretty) 2047106Svbart@nginx.com { 2048106Svbart@nginx.com nxt_uint_t n; 2049106Svbart@nginx.com nxt_conf_array_t *array; 2050106Svbart@nginx.com 2051106Svbart@nginx.com array = value->u.array; 2052106Svbart@nginx.com 2053106Svbart@nginx.com *p++ = '['; 2054106Svbart@nginx.com 2055106Svbart@nginx.com if (array->count != 0) { 2056106Svbart@nginx.com value = array->elements; 2057106Svbart@nginx.com 2058106Svbart@nginx.com if (pretty != NULL) { 2059106Svbart@nginx.com p = nxt_conf_json_newline(p); 2060106Svbart@nginx.com 2061106Svbart@nginx.com pretty->level++; 2062106Svbart@nginx.com p = nxt_conf_json_indentation(p, pretty->level); 2063106Svbart@nginx.com } 2064106Svbart@nginx.com 2065106Svbart@nginx.com p = nxt_conf_json_print(p, &value[0], pretty); 2066106Svbart@nginx.com 2067106Svbart@nginx.com for (n = 1; n < array->count; n++) { 2068106Svbart@nginx.com *p++ = ','; 2069106Svbart@nginx.com 2070106Svbart@nginx.com if (pretty != NULL) { 2071106Svbart@nginx.com p = nxt_conf_json_newline(p); 2072106Svbart@nginx.com p = nxt_conf_json_indentation(p, pretty->level); 2073106Svbart@nginx.com 2074106Svbart@nginx.com pretty->more_space = 0; 2075106Svbart@nginx.com } 2076106Svbart@nginx.com 2077106Svbart@nginx.com p = nxt_conf_json_print(p, &value[n], pretty); 2078106Svbart@nginx.com } 2079106Svbart@nginx.com 2080106Svbart@nginx.com if (pretty != NULL) { 2081106Svbart@nginx.com p = nxt_conf_json_newline(p); 2082106Svbart@nginx.com 2083106Svbart@nginx.com pretty->level--; 2084106Svbart@nginx.com p = nxt_conf_json_indentation(p, pretty->level); 2085106Svbart@nginx.com 2086106Svbart@nginx.com pretty->more_space = 1; 2087106Svbart@nginx.com } 2088106Svbart@nginx.com } 2089106Svbart@nginx.com 2090106Svbart@nginx.com *p++ = ']'; 2091106Svbart@nginx.com 2092106Svbart@nginx.com return p; 2093106Svbart@nginx.com } 2094106Svbart@nginx.com 2095106Svbart@nginx.com 2096106Svbart@nginx.com static size_t 2097106Svbart@nginx.com nxt_conf_json_object_length(nxt_conf_value_t *value, 2098106Svbart@nginx.com nxt_conf_json_pretty_t *pretty) 2099106Svbart@nginx.com { 2100106Svbart@nginx.com size_t len; 2101106Svbart@nginx.com nxt_uint_t n; 2102106Svbart@nginx.com nxt_conf_object_t *object; 2103106Svbart@nginx.com nxt_conf_object_member_t *member; 2104106Svbart@nginx.com 2105106Svbart@nginx.com object = value->u.object; 2106106Svbart@nginx.com 2107106Svbart@nginx.com /* {} */ 2108106Svbart@nginx.com len = 2; 2109106Svbart@nginx.com 2110106Svbart@nginx.com if (pretty != NULL) { 2111106Svbart@nginx.com pretty->level++; 2112106Svbart@nginx.com } 2113106Svbart@nginx.com 2114106Svbart@nginx.com member = object->members; 2115106Svbart@nginx.com 2116106Svbart@nginx.com for (n = 0; n < object->count; n++) { 2117106Svbart@nginx.com len += nxt_conf_json_string_length(&member[n].name) + 1 2118106Svbart@nginx.com + nxt_conf_json_length(&member[n].value, pretty) + 1; 2119106Svbart@nginx.com 2120106Svbart@nginx.com if (pretty != NULL) { 2121106Svbart@nginx.com /* 2122106Svbart@nginx.com * Indentation, space after ":", new line, and possible 2123106Svbart@nginx.com * additional empty line between non-empty objects. 2124106Svbart@nginx.com */ 2125106Svbart@nginx.com len += pretty->level + 1 + 2 + 2; 2126106Svbart@nginx.com } 2127106Svbart@nginx.com } 2128106Svbart@nginx.com 2129106Svbart@nginx.com if (pretty != NULL) { 2130106Svbart@nginx.com pretty->level--; 2131106Svbart@nginx.com 2132106Svbart@nginx.com /* Indentation and new line. */ 2133106Svbart@nginx.com len += pretty->level + 2; 2134106Svbart@nginx.com } 2135106Svbart@nginx.com 2136106Svbart@nginx.com return len; 2137106Svbart@nginx.com } 2138106Svbart@nginx.com 2139106Svbart@nginx.com 2140106Svbart@nginx.com static u_char * 2141106Svbart@nginx.com nxt_conf_json_print_object(u_char *p, nxt_conf_value_t *value, 2142106Svbart@nginx.com nxt_conf_json_pretty_t *pretty) 2143106Svbart@nginx.com { 2144106Svbart@nginx.com nxt_uint_t n; 2145106Svbart@nginx.com nxt_conf_object_t *object; 2146106Svbart@nginx.com nxt_conf_object_member_t *member; 2147106Svbart@nginx.com 2148106Svbart@nginx.com object = value->u.object; 2149106Svbart@nginx.com 2150106Svbart@nginx.com *p++ = '{'; 2151106Svbart@nginx.com 2152106Svbart@nginx.com if (object->count != 0) { 2153106Svbart@nginx.com 2154106Svbart@nginx.com if (pretty != NULL) { 2155106Svbart@nginx.com p = nxt_conf_json_newline(p); 2156106Svbart@nginx.com pretty->level++; 2157106Svbart@nginx.com } 2158106Svbart@nginx.com 2159106Svbart@nginx.com member = object->members; 2160106Svbart@nginx.com 2161106Svbart@nginx.com n = 0; 2162106Svbart@nginx.com 2163106Svbart@nginx.com for ( ;; ) { 2164106Svbart@nginx.com if (pretty != NULL) { 2165106Svbart@nginx.com p = nxt_conf_json_indentation(p, pretty->level); 2166106Svbart@nginx.com } 2167106Svbart@nginx.com 2168106Svbart@nginx.com p = nxt_conf_json_print_string(p, &member[n].name); 2169106Svbart@nginx.com 2170106Svbart@nginx.com *p++ = ':'; 2171106Svbart@nginx.com 2172106Svbart@nginx.com if (pretty != NULL) { 2173106Svbart@nginx.com *p++ = ' '; 2174106Svbart@nginx.com } 2175106Svbart@nginx.com 2176106Svbart@nginx.com p = nxt_conf_json_print(p, &member[n].value, pretty); 2177106Svbart@nginx.com 2178106Svbart@nginx.com n++; 2179106Svbart@nginx.com 2180106Svbart@nginx.com if (n == object->count) { 2181106Svbart@nginx.com break; 2182106Svbart@nginx.com } 2183106Svbart@nginx.com 2184106Svbart@nginx.com *p++ = ','; 2185106Svbart@nginx.com 2186106Svbart@nginx.com if (pretty != NULL) { 2187106Svbart@nginx.com p = nxt_conf_json_newline(p); 2188106Svbart@nginx.com 2189106Svbart@nginx.com if (pretty->more_space) { 2190106Svbart@nginx.com pretty->more_space = 0; 2191106Svbart@nginx.com p = nxt_conf_json_newline(p); 2192106Svbart@nginx.com } 2193106Svbart@nginx.com } 2194106Svbart@nginx.com } 2195106Svbart@nginx.com 2196106Svbart@nginx.com if (pretty != NULL) { 2197106Svbart@nginx.com p = nxt_conf_json_newline(p); 2198106Svbart@nginx.com 2199106Svbart@nginx.com pretty->level--; 2200106Svbart@nginx.com p = nxt_conf_json_indentation(p, pretty->level); 2201106Svbart@nginx.com 2202106Svbart@nginx.com pretty->more_space = 1; 2203106Svbart@nginx.com } 2204106Svbart@nginx.com } 2205106Svbart@nginx.com 2206106Svbart@nginx.com *p++ = '}'; 2207106Svbart@nginx.com 2208106Svbart@nginx.com return p; 2209106Svbart@nginx.com } 2210106Svbart@nginx.com 2211106Svbart@nginx.com 2212106Svbart@nginx.com static size_t 2213106Svbart@nginx.com nxt_conf_json_escape_length(u_char *p, size_t size) 2214106Svbart@nginx.com { 2215106Svbart@nginx.com u_char ch; 2216106Svbart@nginx.com size_t len; 2217106Svbart@nginx.com 2218106Svbart@nginx.com len = size; 2219106Svbart@nginx.com 2220106Svbart@nginx.com while (size) { 2221106Svbart@nginx.com ch = *p++; 2222106Svbart@nginx.com 2223106Svbart@nginx.com if (ch == '\\' || ch == '"') { 2224106Svbart@nginx.com len++; 2225106Svbart@nginx.com 2226106Svbart@nginx.com } else if (ch <= 0x1f) { 2227106Svbart@nginx.com 2228106Svbart@nginx.com switch (ch) { 2229106Svbart@nginx.com case '\n': 2230106Svbart@nginx.com case '\r': 2231106Svbart@nginx.com case '\t': 2232106Svbart@nginx.com case '\b': 2233106Svbart@nginx.com case '\f': 2234106Svbart@nginx.com len++; 2235106Svbart@nginx.com break; 2236106Svbart@nginx.com 2237106Svbart@nginx.com default: 2238106Svbart@nginx.com len += sizeof("\\u001F") - 2; 2239106Svbart@nginx.com } 2240106Svbart@nginx.com } 2241106Svbart@nginx.com 2242106Svbart@nginx.com size--; 2243106Svbart@nginx.com } 2244106Svbart@nginx.com 2245106Svbart@nginx.com return len; 2246106Svbart@nginx.com } 2247106Svbart@nginx.com 2248106Svbart@nginx.com 2249106Svbart@nginx.com static u_char * 2250106Svbart@nginx.com nxt_conf_json_escape(u_char *dst, u_char *src, size_t size) 2251106Svbart@nginx.com { 2252106Svbart@nginx.com u_char ch; 2253106Svbart@nginx.com 2254106Svbart@nginx.com while (size) { 2255106Svbart@nginx.com ch = *src++; 2256106Svbart@nginx.com 2257106Svbart@nginx.com if (ch > 0x1f) { 2258106Svbart@nginx.com 2259106Svbart@nginx.com if (ch == '\\' || ch == '"') { 2260106Svbart@nginx.com *dst++ = '\\'; 2261106Svbart@nginx.com } 2262106Svbart@nginx.com 2263106Svbart@nginx.com *dst++ = ch; 2264106Svbart@nginx.com 2265106Svbart@nginx.com } else { 2266106Svbart@nginx.com *dst++ = '\\'; 2267106Svbart@nginx.com 2268106Svbart@nginx.com switch (ch) { 2269106Svbart@nginx.com case '\n': 2270106Svbart@nginx.com *dst++ = 'n'; 2271106Svbart@nginx.com break; 2272106Svbart@nginx.com 2273106Svbart@nginx.com case '\r': 2274106Svbart@nginx.com *dst++ = 'r'; 2275106Svbart@nginx.com break; 2276106Svbart@nginx.com 2277106Svbart@nginx.com case '\t': 2278106Svbart@nginx.com *dst++ = 't'; 2279106Svbart@nginx.com break; 2280106Svbart@nginx.com 2281106Svbart@nginx.com case '\b': 2282106Svbart@nginx.com *dst++ = 'b'; 2283106Svbart@nginx.com break; 2284106Svbart@nginx.com 2285106Svbart@nginx.com case '\f': 2286106Svbart@nginx.com *dst++ = 'f'; 2287106Svbart@nginx.com break; 2288106Svbart@nginx.com 2289106Svbart@nginx.com default: 2290106Svbart@nginx.com *dst++ = 'u'; *dst++ = '0'; *dst++ = '0'; 2291106Svbart@nginx.com *dst++ = '0' + (ch >> 4); 2292106Svbart@nginx.com 2293106Svbart@nginx.com ch &= 0xf; 2294106Svbart@nginx.com 2295106Svbart@nginx.com *dst++ = (ch < 10) ? ('0' + ch) : ('A' + ch - 10); 2296106Svbart@nginx.com } 2297106Svbart@nginx.com } 2298106Svbart@nginx.com 2299106Svbart@nginx.com size--; 2300106Svbart@nginx.com } 2301106Svbart@nginx.com 2302106Svbart@nginx.com return dst; 2303106Svbart@nginx.com } 2304208Svbart@nginx.com 2305208Svbart@nginx.com 2306208Svbart@nginx.com void 2307208Svbart@nginx.com nxt_conf_json_position(u_char *start, u_char *pos, nxt_uint_t *line, 2308208Svbart@nginx.com nxt_uint_t *column) 2309208Svbart@nginx.com { 2310208Svbart@nginx.com u_char *p; 2311208Svbart@nginx.com ssize_t symbols; 2312208Svbart@nginx.com nxt_uint_t lines; 2313208Svbart@nginx.com 2314208Svbart@nginx.com lines = 1; 2315208Svbart@nginx.com 2316208Svbart@nginx.com for (p = start; p != pos; p++) { 2317208Svbart@nginx.com 2318208Svbart@nginx.com if (*p != '\n') { 2319208Svbart@nginx.com continue; 2320208Svbart@nginx.com } 2321208Svbart@nginx.com 2322208Svbart@nginx.com lines++; 2323208Svbart@nginx.com start = p + 1; 2324208Svbart@nginx.com } 2325208Svbart@nginx.com 2326208Svbart@nginx.com symbols = nxt_utf8_length(start, p - start); 2327208Svbart@nginx.com 2328208Svbart@nginx.com if (symbols != -1) { 2329208Svbart@nginx.com *line = lines; 2330208Svbart@nginx.com *column = 1 + symbols; 2331208Svbart@nginx.com } 2332208Svbart@nginx.com } 2333