XMLHttpRequestString.cpp (5558B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "XMLHttpRequestString.h" 8 9 #include "js/String.h" 10 #include "mozilla/dom/DOMString.h" 11 #include "nsISupportsImpl.h" 12 13 namespace mozilla::dom { 14 15 class XMLHttpRequestStringBuffer final { 16 friend class XMLHttpRequestStringSnapshot; 17 friend class XMLHttpRequestStringWriterHelper; 18 19 public: 20 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(XMLHttpRequestStringBuffer) 21 NS_DECL_OWNINGTHREAD 22 23 XMLHttpRequestStringBuffer() : mMutex("XMLHttpRequestStringBuffer::mMutex") {} 24 25 uint32_t Length() { 26 MutexAutoLock lock(mMutex); 27 return mData.Length(); 28 } 29 30 uint32_t UnsafeLength() const MOZ_NO_THREAD_SAFETY_ANALYSIS { 31 return mData.Length(); 32 } 33 34 mozilla::Result<mozilla::BulkWriteHandle<char16_t>, nsresult> UnsafeBulkWrite( 35 uint32_t aCapacity) MOZ_NO_THREAD_SAFETY_ANALYSIS { 36 return mData.BulkWrite(aCapacity, UnsafeLength(), false); 37 } 38 39 void Append(const nsAString& aString) { 40 NS_ASSERT_OWNINGTHREAD(XMLHttpRequestStringBuffer); 41 42 MutexAutoLock lock(mMutex); 43 mData.Append(aString); 44 } 45 46 [[nodiscard]] bool GetAsString(nsAString& aString) { 47 MutexAutoLock lock(mMutex); 48 return aString.Assign(mData, mozilla::fallible); 49 } 50 51 size_t SizeOfThis(MallocSizeOf aMallocSizeOf) { 52 MutexAutoLock lock(mMutex); 53 return mData.SizeOfExcludingThisIfUnshared(aMallocSizeOf); 54 } 55 56 [[nodiscard]] bool GetAsString(DOMString& aString, uint32_t aLength) { 57 MutexAutoLock lock(mMutex); 58 MOZ_ASSERT(aLength <= mData.Length()); 59 60 // XXX: Bug 1408793 suggests encapsulating the following sequence within 61 // DOMString. 62 if (StringBuffer* buf = mData.GetStringBuffer()) { 63 // We have to use SetStringBuffer, because once we release our mutex mData 64 // can get mutated from some other thread while the DOMString is still 65 // alive. 66 aString.SetStringBuffer(buf, aLength); 67 return true; 68 } 69 70 // We can get here if mData is empty. In that case it won't have an 71 // nsStringBuffer.... 72 MOZ_ASSERT(mData.IsEmpty()); 73 return aString.AsAString().Assign(mData.BeginReading(), aLength, 74 mozilla::fallible); 75 } 76 77 void CreateSnapshot(XMLHttpRequestStringSnapshot& aSnapshot) { 78 MutexAutoLock lock(mMutex); 79 aSnapshot.Set(this, mData.Length()); 80 } 81 82 private: 83 ~XMLHttpRequestStringBuffer() = default; 84 85 Mutex mMutex; 86 87 // The following member variable is protected by mutex. 88 nsString mData MOZ_GUARDED_BY(mMutex); 89 }; 90 91 // --------------------------------------------------------------------------- 92 // XMLHttpRequestString 93 94 XMLHttpRequestString::XMLHttpRequestString() 95 : mBuffer(new XMLHttpRequestStringBuffer()) {} 96 97 XMLHttpRequestString::~XMLHttpRequestString() = default; 98 99 void XMLHttpRequestString::Truncate() { 100 mBuffer = new XMLHttpRequestStringBuffer(); 101 } 102 103 uint32_t XMLHttpRequestString::Length() const { return mBuffer->Length(); } 104 105 void XMLHttpRequestString::Append(const nsAString& aString) { 106 mBuffer->Append(aString); 107 } 108 109 bool XMLHttpRequestString::GetAsString(nsAString& aString) const { 110 return mBuffer->GetAsString(aString); 111 } 112 113 size_t XMLHttpRequestString::SizeOfThis(MallocSizeOf aMallocSizeOf) const { 114 return mBuffer->SizeOfThis(aMallocSizeOf); 115 } 116 117 bool XMLHttpRequestString::IsEmpty() const { return !mBuffer->Length(); } 118 119 void XMLHttpRequestString::CreateSnapshot( 120 XMLHttpRequestStringSnapshot& aSnapshot) { 121 mBuffer->CreateSnapshot(aSnapshot); 122 } 123 124 // --------------------------------------------------------------------------- 125 // XMLHttpRequestStringSnapshot 126 127 XMLHttpRequestStringSnapshot::XMLHttpRequestStringSnapshot() 128 : mLength(0), mVoid(false) {} 129 130 XMLHttpRequestStringSnapshot::~XMLHttpRequestStringSnapshot() = default; 131 132 void XMLHttpRequestStringSnapshot::ResetInternal(bool aIsVoid) { 133 mBuffer = nullptr; 134 mLength = 0; 135 mVoid = aIsVoid; 136 } 137 138 void XMLHttpRequestStringSnapshot::Set(XMLHttpRequestStringBuffer* aBuffer, 139 uint32_t aLength) { 140 MOZ_ASSERT(aBuffer); 141 MOZ_ASSERT(aLength <= aBuffer->UnsafeLength()); 142 143 mBuffer = aBuffer; 144 mLength = aLength; 145 mVoid = false; 146 } 147 148 bool XMLHttpRequestStringSnapshot::GetAsString(DOMString& aString) const { 149 if (mBuffer) { 150 MOZ_ASSERT(!mVoid); 151 return mBuffer->GetAsString(aString, mLength); 152 } 153 154 if (mVoid) { 155 aString.SetNull(); 156 } 157 158 return true; 159 } 160 161 JSString* XMLHttpRequestStringSnapshot::GetAsJSStringCopy( 162 JSContext* aCx) const { 163 MutexAutoLock lock(mBuffer->mMutex); 164 return JS_NewUCStringCopyN(aCx, mBuffer->mData.BeginReading(), 165 mBuffer->mData.Length()); 166 } 167 168 // --------------------------------------------------------------------------- 169 // XMLHttpRequestStringWriterHelper 170 171 XMLHttpRequestStringWriterHelper::XMLHttpRequestStringWriterHelper( 172 XMLHttpRequestString& aString) 173 : mBuffer(aString.mBuffer), mLock(aString.mBuffer->mMutex) {} 174 175 XMLHttpRequestStringWriterHelper::~XMLHttpRequestStringWriterHelper() = default; 176 177 uint32_t XMLHttpRequestStringWriterHelper::Length() const { 178 return mBuffer->UnsafeLength(); 179 } 180 181 mozilla::Result<mozilla::BulkWriteHandle<char16_t>, nsresult> 182 XMLHttpRequestStringWriterHelper::BulkWrite(uint32_t aCapacity) { 183 return mBuffer->UnsafeBulkWrite(aCapacity); 184 } 185 186 } // namespace mozilla::dom