Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "JSStreamWriter.h"
8 #include "mozilla/ArrayUtils.h" // for ArrayLength
9 #include "nsDataHashtable.h"
10 #include "nsString.h"
11 #include "nsTArray.h"
12 #include "nsUTF8Utils.h"
14 #if _MSC_VER
15 #define snprintf _snprintf
16 #endif
18 #define ARRAY (void*)1
19 #define OBJECT (void*)2
21 // Escape a UTF8 string to a stream. When an illegal encoding
22 // is found it will insert "INVALID" and the function will return.
23 static void EscapeToStream(std::ostream& stream, const char* str) {
24 stream << "\"";
26 size_t len = strlen(str);
27 const char* end = &str[len];
28 while (str < end) {
29 bool err;
30 const char* utf8CharStart = str;
31 uint32_t ucs4Char = UTF8CharEnumerator::NextChar(&str, end, &err);
33 if (err) {
34 // Encoding error
35 stream << "INVALID\"";
36 return;
37 }
39 // See http://www.ietf.org/rfc/rfc4627.txt?number=4627
40 // characters that must be escaped: quotation mark,
41 // reverse solidus, and the control characters
42 // (U+0000 through U+001F).
43 if (ucs4Char == '\"') {
44 stream << "\\\"";
45 } else if (ucs4Char == '\\') {
46 stream << "\\\\";
47 } else if (ucs4Char > 0xFF) {
48 char16_t chr[2];
49 ConvertUTF8toUTF16 encoder(chr);
50 encoder.write(utf8CharStart, uint32_t(str-utf8CharStart));
51 char escChar[13];
52 snprintf(escChar, mozilla::ArrayLength(escChar), "\\u%04X\\u%04X", chr[0], chr[1]);
53 stream << escChar;
54 } else if (ucs4Char < 0x1F || ucs4Char > 0xFF) {
55 char escChar[7];
56 snprintf(escChar, mozilla::ArrayLength(escChar), "\\u%04X", ucs4Char);
57 stream << escChar;
58 } else {
59 stream << char(ucs4Char);
60 }
61 }
62 stream << "\"";
63 }
65 JSStreamWriter::JSStreamWriter(std::ostream& aStream)
66 : mStream(aStream)
67 , mNeedsComma(false)
68 , mNeedsName(false)
69 { }
71 JSStreamWriter::~JSStreamWriter()
72 {
73 MOZ_ASSERT(mStack.GetSize() == 0);
74 }
76 void
77 JSStreamWriter::BeginObject()
78 {
79 MOZ_ASSERT(!mNeedsName);
80 if (mNeedsComma && mStack.Peek() == ARRAY) {
81 mStream << ",";
82 }
83 mStream << "{";
84 mNeedsComma = false;
85 mNeedsName = true;
86 mStack.Push(OBJECT);
87 }
89 void
90 JSStreamWriter::EndObject()
91 {
92 MOZ_ASSERT(mStack.Peek() == OBJECT);
93 mStream << "}";
94 mNeedsComma = true;
95 mNeedsName = false;
96 mStack.Pop();
97 if (mStack.GetSize() > 0 && mStack.Peek() == OBJECT) {
98 mNeedsName = true;
99 }
100 }
102 void
103 JSStreamWriter::BeginArray()
104 {
105 MOZ_ASSERT(!mNeedsName);
106 if (mNeedsComma && mStack.Peek() == ARRAY) {
107 mStream << ",";
108 }
109 mStream << "[";
110 mNeedsComma = false;
111 mStack.Push(ARRAY);
112 }
114 void
115 JSStreamWriter::EndArray()
116 {
117 MOZ_ASSERT(!mNeedsName);
118 MOZ_ASSERT(mStack.Peek() == ARRAY);
119 mStream << "]";
120 mNeedsComma = true;
121 mStack.Pop();
122 if (mStack.GetSize() > 0 && mStack.Peek() == OBJECT) {
123 mNeedsName = true;
124 }
125 }
127 void
128 JSStreamWriter::Name(const char *aName)
129 {
130 MOZ_ASSERT(mNeedsName);
131 if (mNeedsComma && mStack.Peek() == OBJECT) {
132 mStream << ",";
133 }
134 EscapeToStream(mStream, aName);
135 mStream << ":";
136 mNeedsName = false;
137 }
139 void
140 JSStreamWriter::Value(int aValue)
141 {
142 MOZ_ASSERT(!mNeedsName);
143 if (mNeedsComma && mStack.Peek() == ARRAY) {
144 mStream << ",";
145 }
146 mStream << aValue;
147 mNeedsComma = true;
148 if (mStack.Peek() == OBJECT) {
149 mNeedsName = true;
150 }
151 }
153 void
154 JSStreamWriter::Value(double aValue)
155 {
156 MOZ_ASSERT(!mNeedsName);
157 if (mNeedsComma && mStack.Peek() == ARRAY) {
158 mStream << ",";
159 }
160 mStream.precision(18);
161 mStream << aValue;
162 mNeedsComma = true;
163 if (mStack.Peek() == OBJECT) {
164 mNeedsName = true;
165 }
166 }
168 void
169 JSStreamWriter::Value(const char *aValue)
170 {
171 MOZ_ASSERT(!mNeedsName);
172 if (mNeedsComma && mStack.Peek() == ARRAY) {
173 mStream << ",";
174 }
175 EscapeToStream(mStream, aValue);
176 mNeedsComma = true;
177 if (mStack.Peek() == OBJECT) {
178 mNeedsName = true;
179 }
180 }