mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-11 20:35:50 +00:00
8188694805
This is automatically generated from `./mach marionette doc`. MozReview-Commit-ID: JpCfM1LGUnh --HG-- extra : rebase_source : 65ae61df148dad2afa60f234fc41fbab1acaf206
301 lines
17 KiB
HTML
301 lines
17 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title>JSDoc: Source: stream-utils.js</title>
|
|
|
|
<script src="scripts/prettify/prettify.js"> </script>
|
|
<script src="scripts/prettify/lang-css.js"> </script>
|
|
<!--[if lt IE 9]>
|
|
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
|
<![endif]-->
|
|
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
|
|
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<div id="main">
|
|
|
|
<h1 class="page-title">Source: stream-utils.js</h1>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<section>
|
|
<article>
|
|
<pre class="prettyprint source linenums"><code>/* 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/. */
|
|
|
|
"use strict";
|
|
|
|
const {Constructor: CC, classes: Cc, interfaces: Ci, utils: Cu, results: Cr} =
|
|
Components;
|
|
|
|
Cu.import("resource://gre/modules/EventEmitter.jsm");
|
|
Cu.import("resource://gre/modules/Services.jsm");
|
|
|
|
const IOUtil = Cc["@mozilla.org/io-util;1"].getService(Ci.nsIIOUtil);
|
|
const ScriptableInputStream =
|
|
CC("@mozilla.org/scriptableinputstream;1",
|
|
"nsIScriptableInputStream", "init");
|
|
|
|
this.EXPORTED_SYMBOLS = ["StreamUtils"];
|
|
|
|
const BUFFER_SIZE = 0x8000;
|
|
|
|
/**
|
|
* This helper function (and its companion object) are used by bulk
|
|
* senders and receivers to read and write data in and out of other streams.
|
|
* Functions that make use of this tool are passed to callers when it is
|
|
* time to read or write bulk data. It is highly recommended to use these
|
|
* copier functions instead of the stream directly because the copier
|
|
* enforces the agreed upon length. Since bulk mode reuses an existing
|
|
* stream, the sender and receiver must write and read exactly the agreed
|
|
* upon amount of data, or else the entire transport will be left in a
|
|
* invalid state. Additionally, other methods of stream copying (such as
|
|
* NetUtil.asyncCopy) close the streams involved, which would terminate
|
|
* the debugging transport, and so it is avoided here.
|
|
*
|
|
* Overall, this *works*, but clearly the optimal solution would be
|
|
* able to just use the streams directly. If it were possible to fully
|
|
* implement nsIInputStream/nsIOutputStream in JS, wrapper streams could
|
|
* be created to enforce the length and avoid closing, and consumers could
|
|
* use familiar stream utilities like NetUtil.asyncCopy.
|
|
*
|
|
* The function takes two async streams and copies a precise number
|
|
* of bytes from one to the other. Copying begins immediately, but may
|
|
* complete at some future time depending on data size. Use the returned
|
|
* promise to know when it's complete.
|
|
*
|
|
* @param {nsIAsyncInputStream} input
|
|
* Stream to copy from.
|
|
* @param {nsIAsyncOutputStream} output
|
|
* Stream to copy to.
|
|
* @param {number} length
|
|
* Amount of data that needs to be copied.
|
|
*
|
|
* @return {Promise}
|
|
* Promise is resolved when copying completes or rejected if any
|
|
* (unexpected) errors occur.
|
|
*/
|
|
function copyStream(input, output, length) {
|
|
let copier = new StreamCopier(input, output, length);
|
|
return copier.copy();
|
|
}
|
|
|
|
/** @class */
|
|
function StreamCopier(input, output, length) {
|
|
EventEmitter.decorate(this);
|
|
this._id = StreamCopier._nextId++;
|
|
this.input = input;
|
|
// Save off the base output stream, since we know it's async as we've
|
|
// required
|
|
this.baseAsyncOutput = output;
|
|
if (IOUtil.outputStreamIsBuffered(output)) {
|
|
this.output = output;
|
|
} else {
|
|
this.output = Cc["@mozilla.org/network/buffered-output-stream;1"]
|
|
.createInstance(Ci.nsIBufferedOutputStream);
|
|
this.output.init(output, BUFFER_SIZE);
|
|
}
|
|
this._length = length;
|
|
this._amountLeft = length;
|
|
this._deferred = {
|
|
promise: new Promise((resolve, reject) => {
|
|
this._deferred.resolve = resolve;
|
|
this._deferred.reject = reject;
|
|
}),
|
|
};
|
|
|
|
this._copy = this._copy.bind(this);
|
|
this._flush = this._flush.bind(this);
|
|
this._destroy = this._destroy.bind(this);
|
|
|
|
// Copy promise's then method up to this object.
|
|
//
|
|
// Allows the copier to offer a promise interface for the simple succeed
|
|
// or fail scenarios, but also emit events (due to the EventEmitter)
|
|
// for other states, like progress.
|
|
this.then = this._deferred.promise.then.bind(this._deferred.promise);
|
|
this.then(this._destroy, this._destroy);
|
|
|
|
// Stream ready callback starts as |_copy|, but may switch to |_flush|
|
|
// at end if flushing would block the output stream.
|
|
this._streamReadyCallback = this._copy;
|
|
}
|
|
StreamCopier._nextId = 0;
|
|
|
|
StreamCopier.prototype = {
|
|
|
|
copy() {
|
|
// Dispatch to the next tick so that it's possible to attach a progress
|
|
// event listener, even for extremely fast copies (like when testing).
|
|
Services.tm.currentThread.dispatch(() => {
|
|
try {
|
|
this._copy();
|
|
} catch (e) {
|
|
this._deferred.reject(e);
|
|
}
|
|
}, 0);
|
|
return this;
|
|
},
|
|
|
|
_copy() {
|
|
let bytesAvailable = this.input.available();
|
|
let amountToCopy = Math.min(bytesAvailable, this._amountLeft);
|
|
this._debug("Trying to copy: " + amountToCopy);
|
|
|
|
let bytesCopied;
|
|
try {
|
|
bytesCopied = this.output.writeFrom(this.input, amountToCopy);
|
|
} catch (e) {
|
|
if (e.result == Cr.NS_BASE_STREAM_WOULD_BLOCK) {
|
|
this._debug("Base stream would block, will retry");
|
|
this._debug("Waiting for output stream");
|
|
this.baseAsyncOutput.asyncWait(this, 0, 0, Services.tm.currentThread);
|
|
return;
|
|
}
|
|
throw e;
|
|
}
|
|
|
|
this._amountLeft -= bytesCopied;
|
|
this._debug("Copied: " + bytesCopied +
|
|
", Left: " + this._amountLeft);
|
|
this._emitProgress();
|
|
|
|
if (this._amountLeft === 0) {
|
|
this._debug("Copy done!");
|
|
this._flush();
|
|
return;
|
|
}
|
|
|
|
this._debug("Waiting for input stream");
|
|
this.input.asyncWait(this, 0, 0, Services.tm.currentThread);
|
|
},
|
|
|
|
_emitProgress() {
|
|
this.emit("progress", {
|
|
bytesSent: this._length - this._amountLeft,
|
|
totalBytes: this._length,
|
|
});
|
|
},
|
|
|
|
_flush() {
|
|
try {
|
|
this.output.flush();
|
|
} catch (e) {
|
|
if (e.result == Cr.NS_BASE_STREAM_WOULD_BLOCK ||
|
|
e.result == Cr.NS_ERROR_FAILURE) {
|
|
this._debug("Flush would block, will retry");
|
|
this._streamReadyCallback = this._flush;
|
|
this._debug("Waiting for output stream");
|
|
this.baseAsyncOutput.asyncWait(this, 0, 0, Services.tm.currentThread);
|
|
return;
|
|
}
|
|
throw e;
|
|
}
|
|
this._deferred.resolve();
|
|
},
|
|
|
|
_destroy() {
|
|
this._destroy = null;
|
|
this._copy = null;
|
|
this._flush = null;
|
|
this.input = null;
|
|
this.output = null;
|
|
},
|
|
|
|
// nsIInputStreamCallback
|
|
onInputStreamReady() {
|
|
this._streamReadyCallback();
|
|
},
|
|
|
|
// nsIOutputStreamCallback
|
|
onOutputStreamReady() {
|
|
this._streamReadyCallback();
|
|
},
|
|
|
|
_debug(msg) {
|
|
},
|
|
|
|
};
|
|
|
|
/**
|
|
* Read from a stream, one byte at a time, up to the next
|
|
* <var>delimiter</var> character, but stopping if we've read |count|
|
|
* without finding it. Reading also terminates early if there are less
|
|
* than <var>count</var> bytes available on the stream. In that case,
|
|
* we only read as many bytes as the stream currently has to offer.
|
|
*
|
|
* @param {nsIInputStream} stream
|
|
* Input stream to read from.
|
|
* @param {string} delimiter
|
|
* Character we're trying to find.
|
|
* @param {number} count
|
|
* Max number of characters to read while searching.
|
|
*
|
|
* @return {string}
|
|
* Collected data. If the delimiter was found, this string will
|
|
* end with it.
|
|
*/
|
|
// TODO: This implementation could be removed if bug 984651 is fixed,
|
|
// which provides a native version of the same idea.
|
|
function delimitedRead(stream, delimiter, count) {
|
|
let scriptableStream;
|
|
if (stream instanceof Ci.nsIScriptableInputStream) {
|
|
scriptableStream = stream;
|
|
} else {
|
|
scriptableStream = new ScriptableInputStream(stream);
|
|
}
|
|
|
|
let data = "";
|
|
|
|
// Don't exceed what's available on the stream
|
|
count = Math.min(count, stream.available());
|
|
|
|
if (count <= 0) {
|
|
return data;
|
|
}
|
|
|
|
let char;
|
|
while (char !== delimiter && count > 0) {
|
|
char = scriptableStream.readBytes(1);
|
|
count--;
|
|
data += char;
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
this.StreamUtils = {
|
|
copyStream,
|
|
delimitedRead,
|
|
};
|
|
</code></pre>
|
|
</article>
|
|
</section>
|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
<nav>
|
|
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="accessibility.Checks.html">Checks</a></li><li><a href="action.Action.html">Action</a></li><li><a href="action.html#.Chain">Chain</a></li><li><a href="action.InputState.Key.html">Key</a></li><li><a href="action.InputState.Null.html">Null</a></li><li><a href="action.InputState.Pointer.html">Pointer</a></li><li><a href="action.Key.html">Key</a></li><li><a href="action.Mouse.html">Mouse</a></li><li><a href="action.PointerParameters.html">PointerParameters</a></li><li><a href="action.Sequence.html">Sequence</a></li><li><a href="AsyncChromeSender.html">AsyncChromeSender</a></li><li><a href="browser.Context.html">Context</a></li><li><a href="browser.Windows.html">Windows</a></li><li><a href="Command.html">Command</a></li><li><a href="DebuggerTransport.html">DebuggerTransport</a></li><li><a href="element.Store.html">Store</a></li><li><a href="ElementClickInterceptedError.html">ElementClickInterceptedError</a></li><li><a href="ElementNotAccessibleError.html">ElementNotAccessibleError</a></li><li><a href="ElementNotInteractableError.html">ElementNotInteractableError</a></li><li><a href="evaluate.this.Sandboxes.html">this.Sandboxes</a></li><li><a href="frame.Manager.html">Manager</a></li><li><a href="GeckoDriver.html">GeckoDriver</a></li><li><a href="InputState.html">InputState</a></li><li><a href="InsecureCertificateError.html">InsecureCertificateError</a></li><li><a href="InvalidArgumentError.html">InvalidArgumentError</a></li><li><a href="JavaScriptError.html">JavaScriptError</a></li><li><a href="Message.html">Message</a></li><li><a href="modal.Dialog.html">Dialog</a></li><li><a href="Packet.html">Packet</a></li><li><a href="proxy.AsyncMessageChannel.html">AsyncMessageChannel</a></li><li><a href="proxy.SyncChromeSender.html">SyncChromeSender</a></li><li><a href="reftest.Runner.html">Runner</a></li><li><a href="Response.html">Response</a></li><li><a href="server.TCPConnection.html">TCPConnection</a></li><li><a href="server.TCPListener.html">TCPListener</a></li><li><a href="session.Capabilities.html">Capabilities</a></li><li><a href="session.Proxy.html">Proxy</a></li><li><a href="session.Timeouts.html">Timeouts</a></li><li><a href="StreamCopier.html">StreamCopier</a></li><li><a href="WebDriverError.html">WebDriverError</a></li></ul><h3>Namespaces</h3><ul><li><a href="accessibility.html">accessibility</a></li><li><a href="action.html">action</a></li><li><a href="addon.html">addon</a></li><li><a href="assert.html">assert</a></li><li><a href="atom.html">atom</a></li><li><a href="browser.html">browser</a></li><li><a href="capture.html">capture</a></li><li><a href="cert.html">cert</a></li><li><a href="cookie.html">cookie</a></li><li><a href="driver.html">driver</a></li><li><a href="element.html">element</a></li><li><a href="error.html">error</a></li><li><a href="evaluate.html">evaluate</a></li><li><a href="global.html#event">event</a></li><li><a href="frame.html">frame</a></li><li><a href="interaction.html">interaction</a></li><li><a href="l10n.html">l10n</a></li><li><a href="legacyaction.html">legacyaction</a></li><li><a href="modal.html">modal</a></li><li><a href="navigate.html">navigate</a></li><li><a href="proxy.html">proxy</a></li><li><a href="reftest.html">reftest</a></li><li><a href="server.html">server</a></li><li><a href="session.html">session</a></li><li><a href="wait.html">wait</a></li></ul><h3>Global</h3><ul><li><a href="global.html#actionChain">actionChain</a></li><li><a href="global.html#addMessageListenerId">addMessageListenerId</a></li><li><a href="global.html#BulkPacket">BulkPacket</a></li><li><a href="global.html#cancelRequest">cancelRequest</a></li><li><a href="global.html#CHECKED_PROPERTY_SUPPORTED_XUL">CHECKED_PROPERTY_SUPPORTED_XUL</a></li><li><a href="global.html#checkExpectedEvent_">checkExpectedEvent_</a></li><li><a href="global.html#ChildDebuggerTransport">ChildDebuggerTransport</a></li><li><a href="global.html#clearElement">clearElement</a></li><li><a href="global.html#clickElement">clickElement</a></li><li><a href="global.html#COMMON_FORM_CONTROLS">COMMON_FORM_CONTROLS</a></li><li><a href="global.html#Cookie">Cookie</a></li><li><a href="global.html#copyStream">copyStream</a></li><li><a href="global.html#createATouch">createATouch</a></li><li><a href="global.html#deleteSession">deleteSession</a></li><li><a href="global.html#delimitedRead">delimitedRead</a></li><li><a href="global.html#DISABLED_ATTRIBUTE_SUPPORTED_XUL">DISABLED_ATTRIBUTE_SUPPORTED_XUL</a></li><li><a href="global.html#dispatchKeyDown">dispatchKeyDown</a></li><li><a href="global.html#dispatchKeyUp">dispatchKeyUp</a></li><li><a href="global.html#dispatchPause">dispatchPause</a></li><li><a href="global.html#dispatchPointerDown">dispatchPointerDown</a></li><li><a href="global.html#dispatchPointerMove">dispatchPointerMove</a></li><li><a href="global.html#dispatchPointerUp">dispatchPointerUp</a></li><li><a href="global.html#filterLinks">filterLinks</a></li><li><a href="global.html#findElement">findElement</a></li><li><a href="global.html#findElementContent">findElementContent</a></li><li><a href="global.html#findElements">findElements</a></li><li><a href="global.html#findElementsContent">findElementsContent</a></li><li><a href="global.html#focusElement">focusElement</a></li><li><a href="global.html#get">get</a></li><li><a href="global.html#getActiveElement">getActiveElement</a></li><li><a href="global.html#getElementRect">getElementRect</a></li><li><a href="global.html#getElementTagName">getElementTagName</a></li><li><a href="global.html#getElementText">getElementText</a></li><li><a href="global.html#getElementValueOfCssProperty">getElementValueOfCssProperty</a></li><li><a href="global.html#getOuterWindowId">getOuterWindowId</a></li><li><a href="global.html#getPageSource">getPageSource</a></li><li><a href="global.html#goBack">goBack</a></li><li><a href="global.html#goForward">goForward</a></li><li><a href="global.html#hex">hex</a></li><li><a href="global.html#INPUT_TYPES_NO_EVENT">INPUT_TYPES_NO_EVENT</a></li><li><a href="global.html#isElementDisplayed">isElementDisplayed</a></li><li><a href="global.html#isElementEnabled">isElementEnabled</a></li><li><a href="global.html#isElementSelected">isElementSelected</a></li><li><a href="global.html#JSONPacket">JSONPacket</a></li><li><a href="global.html#KEY_LOCATION_LOOKUP">KEY_LOCATION_LOOKUP</a></li><li><a href="global.html#loadListener">loadListener</a></li><li><a href="global.html#LocalDebuggerTransport">LocalDebuggerTransport</a></li><li><a href="global.html#MessageOrigin">MessageOrigin</a></li><li><a href="global.html#MODIFIER_NAME_LOOKUP">MODIFIER_NAME_LOOKUP</a></li><li><a href="global.html#multiAction">multiAction</a></li><li><a href="global.html#newSession">newSession</a></li><li><a href="global.html#NORMALIZED_KEY_LOOKUP">NORMALIZED_KEY_LOOKUP</a></li><li><a href="global.html#performActions">performActions</a></li><li><a href="global.html#RawPacket">RawPacket</a></li><li><a href="global.html#refresh">refresh</a></li><li><a href="global.html#registerSelf">registerSelf</a></li><li><a href="global.html#releaseActions">releaseActions</a></li><li><a href="global.html#removeMessageListenerId">removeMessageListenerId</a></li><li><a href="global.html#resetValues">resetValues</a></li><li><a href="global.html#ResponseBody">ResponseBody</a></li><li><a href="global.html#restart">restart</a></li><li><a href="global.html#SELECTED_PROPERTY_SUPPORTED_XUL">SELECTED_PROPERTY_SUPPORTED_XUL</a></li><li><a href="global.html#sendError">sendError</a></li><li><a href="global.html#sendOk">sendOk</a></li><li><a href="global.html#sendResponse">sendResponse</a></li><li><a href="global.html#sendToServer">sendToServer</a></li><li><a href="global.html#set">set</a></li><li><a href="global.html#singleTap">singleTap</a></li><li><a href="global.html#sleepSession">sleepSession</a></li><li><a href="global.html#startListeners">startListeners</a></li><li><a href="global.html#switchToFrame">switchToFrame</a></li><li><a href="global.html#switchToParentFrame">switchToParentFrame</a></li><li><a href="global.html#switchToShadowRoot">switchToShadowRoot</a></li><li><a href="global.html#takeScreenshot">takeScreenshot</a></li><li><a href="global.html#toEvents">toEvents</a></li><li><a href="global.html#waitForPageLoaded">waitForPageLoaded</a></li></ul>
|
|
</nav>
|
|
|
|
<br class="clear">
|
|
|
|
<footer>
|
|
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.3</a> on Wed Jul 26 2017 14:55:00 GMT+0100 (BST)
|
|
</footer>
|
|
|
|
<script> prettyPrint(); </script>
|
|
<script src="scripts/linenumber.js"> </script>
|
|
</body>
|
|
</html>
|