1 /*
2 * Copyright (c) 2007-2014, Lloyd Hilaiel <me@lloyd.io>
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #include "../burp.h"
18 #include "api/yajl_parse.h"
19 #include "yajl_lex.h"
20 #include "yajl_parser.h"
21 #include "yajl_encode.h"
22 #include "yajl_bytestack.h"
23
24 #include <stdlib.h>
25 #include <limits.h>
26 #include <errno.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <ctype.h>
30 #include <assert.h>
31 #include <math.h>
32
33 #define MAX_VALUE_TO_MULTIPLY ((LLONG_MAX / 10) + (LLONG_MAX % 10))
34
35 /* same semantics as strtol */
36 long long
yajl_parse_integer(const unsigned char * number,unsigned int length)37 yajl_parse_integer(const unsigned char *number, unsigned int length)
38 {
39 long long ret = 0;
40 long sign = 1;
41 const unsigned char *pos = number;
42 if (*pos == '-') { pos++; sign = -1; }
43 if (*pos == '+') { pos++; }
44
45 while (pos < number + length) {
46 if ( ret > MAX_VALUE_TO_MULTIPLY ) {
47 errno = ERANGE;
48 return sign == 1 ? LLONG_MAX : LLONG_MIN;
49 }
50 ret *= 10;
51 if (LLONG_MAX - ret < (*pos - '0')) {
52 errno = ERANGE;
53 return sign == 1 ? LLONG_MAX : LLONG_MIN;
54 }
55 if (*pos < '0' || *pos > '9') {
56 errno = ERANGE;
57 return sign == 1 ? LLONG_MAX : LLONG_MIN;
58 }
59 ret += (*pos++ - '0');
60 }
61
62 return sign * ret;
63 }
64
65 unsigned char *
yajl_render_error_string(yajl_handle hand,const unsigned char * jsonText,size_t jsonTextLen,int verbose)66 yajl_render_error_string(yajl_handle hand, const unsigned char * jsonText,
67 size_t jsonTextLen, int verbose)
68 {
69 size_t offset = hand->bytesConsumed;
70 unsigned char * str;
71 const char * errorType = NULL;
72 const char * errorText = NULL;
73 char text[72];
74 const char * arrow = " (right here) ------^\n";
75
76 if (yajl_bs_current(hand->stateStack) == yajl_state_parse_error) {
77 errorType = "parse";
78 errorText = hand->parseError;
79 } else if (yajl_bs_current(hand->stateStack) == yajl_state_lexical_error) {
80 errorType = "lexical";
81 errorText = yajl_lex_error_to_string(yajl_lex_get_error(hand->lexer));
82 } else {
83 errorType = "unknown";
84 }
85
86 {
87 size_t memneeded = 0;
88 memneeded += strlen(errorType);
89 memneeded += strlen(" error");
90 if (errorText != NULL) {
91 memneeded += strlen(": ");
92 memneeded += strlen(errorText);
93 }
94 str = (unsigned char *) YA_MALLOC(&(hand->alloc), memneeded + 2);
95 if (!str) return NULL;
96 str[0] = 0;
97 strcat((char *) str, errorType);
98 strcat((char *) str, " error");
99 if (errorText != NULL) {
100 strcat((char *) str, ": ");
101 strcat((char *) str, errorText);
102 }
103 strcat((char *) str, "\n");
104 }
105
106 /* now we append as many spaces as needed to make sure the error
107 * falls at char 41, if verbose was specified */
108 if (verbose) {
109 size_t start, end, i;
110 size_t spacesNeeded;
111
112 spacesNeeded = (offset < 30 ? 40 - offset : 10);
113 start = (offset >= 30 ? offset - 30 : 0);
114 end = (offset + 30 > jsonTextLen ? jsonTextLen : offset + 30);
115
116 for (i=0;i<spacesNeeded;i++) text[i] = ' ';
117
118 for (;start < end;start++, i++) {
119 if (jsonText[start] != '\n' && jsonText[start] != '\r')
120 {
121 text[i] = jsonText[start];
122 }
123 else
124 {
125 text[i] = ' ';
126 }
127 }
128 assert(i <= 71);
129 text[i++] = '\n';
130 text[i] = 0;
131 {
132 char * newStr = (char *)
133 YA_MALLOC(&(hand->alloc), (unsigned int)(strlen((char *) str) +
134 strlen((char *) text) +
135 strlen(arrow) + 1));
136 if (newStr) {
137 newStr[0] = 0;
138 strcat((char *) newStr, (char *) str);
139 strcat((char *) newStr, text);
140 strcat((char *) newStr, arrow);
141 }
142 YA_FREE(&(hand->alloc), str);
143 str = (unsigned char *) newStr;
144 }
145 }
146 return str;
147 }
148
149 /* check for client cancelation */
150 #define _CC_CHK(x) \
151 if (!(x)) { \
152 yajl_bs_set(hand->stateStack, yajl_state_parse_error); \
153 hand->parseError = \
154 "client cancelled parse via callback return value"; \
155 return yajl_status_client_canceled; \
156 }
157
158
159 yajl_status
yajl_do_finish(yajl_handle hand)160 yajl_do_finish(yajl_handle hand)
161 {
162 yajl_status stat;
163 stat = yajl_do_parse(hand,(const unsigned char *) " ",1);
164
165 if (stat != yajl_status_ok) return stat;
166
167 switch(yajl_bs_current(hand->stateStack))
168 {
169 case yajl_state_parse_error:
170 case yajl_state_lexical_error:
171 return yajl_status_error;
172 case yajl_state_got_value:
173 case yajl_state_parse_complete:
174 return yajl_status_ok;
175 default:
176 if (!(hand->flags & yajl_allow_partial_values))
177 {
178 yajl_bs_set(hand->stateStack, yajl_state_parse_error);
179 hand->parseError = "premature EOF";
180 return yajl_status_error;
181 }
182 return yajl_status_ok;
183 }
184 }
185
186 yajl_status
yajl_do_parse(yajl_handle hand,const unsigned char * jsonText,size_t jsonTextLen)187 yajl_do_parse(yajl_handle hand, const unsigned char * jsonText,
188 size_t jsonTextLen)
189 {
190 yajl_tok tok;
191 const unsigned char * buf;
192 size_t bufLen;
193 size_t * offset = &(hand->bytesConsumed);
194
195 *offset = 0;
196
197 around_again:
198 switch (yajl_bs_current(hand->stateStack)) {
199 case yajl_state_parse_complete:
200 if (hand->flags & yajl_allow_multiple_values) {
201 yajl_bs_set(hand->stateStack, yajl_state_got_value);
202 goto around_again;
203 }
204 if (!(hand->flags & yajl_allow_trailing_garbage)) {
205 if (*offset != jsonTextLen) {
206 tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen,
207 offset, &buf, &bufLen);
208 if (tok != yajl_tok_eof) {
209 yajl_bs_set(hand->stateStack, yajl_state_parse_error);
210 hand->parseError = "trailing garbage";
211 }
212 goto around_again;
213 }
214 }
215 return yajl_status_ok;
216 case yajl_state_lexical_error:
217 case yajl_state_parse_error:
218 return yajl_status_error;
219 case yajl_state_start:
220 case yajl_state_got_value:
221 case yajl_state_map_need_val:
222 case yajl_state_array_need_val:
223 case yajl_state_array_start: {
224 /* for arrays and maps, we advance the state for this
225 * depth, then push the state of the next depth.
226 * If an error occurs during the parsing of the nesting
227 * enitity, the state at this level will not matter.
228 * a state that needs pushing will be anything other
229 * than state_start */
230
231 yajl_state stateToPush = yajl_state_start;
232
233 tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen,
234 offset, &buf, &bufLen);
235
236 switch (tok) {
237 case yajl_tok_eof:
238 return yajl_status_ok;
239 case yajl_tok_error:
240 yajl_bs_set(hand->stateStack, yajl_state_lexical_error);
241 goto around_again;
242 case yajl_tok_string:
243 if (hand->callbacks && hand->callbacks->yajl_string) {
244 _CC_CHK(hand->callbacks->yajl_string(hand->ctx,
245 buf, bufLen));
246 }
247 break;
248 case yajl_tok_string_with_escapes:
249 if (hand->callbacks && hand->callbacks->yajl_string) {
250 yajl_buf_clear(hand->decodeBuf);
251 yajl_string_decode(hand->decodeBuf, buf, bufLen);
252 _CC_CHK(hand->callbacks->yajl_string(
253 hand->ctx, yajl_buf_data(hand->decodeBuf),
254 yajl_buf_len(hand->decodeBuf)));
255 }
256 break;
257 case yajl_tok_bool:
258 if (hand->callbacks && hand->callbacks->yajl_boolean) {
259 _CC_CHK(hand->callbacks->yajl_boolean(hand->ctx,
260 *buf == 't'));
261 }
262 break;
263 case yajl_tok_null:
264 if (hand->callbacks && hand->callbacks->yajl_null) {
265 _CC_CHK(hand->callbacks->yajl_null(hand->ctx));
266 }
267 break;
268 case yajl_tok_left_bracket:
269 if (hand->callbacks && hand->callbacks->yajl_start_map) {
270 _CC_CHK(hand->callbacks->yajl_start_map(hand->ctx));
271 }
272 stateToPush = yajl_state_map_start;
273 break;
274 case yajl_tok_left_brace:
275 if (hand->callbacks && hand->callbacks->yajl_start_array) {
276 _CC_CHK(hand->callbacks->yajl_start_array(hand->ctx));
277 }
278 stateToPush = yajl_state_array_start;
279 break;
280 case yajl_tok_integer:
281 if (hand->callbacks) {
282 if (hand->callbacks->yajl_number) {
283 _CC_CHK(hand->callbacks->yajl_number(
284 hand->ctx,(const char *) buf, bufLen));
285 } else if (hand->callbacks->yajl_integer) {
286 long long int i = 0;
287 errno = 0;
288 i = yajl_parse_integer(buf, bufLen);
289 if ((i == LLONG_MIN || i == LLONG_MAX) &&
290 errno == ERANGE)
291 {
292 yajl_bs_set(hand->stateStack,
293 yajl_state_parse_error);
294 hand->parseError = "integer overflow" ;
295 /* try to restore error offset */
296 if (*offset >= bufLen) *offset -= bufLen;
297 else *offset = 0;
298 goto around_again;
299 }
300 _CC_CHK(hand->callbacks->yajl_integer(hand->ctx,
301 i));
302 }
303 }
304 break;
305 case yajl_tok_double:
306 if (hand->callbacks) {
307 if (hand->callbacks->yajl_number) {
308 _CC_CHK(hand->callbacks->yajl_number(
309 hand->ctx, (const char *) buf, bufLen));
310 } else if (hand->callbacks->yajl_double) {
311 double d = 0.0;
312 yajl_buf_clear(hand->decodeBuf);
313 yajl_buf_append(hand->decodeBuf, buf, bufLen);
314 buf = yajl_buf_data(hand->decodeBuf);
315 errno = 0;
316 d = strtod((char *) buf, NULL);
317 if ((d == HUGE_VAL || d == -HUGE_VAL) &&
318 errno == ERANGE)
319 {
320 yajl_bs_set(hand->stateStack,
321 yajl_state_parse_error);
322 hand->parseError = "numeric (floating point) "
323 "overflow";
324 /* try to restore error offset */
325 if (*offset >= bufLen) *offset -= bufLen;
326 else *offset = 0;
327 goto around_again;
328 }
329 _CC_CHK(hand->callbacks->yajl_double(hand->ctx,
330 d));
331 }
332 }
333 break;
334 case yajl_tok_right_brace: {
335 if (yajl_bs_current(hand->stateStack) ==
336 yajl_state_array_start)
337 {
338 if (hand->callbacks &&
339 hand->callbacks->yajl_end_array)
340 {
341 _CC_CHK(hand->callbacks->yajl_end_array(hand->ctx));
342 }
343 yajl_bs_pop(hand->stateStack);
344 goto around_again;
345 }
346 /* intentional fall-through */
347 }
348 case yajl_tok_colon:
349 case yajl_tok_comma:
350 case yajl_tok_right_bracket:
351 yajl_bs_set(hand->stateStack, yajl_state_parse_error);
352 hand->parseError =
353 "unallowed token at this point in JSON text";
354 goto around_again;
355 default:
356 yajl_bs_set(hand->stateStack, yajl_state_parse_error);
357 hand->parseError = "invalid token, internal error";
358 goto around_again;
359 }
360 /* got a value. transition depends on the state we're in. */
361 {
362 yajl_state s = (yajl_state)yajl_bs_current(hand->stateStack);
363 if (s == yajl_state_start || s == yajl_state_got_value) {
364 yajl_bs_set(hand->stateStack, yajl_state_parse_complete);
365 } else if (s == yajl_state_map_need_val) {
366 yajl_bs_set(hand->stateStack, yajl_state_map_got_val);
367 } else {
368 yajl_bs_set(hand->stateStack, yajl_state_array_got_val);
369 }
370 }
371 if (stateToPush != yajl_state_start) {
372 yajl_bs_push(hand->stateStack, stateToPush);
373 }
374
375 goto around_again;
376 }
377 case yajl_state_map_start:
378 case yajl_state_map_need_key: {
379 /* only difference between these two states is that in
380 * start '}' is valid, whereas in need_key, we've parsed
381 * a comma, and a string key _must_ follow */
382 tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen,
383 offset, &buf, &bufLen);
384 switch (tok) {
385 case yajl_tok_eof:
386 return yajl_status_ok;
387 case yajl_tok_error:
388 yajl_bs_set(hand->stateStack, yajl_state_lexical_error);
389 goto around_again;
390 case yajl_tok_string_with_escapes:
391 if (hand->callbacks && hand->callbacks->yajl_map_key) {
392 yajl_buf_clear(hand->decodeBuf);
393 yajl_string_decode(hand->decodeBuf, buf, bufLen);
394 buf = yajl_buf_data(hand->decodeBuf);
395 bufLen = yajl_buf_len(hand->decodeBuf);
396 }
397 /* intentional fall-through */
398 case yajl_tok_string:
399 if (hand->callbacks && hand->callbacks->yajl_map_key) {
400 _CC_CHK(hand->callbacks->yajl_map_key(hand->ctx, buf,
401 bufLen));
402 }
403 yajl_bs_set(hand->stateStack, yajl_state_map_sep);
404 goto around_again;
405 case yajl_tok_right_bracket:
406 if (yajl_bs_current(hand->stateStack) ==
407 yajl_state_map_start)
408 {
409 if (hand->callbacks && hand->callbacks->yajl_end_map) {
410 _CC_CHK(hand->callbacks->yajl_end_map(hand->ctx));
411 }
412 yajl_bs_pop(hand->stateStack);
413 goto around_again;
414 }
415 default:
416 yajl_bs_set(hand->stateStack, yajl_state_parse_error);
417 hand->parseError =
418 "invalid object key (must be a string)";
419 goto around_again;
420 }
421 }
422 case yajl_state_map_sep: {
423 tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen,
424 offset, &buf, &bufLen);
425 switch (tok) {
426 case yajl_tok_colon:
427 yajl_bs_set(hand->stateStack, yajl_state_map_need_val);
428 goto around_again;
429 case yajl_tok_eof:
430 return yajl_status_ok;
431 case yajl_tok_error:
432 yajl_bs_set(hand->stateStack, yajl_state_lexical_error);
433 goto around_again;
434 default:
435 yajl_bs_set(hand->stateStack, yajl_state_parse_error);
436 hand->parseError = "object key and value must "
437 "be separated by a colon (':')";
438 goto around_again;
439 }
440 }
441 case yajl_state_map_got_val: {
442 tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen,
443 offset, &buf, &bufLen);
444 switch (tok) {
445 case yajl_tok_right_bracket:
446 if (hand->callbacks && hand->callbacks->yajl_end_map) {
447 _CC_CHK(hand->callbacks->yajl_end_map(hand->ctx));
448 }
449 yajl_bs_pop(hand->stateStack);
450 goto around_again;
451 case yajl_tok_comma:
452 yajl_bs_set(hand->stateStack, yajl_state_map_need_key);
453 goto around_again;
454 case yajl_tok_eof:
455 return yajl_status_ok;
456 case yajl_tok_error:
457 yajl_bs_set(hand->stateStack, yajl_state_lexical_error);
458 goto around_again;
459 default:
460 yajl_bs_set(hand->stateStack, yajl_state_parse_error);
461 hand->parseError = "after key and value, inside map, "
462 "I expect ',' or '}'";
463 /* try to restore error offset */
464 if (*offset >= bufLen) *offset -= bufLen;
465 else *offset = 0;
466 goto around_again;
467 }
468 }
469 case yajl_state_array_got_val: {
470 tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen,
471 offset, &buf, &bufLen);
472 switch (tok) {
473 case yajl_tok_right_brace:
474 if (hand->callbacks && hand->callbacks->yajl_end_array) {
475 _CC_CHK(hand->callbacks->yajl_end_array(hand->ctx));
476 }
477 yajl_bs_pop(hand->stateStack);
478 goto around_again;
479 case yajl_tok_comma:
480 yajl_bs_set(hand->stateStack, yajl_state_array_need_val);
481 goto around_again;
482 case yajl_tok_eof:
483 return yajl_status_ok;
484 case yajl_tok_error:
485 yajl_bs_set(hand->stateStack, yajl_state_lexical_error);
486 goto around_again;
487 default:
488 yajl_bs_set(hand->stateStack, yajl_state_parse_error);
489 hand->parseError =
490 "after array element, I expect ',' or ']'";
491 goto around_again;
492 }
493 }
494 }
495
496 abort();
497 return yajl_status_error;
498 }
499
500