Bug 1167730 - Make nsTemporaryFileStream serializable. r=baku

This commit is contained in:
Josh Matthews 2016-09-23 10:34:42 -04:00
parent 4d94ead59d
commit ee501c8947
7 changed files with 196 additions and 1 deletions

View File

@ -0,0 +1,20 @@
const CC = Components.Constructor;
const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1",
"nsIBinaryInputStream",
"setInputStream");
const BinaryOutputStream = CC("@mozilla.org/binaryoutputstream;1",
"nsIBinaryOutputStream",
"setOutputStream");
function handleRequest(request, response) {
var bodyStream = new BinaryInputStream(request.bodyInputStream);
var bodyBytes = [];
while ((bodyAvail = bodyStream.available()) > 0)
Array.prototype.push.apply(bodyBytes, bodyStream.readByteArray(bodyAvail));
var bos = new BinaryOutputStream(response.bodyOutputStream);
response.processAsync();
bos.writeByteArray(bodyBytes, bodyBytes.length);
response.finish();
}

View File

@ -53,3 +53,7 @@ support-files =
test_permission_helper.js
test_permission_embed.html
test_permission_framescript.js
[test_temporaryfile_stream.html]
support-files =
blob_verify.sjs
!/dom/canvas/test/captureStream_common.js

View File

