already_AddRefed<InternalResponse> InternalResponse::Clone() { nsRefPtr<InternalResponse> clone = CreateIncompleteCopy(); clone->mHeaders = new InternalHeaders(*mHeaders); if (mWrappedResponse) { clone->mWrappedResponse = mWrappedResponse->Clone(); MOZ_ASSERT(!mBody); return clone.forget(); } if (!mBody) { return clone.forget(); } nsCOMPtr<nsIInputStream> clonedBody; nsCOMPtr<nsIInputStream> replacementBody; nsresult rv = NS_CloneInputStream(mBody, getter_AddRefs(clonedBody), getter_AddRefs(replacementBody)); if (NS_WARN_IF(NS_FAILED(rv))) { return nullptr; } clone->mBody.swap(clonedBody); if (replacementBody) { mBody.swap(replacementBody); } return clone.forget(); }
TEST(CloneInputStream, NonCloneableInput_NoFallback) { nsTArray<char> inputData; testing::CreateData(4 * 1024, inputData); nsDependentCSubstring inputString(inputData.Elements(), inputData.Length()); nsCOMPtr<nsIInputStream> base; nsresult rv = NS_NewCStringInputStream(getter_AddRefs(base), inputString); ASSERT_TRUE(NS_SUCCEEDED(rv)); // Take advantage of nsBufferedInputStream being non-cloneable right // now. If this changes in the future, then we need a different stream // type in this test. nsCOMPtr<nsIInputStream> stream; rv = NS_NewBufferedInputStream(getter_AddRefs(stream), base, 4096); ASSERT_TRUE(NS_SUCCEEDED(rv)); nsCOMPtr<nsICloneableInputStream> cloneable = do_QueryInterface(stream); ASSERT_TRUE(cloneable == nullptr); nsCOMPtr<nsIInputStream> clone; rv = NS_CloneInputStream(stream, getter_AddRefs(clone)); ASSERT_TRUE(NS_FAILED(rv)); ASSERT_TRUE(clone == nullptr); testing::ConsumeAndValidateStream(stream, inputString); }
TEST(CloneInputStream, InvalidInput) { nsCOMPtr<nsIInputStream> clone; nsresult rv = NS_CloneInputStream(nullptr, getter_AddRefs(clone)); ASSERT_TRUE(NS_FAILED(rv)); ASSERT_FALSE(clone); }
TEST(CloneInputStream, CloneMultiplexStreamPartial) { nsCOMPtr<nsIMultiplexInputStream> stream = do_CreateInstance("@mozilla.org/io/multiplex-input-stream;1"); ASSERT_TRUE(stream); nsTArray<char> inputData; testing::CreateData(1024, inputData); for (uint32_t i = 0; i < 2; ++i) { nsCString inputString(inputData.Elements(), inputData.Length()); nsCOMPtr<nsIInputStream> base; nsresult rv = NS_NewCStringInputStream(getter_AddRefs(base), inputString); ASSERT_TRUE(NS_SUCCEEDED(rv)); rv = stream->AppendStream(base); ASSERT_TRUE(NS_SUCCEEDED(rv)); } // Fail when first stream read, but second hasn't been started. nsAutoPtr<char> buffer(new char[1024]); uint32_t read; nsresult rv = stream->Read(buffer, 1024, &read); ASSERT_TRUE(NS_SUCCEEDED(rv)); nsCOMPtr<nsIInputStream> clone; rv = NS_CloneInputStream(stream, getter_AddRefs(clone)); ASSERT_TRUE(NS_FAILED(rv)); // Fail after beginning read of second stream. rv = stream->Read(buffer, 512, &read); ASSERT_TRUE(NS_SUCCEEDED(rv) && read == 512); rv = NS_CloneInputStream(stream, getter_AddRefs(clone)); ASSERT_TRUE(NS_FAILED(rv)); // Fail at the end. nsAutoCString consumed; rv = NS_ConsumeStream(stream, UINT32_MAX, consumed); ASSERT_TRUE(NS_SUCCEEDED(rv)); rv = NS_CloneInputStream(stream, getter_AddRefs(clone)); ASSERT_TRUE(NS_FAILED(rv)); }
TEST(CloneInputStream, CloneMultiplexStream) { nsCOMPtr<nsIMultiplexInputStream> stream = do_CreateInstance("@mozilla.org/io/multiplex-input-stream;1"); ASSERT_TRUE(stream); nsTArray<char> inputData; testing::CreateData(1024, inputData); for (uint32_t i = 0; i < 2; ++i) { nsCString inputString(inputData.Elements(), inputData.Length()); nsCOMPtr<nsIInputStream> base; nsresult rv = NS_NewCStringInputStream(getter_AddRefs(base), inputString); ASSERT_TRUE(NS_SUCCEEDED(rv)); rv = stream->AppendStream(base); ASSERT_TRUE(NS_SUCCEEDED(rv)); } // Unread stream should clone successfully. nsTArray<char> doubled; doubled.AppendElements(inputData); doubled.AppendElements(inputData); nsCOMPtr<nsIInputStream> clone; nsresult rv = NS_CloneInputStream(stream, getter_AddRefs(clone)); ASSERT_TRUE(NS_SUCCEEDED(rv)); testing::ConsumeAndValidateStream(clone, doubled); // Stream that has been read should fail. nsAutoPtr<char> buffer(new char[512]); uint32_t read; rv = stream->Read(buffer, 512, &read); ASSERT_TRUE(NS_SUCCEEDED(rv)); nsCOMPtr<nsIInputStream> clone2; rv = NS_CloneInputStream(stream, getter_AddRefs(clone2)); ASSERT_TRUE(NS_FAILED(rv)); }
TEST(CloneInputStream, CloneableInput) { nsTArray<char> inputData; testing::CreateData(4 * 1024, inputData); nsDependentCSubstring inputString(inputData.Elements(), inputData.Length()); nsCOMPtr<nsIInputStream> stream; nsresult rv = NS_NewCStringInputStream(getter_AddRefs(stream), inputString); ASSERT_TRUE(NS_SUCCEEDED(rv)); nsCOMPtr<nsIInputStream> clone; rv = NS_CloneInputStream(stream, getter_AddRefs(clone)); ASSERT_TRUE(NS_SUCCEEDED(rv)); testing::ConsumeAndValidateStream(stream, inputString); testing::ConsumeAndValidateStream(clone, inputString); }
TEST(CloneInputStream, NonCloneableInput_Fallback) { nsTArray<char> inputData; testing::CreateData(4 * 1024, inputData); nsDependentCSubstring inputString(inputData.Elements(), inputData.Length()); nsCOMPtr<nsIInputStream> base; nsresult rv = NS_NewCStringInputStream(getter_AddRefs(base), inputString); ASSERT_TRUE(NS_SUCCEEDED(rv)); // Take advantage of nsBufferedInputStream being non-cloneable right // now. If this changes in the future, then we need a different stream // type in this test. nsCOMPtr<nsIInputStream> stream; rv = NS_NewBufferedInputStream(getter_AddRefs(stream), base, 4096); ASSERT_TRUE(NS_SUCCEEDED(rv)); nsCOMPtr<nsICloneableInputStream> cloneable = do_QueryInterface(stream); ASSERT_TRUE(cloneable == nullptr); nsCOMPtr<nsIInputStream> clone; nsCOMPtr<nsIInputStream> replacement; rv = NS_CloneInputStream(stream, getter_AddRefs(clone), getter_AddRefs(replacement)); ASSERT_TRUE(NS_SUCCEEDED(rv)); ASSERT_TRUE(clone != nullptr); ASSERT_TRUE(replacement != nullptr); ASSERT_TRUE(stream.get() != replacement.get()); ASSERT_TRUE(clone.get() != replacement.get()); stream = replacement.forget(); // The stream is being copied asynchronously on the STS event target. Spin // a yield loop here until the data is available. Yes, this is a bit hacky, // but AFAICT, gtest does not support async test completion. uint64_t available; do { mozilla::unused << PR_Sleep(PR_INTERVAL_NO_WAIT); rv = stream->Available(&available); ASSERT_TRUE(NS_SUCCEEDED(rv)); } while(available < inputString.Length()); testing::ConsumeAndValidateStream(stream, inputString); testing::ConsumeAndValidateStream(clone, inputString); }
void BlobImplStream::GetInternalStream(nsIInputStream** aStream, ErrorResult& aRv) { nsCOMPtr<nsIInputStream> clonedStream; nsCOMPtr<nsIInputStream> replacementStream; aRv = NS_CloneInputStream(mInputStream, getter_AddRefs(clonedStream), getter_AddRefs(replacementStream)); if (NS_WARN_IF(aRv.Failed())) { return; } if (replacementStream) { mInputStream = replacementStream.forget(); } clonedStream.forget(aStream); }
already_AddRefed<InternalRequest> InternalRequest::Clone() { RefPtr<InternalRequest> clone = new InternalRequest(*this); if (!mBodyStream) { return clone.forget(); } nsCOMPtr<nsIInputStream> clonedBody; nsCOMPtr<nsIInputStream> replacementBody; nsresult rv = NS_CloneInputStream(mBodyStream, getter_AddRefs(clonedBody), getter_AddRefs(replacementBody)); if (NS_WARN_IF(NS_FAILED(rv))) { return nullptr; } clone->mBodyStream.swap(clonedBody); if (replacementBody) { mBodyStream.swap(replacementBody); } return clone.forget(); }