InputStreamUtils.cpp (7174B)
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 "InputStreamUtils.h" 8 9 #include "nsIIPCSerializableInputStream.h" 10 11 #include "mozilla/Assertions.h" 12 #include "mozilla/dom/File.h" 13 #include "mozilla/dom/quota/DecryptingInputStream_impl.h" 14 #include "mozilla/dom/quota/IPCStreamCipherStrategy.h" 15 #include "mozilla/ipc/DataPipe.h" 16 #include "mozilla/InputStreamLengthHelper.h" 17 #include "mozilla/RemoteLazyInputStream.h" 18 #include "mozilla/RemoteLazyInputStreamChild.h" 19 #include "mozilla/RemoteLazyInputStreamStorage.h" 20 #include "mozilla/SlicedInputStream.h" 21 #include "mozilla/InputStreamLengthWrapper.h" 22 #include "nsBufferedStreams.h" 23 #include "nsComponentManagerUtils.h" 24 #include "nsDebug.h" 25 #include "nsFileStreams.h" 26 #include "nsIAsyncInputStream.h" 27 #include "nsIAsyncOutputStream.h" 28 #include "nsID.h" 29 #include "nsIMIMEInputStream.h" 30 #include "nsIMultiplexInputStream.h" 31 #include "nsIPipe.h" 32 #include "nsMIMEInputStream.h" 33 #include "nsMultiplexInputStream.h" 34 #include "nsNetCID.h" 35 #include "nsStreamUtils.h" 36 #include "nsStringStream.h" 37 #include "nsXULAppAPI.h" 38 39 using namespace mozilla; 40 using namespace mozilla::dom; 41 42 namespace mozilla { 43 namespace ipc { 44 45 void InputStreamHelper::SerializedComplexity(nsIInputStream* aInputStream, 46 uint32_t aMaxSize, 47 uint32_t* aSizeUsed, 48 uint32_t* aPipes, 49 uint32_t* aTransferables) { 50 MOZ_ASSERT(aInputStream); 51 52 nsCOMPtr<nsIIPCSerializableInputStream> serializable = 53 do_QueryInterface(aInputStream); 54 if (!serializable) { 55 MOZ_CRASH("Input stream is not serializable!"); 56 } 57 58 serializable->SerializedComplexity(aMaxSize, aSizeUsed, aPipes, 59 aTransferables); 60 } 61 62 void InputStreamHelper::SerializeInputStream(nsIInputStream* aInputStream, 63 InputStreamParams& aParams, 64 uint32_t aMaxSize, 65 uint32_t* aSizeUsed) { 66 MOZ_ASSERT(aInputStream); 67 68 nsCOMPtr<nsIIPCSerializableInputStream> serializable = 69 do_QueryInterface(aInputStream); 70 if (!serializable) { 71 MOZ_CRASH("Input stream is not serializable!"); 72 } 73 74 serializable->Serialize(aParams, aMaxSize, aSizeUsed); 75 76 if (aParams.type() == InputStreamParams::T__None) { 77 MOZ_CRASH("Serialize failed!"); 78 } 79 } 80 81 void InputStreamHelper::SerializeInputStreamAsPipe(nsIInputStream* aInputStream, 82 InputStreamParams& aParams) { 83 MOZ_ASSERT(aInputStream); 84 85 // Let's try to take the length using InputStreamLengthHelper. If the length 86 // cannot be taken synchronously, and its length is needed, the stream needs 87 // to be fully copied in memory on the deserialization side. 88 int64_t length; 89 if (!InputStreamLengthHelper::GetSyncLength(aInputStream, &length)) { 90 length = -1; 91 } 92 93 RefPtr<DataPipeSender> sender; 94 RefPtr<DataPipeReceiver> receiver; 95 nsresult rv = NewDataPipe(kDefaultDataPipeCapacity, getter_AddRefs(sender), 96 getter_AddRefs(receiver)); 97 if (NS_WARN_IF(NS_FAILED(rv))) { 98 return; 99 } 100 101 nsCOMPtr<nsIEventTarget> target = 102 do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID); 103 104 rv = 105 NS_AsyncCopy(aInputStream, sender, target, NS_ASYNCCOPY_VIA_WRITESEGMENTS, 106 kDefaultDataPipeCapacity, nullptr, nullptr); 107 if (NS_WARN_IF(NS_FAILED(rv))) { 108 return; 109 } 110 111 aParams = DataPipeReceiverStreamParams(WrapNotNull(receiver)); 112 if (length != -1) { 113 aParams = InputStreamLengthWrapperParams(aParams, length, false); 114 } 115 } 116 117 already_AddRefed<nsIInputStream> InputStreamHelper::DeserializeInputStream( 118 const InputStreamParams& aParams) { 119 if (aParams.type() == InputStreamParams::TRemoteLazyInputStreamParams) { 120 const RemoteLazyInputStreamParams& params = 121 aParams.get_RemoteLazyInputStreamParams(); 122 123 // If the RemoteLazyInputStream already has an internal stream, unwrap it. 124 // This is required as some code unfortunately depends on the precise 125 // topology of received streams, and cannot handle being passed a 126 // `RemoteLazyInputStream` in the parent process. 127 nsCOMPtr<nsIInputStream> innerStream; 128 if (XRE_IsParentProcess() && 129 NS_SUCCEEDED( 130 params.stream()->TakeInternalStream(getter_AddRefs(innerStream)))) { 131 return innerStream.forget(); 132 } 133 return do_AddRef(params.stream().get()); 134 } 135 136 if (aParams.type() == InputStreamParams::TDataPipeReceiverStreamParams) { 137 const DataPipeReceiverStreamParams& pipeParams = 138 aParams.get_DataPipeReceiverStreamParams(); 139 return do_AddRef(pipeParams.pipe().get()); 140 } 141 142 nsCOMPtr<nsIIPCSerializableInputStream> serializable; 143 144 switch (aParams.type()) { 145 case InputStreamParams::TStringInputStreamParams: { 146 nsCOMPtr<nsIInputStream> stream; 147 NS_NewCStringInputStream(getter_AddRefs(stream), ""_ns); 148 serializable = do_QueryInterface(stream); 149 } break; 150 151 case InputStreamParams::TFileInputStreamParams: { 152 nsCOMPtr<nsIFileInputStream> stream; 153 nsFileInputStream::Create(NS_GET_IID(nsIFileInputStream), 154 getter_AddRefs(stream)); 155 serializable = do_QueryInterface(stream); 156 } break; 157 158 case InputStreamParams::TBufferedInputStreamParams: { 159 nsCOMPtr<nsIBufferedInputStream> stream; 160 nsBufferedInputStream::Create(NS_GET_IID(nsIBufferedInputStream), 161 getter_AddRefs(stream)); 162 serializable = do_QueryInterface(stream); 163 } break; 164 165 case InputStreamParams::TMIMEInputStreamParams: { 166 nsCOMPtr<nsIMIMEInputStream> stream; 167 nsMIMEInputStreamConstructor(NS_GET_IID(nsIMIMEInputStream), 168 getter_AddRefs(stream)); 169 serializable = do_QueryInterface(stream); 170 } break; 171 172 case InputStreamParams::TMultiplexInputStreamParams: { 173 serializable = new nsMultiplexInputStream(); 174 } break; 175 176 case InputStreamParams::TSlicedInputStreamParams: 177 serializable = new SlicedInputStream(); 178 break; 179 180 case InputStreamParams::TInputStreamLengthWrapperParams: 181 serializable = new InputStreamLengthWrapper(); 182 break; 183 184 case InputStreamParams::TEncryptedFileInputStreamParams: 185 serializable = new dom::quota::DecryptingInputStream< 186 dom::quota::IPCStreamCipherStrategy>(); 187 break; 188 189 default: 190 MOZ_ASSERT(false, "Unknown params!"); 191 return nullptr; 192 } 193 194 MOZ_ASSERT(serializable); 195 196 if (!serializable->Deserialize(aParams)) { 197 MOZ_ASSERT(false, "Deserialize failed!"); 198 return nullptr; 199 } 200 201 nsCOMPtr<nsIInputStream> stream = do_QueryInterface(serializable); 202 MOZ_ASSERT(stream); 203 204 return stream.forget(); 205 } 206 207 } // namespace ipc 208 } // namespace mozilla