зеркало из https://github.com/mozilla/gecko-dev.git
merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
Коммит
5b9719c5fc
|
@ -3,7 +3,7 @@ support-files =
|
|||
head.js
|
||||
|
||||
[browser_all_files_referenced.js]
|
||||
skip-if = debug # no point in running on both opt and debug, and will likely intermittently timeout on debug
|
||||
skip-if = debug || (os == 'linux' && bits == 32) # no point in running on both opt and debug, and will likely intermittently timeout on debug; oom crashes on linux32 (bug 1349307)
|
||||
[browser_misused_characters_in_strings.js]
|
||||
support-files =
|
||||
bug1262648_string_with_newlines.dtd
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Slow on asan builds.
|
||||
requestLongerTimeout(5);
|
||||
|
||||
var isDevtools = SimpleTest.harnessParameters.subsuite == "devtools";
|
||||
|
||||
var gExceptionPaths = ["chrome://browser/content/defaultthemes/",
|
||||
|
|
|
@ -101,6 +101,22 @@ if test "$OS_TARGET" = "Android"; then
|
|||
AC_MSG_ERROR([Couldn't find path to llvm-libc++ in the android ndk])
|
||||
fi
|
||||
|
||||
if ! test -e "$cxx_include"; then
|
||||
# NDK r13 removes the inner "libcxx" directory.
|
||||
cxx_include="$cxx_base/include"
|
||||
if ! test -e "$cxx_include"; then
|
||||
AC_MSG_ERROR([Couldn't find path to libc++ includes in the android ndk])
|
||||
fi
|
||||
fi
|
||||
|
||||
if ! test -e "$cxxabi_include"; then
|
||||
# NDK r13 removes the inner "libcxxabi" directory.
|
||||
cxxabi_include="$cxxabi_base/include"
|
||||
if ! test -e "$cxxabi_include"; then
|
||||
AC_MSG_ERROR([Couldn't find path to libc++abi includes in the android ndk])
|
||||
fi
|
||||
fi
|
||||
|
||||
STLPORT_LIBS="-L$cxx_libs -lc++_static"
|
||||
# NDK r12 split the libc++ runtime libraries into pieces.
|
||||
for lib in c++abi unwind android_support; do
|
||||
|
@ -111,7 +127,7 @@ if test "$OS_TARGET" = "Android"; then
|
|||
# Add android/support/include/ for prototyping long double math
|
||||
# functions, locale-specific C library functions, multibyte support,
|
||||
# etc.
|
||||
STLPORT_CPPFLAGS="-I$android_ndk/sources/android/support/include -I$cxx_include -I$cxxabi_include"
|
||||
STLPORT_CPPFLAGS="-I$cxx_include -I$android_ndk/sources/android/support/include -I$cxxabi_include"
|
||||
;;
|
||||
*)
|
||||
AC_MSG_ERROR([Bad value for --enable-android-cxx-stl])
|
||||
|
|
|
@ -40,12 +40,20 @@ struct OwningAnimationTarget
|
|||
|
||||
struct NonOwningAnimationTarget
|
||||
{
|
||||
NonOwningAnimationTarget() = default;
|
||||
|
||||
NonOwningAnimationTarget(dom::Element* aElement, CSSPseudoElementType aType)
|
||||
: mElement(aElement), mPseudoType(aType) { }
|
||||
|
||||
explicit NonOwningAnimationTarget(const OwningAnimationTarget& aOther)
|
||||
: mElement(aOther.mElement), mPseudoType(aOther.mPseudoType) { }
|
||||
|
||||
bool operator==(const NonOwningAnimationTarget& aOther) const
|
||||
{
|
||||
return mElement == aOther.mElement &&
|
||||
mPseudoType == aOther.mPseudoType;
|
||||
}
|
||||
|
||||
// mElement represents the parent element of a pseudo-element, not the
|
||||
// generated content element.
|
||||
dom::Element* MOZ_NON_OWNING_REF mElement = nullptr;
|
||||
|
|
|
@ -1495,30 +1495,37 @@ DataTransfer::FillInExternalCustomTypes(nsIVariant* aData, uint32_t aIndex,
|
|||
return;
|
||||
}
|
||||
|
||||
stream->SetInputStream(stringStream);
|
||||
rv = stream->SetInputStream(stringStream);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
|
||||
uint32_t type;
|
||||
do {
|
||||
stream->Read32(&type);
|
||||
rv = stream->Read32(&type);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
if (type == eCustomClipboardTypeId_String) {
|
||||
uint32_t formatLength;
|
||||
stream->Read32(&formatLength);
|
||||
rv = stream->Read32(&formatLength);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
char* formatBytes;
|
||||
stream->ReadBytes(formatLength, &formatBytes);
|
||||
rv = stream->ReadBytes(formatLength, &formatBytes);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
nsAutoString format;
|
||||
format.Adopt(reinterpret_cast<char16_t*>(formatBytes),
|
||||
formatLength / sizeof(char16_t));
|
||||
|
||||
uint32_t dataLength;
|
||||
stream->Read32(&dataLength);
|
||||
rv = stream->Read32(&dataLength);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
char* dataBytes;
|
||||
stream->ReadBytes(dataLength, &dataBytes);
|
||||
rv = stream->ReadBytes(dataLength, &dataBytes);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
nsAutoString data;
|
||||
data.Adopt(reinterpret_cast<char16_t*>(dataBytes),
|
||||
dataLength / sizeof(char16_t));
|
||||
|
||||
RefPtr<nsVariantCC> variant = new nsVariantCC();
|
||||
variant->SetAsAString(data);
|
||||
rv = variant->SetAsAString(data);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
|
||||
SetDataWithPrincipal(format, variant, aIndex, aPrincipal);
|
||||
}
|
||||
|
|
|
@ -548,7 +548,7 @@ var interfaceNamesInGlobalScope =
|
|||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"HTMLVideoElement",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "IdleDeadline", nightly: true},
|
||||
{name: "IdleDeadline"},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"IDBCursor",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
|
|
|
@ -675,7 +675,6 @@ nsBindingManager::WalkRules(nsIStyleRuleProcessor::EnumFunc aFunc,
|
|||
do {
|
||||
nsXBLBinding *binding = content->GetXBLBinding();
|
||||
if (binding) {
|
||||
aData->mTreeMatchContext.mScopedRoot = content;
|
||||
binding->WalkRules(aFunc, aData);
|
||||
// If we're not looking at our original content, allow the binding to cut
|
||||
// off style inheritance
|
||||
|
@ -698,9 +697,6 @@ nsBindingManager::WalkRules(nsIStyleRuleProcessor::EnumFunc aFunc,
|
|||
// in the loop.
|
||||
*aCutOffInheritance = (content != nullptr);
|
||||
|
||||
// Null out the scoped root that we set repeatedly
|
||||
aData->mTreeMatchContext.mScopedRoot = nullptr;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -737,20 +737,21 @@ DXGITextureHostD3D11::GetDevice()
|
|||
if (mFlags & TextureFlags::INVALID_COMPOSITOR) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return mProvider->GetD3D11Device();
|
||||
return mDevice;
|
||||
}
|
||||
|
||||
void
|
||||
DXGITextureHostD3D11::SetTextureSourceProvider(TextureSourceProvider* aProvider)
|
||||
{
|
||||
if (!aProvider || !aProvider->GetD3D11Device()) {
|
||||
mDevice = nullptr;
|
||||
mProvider = nullptr;
|
||||
mTextureSource = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
mProvider = aProvider;
|
||||
mDevice = aProvider->GetD3D11Device();
|
||||
|
||||
if (mTextureSource) {
|
||||
mTextureSource->SetTextureSourceProvider(aProvider);
|
||||
|
@ -776,6 +777,9 @@ DXGITextureHostD3D11::LockWithoutCompositor()
|
|||
// Unlike the normal Lock() function, this function may be called when
|
||||
// mCompositor is nullptr such as during WebVR frame submission. So, there is
|
||||
// no 'mCompositor' checking here.
|
||||
if (!mDevice) {
|
||||
mDevice = DeviceManagerDx::Get()->GetCompositorDevice();
|
||||
}
|
||||
return LockInternal();
|
||||
}
|
||||
|
||||
|
@ -805,7 +809,11 @@ DXGITextureHostD3D11::LockInternal()
|
|||
return false;
|
||||
}
|
||||
|
||||
mTextureSource = new DataTextureSourceD3D11(mFormat, mProvider, mTexture);
|
||||
if (mProvider) {
|
||||
mTextureSource = new DataTextureSourceD3D11(mFormat, mProvider, mTexture);
|
||||
} else {
|
||||
mTextureSource = new DataTextureSourceD3D11(mDevice, mFormat, mTexture);
|
||||
}
|
||||
}
|
||||
|
||||
mIsLocked = LockD3DTexture(mTextureSource->GetD3D11Texture());
|
||||
|
@ -895,12 +903,15 @@ void
|
|||
DXGIYCbCrTextureHostD3D11::SetTextureSourceProvider(TextureSourceProvider* aProvider)
|
||||
{
|
||||
if (!aProvider || !aProvider->GetD3D11Device()) {
|
||||
mProvider = nullptr;
|
||||
mTextureSources[0] = nullptr;
|
||||
mTextureSources[1] = nullptr;
|
||||
mTextureSources[2] = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
mProvider = aProvider;
|
||||
|
||||
if (mTextureSources[0]) {
|
||||
mTextureSources[0]->SetTextureSourceProvider(aProvider);
|
||||
}
|
||||
|
|
|
@ -333,6 +333,7 @@ protected:
|
|||
|
||||
bool OpenSharedHandle();
|
||||
|
||||
RefPtr<ID3D11Device> mDevice;
|
||||
RefPtr<ID3D11Texture2D> mTexture;
|
||||
RefPtr<DataTextureSourceD3D11> mTextureSource;
|
||||
gfx::IntSize mSize;
|
||||
|
|
|
@ -1938,9 +1938,9 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier)
|
|||
return true;
|
||||
|
||||
error:
|
||||
flags.isDirtyLine = true;
|
||||
tp->pos.end = userbuf.offset();
|
||||
MOZ_MAKE_MEM_UNDEFINED(&tp->type, sizeof(tp->type));
|
||||
// We didn't get a token, so don't set |flags.isDirtyLine|. And don't
|
||||
// poison any of |*tp|: if we haven't allocated a token, |tp| could be
|
||||
// uninitialized.
|
||||
flags.hadError = true;
|
||||
#ifdef DEBUG
|
||||
// Poisoning userbuf on error establishes an invariant: once an erroneous
|
||||
|
|
|
@ -0,0 +1,143 @@
|
|||
// Constraints on this test's appearance:
|
||||
//
|
||||
// * |TokenStream::SourceCoords::add| must try to allocate memory. (This test
|
||||
// ensures this happens by making the function below >=128 lines long so
|
||||
// that |SourceCoords::lineStartOffsets_| must convert to heap storage. The
|
||||
// precise approach doesn't matter.)
|
||||
// * That allocation attempt must fail (by forced simulated OOM, here).
|
||||
//
|
||||
// It'd be nice to build up the function programmatically, but it appears that
|
||||
// the above only happens if the provided function has a lazy script. Cursory
|
||||
// attempts to relazify |Function("...")| didn't work, so this fuzzer-like
|
||||
// version had to be used instead.
|
||||
if ("oomTest" in this) {
|
||||
oomTest(function() {
|
||||
try {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
} catch(e) {
|
||||
;
|
||||
}
|
||||
})
|
||||
}
|
|
@ -13,6 +13,7 @@
|
|||
#include "mozilla/LinkedList.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/dom/Animation.h"
|
||||
#include "mozilla/AnimationTarget.h"
|
||||
#include "mozilla/Attributes.h" // For MOZ_NON_OWNING_REF
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/TimingParams.h"
|
||||
|
@ -111,48 +112,48 @@ protected:
|
|||
class OwningElementRef final
|
||||
{
|
||||
public:
|
||||
OwningElementRef()
|
||||
: mElement(nullptr)
|
||||
, mPseudoType(CSSPseudoElementType::NotPseudo)
|
||||
OwningElementRef() = default;
|
||||
|
||||
explicit OwningElementRef(const NonOwningAnimationTarget& aTarget)
|
||||
: mTarget(aTarget)
|
||||
{ }
|
||||
|
||||
OwningElementRef(dom::Element& aElement,
|
||||
CSSPseudoElementType aPseudoType)
|
||||
: mElement(&aElement)
|
||||
, mPseudoType(aPseudoType)
|
||||
: mTarget(&aElement, aPseudoType)
|
||||
{ }
|
||||
|
||||
bool Equals(const OwningElementRef& aOther) const
|
||||
{
|
||||
return mElement == aOther.mElement &&
|
||||
mPseudoType == aOther.mPseudoType;
|
||||
return mTarget == aOther.mTarget;
|
||||
}
|
||||
|
||||
bool LessThan(const OwningElementRef& aOther) const
|
||||
{
|
||||
MOZ_ASSERT(mElement && aOther.mElement,
|
||||
MOZ_ASSERT(mTarget.mElement && aOther.mTarget.mElement,
|
||||
"Elements to compare should not be null");
|
||||
|
||||
if (mElement != aOther.mElement) {
|
||||
return nsContentUtils::PositionIsBefore(mElement, aOther.mElement);
|
||||
if (mTarget.mElement != aOther.mTarget.mElement) {
|
||||
return nsContentUtils::PositionIsBefore(mTarget.mElement,
|
||||
aOther.mTarget.mElement);
|
||||
}
|
||||
|
||||
return mPseudoType == CSSPseudoElementType::NotPseudo ||
|
||||
(mPseudoType == CSSPseudoElementType::before &&
|
||||
aOther.mPseudoType == CSSPseudoElementType::after);
|
||||
return mTarget.mPseudoType == CSSPseudoElementType::NotPseudo ||
|
||||
(mTarget.mPseudoType == CSSPseudoElementType::before &&
|
||||
aOther.mTarget.mPseudoType == CSSPseudoElementType::after);
|
||||
}
|
||||
|
||||
bool IsSet() const { return !!mElement; }
|
||||
bool IsSet() const { return !!mTarget.mElement; }
|
||||
|
||||
void GetElement(dom::Element*& aElement,
|
||||
CSSPseudoElementType& aPseudoType) const {
|
||||
aElement = mElement;
|
||||
aPseudoType = mPseudoType;
|
||||
CSSPseudoElementType& aPseudoType) const
|
||||
{
|
||||
aElement = mTarget.mElement;
|
||||
aPseudoType = mTarget.mPseudoType;
|
||||
}
|
||||
|
||||
private:
|
||||
dom::Element* MOZ_NON_OWNING_REF mElement;
|
||||
CSSPseudoElementType mPseudoType;
|
||||
NonOwningAnimationTarget mTarget;
|
||||
};
|
||||
|
||||
template <class EventInfo>
|
||||
|
|
|
@ -70,7 +70,6 @@ CSS_PSEUDO_CLASS(empty, ":empty", 0, "")
|
|||
CSS_PSEUDO_CLASS(mozOnlyWhitespace, ":-moz-only-whitespace", 0, "")
|
||||
CSS_PSEUDO_CLASS(mozEmptyExceptChildrenWithLocalname, ":-moz-empty-except-children-with-localname", 0, "")
|
||||
CSS_PSEUDO_CLASS(lang, ":lang", 0, "")
|
||||
CSS_PSEUDO_CLASS(mozBoundElement, ":-moz-bound-element", 0, "")
|
||||
CSS_PSEUDO_CLASS(root, ":root", 0, "")
|
||||
CSS_PSEUDO_CLASS(any, ":-moz-any", 0, "")
|
||||
|
||||
|
|
|
@ -1968,12 +1968,6 @@ static bool SelectorMatches(Element* aElement,
|
|||
}
|
||||
break;
|
||||
|
||||
case CSSPseudoClassType::mozBoundElement:
|
||||
if (aTreeMatchContext.mScopedRoot != aElement) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case CSSPseudoClassType::root:
|
||||
if (aElement != aElement->OwnerDoc()->GetRootElement()) {
|
||||
return false;
|
||||
|
|
|
@ -342,10 +342,6 @@ struct MOZ_STACK_CLASS TreeMatchContext {
|
|||
// The document we're working with.
|
||||
nsIDocument* const mDocument;
|
||||
|
||||
// Root of scoped stylesheet (set and unset by the supplier of the
|
||||
// scoped stylesheet).
|
||||
nsIContent* mScopedRoot;
|
||||
|
||||
// Whether our document is HTML (as opposed to XML of some sort,
|
||||
// including XHTML).
|
||||
// XXX XBL2 issue: Should we be caching this? What should it be for XBL2?
|
||||
|
@ -396,7 +392,6 @@ struct MOZ_STACK_CLASS TreeMatchContext {
|
|||
, mHaveSpecifiedScope(false)
|
||||
, mVisitedHandling(aVisitedHandling)
|
||||
, mDocument(aDocument)
|
||||
, mScopedRoot(nullptr)
|
||||
, mIsHTMLDocument(aDocument->IsHTMLDocument())
|
||||
, mCompatMode(aDocument->GetCompatibilityMode())
|
||||
, mUsingPrivateBrowsing(false)
|
||||
|
|
|
@ -1624,6 +1624,10 @@ pref("network.http.keep_empty_response_headers_as_empty_string", true);
|
|||
// Max size, in bytes, for received HTTP response header.
|
||||
pref("network.http.max_response_header_size", 393216);
|
||||
|
||||
// The ratio of the transaction count for the focused window and the count of
|
||||
// all available active connections.
|
||||
pref("network.http.focused_window_transaction_ratio", "0.9");
|
||||
|
||||
// default values for FTP
|
||||
// in a DSCP environment this should be 40 (0x28, or AF11), per RFC-4594,
|
||||
// Section 4.8 "High-Throughput Data Service Class", and 80 (0x50, or AF22)
|
||||
|
|
|
@ -58,7 +58,7 @@ nsHttpConnectionMgr::OnMsgPrintDiagnostics(int32_t, ARefBase *)
|
|||
mLogData.AppendPrintf(" RestrictConnections = %d\n",
|
||||
RestrictConnections(ent));
|
||||
mLogData.AppendPrintf(" Pending Q Length = %" PRIuSIZE "\n",
|
||||
ent->mPendingQ.Length());
|
||||
ent->PendingQLength());
|
||||
mLogData.AppendPrintf(" Active Conns Length = %" PRIuSIZE "\n",
|
||||
ent->mActiveConns.Length());
|
||||
mLogData.AppendPrintf(" Idle Conns Length = %" PRIuSIZE "\n",
|
||||
|
@ -83,9 +83,17 @@ nsHttpConnectionMgr::OnMsgPrintDiagnostics(int32_t, ARefBase *)
|
|||
mLogData.AppendPrintf(" :: Half Open #%u\n", i);
|
||||
ent->mHalfOpens[i]->PrintDiagnostics(mLogData);
|
||||
}
|
||||
for (i = 0; i < ent->mPendingQ.Length(); ++i) {
|
||||
mLogData.AppendPrintf(" :: Pending Transaction #%u\n", i);
|
||||
ent->mPendingQ[i]->PrintDiagnostics(mLogData);
|
||||
i = 0;
|
||||
for (auto it = ent->mPendingTransactionTable.Iter();
|
||||
!it.Done();
|
||||
it.Next()) {
|
||||
mLogData.AppendPrintf(" :: Pending Transactions with Window ID = %"
|
||||
PRIu64 "\n", it.Key());
|
||||
for (uint32_t j = 0; j < it.UserData()->Length(); ++j) {
|
||||
mLogData.AppendPrintf(" ::: Pending Transaction #%u\n", i);
|
||||
it.UserData()->ElementAt(j)->PrintDiagnostics(mLogData);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < ent->mCoalescingKeys.Length(); ++i) {
|
||||
mLogData.AppendPrintf(" :: Coalescing Key #%u %s\n",
|
||||
|
@ -198,10 +206,10 @@ nsHttpTransaction::PrintDiagnostics(nsCString &log)
|
|||
|
||||
nsAutoCString requestURI;
|
||||
mRequestHead->RequestURI(requestURI);
|
||||
log.AppendPrintf(" ::: uri = %s\n", requestURI.get());
|
||||
log.AppendPrintf(" caps = 0x%x\n", mCaps);
|
||||
log.AppendPrintf(" priority = %d\n", mPriority);
|
||||
log.AppendPrintf(" restart count = %u\n", mRestartCount);
|
||||
log.AppendPrintf(" :::: uri = %s\n", requestURI.get());
|
||||
log.AppendPrintf(" caps = 0x%x\n", mCaps);
|
||||
log.AppendPrintf(" priority = %d\n", mPriority);
|
||||
log.AppendPrintf(" restart count = %u\n", mRestartCount);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -306,6 +306,13 @@ HSTSPrimingListener::StartHSTSPriming(nsIChannel* aRequestChannel,
|
|||
nsCOMPtr<nsIHttpChannelInternal> internal = do_QueryInterface(primingChannel);
|
||||
NS_ENSURE_STATE(internal);
|
||||
|
||||
// Since this is a perfomrance critical request (blocks the page load) we
|
||||
// want to get the response ASAP.
|
||||
nsCOMPtr<nsIClassOfService> classOfService(do_QueryInterface(primingChannel));
|
||||
if (classOfService) {
|
||||
classOfService->AddClassFlags(nsIClassOfService::UrgentStart);
|
||||
}
|
||||
|
||||
// Currently using HEAD per the draft, but under discussion to change to GET
|
||||
// with credentials so if the upgrade is approved the result is already cached.
|
||||
rv = httpChannel->SetRequestMethod(NS_LITERAL_CSTRING("HEAD"));
|
||||
|
|
|
@ -1372,6 +1372,19 @@ NS_IMETHODIMP HttpBaseChannel::GetTopLevelContentWindowId(uint64_t *aWindowId)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP HttpBaseChannel::SetTopLevelOuterContentWindowId(uint64_t aWindowId)
|
||||
{
|
||||
mTopLevelOuterContentWindowId = aWindowId;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP HttpBaseChannel::GetTopLevelOuterContentWindowId(uint64_t *aWindowId)
|
||||
{
|
||||
EnsureTopLevelOuterContentWindowId();
|
||||
*aWindowId = mTopLevelOuterContentWindowId;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP HttpBaseChannel::SetTopLevelContentWindowId(uint64_t aWindowId)
|
||||
{
|
||||
mContentWindowId = aWindowId;
|
||||
|
|
|
@ -206,6 +206,8 @@ public:
|
|||
NS_IMETHOD SetChannelId(const nsACString& aChannelId) override;
|
||||
NS_IMETHOD GetTopLevelContentWindowId(uint64_t *aContentWindowId) override;
|
||||
NS_IMETHOD SetTopLevelContentWindowId(uint64_t aContentWindowId) override;
|
||||
NS_IMETHOD GetTopLevelOuterContentWindowId(uint64_t *aWindowId) override;
|
||||
NS_IMETHOD SetTopLevelOuterContentWindowId(uint64_t aWindowId) override;
|
||||
NS_IMETHOD GetIsTrackingResource(bool* aIsTrackingResource) override;
|
||||
|
||||
// nsIHttpChannelInternal
|
||||
|
@ -360,11 +362,6 @@ public: /* Necko internal use only... */
|
|||
mIsTrackingResource = true;
|
||||
}
|
||||
|
||||
void SetTopLevelOuterContentWindowId(uint64_t aTopLevelOuterContentWindowId)
|
||||
{
|
||||
mTopLevelOuterContentWindowId = aTopLevelOuterContentWindowId;
|
||||
}
|
||||
|
||||
protected:
|
||||
// Handle notifying listener, removing from loadgroup if request failed.
|
||||
void DoNotifyListener();
|
||||
|
|
|
@ -81,6 +81,18 @@ NullHttpChannel::SetTopLevelContentWindowId(uint64_t aWindowId)
|
|||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
NullHttpChannel::GetTopLevelOuterContentWindowId(uint64_t *aWindowId)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
NullHttpChannel::SetTopLevelOuterContentWindowId(uint64_t aWindowId)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
NullHttpChannel::GetIsTrackingResource(bool* aIsTrackingResource)
|
||||
{
|
||||
|
|
|
@ -50,6 +50,12 @@ public:
|
|||
return PR_SecondsToInterval(15);
|
||||
}
|
||||
|
||||
// We have to override this function because |mTransaction| in nsHalfOpenSocket
|
||||
// could be either nsHttpTransaction or NullHttpTransaction.
|
||||
// NullHttpTransaction will be activated on the connection immediately after
|
||||
// creation and be never put in a pending queue, so it's OK to just return 0.
|
||||
uint64_t TopLevelOuterContentWindowId() override { return 0; }
|
||||
|
||||
protected:
|
||||
virtual ~NullHttpTransaction();
|
||||
|
||||
|
|
|
@ -183,6 +183,11 @@ public:
|
|||
virtual MOZ_MUST_USE nsresult Finish0RTT(bool aRestart, bool aAlpnChanged) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
virtual uint64_t TopLevelOuterContentWindowId() {
|
||||
MOZ_ASSERT(false);
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsAHttpTransaction, NS_AHTTPTRANSACTION_IID)
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include "mozilla/Unused.h"
|
||||
#include "nsIURI.h"
|
||||
|
||||
#include "mozilla/Move.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -550,7 +551,7 @@ nsHttpConnectionMgr::ClearConnectionHistory()
|
|||
ent->mActiveConns.Length() == 0 &&
|
||||
ent->mHalfOpens.Length() == 0 &&
|
||||
ent->mUrgentStartQ.Length() == 0 &&
|
||||
ent->mPendingQ.Length() == 0) {
|
||||
ent->PendingQLength() == 0) {
|
||||
iter.Remove();
|
||||
}
|
||||
}
|
||||
|
@ -635,10 +636,18 @@ nsHttpConnectionMgr::LookupConnectionEntry(nsHttpConnectionInfo *ci,
|
|||
return preferred;
|
||||
}
|
||||
|
||||
if (trans &&
|
||||
(preferred->mPendingQ.Contains(trans, PendingComparator()) ||
|
||||
preferred->mUrgentStartQ.Contains(trans, PendingComparator()))) {
|
||||
return preferred;
|
||||
if (trans) {
|
||||
if (preferred->mUrgentStartQ.Contains(trans, PendingComparator())) {
|
||||
return preferred;
|
||||
}
|
||||
|
||||
nsTArray<RefPtr<PendingTransactionInfo>> *infoArray;
|
||||
if (preferred->mPendingTransactionTable.Get(
|
||||
trans->TopLevelOuterContentWindowId(), &infoArray)) {
|
||||
if (infoArray->Contains(trans, PendingComparator())) {
|
||||
return preferred;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Neither conn nor trans found in preferred, use the default entry
|
||||
|
@ -879,15 +888,17 @@ nsHttpConnectionMgr::GetSpdyPreferredEnt(nsConnectionEntry *aOriginalEntry)
|
|||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
bool
|
||||
nsHttpConnectionMgr::DispatchPendingQ(nsTArray<RefPtr<nsHttpConnectionMgr::PendingTransactionInfo> > &pendingQ,
|
||||
nsConnectionEntry *ent,
|
||||
bool &dispatchedSuccessfully,
|
||||
bool considerAll)
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
|
||||
PendingTransactionInfo *pendingTransInfo = nullptr;
|
||||
nsresult rv;
|
||||
bool dispatchedSuccessfully = false;
|
||||
|
||||
// if !considerAll iterate the pending list until one is dispatched successfully.
|
||||
// Keep iterating afterwards only until a transaction fails to dispatch.
|
||||
// if considerAll == true then try and dispatch all items.
|
||||
|
@ -971,6 +982,35 @@ nsHttpConnectionMgr::DispatchPendingQ(nsTArray<RefPtr<nsHttpConnectionMgr::Pendi
|
|||
++i;
|
||||
|
||||
}
|
||||
return dispatchedSuccessfully;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
nsHttpConnectionMgr::AvailableNewConnectionCount(nsConnectionEntry * ent)
|
||||
{
|
||||
// Add in the in-progress tcp connections, we will assume they are
|
||||
// keepalive enabled.
|
||||
// Exclude half-open's that has already created a usable connection.
|
||||
// This prevents the limit being stuck on ipv6 connections that
|
||||
// eventually time out after typical 21 seconds of no ACK+SYN reply.
|
||||
uint32_t totalCount =
|
||||
ent->mActiveConns.Length() + ent->UnconnectedHalfOpens();
|
||||
|
||||
uint16_t maxPersistConns;
|
||||
|
||||
if (ent->mConnInfo->UsingHttpProxy() && !ent->mConnInfo->UsingConnect()) {
|
||||
maxPersistConns = mMaxPersistConnsPerProxy;
|
||||
} else {
|
||||
maxPersistConns = mMaxPersistConnsPerHost;
|
||||
}
|
||||
|
||||
LOG(("nsHttpConnectionMgr::AvailableNewConnectionCount "
|
||||
"total connection count = %d, limit %d\n",
|
||||
totalCount, maxPersistConns));
|
||||
|
||||
return maxPersistConns > totalCount
|
||||
? maxPersistConns - totalCount
|
||||
: 0;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -983,17 +1023,112 @@ nsHttpConnectionMgr::ProcessPendingQForEntry(nsConnectionEntry *ent, bool consid
|
|||
"queued=%" PRIuSIZE "]\n",
|
||||
ent->mConnInfo->HashKey().get(), ent, ent->mActiveConns.Length(),
|
||||
ent->mIdleConns.Length(), ent->mUrgentStartQ.Length(),
|
||||
ent->mPendingQ.Length()));
|
||||
ent->PendingQLength()));
|
||||
|
||||
ProcessSpdyPendingQ(ent);
|
||||
|
||||
bool dispatchedSuccessfully = false;
|
||||
|
||||
DispatchPendingQ(ent->mUrgentStartQ, ent, dispatchedSuccessfully, considerAll);
|
||||
if (!ent->mUrgentStartQ.IsEmpty()) {
|
||||
dispatchedSuccessfully = DispatchPendingQ(ent->mUrgentStartQ,
|
||||
ent,
|
||||
considerAll);
|
||||
}
|
||||
|
||||
if (dispatchedSuccessfully && !considerAll) {
|
||||
return dispatchedSuccessfully;
|
||||
}
|
||||
DispatchPendingQ(ent->mPendingQ, ent, dispatchedSuccessfully, considerAll);
|
||||
|
||||
uint32_t availableConnections = AvailableNewConnectionCount(ent);
|
||||
// No need to try dispatching if we reach the active connection limit.
|
||||
if (!availableConnections) {
|
||||
return dispatchedSuccessfully;
|
||||
}
|
||||
|
||||
uint32_t maxFocusedWindowConnections =
|
||||
availableConnections * gHttpHandler->FocusedWindowTransactionRatio();
|
||||
MOZ_ASSERT(maxFocusedWindowConnections < availableConnections);
|
||||
|
||||
if (!maxFocusedWindowConnections) {
|
||||
maxFocusedWindowConnections = 1;
|
||||
}
|
||||
|
||||
// Only need to dispatch transactions for either focused or
|
||||
// non-focused window because considerAll is false.
|
||||
if (!considerAll) {
|
||||
nsTArray<RefPtr<PendingTransactionInfo>> pendingQ;
|
||||
ent->AppendPendingQForFocusedWindow(
|
||||
mCurrentTopLevelOuterContentWindowId,
|
||||
pendingQ,
|
||||
maxFocusedWindowConnections);
|
||||
|
||||
if (pendingQ.IsEmpty()) {
|
||||
ent->AppendPendingQForNonFocusedWindows(
|
||||
mCurrentTopLevelOuterContentWindowId,
|
||||
pendingQ,
|
||||
availableConnections);
|
||||
}
|
||||
|
||||
dispatchedSuccessfully |=
|
||||
DispatchPendingQ(pendingQ, ent, considerAll);
|
||||
|
||||
// Put the leftovers into connection entry
|
||||
for (const auto& transactionInfo : pendingQ) {
|
||||
ent->InsertTransaction(transactionInfo);
|
||||
}
|
||||
|
||||
return dispatchedSuccessfully;
|
||||
}
|
||||
|
||||
uint32_t maxNonFocusedWindowConnections =
|
||||
availableConnections - maxFocusedWindowConnections;
|
||||
nsTArray<RefPtr<PendingTransactionInfo>> pendingQ;
|
||||
nsTArray<RefPtr<PendingTransactionInfo>> remainingPendingQ;
|
||||
|
||||
ent->AppendPendingQForFocusedWindow(
|
||||
mCurrentTopLevelOuterContentWindowId,
|
||||
pendingQ,
|
||||
maxFocusedWindowConnections);
|
||||
|
||||
if (maxNonFocusedWindowConnections) {
|
||||
ent->AppendPendingQForNonFocusedWindows(
|
||||
mCurrentTopLevelOuterContentWindowId,
|
||||
remainingPendingQ,
|
||||
maxNonFocusedWindowConnections);
|
||||
}
|
||||
|
||||
// If the slots for the non-focused window are not filled up to
|
||||
// the availability, try to use the remaining available connections
|
||||
// for the focused window (with preference for the focused window).
|
||||
if (remainingPendingQ.Length() < maxNonFocusedWindowConnections) {
|
||||
ent->AppendPendingQForFocusedWindow(
|
||||
mCurrentTopLevelOuterContentWindowId,
|
||||
pendingQ,
|
||||
maxNonFocusedWindowConnections - remainingPendingQ.Length());
|
||||
}
|
||||
|
||||
MOZ_ASSERT(pendingQ.Length() + remainingPendingQ.Length() <=
|
||||
availableConnections);
|
||||
|
||||
LOG(("nsHttpConnectionMgr::ProcessPendingQForEntry "
|
||||
"pendingQ.Length()=%" PRIuSIZE
|
||||
", remainingPendingQ.Length()=%" PRIuSIZE "\n",
|
||||
pendingQ.Length(), remainingPendingQ.Length()));
|
||||
|
||||
// Append elements in |remainingPendingQ| to |pendingQ|. The order in
|
||||
// |pendingQ| is like: [focusedWindowTrans...nonFocusedWindowTrans].
|
||||
pendingQ.AppendElements(Move(remainingPendingQ));
|
||||
|
||||
dispatchedSuccessfully |=
|
||||
DispatchPendingQ(pendingQ, ent, considerAll);
|
||||
|
||||
// Put the leftovers into connection entry
|
||||
for (const auto& transactionInfo : pendingQ) {
|
||||
ent->InsertTransaction(transactionInfo);
|
||||
}
|
||||
|
||||
// Only remove empty pendingQ when considerAll is true.
|
||||
ent->RemoveEmptyPendingQ();
|
||||
|
||||
return dispatchedSuccessfully;
|
||||
}
|
||||
|
@ -1021,23 +1156,10 @@ nsHttpConnectionMgr::AtActiveConnectionLimit(nsConnectionEntry *ent, uint32_t ca
|
|||
LOG(("nsHttpConnectionMgr::AtActiveConnectionLimit [ci=%s caps=%x]\n",
|
||||
ci->HashKey().get(), caps));
|
||||
|
||||
// Add in the in-progress tcp connections, we will assume they are
|
||||
// keepalive enabled.
|
||||
// Exclude half-open's that has already created a usable connection.
|
||||
// This prevents the limit being stuck on ipv6 connections that
|
||||
// eventually time out after typical 21 seconds of no ACK+SYN reply.
|
||||
uint32_t totalCount =
|
||||
ent->mActiveConns.Length() + ent->UnconnectedHalfOpens();
|
||||
|
||||
uint16_t maxPersistConns;
|
||||
|
||||
if (ci->UsingHttpProxy() && !ci->UsingConnect())
|
||||
maxPersistConns = mMaxPersistConnsPerProxy;
|
||||
else
|
||||
maxPersistConns = mMaxPersistConnsPerHost;
|
||||
uint32_t availableConnections = AvailableNewConnectionCount(ent);
|
||||
|
||||
if (caps & NS_HTTP_URGENT_START) {
|
||||
if (totalCount >= static_cast<uint32_t>(mMaxUrgentStartQ + maxPersistConns)) {
|
||||
if (availableConnections > static_cast<uint32_t>(mMaxUrgentStartQ)) {
|
||||
LOG(("The number of total connections are greater than or equal to sum of "
|
||||
"max urgent-start queue length and the number of max persistent connections.\n"));
|
||||
return true;
|
||||
|
@ -1062,11 +1184,8 @@ nsHttpConnectionMgr::AtActiveConnectionLimit(nsConnectionEntry *ent, uint32_t ca
|
|||
return true;
|
||||
}
|
||||
|
||||
LOG((" connection count = %d, limit %d\n", totalCount, maxPersistConns));
|
||||
|
||||
// use >= just to be safe
|
||||
bool result = (totalCount >= maxPersistConns);
|
||||
LOG((" result: %s", result ? "true" : "false"));
|
||||
bool result = !availableConnections;
|
||||
LOG(("AtActiveConnectionLimit result: %s", result ? "true" : "false"));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -1711,15 +1830,15 @@ nsHttpConnectionMgr::ProcessNewTransaction(nsHttpTransaction *trans)
|
|||
if (trans->Caps() & NS_HTTP_URGENT_START) {
|
||||
LOG((" adding transaction to pending queue "
|
||||
"[trans=%p urgent-start-count=%" PRIuSIZE "]\n",
|
||||
trans, ent->mUrgentStartQ.Length()+1));
|
||||
trans, ent->mUrgentStartQ.Length() + 1));
|
||||
// put this transaction on the urgent-start queue...
|
||||
InsertTransactionSorted(ent->mUrgentStartQ, pendingTransInfo);
|
||||
} else {
|
||||
LOG((" adding transaction to pending queue "
|
||||
"[trans=%p pending-count=%" PRIuSIZE "]\n",
|
||||
trans, ent->mPendingQ.Length()+1));
|
||||
trans, ent->PendingQLength() + 1));
|
||||
// put this transaction on the pending queue...
|
||||
InsertTransactionSorted(ent->mPendingQ, pendingTransInfo);
|
||||
ent->InsertTransaction(pendingTransInfo);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -1893,11 +2012,21 @@ nsHttpConnectionMgr::ProcessSpdyPendingQ(nsConnectionEntry *ent)
|
|||
if (!conn || !conn->CanDirectlyActivate()) {
|
||||
return;
|
||||
}
|
||||
|
||||
DispatchSpdyPendingQ(ent->mUrgentStartQ, ent, conn);
|
||||
if (!conn->CanDirectlyActivate()) {
|
||||
return;
|
||||
}
|
||||
DispatchSpdyPendingQ(ent->mPendingQ, ent, conn);
|
||||
|
||||
nsTArray<RefPtr<PendingTransactionInfo>> pendingQ;
|
||||
// XXX Get all transactions for SPDY currently.
|
||||
ent->AppendPendingQForNonFocusedWindows(0, pendingQ);
|
||||
DispatchSpdyPendingQ(pendingQ, ent, conn);
|
||||
|
||||
// Put the leftovers back in the pending queue.
|
||||
for (const auto& transactionInfo : pendingQ) {
|
||||
ent->InsertTransaction(transactionInfo);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2012,11 +2141,16 @@ nsHttpConnectionMgr::OnMsgShutdown(int32_t, ARefBase *param)
|
|||
}
|
||||
|
||||
// Close all pending transactions.
|
||||
while (ent->mPendingQ.Length()) {
|
||||
PendingTransactionInfo *pendingTransInfo = ent->mPendingQ[0];
|
||||
pendingTransInfo->mTransaction->Close(NS_ERROR_ABORT);
|
||||
ent->mPendingQ.RemoveElementAt(0);
|
||||
for (auto it = ent->mPendingTransactionTable.Iter();
|
||||
!it.Done();
|
||||
it.Next()) {
|
||||
while (it.UserData()->Length()) {
|
||||
PendingTransactionInfo *pendingTransInfo = (*it.UserData())[0];
|
||||
pendingTransInfo->mTransaction->Close(NS_ERROR_ABORT);
|
||||
it.UserData()->RemoveElementAt(0);
|
||||
}
|
||||
}
|
||||
ent->mPendingTransactionTable.Clear();
|
||||
|
||||
// Close all half open tcp connections.
|
||||
for (int32_t i = int32_t(ent->mHalfOpens.Length()) - 1; i >= 0; i--) {
|
||||
|
@ -2083,14 +2217,18 @@ nsHttpConnectionMgr::OnMsgReschedTransaction(int32_t priority, ARefBase *param)
|
|||
|
||||
if (ent) {
|
||||
int32_t caps = trans->Caps();
|
||||
nsTArray<RefPtr<PendingTransactionInfo>> *pendingQ;
|
||||
nsTArray<RefPtr<PendingTransactionInfo>> *pendingQ = nullptr;
|
||||
if (caps & NS_HTTP_URGENT_START) {
|
||||
pendingQ = &(ent->mUrgentStartQ);
|
||||
} else {
|
||||
pendingQ = &(ent->mPendingQ);
|
||||
pendingQ =
|
||||
ent->mPendingTransactionTable.Get(
|
||||
trans->TopLevelOuterContentWindowId());
|
||||
}
|
||||
|
||||
int32_t index = pendingQ->IndexOf(trans, 0, PendingComparator());
|
||||
int32_t index = pendingQ
|
||||
? pendingQ->IndexOf(trans, 0, PendingComparator())
|
||||
: -1;
|
||||
if (index >= 0) {
|
||||
RefPtr<PendingTransactionInfo> pendingTransInfo = (*pendingQ)[index];
|
||||
pendingQ->RemoveElementAt(index);
|
||||
|
@ -2127,29 +2265,25 @@ nsHttpConnectionMgr::OnMsgCancelTransaction(int32_t reason, ARefBase *param)
|
|||
int32_t transIndex;
|
||||
// We will abandon all half-open sockets belonging to the given
|
||||
// transaction.
|
||||
nsTArray<RefPtr<PendingTransactionInfo>> *infoArray;
|
||||
RefPtr<PendingTransactionInfo> pendingTransInfo;
|
||||
if (caps & NS_HTTP_URGENT_START) {
|
||||
transIndex = ent->mUrgentStartQ.IndexOf(trans, 0,
|
||||
PendingComparator());
|
||||
if (transIndex >=0) {
|
||||
LOG(("nsHttpConnectionMgr::OnMsgCancelTransaction [trans=%p]"
|
||||
" found in urgentStart queue\n", trans));
|
||||
pendingTransInfo = ent->mUrgentStartQ[transIndex];
|
||||
// We do not need to ReleaseClaimedSockets while we are
|
||||
// going to close them all any way!
|
||||
ent->mUrgentStartQ.RemoveElementAt(transIndex);
|
||||
}
|
||||
infoArray = &ent->mUrgentStartQ;
|
||||
} else {
|
||||
transIndex = ent->mPendingQ.IndexOf(trans, 0,
|
||||
PendingComparator());
|
||||
if (transIndex >=0) {
|
||||
LOG(("nsHttpConnectionMgr::OnMsgCancelTransaction [trans=%p]"
|
||||
" found in pending queue\n", trans));
|
||||
pendingTransInfo = ent->mPendingQ[transIndex];
|
||||
// We do not need to ReleaseClaimedSockets while we are
|
||||
// going to close them all any way!
|
||||
ent->mPendingQ.RemoveElementAt(transIndex);
|
||||
}
|
||||
infoArray = ent->mPendingTransactionTable.Get(
|
||||
trans->TopLevelOuterContentWindowId());
|
||||
}
|
||||
|
||||
transIndex = infoArray
|
||||
? infoArray->IndexOf(trans, 0, PendingComparator())
|
||||
: -1;
|
||||
if (transIndex >=0) {
|
||||
LOG(("nsHttpConnectionMgr::OnMsgCancelTransaction [trans=%p]"
|
||||
" found in urgentStart queue\n", trans));
|
||||
pendingTransInfo = (*infoArray)[transIndex];
|
||||
// We do not need to ReleaseClaimedSockets while we are
|
||||
// going to close them all any way!
|
||||
infoArray->RemoveElementAt(transIndex);
|
||||
}
|
||||
|
||||
// Abandon all half-open sockets belonging to the given transaction.
|
||||
|
@ -2228,6 +2362,21 @@ nsHttpConnectionMgr::CancelTransactions(nsHttpConnectionInfo *ci, nsresult code)
|
|||
return PostEvent(&nsHttpConnectionMgr::OnMsgCancelTransactions, intReason, ci);
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpConnectionMgr::CancelTransactionsHelper(
|
||||
nsTArray<RefPtr<nsHttpConnectionMgr::PendingTransactionInfo>> &pendingQ,
|
||||
const nsHttpConnectionInfo *ci,
|
||||
const nsHttpConnectionMgr::nsConnectionEntry *ent,
|
||||
nsresult reason)
|
||||
{
|
||||
for (const auto& pendingTransInfo : pendingQ) {
|
||||
LOG(("nsHttpConnectionMgr::OnMsgCancelTransactions %s %p %p\n",
|
||||
ci->HashKey().get(), ent, pendingTransInfo->mTransaction.get()));
|
||||
pendingTransInfo->mTransaction->Close(reason);
|
||||
}
|
||||
pendingQ.Clear();
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpConnectionMgr::OnMsgCancelTransactions(int32_t code, ARefBase *param)
|
||||
{
|
||||
|
@ -2240,23 +2389,14 @@ nsHttpConnectionMgr::OnMsgCancelTransactions(int32_t code, ARefBase *param)
|
|||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = ent->mUrgentStartQ.Length(); i > 0;) {
|
||||
--i;
|
||||
PendingTransactionInfo *pendingTransInfo = ent->mUrgentStartQ[i];
|
||||
LOG(("nsHttpConnectionMgr::OnMsgCancelTransactions %s %p %p\n",
|
||||
ci->HashKey().get(), ent, pendingTransInfo->mTransaction.get()));
|
||||
pendingTransInfo->mTransaction->Close(reason);
|
||||
ent->mUrgentStartQ.RemoveElementAt(i);
|
||||
}
|
||||
CancelTransactionsHelper(ent->mUrgentStartQ, ci, ent, reason);
|
||||
|
||||
for (uint32_t i = ent->mPendingQ.Length(); i > 0;) {
|
||||
--i;
|
||||
PendingTransactionInfo *pendingTransInfo = ent->mPendingQ[i];
|
||||
LOG(("nsHttpConnectionMgr::OnMsgCancelTransactions %s %p %p\n",
|
||||
ci->HashKey().get(), ent, pendingTransInfo->mTransaction.get()));
|
||||
pendingTransInfo->mTransaction->Close(reason);
|
||||
ent->mPendingQ.RemoveElementAt(i);
|
||||
for (auto it = ent->mPendingTransactionTable.Iter();
|
||||
!it.Done();
|
||||
it.Next()) {
|
||||
CancelTransactionsHelper(*it.UserData(), ci, ent, reason);
|
||||
}
|
||||
ent->mPendingTransactionTable.Clear();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2326,13 +2466,15 @@ nsHttpConnectionMgr::OnMsgPruneDeadConnections(int32_t, ARefBase *)
|
|||
ConditionallyStopPruneDeadConnectionsTimer();
|
||||
}
|
||||
|
||||
ent->RemoveEmptyPendingQ();
|
||||
|
||||
// If this entry is empty, we have too many entries busy then
|
||||
// we can clean it up and restart
|
||||
if (mCT.Count() > 125 &&
|
||||
ent->mIdleConns.Length() == 0 &&
|
||||
ent->mActiveConns.Length() == 0 &&
|
||||
ent->mHalfOpens.Length() == 0 &&
|
||||
ent->mPendingQ.Length() == 0 &&
|
||||
ent->PendingQLength() == 0 &&
|
||||
ent->mUrgentStartQ.Length() == 0 &&
|
||||
(!ent->mUsingSpdy || mCT.Count() > 300)) {
|
||||
LOG((" removing empty connection entry\n"));
|
||||
|
@ -2344,7 +2486,12 @@ nsHttpConnectionMgr::OnMsgPruneDeadConnections(int32_t, ARefBase *)
|
|||
ent->mIdleConns.Compact();
|
||||
ent->mActiveConns.Compact();
|
||||
ent->mUrgentStartQ.Compact();
|
||||
ent->mPendingQ.Compact();
|
||||
|
||||
for (auto it = ent->mPendingTransactionTable.Iter();
|
||||
!it.Done();
|
||||
it.Next()) {
|
||||
it.UserData()->Compact();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2692,7 +2839,7 @@ nsHttpConnectionMgr::TimeoutTick()
|
|||
" urgentStart pending=%" PRIuSIZE "\n",
|
||||
this, ent->mConnInfo->Origin(), ent->mIdleConns.Length(),
|
||||
ent->mActiveConns.Length(), ent->mHalfOpens.Length(),
|
||||
ent->mPendingQ.Length(), ent->mUrgentStartQ.Length()));
|
||||
ent->PendingQLength(), ent->mUrgentStartQ.Length()));
|
||||
|
||||
// First call the tick handler for each active connection.
|
||||
PRIntervalTime tickTime = PR_IntervalNow();
|
||||
|
@ -3225,6 +3372,34 @@ nsHttpConnectionMgr::nsHalfOpenSocket::Notify(nsITimer *timer)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
already_AddRefed<nsHttpConnectionMgr::PendingTransactionInfo>
|
||||
nsHttpConnectionMgr::
|
||||
nsHalfOpenSocket::FindTransactionHelper(bool removeWhenFound)
|
||||
{
|
||||
uint32_t caps = mTransaction->Caps();
|
||||
nsTArray<RefPtr<PendingTransactionInfo>> *pendingQ = nullptr;
|
||||
if (caps & NS_HTTP_URGENT_START) {
|
||||
pendingQ = &mEnt->mUrgentStartQ;
|
||||
} else {
|
||||
pendingQ =
|
||||
mEnt->mPendingTransactionTable.Get(
|
||||
mTransaction->TopLevelOuterContentWindowId());
|
||||
}
|
||||
|
||||
int32_t index = pendingQ
|
||||
? pendingQ->IndexOf(mTransaction, 0, PendingComparator())
|
||||
: -1;
|
||||
|
||||
RefPtr<PendingTransactionInfo> info;
|
||||
if (index != -1) {
|
||||
info = (*pendingQ)[index];
|
||||
if (removeWhenFound) {
|
||||
pendingQ->RemoveElementAt(index);
|
||||
}
|
||||
}
|
||||
return info.forget();
|
||||
}
|
||||
|
||||
// method for nsIAsyncOutputStreamCallback
|
||||
NS_IMETHODIMP
|
||||
nsHttpConnectionMgr::
|
||||
|
@ -3305,28 +3480,14 @@ nsHalfOpenSocket::OnOutputStreamReady(nsIAsyncOutputStream *out)
|
|||
mHasConnected = true;
|
||||
|
||||
// if this is still in the pending list, remove it and dispatch it
|
||||
uint32_t caps = mTransaction->Caps();
|
||||
int32_t index;
|
||||
if (caps & NS_HTTP_URGENT_START) {
|
||||
index = mEnt->mUrgentStartQ.IndexOf(mTransaction, 0,
|
||||
PendingComparator());
|
||||
} else {
|
||||
index = mEnt->mPendingQ.IndexOf(mTransaction, 0, PendingComparator());
|
||||
}
|
||||
if (index > -1) {
|
||||
RefPtr<PendingTransactionInfo> pendingTransInfo = FindTransactionHelper(true);
|
||||
if (pendingTransInfo) {
|
||||
MOZ_ASSERT(!mSpeculative,
|
||||
"Speculative Half Open found mTransaction");
|
||||
RefPtr<PendingTransactionInfo> temp;
|
||||
if (caps & NS_HTTP_URGENT_START) {
|
||||
temp = mEnt->mUrgentStartQ[index];
|
||||
mEnt->mUrgentStartQ.RemoveElementAt(index);
|
||||
} else {
|
||||
temp = mEnt->mPendingQ[index];
|
||||
mEnt->mPendingQ.RemoveElementAt(index);
|
||||
}
|
||||
|
||||
gHttpHandler->ConnMgr()->AddActiveConn(conn, mEnt);
|
||||
rv = gHttpHandler->ConnMgr()->DispatchTransaction(mEnt,
|
||||
temp->mTransaction,
|
||||
pendingTransInfo->mTransaction,
|
||||
conn);
|
||||
} else {
|
||||
// this transaction was dispatched off the pending q before all the
|
||||
|
@ -3344,7 +3505,7 @@ nsHalfOpenSocket::OnOutputStreamReady(nsIAsyncOutputStream *out)
|
|||
// NullHttpTransaction does not know how to drive Connect
|
||||
if (mEnt->mConnInfo->FirstHopSSL() &&
|
||||
!mEnt->mUrgentStartQ.Length() &&
|
||||
!mEnt->mPendingQ.Length() &&
|
||||
!mEnt->PendingQLength() &&
|
||||
!mEnt->mConnInfo->UsingConnect()) {
|
||||
LOG(("nsHalfOpenSocket::OnOutputStreamReady null transaction will "
|
||||
"be used to finish SSL handshake on conn %p\n", conn.get()));
|
||||
|
@ -3383,9 +3544,10 @@ nsHttpConnectionMgr::nsHalfOpenSocket::OnTransportStatus(nsITransport *trans,
|
|||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
|
||||
if (mTransaction) {
|
||||
RefPtr<PendingTransactionInfo> info = FindTransactionHelper(false);
|
||||
if ((trans == mSocketTransport) ||
|
||||
((trans == mBackupTransport) && (status == NS_NET_STATUS_CONNECTED_TO) &&
|
||||
mEnt->mPendingQ.Contains(mTransaction, PendingComparator()))) {
|
||||
info)) {
|
||||
// Send this status event only if the transaction is still panding,
|
||||
// i.e. it has not found a free already connected socket.
|
||||
// Sockets in halfOpen state can only get following events:
|
||||
|
@ -3656,6 +3818,115 @@ nsConnectionEntry::ResetIPFamilyPreference()
|
|||
mPreferIPv6 = false;
|
||||
}
|
||||
|
||||
size_t
|
||||
nsHttpConnectionMgr::nsConnectionEntry::PendingQLength() const
|
||||
{
|
||||
size_t length = 0;
|
||||
for (auto it = mPendingTransactionTable.ConstIter(); !it.Done(); it.Next()) {
|
||||
length += it.UserData()->Length();
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpConnectionMgr::
|
||||
nsConnectionEntry::InsertTransaction(PendingTransactionInfo *info)
|
||||
{
|
||||
LOG(("nsHttpConnectionMgr::nsConnectionEntry::InsertTransaction"
|
||||
" trans=%p, windowId=%" PRIu64 "\n",
|
||||
info->mTransaction.get(),
|
||||
info->mTransaction->TopLevelOuterContentWindowId()));
|
||||
|
||||
uint64_t windowId = info->mTransaction->TopLevelOuterContentWindowId();
|
||||
nsTArray<RefPtr<PendingTransactionInfo>> *infoArray;
|
||||
if (!mPendingTransactionTable.Get(windowId, &infoArray)) {
|
||||
infoArray = new nsTArray<RefPtr<PendingTransactionInfo>>();
|
||||
mPendingTransactionTable.Put(windowId, infoArray);
|
||||
}
|
||||
|
||||
gHttpHandler->ConnMgr()->InsertTransactionSorted(*infoArray, info);
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpConnectionMgr::
|
||||
nsConnectionEntry::AppendPendingQForFocusedWindow(
|
||||
uint64_t windowId,
|
||||
nsTArray<RefPtr<PendingTransactionInfo>> &result,
|
||||
uint32_t maxCount)
|
||||
{
|
||||
nsTArray<RefPtr<PendingTransactionInfo>> *infoArray = nullptr;
|
||||
if (!mPendingTransactionTable.Get(windowId, &infoArray)) {
|
||||
result.Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t countToAppend = maxCount;
|
||||
countToAppend =
|
||||
countToAppend > infoArray->Length() || countToAppend == 0 ?
|
||||
infoArray->Length() :
|
||||
countToAppend;
|
||||
|
||||
result.InsertElementsAt(result.Length(),
|
||||
infoArray->Elements(),
|
||||
countToAppend);
|
||||
infoArray->RemoveElementsAt(0, countToAppend);
|
||||
|
||||
LOG(("nsConnectionEntry::AppendPendingQForFocusedWindow [ci=%s], "
|
||||
"pendingQ count=%" PRIuSIZE " for focused window (id=%" PRIu64 ")\n",
|
||||
mConnInfo->HashKey().get(), result.Length(),
|
||||
windowId));
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpConnectionMgr::
|
||||
nsConnectionEntry::AppendPendingQForNonFocusedWindows(
|
||||
uint64_t windowId,
|
||||
nsTArray<RefPtr<PendingTransactionInfo>> &result,
|
||||
uint32_t maxCount)
|
||||
{
|
||||
// XXX Adjust the order of transactions in a smarter manner.
|
||||
uint32_t totalCount = 0;
|
||||
for (auto it = mPendingTransactionTable.Iter(); !it.Done(); it.Next()) {
|
||||
if (windowId && it.Key() == windowId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t count = 0;
|
||||
for (; count < it.UserData()->Length(); ++count) {
|
||||
if (maxCount && totalCount == maxCount) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Because elements in |result| could come from multiple penndingQ,
|
||||
// call |InsertTransactionSorted| to make sure the order is correct.
|
||||
gHttpHandler->ConnMgr()->InsertTransactionSorted(
|
||||
result,
|
||||
it.UserData()->ElementAt(count));
|
||||
++totalCount;
|
||||
}
|
||||
it.UserData()->RemoveElementsAt(0, count);
|
||||
|
||||
if (maxCount && totalCount == maxCount) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LOG(("nsConnectionEntry::AppendPendingQForNonFocusedWindows [ci=%s], "
|
||||
"pendingQ count=%" PRIuSIZE " for non focused window\n",
|
||||
mConnInfo->HashKey().get(), result.Length()));
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpConnectionMgr::nsConnectionEntry::RemoveEmptyPendingQ()
|
||||
{
|
||||
for (auto it = mPendingTransactionTable.Iter(); !it.Done(); it.Next()) {
|
||||
if (it.UserData()->IsEmpty()) {
|
||||
it.Remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpConnectionMgr::MoveToWildCardConnEntry(nsHttpConnectionInfo *specificCI,
|
||||
nsHttpConnectionInfo *wildCardCI,
|
||||
|
@ -3686,12 +3957,12 @@ nsHttpConnectionMgr::MoveToWildCardConnEntry(nsHttpConnectionInfo *specificCI,
|
|||
LOG(("nsHttpConnectionMgr::MakeConnEntryWildCard ent %p "
|
||||
"idle=%" PRIuSIZE " active=%" PRIuSIZE " half=%" PRIuSIZE " pending=%" PRIuSIZE "\n",
|
||||
ent, ent->mIdleConns.Length(), ent->mActiveConns.Length(),
|
||||
ent->mHalfOpens.Length(), ent->mPendingQ.Length()));
|
||||
ent->mHalfOpens.Length(), ent->PendingQLength()));
|
||||
|
||||
LOG(("nsHttpConnectionMgr::MakeConnEntryWildCard wc-ent %p "
|
||||
"idle=%" PRIuSIZE " active=%" PRIuSIZE " half=%" PRIuSIZE " pending=%" PRIuSIZE "\n",
|
||||
wcEnt, wcEnt->mIdleConns.Length(), wcEnt->mActiveConns.Length(),
|
||||
wcEnt->mHalfOpens.Length(), wcEnt->mPendingQ.Length()));
|
||||
wcEnt->mHalfOpens.Length(), wcEnt->PendingQLength()));
|
||||
|
||||
int32_t count = ent->mActiveConns.Length();
|
||||
RefPtr<nsHttpConnection> deleteProtector(proxyConn);
|
||||
|
|
|
@ -221,7 +221,13 @@ private:
|
|||
|
||||
RefPtr<nsHttpConnectionInfo> mConnInfo;
|
||||
nsTArray<RefPtr<PendingTransactionInfo> > mUrgentStartQ;// the urgent start transaction queue
|
||||
nsTArray<RefPtr<PendingTransactionInfo> > mPendingQ; // pending transaction queue
|
||||
|
||||
// This table provides a mapping from top level outer content window id
|
||||
// to a queue of pending transaction information.
|
||||
// Note that the window id could be 0 if the http request
|
||||
// is initialized without a window.
|
||||
nsClassHashtable<nsUint64HashKey,
|
||||
nsTArray<RefPtr<PendingTransactionInfo>>> mPendingTransactionTable;
|
||||
nsTArray<RefPtr<nsHttpConnection> > mActiveConns; // active connections
|
||||
nsTArray<RefPtr<nsHttpConnection> > mIdleConns; // idle persistent connections
|
||||
nsTArray<nsHalfOpenSocket*> mHalfOpens; // half open connections
|
||||
|
@ -269,6 +275,33 @@ private:
|
|||
void RecordIPFamilyPreference(uint16_t family);
|
||||
// Resets all flags to their default values
|
||||
void ResetIPFamilyPreference();
|
||||
|
||||
// Return the count of pending transactions for all window ids.
|
||||
size_t PendingQLength() const;
|
||||
|
||||
// Add a transaction information into the pending queue in
|
||||
// |mPendingTransactionTable| according to the transaction's
|
||||
// top level outer content window id.
|
||||
void InsertTransaction(PendingTransactionInfo *info);
|
||||
|
||||
// Append transactions to the |result| whose window id
|
||||
// is equal to |windowId|.
|
||||
// NOTE: maxCount == 0 will get all transactions in the queue.
|
||||
void AppendPendingQForFocusedWindow(
|
||||
uint64_t windowId,
|
||||
nsTArray<RefPtr<PendingTransactionInfo>> &result,
|
||||
uint32_t maxCount = 0);
|
||||
|
||||
// Append transactions whose window id isn't equal to |windowId|.
|
||||
// NOTE: windowId == 0 will get all transactions for both
|
||||
// focused and non-focused windows.
|
||||
void AppendPendingQForNonFocusedWindows(
|
||||
uint64_t windowId,
|
||||
nsTArray<RefPtr<PendingTransactionInfo>> &result,
|
||||
uint32_t maxCount = 0);
|
||||
|
||||
// Remove the empty pendingQ in |mPendingTransactionTable|.
|
||||
void RemoveEmptyPendingQ();
|
||||
};
|
||||
|
||||
public:
|
||||
|
@ -327,8 +360,14 @@ private:
|
|||
|
||||
void PrintDiagnostics(nsCString &log);
|
||||
private:
|
||||
// To find out whether |mTransaction| is still in the connection entry's
|
||||
// pending queue. If the transaction is found and |removeWhenFound| is
|
||||
// true, the transaction will be removed from the pending queue.
|
||||
already_AddRefed<PendingTransactionInfo>
|
||||
FindTransactionHelper(bool removeWhenFound);
|
||||
|
||||
nsConnectionEntry *mEnt;
|
||||
RefPtr<nsAHttpTransaction> mTransaction;
|
||||
RefPtr<nsAHttpTransaction> mTransaction;
|
||||
bool mDispatchedMTransaction;
|
||||
nsCOMPtr<nsISocketTransport> mSocketTransport;
|
||||
nsCOMPtr<nsIAsyncOutputStream> mStreamOut;
|
||||
|
@ -419,10 +458,14 @@ private:
|
|||
|
||||
MOZ_MUST_USE bool ProcessPendingQForEntry(nsConnectionEntry *,
|
||||
bool considerAll);
|
||||
void DispatchPendingQ(nsTArray<RefPtr<PendingTransactionInfo>> &pendingQ,
|
||||
bool DispatchPendingQ(nsTArray<RefPtr<PendingTransactionInfo>> &pendingQ,
|
||||
nsConnectionEntry *ent,
|
||||
bool &dispatchedSuccessfully,
|
||||
bool considerAll);
|
||||
|
||||
// Given the connection entry, return the available count for creating
|
||||
// new connections. Return 0 if the active connection count is
|
||||
// exceeded |mMaxPersistConnsPerProxy| or |mMaxPersistConnsPerHost|.
|
||||
uint32_t AvailableNewConnectionCount(nsConnectionEntry * ent);
|
||||
bool AtActiveConnectionLimit(nsConnectionEntry *, uint32_t caps);
|
||||
MOZ_MUST_USE nsresult TryDispatchTransaction(nsConnectionEntry *ent,
|
||||
bool onlyReusedConnection,
|
||||
|
@ -484,6 +527,14 @@ private:
|
|||
int32_t iparam = 0,
|
||||
ARefBase *vparam = nullptr);
|
||||
|
||||
// Used to close all transactions in the |pendingQ| with the given |reason|.
|
||||
// Note that the |pendingQ| will be also cleared.
|
||||
void CancelTransactionsHelper(
|
||||
nsTArray<RefPtr<PendingTransactionInfo>> &pendingQ,
|
||||
const nsHttpConnectionInfo *ci,
|
||||
const nsConnectionEntry *ent,
|
||||
nsresult reason);
|
||||
|
||||
// message handlers
|
||||
void OnMsgShutdown (int32_t, ARefBase *);
|
||||
void OnMsgShutdownConfirm (int32_t, ARefBase *);
|
||||
|
|
|
@ -238,6 +238,7 @@ nsHttpHandler::nsHttpHandler()
|
|||
, mKeepEmptyResponseHeadersAsEmtpyString(false)
|
||||
, mDefaultHpackBuffer(4096)
|
||||
, mMaxHttpResponseHeaderSize(393216)
|
||||
, mFocusedWindowTransactionRatio(0.9f)
|
||||
{
|
||||
LOG(("Creating nsHttpHandler [this=%p].\n", this));
|
||||
|
||||
|
@ -1448,6 +1449,19 @@ nsHttpHandler::PrefsChanged(nsIPrefBranch *prefs, const char *pref)
|
|||
mMaxHttpResponseHeaderSize = val;
|
||||
}
|
||||
}
|
||||
|
||||
if (PREF_CHANGED(HTTP_PREF("focused_window_transaction_ratio"))) {
|
||||
float ratio = 0;
|
||||
rv = prefs->GetFloatPref(HTTP_PREF("focused_window_transaction_ratio"), &ratio);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
if (ratio > 0 && ratio < 1) {
|
||||
mFocusedWindowTransactionRatio = ratio;
|
||||
} else {
|
||||
NS_WARNING("Wrong value for focused_window_transaction_ratio");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// INTL options
|
||||
//
|
||||
|
|
|
@ -358,6 +358,11 @@ public:
|
|||
return mMaxHttpResponseHeaderSize;
|
||||
}
|
||||
|
||||
float FocusedWindowTransactionRatio() const
|
||||
{
|
||||
return mFocusedWindowTransactionRatio;
|
||||
}
|
||||
|
||||
private:
|
||||
virtual ~nsHttpHandler();
|
||||
|
||||
|
@ -566,6 +571,9 @@ private:
|
|||
// The max size (in bytes) for received Http response header.
|
||||
uint32_t mMaxHttpResponseHeaderSize;
|
||||
|
||||
// The ratio for dispatching transactions from the focused window.
|
||||
float mFocusedWindowTransactionRatio;
|
||||
|
||||
private:
|
||||
// For Rate Pacing Certain Network Events. Only assign this pointer on
|
||||
// socket thread.
|
||||
|
|
|
@ -171,7 +171,7 @@ public:
|
|||
MOZ_MUST_USE bool Do0RTT() override;
|
||||
MOZ_MUST_USE nsresult Finish0RTT(bool aRestart, bool aAlpnChanged /* ignored */) override;
|
||||
|
||||
uint64_t TopLevelOuterContentWindowId()
|
||||
uint64_t TopLevelOuterContentWindowId() override
|
||||
{
|
||||
return mTopLevelOuterContentWindowId;
|
||||
}
|
||||
|
|
|
@ -469,4 +469,13 @@ interface nsIHttpChannel : nsIChannel
|
|||
* should only be relied on after the channel has established a connection.
|
||||
*/
|
||||
[infallible] readonly attribute boolean isTrackingResource;
|
||||
|
||||
/**
|
||||
* ID of the top-level outer content window. Identifies this channel's
|
||||
* top-level window it comes from.
|
||||
*
|
||||
* NOTE: The setter of this attribute is currently for xpcshell test only.
|
||||
* Don't alter it otherwise.
|
||||
*/
|
||||
[must_use] attribute uint64_t topLevelOuterContentWindowId;
|
||||
};
|
||||
|
|
|
@ -739,6 +739,20 @@ nsViewSourceChannel::SetTopLevelContentWindowId(uint64_t aWindowId)
|
|||
mHttpChannel->SetTopLevelContentWindowId(aWindowId);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsViewSourceChannel::GetTopLevelOuterContentWindowId(uint64_t *aWindowId)
|
||||
{
|
||||
return !mHttpChannel ? NS_ERROR_NULL_POINTER :
|
||||
mHttpChannel->GetTopLevelOuterContentWindowId(aWindowId);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsViewSourceChannel::SetTopLevelOuterContentWindowId(uint64_t aWindowId)
|
||||
{
|
||||
return !mHttpChannel ? NS_ERROR_NULL_POINTER :
|
||||
mHttpChannel->SetTopLevelOuterContentWindowId(aWindowId);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsViewSourceChannel::GetIsTrackingResource(bool* aIsTrackingResource)
|
||||
{
|
||||
|
|
|
@ -69,6 +69,7 @@ function urgentStartHttpRequest(id) {
|
|||
}
|
||||
|
||||
function setup_httpRequests() {
|
||||
log("setup_httpRequests");
|
||||
for (var i = 0; i < maxConnections ; i++) {
|
||||
commonHttpRequest(i);
|
||||
do_test_pending();
|
||||
|
@ -105,10 +106,12 @@ HttpResponseListener.prototype =
|
|||
var responseQueue = new Array();
|
||||
function setup_http_server()
|
||||
{
|
||||
log("setup_http_server");
|
||||
var prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
|
||||
maxConnections = prefs.getIntPref("network.http.max-persistent-connections-per-server");
|
||||
urgentRequests = 2;
|
||||
totalRequests = maxConnections + urgentRequests;
|
||||
var allCommonHttpRequestReceived = false;
|
||||
// Start server; will be stopped at test cleanup time.
|
||||
server.registerPathHandler('/', function(metadata, response)
|
||||
{
|
||||
|
@ -116,6 +119,11 @@ function setup_http_server()
|
|||
log("Server recived the response id=" + id);
|
||||
response.processAsync();
|
||||
responseQueue.push(response);
|
||||
|
||||
if (responseQueue.length == maxConnections && !allCommonHttpRequestReceived) {
|
||||
allCommonHttpRequestReceived = true;
|
||||
setup_urgentStartRequests();
|
||||
}
|
||||
// Wait for all expected requests to come but don't process then.
|
||||
// Collect them in a queue for later processing. We don't want to
|
||||
// respond to the client until all the expected requests are made
|
||||
|
@ -140,6 +148,5 @@ function processResponse() {
|
|||
function run_test() {
|
||||
setup_http_server();
|
||||
setup_httpRequests();
|
||||
setup_urgentStartRequests();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,181 @@
|
|||
// test bug 1312782.
|
||||
//
|
||||
// Summary:
|
||||
// Assume we have 6 http requests in queue, 4 are from the focused window and
|
||||
// the other 2 are from the non-focused window. We want to test that the server
|
||||
// should receive 4 requests from the focused window first and then receive the
|
||||
// rest 2 requests.
|
||||
//
|
||||
// Test step:
|
||||
// 1. Create 6 dummy http requests. Server would not process responses until get
|
||||
// all 6 requests.
|
||||
// 2. Once server receive 6 dummy requests, create 4 http requests with the focused
|
||||
// window id and 2 requests with non-focused window id. Note that the requets's
|
||||
// id is a serial number starting from the focused window id.
|
||||
// 3. Server starts to process the 6 dummy http requests, so the client can start to
|
||||
// process the pending queue. Server will queue those http requests again and wait
|
||||
// until get all 6 requests.
|
||||
// 4. When the server receive all 6 requests, starts to check that the request ids of
|
||||
// the first 4 requests in the queue should be all less than focused window id
|
||||
// plus 4. Also, the request ids of the rest requests should be less than non-focused
|
||||
// window id + 2.
|
||||
|
||||
Cu.import("resource://testing-common/httpd.js");
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
var server = new HttpServer();
|
||||
server.start(-1);
|
||||
var baseURL = "http://localhost:" + server.identity.primaryPort + "/";
|
||||
var maxConnections = 0;
|
||||
var debug = false;
|
||||
const FOCUSED_WINDOW_ID = 123;
|
||||
var NON_FOCUSED_WINDOW_ID;
|
||||
var FOCUSED_WINDOW_REQUEST_COUNT;
|
||||
var NON_FOCUSED_WINDOW_REQUEST_COUNT;
|
||||
|
||||
function log(msg) {
|
||||
if (!debug) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (msg) {
|
||||
dump("TEST INFO | " + msg + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
function make_channel(url) {
|
||||
var request = NetUtil.newChannel({uri: url, loadUsingSystemPrincipal: true});
|
||||
request.QueryInterface(Ci.nsIHttpChannel);
|
||||
return request;
|
||||
}
|
||||
|
||||
function serverStopListener() {
|
||||
server.stop();
|
||||
}
|
||||
|
||||
function createHttpRequest(windowId, requestId) {
|
||||
let uri = baseURL;
|
||||
var chan = make_channel(uri);
|
||||
chan.topLevelOuterContentWindowId = windowId;
|
||||
var listner = new HttpResponseListener(requestId);
|
||||
chan.setRequestHeader("X-ID", requestId, false);
|
||||
chan.setRequestHeader("Cache-control", "no-store", false);
|
||||
chan.asyncOpen2(listner);
|
||||
log("Create http request id=" + requestId);
|
||||
}
|
||||
|
||||
function setup_dummyHttpRequests() {
|
||||
log("setup_dummyHttpRequests");
|
||||
for (var i = 0; i < maxConnections ; i++) {
|
||||
createHttpRequest(0, i);
|
||||
do_test_pending();
|
||||
}
|
||||
}
|
||||
|
||||
function setup_focusedWindowHttpRequests() {
|
||||
log("setup_focusedWindowHttpRequests");
|
||||
for (var i = 0; i < FOCUSED_WINDOW_REQUEST_COUNT ; i++) {
|
||||
createHttpRequest(FOCUSED_WINDOW_ID, FOCUSED_WINDOW_ID + i);
|
||||
do_test_pending();
|
||||
}
|
||||
}
|
||||
|
||||
function setup_nonFocusedWindowHttpRequests() {
|
||||
log("setup_nonFocusedWindowHttpRequests");
|
||||
for (var i = 0; i < NON_FOCUSED_WINDOW_REQUEST_COUNT ; i++) {
|
||||
createHttpRequest(NON_FOCUSED_WINDOW_ID, NON_FOCUSED_WINDOW_ID + i);
|
||||
do_test_pending();
|
||||
}
|
||||
}
|
||||
|
||||
function HttpResponseListener(id)
|
||||
{
|
||||
this.id = id
|
||||
};
|
||||
|
||||
HttpResponseListener.prototype =
|
||||
{
|
||||
onStartRequest: function (request, ctx) {
|
||||
},
|
||||
|
||||
onDataAvailable: function (request, ctx, stream, off, cnt) {
|
||||
},
|
||||
|
||||
onStopRequest: function (request, ctx, status) {
|
||||
log("STOP id=" + this.id);
|
||||
do_test_finished();
|
||||
}
|
||||
};
|
||||
|
||||
function check_response_id(responses, maxWindowId)
|
||||
{
|
||||
for (var i = 0; i < responses.length; i++) {
|
||||
var id = responses[i].getHeader("X-ID");
|
||||
log("response id=" + id + " maxWindowId=" + maxWindowId);
|
||||
do_check_true(id < maxWindowId);
|
||||
}
|
||||
}
|
||||
|
||||
var responseQueue = new Array();
|
||||
function setup_http_server()
|
||||
{
|
||||
log("setup_http_server");
|
||||
var prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
|
||||
maxConnections = prefs.getIntPref("network.http.max-persistent-connections-per-server");
|
||||
FOCUSED_WINDOW_REQUEST_COUNT = Math.floor(maxConnections * 0.8);
|
||||
NON_FOCUSED_WINDOW_REQUEST_COUNT = maxConnections - FOCUSED_WINDOW_REQUEST_COUNT;
|
||||
NON_FOCUSED_WINDOW_ID = FOCUSED_WINDOW_ID + FOCUSED_WINDOW_REQUEST_COUNT;
|
||||
|
||||
var allDummyHttpRequestReceived = false;
|
||||
// Start server; will be stopped at test cleanup time.
|
||||
server.registerPathHandler('/', function(metadata, response)
|
||||
{
|
||||
var id = metadata.getHeader("X-ID");
|
||||
log("Server recived the response id=" + id);
|
||||
|
||||
response.processAsync();
|
||||
response.setHeader("X-ID", id);
|
||||
responseQueue.push(response);
|
||||
|
||||
if (responseQueue.length == maxConnections && !allDummyHttpRequestReceived) {
|
||||
log("received all dummy http requets");
|
||||
allDummyHttpRequestReceived = true;
|
||||
setup_nonFocusedWindowHttpRequests();
|
||||
setup_focusedWindowHttpRequests();
|
||||
processResponses();
|
||||
} else if (responseQueue.length == maxConnections) {
|
||||
var focusedWindowResponses = responseQueue.slice(0, FOCUSED_WINDOW_REQUEST_COUNT);
|
||||
var nonFocusedWindowResponses = responseQueue.slice(FOCUSED_WINDOW_REQUEST_COUNT, responseQueue.length);
|
||||
check_response_id(focusedWindowResponses, FOCUSED_WINDOW_ID + FOCUSED_WINDOW_REQUEST_COUNT);
|
||||
check_response_id(nonFocusedWindowResponses, NON_FOCUSED_WINDOW_ID + NON_FOCUSED_WINDOW_REQUEST_COUNT);
|
||||
processResponses();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
do_register_cleanup(function() {
|
||||
server.stop(serverStopListener);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function processResponses() {
|
||||
while (responseQueue.length) {
|
||||
var resposne = responseQueue.pop();
|
||||
resposne.finish();
|
||||
}
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
setup_http_server();
|
||||
setup_dummyHttpRequests();
|
||||
|
||||
var windowIdWrapper = Cc["@mozilla.org/supports-PRUint64;1"]
|
||||
.createInstance(Ci.nsISupportsPRUint64);
|
||||
windowIdWrapper.data = FOCUSED_WINDOW_ID;
|
||||
var obsvc = Cc["@mozilla.org/observer-service;1"].
|
||||
getService(Ci.nsIObserverService);
|
||||
obsvc.notifyObservers(windowIdWrapper, "net:current-toplevel-outer-content-windowid", null);
|
||||
}
|
|
@ -384,3 +384,4 @@ skip-if = os == "android"
|
|||
[test_race_cache_network.js]
|
||||
[test_channel_priority.js]
|
||||
[test_bug1312774_http1.js]
|
||||
[test_bug1312782_http1.js]
|
||||
|
|
|
@ -53,16 +53,19 @@
|
|||
|
||||
#if defined(MOZ_PROFILING) && \
|
||||
(defined(GP_OS_windows) || defined(GP_OS_darwin))
|
||||
# define HAVE_NATIVE_UNWIND
|
||||
# define USE_NS_STACKWALK
|
||||
#endif
|
||||
|
||||
// This should also work on ARM Linux, but not tested there yet.
|
||||
#if defined(GP_PLAT_arm_android)
|
||||
# define HAVE_NATIVE_UNWIND
|
||||
# define USE_EHABI_STACKWALK
|
||||
# include "EHABIStackWalk.h"
|
||||
#endif
|
||||
|
||||
#if defined(GP_PLAT_amd64_linux) || defined(GP_PLAT_x86_linux)
|
||||
# define HAVE_NATIVE_UNWIND
|
||||
# define USE_LUL_STACKWALK
|
||||
# include "lul/LulMain.h"
|
||||
# include "lul/platform-linux-lul.h"
|
||||
|
@ -972,16 +975,14 @@ Tick(PS::LockRef aLock, ProfileBuffer* aBuffer, TickSample* aSample)
|
|||
|
||||
NotNull<PseudoStack*> stack = threadInfo.Stack();
|
||||
|
||||
#if defined(USE_NS_STACKWALK) || defined(USE_EHABI_STACKWALK) || \
|
||||
defined(USE_LUL_STACKWALK)
|
||||
#if defined(HAVE_NATIVE_UNWIND)
|
||||
if (gPS->FeatureStackWalk(aLock)) {
|
||||
DoNativeBacktrace(aLock, aBuffer, aSample);
|
||||
} else {
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
DoSampleStackTrace(aLock, aBuffer, aSample);
|
||||
}
|
||||
#else
|
||||
DoSampleStackTrace(aLock, aBuffer, aSample);
|
||||
#endif
|
||||
|
||||
// Don't process the PeudoStack's markers if we're synchronously sampling the
|
||||
// current thread.
|
||||
|
@ -1461,16 +1462,6 @@ set_profiler_entries(PS::LockRef aLock, const char* aEntries)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
is_native_unwinding_avail()
|
||||
{
|
||||
# if defined(HAVE_NATIVE_UNWIND)
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
profiler_usage(int aExitCode)
|
||||
{
|
||||
|
@ -1508,7 +1499,11 @@ profiler_usage(int aExitCode)
|
|||
"\n"
|
||||
" This platform %s native unwinding.\n"
|
||||
"\n",
|
||||
is_native_unwinding_avail() ? "supports" : "does not support\n"
|
||||
#if defined(HAVE_NATIVE_UNWIND)
|
||||
"supports"
|
||||
#else
|
||||
"does not support"
|
||||
#endif
|
||||
);
|
||||
|
||||
exit(aExitCode);
|
||||
|
@ -2295,7 +2290,7 @@ profiler_get_features()
|
|||
MOZ_RELEASE_ASSERT(gPS);
|
||||
|
||||
static const char* features[] = {
|
||||
#if defined(MOZ_PROFILING) && defined(HAVE_NATIVE_UNWIND)
|
||||
#if defined(HAVE_NATIVE_UNWIND)
|
||||
// Walk the C++ stack.
|
||||
"stackwalk",
|
||||
#endif
|
||||
|
|
|
@ -111,24 +111,6 @@ public:
|
|||
static tid_t GetCurrentId();
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// HAVE_NATIVE_UNWIND
|
||||
//
|
||||
// Pseudo backtraces are available on all platforms. Native
|
||||
// backtraces are available only on selected platforms. Breakpad is
|
||||
// the only supported native unwinder. HAVE_NATIVE_UNWIND is set at
|
||||
// build time to indicate whether native unwinding is possible on this
|
||||
// platform.
|
||||
|
||||
#undef HAVE_NATIVE_UNWIND
|
||||
#if defined(MOZ_PROFILING) && \
|
||||
(defined(GP_OS_windows) || \
|
||||
defined(GP_OS_darwin) || \
|
||||
defined(GP_OS_linux) || \
|
||||
defined(GP_PLAT_arm_android))
|
||||
# define HAVE_NATIVE_UNWIND
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// ProfilerState auxiliaries
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче