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