mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 13:34:03 +00:00
import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 1257611 - Fix wrong CondVar::Wait() and Monitor::Wait() usage in netwerk/cache2, r=honzab (54f1a79f43) - Bug 1239687 - Leak invalid/doomed file handles immediately after HTTP cache shutdown. r=michal (a20bcf662b) - Bug 996836 - Merge CLOSE and WRITE priority in cache2 I/O thread. r=michal (8b0af50593) - Bug 1265243 - Do not initialize CacheObserver in the child process, r=honzab (87f69529d2) - Bug 1247432 - Don't do any unnecessary I/O in cache2 after shutdown. r=michal (7c5a2b89ac) - Bug 1220272 - Fix signalling in HTTP cache test code suspender. r=michal (293a16731d) - Bug 1160368 - Part 2: Clean up some cruft in nsCookie.h from PRBool/bool conversions. r=jdm (aa873f2dcc) - Bug 1160368 - Part 5: Clean up some confusing browser_storage_listings.js checks. r=jdm (b27f5930a9) - Bug 866380 - Null check for amlogic libc implementation. r=valentin (c3a487af9c) - Bug 1257320 - Disable C4577 to unblock compilation on VS2015; r=mayhemer (2f800ca85c) - Bug 1229726 - fix the data copy from sockaddr to NetAddr on OSX/FreeBSD. r=mcmanus. (fde11e004e) - Bug 1241368 - provide JS implemented MDNS service as a fallback. r=nwgh,nalexander. (afe1445eb8) - Bug 571126: Remove NECKO_SEPARATE_STACKS support, r=jduell (fb5b87bb3a) - Bug 1057689 - Add xpcshell test checking correct notifications and app-offline state r=jduell (89946b44ba) - Bug 1259459 - h2 0 length options puts end-stream on headers r=hurley (618480a609) - Bug 1234251 - Remove HttpChannelChild::mSynthesizedResponseHead; r=jdm (20981affea) - Bug 904559 - Veto redirect when target channel doesn't implement nsIParentRedirectingChannel. r=jduell (b3da2fae91) - Bug 1261784 Make sure InterceptedChannel body streams are always closed. r=jdm (cd50b1a52b) - Bug 1224508 - Use URI path without reference as the callback key. r=valentin. (b8a953f23a) - Bug 1226760 - ViewSource doesn't work for packaged app resources r=mcmanus (ec9b0297de) - Bug 1254061 - Rewrite nsHttp::ParseInt64 using strtoll r=mcmanus (2125b8ae6f) - Bug 1241565 - nsIHttpChannelInternal should be a builtinclass, r=honzab.moz (d24da6a95a) - Bug 1252386 - Removed debugging printf,r=me (c5d89f353c) - bug 277813 - autogenerated expires needs max r=mayhemer (6aa7c255a5) - Bug 1225384 - Change how the default resource "host names" are handled. r=michal (868732baab) - Bug 719905: Fix resolution of resource: URLs containing : and / characters. r=valentin (f60f4baacf) - Bug 1195173 - Convert ExtensionProtocolHandler to use channel->Open2() (r=maglione) (063f5d5d10) - Bug 1226909 followup to fix bustage. Make sure that the channel returned by NS_NewChannel doesn't have a loadinfo that indicates that the channel has already been opened (42ebe0f44e) - Bug 241698 - Fixed init and use of nsDirIndex::mLastModified (-1LL) + built in nullptr checks where they were missing. r=dragana (e9c2277a3d) - Bug 1261318 - make sure brotli context is created in onstoprequest r=bagder (6646fed64d) - Bug 1212223 - Update |bufLen| as well when we probed the multipart preamble. r=valentin. (ec878c5b0f) - Bug 1259561: Increase CRAZY_COORD (threshold for debug build layout warnings) by an order of magnitude. r=mats (c05c16dd85) - Bug 1261698. Make ReparentFrameViewTo return void because it always returns NS_OK. r=mats (e806d6abcb) - Bug 1261698. Remove comment that is not relevant in nsContainerFrame.cpp. (f570189d15) - Bug 1261698. Don't descend into child frames looking for views in ReparentFrameViewTo if the frame doesn't have the NS_FRAME_HAS_CHILD_WITH_VIEW bit set. r=mats (0d42befd46) - Bug 1265154 - Fix compile error in MSVC 2013 caused by ArrayLength; r=heycam (1c962f2840) - Bug 1260351 - Image: Enable ConvolveVertically/Horizontally in LS3 MMI. r=tnikkel (576b6bbdb3) - Bug 1209780 (Part 1) - Mark DrawResult MOZ_MUST_USE. r=tn (e6c113bef2) - Bug 1253753 - Remove unnecessary switch fallthrough to avoid -Wimplicit-fallthrough warning. r=karlt (96bd93fc5c) - bug 1260178 null check pattern from -unico-border-gradient r=acomminos (f63c9c7ffb) - Bug 1247796. Use keyboardFocusIndicatorColor for ActiveBorder system color keyword. r=mstange (7ed133de97) - Bug 1248675 - Update the cached mBounds in nsChildView when its backing scale factor (display DPI) changes. r=mstange (8197274118) - Bug 1256576 - Make sure texture is (re)initialized if the size changed. r=snorp (2c56790ca9) - Bug 1242449 - Fix confusion among CSS, desktop and device pixel units in nsXULWindow position/size and window staggering so as to work consistently across mixed resolution displays. r=emk (f73d2fd41d) - Bug 1255645 - Ensure nsXULWindow constrains the window to the bounds of its screen after applying intrinsic sizing (if appropriate), by re-doing positioning after the window has been sized properly. r=emk (e87e0cea81) - Bug 1259492 - Ensure window position is constrained to the screen after it has been sized properly in nsXULWindow::OnChromeLoaded. r=emk (7cf599b39b) - Bug 1832708 - Disable std::__throw_* wrapping on libc++ >= 14.0. r=firefox-build-system-reviewers,andi (29e0cc9319)
This commit is contained in:
@@ -477,7 +477,7 @@ HardwareKeyHandler::GetCurrentTarget()
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<mozIDOMWindowProxy> focusedWindow;
|
||||
nsCOMPtr<nsIDOMWindow> domWindow;
|
||||
fm->GetFocusedWindow(getter_AddRefs(focusedWindow));
|
||||
if (NS_WARN_IF(!focusedWindow)) {
|
||||
return nullptr;
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
let test_generator = do_run_test();
|
||||
"use strict";
|
||||
|
||||
var test_generator = do_run_test();
|
||||
|
||||
function run_test()
|
||||
{
|
||||
@@ -31,10 +33,10 @@ function repeat_test()
|
||||
}
|
||||
|
||||
// Purge threshold, in seconds.
|
||||
let gPurgeAge = 1;
|
||||
var gPurgeAge = 1;
|
||||
|
||||
// Short expiry age, in seconds.
|
||||
let gShortExpiry = 2;
|
||||
var gShortExpiry = 2;
|
||||
|
||||
// Required delay to ensure a purge occurs, in milliseconds. This must be at
|
||||
// least gPurgeAge + 10%, and includes a little fuzz to account for timer
|
||||
@@ -231,7 +233,7 @@ function get_creationTime(i)
|
||||
function check_remaining_cookies(aNumberTotal, aNumberOld, aNumberToExpect) {
|
||||
var enumerator = Services.cookiemgr.enumerator;
|
||||
|
||||
i = 0;
|
||||
let i = 0;
|
||||
while (enumerator.hasMoreElements()) {
|
||||
var cookie = enumerator.getNext().QueryInterface(Ci.nsICookie2);
|
||||
++i;
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "gfxPrefs.h"
|
||||
#include "image_operations.h"
|
||||
#include "mozilla/SSE.h"
|
||||
#include "mozilla/mips.h"
|
||||
#include "convolver.h"
|
||||
#include "skia/include/core/SkTypes.h"
|
||||
|
||||
@@ -228,7 +229,7 @@ Downscaler::CommitRow()
|
||||
if (mCurrentInLine == inLineToRead) {
|
||||
skia::ConvolveHorizontally(mRowBuffer.get(), *mXFilter,
|
||||
mWindow[mLinesInBuffer++], mHasAlpha,
|
||||
supports_sse2());
|
||||
supports_sse2() || supports_mmi());
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mCurrentOutLine < mTargetSize.height,
|
||||
@@ -316,7 +317,7 @@ Downscaler::DownscaleInputLine()
|
||||
&mOutputBuffer[currentOutLine * mTargetSize.width * sizeof(uint32_t)];
|
||||
skia::ConvolveVertically(static_cast<const FilterValue*>(filterValues),
|
||||
filterLength, mWindow.get(), mXFilter->num_values(),
|
||||
outputLine, mHasAlpha, supports_sse2());
|
||||
outputLine, mHasAlpha, supports_sse2() || supports_mmi());
|
||||
|
||||
mCurrentOutLine += 1;
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/SSE.h"
|
||||
#include "mozilla/mips.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "gfxPrefs.h"
|
||||
@@ -236,7 +237,7 @@ public:
|
||||
if (mInputRow == inputRowToRead) {
|
||||
skia::ConvolveHorizontally(mRowBuffer.get(), *mXFilter,
|
||||
mWindow[mRowsInWindow++], mHasAlpha,
|
||||
supports_sse2());
|
||||
supports_sse2() || supports_mmi());
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mOutputRow < mNext.InputSize().height,
|
||||
@@ -311,7 +312,7 @@ private:
|
||||
skia::ConvolveVertically(static_cast<const FilterValue*>(filterValues),
|
||||
filterLength, mWindow.get(), mXFilter->num_values(),
|
||||
reinterpret_cast<uint8_t*>(aRow), mHasAlpha,
|
||||
supports_sse2());
|
||||
supports_sse2() || supports_mmi());
|
||||
return Some(WriteState::NEED_MORE_DATA);
|
||||
});
|
||||
|
||||
|
||||
+1
-1
@@ -45,7 +45,7 @@ namespace image {
|
||||
*
|
||||
* BAD_ARGS: We failed to draw because bad arguments were passed to draw().
|
||||
*/
|
||||
enum class DrawResult : uint8_t
|
||||
enum class MOZ_MUST_USE DrawResult : uint8_t
|
||||
{
|
||||
SUCCESS,
|
||||
INCOMPLETE,
|
||||
|
||||
@@ -372,22 +372,17 @@ nsContainerFrame::PeekOffsetCharacter(bool aForward, int32_t* aOffset,
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Helper member functions
|
||||
|
||||
static nsresult
|
||||
static void
|
||||
ReparentFrameViewTo(nsIFrame* aFrame,
|
||||
nsViewManager* aViewManager,
|
||||
nsView* aNewParentView,
|
||||
nsView* aOldParentView)
|
||||
{
|
||||
|
||||
// XXX What to do about placeholder views for "position: fixed" elements?
|
||||
// They should be reparented too.
|
||||
|
||||
// Does aFrame have a view?
|
||||
if (aFrame->HasView()) {
|
||||
#ifdef MOZ_XUL
|
||||
if (aFrame->GetType() == nsGkAtoms::menuPopupFrame) {
|
||||
// This view must be parented by the root view, don't reparent it.
|
||||
return NS_OK;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
nsView* view = aFrame->GetView();
|
||||
@@ -400,7 +395,7 @@ ReparentFrameViewTo(nsIFrame* aFrame,
|
||||
// The view will remember the Z-order and other attributes that have been set on it.
|
||||
nsView* insertBefore = nsLayoutUtils::FindSiblingViewFor(aNewParentView, aFrame);
|
||||
aViewManager->InsertChild(aNewParentView, view, insertBefore, insertBefore != nullptr);
|
||||
} else {
|
||||
} else if (aFrame->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW) {
|
||||
nsIFrame::ChildListIterator lists(aFrame);
|
||||
for (; !lists.IsDone(); lists.Next()) {
|
||||
// Iterate the child frames, and check each child frame to see if it has
|
||||
@@ -412,8 +407,6 @@ ReparentFrameViewTo(nsIFrame* aFrame,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -545,8 +538,8 @@ nsContainerFrame::ReparentFrameView(nsIFrame* aChildFrame,
|
||||
// anything
|
||||
if (oldParentView != newParentView) {
|
||||
// They're not so we need to reparent any child views
|
||||
return ReparentFrameViewTo(aChildFrame, oldParentView->GetViewManager(), newParentView,
|
||||
oldParentView);
|
||||
ReparentFrameViewTo(aChildFrame, oldParentView->GetViewManager(), newParentView,
|
||||
oldParentView);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
||||
@@ -34,7 +34,10 @@ class FramePropertyTable;
|
||||
// dependency on nsDeviceContext.h. It doesn't matter if it's a
|
||||
// little off.
|
||||
#ifdef DEBUG
|
||||
#define CRAZY_COORD (1000000*60)
|
||||
// 10 million pixels, converted to app units. Note that this a bit larger
|
||||
// than 1/4 of nscoord_MAX. So, if any content gets to be this large, we're
|
||||
// definitely in danger of grazing up against nscoord_MAX; hence, it's CRAZY.
|
||||
#define CRAZY_COORD (10000000*60)
|
||||
#define CRAZY_SIZE(_x) (((_x) < -CRAZY_COORD) || ((_x) > CRAZY_COORD))
|
||||
#endif
|
||||
|
||||
|
||||
@@ -910,12 +910,10 @@ KTableEntry nsCSSProps::kBackgroundClipKTable[] = {
|
||||
{ eCSSKeyword_UNKNOWN, -1 }
|
||||
};
|
||||
|
||||
#if 0
|
||||
static_assert(ArrayLength(nsCSSProps::kImageLayerOriginKTable) ==
|
||||
ArrayLength(nsCSSProps::kBackgroundClipKTable) - 1,
|
||||
static_assert(MOZ_ARRAY_LENGTH(nsCSSProps::kImageLayerOriginKTable) ==
|
||||
MOZ_ARRAY_LENGTH(nsCSSProps::kBackgroundClipKTable) - 1,
|
||||
"background-clip has one extra value, which is text, compared"
|
||||
"to {background,mask}-origin");
|
||||
#endif
|
||||
|
||||
// Note: Don't change this table unless you update
|
||||
// ParseImageLayerPosition!
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#ifndef mozilla_throw_gcc_h
|
||||
#define mozilla_throw_gcc_h
|
||||
|
||||
#if !defined(_LIBCPP_VERSION) || _LIBCPP_VERSION < 14000
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
#include <stdio.h> // snprintf
|
||||
@@ -151,4 +153,9 @@ __throw_system_error(int err)
|
||||
|
||||
} // namespace std
|
||||
|
||||
#undef MOZ_THROW_NORETURN
|
||||
#undef MOZ_THROW_INLINE
|
||||
|
||||
#endif
|
||||
|
||||
#endif // mozilla_throw_gcc_h
|
||||
|
||||
@@ -2217,6 +2217,9 @@ pref("network.stricttransportsecurity.enabled", true);
|
||||
// Use the HSTS preload list by default
|
||||
pref("network.stricttransportsecurity.preloadlist", true);
|
||||
|
||||
// Use JS mDNS as a fallback
|
||||
pref("network.mdns.use_js_fallback", false);
|
||||
|
||||
pref("converter.html2txt.structs", true); // Output structured phrases (strong, em, code, sub, sup, b, i, u)
|
||||
pref("converter.html2txt.header_strategy", 1); // 0 = no indention; 1 = indention, increased with header level; 2 = numbering and slight indention
|
||||
// Whether we include ruby annotation in the text despite whether it
|
||||
|
||||
@@ -532,9 +532,9 @@ CacheFileHandles::SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
|
||||
|
||||
class ShutdownEvent : public nsRunnable {
|
||||
public:
|
||||
ShutdownEvent(mozilla::Mutex *aLock, mozilla::CondVar *aCondVar)
|
||||
: mLock(aLock)
|
||||
, mCondVar(aCondVar)
|
||||
ShutdownEvent()
|
||||
: mMonitor("ShutdownEvent.mMonitor")
|
||||
, mNotified(false)
|
||||
, mPrepare(true)
|
||||
{
|
||||
MOZ_COUNT_CTOR(ShutdownEvent);
|
||||
@@ -564,18 +564,35 @@ public:
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MutexAutoLock lock(*mLock);
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
|
||||
CacheFileIOManager::gInstance->ShutdownInternal();
|
||||
|
||||
mCondVar->Notify();
|
||||
mNotified = true;
|
||||
mon.Notify();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void PostAndWait()
|
||||
{
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
|
||||
DebugOnly<nsresult> rv;
|
||||
nsCOMPtr<nsIEventTarget> ioTarget =
|
||||
CacheFileIOManager::gInstance->mIOThread->Target();
|
||||
MOZ_ASSERT(ioTarget);
|
||||
rv = ioTarget->Dispatch(this, nsIEventTarget::DISPATCH_NORMAL);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
while (!mNotified) {
|
||||
mon.Wait();
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
mozilla::Mutex *mLock;
|
||||
mozilla::CondVar *mCondVar;
|
||||
bool mPrepare;
|
||||
mozilla::Monitor mMonitor;
|
||||
bool mNotified;
|
||||
bool mPrepare;
|
||||
};
|
||||
|
||||
class OpenFileEvent : public nsRunnable {
|
||||
@@ -1157,23 +1174,14 @@ CacheFileIOManager::Shutdown()
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
gInstance->mShutdownDemanded = true;
|
||||
|
||||
CacheIndex::PreShutdown();
|
||||
|
||||
ShutdownMetadataWriteScheduling();
|
||||
|
||||
{
|
||||
mozilla::Mutex lock("CacheFileIOManager::Shutdown() lock");
|
||||
mozilla::CondVar condVar(lock, "CacheFileIOManager::Shutdown() condVar");
|
||||
|
||||
MutexAutoLock autoLock(lock);
|
||||
RefPtr<ShutdownEvent> ev = new ShutdownEvent(&lock, &condVar);
|
||||
DebugOnly<nsresult> rv;
|
||||
nsCOMPtr<nsIEventTarget> ioTarget = gInstance->mIOThread->Target();
|
||||
MOZ_ASSERT(ioTarget);
|
||||
rv = ioTarget->Dispatch(ev, nsIEventTarget::DISPATCH_NORMAL);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
condVar.Wait();
|
||||
}
|
||||
RefPtr<ShutdownEvent> ev = new ShutdownEvent();
|
||||
ev->PostAndWait();
|
||||
|
||||
MOZ_ASSERT(gInstance->mHandles.HandleCount() == 0);
|
||||
MOZ_ASSERT(gInstance->mHandlesByLastUsed.Length() == 0);
|
||||
@@ -2289,15 +2297,21 @@ CacheFileIOManager::ReleaseNSPRHandleInternal(CacheFileHandle *aHandle,
|
||||
found = mHandlesByLastUsed.RemoveElement(aHandle);
|
||||
MOZ_ASSERT(found);
|
||||
|
||||
if (aIgnoreShutdownLag || !IsPastShutdownIOLag()) {
|
||||
PR_Close(aHandle->mFD);
|
||||
} else {
|
||||
// Leak invalid (w/o metadata) and doomed handles immediately after shutdown.
|
||||
// Leak other handles when past the shutdown time maximum lag.
|
||||
if (
|
||||
#ifndef DEBUG
|
||||
((aHandle->mInvalid || aHandle->mIsDoomed) && MOZ_UNLIKELY(mShutdownDemanded)) ||
|
||||
#endif
|
||||
MOZ_UNLIKELY(!aIgnoreShutdownLag && IsPastShutdownIOLag())) {
|
||||
// Pretend this file has been validated (the metadata has been written)
|
||||
// to prevent removal I/O on this apparently used file. The entry will
|
||||
// never be used, since it doesn't have correct metadata, thus we don't
|
||||
// need to worry about removing it.
|
||||
aHandle->mInvalid = false;
|
||||
LOG((" past the shutdown I/O lag, leaking file handle"));
|
||||
} else {
|
||||
PR_Close(aHandle->mFD);
|
||||
}
|
||||
|
||||
aHandle->mFD = nullptr;
|
||||
@@ -4033,13 +4047,16 @@ public:
|
||||
}
|
||||
|
||||
mozilla::MonitorAutoLock mon(mMonitor);
|
||||
mMonitorNotified = false;
|
||||
nsresult rv = target->Dispatch(this, nsIEventTarget::DISPATCH_NORMAL);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_ERROR("Dispatch failed, cannot do memory report of CacheFileHandles");
|
||||
return 0;
|
||||
}
|
||||
|
||||
mon.Wait();
|
||||
while (!mMonitorNotified) {
|
||||
mon.Wait();
|
||||
}
|
||||
return mSize;
|
||||
}
|
||||
|
||||
@@ -4053,12 +4070,14 @@ public:
|
||||
mSize += mSpecialHandles[i]->SizeOfIncludingThis(mMallocSizeOf);
|
||||
}
|
||||
|
||||
mMonitorNotified = true;
|
||||
mon.Notify();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
mozilla::Monitor mMonitor;
|
||||
bool mMonitorNotified;
|
||||
mozilla::MallocSizeOf mMallocSizeOf;
|
||||
CacheFileHandles const &mHandles;
|
||||
nsTArray<CacheFileHandle *> const &mSpecialHandles;
|
||||
|
||||
@@ -444,6 +444,10 @@ private:
|
||||
// Shutdown time stamp, accessed only on the I/O thread. Used to bypass
|
||||
// I/O after a certain time pass the shutdown has been demanded.
|
||||
TimeStamp mShutdownDemandedTime;
|
||||
// Set true on the main thread when cache shutdown is first demanded.
|
||||
Atomic<bool, Relaxed> mShutdownDemanded;
|
||||
// Set true on the IO thread, CLOSE level as part of the internal shutdown
|
||||
// procedure.
|
||||
bool mShuttingDown;
|
||||
RefPtr<CacheIOThread> mIOThread;
|
||||
nsCOMPtr<nsIFile> mCacheDirectory;
|
||||
|
||||
@@ -157,8 +157,9 @@ already_AddRefed<nsIEventTarget> CacheIOThread::Target()
|
||||
if (!target && mThread)
|
||||
{
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
if (!mXPCOMThread)
|
||||
while (!mXPCOMThread) {
|
||||
lock.Wait();
|
||||
}
|
||||
|
||||
target = mXPCOMThread;
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ public:
|
||||
READ,
|
||||
MANAGEMENT,
|
||||
WRITE,
|
||||
CLOSE,
|
||||
CLOSE = WRITE,
|
||||
INDEX,
|
||||
EVICT,
|
||||
LAST_LEVEL,
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "mozilla/net/NeckoCommon.h"
|
||||
#include "prsystem.h"
|
||||
#include <time.h>
|
||||
#include <math.h>
|
||||
@@ -98,6 +99,10 @@ NS_IMPL_ISUPPORTS(CacheObserver,
|
||||
nsresult
|
||||
CacheObserver::Init()
|
||||
{
|
||||
if (IsNeckoChild()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (sSelf) {
|
||||
return NS_OK;
|
||||
}
|
||||
@@ -446,18 +451,13 @@ CacheObserver::Observe(nsISupports* aSubject,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!strcmp(aTopic, "profile-before-change")) {
|
||||
if (!strcmp(aTopic, "profile-change-net-teardown") ||
|
||||
!strcmp(aTopic, "profile-before-change") ||
|
||||
!strcmp(aTopic, "xpcom-shutdown")) {
|
||||
RefPtr<CacheStorageService> service = CacheStorageService::Self();
|
||||
if (service)
|
||||
service->Shutdown();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!strcmp(aTopic, "xpcom-shutdown")) {
|
||||
RefPtr<CacheStorageService> service = CacheStorageService::Self();
|
||||
if (service)
|
||||
if (service) {
|
||||
service->Shutdown();
|
||||
}
|
||||
|
||||
CacheFileIOManager::Shutdown();
|
||||
return NS_OK;
|
||||
@@ -465,8 +465,9 @@ CacheObserver::Observe(nsISupports* aSubject,
|
||||
|
||||
if (!strcmp(aTopic, "last-pb-context-exited")) {
|
||||
RefPtr<CacheStorageService> service = CacheStorageService::Self();
|
||||
if (service)
|
||||
if (service) {
|
||||
service->DropPrivateBrowsingEntries();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -2084,7 +2084,9 @@ NS_IMETHODIMP
|
||||
CacheStorageService::IOThreadSuspender::Run()
|
||||
{
|
||||
MonitorAutoLock mon(mMon);
|
||||
mon.Wait();
|
||||
while (!mSignaled) {
|
||||
mon.Wait();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -2092,6 +2094,7 @@ void
|
||||
CacheStorageService::IOThreadSuspender::Notify()
|
||||
{
|
||||
MonitorAutoLock mon(mMon);
|
||||
mSignaled = true;
|
||||
mon.Notify();
|
||||
}
|
||||
|
||||
|
||||
@@ -366,13 +366,14 @@ private:
|
||||
class IOThreadSuspender : public nsRunnable
|
||||
{
|
||||
public:
|
||||
IOThreadSuspender() : mMon("IOThreadSuspender") { }
|
||||
IOThreadSuspender() : mMon("IOThreadSuspender"), mSignaled(false) { }
|
||||
void Notify();
|
||||
private:
|
||||
virtual ~IOThreadSuspender() { }
|
||||
NS_IMETHOD Run() override;
|
||||
|
||||
Monitor mMon;
|
||||
bool mSignaled;
|
||||
};
|
||||
|
||||
RefPtr<IOThreadSuspender> mActiveIOSuspender;
|
||||
|
||||
@@ -56,9 +56,9 @@ class nsCookie : public nsICookie2
|
||||
, mExpiry(aExpiry)
|
||||
, mLastAccessed(aLastAccessed)
|
||||
, mCreationTime(aCreationTime)
|
||||
, mIsSession(aIsSession != false)
|
||||
, mIsSecure(aIsSecure != false)
|
||||
, mIsHttpOnly(aIsHttpOnly != false)
|
||||
, mIsSession(aIsSession)
|
||||
, mIsSecure(aIsSecure)
|
||||
, mIsHttpOnly(aIsHttpOnly)
|
||||
, mOriginAttributes(aOriginAttributes)
|
||||
{
|
||||
}
|
||||
@@ -101,7 +101,7 @@ class nsCookie : public nsICookie2
|
||||
// setters
|
||||
inline void SetExpiry(int64_t aExpiry) { mExpiry = aExpiry; }
|
||||
inline void SetLastAccessed(int64_t aTime) { mLastAccessed = aTime; }
|
||||
inline void SetIsSession(bool aIsSession) { mIsSession = (bool) aIsSession; }
|
||||
inline void SetIsSession(bool aIsSession) { mIsSession = aIsSession; }
|
||||
// Set the creation time manually, overriding the monotonicity checks in
|
||||
// Create(). Use with caution!
|
||||
inline void SetCreationTime(int64_t aTime) { mCreationTime = aTime; }
|
||||
@@ -111,6 +111,7 @@ class nsCookie : public nsICookie2
|
||||
protected:
|
||||
virtual ~nsCookie() {}
|
||||
|
||||
private:
|
||||
// member variables
|
||||
// we use char* ptrs to store the strings in a contiguous block,
|
||||
// so we save on the overhead of using nsCStrings. However, we
|
||||
|
||||
@@ -281,7 +281,11 @@ GetAddrInfoReplyRunnable::Reply(DNSServiceRef aSdRef,
|
||||
}
|
||||
|
||||
NetAddr address;
|
||||
memcpy(&address, aAddress, sizeof(*aAddress));
|
||||
address.raw.family = aAddress->sa_family;
|
||||
|
||||
static_assert(sizeof(address.raw.data) >= sizeof(aAddress->sa_data),
|
||||
"size of sockaddr.sa_data is too big");
|
||||
memcpy(&address.raw.data, aAddress->sa_data, sizeof(aAddress->sa_data));
|
||||
|
||||
thread->Dispatch(new GetAddrInfoReplyRunnable(aSdRef,
|
||||
aFlags,
|
||||
|
||||
@@ -0,0 +1,244 @@
|
||||
// -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; js2-basic-offset: 2; js2-skip-preprocessor-directives: t; -*-
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["MulticastDNS"];
|
||||
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Messaging.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
var log = Cu.import("resource://gre/modules/AndroidLog.jsm", {}).AndroidLog.d.bind(null, "MulticastDNS");
|
||||
|
||||
const FAILURE_INTERNAL_ERROR = -65537;
|
||||
|
||||
// Helper function for sending commands to Java.
|
||||
function send(type, data, callback) {
|
||||
let msg = {
|
||||
type: type
|
||||
};
|
||||
|
||||
for (let i in data) {
|
||||
try {
|
||||
msg[i] = data[i];
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
|
||||
Messaging.sendRequestForResult(msg)
|
||||
.then(result => callback(result, null),
|
||||
err => callback(null, typeof err === "number" ? err : FAILURE_INTERNAL_ERROR));
|
||||
}
|
||||
|
||||
// Receives service found/lost event from NsdManager
|
||||
function ServiceManager() {
|
||||
}
|
||||
|
||||
ServiceManager.prototype = {
|
||||
listeners: {},
|
||||
numListeners: 0,
|
||||
|
||||
registerEvent: function() {
|
||||
log("registerEvent");
|
||||
Messaging.addListener(this.onServiceFound.bind(this), "NsdManager:ServiceFound");
|
||||
Messaging.addListener(this.onServiceLost.bind(this), "NsdManager:ServiceLost");
|
||||
},
|
||||
|
||||
unregisterEvent: function() {
|
||||
log("unregisterEvent");
|
||||
Messaging.removeListener("NsdManager:ServiceFound");
|
||||
Messaging.removeListener("NsdManager:ServiceLost");
|
||||
},
|
||||
|
||||
addListener: function(aServiceType, aListener) {
|
||||
log("addListener: " + aServiceType + ", " + aListener);
|
||||
|
||||
if (!this.listeners[aServiceType]) {
|
||||
this.listeners[aServiceType] = [];
|
||||
}
|
||||
if (this.listeners[aServiceType].includes(aListener)) {
|
||||
log("listener already exists");
|
||||
return;
|
||||
}
|
||||
|
||||
this.listeners[aServiceType].push(aListener);
|
||||
++this.numListeners;
|
||||
|
||||
if (this.numListeners === 1) {
|
||||
this.registerEvent();
|
||||
}
|
||||
|
||||
log("listener added: " + this);
|
||||
},
|
||||
|
||||
removeListener: function(aServiceType, aListener) {
|
||||
log("removeListener: " + aServiceType + ", " + aListener);
|
||||
|
||||
if (!this.listeners[aServiceType]) {
|
||||
log("listener doesn't exist");
|
||||
return;
|
||||
}
|
||||
let index = this.listeners[aServiceType].indexOf(aListener);
|
||||
if (index < 0) {
|
||||
log("listener doesn't exist");
|
||||
return;
|
||||
}
|
||||
|
||||
this.listeners[aServiceType].splice(index, 1);
|
||||
--this.numListeners;
|
||||
|
||||
if (this.numListeners === 0) {
|
||||
this.unregisterEvent();
|
||||
}
|
||||
|
||||
log("listener removed" + this);
|
||||
},
|
||||
|
||||
onServiceFound: function(aServiceInfo) {
|
||||
let listeners = this.listeners[aServiceInfo.serviceType];
|
||||
if (listeners) {
|
||||
for (let listener of listeners) {
|
||||
listener.onServiceFound(aServiceInfo);
|
||||
}
|
||||
} else {
|
||||
log("no listener");
|
||||
}
|
||||
return {};
|
||||
},
|
||||
|
||||
onServiceLost: function(aServiceInfo) {
|
||||
let listeners = this.listeners[aServiceInfo.serviceType];
|
||||
if (listeners) {
|
||||
for (let listener of listeners) {
|
||||
listener.onServiceLost(aServiceInfo);
|
||||
}
|
||||
} else {
|
||||
log("no listener");
|
||||
}
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
// make an object from nsIPropertyBag2
|
||||
function parsePropertyBag2(bag) {
|
||||
if (!bag || !(bag instanceof Ci.nsIPropertyBag2)) {
|
||||
throw new TypeError("Not a property bag");
|
||||
}
|
||||
|
||||
let attributes = [];
|
||||
let enumerator = bag.enumerator;
|
||||
while (enumerator.hasMoreElements()) {
|
||||
let name = enumerator.getNext().QueryInterface(Ci.nsIProperty).name;
|
||||
let value = bag.getPropertyAsACString(name);
|
||||
attributes.push({
|
||||
"name": name,
|
||||
"value": value
|
||||
});
|
||||
}
|
||||
|
||||
return attributes;
|
||||
}
|
||||
|
||||
function MulticastDNS() {
|
||||
this.serviceManager = new ServiceManager();
|
||||
}
|
||||
|
||||
MulticastDNS.prototype = {
|
||||
startDiscovery: function(aServiceType, aListener) {
|
||||
this.serviceManager.addListener(aServiceType, aListener);
|
||||
|
||||
let serviceInfo = {
|
||||
serviceType: aServiceType,
|
||||
uniqueId: aListener.uuid
|
||||
};
|
||||
|
||||
send("NsdManager:DiscoverServices", serviceInfo, (result, err) => {
|
||||
if (err) {
|
||||
log("onStartDiscoveryFailed: " + aServiceType + " (" + err + ")");
|
||||
this.serviceManager.removeListener(aServiceType, aListener);
|
||||
aListener.onStartDiscoveryFailed(aServiceType, err);
|
||||
} else {
|
||||
aListener.onDiscoveryStarted(result);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
stopDiscovery: function(aServiceType, aListener) {
|
||||
this.serviceManager.removeListener(aServiceType, aListener);
|
||||
|
||||
let serviceInfo = {
|
||||
uniqueId: aListener.uuid
|
||||
};
|
||||
|
||||
send("NsdManager:StopServiceDiscovery", serviceInfo, (result, err) => {
|
||||
if (err) {
|
||||
log("onStopDiscoveryFailed: " + aServiceType + " (" + err + ")");
|
||||
aListener.onStopDiscoveryFailed(aServiceType, err);
|
||||
} else {
|
||||
aListener.onDiscoveryStopped(aServiceType);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
registerService: function(aServiceInfo, aListener) {
|
||||
let serviceInfo = {
|
||||
port: aServiceInfo.port,
|
||||
serviceType: aServiceInfo.serviceType,
|
||||
uniqueId: aListener.uuid
|
||||
};
|
||||
|
||||
try {
|
||||
serviceInfo.host = aServiceInfo.host;
|
||||
} catch(e) {
|
||||
// host unspecified
|
||||
}
|
||||
try {
|
||||
serviceInfo.serviceName = aServiceInfo.serviceName;
|
||||
} catch(e) {
|
||||
// serviceName unspecified
|
||||
}
|
||||
try {
|
||||
serviceInfo.attributes = parsePropertyBag2(aServiceInfo.attributes);
|
||||
} catch(e) {
|
||||
// attributes unspecified
|
||||
}
|
||||
|
||||
send("NsdManager:RegisterService", serviceInfo, (result, err) => {
|
||||
if (err) {
|
||||
log("onRegistrationFailed: (" + err + ")");
|
||||
aListener.onRegistrationFailed(aServiceInfo, err);
|
||||
} else {
|
||||
aListener.onServiceRegistered(result);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
unregisterService: function(aServiceInfo, aListener) {
|
||||
let serviceInfo = {
|
||||
uniqueId: aListener.uuid
|
||||
};
|
||||
|
||||
send("NsdManager:UnregisterService", serviceInfo, (result, err) => {
|
||||
if (err) {
|
||||
log("onUnregistrationFailed: (" + err + ")");
|
||||
aListener.onUnregistrationFailed(aServiceInfo, err);
|
||||
} else {
|
||||
aListener.onServiceUnregistered(aServiceInfo);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
resolveService: function(aServiceInfo, aListener) {
|
||||
send("NsdManager:ResolveService", aServiceInfo, (result, err) => {
|
||||
if (err) {
|
||||
log("onResolveFailed: (" + err + ")");
|
||||
aListener.onResolveFailed(aServiceInfo, err);
|
||||
} else {
|
||||
aListener.onServiceResolved(result);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,577 @@
|
||||
/* -*- Mode: js; js-indent-level: 2; indent-tabs-mode: nil; tab-width: 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/. */
|
||||
/* jshint esnext: true, moz: true */
|
||||
|
||||
'use strict';
|
||||
|
||||
this.EXPORTED_SYMBOLS = ['MulticastDNS'];
|
||||
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
|
||||
|
||||
Cu.import('resource://gre/modules/Services.jsm');
|
||||
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
||||
|
||||
const MDNS_PORT = 5353;
|
||||
const MDNS_ADDRESS = '224.0.0.251';
|
||||
|
||||
const DNS_REC_TYPE_PTR = 12;
|
||||
const DNS_REC_TYPE_TXT = 16;
|
||||
const DNS_REC_TYPE_SRV = 33;
|
||||
const DNS_REC_TYPE_A = 1;
|
||||
const DNS_REC_TYPE_NSEC= 47;
|
||||
|
||||
const DNS_CLASS_QU = 0x8000;
|
||||
const DNS_CLASS_IN = 0x0001;
|
||||
|
||||
const DNS_SECTION_QD = 'qd';
|
||||
const DNS_SECTION_AN = 'an';
|
||||
const DNS_SECTION_NS = 'ns';
|
||||
const DNS_SECTION_AR = 'ar';
|
||||
|
||||
const DEBUG = false;
|
||||
|
||||
function debug(msg) {
|
||||
Services.console.logStringMessage('MulticastDNSFallback: ' + msg);
|
||||
}
|
||||
|
||||
/* The following was taken from https://raw.githubusercontent.com/GoogleChrome/chrome-app-samples/master/mdns-browser/dns.js */
|
||||
|
||||
/**
|
||||
* DataWriter writes data to an ArrayBuffer, presenting it as the instance
|
||||
* variable 'buffer'.
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
let DataWriter = function(opt_size) {
|
||||
let loc = 0;
|
||||
let view = new Uint8Array(new ArrayBuffer(opt_size || 512));
|
||||
|
||||
this.byte_ = function(v) {
|
||||
view[loc] = v;
|
||||
++loc;
|
||||
this.buffer = view.buffer.slice(0, loc);
|
||||
}.bind(this);
|
||||
};
|
||||
|
||||
DataWriter.prototype.byte = function(v) {
|
||||
this.byte_(v);
|
||||
return this;
|
||||
};
|
||||
|
||||
DataWriter.prototype.short = function(v) {
|
||||
return this.byte((v >> 8) & 0xff).byte(v & 0xff);
|
||||
};
|
||||
|
||||
DataWriter.prototype.long = function(v) {
|
||||
return this.short((v >> 16) & 0xffff).short(v & 0xffff);
|
||||
};
|
||||
|
||||
/**
|
||||
* Writes a DNS name. If opt_ref is specified, will finish this name with a
|
||||
* suffix reference (i.e., 0xc0 <ref>). If not, then will terminate with a NULL
|
||||
* byte.
|
||||
*/
|
||||
DataWriter.prototype.name = function(v, opt_ref) {
|
||||
let parts = v.split('.');
|
||||
parts.forEach(function(part) {
|
||||
this.byte(part.length);
|
||||
for (let i = 0; i < part.length; ++i) {
|
||||
this.byte(part.charCodeAt(i));
|
||||
}
|
||||
}.bind(this));
|
||||
if (opt_ref) {
|
||||
this.byte(0xc0).byte(opt_ref);
|
||||
} else {
|
||||
this.byte(0);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* DataConsumer consumes data from an ArrayBuffer.
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
let DataConsumer = function(arg) {
|
||||
if (arg instanceof Uint8Array) {
|
||||
this.view_ = arg;
|
||||
} else {
|
||||
this.view_ = new Uint8Array(arg);
|
||||
}
|
||||
this.loc_ = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @return whether this DataConsumer has consumed all its data
|
||||
*/
|
||||
DataConsumer.prototype.isEOF = function() {
|
||||
return this.loc_ >= this.view_.byteLength;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param length {integer} number of bytes to return from the front of the view
|
||||
* @return a Uint8Array
|
||||
*/
|
||||
DataConsumer.prototype.slice = function(length) {
|
||||
let view = this.view_.subarray(this.loc_, this.loc_ + length);
|
||||
this.loc_ += length;
|
||||
return view;
|
||||
};
|
||||
|
||||
DataConsumer.prototype.byte = function() {
|
||||
this.loc_ += 1;
|
||||
return this.view_[this.loc_ - 1];
|
||||
};
|
||||
|
||||
DataConsumer.prototype.short = function() {
|
||||
return (this.byte() << 8) + this.byte();
|
||||
};
|
||||
|
||||
DataConsumer.prototype.long = function() {
|
||||
return (this.short() << 16) + this.short();
|
||||
};
|
||||
|
||||
/**
|
||||
* Consumes a DNS name, which will finish with a NULL byte.
|
||||
*/
|
||||
DataConsumer.prototype.name = function() {
|
||||
let parts = [];
|
||||
for (;;) {
|
||||
let len = this.byte();
|
||||
if (!len) {
|
||||
break;
|
||||
} else if (len == 0xc0) {
|
||||
// concat suffix reference (i.e., 0xc0 <ref>).
|
||||
let ref = this.byte();
|
||||
let refConsumer = new DataConsumer(new Uint8Array(this.view_.buffer, ref));
|
||||
parts.push(refConsumer.name());
|
||||
break;
|
||||
}
|
||||
|
||||
// Otherwise, consume a string!
|
||||
let v = '';
|
||||
while (len-- > 0) {
|
||||
v += String.fromCharCode(this.byte());
|
||||
}
|
||||
parts.push(v);
|
||||
}
|
||||
return parts.join('.');
|
||||
};
|
||||
|
||||
/**
|
||||
* Consumes a string according to length.
|
||||
*/
|
||||
DataConsumer.prototype.string = function() {
|
||||
let len = this.byte();
|
||||
if (!len) {
|
||||
return;
|
||||
}
|
||||
|
||||
let v = '';
|
||||
while (len-- > 0) {
|
||||
v += String.fromCharCode(this.byte());
|
||||
}
|
||||
return v;
|
||||
};
|
||||
|
||||
/**
|
||||
* DNSPacket holds the state of a DNS packet. It can be modified or serialized
|
||||
* in-place.
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
let DNSPacket = function(opt_flags) {
|
||||
this.flags_ = opt_flags || 0; /* uint16 */
|
||||
this.data_ = {};
|
||||
this.data_[DNS_SECTION_QD] = [];
|
||||
this.data_[DNS_SECTION_AN] = [];
|
||||
this.data_[DNS_SECTION_NS] = [];
|
||||
this.data_[DNS_SECTION_AR] = [];
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse a DNSPacket from an ArrayBuffer (or Uint8Array).
|
||||
*/
|
||||
DNSPacket.parse = function(buffer) {
|
||||
let consumer = new DataConsumer(buffer);
|
||||
if (consumer.short()) {
|
||||
throw new Error('DNS packet must start with 00 00');
|
||||
}
|
||||
let flags = consumer.short();
|
||||
let count = {};
|
||||
count[DNS_SECTION_QD] = consumer.short();
|
||||
count[DNS_SECTION_AN] = consumer.short();
|
||||
count[DNS_SECTION_NS] = consumer.short();
|
||||
count[DNS_SECTION_AR] = consumer.short();
|
||||
|
||||
let packet = new DNSPacket(flags);
|
||||
|
||||
// Parse the QUESTION section.
|
||||
for (let i = 0; i < count[DNS_SECTION_QD]; ++i) {
|
||||
let part = new DNSRecord(
|
||||
consumer.name(),
|
||||
consumer.short(), // type
|
||||
consumer.short()); // class
|
||||
packet.push(DNS_SECTION_QD, part);
|
||||
}
|
||||
|
||||
// Parse the ANSWER, AUTHORITY and ADDITIONAL sections.
|
||||
[DNS_SECTION_AN, DNS_SECTION_NS, DNS_SECTION_AR].forEach(function(section) {
|
||||
for (let i = 0; i < count[section]; ++i) {
|
||||
let part = new DNSRecord(
|
||||
consumer.name(),
|
||||
consumer.short(),
|
||||
consumer.short(), // class
|
||||
consumer.long(), // ttl
|
||||
consumer.slice(consumer.short()));
|
||||
packet.push(section, part);
|
||||
}
|
||||
});
|
||||
|
||||
if (consumer.isEOF()) {
|
||||
DEBUG && debug('was not EOF on incoming packet');
|
||||
}
|
||||
return packet;
|
||||
};
|
||||
|
||||
DNSPacket.prototype.push = function(section, record) {
|
||||
this.data_[section].push(record);
|
||||
};
|
||||
|
||||
DNSPacket.prototype.each = function(section) {
|
||||
let filter = false;
|
||||
let call;
|
||||
if (arguments.length == 2) {
|
||||
call = arguments[1];
|
||||
} else {
|
||||
filter = arguments[1];
|
||||
call = arguments[2];
|
||||
}
|
||||
this.data_[section].forEach(function(rec) {
|
||||
if (!filter || rec.type == filter) {
|
||||
call(rec);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Serialize this DNSPacket into an ArrayBuffer for sending over UDP.
|
||||
*/
|
||||
DNSPacket.prototype.serialize = function() {
|
||||
let out = new DataWriter();
|
||||
let s = [DNS_SECTION_QD, DNS_SECTION_AN, DNS_SECTION_NS, DNS_SECTION_AR];
|
||||
|
||||
out.short(0).short(this.flags_);
|
||||
|
||||
s.forEach(function(section) {
|
||||
out.short(this.data_[section].length);
|
||||
}.bind(this));
|
||||
|
||||
s.forEach(function(section) {
|
||||
this.data_[section].forEach(function(rec) {
|
||||
out.name(rec.name).short(rec.type).short(rec.cl);
|
||||
|
||||
if (section != DNS_SECTION_QD) {
|
||||
// TODO: implement .bytes()
|
||||
throw new Error('can\'t yet serialize non-QD records');
|
||||
// out.long(rec.ttl).bytes(rec.data_);
|
||||
}
|
||||
});
|
||||
}.bind(this));
|
||||
|
||||
return out.buffer;
|
||||
};
|
||||
|
||||
/**
|
||||
* DNSRecord is a record inside a DNS packet; e.g. a QUESTION, or an ANSWER,
|
||||
* AUTHORITY, or ADDITIONAL record. Note that QUESTION records are special,
|
||||
* and do not have ttl or data.
|
||||
*/
|
||||
let DNSRecord = function(name, type, cl, opt_ttl, opt_data) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.cl = cl;
|
||||
|
||||
this.isQD = (arguments.length == 3);
|
||||
if (!this.isQD) {
|
||||
this.ttl = opt_ttl;
|
||||
this.data_ = opt_data;
|
||||
}
|
||||
};
|
||||
|
||||
DNSRecord.prototype.asName = function() {
|
||||
return new DataConsumer(this.data_).name();
|
||||
};
|
||||
|
||||
DNSRecord.prototype.asSRV = function() {
|
||||
if (this.type !== DNS_REC_TYPE_SRV) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let consumer = new DataConsumer(this.data_);
|
||||
let data_length = this.data_.length;
|
||||
return {
|
||||
priority: consumer.short(),
|
||||
weight: consumer.short(),
|
||||
port: consumer.short(),
|
||||
target: consumer.name() + consumer.name(),
|
||||
};
|
||||
};
|
||||
|
||||
DNSRecord.prototype.asTXT = function() {
|
||||
if (this.type !== DNS_REC_TYPE_TXT) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let consumer = new DataConsumer(this.data_);
|
||||
let attributes = [];
|
||||
while(!consumer.isEOF()) {
|
||||
attributes.push(consumer.string());
|
||||
}
|
||||
|
||||
return attributes;
|
||||
};
|
||||
|
||||
/* end https://raw.githubusercontent.com/GoogleChrome/chrome-app-samples/master/mdns-browser/dns.js */
|
||||
|
||||
/**
|
||||
* Parse fully qualified domain name to service name, instance name,
|
||||
* and domain name. See https://tools.ietf.org/html/rfc6763#section-7.
|
||||
*
|
||||
* example: The Server._http._tcp.example.com
|
||||
* instance name = "The Server"
|
||||
* service type = "_http._tcp"
|
||||
* domain = "example.com"
|
||||
* @private
|
||||
*/
|
||||
function _parseDomainName(str) {
|
||||
let items = str.split('.');
|
||||
let idx = items.findIndex(function(element) {
|
||||
return element === '_tcp' || element === '_udp';
|
||||
});
|
||||
|
||||
return {
|
||||
instanceName: items.splice(0, idx - 1).join('.'),
|
||||
serviceType: items.splice(0, 2). join('.'),
|
||||
domainName: items.join('.')
|
||||
};
|
||||
}
|
||||
|
||||
function _createPropertyBag(map) {
|
||||
let bag = Cc['@mozilla.org/hash-property-bag;1']
|
||||
.createInstance(Ci.nsIWritablePropertyBag);
|
||||
|
||||
for (let entry of map.entries()) {
|
||||
bag.setProperty(entry[0], entry[1]);
|
||||
}
|
||||
|
||||
return bag;
|
||||
}
|
||||
|
||||
let MulticastDNS = function() {
|
||||
this._targets = new Map();
|
||||
};
|
||||
|
||||
MulticastDNS.prototype = {
|
||||
socket: null,
|
||||
//public API
|
||||
startDiscovery: function(aServiceType, aListener) {
|
||||
DEBUG && debug('startDiscovery for ' + aServiceType);
|
||||
let { serviceType } = _parseDomainName(aServiceType);
|
||||
this._addServiceListener(serviceType, aListener);
|
||||
|
||||
try {
|
||||
this._ensureSocket();
|
||||
this._query(serviceType + '.local', DNS_REC_TYPE_PTR);
|
||||
aListener.onDiscoveryStarted(serviceType);
|
||||
} catch (e) {
|
||||
DEBUG && debug('onStartDiscoveryFailed: ' + serviceType + ' (' + e + ')');
|
||||
this._removeServiceListener(serviceType, aListener);
|
||||
aListener.onStartDiscoveryFailed(serviceType, Cr.NS_ERROR_FAILURE);
|
||||
}
|
||||
},
|
||||
|
||||
stopDiscovery: function(aServiceType, aListener) {
|
||||
DEBUG && debug('stopDiscovery for ' + aServiceType);
|
||||
let { serviceType } = _parseDomainName(aServiceType);
|
||||
this._removeServiceListener(serviceType, aListener);
|
||||
|
||||
aListener.onDiscoveryStopped(serviceType);
|
||||
if (this._targets.size === 0) {
|
||||
DEBUG && debug('close current socket');
|
||||
this.socket.close();
|
||||
delete this.socket;
|
||||
}
|
||||
},
|
||||
|
||||
registerService: function(aServiceInfo, aListener) {
|
||||
DEBUG && debug('service registration is not supported');
|
||||
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
|
||||
},
|
||||
|
||||
unregisterService: function(aServiceInfo, aListener) {
|
||||
DEBUG && debug('service registration is not supported');
|
||||
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
|
||||
},
|
||||
|
||||
resolveService: function(aServiceInfo, aListener) {
|
||||
DEBUG && debug('address info is already resolve during discovery phase');
|
||||
aListener.onServiceResolved(aServiceInfo);
|
||||
},
|
||||
|
||||
//private API
|
||||
onReceive: function(info) {
|
||||
let packet = DNSPacket.parse(info.rawData);
|
||||
let serviceRecords = {};
|
||||
|
||||
packet.each(DNS_SECTION_AR, DNS_REC_TYPE_SRV, (rec) => {
|
||||
DEBUG && debug('recieve SRV: ' + rec.name);
|
||||
let srv = rec.asSRV();
|
||||
serviceRecords[rec.name] = {
|
||||
port: srv.port,
|
||||
host: srv.target,
|
||||
};
|
||||
});
|
||||
|
||||
packet.each(DNS_SECTION_AR, DNS_REC_TYPE_TXT, (rec) => {
|
||||
DEBUG && debug('recieve TXT: ' + rec.name);
|
||||
if (!serviceRecords[rec.name]) {
|
||||
return;
|
||||
}
|
||||
|
||||
let txt = rec.asTXT();
|
||||
let attributes = new Map();
|
||||
for(let x in txt) {
|
||||
let idx = x.indexOf('=');
|
||||
if (idx < 0) {
|
||||
attributes.set(txt[x], true);
|
||||
continue;
|
||||
}
|
||||
|
||||
let key = txt[x].substring(0, idx);
|
||||
let value = txt[x].substring(idx + 1);
|
||||
attributes.set(key, value);
|
||||
}
|
||||
serviceRecords[rec.name].attributes = attributes;
|
||||
});
|
||||
|
||||
packet.each(DNS_SECTION_AN, DNS_REC_TYPE_PTR, (rec) => {
|
||||
DEBUG && debug('recieve PTR: ' + rec.name);
|
||||
let { serviceType: answerType } = _parseDomainName(rec.name);
|
||||
if (this._targets.has(answerType)) {
|
||||
let name = rec.asName();
|
||||
DEBUG && debug('>> for ' + name);
|
||||
let {instanceName, serviceType, domainName} = _parseDomainName(name);
|
||||
let serviceInfo = {
|
||||
host: serviceRecords[name].host,
|
||||
address: info.fromAddr.address,
|
||||
port: serviceRecords[name].port,
|
||||
serviceType: serviceType,
|
||||
serviceName: instanceName,
|
||||
domainName: domainName,
|
||||
attributes: _createPropertyBag(serviceRecords[name].attributes),
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceInfo]),
|
||||
};
|
||||
this._targets.get(serviceType).forEach(function(listener) {
|
||||
listener.onServiceFound(serviceInfo);
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles network error occured while waiting for data.
|
||||
* @private
|
||||
*/
|
||||
onReceiveError: function(socket, status) {
|
||||
DEBUG && debug('receiver socket error' + status);
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Broadcasts for services on the given socket/address.
|
||||
* @private
|
||||
*/
|
||||
_query: function(search, type) {
|
||||
DEBUG && debug('query for service: ' + search);
|
||||
let packet = new DNSPacket();
|
||||
packet.push(DNS_SECTION_QD, new DNSRecord(search, type, DNS_CLASS_IN | DNS_CLASS_QU));
|
||||
|
||||
this._broadcast(this.socket, packet);
|
||||
},
|
||||
|
||||
/**
|
||||
* Broadcasts a MDNS packet on the given socket/address.
|
||||
* @private
|
||||
*/
|
||||
_broadcast: function(sock, packet) {
|
||||
let raw = new DataView(packet.serialize());
|
||||
let length = raw.byteLength;
|
||||
let buf = [];
|
||||
for (let x = 0; x < length; x++) {
|
||||
let charcode = raw.getUint8(x);
|
||||
buf[x] = charcode;
|
||||
}
|
||||
sock.send(MDNS_ADDRESS, MDNS_PORT, buf, buf.length);
|
||||
},
|
||||
|
||||
_addServiceListener: function(serviceType, listener) {
|
||||
let listeners = this._targets.get(serviceType);
|
||||
if (!listeners) {
|
||||
listeners = [];
|
||||
this._targets.set(serviceType, listeners);
|
||||
}
|
||||
|
||||
if (!listeners.find((element) => {
|
||||
return element === listener;
|
||||
})) {
|
||||
DEBUG && debug('insert new listener');
|
||||
listeners.push(listener);
|
||||
}
|
||||
},
|
||||
|
||||
_removeServiceListener: function(serviceType, listener) {
|
||||
if (!this._targets.has(serviceType)) {
|
||||
DEBUG && debug('listener doesnt exist');
|
||||
return;
|
||||
}
|
||||
|
||||
let listeners = this._targets.get(serviceType);
|
||||
let idx = listeners.findIndex(function(element) {
|
||||
return element === listener;
|
||||
});
|
||||
|
||||
if (idx >= 0) {
|
||||
listeners.splice(idx, 1);
|
||||
}
|
||||
|
||||
if (listeners.length === 0) {
|
||||
this._targets.delete(serviceType);
|
||||
}
|
||||
},
|
||||
|
||||
_ensureSocket: function() {
|
||||
if (this.socket) {
|
||||
DEBUG && debug('reuse current socket');
|
||||
return;
|
||||
}
|
||||
|
||||
this.socket = Cc['@mozilla.org/network/udp-socket;1']
|
||||
.createInstance(Ci.nsIUDPSocket);
|
||||
let self = this;
|
||||
this.socket.init(MDNS_PORT, false,
|
||||
Services.scriptSecurityManager.getSystemPrincipal());
|
||||
this.socket.asyncListen({
|
||||
onPacketReceived: function(aSocket, aMessage) {
|
||||
self.onReceive(aMessage);
|
||||
},
|
||||
|
||||
onStopListening: function(aSocket, aStatus) {
|
||||
self.onReceiveError(aSocket, aStatus);
|
||||
},
|
||||
});
|
||||
this.socket.joinMulticast(MDNS_ADDRESS);
|
||||
},
|
||||
};
|
||||
@@ -10,6 +10,11 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
|
||||
'nsDNSServiceDiscovery.manifest',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
'MulticastDNSAndroid.jsm',
|
||||
'MulticastDNSFallback.jsm',
|
||||
]
|
||||
|
||||
elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa' or \
|
||||
(CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk' and CONFIG['ANDROID_VERSION'] >= '16'):
|
||||
UNIFIED_SOURCES += [
|
||||
|
||||
@@ -5,9 +5,15 @@
|
||||
|
||||
const { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/MulticastDNS.jsm");
|
||||
Cu.import('resource://gre/modules/Services.jsm');
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
if (Services.prefs.getBoolPref("network.mdns.use_js_fallback")) {
|
||||
Cu.import("resource://gre/modules/MulticastDNSFallback.jsm");
|
||||
} else {
|
||||
Cu.import("resource://gre/modules/MulticastDNSAndroid.jsm");
|
||||
}
|
||||
|
||||
const DNSSERVICEDISCOVERY_CID = Components.ID("{f9346d98-f27a-4e89-b744-493843416480}");
|
||||
const DNSSERVICEDISCOVERY_CONTRACT_ID = "@mozilla.org/toolkit/components/mdnsresponder/dns-sd;1";
|
||||
const DNSSERVICEINFO_CONTRACT_ID = "@mozilla.org/toolkit/components/mdnsresponder/dns-info;1";
|
||||
@@ -135,7 +141,7 @@ nsDNSServiceDiscovery.prototype = {
|
||||
this.stopDiscovery = true;
|
||||
return;
|
||||
}
|
||||
this.mdns.stopDiscovery(aServiceType, this);
|
||||
this.mdns.stopDiscovery(aServiceType, listener);
|
||||
}).bind(listener)
|
||||
};
|
||||
},
|
||||
@@ -153,7 +159,7 @@ nsDNSServiceDiscovery.prototype = {
|
||||
this.stopRegistration = true;
|
||||
return;
|
||||
}
|
||||
this.mdns.unregisterService(aServiceInfo, this);
|
||||
this.mdns.unregisterService(aServiceInfo, listener);
|
||||
}).bind(listener)
|
||||
};
|
||||
},
|
||||
|
||||
@@ -79,3 +79,10 @@ else:
|
||||
UNIFIED_SOURCES += [
|
||||
'nameprep.c',
|
||||
]
|
||||
|
||||
if CONFIG['_MSC_VER']:
|
||||
# This is intended as a temporary hack to support building with VS2015.
|
||||
# icu\source\common\unicode/ucasemap.h(93): warning C4577:
|
||||
# 'noexcept' used with no exception handling mode specified;
|
||||
# termination on exception is not guaranteed. Specify /EHsc from unified dns
|
||||
CXXFLAGS += ['-wd4577']
|
||||
|
||||
@@ -406,7 +406,8 @@ HostDB_MatchEntry(const PLDHashEntryHdr *entry,
|
||||
const nsHostDBEnt *he = static_cast<const nsHostDBEnt *>(entry);
|
||||
const nsHostKey *hk = static_cast<const nsHostKey *>(key);
|
||||
|
||||
return !strcmp(he->rec->host, hk->host) &&
|
||||
return !strcmp(he->rec->host ? he->rec->host : "",
|
||||
hk->host ? hk->host : "") &&
|
||||
RES_KEY_FLAGS (he->rec->flags) == RES_KEY_FLAGS(hk->flags) &&
|
||||
he->rec->af == hk->af &&
|
||||
!strcmp(he->rec->netInterface, hk->netInterface);
|
||||
|
||||
@@ -90,13 +90,8 @@ IsNeckoChild()
|
||||
static bool amChild = false;
|
||||
|
||||
if (!didCheck) {
|
||||
// This allows independent necko-stacks (instead of single stack in chrome)
|
||||
// to still be run.
|
||||
// TODO: Remove eventually when no longer supported (bug 571126)
|
||||
const char * e = PR_GetEnv("NECKO_SEPARATE_STACKS");
|
||||
if (!e)
|
||||
amChild = XRE_IsContentProcess();
|
||||
didCheck = true;
|
||||
amChild = (XRE_GetProcessType() == GeckoProcessType_Content);
|
||||
}
|
||||
return amChild;
|
||||
}
|
||||
|
||||
@@ -1005,6 +1005,17 @@ NeckoParent::OfflineNotification(nsISupports *aSubject)
|
||||
|
||||
}
|
||||
|
||||
// XPCShells don't have any TabParents
|
||||
// Just send the ipdl message to the child process.
|
||||
if (!UsingNeckoIPCSecurity()) {
|
||||
bool offline = false;
|
||||
gIOService->IsAppOffline(targetAppId, &offline);
|
||||
if (!SendAppOfflineStatus(targetAppId, offline)) {
|
||||
printf_stderr("NeckoParent: "
|
||||
"SendAppOfflineStatus failed for targetAppId: %u\n", targetAppId);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -564,8 +564,7 @@ Http2Stream::GenerateOpen()
|
||||
firstFrameFlags |= Http2Session::kFlag_END_STREAM;
|
||||
} else if (head->IsPost() ||
|
||||
head->IsPut() ||
|
||||
head->IsConnect() ||
|
||||
head->IsOptions()) {
|
||||
head->IsConnect()) {
|
||||
// place fin in a data frame even for 0 length messages for iterop
|
||||
} else if (!mRequestBodyLenRemaining) {
|
||||
// for other HTTP extension methods, rely on the content-length
|
||||
|
||||
@@ -184,7 +184,6 @@ private:
|
||||
nsCOMPtr<nsIChildChannel> mRedirectChannelChild;
|
||||
RefPtr<InterceptStreamListener> mInterceptListener;
|
||||
RefPtr<nsInputStreamPump> mSynthesizedResponsePump;
|
||||
nsAutoPtr<nsHttpResponseHead> mSynthesizedResponseHead;
|
||||
nsCOMPtr<nsIInputStream> mSynthesizedInput;
|
||||
int64_t mSynthesizedStreamLength;
|
||||
|
||||
|
||||
@@ -148,6 +148,14 @@ HttpChannelParentListener::AsyncOnChannelRedirect(
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIParentRedirectingChannel> activeRedirectingChannel =
|
||||
do_QueryInterface(mNextListener);
|
||||
if (!activeRedirectingChannel) {
|
||||
NS_ERROR("Channel got a redirect response, but doesn't implement "
|
||||
"nsIParentRedirectingChannel to handle it.");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
// Register the new channel and obtain id for it
|
||||
nsCOMPtr<nsIRedirectChannelRegistrar> registrar =
|
||||
do_GetService("@mozilla.org/redirectchannelregistrar;1", &rv);
|
||||
@@ -158,13 +166,6 @@ HttpChannelParentListener::AsyncOnChannelRedirect(
|
||||
|
||||
LOG(("Registered %p channel under id=%d", newChannel, mRedirectChannelId));
|
||||
|
||||
nsCOMPtr<nsIParentRedirectingChannel> activeRedirectingChannel =
|
||||
do_QueryInterface(mNextListener);
|
||||
if (!activeRedirectingChannel) {
|
||||
NS_RUNTIMEABORT("Channel got a redirect response, but doesn't implement "
|
||||
"nsIParentRedirectingChannel to handle it.");
|
||||
}
|
||||
|
||||
return activeRedirectingChannel->StartRedirect(mRedirectChannelId,
|
||||
newChannel,
|
||||
redirectFlags,
|
||||
|
||||
@@ -198,6 +198,9 @@ InterceptedChannelChrome::ResetInterception()
|
||||
nsresult rv = mChannel->StartRedirectChannelToURI(uri, nsIChannelEventSink::REDIRECT_INTERNAL);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mResponseBody->Close();
|
||||
mResponseBody = nullptr;
|
||||
|
||||
mReleaseHandle = nullptr;
|
||||
mChannel = nullptr;
|
||||
return NS_OK;
|
||||
@@ -230,6 +233,11 @@ InterceptedChannelChrome::FinishSynthesizedResponse(const nsACString& aFinalURLS
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
// Make sure the cache entry's output stream is always closed. If the
|
||||
// channel was intercepted with a null-body response then its possible
|
||||
// the synthesis completed without a stream copy operation.
|
||||
mResponseBody->Close();
|
||||
|
||||
mReportCollector->FlushConsoleReports(mChannel);
|
||||
|
||||
EnsureSynthesizedResponse();
|
||||
@@ -382,6 +390,7 @@ InterceptedChannelContent::ResetInterception()
|
||||
|
||||
mReportCollector->FlushConsoleReports(mChannel);
|
||||
|
||||
mResponseBody->Close();
|
||||
mResponseBody = nullptr;
|
||||
mSynthesizedInput = nullptr;
|
||||
|
||||
@@ -418,6 +427,11 @@ InterceptedChannelContent::FinishSynthesizedResponse(const nsACString& aFinalURL
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
// Make sure the body output stream is always closed. If the channel was
|
||||
// intercepted with a null-body response then its possible the synthesis
|
||||
// completed without a stream copy operation.
|
||||
mResponseBody->Close();
|
||||
|
||||
mReportCollector->FlushConsoleReports(mChannel);
|
||||
|
||||
EnsureSynthesizedResponse();
|
||||
|
||||
@@ -727,7 +727,7 @@ PackagedAppService::PackagedAppDownloader::AddCallback(nsIURI *aURI,
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(NS_IsMainThread(), "mCallbacks hashtable is not thread safe");
|
||||
nsAutoCString spec;
|
||||
aURI->GetAsciiSpec(spec);
|
||||
aURI->GetSpecIgnoringRef(spec);
|
||||
|
||||
LogURI("PackagedAppDownloader::AddCallback", this, aURI);
|
||||
LOG(("[%p] > callback: %p\n", this, aCallback));
|
||||
@@ -1037,7 +1037,7 @@ PackagedAppService::GetResource(nsIChannel *aChannel,
|
||||
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
rv = principal->GetURI(getter_AddRefs(uri));
|
||||
rv = aChannel->GetURI(getter_AddRefs(uri));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
LOG(("[%p] > Error calling GetURI rv=%X\n", this, rv));
|
||||
return rv;
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/HashFunctions.h"
|
||||
#include "nsCRT.h"
|
||||
#include <errno.h>
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
@@ -294,19 +295,25 @@ nsHttp::FindToken(const char *input, const char *token, const char *seps)
|
||||
bool
|
||||
nsHttp::ParseInt64(const char *input, const char **next, int64_t *r)
|
||||
{
|
||||
const char *start = input;
|
||||
*r = 0;
|
||||
while (*input >= '0' && *input <= '9') {
|
||||
int64_t next = 10 * (*r) + (*input - '0');
|
||||
if (next < *r) // overflow?
|
||||
return false;
|
||||
*r = next;
|
||||
++input;
|
||||
}
|
||||
if (input == start) // nothing parsed?
|
||||
MOZ_ASSERT(input);
|
||||
MOZ_ASSERT(r);
|
||||
|
||||
char *end = nullptr;
|
||||
errno = 0; // Clear errno to make sure its value is set by strtoll
|
||||
int64_t value = strtoll(input, &end, /* base */ 10);
|
||||
|
||||
// Fail if: - the parsed number overflows.
|
||||
// - the end points to the start of the input string.
|
||||
// - we parsed a negative value. Consumers don't expect that.
|
||||
if (errno != 0 || end == input || value < 0) {
|
||||
LOG(("nsHttp::ParseInt64 value=%ld errno=%d", value, errno));
|
||||
return false;
|
||||
if (next)
|
||||
*next = input;
|
||||
}
|
||||
|
||||
if (next) {
|
||||
*next = end;
|
||||
}
|
||||
*r = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -824,9 +824,7 @@ nsHttpChannelAuthProvider::BlockPrompt()
|
||||
nsCOMPtr<nsIHttpChannelInternal> chanInternal = do_QueryInterface(mAuthChannel);
|
||||
MOZ_ASSERT(chanInternal);
|
||||
|
||||
bool skipAuthentication = false;
|
||||
nsresult rv = chanInternal->GetBlockAuthPrompt(&skipAuthentication);
|
||||
if (NS_SUCCEEDED(rv) && skipAuthentication) {
|
||||
if (chanInternal->GetBlockAuthPrompt()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -185,7 +185,6 @@ nsHttpConnectionMgr::Shutdown()
|
||||
|
||||
// wait for shutdown event to complete
|
||||
while (!shutdownWrapper->mBool) {
|
||||
fprintf(stderr, "nsHttpConnectionMgr::Shutdown() ProcessNextEvent\n");
|
||||
NS_ProcessNextEvent(NS_GetCurrentThread());
|
||||
}
|
||||
|
||||
|
||||
@@ -415,7 +415,7 @@ nsHttpResponseHead::ComputeCurrentAge(uint32_t now,
|
||||
// <or>
|
||||
// freshnessLifetime = expires_value - date_value
|
||||
// <or>
|
||||
// freshnessLifetime = (date_value - last_modified_value) * 0.10
|
||||
// freshnessLifetime = min(one-week,(date_value - last_modified_value) * 0.10)
|
||||
// <or>
|
||||
// freshnessLifetime = 0
|
||||
//
|
||||
@@ -463,6 +463,8 @@ nsHttpResponseHead::ComputeFreshnessLifetime(uint32_t *result) const
|
||||
if (date2 <= date) {
|
||||
// this only makes sense if last-modified is actually in the past
|
||||
*result = (date - date2) / 10;
|
||||
const uint32_t kOneWeek = 60 * 60 * 24 * 7;
|
||||
*result = std::min(kOneWeek, *result);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ interface nsIHttpUpgradeListener : nsISupports
|
||||
* using any feature exposed by this interface, be aware that this interface
|
||||
* will change and you will be broken. You have been warned.
|
||||
*/
|
||||
[scriptable, uuid(01b8296a-e206-4e5f-acab-82bd8b6a900c)]
|
||||
[builtinclass, scriptable, uuid(4e28263d-1e03-46f4-aa5c-9512f91957f9)]
|
||||
interface nsIHttpChannelInternal : nsISupports
|
||||
{
|
||||
/**
|
||||
@@ -283,5 +283,6 @@ interface nsIHttpChannelInternal : nsISupports
|
||||
* authentication failure, that failure will be propagated to the channel
|
||||
* listener. Must be called before opening the channel, otherwise throws.
|
||||
*/
|
||||
[infallible]
|
||||
attribute boolean blockAuthPrompt;
|
||||
};
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "nsIStreamConverterService.h"
|
||||
#include "nsIPipe.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "LoadInfo.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@@ -103,8 +104,9 @@ ExtensionProtocolHandler::SubstituteChannel(nsIURI* aURI,
|
||||
const char* kToType = "text/css";
|
||||
|
||||
nsCOMPtr<nsIInputStream> inputStream;
|
||||
if (aLoadInfo && aLoadInfo->GetSecurityMode()) {
|
||||
// Certain security checks require an async channel.
|
||||
if (aLoadInfo &&
|
||||
aLoadInfo->GetSecurityMode() == nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS) {
|
||||
// If the channel needs to enforce CORS, we need to open the channel async.
|
||||
|
||||
nsCOMPtr<nsIOutputStream> outputStream;
|
||||
rv = NS_NewPipe(getter_AddRefs(inputStream), getter_AddRefs(outputStream),
|
||||
@@ -121,13 +123,20 @@ ExtensionProtocolHandler::SubstituteChannel(nsIURI* aURI,
|
||||
aURI, getter_AddRefs(converter));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsILoadInfo> loadInfo =
|
||||
static_cast<mozilla::LoadInfo*>(aLoadInfo)->CloneForNewRequest();
|
||||
(*result)->SetLoadInfo(loadInfo);
|
||||
|
||||
rv = (*result)->AsyncOpen2(converter);
|
||||
} else {
|
||||
// Stylesheet loads for extension content scripts require a sync channel,
|
||||
// but fortunately do not invoke security checks.
|
||||
// Stylesheet loads for extension content scripts require a sync channel.
|
||||
|
||||
nsCOMPtr<nsIInputStream> sourceStream;
|
||||
rv = (*result)->Open(getter_AddRefs(sourceStream));
|
||||
if (aLoadInfo && aLoadInfo->GetEnforceSecurity()) {
|
||||
rv = (*result)->Open2(getter_AddRefs(sourceStream));
|
||||
} else {
|
||||
rv = (*result)->Open(getter_AddRefs(sourceStream));
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = convService->Convert(sourceStream, kFromType, kToType,
|
||||
|
||||
@@ -352,28 +352,40 @@ SubstitutingProtocolHandler::ResolveURI(nsIURI *uri, nsACString &result)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Unescape the path so we can perform some checks on it.
|
||||
nsAutoCString unescapedPath(path);
|
||||
NS_UnescapeURL(unescapedPath);
|
||||
|
||||
// Don't misinterpret the filepath as an absolute URI.
|
||||
if (unescapedPath.FindChar(':') != -1)
|
||||
return NS_ERROR_MALFORMED_URI;
|
||||
|
||||
if (unescapedPath.FindChar('\\') != -1)
|
||||
return NS_ERROR_MALFORMED_URI;
|
||||
|
||||
const char *p = path.get() + 1; // path always starts with a slash
|
||||
NS_ASSERTION(*(p-1) == '/', "Path did not begin with a slash!");
|
||||
|
||||
if (*p == '/')
|
||||
return NS_ERROR_MALFORMED_URI;
|
||||
|
||||
nsCOMPtr<nsIURI> baseURI;
|
||||
rv = GetSubstitution(host, getter_AddRefs(baseURI));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = baseURI->Resolve(nsDependentCString(p, path.Length()-1), result);
|
||||
// Unescape the path so we can perform some checks on it.
|
||||
nsCOMPtr<nsIURL> url = do_QueryInterface(uri);
|
||||
if (!url) {
|
||||
return NS_ERROR_MALFORMED_URI;
|
||||
}
|
||||
|
||||
nsAutoCString unescapedPath;
|
||||
rv = url->GetFilePath(unescapedPath);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
NS_UnescapeURL(unescapedPath);
|
||||
if (unescapedPath.FindChar('\\') != -1) {
|
||||
return NS_ERROR_MALFORMED_URI;
|
||||
}
|
||||
|
||||
// Some code relies on an empty path resolving to a file rather than a
|
||||
// directory.
|
||||
NS_ASSERTION(path.CharAt(0) == '/', "Path must begin with '/'");
|
||||
if (path.Length() == 1) {
|
||||
rv = baseURI->GetSpec(result);
|
||||
} else {
|
||||
// Make sure we always resolve the path as file-relative to our target URI.
|
||||
path.InsertLiteral(".", 0);
|
||||
|
||||
rv = baseURI->Resolve(path, result);
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (MOZ_LOG_TEST(gResLog, LogLevel::Debug)) {
|
||||
nsAutoCString spec;
|
||||
|
||||
@@ -21,46 +21,27 @@ using mozilla::dom::ContentParent;
|
||||
using mozilla::LogLevel;
|
||||
using mozilla::Unused;
|
||||
|
||||
#define kAPP NS_LITERAL_CSTRING("app")
|
||||
#define kGRE NS_LITERAL_CSTRING("gre")
|
||||
#define kAPP "app"
|
||||
#define kGRE "gre"
|
||||
|
||||
nsresult
|
||||
nsResProtocolHandler::Init()
|
||||
{
|
||||
nsresult rv;
|
||||
nsAutoCString appURI, greURI;
|
||||
rv = mozilla::Omnijar::GetURIString(mozilla::Omnijar::APP, appURI);
|
||||
rv = mozilla::Omnijar::GetURIString(mozilla::Omnijar::APP, mAppURI);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = mozilla::Omnijar::GetURIString(mozilla::Omnijar::GRE, greURI);
|
||||
rv = mozilla::Omnijar::GetURIString(mozilla::Omnijar::GRE, mGREURI);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
//
|
||||
// make resource:/// point to the application directory or omnijar
|
||||
//
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
rv = NS_NewURI(getter_AddRefs(uri), appURI.Length() ? appURI : greURI);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = SetSubstitution(EmptyCString(), uri);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
//
|
||||
// make resource://app/ point to the application directory or omnijar
|
||||
//
|
||||
rv = SetSubstitution(kAPP, uri);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
//
|
||||
// make resource://gre/ point to the GRE directory
|
||||
//
|
||||
if (appURI.Length()) { // We already have greURI in uri if appURI.Length() is 0.
|
||||
rv = NS_NewURI(getter_AddRefs(uri), greURI);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
// mozilla::Omnijar::GetURIString always returns a string ending with /,
|
||||
// and we want to remove it.
|
||||
mGREURI.Truncate(mGREURI.Length() - 1);
|
||||
if (mAppURI.Length()) {
|
||||
mAppURI.Truncate(mAppURI.Length() - 1);
|
||||
} else {
|
||||
mAppURI = mGREURI;
|
||||
}
|
||||
|
||||
rv = SetSubstitution(kGRE, uri);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
//XXXbsmedberg Neil wants a resource://pchrome/ for the profile chrome dir...
|
||||
// but once I finish multiple chrome registration I'm not sure that it is needed
|
||||
|
||||
@@ -83,20 +64,36 @@ NS_IMPL_RELEASE_INHERITED(nsResProtocolHandler, SubstitutingProtocolHandler)
|
||||
nsresult
|
||||
nsResProtocolHandler::GetSubstitutionInternal(const nsACString& root, nsIURI **result)
|
||||
{
|
||||
// try invoking the directory service for "resource:root"
|
||||
nsAutoCString uri;
|
||||
|
||||
nsAutoCString key;
|
||||
key.AssignLiteral("resource:");
|
||||
key.Append(root);
|
||||
|
||||
nsCOMPtr<nsIFile> file;
|
||||
nsresult rv = NS_GetSpecialDirectory(key.get(), getter_AddRefs(file));
|
||||
if (NS_FAILED(rv))
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
rv = IOService()->NewFileURI(file, result);
|
||||
if (NS_FAILED(rv))
|
||||
if (!ResolveSpecialCases(root, NS_LITERAL_CSTRING("/"), uri)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
return NS_NewURI(result, uri);
|
||||
}
|
||||
|
||||
bool
|
||||
nsResProtocolHandler::ResolveSpecialCases(const nsACString& aHost,
|
||||
const nsACString& aPath,
|
||||
nsACString& aResult)
|
||||
{
|
||||
if (aHost.Equals("") || aHost.Equals(kAPP)) {
|
||||
aResult.Assign(mAppURI);
|
||||
} else if (aHost.Equals(kGRE)) {
|
||||
aResult.Assign(mGREURI);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
aResult.Append(aPath);
|
||||
return true;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsResProtocolHandler::SetSubstitution(const nsACString& aRoot, nsIURI* aBaseURI)
|
||||
{
|
||||
MOZ_ASSERT(!aRoot.Equals(""));
|
||||
MOZ_ASSERT(!aRoot.Equals(kAPP));
|
||||
MOZ_ASSERT(!aRoot.Equals(kGRE));
|
||||
return SubstitutingProtocolHandler::SetSubstitution(aRoot, aBaseURI);
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ public:
|
||||
NS_DECL_NSIRESPROTOCOLHANDLER
|
||||
|
||||
NS_FORWARD_NSIPROTOCOLHANDLER(mozilla::SubstitutingProtocolHandler::)
|
||||
NS_FORWARD_NSISUBSTITUTINGPROTOCOLHANDLER(mozilla::SubstitutingProtocolHandler::)
|
||||
|
||||
nsResProtocolHandler()
|
||||
: SubstitutingProtocolHandler("resource", URI_STD | URI_IS_UI_RESOURCE | URI_IS_LOCAL_RESOURCE,
|
||||
@@ -32,9 +31,33 @@ public:
|
||||
|
||||
nsresult Init();
|
||||
|
||||
NS_IMETHOD SetSubstitution(const nsACString& aRoot, nsIURI* aBaseURI) override;
|
||||
|
||||
NS_IMETHOD GetSubstitution(const nsACString& aRoot, nsIURI** aResult) override
|
||||
{
|
||||
return mozilla::SubstitutingProtocolHandler::GetSubstitution(aRoot, aResult);
|
||||
}
|
||||
|
||||
NS_IMETHOD HasSubstitution(const nsACString& aRoot, bool* aResult) override
|
||||
{
|
||||
return mozilla::SubstitutingProtocolHandler::HasSubstitution(aRoot, aResult);
|
||||
}
|
||||
|
||||
NS_IMETHOD ResolveURI(nsIURI *aResURI, nsACString& aResult) override
|
||||
{
|
||||
return mozilla::SubstitutingProtocolHandler::ResolveURI(aResURI, aResult);
|
||||
}
|
||||
|
||||
protected:
|
||||
nsresult GetSubstitutionInternal(const nsACString& aRoot, nsIURI** aResult) override;
|
||||
virtual ~nsResProtocolHandler() {}
|
||||
|
||||
bool ResolveSpecialCases(const nsACString& aHost, const nsACString& aPath,
|
||||
nsACString& aResult) override;
|
||||
|
||||
private:
|
||||
nsCString mAppURI;
|
||||
nsCString mGREURI;
|
||||
};
|
||||
|
||||
#endif /* nsResProtocolHandler_h___ */
|
||||
|
||||
@@ -10,7 +10,8 @@ NS_IMPL_ISUPPORTS(nsDirIndex,
|
||||
|
||||
nsDirIndex::nsDirIndex() : mType(TYPE_UNKNOWN),
|
||||
mSize(UINT64_MAX),
|
||||
mLastModified(-1) {
|
||||
mLastModified(-1LL)
|
||||
{
|
||||
}
|
||||
|
||||
nsDirIndex::~nsDirIndex() {}
|
||||
@@ -18,9 +19,7 @@ nsDirIndex::~nsDirIndex() {}
|
||||
NS_IMETHODIMP
|
||||
nsDirIndex::GetType(uint32_t* aType)
|
||||
{
|
||||
if (!aType) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
NS_ENSURE_ARG_POINTER(aType);
|
||||
|
||||
*aType = mType;
|
||||
return NS_OK;
|
||||
@@ -34,7 +33,10 @@ nsDirIndex::SetType(uint32_t aType)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDirIndex::GetContentType(char* *aContentType) {
|
||||
nsDirIndex::GetContentType(char* *aContentType)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aContentType);
|
||||
|
||||
*aContentType = ToNewCString(mContentType);
|
||||
if (!*aContentType)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
@@ -43,13 +45,17 @@ nsDirIndex::GetContentType(char* *aContentType) {
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDirIndex::SetContentType(const char* aContentType) {
|
||||
nsDirIndex::SetContentType(const char* aContentType)
|
||||
{
|
||||
mContentType = aContentType;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDirIndex::GetLocation(char* *aLocation) {
|
||||
nsDirIndex::GetLocation(char* *aLocation)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aLocation);
|
||||
|
||||
*aLocation = ToNewCString(mLocation);
|
||||
if (!*aLocation)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
@@ -58,13 +64,17 @@ nsDirIndex::GetLocation(char* *aLocation) {
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDirIndex::SetLocation(const char* aLocation) {
|
||||
nsDirIndex::SetLocation(const char* aLocation)
|
||||
{
|
||||
mLocation = aLocation;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDirIndex::GetDescription(char16_t* *aDescription) {
|
||||
nsDirIndex::GetDescription(char16_t* *aDescription)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aDescription);
|
||||
|
||||
*aDescription = ToNewUnicode(mDescription);
|
||||
if (!*aDescription)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
@@ -73,7 +83,8 @@ nsDirIndex::GetDescription(char16_t* *aDescription) {
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDirIndex::SetDescription(const char16_t* aDescription) {
|
||||
nsDirIndex::SetDescription(const char16_t* aDescription)
|
||||
{
|
||||
mDescription.Assign(aDescription);
|
||||
return NS_OK;
|
||||
}
|
||||
@@ -81,9 +92,7 @@ nsDirIndex::SetDescription(const char16_t* aDescription) {
|
||||
NS_IMETHODIMP
|
||||
nsDirIndex::GetSize(int64_t* aSize)
|
||||
{
|
||||
if (!aSize) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
NS_ENSURE_ARG_POINTER(aSize);
|
||||
|
||||
*aSize = mSize;
|
||||
return NS_OK;
|
||||
@@ -99,9 +108,7 @@ nsDirIndex::SetSize(int64_t aSize)
|
||||
NS_IMETHODIMP
|
||||
nsDirIndex::GetLastModified(PRTime* aLastModified)
|
||||
{
|
||||
if (!aLastModified) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
NS_ENSURE_ARG_POINTER(aLastModified);
|
||||
|
||||
*aLastModified = mLastModified;
|
||||
return NS_OK;
|
||||
|
||||
@@ -134,7 +134,7 @@ nsHTTPCompressConv::OnStopRequest(nsIRequest* request, nsISupports *aContext,
|
||||
if (fpChannel && !isPending) {
|
||||
fpChannel->ForcePending(true);
|
||||
}
|
||||
if (mBrotli && mBrotli->mTotalOut == 0 && !BrotliDecoderIsFinished(&mBrotli->mState)) {
|
||||
if (mBrotli && (mBrotli->mTotalOut == 0) && !BrotliDecoderIsFinished(&mBrotli->mState)) {
|
||||
status = NS_ERROR_INVALID_CONTENT_ENCODING;
|
||||
}
|
||||
if (fpChannel && !isPending) {
|
||||
|
||||
@@ -800,7 +800,7 @@ nsIndexedToHTML::OnIndexAvailable(nsIRequest *aRequest,
|
||||
PRTime t;
|
||||
aIndex->GetLastModified(&t);
|
||||
|
||||
if (t == -1) {
|
||||
if (t == -1LL) {
|
||||
pushBuffer.AppendLiteral("></td>\n <td>");
|
||||
} else {
|
||||
pushBuffer.AppendLiteral(" sortable-data=\"");
|
||||
|
||||
@@ -666,6 +666,10 @@ nsMultiMixedConv::OnDataAvailable(nsIRequest *request, nsISupports *context,
|
||||
// Push the cursor to the token so that the while loop below will
|
||||
// find token from the right position.
|
||||
cursor = tokenPos;
|
||||
|
||||
// Update bufLen to exlude the preamble. Otherwise, the first
|
||||
// |SendData| would claim longer buffer length.
|
||||
bufLen -= mPreamble.Length();
|
||||
}
|
||||
} else {
|
||||
// If the boundary was set in the header,
|
||||
|
||||
@@ -1,41 +1,114 @@
|
||||
/* verify that certain invalid URIs are not parsed by the resource
|
||||
protocol handler */
|
||||
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const specs = [
|
||||
"resource:////",
|
||||
"resource:///http://www.mozilla.org/",
|
||||
"resource:///file:///",
|
||||
"resource:///..\\",
|
||||
"resource:///..\\..\\",
|
||||
"resource:///..%5C",
|
||||
"resource:///..%5c"
|
||||
"resource://res-test//",
|
||||
"resource://res-test/?foo=http:",
|
||||
"resource://res-test/?foo=" + encodeURIComponent("http://example.com/"),
|
||||
"resource://res-test/?foo=" + encodeURIComponent("x\\y"),
|
||||
"resource://res-test/..%2F",
|
||||
"resource://res-test/..%2f",
|
||||
"resource://res-test/..%2F..",
|
||||
"resource://res-test/..%2f..",
|
||||
"resource://res-test/../../",
|
||||
"resource://res-test/http://www.mozilla.org/",
|
||||
"resource://res-test/file:///",
|
||||
];
|
||||
|
||||
function check_for_exception(spec)
|
||||
const error_specs = [
|
||||
"resource://res-test/..\\",
|
||||
"resource://res-test/..\\..\\",
|
||||
"resource://res-test/..%5C",
|
||||
"resource://res-test/..%5c",
|
||||
];
|
||||
|
||||
// Create some fake principal that has not enough
|
||||
// privileges to access any resource: uri.
|
||||
var uri = NetUtil.newURI("http://www.example.com", null, null);
|
||||
var principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
|
||||
|
||||
function get_channel(spec)
|
||||
{
|
||||
var ios =
|
||||
Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
var channelURI = NetUtil.newURI(spec, null, null);
|
||||
|
||||
var channel = NetUtil.newChannel({
|
||||
uri: NetUtil.newURI(spec, null, null),
|
||||
loadingPrincipal: principal,
|
||||
securityFlags: Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
|
||||
contentPolicyType: Ci.nsIContentPolicy.TYPE_OTHER
|
||||
});
|
||||
|
||||
try {
|
||||
var channel = ios.newChannel2(spec,
|
||||
null,
|
||||
null,
|
||||
null, // aLoadingNode
|
||||
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
null, // aTriggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_NORMAL,
|
||||
Ci.nsIContentPolicy.TYPE_OTHER);
|
||||
channel.asyncOpen2(null);
|
||||
ok(false, "asyncOpen2() of URI: " + spec + "should throw");
|
||||
}
|
||||
catch (e) {
|
||||
return;
|
||||
// make sure we get the right error code in the exception
|
||||
// ERROR code for NS_ERROR_DOM_BAD_URI is 1012
|
||||
equal(e.code, 1012);
|
||||
}
|
||||
|
||||
do_throw("Successfully opened invalid URI: '" + spec + "'");
|
||||
try {
|
||||
channel.open2();
|
||||
ok(false, "Open2() of uri: " + spec + "should throw");
|
||||
}
|
||||
catch (e) {
|
||||
// make sure we get the right error code in the exception
|
||||
// ERROR code for NS_ERROR_DOM_BAD_URI is 1012
|
||||
equal(e.code, 1012);
|
||||
}
|
||||
|
||||
return channel;
|
||||
}
|
||||
|
||||
function check_safe_resolution(spec, rootURI)
|
||||
{
|
||||
do_print(`Testing URL "${spec}"`);
|
||||
|
||||
let channel = get_channel(spec);
|
||||
|
||||
ok(channel.name.startsWith(rootURI), `URL resolved safely to ${channel.name}`);
|
||||
ok(!/%2f/i.test(channel.name), `URL contains no escaped / characters`);
|
||||
}
|
||||
|
||||
function check_resolution_error(spec)
|
||||
{
|
||||
try {
|
||||
get_channel(spec);
|
||||
ok(false, "Expected an error");
|
||||
} catch (e) {
|
||||
equal(e.result, Components.results.NS_ERROR_MALFORMED_URI,
|
||||
"Expected a malformed URI error");
|
||||
}
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
// resource:/// and resource://gre/ are resolved specially, so we need
|
||||
// to create a temporary resource package to test the standard logic
|
||||
// with.
|
||||
|
||||
let resProto = Cc['@mozilla.org/network/protocol;1?name=resource'].getService(Ci.nsIResProtocolHandler);
|
||||
let rootFile = Services.dirsvc.get("GreD", Ci.nsIFile);
|
||||
let rootURI = Services.io.newFileURI(rootFile);
|
||||
|
||||
resProto.setSubstitution("res-test", rootURI);
|
||||
do_register_cleanup(() => {
|
||||
resProto.setSubstitution("res-test", null);
|
||||
});
|
||||
|
||||
let baseRoot = resProto.resolveURI(Services.io.newURI("resource:///", null, null));
|
||||
let greRoot = resProto.resolveURI(Services.io.newURI("resource://gre/", null, null));
|
||||
|
||||
for (var spec of specs) {
|
||||
check_for_exception(spec);
|
||||
check_safe_resolution(spec, rootURI.spec);
|
||||
check_safe_resolution(spec.replace("res-test", ""), baseRoot);
|
||||
check_safe_resolution(spec.replace("res-test", "gre"), greRoot);
|
||||
}
|
||||
|
||||
for (var spec of error_specs) {
|
||||
check_resolution_error(spec);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ This test exercises the CacheFileContextEvictor::WasEvicted API and code using i
|
||||
|
||||
- We store 10+10 (pinned and non-pinned) entries to the cache, wait for them being written.
|
||||
- Then we purge the memory pools.
|
||||
- Now the IO thread is suspended on the EVICT (8) level to prevent actual deletion of the files.
|
||||
- Now the IO thread is suspended on the EVICT (7) level to prevent actual deletion of the files.
|
||||
- Index is disabled.
|
||||
- We do clear() of the cache, this creates the "ce_*" file and posts to the EVICT level
|
||||
the eviction loop mechanics.
|
||||
@@ -47,9 +47,9 @@ function run_test()
|
||||
|
||||
// (1), here we start
|
||||
|
||||
log_("first set of opens");
|
||||
var i;
|
||||
for (i = 0; i < kENTRYCOUNT; ++i) {
|
||||
log_("first set of opens");
|
||||
|
||||
// Callbacks 1-20
|
||||
mc.add();
|
||||
@@ -72,7 +72,7 @@ function run_test()
|
||||
log_("after purge");
|
||||
// Prevent the I/O thread from evicting physically the data. We first want to re-open the entries.
|
||||
// This deterministically emulates a slow hard drive.
|
||||
testingInterface.suspendCacheIOThread(8);
|
||||
testingInterface.suspendCacheIOThread(7);
|
||||
|
||||
log_("clearing");
|
||||
// Now clear everything except pinned. Stores the "ce_*" file and schedules background eviction.
|
||||
@@ -96,7 +96,9 @@ function run_test()
|
||||
// an early check on CacheIOThread::YieldAndRerun() in that method.
|
||||
// CacheFileIOManager::OpenFileInternal should now run and CacheFileContextEvictor::WasEvicted
|
||||
// should be checked on.
|
||||
log_("resuming");
|
||||
testingInterface.resumeCacheIOThread();
|
||||
log_("resumed");
|
||||
|
||||
mc.fired(); // Finishes this test
|
||||
}
|
||||
|
||||
@@ -76,11 +76,17 @@ function contentHandler_type_missing(metadata, response)
|
||||
response.bodyOutputStream.write(body, body.length);
|
||||
}
|
||||
|
||||
function contentHandler_with_package_header(metadata, response)
|
||||
function contentHandler_with_package_header(chunkSize, metadata, response)
|
||||
{
|
||||
response.setHeader("Content-Type", 'application/package');
|
||||
var body = testData.packageHeader + testData.getData();
|
||||
response.bodyOutputStream.write(body, body.length);
|
||||
|
||||
response.bodyOutputStream.write(body.substring(0,chunkSize), chunkSize);
|
||||
response.processAsync();
|
||||
do_timeout(5, function() {
|
||||
response.bodyOutputStream.write(body.substring(chunkSize), body.length-chunkSize);
|
||||
response.finish();
|
||||
});
|
||||
}
|
||||
|
||||
var testData = {
|
||||
@@ -244,7 +250,7 @@ function test_multipart_content_type_other() {
|
||||
chan.asyncOpen(conv, null);
|
||||
}
|
||||
|
||||
function test_multipart_package_header() {
|
||||
function test_multipart_package_header(aChunkSize) {
|
||||
var streamConv = Cc["@mozilla.org/streamConverters;1"]
|
||||
.getService(Ci.nsIStreamConverterService);
|
||||
|
||||
@@ -253,10 +259,29 @@ function test_multipart_package_header() {
|
||||
new multipartListener(testData, false, true),
|
||||
null);
|
||||
|
||||
var chan = make_channel(uri + "/multipart5");
|
||||
var chan = make_channel(uri + "/multipart5_" + aChunkSize);
|
||||
chan.asyncOpen(conv, null);
|
||||
}
|
||||
|
||||
// Bug 1212223 - Test multipart with package header and different chunk size.
|
||||
// Use explict function name to make the test case log more readable.
|
||||
|
||||
function test_multipart_package_header_50() {
|
||||
return test_multipart_package_header(50);
|
||||
}
|
||||
|
||||
function test_multipart_package_header_100() {
|
||||
return test_multipart_package_header(100);
|
||||
}
|
||||
|
||||
function test_multipart_package_header_150() {
|
||||
return test_multipart_package_header(150);
|
||||
}
|
||||
|
||||
function test_multipart_package_header_200() {
|
||||
return test_multipart_package_header(200);
|
||||
}
|
||||
|
||||
function run_test()
|
||||
{
|
||||
httpserver = new HttpServer();
|
||||
@@ -264,7 +289,13 @@ function run_test()
|
||||
httpserver.registerPathHandler("/multipart2", contentHandler_with_boundary);
|
||||
httpserver.registerPathHandler("/multipart3", contentHandler_chunked_headers);
|
||||
httpserver.registerPathHandler("/multipart4", contentHandler_type_missing);
|
||||
httpserver.registerPathHandler("/multipart5", contentHandler_with_package_header);
|
||||
|
||||
// Bug 1212223 - Test multipart with package header and different chunk size.
|
||||
httpserver.registerPathHandler("/multipart5_50", contentHandler_with_package_header.bind(null, 50));
|
||||
httpserver.registerPathHandler("/multipart5_100", contentHandler_with_package_header.bind(null, 100));
|
||||
httpserver.registerPathHandler("/multipart5_150", contentHandler_with_package_header.bind(null, 150));
|
||||
httpserver.registerPathHandler("/multipart5_200", contentHandler_with_package_header.bind(null, 200));
|
||||
|
||||
httpserver.start(-1);
|
||||
|
||||
run_next_test();
|
||||
@@ -274,4 +305,9 @@ add_test(test_multipart);
|
||||
add_test(test_multipart_with_boundary);
|
||||
add_test(test_multipart_chunked_headers);
|
||||
add_test(test_multipart_content_type_other);
|
||||
add_test(test_multipart_package_header);
|
||||
|
||||
// Bug 1212223 - Test multipart with package header and different chunk size.
|
||||
add_test(test_multipart_package_header_50);
|
||||
add_test(test_multipart_package_header_100);
|
||||
add_test(test_multipart_package_header_150);
|
||||
add_test(test_multipart_package_header_200);
|
||||
|
||||
@@ -247,6 +247,8 @@ function run_test()
|
||||
add_test(test_worse_package_4);
|
||||
add_test(test_worse_package_5);
|
||||
|
||||
add_test(test_request_has_ref);
|
||||
|
||||
// run tests
|
||||
run_next_test();
|
||||
}
|
||||
@@ -334,6 +336,13 @@ function test_updated_package() {
|
||||
new packagedResourceListener(testData.content[0].data.replace(/\.\.\./g, 'xxx')));
|
||||
}
|
||||
|
||||
// This tests that requested URI with reference should still work.
|
||||
function test_request_has_ref() {
|
||||
packagePath = "/package";
|
||||
let url = uri + packagePath + "!//index.html#Ref";
|
||||
paservice.getResource(getChannelForURL(url), cacheListener);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// This listener checks that the requested resources are not returned
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
function is_app_offline(appId) {
|
||||
let ioservice = Cc['@mozilla.org/network/io-service;1'].
|
||||
getService(Ci.nsIIOService);
|
||||
return ioservice.isAppOffline(appId);
|
||||
}
|
||||
|
||||
var events_observed_no = 0;
|
||||
|
||||
// Holds the last observed app-offline event
|
||||
var info = null;
|
||||
function observer(aSubject, aTopic, aData) {
|
||||
events_observed_no++;
|
||||
info = aSubject.QueryInterface(Ci.nsIAppOfflineInfo);
|
||||
dump("ChildObserver - subject: {" + aSubject.appId + ", " + aSubject.mode + "} ");
|
||||
}
|
||||
|
||||
// Add observer for the app-offline notification
|
||||
function run_test() {
|
||||
Services.obs.addObserver(observer, "network:app-offline-status-changed", false);
|
||||
}
|
||||
|
||||
// Chech that the app has the proper offline status
|
||||
function check_status(appId, status)
|
||||
{
|
||||
do_check_eq(is_app_offline(appId), status == Ci.nsIAppOfflineInfo.OFFLINE);
|
||||
}
|
||||
|
||||
// Check that the app has the proper offline status
|
||||
// and that the correct notification has been received
|
||||
function check_notification_and_status(appId, status) {
|
||||
do_check_eq(info.appId, appId);
|
||||
do_check_eq(info.mode, status);
|
||||
do_check_eq(is_app_offline(appId), status == Ci.nsIAppOfflineInfo.OFFLINE);
|
||||
}
|
||||
|
||||
// Remove the observer from the child process
|
||||
function finished() {
|
||||
Services.obs.removeObserver(observer, "network:app-offline-status-changed");
|
||||
do_check_eq(events_observed_no, 2);
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
// Checks that app-offline notifications are received in both the parent
|
||||
// and the child process, and that after receiving the notification
|
||||
// isAppOffline returns the correct value
|
||||
|
||||
|
||||
Cu.import("resource://testing-common/httpd.js");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
var test_index = 0;
|
||||
var APP_ID = 42;
|
||||
var events_observed_no = 0;
|
||||
|
||||
function set_app_offline(appId, offline) {
|
||||
let ioservice = Cc['@mozilla.org/network/io-service;1'].
|
||||
getService(Ci.nsIIOService);
|
||||
ioservice.setAppOffline(appId, offline);
|
||||
}
|
||||
|
||||
function is_app_offline(appId) {
|
||||
let ioservice = Cc['@mozilla.org/network/io-service;1'].
|
||||
getService(Ci.nsIIOService);
|
||||
return ioservice.isAppOffline(appId);
|
||||
}
|
||||
|
||||
// The expected offline status after running each function,
|
||||
// and the next function that should be run.
|
||||
|
||||
// test0 test1 test2 test3 test4
|
||||
let expected_offline = [ false, true, true, false, false];
|
||||
let callbacks = [ test1, test2, test3, test4, finished];
|
||||
|
||||
function observer(aSubject, aTopic, aData) {
|
||||
events_observed_no++;
|
||||
let info = aSubject.QueryInterface(Ci.nsIAppOfflineInfo);
|
||||
dump("ParentObserver - subject: {" + aSubject.appId + ", " + aSubject.mode + "} " +
|
||||
"topic: " + aTopic + "\n");
|
||||
|
||||
// Check that the correct offline status is in place
|
||||
do_check_eq(is_app_offline(APP_ID), expected_offline[test_index]);
|
||||
|
||||
// Execute the callback for the current test
|
||||
do_execute_soon(callbacks[test_index]);
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
Services.obs.addObserver(observer, "network:app-offline-status-changed", false);
|
||||
|
||||
test_index = 0;
|
||||
do_check_eq(is_app_offline(APP_ID), expected_offline[test_index]) // The app should be online at first
|
||||
run_test_in_child("child_app_offline_notifications.js", test0);
|
||||
}
|
||||
|
||||
// Check that the app is online by default in the child
|
||||
function test0() {
|
||||
dump("parent: RUNNING: test0\n");
|
||||
test_index = 0;
|
||||
sendCommand('check_status('+APP_ID+','+Ci.nsIAppOfflineInfo.ONLINE+');\n', test1);
|
||||
}
|
||||
|
||||
// Set the app OFFLINE
|
||||
// Check that the notification is emmited in the parent process
|
||||
// The observer function will execute test2 which does the check in the child
|
||||
function test1() {
|
||||
dump("parent: RUNNING: test1\n");
|
||||
test_index = 1;
|
||||
set_app_offline(APP_ID, Ci.nsIAppOfflineInfo.OFFLINE);
|
||||
}
|
||||
|
||||
// Checks that child process sees the app OFFLINE
|
||||
function test2() {
|
||||
dump("parent: RUNNING: test2\n");
|
||||
test_index = 2;
|
||||
sendCommand('check_notification_and_status('+APP_ID+','+Ci.nsIAppOfflineInfo.OFFLINE+');\n', test3);
|
||||
}
|
||||
|
||||
// Set the app ONLINE
|
||||
// Chech that the notification is received in the parent
|
||||
// The observer function will execute test3 and do the check in the child
|
||||
function test3() {
|
||||
dump("parent: RUNNING: test3\n");
|
||||
test_index = 3;
|
||||
set_app_offline(APP_ID, Ci.nsIAppOfflineInfo.ONLINE);
|
||||
}
|
||||
|
||||
// Chech that the app is back online
|
||||
function test4() {
|
||||
dump("parent: RUNNING: test4\n");
|
||||
test_index = 4;
|
||||
sendCommand('check_notification_and_status('+APP_ID+','+Ci.nsIAppOfflineInfo.ONLINE+');\n', function() {
|
||||
// Send command to unregister observer on the child
|
||||
sendCommand('finished();\n', finished);
|
||||
});
|
||||
}
|
||||
|
||||
// Remove observer and end test
|
||||
function finished() {
|
||||
dump("parent: RUNNING: finished\n");
|
||||
Services.obs.removeObserver(observer, "network:app-offline-status-changed");
|
||||
do_check_eq(events_observed_no, 2);
|
||||
do_test_finished();
|
||||
}
|
||||
@@ -92,3 +92,4 @@ skip-if = true
|
||||
[test_reply_without_content_type_wrap.js]
|
||||
[test_app_offline_http.js]
|
||||
[test_getHost_wrap.js]
|
||||
[test_app_offline_notifications.js]
|
||||
|
||||
@@ -991,6 +991,8 @@ nsChildView::BackingScaleFactorChanged()
|
||||
}
|
||||
|
||||
mBackingScaleFactor = newScale;
|
||||
NSRect frame = [mView frame];
|
||||
mBounds = nsCocoaUtils::CocoaRectToGeckoRectDevPix(frame, newScale);
|
||||
|
||||
if (mWidgetListener && !mWidgetListener->GetXULWindow()) {
|
||||
nsIPresShell* presShell = mWidgetListener->GetPresShell();
|
||||
@@ -2968,6 +2970,7 @@ RectTextureImage::EndUpdate(bool aKeepSurface)
|
||||
LayoutDeviceIntRegion updateRegion = mUpdateRegion;
|
||||
if (mTextureSize != mBufferSize) {
|
||||
mTextureSize = mBufferSize;
|
||||
needInit = true;
|
||||
}
|
||||
|
||||
if (needInit || !CanUploadSubtextures()) {
|
||||
|
||||
@@ -169,7 +169,7 @@ nsLookAndFeel::NativeGetColor(ColorID aID, nscolor &aColor)
|
||||
aColor = GetColorFromNSColor([NSColor gridColor]);
|
||||
break;
|
||||
case eColorID_activeborder:
|
||||
aColor = NS_RGB(0x00,0x00,0x00);
|
||||
aColor = GetColorFromNSColor([NSColor keyboardFocusIndicatorColor]);
|
||||
break;
|
||||
case eColorID_appworkspace:
|
||||
aColor = NS_RGB(0xFF,0xFF,0xFF);
|
||||
@@ -601,4 +601,4 @@ nsLookAndFeel::RefreshImpl()
|
||||
mUseOverlayScrollbarsCached = false;
|
||||
mAllowOverlayScrollbarsOverlapCached = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,7 +226,7 @@ NativeKeyBindings::GetInstance(NativeKeyBindingsType aType)
|
||||
|
||||
default:
|
||||
// fallback to multiline editor case in release build
|
||||
MOZ_ASSERT(false, "aType is invalid or not yet implemented");
|
||||
MOZ_FALLTHROUGH_ASSERT("aType is invalid or not yet implemented");
|
||||
case nsIWidget::NativeKeyBindingsForMultiLineEditor:
|
||||
case nsIWidget::NativeKeyBindingsForRichTextEditor:
|
||||
if (!sInstanceForMultiLineEditor) {
|
||||
|
||||
@@ -83,6 +83,8 @@ GetGradientColors(const GValue* aValue,
|
||||
return false;
|
||||
|
||||
auto pattern = static_cast<cairo_pattern_t*>(g_value_get_boxed(aValue));
|
||||
if (!pattern)
|
||||
return false;
|
||||
|
||||
// Just picking the lightest and darkest colors as simple samples rather
|
||||
// than trying to blend, which could get messy if there are many stops.
|
||||
|
||||
+108
-55
@@ -1032,6 +1032,13 @@ void nsXULWindow::OnChromeLoaded()
|
||||
ApplyChromeFlags();
|
||||
SyncAttributesToWidget();
|
||||
|
||||
int32_t specWidth = -1, specHeight = -1;
|
||||
bool gotSize = false;
|
||||
|
||||
if (!mIgnoreXULSize) {
|
||||
gotSize = LoadSizeFromXUL(specWidth, specHeight);
|
||||
}
|
||||
|
||||
bool positionSet = !mIgnoreXULPosition;
|
||||
nsCOMPtr<nsIXULWindow> parentWindow(do_QueryReferent(mParentWindow));
|
||||
#if defined(XP_UNIX) && !defined(XP_MACOSX)
|
||||
@@ -1041,11 +1048,18 @@ void nsXULWindow::OnChromeLoaded()
|
||||
if (!parentWindow)
|
||||
positionSet = false;
|
||||
#endif
|
||||
if (positionSet)
|
||||
positionSet = LoadPositionFromXUL();
|
||||
if (positionSet) {
|
||||
// We have to do this before sizing the window, because sizing depends
|
||||
// on the resolution of the screen we're on. But positioning needs to
|
||||
// know the size so that it can constrain to screen bounds.... as an
|
||||
// initial guess here, we'll use the specified size (if any).
|
||||
positionSet = LoadPositionFromXUL(specWidth, specHeight);
|
||||
}
|
||||
|
||||
if (gotSize) {
|
||||
SetSpecifiedSize(specWidth, specHeight);
|
||||
}
|
||||
|
||||
if (!mIgnoreXULSize)
|
||||
LoadSizeFromXUL();
|
||||
if (mIntrinsicallySized) {
|
||||
// (if LoadSizeFromXUL set the size, mIntrinsicallySized will be false)
|
||||
nsCOMPtr<nsIContentViewer> cv;
|
||||
@@ -1060,15 +1074,25 @@ void nsXULWindow::OnChromeLoaded()
|
||||
int32_t width = 0, height = 0;
|
||||
if (NS_SUCCEEDED(cv->GetContentSize(&width, &height))) {
|
||||
treeOwner->SizeShellTo(docShellAsItem, width, height);
|
||||
// Update specified size for the final LoadPositionFromXUL call.
|
||||
specWidth = width;
|
||||
specHeight = height;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now that we have set the window's final size, we can re-do its
|
||||
// positioning so that it is properly constrained to the screen.
|
||||
if (positionSet) {
|
||||
LoadPositionFromXUL(specWidth, specHeight);
|
||||
}
|
||||
|
||||
LoadMiscPersistentAttributesFromXUL();
|
||||
|
||||
if (mCenterAfterLoad && !positionSet)
|
||||
if (mCenterAfterLoad && !positionSet) {
|
||||
Center(parentWindow, parentWindow ? false : true, false);
|
||||
}
|
||||
|
||||
if (mShowAfterLoad) {
|
||||
SetVisibility(true);
|
||||
@@ -1079,7 +1103,10 @@ void nsXULWindow::OnChromeLoaded()
|
||||
mPersistentAttributesMask |= PAD_POSITION | PAD_SIZE | PAD_MISC;
|
||||
}
|
||||
|
||||
bool nsXULWindow::LoadPositionFromXUL()
|
||||
// If aSpecWidth and/or aSpecHeight are > 0, we will use these CSS px sizes
|
||||
// to fit to the screen when staggering windows; if they're negative,
|
||||
// we use the window's current size instead.
|
||||
bool nsXULWindow::LoadPositionFromXUL(int32_t aSpecWidth, int32_t aSpecHeight)
|
||||
{
|
||||
bool gotPosition = false;
|
||||
|
||||
@@ -1102,11 +1129,16 @@ bool nsXULWindow::LoadPositionFromXUL()
|
||||
|
||||
// Convert to global display pixels for consistent window management across
|
||||
// screens with diverse resolutions
|
||||
double scale = mWindow->GetDesktopToDeviceScale().scale;
|
||||
currX = NSToIntRound(currX / scale);
|
||||
currY = NSToIntRound(currY / scale);
|
||||
currWidth = NSToIntRound(currWidth / scale);
|
||||
currHeight = NSToIntRound(currHeight / scale);
|
||||
double devToDesktopScale = 1.0 / mWindow->GetDesktopToDeviceScale().scale;
|
||||
currX = NSToIntRound(currX * devToDesktopScale);
|
||||
currY = NSToIntRound(currY * devToDesktopScale);
|
||||
|
||||
// For size, use specified value if > 0, else current value
|
||||
double devToCSSScale = 1.0 / mWindow->GetDefaultScale().scale;
|
||||
int32_t cssWidth =
|
||||
aSpecWidth > 0 ? aSpecWidth : NSToIntRound(currWidth * devToCSSScale);
|
||||
int32_t cssHeight =
|
||||
aSpecHeight > 0 ? aSpecHeight : NSToIntRound(currHeight * devToCSSScale);
|
||||
|
||||
// Obtain the position information from the <xul:window> element.
|
||||
int32_t specX = currX;
|
||||
@@ -1142,7 +1174,7 @@ bool nsXULWindow::LoadPositionFromXUL()
|
||||
}
|
||||
}
|
||||
else {
|
||||
StaggerPosition(specX, specY, currWidth, currHeight);
|
||||
StaggerPosition(specX, specY, cssWidth, cssHeight);
|
||||
}
|
||||
}
|
||||
mWindow->ConstrainPosition(false, &specX, &specY);
|
||||
@@ -1153,76 +1185,81 @@ bool nsXULWindow::LoadPositionFromXUL()
|
||||
return gotPosition;
|
||||
}
|
||||
|
||||
bool nsXULWindow::LoadSizeFromXUL()
|
||||
bool
|
||||
nsXULWindow::LoadSizeFromXUL(int32_t& aSpecWidth, int32_t& aSpecHeight)
|
||||
{
|
||||
bool gotSize = false;
|
||||
|
||||
// if we're the hidden window, don't try to validate our size/position. We're
|
||||
// special.
|
||||
if (mIsHiddenWindow)
|
||||
if (mIsHiddenWindow) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<dom::Element> windowElement = GetWindowDOMElement();
|
||||
NS_ENSURE_TRUE(windowElement, false);
|
||||
|
||||
int32_t currWidth = 0;
|
||||
int32_t currHeight = 0;
|
||||
nsresult errorCode;
|
||||
int32_t temp;
|
||||
|
||||
NS_ASSERTION(mWindow, "we expected to have a window already");
|
||||
|
||||
GetSize(&currWidth, &currHeight);
|
||||
double displayToDevPx =
|
||||
mWindow ? mWindow->GetDesktopToDeviceScale().scale : 1.0;
|
||||
double cssToDevPx = mWindow ? mWindow->GetDefaultScale().scale : 1.0;
|
||||
currWidth = NSToIntRound(currWidth * displayToDevPx / cssToDevPx);
|
||||
currHeight = NSToIntRound(currHeight * displayToDevPx / cssToDevPx);
|
||||
|
||||
// Obtain the position and sizing information from the <xul:window> element.
|
||||
int32_t specWidth = currWidth;
|
||||
int32_t specHeight = currHeight;
|
||||
// Obtain the sizing information from the <xul:window> element.
|
||||
aSpecWidth = 100;
|
||||
aSpecHeight = 100;
|
||||
nsAutoString sizeString;
|
||||
|
||||
windowElement->GetAttribute(WIDTH_ATTRIBUTE, sizeString);
|
||||
temp = sizeString.ToInteger(&errorCode);
|
||||
if (NS_SUCCEEDED(errorCode) && temp > 0) {
|
||||
specWidth = std::max(temp, 100);
|
||||
aSpecWidth = std::max(temp, 100);
|
||||
gotSize = true;
|
||||
}
|
||||
windowElement->GetAttribute(HEIGHT_ATTRIBUTE, sizeString);
|
||||
temp = sizeString.ToInteger(&errorCode);
|
||||
if (NS_SUCCEEDED(errorCode) && temp > 0) {
|
||||
specHeight = std::max(temp, 100);
|
||||
aSpecHeight = std::max(temp, 100);
|
||||
gotSize = true;
|
||||
}
|
||||
|
||||
if (gotSize) {
|
||||
// constrain to screen size
|
||||
nsCOMPtr<nsIDOMWindow> domWindow;
|
||||
GetWindowDOMWindow(getter_AddRefs(domWindow));
|
||||
if (domWindow) {
|
||||
nsCOMPtr<nsIDOMScreen> screen;
|
||||
domWindow->GetScreen(getter_AddRefs(screen));
|
||||
if (screen) {
|
||||
int32_t screenWidth;
|
||||
int32_t screenHeight;
|
||||
screen->GetAvailWidth(&screenWidth); // CSS pixels
|
||||
screen->GetAvailHeight(&screenHeight);
|
||||
if (specWidth > screenWidth)
|
||||
specWidth = screenWidth;
|
||||
if (specHeight > screenHeight)
|
||||
specHeight = screenHeight;
|
||||
}
|
||||
}
|
||||
return gotSize;
|
||||
}
|
||||
|
||||
mIntrinsicallySized = false;
|
||||
if (specWidth != currWidth || specHeight != currHeight) {
|
||||
SetSize(specWidth * cssToDevPx, specHeight * cssToDevPx, false);
|
||||
void
|
||||
nsXULWindow::SetSpecifiedSize(int32_t aSpecWidth, int32_t aSpecHeight)
|
||||
{
|
||||
// constrain to screen size
|
||||
nsCOMPtr<nsIDOMWindow> domWindow;
|
||||
GetWindowDOMWindow(getter_AddRefs(domWindow));
|
||||
if (domWindow) {
|
||||
nsCOMPtr<nsIDOMScreen> screen;
|
||||
domWindow->GetScreen(getter_AddRefs(screen));
|
||||
if (screen) {
|
||||
int32_t screenWidth;
|
||||
int32_t screenHeight;
|
||||
screen->GetAvailWidth(&screenWidth); // CSS pixels
|
||||
screen->GetAvailHeight(&screenHeight);
|
||||
if (aSpecWidth > screenWidth) {
|
||||
aSpecWidth = screenWidth;
|
||||
}
|
||||
if (aSpecHeight > screenHeight) {
|
||||
aSpecHeight = screenHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return gotSize;
|
||||
NS_ASSERTION(mWindow, "we expected to have a window already");
|
||||
|
||||
int32_t currWidth = 0;
|
||||
int32_t currHeight = 0;
|
||||
GetSize(&currWidth, &currHeight); // returns device pixels
|
||||
|
||||
// convert specified values to device pixels, and resize if needed
|
||||
double cssToDevPx = mWindow ? mWindow->GetDefaultScale().scale : 1.0;
|
||||
aSpecWidth = NSToIntRound(aSpecWidth * cssToDevPx);
|
||||
aSpecHeight = NSToIntRound(aSpecHeight * cssToDevPx);
|
||||
mIntrinsicallySized = false;
|
||||
if (aSpecWidth != currWidth || aSpecHeight != currHeight) {
|
||||
SetSize(aSpecWidth, aSpecHeight, false);
|
||||
}
|
||||
}
|
||||
|
||||
/* Miscellaneous persistent attributes are attributes named in the
|
||||
@@ -1308,12 +1345,17 @@ bool nsXULWindow::LoadMiscPersistentAttributesFromXUL()
|
||||
This code does have a scary double loop -- it'll keep passing through
|
||||
the entire list of open windows until it finds a non-collision. Doesn't
|
||||
seem to be a problem, but it deserves watching.
|
||||
The aRequested{X,Y} parameters here are in desktop pixels;
|
||||
the aSpec{Width,Height} parameters are CSS pixel dimensions.
|
||||
*/
|
||||
void nsXULWindow::StaggerPosition(int32_t &aRequestedX, int32_t &aRequestedY,
|
||||
int32_t aSpecWidth, int32_t aSpecHeight)
|
||||
{
|
||||
const int32_t kOffset = 22;
|
||||
const uint32_t kSlop = 4;
|
||||
// These "constants" will be converted from CSS to desktop pixels
|
||||
// for the appropriate screen, assuming we find a screen to use...
|
||||
// hence they're not actually declared const here.
|
||||
int32_t kOffset = 22;
|
||||
uint32_t kSlop = 4;
|
||||
|
||||
bool keepTrying;
|
||||
int bouncedX = 0, // bounced off vertical edge of screen
|
||||
@@ -1354,6 +1396,17 @@ void nsXULWindow::StaggerPosition(int32_t &aRequestedX, int32_t &aRequestedY,
|
||||
&screenWidth, &screenHeight);
|
||||
screenBottom = screenTop + screenHeight;
|
||||
screenRight = screenLeft + screenWidth;
|
||||
// Get the screen's scaling factors and convert staggering constants
|
||||
// from CSS px to desktop pixel units
|
||||
double desktopToDeviceScale = 1.0, cssToDeviceScale = 1.0;
|
||||
ourScreen->GetContentsScaleFactor(&desktopToDeviceScale);
|
||||
ourScreen->GetDefaultCSSScaleFactor(&cssToDeviceScale);
|
||||
double cssToDesktopFactor = cssToDeviceScale / desktopToDeviceScale;
|
||||
kOffset = NSToIntRound(kOffset * cssToDesktopFactor);
|
||||
kSlop = NSToIntRound(kSlop * cssToDesktopFactor);
|
||||
// Convert dimensions from CSS to desktop pixels
|
||||
aSpecWidth = NSToIntRound(aSpecWidth * cssToDesktopFactor);
|
||||
aSpecHeight = NSToIntRound(aSpecHeight * cssToDesktopFactor);
|
||||
gotScreen = true;
|
||||
}
|
||||
}
|
||||
@@ -1384,7 +1437,7 @@ void nsXULWindow::StaggerPosition(int32_t &aRequestedX, int32_t &aRequestedY,
|
||||
nsCOMPtr<nsIBaseWindow> listBaseWindow(do_QueryInterface(supportsWindow));
|
||||
listBaseWindow->GetPosition(&listX, &listY);
|
||||
double scale;
|
||||
if (NS_SUCCEEDED(listBaseWindow->GetUnscaledDevicePixelsPerCSSPixel(&scale))) {
|
||||
if (NS_SUCCEEDED(listBaseWindow->GetDevicePixelsPerDesktopPixel(&scale))) {
|
||||
listX = NSToIntRound(listX / scale);
|
||||
listY = NSToIntRound(listY / scale);
|
||||
}
|
||||
|
||||
@@ -93,8 +93,9 @@ protected:
|
||||
void OnChromeLoaded();
|
||||
void StaggerPosition(int32_t &aRequestedX, int32_t &aRequestedY,
|
||||
int32_t aSpecWidth, int32_t aSpecHeight);
|
||||
bool LoadPositionFromXUL();
|
||||
bool LoadSizeFromXUL();
|
||||
bool LoadPositionFromXUL(int32_t aSpecWidth, int32_t aSpecHeight);
|
||||
bool LoadSizeFromXUL(int32_t& aSpecWidth, int32_t& aSpecHeight);
|
||||
void SetSpecifiedSize(int32_t aSpecWidth, int32_t aSpecHeight);
|
||||
bool LoadMiscPersistentAttributesFromXUL();
|
||||
void SyncAttributesToWidget();
|
||||
NS_IMETHOD SavePersistentAttributes();
|
||||
|
||||
Reference in New Issue
Block a user