зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to autoland
--HG-- rename : memory/mozjemalloc/jemalloc.c => memory/mozjemalloc/mozjemalloc.cpp
This commit is contained in:
Коммит
0bbdca7c50
|
@ -61,6 +61,9 @@ var whitelist = new Set([
|
|||
{file: "chrome://devtools/content/inspector/markup/markup.xhtml",
|
||||
isFromDevTools: true},
|
||||
|
||||
// Kept for add-on compatibility, should be removed in bug 851471.
|
||||
{file: "chrome://mozapps/skin/downloads/downloadIcon.png"},
|
||||
|
||||
// extensions/pref/autoconfig/src/nsReadConfig.cpp
|
||||
{file: "resource://gre/defaults/autoconfig/prefcalls.js"},
|
||||
|
||||
|
@ -111,7 +114,6 @@ var whitelist = new Set([
|
|||
// browser/extensions/pdfjs/content/web/viewer.js#7450
|
||||
{file: "resource://pdf.js/web/debugger.js"},
|
||||
|
||||
|
||||
// Starting from here, files in the whitelist are bugs that need fixing.
|
||||
// Bug 1339420
|
||||
{file: "chrome://branding/content/icon128.png"},
|
||||
|
|
|
@ -2201,7 +2201,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|||
|
||||
delta /= 1000;
|
||||
|
||||
// This code is taken from nsDownloadManager.cpp
|
||||
// This algorithm is the same used by the downloads code.
|
||||
let speed = (aProgress - this.notification.lastProgress) / delta;
|
||||
if (this.notification.speed)
|
||||
speed = speed * 0.9 + this.notification.speed * 0.1;
|
||||
|
|
|
@ -634,17 +634,11 @@ XPCOMUtils.defineLazyGetter(DownloadsCommon, "isWinVistaOrHigher", function() {
|
|||
|
||||
/**
|
||||
* Retrieves the list of past and completed downloads from the underlying
|
||||
* Download Manager data, and provides asynchronous notifications allowing to
|
||||
* Downloads API data, and provides asynchronous notifications allowing to
|
||||
* build a consistent view of the available data.
|
||||
*
|
||||
* This object responds to real-time changes in the underlying Download Manager
|
||||
* data. For example, the deletion of one or more downloads is notified through
|
||||
* the nsIObserver interface, while any state or progress change is notified
|
||||
* through the nsIDownloadProgressListener interface.
|
||||
*
|
||||
* Note that using this object does not automatically start the Download Manager
|
||||
* service. Consumers will see an empty list of downloads until the service is
|
||||
* actually started. This is useful to display a neutral progress indicator in
|
||||
* Note that using this object does not automatically initialize the list of
|
||||
* downloads. This is useful to display a neutral progress indicator in
|
||||
* the main browser window until the autostart timeout elapses.
|
||||
*
|
||||
* Note that DownloadsData and PrivateDownloadsData are two equivalent singleton
|
||||
|
|
|
@ -507,15 +507,6 @@ var gMainPane = {
|
|||
iconUrlSpec = fph.getURLSpecFromFile(currentDirPref.value);
|
||||
} else if (folderListPref.value == 1) {
|
||||
// 'Downloads'
|
||||
// In 1.5, this pointed to a folder we created called 'My Downloads'
|
||||
// and was available as an option in the 1.5 drop down. On XP this
|
||||
// was in My Documents, on OSX it was in User Docs. In 2.0, we did
|
||||
// away with the drop down option, although the special label was
|
||||
// still supported for the folder if it existed. Because it was
|
||||
// not exposed it was rarely used.
|
||||
// With 3.0, a new desktop folder - 'Downloads' was introduced for
|
||||
// platforms and versions that don't support a default system downloads
|
||||
// folder. See nsDownloadManager for details.
|
||||
downloadFolder.label = bundlePreferences.getString("downloadsFolderName");
|
||||
iconUrlSpec = fph.getURLSpecFromFile(await this._indexToFolder(1));
|
||||
} else {
|
||||
|
|
|
@ -2019,15 +2019,6 @@ var gApplicationsPane = {
|
|||
iconUrlSpec = fph.getURLSpecFromFile(currentDirPref.value);
|
||||
} else if (folderListPref.value == 1) {
|
||||
// 'Downloads'
|
||||
// In 1.5, this pointed to a folder we created called 'My Downloads'
|
||||
// and was available as an option in the 1.5 drop down. On XP this
|
||||
// was in My Documents, on OSX it was in User Docs. In 2.0, we did
|
||||
// away with the drop down option, although the special label was
|
||||
// still supported for the folder if it existed. Because it was
|
||||
// not exposed it was rarely used.
|
||||
// With 3.0, a new desktop folder - 'Downloads' was introduced for
|
||||
// platforms and versions that don't support a default system downloads
|
||||
// folder. See nsDownloadManager for details.
|
||||
downloadFolder.label = bundlePreferences.getString("downloadsFolderName");
|
||||
iconUrlSpec = fph.getURLSpecFromFile(await this._indexToFolder(1));
|
||||
} else {
|
||||
|
|
|
@ -60,7 +60,6 @@ else
|
|||
MAR_CHANNEL_ID=firefox-mozilla-central
|
||||
fi
|
||||
MOZ_PROFILE_MIGRATOR=1
|
||||
MOZ_JSDOWNLOADS=1
|
||||
|
||||
# Enable checking that add-ons are signed by the trusted root
|
||||
MOZ_ADDON_SIGNING=1
|
||||
|
|
|
@ -538,7 +538,7 @@ toolbarpaletteitem[place="palette"] > #personal-bookmarks > #bookmarks-toolbar-p
|
|||
|
||||
#urlbar,
|
||||
.searchbar-textbox {
|
||||
font: icon;
|
||||
font-size: 1.25em;
|
||||
}
|
||||
|
||||
%else
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
box-shadow: 0 1px 4px hsla(0, 0%, 0%, .05);
|
||||
padding: 0;
|
||||
margin: 0 2px;
|
||||
min-height: 30px;
|
||||
}
|
||||
|
||||
#urlbar:-moz-lwtheme,
|
||||
|
|
|
@ -752,7 +752,9 @@ toolbar[brighttext] #close-button {
|
|||
#urlbar,
|
||||
.searchbar-textbox {
|
||||
font-size: 1.15em;
|
||||
%ifndef MOZ_PHOTON_THEME
|
||||
min-height: 28px;
|
||||
%endif
|
||||
}
|
||||
|
||||
:root {
|
||||
|
|
|
@ -14,5 +14,15 @@ DEFINES['LOCALE_SNAME'] = 0x5c
|
|||
|
||||
LOCAL_INCLUDES += ['/intl/icu/source/i18n']
|
||||
|
||||
if CONFIG['GNU_CXX']:
|
||||
CXXFLAGS += [
|
||||
'-Wno-deprecated-declarations',
|
||||
'-Wno-type-limits',
|
||||
'-Wno-unused-but-set-variable',
|
||||
'-Wno-unused-function',
|
||||
'-Wno-sign-compare',
|
||||
'-Wno-maybe-uninitialized',
|
||||
]
|
||||
|
||||
include('../defs.mozbuild')
|
||||
include('sources.mozbuild')
|
||||
|
|
|
@ -979,14 +979,13 @@ html .arrow.expanded svg {
|
|||
.search-field .search-nav-buttons .nav-btn path {
|
||||
fill: var(--theme-comment);
|
||||
}
|
||||
|
||||
.result-list {
|
||||
list-style: none;
|
||||
width: 100%;
|
||||
background-color: var(--theme-toolbar-background);
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
overflow: auto;
|
||||
width: calc(100% - 1px); /* 1px fixes the hidden right border */
|
||||
}
|
||||
|
||||
.result-list.big {
|
||||
|
@ -1004,10 +1003,7 @@ html .arrow.expanded svg {
|
|||
padding: 4px 13px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.result-list li:first-child {
|
||||
border-top: none;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.result-list.big li {
|
||||
|
@ -1022,12 +1018,7 @@ html .arrow.expanded svg {
|
|||
}
|
||||
|
||||
.result-list li.selected {
|
||||
border: 1px solid var(--theme-selection-background);
|
||||
}
|
||||
|
||||
.result-list.big li.selected {
|
||||
padding-left: 9px;
|
||||
padding-top: 9px;
|
||||
border-color: var(--theme-selection-background);
|
||||
}
|
||||
|
||||
.search-bar .result-list li.selected {
|
||||
|
@ -1035,6 +1026,10 @@ html .arrow.expanded svg {
|
|||
color: white;
|
||||
}
|
||||
|
||||
.theme-dark .search-bar .result-list li.selected {
|
||||
background-color: var(--theme-body-background);
|
||||
}
|
||||
|
||||
.result-list li .title {
|
||||
line-height: 1.5em;
|
||||
word-break: break-all;
|
||||
|
@ -1132,6 +1127,35 @@ html .arrow.expanded svg {
|
|||
padding-top: 5px;
|
||||
text-align: center;
|
||||
}
|
||||
.outline-list {
|
||||
list-style-type: "-";
|
||||
}
|
||||
|
||||
.outline-list__element {
|
||||
color: blue;
|
||||
padding-left: 0.5rem;
|
||||
}
|
||||
|
||||
.function-signature {
|
||||
line-height: 20px;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.function-signature .function-name {
|
||||
color: var(--theme-highlight-blue);
|
||||
}
|
||||
|
||||
.function-signature .param {
|
||||
color: var(--string-color);
|
||||
}
|
||||
|
||||
.function-signature .paren {
|
||||
color: var(--object-color);
|
||||
}
|
||||
|
||||
.function-signature .comma {
|
||||
color: var(--object-color);
|
||||
}
|
||||
.tree {
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
|
@ -1159,6 +1183,10 @@ html .arrow.expanded svg {
|
|||
background-color: var(--theme-selection-background);
|
||||
}
|
||||
|
||||
.theme-dark .tree .node.focused {
|
||||
background-color: var(--theme-selection-background-semitransparent);
|
||||
}
|
||||
|
||||
html:not([dir="rtl"]) .tree .node > div {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
@ -1209,6 +1237,11 @@ html[dir="rtl"] .tree .node > div {
|
|||
transform: translate(0, 2px);
|
||||
transition: transform 0.25s ease-in-out;
|
||||
cursor: pointer;
|
||||
padding: 5px 2px;
|
||||
}
|
||||
|
||||
.toggle-button-start.vertical,
|
||||
.toggle-button-end.vertical {
|
||||
padding: 4px 2px;
|
||||
}
|
||||
|
||||
|
@ -1241,10 +1274,6 @@ html .toggle-button-end.vertical svg {
|
|||
transform: rotate(-90deg);
|
||||
}
|
||||
|
||||
.toggle-button-end.vertical {
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.toggle-button-start.collapsed,
|
||||
.toggle-button-end.collapsed {
|
||||
transform: rotate(180deg);
|
||||
|
@ -1454,78 +1483,59 @@ html .toggle-button-end.vertical svg {
|
|||
.search-bar .result-list {
|
||||
max-height: 230px;
|
||||
}
|
||||
|
||||
.function-signature {
|
||||
line-height: 20px;
|
||||
align-self: center;
|
||||
.object-value .unavailable {
|
||||
color: var(--theme-comment);
|
||||
}
|
||||
.bracket-arrow {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.function-signature .function-name {
|
||||
color: var(--theme-highlight-blue);
|
||||
}
|
||||
|
||||
.function-signature .param {
|
||||
color: var(--string-color);
|
||||
}
|
||||
|
||||
.function-signature .paren {
|
||||
color: var(--object-color);
|
||||
}
|
||||
|
||||
.function-signature .comma {
|
||||
color: var(--object-color);
|
||||
}
|
||||
.popover {
|
||||
position: fixed;
|
||||
z-index: 100;
|
||||
box-shadow: 1px 2px 4px 1px var(--theme-toolbar-background-alt);
|
||||
}
|
||||
|
||||
.popover .gap {
|
||||
height: 5px;
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
||||
.popover::before,
|
||||
.popover::after {
|
||||
.bracket-arrow::before,
|
||||
.bracket-arrow::after {
|
||||
content: '';
|
||||
height: 0;
|
||||
width: 0;
|
||||
position: absolute;
|
||||
border: 7px solid transparent;
|
||||
left: calc(20% - 7px); /* corresponds to calculation in Popover.js */
|
||||
}
|
||||
|
||||
.popover::before {
|
||||
.bracket-arrow.up::before {
|
||||
border-bottom-color: var(--theme-splitter-color);
|
||||
top: -9px;
|
||||
top: -1px;
|
||||
}
|
||||
|
||||
.theme-dark .popover::before {
|
||||
.theme-dark .bracket-arrow.up::before {
|
||||
border-bottom-color: var(--theme-body-color);
|
||||
}
|
||||
|
||||
.popover::after {
|
||||
.bracket-arrow.up::after {
|
||||
border-bottom-color: var(--theme-body-background);
|
||||
top: -8px;
|
||||
top: 0px;
|
||||
}
|
||||
|
||||
.popover.up::before {
|
||||
.bracket-arrow.down::before {
|
||||
border-bottom-color: transparent;
|
||||
border-top-color: var(--theme-splitter-color);
|
||||
bottom: -9px;
|
||||
top: initial;
|
||||
top: 0px;
|
||||
}
|
||||
|
||||
.theme-dark .popover.up::before {
|
||||
.theme-dark .bracket-arrow.down::before {
|
||||
border-top-color: var(--theme-body-color);
|
||||
}
|
||||
|
||||
.popover.up::after {
|
||||
.bracket-arrow.down::after {
|
||||
border-bottom-color: transparent;
|
||||
border-top-color: var(--theme-body-background);
|
||||
bottom: -8px;
|
||||
top: initial;
|
||||
border-top-color: var(--theme-toolbar-background);
|
||||
top: -1px;
|
||||
}
|
||||
.popover {
|
||||
position: fixed;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.popover .gap {
|
||||
height: 5px;
|
||||
padding-top: 5px;
|
||||
}
|
||||
.popover .preview {
|
||||
background: var(--theme-body-background);
|
||||
|
@ -1607,6 +1617,7 @@ html .toggle-button-end.vertical svg {
|
|||
|
||||
.add-to-expression-bar {
|
||||
border: 1px solid var(--theme-splitter-color);
|
||||
border-top: none;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
|
@ -1633,11 +1644,15 @@ html .toggle-button-end.vertical svg {
|
|||
color: var(--theme-comment);
|
||||
cursor: pointer;
|
||||
}
|
||||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
.editor-wrapper {
|
||||
--debug-line-background: rgba(226, 236, 247, 0.5);
|
||||
--debug-line-border: rgb(145, 188, 219);
|
||||
}
|
||||
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
.theme-dark .editor-wrapper {
|
||||
--debug-line-background: rgb(73, 82, 103);
|
||||
--debug-line-border: rgb(119, 134, 162);
|
||||
}
|
||||
|
||||
/**
|
||||
* There's a known codemirror flex issue with chrome that this addresses.
|
||||
|
@ -1677,6 +1692,10 @@ html[dir="rtl"] .editor-mount {
|
|||
height: 14px;
|
||||
}
|
||||
|
||||
.editor-wrapper .highlight-lines {
|
||||
background: var(--theme-selection-background-semitransparent);
|
||||
}
|
||||
|
||||
.coverage-on .CodeMirror-code :not(.hit-marker) .CodeMirror-line,
|
||||
.coverage-on .CodeMirror-code :not(.hit-marker) .CodeMirror-gutter-wrapper {
|
||||
opacity: 0.5;
|
||||
|
@ -1717,6 +1736,17 @@ html[dir="rtl"] .editor-mount {
|
|||
opacity: 0.3;
|
||||
}
|
||||
|
||||
.editor.column-breakpoint svg {
|
||||
fill: var(--theme-selection-background);
|
||||
vertical-align: middle;
|
||||
width: 17px;
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
.editor.column-breakpoint.breakpoint-disabled svg {
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
.CodeMirror {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
@ -1756,13 +1786,18 @@ html[dir="rtl"] .editor-mount {
|
|||
color: var(--theme-content-color3);
|
||||
}
|
||||
|
||||
.debug-line .CodeMirror-line {
|
||||
background-color: var(--breakpoint-active-color) !important;
|
||||
.new-debug-line .CodeMirror-line {
|
||||
background-color: var(--debug-line-background) !important;
|
||||
outline: var(--debug-line-border) solid 1px;
|
||||
}
|
||||
|
||||
.new-debug-line .CodeMirror-linenumber {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
/* Don't display the highlight color since the debug line
|
||||
is already highlighted */
|
||||
.debug-line .CodeMirror-activeline-background {
|
||||
.new-debug-line .CodeMirror-activeline-background {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
@ -1812,13 +1847,13 @@ html[dir="rtl"] .editor-mount {
|
|||
}
|
||||
|
||||
.why-paused {
|
||||
background-color: var(--breakpoint-active-color);
|
||||
background-color: var(--theme-body-background);
|
||||
border-bottom: 1px solid var(--theme-splitter-color);
|
||||
color: var(--theme-highlight-blue);
|
||||
padding: 10px 10px 10px 20px;
|
||||
white-space: normal;
|
||||
opacity: 0.9;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
flex: 0 1 auto;
|
||||
}
|
||||
|
||||
|
@ -1829,6 +1864,10 @@ html[dir="rtl"] .editor-mount {
|
|||
.why-paused .message {
|
||||
font-size: 10px;
|
||||
}
|
||||
.breakpoints-toggle {
|
||||
margin: 2px 3px;
|
||||
}
|
||||
|
||||
.breakpoints-list * {
|
||||
-moz-user-select: none;
|
||||
user-select: none;
|
||||
|
@ -1884,6 +1923,7 @@ html .breakpoints-list .breakpoint.paused {
|
|||
|
||||
.breakpoints-list .breakpoint-checkbox {
|
||||
margin-inline-start: 0;
|
||||
vertical-align: -2px;
|
||||
}
|
||||
|
||||
.breakpoints-list .breakpoint-label {
|
||||
|
@ -1916,8 +1956,9 @@ html .breakpoints-list .breakpoint.paused {
|
|||
|
||||
.breakpoint .close-btn {
|
||||
position: absolute;
|
||||
offset-inline-end: 16px;
|
||||
top: 12px;
|
||||
offset-inline-end: 13px;
|
||||
offset-inline-start: auto;
|
||||
top: 9px;
|
||||
}
|
||||
|
||||
.breakpoint .close {
|
||||
|
@ -2410,10 +2451,16 @@ html .command-bar > button:disabled {
|
|||
z-index: 100;
|
||||
}
|
||||
|
||||
html .welcomebox .toggle-button-end {
|
||||
bottom: 11px;
|
||||
.welcomebox .toggle-button-end {
|
||||
position: absolute;
|
||||
top: auto;
|
||||
bottom: 0;
|
||||
offset-inline-end: 0;
|
||||
offset-inline-start: auto;
|
||||
}
|
||||
|
||||
html .welcomebox .toggle-button-end.collapsed {
|
||||
bottom: 1px;
|
||||
}
|
||||
.source-header {
|
||||
border-bottom: 1px solid var(--theme-splitter-color);
|
||||
|
@ -2430,7 +2477,7 @@ html .welcomebox .toggle-button-end {
|
|||
|
||||
.source-header .new-tab-btn {
|
||||
padding: 0px 4px;
|
||||
margin-top: 8px;
|
||||
margin-top: 4px;
|
||||
cursor: pointer;
|
||||
fill: var(--theme-comment);
|
||||
transition: 0.1s ease;
|
||||
|
@ -2450,15 +2497,15 @@ html .welcomebox .toggle-button-end {
|
|||
border: 1px solid transparent;
|
||||
border-top-left-radius: 2px;
|
||||
border-top-right-radius: 2px;
|
||||
height: 30px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
align-items: flex-end;
|
||||
position: relative;
|
||||
transition: all 0.25s ease;
|
||||
min-width: 40px;
|
||||
overflow: hidden;
|
||||
padding: 6px;
|
||||
padding: 5px;
|
||||
margin-inline-start: 3px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.source-tab:hover {
|
||||
|
@ -2492,9 +2539,10 @@ html .welcomebox .toggle-button-end {
|
|||
fill: var(--theme-textbox-box-shadow);
|
||||
}
|
||||
|
||||
.source-tab .blackBox {
|
||||
.source-tab .blackBox,
|
||||
.source-tab .prettyPrint {
|
||||
line-height: 0;
|
||||
padding: 5px;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.source-tab .blackBox svg {
|
||||
|
@ -2506,20 +2554,21 @@ html .welcomebox .toggle-button-end {
|
|||
fill: var(--theme-textbox-box-shadow);
|
||||
}
|
||||
|
||||
.theme-dark .source-tab .blackBox circle {
|
||||
fill: var(--theme-body-color);
|
||||
}
|
||||
|
||||
.source-tab .filename {
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.source-tab.pretty .filename {
|
||||
padding-inline-start: 8px;
|
||||
padding: 0 4px;
|
||||
align-self: flex-start;
|
||||
}
|
||||
|
||||
.source-tab .close-btn {
|
||||
visibility: hidden;
|
||||
line-height: 0;
|
||||
margin-inline-start: 6px;
|
||||
}
|
||||
|
||||
.source-tab.active .close-btn {
|
||||
|
@ -2536,8 +2585,8 @@ html .welcomebox .toggle-button-end {
|
|||
box-shadow: 0 4px 4px 0 var(--search-overlays-semitransparent);
|
||||
max-height: 300px;
|
||||
position: absolute;
|
||||
right: 8px;
|
||||
top: 35px;
|
||||
right: 0;
|
||||
top: 23px;
|
||||
width: var(--width);
|
||||
z-index: 1000;
|
||||
}
|
||||
|
@ -2559,7 +2608,6 @@ html[dir="rtl"] .dropdown {
|
|||
border: none;
|
||||
padding: 0;
|
||||
font-weight: 100;
|
||||
margin-top: 6px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -5368,7 +5368,7 @@ return /******/ (function(modules) { // webpackBootstrap
|
|||
|
||||
this.potentialArrowAt = -1;
|
||||
|
||||
this.inMethod = this.inFunction = this.inGenerator = this.inAsync = this.inPropertyName = this.inType = this.noAnonFunctionType = false;
|
||||
this.inMethod = this.inFunction = this.inGenerator = this.inAsync = this.inPropertyName = this.inType = this.inClassProperty = this.noAnonFunctionType = false;
|
||||
|
||||
this.labels = [];
|
||||
|
||||
|
@ -6080,25 +6080,29 @@ return /******/ (function(modules) { // webpackBootstrap
|
|||
|
||||
Tokenizer.prototype.readNumber = function readNumber(startsWithDot) {
|
||||
var start = this.state.pos;
|
||||
var octal = this.input.charCodeAt(this.state.pos) === 48;
|
||||
var octal = this.input.charCodeAt(start) === 48; // '0'
|
||||
var isFloat = false;
|
||||
|
||||
if (!startsWithDot && this.readInt(10) === null) this.raise(start, "Invalid number");
|
||||
if (octal && this.state.pos == start + 1) octal = false; // number === 0
|
||||
|
||||
var next = this.input.charCodeAt(this.state.pos);
|
||||
if (next === 46) {
|
||||
if (next === 46 && !octal) {
|
||||
// '.'
|
||||
++this.state.pos;
|
||||
this.readInt(10);
|
||||
isFloat = true;
|
||||
next = this.input.charCodeAt(this.state.pos);
|
||||
}
|
||||
if (next === 69 || next === 101) {
|
||||
|
||||
if ((next === 69 || next === 101) && !octal) {
|
||||
// 'eE'
|
||||
next = this.input.charCodeAt(++this.state.pos);
|
||||
if (next === 43 || next === 45) ++this.state.pos; // '+-'
|
||||
if (this.readInt(10) === null) this.raise(start, "Invalid number");
|
||||
isFloat = true;
|
||||
}
|
||||
|
||||
if (isIdentifierStart(this.fullCharCodeAtPos())) this.raise(this.state.pos, "Identifier directly after number");
|
||||
|
||||
var str = this.input.slice(start, this.state.pos);
|
||||
|
@ -6107,8 +6111,10 @@ return /******/ (function(modules) { // webpackBootstrap
|
|||
val = parseFloat(str);
|
||||
} else if (!octal || str.length === 1) {
|
||||
val = parseInt(str, 10);
|
||||
} else if (/[89]/.test(str) || this.state.strict) {
|
||||
} else if (this.state.strict) {
|
||||
this.raise(start, "Invalid number");
|
||||
} else if (/[89]/.test(str)) {
|
||||
val = parseInt(str, 10);
|
||||
} else {
|
||||
val = parseInt(str, 8);
|
||||
}
|
||||
|
@ -7407,6 +7413,7 @@ return /******/ (function(modules) { // webpackBootstrap
|
|||
};
|
||||
|
||||
pp$1.parseClassProperty = function (node) {
|
||||
this.state.inClassProperty = true;
|
||||
if (this.match(types.eq)) {
|
||||
if (!this.hasPlugin("classProperties")) this.unexpected();
|
||||
this.next();
|
||||
|
@ -7415,6 +7422,7 @@ return /******/ (function(modules) { // webpackBootstrap
|
|||
node.value = null;
|
||||
}
|
||||
this.semicolon();
|
||||
this.state.inClassProperty = false;
|
||||
return this.finishNode(node, "ClassProperty");
|
||||
};
|
||||
|
||||
|
@ -8446,7 +8454,7 @@ return /******/ (function(modules) { // webpackBootstrap
|
|||
|
||||
switch (this.state.type) {
|
||||
case types._super:
|
||||
if (!this.state.inMethod && !this.options.allowSuperOutsideMethod) {
|
||||
if (!this.state.inMethod && !this.state.inClassProperty && !this.options.allowSuperOutsideMethod) {
|
||||
this.raise(this.state.start, "'super' outside of function or class");
|
||||
}
|
||||
|
||||
|
@ -8955,8 +8963,9 @@ return /******/ (function(modules) { // webpackBootstrap
|
|||
}
|
||||
|
||||
if (!prop.computed && prop.key.type === "Identifier") {
|
||||
this.checkReservedWord(prop.key.name, prop.key.start, true, true);
|
||||
|
||||
if (isPattern) {
|
||||
this.checkReservedWord(prop.key.name, prop.key.start, true, true);
|
||||
prop.value = this.parseMaybeDefault(startPos, startLoc, prop.key.__clone());
|
||||
} else if (this.match(types.eq) && refShorthandDefaultPos) {
|
||||
if (!refShorthandDefaultPos.start) {
|
||||
|
@ -10199,7 +10208,7 @@ return /******/ (function(modules) { // webpackBootstrap
|
|||
} else {
|
||||
if (this.match(types.ellipsis)) {
|
||||
if (!allowSpread) {
|
||||
this.unexpected(null, "Spread operator cannnot appear in class or interface definitions");
|
||||
this.unexpected(null, "Spread operator cannot appear in class or interface definitions");
|
||||
}
|
||||
if (variance) {
|
||||
this.unexpected(variance.start, "Spread properties cannot have variance");
|
||||
|
@ -10885,6 +10894,12 @@ return /******/ (function(modules) { // webpackBootstrap
|
|||
};
|
||||
});
|
||||
|
||||
instance.extend("isNonstaticConstructor", function (inner) {
|
||||
return function (method) {
|
||||
return !this.match(types.colon) && inner.call(this, method);
|
||||
};
|
||||
});
|
||||
|
||||
// parse type parameters for class methods
|
||||
instance.extend("parseClassMethod", function (inner) {
|
||||
return function (classBody, method) {
|
||||
|
@ -11141,6 +11156,12 @@ return /******/ (function(modules) { // webpackBootstrap
|
|||
} catch (err) {
|
||||
if (err instanceof SyntaxError) {
|
||||
this.state = state;
|
||||
|
||||
// Remove `tc.j_expr` and `tc.j_oTag` from context added
|
||||
// by parsing `jsxTagStart` to stop the JSX plugin from
|
||||
// messing with the tokens
|
||||
this.state.context.length -= 2;
|
||||
|
||||
jsxError = err;
|
||||
} else {
|
||||
// istanbul ignore next: no such error is expected
|
||||
|
@ -11149,9 +11170,6 @@ return /******/ (function(modules) { // webpackBootstrap
|
|||
}
|
||||
}
|
||||
|
||||
// Need to push something onto the context to stop
|
||||
// the JSX plugin from messing with the tokens
|
||||
this.state.context.push(types$1.parenExpression);
|
||||
if (jsxError != null || this.isRelational("<")) {
|
||||
var arrowExpression = void 0;
|
||||
var typeParameters = void 0;
|
||||
|
@ -11174,7 +11192,6 @@ return /******/ (function(modules) { // webpackBootstrap
|
|||
this.raise(typeParameters.start, "Expected an arrow function after this type parameter declaration");
|
||||
}
|
||||
}
|
||||
this.state.context.pop();
|
||||
|
||||
return inner.apply(this, args);
|
||||
};
|
||||
|
@ -19540,7 +19557,7 @@ return /******/ (function(modules) { // webpackBootstrap
|
|||
exports.disable = disable;
|
||||
exports.enable = enable;
|
||||
exports.enabled = enabled;
|
||||
exports.humanize = __webpack_require__(1016);
|
||||
exports.humanize = __webpack_require__(1024);
|
||||
|
||||
/**
|
||||
* The currently active debug mode names, and names to skip.
|
||||
|
@ -28947,41 +28964,63 @@ return /******/ (function(modules) { // webpackBootstrap
|
|||
exports.getVariablesInScope = getVariablesInScope;
|
||||
exports.isExpressionInScope = isExpressionInScope;
|
||||
|
||||
var _babylon = __webpack_require__(435);
|
||||
|
||||
var babylon = _interopRequireWildcard(_babylon);
|
||||
|
||||
var _babelTraverse = __webpack_require__(436);
|
||||
|
||||
var _babelTraverse2 = _interopRequireDefault(_babelTraverse);
|
||||
|
||||
var _babelTypes = __webpack_require__(493);
|
||||
|
||||
var t = _interopRequireWildcard(_babelTypes);
|
||||
|
||||
var _devtoolsConfig = __webpack_require__(828);
|
||||
|
||||
var _toPairs = __webpack_require__(195);
|
||||
|
||||
var _toPairs2 = _interopRequireDefault(_toPairs);
|
||||
|
||||
var _isEmpty = __webpack_require__(963);
|
||||
|
||||
var _isEmpty2 = _interopRequireDefault(_isEmpty);
|
||||
|
||||
var _uniq = __webpack_require__(561);
|
||||
|
||||
var _uniq2 = _interopRequireDefault(_uniq);
|
||||
|
||||
var _parseScriptTags = __webpack_require__(1023);
|
||||
|
||||
var _parseScriptTags2 = _interopRequireDefault(_parseScriptTags);
|
||||
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
|
||||
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
|
||||
|
||||
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
|
||||
|
||||
var babylon = __webpack_require__(435);
|
||||
var traverse = __webpack_require__(436).default;
|
||||
var t = __webpack_require__(493);
|
||||
|
||||
var _require = __webpack_require__(828),
|
||||
isDevelopment = _require.isDevelopment;
|
||||
|
||||
var toPairs = __webpack_require__(195);
|
||||
var isEmpty = __webpack_require__(963);
|
||||
var uniq = __webpack_require__(561);
|
||||
|
||||
var ASTs = new Map();
|
||||
|
||||
var symbolDeclarations = new Map();
|
||||
|
||||
function _parse(code) {
|
||||
return babylon.parse(code, {
|
||||
function _parse(code, opts) {
|
||||
return babylon.parse(code, Object.assign({}, opts, {
|
||||
sourceType: "module",
|
||||
|
||||
plugins: ["jsx", "flow"]
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
function parse(text) {
|
||||
function parse(text, opts) {
|
||||
var ast = void 0;
|
||||
if (!text) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
ast = _parse(text);
|
||||
ast = _parse(text, opts);
|
||||
} catch (error) {
|
||||
if (isDevelopment()) {
|
||||
if ((0, _devtoolsConfig.isDevelopment)()) {
|
||||
console.warn("parse failed", text);
|
||||
}
|
||||
|
||||
|
@ -28997,7 +29036,19 @@ return /******/ (function(modules) { // webpackBootstrap
|
|||
}
|
||||
|
||||
var ast = {};
|
||||
if (sourceText.contentType == "text/javascript") {
|
||||
if (sourceText.contentType == "text/html") {
|
||||
// Custom parser for parse-script-tags that adapts its input structure to
|
||||
// our parser's signature
|
||||
var parser = (_ref) => {
|
||||
var source = _ref.source,
|
||||
line = _ref.line;
|
||||
|
||||
return parse(source, {
|
||||
startLine: line
|
||||
});
|
||||
};
|
||||
ast = (0, _parseScriptTags2.default)(sourceText.text, parser) || {};
|
||||
} else if (sourceText.contentType == "text/javascript") {
|
||||
ast = parse(sourceText.text);
|
||||
}
|
||||
|
||||
|
@ -29046,32 +29097,22 @@ return /******/ (function(modules) { // webpackBootstrap
|
|||
return t.isFunction(path) || t.isArrowFunctionExpression(path) || t.isObjectMethod(path) || t.isClassMethod(path);
|
||||
}
|
||||
|
||||
function formatSymbol(symbol) {
|
||||
return {
|
||||
id: `${symbol.name}:${symbol.location.start.line}`,
|
||||
title: symbol.name,
|
||||
subtitle: `:${symbol.location.start.line}`,
|
||||
value: symbol.name,
|
||||
location: symbol.location
|
||||
};
|
||||
}
|
||||
|
||||
function getVariableNames(path) {
|
||||
if (t.isObjectProperty(path) && !isFunction(path.node.value)) {
|
||||
return [formatSymbol({
|
||||
return [{
|
||||
name: path.node.key.name,
|
||||
location: path.node.loc
|
||||
})];
|
||||
}];
|
||||
}
|
||||
|
||||
if (!path.node.declarations) {
|
||||
return path.node.params.map(dec => formatSymbol({
|
||||
return path.node.params.map(dec => ({
|
||||
name: dec.name,
|
||||
location: dec.loc
|
||||
}));
|
||||
}
|
||||
|
||||
return path.node.declarations.map(dec => formatSymbol({
|
||||
return path.node.declarations.map(dec => ({
|
||||
name: dec.id.name,
|
||||
location: dec.loc
|
||||
}));
|
||||
|
@ -29101,10 +29142,10 @@ return /******/ (function(modules) { // webpackBootstrap
|
|||
var bindings = scope.bindings;
|
||||
|
||||
|
||||
return toPairs(bindings).map((_ref) => {
|
||||
var _ref2 = _slicedToArray(_ref, 2),
|
||||
name = _ref2[0],
|
||||
binding = _ref2[1];
|
||||
return (0, _toPairs2.default)(bindings).map((_ref2) => {
|
||||
var _ref3 = _slicedToArray(_ref2, 2),
|
||||
name = _ref3[0],
|
||||
binding = _ref3[1];
|
||||
|
||||
return {
|
||||
name,
|
||||
|
@ -29127,9 +29168,9 @@ return /******/ (function(modules) { // webpackBootstrap
|
|||
* helps find member expressions on one line and function scopes that are
|
||||
* often many lines
|
||||
*/
|
||||
function nodeContainsLocation(_ref3) {
|
||||
var node = _ref3.node,
|
||||
location = _ref3.location;
|
||||
function nodeContainsLocation(_ref4) {
|
||||
var node = _ref4.node,
|
||||
location = _ref4.location;
|
||||
var _node$loc = node.loc,
|
||||
start = _node$loc.start,
|
||||
end = _node$loc.end;
|
||||
|
@ -29171,11 +29212,11 @@ return /******/ (function(modules) { // webpackBootstrap
|
|||
|
||||
var symbols = { functions: [], variables: [] };
|
||||
|
||||
if (isEmpty(ast)) {
|
||||
if ((0, _isEmpty2.default)(ast)) {
|
||||
return symbols;
|
||||
}
|
||||
|
||||
traverse(ast, {
|
||||
(0, _babelTraverse2.default)(ast, {
|
||||
enter(path) {
|
||||
if (isVariable(path)) {
|
||||
var _symbols$variables;
|
||||
|
@ -29184,17 +29225,17 @@ return /******/ (function(modules) { // webpackBootstrap
|
|||
}
|
||||
|
||||
if (isFunction(path)) {
|
||||
symbols.functions.push(formatSymbol({
|
||||
symbols.functions.push({
|
||||
name: getFunctionName(path),
|
||||
location: path.node.loc
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
if (t.isClassDeclaration(path)) {
|
||||
symbols.variables.push(formatSymbol({
|
||||
symbols.variables.push({
|
||||
name: path.node.id.name,
|
||||
location: path.node.loc
|
||||
}));
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -29205,12 +29246,12 @@ return /******/ (function(modules) { // webpackBootstrap
|
|||
|
||||
function getClosestMemberExpression(source, token, location) {
|
||||
var ast = getAst(source);
|
||||
if (isEmpty(ast)) {
|
||||
if ((0, _isEmpty2.default)(ast)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var expression = null;
|
||||
traverse(ast, {
|
||||
(0, _babelTraverse2.default)(ast, {
|
||||
enter(path) {
|
||||
var node = path.node;
|
||||
|
||||
|
@ -29263,13 +29304,13 @@ return /******/ (function(modules) { // webpackBootstrap
|
|||
|
||||
function getClosestScope(source, location) {
|
||||
var ast = getAst(source);
|
||||
if (isEmpty(ast)) {
|
||||
if ((0, _isEmpty2.default)(ast)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var closestPath = null;
|
||||
|
||||
traverse(ast, {
|
||||
(0, _babelTraverse2.default)(ast, {
|
||||
enter(path) {
|
||||
if (isLexicalScope(path) && nodeContainsLocation({ node: path.node, location })) {
|
||||
closestPath = path;
|
||||
|
@ -29286,13 +29327,13 @@ return /******/ (function(modules) { // webpackBootstrap
|
|||
|
||||
function getClosestPath(source, location) {
|
||||
var ast = getAst(source);
|
||||
if (isEmpty(ast)) {
|
||||
if ((0, _isEmpty2.default)(ast)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var closestPath = null;
|
||||
|
||||
traverse(ast, {
|
||||
(0, _babelTraverse2.default)(ast, {
|
||||
enter(path) {
|
||||
if (nodeContainsLocation({ node: path.node, location })) {
|
||||
closestPath = path;
|
||||
|
@ -29308,12 +29349,12 @@ return /******/ (function(modules) { // webpackBootstrap
|
|||
}
|
||||
|
||||
function getVariablesInScope(scope) {
|
||||
var _ref4;
|
||||
var _ref5;
|
||||
|
||||
var scopes = getScopeChain(scope);
|
||||
var scopeVars = scopes.map(getScopeVariables);
|
||||
var vars = (_ref4 = [{ name: "this" }, { name: "arguments" }]).concat.apply(_ref4, _toConsumableArray(scopeVars)).map(variable => variable.name);
|
||||
return uniq(vars);
|
||||
var vars = (_ref5 = [{ name: "this" }, { name: "arguments" }]).concat.apply(_ref5, _toConsumableArray(scopeVars)).map(variable => variable.name);
|
||||
return (0, _uniq2.default)(vars);
|
||||
}
|
||||
|
||||
function isExpressionInScope(expression, scope) {
|
||||
|
@ -29462,7 +29503,159 @@ return /******/ (function(modules) { // webpackBootstrap
|
|||
/* 1013 */,
|
||||
/* 1014 */,
|
||||
/* 1015 */,
|
||||
/* 1016 */
|
||||
/* 1016 */,
|
||||
/* 1017 */,
|
||||
/* 1018 */,
|
||||
/* 1019 */,
|
||||
/* 1020 */,
|
||||
/* 1021 */,
|
||||
/* 1022 */,
|
||||
/* 1023 */
|
||||
/***/ function(module, exports, __webpack_require__) {
|
||||
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
|
||||
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
|
||||
|
||||
var babylon = __webpack_require__(435);
|
||||
var types = __webpack_require__(493);
|
||||
|
||||
var startScript = /<script[^>]*>/im;
|
||||
var endScript = /<\/script\s*>/im;
|
||||
|
||||
function getCandidateScriptLocations(source, index) {
|
||||
var i = index || 0;
|
||||
var str = source.substring(i);
|
||||
|
||||
var startMatch = startScript.exec(str);
|
||||
if (startMatch) {
|
||||
var startsAt = startMatch.index + startMatch[0].length;
|
||||
var afterStart = str.substring(startsAt);
|
||||
var endMatch = endScript.exec(afterStart);
|
||||
if (endMatch) {
|
||||
var locLength = endMatch.index;
|
||||
var locIndex = i + startsAt;
|
||||
|
||||
return [adjustForLineAndColumn(source, {
|
||||
index: locIndex,
|
||||
length: locLength,
|
||||
source: source.substring(locIndex, locIndex + locLength)
|
||||
})].concat(_toConsumableArray(getCandidateScriptLocations(source, locIndex + locLength + endMatch[0].length)));
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
function parseScript(_ref) {
|
||||
var source = _ref.source,
|
||||
line = _ref.line;
|
||||
|
||||
// remove empty or only whitespace scripts
|
||||
if (source.length === 0 || /^\s+$/.test(source)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return babylon.parse(source, {
|
||||
sourceType: "script",
|
||||
startLine: line
|
||||
});
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function parseScripts(locations) {
|
||||
var parser = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : parseScript;
|
||||
|
||||
return locations.map(parser);
|
||||
}
|
||||
|
||||
function generateWhitespace(length) {
|
||||
return Array.from(new Array(length + 1)).join(" ");
|
||||
}
|
||||
|
||||
function calcLineAndColumn(source, index) {
|
||||
var lines = source.substring(0, index).replace(/\r\l?/, "\n").split(/\n/);
|
||||
var line = lines.length;
|
||||
var column = lines.pop().length + 1;
|
||||
|
||||
return {
|
||||
column: column,
|
||||
line: line
|
||||
};
|
||||
}
|
||||
|
||||
function adjustForLineAndColumn(fullSource, location) {
|
||||
var _calcLineAndColumn = calcLineAndColumn(fullSource, location.index),
|
||||
column = _calcLineAndColumn.column,
|
||||
line = _calcLineAndColumn.line;
|
||||
|
||||
return Object.assign({}, location, {
|
||||
line: line,
|
||||
column: column,
|
||||
// prepend whitespace for scripts that do not start on the first column
|
||||
source: generateWhitespace(column) + location.source
|
||||
});
|
||||
}
|
||||
|
||||
function parseScriptTags(source, parser) {
|
||||
var scripts = parseScripts(getCandidateScriptLocations(source), parser).filter(types.isFile).reduce(function (main, script) {
|
||||
return {
|
||||
statements: main.statements.concat(script.program.body),
|
||||
comments: main.comments.concat(script.comments),
|
||||
tokens: main.tokens.concat(script.tokens)
|
||||
};
|
||||
}, {
|
||||
statements: [],
|
||||
comments: [],
|
||||
tokens: []
|
||||
});
|
||||
|
||||
var program = types.program(scripts.statements);
|
||||
var file = types.file(program, scripts.comments, scripts.tokens);
|
||||
|
||||
var end = calcLineAndColumn(source, source.length);
|
||||
file.start = program.start = 0;
|
||||
file.end = program.end = source.length;
|
||||
file.loc = program.loc = {
|
||||
start: {
|
||||
line: 1,
|
||||
column: 0
|
||||
},
|
||||
end: end
|
||||
};
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
function extractScriptTags(source) {
|
||||
return parseScripts(getCandidateScriptLocations(source), function (loc) {
|
||||
var ast = parseScript(loc);
|
||||
|
||||
if (ast) {
|
||||
return loc;
|
||||
}
|
||||
|
||||
return null;
|
||||
}).filter(types.isFile);
|
||||
}
|
||||
|
||||
exports.default = parseScriptTags;
|
||||
exports.extractScriptTags = extractScriptTags;
|
||||
exports.generateWhitespace = generateWhitespace;
|
||||
exports.getCandidateScriptLocations = getCandidateScriptLocations;
|
||||
exports.parseScript = parseScript;
|
||||
exports.parseScripts = parseScripts;
|
||||
exports.parseScriptTags = parseScriptTags;
|
||||
|
||||
/***/ },
|
||||
/* 1024 */
|
||||
/***/ function(module, exports) {
|
||||
|
||||
/**
|
||||
|
|
|
@ -47,7 +47,7 @@ add_task(function*() {
|
|||
|
||||
yield addExpression(dbg, "f");
|
||||
is(getLabel(dbg, 1), "f");
|
||||
is(getValue(dbg, 1), "ReferenceError");
|
||||
is(getValue(dbg, 1), "(unavailable)");
|
||||
|
||||
yield editExpression(dbg, "oo");
|
||||
is(getLabel(dbg, 1), "foo()");
|
||||
|
|
|
@ -83,38 +83,13 @@ add_task(async function() {
|
|||
await onPaused;
|
||||
|
||||
is(
|
||||
getScopeNodeLabel(dbg, 6),
|
||||
"lastName",
|
||||
'The sixth element in the scope panel is still "lastName"'
|
||||
getScopeNodeLabel(dbg, 2),
|
||||
"<this>",
|
||||
'The second element in the scope panel is "<this>"'
|
||||
);
|
||||
is(
|
||||
getScopeNodeValue(dbg, 6),
|
||||
'"Doe"',
|
||||
'The "lastName" property is still "Doe", but it should be "Pierce"' +
|
||||
"since it was changed in the script."
|
||||
getScopeNodeLabel(dbg, 3),
|
||||
"phonebook",
|
||||
'The third element in the scope panel is "phonebook"'
|
||||
);
|
||||
|
||||
onPaused = waitForPaused(dbg);
|
||||
await resume(dbg);
|
||||
await onPaused;
|
||||
is(
|
||||
getScopeNodeLabel(dbg, 6),
|
||||
"lastName",
|
||||
'The sixth element in the scope panel is still "lastName"'
|
||||
);
|
||||
is(
|
||||
getScopeNodeLabel(dbg, 7),
|
||||
"__proto__",
|
||||
'The seventh element in the scope panel is still "__proto__", ' +
|
||||
'but it should be now "timezone", since it was added to the "sarah" object ' +
|
||||
"in the script"
|
||||
);
|
||||
is(
|
||||
getScopeNodeValue(dbg, 7),
|
||||
"Object",
|
||||
'The seventh element in the scope panel has the value "Object", ' +
|
||||
'but it should be "PST"'
|
||||
);
|
||||
|
||||
await resume(dbg);
|
||||
});
|
||||
|
|
|
@ -9,7 +9,7 @@ function getLabel(dbg, index) {
|
|||
return findElement(dbg, "scopeNode", index).innerText;
|
||||
}
|
||||
|
||||
add_task(function* () {
|
||||
add_task(function*() {
|
||||
const dbg = yield initDebugger("doc-script-switching.html");
|
||||
|
||||
toggleScopes(dbg);
|
||||
|
@ -23,9 +23,9 @@ add_task(function* () {
|
|||
|
||||
toggleNode(dbg, 4);
|
||||
yield waitForDispatch(dbg, "LOAD_OBJECT_PROPERTIES");
|
||||
is(getLabel(dbg, 5), "prototype");
|
||||
is(getLabel(dbg, 5), "length");
|
||||
|
||||
yield stepOver(dbg);
|
||||
is(getLabel(dbg, 4), "foo()");
|
||||
is(getLabel(dbg, 5), "prototype");
|
||||
is(getLabel(dbg, 5), "Window");
|
||||
});
|
||||
|
|
|
@ -11,11 +11,11 @@ function* waitForSourceCount(dbg, i) {
|
|||
});
|
||||
}
|
||||
|
||||
add_task(function* () {
|
||||
add_task(function*() {
|
||||
const dbg = yield initDebugger("doc-sources.html");
|
||||
const { selectors: { getSelectedSource }, getState } = dbg;
|
||||
|
||||
yield waitForSources(dbg, "simple1");
|
||||
yield waitForSources(dbg, "simple1", "simple2", "nested-source", "long.js");
|
||||
|
||||
// Expand nodes and make sure more sources appear.
|
||||
is(findAllElements(dbg, "sourceNodes").length, 2);
|
||||
|
@ -27,15 +27,21 @@ add_task(function* () {
|
|||
is(findAllElements(dbg, "sourceNodes").length, 8);
|
||||
|
||||
// Select a source.
|
||||
ok(!findElementWithSelector(dbg, ".sources-list .focused"),
|
||||
"Source is not focused");
|
||||
ok(
|
||||
!findElementWithSelector(dbg, ".sources-list .focused"),
|
||||
"Source is not focused"
|
||||
);
|
||||
const selected = waitForDispatch(dbg, "SELECT_SOURCE");
|
||||
clickElement(dbg, "sourceNode", 4);
|
||||
yield selected;
|
||||
ok(findElementWithSelector(dbg, ".sources-list .focused"),
|
||||
"Source is focused");
|
||||
ok(getSelectedSource(getState()).get("url").includes("nested-source.js"),
|
||||
"The right source is selected");
|
||||
ok(
|
||||
findElementWithSelector(dbg, ".sources-list .focused"),
|
||||
"Source is focused"
|
||||
);
|
||||
ok(
|
||||
getSelectedSource(getState()).get("url").includes("nested-source.js"),
|
||||
"The right source is selected"
|
||||
);
|
||||
|
||||
// Make sure new sources appear in the list.
|
||||
ContentTask.spawn(gBrowser.selectedBrowser, null, function() {
|
||||
|
@ -45,16 +51,20 @@ add_task(function* () {
|
|||
});
|
||||
|
||||
yield waitForSourceCount(dbg, 9);
|
||||
is(findElement(dbg, "sourceNode", 7).textContent,
|
||||
"math.min.js",
|
||||
"The dynamic script exists");
|
||||
is(
|
||||
findElement(dbg, "sourceNode", 7).textContent,
|
||||
"math.min.js",
|
||||
"The dynamic script exists"
|
||||
);
|
||||
|
||||
// Make sure named eval sources appear in the list.
|
||||
ContentTask.spawn(gBrowser.selectedBrowser, null, function() {
|
||||
content.eval("window.evaledFunc = function() {} //# sourceURL=evaled.js");
|
||||
});
|
||||
yield waitForSourceCount(dbg, 11);
|
||||
is(findElement(dbg, "sourceNode", 2).textContent,
|
||||
"evaled.js",
|
||||
"The eval script exists");
|
||||
is(
|
||||
findElement(dbg, "sourceNode", 2).textContent,
|
||||
"evaled.js",
|
||||
"The eval script exists"
|
||||
);
|
||||
});
|
||||
|
|
|
@ -176,8 +176,7 @@ function waitForSources(dbg, ...sources) {
|
|||
sources.map(url => {
|
||||
function sourceExists(state) {
|
||||
return getSources(state).some(s => {
|
||||
let u = s.get("url");
|
||||
return u && u.includes(url);
|
||||
return (s.get("url") || "").includes(url);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -214,9 +213,8 @@ function assertPausedLocation(dbg, source, line) {
|
|||
is(location.get("line"), line);
|
||||
|
||||
// Check the debug line
|
||||
let cm = dbg.win.document.querySelector(".CodeMirror").CodeMirror;
|
||||
ok(
|
||||
cm.lineInfo(line - 1).wrapClass.includes("debug-line"),
|
||||
getCM(dbg).lineInfo(line - 1).wrapClass.includes("debug-line"),
|
||||
"Line is highlighted as paused"
|
||||
);
|
||||
}
|
||||
|
@ -245,7 +243,7 @@ function assertHighlightLocation(dbg, source, line) {
|
|||
"Highlighted line is visible"
|
||||
);
|
||||
ok(
|
||||
dbg.win.cm.lineInfo(line - 1).wrapClass.includes("highlight-line"),
|
||||
getCM(dbg).lineInfo(line - 1).wrapClass.includes("highlight-line"),
|
||||
"Line is highlighted"
|
||||
);
|
||||
}
|
||||
|
@ -359,10 +357,7 @@ function findSource(dbg, url) {
|
|||
}
|
||||
|
||||
const sources = dbg.selectors.getSources(dbg.getState());
|
||||
const source = sources.find(s => {
|
||||
let u = s.get("url");
|
||||
return u && u.includes(url);
|
||||
});
|
||||
const source = sources.find(s => (s.get("url") || "").includes(url));
|
||||
|
||||
if (!source) {
|
||||
throw new Error("Unable to find source: " + url);
|
||||
|
@ -623,9 +618,12 @@ function isVisibleWithin(outerEl, innerEl) {
|
|||
const selectors = {
|
||||
callStackHeader: ".call-stack-pane ._header",
|
||||
callStackBody: ".call-stack-pane .pane",
|
||||
expressionNode: i => `.expressions-list .tree-node:nth-child(${i}) .object-label`,
|
||||
expressionValue: i => `.expressions-list .tree-node:nth-child(${i}) .object-value`,
|
||||
expressionClose: i => `.expressions-list .expression-container:nth-child(${i}) .close`,
|
||||
expressionNode: i =>
|
||||
`.expressions-list .tree-node:nth-child(${i}) .object-label`,
|
||||
expressionValue: i =>
|
||||
`.expressions-list .tree-node:nth-child(${i}) .object-value`,
|
||||
expressionClose: i =>
|
||||
`.expressions-list .expression-container:nth-child(${i}) .close`,
|
||||
expressionNodes: ".expressions-list .tree-node",
|
||||
scopesHeader: ".scopes-pane ._header",
|
||||
breakpointItem: i => `.breakpoints-list .breakpoint:nth-child(${i})`,
|
||||
|
@ -746,3 +744,8 @@ function toggleCallStack(dbg) {
|
|||
function toggleScopes(dbg) {
|
||||
return findElement(dbg, "scopesHeader").click();
|
||||
}
|
||||
|
||||
function getCM(dbg) {
|
||||
const el = dbg.win.document.querySelector(".CodeMirror");
|
||||
return el.CodeMirror;
|
||||
}
|
||||
|
|
|
@ -151,7 +151,7 @@ function bindToolboxHandlers() {
|
|||
}
|
||||
|
||||
function setupThreadListeners(panel) {
|
||||
updateBadgeText(panel._selectors().getPause(panel._getState()));
|
||||
updateBadgeText(panel._selectors.getPause(panel._getState()));
|
||||
|
||||
let onPaused = updateBadgeText.bind(null, true);
|
||||
let onResumed = updateBadgeText.bind(null, false);
|
||||
|
|
|
@ -128,25 +128,33 @@ otherEvents=Other
|
|||
# source.
|
||||
blackboxCheckboxTooltip2=Toggle blackboxing
|
||||
|
||||
# LOCALIZATION NOTE (sources.search.key): Key shortcut to open the search for
|
||||
# LOCALIZATION NOTE (sources.search.key2): Key shortcut to open the search for
|
||||
# searching all the source files the debugger has seen.
|
||||
sources.search.key=P
|
||||
sources.search.key2=CmdOrCtrl+P
|
||||
|
||||
# LOCALIZATION NOTE (sources.search.alt.key): A second key shortcut to open the
|
||||
# search for searching all the source files the debugger has seen.
|
||||
sources.search.alt.key=CmdOrCtrl+O
|
||||
|
||||
# LOCALIZATION NOTE (sources.noSourcesAvailable): Text shown when the debugger
|
||||
# does not have any sources.
|
||||
sources.noSourcesAvailable=This page has no sources
|
||||
|
||||
# LOCALIZATION NOTE (sourceSearch.search.key): Key shortcut to open the search
|
||||
# LOCALIZATION NOTE (sourceSearch.search.key2): Key shortcut to open the search
|
||||
# for searching within a the currently opened files in the editor
|
||||
sourceSearch.search.key=F
|
||||
sourceSearch.search.key2=CmdOrCtrl+F
|
||||
|
||||
# LOCALIZATION NOTE (sourceSearch.search.placeholder): placeholder text in
|
||||
# the source search input bar
|
||||
sourceSearch.search.placeholder=Search in file…
|
||||
|
||||
# LOCALIZATION NOTE (sourceSearch.search.again.key): Key shortcut to re-open
|
||||
# the search for re-searching the same search triggered from a sourceSearch
|
||||
sourceSearch.search.again.key=G
|
||||
# LOCALIZATION NOTE (sourceSearch.search.again.key2): Key shortcut to highlight
|
||||
# the next occurrence of the last search triggered from a source search
|
||||
sourceSearch.search.again.key2=CmdOrCtrl+G
|
||||
|
||||
# LOCALIZATION NOTE (sourceSearch.search.againPrev.key2): Key shortcut to highlight
|
||||
# the previous occurrence of the last search triggered from a source search
|
||||
sourceSearch.search.againPrev.key2=CmdOrCtrl+Shift+G
|
||||
|
||||
# LOCALIZATION NOTE (sourceSearch.resultsSummary1): Shows a summary of
|
||||
# the number of matches for autocomplete
|
||||
|
@ -552,9 +560,9 @@ symbolSearch.search.functionsPlaceholder=Search functions…
|
|||
# text displayed when the user searches for variables in a file
|
||||
symbolSearch.search.variablesPlaceholder=Search variables…
|
||||
|
||||
# LOCALIZATION NOTE(symbolSearch.search.key): The shortcut (cmd+shift+o) for
|
||||
# LOCALIZATION NOTE(symbolSearch.search.key2): The Key Shortcut for
|
||||
# searching for a function or variable
|
||||
symbolSearch.search.key=O
|
||||
symbolSearch.search.key2=CmdOrCtrl+Shift+O
|
||||
|
||||
# LOCALIZATION NOTE(symbolSearch.searchModifier.regex): A search option
|
||||
# when searching text in a file
|
||||
|
|
|
@ -2211,9 +2211,9 @@ DOMGCSliceCallback(JSContext* aCx, JS::GCProgress aProgress, const JS::GCDescrip
|
|||
|
||||
case JS::GC_SLICE_END:
|
||||
|
||||
// The GC has more work to do, so schedule another GC slice.
|
||||
// Schedule another GC slice if the GC has more work to do.
|
||||
nsJSContext::KillInterSliceGCTimer();
|
||||
if (!sShuttingDown) {
|
||||
if (!sShuttingDown && !aDesc.isComplete_) {
|
||||
CallCreateInstance("@mozilla.org/timer;1", &sInterSliceGCTimer);
|
||||
sInterSliceGCTimer->SetTarget(SystemGroup::EventTargetFor(TaskCategory::GarbageCollection));
|
||||
sInterSliceGCTimer->InitWithNamedFuncCallback(InterSliceGCTimerFired,
|
||||
|
|
|
@ -41,7 +41,7 @@ class nsWindowRoot;
|
|||
// This may waste space for some other nsWrapperCache-derived objects that have
|
||||
// a 32-bit field as their first member, but those objects are unlikely to be as
|
||||
// numerous or performance-critical as DOM nodes.
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
#if defined(_M_X64) || defined(__x86_64__) || defined(__aarch64__)
|
||||
static_assert(sizeof(void*) == 8, "These architectures should be 64-bit");
|
||||
#define BOOL_FLAGS_ON_WRAPPER_CACHE
|
||||
#else
|
||||
|
|
|
@ -110,7 +110,7 @@ static inline void* getSurface(JNIEnv* env, jobject view) {
|
|||
env->DeleteLocalRef(holder);
|
||||
env->DeleteLocalRef(surface);
|
||||
|
||||
return (void*)surfacePointer;
|
||||
return reinterpret_cast<void*>(uintptr_t(surfacePointer));
|
||||
}
|
||||
|
||||
static ANPBitmapFormat convertPixelFormat(int32_t format) {
|
||||
|
|
|
@ -319,13 +319,9 @@ class GarbageCollectionEvent
|
|||
|
||||
enum GCProgress {
|
||||
/*
|
||||
* During non-incremental GC, the GC is bracketed by JSGC_CYCLE_BEGIN/END
|
||||
* callbacks. During an incremental GC, the sequence of callbacks is as
|
||||
* follows:
|
||||
* JSGC_CYCLE_BEGIN, JSGC_SLICE_END (first slice)
|
||||
* JSGC_SLICE_BEGIN, JSGC_SLICE_END (second slice)
|
||||
* ...
|
||||
* JSGC_SLICE_BEGIN, JSGC_CYCLE_END (last slice)
|
||||
* During GC, the GC is bracketed by GC_CYCLE_BEGIN/END callbacks. Each
|
||||
* slice between those (whether an incremental or the sole non-incremental
|
||||
* slice) is bracketed by GC_SLICE_BEGIN/GC_SLICE_END.
|
||||
*/
|
||||
|
||||
GC_CYCLE_BEGIN,
|
||||
|
@ -336,11 +332,12 @@ enum GCProgress {
|
|||
|
||||
struct JS_PUBLIC_API(GCDescription) {
|
||||
bool isZone_;
|
||||
bool isComplete_;
|
||||
JSGCInvocationKind invocationKind_;
|
||||
gcreason::Reason reason_;
|
||||
|
||||
GCDescription(bool isZone, JSGCInvocationKind kind, gcreason::Reason reason)
|
||||
: isZone_(isZone), invocationKind_(kind), reason_(reason) {}
|
||||
GCDescription(bool isZone, bool isComplete, JSGCInvocationKind kind, gcreason::Reason reason)
|
||||
: isZone_(isZone), isComplete_(isComplete), invocationKind_(kind), reason_(reason) {}
|
||||
|
||||
char16_t* formatSliceMessage(JSContext* cx) const;
|
||||
char16_t* formatSummaryMessage(JSContext* cx) const;
|
||||
|
|
|
@ -508,8 +508,12 @@ FOR_EACH_NURSERY_PROFILE_TIME(EXTRACT_NAME)
|
|||
"" };
|
||||
|
||||
size_t i = 0;
|
||||
for (auto time : profileDurations_)
|
||||
json.property(names[i++], time, json.MICROSECONDS);
|
||||
if (trackTimings_) {
|
||||
for (auto time : profileDurations_)
|
||||
json.property(names[i++], time, json.MICROSECONDS);
|
||||
} else {
|
||||
json.property(names[0], *profileDurations_.begin(), json.MICROSECONDS);
|
||||
}
|
||||
|
||||
json.endObject();
|
||||
}
|
||||
|
|
|
@ -581,6 +581,7 @@ Statistics::formatJsonDescription(uint64_t timestamp, JSONPrinter& json) const
|
|||
json.property("total_compartments", zoneStats.compartmentCount);
|
||||
json.property("minor_gcs", counts[STAT_MINOR_GC]);
|
||||
json.property("store_buffer_overflows", counts[STAT_STOREBUFFER_OVERFLOW]);
|
||||
json.property("slices", slices_.length());
|
||||
|
||||
const double mmu20 = computeMMU(TimeDuration::FromMilliseconds(20));
|
||||
const double mmu50 = computeMMU(TimeDuration::FromMilliseconds(50));
|
||||
|
@ -958,10 +959,13 @@ Statistics::beginSlice(const ZoneGCStats& zoneStats, JSGCInvocationKind gckind,
|
|||
|
||||
// Slice callbacks should only fire for the outermost level.
|
||||
bool wasFullGC = zoneStats.isCollectingAllZones();
|
||||
if (sliceCallback)
|
||||
(*sliceCallback)(TlsContext.get(),
|
||||
first ? JS::GC_CYCLE_BEGIN : JS::GC_SLICE_BEGIN,
|
||||
JS::GCDescription(!wasFullGC, gckind, reason));
|
||||
if (sliceCallback) {
|
||||
JSContext* cx = TlsContext.get();
|
||||
JS::GCDescription desc(!wasFullGC, false, gckind, reason);
|
||||
if (first)
|
||||
(*sliceCallback)(cx, JS::GC_CYCLE_BEGIN, desc);
|
||||
(*sliceCallback)(cx, JS::GC_SLICE_BEGIN, desc);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1005,10 +1009,13 @@ Statistics::endSlice()
|
|||
// Slice callbacks should only fire for the outermost level.
|
||||
if (!aborted) {
|
||||
bool wasFullGC = zoneStats.isCollectingAllZones();
|
||||
if (sliceCallback)
|
||||
(*sliceCallback)(TlsContext.get(),
|
||||
last ? JS::GC_CYCLE_END : JS::GC_SLICE_END,
|
||||
JS::GCDescription(!wasFullGC, gckind, slices_.back().reason));
|
||||
if (sliceCallback) {
|
||||
JSContext* cx = TlsContext.get();
|
||||
JS::GCDescription desc(!wasFullGC, last, gckind, slices_.back().reason);
|
||||
(*sliceCallback)(cx, JS::GC_SLICE_END, desc);
|
||||
if (last)
|
||||
(*sliceCallback)(cx, JS::GC_CYCLE_END, desc);
|
||||
}
|
||||
}
|
||||
|
||||
// Do this after the slice callback since it uses these values.
|
||||
|
|
|
@ -151,9 +151,11 @@ class Decoder {
|
|||
|
||||
// Top-level wrappers around the actual decoding function.
|
||||
void Decode(const Instruction* instr) {
|
||||
#ifdef DEBUG
|
||||
for (auto visitor : visitors_) {
|
||||
VIXL_ASSERT(visitor->IsConstVisitor());
|
||||
}
|
||||
#endif
|
||||
DecodeInstruction(instr);
|
||||
}
|
||||
void Decode(Instruction* instr) {
|
||||
|
|
|
@ -76,7 +76,7 @@ const int MBytes = 1024 * KBytes;
|
|||
#define VIXL_ASSERT(condition) ((void) 0)
|
||||
#define VIXL_CHECK(condition) ((void) 0)
|
||||
#define VIXL_UNIMPLEMENTED() ((void) 0)
|
||||
#define VIXL_UNREACHABLE() ((void) 0)
|
||||
#define VIXL_UNREACHABLE() MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE()
|
||||
#endif
|
||||
// This is not as powerful as template based assertions, but it is simple.
|
||||
// It assumes that the descriptions are unique. If this starts being a problem,
|
||||
|
|
|
@ -14,12 +14,15 @@ static unsigned gSliceCallbackCount = 0;
|
|||
static void
|
||||
NonIncrementalGCSliceCallback(JSContext* cx, JS::GCProgress progress, const JS::GCDescription& desc)
|
||||
{
|
||||
++gSliceCallbackCount;
|
||||
MOZ_RELEASE_ASSERT(progress == JS::GC_CYCLE_BEGIN || progress == JS::GC_CYCLE_END);
|
||||
using namespace JS;
|
||||
static GCProgress expect[] =
|
||||
{ GC_CYCLE_BEGIN, GC_SLICE_BEGIN, GC_SLICE_END, GC_CYCLE_END };
|
||||
|
||||
MOZ_RELEASE_ASSERT(progress == expect[gSliceCallbackCount++]);
|
||||
MOZ_RELEASE_ASSERT(desc.isZone_ == false);
|
||||
MOZ_RELEASE_ASSERT(desc.invocationKind_ == GC_NORMAL);
|
||||
MOZ_RELEASE_ASSERT(desc.reason_ == JS::gcreason::API);
|
||||
if (progress == JS::GC_CYCLE_END) {
|
||||
if (progress == GC_CYCLE_END) {
|
||||
mozilla::UniquePtr<char16_t> summary(desc.formatSummaryMessage(cx));
|
||||
mozilla::UniquePtr<char16_t> message(desc.formatSliceMessage(cx));
|
||||
mozilla::UniquePtr<char16_t> json(desc.formatJSON(cx, 0));
|
||||
|
@ -31,7 +34,7 @@ BEGIN_TEST(testGCSliceCallback)
|
|||
JS::SetGCSliceCallback(cx, NonIncrementalGCSliceCallback);
|
||||
JS_GC(cx);
|
||||
JS::SetGCSliceCallback(cx, nullptr);
|
||||
CHECK(gSliceCallbackCount == 2);
|
||||
CHECK(gSliceCallbackCount == 4);
|
||||
return true;
|
||||
}
|
||||
END_TEST(testGCSliceCallback)
|
||||
|
|
|
@ -756,8 +756,7 @@ XPCJSRuntime::GCSliceCallback(JSContext* cx,
|
|||
return;
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
CrashReporter::SetGarbageCollecting(progress == JS::GC_CYCLE_BEGIN ||
|
||||
progress == JS::GC_SLICE_BEGIN);
|
||||
CrashReporter::SetGarbageCollecting(progress == JS::GC_CYCLE_BEGIN);
|
||||
#endif
|
||||
|
||||
if (self->mPrevGCSliceCallback)
|
||||
|
|
|
@ -11072,8 +11072,8 @@ void DR_State::ParseRulesFile()
|
|||
for (DR_Rule* rule = ParseRule(inFile); rule; rule = ParseRule(inFile)) {
|
||||
if (rule->mTarget) {
|
||||
LayoutFrameType fType = rule->mTarget->mFrameType;
|
||||
DR_FrameTypeInfo* info = GetFrameTypeInfo(fType);
|
||||
if (info) {
|
||||
if (fType != LayoutFrameType::None) {
|
||||
DR_FrameTypeInfo* info = GetFrameTypeInfo(fType);
|
||||
AddRule(info->mRules, *rule);
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -337,6 +337,10 @@ void *_mmap(void *addr, size_t length, int prot, int flags,
|
|||
} args = { addr, length, prot, flags, fd, offset };
|
||||
return (void *) syscall(SYS_mmap, &args);
|
||||
#else
|
||||
#if defined(MOZ_MEMORY_ANDROID) && defined(__aarch64__) && defined(SYS_mmap2)
|
||||
/* Android NDK defines SYS_mmap2 for AArch64 despite it not supporting mmap2 */
|
||||
#undef SYS_mmap2
|
||||
#endif
|
||||
#ifdef SYS_mmap2
|
||||
return (void *) syscall(SYS_mmap2, addr, length, prot, flags,
|
||||
fd, offset >> 12);
|
||||
|
|
|
@ -291,7 +291,7 @@ public class AppConstants {
|
|||
//#endif
|
||||
|
||||
/**
|
||||
* Target CPU architecture: "armeabi-v7a", "x86, "mips", ..
|
||||
* Target CPU architecture: "armeabi-v7a", "arm64-v8a", "x86", "mips", ..
|
||||
*/
|
||||
public static final String ANDROID_CPU_ARCH = "@ANDROID_CPU_ARCH@";
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ public class BuildConfig {
|
|||
MOZ_APP_VERSION;
|
||||
|
||||
/**
|
||||
* Target CPU architecture: "armeabi-v7a", "x86, "mips", ..
|
||||
* Target CPU architecture: "armeabi-v7a", "arm64-v8a", "x86", "mips", ..
|
||||
*/
|
||||
public static final String ANDROID_CPU_ARCH = "@ANDROID_CPU_ARCH@";
|
||||
}
|
||||
|
|
|
@ -85,6 +85,11 @@ public final class HardwareUtils {
|
|||
return Build.CPU_ABI != null && Build.CPU_ABI.equals("armeabi-v7a");
|
||||
}
|
||||
|
||||
public static boolean isARM64System() {
|
||||
// 64-bit support was introduced in 21.
|
||||
return Build.VERSION.SDK_INT >= 21 && "arm64-v8a".equals(Build.SUPPORTED_ABIS[0]);
|
||||
}
|
||||
|
||||
public static boolean isX86System() {
|
||||
if (Build.CPU_ABI != null && Build.CPU_ABI.equals("x86")) {
|
||||
return true;
|
||||
|
@ -122,8 +127,10 @@ public final class HardwareUtils {
|
|||
// See http://developer.android.com/ndk/guides/abis.html
|
||||
final boolean isSystemX86 = isX86System();
|
||||
final boolean isSystemARM = !isSystemX86 && isARMSystem();
|
||||
final boolean isSystemARM64 = isARM64System();
|
||||
|
||||
boolean isAppARM = BuildConfig.ANDROID_CPU_ARCH.startsWith("armeabi-v7a");
|
||||
boolean isAppARM64 = BuildConfig.ANDROID_CPU_ARCH.startsWith("arm64-v8a");
|
||||
boolean isAppX86 = BuildConfig.ANDROID_CPU_ARCH.startsWith("x86");
|
||||
|
||||
// Only reject known incompatible ABIs. Better safe than sorry.
|
||||
|
@ -131,7 +138,8 @@ public final class HardwareUtils {
|
|||
return false;
|
||||
}
|
||||
|
||||
if ((isSystemX86 && isAppX86) || (isSystemARM && isAppARM)) {
|
||||
if ((isSystemX86 && isAppX86) || (isSystemARM && isAppARM) ||
|
||||
(isSystemARM64 && (isAppARM64 || isAppARM))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -185,7 +185,7 @@ LoadedElf::InitDyn(const Phdr *pt_dyn)
|
|||
switch (dyn->d_tag) {
|
||||
case DT_HASH:
|
||||
{
|
||||
DEBUG_LOG("%s 0x%08" PRIxPTR, "DT_HASH", dyn->d_un.d_val);
|
||||
DEBUG_LOG("%s 0x%08" PRIxPTR, "DT_HASH", uintptr_t(dyn->d_un.d_val));
|
||||
const Elf::Word *hash_table_header = \
|
||||
GetPtr<Elf::Word>(dyn->d_un.d_ptr);
|
||||
symnum = hash_table_header[1];
|
||||
|
@ -194,11 +194,11 @@ LoadedElf::InitDyn(const Phdr *pt_dyn)
|
|||
}
|
||||
break;
|
||||
case DT_STRTAB:
|
||||
DEBUG_LOG("%s 0x%08" PRIxPTR, "DT_STRTAB", dyn->d_un.d_val);
|
||||
DEBUG_LOG("%s 0x%08" PRIxPTR, "DT_STRTAB", uintptr_t(dyn->d_un.d_val));
|
||||
strtab.Init(GetPtr(dyn->d_un.d_ptr));
|
||||
break;
|
||||
case DT_SYMTAB:
|
||||
DEBUG_LOG("%s 0x%08" PRIxPTR, "DT_SYMTAB", dyn->d_un.d_val);
|
||||
DEBUG_LOG("%s 0x%08" PRIxPTR, "DT_SYMTAB", uintptr_t(dyn->d_un.d_val));
|
||||
symtab.Init(GetPtr(dyn->d_un.d_ptr));
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -65,8 +65,9 @@ void debug_phdr(const char *type, const Phdr *phdr)
|
|||
"memsz: 0x%08" PRIxPTR ", "
|
||||
"offset: 0x%08" PRIxPTR ", "
|
||||
"flags: %c%c%c)",
|
||||
type, phdr->p_vaddr, phdr->p_filesz, phdr->p_memsz,
|
||||
phdr->p_offset, phdr->p_flags & PF_R ? 'r' : '-',
|
||||
type, uintptr_t(phdr->p_vaddr), uintptr_t(phdr->p_filesz),
|
||||
uintptr_t(phdr->p_memsz), uintptr_t(phdr->p_offset),
|
||||
phdr->p_flags & PF_R ? 'r' : '-',
|
||||
phdr->p_flags & PF_W ? 'w' : '-', phdr->p_flags & PF_X ? 'x' : '-');
|
||||
}
|
||||
|
||||
|
@ -186,7 +187,7 @@ CustomElf::Load(Mappable *mappable, const char *path, int flags)
|
|||
|
||||
if (min_vaddr != 0) {
|
||||
ERROR("%s: Unsupported minimal virtual address: 0x%08" PRIxPTR,
|
||||
elf->GetPath(), min_vaddr);
|
||||
elf->GetPath(), uintptr_t(min_vaddr));
|
||||
return nullptr;
|
||||
}
|
||||
if (!dyn) {
|
||||
|
@ -456,7 +457,7 @@ namespace {
|
|||
|
||||
void debug_dyn(const char *type, const Dyn *dyn)
|
||||
{
|
||||
DEBUG_LOG("%s 0x%08" PRIxPTR, type, dyn->d_un.d_val);
|
||||
DEBUG_LOG("%s 0x%08" PRIxPTR, type, uintptr_t(dyn->d_un.d_val));
|
||||
}
|
||||
|
||||
} /* anonymous namespace */
|
||||
|
@ -587,7 +588,7 @@ CustomElf::InitDyn(const Phdr *pt_dyn)
|
|||
flags &= ~DF_SYMBOLIC;
|
||||
if (flags)
|
||||
WARN("%s: unhandled flags #%" PRIxPTR" not handled",
|
||||
GetPath(), flags);
|
||||
GetPath(), uintptr_t(flags));
|
||||
}
|
||||
break;
|
||||
case DT_SONAME: /* Should match GetName(), but doesn't matter */
|
||||
|
@ -610,7 +611,7 @@ CustomElf::InitDyn(const Phdr *pt_dyn)
|
|||
break;
|
||||
default:
|
||||
WARN("%s: dynamic header type #%" PRIxPTR" not handled",
|
||||
GetPath(), dyn->d_tag);
|
||||
GetPath(), uintptr_t(dyn->d_tag));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -671,7 +672,7 @@ CustomElf::Relocate()
|
|||
|
||||
if (symptr == nullptr)
|
||||
WARN("%s: Relocation to NULL @0x%08" PRIxPTR,
|
||||
GetPath(), rel->r_offset);
|
||||
GetPath(), uintptr_t(rel->r_offset));
|
||||
|
||||
/* Apply relocation */
|
||||
switch (ELF_R_TYPE(rel->r_info)) {
|
||||
|
@ -685,7 +686,7 @@ CustomElf::Relocate()
|
|||
break;
|
||||
default:
|
||||
ERROR("%s: Unsupported relocation type: 0x%" PRIxPTR,
|
||||
GetPath(), ELF_R_TYPE(rel->r_info));
|
||||
GetPath(), uintptr_t(ELF_R_TYPE(rel->r_info)));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -719,11 +720,11 @@ CustomElf::RelocateJumps()
|
|||
if (ELF_ST_BIND(sym.st_info) == STB_WEAK) {
|
||||
WARN("%s: Relocation to NULL @0x%08" PRIxPTR " for symbol \"%s\"",
|
||||
GetPath(),
|
||||
rel->r_offset, strtab.GetStringAt(sym.st_name));
|
||||
uintptr_t(rel->r_offset), strtab.GetStringAt(sym.st_name));
|
||||
} else {
|
||||
ERROR("%s: Relocation to NULL @0x%08" PRIxPTR " for symbol \"%s\"",
|
||||
GetPath(),
|
||||
rel->r_offset, strtab.GetStringAt(sym.st_name));
|
||||
uintptr_t(rel->r_offset), strtab.GetStringAt(sym.st_name));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -609,12 +609,12 @@ ElfLoader::~ElfLoader()
|
|||
it < list.rend(); ++it) {
|
||||
if ((*it)->AsSystemElf()) {
|
||||
DEBUG_LOG("ElfLoader::~ElfLoader(): Remaining handle for \"%s\" "
|
||||
"[%d direct refs, %d refs total]", (*it)->GetPath(),
|
||||
(*it)->DirectRefCount(), (*it)->refCount());
|
||||
"[%" PRIdPTR " direct refs, %" PRIdPTR " refs total]",
|
||||
(*it)->GetPath(), (*it)->DirectRefCount(), (*it)->refCount());
|
||||
} else {
|
||||
DEBUG_LOG("ElfLoader::~ElfLoader(): Unexpected remaining handle for \"%s\" "
|
||||
"[%d direct refs, %d refs total]", (*it)->GetPath(),
|
||||
(*it)->DirectRefCount(), (*it)->refCount());
|
||||
"[%" PRIdPTR " direct refs, %" PRIdPTR " refs total]",
|
||||
(*it)->GetPath(), (*it)->DirectRefCount(), (*it)->refCount());
|
||||
/* Not removing, since it could have references to other libraries,
|
||||
* destroying them as a side effect, and possibly leaving dangling
|
||||
* pointers in the handle list we're scanning */
|
||||
|
@ -970,7 +970,7 @@ ElfLoader::DebuggerHelper::Remove(ElfLoader::link_map *map)
|
|||
dbg->r_brk();
|
||||
}
|
||||
|
||||
#if defined(ANDROID)
|
||||
#if defined(ANDROID) && defined(__NR_sigaction)
|
||||
/* As some system libraries may be calling signal() or sigaction() to
|
||||
* set a SIGSEGV handler, effectively breaking MappableSeekableZStream,
|
||||
* or worse, restore our SIGSEGV handler with wrong flags (which using
|
||||
|
@ -1016,8 +1016,9 @@ Divert(T func, T new_func)
|
|||
*reinterpret_cast<intptr_t *>(addr + 1) =
|
||||
reinterpret_cast<uintptr_t>(new_func) - addr - 5; // target displacement
|
||||
return true;
|
||||
#elif defined(__arm__)
|
||||
#elif defined(__arm__) || defined(__aarch64__)
|
||||
const unsigned char trampoline[] = {
|
||||
# ifdef __arm__
|
||||
// .thumb
|
||||
0x46, 0x04, // nop
|
||||
0x78, 0x47, // bx pc
|
||||
|
@ -1025,8 +1026,15 @@ Divert(T func, T new_func)
|
|||
// .arm
|
||||
0x04, 0xf0, 0x1f, 0xe5, // ldr pc, [pc, #-4]
|
||||
// .word <new_func>
|
||||
# else // __aarch64__
|
||||
0x50, 0x00, 0x00, 0x58, // ldr x16, [pc, #8] ; x16 (aka ip0) is the first
|
||||
0x00, 0x02, 0x1f, 0xd6, // br x16 ; intra-procedure-call
|
||||
// .word <new_func.lo> ; scratch register.
|
||||
// .word <new_func.hi>
|
||||
# endif
|
||||
};
|
||||
const unsigned char *start;
|
||||
# ifdef __arm__
|
||||
if (addr & 0x01) {
|
||||
/* Function is thumb, the actual address of the code is without the
|
||||
* least significant bit. */
|
||||
|
@ -1040,12 +1048,16 @@ Divert(T func, T new_func)
|
|||
/* Function is arm, we only need the arm part of the trampoline */
|
||||
start = trampoline + 6;
|
||||
}
|
||||
# else // __aarch64__
|
||||
start = trampoline;
|
||||
#endif
|
||||
|
||||
size_t len = sizeof(trampoline) - (start - trampoline);
|
||||
EnsureWritable w(reinterpret_cast<void *>(addr), len + sizeof(void *));
|
||||
memcpy(reinterpret_cast<void *>(addr), start, len);
|
||||
*reinterpret_cast<void **>(addr + len) = FunctionPtr(new_func);
|
||||
cacheflush(addr, addr + len + sizeof(void *), 0);
|
||||
__builtin___clear_cache(reinterpret_cast<char*>(addr),
|
||||
reinterpret_cast<char*>(addr + len + sizeof(void *)));
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
|
|
|
@ -110,6 +110,18 @@
|
|||
#define STR_RELOC(n) "DT_REL" # n
|
||||
#define Reloc Rel
|
||||
|
||||
#elif defined(__aarch64__)
|
||||
#define ELFMACHINE EM_AARCH64
|
||||
|
||||
#define R_ABS R_AARCH64_ABS64
|
||||
#define R_GLOB_DAT R_AARCH64_GLOB_DAT
|
||||
#define R_JMP_SLOT R_AARCH64_JUMP_SLOT
|
||||
#define R_RELATIVE R_AARCH64_RELATIVE
|
||||
#define RELOC(n) DT_RELA ## n
|
||||
#define UNSUPPORTED_RELOC(n) DT_REL ## n
|
||||
#define STR_RELOC(n) "DT_RELA" # n
|
||||
#define Reloc Rela
|
||||
|
||||
#else
|
||||
#error Unknown ELF machine type
|
||||
#endif
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#include "Mappable.h"
|
||||
|
||||
#include "mozilla/IntegerPrintfMacros.h"
|
||||
#include "mozilla/SizePrintfMacros.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
||||
|
@ -212,7 +213,8 @@ MappableExtractFile::Create(const char *name, Zip *zip, Zip::Stream *stream)
|
|||
ERROR("Couldn't initialize XZ decoder");
|
||||
return nullptr;
|
||||
}
|
||||
DEBUG_LOG("XZStream created, compressed=%u, uncompressed=%u",
|
||||
DEBUG_LOG("XZStream created, compressed=%" PRIuPTR
|
||||
", uncompressed=%" PRIuPTR,
|
||||
xzStream.Size(), xzStream.UncompressedSize());
|
||||
|
||||
if (ftruncate(fd, xzStream.UncompressedSize()) == -1) {
|
||||
|
@ -226,7 +228,7 @@ MappableExtractFile::Create(const char *name, Zip *zip, Zip::Stream *stream)
|
|||
return nullptr;
|
||||
}
|
||||
const size_t written = xzStream.Decode(buffer, buffer.GetLength());
|
||||
DEBUG_LOG("XZStream decoded %u", written);
|
||||
DEBUG_LOG("XZStream decoded %" PRIuPTR, written);
|
||||
if (written != buffer.GetLength()) {
|
||||
ERROR("Error decoding XZ file %s", file.get());
|
||||
return nullptr;
|
||||
|
@ -294,16 +296,19 @@ public:
|
|||
* depending on how mappings grow in the address space.
|
||||
*/
|
||||
#if defined(__arm__)
|
||||
// Address increases on ARM.
|
||||
void *buf = ::mmap(nullptr, length + PAGE_SIZE, PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED, fd, 0);
|
||||
if (buf != MAP_FAILED) {
|
||||
::mmap(AlignedEndPtr(reinterpret_cast<char *>(buf) + length, PAGE_SIZE),
|
||||
PAGE_SIZE, PROT_NONE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
DEBUG_LOG("Decompression buffer of size 0x%x in ashmem \"%s\", mapped @%p",
|
||||
DEBUG_LOG("Decompression buffer of size 0x%" PRIxPTR
|
||||
" in ashmem \"%s\", mapped @%p",
|
||||
length, str, buf);
|
||||
return new _MappableBuffer(fd.forget(), buf, length);
|
||||
}
|
||||
#elif defined(__i386__)
|
||||
#elif defined(__i386__) || defined(__aarch64__)
|
||||
// Address decreases on x86 and AArch64.
|
||||
size_t anon_mapping_length = length + PAGE_SIZE;
|
||||
void *buf = ::mmap(nullptr, anon_mapping_length, PROT_NONE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
|
@ -319,8 +324,8 @@ public:
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
DEBUG_LOG("Decompression buffer of size 0x%x in ashmem \"%s\", mapped @%p",
|
||||
length, str, actual_buf);
|
||||
DEBUG_LOG("Decompression buffer of size 0x%" PRIxPTR
|
||||
" in ashmem \"%s\", mapped @%p", length, str, actual_buf);
|
||||
return new _MappableBuffer(fd.forget(), actual_buf, length);
|
||||
}
|
||||
#else
|
||||
|
@ -368,7 +373,7 @@ public:
|
|||
/* Free the additional page we allocated. See _MappableBuffer::Create */
|
||||
#if defined(__arm__)
|
||||
::munmap(AlignedEndPtr(*this + GetLength(), PAGE_SIZE), PAGE_SIZE);
|
||||
#elif defined(__i386__)
|
||||
#elif defined(__i386__) || defined(__aarch64__)
|
||||
::munmap(*this - PAGE_SIZE, GetLength() + PAGE_SIZE);
|
||||
#else
|
||||
#error need to add a case for your CPU
|
||||
|
|
|
@ -18,7 +18,7 @@ ParseVarLenInt(const uint8_t* aBuf, size_t aBufSize, uint64_t* aValue)
|
|||
if (!aBufSize) {
|
||||
return 0;
|
||||
}
|
||||
aBufSize = std::min(9u, aBufSize);
|
||||
aBufSize = std::min(size_t(9), aBufSize);
|
||||
|
||||
*aValue = aBuf[0] & 0x7F;
|
||||
size_t i = 0;
|
||||
|
|
|
@ -190,6 +190,7 @@ StackWalkInitCriticalAddress()
|
|||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/StackWalk_windows.h"
|
||||
#include "mozilla/WindowsVersion.h"
|
||||
|
||||
#ifdef MOZ_STATIC_JS // The standalone SM build lacks the interceptor headers.
|
||||
#include "nsWindowsDllInterceptor.h"
|
||||
|
@ -406,9 +407,11 @@ EnsureWalkThreadReady()
|
|||
NtDllInterceptor.AddHook("LdrUnloadDll",
|
||||
reinterpret_cast<intptr_t>(patched_LdrUnloadDll),
|
||||
(void**)&stub_LdrUnloadDll);
|
||||
NtDllInterceptor.AddHook("LdrResolveDelayLoadedAPI",
|
||||
reinterpret_cast<intptr_t>(patched_LdrResolveDelayLoadedAPI),
|
||||
(void**)&stub_LdrResolveDelayLoadedAPI);
|
||||
if (IsWin8OrLater()) { // LdrResolveDelayLoadedAPI was introduced in Win8
|
||||
NtDllInterceptor.AddHook("LdrResolveDelayLoadedAPI",
|
||||
reinterpret_cast<intptr_t>(patched_LdrResolveDelayLoadedAPI),
|
||||
(void**)&stub_LdrResolveDelayLoadedAPI);
|
||||
}
|
||||
#endif
|
||||
|
||||
InitializeDbgHelpCriticalSection();
|
||||
|
|
|
@ -1550,7 +1550,9 @@ Predictor::LearnNative(nsIURI *targetURI, nsIURI *sourceURI,
|
|||
|
||||
RefPtr<PredictorLearnRunnable> runnable = new PredictorLearnRunnable(
|
||||
targetURI, sourceURI, reason, originAttributes);
|
||||
NS_DispatchToMainThread(runnable);
|
||||
SystemGroup::Dispatch("PredictorLearnRunnable",
|
||||
TaskCategory::Other,
|
||||
runnable.forget());
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -4990,11 +4990,6 @@ if test "$MOZ_REQUIRE_SIGNING" = 1; then
|
|||
AC_DEFINE(MOZ_REQUIRE_SIGNING)
|
||||
fi
|
||||
|
||||
AC_SUBST(MOZ_JSDOWNLOADS)
|
||||
if test -n "$MOZ_JSDOWNLOADS"; then
|
||||
AC_DEFINE(MOZ_JSDOWNLOADS)
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Mac bundle name prefix
|
||||
dnl ========================================================
|
||||
|
|
|
@ -76,6 +76,10 @@ CONFIG_OPTIONS = [
|
|||
"dest": "bucket",
|
||||
"help": "s3 bucket to move beets to.",
|
||||
}],
|
||||
[["--product"], {
|
||||
"dest": "product",
|
||||
"help": "product for which artifacts are beetmoved",
|
||||
}],
|
||||
[["--exclude"], {
|
||||
"dest": "excludes",
|
||||
"action": "append",
|
||||
|
@ -151,7 +155,6 @@ class BeetMover(BaseScript, VirtualenvMixin, object):
|
|||
"mar",
|
||||
],
|
||||
"virtualenv_path": "venv",
|
||||
'product': 'firefox',
|
||||
},
|
||||
}
|
||||
#todo do excludes need to be configured via command line for specific builds?
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
|
||||
#include "nsDownloadManager.h"
|
||||
#include "DownloadPlatform.h"
|
||||
#include "nsDownloadProxy.h"
|
||||
#include "rdf.h"
|
||||
|
||||
#include "nsTypeAheadFind.h"
|
||||
|
@ -88,7 +87,6 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsAlertsService)
|
|||
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsDownloadManager,
|
||||
nsDownloadManager::GetSingleton)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(DownloadPlatform)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsDownloadProxy)
|
||||
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsTypeAheadFind)
|
||||
|
||||
|
@ -147,7 +145,6 @@ NS_DEFINE_NAMED_CID(NS_PARENTALCONTROLSSERVICE_CID);
|
|||
#endif
|
||||
NS_DEFINE_NAMED_CID(NS_DOWNLOADMANAGER_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_DOWNLOADPLATFORM_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_DOWNLOAD_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_FIND_SERVICE_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_TYPEAHEADFIND_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_APPLICATION_REPUTATION_SERVICE_CID);
|
||||
|
@ -183,7 +180,6 @@ static const Module::CIDEntry kToolkitCIDs[] = {
|
|||
#endif
|
||||
{ &kNS_DOWNLOADMANAGER_CID, false, nullptr, nsDownloadManagerConstructor },
|
||||
{ &kNS_DOWNLOADPLATFORM_CID, false, nullptr, DownloadPlatformConstructor },
|
||||
{ &kNS_DOWNLOAD_CID, false, nullptr, nsDownloadProxyConstructor },
|
||||
{ &kNS_FIND_SERVICE_CID, false, nullptr, nsFindServiceConstructor },
|
||||
{ &kNS_TYPEAHEADFIND_CID, false, nullptr, nsTypeAheadFindConstructor },
|
||||
{ &kNS_APPLICATION_REPUTATION_SERVICE_CID, false, nullptr, ApplicationReputationServiceConstructor },
|
||||
|
|
|
@ -1,146 +0,0 @@
|
|||
/* vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/storage.h"
|
||||
#include "mozilla/storage/Variant.h"
|
||||
#include "mozilla/mozalloc.h"
|
||||
#include "nsString.h"
|
||||
#include "SQLFunctions.h"
|
||||
#include "nsUTF8Utils.h"
|
||||
#include "plbase64.h"
|
||||
#include "prio.h"
|
||||
|
||||
#ifdef XP_WIN
|
||||
#include <windows.h>
|
||||
#include <wincrypt.h>
|
||||
#endif
|
||||
|
||||
// The length of guids that are used by the download manager
|
||||
#define GUID_LENGTH 12
|
||||
|
||||
namespace mozilla {
|
||||
namespace downloads {
|
||||
|
||||
// Keep this file in sync with the GUID-related code in toolkit/places/SQLFunctions.cpp
|
||||
// and toolkit/places/Helpers.cpp!
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// GUID Creation Function
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//// GenerateGUIDFunction
|
||||
|
||||
/* static */
|
||||
nsresult
|
||||
GenerateGUIDFunction::create(mozIStorageConnection *aDBConn)
|
||||
{
|
||||
RefPtr<GenerateGUIDFunction> function = new GenerateGUIDFunction();
|
||||
nsresult rv = aDBConn->CreateFunction(
|
||||
NS_LITERAL_CSTRING("generate_guid"), 0, function
|
||||
);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(
|
||||
GenerateGUIDFunction,
|
||||
mozIStorageFunction
|
||||
)
|
||||
|
||||
static
|
||||
nsresult
|
||||
Base64urlEncode(const uint8_t* aBytes,
|
||||
uint32_t aNumBytes,
|
||||
nsCString& _result)
|
||||
{
|
||||
// SetLength does not set aside space for null termination. PL_Base64Encode
|
||||
// will not null terminate, however, nsCStrings must be null terminated. As a
|
||||
// result, we set the capacity to be one greater than what we need, and the
|
||||
// length to our desired length.
|
||||
uint32_t length = (aNumBytes + 2) / 3 * 4; // +2 due to integer math.
|
||||
NS_ENSURE_TRUE(_result.SetCapacity(length + 1, mozilla::fallible),
|
||||
NS_ERROR_OUT_OF_MEMORY);
|
||||
_result.SetLength(length);
|
||||
(void)PL_Base64Encode(reinterpret_cast<const char*>(aBytes), aNumBytes,
|
||||
_result.BeginWriting());
|
||||
|
||||
// base64url encoding is defined in RFC 4648. It replaces the last two
|
||||
// alphabet characters of base64 encoding with '-' and '_' respectively.
|
||||
_result.ReplaceChar('+', '-');
|
||||
_result.ReplaceChar('/', '_');
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static
|
||||
nsresult
|
||||
GenerateRandomBytes(uint32_t aSize,
|
||||
uint8_t* _buffer)
|
||||
{
|
||||
// On Windows, we'll use its built-in cryptographic API.
|
||||
#if defined(XP_WIN)
|
||||
HCRYPTPROV cryptoProvider;
|
||||
BOOL rc = CryptAcquireContext(&cryptoProvider, 0, 0, PROV_RSA_FULL,
|
||||
CRYPT_VERIFYCONTEXT | CRYPT_SILENT);
|
||||
if (rc) {
|
||||
rc = CryptGenRandom(cryptoProvider, aSize, _buffer);
|
||||
(void)CryptReleaseContext(cryptoProvider, 0);
|
||||
}
|
||||
return rc ? NS_OK : NS_ERROR_FAILURE;
|
||||
|
||||
// On Unix, we'll just read in from /dev/urandom.
|
||||
#elif defined(XP_UNIX)
|
||||
NS_ENSURE_ARG_MAX(aSize, INT32_MAX);
|
||||
PRFileDesc* urandom = PR_Open("/dev/urandom", PR_RDONLY, 0);
|
||||
nsresult rv = NS_ERROR_FAILURE;
|
||||
if (urandom) {
|
||||
int32_t bytesRead = PR_Read(urandom, _buffer, aSize);
|
||||
if (bytesRead == static_cast<int32_t>(aSize)) {
|
||||
rv = NS_OK;
|
||||
}
|
||||
(void)PR_Close(urandom);
|
||||
}
|
||||
return rv;
|
||||
#endif
|
||||
}
|
||||
|
||||
nsresult
|
||||
GenerateGUID(nsCString& _guid)
|
||||
{
|
||||
_guid.Truncate();
|
||||
|
||||
// Request raw random bytes and base64url encode them. For each set of three
|
||||
// bytes, we get one character.
|
||||
const uint32_t kRequiredBytesLength =
|
||||
static_cast<uint32_t>(GUID_LENGTH / 4 * 3);
|
||||
|
||||
uint8_t buffer[kRequiredBytesLength];
|
||||
nsresult rv = GenerateRandomBytes(kRequiredBytesLength, buffer);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = Base64urlEncode(buffer, kRequiredBytesLength, _guid);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
NS_ASSERTION(_guid.Length() == GUID_LENGTH, "GUID is not the right size!");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//// mozIStorageFunction
|
||||
|
||||
NS_IMETHODIMP
|
||||
GenerateGUIDFunction::OnFunctionCall(mozIStorageValueArray *aArguments,
|
||||
nsIVariant **_result)
|
||||
{
|
||||
nsAutoCString guid;
|
||||
nsresult rv = GenerateGUID(guid);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
NS_ADDREF(*_result = new mozilla::storage::UTF8TextVariant(guid));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace downloads
|
||||
} // namespace mozilla
|
|
@ -1,46 +0,0 @@
|
|||
/* vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_downloads_SQLFunctions_h
|
||||
#define mozilla_downloads_SQLFunctions_h
|
||||
|
||||
#include "mozIStorageFunction.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
class nsCString;
|
||||
class mozIStorageConnection;
|
||||
|
||||
namespace mozilla {
|
||||
namespace downloads {
|
||||
|
||||
/**
|
||||
* SQL function to generate a GUID for a place or bookmark item. This is just
|
||||
* a wrapper around GenerateGUID in SQLFunctions.cpp.
|
||||
*
|
||||
* @return a guid for the item.
|
||||
* @see toolkit/components/places/SQLFunctions.h - keep this in sync
|
||||
*/
|
||||
class GenerateGUIDFunction final : public mozIStorageFunction
|
||||
{
|
||||
~GenerateGUIDFunction() {}
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_MOZISTORAGEFUNCTION
|
||||
|
||||
/**
|
||||
* Registers the function with the specified database connection.
|
||||
*
|
||||
* @param aDBConn
|
||||
* The database connection to register with.
|
||||
*/
|
||||
static nsresult create(mozIStorageConnection *aDBConn);
|
||||
};
|
||||
|
||||
nsresult GenerateGUID(nsCString& _guid);
|
||||
|
||||
} // namespace downloads
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
|
@ -19,7 +19,7 @@ if [ ! -e $PROTOC_PATH ]; then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f nsDownloadManager.cpp ]; then
|
||||
if [ ! -f nsIApplicationReputation.idl ]; then
|
||||
echo "You must run this script in the toolkit/components/downloads" >&2
|
||||
echo "directory of the source tree." >&2
|
||||
exit 1
|
||||
|
|
|
@ -37,18 +37,6 @@ UNIFIED_SOURCES += [
|
|||
'nsDownloadManager.cpp'
|
||||
]
|
||||
|
||||
# SQLFunctions.cpp cannot be built in unified mode because of Windows headers.
|
||||
SOURCES += [
|
||||
'SQLFunctions.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['OS_ARCH'] == 'WINNT':
|
||||
# Can't build unified because we need CreateEvent which some IPC code
|
||||
# included in LoadContext ends up undefining.
|
||||
SOURCES += [
|
||||
'nsDownloadScanner.cpp',
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -6,449 +6,34 @@
|
|||
#ifndef downloadmanager___h___
|
||||
#define downloadmanager___h___
|
||||
|
||||
#if defined(XP_WIN)
|
||||
#define DOWNLOAD_SCANNER
|
||||
#endif
|
||||
|
||||
#include "nsIDownload.h"
|
||||
#include "nsIDownloadManager.h"
|
||||
#include "nsIDownloadProgressListener.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsIMIMEInfo.h"
|
||||
#include "nsINavHistoryService.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIStringBundle.h"
|
||||
#include "nsISupportsPrimitives.h"
|
||||
#include "nsWeakReference.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsString.h"
|
||||
|
||||
#include "mozIDOMWindow.h"
|
||||
#include "mozStorageHelper.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCOMArray.h"
|
||||
|
||||
typedef int16_t DownloadState;
|
||||
typedef int16_t DownloadType;
|
||||
|
||||
class nsIArray;
|
||||
class nsDownload;
|
||||
|
||||
#ifdef DOWNLOAD_SCANNER
|
||||
#include "nsDownloadScanner.h"
|
||||
#endif
|
||||
|
||||
class nsDownloadManager final : public nsIDownloadManager,
|
||||
public nsINavHistoryObserver,
|
||||
public nsIObserver,
|
||||
public nsSupportsWeakReference
|
||||
class nsDownloadManager final : public nsIDownloadManager
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIDOWNLOADMANAGER
|
||||
NS_DECL_NSINAVHISTORYOBSERVER
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
nsresult Init();
|
||||
|
||||
static nsDownloadManager *GetSingleton();
|
||||
|
||||
nsDownloadManager()
|
||||
#ifdef DOWNLOAD_SCANNER
|
||||
: mScanner(nullptr)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~nsDownloadManager();
|
||||
|
||||
nsresult InitDB();
|
||||
nsresult InitFileDB();
|
||||
void CloseAllDBs();
|
||||
void CloseDB(mozIStorageConnection* aDBConn,
|
||||
mozIStorageStatement* aUpdateStmt,
|
||||
mozIStorageStatement* aGetIdsStmt);
|
||||
nsresult InitPrivateDB();
|
||||
already_AddRefed<mozIStorageConnection> GetFileDBConnection(nsIFile *dbFile) const;
|
||||
already_AddRefed<mozIStorageConnection> GetPrivateDBConnection() const;
|
||||
nsresult CreateTable(mozIStorageConnection* aDBConn);
|
||||
|
||||
/**
|
||||
* Fix up the database after a crash such as dealing with previously-active
|
||||
* downloads. Call this before RestoreActiveDownloads to get the downloads
|
||||
* fixed here to be auto-resumed.
|
||||
*/
|
||||
nsresult RestoreDatabaseState();
|
||||
|
||||
/**
|
||||
* Paused downloads that survive across sessions are considered active, so
|
||||
* rebuild the list of these downloads.
|
||||
*/
|
||||
nsresult RestoreActiveDownloads();
|
||||
|
||||
nsresult GetDownloadFromDB(const nsACString& aGUID, nsDownload **retVal);
|
||||
nsresult GetDownloadFromDB(uint32_t aID, nsDownload **retVal);
|
||||
nsresult GetDownloadFromDB(mozIStorageConnection* aDBConn,
|
||||
mozIStorageStatement* stmt,
|
||||
nsDownload **retVal);
|
||||
|
||||
/**
|
||||
* Specially track the active downloads so that we don't need to check
|
||||
* every download to see if they're in progress.
|
||||
*/
|
||||
nsresult AddToCurrentDownloads(nsDownload *aDl);
|
||||
|
||||
void SendEvent(nsDownload *aDownload, const char *aTopic);
|
||||
|
||||
/**
|
||||
* Adds a download with the specified information to the DB.
|
||||
*
|
||||
* @return The id of the download, or 0 if there was an error.
|
||||
*/
|
||||
int64_t AddDownloadToDB(const nsAString &aName,
|
||||
const nsACString &aSource,
|
||||
const nsACString &aTarget,
|
||||
const nsAString &aTempPath,
|
||||
int64_t aStartTime,
|
||||
int64_t aEndTime,
|
||||
const nsACString &aMimeType,
|
||||
const nsACString &aPreferredApp,
|
||||
nsHandlerInfoAction aPreferredAction,
|
||||
bool aPrivate,
|
||||
nsACString &aNewGUID);
|
||||
|
||||
void NotifyListenersOnDownloadStateChange(int16_t aOldState,
|
||||
nsDownload *aDownload);
|
||||
void NotifyListenersOnProgressChange(nsIWebProgress *aProgress,
|
||||
nsIRequest *aRequest,
|
||||
int64_t aCurSelfProgress,
|
||||
int64_t aMaxSelfProgress,
|
||||
int64_t aCurTotalProgress,
|
||||
int64_t aMaxTotalProgress,
|
||||
nsDownload *aDownload);
|
||||
void NotifyListenersOnStateChange(nsIWebProgress *aProgress,
|
||||
nsIRequest *aRequest,
|
||||
uint32_t aStateFlags,
|
||||
nsresult aStatus,
|
||||
nsDownload *aDownload);
|
||||
|
||||
nsDownload *FindDownload(const nsACString& aGUID);
|
||||
nsDownload *FindDownload(uint32_t aID);
|
||||
|
||||
/**
|
||||
* First try to resume the download, and if that fails, retry it.
|
||||
*
|
||||
* @param aDl The download to resume and/or retry.
|
||||
*/
|
||||
nsresult ResumeRetry(nsDownload *aDl);
|
||||
|
||||
/**
|
||||
* Pause all active downloads and remember if they should try to auto-resume
|
||||
* when the download manager starts again.
|
||||
*
|
||||
* @param aSetResume Indicate if the downloads that get paused should be set
|
||||
* as auto-resume.
|
||||
*/
|
||||
nsresult PauseAllDownloads(bool aSetResume);
|
||||
|
||||
/**
|
||||
* Resume all paused downloads unless we're only supposed to do the automatic
|
||||
* ones; in that case, try to retry them as well if resuming doesn't work.
|
||||
*
|
||||
* @param aResumeAll If true, all downloads will be resumed; otherwise, only
|
||||
* those that are marked as auto-resume will resume.
|
||||
*/
|
||||
nsresult ResumeAllDownloads(bool aResumeAll);
|
||||
|
||||
/**
|
||||
* Stop tracking the active downloads. Only use this when we're about to quit
|
||||
* the download manager because we destroy our list of active downloads to
|
||||
* break the dlmgr<->dl cycle. Active downloads that aren't real-paused will
|
||||
* be canceled.
|
||||
*/
|
||||
nsresult RemoveAllDownloads();
|
||||
|
||||
/**
|
||||
* Find all downloads from a source URI and delete them.
|
||||
*
|
||||
* @param aURI
|
||||
* The source URI to remove downloads
|
||||
*/
|
||||
nsresult RemoveDownloadsForURI(nsIURI *aURI);
|
||||
|
||||
/**
|
||||
* Callback used for resuming downloads after getting a wake notification.
|
||||
*
|
||||
* @param aTimer
|
||||
* Timer object fired after some delay after a wake notification
|
||||
* @param aClosure
|
||||
* nsDownloadManager object used to resume downloads
|
||||
*/
|
||||
static void ResumeOnWakeCallback(nsITimer *aTimer, void *aClosure);
|
||||
nsCOMPtr<nsITimer> mResumeOnWakeTimer;
|
||||
|
||||
void ConfirmCancelDownloads(int32_t aCount,
|
||||
nsISupportsPRBool *aCancelDownloads,
|
||||
const char16_t *aTitle,
|
||||
const char16_t *aCancelMessageMultiple,
|
||||
const char16_t *aCancelMessageSingle,
|
||||
const char16_t *aDontCancelButton);
|
||||
|
||||
int32_t GetRetentionBehavior();
|
||||
|
||||
/**
|
||||
* Type to indicate possible behaviors for active downloads across sessions.
|
||||
*
|
||||
* Possible values are:
|
||||
* QUIT_AND_RESUME - downloads should be auto-resumed
|
||||
* QUIT_AND_PAUSE - downloads should be paused
|
||||
* QUIT_AND_CANCEL - downloads should be cancelled
|
||||
*/
|
||||
enum QuitBehavior {
|
||||
QUIT_AND_RESUME = 0,
|
||||
QUIT_AND_PAUSE = 1,
|
||||
QUIT_AND_CANCEL = 2
|
||||
};
|
||||
|
||||
/**
|
||||
* Indicates user-set behavior for active downloads across sessions,
|
||||
*
|
||||
* @return value of user-set pref for active download behavior
|
||||
*/
|
||||
enum QuitBehavior GetQuitBehavior();
|
||||
|
||||
void OnEnterPrivateBrowsingMode();
|
||||
void OnLeavePrivateBrowsingMode();
|
||||
|
||||
nsresult RetryDownload(const nsACString& aGUID);
|
||||
nsresult RetryDownload(nsDownload* dl);
|
||||
|
||||
nsresult RemoveDownload(const nsACString& aGUID);
|
||||
|
||||
nsresult NotifyDownloadRemoval(nsDownload* aRemoved);
|
||||
|
||||
// Virus scanner for windows
|
||||
#ifdef DOWNLOAD_SCANNER
|
||||
private:
|
||||
nsDownloadScanner* mScanner;
|
||||
#endif
|
||||
|
||||
private:
|
||||
nsresult CleanUp(mozIStorageConnection* aDBConn);
|
||||
nsresult InitStatements(mozIStorageConnection* aDBConn,
|
||||
mozIStorageStatement** aUpdateStatement,
|
||||
mozIStorageStatement** aGetIdsStatement);
|
||||
nsresult RemoveAllDownloads(nsCOMArray<nsDownload>& aDownloads);
|
||||
nsresult PauseAllDownloads(nsCOMArray<nsDownload>& aDownloads, bool aSetResume);
|
||||
nsresult ResumeAllDownloads(nsCOMArray<nsDownload>& aDownloads, bool aResumeAll);
|
||||
nsresult RemoveDownloadsForURI(mozIStorageStatement* aStatement, nsIURI *aURI);
|
||||
|
||||
bool mUseJSTransfer;
|
||||
nsCOMArray<nsIDownloadProgressListener> mListeners;
|
||||
nsCOMArray<nsIDownloadProgressListener> mPrivacyAwareListeners;
|
||||
nsCOMPtr<nsIStringBundle> mBundle;
|
||||
nsCOMPtr<mozIStorageConnection> mDBConn;
|
||||
nsCOMPtr<mozIStorageConnection> mPrivateDBConn;
|
||||
nsCOMArray<nsDownload> mCurrentDownloads;
|
||||
nsCOMArray<nsDownload> mCurrentPrivateDownloads;
|
||||
nsCOMPtr<nsIObserverService> mObserverService;
|
||||
nsCOMPtr<mozIStorageStatement> mUpdateDownloadStatement;
|
||||
nsCOMPtr<mozIStorageStatement> mUpdatePrivateDownloadStatement;
|
||||
nsCOMPtr<mozIStorageStatement> mGetIdsForURIStatement;
|
||||
nsCOMPtr<mozIStorageStatement> mGetPrivateIdsForURIStatement;
|
||||
nsAutoPtr<mozStorageTransaction> mHistoryTransaction;
|
||||
|
||||
static nsDownloadManager *gDownloadManagerService;
|
||||
|
||||
friend class nsDownload;
|
||||
};
|
||||
|
||||
class nsDownload final : public nsIDownload
|
||||
{
|
||||
public:
|
||||
NS_DECL_NSIWEBPROGRESSLISTENER
|
||||
NS_DECL_NSIWEBPROGRESSLISTENER2
|
||||
NS_DECL_NSITRANSFER
|
||||
NS_DECL_NSIDOWNLOAD
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
nsDownload();
|
||||
|
||||
/**
|
||||
* This method MUST be called when changing states on a download. It will
|
||||
* notify the download listener when a change happens. This also updates the
|
||||
* database, by calling UpdateDB().
|
||||
*/
|
||||
nsresult SetState(DownloadState aState);
|
||||
|
||||
protected:
|
||||
virtual ~nsDownload();
|
||||
|
||||
/**
|
||||
* Finish up the download by breaking reference cycles and clearing unneeded
|
||||
* data. Additionally, the download removes itself from the download
|
||||
* manager's list of current downloads.
|
||||
*
|
||||
* NOTE: This method removes the cycle created when starting the download, so
|
||||
* make sure to use kungFuDeathGrip if you want to access member variables.
|
||||
*/
|
||||
void Finalize();
|
||||
|
||||
/**
|
||||
* For finished resumed downloads that came in from exthandler, perform the
|
||||
* action that would have been done if the download wasn't resumed.
|
||||
*/
|
||||
nsresult ExecuteDesiredAction();
|
||||
|
||||
/**
|
||||
* Move the temporary file to the final destination by removing the existing
|
||||
* dummy target and renaming the temporary.
|
||||
*/
|
||||
nsresult MoveTempToTarget();
|
||||
|
||||
/**
|
||||
* Set the target file permissions to be appropriate.
|
||||
*/
|
||||
nsresult FixTargetPermissions();
|
||||
|
||||
/**
|
||||
* Update the start time which also implies the last update time is the same.
|
||||
*/
|
||||
void SetStartTime(int64_t aStartTime);
|
||||
|
||||
/**
|
||||
* Update the amount of bytes transferred and max bytes; and recalculate the
|
||||
* download percent.
|
||||
*/
|
||||
void SetProgressBytes(int64_t aCurrBytes, int64_t aMaxBytes);
|
||||
|
||||
/**
|
||||
* All this does is cancel the connection that the download is using. It does
|
||||
* not remove it from the download manager.
|
||||
*/
|
||||
nsresult CancelTransfer();
|
||||
|
||||
/**
|
||||
* Download is not transferring?
|
||||
*/
|
||||
bool IsPaused();
|
||||
|
||||
/**
|
||||
* Download can continue from the middle of a transfer?
|
||||
*/
|
||||
bool IsResumable();
|
||||
|
||||
/**
|
||||
* Download was resumed?
|
||||
*/
|
||||
bool WasResumed();
|
||||
|
||||
/**
|
||||
* Indicates if the download should try to automatically resume or not.
|
||||
*/
|
||||
bool ShouldAutoResume();
|
||||
|
||||
/**
|
||||
* Download is in a state to stop and complete the download?
|
||||
*/
|
||||
bool IsFinishable();
|
||||
|
||||
/**
|
||||
* Download is totally done transferring and all?
|
||||
*/
|
||||
bool IsFinished();
|
||||
|
||||
/**
|
||||
* Update the DB with the current state of the download including time,
|
||||
* download state and other values not known when first creating the
|
||||
* download DB entry.
|
||||
*/
|
||||
nsresult UpdateDB();
|
||||
|
||||
/**
|
||||
* Fail a download because of a failure status and prompt the provided
|
||||
* message or use a generic download failure message if nullptr.
|
||||
*/
|
||||
nsresult FailDownload(nsresult aStatus, const char16_t *aMessage);
|
||||
|
||||
/**
|
||||
* Opens the downloaded file with the appropriate application, which is
|
||||
* either the OS default, MIME type default, or the one selected by the user.
|
||||
*
|
||||
* This also adds the temporary file to the "To be deleted on Exit" list, if
|
||||
* the corresponding user preference is set (except on OS X).
|
||||
*
|
||||
* This function was adopted from nsExternalAppHandler::OpenWithApplication
|
||||
* (uriloader/exthandler/nsExternalHelperAppService.cpp).
|
||||
*/
|
||||
nsresult OpenWithApplication();
|
||||
|
||||
nsDownloadManager *mDownloadManager;
|
||||
nsCOMPtr<nsIURI> mTarget;
|
||||
|
||||
private:
|
||||
nsString mDisplayName;
|
||||
nsCString mEntityID;
|
||||
nsCString mGUID;
|
||||
|
||||
nsCOMPtr<nsIURI> mSource;
|
||||
nsCOMPtr<nsIURI> mReferrer;
|
||||
nsCOMPtr<nsICancelable> mCancelable;
|
||||
nsCOMPtr<nsIRequest> mRequest;
|
||||
nsCOMPtr<nsIFile> mTempFile;
|
||||
nsCOMPtr<nsIMIMEInfo> mMIMEInfo;
|
||||
|
||||
DownloadState mDownloadState;
|
||||
|
||||
uint32_t mID;
|
||||
int32_t mPercentComplete;
|
||||
|
||||
/**
|
||||
* These bytes are based on the position of where the request started, so 0
|
||||
* doesn't necessarily mean we have nothing. Use GetAmountTransferred and
|
||||
* GetSize for the real transferred amount and size.
|
||||
*/
|
||||
int64_t mCurrBytes;
|
||||
int64_t mMaxBytes;
|
||||
|
||||
PRTime mStartTime;
|
||||
PRTime mLastUpdate;
|
||||
int64_t mResumedAt;
|
||||
double mSpeed;
|
||||
|
||||
bool mHasMultipleFiles;
|
||||
bool mPrivate;
|
||||
|
||||
/**
|
||||
* Track various states of the download trying to auto-resume when starting
|
||||
* the download manager or restoring from a crash.
|
||||
*
|
||||
* DONT_RESUME: Don't automatically resume the download
|
||||
* AUTO_RESUME: Automaically resume the download
|
||||
*/
|
||||
enum AutoResume { DONT_RESUME, AUTO_RESUME };
|
||||
AutoResume mAutoResume;
|
||||
|
||||
/**
|
||||
* Stores the SHA-256 hash associated with the downloaded file.
|
||||
*/
|
||||
nsCString mHash;
|
||||
|
||||
/**
|
||||
* Stores the certificate chains in an nsIArray of nsIX509CertList of
|
||||
* nsIX509Cert, if this binary is signed.
|
||||
*/
|
||||
nsCOMPtr<nsIArray> mSignatureInfo;
|
||||
|
||||
/**
|
||||
* Stores the redirects that led to this download in an nsIArray of
|
||||
* nsIPrincipal.
|
||||
*/
|
||||
nsCOMPtr<nsIArray> mRedirects;
|
||||
|
||||
friend class nsDownloadManager;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,179 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef downloadproxy___h___
|
||||
#define downloadproxy___h___
|
||||
|
||||
#include "nsIDownloadManager.h"
|
||||
#include "nsIPrefBranch.h"
|
||||
#include "nsIPrefService.h"
|
||||
#include "nsIMIMEInfo.h"
|
||||
#include "nsIFileURL.h"
|
||||
#include "nsIDownloadManagerUI.h"
|
||||
|
||||
#define PREF_BDM_SHOWWHENSTARTING "browser.download.manager.showWhenStarting"
|
||||
#define PREF_BDM_FOCUSWHENSTARTING "browser.download.manager.focusWhenStarting"
|
||||
|
||||
// This class only exists because nsDownload cannot inherit from nsITransfer
|
||||
// directly. The reason for this is that nsDownloadManager (incorrectly) keeps
|
||||
// an nsCOMArray of nsDownloads, and nsCOMArray is only intended for use with
|
||||
// abstract classes. Using a concrete class that multiply inherits from classes
|
||||
// deriving from nsISupports will throw ambiguous base class errors.
|
||||
class nsDownloadProxy : public nsITransfer
|
||||
{
|
||||
protected:
|
||||
|
||||
virtual ~nsDownloadProxy() { }
|
||||
|
||||
public:
|
||||
|
||||
nsDownloadProxy() { }
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_IMETHOD Init(nsIURI* aSource,
|
||||
nsIURI* aTarget,
|
||||
const nsAString& aDisplayName,
|
||||
nsIMIMEInfo *aMIMEInfo,
|
||||
PRTime aStartTime,
|
||||
nsIFile* aTempFile,
|
||||
nsICancelable* aCancelable,
|
||||
bool aIsPrivate) override {
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIDownloadManager> dm = do_GetService("@mozilla.org/download-manager;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = dm->AddDownload(nsIDownloadManager::DOWNLOAD_TYPE_DOWNLOAD, aSource,
|
||||
aTarget, aDisplayName, aMIMEInfo, aStartTime,
|
||||
aTempFile, aCancelable, aIsPrivate,
|
||||
getter_AddRefs(mInner));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIPrefService> prefs = do_GetService("@mozilla.org/preferences-service;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsIPrefBranch> branch = do_QueryInterface(prefs);
|
||||
|
||||
bool showDM = true;
|
||||
if (branch)
|
||||
branch->GetBoolPref(PREF_BDM_SHOWWHENSTARTING, &showDM);
|
||||
|
||||
if (showDM) {
|
||||
nsCOMPtr<nsIDownloadManagerUI> dmui =
|
||||
do_GetService("@mozilla.org/download-manager-ui;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
bool visible;
|
||||
rv = dmui->GetVisible(&visible);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
bool focusWhenStarting = true;
|
||||
if (branch)
|
||||
(void)branch->GetBoolPref(PREF_BDM_FOCUSWHENSTARTING, &focusWhenStarting);
|
||||
|
||||
if (visible && !focusWhenStarting)
|
||||
return NS_OK;
|
||||
|
||||
return dmui->Show(nullptr, mInner, nsIDownloadManagerUI::REASON_NEW_DOWNLOAD, aIsPrivate);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHOD OnStateChange(nsIWebProgress* aWebProgress,
|
||||
nsIRequest* aRequest, uint32_t aStateFlags,
|
||||
nsresult aStatus) override
|
||||
{
|
||||
NS_ENSURE_TRUE(mInner, NS_ERROR_NOT_INITIALIZED);
|
||||
return mInner->OnStateChange(aWebProgress, aRequest, aStateFlags, aStatus);
|
||||
}
|
||||
|
||||
NS_IMETHOD OnStatusChange(nsIWebProgress *aWebProgress,
|
||||
nsIRequest *aRequest, nsresult aStatus,
|
||||
const char16_t *aMessage) override
|
||||
{
|
||||
NS_ENSURE_TRUE(mInner, NS_ERROR_NOT_INITIALIZED);
|
||||
return mInner->OnStatusChange(aWebProgress, aRequest, aStatus, aMessage);
|
||||
}
|
||||
|
||||
NS_IMETHOD OnLocationChange(nsIWebProgress *aWebProgress,
|
||||
nsIRequest *aRequest, nsIURI *aLocation,
|
||||
uint32_t aFlags) override
|
||||
{
|
||||
NS_ENSURE_TRUE(mInner, NS_ERROR_NOT_INITIALIZED);
|
||||
return mInner->OnLocationChange(aWebProgress, aRequest, aLocation, aFlags);
|
||||
}
|
||||
|
||||
NS_IMETHOD OnProgressChange(nsIWebProgress *aWebProgress,
|
||||
nsIRequest *aRequest,
|
||||
int32_t aCurSelfProgress,
|
||||
int32_t aMaxSelfProgress,
|
||||
int32_t aCurTotalProgress,
|
||||
int32_t aMaxTotalProgress) override
|
||||
{
|
||||
NS_ENSURE_TRUE(mInner, NS_ERROR_NOT_INITIALIZED);
|
||||
return mInner->OnProgressChange(aWebProgress, aRequest,
|
||||
aCurSelfProgress,
|
||||
aMaxSelfProgress,
|
||||
aCurTotalProgress,
|
||||
aMaxTotalProgress);
|
||||
}
|
||||
|
||||
NS_IMETHOD OnProgressChange64(nsIWebProgress *aWebProgress,
|
||||
nsIRequest *aRequest,
|
||||
int64_t aCurSelfProgress,
|
||||
int64_t aMaxSelfProgress,
|
||||
int64_t aCurTotalProgress,
|
||||
int64_t aMaxTotalProgress) override
|
||||
{
|
||||
NS_ENSURE_TRUE(mInner, NS_ERROR_NOT_INITIALIZED);
|
||||
return mInner->OnProgressChange64(aWebProgress, aRequest,
|
||||
aCurSelfProgress,
|
||||
aMaxSelfProgress,
|
||||
aCurTotalProgress,
|
||||
aMaxTotalProgress);
|
||||
}
|
||||
|
||||
NS_IMETHOD OnRefreshAttempted(nsIWebProgress *aWebProgress,
|
||||
nsIURI *aUri,
|
||||
int32_t aDelay,
|
||||
bool aSameUri,
|
||||
bool *allowRefresh) override
|
||||
{
|
||||
*allowRefresh = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD OnSecurityChange(nsIWebProgress *aWebProgress,
|
||||
nsIRequest *aRequest, uint32_t aState) override
|
||||
{
|
||||
NS_ENSURE_TRUE(mInner, NS_ERROR_NOT_INITIALIZED);
|
||||
return mInner->OnSecurityChange(aWebProgress, aRequest, aState);
|
||||
}
|
||||
|
||||
NS_IMETHOD SetSha256Hash(const nsACString& aHash) override
|
||||
{
|
||||
NS_ENSURE_TRUE(mInner, NS_ERROR_NOT_INITIALIZED);
|
||||
return mInner->SetSha256Hash(aHash);
|
||||
}
|
||||
|
||||
NS_IMETHOD SetSignatureInfo(nsIArray* aSignatureInfo) override
|
||||
{
|
||||
NS_ENSURE_TRUE(mInner, NS_ERROR_NOT_INITIALIZED);
|
||||
return mInner->SetSignatureInfo(aSignatureInfo);
|
||||
}
|
||||
|
||||
NS_IMETHOD SetRedirects(nsIArray* aRedirects) override
|
||||
{
|
||||
NS_ENSURE_TRUE(mInner, NS_ERROR_NOT_INITIALIZED);
|
||||
return mInner->SetRedirects(aRedirects);
|
||||
}
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIDownload> mInner;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsDownloadProxy, nsITransfer,
|
||||
nsIWebProgressListener, nsIWebProgressListener2)
|
||||
|
||||
#endif
|
|
@ -1,728 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: se cin sw=2 ts=2 et : */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsDownloadScanner.h"
|
||||
#include <comcat.h>
|
||||
#include <process.h>
|
||||
#include "nsDownloadManager.h"
|
||||
#include "nsIXULAppInfo.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "nsIPrefService.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "prtime.h"
|
||||
#include "nsDeque.h"
|
||||
#include "nsIFileURL.h"
|
||||
#include "nsIPrefBranch.h"
|
||||
#include "nsXPCOMCIDInternal.h"
|
||||
|
||||
/**
|
||||
* Code overview
|
||||
*
|
||||
* Download scanner attempts to make use of one of two different virus
|
||||
* scanning interfaces available on Windows - IOfficeAntiVirus (Windows
|
||||
* 95/NT 4 and IE 5) and IAttachmentExecute (XPSP2 and up). The latter
|
||||
* interface supports calling IOfficeAntiVirus internally, while also
|
||||
* adding support for XPSP2+ ADS forks which define security related
|
||||
* prompting on downloaded content.
|
||||
*
|
||||
* Both interfaces are synchronous and can take a while, so it is not a
|
||||
* good idea to call either from the main thread. Some antivirus scanners can
|
||||
* take a long time to scan or the call might block while the scanner shows
|
||||
* its UI so if the user were to download many files that finished around the
|
||||
* same time, they would have to wait a while if the scanning were done on
|
||||
* exactly one other thread. Since the overhead of creating a thread is
|
||||
* relatively small compared to the time it takes to download a file and scan
|
||||
* it, a new thread is spawned for each download that is to be scanned. Since
|
||||
* most of the mozilla codebase is not threadsafe, all the information needed
|
||||
* for the scanner is gathered in the main thread in nsDownloadScanner::Scan::Start.
|
||||
* The only function of nsDownloadScanner::Scan which is invoked on another
|
||||
* thread is DoScan.
|
||||
*
|
||||
* Watchdog overview
|
||||
*
|
||||
* The watchdog is used internally by the scanner. It maintains a queue of
|
||||
* current download scans. In a separate thread, it dequeues the oldest scan
|
||||
* and waits on that scan's thread with a timeout given by WATCHDOG_TIMEOUT
|
||||
* (default is 30 seconds). If the wait times out, then the watchdog notifies
|
||||
* the Scan that it has timed out. If the scan really has timed out, then the
|
||||
* Scan object will dispatch its run method to the main thread; this will
|
||||
* release the watchdog thread's addref on the Scan. If it has not timed out
|
||||
* (i.e. the Scan just finished in time), then the watchdog dispatches a
|
||||
* ReleaseDispatcher to release its ref of the Scan on the main thread.
|
||||
*
|
||||
* In order to minimize execution time, there are two events used to notify the
|
||||
* watchdog thread of a non-empty queue and a quit event. Every blocking wait
|
||||
* that the watchdog thread does waits on the quit event; this lets the thread
|
||||
* quickly exit when shutting down. Also, the download scan queue will be empty
|
||||
* most of the time; rather than use a spin loop, a simple event is triggered
|
||||
* by the main thread when a new scan is added to an empty queue. When the
|
||||
* watchdog thread knows that it has run out of elements in the queue, it will
|
||||
* wait on the new item event.
|
||||
*
|
||||
* Memory/resource leaks due to timeout:
|
||||
* In the event of a timeout, the thread must remain alive; terminating it may
|
||||
* very well cause the antivirus scanner to crash or be put into an
|
||||
* inconsistent state; COM resources may also not be cleaned up. The downside
|
||||
* is that we need to leave the thread running; suspending it may lead to a
|
||||
* deadlock. Because the scan call may be ongoing, it may be dependent on the
|
||||
* memory referenced by the MSOAVINFO structure, so we cannot free mName, mPath
|
||||
* or mOrigin; this means that we cannot free the Scan object since doing so
|
||||
* will deallocate that memory. Note that mDownload is set to null upon timeout
|
||||
* or completion, so the download itself is never leaked. If the scan does
|
||||
* eventually complete, then the all the memory and resources will be freed.
|
||||
* It is possible, however extremely rare, that in the event of a timeout, the
|
||||
* mStateSync critical section will leak its event; this will happen only if
|
||||
* the scanning thread, watchdog thread or main thread try to enter the
|
||||
* critical section when one of the others is already in it.
|
||||
*
|
||||
* Reasoning for CheckAndSetState - there exists a race condition between the time when
|
||||
* either the timeout or normal scan sets the state and when Scan::Run is
|
||||
* executed on the main thread. Ex: mStatus could be set by Scan::DoScan* which
|
||||
* then queues a dispatch on the main thread. Before that dispatch is executed,
|
||||
* the timeout code fires and sets mStatus to AVSCAN_TIMEDOUT which then queues
|
||||
* its dispatch to the main thread (the same function as DoScan*). Both
|
||||
* dispatches run and both try to set the download state to AVSCAN_TIMEDOUT
|
||||
* which is incorrect.
|
||||
*
|
||||
* There are 5 possible outcomes of the virus scan:
|
||||
* AVSCAN_GOOD => the file is clean
|
||||
* AVSCAN_BAD => the file has a virus
|
||||
* AVSCAN_UGLY => the file had a virus, but it was cleaned
|
||||
* AVSCAN_FAILED => something else went wrong with the virus scanner.
|
||||
* AVSCAN_TIMEDOUT => the scan (thread setup + execution) took too long
|
||||
*
|
||||
* Both the good and ugly states leave the user with a benign file, so they
|
||||
* transition to the finished state. Bad files are sent to the blocked state.
|
||||
* The failed and timedout states transition to finished downloads.
|
||||
*
|
||||
* Possible Future enhancements:
|
||||
* * Create an interface for scanning files in general
|
||||
* * Make this a service
|
||||
* * Get antivirus scanner status via WMI/registry
|
||||
*/
|
||||
|
||||
// IAttachementExecute supports user definable settings for certain
|
||||
// security related prompts. This defines a general GUID for use in
|
||||
// all projects. Individual projects can define an individual guid
|
||||
// if they want to.
|
||||
#ifndef MOZ_VIRUS_SCANNER_PROMPT_GUID
|
||||
#define MOZ_VIRUS_SCANNER_PROMPT_GUID \
|
||||
{ 0xb50563d1, 0x16b6, 0x43c2, { 0xa6, 0x6a, 0xfa, 0xe6, 0xd2, 0x11, 0xf2, \
|
||||
0xea } }
|
||||
#endif
|
||||
static const GUID GUID_MozillaVirusScannerPromptGeneric =
|
||||
MOZ_VIRUS_SCANNER_PROMPT_GUID;
|
||||
|
||||
// Initial timeout is 30 seconds
|
||||
#define WATCHDOG_TIMEOUT (30*PR_USEC_PER_SEC)
|
||||
|
||||
// Maximum length for URI's passed into IAE
|
||||
#define MAX_IAEURILENGTH 1683
|
||||
|
||||
class nsDownloadScannerWatchdog
|
||||
{
|
||||
typedef nsDownloadScanner::Scan Scan;
|
||||
public:
|
||||
nsDownloadScannerWatchdog();
|
||||
~nsDownloadScannerWatchdog();
|
||||
|
||||
nsresult Init();
|
||||
nsresult Shutdown();
|
||||
|
||||
void Watch(Scan *scan);
|
||||
private:
|
||||
static unsigned int __stdcall WatchdogThread(void *p);
|
||||
CRITICAL_SECTION mQueueSync;
|
||||
nsDeque mScanQueue;
|
||||
HANDLE mThread;
|
||||
HANDLE mNewItemEvent;
|
||||
HANDLE mQuitEvent;
|
||||
};
|
||||
|
||||
nsDownloadScanner::nsDownloadScanner() :
|
||||
mAESExists(false)
|
||||
{
|
||||
}
|
||||
|
||||
// This destructor appeases the compiler; it would otherwise complain about an
|
||||
// incomplete type for nsDownloadWatchdog in the instantiation of
|
||||
// nsAutoPtr::~nsAutoPtr
|
||||
// Plus, it's a handy location to call nsDownloadScannerWatchdog::Shutdown from
|
||||
nsDownloadScanner::~nsDownloadScanner() {
|
||||
if (mWatchdog)
|
||||
(void)mWatchdog->Shutdown();
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDownloadScanner::Init()
|
||||
{
|
||||
// This CoInitialize/CoUninitialize pattern seems to be common in the Mozilla
|
||||
// codebase. All other COM calls/objects are made on different threads.
|
||||
nsresult rv = NS_OK;
|
||||
CoInitialize(nullptr);
|
||||
|
||||
if (!IsAESAvailable()) {
|
||||
CoUninitialize();
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
mAESExists = true;
|
||||
|
||||
// Initialize scanning
|
||||
mWatchdog = new nsDownloadScannerWatchdog();
|
||||
if (mWatchdog) {
|
||||
rv = mWatchdog->Init();
|
||||
if (FAILED(rv))
|
||||
mWatchdog = nullptr;
|
||||
} else {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
bool
|
||||
nsDownloadScanner::IsAESAvailable()
|
||||
{
|
||||
// Try to instantiate IAE to see if it's available.
|
||||
RefPtr<IAttachmentExecute> ae;
|
||||
HRESULT hr;
|
||||
hr = CoCreateInstance(CLSID_AttachmentServices, nullptr, CLSCTX_INPROC,
|
||||
IID_IAttachmentExecute, getter_AddRefs(ae));
|
||||
if (FAILED(hr)) {
|
||||
NS_WARNING("Could not instantiate attachment execution service\n");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// If IAttachementExecute is available, use the CheckPolicy call to find out
|
||||
// if this download should be prevented due to Security Zone Policy settings.
|
||||
AVCheckPolicyState
|
||||
nsDownloadScanner::CheckPolicy(nsIURI *aSource, nsIURI *aTarget)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
if (!mAESExists || !aSource || !aTarget)
|
||||
return AVPOLICY_DOWNLOAD;
|
||||
|
||||
nsAutoCString source;
|
||||
rv = aSource->GetSpec(source);
|
||||
if (NS_FAILED(rv))
|
||||
return AVPOLICY_DOWNLOAD;
|
||||
|
||||
nsCOMPtr<nsIFileURL> fileUrl(do_QueryInterface(aTarget));
|
||||
if (!fileUrl)
|
||||
return AVPOLICY_DOWNLOAD;
|
||||
|
||||
nsCOMPtr<nsIFile> theFile;
|
||||
nsAutoString aFileName;
|
||||
if (NS_FAILED(fileUrl->GetFile(getter_AddRefs(theFile))) ||
|
||||
NS_FAILED(theFile->GetLeafName(aFileName)))
|
||||
return AVPOLICY_DOWNLOAD;
|
||||
|
||||
// IAttachementExecute prohibits src data: schemes by default but we
|
||||
// support them. If this is a data src, skip off doing a policy check.
|
||||
// (The file will still be scanned once it lands on the local system.)
|
||||
bool isDataScheme(false);
|
||||
nsCOMPtr<nsIURI> innerURI = NS_GetInnermostURI(aSource);
|
||||
if (innerURI)
|
||||
(void)innerURI->SchemeIs("data", &isDataScheme);
|
||||
if (isDataScheme)
|
||||
return AVPOLICY_DOWNLOAD;
|
||||
|
||||
RefPtr<IAttachmentExecute> ae;
|
||||
HRESULT hr;
|
||||
hr = CoCreateInstance(CLSID_AttachmentServices, nullptr, CLSCTX_INPROC,
|
||||
IID_IAttachmentExecute, getter_AddRefs(ae));
|
||||
if (FAILED(hr))
|
||||
return AVPOLICY_DOWNLOAD;
|
||||
|
||||
(void)ae->SetClientGuid(GUID_MozillaVirusScannerPromptGeneric);
|
||||
(void)ae->SetSource(NS_ConvertUTF8toUTF16(source).get());
|
||||
(void)ae->SetFileName(aFileName.get());
|
||||
|
||||
// Any failure means the file download/exec will be blocked by the system.
|
||||
// S_OK or S_FALSE imply it's ok.
|
||||
hr = ae->CheckPolicy();
|
||||
|
||||
if (hr == S_OK)
|
||||
return AVPOLICY_DOWNLOAD;
|
||||
|
||||
if (hr == S_FALSE)
|
||||
return AVPOLICY_PROMPT;
|
||||
|
||||
if (hr == E_INVALIDARG)
|
||||
return AVPOLICY_PROMPT;
|
||||
|
||||
return AVPOLICY_BLOCKED;
|
||||
}
|
||||
|
||||
#ifndef THREAD_MODE_BACKGROUND_BEGIN
|
||||
#define THREAD_MODE_BACKGROUND_BEGIN 0x00010000
|
||||
#endif
|
||||
|
||||
#ifndef THREAD_MODE_BACKGROUND_END
|
||||
#define THREAD_MODE_BACKGROUND_END 0x00020000
|
||||
#endif
|
||||
|
||||
unsigned int __stdcall
|
||||
nsDownloadScanner::ScannerThreadFunction(void *p)
|
||||
{
|
||||
HANDLE currentThread = GetCurrentThread();
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Antivirus scan should not be run on the main thread");
|
||||
nsDownloadScanner::Scan *scan = static_cast<nsDownloadScanner::Scan*>(p);
|
||||
if (!SetThreadPriority(currentThread, THREAD_MODE_BACKGROUND_BEGIN))
|
||||
(void)SetThreadPriority(currentThread, THREAD_PRIORITY_IDLE);
|
||||
scan->DoScan();
|
||||
(void)SetThreadPriority(currentThread, THREAD_MODE_BACKGROUND_END);
|
||||
_endthreadex(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// The sole purpose of this class is to release an object on the main thread
|
||||
// It assumes that its creator will addref it and it will release itself on
|
||||
// the main thread too
|
||||
class ReleaseDispatcher : public mozilla::Runnable {
|
||||
public:
|
||||
explicit ReleaseDispatcher(nsISupports *ptr)
|
||||
: mPtr(ptr) {}
|
||||
NS_IMETHOD Run();
|
||||
private:
|
||||
nsISupports *mPtr;
|
||||
};
|
||||
|
||||
nsresult ReleaseDispatcher::Run() {
|
||||
NS_ASSERTION(NS_IsMainThread(), "Antivirus scan release dispatch should be run on the main thread");
|
||||
NS_RELEASE(mPtr);
|
||||
NS_RELEASE_THIS();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsDownloadScanner::Scan::Scan(nsDownloadScanner *scanner, nsDownload *download)
|
||||
: mDLScanner(scanner), mThread(nullptr),
|
||||
mDownload(download), mStatus(AVSCAN_NOTSTARTED),
|
||||
mSkipSource(false)
|
||||
{
|
||||
InitializeCriticalSection(&mStateSync);
|
||||
}
|
||||
|
||||
nsDownloadScanner::Scan::~Scan() {
|
||||
DeleteCriticalSection(&mStateSync);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDownloadScanner::Scan::Start()
|
||||
{
|
||||
mStartTime = PR_Now();
|
||||
|
||||
mThread = (HANDLE)_beginthreadex(nullptr, 0, ScannerThreadFunction,
|
||||
this, CREATE_SUSPENDED, nullptr);
|
||||
if (!mThread)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
// Get the path to the file on disk
|
||||
nsCOMPtr<nsIFile> file;
|
||||
rv = mDownload->GetTargetFile(getter_AddRefs(file));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = file->GetPath(mPath);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Grab the app name
|
||||
nsCOMPtr<nsIXULAppInfo> appinfo =
|
||||
do_GetService(XULAPPINFO_SERVICE_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsAutoCString name;
|
||||
rv = appinfo->GetName(name);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
CopyUTF8toUTF16(name, mName);
|
||||
|
||||
// Get the origin
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
rv = mDownload->GetSource(getter_AddRefs(uri));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsAutoCString origin;
|
||||
rv = uri->GetSpec(origin);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Certain virus interfaces do not like extremely long uris.
|
||||
// Chop off the path and cgi data and just pass the base domain.
|
||||
if (origin.Length() > MAX_IAEURILENGTH) {
|
||||
rv = uri->GetPrePath(origin);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
CopyUTF8toUTF16(origin, mOrigin);
|
||||
|
||||
// We count https/ftp/http as an http download
|
||||
bool isHttp(false), isFtp(false), isHttps(false);
|
||||
nsCOMPtr<nsIURI> innerURI = NS_GetInnermostURI(uri);
|
||||
if (!innerURI) innerURI = uri;
|
||||
(void)innerURI->SchemeIs("http", &isHttp);
|
||||
(void)innerURI->SchemeIs("ftp", &isFtp);
|
||||
(void)innerURI->SchemeIs("https", &isHttps);
|
||||
mIsHttpDownload = isHttp || isFtp || isHttps;
|
||||
|
||||
// IAttachementExecute prohibits src data: schemes by default but we
|
||||
// support them. Mark the download if it's a data scheme, so we
|
||||
// can skip off supplying the src to IAttachementExecute when we scan
|
||||
// the resulting file.
|
||||
(void)innerURI->SchemeIs("data", &mSkipSource);
|
||||
|
||||
// ResumeThread returns the previous suspend count
|
||||
if (1 != ::ResumeThread(mThread)) {
|
||||
CloseHandle(mThread);
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDownloadScanner::Scan::Run()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Antivirus scan dispatch should be run on the main thread");
|
||||
|
||||
// Cleanup our thread
|
||||
if (mStatus != AVSCAN_TIMEDOUT)
|
||||
WaitForSingleObject(mThread, INFINITE);
|
||||
CloseHandle(mThread);
|
||||
|
||||
DownloadState downloadState = 0;
|
||||
EnterCriticalSection(&mStateSync);
|
||||
switch (mStatus) {
|
||||
case AVSCAN_BAD:
|
||||
downloadState = nsIDownloadManager::DOWNLOAD_DIRTY;
|
||||
break;
|
||||
default:
|
||||
case AVSCAN_FAILED:
|
||||
case AVSCAN_GOOD:
|
||||
case AVSCAN_UGLY:
|
||||
case AVSCAN_TIMEDOUT:
|
||||
downloadState = nsIDownloadManager::DOWNLOAD_FINISHED;
|
||||
break;
|
||||
}
|
||||
LeaveCriticalSection(&mStateSync);
|
||||
// Download will be null if we already timed out
|
||||
if (mDownload)
|
||||
(void)mDownload->SetState(downloadState);
|
||||
|
||||
// Clean up some other variables
|
||||
// In the event of a timeout, our destructor won't be called
|
||||
mDownload = nullptr;
|
||||
|
||||
NS_RELEASE_THIS();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static DWORD
|
||||
ExceptionFilterFunction(DWORD exceptionCode) {
|
||||
switch(exceptionCode) {
|
||||
case EXCEPTION_ACCESS_VIOLATION:
|
||||
case EXCEPTION_ILLEGAL_INSTRUCTION:
|
||||
case EXCEPTION_IN_PAGE_ERROR:
|
||||
case EXCEPTION_PRIV_INSTRUCTION:
|
||||
case EXCEPTION_STACK_OVERFLOW:
|
||||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
default:
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
nsDownloadScanner::Scan::DoScanAES()
|
||||
{
|
||||
// This warning is for the destructor of ae which will not be invoked in the
|
||||
// event of a win32 exception
|
||||
#pragma warning(disable: 4509)
|
||||
HRESULT hr;
|
||||
RefPtr<IAttachmentExecute> ae;
|
||||
MOZ_SEH_TRY {
|
||||
hr = CoCreateInstance(CLSID_AttachmentServices, nullptr, CLSCTX_ALL,
|
||||
IID_IAttachmentExecute, getter_AddRefs(ae));
|
||||
} MOZ_SEH_EXCEPT(ExceptionFilterFunction(GetExceptionCode())) {
|
||||
return CheckAndSetState(AVSCAN_NOTSTARTED,AVSCAN_FAILED);
|
||||
}
|
||||
|
||||
// If we (somehow) already timed out, then don't bother scanning
|
||||
if (CheckAndSetState(AVSCAN_SCANNING, AVSCAN_NOTSTARTED)) {
|
||||
AVScanState newState;
|
||||
if (SUCCEEDED(hr)) {
|
||||
bool gotException = false;
|
||||
MOZ_SEH_TRY {
|
||||
(void)ae->SetClientGuid(GUID_MozillaVirusScannerPromptGeneric);
|
||||
(void)ae->SetLocalPath(mPath.get());
|
||||
// Provide the src for everything but data: schemes.
|
||||
if (!mSkipSource)
|
||||
(void)ae->SetSource(mOrigin.get());
|
||||
|
||||
// Save() will invoke the scanner
|
||||
hr = ae->Save();
|
||||
} MOZ_SEH_EXCEPT(ExceptionFilterFunction(GetExceptionCode())) {
|
||||
gotException = true;
|
||||
}
|
||||
|
||||
MOZ_SEH_TRY {
|
||||
ae = nullptr;
|
||||
} MOZ_SEH_EXCEPT(ExceptionFilterFunction(GetExceptionCode())) {
|
||||
gotException = true;
|
||||
}
|
||||
|
||||
if(gotException) {
|
||||
newState = AVSCAN_FAILED;
|
||||
}
|
||||
else if (SUCCEEDED(hr)) { // Passed the scan
|
||||
newState = AVSCAN_GOOD;
|
||||
}
|
||||
else if (HRESULT_CODE(hr) == ERROR_FILE_NOT_FOUND) {
|
||||
NS_WARNING("Downloaded file disappeared before it could be scanned");
|
||||
newState = AVSCAN_FAILED;
|
||||
}
|
||||
else if (hr == E_INVALIDARG) {
|
||||
NS_WARNING("IAttachementExecute returned invalid argument error");
|
||||
newState = AVSCAN_FAILED;
|
||||
}
|
||||
else {
|
||||
newState = AVSCAN_UGLY;
|
||||
}
|
||||
}
|
||||
else {
|
||||
newState = AVSCAN_FAILED;
|
||||
}
|
||||
return CheckAndSetState(newState, AVSCAN_SCANNING);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#pragma warning(default: 4509)
|
||||
|
||||
void
|
||||
nsDownloadScanner::Scan::DoScan()
|
||||
{
|
||||
CoInitialize(nullptr);
|
||||
|
||||
if (DoScanAES()) {
|
||||
// We need to do a few more things on the main thread
|
||||
NS_DispatchToMainThread(this);
|
||||
} else {
|
||||
// We timed out, so just release
|
||||
ReleaseDispatcher* releaser = new ReleaseDispatcher(ToSupports(this));
|
||||
if(releaser) {
|
||||
NS_ADDREF(releaser);
|
||||
NS_DispatchToMainThread(releaser);
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_SEH_TRY {
|
||||
CoUninitialize();
|
||||
} MOZ_SEH_EXCEPT(ExceptionFilterFunction(GetExceptionCode())) {
|
||||
// Not much we can do at this point...
|
||||
}
|
||||
}
|
||||
|
||||
HANDLE
|
||||
nsDownloadScanner::Scan::GetWaitableThreadHandle() const
|
||||
{
|
||||
HANDLE targetHandle = INVALID_HANDLE_VALUE;
|
||||
(void)DuplicateHandle(GetCurrentProcess(), mThread,
|
||||
GetCurrentProcess(), &targetHandle,
|
||||
SYNCHRONIZE, // Only allow clients to wait on this handle
|
||||
FALSE, // cannot be inherited by child processes
|
||||
0);
|
||||
return targetHandle;
|
||||
}
|
||||
|
||||
bool
|
||||
nsDownloadScanner::Scan::NotifyTimeout()
|
||||
{
|
||||
bool didTimeout = CheckAndSetState(AVSCAN_TIMEDOUT, AVSCAN_SCANNING) ||
|
||||
CheckAndSetState(AVSCAN_TIMEDOUT, AVSCAN_NOTSTARTED);
|
||||
if (didTimeout) {
|
||||
// We need to do a few more things on the main thread
|
||||
NS_DispatchToMainThread(this);
|
||||
}
|
||||
return didTimeout;
|
||||
}
|
||||
|
||||
bool
|
||||
nsDownloadScanner::Scan::CheckAndSetState(AVScanState newState, AVScanState expectedState) {
|
||||
bool gotExpectedState = false;
|
||||
EnterCriticalSection(&mStateSync);
|
||||
if((gotExpectedState = (mStatus == expectedState)))
|
||||
mStatus = newState;
|
||||
LeaveCriticalSection(&mStateSync);
|
||||
return gotExpectedState;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDownloadScanner::ScanDownload(nsDownload *download)
|
||||
{
|
||||
if (!mAESExists)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
// No ref ptr, see comment below
|
||||
Scan *scan = new Scan(this, download);
|
||||
if (!scan)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
NS_ADDREF(scan);
|
||||
|
||||
nsresult rv = scan->Start();
|
||||
|
||||
// Note that we only release upon error. On success, the scan is passed off
|
||||
// to a new thread. It is eventually released in Scan::Run on the main thread.
|
||||
if (NS_FAILED(rv))
|
||||
NS_RELEASE(scan);
|
||||
else
|
||||
// Notify the watchdog
|
||||
mWatchdog->Watch(scan);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsDownloadScannerWatchdog::nsDownloadScannerWatchdog()
|
||||
: mNewItemEvent(nullptr), mQuitEvent(nullptr) {
|
||||
InitializeCriticalSection(&mQueueSync);
|
||||
}
|
||||
nsDownloadScannerWatchdog::~nsDownloadScannerWatchdog() {
|
||||
DeleteCriticalSection(&mQueueSync);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDownloadScannerWatchdog::Init() {
|
||||
// Both events are auto-reset
|
||||
mNewItemEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
||||
if (INVALID_HANDLE_VALUE == mNewItemEvent)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
mQuitEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
||||
if (INVALID_HANDLE_VALUE == mQuitEvent) {
|
||||
(void)CloseHandle(mNewItemEvent);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// This thread is always running, however it will be asleep
|
||||
// for most of the dlmgr's lifetime
|
||||
mThread = (HANDLE)_beginthreadex(nullptr, 0, WatchdogThread,
|
||||
this, 0, nullptr);
|
||||
if (!mThread) {
|
||||
(void)CloseHandle(mNewItemEvent);
|
||||
(void)CloseHandle(mQuitEvent);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDownloadScannerWatchdog::Shutdown() {
|
||||
// Tell the watchdog thread to quite
|
||||
(void)SetEvent(mQuitEvent);
|
||||
(void)WaitForSingleObject(mThread, INFINITE);
|
||||
(void)CloseHandle(mThread);
|
||||
// Manually clear and release the queued scans
|
||||
while (mScanQueue.GetSize() != 0) {
|
||||
Scan *scan = reinterpret_cast<Scan*>(mScanQueue.Pop());
|
||||
NS_RELEASE(scan);
|
||||
}
|
||||
(void)CloseHandle(mNewItemEvent);
|
||||
(void)CloseHandle(mQuitEvent);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsDownloadScannerWatchdog::Watch(Scan *scan) {
|
||||
bool wasEmpty;
|
||||
// Note that there is no release in this method
|
||||
// The scan will be released by the watchdog ALWAYS on the main thread
|
||||
// when either the watchdog thread processes the scan or the watchdog
|
||||
// is shut down
|
||||
NS_ADDREF(scan);
|
||||
EnterCriticalSection(&mQueueSync);
|
||||
wasEmpty = mScanQueue.GetSize()==0;
|
||||
mScanQueue.Push(scan);
|
||||
LeaveCriticalSection(&mQueueSync);
|
||||
// If the queue was empty, then the watchdog thread is/will be asleep
|
||||
if (wasEmpty)
|
||||
(void)SetEvent(mNewItemEvent);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
__stdcall
|
||||
nsDownloadScannerWatchdog::WatchdogThread(void *p) {
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Antivirus scan watchdog should not be run on the main thread");
|
||||
nsDownloadScannerWatchdog *watchdog = (nsDownloadScannerWatchdog*)p;
|
||||
HANDLE waitHandles[3] = {watchdog->mNewItemEvent, watchdog->mQuitEvent, INVALID_HANDLE_VALUE};
|
||||
DWORD waitStatus;
|
||||
DWORD queueItemsLeft = 0;
|
||||
// Loop until quit event or error
|
||||
while (0 != queueItemsLeft ||
|
||||
((WAIT_OBJECT_0 + 1) !=
|
||||
(waitStatus =
|
||||
WaitForMultipleObjects(2, waitHandles, FALSE, INFINITE)) &&
|
||||
waitStatus != WAIT_FAILED)) {
|
||||
Scan *scan = nullptr;
|
||||
PRTime startTime, expectedEndTime, now;
|
||||
DWORD waitTime;
|
||||
|
||||
// Pop scan from queue
|
||||
EnterCriticalSection(&watchdog->mQueueSync);
|
||||
scan = reinterpret_cast<Scan*>(watchdog->mScanQueue.Pop());
|
||||
queueItemsLeft = watchdog->mScanQueue.GetSize();
|
||||
LeaveCriticalSection(&watchdog->mQueueSync);
|
||||
|
||||
// Calculate expected end time
|
||||
startTime = scan->GetStartTime();
|
||||
expectedEndTime = WATCHDOG_TIMEOUT + startTime;
|
||||
now = PR_Now();
|
||||
// PRTime is not guaranteed to be a signed integral type (afaik), but
|
||||
// currently it is
|
||||
if (now > expectedEndTime) {
|
||||
waitTime = 0;
|
||||
} else {
|
||||
// This is a positive value, and we know that it will not overflow
|
||||
// (bounded by WATCHDOG_TIMEOUT)
|
||||
// waitTime is in milliseconds, nspr uses microseconds
|
||||
waitTime = static_cast<DWORD>((expectedEndTime - now)/PR_USEC_PER_MSEC);
|
||||
}
|
||||
HANDLE hThread = waitHandles[2] = scan->GetWaitableThreadHandle();
|
||||
|
||||
// Wait for the thread (obj 1) or quit event (obj 0)
|
||||
waitStatus = WaitForMultipleObjects(2, (waitHandles+1), FALSE, waitTime);
|
||||
CloseHandle(hThread);
|
||||
|
||||
ReleaseDispatcher* releaser = new ReleaseDispatcher(ToSupports(scan));
|
||||
if(!releaser)
|
||||
continue;
|
||||
NS_ADDREF(releaser);
|
||||
// Got quit event or error
|
||||
if (waitStatus == WAIT_FAILED || waitStatus == WAIT_OBJECT_0) {
|
||||
NS_DispatchToMainThread(releaser);
|
||||
break;
|
||||
// Thread exited normally
|
||||
} else if (waitStatus == (WAIT_OBJECT_0+1)) {
|
||||
NS_DispatchToMainThread(releaser);
|
||||
continue;
|
||||
// Timeout case
|
||||
} else {
|
||||
NS_ASSERTION(waitStatus == WAIT_TIMEOUT, "Unexpected wait status in dlmgr watchdog thread");
|
||||
if (!scan->NotifyTimeout()) {
|
||||
// If we didn't time out, then release the thread
|
||||
NS_DispatchToMainThread(releaser);
|
||||
} else {
|
||||
// NotifyTimeout did a dispatch which will release the scan, so we
|
||||
// don't need to release the scan
|
||||
NS_RELEASE(releaser);
|
||||
}
|
||||
}
|
||||
}
|
||||
_endthreadex(0);
|
||||
return 0;
|
||||
}
|
|
@ -1,121 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* vim: se cin sw=2 ts=2 et : */
|
||||
|
||||
#ifndef nsDownloadScanner_h_
|
||||
#define nsDownloadScanner_h_
|
||||
|
||||
#ifdef WIN32_LEAN_AND_MEAN
|
||||
#undef WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#define AVVENDOR
|
||||
#include <objidl.h>
|
||||
#include <msoav.h>
|
||||
#include <shlobj.h>
|
||||
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsIURI.h"
|
||||
|
||||
enum AVScanState
|
||||
{
|
||||
AVSCAN_NOTSTARTED = 0,
|
||||
AVSCAN_SCANNING,
|
||||
AVSCAN_GOOD,
|
||||
AVSCAN_BAD,
|
||||
AVSCAN_UGLY,
|
||||
AVSCAN_FAILED,
|
||||
AVSCAN_TIMEDOUT
|
||||
};
|
||||
|
||||
enum AVCheckPolicyState
|
||||
{
|
||||
AVPOLICY_DOWNLOAD,
|
||||
AVPOLICY_PROMPT,
|
||||
AVPOLICY_BLOCKED
|
||||
};
|
||||
|
||||
// See nsDownloadScanner.cpp for declaration and definition
|
||||
class nsDownloadScannerWatchdog;
|
||||
class nsDownload;
|
||||
|
||||
class nsDownloadScanner
|
||||
{
|
||||
public:
|
||||
nsDownloadScanner();
|
||||
~nsDownloadScanner();
|
||||
nsresult Init();
|
||||
nsresult ScanDownload(nsDownload *download);
|
||||
AVCheckPolicyState CheckPolicy(nsIURI *aSource, nsIURI *aTarget);
|
||||
|
||||
private:
|
||||
bool mAESExists;
|
||||
nsTArray<CLSID> mScanCLSID;
|
||||
bool IsAESAvailable();
|
||||
bool EnumerateOAVProviders();
|
||||
|
||||
nsAutoPtr<nsDownloadScannerWatchdog> mWatchdog;
|
||||
|
||||
static unsigned int __stdcall ScannerThreadFunction(void *p);
|
||||
class Scan : public mozilla::Runnable
|
||||
{
|
||||
public:
|
||||
Scan(nsDownloadScanner *scanner, nsDownload *download);
|
||||
~Scan();
|
||||
nsresult Start();
|
||||
|
||||
// Returns the time that Start was called
|
||||
PRTime GetStartTime() const { return mStartTime; }
|
||||
// Returns a copy of the thread handle that can be waited on, but not
|
||||
// terminated
|
||||
// The caller is responsible for closing the handle
|
||||
// If the thread has terminated, then this will return the pseudo-handle
|
||||
// INVALID_HANDLE_VALUE
|
||||
HANDLE GetWaitableThreadHandle() const;
|
||||
|
||||
// Called on a secondary thread to notify the scan that it has timed out
|
||||
// this is used only by the watchdog thread
|
||||
bool NotifyTimeout();
|
||||
|
||||
private:
|
||||
nsDownloadScanner *mDLScanner;
|
||||
PRTime mStartTime;
|
||||
HANDLE mThread;
|
||||
RefPtr<nsDownload> mDownload;
|
||||
// Guards mStatus
|
||||
CRITICAL_SECTION mStateSync;
|
||||
AVScanState mStatus;
|
||||
nsString mPath;
|
||||
nsString mName;
|
||||
nsString mOrigin;
|
||||
// Also true if it is an ftp download
|
||||
bool mIsHttpDownload;
|
||||
bool mSkipSource;
|
||||
|
||||
/* @summary Sets the Scan's state to newState if the current state is
|
||||
expectedState
|
||||
* @param newState The new state of the scan
|
||||
* @param expectedState The state that the caller expects the scan to be in
|
||||
* @return If the old state matched expectedState
|
||||
*/
|
||||
bool CheckAndSetState(AVScanState newState, AVScanState expectedState);
|
||||
|
||||
NS_IMETHOD Run();
|
||||
|
||||
void DoScan();
|
||||
bool DoScanAES();
|
||||
bool DoScanOAV();
|
||||
|
||||
friend unsigned int __stdcall nsDownloadScanner::ScannerThreadFunction(void *);
|
||||
};
|
||||
// Used to give access to Scan
|
||||
friend class nsDownloadScannerWatchdog;
|
||||
};
|
||||
#endif
|
||||
|
|
@ -25,8 +25,6 @@
|
|||
|
||||
using namespace mozilla::storage;
|
||||
|
||||
// Keep the GUID-related parts of this file in sync with toolkit/downloads/SQLFunctions.cpp!
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Anonymous Helpers
|
||||
|
||||
|
|
|
@ -4,14 +4,13 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsBrowserStatusFilter.h"
|
||||
#include "mozilla/SystemGroup.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsString.h"
|
||||
|
||||
// XXX
|
||||
// XXX DO NOT TOUCH THIS CODE UNLESS YOU KNOW WHAT YOU'RE DOING !!!
|
||||
// XXX
|
||||
using namespace mozilla;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsBrowserStatusFilter <public>
|
||||
|
@ -355,6 +354,9 @@ nsBrowserStatusFilter::StartDelayTimer()
|
|||
if (!mTimer)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// Use the system group. The browser status filter is always used by chrome
|
||||
// code.
|
||||
mTimer->SetTarget(SystemGroup::EventTargetFor(TaskCategory::Other));
|
||||
return mTimer->InitWithNamedFuncCallback(
|
||||
TimeoutHandler, this, 160, nsITimer::TYPE_ONE_SHOT,
|
||||
"nsBrowserStatusFilter::TimeoutHandler");
|
||||
|
|
|
@ -13072,5 +13072,15 @@
|
|||
"n_buckets": 100,
|
||||
"bug_numbers": [1345540],
|
||||
"description": "Time (ms) for the APZ handled wheel event spent in handlers."
|
||||
},
|
||||
"TIME_BETWEEN_UNLABELED_RUNNABLES_MS": {
|
||||
"record_in_processes": ["content"],
|
||||
"alert_emails": ["wmccloskey@mozilla.com"],
|
||||
"expires_in_version": "60",
|
||||
"kind": "exponential",
|
||||
"high": 30000,
|
||||
"n_buckets": 30,
|
||||
"bug_numbers": [1351021],
|
||||
"description": "Every time we run an unlabeled runnable, this histogram records the time (in ms) since the last unlabeled runnable ran."
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "mozilla/gfx/GPUProcessManager.h"
|
||||
#include "mozilla/StaticMutex.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/SystemGroup.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsITimer.h"
|
||||
|
@ -21,6 +22,8 @@
|
|||
using mozilla::StaticMutex;
|
||||
using mozilla::StaticMutexAutoLock;
|
||||
using mozilla::StaticAutoPtr;
|
||||
using mozilla::SystemGroup;
|
||||
using mozilla::TaskCategory;
|
||||
using mozilla::Telemetry::Accumulation;
|
||||
using mozilla::Telemetry::KeyedAccumulation;
|
||||
using mozilla::Telemetry::ScalarActionType;
|
||||
|
@ -80,6 +83,7 @@ DoArmIPCTimerMainThread(const StaticMutexAutoLock& lock)
|
|||
CallCreateInstance(NS_TIMER_CONTRACTID, &gIPCTimer);
|
||||
}
|
||||
if (gIPCTimer) {
|
||||
gIPCTimer->SetTarget(SystemGroup::EventTargetFor(TaskCategory::Other));
|
||||
gIPCTimer->InitWithNamedFuncCallback(TelemetryIPCAccumulator::IPCTimerFired,
|
||||
nullptr, kBatchTimeoutMs,
|
||||
nsITimer::TYPE_ONE_SHOT,
|
||||
|
@ -321,12 +325,6 @@ TelemetryIPCAccumulator::DeInitializeGlobalState()
|
|||
void
|
||||
TelemetryIPCAccumulator::DispatchToMainThread(already_AddRefed<nsIRunnable>&& aEvent)
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> event(aEvent);
|
||||
nsCOMPtr<nsIThread> thread;
|
||||
nsresult rv = NS_GetMainThread(getter_AddRefs(thread));
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("NS_FAILED DispatchToMainThread. Maybe we're shutting down?");
|
||||
return;
|
||||
}
|
||||
thread->Dispatch(event, 0);
|
||||
SystemGroup::EventTargetFor(TaskCategory::Other)->Dispatch(Move(aEvent),
|
||||
nsIEventTarget::DISPATCH_NORMAL);
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsISelectionController.h"
|
||||
#include "nsIController.h"
|
||||
|
|
|
@ -136,6 +136,9 @@ var WebProgressListener = {
|
|||
this._send("Content:StateChange", json, objects);
|
||||
},
|
||||
|
||||
// Note: Because the nsBrowserStatusFilter timeout runnable is
|
||||
// SystemGroup-labeled, this method should not modify content DOM or
|
||||
// run content JS.
|
||||
onProgressChange: function onProgressChange(aWebProgress, aRequest, aCurSelf, aMaxSelf, aCurTotal, aMaxTotal) {
|
||||
let json = this._setupJSON(aWebProgress, aRequest);
|
||||
let objects = this._setupObjects(aWebProgress, aRequest);
|
||||
|
@ -186,6 +189,9 @@ var WebProgressListener = {
|
|||
this._send("Content:LocationChange", json, objects);
|
||||
},
|
||||
|
||||
// Note: Because the nsBrowserStatusFilter timeout runnable is
|
||||
// SystemGroup-labeled, this method should not modify content DOM or
|
||||
// run content JS.
|
||||
onStatusChange: function onStatusChange(aWebProgress, aRequest, aStatus, aMessage) {
|
||||
let json = this._setupJSON(aWebProgress, aRequest);
|
||||
let objects = this._setupObjects(aWebProgress, aRequest);
|
||||
|
|
|
@ -4345,8 +4345,6 @@ struct kernel_statfs {
|
|||
loff_t, o)
|
||||
LSS_INLINE _syscall3(int, readahead, int, f,
|
||||
loff_t, o, unsigned, c)
|
||||
LSS_INLINE _syscall6(void *, mmap, void *, addr, size_t, length, int, prot,
|
||||
int, flags, int, fd, int64_t, offset)
|
||||
#else
|
||||
#define __NR__pread64 __NR_pread64
|
||||
#define __NR__pwrite64 __NR_pwrite64
|
||||
|
@ -4403,8 +4401,6 @@ struct kernel_statfs {
|
|||
|
||||
#if defined(__aarch64__)
|
||||
LSS_INLINE _syscall3(int, dup3, int, s, int, d, int, f)
|
||||
LSS_INLINE _syscall6(void *, mmap, void *, addr, size_t, length, int, prot,
|
||||
int, flags, int, fd, int64_t, offset)
|
||||
LSS_INLINE _syscall4(int, newfstatat, int, dirfd, const char *, pathname,
|
||||
struct kernel_stat *, buf, int, flags)
|
||||
LSS_INLINE _syscall2(int, pipe2, int *, pipefd, int, flags)
|
||||
|
|
|
@ -22,14 +22,6 @@ shortHours=h;h
|
|||
# d is the short form for days
|
||||
shortDays=d;d
|
||||
|
||||
# LOCALIZATION NOTE (paused): — is the "em dash" (long dash)
|
||||
paused=Paused — #1
|
||||
downloading=Downloading
|
||||
notStarted=Not Started
|
||||
failed=Failed
|
||||
finished=Finished
|
||||
canceled=Canceled
|
||||
|
||||
downloadErrorAlertTitle=Download Error
|
||||
downloadErrorGeneric=The download cannot be saved because an unknown error occurred.\n\nPlease try again.
|
||||
|
||||
|
@ -51,8 +43,6 @@ dontQuitButtonWin=Don’t Exit
|
|||
dontQuitButtonMac=Don’t Quit
|
||||
dontGoOfflineButton=Stay Online
|
||||
dontLeavePrivateBrowsingButton2=Stay in Private Browsing
|
||||
downloadsCompleteTitle=Downloads Complete
|
||||
downloadsCompleteMsg=All files have finished downloading.
|
||||
|
||||
# LOCALIZATION NOTE (infiniteRate):
|
||||
# If download speed is a JavaScript Infinity value, this phrase is used
|
||||
|
|
|
@ -264,6 +264,8 @@ const FILE_RDF_MANIFEST = "install.rdf";
|
|||
const FILE_WEB_MANIFEST = "manifest.json";
|
||||
const FILE_XPI_ADDONS_LIST = "extensions.ini";
|
||||
|
||||
const ADDON_ID_DEFAULT_THEME = "{972ce4c6-7e08-4474-a285-3208198ce6fd}";
|
||||
|
||||
const KEY_PROFILEDIR = "ProfD";
|
||||
const KEY_ADDON_APP_DIR = "XREAddonAppDir";
|
||||
const KEY_TEMPDIR = "TmpD";
|
||||
|
@ -4088,6 +4090,30 @@ this.XPIProvider = {
|
|||
.filter(addon => addon.dependencies.includes(aAddon.id));
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the add-on state data for the restartful extensions which
|
||||
* should be available in safe mode. In particular, this means the
|
||||
* default theme, and only the default theme.
|
||||
*
|
||||
* @returns {object}
|
||||
*/
|
||||
getSafeModeExtensions() {
|
||||
let loc = XPIStates.getLocation(KEY_APP_GLOBAL);
|
||||
let state = loc.get(ADDON_ID_DEFAULT_THEME);
|
||||
|
||||
// Use the default state data for the default theme, but always mark
|
||||
// it enabled, in case another theme is enabled in normal mode.
|
||||
let addonData = state.toJSON();
|
||||
addonData.enabled = true;
|
||||
|
||||
return {
|
||||
[KEY_APP_GLOBAL]: {
|
||||
path: loc.path,
|
||||
addons: { [ADDON_ID_DEFAULT_THEME]: addonData },
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks for any changes that have occurred since the last time the
|
||||
* application was launched.
|
||||
|
@ -4207,6 +4233,12 @@ this.XPIProvider = {
|
|||
}
|
||||
}
|
||||
|
||||
if (Services.appinfo.inSafeMode) {
|
||||
aomStartup.initializeExtensions(this.getSafeModeExtensions());
|
||||
logger.debug("Initialized safe mode add-ons");
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the application crashed before completing any pending operations then
|
||||
// we should perform them now.
|
||||
if (extensionListChanged || hasPendingChanges) {
|
||||
|
|
|
@ -530,9 +530,6 @@ nsXREDirProvider::GetFile(const char* aProperty, bool* aPersistent,
|
|||
ensureFilePermissions = true;
|
||||
}
|
||||
}
|
||||
else if (!strcmp(aProperty, NS_APP_DOWNLOADS_50_FILE)) {
|
||||
rv = file->AppendNative(NS_LITERAL_CSTRING("downloads.rdf"));
|
||||
}
|
||||
else if (!strcmp(aProperty, NS_APP_PREFS_OVERRIDE_DIR)) {
|
||||
rv = mProfileDir->Clone(getter_AddRefs(file));
|
||||
nsresult tmp = file->AppendNative(NS_LITERAL_CSTRING(PREF_OVERRIDE_DIRNAME));
|
||||
|
|
|
@ -483,7 +483,7 @@ int main()
|
|||
#ifdef _M_X64
|
||||
TestHook(TestGetKeyState, "user32.dll", "GetKeyState") && // see Bug 1316415
|
||||
TestHook(TestLdrUnloadDll, "ntdll.dll", "LdrUnloadDll") &&
|
||||
TestHook(TestLdrResolveDelayLoadedAPI, "ntdll.dll", "LdrResolveDelayLoadedAPI") &&
|
||||
MaybeTestHook(IsWin8OrLater(), TestLdrResolveDelayLoadedAPI, "ntdll.dll", "LdrResolveDelayLoadedAPI") &&
|
||||
#endif
|
||||
MaybeTestHook(ShouldTestTipTsf(), TestProcessCaretEvents, "tiptsf.dll", "ProcessCaretEvents") &&
|
||||
#ifdef _M_IX86
|
||||
|
|
|
@ -273,7 +273,7 @@ static bool GetFilenameAndExtensionFromChannel(nsIChannel* aChannel,
|
|||
* Obtains the directory to use. This tends to vary per platform, and
|
||||
* needs to be consistent throughout our codepaths. For platforms where
|
||||
* helper apps use the downloads directory, this should be kept in
|
||||
* sync with nsDownloadManager.cpp
|
||||
* sync with DownloadIntegration.jsm.
|
||||
*
|
||||
* Optionally skip availability of the directory and storage.
|
||||
*/
|
||||
|
@ -2427,7 +2427,7 @@ NS_IMETHODIMP nsExternalAppHandler::LaunchWithApplication(nsIFile * aApplication
|
|||
// was specified in mSuggestedFileName after the download is done prior to
|
||||
// launching the helper app. So that any existing file of that name won't be
|
||||
// overwritten we call CreateUnique(). Also note that we use the same
|
||||
// directory as originally downloaded so nsDownload can rename in place
|
||||
// directory as originally downloaded so the download can be renamed in place
|
||||
// later.
|
||||
nsCOMPtr<nsIFile> fileToUse;
|
||||
(void) GetDownloadDirectory(getter_AddRefs(fileToUse));
|
||||
|
|
|
@ -10,11 +10,6 @@ XPCSHELL_TESTS_MANIFESTS += ['unit/xpcshell.ini']
|
|||
|
||||
BROWSER_CHROME_MANIFESTS += ['mochitest/browser.ini']
|
||||
|
||||
# The encoding test is already implemented in the Downloads API by a set of
|
||||
# test cases with the string "content_encoding" in their names.
|
||||
if not CONFIG['MOZ_JSDOWNLOADS']:
|
||||
XPCSHELL_TESTS_MANIFESTS += ['unit_ipc/xpcshell.ini']
|
||||
|
||||
TESTING_JS_MODULES += [
|
||||
'HandlerServiceTestUtils.jsm',
|
||||
]
|
||||
|
|
|
@ -1,231 +0,0 @@
|
|||
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
var Cu = Components.utils;
|
||||
var Cr = Components.results;
|
||||
|
||||
Cu.import("resource://testing-common/httpd.js");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
Cu.import("resource://testing-common/MockRegistrar.js");
|
||||
|
||||
do_get_profile();
|
||||
|
||||
var DownloadListener = {
|
||||
init: function () {
|
||||
let obs = Services.obs;
|
||||
obs.addObserver(this, "dl-done", true);
|
||||
},
|
||||
|
||||
observe: function (subject, topic, data) {
|
||||
this.onFinished(subject, topic, data);
|
||||
},
|
||||
|
||||
QueryInterface: function (iid) {
|
||||
if (iid.equals(Ci.nsIObserver) ||
|
||||
iid.equals(Ci.nsISupportsWeakReference) ||
|
||||
iid.equals(Ci.nsISupports))
|
||||
return this;
|
||||
|
||||
throw Cr.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
}
|
||||
DownloadListener.init();
|
||||
|
||||
function HelperAppDlg() { }
|
||||
HelperAppDlg.prototype = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIHelperAppLauncherDialog]),
|
||||
show: function (launcher, ctx, reason, usePrivateUI) {
|
||||
launcher.MIMEInfo.preferredAction = Ci.nsIMIMEInfo.saveToFile;
|
||||
launcher.launchWithApplication(null, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Override the download-manager-ui to prevent anyone from trying to open
|
||||
// a window.
|
||||
function DownloadMgrUI() { }
|
||||
DownloadMgrUI.prototype = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDownloadManagerUI]),
|
||||
show: function (ir, aID, reason) { },
|
||||
|
||||
visible: false,
|
||||
|
||||
getAttention: function () { }
|
||||
}
|
||||
|
||||
function AlertsSVC() { }
|
||||
AlertsSVC.prototype = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIAlertsService]),
|
||||
showAlertNotification: function (url, title, text, clickable, cookie, listener, name) { },
|
||||
}
|
||||
|
||||
MockRegistrar.register("@mozilla.org/helperapplauncherdialog;1",
|
||||
HelperAppDlg);
|
||||
MockRegistrar.register("@mozilla.org/download-manager-ui;1",
|
||||
DownloadMgrUI);
|
||||
MockRegistrar.register("@mozilla.org/alerts-service;1",
|
||||
AlertsSVC);
|
||||
|
||||
function initChildTestEnv()
|
||||
{
|
||||
sendCommand(' \
|
||||
const Cc = Components.classes; \
|
||||
const Ci = Components.interfaces; \
|
||||
const Cr = Components.results; \
|
||||
const Cu = Components.utils; \
|
||||
Cu.import("resource://gre/modules/Services.jsm"); \
|
||||
function WindowContext() { } \
|
||||
\
|
||||
WindowContext.prototype = { \
|
||||
getInterface: function (iid) { \
|
||||
if (iid.equals(Ci.nsIInterfaceRequestor) || \
|
||||
iid.equals(Ci.nsIURIContentListener) || \
|
||||
iid.equals(Ci.nsILoadGroup) || \
|
||||
iid.equals(Ci.nsIDocumentLoader) || \
|
||||
iid.equals(Ci.nsIDOMWindow)) \
|
||||
return this; \
|
||||
\
|
||||
throw Cr.NS_ERROR_NO_INTERFACE; \
|
||||
}, \
|
||||
\
|
||||
/* nsIURIContentListener */ \
|
||||
onStartURIOpen: function (uri) { }, \
|
||||
isPreferred: function (type, desiredtype) { return false; }, \
|
||||
\
|
||||
/* nsILoadGroup */ \
|
||||
addRequest: function (request, context) { }, \
|
||||
removeRequest: function (request, context, status) { } \
|
||||
}; \
|
||||
\
|
||||
var ioservice = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);\
|
||||
var uriloader = Cc["@mozilla.org/uriloader;1"].getService(Ci.nsIURILoader);\
|
||||
');
|
||||
}
|
||||
|
||||
function testFinisher(endFunc) {
|
||||
let ef = endFunc;
|
||||
return function (file) {
|
||||
ef(file);
|
||||
runNextTest();
|
||||
}
|
||||
}
|
||||
|
||||
function runChildTestSet(set)
|
||||
{
|
||||
DownloadListener.onFinished = testFinisher(set[2]);
|
||||
sendCommand('\
|
||||
let uri = ioservice.newURI("http://localhost:4444' + set[0] + '", null, null); \
|
||||
let channel = NetUtil.newChannel({uri: uri, loadUsingSystemPrincipal: true}); \
|
||||
uriloader.openURI(channel, Ci.nsIURILoader.IS_CONTENT_PREFERRED, new WindowContext()); \
|
||||
');
|
||||
}
|
||||
|
||||
var httpserver = null;
|
||||
var currentTest = 0;
|
||||
function runNextTest()
|
||||
{
|
||||
if (currentTest == tests.length) {
|
||||
httpserver.stop(do_test_finished);
|
||||
return;
|
||||
}
|
||||
|
||||
let set = tests[currentTest++];
|
||||
runChildTestSet(set);
|
||||
}
|
||||
|
||||
const responseBody = [0x1f, 0x8b, 0x08, 0x00, 0x16, 0x5a, 0x8a, 0x48, 0x02,
|
||||
0x03, 0x2b, 0x49, 0x2d, 0x2e, 0xe1, 0x02, 0x00, 0xc6,
|
||||
0x35, 0xb9, 0x3b, 0x05, 0x00, 0x00, 0x00];
|
||||
|
||||
/*
|
||||
* First test: a file with Content-Type application/x-gzip and Content-Encoding gzip
|
||||
* should not be decoded in a round-trip
|
||||
*/
|
||||
function testResponse1(metadata, response) {
|
||||
response.setHeader("Content-Type", "application/x-gzip", false);
|
||||
response.setHeader("Content-Encoding", "gzip", false);
|
||||
response.setHeader("Content-Disposition", "attachment", false);
|
||||
|
||||
var bos = Cc["@mozilla.org/binaryoutputstream;1"].createInstance(Ci.nsIBinaryOutputStream);
|
||||
bos.setOutputStream(response.bodyOutputStream);
|
||||
bos.writeByteArray(responseBody, responseBody.length);
|
||||
}
|
||||
|
||||
function finishTest1(subject, topic, data) {
|
||||
let file = subject.QueryInterface(Ci.nsIDownload).targetFile;
|
||||
do_check_true(file.path.search("test1.gz") != 0);
|
||||
let fis = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream);
|
||||
fis.init(file, -1, -1, 0);
|
||||
let bis = Cc["@mozilla.org/binaryinputstream;1"].createInstance(Ci.nsIBinaryInputStream);
|
||||
bis.setInputStream(fis);
|
||||
let str = bis.readByteArray(bis.available());
|
||||
do_check_matches(str, responseBody);
|
||||
}
|
||||
|
||||
/*
|
||||
* Second test: a file with Content-Type text/html and Content-Encoding gzip
|
||||
* should not be decoded in a round-trip, if its filename ends in ".gz".
|
||||
* We specify a Content-disposition header to force it to be saved as a file.
|
||||
*/
|
||||
function testResponse2(metadata, response) {
|
||||
response.setHeader("Content-Type", "text/html", false);
|
||||
response.setHeader("Content-Encoding", "gzip", false);
|
||||
response.setHeader("Content-Disposition", "attachment", false);
|
||||
|
||||
var bos = Cc["@mozilla.org/binaryoutputstream;1"].createInstance(Ci.nsIBinaryOutputStream);
|
||||
bos.setOutputStream(response.bodyOutputStream);
|
||||
bos.writeByteArray(responseBody, responseBody.length);
|
||||
}
|
||||
|
||||
function finishTest2(subject, topic, data) {
|
||||
let file = subject.QueryInterface(Ci.nsIDownload).targetFile;
|
||||
do_check_true(file.path.search("test2.gz") != 0);
|
||||
let fis = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream);
|
||||
fis.init(file, -1, -1, 0);
|
||||
let bis = Cc["@mozilla.org/binaryinputstream;1"].createInstance(Ci.nsIBinaryInputStream);
|
||||
bis.setInputStream(fis);
|
||||
let str = bis.readByteArray(bis.available());
|
||||
do_check_matches(str, responseBody);
|
||||
}
|
||||
|
||||
function testResponse3(metadata, response) {
|
||||
response.setHeader("Content-Type", "text/html", false);
|
||||
response.setHeader("Content-Encoding", "gzip", false);
|
||||
response.setHeader("Content-Disposition", "attachment", false);
|
||||
|
||||
var bos = Cc["@mozilla.org/binaryoutputstream;1"].createInstance(Ci.nsIBinaryOutputStream);
|
||||
bos.setOutputStream(response.bodyOutputStream);
|
||||
bos.writeByteArray(responseBody, responseBody.length);
|
||||
}
|
||||
|
||||
function finishTest3(subject, topic, data) {
|
||||
let file = subject.QueryInterface(Ci.nsIDownload).targetFile;
|
||||
do_check_true(file.path.search("test3.txt") != 0);
|
||||
let fis = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream);
|
||||
fis.init(file, -1, -1, 0);
|
||||
let bis = Cc["@mozilla.org/binaryinputstream;1"].createInstance(Ci.nsIBinaryInputStream);
|
||||
bis.setInputStream(fis);
|
||||
let str = bis.readByteArray(bis.available());
|
||||
let decodedBody = [ 116, 101, 115, 116, 10 ]; // 't','e','s','t','\n'
|
||||
do_check_matches(str, decodedBody);
|
||||
}
|
||||
|
||||
var tests = [
|
||||
[ "/test1.gz", testResponse1, finishTest1 ],
|
||||
[ "/test2.gz", testResponse2, finishTest2 ],
|
||||
[ "/test3.txt", testResponse3, finishTest3 ],
|
||||
];
|
||||
|
||||
function run_test() {
|
||||
// do_load_child_test_harness();
|
||||
httpserver = new HttpServer();
|
||||
httpserver.start(4444);
|
||||
do_test_pending();
|
||||
|
||||
initChildTestEnv();
|
||||
|
||||
for (let set of tests)
|
||||
httpserver.registerPathHandler(set[0], set[1]);
|
||||
|
||||
runNextTest();
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
[DEFAULT]
|
||||
head =
|
||||
|
||||
[test_encoding.js]
|
||||
# Bug 676995: test hangs consistently on Android
|
||||
# Bug 907732: thunderbird still uses legacy downloads manager.
|
||||
skip-if = (os == "android" || buildapp == '../mail')
|
|
@ -129,7 +129,7 @@ AndroidBridge::ConstructBridge()
|
|||
* to call dlclose() while we're already inside dlclose().
|
||||
* Conveniently, NSS has an env var that can prevent it from unloading.
|
||||
*/
|
||||
putenv("NSS_DISABLE_UNLOAD=1");
|
||||
putenv(const_cast<char*>("NSS_DISABLE_UNLOAD=1"));
|
||||
|
||||
MOZ_ASSERT(!sBridge);
|
||||
sBridge = new AndroidBridge();
|
||||
|
|
|
@ -1432,8 +1432,8 @@ nsWindow::LogWindow(nsWindow *win, int index, int indent)
|
|||
#if defined(DEBUG) || defined(FORCE_ALOG)
|
||||
char spaces[] = " ";
|
||||
spaces[indent < 20 ? indent : 20] = 0;
|
||||
ALOG("%s [% 2d] 0x%08x [parent 0x%08x] [% 3d,% 3dx% 3d,% 3d] vis %d type %d",
|
||||
spaces, index, (intptr_t)win, (intptr_t)win->mParent,
|
||||
ALOG("%s [% 2d] 0x%p [parent 0x%p] [% 3d,% 3dx% 3d,% 3d] vis %d type %d",
|
||||
spaces, index, win, win->mParent,
|
||||
win->mBounds.x, win->mBounds.y,
|
||||
win->mBounds.width, win->mBounds.height,
|
||||
win->mIsVisible, win->mWindowType);
|
||||
|
|
|
@ -471,6 +471,8 @@ RealBreak()
|
|||
".object_arch armv4t\n"
|
||||
#endif
|
||||
"BKPT #0");
|
||||
#elif defined(__aarch64__)
|
||||
asm("brk #0");
|
||||
#elif defined(SOLARIS)
|
||||
#if defined(__i386__) || defined(__i386) || defined(__x86_64__)
|
||||
asm("int $3");
|
||||
|
@ -549,7 +551,7 @@ Break(const char* aMsg)
|
|||
RealBreak();
|
||||
#elif defined(__GNUC__) && (defined(__i386__) || defined(__i386) || defined(__x86_64__))
|
||||
RealBreak();
|
||||
#elif defined(__arm__)
|
||||
#elif defined(__arm__) || defined(__aarch64__)
|
||||
RealBreak();
|
||||
#elif defined(SOLARIS)
|
||||
RealBreak();
|
||||
|
|
|
@ -49,7 +49,7 @@ nsMemoryImpl::IsLowMemoryPlatform(bool* aResult)
|
|||
return NS_OK;
|
||||
}
|
||||
uint64_t mem = 0;
|
||||
int rv = fscanf(fd, "MemTotal: %llu kB", &mem);
|
||||
int rv = fscanf(fd, "MemTotal: %" PRIu64 " kB", &mem);
|
||||
if (fclose(fd)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -73,8 +73,6 @@
|
|||
#define NS_APP_USER_PANELS_50_FILE "UPnls"
|
||||
#define NS_APP_CACHE_PARENT_DIR "cachePDir"
|
||||
|
||||
#define NS_APP_DOWNLOADS_50_FILE "DLoads"
|
||||
|
||||
#define NS_APP_SEARCH_50_FILE "SrchF"
|
||||
|
||||
#define NS_APP_INSTALL_CLEANUP_DIR "XPIClnupD" //location of xpicleanup.dat xpicleanup.exe
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
#include "mozilla/Compiler.h"
|
||||
|
||||
#if !defined(__arm__) && !(defined(LINUX) || defined(ANDROID) || defined(XP_IOS))
|
||||
#if !defined(__arm__) || !(defined(LINUX) || defined(ANDROID) || defined(XP_IOS))
|
||||
#error "This code is for Linux/iOS ARM only. Check that it works on your system, too.\nBeware that this code is highly compiler dependent."
|
||||
#endif
|
||||
|
||||
|
|
|
@ -19,35 +19,6 @@
|
|||
|
||||
using namespace mozilla;
|
||||
|
||||
class SchedulerGroup::Runnable final : public mozilla::Runnable
|
||||
{
|
||||
public:
|
||||
Runnable(already_AddRefed<nsIRunnable>&& aRunnable,
|
||||
SchedulerGroup* aDispatcher);
|
||||
|
||||
NS_IMETHODIMP
|
||||
GetName(nsACString& aName) override
|
||||
{
|
||||
mozilla::Runnable::GetName(aName);
|
||||
if (aName.IsEmpty()) {
|
||||
// Try to get a name from the underlying runnable.
|
||||
nsCOMPtr<nsINamed> named = do_QueryInterface(mRunnable);
|
||||
if (named) {
|
||||
named->GetName(aName);
|
||||
}
|
||||
}
|
||||
aName.AppendASCII("(labeled)");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool IsBackground() const { return mDispatcher->IsBackground(); }
|
||||
|
||||
NS_DECL_NSIRUNNABLE
|
||||
private:
|
||||
nsCOMPtr<nsIRunnable> mRunnable;
|
||||
RefPtr<SchedulerGroup> mDispatcher;
|
||||
};
|
||||
|
||||
/* SchedulerEventTarget */
|
||||
|
||||
namespace {
|
||||
|
@ -350,18 +321,36 @@ SchedulerGroup::SetValidatingAccess(ValidationType aType)
|
|||
}
|
||||
|
||||
SchedulerGroup::Runnable::Runnable(already_AddRefed<nsIRunnable>&& aRunnable,
|
||||
SchedulerGroup* aDispatcher)
|
||||
SchedulerGroup* aGroup)
|
||||
: mRunnable(Move(aRunnable)),
|
||||
mDispatcher(aDispatcher)
|
||||
mGroup(aGroup)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SchedulerGroup::Runnable::GetName(nsACString& aName)
|
||||
{
|
||||
mozilla::Runnable::GetName(aName);
|
||||
if (aName.IsEmpty()) {
|
||||
// Try to get a name from the underlying runnable.
|
||||
nsCOMPtr<nsINamed> named = do_QueryInterface(mRunnable);
|
||||
if (named) {
|
||||
named->GetName(aName);
|
||||
}
|
||||
if (aName.IsEmpty()) {
|
||||
aName.AssignLiteral("anonymous");
|
||||
}
|
||||
}
|
||||
aName.AppendASCII("(labeled)");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SchedulerGroup::Runnable::Run()
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
||||
|
||||
mDispatcher->SetValidatingAccess(StartValidation);
|
||||
mGroup->SetValidatingAccess(StartValidation);
|
||||
|
||||
nsresult result;
|
||||
|
||||
|
@ -374,10 +363,14 @@ SchedulerGroup::Runnable::Run()
|
|||
// the scope of the TabGroup.
|
||||
mRunnable = nullptr;
|
||||
|
||||
mDispatcher->SetValidatingAccess(EndValidation);
|
||||
mGroup->SetValidatingAccess(EndValidation);
|
||||
return result;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED(SchedulerGroup::Runnable,
|
||||
mozilla::Runnable,
|
||||
SchedulerGroup::Runnable)
|
||||
|
||||
SchedulerGroup::AutoProcessEvent::AutoProcessEvent()
|
||||
: mPrevRunningDispatcher(SchedulerGroup::sRunningDispatcher)
|
||||
{
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "mozilla/TimeStamp.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
class nsIEventTarget;
|
||||
class nsIRunnable;
|
||||
|
@ -22,16 +23,20 @@ namespace dom {
|
|||
class TabGroup;
|
||||
}
|
||||
|
||||
#define NS_SCHEDULERGROUPRUNNABLE_IID \
|
||||
{ 0xd31b7420, 0x872b, 0x4cfb, \
|
||||
{ 0xa9, 0xc6, 0xae, 0x4c, 0x0f, 0x06, 0x36, 0x74 } }
|
||||
|
||||
// The "main thread" in Gecko will soon be a set of cooperatively scheduled
|
||||
// "fibers". Global state in Gecko will be partitioned into a series of "groups"
|
||||
// (with roughly one group per tab). Runnables will be annotated with the set of
|
||||
// groups that they touch. Two runnables may run concurrently on different
|
||||
// fibers as long as they touch different groups.
|
||||
//
|
||||
// A Dispatcher is an abstract class to represent a "group". Essentially the
|
||||
// only functionality offered by a Dispatcher is the ability to dispatch
|
||||
// A SchedulerGroup is an abstract class to represent a "group". Essentially the
|
||||
// only functionality offered by a SchedulerGroup is the ability to dispatch
|
||||
// runnables to the group. TabGroup, DocGroup, and SystemGroup are the concrete
|
||||
// implementations of Dispatcher.
|
||||
// implementations of SchedulerGroup.
|
||||
class SchedulerGroup
|
||||
{
|
||||
public:
|
||||
|
@ -58,7 +63,29 @@ public:
|
|||
MOZ_ASSERT(!sRunningDispatcher || mAccessValid);
|
||||
}
|
||||
|
||||
class Runnable;
|
||||
class Runnable final : public mozilla::Runnable
|
||||
{
|
||||
public:
|
||||
Runnable(already_AddRefed<nsIRunnable>&& aRunnable,
|
||||
SchedulerGroup* aGroup);
|
||||
|
||||
SchedulerGroup* Group() const { return mGroup; }
|
||||
|
||||
NS_IMETHOD GetName(nsACString& aName) override;
|
||||
|
||||
bool IsBackground() const { return mGroup->IsBackground(); }
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIRUNNABLE
|
||||
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_SCHEDULERGROUPRUNNABLE_IID);
|
||||
|
||||
private:
|
||||
~Runnable() = default;
|
||||
|
||||
nsCOMPtr<nsIRunnable> mRunnable;
|
||||
RefPtr<SchedulerGroup> mGroup;
|
||||
};
|
||||
friend class Runnable;
|
||||
|
||||
bool* GetValidAccessPtr() { return &mAccessValid; }
|
||||
|
@ -121,6 +148,8 @@ protected:
|
|||
RefPtr<AbstractThread> mAbstractThreads[size_t(TaskCategory::Count)];
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(SchedulerGroup::Runnable, NS_SCHEDULERGROUPRUNNABLE_IID);
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_SchedulerGroup_h
|
||||
|
|
|
@ -481,7 +481,7 @@ nsThread::ThreadFunc(void* aArg)
|
|||
nsCOMPtr<nsIRunnable> event;
|
||||
{
|
||||
MutexAutoLock lock(self->mLock);
|
||||
if (!self->mEvents->GetEvent(true, getter_AddRefs(event), lock)) {
|
||||
if (!self->mEvents->GetEvent(true, getter_AddRefs(event), nullptr, lock)) {
|
||||
NS_WARNING("failed waiting for thread startup event");
|
||||
return;
|
||||
}
|
||||
|
@ -642,6 +642,7 @@ nsThread::nsThread(MainThreadFlag aMainThread, uint32_t aStackSize)
|
|||
, mShutdownRequired(false)
|
||||
, mEventsAreDoomed(false)
|
||||
, mIsMainThread(aMainThread)
|
||||
, mLastUnlabeledRunnable(TimeStamp::Now())
|
||||
, mCanInvokeJS(false)
|
||||
{
|
||||
}
|
||||
|
@ -809,6 +810,7 @@ nsThread::DispatchInternal(already_AddRefed<nsIRunnable> aEvent, uint32_t aFlags
|
|||
|
||||
bool
|
||||
nsThread::nsChainedEventQueue::GetEvent(bool aMayWait, nsIRunnable** aEvent,
|
||||
unsigned short* aPriority,
|
||||
mozilla::MutexAutoLock& aProofOfLock)
|
||||
{
|
||||
bool retVal = false;
|
||||
|
@ -817,6 +819,9 @@ nsThread::nsChainedEventQueue::GetEvent(bool aMayWait, nsIRunnable** aEvent,
|
|||
MOZ_ASSERT(mSecondaryQueue->HasPendingEvent(aProofOfLock));
|
||||
retVal = mSecondaryQueue->GetEvent(aMayWait, aEvent, aProofOfLock);
|
||||
MOZ_ASSERT(*aEvent);
|
||||
if (aPriority) {
|
||||
*aPriority = nsIRunnablePriority::PRIORITY_HIGH;
|
||||
}
|
||||
mProcessSecondaryQueueRunnable = false;
|
||||
return retVal;
|
||||
}
|
||||
|
@ -826,6 +831,9 @@ nsThread::nsChainedEventQueue::GetEvent(bool aMayWait, nsIRunnable** aEvent,
|
|||
aMayWait && !mSecondaryQueue->HasPendingEvent(aProofOfLock);
|
||||
retVal =
|
||||
mNormalQueue->GetEvent(reallyMayWait, aEvent, aProofOfLock);
|
||||
if (aPriority) {
|
||||
*aPriority = nsIRunnablePriority::PRIORITY_NORMAL;
|
||||
}
|
||||
|
||||
// Let's see if we should next time process an event from the secondary
|
||||
// queue.
|
||||
|
@ -1157,14 +1165,16 @@ nsThread::GetIdleEvent(nsIRunnable** aEvent, MutexAutoLock& aProofOfLock)
|
|||
}
|
||||
|
||||
void
|
||||
nsThread::GetEvent(bool aWait, nsIRunnable** aEvent, MutexAutoLock& aProofOfLock)
|
||||
nsThread::GetEvent(bool aWait, nsIRunnable** aEvent,
|
||||
unsigned short* aPriority,
|
||||
MutexAutoLock& aProofOfLock)
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == mThread);
|
||||
MOZ_ASSERT(aEvent);
|
||||
|
||||
// We'll try to get an event to execute in three stages.
|
||||
// [1] First we just try to get it from the regular queue without waiting.
|
||||
mEvents->GetEvent(false, aEvent, aProofOfLock);
|
||||
mEvents->GetEvent(false, aEvent, aPriority, aProofOfLock);
|
||||
|
||||
// [2] If we didn't get an event from the regular queue, try to
|
||||
// get one from the idle queue
|
||||
|
@ -1175,6 +1185,11 @@ nsThread::GetEvent(bool aWait, nsIRunnable** aEvent, MutexAutoLock& aProofOfLock
|
|||
// wait for an idle event, since a higher priority event might
|
||||
// appear at any time.
|
||||
GetIdleEvent(aEvent, aProofOfLock);
|
||||
|
||||
if (*aEvent && aPriority) {
|
||||
// Idle events count as normal priority.
|
||||
*aPriority = nsIRunnablePriority::PRIORITY_NORMAL;
|
||||
}
|
||||
}
|
||||
|
||||
// [3] If we neither got an event from the regular queue nor the
|
||||
|
@ -1182,7 +1197,7 @@ nsThread::GetEvent(bool aWait, nsIRunnable** aEvent, MutexAutoLock& aProofOfLock
|
|||
// main queue until an event is available.
|
||||
// If we are shutting down, then do not wait for new events.
|
||||
if (!*aEvent && aWait) {
|
||||
mEvents->GetEvent(aWait, aEvent, aProofOfLock);
|
||||
mEvents->GetEvent(aWait, aEvent, aPriority, aProofOfLock);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1241,9 +1256,10 @@ nsThread::ProcessNextEvent(bool aMayWait, bool* aResult)
|
|||
// mNestedEventLoopDepth has been incremented, since that destructor can
|
||||
// also do work.
|
||||
nsCOMPtr<nsIRunnable> event;
|
||||
unsigned short priority;
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
GetEvent(reallyWait, getter_AddRefs(event), lock);
|
||||
GetEvent(reallyWait, getter_AddRefs(event), &priority, lock);
|
||||
}
|
||||
|
||||
*aResult = (event.get() != nullptr);
|
||||
|
@ -1258,15 +1274,28 @@ nsThread::ProcessNextEvent(bool aMayWait, bool* aResult)
|
|||
|
||||
#ifndef RELEASE_OR_BETA
|
||||
nsCString name;
|
||||
if (nsCOMPtr<nsINamed> named = do_QueryInterface(event)) {
|
||||
if (NS_FAILED(named->GetName(name))) {
|
||||
name.AssignLiteral("GetName failed");
|
||||
} else if (name.IsEmpty()) {
|
||||
name.AssignLiteral("anonymous runnable");
|
||||
}
|
||||
bool labeled = false;
|
||||
if (RefPtr<SchedulerGroup::Runnable> groupRunnable = do_QueryObject(event)) {
|
||||
labeled = true;
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(groupRunnable->GetName(name)));
|
||||
} else if (nsCOMPtr<nsINamed> named = do_QueryInterface(event)) {
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(named->GetName(name)));
|
||||
} else {
|
||||
name.AssignLiteral("non-nsINamed runnable");
|
||||
}
|
||||
if (name.IsEmpty()) {
|
||||
name.AssignLiteral("anonymous runnable");
|
||||
}
|
||||
|
||||
// High-priority runnables are ignored here since they'll run right away
|
||||
// even with the cooperative scheduler.
|
||||
if (!labeled && priority == nsIRunnablePriority::PRIORITY_NORMAL) {
|
||||
TimeStamp now = TimeStamp::Now();
|
||||
double diff = (now - mLastUnlabeledRunnable).ToMilliseconds();
|
||||
Telemetry::Accumulate(Telemetry::TIME_BETWEEN_UNLABELED_RUNNABLES_MS, diff);
|
||||
mLastUnlabeledRunnable = now;
|
||||
}
|
||||
|
||||
timer.emplace(name);
|
||||
#endif
|
||||
}
|
||||
|
@ -1461,7 +1490,7 @@ nsThread::PopEventQueue(nsIEventTarget* aInnermostTarget)
|
|||
mEvents = WrapNotNull(mEvents->mNext);
|
||||
|
||||
nsCOMPtr<nsIRunnable> event;
|
||||
while (queue->GetEvent(false, getter_AddRefs(event), lock)) {
|
||||
while (queue->GetEvent(false, getter_AddRefs(event), nullptr, lock)) {
|
||||
mEvents->PutEvent(event.forget(), lock);
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "nsTObserverArray.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/NotNull.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "mozilla/AlreadyAddRefed.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
@ -98,6 +99,7 @@ private:
|
|||
|
||||
void GetIdleEvent(nsIRunnable** aEvent, mozilla::MutexAutoLock& aProofOfLock);
|
||||
void GetEvent(bool aWait, nsIRunnable** aEvent,
|
||||
unsigned short* aPriority,
|
||||
mozilla::MutexAutoLock& aProofOfLock);
|
||||
|
||||
protected:
|
||||
|
@ -154,6 +156,7 @@ protected:
|
|||
}
|
||||
|
||||
bool GetEvent(bool aMayWait, nsIRunnable** aEvent,
|
||||
unsigned short* aPriority,
|
||||
mozilla::MutexAutoLock& aProofOfLock);
|
||||
|
||||
void PutEvent(nsIRunnable* aEvent, mozilla::MutexAutoLock& aProofOfLock)
|
||||
|
@ -270,6 +273,10 @@ protected:
|
|||
bool mEventsAreDoomed;
|
||||
MainThreadFlag mIsMainThread;
|
||||
|
||||
// The time when we last ran an unlabeled runnable (one not associated with a
|
||||
// SchedulerGroup).
|
||||
mozilla::TimeStamp mLastUnlabeledRunnable;
|
||||
|
||||
// Set to true if this thread creates a JSRuntime.
|
||||
bool mCanInvokeJS;
|
||||
};
|
||||
|
|
Загрузка…
Ссылка в новой задаче