summaryrefslogtreecommitdiffstats
path: root/dom/xhr/XMLHttpRequestString.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/xhr/XMLHttpRequestString.cpp')
-rw-r--r--dom/xhr/XMLHttpRequestString.cpp186
1 files changed, 186 insertions, 0 deletions
diff --git a/dom/xhr/XMLHttpRequestString.cpp b/dom/xhr/XMLHttpRequestString.cpp
new file mode 100644
index 0000000000..8f9092243a
--- /dev/null
+++ b/dom/xhr/XMLHttpRequestString.cpp
@@ -0,0 +1,186 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "XMLHttpRequestString.h"
+#include "js/String.h"
+#include "nsISupportsImpl.h"
+#include "mozilla/dom/DOMString.h"
+
+namespace mozilla::dom {
+
+class XMLHttpRequestStringBuffer final {
+ friend class XMLHttpRequestStringSnapshot;
+ friend class XMLHttpRequestStringWriterHelper;
+
+ public:
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(XMLHttpRequestStringBuffer)
+ NS_DECL_OWNINGTHREAD
+
+ XMLHttpRequestStringBuffer() : mMutex("XMLHttpRequestStringBuffer::mMutex") {}
+
+ uint32_t Length() {
+ MutexAutoLock lock(mMutex);
+ return mData.Length();
+ }
+
+ uint32_t UnsafeLength() const MOZ_NO_THREAD_SAFETY_ANALYSIS {
+ return mData.Length();
+ }
+
+ mozilla::Result<mozilla::BulkWriteHandle<char16_t>, nsresult> UnsafeBulkWrite(
+ uint32_t aCapacity) MOZ_NO_THREAD_SAFETY_ANALYSIS {
+ return mData.BulkWrite(aCapacity, UnsafeLength(), false);
+ }
+
+ void Append(const nsAString& aString) {
+ NS_ASSERT_OWNINGTHREAD(XMLHttpRequestStringBuffer);
+
+ MutexAutoLock lock(mMutex);
+ mData.Append(aString);
+ }
+
+ [[nodiscard]] bool GetAsString(nsAString& aString) {
+ MutexAutoLock lock(mMutex);
+ return aString.Assign(mData, mozilla::fallible);
+ }
+
+ size_t SizeOfThis(MallocSizeOf aMallocSizeOf) {
+ MutexAutoLock lock(mMutex);
+ return mData.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
+ }
+
+ [[nodiscard]] bool GetAsString(DOMString& aString, uint32_t aLength) {
+ MutexAutoLock lock(mMutex);
+ MOZ_ASSERT(aLength <= mData.Length());
+
+ // XXX: Bug 1408793 suggests encapsulating the following sequence within
+ // DOMString.
+ nsStringBuffer* buf = nsStringBuffer::FromString(mData);
+ if (buf) {
+ // We have to use SetStringBuffer, because once we release our mutex mData
+ // can get mutated from some other thread while the DOMString is still
+ // alive.
+ aString.SetStringBuffer(buf, aLength);
+ return true;
+ }
+
+ // We can get here if mData is empty. In that case it won't have an
+ // nsStringBuffer....
+ MOZ_ASSERT(mData.IsEmpty());
+ return aString.AsAString().Assign(mData.BeginReading(), aLength,
+ mozilla::fallible);
+ }
+
+ void CreateSnapshot(XMLHttpRequestStringSnapshot& aSnapshot) {
+ MutexAutoLock lock(mMutex);
+ aSnapshot.Set(this, mData.Length());
+ }
+
+ private:
+ ~XMLHttpRequestStringBuffer() = default;
+
+ Mutex mMutex;
+
+ // The following member variable is protected by mutex.
+ nsString mData MOZ_GUARDED_BY(mMutex);
+};
+
+// ---------------------------------------------------------------------------
+// XMLHttpRequestString
+
+XMLHttpRequestString::XMLHttpRequestString()
+ : mBuffer(new XMLHttpRequestStringBuffer()) {}
+
+XMLHttpRequestString::~XMLHttpRequestString() = default;
+
+void XMLHttpRequestString::Truncate() {
+ mBuffer = new XMLHttpRequestStringBuffer();
+}
+
+uint32_t XMLHttpRequestString::Length() const { return mBuffer->Length(); }
+
+void XMLHttpRequestString::Append(const nsAString& aString) {
+ mBuffer->Append(aString);
+}
+
+bool XMLHttpRequestString::GetAsString(nsAString& aString) const {
+ return mBuffer->GetAsString(aString);
+}
+
+size_t XMLHttpRequestString::SizeOfThis(MallocSizeOf aMallocSizeOf) const {
+ return mBuffer->SizeOfThis(aMallocSizeOf);
+}
+
+bool XMLHttpRequestString::IsEmpty() const { return !mBuffer->Length(); }
+
+void XMLHttpRequestString::CreateSnapshot(
+ XMLHttpRequestStringSnapshot& aSnapshot) {
+ mBuffer->CreateSnapshot(aSnapshot);
+}
+
+// ---------------------------------------------------------------------------
+// XMLHttpRequestStringSnapshot
+
+XMLHttpRequestStringSnapshot::XMLHttpRequestStringSnapshot()
+ : mLength(0), mVoid(false) {}
+
+XMLHttpRequestStringSnapshot::~XMLHttpRequestStringSnapshot() = default;
+
+void XMLHttpRequestStringSnapshot::ResetInternal(bool aIsVoid) {
+ mBuffer = nullptr;
+ mLength = 0;
+ mVoid = aIsVoid;
+}
+
+void XMLHttpRequestStringSnapshot::Set(XMLHttpRequestStringBuffer* aBuffer,
+ uint32_t aLength) {
+ MOZ_ASSERT(aBuffer);
+ MOZ_ASSERT(aLength <= aBuffer->UnsafeLength());
+
+ mBuffer = aBuffer;
+ mLength = aLength;
+ mVoid = false;
+}
+
+bool XMLHttpRequestStringSnapshot::GetAsString(DOMString& aString) const {
+ if (mBuffer) {
+ MOZ_ASSERT(!mVoid);
+ return mBuffer->GetAsString(aString, mLength);
+ }
+
+ if (mVoid) {
+ aString.SetNull();
+ }
+
+ return true;
+}
+
+JSString* XMLHttpRequestStringSnapshot::GetAsJSStringCopy(
+ JSContext* aCx) const {
+ MutexAutoLock lock(mBuffer->mMutex);
+ return JS_NewUCStringCopyN(aCx, mBuffer->mData.BeginReading(),
+ mBuffer->mData.Length());
+}
+
+// ---------------------------------------------------------------------------
+// XMLHttpRequestStringWriterHelper
+
+XMLHttpRequestStringWriterHelper::XMLHttpRequestStringWriterHelper(
+ XMLHttpRequestString& aString)
+ : mBuffer(aString.mBuffer), mLock(aString.mBuffer->mMutex) {}
+
+XMLHttpRequestStringWriterHelper::~XMLHttpRequestStringWriterHelper() = default;
+
+uint32_t XMLHttpRequestStringWriterHelper::Length() const {
+ return mBuffer->UnsafeLength();
+}
+
+mozilla::Result<mozilla::BulkWriteHandle<char16_t>, nsresult>
+XMLHttpRequestStringWriterHelper::BulkWrite(uint32_t aCapacity) {
+ return mBuffer->UnsafeBulkWrite(aCapacity);
+}
+
+} // namespace mozilla::dom