@ -0,0 +1,80 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Send an nsTemporaryFileInputStream cross-process</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<script src="/tests/dom/canvas/test/captureStream_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<pre id="test">
<div id="content">
</div>
<script class="testbody" type="text/javascript">
function startTest() {
var canvas = document.createElement("canvas");
canvas.width = canvas.height = 100;
document.getElementById("content").appendChild(canvas);
var helper = new CaptureStreamTestHelper2D(100, 100);
helper.drawColor(canvas, helper.red);
var stream = canvas.captureStream(0);
var blob;
mediaRecorder = new MediaRecorder(stream);
is(mediaRecorder.stream, stream,
"Media recorder stream = canvas stream at the start of recording");
mediaRecorder.onwarning = () => ok(false, "warning unexpectedly fired");
mediaRecorder.onerror = () => ok(false, "Recording failed");
mediaRecorder.ondataavailable = ev => {
is(blob, undefined, "Should only get one dataavailable event");
blob = ev.data;
};
mediaRecorder.onstart = () => {
info("Got 'start' event");
// We just want one frame encoded, to see that the recorder produces something readable.
mediaRecorder.stop();
};
mediaRecorder.onstop = () => {
info("Got 'stop' event");
ok(blob, "Should have gotten a data blob");
var xhr = new XMLHttpRequest();
xhr.open('POST', 'blob_verify.sjs', true);
xhr.onload = () => {
var video = document.createElement("video");
video.id = "recorded-video";
video.src = URL.createObjectURL(xhr.response);
video.play();
video.onerror = err => {
ok(false, "Should be able to play the recording. Got error. code=" + video.error.code);
SimpleTest.finish();
};
document.getElementById("content").appendChild(video);
helper.waitForPixelColor(video, helper.red, 128, "Should become red")
.then(SimpleTest.finish);
};
xhr.onerror = () => {
ok(false, "XHR error");
SimpleTest.finish();
}
xhr.responseType = "blob";
xhr.send(blob);
};
mediaRecorder.start();
is(mediaRecorder.state, "recording", "Media recorder should be recording");
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({set:[["media.recorder.max_memory", 1]]}, startTest);
</script>
</pre>
</body>
</html>

View File

@ -30,6 +30,13 @@ struct PartialFileInputStreamParams
uint64_t length;
};
struct TemporaryFileInputStreamParams
{
uint32_t fileDescriptorIndex;
uint64_t startPos;
uint64_t endPos;
};
struct MultiplexInputStreamParams
{
InputStreamParams[] streams;
@ -56,6 +63,7 @@ union InputStreamParams
StringInputStreamParams;
FileInputStreamParams;
PartialFileInputStreamParams;
TemporaryFileInputStreamParams;
BufferedInputStreamParams;
MIMEInputStreamParams;
MultiplexInputStreamParams;

View File

@ -93,6 +93,10 @@ DeserializeInputStream(const InputStreamParams& aParams,
serializable = do_CreateInstance(kPartialFileInputStreamCID);
break;
case InputStreamParams::TTemporaryFileInputStreamParams:
serializable = new nsTemporaryFileInputStream();
break;
case InputStreamParams::TBufferedInputStreamParams:
serializable = do_CreateInstance(kBufferedInputStreamCID);
break;

View File

@ -7,7 +7,12 @@
#include "nsStreamUtils.h"
#include <algorithm>
NS_IMPL_ISUPPORTS(nsTemporaryFileInputStream, nsIInputStream, nsISeekableStream)
typedef mozilla::ipc::FileDescriptor::PlatformHandleType FileHandleType;
NS_IMPL_ISUPPORTS(nsTemporaryFileInputStream,
nsIInputStream,
nsISeekableStream,
nsIIPCSerializableInputStream)
nsTemporaryFileInputStream::nsTemporaryFileInputStream(FileDescOwner* aFileDescOwner, uint64_t aStartPos, uint64_t aEndPos)
: mFileDescOwner(aFileDescOwner),
@ -19,6 +24,14 @@ nsTemporaryFileInputStream::nsTemporaryFileInputStream(FileDescOwner* aFileDescO
NS_ASSERTION(aStartPos <= aEndPos, "StartPos should less equal than EndPos!");
}
nsTemporaryFileInputStream::nsTemporaryFileInputStream()
: mStartPos(0),
mCurPos(0),
mEndPos(0),
mClosed(false)
{
}
NS_IMETHODIMP
nsTemporaryFileInputStream::Close()
{
@ -164,3 +177,65 @@ nsTemporaryFileInputStream::SetEOF()
return Close();
}
void
nsTemporaryFileInputStream::Serialize(InputStreamParams& aParams,
FileDescriptorArray& aFileDescriptors)
{
TemporaryFileInputStreamParams params;
MutexAutoLock lock(mFileDescOwner->FileMutex());
MOZ_ASSERT(mFileDescOwner->mFD);
if (!mClosed) {
FileHandleType fd = FileHandleType(PR_FileDesc2NativeHandle(mFileDescOwner->mFD));
NS_ASSERTION(fd, "This should never be null!");
DebugOnly<FileDescriptor*> dbgFD = aFileDescriptors.AppendElement(fd);
NS_ASSERTION(dbgFD->IsValid(), "Sending an invalid file descriptor!");
params.fileDescriptorIndex() = aFileDescriptors.Length() - 1;
Close();
} else {
NS_WARNING("The stream is already closed. "
"Sending an invalid file descriptor to the other process!");
params.fileDescriptorIndex() = UINT32_MAX;
}
params.startPos() = mCurPos;
params.endPos() = mEndPos;
aParams = params;
}
bool
nsTemporaryFileInputStream::Deserialize(const InputStreamParams& aParams,
const FileDescriptorArray& aFileDescriptors)
{
const TemporaryFileInputStreamParams& params = aParams.get_TemporaryFileInputStreamParams();
uint32_t fileDescriptorIndex = params.fileDescriptorIndex();
FileDescriptor fd;
if (fileDescriptorIndex < aFileDescriptors.Length()) {
fd = aFileDescriptors[fileDescriptorIndex];
NS_WARNING_ASSERTION(fd.IsValid(),
"Received an invalid file descriptor!");
} else {
NS_WARNING("Received a bad file descriptor index!");
}
if (fd.IsValid()) {
auto rawFD = fd.ClonePlatformHandle();
PRFileDesc* fileDesc = PR_ImportFile(PROsfd(rawFD.release()));
if (!fileDesc) {
NS_WARNING("Failed to import file handle!");
return false;
}
mFileDescOwner = new FileDescOwner(fileDesc);
} else {
mClosed = true;
}
mStartPos = mCurPos = params.startPos();
mEndPos = params.endPos();
return true;
}

View File

@ -9,11 +9,13 @@
#include "mozilla/Mutex.h"
#include "nsAutoPtr.h"
#include "nsIInputStream.h"
#include "nsIIPCSerializableInputStream.h"
#include "nsISeekableStream.h"
#include "prio.h"
class nsTemporaryFileInputStream : public nsIInputStream
, public nsISeekableStream
, public nsIIPCSerializableInputStream
{
public:
//used to release a PRFileDesc
@ -42,10 +44,12 @@ public:
};
nsTemporaryFileInputStream(FileDescOwner* aFileDescOwner, uint64_t aStartPos, uint64_t aEndPos);
nsTemporaryFileInputStream();
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIINPUTSTREAM
NS_DECL_NSISEEKABLESTREAM
NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM
private:
virtual ~nsTemporaryFileInputStream() { }