nsStructuredCloneContainer.cpp (4097B)
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 "nsStructuredCloneContainer.h" 8 9 #include <cstddef> 10 11 #include "ErrorList.h" 12 #include "js/RootingAPI.h" 13 #include "js/StructuredClone.h" 14 #include "js/Value.h" 15 #include "mozilla/Assertions.h" 16 #include "mozilla/Base64.h" 17 #include "mozilla/CheckedInt.h" 18 #include "mozilla/DebugOnly.h" 19 #include "mozilla/ErrorResult.h" 20 #include "mozilla/fallible.h" 21 #include "nsCOMPtr.h" 22 #include "nsDebug.h" 23 #include "nsError.h" 24 #include "nsIVariant.h" 25 #include "nsIXPConnect.h" 26 #include "nsString.h" 27 #include "nscore.h" 28 29 using namespace mozilla; 30 using namespace mozilla::dom; 31 32 NS_IMPL_ADDREF(nsStructuredCloneContainer) 33 NS_IMPL_RELEASE(nsStructuredCloneContainer) 34 35 NS_INTERFACE_MAP_BEGIN(nsStructuredCloneContainer) 36 NS_INTERFACE_MAP_ENTRY(nsIStructuredCloneContainer) 37 NS_INTERFACE_MAP_ENTRY(nsISupports) 38 NS_INTERFACE_MAP_END 39 40 nsStructuredCloneContainer::nsStructuredCloneContainer() : mVersion(0) {} 41 nsStructuredCloneContainer::nsStructuredCloneContainer(uint32_t aVersion) 42 : mVersion(aVersion) {} 43 44 nsStructuredCloneContainer::~nsStructuredCloneContainer() = default; 45 46 NS_IMETHODIMP 47 nsStructuredCloneContainer::InitFromJSVal(JS::Handle<JS::Value> aData, 48 JSContext* aCx) { 49 if (DataLength()) { 50 return NS_ERROR_FAILURE; 51 } 52 53 ErrorResult rv; 54 Write(aCx, aData, rv); 55 if (NS_WARN_IF(rv.Failed())) { 56 // XXX propagate the error message as well. 57 // We cannot StealNSResult because we threw a DOM exception. 58 rv.SuppressException(); 59 return NS_ERROR_DOM_DATA_CLONE_ERR; 60 } 61 62 mVersion = JS_STRUCTURED_CLONE_VERSION; 63 return NS_OK; 64 } 65 66 NS_IMETHODIMP 67 nsStructuredCloneContainer::InitFromBase64(const nsAString& aData, 68 uint32_t aFormatVersion) { 69 if (DataLength()) { 70 return NS_ERROR_FAILURE; 71 } 72 73 NS_ConvertUTF16toUTF8 data(aData); 74 75 nsAutoCString binaryData; 76 nsresult rv = Base64Decode(data, binaryData); 77 NS_ENSURE_SUCCESS(rv, rv); 78 79 if (!CopyExternalData(binaryData.get(), binaryData.Length())) { 80 return NS_ERROR_OUT_OF_MEMORY; 81 } 82 83 mVersion = aFormatVersion; 84 return NS_OK; 85 } 86 87 nsresult nsStructuredCloneContainer::DeserializeToJsval( 88 JSContext* aCx, JS::MutableHandle<JS::Value> aValue) { 89 aValue.setNull(); 90 JS::Rooted<JS::Value> jsStateObj(aCx); 91 92 ErrorResult rv; 93 Read(aCx, &jsStateObj, rv); 94 if (NS_WARN_IF(rv.Failed())) { 95 // XXX propagate the error message as well. 96 // We cannot StealNSResult because we threw a DOM exception. 97 rv.SuppressException(); 98 return NS_ERROR_DOM_DATA_CLONE_ERR; 99 } 100 101 aValue.set(jsStateObj); 102 return NS_OK; 103 } 104 105 NS_IMETHODIMP 106 nsStructuredCloneContainer::GetDataAsBase64(nsAString& aOut) { 107 aOut.Truncate(); 108 109 if (!DataLength()) { 110 return NS_ERROR_FAILURE; 111 } 112 113 if (HasClonedDOMObjects()) { 114 return NS_ERROR_FAILURE; 115 } 116 117 auto iter = Data().Start(); 118 size_t size = Data().Size(); 119 CheckedInt<nsAutoCString::size_type> sizeCheck(size); 120 if (!sizeCheck.isValid()) { 121 return NS_ERROR_FAILURE; 122 } 123 124 nsAutoCString binaryData; 125 if (!binaryData.SetLength(size, fallible)) { 126 return NS_ERROR_OUT_OF_MEMORY; 127 } 128 129 DebugOnly<bool> res = Data().ReadBytes(iter, binaryData.BeginWriting(), size); 130 MOZ_ASSERT(res); 131 132 nsresult rv = Base64Encode(binaryData, aOut); 133 if (NS_WARN_IF(NS_FAILED(rv))) { 134 return rv; 135 } 136 137 return NS_OK; 138 } 139 140 NS_IMETHODIMP 141 nsStructuredCloneContainer::GetSerializedNBytes(uint64_t* aSize) { 142 NS_ENSURE_ARG_POINTER(aSize); 143 144 if (!DataLength()) { 145 return NS_ERROR_FAILURE; 146 } 147 148 *aSize = DataLength(); 149 return NS_OK; 150 } 151 152 NS_IMETHODIMP 153 nsStructuredCloneContainer::GetFormatVersion(uint32_t* aFormatVersion) { 154 NS_ENSURE_ARG_POINTER(aFormatVersion); 155 156 if (!DataLength()) { 157 return NS_ERROR_FAILURE; 158 } 159 160 *aFormatVersion = mVersion; 161 return NS_OK; 162 }