1 /*
2  * Copyright (C) 2010 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include "config.h"
32 #include "InspectorValues.h"
33 
34 #if ENABLE(INSPECTOR)
35 
36 #include <wtf/DecimalNumber.h>
37 
38 namespace WebCore {
39 
40 namespace {
41 
42 static const int stackLimit = 1000;
43 
44 enum Token {
45     OBJECT_BEGIN,
46     OBJECT_END,
47     ARRAY_BEGIN,
48     ARRAY_END,
49     STRING,
50     NUMBER,
51     BOOL_TRUE,
52     BOOL_FALSE,
53     NULL_TOKEN,
54     LIST_SEPARATOR,
55     OBJECT_PAIR_SEPARATOR,
56     INVALID_TOKEN,
57 };
58 
59 const char* const nullString = "null";
60 const char* const trueString = "true";
61 const char* const falseString = "false";
62 
parseConstToken(const UChar * start,const UChar * end,const UChar ** tokenEnd,const char * token)63 bool parseConstToken(const UChar* start, const UChar* end, const UChar** tokenEnd, const char* token)
64 {
65     while (start < end && *token != '\0' && *start++ == *token++) { }
66     if (*token != '\0')
67         return false;
68     *tokenEnd = start;
69     return true;
70 }
71 
readInt(const UChar * start,const UChar * end,const UChar ** tokenEnd,bool canHaveLeadingZeros)72 bool readInt(const UChar* start, const UChar* end, const UChar** tokenEnd, bool canHaveLeadingZeros)
73 {
74     if (start == end)
75         return false;
76     bool haveLeadingZero = '0' == *start;
77     int length = 0;
78     while (start < end && '0' <= *start && *start <= '9') {
79         ++start;
80         ++length;
81     }
82     if (!length)
83         return false;
84     if (!canHaveLeadingZeros && length > 1 && haveLeadingZero)
85         return false;
86     *tokenEnd = start;
87     return true;
88 }
89 
parseNumberToken(const UChar * start,const UChar * end,const UChar ** tokenEnd)90 bool parseNumberToken(const UChar* start, const UChar* end, const UChar** tokenEnd)
91 {
92     // We just grab the number here.  We validate the size in DecodeNumber.
93     // According   to RFC4627, a valid number is: [minus] int [frac] [exp]
94     if (start == end)
95         return false;
96     UChar c = *start;
97     if ('-' == c)
98         ++start;
99 
100     if (!readInt(start, end, &start, false))
101         return false;
102     if (start == end) {
103         *tokenEnd = start;
104         return true;
105     }
106 
107     // Optional fraction part
108     c = *start;
109     if ('.' == c) {
110         ++start;
111         if (!readInt(start, end, &start, true))
112             return false;
113         if (start == end) {
114             *tokenEnd = start;
115             return true;
116         }
117         c = *start;
118     }
119 
120     // Optional exponent part
121     if ('e' == c || 'E' == c) {
122         ++start;
123         if (start == end)
124             return false;
125         c = *start;
126         if ('-' == c || '+' == c) {
127             ++start;
128             if (start == end)
129                 return false;
130         }
131         if (!readInt(start, end, &start, true))
132             return false;
133     }
134 
135     *tokenEnd = start;
136     return true;
137 }
138 
readHexDigits(const UChar * start,const UChar * end,const UChar ** tokenEnd,int digits)139 bool readHexDigits(const UChar* start, const UChar* end, const UChar** tokenEnd, int digits)
140 {
141     if (end - start < digits)
142         return false;
143     for (int i = 0; i < digits; ++i) {
144         UChar c = *start++;
145         if (!(('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F')))
146             return false;
147     }
148     *tokenEnd = start;
149     return true;
150 }
151 
parseStringToken(const UChar * start,const UChar * end,const UChar ** tokenEnd)152 bool parseStringToken(const UChar* start, const UChar* end, const UChar** tokenEnd)
153 {
154     while (start < end) {
155         UChar c = *start++;
156         if ('\\' == c) {
157             c = *start++;
158             // Make sure the escaped char is valid.
159             switch (c) {
160             case 'x':
161                 if (!readHexDigits(start, end, &start, 2))
162                     return false;
163                 break;
164             case 'u':
165                 if (!readHexDigits(start, end, &start, 4))
166                     return false;
167                 break;
168             case '\\':
169             case '/':
170             case 'b':
171             case 'f':
172             case 'n':
173             case 'r':
174             case 't':
175             case 'v':
176             case '"':
177                 break;
178             default:
179                 return false;
180             }
181         } else if ('"' == c) {
182             *tokenEnd = start;
183             return true;
184         }
185     }
186     return false;
187 }
188 
parseToken(const UChar * start,const UChar * end,const UChar ** tokenEnd)189 Token parseToken(const UChar* start, const UChar* end, const UChar** tokenEnd)
190 {
191     if (start == end)
192         return INVALID_TOKEN;
193 
194     switch (*start) {
195     case 'n':
196         if (parseConstToken(start, end, tokenEnd, nullString))
197             return NULL_TOKEN;
198         break;
199     case 't':
200         if (parseConstToken(start, end, tokenEnd, trueString))
201             return BOOL_TRUE;
202         break;
203     case 'f':
204         if (parseConstToken(start, end, tokenEnd, falseString))
205             return BOOL_FALSE;
206         break;
207     case '[':
208         *tokenEnd = start + 1;
209         return ARRAY_BEGIN;
210     case ']':
211         *tokenEnd = start + 1;
212         return ARRAY_END;
213     case ',':
214         *tokenEnd = start + 1;
215         return LIST_SEPARATOR;
216     case '{':
217         *tokenEnd = start + 1;
218         return OBJECT_BEGIN;
219     case '}':
220         *tokenEnd = start + 1;
221         return OBJECT_END;
222     case ':':
223         *tokenEnd = start + 1;
224         return OBJECT_PAIR_SEPARATOR;
225     case '0':
226     case '1':
227     case '2':
228     case '3':
229     case '4':
230     case '5':
231     case '6':
232     case '7':
233     case '8':
234     case '9':
235     case '-':
236         if (parseNumberToken(start, end, tokenEnd))
237             return NUMBER;
238         break;
239     case '"':
240         if (parseStringToken(start + 1, end, tokenEnd))
241             return STRING;
242         break;
243     }
244     return INVALID_TOKEN;
245 }
246 
hexToInt(UChar c)247 inline int hexToInt(UChar c)
248 {
249     if ('0' <= c && c <= '9')
250         return c - '0';
251     if ('A' <= c && c <= 'F')
252         return c - 'A' + 10;
253     if ('a' <= c && c <= 'f')
254         return c - 'a' + 10;
255     ASSERT_NOT_REACHED();
256     return 0;
257 }
258 
decodeString(const UChar * start,const UChar * end,Vector<UChar> * output)259 bool decodeString(const UChar* start, const UChar* end, Vector<UChar>* output)
260 {
261     while (start < end) {
262         UChar c = *start++;
263         if ('\\' != c) {
264             output->append(c);
265             continue;
266         }
267         c = *start++;
268         switch (c) {
269         case '"':
270         case '/':
271         case '\\':
272             break;
273         case 'b':
274             c = '\b';
275             break;
276         case 'f':
277             c = '\f';
278             break;
279         case 'n':
280             c = '\n';
281             break;
282         case 'r':
283             c = '\r';
284             break;
285         case 't':
286             c = '\t';
287             break;
288         case 'v':
289             c = '\v';
290             break;
291         case 'x':
292             c = (hexToInt(*start) << 4) +
293                 hexToInt(*(start + 1));
294             start += 2;
295             break;
296         case 'u':
297             c = (hexToInt(*start) << 12) +
298                 (hexToInt(*(start + 1)) << 8) +
299                 (hexToInt(*(start + 2)) << 4) +
300                 hexToInt(*(start + 3));
301             start += 4;
302             break;
303         default:
304             return false;
305         }
306         output->append(c);
307     }
308     return true;
309 }
310 
decodeString(const UChar * start,const UChar * end,String * output)311 bool decodeString(const UChar* start, const UChar* end, String* output)
312 {
313     if (start == end) {
314         *output = "";
315         return true;
316     }
317     if (start > end)
318         return false;
319     Vector<UChar> buffer;
320     buffer.reserveCapacity(end - start);
321     if (!decodeString(start, end, &buffer))
322         return false;
323     *output = String(buffer.data(), buffer.size());
324     return true;
325 }
326 
buildValue(const UChar * start,const UChar * end,const UChar ** valueTokenEnd,int depth)327 PassRefPtr<InspectorValue> buildValue(const UChar* start, const UChar* end, const UChar** valueTokenEnd, int depth)
328 {
329     if (depth > stackLimit)
330         return 0;
331 
332     RefPtr<InspectorValue> result;
333     const UChar* tokenEnd;
334     Token token = parseToken(start, end, &tokenEnd);
335     switch (token) {
336     case INVALID_TOKEN:
337         return 0;
338     case NULL_TOKEN:
339         result = InspectorValue::null();
340         break;
341     case BOOL_TRUE:
342         result = InspectorBasicValue::create(true);
343         break;
344     case BOOL_FALSE:
345         result = InspectorBasicValue::create(false);
346         break;
347     case NUMBER: {
348         bool ok;
349         double value = charactersToDouble(start, tokenEnd - start, &ok);
350         if (!ok)
351             return 0;
352         result = InspectorBasicValue::create(value);
353         break;
354     }
355     case STRING: {
356         String value;
357         bool ok = decodeString(start + 1, tokenEnd - 1, &value);
358         if (!ok)
359             return 0;
360         result = InspectorString::create(value);
361         break;
362     }
363     case ARRAY_BEGIN: {
364         RefPtr<InspectorArray> array = InspectorArray::create();
365         start = tokenEnd;
366         token = parseToken(start, end, &tokenEnd);
367         while (token != ARRAY_END) {
368             RefPtr<InspectorValue> arrayNode = buildValue(start, end, &tokenEnd, depth + 1);
369             if (!arrayNode)
370                 return 0;
371             array->pushValue(arrayNode);
372 
373             // After a list value, we expect a comma or the end of the list.
374             start = tokenEnd;
375             token = parseToken(start, end, &tokenEnd);
376             if (token == LIST_SEPARATOR) {
377                 start = tokenEnd;
378                 token = parseToken(start, end, &tokenEnd);
379                 if (token == ARRAY_END)
380                     return 0;
381             } else if (token != ARRAY_END) {
382                 // Unexpected value after list value.  Bail out.
383                 return 0;
384             }
385         }
386         if (token != ARRAY_END)
387             return 0;
388         result = array.release();
389         break;
390     }
391     case OBJECT_BEGIN: {
392         RefPtr<InspectorObject> object = InspectorObject::create();
393         start = tokenEnd;
394         token = parseToken(start, end, &tokenEnd);
395         while (token != OBJECT_END) {
396             if (token != STRING)
397                 return 0;
398             String key;
399             if (!decodeString(start + 1, tokenEnd - 1, &key))
400                 return 0;
401             start = tokenEnd;
402 
403             token = parseToken(start, end, &tokenEnd);
404             if (token != OBJECT_PAIR_SEPARATOR)
405                 return 0;
406             start = tokenEnd;
407 
408             RefPtr<InspectorValue> value = buildValue(start, end, &tokenEnd, depth + 1);
409             if (!value)
410                 return 0;
411             object->setValue(key, value);
412             start = tokenEnd;
413 
414             // After a key/value pair, we expect a comma or the end of the
415             // object.
416             token = parseToken(start, end, &tokenEnd);
417             if (token == LIST_SEPARATOR) {
418                 start = tokenEnd;
419                 token = parseToken(start, end, &tokenEnd);
420                  if (token == OBJECT_END)
421                     return 0;
422             } else if (token != OBJECT_END) {
423                 // Unexpected value after last object value.  Bail out.
424                 return 0;
425             }
426         }
427         if (token != OBJECT_END)
428             return 0;
429         result = object.release();
430         break;
431     }
432 
433     default:
434         // We got a token that's not a value.
435         return 0;
436     }
437     *valueTokenEnd = tokenEnd;
438     return result.release();
439 }
440 
escapeChar(UChar c,Vector<UChar> * dst)441 inline bool escapeChar(UChar c, Vector<UChar>* dst)
442 {
443     switch (c) {
444     case '\b': dst->append("\\b", 2); break;
445     case '\f': dst->append("\\f", 2); break;
446     case '\n': dst->append("\\n", 2); break;
447     case '\r': dst->append("\\r", 2); break;
448     case '\t': dst->append("\\t", 2); break;
449     case '\\': dst->append("\\\\", 2); break;
450     case '"': dst->append("\\\"", 2); break;
451     default:
452         return false;
453     }
454     return true;
455 }
456 
doubleQuoteString(const String & str,Vector<UChar> * dst)457 inline void doubleQuoteString(const String& str, Vector<UChar>* dst)
458 {
459     dst->append('"');
460     for (unsigned i = 0; i < str.length(); ++i) {
461         UChar c = str[i];
462         if (!escapeChar(c, dst)) {
463             if (c < 32 || c > 126 || c == '<' || c == '>') {
464                 // 1. Escaping <, > to prevent script execution.
465                 // 2. Technically, we could also pass through c > 126 as UTF8, but this
466                 //    is also optional.  It would also be a pain to implement here.
467                 unsigned int symbol = static_cast<unsigned int>(c);
468                 String symbolCode = String::format("\\u%04X", symbol);
469                 dst->append(symbolCode.characters(), symbolCode.length());
470             } else
471                 dst->append(c);
472         }
473     }
474     dst->append('"');
475 }
476 
477 } // anonymous namespace
478 
asBoolean(bool *) const479 bool InspectorValue::asBoolean(bool*) const
480 {
481     return false;
482 }
483 
asNumber(double *) const484 bool InspectorValue::asNumber(double*) const
485 {
486     return false;
487 }
488 
asNumber(long *) const489 bool InspectorValue::asNumber(long*) const
490 {
491     return false;
492 }
493 
asNumber(int *) const494 bool InspectorValue::asNumber(int*) const
495 {
496     return false;
497 }
498 
asNumber(unsigned long *) const499 bool InspectorValue::asNumber(unsigned long*) const
500 {
501     return false;
502 }
503 
asNumber(unsigned int *) const504 bool InspectorValue::asNumber(unsigned int*) const
505 {
506     return false;
507 }
508 
asString(String *) const509 bool InspectorValue::asString(String*) const
510 {
511     return false;
512 }
513 
asValue(RefPtr<InspectorValue> * output)514 bool InspectorValue::asValue(RefPtr<InspectorValue>* output)
515 {
516     *output = this;
517     return true;
518 }
519 
asObject(RefPtr<InspectorObject> *)520 bool InspectorValue::asObject(RefPtr<InspectorObject>*)
521 {
522     return false;
523 }
524 
asArray(RefPtr<InspectorArray> *)525 bool InspectorValue::asArray(RefPtr<InspectorArray>*)
526 {
527     return false;
528 }
529 
asObject()530 PassRefPtr<InspectorObject> InspectorValue::asObject()
531 {
532     return 0;
533 }
534 
asArray()535 PassRefPtr<InspectorArray> InspectorValue::asArray()
536 {
537     return 0;
538 }
539 
parseJSON(const String & json)540 PassRefPtr<InspectorValue> InspectorValue::parseJSON(const String& json)
541 {
542     const UChar* start = json.characters();
543     const UChar* end = json.characters() + json.length();
544     const UChar *tokenEnd;
545     RefPtr<InspectorValue> value = buildValue(start, end, &tokenEnd, 0);
546     if (!value || tokenEnd != end)
547         return 0;
548     return value.release();
549 }
550 
toJSONString() const551 String InspectorValue::toJSONString() const
552 {
553     Vector<UChar> result;
554     result.reserveCapacity(512);
555     writeJSON(&result);
556     return String(result.data(), result.size());
557 }
558 
writeJSON(Vector<UChar> * output) const559 void InspectorValue::writeJSON(Vector<UChar>* output) const
560 {
561     ASSERT(m_type == TypeNull);
562     output->append(nullString, 4);
563 }
564 
asBoolean(bool * output) const565 bool InspectorBasicValue::asBoolean(bool* output) const
566 {
567     if (type() != TypeBoolean)
568         return false;
569     *output = m_boolValue;
570     return true;
571 }
572 
asNumber(double * output) const573 bool InspectorBasicValue::asNumber(double* output) const
574 {
575     if (type() != TypeNumber)
576         return false;
577     *output = m_doubleValue;
578     return true;
579 }
580 
asNumber(long * output) const581 bool InspectorBasicValue::asNumber(long* output) const
582 {
583     if (type() != TypeNumber)
584         return false;
585     *output = static_cast<long>(m_doubleValue);
586     return true;
587 }
588 
asNumber(int * output) const589 bool InspectorBasicValue::asNumber(int* output) const
590 {
591     if (type() != TypeNumber)
592         return false;
593     *output = static_cast<int>(m_doubleValue);
594     return true;
595 }
596 
asNumber(unsigned long * output) const597 bool InspectorBasicValue::asNumber(unsigned long* output) const
598 {
599     if (type() != TypeNumber)
600         return false;
601     *output = static_cast<unsigned long>(m_doubleValue);
602     return true;
603 }
604 
asNumber(unsigned int * output) const605 bool InspectorBasicValue::asNumber(unsigned int* output) const
606 {
607     if (type() != TypeNumber)
608         return false;
609     *output = static_cast<unsigned int>(m_doubleValue);
610     return true;
611 }
612 
writeJSON(Vector<UChar> * output) const613 void InspectorBasicValue::writeJSON(Vector<UChar>* output) const
614 {
615     ASSERT(type() == TypeBoolean || type() == TypeNumber);
616     if (type() == TypeBoolean) {
617         if (m_boolValue)
618             output->append(trueString, 4);
619         else
620             output->append(falseString, 5);
621     } else if (type() == TypeNumber) {
622         NumberToStringBuffer buffer;
623         DecimalNumber decimal = m_doubleValue;
624         unsigned length = 0;
625         if (decimal.bufferLengthForStringDecimal() > WTF::NumberToStringBufferLength) {
626             // Not enough room for decimal. Use exponential format.
627             if (decimal.bufferLengthForStringExponential() > WTF::NumberToStringBufferLength) {
628                 // Fallback for an abnormal case if it's too little even for exponential.
629                 output->append("NaN", 3);
630                 return;
631             }
632             length = decimal.toStringExponential(buffer, WTF::NumberToStringBufferLength);
633         } else
634             length = decimal.toStringDecimal(buffer, WTF::NumberToStringBufferLength);
635         output->append(buffer, length);
636     }
637 }
638 
asString(String * output) const639 bool InspectorString::asString(String* output) const
640 {
641     *output = m_stringValue;
642     return true;
643 }
644 
writeJSON(Vector<UChar> * output) const645 void InspectorString::writeJSON(Vector<UChar>* output) const
646 {
647     ASSERT(type() == TypeString);
648     doubleQuoteString(m_stringValue, output);
649 }
650 
~InspectorObject()651 InspectorObject::~InspectorObject()
652 {
653 }
654 
asObject(RefPtr<InspectorObject> * output)655 bool InspectorObject::asObject(RefPtr<InspectorObject>* output)
656 {
657     *output = this;
658     return true;
659 }
660 
asObject()661 PassRefPtr<InspectorObject> InspectorObject::asObject()
662 {
663     return this;
664 }
665 
getBoolean(const String & name,bool * output) const666 bool InspectorObject::getBoolean(const String& name, bool* output) const
667 {
668     RefPtr<InspectorValue> value = get(name);
669     if (!value)
670         return false;
671     return value->asBoolean(output);
672 }
673 
getString(const String & name,String * output) const674 bool InspectorObject::getString(const String& name, String* output) const
675 {
676     RefPtr<InspectorValue> value = get(name);
677     if (!value)
678         return false;
679     return value->asString(output);
680 }
681 
getObject(const String & name) const682 PassRefPtr<InspectorObject> InspectorObject::getObject(const String& name) const
683 {
684     PassRefPtr<InspectorValue> value = get(name);
685     if (!value)
686         return 0;
687     return value->asObject();
688 }
689 
getArray(const String & name) const690 PassRefPtr<InspectorArray> InspectorObject::getArray(const String& name) const
691 {
692     PassRefPtr<InspectorValue> value = get(name);
693     if (!value)
694         return 0;
695     return value->asArray();
696 }
697 
get(const String & name) const698 PassRefPtr<InspectorValue> InspectorObject::get(const String& name) const
699 {
700     Dictionary::const_iterator it = m_data.find(name);
701     if (it == m_data.end())
702         return 0;
703     return it->second;
704 }
705 
remove(const String & name)706 void InspectorObject::remove(const String& name)
707 {
708     m_data.remove(name);
709     for (size_t i = 0; i < m_order.size(); ++i) {
710         if (m_order[i] == name) {
711             m_order.remove(i);
712             break;
713         }
714     }
715 }
716 
writeJSON(Vector<UChar> * output) const717 void InspectorObject::writeJSON(Vector<UChar>* output) const
718 {
719     output->append('{');
720     for (size_t i = 0; i < m_order.size(); ++i) {
721         Dictionary::const_iterator it = m_data.find(m_order[i]);
722         ASSERT(it != m_data.end());
723         if (i)
724             output->append(',');
725         doubleQuoteString(it->first, output);
726         output->append(':');
727         it->second->writeJSON(output);
728     }
729     output->append('}');
730 }
731 
InspectorObject()732 InspectorObject::InspectorObject()
733     : InspectorValue(TypeObject)
734     , m_data()
735     , m_order()
736 {
737 }
738 
~InspectorArray()739 InspectorArray::~InspectorArray()
740 {
741 }
742 
asArray(RefPtr<InspectorArray> * output)743 bool InspectorArray::asArray(RefPtr<InspectorArray>* output)
744 {
745     *output = this;
746     return true;
747 }
748 
asArray()749 PassRefPtr<InspectorArray> InspectorArray::asArray()
750 {
751     return this;
752 }
753 
writeJSON(Vector<UChar> * output) const754 void InspectorArray::writeJSON(Vector<UChar>* output) const
755 {
756     output->append('[');
757     for (Vector<RefPtr<InspectorValue> >::const_iterator it = m_data.begin(); it != m_data.end(); ++it) {
758         if (it != m_data.begin())
759             output->append(',');
760         (*it)->writeJSON(output);
761     }
762     output->append(']');
763 }
764 
InspectorArray()765 InspectorArray::InspectorArray()
766     : InspectorValue(TypeArray)
767     , m_data()
768 {
769 }
770 
get(size_t index)771 PassRefPtr<InspectorValue> InspectorArray::get(size_t index)
772 {
773     ASSERT(index < m_data.size());
774     return m_data[index];
775 }
776 
777 } // namespace WebCore
778 
779 #endif // ENABLE(INSPECTOR)
780