зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to fx-team. a=merge
This commit is contained in:
Коммит
c9c9d14f70
|
@ -1078,6 +1078,13 @@ pref("dom.mozSettings.allowForceReadOnly", false);
|
|||
// RequestSync API is enabled by default on B2G.
|
||||
pref("dom.requestSync.enabled", true);
|
||||
|
||||
// Enable hardware vsync compositor
|
||||
// Only enable for kit kat and above devices
|
||||
// kit kat == 19, L = 21, 20 is kit-kat for wearables
|
||||
// 15 is for the ICS emulators which will fallback to software vsync
|
||||
#if ANDROID_VERSION == 19 || ANDROID_VERSION == 21 || ANDROID_VERSION == 15
|
||||
pref("gfx.vsync.hw-vsync.enabled", true);
|
||||
pref("gfx.vsync.compositor", true);
|
||||
#else
|
||||
pref("gfx.vsync.hw-vsync.enabled", false);
|
||||
pref("gfx.vsync.compositor", false);
|
||||
#endif
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="e06971db7acf7a35c32eb74d675a4e12e288e6be">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="ba613ae583a706131c45e885f65d428d4a541a81"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="782d371263911a526870263bffcb419b52c7c88a"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="ba613ae583a706131c45e885f65d428d4a541a81"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="782d371263911a526870263bffcb419b52c7c88a"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d5d3f93914558b6f168447b805cd799c8233e300"/>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="ba613ae583a706131c45e885f65d428d4a541a81"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="782d371263911a526870263bffcb419b52c7c88a"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="d6a27295acb0a25926bf6290dd2532a7f9027864"/>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="e06971db7acf7a35c32eb74d675a4e12e288e6be">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="ba613ae583a706131c45e885f65d428d4a541a81"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="782d371263911a526870263bffcb419b52c7c88a"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="ba613ae583a706131c45e885f65d428d4a541a81"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="782d371263911a526870263bffcb419b52c7c88a"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d5d3f93914558b6f168447b805cd799c8233e300"/>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="e06971db7acf7a35c32eb74d675a4e12e288e6be">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="ba613ae583a706131c45e885f65d428d4a541a81"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="782d371263911a526870263bffcb419b52c7c88a"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
</project>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="ba613ae583a706131c45e885f65d428d4a541a81"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="782d371263911a526870263bffcb419b52c7c88a"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="d6a27295acb0a25926bf6290dd2532a7f9027864"/>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
{
|
||||
"git": {
|
||||
"git_revision": "ba613ae583a706131c45e885f65d428d4a541a81",
|
||||
"git_revision": "782d371263911a526870263bffcb419b52c7c88a",
|
||||
"remote": "https://git.mozilla.org/releases/gaia.git",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "4705c493adb5c766382b27e4fbff42f7447900e9",
|
||||
"revision": "8c97eed028b3ad9580854e6c12f80e3046440e45",
|
||||
"repo_path": "integration/gaia-central"
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="ba613ae583a706131c45e885f65d428d4a541a81"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="782d371263911a526870263bffcb419b52c7c88a"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="ba613ae583a706131c45e885f65d428d4a541a81"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="782d371263911a526870263bffcb419b52c7c88a"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="ba613ae583a706131c45e885f65d428d4a541a81"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="782d371263911a526870263bffcb419b52c7c88a"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="d6a27295acb0a25926bf6290dd2532a7f9027864"/>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="ba613ae583a706131c45e885f65d428d4a541a81"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="782d371263911a526870263bffcb419b52c7c88a"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
|
|
@ -235,6 +235,11 @@ FeedConverter.prototype = {
|
|||
getService(Ci.nsIIOService);
|
||||
var chromeChannel;
|
||||
|
||||
// handling a redirect, hence forwarding the loadInfo from the old channel
|
||||
// to the newchannel.
|
||||
var oldChannel = this._request.QueryInterface(Ci.nsIChannel);
|
||||
var loadInfo = oldChannel.loadInfo;
|
||||
|
||||
// If there was no automatic handler, or this was a podcast,
|
||||
// photostream or some other kind of application, show the preview page
|
||||
// if the parser returned a document.
|
||||
|
@ -246,12 +251,12 @@ FeedConverter.prototype = {
|
|||
|
||||
// Now load the actual XUL document.
|
||||
var aboutFeedsURI = ios.newURI("about:feeds", null, null);
|
||||
chromeChannel = ios.newChannelFromURI(aboutFeedsURI, null);
|
||||
chromeChannel = ios.newChannelFromURIWithLoadInfo(aboutFeedsURI, loadInfo);
|
||||
chromeChannel.originalURI = result.uri;
|
||||
chromeChannel.owner =
|
||||
Services.scriptSecurityManager.getNoAppCodebasePrincipal(aboutFeedsURI);
|
||||
} else {
|
||||
chromeChannel = ios.newChannelFromURI(result.uri, null);
|
||||
chromeChannel = ios.newChannelFromURIWithLoadInfo(result.uri, loadInfo);
|
||||
}
|
||||
|
||||
chromeChannel.loadGroup = this._request.loadGroup;
|
||||
|
@ -546,7 +551,12 @@ GenericProtocolHandler.prototype = {
|
|||
newChannel: function GPH_newChannel(aUri) {
|
||||
var inner = aUri.QueryInterface(Ci.nsINestedURI).innerURI;
|
||||
var channel = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService).newChannelFromURI(inner, null);
|
||||
getService(Ci.nsIIOService).newChannelFromURI2(inner,
|
||||
null, // aLoadingNode
|
||||
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
null, // aTriggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_NORMAL,
|
||||
Ci.nsIContentPolicy.TYPE_OTHER);
|
||||
if (channel instanceof Components.interfaces.nsIHttpChannel)
|
||||
// Set this so we know this is supposed to be a feed
|
||||
channel.setRequestHeader("X-Moz-Is-Feed", "1", false);
|
||||
|
|
|
@ -1128,9 +1128,19 @@ FeedWriter.prototype = {
|
|||
getInterface(Ci.nsIWebNavigation).
|
||||
QueryInterface(Ci.nsIDocShell).currentDocumentChannel;
|
||||
|
||||
var nullPrincipal = Cc["@mozilla.org/nullprincipal;1"].
|
||||
createInstance(Ci.nsIPrincipal);
|
||||
|
||||
var resolvedURI = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService).
|
||||
newChannel("about:feeds", null, null).URI;
|
||||
newChannel2("about:feeds",
|
||||
null,
|
||||
null,
|
||||
null, // aLoadingNode
|
||||
nullPrincipal,
|
||||
null, // aTriggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_NORMAL,
|
||||
Ci.nsIContentPolicy.TYPE_OTHER).URI;
|
||||
|
||||
if (resolvedURI.equals(chan.URI))
|
||||
return chan.originalURI;
|
||||
|
|
|
@ -4,5 +4,17 @@
|
|||
"digest": "bb345b0e700ffab4d09436981f14b5de84da55a3f18a7f09ebc4364a4488acdeab8d46f447b12ac70f2da1444a68b8ce8b8675f0dae2ccf845e966d1df0f0869",
|
||||
"algorithm": "sha512",
|
||||
"filename": "mozmake.exe"
|
||||
},
|
||||
{
|
||||
"size": 176,
|
||||
"digest": "2809058907ac5eefdc394113d2e4fe76ba559ac61c2eca2f88e7a12a74bdf44a15d9039fa8aa229f7362a14b67d67395063f68147ae098beac5dfcc78aff98da",
|
||||
"algorithm": "sha512",
|
||||
"filename": "setup.sh"
|
||||
},
|
||||
{
|
||||
"size": 166506,
|
||||
"digest": "f3c214fd571f21d64937584645212f8d7c2d12c9016be613bd2bc9cecd80b3d52a741423cc1ca69bd85fb924c3d0572c85a1734d12db1616df37abcc397e9252",
|
||||
"algorithm": "sha512",
|
||||
"filename": "sccache.tar.bz2"
|
||||
}
|
||||
]
|
||||
|
|
|
@ -896,13 +896,16 @@ Messages.Simple.prototype = Heritage.extend(Messages.BaseMessage.prototype,
|
|||
let body = this.document.createElementNS(XHTML_NS, "span");
|
||||
body.className = "message-body-wrapper message-body devtools-monospace";
|
||||
|
||||
let anchor, container = body;
|
||||
let bodyInner = this.document.createElementNS(XHTML_NS, "span");
|
||||
body.appendChild(bodyInner);
|
||||
|
||||
let anchor, container = bodyInner;
|
||||
if (this._link || this._linkCallback) {
|
||||
container = anchor = this.document.createElementNS(XHTML_NS, "a");
|
||||
anchor.href = this._link || "#";
|
||||
anchor.draggable = false;
|
||||
this._addLinkCallback(anchor, this._linkCallback);
|
||||
body.appendChild(anchor);
|
||||
bodyInner.appendChild(anchor);
|
||||
}
|
||||
|
||||
if (typeof this._message == "function") {
|
||||
|
|
|
@ -57,7 +57,9 @@ function consoleOpened(aHud) {
|
|||
controller = top.document.commandDispatcher.getControllerForCommand("cmd_copy");
|
||||
is(controller.isCommandEnabled("cmd_copy"), true, "cmd_copy is enabled");
|
||||
|
||||
let selection = HUD.iframeWindow.getSelection() + "";
|
||||
// Remove new lines since getSelection() includes one between message and line
|
||||
// number, but the clipboard doesn't (see bug 1119503)
|
||||
let selection = (HUD.iframeWindow.getSelection() + "").replace(/\r?\n|\r/g, " ");
|
||||
isnot(selection.indexOf("bug587617"), -1,
|
||||
"selection text includes 'bug587617'");
|
||||
|
||||
|
@ -80,7 +82,9 @@ function testContextMenuCopy() {
|
|||
let copyItem = contextMenu.querySelector("*[command='cmd_copy']");
|
||||
ok(copyItem, "the context menu on the output node has a \"Copy\" item");
|
||||
|
||||
let selection = HUD.iframeWindow.getSelection() + "";
|
||||
// Remove new lines since getSelection() includes one between message and line
|
||||
// number, but the clipboard doesn't (see bug 1119503)
|
||||
let selection = (HUD.iframeWindow.getSelection() + "").replace(/\r?\n|\r/g, " ");
|
||||
|
||||
copyItem.doCommand();
|
||||
|
||||
|
|
|
@ -69,7 +69,9 @@ function performTest(HUD, [result]) {
|
|||
getControllerForCommand("cmd_copy");
|
||||
is(controller.isCommandEnabled("cmd_copy"), true, "cmd_copy is enabled");
|
||||
|
||||
let selectionText = HUD.iframeWindow.getSelection() + "";
|
||||
// Remove new lines since getSelection() includes one between message and line
|
||||
// number, but the clipboard doesn't (see bug 1119503)
|
||||
let selectionText = (HUD.iframeWindow.getSelection() + "").replace(/\r?\n|\r/g, " ");
|
||||
isnot(selectionText.indexOf("foobarBazBug613280"), -1,
|
||||
"selection text includes 'foobarBazBug613280'");
|
||||
|
||||
|
|
|
@ -117,7 +117,7 @@ a {
|
|||
display: flex;
|
||||
}
|
||||
|
||||
.message-body {
|
||||
.message-body > * {
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
|
|
@ -753,7 +753,7 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
|
|||
}
|
||||
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
|
||||
-moz-border-end: none;
|
||||
-moz-border-end: none transparent;
|
||||
}
|
||||
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
|
||||
|
|
|
@ -97,7 +97,8 @@ SelectionCopyHelper(nsISelection *aSel, nsIDocument *aDoc,
|
|||
|
||||
// Do the first and potentially trial encoding as preformatted and raw.
|
||||
uint32_t flags = aFlags | nsIDocumentEncoder::OutputPreformatted
|
||||
| nsIDocumentEncoder::OutputRaw;
|
||||
| nsIDocumentEncoder::OutputRaw
|
||||
| nsIDocumentEncoder::OutputForPlainTextClipboardCopy;
|
||||
|
||||
nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(aDoc);
|
||||
NS_ASSERTION(domDoc, "Need a document");
|
||||
|
|
|
@ -1220,8 +1220,7 @@ nsDOMWindowUtils::SendKeyEvent(const nsAString& aType,
|
|||
|
||||
uint32_t locationFlag = (aAdditionalFlags &
|
||||
(KEY_FLAG_LOCATION_STANDARD | KEY_FLAG_LOCATION_LEFT |
|
||||
KEY_FLAG_LOCATION_RIGHT | KEY_FLAG_LOCATION_NUMPAD |
|
||||
KEY_FLAG_LOCATION_MOBILE | KEY_FLAG_LOCATION_JOYSTICK));
|
||||
KEY_FLAG_LOCATION_RIGHT | KEY_FLAG_LOCATION_NUMPAD));
|
||||
switch (locationFlag) {
|
||||
case KEY_FLAG_LOCATION_STANDARD:
|
||||
event.location = nsIDOMKeyEvent::DOM_KEY_LOCATION_STANDARD;
|
||||
|
@ -1235,12 +1234,6 @@ nsDOMWindowUtils::SendKeyEvent(const nsAString& aType,
|
|||
case KEY_FLAG_LOCATION_NUMPAD:
|
||||
event.location = nsIDOMKeyEvent::DOM_KEY_LOCATION_NUMPAD;
|
||||
break;
|
||||
case KEY_FLAG_LOCATION_MOBILE:
|
||||
event.location = nsIDOMKeyEvent::DOM_KEY_LOCATION_MOBILE;
|
||||
break;
|
||||
case KEY_FLAG_LOCATION_JOYSTICK:
|
||||
event.location = nsIDOMKeyEvent::DOM_KEY_LOCATION_JOYSTICK;
|
||||
break;
|
||||
default:
|
||||
if (locationFlag != 0) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
|
|
@ -227,6 +227,13 @@ interface nsIDocumentEncoder : nsISupports
|
|||
*/
|
||||
const unsigned long OutputDontRemoveLineEndingSpaces = (1 << 24);
|
||||
|
||||
/**
|
||||
* Serialize in a way that is suitable for copying a plaintext version of the
|
||||
* document to the clipboard. This can for example cause line endings to be
|
||||
* injected at preformatted block element boundaries.
|
||||
*/
|
||||
const unsigned long OutputForPlainTextClipboardCopy = (1 << 25);
|
||||
|
||||
/**
|
||||
* Initialize with a pointer to the document and the mime type.
|
||||
* @param aDocument Document to encode.
|
||||
|
|
|
@ -91,6 +91,8 @@ nsPlainTextSerializer::nsPlainTextSerializer()
|
|||
mPreFormatted = false;
|
||||
mStartedOutput = false;
|
||||
|
||||
mPreformattedBlockBoundary = false;
|
||||
|
||||
// initialize the tag stack to zero:
|
||||
// The stack only ever contains pointers to static atoms, so they don't
|
||||
// need refcounting.
|
||||
|
@ -167,6 +169,8 @@ nsPlainTextSerializer::Init(uint32_t aFlags, uint32_t aWrapColumn,
|
|||
mLineBreakDue = false;
|
||||
mFloatingLines = -1;
|
||||
|
||||
mPreformattedBlockBoundary = false;
|
||||
|
||||
if (mFlags & nsIDocumentEncoder::OutputFormatted) {
|
||||
// Get some prefs that controls how we do formatted output
|
||||
mStructs = Preferences::GetBool(PREF_STRUCTS, mStructs);
|
||||
|
@ -437,6 +441,16 @@ nsPlainTextSerializer::DoOpenContainer(nsIAtom* aTag)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
if (mFlags & nsIDocumentEncoder::OutputForPlainTextClipboardCopy) {
|
||||
if (mPreformattedBlockBoundary && DoOutput()) {
|
||||
// Should always end a line, but get no more whitespace
|
||||
if (mFloatingLines < 0)
|
||||
mFloatingLines = 0;
|
||||
mLineBreakDue = true;
|
||||
}
|
||||
mPreformattedBlockBoundary = false;
|
||||
}
|
||||
|
||||
if (mFlags & nsIDocumentEncoder::OutputRaw) {
|
||||
// Raw means raw. Don't even think about doing anything fancy
|
||||
// here like indenting, adding line breaks or any other
|
||||
|
@ -670,7 +684,7 @@ nsPlainTextSerializer::DoOpenContainer(nsIAtom* aTag)
|
|||
|
||||
// Else make sure we'll separate block level tags,
|
||||
// even if we're about to leave, before doing any other formatting.
|
||||
else if (nsContentUtils::IsHTMLBlock(aTag)) {
|
||||
else if (IsElementBlock(mElement)) {
|
||||
EnsureVerticalSpace(0);
|
||||
}
|
||||
|
||||
|
@ -767,6 +781,14 @@ nsPlainTextSerializer::DoCloseContainer(nsIAtom* aTag)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
if (mFlags & nsIDocumentEncoder::OutputForPlainTextClipboardCopy) {
|
||||
if (DoOutput() && IsInPre() && IsElementBlock(mElement)) {
|
||||
// If we're closing a preformatted block element, output a line break
|
||||
// when we find a new container.
|
||||
mPreformattedBlockBoundary = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (mFlags & nsIDocumentEncoder::OutputRaw) {
|
||||
// Raw means raw. Don't even think about doing anything fancy
|
||||
// here like indenting, adding line breaks or any other
|
||||
|
@ -887,8 +909,7 @@ nsPlainTextSerializer::DoCloseContainer(nsIAtom* aTag)
|
|||
else if (aTag == nsGkAtoms::q) {
|
||||
Write(NS_LITERAL_STRING("\""));
|
||||
}
|
||||
else if (nsContentUtils::IsHTMLBlock(aTag)
|
||||
&& aTag != nsGkAtoms::script) {
|
||||
else if (IsElementBlock(mElement) && aTag != nsGkAtoms::script) {
|
||||
// All other blocks get 1 vertical space after them
|
||||
// in formatted mode, otherwise 0.
|
||||
// This is hard. Sometimes 0 is a better number, but
|
||||
|
@ -1037,6 +1058,8 @@ nsPlainTextSerializer::DoAddText(bool aIsLineBreak, const nsAString& aText)
|
|||
nsresult
|
||||
nsPlainTextSerializer::DoAddLeaf(nsIAtom* aTag)
|
||||
{
|
||||
mPreformattedBlockBoundary = false;
|
||||
|
||||
// If we don't want any output, just return
|
||||
if (!DoOutput()) {
|
||||
return NS_OK;
|
||||
|
@ -1778,6 +1801,20 @@ nsPlainTextSerializer::IsElementPreformatted(Element* aElement)
|
|||
return GetIdForContent(aElement) == nsGkAtoms::pre;
|
||||
}
|
||||
|
||||
bool
|
||||
nsPlainTextSerializer::IsElementBlock(Element* aElement)
|
||||
{
|
||||
nsRefPtr<nsStyleContext> styleContext =
|
||||
nsComputedDOMStyle::GetStyleContextForElementNoFlush(aElement, nullptr,
|
||||
nullptr);
|
||||
if (styleContext) {
|
||||
const nsStyleDisplay* displayStyle = styleContext->StyleDisplay();
|
||||
return displayStyle->IsBlockOutsideStyle();
|
||||
}
|
||||
// Fall back to looking at the tag, in case there is no style information.
|
||||
return nsContentUtils::IsHTMLBlock(GetIdForContent(aElement));
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is required only to identify LI's inside OL.
|
||||
* Returns TRUE if we are inside an OL tag and FALSE otherwise.
|
||||
|
|
|
@ -115,6 +115,7 @@ private:
|
|||
bool ShouldReplaceContainerWithPlaceholder(nsIAtom* aTag);
|
||||
|
||||
bool IsElementPreformatted(mozilla::dom::Element* aElement);
|
||||
bool IsElementBlock(mozilla::dom::Element* aElement);
|
||||
|
||||
private:
|
||||
nsString mCurrentLine;
|
||||
|
@ -169,7 +170,9 @@ private:
|
|||
// While handling a new tag, this variable should remind if any line break
|
||||
// is due because of a closing tag. Setting it to "TRUE" while closing the tags.
|
||||
// Hence opening tags are guaranteed to start with appropriate line breaks.
|
||||
bool mLineBreakDue;
|
||||
bool mLineBreakDue;
|
||||
|
||||
bool mPreformattedBlockBoundary;
|
||||
|
||||
nsString mURL;
|
||||
int32_t mHeaderStrategy; /* Header strategy (pref)
|
||||
|
|
|
@ -137,6 +137,31 @@ TestPreElement()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
TestBlockElement()
|
||||
{
|
||||
nsString test;
|
||||
test.AppendLiteral(
|
||||
"<html>" NS_LINEBREAK
|
||||
"<body>" NS_LINEBREAK
|
||||
"<div>" NS_LINEBREAK
|
||||
" first" NS_LINEBREAK
|
||||
"</div>" NS_LINEBREAK
|
||||
"<div>" NS_LINEBREAK
|
||||
" second" NS_LINEBREAK
|
||||
"</div>" NS_LINEBREAK
|
||||
"</body>" NS_LINEBREAK "</html>");
|
||||
|
||||
ConvertBufToPlainText(test, 0);
|
||||
if (!test.EqualsLiteral("first" NS_LINEBREAK "second" NS_LINEBREAK)) {
|
||||
fail("Wrong prettyprinted html to text serialization");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
passed("prettyprinted HTML to text serialization test");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
TestPlainTextSerializer()
|
||||
{
|
||||
|
@ -163,6 +188,9 @@ TestPlainTextSerializer()
|
|||
rv = TestPreElement();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = TestBlockElement();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Add new tests here...
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,14 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=116083
|
|||
<div data-result="bar baz"><span style="white-space: pre-wrap">bar </span>baz</div>
|
||||
<div data-result="bar baz"><span style="white-space: pre-line">bar </span>baz</div>
|
||||
<div data-result="bar baz"><span style="white-space: -moz-pre-space">bar </span>baz</div>
|
||||
<div data-result="foo bar ! baz" style="white-space: pre"><div>foo </div><div> bar</div><div><br></div><div>!</div><div><br><br></div><div>baz</div></div>
|
||||
<div data-result="foo bar ! baz" style="white-space: pre" contenteditable><div>foo </div><div> bar</div><div><br></div><div>!</div><div><br><br></div><div>baz</div></div>
|
||||
<div data-result="foo bar ! baz" style="white-space: pre-wrap"><div>foo </div><div> bar</div><div><br></div><div>!</div><div><br><br></div><div>baz</div></div>
|
||||
<div data-result="foo bar ! baz" style="white-space: pre-wrap" contenteditable><div>foo </div><div> bar</div><div><br></div><div>!</div><div><br><br></div><div>baz</div></div>
|
||||
<div data-result="foo bar ! baz" style="white-space: pre-line"><div>foo </div><div> bar</div><div><br></div><div>!</div><div><br><br></div><div>baz</div></div>
|
||||
<div data-result="foo bar ! baz" style="white-space: pre-line" contenteditable><div>foo </div><div> bar</div><div><br></div><div>!</div><div><br><br></div><div>baz</div></div>
|
||||
<div data-result="foo bar ! baz" style="white-space: -moz-pre-space"><div>foo </div><div> bar</div><div><br></div><div>!</div><div><br><br></div><div>baz</div></div>
|
||||
<div data-result="foo bar ! baz" style="white-space: -moz-pre-space" contenteditable><div>foo </div><div> bar</div><div><br></div><div>!</div><div><br><br></div><div>baz</div></div>
|
||||
<div data-result=" foo bar ">foo bar</div>
|
||||
</div>
|
||||
<script type="application/javascript">
|
||||
|
|
|
@ -200,10 +200,6 @@ function testSynthesizedKeyLocation()
|
|||
event: { shiftKey: false, ctrlKey: false, altKey: false, metaKey: false,
|
||||
location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
|
||||
},
|
||||
{ key: "VK_DOWN", isModifier: false,
|
||||
event: { shiftKey: false, ctrlKey: false, altKey: false, metaKey: false,
|
||||
location: KeyboardEvent.DOM_KEY_LOCATION_JOYSTICK },
|
||||
},
|
||||
{ key: "5", isModifier: false,
|
||||
event: { shiftKey: false, ctrlKey: false, altKey: false, metaKey: false,
|
||||
location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
|
||||
|
@ -212,14 +208,6 @@ function testSynthesizedKeyLocation()
|
|||
event: { shiftKey: false, ctrlKey: false, altKey: false, metaKey: false,
|
||||
location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
|
||||
},
|
||||
{ key: "5", isModifier: false,
|
||||
event: { shiftKey: false, ctrlKey: false, altKey: false, metaKey: false,
|
||||
location: KeyboardEvent.DOM_KEY_LOCATION_MOBILE },
|
||||
},
|
||||
{ key: "VK_NUMPAD5", isModifier: false,
|
||||
event: { shiftKey: false, ctrlKey: false, altKey: false, metaKey: false,
|
||||
location: KeyboardEvent.DOM_KEY_LOCATION_MOBILE },
|
||||
},
|
||||
{ key: "+", isModifier: false,
|
||||
event: { shiftKey: false, ctrlKey: false, altKey: false, metaKey: false,
|
||||
location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
|
||||
|
@ -259,12 +247,8 @@ function testSynthesizedKeyLocation()
|
|||
return "DOM_KEY_LOCATION_LEFT";
|
||||
case KeyboardEvent.DOM_KEY_LOCATION_RIGHT:
|
||||
return "DOM_KEY_LOCATION_RIGHT";
|
||||
case KeyboardEvent.DOM_KEY_LOCATION_MOBILE:
|
||||
return "DOM_KEY_LOCATION_MOBILE";
|
||||
case KeyboardEvent.DOM_KEY_LOCATION_NUMPAD:
|
||||
return "DOM_KEY_LOCATION_NUMPAD";
|
||||
case KeyboardEvent.DOM_KEY_LOCATION_JOYSTICK:
|
||||
return "DOM_KEY_LOCATION_JOYSTICK";
|
||||
default:
|
||||
return "Invalid value (" + aLocation + ")";
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ interface nsITranslationNodeList;
|
|||
interface nsIJSRAIIHelper;
|
||||
interface nsIContentPermissionRequest;
|
||||
|
||||
[scriptable, uuid(04db2684-f9ed-4d70-827d-3d5b87825238)]
|
||||
[scriptable, uuid(5ed850de-2b57-4555-ac48-93292e852eab)]
|
||||
interface nsIDOMWindowUtils : nsISupports {
|
||||
|
||||
/**
|
||||
|
@ -556,8 +556,6 @@ interface nsIDOMWindowUtils : nsISupports {
|
|||
const unsigned long KEY_FLAG_LOCATION_LEFT = 0x0020;
|
||||
const unsigned long KEY_FLAG_LOCATION_RIGHT = 0x0040;
|
||||
const unsigned long KEY_FLAG_LOCATION_NUMPAD = 0x0080;
|
||||
const unsigned long KEY_FLAG_LOCATION_MOBILE = 0x0100;
|
||||
const unsigned long KEY_FLAG_LOCATION_JOYSTICK = 0x0200;
|
||||
|
||||
boolean sendKeyEvent(in AString aType,
|
||||
in long aKeyCode,
|
||||
|
|
|
@ -250,8 +250,6 @@ interface nsIDOMKeyEvent : nsIDOMUIEvent
|
|||
const unsigned long DOM_KEY_LOCATION_LEFT = 0x01;
|
||||
const unsigned long DOM_KEY_LOCATION_RIGHT = 0x02;
|
||||
const unsigned long DOM_KEY_LOCATION_NUMPAD = 0x03;
|
||||
const unsigned long DOM_KEY_LOCATION_MOBILE = 0x04;
|
||||
const unsigned long DOM_KEY_LOCATION_JOYSTICK = 0x05;
|
||||
|
||||
readonly attribute unsigned long location;
|
||||
readonly attribute boolean repeat;
|
||||
|
|
|
@ -36,6 +36,9 @@
|
|||
using namespace mozilla::layers;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
// Default timeout msecs until try to enter dormant state by heuristic.
|
||||
static const int DEFAULT_HEURISTIC_DORMANT_TIMEOUT_MSECS = 60000;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// Number of estimated seconds worth of data we need to have buffered
|
||||
|
@ -123,27 +126,56 @@ void MediaDecoder::NotifyOwnerActivityChanged()
|
|||
MOZ_ASSERT(NS_IsMainThread());
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
|
||||
if (!mDecoderStateMachine ||
|
||||
!mDecoderStateMachine->IsDormantNeeded() ||
|
||||
mPlayState == PLAY_STATE_SHUTDOWN) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mOwner) {
|
||||
NS_WARNING("MediaDecoder without a decoder owner, can't update dormant");
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateDormantState(false /* aDormantTimeout */, false /* aActivity */);
|
||||
// Start dormant timer if necessary
|
||||
StartDormantTimer();
|
||||
}
|
||||
|
||||
void MediaDecoder::UpdateDormantState(bool aDormantTimeout, bool aActivity)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
GetReentrantMonitor().AssertCurrentThreadIn();
|
||||
|
||||
if (!mDecoderStateMachine ||
|
||||
mPlayState == PLAY_STATE_SHUTDOWN ||
|
||||
!mOwner->GetVideoFrameContainer() ||
|
||||
!mDecoderStateMachine->IsDormantNeeded())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool prevDormant = mIsDormant;
|
||||
mIsDormant = false;
|
||||
if (!mOwner->IsActive() && mOwner->GetVideoFrameContainer()) {
|
||||
if (!mOwner->IsActive()) {
|
||||
mIsDormant = true;
|
||||
}
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
if (mOwner->IsHidden() && mOwner->GetVideoFrameContainer()) {
|
||||
if (mOwner->IsHidden()) {
|
||||
mIsDormant = true;
|
||||
}
|
||||
#endif
|
||||
// Try to enable dormant by idle heuristic, when the owner is hidden.
|
||||
bool prevHeuristicDormant = mIsHeuristicDormant;
|
||||
mIsHeuristicDormant = false;
|
||||
if (mIsHeuristicDormantSupported && mOwner->IsHidden()) {
|
||||
if (aDormantTimeout && !aActivity &&
|
||||
(mPlayState == PLAY_STATE_PAUSED || mPlayState == PLAY_STATE_ENDED)) {
|
||||
// Enable heuristic dormant
|
||||
mIsHeuristicDormant = true;
|
||||
} else if(prevHeuristicDormant && !aActivity) {
|
||||
// Continue heuristic dormant
|
||||
mIsHeuristicDormant = true;
|
||||
}
|
||||
|
||||
if (mIsHeuristicDormant) {
|
||||
mIsDormant = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (prevDormant == mIsDormant) {
|
||||
// No update to dormant state
|
||||
|
@ -167,6 +199,47 @@ void MediaDecoder::NotifyOwnerActivityChanged()
|
|||
}
|
||||
}
|
||||
|
||||
void MediaDecoder::DormantTimerExpired(nsITimer* aTimer, void* aClosure)
|
||||
{
|
||||
MOZ_ASSERT(aClosure);
|
||||
MediaDecoder* decoder = static_cast<MediaDecoder*>(aClosure);
|
||||
ReentrantMonitorAutoEnter mon(decoder->GetReentrantMonitor());
|
||||
decoder->UpdateDormantState(true /* aDormantTimeout */,
|
||||
false /* aActivity */);
|
||||
}
|
||||
|
||||
void MediaDecoder::StartDormantTimer()
|
||||
{
|
||||
if (!mIsHeuristicDormantSupported) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mIsHeuristicDormant ||
|
||||
mShuttingDown ||
|
||||
!mOwner ||
|
||||
!mOwner->IsHidden() ||
|
||||
(mPlayState != PLAY_STATE_PAUSED &&
|
||||
mPlayState != PLAY_STATE_ENDED))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mDormantTimer) {
|
||||
mDormantTimer = do_CreateInstance("@mozilla.org/timer;1");
|
||||
}
|
||||
mDormantTimer->InitWithFuncCallback(&MediaDecoder::DormantTimerExpired,
|
||||
this,
|
||||
mHeuristicDormantTimeout,
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
}
|
||||
|
||||
void MediaDecoder::CancelDormantTimer()
|
||||
{
|
||||
if (mDormantTimer) {
|
||||
mDormantTimer->Cancel();
|
||||
}
|
||||
}
|
||||
|
||||
void MediaDecoder::Pause()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
@ -472,7 +545,13 @@ MediaDecoder::MediaDecoder() :
|
|||
mPausedForPlaybackRateNull(false),
|
||||
mMinimizePreroll(false),
|
||||
mMediaTracksConstructed(false),
|
||||
mIsDormant(false)
|
||||
mIsDormant(false),
|
||||
mIsHeuristicDormantSupported(
|
||||
Preferences::GetBool("media.decoder.heuristic.dormant.enabled", false)),
|
||||
mHeuristicDormantTimeout(
|
||||
Preferences::GetInt("media.decoder.heuristic.dormant.timeout",
|
||||
DEFAULT_HEURISTIC_DORMANT_TIMEOUT_MSECS)),
|
||||
mIsHeuristicDormant(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(MediaDecoder);
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
@ -521,6 +600,8 @@ void MediaDecoder::Shutdown()
|
|||
mResource->Close();
|
||||
}
|
||||
|
||||
CancelDormantTimer();
|
||||
|
||||
ChangeState(PLAY_STATE_SHUTDOWN);
|
||||
|
||||
mOwner = nullptr;
|
||||
|
@ -622,6 +703,8 @@ nsresult MediaDecoder::Play()
|
|||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
UpdateDormantState(false /* aDormantTimeout */, true /* aActivity */);
|
||||
|
||||
NS_ASSERTION(mDecoderStateMachine != nullptr, "Should have state machine.");
|
||||
if (mPausedForPlaybackRateNull) {
|
||||
return NS_OK;
|
||||
|
@ -644,6 +727,7 @@ nsresult MediaDecoder::Seek(double aTime, SeekTarget::Type aSeekType)
|
|||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
UpdateDormantState(false /* aDormantTimeout */, true /* aActivity */);
|
||||
|
||||
NS_ABORT_IF_FALSE(aTime >= 0.0, "Cannot seek to a negative value.");
|
||||
|
||||
|
@ -1192,6 +1276,10 @@ void MediaDecoder::ChangeState(PlayState aState)
|
|||
|
||||
ApplyStateToStateMachine(mPlayState);
|
||||
|
||||
CancelDormantTimer();
|
||||
// Start dormant timer if necessary
|
||||
StartDormantTimer();
|
||||
|
||||
GetReentrantMonitor().NotifyAll();
|
||||
}
|
||||
|
||||
|
|
|
@ -188,6 +188,7 @@ destroying the MediaDecoder object.
|
|||
#include "nsCOMPtr.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsITimer.h"
|
||||
#include "MediaResource.h"
|
||||
#include "mozilla/dom/AudioChannelBinding.h"
|
||||
#include "mozilla/gfx/Rect.h"
|
||||
|
@ -367,6 +368,8 @@ public:
|
|||
// It is used to share scarece media resources in system.
|
||||
virtual void NotifyOwnerActivityChanged();
|
||||
|
||||
void UpdateDormantState(bool aDormantTimeout, bool aActivity);
|
||||
|
||||
// Pause video playback.
|
||||
virtual void Pause();
|
||||
// Adjust the speed of the playback, optionally with pitch correction,
|
||||
|
@ -1022,6 +1025,14 @@ protected:
|
|||
virtual ~MediaDecoder();
|
||||
void SetStateMachineParameters();
|
||||
|
||||
static void DormantTimerExpired(nsITimer *aTimer, void *aClosure);
|
||||
|
||||
// Start a timer for heuristic dormant.
|
||||
void StartDormantTimer();
|
||||
|
||||
// Cancel a timer for heuristic dormant.
|
||||
void CancelDormantTimer();
|
||||
|
||||
/******
|
||||
* The following members should be accessed with the decoder lock held.
|
||||
******/
|
||||
|
@ -1219,6 +1230,18 @@ protected:
|
|||
|
||||
// True if MediaDecoder is in dormant state.
|
||||
bool mIsDormant;
|
||||
|
||||
// True if heuristic dormant is supported.
|
||||
const bool mIsHeuristicDormantSupported;
|
||||
|
||||
// Timeout ms of heuristic dormant timer.
|
||||
const int mHeuristicDormantTimeout;
|
||||
|
||||
// True if MediaDecoder is in dormant by heuristic.
|
||||
bool mIsHeuristicDormant;
|
||||
|
||||
// Timer to schedule updating dormant state.
|
||||
nsCOMPtr<nsITimer> mDormantTimer;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -21,8 +21,6 @@ interface KeyboardEvent : UIEvent
|
|||
const unsigned long DOM_KEY_LOCATION_LEFT = 0x01;
|
||||
const unsigned long DOM_KEY_LOCATION_RIGHT = 0x02;
|
||||
const unsigned long DOM_KEY_LOCATION_NUMPAD = 0x03;
|
||||
const unsigned long DOM_KEY_LOCATION_MOBILE = 0x04;
|
||||
const unsigned long DOM_KEY_LOCATION_JOYSTICK = 0x05;
|
||||
|
||||
readonly attribute unsigned long location;
|
||||
readonly attribute boolean repeat;
|
||||
|
|
|
@ -53,6 +53,7 @@ gfxHarfBuzzShaper::gfxHarfBuzzShaper(gfxFont *aFont)
|
|||
mUseFontGlyphWidths(false),
|
||||
mInitialized(false),
|
||||
mVerticalInitialized(false),
|
||||
mLoadedLocaGlyf(false),
|
||||
mLocaLongOffsets(false)
|
||||
{
|
||||
}
|
||||
|
@ -346,54 +347,13 @@ gfxHarfBuzzShaper::GetGlyphVOrigin(hb_codepoint_t aGlyph,
|
|||
}
|
||||
|
||||
if (mVmtxTable) {
|
||||
if (mLocaTable && mGlyfTable) {
|
||||
// TrueType outlines: use glyph bbox + top sidebearing
|
||||
uint32_t offset; // offset of glyph record in the 'glyf' table
|
||||
uint32_t len;
|
||||
const char* data = hb_blob_get_data(mLocaTable, &len);
|
||||
if (mLocaLongOffsets) {
|
||||
if ((aGlyph + 1) * sizeof(AutoSwap_PRUint32) > len) {
|
||||
*aY = 0;
|
||||
return;
|
||||
}
|
||||
const AutoSwap_PRUint32* offsets =
|
||||
reinterpret_cast<const AutoSwap_PRUint32*>(data);
|
||||
offset = offsets[aGlyph];
|
||||
if (offset == offsets[aGlyph + 1]) {
|
||||
// empty glyph
|
||||
*aY = 0;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if ((aGlyph + 1) * sizeof(AutoSwap_PRUint16) > len) {
|
||||
*aY = 0;
|
||||
return;
|
||||
}
|
||||
const AutoSwap_PRUint16* offsets =
|
||||
reinterpret_cast<const AutoSwap_PRUint16*>(data);
|
||||
offset = uint16_t(offsets[aGlyph]);
|
||||
if (offset == uint16_t(offsets[aGlyph + 1])) {
|
||||
// empty glyph
|
||||
*aY = 0;
|
||||
return;
|
||||
}
|
||||
offset *= 2;
|
||||
}
|
||||
|
||||
struct Glyf { // we only need the bounding-box at the beginning
|
||||
// of the glyph record, not the actual outline data
|
||||
AutoSwap_PRInt16 numberOfContours;
|
||||
AutoSwap_PRInt16 xMin;
|
||||
AutoSwap_PRInt16 yMin;
|
||||
AutoSwap_PRInt16 xMax;
|
||||
AutoSwap_PRInt16 yMax;
|
||||
};
|
||||
data = hb_blob_get_data(mGlyfTable, &len);
|
||||
if (offset + sizeof(Glyf) > len) {
|
||||
bool emptyGlyf;
|
||||
const Glyf *glyf = FindGlyf(aGlyph, &emptyGlyf);
|
||||
if (glyf) {
|
||||
if (emptyGlyf) {
|
||||
*aY = 0;
|
||||
return;
|
||||
}
|
||||
const Glyf* glyf = reinterpret_cast<const Glyf*>(data + offset);
|
||||
|
||||
if (aGlyph >= uint32_t(mNumLongVMetrics)) {
|
||||
aGlyph = mNumLongVMetrics - 1;
|
||||
|
@ -406,7 +366,8 @@ gfxHarfBuzzShaper::GetGlyphVOrigin(hb_codepoint_t aGlyph,
|
|||
int16_t(glyf->yMax)));
|
||||
return;
|
||||
} else {
|
||||
// XXX TODO: CFF outlines - need to get glyph extents.
|
||||
// XXX TODO: not a truetype font; need to get glyph extents
|
||||
// via some other API?
|
||||
// For now, fall through to default code below.
|
||||
}
|
||||
}
|
||||
|
@ -431,6 +392,112 @@ gfxHarfBuzzShaper::GetGlyphVOrigin(hb_codepoint_t aGlyph,
|
|||
*aY = -FloatToFixed(GetFont()->GetAdjustedSize() / 2);
|
||||
}
|
||||
|
||||
static hb_bool_t
|
||||
HBGetGlyphExtents(hb_font_t *font, void *font_data,
|
||||
hb_codepoint_t glyph,
|
||||
hb_glyph_extents_t *extents,
|
||||
void *user_data)
|
||||
{
|
||||
const gfxHarfBuzzShaper::FontCallbackData *fcd =
|
||||
static_cast<const gfxHarfBuzzShaper::FontCallbackData*>(font_data);
|
||||
return fcd->mShaper->GetGlyphExtents(glyph, extents);
|
||||
}
|
||||
|
||||
// Find the data for glyph ID |aGlyph| in the 'glyf' table, if present.
|
||||
// Returns null if not found, otherwise pointer to the beginning of the
|
||||
// glyph's data. Sets aEmptyGlyf true if there is no actual data;
|
||||
// otherwise, it's guaranteed that we can read at least the bounding box.
|
||||
const gfxHarfBuzzShaper::Glyf*
|
||||
gfxHarfBuzzShaper::FindGlyf(hb_codepoint_t aGlyph, bool *aEmptyGlyf) const
|
||||
{
|
||||
if (!mLoadedLocaGlyf) {
|
||||
mLoadedLocaGlyf = true; // only try this once; if it fails, this
|
||||
// isn't a truetype font
|
||||
gfxFontEntry *entry = mFont->GetFontEntry();
|
||||
uint32_t len;
|
||||
gfxFontEntry::AutoTable headTable(entry,
|
||||
TRUETYPE_TAG('h','e','a','d'));
|
||||
const HeadTable* head =
|
||||
reinterpret_cast<const HeadTable*>(hb_blob_get_data(headTable,
|
||||
&len));
|
||||
if (len < sizeof(HeadTable)) {
|
||||
return nullptr;
|
||||
}
|
||||
mLocaLongOffsets = int16_t(head->indexToLocFormat) > 0;
|
||||
mLocaTable = entry->GetFontTable(TRUETYPE_TAG('l','o','c','a'));
|
||||
mGlyfTable = entry->GetFontTable(TRUETYPE_TAG('g','l','y','f'));
|
||||
}
|
||||
|
||||
if (!mLocaTable || !mGlyfTable) {
|
||||
// it's not a truetype font
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint32_t offset; // offset of glyph record in the 'glyf' table
|
||||
uint32_t len;
|
||||
const char* data = hb_blob_get_data(mLocaTable, &len);
|
||||
if (mLocaLongOffsets) {
|
||||
if ((aGlyph + 1) * sizeof(AutoSwap_PRUint32) > len) {
|
||||
return nullptr;
|
||||
}
|
||||
const AutoSwap_PRUint32* offsets =
|
||||
reinterpret_cast<const AutoSwap_PRUint32*>(data);
|
||||
offset = offsets[aGlyph];
|
||||
*aEmptyGlyf = (offset == uint16_t(offsets[aGlyph + 1]));
|
||||
} else {
|
||||
if ((aGlyph + 1) * sizeof(AutoSwap_PRUint16) > len) {
|
||||
return nullptr;
|
||||
}
|
||||
const AutoSwap_PRUint16* offsets =
|
||||
reinterpret_cast<const AutoSwap_PRUint16*>(data);
|
||||
offset = uint16_t(offsets[aGlyph]);
|
||||
*aEmptyGlyf = (offset == uint16_t(offsets[aGlyph + 1]));
|
||||
offset *= 2;
|
||||
}
|
||||
|
||||
data = hb_blob_get_data(mGlyfTable, &len);
|
||||
if (offset + sizeof(Glyf) > len) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return reinterpret_cast<const Glyf*>(data + offset);
|
||||
}
|
||||
|
||||
hb_bool_t
|
||||
gfxHarfBuzzShaper::GetGlyphExtents(hb_codepoint_t aGlyph,
|
||||
hb_glyph_extents_t *aExtents) const
|
||||
{
|
||||
bool emptyGlyf;
|
||||
const Glyf *glyf = FindGlyf(aGlyph, &emptyGlyf);
|
||||
if (!glyf) {
|
||||
// TODO: for non-truetype fonts, get extents some other way?
|
||||
return false;
|
||||
}
|
||||
|
||||
if (emptyGlyf) {
|
||||
aExtents->x_bearing = 0;
|
||||
aExtents->y_bearing = 0;
|
||||
aExtents->width = 0;
|
||||
aExtents->height = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
double f = mFont->FUnitsToDevUnitsFactor();
|
||||
aExtents->x_bearing = FloatToFixed(int16_t(glyf->xMin) * f);
|
||||
aExtents->width =
|
||||
FloatToFixed((int16_t(glyf->xMax) - int16_t(glyf->xMin)) * f);
|
||||
|
||||
// Our y-coordinates are positive-downwards, whereas harfbuzz assumes
|
||||
// positive-upwards; hence the apparently-reversed subtractions here.
|
||||
aExtents->y_bearing =
|
||||
FloatToFixed(int16_t(glyf->yMax) * f -
|
||||
mFont->GetHorizontalMetrics().emAscent);
|
||||
aExtents->height =
|
||||
FloatToFixed((int16_t(glyf->yMin) - int16_t(glyf->yMax)) * f);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static hb_bool_t
|
||||
HBGetContourPoint(hb_font_t *font, void *font_data,
|
||||
unsigned int point_index, hb_codepoint_t glyph,
|
||||
|
@ -1066,6 +1133,9 @@ gfxHarfBuzzShaper::Initialize()
|
|||
hb_font_funcs_set_glyph_v_origin_func(sHBFontFuncs,
|
||||
HBGetGlyphVOrigin,
|
||||
nullptr, nullptr);
|
||||
hb_font_funcs_set_glyph_extents_func(sHBFontFuncs,
|
||||
HBGetGlyphExtents,
|
||||
nullptr, nullptr);
|
||||
hb_font_funcs_set_glyph_contour_point_func(sHBFontFuncs,
|
||||
HBGetContourPoint,
|
||||
nullptr, nullptr);
|
||||
|
@ -1225,20 +1295,6 @@ gfxHarfBuzzShaper::InitializeVertical()
|
|||
mVORGTable = nullptr;
|
||||
}
|
||||
}
|
||||
} else if (mVmtxTable) {
|
||||
// Otherwise, try to load loca and glyf tables so that we can read
|
||||
// bounding boxes (needed to support vertical glyph origin).
|
||||
uint32_t len;
|
||||
gfxFontEntry::AutoTable headTable(entry,
|
||||
TRUETYPE_TAG('h','e','a','d'));
|
||||
const HeadTable* head =
|
||||
reinterpret_cast<const HeadTable*>(hb_blob_get_data(headTable,
|
||||
&len));
|
||||
if (len >= sizeof(HeadTable)) {
|
||||
mLocaLongOffsets = int16_t(head->indexToLocFormat) > 0;
|
||||
mLocaTable = entry->GetFontTable(TRUETYPE_TAG('l','o','c','a'));
|
||||
mGlyfTable = entry->GetFontTable(TRUETYPE_TAG('g','l','y','f'));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -73,6 +73,9 @@ public:
|
|||
hb_position_t GetHKerning(uint16_t aFirstGlyph,
|
||||
uint16_t aSecondGlyph) const;
|
||||
|
||||
hb_bool_t GetGlyphExtents(hb_codepoint_t aGlyph,
|
||||
hb_glyph_extents_t *aExtents) const;
|
||||
|
||||
static hb_script_t
|
||||
GetHBScriptUsedForShaping(int32_t aScript) {
|
||||
// Decide what harfbuzz script code will be used for shaping
|
||||
|
@ -107,6 +110,17 @@ protected:
|
|||
bool InitializeVertical();
|
||||
bool LoadHmtxTable();
|
||||
|
||||
struct Glyf { // we only need the bounding-box at the beginning
|
||||
// of the glyph record, not the actual outline data
|
||||
AutoSwap_PRInt16 numberOfContours;
|
||||
AutoSwap_PRInt16 xMin;
|
||||
AutoSwap_PRInt16 yMin;
|
||||
AutoSwap_PRInt16 xMax;
|
||||
AutoSwap_PRInt16 yMax;
|
||||
};
|
||||
|
||||
const Glyf *FindGlyf(hb_codepoint_t aGlyph, bool *aEmptyGlyf) const;
|
||||
|
||||
// harfbuzz face object: we acquire a reference from the font entry
|
||||
// on shaper creation, and release it in our destructor
|
||||
hb_face_t *mHBFace;
|
||||
|
@ -161,7 +175,10 @@ protected:
|
|||
|
||||
bool mInitialized;
|
||||
bool mVerticalInitialized;
|
||||
bool mLocaLongOffsets;
|
||||
|
||||
// these are set from the FindGlyf callback on first use of the glyf data
|
||||
mutable bool mLoadedLocaGlyf;
|
||||
mutable bool mLocaLongOffsets;
|
||||
};
|
||||
|
||||
#endif /* GFX_HARFBUZZSHAPER_H */
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <dbus/dbus-glib-lowlevel.h>
|
||||
#include <mozilla/dom/battery/Constants.h>
|
||||
#include "nsAutoRef.h"
|
||||
#include <cmath>
|
||||
|
||||
/*
|
||||
* Helper that manages the destruction of glib objects as soon as they leave
|
||||
|
@ -428,14 +429,14 @@ UPowerClient::UpdateSavedInfo(GHashTable* aHashTable)
|
|||
}
|
||||
|
||||
/*
|
||||
* The battery level might be very close to 100% (like 99.xxxx%) without
|
||||
* The battery level might be very close to 100% (like 99%) without
|
||||
* increasing. It seems that upower sets the battery state as 'full' in that
|
||||
* case so we should trust it and not even try to get the value.
|
||||
*/
|
||||
if (isFull) {
|
||||
mLevel = 1.0;
|
||||
} else {
|
||||
mLevel = g_value_get_double(static_cast<const GValue*>(g_hash_table_lookup(aHashTable, "Percentage")))*0.01;
|
||||
mLevel = round(g_value_get_double(static_cast<const GValue*>(g_hash_table_lookup(aHashTable, "Percentage"))))*0.01;
|
||||
}
|
||||
|
||||
if (isFull) {
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
if (!this.hasOwnProperty("SIMD"))
|
||||
quit();
|
||||
|
||||
setJitCompilerOption("baseline.warmup.trigger", 10);
|
||||
setJitCompilerOption("ion.warmup.trigger", 30);
|
||||
|
|
@ -4,6 +4,9 @@
|
|||
// as plain JS) as it should be. That gave rise to a difference in
|
||||
// output.
|
||||
|
||||
if (!this.SharedArrayBuffer)
|
||||
quit(0);
|
||||
|
||||
// Original test
|
||||
|
||||
g = (function(stdlib, n, heap) {
|
||||
|
|
|
@ -3735,6 +3735,10 @@ already_AddRefed<Layer>
|
|||
nsDisplayOpacity::BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager,
|
||||
const ContainerLayerParameters& aContainerParameters) {
|
||||
if (mOpacity == 0 && mFrame->GetContent() &&
|
||||
!nsLayoutUtils::HasAnimations(mFrame->GetContent(), eCSSProperty_opacity)) {
|
||||
return nullptr;
|
||||
}
|
||||
nsRefPtr<Layer> container = aManager->GetLayerBuilder()->
|
||||
BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList,
|
||||
aContainerParameters, nullptr);
|
||||
|
|
|
@ -2921,10 +2921,22 @@ nsBlockFrame::AttributeChanged(int32_t aNameSpaceID,
|
|||
}
|
||||
|
||||
static inline bool
|
||||
IsNonAutoNonZeroHeight(const nsStyleCoord& aCoord)
|
||||
IsNonAutoNonZeroBSize(const nsStyleCoord& aCoord)
|
||||
{
|
||||
if (aCoord.GetUnit() == eStyleUnit_Auto)
|
||||
nsStyleUnit unit = aCoord.GetUnit();
|
||||
if (unit == eStyleUnit_Auto ||
|
||||
// The enumerated values were originally aimed at inline-size
|
||||
// (or width, as it was before logicalization). For now, let them
|
||||
// return false here, so we treat them like 'auto' pending a
|
||||
// real implementation. (See bug 1126420.)
|
||||
//
|
||||
// FIXME (bug 567039, bug 527285)
|
||||
// This isn't correct for the 'fill' value, which should more
|
||||
// likely (but not necessarily, depending on the available space)
|
||||
// be returning true.
|
||||
unit == eStyleUnit_Enumerated) {
|
||||
return false;
|
||||
}
|
||||
if (aCoord.IsCoordPercentCalcUnit()) {
|
||||
// If we evaluate the length/percent/calc at a percentage basis of
|
||||
// both nscoord_MAX and 0, and it's zero both ways, then it's a zero
|
||||
|
@ -2951,13 +2963,13 @@ nsBlockFrame::IsSelfEmpty()
|
|||
bool vertical = GetWritingMode().IsVertical();
|
||||
|
||||
if (vertical) {
|
||||
if (IsNonAutoNonZeroHeight(position->mMinWidth) ||
|
||||
IsNonAutoNonZeroHeight(position->mWidth)) {
|
||||
if (IsNonAutoNonZeroBSize(position->mMinWidth) ||
|
||||
IsNonAutoNonZeroBSize(position->mWidth)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (IsNonAutoNonZeroHeight(position->mMinHeight) ||
|
||||
IsNonAutoNonZeroHeight(position->mHeight)) {
|
||||
if (IsNonAutoNonZeroBSize(position->mMinHeight) ||
|
||||
IsNonAutoNonZeroBSize(position->mHeight)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1948,6 +1948,17 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
|
|||
return;
|
||||
|
||||
const nsStyleDisplay* disp = StyleDisplay();
|
||||
// We can stop right away if this is a zero-opacity stacking context and
|
||||
// we're painting, and we're not animating opacity. Don't do this
|
||||
// if we're going to compute plugin geometry, since opacity-0 plugins
|
||||
// need to have display items built for them.
|
||||
if (disp->mOpacity == 0.0 && aBuilder->IsForPainting() &&
|
||||
!aBuilder->WillComputePluginGeometry() &&
|
||||
!(disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_OPACITY) &&
|
||||
!nsLayoutUtils::HasAnimations(mContent, eCSSProperty_opacity)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (disp->mWillChangeBitField != 0) {
|
||||
aBuilder->AddToWillChangeBudget(this, GetSize());
|
||||
}
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset=utf-8>
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: test;
|
||||
/* Note that this font has no OpenType layout tables: */
|
||||
src: url(../fonts/sil/GenR102.ttf);
|
||||
}
|
||||
body {
|
||||
font-family: test;
|
||||
}
|
||||
.test {
|
||||
font-size: 100px;
|
||||
line-height: 2;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
These examples should NOT look the same:
|
||||
<div class=test>x̃̂ x̂̃</div>
|
||||
</body>
|
|
@ -0,0 +1,23 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset=utf-8>
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: test;
|
||||
/* Note that this font has no OpenType layout tables: */
|
||||
src: url(../fonts/sil/GenR102.ttf);
|
||||
}
|
||||
body {
|
||||
font-family: test;
|
||||
}
|
||||
.test {
|
||||
font-size: 100px;
|
||||
line-height: 2;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
These examples should NOT look the same:
|
||||
<div class=test>x̂̃ x̃̂</div>
|
||||
</body>
|
|
@ -163,6 +163,8 @@ fails-if(cocoaWidget||Android||B2G) HTTP(..) == arabic-fallback-2.html arabic-fa
|
|||
fails-if(cocoaWidget||Android||B2G) HTTP(..) == arabic-fallback-3.html arabic-fallback-3-ref.html
|
||||
fails-if(!cocoaWidget&&!Android&&!B2G) HTTP(..) != arabic-fallback-4.html arabic-fallback-4-notref.html
|
||||
== arabic-marks-1.html arabic-marks-1-ref.html
|
||||
# harfbuzz fallback mark stacking in the absence of GPOS:
|
||||
HTTP(..) != fallback-mark-stacking-1.html fallback-mark-stacking-1-notref.html
|
||||
|
||||
== 726392-1.html 726392-1-ref.html
|
||||
== 726392-2.html 726392-2-ref.html
|
||||
|
|
|
@ -115,26 +115,6 @@ public class GeckoEvent {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The DomKeyLocation enum encapsulates the DOM KeyboardEvent's constants.
|
||||
* @see https://developer.mozilla.org/en-US/docs/DOM/KeyboardEvent#Key_location_constants
|
||||
*/
|
||||
@JNITarget
|
||||
public enum DomKeyLocation {
|
||||
DOM_KEY_LOCATION_STANDARD(0),
|
||||
DOM_KEY_LOCATION_LEFT(1),
|
||||
DOM_KEY_LOCATION_RIGHT(2),
|
||||
DOM_KEY_LOCATION_NUMPAD(3),
|
||||
DOM_KEY_LOCATION_MOBILE(4),
|
||||
DOM_KEY_LOCATION_JOYSTICK(5);
|
||||
|
||||
public final int value;
|
||||
|
||||
private DomKeyLocation(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
// Encapsulation of common IME actions.
|
||||
@JNITarget
|
||||
public enum ImeAction {
|
||||
|
@ -223,7 +203,6 @@ public class GeckoEvent {
|
|||
private int mRangeLineColor;
|
||||
private Location mLocation;
|
||||
private Address mAddress;
|
||||
private DomKeyLocation mDomKeyLocation;
|
||||
|
||||
private int mConnectionType;
|
||||
private boolean mIsWifi;
|
||||
|
@ -313,30 +292,6 @@ public class GeckoEvent {
|
|||
mDOMPrintableKeyValue = k.getUnicodeChar(unmodifiedMetaState);
|
||||
}
|
||||
}
|
||||
mDomKeyLocation = isJoystickButton(mKeyCode) ? DomKeyLocation.DOM_KEY_LOCATION_JOYSTICK
|
||||
: DomKeyLocation.DOM_KEY_LOCATION_MOBILE;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method tests if a key is one of the described in:
|
||||
* https://bugzilla.mozilla.org/show_bug.cgi?id=756504#c0
|
||||
* @param keyCode int with the key code (Android key constant from KeyEvent)
|
||||
* @return true if the key is one of the listed above, false otherwise.
|
||||
*/
|
||||
private static boolean isJoystickButton(int keyCode) {
|
||||
switch (keyCode) {
|
||||
case KeyEvent.KEYCODE_DPAD_CENTER:
|
||||
case KeyEvent.KEYCODE_DPAD_LEFT:
|
||||
case KeyEvent.KEYCODE_DPAD_RIGHT:
|
||||
case KeyEvent.KEYCODE_DPAD_DOWN:
|
||||
case KeyEvent.KEYCODE_DPAD_UP:
|
||||
return true;
|
||||
default:
|
||||
if (Versions.feature12Plus) {
|
||||
return KeyEvent.isGamepadButton(keyCode);
|
||||
}
|
||||
return GeckoEvent.isGamepadButton(keyCode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1319,6 +1319,7 @@ pref("network.http.spdy.ping-timeout", 8);
|
|||
pref("network.http.spdy.send-buffer-size", 131072);
|
||||
pref("network.http.spdy.allow-push", true);
|
||||
pref("network.http.spdy.push-allowance", 131072);
|
||||
pref("network.http.spdy.default-concurrent", 100);
|
||||
|
||||
// alt-svc allows separation of transport routing from
|
||||
// the origin host without using a proxy.
|
||||
|
|
|
@ -50,6 +50,8 @@ public:
|
|||
// scenarios.
|
||||
const static uint32_t kInitialRwin = 256 * 1024 * 1024;
|
||||
|
||||
const static uint32_t kDefaultMaxConcurrent = 100;
|
||||
|
||||
// soft errors are errors that terminate a stream without terminating the
|
||||
// connection. In general non-network errors are stream errors as well
|
||||
// as network specific items like cancels.
|
||||
|
|
|
@ -89,7 +89,6 @@ Http2Session::Http2Session(nsISocketTransport *aSocketTransport, uint32_t versio
|
|||
, mGoAwayReason(NO_HTTP_ERROR)
|
||||
, mGoAwayID(0)
|
||||
, mOutgoingGoAwayID(0)
|
||||
, mMaxConcurrent(kDefaultMaxConcurrent)
|
||||
, mConcurrent(0)
|
||||
, mServerPushedResources(0)
|
||||
, mServerInitialStreamWindow(kDefaultRwin)
|
||||
|
@ -119,7 +118,7 @@ Http2Session::Http2Session(nsISocketTransport *aSocketTransport, uint32_t versio
|
|||
mDecompressor.SetCompressor(&mCompressor);
|
||||
|
||||
mPushAllowance = gHttpHandler->SpdyPushAllowance();
|
||||
|
||||
mMaxConcurrent = gHttpHandler->DefaultSpdyConcurrent();
|
||||
mSendingChunkSize = gHttpHandler->SpdySendingChunkSize();
|
||||
SendHello();
|
||||
|
||||
|
|
|
@ -135,7 +135,6 @@ public:
|
|||
const static uint32_t kQueueTailRoom = 4096;
|
||||
const static uint32_t kQueueReserved = 1024;
|
||||
|
||||
const static uint32_t kDefaultMaxConcurrent = 100;
|
||||
const static uint32_t kMaxStreamID = 0x7800000;
|
||||
|
||||
// This is a sentinel for a deleted stream. It is not a valid
|
||||
|
|
|
@ -184,11 +184,10 @@ Http2Stream::ReadSegments(nsAHttpSegmentReader *reader,
|
|||
|
||||
// If the sending flow control window is open (!mBlockedOnRwin) then
|
||||
// continue sending the request
|
||||
if (!mBlockedOnRwin && mUpstreamState != GENERATING_HEADERS &&
|
||||
if (!mBlockedOnRwin && mOpenGenerated &&
|
||||
!mTxInlineFrameUsed && NS_SUCCEEDED(rv) && (!*countRead)) {
|
||||
MOZ_ASSERT(!mQueued);
|
||||
MOZ_ASSERT(mRequestHeadersDone);
|
||||
MOZ_ASSERT(mOpenGenerated);
|
||||
LOG3(("Http2Stream::ReadSegments %p 0x%X: Sending request data complete, "
|
||||
"mUpstreamState=%x\n",this, mStreamID, mUpstreamState));
|
||||
if (mSentFin) {
|
||||
|
@ -1234,7 +1233,7 @@ Http2Stream::OnReadSegment(const char *buf,
|
|||
if (mRequestHeadersDone && !mOpenGenerated) {
|
||||
if (!mSession->TryToActivate(this)) {
|
||||
LOG3(("Http2Stream::OnReadSegment %p cannot activate now. queued.\n", this));
|
||||
return NS_OK;
|
||||
return *countRead ? NS_OK : NS_BASE_STREAM_WOULD_BLOCK;
|
||||
}
|
||||
if (NS_FAILED(rv = GenerateOpen())) {
|
||||
return rv;
|
||||
|
|
|
@ -63,7 +63,6 @@ SpdySession31::SpdySession31(nsISocketTransport *aSocketTransport)
|
|||
, mCleanShutdown(false)
|
||||
, mDataPending(false)
|
||||
, mGoAwayID(0)
|
||||
, mMaxConcurrent(kDefaultMaxConcurrent)
|
||||
, mConcurrent(0)
|
||||
, mServerPushedResources(0)
|
||||
, mServerInitialStreamWindow(kDefaultRwin)
|
||||
|
@ -89,7 +88,7 @@ SpdySession31::SpdySession31(nsISocketTransport *aSocketTransport)
|
|||
zlibInit();
|
||||
|
||||
mPushAllowance = gHttpHandler->SpdyPushAllowance();
|
||||
|
||||
mMaxConcurrent = gHttpHandler->DefaultSpdyConcurrent();
|
||||
mSendingChunkSize = gHttpHandler->SpdySendingChunkSize();
|
||||
GenerateSettings();
|
||||
|
||||
|
|
|
@ -134,7 +134,6 @@ public:
|
|||
const static uint32_t kQueueTailRoom = 4096;
|
||||
const static uint32_t kQueueReserved = 1024;
|
||||
|
||||
const static uint32_t kDefaultMaxConcurrent = 100;
|
||||
const static uint32_t kMaxStreamID = 0x7800000;
|
||||
|
||||
// This is a sentinel for a deleted stream. It is not a valid
|
||||
|
|
|
@ -160,7 +160,7 @@ SpdyStream31::ReadSegments(nsAHttpSegmentReader *reader,
|
|||
|
||||
// If the sending flow control window is open (!mBlockedOnRwin) then
|
||||
// continue sending the request
|
||||
if (!mBlockedOnRwin && mUpstreamState != GENERATING_SYN_STREAM &&
|
||||
if (!mBlockedOnRwin && mSynFrameGenerated &&
|
||||
!mTxInlineFrameUsed && NS_SUCCEEDED(rv) && (!*countRead)) {
|
||||
LOG3(("SpdyStream31::ReadSegments %p 0x%X: Sending request data complete, "
|
||||
"mUpstreamState=%x finondata=%d",this, mStreamID,
|
||||
|
@ -1491,7 +1491,7 @@ SpdyStream31::OnReadSegment(const char *buf,
|
|||
if (mRequestHeadersDone && !mSynFrameGenerated) {
|
||||
if (!mSession->TryToActivate(this)) {
|
||||
LOG3(("SpdyStream31::OnReadSegment %p cannot activate now. queued.\n", this));
|
||||
return NS_OK;
|
||||
return *countRead ? NS_OK : NS_BASE_STREAM_WOULD_BLOCK;
|
||||
}
|
||||
if (NS_FAILED(rv = GenerateSynFrame())) {
|
||||
return rv;
|
||||
|
|
|
@ -194,6 +194,7 @@ nsHttpHandler::nsHttpHandler()
|
|||
, mSpdySendingChunkSize(ASpdySession::kSendingChunkSize)
|
||||
, mSpdySendBufferSize(ASpdySession::kTCPSendBufferSize)
|
||||
, mSpdyPushAllowance(32768)
|
||||
, mDefaultSpdyConcurrent(ASpdySession::kDefaultMaxConcurrent)
|
||||
, mSpdyPingThreshold(PR_SecondsToInterval(58))
|
||||
, mSpdyPingTimeout(PR_SecondsToInterval(8))
|
||||
, mConnectTimeout(90000)
|
||||
|
@ -1287,6 +1288,14 @@ nsHttpHandler::PrefsChanged(nsIPrefBranch *prefs, const char *pref)
|
|||
}
|
||||
}
|
||||
|
||||
if (PREF_CHANGED(HTTP_PREF("spdy.default-concurrent"))) {
|
||||
rv = prefs->GetIntPref(HTTP_PREF("spdy.default-concurrent"), &val);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mDefaultSpdyConcurrent =
|
||||
static_cast<uint32_t>(std::max<int32_t>(std::min<int32_t>(val, 9999), 1));
|
||||
}
|
||||
}
|
||||
|
||||
// The amount of seconds to wait for a spdy ping response before
|
||||
// closing the session.
|
||||
if (PREF_CHANGED(HTTP_PREF("spdy.send-buffer-size"))) {
|
||||
|
|
|
@ -105,6 +105,7 @@ public:
|
|||
uint32_t SpdySendingChunkSize() { return mSpdySendingChunkSize; }
|
||||
uint32_t SpdySendBufferSize() { return mSpdySendBufferSize; }
|
||||
uint32_t SpdyPushAllowance() { return mSpdyPushAllowance; }
|
||||
uint32_t DefaultSpdyConcurrent() { return mDefaultSpdyConcurrent; }
|
||||
PRIntervalTime SpdyPingThreshold() { return mSpdyPingThreshold; }
|
||||
PRIntervalTime SpdyPingTimeout() { return mSpdyPingTimeout; }
|
||||
bool AllowPush() { return mAllowPush; }
|
||||
|
@ -487,6 +488,7 @@ private:
|
|||
uint32_t mSpdySendingChunkSize;
|
||||
uint32_t mSpdySendBufferSize;
|
||||
uint32_t mSpdyPushAllowance;
|
||||
uint32_t mDefaultSpdyConcurrent;
|
||||
PRIntervalTime mSpdyPingThreshold;
|
||||
PRIntervalTime mSpdyPingTimeout;
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ function generateContent(size) {
|
|||
var posts = [];
|
||||
posts.push(generateContent(10));
|
||||
posts.push(generateContent(250000));
|
||||
posts.push(generateContent(128000));
|
||||
|
||||
// pre-calculated md5sums (in hex) of the above posts
|
||||
var md5s = ['f1b708bba17f1ce948dc979f4d7092bc',
|
||||
|
@ -277,11 +278,20 @@ var Http2ConcurrentListener = function() {};
|
|||
Http2ConcurrentListener.prototype = new Http2CheckListener();
|
||||
Http2ConcurrentListener.prototype.count = 0;
|
||||
Http2ConcurrentListener.prototype.target = 0;
|
||||
Http2ConcurrentListener.prototype.reset = 0;
|
||||
Http2ConcurrentListener.prototype.recvdHdr = 0;
|
||||
|
||||
Http2ConcurrentListener.prototype.onStopRequest = function(request, ctx, status) {
|
||||
this.count++;
|
||||
do_check_true(this.isHttp2Connection);
|
||||
if (this.recvdHdr > 0) {
|
||||
do_check_eq(request.getResponseHeader("X-Recvd"), this.recvdHdr);
|
||||
}
|
||||
|
||||
if (this.count == this.target) {
|
||||
if (this.reset > 0) {
|
||||
prefs.setIntPref("network.http.spdy.default-concurrent", this.reset);
|
||||
}
|
||||
run_next_test();
|
||||
do_test_finished();
|
||||
}
|
||||
|
@ -290,6 +300,9 @@ Http2ConcurrentListener.prototype.onStopRequest = function(request, ctx, status)
|
|||
function test_http2_concurrent() {
|
||||
var concurrent_listener = new Http2ConcurrentListener();
|
||||
concurrent_listener.target = 201;
|
||||
concurrent_listener.reset = prefs.getIntPref("network.http.spdy.default-concurrent");
|
||||
prefs.setIntPref("network.http.spdy.default-concurrent", 100);
|
||||
|
||||
for (var i = 0; i < concurrent_listener.target; i++) {
|
||||
concurrent_channels[i] = makeChan("https://localhost:" + serverPort + "/750ms");
|
||||
concurrent_channels[i].loadFlags = Ci.nsIRequest.LOAD_BYPASS_CACHE;
|
||||
|
@ -297,6 +310,26 @@ function test_http2_concurrent() {
|
|||
}
|
||||
}
|
||||
|
||||
function test_http2_concurrent_post() {
|
||||
var concurrent_listener = new Http2ConcurrentListener();
|
||||
concurrent_listener.target = 8;
|
||||
concurrent_listener.recvdHdr = posts[2].length;
|
||||
concurrent_listener.reset = prefs.getIntPref("network.http.spdy.default-concurrent");
|
||||
prefs.setIntPref("network.http.spdy.default-concurrent", 3);
|
||||
|
||||
for (var i = 0; i < concurrent_listener.target; i++) {
|
||||
concurrent_channels[i] = makeChan("https://localhost:" + serverPort + "/750msPost");
|
||||
concurrent_channels[i].loadFlags = Ci.nsIRequest.LOAD_BYPASS_CACHE;
|
||||
var stream = Cc["@mozilla.org/io/string-input-stream;1"]
|
||||
.createInstance(Ci.nsIStringInputStream);
|
||||
stream.data = posts[2];
|
||||
var uchan = concurrent_channels[i].QueryInterface(Ci.nsIUploadChannel);
|
||||
uchan.setUploadStream(stream, "text/plain", stream.available());
|
||||
concurrent_channels[i].requestMethod = "POST";
|
||||
concurrent_channels[i].asyncOpen(concurrent_listener, null);
|
||||
}
|
||||
}
|
||||
|
||||
// Test to make sure we get multiplexing right
|
||||
function test_http2_multiplex() {
|
||||
var chan1 = makeChan("https://localhost:" + serverPort + "/multiplex1");
|
||||
|
@ -625,6 +658,7 @@ function test_complete() {
|
|||
var tests = [ test_http2_post_big
|
||||
, test_http2_basic
|
||||
, test_http2_concurrent
|
||||
, test_http2_concurrent_post
|
||||
, test_http2_basic_unblocked_dep
|
||||
, test_http2_nospdy
|
||||
, test_http2_push1
|
||||
|
|
|
@ -103,7 +103,9 @@ Log(const char* aMessageType,
|
|||
NS_DebugBreak(NS_DEBUG_WARNING, nullptr, msg.c_str(), nullptr, -1);
|
||||
#endif
|
||||
|
||||
nsContentUtils::LogMessageToConsole(msg.c_str());
|
||||
if (nsContentUtils::IsInitialized()) {
|
||||
nsContentUtils::LogMessageToConsole(msg.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize sandbox logging if required.
|
||||
|
|
|
@ -305,7 +305,12 @@ RESTRequest.prototype = {
|
|||
}
|
||||
|
||||
// Create and initialize HTTP channel.
|
||||
let channel = Services.io.newChannelFromURI(this.uri, null, null)
|
||||
let channel = Services.io.newChannelFromURI2(this.uri,
|
||||
null, // aLoadingNode
|
||||
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
null, // aTriggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_NORMAL,
|
||||
Ci.nsIContentPolicy.TYPE_OTHER)
|
||||
.QueryInterface(Ci.nsIRequest)
|
||||
.QueryInterface(Ci.nsIHttpChannel);
|
||||
this.channel = channel;
|
||||
|
|
|
@ -180,7 +180,12 @@ AboutWeaveLog.prototype = {
|
|||
newChannel: function(aURI) {
|
||||
let dir = FileUtils.getDir("ProfD", ["weave", "logs"], true);
|
||||
let uri = Services.io.newFileURI(dir);
|
||||
let channel = Services.io.newChannelFromURI(uri);
|
||||
let channel = Services.io.newChannelFromURI2(uri,
|
||||
null, // aLoadingNode
|
||||
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
null, // aTriggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_NORMAL,
|
||||
Ci.nsIContentPolicy.TYPE_OTHER);
|
||||
channel.originalURI = aURI;
|
||||
|
||||
// Ensure that the about page has the same privileges as a regular directory
|
||||
|
|
|
@ -146,7 +146,14 @@ AsyncResource.prototype = {
|
|||
// to obtain a request channel.
|
||||
//
|
||||
_createRequest: function Res__createRequest(method) {
|
||||
let channel = Services.io.newChannel(this.spec, null, null)
|
||||
let channel = Services.io.newChannel2(this.spec,
|
||||
null,
|
||||
null,
|
||||
null, // aLoadingNode
|
||||
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
null, // aTriggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_NORMAL,
|
||||
Ci.nsIContentPolicy.TYPE_OTHER)
|
||||
.QueryInterface(Ci.nsIRequest)
|
||||
.QueryInterface(Ci.nsIHttpChannel);
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ Cu.import("resource://services-sync/service.js");
|
|||
Cu.import("resource://services-sync/util.js");
|
||||
Cu.import("resource://gre/modules/FileUtils.jsm");
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const logsdir = FileUtils.getDir("ProfD", ["weave", "logs"], true);
|
||||
const LOG_PREFIX_SUCCESS = "success-";
|
||||
|
@ -81,11 +82,16 @@ add_test(function test_logOnSuccess_false() {
|
|||
});
|
||||
|
||||
function readFile(file, callback) {
|
||||
NetUtil.asyncFetch(file, function (inputStream, statusCode, request) {
|
||||
NetUtil.asyncFetch2(file, function (inputStream, statusCode, request) {
|
||||
let data = NetUtil.readInputStreamToString(inputStream,
|
||||
inputStream.available());
|
||||
callback(statusCode, data);
|
||||
});
|
||||
},
|
||||
null, // aLoadingNode
|
||||
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
null, // aTriggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_NORMAL,
|
||||
Ci.nsIContentPolicy.TYPE_OTHER);
|
||||
}
|
||||
|
||||
add_test(function test_logOnSuccess_true() {
|
||||
|
|
|
@ -552,12 +552,6 @@ function synthesizeKey(aKey, aEvent, aWindow)
|
|||
case KeyboardEvent.DOM_KEY_LOCATION_NUMPAD:
|
||||
flags |= utils.KEY_FLAG_LOCATION_NUMPAD;
|
||||
break;
|
||||
case KeyboardEvent.DOM_KEY_LOCATION_MOBILE:
|
||||
flags |= utils.KEY_FLAG_LOCATION_MOBILE;
|
||||
break;
|
||||
case KeyboardEvent.DOM_KEY_LOCATION_JOYSTICK:
|
||||
flags |= utils.KEY_FLAG_LOCATION_JOYSTICK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,14 @@ const STATE_ENABLED = 1;
|
|||
const STATE_DISABLED = 2;
|
||||
|
||||
function GetFileAsText(file) {
|
||||
let channel = Services.io.newChannel(file, null, null);
|
||||
let channel = Services.io.newChannel2(file,
|
||||
null,
|
||||
null,
|
||||
null, // aLoadingNode
|
||||
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
null, // aTriggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_NORMAL,
|
||||
Ci.nsIContentPolicy.TYPE_OTHER);
|
||||
let inputStream = channel.open();
|
||||
if (channel instanceof Ci.nsIHttpChannel &&
|
||||
channel.responseStatus != 200) {
|
||||
|
|
|
@ -586,12 +586,6 @@ function synthesizeKey(aKey, aEvent, aWindow)
|
|||
case KeyboardEvent.DOM_KEY_LOCATION_NUMPAD:
|
||||
flags |= utils.KEY_FLAG_LOCATION_NUMPAD;
|
||||
break;
|
||||
case KeyboardEvent.DOM_KEY_LOCATION_MOBILE:
|
||||
flags |= utils.KEY_FLAG_LOCATION_MOBILE;
|
||||
break;
|
||||
case KeyboardEvent.DOM_KEY_LOCATION_JOYSTICK:
|
||||
flags |= utils.KEY_FLAG_LOCATION_JOYSTICK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -283,6 +283,29 @@ function handleRequest(req, res) {
|
|||
return;
|
||||
}
|
||||
|
||||
else if (u.pathname === "/750msPost") {
|
||||
if (req.method != "POST") {
|
||||
res.writeHead(405);
|
||||
res.end('Unexpected method: ' + req.method);
|
||||
return;
|
||||
}
|
||||
|
||||
var accum = 0;
|
||||
req.on('data', function receivePostData(chunk) {
|
||||
accum += chunk.length;
|
||||
});
|
||||
req.on('end', function finishPost() {
|
||||
res.setHeader('X-Recvd', accum);
|
||||
var rl = new runlater();
|
||||
rl.req = req;
|
||||
rl.resp = res;
|
||||
setTimeout(executeRunLater, 750, rl);
|
||||
return;
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
else if (u.pathname === "/h11required_stream") {
|
||||
if (req.httpVersionMajor === 2) {
|
||||
h11required_conn = req.stream.connection;
|
||||
|
|
|
@ -1,7 +1,20 @@
|
|||
Version history
|
||||
===============
|
||||
|
||||
### 3.0.0 (2014-08-XX) ###
|
||||
### 3.1.0 (2014-12-11) ###
|
||||
|
||||
* Upgrade to the latest draft: [draft-ietf-httpbis-http2-16]
|
||||
* This involves some state transition changes that are technically incompatible with draft-14. If you need to be assured to interop on -14, continue using 3.0.1
|
||||
|
||||
[draft-ietf-httpbis-http2-16]: http://tools.ietf.org/html/draft-ietf-httpbis-http2-16
|
||||
|
||||
### 3.0.1 (2014-11-20) ###
|
||||
|
||||
* Bugfix release.
|
||||
* Fixed #81 and #87
|
||||
* Fixed a bug in flow control (without GitHub issue)
|
||||
|
||||
### 3.0.0 (2014-08-25) ###
|
||||
|
||||
* Re-join node-http2 and node-http2-protocol into one repository
|
||||
* API Changes
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
node-http2
|
||||
==========
|
||||
|
||||
An HTTP/2 ([draft-ietf-httpbis-http2-14](http://tools.ietf.org/html/draft-ietf-httpbis-http2-14))
|
||||
An HTTP/2 ([draft-ietf-httpbis-http2-16](http://tools.ietf.org/html/draft-ietf-httpbis-http2-16))
|
||||
client and server implementation for node.js.
|
||||
|
||||
![Travis CI status](https://travis-ci.org/molnarg/node-http2.svg?branch=master)
|
||||
|
@ -116,12 +116,12 @@ point to understand the code.
|
|||
### Test coverage ###
|
||||
|
||||
To generate a code coverage report, run `npm test --coverage` (which runs very slowly, be patient).
|
||||
Code coverage summary as of version 3.0.0:
|
||||
Code coverage summary as of version 3.0.1:
|
||||
```
|
||||
Statements : 91.85% ( 1747/1902 )
|
||||
Branches : 81.61% ( 688/843 )
|
||||
Functions : 90.95% ( 211/232 )
|
||||
Lines : 91.92% ( 1741/1894 )
|
||||
Statements : 92.09% ( 1759/1910 )
|
||||
Branches : 82.56% ( 696/843 )
|
||||
Functions : 91.38% ( 212/232 )
|
||||
Lines : 92.17% ( 1753/1902 )
|
||||
```
|
||||
|
||||
There's a hosted version of the detailed (line-by-line) coverage report
|
||||
|
@ -151,12 +151,17 @@ $ HTTP2_LOG=info node ./example/client.js 'http://localhost:8080/server.js' >/de
|
|||
Contributors
|
||||
------------
|
||||
|
||||
The co-maintainer of the project is [Nick Hurley](https://github.com/todesschaf).
|
||||
|
||||
Code contributions are always welcome! People who contributed to node-http2 so far:
|
||||
|
||||
* Nick Hurley
|
||||
* Mike Belshe
|
||||
* Yoshihiro Iwanaga
|
||||
* vsemogutor
|
||||
* [Nick Hurley](https://github.com/todesschaf)
|
||||
* [Mike Belshe](https://github.com/mbelshe)
|
||||
* [Yoshihiro Iwanaga](https://github.com/iwanaga)
|
||||
* [Igor Novikov](https://github.com/vsemogutor)
|
||||
* [James Willcox](https://github.com/snorp)
|
||||
* [David Björklund](https://github.com/kesla)
|
||||
* [Patrick McManus](https://github.com/mcmanus)
|
||||
|
||||
Special thanks to Google for financing the development of this module as part of their [Summer of
|
||||
Code program](https://developers.google.com/open-source/soc/) (project: [HTTP/2 prototype server
|
||||
|
|
|
@ -2,18 +2,17 @@ var fs = require('fs');
|
|||
var path = require('path');
|
||||
var http2 = require('..');
|
||||
|
||||
// Setting the global logger (optional)
|
||||
http2.globalAgent = new http2.Agent({
|
||||
log: require('../test/util').createLogger('client')
|
||||
});
|
||||
|
||||
// We use self signed certs in the example code so we ignore cert errors
|
||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
|
||||
|
||||
// Sending the request
|
||||
// It would be `var request = http2.get(process.argv.pop());` if we wouldn't care about plain mode
|
||||
var options = require('url').parse(process.argv.pop());
|
||||
options.plain = Boolean(process.env.HTTP2_PLAIN);
|
||||
var request = http2.request(options);
|
||||
request.end();
|
||||
var url = process.argv.pop();
|
||||
var request = process.env.HTTP2_PLAIN ? http2.raw.get(url) : http2.get(url);
|
||||
|
||||
// Receiving the response
|
||||
request.on('response', function(response) {
|
||||
|
|
|
@ -2,22 +2,12 @@ var fs = require('fs');
|
|||
var path = require('path');
|
||||
var http2 = require('..');
|
||||
|
||||
var options = process.env.HTTP2_PLAIN ? {
|
||||
plain: true
|
||||
} : {
|
||||
key: fs.readFileSync(path.join(__dirname, '/localhost.key')),
|
||||
cert: fs.readFileSync(path.join(__dirname, '/localhost.crt'))
|
||||
};
|
||||
|
||||
// Passing bunyan logger (optional)
|
||||
options.log = require('../test/util').createLogger('server');
|
||||
|
||||
// We cache one file to be able to do simple performance tests without waiting for the disk
|
||||
var cachedFile = fs.readFileSync(path.join(__dirname, './server.js'));
|
||||
var cachedUrl = '/server.js';
|
||||
|
||||
// Creating the server
|
||||
var server = http2.createServer(options, function(request, response) {
|
||||
// The callback to handle requests
|
||||
function onRequest(request, response) {
|
||||
var filename = path.join(__dirname, request.url);
|
||||
|
||||
// Serving server.js from cache. Useful for microbenchmarks.
|
||||
|
@ -44,6 +34,22 @@ var server = http2.createServer(options, function(request, response) {
|
|||
response.writeHead('404');
|
||||
response.end();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Creating a bunyan logger (optional)
|
||||
var log = require('../test/util').createLogger('server');
|
||||
|
||||
// Creating the server in plain or TLS mode (TLS mode is the default)
|
||||
var server;
|
||||
if (process.env.HTTP2_PLAIN) {
|
||||
server = http2.raw.createServer({
|
||||
log: log
|
||||
}, onRequest);
|
||||
} else {
|
||||
server = http2.createServer({
|
||||
log: log,
|
||||
key: fs.readFileSync(path.join(__dirname, '/localhost.key')),
|
||||
cert: fs.readFileSync(path.join(__dirname, '/localhost.crt'))
|
||||
}, onRequest);
|
||||
}
|
||||
server.listen(process.env.HTTP2_PORT || 8080);
|
||||
|
|
|
@ -121,7 +121,7 @@
|
|||
//
|
||||
// [1]: http://nodejs.org/api/https.html
|
||||
// [2]: http://nodejs.org/api/http.html
|
||||
// [3]: http://tools.ietf.org/html/draft-ietf-httpbis-http2-14#section-8.1.3.2
|
||||
// [3]: http://tools.ietf.org/html/draft-ietf-httpbis-http2-16#section-8.1.2.4
|
||||
// [expect-continue]: https://github.com/http2/http2-spec/issues/18
|
||||
// [connect]: https://github.com/http2/http2-spec/issues/230
|
||||
|
||||
|
@ -246,7 +246,7 @@ function IncomingMessage(stream) {
|
|||
}
|
||||
IncomingMessage.prototype = Object.create(PassThrough.prototype, { constructor: { value: IncomingMessage } });
|
||||
|
||||
// [Request Header Fields](http://tools.ietf.org/html/draft-ietf-httpbis-http2-14#section-8.1.3.1)
|
||||
// [Request Header Fields](http://tools.ietf.org/html/draft-ietf-httpbis-http2-16#section-8.1.2.3)
|
||||
// * `headers` argument: HTTP/2.0 request and response header fields carry information as a series
|
||||
// of key-value pairs. This includes the target URI for the request, the status code for the
|
||||
// response, as well as HTTP header fields.
|
||||
|
@ -602,7 +602,7 @@ function IncomingRequest(stream) {
|
|||
}
|
||||
IncomingRequest.prototype = Object.create(IncomingMessage.prototype, { constructor: { value: IncomingRequest } });
|
||||
|
||||
// [Request Header Fields](http://tools.ietf.org/html/draft-ietf-httpbis-http2-14#section-8.1.3.1)
|
||||
// [Request Header Fields](http://tools.ietf.org/html/draft-ietf-httpbis-http2-16#section-8.1.2.3)
|
||||
// * `headers` argument: HTTP/2.0 request and response header fields carry information as a series
|
||||
// of key-value pairs. This includes the target URI for the request, the status code for the
|
||||
// response, as well as HTTP header fields.
|
||||
|
@ -753,7 +753,8 @@ function requestRaw(options, callback) {
|
|||
if (typeof options === "string") {
|
||||
options = url.parse(options);
|
||||
}
|
||||
if ((options.protocol && options.protocol !== "http:") || !options.plain) {
|
||||
options.plain = true;
|
||||
if (options.protocol && options.protocol !== "http:") {
|
||||
throw new Error('This interface only supports http-schemed URLs');
|
||||
}
|
||||
return (options.agent || exports.globalAgent).request(options, callback);
|
||||
|
@ -763,7 +764,8 @@ function requestTLS(options, callback) {
|
|||
if (typeof options === "string") {
|
||||
options = url.parse(options);
|
||||
}
|
||||
if ((options.protocol && options.protocol !== "https:") || options.plain) {
|
||||
options.plain = false;
|
||||
if (options.protocol && options.protocol !== "https:") {
|
||||
throw new Error('This interface only supports https-schemed URLs');
|
||||
}
|
||||
return (options.agent || exports.globalAgent).request(options, callback);
|
||||
|
@ -773,7 +775,8 @@ function getRaw(options, callback) {
|
|||
if (typeof options === "string") {
|
||||
options = url.parse(options);
|
||||
}
|
||||
if ((options.protocol && options.protocol !== "http:") || !options.plain) {
|
||||
options.plain = true;
|
||||
if (options.protocol && options.protocol !== "http:") {
|
||||
throw new Error('This interface only supports http-schemed URLs');
|
||||
}
|
||||
return (options.agent || exports.globalAgent).get(options, callback);
|
||||
|
@ -783,7 +786,8 @@ function getTLS(options, callback) {
|
|||
if (typeof options === "string") {
|
||||
options = url.parse(options);
|
||||
}
|
||||
if ((options.protocol && options.protocol !== "https:") || options.plain) {
|
||||
options.plain = false;
|
||||
if (options.protocol && options.protocol !== "https:") {
|
||||
throw new Error('This interface only supports https-schemed URLs');
|
||||
}
|
||||
return (options.agent || exports.globalAgent).get(options, callback);
|
||||
|
@ -863,7 +867,7 @@ Agent.prototype.request = function request(options, callback) {
|
|||
request._start(endpoint.createStream(), options);
|
||||
}
|
||||
|
||||
// * HTTP/2 over TLS negotiated using NPN or ALPN
|
||||
// * HTTP/2 over TLS negotiated using NPN or ALPN, or fallback to HTTPS1
|
||||
else {
|
||||
var started = false;
|
||||
options.ALPNProtocols = supportedProtocols;
|
||||
|
@ -876,7 +880,7 @@ Agent.prototype.request = function request(options, callback) {
|
|||
httpsRequest.on('socket', function(socket) {
|
||||
var negotiatedProtocol = socket.alpnProtocol || socket.npnProtocol;
|
||||
if (negotiatedProtocol != null) { // null in >=0.11.0, undefined in <0.11.0
|
||||
negotiated()
|
||||
negotiated();
|
||||
} else {
|
||||
socket.on('secureConnect', negotiated);
|
||||
}
|
||||
|
@ -894,11 +898,12 @@ Agent.prototype.request = function request(options, callback) {
|
|||
endpoint.pipe(endpoint.socket).pipe(endpoint);
|
||||
}
|
||||
if (started) {
|
||||
// ** In the meantime, an other connection was made to the same host...
|
||||
if (endpoint) {
|
||||
// *** and it turned out to be HTTP2 and the request was multiplexed on that one, so we should close this one
|
||||
endpoint.close();
|
||||
} else {
|
||||
httpsRequest.abort();
|
||||
}
|
||||
// *** otherwise, the fallback to HTTPS1 is already done.
|
||||
} else {
|
||||
if (endpoint) {
|
||||
self._log.info({ e: endpoint, server: options.host + ':' + options.port },
|
||||
|
@ -1079,7 +1084,7 @@ function IncomingResponse(stream) {
|
|||
}
|
||||
IncomingResponse.prototype = Object.create(IncomingMessage.prototype, { constructor: { value: IncomingResponse } });
|
||||
|
||||
// [Response Header Fields](http://tools.ietf.org/html/draft-ietf-httpbis-http2-14#section-8.1.3.2)
|
||||
// [Response Header Fields](http://tools.ietf.org/html/draft-ietf-httpbis-http2-16#section-8.1.2.4)
|
||||
// * `headers` argument: HTTP/2.0 request and response header fields carry information as a series
|
||||
// of key-value pairs. This includes the target URI for the request, the status code for the
|
||||
// response, as well as HTTP header fields.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// [node-http2][homepage] is an [HTTP/2 (draft 14)][http2] implementation for [node.js][node].
|
||||
// [node-http2][homepage] is an [HTTP/2 (draft 16)][http2] implementation for [node.js][node].
|
||||
//
|
||||
// The core of the protocol is implemented in the protocol sub-directory. This directory provides
|
||||
// two important features on top of the protocol:
|
||||
|
@ -10,7 +10,7 @@
|
|||
// (which is in turn very similar to the [HTTP module API][node-http]).
|
||||
//
|
||||
// [homepage]: https://github.com/molnarg/node-http2
|
||||
// [http2]: http://tools.ietf.org/html/draft-ietf-httpbis-http2-14
|
||||
// [http2]: http://tools.ietf.org/html/draft-ietf-httpbis-http2-16
|
||||
// [node]: http://nodejs.org/
|
||||
// [node-https]: http://nodejs.org/api/https.html
|
||||
// [node-http]: http://nodejs.org/api/http.html
|
||||
|
|
|
@ -1123,10 +1123,10 @@ Compressor.prototype.compress = function compress(headers) {
|
|||
// separate header fields, each with one or more cookie-pairs.
|
||||
if (name == 'cookie') {
|
||||
if (!(value instanceof Array)) {
|
||||
value = [value]
|
||||
value = [value];
|
||||
}
|
||||
value = Array.prototype.concat.apply([], value.map(function(cookie) {
|
||||
return String(cookie).split(';').map(trim)
|
||||
return String(cookie).split(';').map(trim);
|
||||
}));
|
||||
}
|
||||
|
||||
|
@ -1256,7 +1256,7 @@ Decompressor.prototype.decompress = function decompress(block) {
|
|||
// into a single octet string using the two octet delimiter of 0x3B, 0x20 (the ASCII
|
||||
// string "; ").
|
||||
if (('cookie' in headers) && (headers['cookie'] instanceof Array)) {
|
||||
headers['cookie'] = headers['cookie'].join('; ')
|
||||
headers['cookie'] = headers['cookie'].join('; ');
|
||||
}
|
||||
|
||||
return headers;
|
||||
|
@ -1340,5 +1340,5 @@ function cut(buffer, size) {
|
|||
}
|
||||
|
||||
function trim(string) {
|
||||
return string.trim()
|
||||
return string.trim();
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ exports.Flow = Flow;
|
|||
// * **setInitialWindow(size)**: the initial flow control window size can be changed *any time*
|
||||
// ([as described in the standard][1]) using this method
|
||||
//
|
||||
// [1]: http://tools.ietf.org/html/draft-ietf-httpbis-http2-14#section-6.9.2
|
||||
// [1]: http://tools.ietf.org/html/draft-ietf-httpbis-http2-16#section-6.9.2
|
||||
|
||||
// API for child classes
|
||||
// ---------------------
|
||||
|
@ -81,7 +81,9 @@ Flow.prototype._receive = function _receive(frame, callback) {
|
|||
// incoming frame is a WINDOW_UPDATE.
|
||||
// [1]: http://nodejs.org/api/stream.html#stream_writable_write_chunk_encoding_callback_1
|
||||
Flow.prototype._write = function _write(frame, encoding, callback) {
|
||||
if (frame.flags.END_STREAM || (frame.type === 'RST_STREAM')) {
|
||||
var sentToUs = (this._flowControlId === undefined) || (frame.stream === this._flowControlId);
|
||||
|
||||
if (sentToUs && (frame.flags.END_STREAM || (frame.type === 'RST_STREAM'))) {
|
||||
this._ended = true;
|
||||
}
|
||||
|
||||
|
@ -99,8 +101,7 @@ Flow.prototype._write = function _write(frame, encoding, callback) {
|
|||
this._receive(frame, callback);
|
||||
}
|
||||
|
||||
if ((frame.type === 'WINDOW_UPDATE') &&
|
||||
((this._flowControlId === undefined) || (frame.stream === this._flowControlId))) {
|
||||
if (sentToUs && (frame.type === 'WINDOW_UPDATE')) {
|
||||
this._updateWindow(frame);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -146,7 +146,7 @@ Deserializer.prototype._transform = function _transform(chunk, encoding, done) {
|
|||
done();
|
||||
};
|
||||
|
||||
// [Frame Header](http://tools.ietf.org/html/draft-ietf-httpbis-http2-14#section-4.1)
|
||||
// [Frame Header](http://tools.ietf.org/html/draft-ietf-httpbis-http2-16#section-4.1)
|
||||
// --------------------------------------------------------------
|
||||
//
|
||||
// HTTP/2.0 frames share a common base format consisting of a 9-byte header followed by 0 to 2^24 - 1
|
||||
|
@ -269,7 +269,7 @@ Deserializer.commonHeader = function readCommonHeader(buffer, frame) {
|
|||
// * `typeSpecificAttributes`: a register of frame specific frame object attributes (used by
|
||||
// logging code and also serves as documentation for frame objects)
|
||||
|
||||
// [DATA Frames](http://tools.ietf.org/html/draft-ietf-httpbis-http2-14#section-6.1)
|
||||
// [DATA Frames](http://tools.ietf.org/html/draft-ietf-httpbis-http2-16#section-6.1)
|
||||
// ------------------------------------------------------------
|
||||
//
|
||||
// DATA frames (type=0x0) convey arbitrary, variable-length sequences of octets associated with a
|
||||
|
@ -308,7 +308,7 @@ Deserializer.DATA = function readData(buffer, frame) {
|
|||
}
|
||||
};
|
||||
|
||||
// [HEADERS](http://tools.ietf.org/html/draft-ietf-httpbis-http2-14#section-6.2)
|
||||
// [HEADERS](http://tools.ietf.org/html/draft-ietf-httpbis-http2-16#section-6.2)
|
||||
// --------------------------------------------------------------
|
||||
//
|
||||
// The HEADERS frame (type=0x1) allows the sender to create a stream.
|
||||
|
@ -390,7 +390,7 @@ Deserializer.HEADERS = function readHeadersPriority(buffer, frame) {
|
|||
}
|
||||
};
|
||||
|
||||
// [PRIORITY](http://tools.ietf.org/html/draft-ietf-httpbis-http2-14#section-6.3)
|
||||
// [PRIORITY](http://tools.ietf.org/html/draft-ietf-httpbis-http2-16#section-6.3)
|
||||
// -------------------------------------------------------
|
||||
//
|
||||
// The PRIORITY frame (type=0x2) specifies the sender-advised priority of a stream.
|
||||
|
@ -435,7 +435,7 @@ Deserializer.PRIORITY = function readPriority(buffer, frame) {
|
|||
frame.priorityWeight = buffer.readUInt8(4);
|
||||
};
|
||||
|
||||
// [RST_STREAM](http://tools.ietf.org/html/draft-ietf-httpbis-http2-14#section-6.4)
|
||||
// [RST_STREAM](http://tools.ietf.org/html/draft-ietf-httpbis-http2-16#section-6.4)
|
||||
// -----------------------------------------------------------
|
||||
//
|
||||
// The RST_STREAM frame (type=0x3) allows for abnormal termination of a stream.
|
||||
|
@ -473,7 +473,7 @@ Deserializer.RST_STREAM = function readRstStream(buffer, frame) {
|
|||
}
|
||||
};
|
||||
|
||||
// [SETTINGS](http://tools.ietf.org/html/draft-ietf-httpbis-http2-14#section-6.5)
|
||||
// [SETTINGS](http://tools.ietf.org/html/draft-ietf-httpbis-http2-16#section-6.5)
|
||||
// -------------------------------------------------------
|
||||
//
|
||||
// The SETTINGS frame (type=0x4) conveys configuration parameters that affect how endpoints
|
||||
|
@ -580,7 +580,7 @@ definedSettings[4] = { name: 'SETTINGS_INITIAL_WINDOW_SIZE', flag: false };
|
|||
// indicates the maximum size of a frame the receiver will allow.
|
||||
definedSettings[5] = { name: 'SETTINGS_MAX_FRAME_SIZE', flag: false };
|
||||
|
||||
// [PUSH_PROMISE](http://tools.ietf.org/html/draft-ietf-httpbis-http2-14#section-6.6)
|
||||
// [PUSH_PROMISE](http://tools.ietf.org/html/draft-ietf-httpbis-http2-16#section-6.6)
|
||||
// ---------------------------------------------------------------
|
||||
//
|
||||
// The PUSH_PROMISE frame (type=0x5) is used to notify the peer endpoint in advance of streams the
|
||||
|
@ -641,7 +641,7 @@ Deserializer.PUSH_PROMISE = function readPushPromise(buffer, frame) {
|
|||
}
|
||||
};
|
||||
|
||||
// [PING](http://tools.ietf.org/html/draft-ietf-httpbis-http2-14#section-6.7)
|
||||
// [PING](http://tools.ietf.org/html/draft-ietf-httpbis-http2-16#section-6.7)
|
||||
// -----------------------------------------------
|
||||
//
|
||||
// The PING frame (type=0x6) is a mechanism for measuring a minimal round-trip time from the
|
||||
|
@ -671,7 +671,7 @@ Deserializer.PING = function readPing(buffer, frame) {
|
|||
frame.data = buffer;
|
||||
};
|
||||
|
||||
// [GOAWAY](http://tools.ietf.org/html/draft-ietf-httpbis-http2-14#section-6.8)
|
||||
// [GOAWAY](http://tools.ietf.org/html/draft-ietf-httpbis-http2-16#section-6.8)
|
||||
// ---------------------------------------------------
|
||||
//
|
||||
// The GOAWAY frame (type=0x7) informs the remote peer to stop creating streams on this connection.
|
||||
|
@ -722,7 +722,7 @@ Deserializer.GOAWAY = function readGoaway(buffer, frame) {
|
|||
}
|
||||
};
|
||||
|
||||
// [WINDOW_UPDATE](http://tools.ietf.org/html/draft-ietf-httpbis-http2-14#section-6.9)
|
||||
// [WINDOW_UPDATE](http://tools.ietf.org/html/draft-ietf-httpbis-http2-16#section-6.9)
|
||||
// -----------------------------------------------------------------
|
||||
//
|
||||
// The WINDOW_UPDATE frame (type=0x8) is used to implement flow control.
|
||||
|
@ -760,7 +760,7 @@ Deserializer.WINDOW_UPDATE = function readWindowUpdate(buffer, frame) {
|
|||
}
|
||||
};
|
||||
|
||||
// [CONTINUATION](http://tools.ietf.org/html/draft-ietf-httpbis-http2-14#section-6.10)
|
||||
// [CONTINUATION](http://tools.ietf.org/html/draft-ietf-httpbis-http2-16#section-6.10)
|
||||
// ------------------------------------------------------------
|
||||
//
|
||||
// The CONTINUATION frame (type=0x9) is used to continue a sequence of header block fragments.
|
||||
|
@ -785,7 +785,7 @@ Deserializer.CONTINUATION = function readContinuation(buffer, frame) {
|
|||
frame.data = buffer;
|
||||
};
|
||||
|
||||
// [ALTSVC](http://tools.ietf.org/html/draft-ietf-httpbis-http2-14#section-6.11)
|
||||
// [ALTSVC](http://tools.ietf.org/html/draft-ietf-httpbis-alt-svc-04#section-4)
|
||||
// ------------------------------------------------------------
|
||||
//
|
||||
// The ALTSVC frame (type=0xA) advertises the availability of an alternative service to the client.
|
||||
|
@ -874,7 +874,7 @@ Deserializer.ALTSVC = function readAltSvc(buffer, frame) {
|
|||
frame.origin = buffer.toString('ascii', 9 + pidLength + hostLength);
|
||||
};
|
||||
|
||||
// [BLOCKED](http://tools.ietf.org/html/draft-ietf-httpbis-http2-14#section-6.12)
|
||||
// BLOCKED
|
||||
// ------------------------------------------------------------
|
||||
//
|
||||
// The BLOCKED frame (type=0xB) indicates that the sender is unable to send data
|
||||
|
@ -894,7 +894,7 @@ Serializer.BLOCKED = function writeBlocked(frame, buffers) {
|
|||
Deserializer.BLOCKED = function readBlocked(buffer, frame) {
|
||||
};
|
||||
|
||||
// [Error Codes](http://tools.ietf.org/html/draft-ietf-httpbis-http2-14#section-7)
|
||||
// [Error Codes](http://tools.ietf.org/html/draft-ietf-httpbis-http2-16#section-7)
|
||||
// ------------------------------------------------------------
|
||||
|
||||
var errorCodes = [
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// [node-http2-protocol][homepage] is an implementation of the [HTTP/2 (draft 14)][http2]
|
||||
// [node-http2-protocol][homepage] is an implementation of the [HTTP/2 (draft 16)][http2]
|
||||
// framing layer for [node.js][node].
|
||||
//
|
||||
// The main building blocks are [node.js streams][node-stream] that are connected through pipes.
|
||||
|
@ -28,10 +28,10 @@
|
|||
// between the binary and the JavaScript object representation of HTTP/2 frames
|
||||
//
|
||||
// [homepage]: https://github.com/molnarg/node-http2
|
||||
// [http2]: http://tools.ietf.org/html/draft-ietf-httpbis-http2-14
|
||||
// [http2-connheader]: http://tools.ietf.org/html/draft-ietf-httpbis-http2-14#section-3.5
|
||||
// [http2-stream]: http://tools.ietf.org/html/draft-ietf-httpbis-http2-14#section-5
|
||||
// [http2-streamstate]: http://tools.ietf.org/html/draft-ietf-httpbis-http2-14#section-5.1
|
||||
// [http2]: http://tools.ietf.org/html/draft-ietf-httpbis-http2-16
|
||||
// [http2-connheader]: http://tools.ietf.org/html/draft-ietf-httpbis-http2-16#section-3.5
|
||||
// [http2-stream]: http://tools.ietf.org/html/draft-ietf-httpbis-http2-16#section-5
|
||||
// [http2-streamstate]: http://tools.ietf.org/html/draft-ietf-httpbis-http2-16#section-5.1
|
||||
// [node]: http://nodejs.org/
|
||||
// [node-stream]: http://nodejs.org/api/stream.html
|
||||
// [node-https]: http://nodejs.org/api/https.html
|
||||
|
|
|
@ -352,7 +352,7 @@ Stream.prototype._finishing = function _finishing() {
|
|||
}
|
||||
};
|
||||
|
||||
// [Stream States](http://tools.ietf.org/html/draft-ietf-httpbis-http2-14#section-5.1)
|
||||
// [Stream States](http://tools.ietf.org/html/draft-ietf-httpbis-http2-16#section-5.1)
|
||||
// ----------------
|
||||
//
|
||||
// +--------+
|
||||
|
@ -464,7 +464,7 @@ Stream.prototype._transition = function transition(sending, frame) {
|
|||
this._setState('HALF_CLOSED_REMOTE');
|
||||
} else if (RST_STREAM) {
|
||||
this._setState('CLOSED');
|
||||
} else if (receiving && PRIORITY) {
|
||||
} else if (PRIORITY) {
|
||||
/* No state change */
|
||||
} else {
|
||||
connectionError = 'PROTOCOL_ERROR';
|
||||
|
@ -483,7 +483,7 @@ Stream.prototype._transition = function transition(sending, frame) {
|
|||
this._setState('CLOSED');
|
||||
} else if (receiving && HEADERS) {
|
||||
this._setState('HALF_CLOSED_LOCAL');
|
||||
} else if (BLOCKED || (sending && PRIORITY)) {
|
||||
} else if (BLOCKED || PRIORITY) {
|
||||
/* No state change */
|
||||
} else {
|
||||
connectionError = 'PROTOCOL_ERROR';
|
||||
|
@ -518,7 +518,7 @@ Stream.prototype._transition = function transition(sending, frame) {
|
|||
case 'HALF_CLOSED_LOCAL':
|
||||
if (RST_STREAM || (receiving && frame.flags.END_STREAM)) {
|
||||
this._setState('CLOSED');
|
||||
} else if (BLOCKED || ALTSVC ||receiving || (sending && (PRIORITY || WINDOW_UPDATE))) {
|
||||
} else if (BLOCKED || ALTSVC || receiving || PRIORITY || (sending && WINDOW_UPDATE)) {
|
||||
/* No state change */
|
||||
} else {
|
||||
connectionError = 'PROTOCOL_ERROR';
|
||||
|
@ -538,7 +538,7 @@ Stream.prototype._transition = function transition(sending, frame) {
|
|||
case 'HALF_CLOSED_REMOTE':
|
||||
if (RST_STREAM || (sending && frame.flags.END_STREAM)) {
|
||||
this._setState('CLOSED');
|
||||
} else if (BLOCKED || ALTSVC ||sending || (receiving && (WINDOW_UPDATE || PRIORITY))) {
|
||||
} else if (BLOCKED || ALTSVC || sending || PRIORITY || (receiving && WINDOW_UPDATE)) {
|
||||
/* No state change */
|
||||
} else {
|
||||
connectionError = 'PROTOCOL_ERROR';
|
||||
|
@ -566,9 +566,9 @@ Stream.prototype._transition = function transition(sending, frame) {
|
|||
// causes a stream to become "reserved". If promised streams are not desired, a RST_STREAM
|
||||
// can be used to close any of those streams.
|
||||
case 'CLOSED':
|
||||
if ((sending && RST_STREAM) ||
|
||||
if (PRIORITY || (sending && RST_STREAM) ||
|
||||
(receiving && this._closedByUs &&
|
||||
(this._closedWithRst || WINDOW_UPDATE || PRIORITY || RST_STREAM || ALTSVC))) {
|
||||
(this._closedWithRst || WINDOW_UPDATE || RST_STREAM || ALTSVC))) {
|
||||
/* No state change */
|
||||
} else {
|
||||
streamError = 'STREAM_CLOSED';
|
||||
|
@ -637,7 +637,7 @@ Stream.prototype._transition = function transition(sending, frame) {
|
|||
this.emit('connectionError', connectionError);
|
||||
} else {
|
||||
this.reset(streamError);
|
||||
this.emit('error', streamError)
|
||||
this.emit('error', streamError);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "http2",
|
||||
"version": "3.0.0",
|
||||
"version": "3.1.0",
|
||||
"description": "An HTTP/2 client and server implementation",
|
||||
"main": "lib/index.js",
|
||||
"engines" : {
|
||||
|
@ -14,7 +14,7 @@
|
|||
"bunyan": "*"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "istanbul test _mocha -- --reporter spec --slow 200",
|
||||
"test": "istanbul test _mocha -- --reporter spec --slow 500 --timeout 15000",
|
||||
"doc": "docco lib/* --output doc --layout parallel --css doc/docco.css"
|
||||
},
|
||||
"repository": {
|
||||
|
@ -36,7 +36,10 @@
|
|||
"Nick Hurley",
|
||||
"Mike Belshe",
|
||||
"Yoshihiro Iwanaga",
|
||||
"vsemogutor"
|
||||
"Igor Novikov",
|
||||
"James Willcox",
|
||||
"David Björklund",
|
||||
"Patrick McManus"
|
||||
],
|
||||
"license": "MIT",
|
||||
"readmeFilename": "README.md"
|
||||
|
|
|
@ -406,21 +406,21 @@ describe('compressor.js', function() {
|
|||
expect(table.encode(new Buffer(decoded)).toString('hex')).to.equal(encoded);
|
||||
}
|
||||
});
|
||||
})
|
||||
});
|
||||
describe('method decode(buffer)', function() {
|
||||
it('should return the Huffman decoded version of the input buffer', function() {
|
||||
var table = HuffmanTable.huffmanTable;
|
||||
for (var decoded in test_huffman_request) {
|
||||
var encoded = test_huffman_request[decoded];
|
||||
expect(table.decode(new Buffer(encoded, 'hex')).toString()).to.equal(decoded)
|
||||
expect(table.decode(new Buffer(encoded, 'hex')).toString()).to.equal(decoded);
|
||||
}
|
||||
table = HuffmanTable.huffmanTable;
|
||||
for (decoded in test_huffman_response) {
|
||||
encoded = test_huffman_response[decoded];
|
||||
expect(table.decode(new Buffer(encoded, 'hex')).toString()).to.equal(decoded)
|
||||
expect(table.decode(new Buffer(encoded, 'hex')).toString()).to.equal(decoded);
|
||||
}
|
||||
});
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
describe('HeaderSetCompressor', function() {
|
||||
|
@ -569,7 +569,7 @@ describe('compressor.js', function() {
|
|||
var result = table.decode(table.encode(buffer));
|
||||
expect(result).to.deep.equal(buffer);
|
||||
}
|
||||
})
|
||||
})
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -131,7 +131,7 @@ describe('connection.js', function() {
|
|||
client_stream.on('data', function(data) {
|
||||
expect(data).to.deep.equal(response_data);
|
||||
done();
|
||||
})
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('server push', function() {
|
||||
|
|
|
@ -254,7 +254,7 @@ describe('flow.js', function() {
|
|||
|
||||
// Start piping
|
||||
flow1.pipe(flow2).pipe(flow1);
|
||||
})
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -124,7 +124,7 @@ describe('http.js', function() {
|
|||
var response = new http2.OutgoingResponse(stream);
|
||||
|
||||
response.writeHead(200);
|
||||
response.writeHead(404)
|
||||
response.writeHead(404);
|
||||
});
|
||||
});
|
||||
describe('test scenario', function() {
|
||||
|
@ -149,6 +149,66 @@ describe('http.js', function() {
|
|||
});
|
||||
});
|
||||
});
|
||||
describe('2 simple request in parallel', function() {
|
||||
it('should work as expected', function(originalDone) {
|
||||
var path = '/x';
|
||||
var message = 'Hello world';
|
||||
done = util.callNTimes(2, function() {
|
||||
server.close();
|
||||
originalDone();
|
||||
});
|
||||
|
||||
var server = http2.createServer(options, function(request, response) {
|
||||
expect(request.url).to.equal(path);
|
||||
response.end(message);
|
||||
});
|
||||
|
||||
server.listen(1234, function() {
|
||||
http2.get('https://localhost:1234' + path, function(response) {
|
||||
response.on('data', function(data) {
|
||||
expect(data.toString()).to.equal(message);
|
||||
done();
|
||||
});
|
||||
});
|
||||
http2.get('https://localhost:1234' + path, function(response) {
|
||||
response.on('data', function(data) {
|
||||
expect(data.toString()).to.equal(message);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('100 simple request in a series', function() {
|
||||
it('should work as expected', function(done) {
|
||||
var path = '/x';
|
||||
var message = 'Hello world';
|
||||
|
||||
var server = http2.createServer(options, function(request, response) {
|
||||
expect(request.url).to.equal(path);
|
||||
response.end(message);
|
||||
});
|
||||
|
||||
var n = 100;
|
||||
server.listen(1242, function() {
|
||||
doRequest();
|
||||
function doRequest() {
|
||||
http2.get('https://localhost:1242' + path, function(response) {
|
||||
response.on('data', function(data) {
|
||||
expect(data.toString()).to.equal(message);
|
||||
if (n) {
|
||||
n -= 1;
|
||||
doRequest();
|
||||
} else {
|
||||
server.close();
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('request with payload', function() {
|
||||
it('should work as expected', function(done) {
|
||||
var path = '/x';
|
||||
|
@ -240,7 +300,6 @@ describe('http.js', function() {
|
|||
var message = 'Hello world';
|
||||
|
||||
var server = http2.raw.createServer({
|
||||
plain: true,
|
||||
log: util.serverLog
|
||||
}, function(request, response) {
|
||||
expect(request.url).to.equal(path);
|
||||
|
@ -264,6 +323,30 @@ describe('http.js', function() {
|
|||
});
|
||||
});
|
||||
});
|
||||
describe('get over plain TCP', function() {
|
||||
it('should work as expected', function(done) {
|
||||
var path = '/x';
|
||||
var message = 'Hello world';
|
||||
|
||||
var server = http2.raw.createServer({
|
||||
log: util.serverLog
|
||||
}, function(request, response) {
|
||||
expect(request.url).to.equal(path);
|
||||
response.end(message);
|
||||
});
|
||||
|
||||
server.listen(1237, function() {
|
||||
var request = http2.raw.get('http://localhost:1237/x', function(response) {
|
||||
response.on('data', function(data) {
|
||||
expect(data.toString()).to.equal(message);
|
||||
server.close();
|
||||
done();
|
||||
});
|
||||
});
|
||||
request.end();
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('request to an HTTPS/1 server', function() {
|
||||
it('should fall back to HTTPS/1 successfully', function(done) {
|
||||
var path = '/x';
|
||||
|
@ -284,6 +367,36 @@ describe('http.js', function() {
|
|||
});
|
||||
});
|
||||
});
|
||||
describe('2 parallel request to an HTTPS/1 server', function() {
|
||||
it('should fall back to HTTPS/1 successfully', function(originalDone) {
|
||||
var path = '/x';
|
||||
var message = 'Hello world';
|
||||
done = util.callNTimes(2, function() {
|
||||
server.close();
|
||||
originalDone();
|
||||
});
|
||||
|
||||
var server = https.createServer(options, function(request, response) {
|
||||
expect(request.url).to.equal(path);
|
||||
response.end(message);
|
||||
});
|
||||
|
||||
server.listen(6789, function() {
|
||||
http2.get('https://localhost:6789' + path, function(response) {
|
||||
response.on('data', function(data) {
|
||||
expect(data.toString()).to.equal(message);
|
||||
done();
|
||||
});
|
||||
});
|
||||
http2.get('https://localhost:6789' + path, function(response) {
|
||||
response.on('data', function(data) {
|
||||
expect(data.toString()).to.equal(message);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('HTTPS/1 request to a HTTP/2 server', function() {
|
||||
it('should fall back to HTTPS/1 successfully', function(done) {
|
||||
var path = '/x';
|
||||
|
|
|
@ -112,7 +112,6 @@ var example_frames = [
|
|||
var invalid_incoming_frames = {
|
||||
IDLE: [
|
||||
{ type: 'DATA', flags: {}, data: new Buffer(5) },
|
||||
{ type: 'PRIORITY', flags: {}, priority: 1 },
|
||||
{ type: 'WINDOW_UPDATE', flags: {}, settings: {} },
|
||||
{ type: 'PUSH_PROMISE', flags: {}, headers: {} },
|
||||
{ type: 'RST_STREAM', flags: {}, error: 'CANCEL' }
|
||||
|
@ -125,7 +124,6 @@ var invalid_incoming_frames = {
|
|||
],
|
||||
RESERVED_REMOTE: [
|
||||
{ type: 'DATA', flags: {}, data: new Buffer(5) },
|
||||
{ type: 'PRIORITY', flags: {}, priority: 1 },
|
||||
{ type: 'PUSH_PROMISE', flags: {}, headers: {} },
|
||||
{ type: 'WINDOW_UPDATE', flags: {}, settings: {} }
|
||||
],
|
||||
|
@ -143,13 +141,11 @@ var invalid_incoming_frames = {
|
|||
var invalid_outgoing_frames = {
|
||||
IDLE: [
|
||||
{ type: 'DATA', flags: {}, data: new Buffer(5) },
|
||||
{ type: 'PRIORITY', flags: {}, priority: 1 },
|
||||
{ type: 'WINDOW_UPDATE', flags: {}, settings: {} },
|
||||
{ type: 'PUSH_PROMISE', flags: {}, headers: {} }
|
||||
],
|
||||
RESERVED_LOCAL: [
|
||||
{ type: 'DATA', flags: {}, data: new Buffer(5) },
|
||||
{ type: 'PRIORITY', flags: {}, priority: 1 },
|
||||
{ type: 'PUSH_PROMISE', flags: {}, headers: {} },
|
||||
{ type: 'WINDOW_UPDATE', flags: {}, settings: {} }
|
||||
],
|
||||
|
@ -169,7 +165,6 @@ var invalid_outgoing_frames = {
|
|||
HALF_CLOSED_REMOTE: [
|
||||
],
|
||||
CLOSED: [
|
||||
{ type: 'PRIORITY', flags: {}, priority: 1 },
|
||||
{ type: 'WINDOW_UPDATE', flags: {}, settings: {} },
|
||||
{ type: 'HEADERS', flags: {}, headers: {}, priority: undefined },
|
||||
{ type: 'DATA', flags: {}, data: new Buffer(5) },
|
||||
|
@ -188,7 +183,7 @@ describe('stream.js', function() {
|
|||
stream.state = state;
|
||||
stream.once('connectionError', function() { connectionErrorHappened = true; });
|
||||
stream._transition(false, invalid_frame);
|
||||
expect(connectionErrorHappened)
|
||||
expect(connectionErrorHappened);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -197,7 +192,7 @@ describe('stream.js', function() {
|
|||
stream.headers({});
|
||||
stream.end();
|
||||
stream.upstream.write({ type: 'HEADERS', headers:{}, flags: { END_STREAM: true }, count_change: util.noop });
|
||||
example_frames.forEach(function(invalid_frame) {
|
||||
example_frames.slice(1).forEach(function(invalid_frame) {
|
||||
invalid_frame.count_change = util.noop;
|
||||
expect(stream._transition.bind(stream, false, invalid_frame)).to.throw('Uncaught, unspecified "error" event.');
|
||||
});
|
||||
|
|
|
@ -86,4 +86,4 @@ exports.shuffleBuffers = function shuffleBuffers(buffers) {
|
|||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -567,7 +567,7 @@ End of 5th\n\
|
|||
SimpleTest.waitForClipboard(
|
||||
function(aActual) {
|
||||
mostRecentActual = aActual;
|
||||
return aActual === aExpected;
|
||||
return aActual.trim() === aExpected.trim();
|
||||
},
|
||||
function() {
|
||||
synthesizeKey("A", {accelKey: true});
|
||||
|
|
|
@ -106,7 +106,7 @@
|
|||
SimpleTest.waitForClipboard(
|
||||
function(aActual) {
|
||||
mostRecentActual = aActual;
|
||||
return aActual === aExpected;
|
||||
return aActual.trim() === aExpected.trim();
|
||||
},
|
||||
function() {
|
||||
synthesizeKey("A", {accelKey: true});
|
||||
|
|
|
@ -106,7 +106,7 @@
|
|||
let actual = SpecialPowers.getClipboardData("text/unicode");
|
||||
actual = actual.replace(/\(pid \d+\)/g, "(pid NNN)");
|
||||
|
||||
if (actual === aExpected) {
|
||||
if (actual.trim() === aExpected.trim()) {
|
||||
SimpleTest.ok(true, "Clipboard has the expected contents");
|
||||
aNext();
|
||||
} else {
|
||||
|
|
|
@ -54,7 +54,7 @@
|
|||
let actual = SpecialPowers.getClipboardData("text/unicode");
|
||||
actual = actual.replace(/\(pid \d+\)/, "(pid NNN)");
|
||||
|
||||
if (actual === aExpected) {
|
||||
if (actual.trim() === aExpected.trim()) {
|
||||
SimpleTest.ok(true, "Clipboard has the expected contents");
|
||||
aNext();
|
||||
} else {
|
||||
|
|
|
@ -463,20 +463,27 @@ exports.fetch = function fetch(aURL, aOptions={ loadFromCache: true }) {
|
|||
case "chrome":
|
||||
case "resource":
|
||||
try {
|
||||
NetUtil.asyncFetch(url, function onFetch(aStream, aStatus, aRequest) {
|
||||
if (!components.isSuccessCode(aStatus)) {
|
||||
deferred.reject(new Error("Request failed with status code = "
|
||||
+ aStatus
|
||||
+ " after NetUtil.asyncFetch for url = "
|
||||
+ url));
|
||||
return;
|
||||
}
|
||||
NetUtil.asyncFetch2(
|
||||
url,
|
||||
function onFetch(aStream, aStatus, aRequest) {
|
||||
if (!components.isSuccessCode(aStatus)) {
|
||||
deferred.reject(new Error("Request failed with status code = "
|
||||
+ aStatus
|
||||
+ " after NetUtil.asyncFetch2 for url = "
|
||||
+ url));
|
||||
return;
|
||||
}
|
||||
|
||||
let source = NetUtil.readInputStreamToString(aStream, aStream.available());
|
||||
contentType = aRequest.contentType;
|
||||
deferred.resolve(source);
|
||||
aStream.close();
|
||||
});
|
||||
let source = NetUtil.readInputStreamToString(aStream, aStream.available());
|
||||
contentType = aRequest.contentType;
|
||||
deferred.resolve(source);
|
||||
aStream.close();
|
||||
},
|
||||
null, // aLoadingNode
|
||||
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
null, // aTriggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_NORMAL,
|
||||
Ci.nsIContentPolicy.TYPE_OTHER);
|
||||
} catch (ex) {
|
||||
deferred.reject(ex);
|
||||
}
|
||||
|
|
|
@ -199,14 +199,22 @@ SrcdirProvider.prototype = {
|
|||
_readFile: function(filename) {
|
||||
let deferred = promise.defer();
|
||||
let file = new FileUtils.File(filename);
|
||||
NetUtil.asyncFetch(file, (inputStream, status) => {
|
||||
if (!Components.isSuccessCode(status)) {
|
||||
deferred.reject(new Error("Couldn't load manifest: " + filename + "\n"));
|
||||
return;
|
||||
}
|
||||
var data = NetUtil.readInputStreamToString(inputStream, inputStream.available());
|
||||
deferred.resolve(data);
|
||||
});
|
||||
NetUtil.asyncFetch2(
|
||||
file,
|
||||
(inputStream, status) => {
|
||||
if (!Components.isSuccessCode(status)) {
|
||||
deferred.reject(new Error("Couldn't load manifest: " + filename + "\n"));
|
||||
return;
|
||||
}
|
||||
var data = NetUtil.readInputStreamToString(inputStream, inputStream.available());
|
||||
deferred.resolve(data);
|
||||
},
|
||||
null, // aLoadingNode
|
||||
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
null, // aTriggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_NORMAL,
|
||||
Ci.nsIContentPolicy.TYPE_OTHER);
|
||||
|
||||
return deferred.promise;
|
||||
},
|
||||
|
||||
|
|
|
@ -187,17 +187,24 @@ function uploadPackageBulk(client, webappsActor, packageFile, progressCallback)
|
|||
});
|
||||
|
||||
request.on("bulk-send-ready", ({copyFrom}) => {
|
||||
NetUtil.asyncFetch(packageFile, function(inputStream) {
|
||||
let copying = copyFrom(inputStream);
|
||||
copying.on("progress", (e, progress) => {
|
||||
progressCallback(progress);
|
||||
});
|
||||
copying.then(() => {
|
||||
console.log("Bulk upload done");
|
||||
inputStream.close();
|
||||
deferred.resolve(actor);
|
||||
});
|
||||
});
|
||||
NetUtil.asyncFetch2(
|
||||
packageFile,
|
||||
function(inputStream) {
|
||||
let copying = copyFrom(inputStream);
|
||||
copying.on("progress", (e, progress) => {
|
||||
progressCallback(progress);
|
||||
});
|
||||
copying.then(() => {
|
||||
console.log("Bulk upload done");
|
||||
inputStream.close();
|
||||
deferred.resolve(actor);
|
||||
});
|
||||
},
|
||||
null, // aLoadingNode
|
||||
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
null, // aTriggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_NORMAL,
|
||||
Ci.nsIContentPolicy.TYPE_OTHER);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -86,7 +86,14 @@ function webappActorRequest(request, onResponse) {
|
|||
|
||||
|
||||
function downloadURL(url, file) {
|
||||
let channel = Services.io.newChannel(url, null, null);
|
||||
let channel = Services.io.newChannel2(url,
|
||||
null,
|
||||
null,
|
||||
null, // aLoadingNode
|
||||
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
null, // aTriggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_NORMAL,
|
||||
Ci.nsIContentPolicy.TYPE_OTHER);
|
||||
let istream = channel.open();
|
||||
let bstream = Cc["@mozilla.org/binaryinputstream;1"]
|
||||
.createInstance(Ci.nsIBinaryInputStream);
|
||||
|
|
|
@ -156,7 +156,14 @@ exports.items = [
|
|||
try {
|
||||
let io = Cc["@mozilla.org/network/io-service;1"]
|
||||
.getService(Ci.nsIIOService);
|
||||
let channel = io.newChannel(data, null, null);
|
||||
let channel = io.newChannel2(data,
|
||||
null,
|
||||
null,
|
||||
null, // aLoadingNode
|
||||
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
null, // aTriggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_NORMAL,
|
||||
Ci.nsIContentPolicy.TYPE_IMAGE);
|
||||
let input = channel.open();
|
||||
let imgTools = Cc["@mozilla.org/image/tools;1"]
|
||||
.getService(Ci.imgITools);
|
||||
|
|
|
@ -667,20 +667,27 @@ function fetch(aURL, aOptions={ loadFromCache: true, window: null,
|
|||
case "chrome":
|
||||
case "resource":
|
||||
try {
|
||||
NetUtil.asyncFetch(url, function onFetch(aStream, aStatus, aRequest) {
|
||||
if (!components.isSuccessCode(aStatus)) {
|
||||
deferred.reject(new Error("Request failed with status code = "
|
||||
+ aStatus
|
||||
+ " after NetUtil.asyncFetch for url = "
|
||||
+ url));
|
||||
return;
|
||||
}
|
||||
NetUtil.asyncFetch2(
|
||||
url,
|
||||
function onFetch(aStream, aStatus, aRequest) {
|
||||
if (!components.isSuccessCode(aStatus)) {
|
||||
deferred.reject(new Error("Request failed with status code = "
|
||||
+ aStatus
|
||||
+ " after NetUtil.asyncFetch2 for url = "
|
||||
+ url));
|
||||
return;
|
||||
}
|
||||
|
||||
let source = NetUtil.readInputStreamToString(aStream, aStream.available());
|
||||
contentType = aRequest.contentType;
|
||||
deferred.resolve(source);
|
||||
aStream.close();
|
||||
});
|
||||
let source = NetUtil.readInputStreamToString(aStream, aStream.available());
|
||||
contentType = aRequest.contentType;
|
||||
deferred.resolve(source);
|
||||
aStream.close();
|
||||
},
|
||||
null, // aLoadingNode
|
||||
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
null, // aTriggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_NORMAL,
|
||||
Ci.nsIContentPolicy.TYPE_STYLESHEET);
|
||||
} catch (ex) {
|
||||
deferred.reject(ex);
|
||||
}
|
||||
|
@ -689,12 +696,26 @@ function fetch(aURL, aOptions={ loadFromCache: true, window: null,
|
|||
default:
|
||||
let channel;
|
||||
try {
|
||||
channel = Services.io.newChannel(url, null, null);
|
||||
channel = Services.io.newChannel2(url,
|
||||
null,
|
||||
null,
|
||||
null, // aLoadingNode
|
||||
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
null, // aTriggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_NORMAL,
|
||||
Ci.nsIContentPolicy.TYPE_STYLESHEET);
|
||||
} catch (e if e.name == "NS_ERROR_UNKNOWN_PROTOCOL") {
|
||||
// On Windows xpcshell tests, c:/foo/bar can pass as a valid URL, but
|
||||
// newChannel won't be able to handle it.
|
||||
url = "file:///" + url;
|
||||
channel = Services.io.newChannel(url, null, null);
|
||||
channel = Services.io.newChannel2(url,
|
||||
null,
|
||||
null,
|
||||
null, // aLoadingNode
|
||||
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
null, // aTriggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_NORMAL,
|
||||
Ci.nsIContentPolicy.TYPE_STYLESHEET);
|
||||
}
|
||||
let chunks = [];
|
||||
let streamListener = {
|
||||
|
|
|
@ -1086,20 +1086,27 @@ function fetch(aURL, aOptions={ loadFromCache: true, window: null,
|
|||
case "chrome":
|
||||
case "resource":
|
||||
try {
|
||||
NetUtil.asyncFetch(url, function onFetch(aStream, aStatus, aRequest) {
|
||||
if (!components.isSuccessCode(aStatus)) {
|
||||
deferred.reject(new Error("Request failed with status code = "
|
||||
+ aStatus
|
||||
+ " after NetUtil.asyncFetch for url = "
|
||||
+ url));
|
||||
return;
|
||||
}
|
||||
NetUtil.asyncFetch2(
|
||||
url,
|
||||
function onFetch(aStream, aStatus, aRequest) {
|
||||
if (!components.isSuccessCode(aStatus)) {
|
||||
deferred.reject(new Error("Request failed with status code = "
|
||||
+ aStatus
|
||||
+ " after NetUtil.asyncFetch2 for url = "
|
||||
+ url));
|
||||
return;
|
||||
}
|
||||
|
||||
let source = NetUtil.readInputStreamToString(aStream, aStream.available());
|
||||
contentType = aRequest.contentType;
|
||||
deferred.resolve(source);
|
||||
aStream.close();
|
||||
});
|
||||
let source = NetUtil.readInputStreamToString(aStream, aStream.available());
|
||||
contentType = aRequest.contentType;
|
||||
deferred.resolve(source);
|
||||
aStream.close();
|
||||
},
|
||||
null, // aLoadingNode
|
||||
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
null, // aTriggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_NORMAL,
|
||||
Ci.nsIContentPolicy.TYPE_STYLESHEET);
|
||||
} catch (ex) {
|
||||
deferred.reject(ex);
|
||||
}
|
||||
|
@ -1108,12 +1115,26 @@ function fetch(aURL, aOptions={ loadFromCache: true, window: null,
|
|||
default:
|
||||
let channel;
|
||||
try {
|
||||
channel = Services.io.newChannel(url, null, null);
|
||||
channel = Services.io.newChannel2(url,
|
||||
null,
|
||||
null,
|
||||
null, // aLoadingNode
|
||||
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
null, // aTriggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_NORMAL,
|
||||
Ci.nsIContentPolicy.TYPE_STYLESHEET);
|
||||
} catch (e if e.name == "NS_ERROR_UNKNOWN_PROTOCOL") {
|
||||
// On Windows xpcshell tests, c:/foo/bar can pass as a valid URL, but
|
||||
// newChannel won't be able to handle it.
|
||||
url = "file:///" + url;
|
||||
channel = Services.io.newChannel(url, null, null);
|
||||
channel = Services.io.newChannel2(url,
|
||||
null,
|
||||
null,
|
||||
null, // aLoadingNode
|
||||
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
null, // aTriggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_NORMAL,
|
||||
Ci.nsIContentPolicy.TYPE_STYLESHEET);
|
||||
}
|
||||
let chunks = [];
|
||||
let streamListener = {
|
||||
|
|
|
@ -7,6 +7,7 @@ let { DebuggerClient } =
|
|||
Cu.import("resource://gre/modules/devtools/dbg-client.jsm", {});
|
||||
let { FileUtils } = Cu.import("resource://gre/modules/FileUtils.jsm", {});
|
||||
let { NetUtil } = Cu.import("resource://gre/modules/NetUtil.jsm", {});
|
||||
let { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
|
||||
let Pipe = CC("@mozilla.org/pipe;1", "nsIPipe", "init");
|
||||
let { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
|
||||
|
||||
|
@ -61,11 +62,18 @@ TestBulkActor.prototype = {
|
|||
type: type,
|
||||
length: really_long().length
|
||||
}).then(({copyFrom}) => {
|
||||
NetUtil.asyncFetch(getTestTempFile("bulk-input"), input => {
|
||||
copyFrom(input).then(() => {
|
||||
input.close();
|
||||
});
|
||||
});
|
||||
NetUtil.asyncFetch2(
|
||||
getTestTempFile("bulk-input"),
|
||||
input => {
|
||||
copyFrom(input).then(() => {
|
||||
input.close();
|
||||
});
|
||||
},
|
||||
null, // aLoadingNode
|
||||
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
null, // aTriggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_NORMAL,
|
||||
Ci.nsIContentPolicy.TYPE_OTHER);
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -160,12 +168,19 @@ let test_bulk_request_cs = Task.async(function*(transportFactory, actorType, rep
|
|||
|
||||
// Send bulk data to server
|
||||
request.on("bulk-send-ready", ({copyFrom}) => {
|
||||
NetUtil.asyncFetch(getTestTempFile("bulk-input"), input => {
|
||||
copyFrom(input).then(() => {
|
||||
input.close();
|
||||
bulkCopyDeferred.resolve();
|
||||
});
|
||||
});
|
||||
NetUtil.asyncFetch2(
|
||||
getTestTempFile("bulk-input"),
|
||||
input => {
|
||||
copyFrom(input).then(() => {
|
||||
input.close();
|
||||
bulkCopyDeferred.resolve();
|
||||
});
|
||||
},
|
||||
null, // aLoadingNode
|
||||
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
null, // aTriggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_NORMAL,
|
||||
Ci.nsIContentPolicy.TYPE_OTHER);
|
||||
});
|
||||
|
||||
// Set up reply handling for this type
|
||||
|
@ -242,13 +257,20 @@ function verify_files() {
|
|||
|
||||
// Ensure output file contents actually match
|
||||
let compareDeferred = promise.defer();
|
||||
NetUtil.asyncFetch(getTestTempFile("bulk-output"), input => {
|
||||
let outputData = NetUtil.readInputStreamToString(input, reallyLong.length);
|
||||
// Avoid do_check_eq here so we don't log the contents
|
||||
do_check_true(outputData === reallyLong);
|
||||
input.close();
|
||||
compareDeferred.resolve();
|
||||
});
|
||||
NetUtil.asyncFetch2(
|
||||
getTestTempFile("bulk-output"),
|
||||
input => {
|
||||
let outputData = NetUtil.readInputStreamToString(input, reallyLong.length);
|
||||
// Avoid do_check_eq here so we don't log the contents
|
||||
do_check_true(outputData === reallyLong);
|
||||
input.close();
|
||||
compareDeferred.resolve();
|
||||
},
|
||||
null, // aLoadingNode
|
||||
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
null, // aTriggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_NORMAL,
|
||||
Ci.nsIContentPolicy.TYPE_OTHER);
|
||||
|
||||
return compareDeferred.promise.then(cleanup_files);
|
||||
}
|
||||
|
|
|
@ -40,11 +40,18 @@ let test_transport = Task.async(function*(transportFactory) {
|
|||
|
||||
// Sending from client to server
|
||||
function write_data({copyFrom}) {
|
||||
NetUtil.asyncFetch(getTestTempFile("bulk-input"), function(input, status) {
|
||||
copyFrom(input).then(() => {
|
||||
input.close();
|
||||
});
|
||||
});
|
||||
NetUtil.asyncFetch2(
|
||||
getTestTempFile("bulk-input"),
|
||||
function(input, status) {
|
||||
copyFrom(input).then(() => {
|
||||
input.close();
|
||||
});
|
||||
},
|
||||
null, // aLoadingNode
|
||||
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
null, // aTriggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_NORMAL,
|
||||
Ci.nsIContentPolicy.TYPE_OTHER);
|
||||
}
|
||||
|
||||
// Receiving on server from client
|
||||
|
@ -148,13 +155,20 @@ function verify() {
|
|||
|
||||
// Ensure output file contents actually match
|
||||
let compareDeferred = promise.defer();
|
||||
NetUtil.asyncFetch(getTestTempFile("bulk-output"), input => {
|
||||
let outputData = NetUtil.readInputStreamToString(input, reallyLong.length);
|
||||
// Avoid do_check_eq here so we don't log the contents
|
||||
do_check_true(outputData === reallyLong);
|
||||
input.close();
|
||||
compareDeferred.resolve();
|
||||
});
|
||||
NetUtil.asyncFetch2(
|
||||
getTestTempFile("bulk-output"),
|
||||
input => {
|
||||
let outputData = NetUtil.readInputStreamToString(input, reallyLong.length);
|
||||
// Avoid do_check_eq here so we don't log the contents
|
||||
do_check_true(outputData === reallyLong);
|
||||
input.close();
|
||||
compareDeferred.resolve();
|
||||
},
|
||||
null, // aLoadingNode
|
||||
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
null, // aTriggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_NORMAL,
|
||||
Ci.nsIContentPolicy.TYPE_OTHER);
|
||||
|
||||
return compareDeferred.promise.then(cleanup_files);
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ let { DebuggerServer } =
|
|||
Cu.import("resource://gre/modules/devtools/dbg-server.jsm", {});
|
||||
let { FileUtils } = Cu.import("resource://gre/modules/FileUtils.jsm", {});
|
||||
let { NetUtil } = Cu.import("resource://gre/modules/NetUtil.jsm", {});
|
||||
let { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
|
||||
|
||||
function run_test() {
|
||||
initTestDebuggerServer();
|
||||
|
@ -40,11 +41,18 @@ let test_bulk_transfer_transport = Task.async(function*(transportFactory) {
|
|||
|
||||
// Sending from client to server
|
||||
function write_data({copyFrom}) {
|
||||
NetUtil.asyncFetch(getTestTempFile("bulk-input"), function(input, status) {
|
||||
copyFrom(input).then(() => {
|
||||
input.close();
|
||||
});
|
||||
});
|
||||
NetUtil.asyncFetch2(
|
||||
getTestTempFile("bulk-input"),
|
||||
function(input, status) {
|
||||
copyFrom(input).then(() => {
|
||||
input.close();
|
||||
});
|
||||
},
|
||||
null, // aLoadingNode
|
||||
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
null, // aTriggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_NORMAL,
|
||||
Ci.nsIContentPolicy.TYPE_OTHER);
|
||||
}
|
||||
|
||||
// Receiving on server from client
|
||||
|
@ -119,13 +127,20 @@ function verify() {
|
|||
|
||||
// Ensure output file contents actually match
|
||||
let compareDeferred = promise.defer();
|
||||
NetUtil.asyncFetch(getTestTempFile("bulk-output"), input => {
|
||||
let outputData = NetUtil.readInputStreamToString(input, reallyLong.length);
|
||||
// Avoid do_check_eq here so we don't log the contents
|
||||
do_check_true(outputData === reallyLong);
|
||||
input.close();
|
||||
compareDeferred.resolve();
|
||||
});
|
||||
NetUtil.asyncFetch2(
|
||||
getTestTempFile("bulk-output"),
|
||||
input => {
|
||||
let outputData = NetUtil.readInputStreamToString(input, reallyLong.length);
|
||||
// Avoid do_check_eq here so we don't log the contents
|
||||
do_check_true(outputData === reallyLong);
|
||||
input.close();
|
||||
compareDeferred.resolve();
|
||||
},
|
||||
null, // aLoadingNode
|
||||
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
null, // aTriggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_NORMAL,
|
||||
Ci.nsIContentPolicy.TYPE_OTHER);
|
||||
|
||||
return compareDeferred.promise.then(cleanup_files);
|
||||
}
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче