mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-08 00:07:30 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
45
netwerk/base/ADivertableParentChannel.h
Normal file
45
netwerk/base/ADivertableParentChannel.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef _adivertablechannelparent_h_
|
||||
#define _adivertablechannelparent_h_
|
||||
|
||||
#include "nsISupports.h"
|
||||
|
||||
class nsIStreamListener;
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
// To be implemented by a channel's parent actors, e.g. HttpChannelParent
|
||||
// and FTPChannelParent. Used by ChannelDiverterParent to divert
|
||||
// nsIStreamListener callbacks from the child process to a new
|
||||
// listener in the parent process.
|
||||
class ADivertableParentChannel : public nsISupports
|
||||
{
|
||||
public:
|
||||
// Called by ChannelDiverterParent::DivertTo(nsIStreamListener*).
|
||||
// The listener should now be used to received nsIStreamListener callbacks,
|
||||
// i.e. OnStartRequest, OnDataAvailable and OnStopRequest, as if it had been
|
||||
// passed to AsyncOpen for the channel. A reference to the listener will be
|
||||
// added and kept until OnStopRequest has completed.
|
||||
virtual void DivertTo(nsIStreamListener *aListener) = 0;
|
||||
|
||||
// Called to suspend parent channel in ChannelDiverterParent constructor.
|
||||
virtual nsresult SuspendForDiversion() = 0;
|
||||
|
||||
// While messages are diverted back from the child to the parent calls to
|
||||
// suspend/resume the channel must also suspend/resume the message diversion.
|
||||
// These two functions will be called by nsHttpChannel and nsFtpChannel
|
||||
// Suspend()/Resume() functions.
|
||||
virtual nsresult SuspendMessageDiversion() = 0;
|
||||
virtual nsresult ResumeMessageDiversion() = 0;
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
32
netwerk/base/ARefBase.h
Normal file
32
netwerk/base/ARefBase.h
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_net_ARefBase_h
|
||||
#define mozilla_net_ARefBase_h
|
||||
|
||||
#include "nscore.h"
|
||||
|
||||
namespace mozilla { namespace net {
|
||||
|
||||
// This is an abstract class that can be pointed to by either
|
||||
// nsCOMPtr or nsRefPtr. nsHttpConnectionMgr uses it for generic
|
||||
// objects that need to be reference counted - similiar to nsISupports
|
||||
// but it may or may not be xpcom.
|
||||
|
||||
class ARefBase
|
||||
{
|
||||
public:
|
||||
ARefBase() {}
|
||||
virtual ~ARefBase() {}
|
||||
|
||||
NS_IMETHOD_ (MozExternalRefCountType) AddRef() = 0;
|
||||
NS_IMETHOD_ (MozExternalRefCountType) Release() = 0;
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
120
netwerk/base/ArrayBufferInputStream.cpp
Normal file
120
netwerk/base/ArrayBufferInputStream.cpp
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include <algorithm>
|
||||
#include "ArrayBufferInputStream.h"
|
||||
#include "nsStreamUtils.h"
|
||||
#include "jsapi.h"
|
||||
#include "jsfriendapi.h"
|
||||
|
||||
NS_IMPL_ISUPPORTS(ArrayBufferInputStream, nsIArrayBufferInputStream, nsIInputStream);
|
||||
|
||||
ArrayBufferInputStream::ArrayBufferInputStream()
|
||||
: mBufferLength(0)
|
||||
, mPos(0)
|
||||
, mClosed(false)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ArrayBufferInputStream::SetData(JS::Handle<JS::Value> aBuffer,
|
||||
uint32_t aByteOffset,
|
||||
uint32_t aLength,
|
||||
JSContext* aCx)
|
||||
{
|
||||
if (!aBuffer.isObject()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
JS::RootedObject arrayBuffer(aCx, &aBuffer.toObject());
|
||||
if (!JS_IsArrayBufferObject(arrayBuffer)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
uint32_t buflen = JS_GetArrayBufferByteLength(arrayBuffer);
|
||||
uint32_t offset = std::min(buflen, aByteOffset);
|
||||
mBufferLength = std::min(buflen - offset, aLength);
|
||||
|
||||
mArrayBuffer = mozilla::MakeUnique<char[]>(mBufferLength);
|
||||
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
bool isShared;
|
||||
char* src = (char*) JS_GetArrayBufferData(arrayBuffer, &isShared, nogc) + offset;
|
||||
memcpy(&mArrayBuffer[0], src, mBufferLength);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ArrayBufferInputStream::Close()
|
||||
{
|
||||
mClosed = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ArrayBufferInputStream::Available(uint64_t* aCount)
|
||||
{
|
||||
if (mClosed) {
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
if (mArrayBuffer) {
|
||||
*aCount = mBufferLength ? mBufferLength - mPos : 0;
|
||||
} else {
|
||||
*aCount = 0;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ArrayBufferInputStream::Read(char* aBuf, uint32_t aCount, uint32_t *aReadCount)
|
||||
{
|
||||
return ReadSegments(NS_CopySegmentToBuffer, aBuf, aCount, aReadCount);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ArrayBufferInputStream::ReadSegments(nsWriteSegmentFun writer, void *closure,
|
||||
uint32_t aCount, uint32_t *result)
|
||||
{
|
||||
NS_ASSERTION(result, "null ptr");
|
||||
NS_ASSERTION(mBufferLength >= mPos, "bad stream state");
|
||||
|
||||
if (mClosed) {
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mArrayBuffer || (mPos == mBufferLength), "stream inited incorrectly");
|
||||
|
||||
*result = 0;
|
||||
while (mPos < mBufferLength) {
|
||||
uint32_t remaining = mBufferLength - mPos;
|
||||
MOZ_ASSERT(mArrayBuffer);
|
||||
|
||||
uint32_t count = std::min(aCount, remaining);
|
||||
if (count == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t written;
|
||||
nsresult rv = writer(this, closure, &mArrayBuffer[0] + mPos, *result, count, &written);
|
||||
if (NS_FAILED(rv)) {
|
||||
// InputStreams do not propagate errors to caller.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_ASSERTION(written <= count,
|
||||
"writer should not write more than we asked it to write");
|
||||
mPos += written;
|
||||
*result += written;
|
||||
aCount -= written;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ArrayBufferInputStream::IsNonBlocking(bool *aNonBlocking)
|
||||
{
|
||||
*aNonBlocking = true;
|
||||
return NS_OK;
|
||||
}
|
||||
38
netwerk/base/ArrayBufferInputStream.h
Normal file
38
netwerk/base/ArrayBufferInputStream.h
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef ArrayBufferInputStream_h
|
||||
#define ArrayBufferInputStream_h
|
||||
|
||||
#include "nsIArrayBufferInputStream.h"
|
||||
#include "js/Value.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
||||
#define NS_ARRAYBUFFERINPUTSTREAM_CONTRACTID "@mozilla.org/io/arraybuffer-input-stream;1"
|
||||
#define NS_ARRAYBUFFERINPUTSTREAM_CID \
|
||||
{ /* 3014dde6-aa1c-41db-87d0-48764a3710f6 */ \
|
||||
0x3014dde6, \
|
||||
0xaa1c, \
|
||||
0x41db, \
|
||||
{0x87, 0xd0, 0x48, 0x76, 0x4a, 0x37, 0x10, 0xf6} \
|
||||
}
|
||||
|
||||
class ArrayBufferInputStream : public nsIArrayBufferInputStream {
|
||||
public:
|
||||
ArrayBufferInputStream();
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIARRAYBUFFERINPUTSTREAM
|
||||
NS_DECL_NSIINPUTSTREAM
|
||||
|
||||
private:
|
||||
virtual ~ArrayBufferInputStream() {}
|
||||
mozilla::UniquePtr<char[]> mArrayBuffer;
|
||||
uint32_t mBufferLength;
|
||||
uint32_t mPos;
|
||||
bool mClosed;
|
||||
};
|
||||
|
||||
#endif // ArrayBufferInputStream_h
|
||||
77
netwerk/base/AutoClose.h
Normal file
77
netwerk/base/AutoClose.h
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_net_AutoClose_h
|
||||
#define mozilla_net_AutoClose_h
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
|
||||
namespace mozilla { namespace net {
|
||||
|
||||
// Like an nsAutoPtr for XPCOM streams (e.g. nsIAsyncInputStream) and other
|
||||
// refcounted classes that need to have the Close() method called explicitly
|
||||
// before they are destroyed.
|
||||
template <typename T>
|
||||
class AutoClose
|
||||
{
|
||||
public:
|
||||
AutoClose() : mMutex("net::AutoClose.mMutex") { }
|
||||
~AutoClose(){
|
||||
CloseAndRelease();
|
||||
}
|
||||
|
||||
explicit operator bool()
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
return mPtr;
|
||||
}
|
||||
|
||||
already_AddRefed<T> forget()
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
return mPtr.forget();
|
||||
}
|
||||
|
||||
void takeOver(nsCOMPtr<T> & rhs)
|
||||
{
|
||||
already_AddRefed<T> other = rhs.forget();
|
||||
TakeOverInternal(&other);
|
||||
}
|
||||
|
||||
void CloseAndRelease()
|
||||
{
|
||||
TakeOverInternal(nullptr);
|
||||
}
|
||||
|
||||
private:
|
||||
void TakeOverInternal(already_AddRefed<T> *aOther)
|
||||
{
|
||||
nsCOMPtr<T> ptr;
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
ptr.swap(mPtr);
|
||||
if (aOther) {
|
||||
mPtr = *aOther;
|
||||
}
|
||||
}
|
||||
|
||||
if (ptr) {
|
||||
ptr->Close();
|
||||
}
|
||||
}
|
||||
|
||||
void operator=(const AutoClose<T> &) = delete;
|
||||
AutoClose(const AutoClose<T> &) = delete;
|
||||
|
||||
nsCOMPtr<T> mPtr;
|
||||
Mutex mMutex;
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_net_AutoClose_h
|
||||
1273
netwerk/base/BackgroundFileSaver.cpp
Normal file
1273
netwerk/base/BackgroundFileSaver.cpp
Normal file
File diff suppressed because it is too large
Load diff
418
netwerk/base/BackgroundFileSaver.h
Normal file
418
netwerk/base/BackgroundFileSaver.h
Normal file
|
|
@ -0,0 +1,418 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
/**
|
||||
* This file defines two implementations of the nsIBackgroundFileSaver
|
||||
* interface. See the "test_backgroundfilesaver.js" file for usage examples.
|
||||
*/
|
||||
|
||||
#ifndef BackgroundFileSaver_h__
|
||||
#define BackgroundFileSaver_h__
|
||||
|
||||
#include "ScopedNSSTypes.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIAsyncOutputStream.h"
|
||||
#include "nsIBackgroundFileSaver.h"
|
||||
#include "nsIStreamListener.h"
|
||||
#include "nsNSSShutDown.h"
|
||||
#include "nsStreamUtils.h"
|
||||
#include "nsString.h"
|
||||
|
||||
class nsIAsyncInputStream;
|
||||
class nsIThread;
|
||||
class nsIX509CertList;
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
class DigestOutputStream;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// BackgroundFileSaver
|
||||
|
||||
class BackgroundFileSaver : public nsIBackgroundFileSaver,
|
||||
public nsNSSShutDownObject
|
||||
{
|
||||
public:
|
||||
NS_DECL_NSIBACKGROUNDFILESAVER
|
||||
|
||||
BackgroundFileSaver();
|
||||
|
||||
/**
|
||||
* Initializes the pipe and the worker thread on XPCOM construction.
|
||||
*
|
||||
* This is called automatically by the XPCOM infrastructure, and if this
|
||||
* fails, the factory will delete this object without returning a reference.
|
||||
*/
|
||||
nsresult Init();
|
||||
|
||||
/**
|
||||
* Used by nsNSSShutDownList to manage nsNSSShutDownObjects.
|
||||
*/
|
||||
void virtualDestroyNSSReference() override;
|
||||
|
||||
/**
|
||||
* Number of worker threads that are currently running.
|
||||
*/
|
||||
static uint32_t sThreadCount;
|
||||
|
||||
/**
|
||||
* Maximum number of worker threads reached during the current download session,
|
||||
* used for telemetry.
|
||||
*
|
||||
* When there are no more worker threads running, we consider the download
|
||||
* session finished, and this counter is reset.
|
||||
*/
|
||||
static uint32_t sTelemetryMaxThreadCount;
|
||||
|
||||
|
||||
protected:
|
||||
virtual ~BackgroundFileSaver();
|
||||
|
||||
/**
|
||||
* Helper function for managing NSS objects (mDigestContext).
|
||||
*/
|
||||
void destructorSafeDestroyNSSReference();
|
||||
|
||||
/**
|
||||
* Thread that constructed this object.
|
||||
*/
|
||||
nsCOMPtr<nsIThread> mControlThread;
|
||||
|
||||
/**
|
||||
* Thread to which the actual input/output is delegated.
|
||||
*/
|
||||
nsCOMPtr<nsIThread> mWorkerThread;
|
||||
|
||||
/**
|
||||
* Stream that receives data from derived classes. The received data will be
|
||||
* available to the worker thread through mPipeInputStream. This is an
|
||||
* instance of nsPipeOutputStream, not BackgroundFileSaverOutputStream.
|
||||
*/
|
||||
nsCOMPtr<nsIAsyncOutputStream> mPipeOutputStream;
|
||||
|
||||
/**
|
||||
* Used during initialization, determines if the pipe is created with an
|
||||
* infinite buffer. An infinite buffer is required if the derived class
|
||||
* implements nsIStreamListener, because this interface requires all the
|
||||
* provided data to be consumed synchronously.
|
||||
*/
|
||||
virtual bool HasInfiniteBuffer() = 0;
|
||||
|
||||
/**
|
||||
* Used by derived classes if they need to be called back while copying.
|
||||
*/
|
||||
virtual nsAsyncCopyProgressFun GetProgressCallback() = 0;
|
||||
|
||||
/**
|
||||
* Stream used by the worker thread to read the data to be saved.
|
||||
*/
|
||||
nsCOMPtr<nsIAsyncInputStream> mPipeInputStream;
|
||||
|
||||
private:
|
||||
friend class NotifyTargetChangeRunnable;
|
||||
|
||||
/**
|
||||
* Matches the nsIBackgroundFileSaver::observer property.
|
||||
*
|
||||
* @remarks This is a strong reference so that JavaScript callers don't need
|
||||
* to worry about keeping another reference to the observer.
|
||||
*/
|
||||
nsCOMPtr<nsIBackgroundFileSaverObserver> mObserver;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//// Shared state between control and worker threads
|
||||
|
||||
/**
|
||||
* Protects the shared state between control and worker threads. This mutex
|
||||
* is always locked for a very short time, never during input/output.
|
||||
*/
|
||||
mozilla::Mutex mLock;
|
||||
|
||||
/**
|
||||
* True if the worker thread is already waiting to process a change in state.
|
||||
*/
|
||||
bool mWorkerThreadAttentionRequested;
|
||||
|
||||
/**
|
||||
* True if the operation should finish as soon as possibile.
|
||||
*/
|
||||
bool mFinishRequested;
|
||||
|
||||
/**
|
||||
* True if the operation completed, with either success or failure.
|
||||
*/
|
||||
bool mComplete;
|
||||
|
||||
/**
|
||||
* Holds the current file saver status. This is a success status while the
|
||||
* object is working correctly, and remains such if the operation completes
|
||||
* successfully. This becomes an error status when an error occurs on the
|
||||
* worker thread, or when the operation is canceled.
|
||||
*/
|
||||
nsresult mStatus;
|
||||
|
||||
/**
|
||||
* True if we should append data to the initial target file, instead of
|
||||
* overwriting it.
|
||||
*/
|
||||
bool mAppend;
|
||||
|
||||
/**
|
||||
* This is set by the first SetTarget call on the control thread, and contains
|
||||
* the target file name that will be used by the worker thread, as soon as it
|
||||
* is possible to update mActualTarget and open the file. This is null if no
|
||||
* target was ever assigned to this object.
|
||||
*/
|
||||
nsCOMPtr<nsIFile> mInitialTarget;
|
||||
|
||||
/**
|
||||
* This is set by the first SetTarget call on the control thread, and
|
||||
* indicates whether mInitialTarget should be kept as partially completed,
|
||||
* rather than deleted, if the operation fails or is canceled.
|
||||
*/
|
||||
bool mInitialTargetKeepPartial;
|
||||
|
||||
/**
|
||||
* This is set by subsequent SetTarget calls on the control thread, and
|
||||
* contains the new target file name to which the worker thread will move the
|
||||
* target file, as soon as it can be done. This is null if SetTarget was
|
||||
* called only once, or no target was ever assigned to this object.
|
||||
*
|
||||
* The target file can be renamed multiple times, though only the most recent
|
||||
* rename is guaranteed to be processed by the worker thread.
|
||||
*/
|
||||
nsCOMPtr<nsIFile> mRenamedTarget;
|
||||
|
||||
/**
|
||||
* This is set by subsequent SetTarget calls on the control thread, and
|
||||
* indicates whether mRenamedTarget should be kept as partially completed,
|
||||
* rather than deleted, if the operation fails or is canceled.
|
||||
*/
|
||||
bool mRenamedTargetKeepPartial;
|
||||
|
||||
/**
|
||||
* While NS_AsyncCopy is in progress, allows canceling it. Null otherwise.
|
||||
* This is read by both threads but only written by the worker thread.
|
||||
*/
|
||||
nsCOMPtr<nsISupports> mAsyncCopyContext;
|
||||
|
||||
/**
|
||||
* The SHA 256 hash in raw bytes of the downloaded file. This is written
|
||||
* by the worker thread but can be read on the main thread.
|
||||
*/
|
||||
nsCString mSha256;
|
||||
|
||||
/**
|
||||
* Whether or not to compute the hash. Must be set on the main thread before
|
||||
* setTarget is called.
|
||||
*/
|
||||
bool mSha256Enabled;
|
||||
|
||||
/**
|
||||
* Store the signature info.
|
||||
*/
|
||||
nsCOMArray<nsIX509CertList> mSignatureInfo;
|
||||
|
||||
/**
|
||||
* Whether or not to extract the signature. Must be set on the main thread
|
||||
* before setTarget is called.
|
||||
*/
|
||||
bool mSignatureInfoEnabled;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//// State handled exclusively by the worker thread
|
||||
|
||||
/**
|
||||
* Current target file associated to the input and output streams.
|
||||
*/
|
||||
nsCOMPtr<nsIFile> mActualTarget;
|
||||
|
||||
/**
|
||||
* Indicates whether mActualTarget should be kept as partially completed,
|
||||
* rather than deleted, if the operation fails or is canceled.
|
||||
*/
|
||||
bool mActualTargetKeepPartial;
|
||||
|
||||
/**
|
||||
* Used to calculate the file hash. This keeps state across file renames and
|
||||
* is lazily initialized in ProcessStateChange.
|
||||
*/
|
||||
UniquePK11Context mDigestContext;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//// Private methods
|
||||
|
||||
/**
|
||||
* Called when NS_AsyncCopy completes.
|
||||
*
|
||||
* @param aClosure
|
||||
* Populated with a raw pointer to the BackgroundFileSaver object.
|
||||
* @param aStatus
|
||||
* Success or failure status specified when the copy was interrupted.
|
||||
*/
|
||||
static void AsyncCopyCallback(void *aClosure, nsresult aStatus);
|
||||
|
||||
/**
|
||||
* Called on the control thread after state changes, to ensure that the worker
|
||||
* thread will process the state change appropriately.
|
||||
*
|
||||
* @param aShouldInterruptCopy
|
||||
* If true, the current NS_AsyncCopy, if any, is canceled.
|
||||
*/
|
||||
nsresult GetWorkerThreadAttention(bool aShouldInterruptCopy);
|
||||
|
||||
/**
|
||||
* Event called on the worker thread to begin processing a state change.
|
||||
*/
|
||||
nsresult ProcessAttention();
|
||||
|
||||
/**
|
||||
* Called by ProcessAttention to execute the operations corresponding to the
|
||||
* state change. If this results in an error, ProcessAttention will force the
|
||||
* entire operation to be aborted.
|
||||
*/
|
||||
nsresult ProcessStateChange();
|
||||
|
||||
/**
|
||||
* Returns true if completion conditions are met on the worker thread. The
|
||||
* first time this happens, posts the completion event to the control thread.
|
||||
*/
|
||||
bool CheckCompletion();
|
||||
|
||||
/**
|
||||
* Event called on the control thread to indicate that file contents will now
|
||||
* be saved to the specified file.
|
||||
*/
|
||||
nsresult NotifyTargetChange(nsIFile *aTarget);
|
||||
|
||||
/**
|
||||
* Event called on the control thread to send the final notification.
|
||||
*/
|
||||
nsresult NotifySaveComplete();
|
||||
|
||||
/**
|
||||
* Verifies the signature of the binary at the specified file path and stores
|
||||
* the signature data in mSignatureInfo. We extract only X.509 certificates,
|
||||
* since that is what Google's Safebrowsing protocol specifies.
|
||||
*/
|
||||
nsresult ExtractSignatureInfo(const nsAString& filePath);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// BackgroundFileSaverOutputStream
|
||||
|
||||
class BackgroundFileSaverOutputStream : public BackgroundFileSaver
|
||||
, public nsIAsyncOutputStream
|
||||
, public nsIOutputStreamCallback
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIOUTPUTSTREAM
|
||||
NS_DECL_NSIASYNCOUTPUTSTREAM
|
||||
NS_DECL_NSIOUTPUTSTREAMCALLBACK
|
||||
|
||||
BackgroundFileSaverOutputStream();
|
||||
|
||||
protected:
|
||||
virtual bool HasInfiniteBuffer() override;
|
||||
virtual nsAsyncCopyProgressFun GetProgressCallback() override;
|
||||
|
||||
private:
|
||||
~BackgroundFileSaverOutputStream();
|
||||
|
||||
/**
|
||||
* Original callback provided to our AsyncWait wrapper.
|
||||
*/
|
||||
nsCOMPtr<nsIOutputStreamCallback> mAsyncWaitCallback;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// BackgroundFileSaverStreamListener. This class is instantiated by
|
||||
// nsExternalHelperAppService, DownloadCore.jsm, and possibly others.
|
||||
|
||||
class BackgroundFileSaverStreamListener final : public BackgroundFileSaver
|
||||
, public nsIStreamListener
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
NS_DECL_NSISTREAMLISTENER
|
||||
|
||||
BackgroundFileSaverStreamListener();
|
||||
|
||||
protected:
|
||||
virtual bool HasInfiniteBuffer() override;
|
||||
virtual nsAsyncCopyProgressFun GetProgressCallback() override;
|
||||
|
||||
private:
|
||||
~BackgroundFileSaverStreamListener();
|
||||
|
||||
/**
|
||||
* Protects the state related to whether the request should be suspended.
|
||||
*/
|
||||
mozilla::Mutex mSuspensionLock;
|
||||
|
||||
/**
|
||||
* Whether we should suspend the request because we received too much data.
|
||||
*/
|
||||
bool mReceivedTooMuchData;
|
||||
|
||||
/**
|
||||
* Request for which we received too much data. This is populated when
|
||||
* mReceivedTooMuchData becomes true for the first time.
|
||||
*/
|
||||
nsCOMPtr<nsIRequest> mRequest;
|
||||
|
||||
/**
|
||||
* Whether mRequest is currently suspended.
|
||||
*/
|
||||
bool mRequestSuspended;
|
||||
|
||||
/**
|
||||
* Called while NS_AsyncCopy is copying data.
|
||||
*/
|
||||
static void AsyncCopyProgressCallback(void *aClosure, uint32_t aCount);
|
||||
|
||||
/**
|
||||
* Called on the control thread to suspend or resume the request.
|
||||
*/
|
||||
nsresult NotifySuspendOrResume();
|
||||
};
|
||||
|
||||
// A wrapper around nsIOutputStream, so that we can compute hashes on the
|
||||
// stream without copying and without polluting pristine NSS code with XPCOM
|
||||
// interfaces.
|
||||
class DigestOutputStream : public nsNSSShutDownObject,
|
||||
public nsIOutputStream
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIOUTPUTSTREAM
|
||||
// Constructor. Neither parameter may be null. The caller owns both.
|
||||
DigestOutputStream(nsIOutputStream* outputStream, PK11Context* aContext);
|
||||
|
||||
// We don't own any NSS objects here, so no need to clean up
|
||||
void virtualDestroyNSSReference() override { }
|
||||
|
||||
private:
|
||||
~DigestOutputStream();
|
||||
|
||||
// Calls to write are passed to this stream.
|
||||
nsCOMPtr<nsIOutputStream> mOutputStream;
|
||||
// Digest context used to compute the hash, owned by the caller.
|
||||
PK11Context* mDigestContext;
|
||||
|
||||
// Don't accidentally copy construct.
|
||||
DigestOutputStream(const DigestOutputStream& d);
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
366
netwerk/base/CaptivePortalService.cpp
Normal file
366
netwerk/base/CaptivePortalService.cpp
Normal file
|
|
@ -0,0 +1,366 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/net/CaptivePortalService.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
|
||||
static const char16_t kInterfaceName[] = u"captive-portal-inteface";
|
||||
|
||||
static const char kOpenCaptivePortalLoginEvent[] = "captive-portal-login";
|
||||
static const char kAbortCaptivePortalLoginEvent[] = "captive-portal-login-abort";
|
||||
static const char kCaptivePortalLoginSuccessEvent[] = "captive-portal-login-success";
|
||||
|
||||
static const uint32_t kDefaultInterval = 60*1000; // check every 60 seconds
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
static LazyLogModule gCaptivePortalLog("CaptivePortalService");
|
||||
#undef LOG
|
||||
#define LOG(args) MOZ_LOG(gCaptivePortalLog, mozilla::LogLevel::Debug, args)
|
||||
|
||||
NS_IMPL_ISUPPORTS(CaptivePortalService, nsICaptivePortalService, nsIObserver,
|
||||
nsISupportsWeakReference, nsITimerCallback,
|
||||
nsICaptivePortalCallback)
|
||||
|
||||
CaptivePortalService::CaptivePortalService()
|
||||
: mState(UNKNOWN)
|
||||
, mStarted(false)
|
||||
, mInitialized(false)
|
||||
, mRequestInProgress(false)
|
||||
, mEverBeenCaptive(false)
|
||||
, mDelay(kDefaultInterval)
|
||||
, mSlackCount(0)
|
||||
, mMinInterval(kDefaultInterval)
|
||||
, mMaxInterval(25*kDefaultInterval)
|
||||
, mBackoffFactor(5.0)
|
||||
{
|
||||
mLastChecked = TimeStamp::Now();
|
||||
}
|
||||
|
||||
CaptivePortalService::~CaptivePortalService()
|
||||
{
|
||||
LOG(("CaptivePortalService::~CaptivePortalService isParentProcess:%d\n",
|
||||
XRE_GetProcessType() == GeckoProcessType_Default));
|
||||
}
|
||||
|
||||
nsresult
|
||||
CaptivePortalService::PerformCheck()
|
||||
{
|
||||
LOG(("CaptivePortalService::PerformCheck mRequestInProgress:%d mInitialized:%d mStarted:%d\n",
|
||||
mRequestInProgress, mInitialized, mStarted));
|
||||
// Don't issue another request if last one didn't complete
|
||||
if (mRequestInProgress || !mInitialized || !mStarted) {
|
||||
return NS_OK;
|
||||
}
|
||||
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
|
||||
nsresult rv;
|
||||
if (!mCaptivePortalDetector) {
|
||||
mCaptivePortalDetector =
|
||||
do_GetService("@mozilla.org/toolkit/captive-detector;1", &rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("Unable to get a captive portal detector\n"));
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
LOG(("CaptivePortalService::PerformCheck - Calling CheckCaptivePortal\n"));
|
||||
mRequestInProgress = true;
|
||||
mCaptivePortalDetector->CheckCaptivePortal(kInterfaceName, this);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
CaptivePortalService::RearmTimer()
|
||||
{
|
||||
LOG(("CaptivePortalService::RearmTimer\n"));
|
||||
// Start a timer to recheck
|
||||
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
|
||||
if (mTimer) {
|
||||
mTimer->Cancel();
|
||||
}
|
||||
|
||||
// If we have successfully determined the state, and we have never detected
|
||||
// a captive portal, we don't need to keep polling, but will rely on events
|
||||
// to trigger detection.
|
||||
if (mState == NOT_CAPTIVE) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!mTimer) {
|
||||
mTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
|
||||
}
|
||||
|
||||
if (mTimer && mDelay > 0) {
|
||||
LOG(("CaptivePortalService - Reloading timer with delay %u\n", mDelay));
|
||||
return mTimer->InitWithCallback(this, mDelay, nsITimer::TYPE_ONE_SHOT);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
CaptivePortalService::Initialize()
|
||||
{
|
||||
if (mInitialized) {
|
||||
return NS_OK;
|
||||
}
|
||||
mInitialized = true;
|
||||
|
||||
// Only the main process service should actually do anything. The service in
|
||||
// the content process only mirrors the CP state in the main process.
|
||||
if (XRE_GetProcessType() != GeckoProcessType_Default) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
mozilla::services::GetObserverService();
|
||||
if (observerService) {
|
||||
observerService->AddObserver(this, kOpenCaptivePortalLoginEvent, true);
|
||||
observerService->AddObserver(this, kAbortCaptivePortalLoginEvent, true);
|
||||
observerService->AddObserver(this, kCaptivePortalLoginSuccessEvent, true);
|
||||
}
|
||||
|
||||
LOG(("Initialized CaptivePortalService\n"));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
CaptivePortalService::Start()
|
||||
{
|
||||
if (!mInitialized) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
if (XRE_GetProcessType() != GeckoProcessType_Default) {
|
||||
// Doesn't do anything if called in the content process.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (mStarted) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mState == UNKNOWN, "Initial state should be UNKNOWN");
|
||||
mStarted = true;
|
||||
mEverBeenCaptive = false;
|
||||
|
||||
// Get the delay prefs
|
||||
Preferences::GetUint("network.captive-portal-service.minInterval", &mMinInterval);
|
||||
Preferences::GetUint("network.captive-portal-service.maxInterval", &mMaxInterval);
|
||||
Preferences::GetFloat("network.captive-portal-service.backoffFactor", &mBackoffFactor);
|
||||
|
||||
LOG(("CaptivePortalService::Start min:%u max:%u backoff:%.2f\n",
|
||||
mMinInterval, mMaxInterval, mBackoffFactor));
|
||||
|
||||
mSlackCount = 0;
|
||||
mDelay = mMinInterval;
|
||||
|
||||
// When Start is called, perform a check immediately
|
||||
PerformCheck();
|
||||
RearmTimer();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
CaptivePortalService::Stop()
|
||||
{
|
||||
LOG(("CaptivePortalService::Stop\n"));
|
||||
|
||||
if (XRE_GetProcessType() != GeckoProcessType_Default) {
|
||||
// Doesn't do anything when called in the content process.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!mStarted) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (mTimer) {
|
||||
mTimer->Cancel();
|
||||
}
|
||||
mTimer = nullptr;
|
||||
mRequestInProgress = false;
|
||||
mStarted = false;
|
||||
if (mCaptivePortalDetector) {
|
||||
mCaptivePortalDetector->Abort(kInterfaceName);
|
||||
}
|
||||
mCaptivePortalDetector = nullptr;
|
||||
|
||||
// Clear the state in case anyone queries the state while detection is off.
|
||||
mState = UNKNOWN;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
CaptivePortalService::SetStateInChild(int32_t aState)
|
||||
{
|
||||
// This should only be called in the content process, from ContentChild.cpp
|
||||
// in order to mirror the captive portal state set in the chrome process.
|
||||
MOZ_ASSERT(XRE_GetProcessType() != GeckoProcessType_Default);
|
||||
|
||||
mState = aState;
|
||||
mLastChecked = TimeStamp::Now();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CaptivePortalService::nsICaptivePortalService
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
NS_IMETHODIMP
|
||||
CaptivePortalService::GetState(int32_t *aState)
|
||||
{
|
||||
*aState = mState;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
CaptivePortalService::RecheckCaptivePortal()
|
||||
{
|
||||
LOG(("CaptivePortalService::RecheckCaptivePortal\n"));
|
||||
|
||||
if (XRE_GetProcessType() != GeckoProcessType_Default) {
|
||||
// Doesn't do anything if called in the content process.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// This is called for user activity. We need to reset the slack count,
|
||||
// so the checks continue to be quite frequent.
|
||||
mSlackCount = 0;
|
||||
mDelay = mMinInterval;
|
||||
|
||||
PerformCheck();
|
||||
RearmTimer();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
CaptivePortalService::GetLastChecked(uint64_t *aLastChecked)
|
||||
{
|
||||
double duration = (TimeStamp::Now() - mLastChecked).ToMilliseconds();
|
||||
*aLastChecked = static_cast<uint64_t>(duration);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CaptivePortalService::nsITimer
|
||||
// This callback gets called every mDelay miliseconds
|
||||
// It issues a checkCaptivePortal operation if one isn't already in progress
|
||||
//-----------------------------------------------------------------------------
|
||||
NS_IMETHODIMP
|
||||
CaptivePortalService::Notify(nsITimer *aTimer)
|
||||
{
|
||||
LOG(("CaptivePortalService::Notify\n"));
|
||||
MOZ_ASSERT(aTimer == mTimer);
|
||||
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
|
||||
|
||||
PerformCheck();
|
||||
|
||||
// This is needed because we don't want to always make requests very often.
|
||||
// Every 10 checks, we the delay is increased mBackoffFactor times
|
||||
// to a maximum delay of mMaxInterval
|
||||
mSlackCount++;
|
||||
if (mSlackCount % 10 == 0) {
|
||||
mDelay = mDelay * mBackoffFactor;
|
||||
}
|
||||
if (mDelay > mMaxInterval) {
|
||||
mDelay = mMaxInterval;
|
||||
}
|
||||
|
||||
// Note - if mDelay is 0, the timer will not be rearmed.
|
||||
RearmTimer();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CaptivePortalService::nsIObserver
|
||||
//-----------------------------------------------------------------------------
|
||||
NS_IMETHODIMP
|
||||
CaptivePortalService::Observe(nsISupports *aSubject,
|
||||
const char * aTopic,
|
||||
const char16_t * aData)
|
||||
{
|
||||
if (XRE_GetProcessType() != GeckoProcessType_Default) {
|
||||
// Doesn't do anything if called in the content process.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
LOG(("CaptivePortalService::Observe() topic=%s\n", aTopic));
|
||||
if (!strcmp(aTopic, kOpenCaptivePortalLoginEvent)) {
|
||||
// A redirect or altered content has been detected.
|
||||
// The user needs to log in. We are in a captive portal.
|
||||
mState = LOCKED_PORTAL;
|
||||
mLastChecked = TimeStamp::Now();
|
||||
mEverBeenCaptive = true;
|
||||
} else if (!strcmp(aTopic, kCaptivePortalLoginSuccessEvent)) {
|
||||
// The user has successfully logged in. We have connectivity.
|
||||
mState = UNLOCKED_PORTAL;
|
||||
mLastChecked = TimeStamp::Now();
|
||||
mSlackCount = 0;
|
||||
mDelay = mMinInterval;
|
||||
|
||||
RearmTimer();
|
||||
} else if (!strcmp(aTopic, kAbortCaptivePortalLoginEvent)) {
|
||||
// The login has been aborted
|
||||
mState = UNKNOWN;
|
||||
mLastChecked = TimeStamp::Now();
|
||||
mSlackCount = 0;
|
||||
}
|
||||
|
||||
// Send notification so that the captive portal state is mirrored in the
|
||||
// content process.
|
||||
nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
|
||||
if (observerService) {
|
||||
nsCOMPtr<nsICaptivePortalService> cps(this);
|
||||
observerService->NotifyObservers(cps, NS_IPC_CAPTIVE_PORTAL_SET_STATE, nullptr);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CaptivePortalService::nsICaptivePortalCallback
|
||||
//-----------------------------------------------------------------------------
|
||||
NS_IMETHODIMP
|
||||
CaptivePortalService::Prepare()
|
||||
{
|
||||
LOG(("CaptivePortalService::Prepare\n"));
|
||||
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
|
||||
// XXX: Finish preparation shouldn't be called until dns and routing is available.
|
||||
if (mCaptivePortalDetector) {
|
||||
mCaptivePortalDetector->FinishPreparation(kInterfaceName);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
CaptivePortalService::Complete(bool success)
|
||||
{
|
||||
LOG(("CaptivePortalService::Complete(success=%d) mState=%d\n", success, mState));
|
||||
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
|
||||
mLastChecked = TimeStamp::Now();
|
||||
|
||||
// Note: this callback gets called when:
|
||||
// 1. the request is completed, and content is valid (success == true)
|
||||
// 2. when the request is aborted or times out (success == false)
|
||||
|
||||
if (success) {
|
||||
if (mEverBeenCaptive) {
|
||||
mState = UNLOCKED_PORTAL;
|
||||
} else {
|
||||
mState = NOT_CAPTIVE;
|
||||
}
|
||||
}
|
||||
|
||||
mRequestInProgress = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
70
netwerk/base/CaptivePortalService.h
Normal file
70
netwerk/base/CaptivePortalService.h
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef CaptivePortalService_h_
|
||||
#define CaptivePortalService_h_
|
||||
|
||||
#include "nsICaptivePortalService.h"
|
||||
#include "nsICaptivePortalDetector.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsWeakReference.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
class CaptivePortalService
|
||||
: public nsICaptivePortalService
|
||||
, public nsIObserver
|
||||
, public nsSupportsWeakReference
|
||||
, public nsITimerCallback
|
||||
, public nsICaptivePortalCallback
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSICAPTIVEPORTALSERVICE
|
||||
NS_DECL_NSIOBSERVER
|
||||
NS_DECL_NSITIMERCALLBACK
|
||||
NS_DECL_NSICAPTIVEPORTALCALLBACK
|
||||
|
||||
CaptivePortalService();
|
||||
nsresult Initialize();
|
||||
nsresult Start();
|
||||
nsresult Stop();
|
||||
|
||||
// This method is only called in the content process, in order to mirror
|
||||
// the captive portal state in the parent process.
|
||||
void SetStateInChild(int32_t aState);
|
||||
private:
|
||||
virtual ~CaptivePortalService();
|
||||
nsresult PerformCheck();
|
||||
nsresult RearmTimer();
|
||||
|
||||
nsCOMPtr<nsICaptivePortalDetector> mCaptivePortalDetector;
|
||||
int32_t mState;
|
||||
|
||||
nsCOMPtr<nsITimer> mTimer;
|
||||
bool mStarted;
|
||||
bool mInitialized;
|
||||
bool mRequestInProgress;
|
||||
bool mEverBeenCaptive;
|
||||
|
||||
uint32_t mDelay;
|
||||
int32_t mSlackCount;
|
||||
|
||||
uint32_t mMinInterval;
|
||||
uint32_t mMaxInterval;
|
||||
float mBackoffFactor;
|
||||
|
||||
// This holds a timestamp when the last time when the captive portal check
|
||||
// has changed state.
|
||||
mozilla::TimeStamp mLastChecked;
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // CaptivePortalService_h_
|
||||
27
netwerk/base/ChannelDiverterChild.cpp
Normal file
27
netwerk/base/ChannelDiverterChild.cpp
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/net/ChannelDiverterChild.h"
|
||||
#include "mozilla/net/NeckoChannelParams.h"
|
||||
#include "mozilla/net/HttpChannelChild.h"
|
||||
#include "mozilla/net/FTPChannelChild.h"
|
||||
#include "mozilla/net/PHttpChannelChild.h"
|
||||
#include "mozilla/net/PFTPChannelChild.h"
|
||||
#include "nsIDivertableChannel.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
ChannelDiverterChild::ChannelDiverterChild()
|
||||
{
|
||||
}
|
||||
|
||||
ChannelDiverterChild::~ChannelDiverterChild()
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
26
netwerk/base/ChannelDiverterChild.h
Normal file
26
netwerk/base/ChannelDiverterChild.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef _channeldiverterchild_h_
|
||||
#define _channeldiverterchild_h_
|
||||
|
||||
#include "mozilla/net/PChannelDiverterChild.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
class ChannelDiverterChild :
|
||||
public PChannelDiverterChild
|
||||
{
|
||||
public:
|
||||
ChannelDiverterChild();
|
||||
virtual ~ChannelDiverterChild();
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* _channeldiverterchild_h_ */
|
||||
75
netwerk/base/ChannelDiverterParent.cpp
Normal file
75
netwerk/base/ChannelDiverterParent.cpp
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/net/ChannelDiverterParent.h"
|
||||
#include "mozilla/net/NeckoChannelParams.h"
|
||||
#include "mozilla/net/HttpChannelParent.h"
|
||||
#include "mozilla/net/FTPChannelParent.h"
|
||||
#include "mozilla/net/PHttpChannelParent.h"
|
||||
#include "mozilla/net/PFTPChannelParent.h"
|
||||
#include "ADivertableParentChannel.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
ChannelDiverterParent::ChannelDiverterParent()
|
||||
{
|
||||
}
|
||||
|
||||
ChannelDiverterParent::~ChannelDiverterParent()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
ChannelDiverterParent::Init(const ChannelDiverterArgs& aArgs)
|
||||
{
|
||||
switch (aArgs.type()) {
|
||||
case ChannelDiverterArgs::THttpChannelDiverterArgs:
|
||||
{
|
||||
auto httpParent = static_cast<HttpChannelParent*>(
|
||||
aArgs.get_HttpChannelDiverterArgs().mChannelParent());
|
||||
httpParent->SetApplyConversion(aArgs.get_HttpChannelDiverterArgs().mApplyConversion());
|
||||
|
||||
mDivertableChannelParent =
|
||||
static_cast<ADivertableParentChannel*>(httpParent);
|
||||
break;
|
||||
}
|
||||
case ChannelDiverterArgs::TPFTPChannelParent:
|
||||
{
|
||||
mDivertableChannelParent = static_cast<ADivertableParentChannel*>(
|
||||
static_cast<FTPChannelParent*>(aArgs.get_PFTPChannelParent()));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
NS_NOTREACHED("unknown ChannelDiverterArgs type");
|
||||
return false;
|
||||
}
|
||||
MOZ_ASSERT(mDivertableChannelParent);
|
||||
|
||||
nsresult rv = mDivertableChannelParent->SuspendForDiversion();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
ChannelDiverterParent::DivertTo(nsIStreamListener* newListener)
|
||||
{
|
||||
MOZ_ASSERT(newListener);
|
||||
MOZ_ASSERT(mDivertableChannelParent);
|
||||
|
||||
mDivertableChannelParent->DivertTo(newListener);
|
||||
}
|
||||
|
||||
void
|
||||
ChannelDiverterParent::ActorDestroy(ActorDestroyReason aWhy)
|
||||
{
|
||||
// Implement me! Bug 1005179
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
40
netwerk/base/ChannelDiverterParent.h
Normal file
40
netwerk/base/ChannelDiverterParent.h
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef _channeldiverterparent_h_
|
||||
#define _channeldiverterparent_h_
|
||||
|
||||
#include "mozilla/net/PChannelDiverterParent.h"
|
||||
|
||||
class nsIStreamListener;
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
class ChannelDiverterArgs;
|
||||
class ADivertableParentChannel;
|
||||
|
||||
class ChannelDiverterParent :
|
||||
public PChannelDiverterParent
|
||||
{
|
||||
public:
|
||||
ChannelDiverterParent();
|
||||
virtual ~ChannelDiverterParent();
|
||||
|
||||
bool Init(const ChannelDiverterArgs& aArgs);
|
||||
|
||||
void DivertTo(nsIStreamListener* newListener);
|
||||
|
||||
virtual void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
|
||||
private:
|
||||
RefPtr<ADivertableParentChannel> mDivertableChannelParent;
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* _channeldiverterparent_h_ */
|
||||
921
netwerk/base/Dashboard.cpp
Normal file
921
netwerk/base/Dashboard.cpp
Normal file
|
|
@ -0,0 +1,921 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http:mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/dom/NetDashboardBinding.h"
|
||||
#include "mozilla/dom/ToJSValue.h"
|
||||
#include "mozilla/ErrorNames.h"
|
||||
#include "mozilla/net/Dashboard.h"
|
||||
#include "mozilla/net/HttpInfo.h"
|
||||
#include "nsHttp.h"
|
||||
#include "nsICancelable.h"
|
||||
#include "nsIDNSService.h"
|
||||
#include "nsIDNSRecord.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsISocketTransport.h"
|
||||
#include "nsIThread.h"
|
||||
#include "nsProxyRelease.h"
|
||||
#include "nsSocketTransportService2.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsURLHelper.h"
|
||||
#include "mozilla/Logging.h"
|
||||
|
||||
using mozilla::AutoSafeJSContext;
|
||||
using mozilla::dom::Sequence;
|
||||
using mozilla::dom::ToJSValue;
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
class SocketData
|
||||
: public nsISupports
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
SocketData()
|
||||
{
|
||||
mTotalSent = 0;
|
||||
mTotalRecv = 0;
|
||||
mThread = nullptr;
|
||||
}
|
||||
|
||||
uint64_t mTotalSent;
|
||||
uint64_t mTotalRecv;
|
||||
nsTArray<SocketInfo> mData;
|
||||
nsMainThreadPtrHandle<NetDashboardCallback> mCallback;
|
||||
nsIThread *mThread;
|
||||
|
||||
private:
|
||||
virtual ~SocketData()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
static void GetErrorString(nsresult rv, nsAString& errorString);
|
||||
|
||||
NS_IMPL_ISUPPORTS0(SocketData)
|
||||
|
||||
|
||||
class HttpData
|
||||
: public nsISupports
|
||||
{
|
||||
virtual ~HttpData()
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
HttpData()
|
||||
{
|
||||
mThread = nullptr;
|
||||
}
|
||||
|
||||
nsTArray<HttpRetParams> mData;
|
||||
nsMainThreadPtrHandle<NetDashboardCallback> mCallback;
|
||||
nsIThread *mThread;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS0(HttpData)
|
||||
|
||||
|
||||
class WebSocketRequest
|
||||
: public nsISupports
|
||||
{
|
||||
virtual ~WebSocketRequest()
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
WebSocketRequest()
|
||||
{
|
||||
mThread = nullptr;
|
||||
}
|
||||
|
||||
nsMainThreadPtrHandle<NetDashboardCallback> mCallback;
|
||||
nsIThread *mThread;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS0(WebSocketRequest)
|
||||
|
||||
|
||||
class DnsData
|
||||
: public nsISupports
|
||||
{
|
||||
virtual ~DnsData()
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
DnsData()
|
||||
{
|
||||
mThread = nullptr;
|
||||
}
|
||||
|
||||
nsTArray<DNSCacheEntries> mData;
|
||||
nsMainThreadPtrHandle<NetDashboardCallback> mCallback;
|
||||
nsIThread *mThread;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS0(DnsData)
|
||||
|
||||
|
||||
class ConnectionData
|
||||
: public nsITransportEventSink
|
||||
, public nsITimerCallback
|
||||
{
|
||||
virtual ~ConnectionData()
|
||||
{
|
||||
if (mTimer) {
|
||||
mTimer->Cancel();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSITRANSPORTEVENTSINK
|
||||
NS_DECL_NSITIMERCALLBACK
|
||||
|
||||
void StartTimer(uint32_t aTimeout);
|
||||
void StopTimer();
|
||||
|
||||
explicit ConnectionData(Dashboard *target)
|
||||
{
|
||||
mThread = nullptr;
|
||||
mDashboard = target;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISocketTransport> mSocket;
|
||||
nsCOMPtr<nsIInputStream> mStreamIn;
|
||||
nsCOMPtr<nsITimer> mTimer;
|
||||
nsMainThreadPtrHandle<NetDashboardCallback> mCallback;
|
||||
nsIThread *mThread;
|
||||
Dashboard *mDashboard;
|
||||
|
||||
nsCString mHost;
|
||||
uint32_t mPort;
|
||||
const char *mProtocol;
|
||||
uint32_t mTimeout;
|
||||
|
||||
nsString mStatus;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(ConnectionData, nsITransportEventSink, nsITimerCallback)
|
||||
|
||||
NS_IMETHODIMP
|
||||
ConnectionData::OnTransportStatus(nsITransport *aTransport, nsresult aStatus,
|
||||
int64_t aProgress, int64_t aProgressMax)
|
||||
{
|
||||
if (aStatus == NS_NET_STATUS_CONNECTED_TO) {
|
||||
StopTimer();
|
||||
}
|
||||
|
||||
GetErrorString(aStatus, mStatus);
|
||||
mThread->Dispatch(NewRunnableMethod<RefPtr<ConnectionData>>
|
||||
(mDashboard, &Dashboard::GetConnectionStatus, this),
|
||||
NS_DISPATCH_NORMAL);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ConnectionData::Notify(nsITimer *aTimer)
|
||||
{
|
||||
MOZ_ASSERT(aTimer == mTimer);
|
||||
|
||||
if (mSocket) {
|
||||
mSocket->Close(NS_ERROR_ABORT);
|
||||
mSocket = nullptr;
|
||||
mStreamIn = nullptr;
|
||||
}
|
||||
|
||||
mTimer = nullptr;
|
||||
|
||||
mStatus.AssignLiteral(u"NS_ERROR_NET_TIMEOUT");
|
||||
mThread->Dispatch(NewRunnableMethod<RefPtr<ConnectionData>>
|
||||
(mDashboard, &Dashboard::GetConnectionStatus, this),
|
||||
NS_DISPATCH_NORMAL);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
ConnectionData::StartTimer(uint32_t aTimeout)
|
||||
{
|
||||
if (!mTimer) {
|
||||
mTimer = do_CreateInstance("@mozilla.org/timer;1");
|
||||
}
|
||||
|
||||
mTimer->InitWithCallback(this, aTimeout * 1000,
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
}
|
||||
|
||||
void
|
||||
ConnectionData::StopTimer()
|
||||
{
|
||||
if (mTimer) {
|
||||
mTimer->Cancel();
|
||||
mTimer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class LookupHelper;
|
||||
|
||||
class LookupArgument
|
||||
: public nsISupports
|
||||
{
|
||||
virtual ~LookupArgument()
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
LookupArgument(nsIDNSRecord *aRecord, LookupHelper *aHelper)
|
||||
{
|
||||
mRecord = aRecord;
|
||||
mHelper = aHelper;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDNSRecord> mRecord;
|
||||
RefPtr<LookupHelper> mHelper;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS0(LookupArgument)
|
||||
|
||||
|
||||
class LookupHelper
|
||||
: public nsIDNSListener
|
||||
{
|
||||
virtual ~LookupHelper()
|
||||
{
|
||||
if (mCancel) {
|
||||
mCancel->Cancel(NS_ERROR_ABORT);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIDNSLISTENER
|
||||
|
||||
LookupHelper() {
|
||||
}
|
||||
|
||||
nsresult ConstructAnswer(LookupArgument *aArgument);
|
||||
public:
|
||||
nsCOMPtr<nsICancelable> mCancel;
|
||||
nsMainThreadPtrHandle<NetDashboardCallback> mCallback;
|
||||
nsIThread *mThread;
|
||||
nsresult mStatus;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(LookupHelper, nsIDNSListener)
|
||||
|
||||
NS_IMETHODIMP
|
||||
LookupHelper::OnLookupComplete(nsICancelable *aRequest,
|
||||
nsIDNSRecord *aRecord, nsresult aStatus)
|
||||
{
|
||||
MOZ_ASSERT(aRequest == mCancel);
|
||||
mCancel = nullptr;
|
||||
mStatus = aStatus;
|
||||
|
||||
RefPtr<LookupArgument> arg = new LookupArgument(aRecord, this);
|
||||
mThread->Dispatch(NewRunnableMethod<RefPtr<LookupArgument>>
|
||||
(this, &LookupHelper::ConstructAnswer, arg),
|
||||
NS_DISPATCH_NORMAL);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
LookupHelper::ConstructAnswer(LookupArgument *aArgument)
|
||||
{
|
||||
nsIDNSRecord *aRecord = aArgument->mRecord;
|
||||
AutoSafeJSContext cx;
|
||||
|
||||
mozilla::dom::DNSLookupDict dict;
|
||||
dict.mAddress.Construct();
|
||||
|
||||
Sequence<nsString> &addresses = dict.mAddress.Value();
|
||||
|
||||
if (NS_SUCCEEDED(mStatus)) {
|
||||
dict.mAnswer = true;
|
||||
bool hasMore;
|
||||
aRecord->HasMore(&hasMore);
|
||||
while (hasMore) {
|
||||
nsString* nextAddress = addresses.AppendElement(fallible);
|
||||
if (!nextAddress) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
nsCString nextAddressASCII;
|
||||
aRecord->GetNextAddrAsString(nextAddressASCII);
|
||||
CopyASCIItoUTF16(nextAddressASCII, *nextAddress);
|
||||
aRecord->HasMore(&hasMore);
|
||||
}
|
||||
} else {
|
||||
dict.mAnswer = false;
|
||||
GetErrorString(mStatus, dict.mError);
|
||||
}
|
||||
|
||||
JS::RootedValue val(cx);
|
||||
if (!ToJSValue(cx, dict, &val)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
this->mCallback->OnDashboardDataAvailable(val);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(Dashboard, nsIDashboard, nsIDashboardEventNotifier)
|
||||
|
||||
Dashboard::Dashboard()
|
||||
{
|
||||
mEnableLogging = false;
|
||||
}
|
||||
|
||||
Dashboard::~Dashboard()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Dashboard::RequestSockets(NetDashboardCallback *aCallback)
|
||||
{
|
||||
RefPtr<SocketData> socketData = new SocketData();
|
||||
socketData->mCallback =
|
||||
new nsMainThreadPtrHolder<NetDashboardCallback>(aCallback, true);
|
||||
socketData->mThread = NS_GetCurrentThread();
|
||||
gSocketTransportService->Dispatch(NewRunnableMethod<RefPtr<SocketData>>
|
||||
(this, &Dashboard::GetSocketsDispatch, socketData),
|
||||
NS_DISPATCH_NORMAL);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Dashboard::GetSocketsDispatch(SocketData *aSocketData)
|
||||
{
|
||||
RefPtr<SocketData> socketData = aSocketData;
|
||||
if (gSocketTransportService) {
|
||||
gSocketTransportService->GetSocketConnections(&socketData->mData);
|
||||
socketData->mTotalSent = gSocketTransportService->GetSentBytes();
|
||||
socketData->mTotalRecv = gSocketTransportService->GetReceivedBytes();
|
||||
}
|
||||
socketData->mThread->Dispatch(NewRunnableMethod<RefPtr<SocketData>>
|
||||
(this, &Dashboard::GetSockets, socketData),
|
||||
NS_DISPATCH_NORMAL);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Dashboard::GetSockets(SocketData *aSocketData)
|
||||
{
|
||||
RefPtr<SocketData> socketData = aSocketData;
|
||||
AutoSafeJSContext cx;
|
||||
|
||||
mozilla::dom::SocketsDict dict;
|
||||
dict.mSockets.Construct();
|
||||
dict.mSent = 0;
|
||||
dict.mReceived = 0;
|
||||
|
||||
Sequence<mozilla::dom::SocketElement> &sockets = dict.mSockets.Value();
|
||||
|
||||
uint32_t length = socketData->mData.Length();
|
||||
if (!sockets.SetCapacity(length, fallible)) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < socketData->mData.Length(); i++) {
|
||||
dom::SocketElement &mSocket = *sockets.AppendElement(fallible);
|
||||
CopyASCIItoUTF16(socketData->mData[i].host, mSocket.mHost);
|
||||
mSocket.mPort = socketData->mData[i].port;
|
||||
mSocket.mActive = socketData->mData[i].active;
|
||||
mSocket.mTcp = socketData->mData[i].tcp;
|
||||
mSocket.mSent = (double) socketData->mData[i].sent;
|
||||
mSocket.mReceived = (double) socketData->mData[i].received;
|
||||
dict.mSent += socketData->mData[i].sent;
|
||||
dict.mReceived += socketData->mData[i].received;
|
||||
}
|
||||
|
||||
dict.mSent += socketData->mTotalSent;
|
||||
dict.mReceived += socketData->mTotalRecv;
|
||||
JS::RootedValue val(cx);
|
||||
if (!ToJSValue(cx, dict, &val))
|
||||
return NS_ERROR_FAILURE;
|
||||
socketData->mCallback->OnDashboardDataAvailable(val);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Dashboard::RequestHttpConnections(NetDashboardCallback *aCallback)
|
||||
{
|
||||
RefPtr<HttpData> httpData = new HttpData();
|
||||
httpData->mCallback =
|
||||
new nsMainThreadPtrHolder<NetDashboardCallback>(aCallback, true);
|
||||
httpData->mThread = NS_GetCurrentThread();
|
||||
|
||||
gSocketTransportService->Dispatch(NewRunnableMethod<RefPtr<HttpData>>
|
||||
(this, &Dashboard::GetHttpDispatch, httpData),
|
||||
NS_DISPATCH_NORMAL);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Dashboard::GetHttpDispatch(HttpData *aHttpData)
|
||||
{
|
||||
RefPtr<HttpData> httpData = aHttpData;
|
||||
HttpInfo::GetHttpConnectionData(&httpData->mData);
|
||||
httpData->mThread->Dispatch(NewRunnableMethod<RefPtr<HttpData>>
|
||||
(this, &Dashboard::GetHttpConnections, httpData),
|
||||
NS_DISPATCH_NORMAL);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
Dashboard::GetHttpConnections(HttpData *aHttpData)
|
||||
{
|
||||
RefPtr<HttpData> httpData = aHttpData;
|
||||
AutoSafeJSContext cx;
|
||||
|
||||
mozilla::dom::HttpConnDict dict;
|
||||
dict.mConnections.Construct();
|
||||
|
||||
using mozilla::dom::HalfOpenInfoDict;
|
||||
using mozilla::dom::HttpConnectionElement;
|
||||
using mozilla::dom::HttpConnInfo;
|
||||
Sequence<HttpConnectionElement> &connections = dict.mConnections.Value();
|
||||
|
||||
uint32_t length = httpData->mData.Length();
|
||||
if (!connections.SetCapacity(length, fallible)) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < httpData->mData.Length(); i++) {
|
||||
HttpConnectionElement &connection = *connections.AppendElement(fallible);
|
||||
|
||||
CopyASCIItoUTF16(httpData->mData[i].host, connection.mHost);
|
||||
connection.mPort = httpData->mData[i].port;
|
||||
connection.mSpdy = httpData->mData[i].spdy;
|
||||
connection.mSsl = httpData->mData[i].ssl;
|
||||
|
||||
connection.mActive.Construct();
|
||||
connection.mIdle.Construct();
|
||||
connection.mHalfOpens.Construct();
|
||||
|
||||
Sequence<HttpConnInfo> &active = connection.mActive.Value();
|
||||
Sequence<HttpConnInfo> &idle = connection.mIdle.Value();
|
||||
Sequence<HalfOpenInfoDict> &halfOpens = connection.mHalfOpens.Value();
|
||||
|
||||
if (!active.SetCapacity(httpData->mData[i].active.Length(), fallible) ||
|
||||
!idle.SetCapacity(httpData->mData[i].idle.Length(), fallible) ||
|
||||
!halfOpens.SetCapacity(httpData->mData[i].halfOpens.Length(),
|
||||
fallible)) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
for (uint32_t j = 0; j < httpData->mData[i].active.Length(); j++) {
|
||||
HttpConnInfo &info = *active.AppendElement(fallible);
|
||||
info.mRtt = httpData->mData[i].active[j].rtt;
|
||||
info.mTtl = httpData->mData[i].active[j].ttl;
|
||||
info.mProtocolVersion =
|
||||
httpData->mData[i].active[j].protocolVersion;
|
||||
}
|
||||
|
||||
for (uint32_t j = 0; j < httpData->mData[i].idle.Length(); j++) {
|
||||
HttpConnInfo &info = *idle.AppendElement(fallible);
|
||||
info.mRtt = httpData->mData[i].idle[j].rtt;
|
||||
info.mTtl = httpData->mData[i].idle[j].ttl;
|
||||
info.mProtocolVersion = httpData->mData[i].idle[j].protocolVersion;
|
||||
}
|
||||
|
||||
for (uint32_t j = 0; j < httpData->mData[i].halfOpens.Length(); j++) {
|
||||
HalfOpenInfoDict &info = *halfOpens.AppendElement(fallible);
|
||||
info.mSpeculative = httpData->mData[i].halfOpens[j].speculative;
|
||||
}
|
||||
}
|
||||
|
||||
JS::RootedValue val(cx);
|
||||
if (!ToJSValue(cx, dict, &val)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
httpData->mCallback->OnDashboardDataAvailable(val);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Dashboard::GetEnableLogging(bool *value)
|
||||
{
|
||||
*value = mEnableLogging;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Dashboard::SetEnableLogging(const bool value)
|
||||
{
|
||||
mEnableLogging = value;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Dashboard::AddHost(const nsACString& aHost, uint32_t aSerial, bool aEncrypted)
|
||||
{
|
||||
if (mEnableLogging) {
|
||||
mozilla::MutexAutoLock lock(mWs.lock);
|
||||
LogData mData(nsCString(aHost), aSerial, aEncrypted);
|
||||
if (mWs.data.Contains(mData)) {
|
||||
return NS_OK;
|
||||
}
|
||||
if (!mWs.data.AppendElement(mData)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Dashboard::RemoveHost(const nsACString& aHost, uint32_t aSerial)
|
||||
{
|
||||
if (mEnableLogging) {
|
||||
mozilla::MutexAutoLock lock(mWs.lock);
|
||||
int32_t index = mWs.IndexOf(nsCString(aHost), aSerial);
|
||||
if (index == -1)
|
||||
return NS_ERROR_FAILURE;
|
||||
mWs.data.RemoveElementAt(index);
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Dashboard::NewMsgSent(const nsACString& aHost, uint32_t aSerial, uint32_t aLength)
|
||||
{
|
||||
if (mEnableLogging) {
|
||||
mozilla::MutexAutoLock lock(mWs.lock);
|
||||
int32_t index = mWs.IndexOf(nsCString(aHost), aSerial);
|
||||
if (index == -1)
|
||||
return NS_ERROR_FAILURE;
|
||||
mWs.data[index].mMsgSent++;
|
||||
mWs.data[index].mSizeSent += aLength;
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Dashboard::NewMsgReceived(const nsACString& aHost, uint32_t aSerial, uint32_t aLength)
|
||||
{
|
||||
if (mEnableLogging) {
|
||||
mozilla::MutexAutoLock lock(mWs.lock);
|
||||
int32_t index = mWs.IndexOf(nsCString(aHost), aSerial);
|
||||
if (index == -1)
|
||||
return NS_ERROR_FAILURE;
|
||||
mWs.data[index].mMsgReceived++;
|
||||
mWs.data[index].mSizeReceived += aLength;
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Dashboard::RequestWebsocketConnections(NetDashboardCallback *aCallback)
|
||||
{
|
||||
RefPtr<WebSocketRequest> wsRequest = new WebSocketRequest();
|
||||
wsRequest->mCallback =
|
||||
new nsMainThreadPtrHolder<NetDashboardCallback>(aCallback, true);
|
||||
wsRequest->mThread = NS_GetCurrentThread();
|
||||
|
||||
wsRequest->mThread->Dispatch(NewRunnableMethod<RefPtr<WebSocketRequest>>
|
||||
(this, &Dashboard::GetWebSocketConnections, wsRequest),
|
||||
NS_DISPATCH_NORMAL);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Dashboard::GetWebSocketConnections(WebSocketRequest *aWsRequest)
|
||||
{
|
||||
RefPtr<WebSocketRequest> wsRequest = aWsRequest;
|
||||
AutoSafeJSContext cx;
|
||||
|
||||
mozilla::dom::WebSocketDict dict;
|
||||
dict.mWebsockets.Construct();
|
||||
Sequence<mozilla::dom::WebSocketElement> &websockets =
|
||||
dict.mWebsockets.Value();
|
||||
|
||||
mozilla::MutexAutoLock lock(mWs.lock);
|
||||
uint32_t length = mWs.data.Length();
|
||||
if (!websockets.SetCapacity(length, fallible)) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < mWs.data.Length(); i++) {
|
||||
dom::WebSocketElement &websocket = *websockets.AppendElement(fallible);
|
||||
CopyASCIItoUTF16(mWs.data[i].mHost, websocket.mHostport);
|
||||
websocket.mMsgsent = mWs.data[i].mMsgSent;
|
||||
websocket.mMsgreceived = mWs.data[i].mMsgReceived;
|
||||
websocket.mSentsize = mWs.data[i].mSizeSent;
|
||||
websocket.mReceivedsize = mWs.data[i].mSizeReceived;
|
||||
websocket.mEncrypted = mWs.data[i].mEncrypted;
|
||||
}
|
||||
|
||||
JS::RootedValue val(cx);
|
||||
if (!ToJSValue(cx, dict, &val)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
wsRequest->mCallback->OnDashboardDataAvailable(val);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Dashboard::RequestDNSInfo(NetDashboardCallback *aCallback)
|
||||
{
|
||||
RefPtr<DnsData> dnsData = new DnsData();
|
||||
dnsData->mCallback =
|
||||
new nsMainThreadPtrHolder<NetDashboardCallback>(aCallback, true);
|
||||
|
||||
nsresult rv;
|
||||
dnsData->mData.Clear();
|
||||
dnsData->mThread = NS_GetCurrentThread();
|
||||
|
||||
if (!mDnsService) {
|
||||
mDnsService = do_GetService("@mozilla.org/network/dns-service;1", &rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
gSocketTransportService->Dispatch(NewRunnableMethod<RefPtr<DnsData>>
|
||||
(this, &Dashboard::GetDnsInfoDispatch, dnsData),
|
||||
NS_DISPATCH_NORMAL);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Dashboard::GetDnsInfoDispatch(DnsData *aDnsData)
|
||||
{
|
||||
RefPtr<DnsData> dnsData = aDnsData;
|
||||
if (mDnsService) {
|
||||
mDnsService->GetDNSCacheEntries(&dnsData->mData);
|
||||
}
|
||||
dnsData->mThread->Dispatch(NewRunnableMethod<RefPtr<DnsData>>
|
||||
(this, &Dashboard::GetDNSCacheEntries, dnsData),
|
||||
NS_DISPATCH_NORMAL);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Dashboard::GetDNSCacheEntries(DnsData *dnsData)
|
||||
{
|
||||
AutoSafeJSContext cx;
|
||||
|
||||
mozilla::dom::DNSCacheDict dict;
|
||||
dict.mEntries.Construct();
|
||||
Sequence<mozilla::dom::DnsCacheEntry> &entries = dict.mEntries.Value();
|
||||
|
||||
uint32_t length = dnsData->mData.Length();
|
||||
if (!entries.SetCapacity(length, fallible)) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < dnsData->mData.Length(); i++) {
|
||||
dom::DnsCacheEntry &entry = *entries.AppendElement(fallible);
|
||||
entry.mHostaddr.Construct();
|
||||
|
||||
Sequence<nsString> &addrs = entry.mHostaddr.Value();
|
||||
if (!addrs.SetCapacity(dnsData->mData[i].hostaddr.Length(), fallible)) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
CopyASCIItoUTF16(dnsData->mData[i].hostname, entry.mHostname);
|
||||
entry.mExpiration = dnsData->mData[i].expiration;
|
||||
|
||||
for (uint32_t j = 0; j < dnsData->mData[i].hostaddr.Length(); j++) {
|
||||
nsString* addr = addrs.AppendElement(fallible);
|
||||
if (!addr) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
CopyASCIItoUTF16(dnsData->mData[i].hostaddr[j], *addr);
|
||||
}
|
||||
|
||||
if (dnsData->mData[i].family == PR_AF_INET6) {
|
||||
CopyASCIItoUTF16("ipv6", entry.mFamily);
|
||||
} else {
|
||||
CopyASCIItoUTF16("ipv4", entry.mFamily);
|
||||
}
|
||||
}
|
||||
|
||||
JS::RootedValue val(cx);
|
||||
if (!ToJSValue(cx, dict, &val)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
dnsData->mCallback->OnDashboardDataAvailable(val);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Dashboard::RequestDNSLookup(const nsACString &aHost,
|
||||
NetDashboardCallback *aCallback)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
if (!mDnsService) {
|
||||
mDnsService = do_GetService("@mozilla.org/network/dns-service;1", &rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<LookupHelper> helper = new LookupHelper();
|
||||
helper->mCallback =
|
||||
new nsMainThreadPtrHolder<NetDashboardCallback>(aCallback, true);
|
||||
helper->mThread = NS_GetCurrentThread();
|
||||
rv = mDnsService->AsyncResolve(aHost, 0, helper.get(),
|
||||
NS_GetCurrentThread(),
|
||||
getter_AddRefs(helper->mCancel));
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
HttpConnInfo::SetHTTP1ProtocolVersion(uint8_t pv)
|
||||
{
|
||||
switch (pv) {
|
||||
case NS_HTTP_VERSION_0_9:
|
||||
protocolVersion.AssignLiteral(u"http/0.9");
|
||||
break;
|
||||
case NS_HTTP_VERSION_1_0:
|
||||
protocolVersion.AssignLiteral(u"http/1.0");
|
||||
break;
|
||||
case NS_HTTP_VERSION_1_1:
|
||||
protocolVersion.AssignLiteral(u"http/1.1");
|
||||
break;
|
||||
case NS_HTTP_VERSION_2_0:
|
||||
protocolVersion.AssignLiteral(u"http/2.0");
|
||||
break;
|
||||
default:
|
||||
protocolVersion.AssignLiteral(u"unknown protocol version");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
HttpConnInfo::SetHTTP2ProtocolVersion(uint8_t pv)
|
||||
{
|
||||
MOZ_ASSERT (pv == HTTP_VERSION_2);
|
||||
protocolVersion.Assign(u"h2");
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Dashboard::GetLogPath(nsACString &aLogPath)
|
||||
{
|
||||
aLogPath.SetCapacity(2048);
|
||||
uint32_t len = LogModule::GetLogFile(aLogPath.BeginWriting(), 2048);
|
||||
aLogPath.SetLength(len);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Dashboard::RequestConnection(const nsACString& aHost, uint32_t aPort,
|
||||
const char *aProtocol, uint32_t aTimeout,
|
||||
NetDashboardCallback *aCallback)
|
||||
{
|
||||
nsresult rv;
|
||||
RefPtr<ConnectionData> connectionData = new ConnectionData(this);
|
||||
connectionData->mHost = aHost;
|
||||
connectionData->mPort = aPort;
|
||||
connectionData->mProtocol = aProtocol;
|
||||
connectionData->mTimeout = aTimeout;
|
||||
|
||||
connectionData->mCallback =
|
||||
new nsMainThreadPtrHolder<NetDashboardCallback>(aCallback, true);
|
||||
connectionData->mThread = NS_GetCurrentThread();
|
||||
|
||||
rv = TestNewConnection(connectionData);
|
||||
if (NS_FAILED(rv)) {
|
||||
mozilla::net::GetErrorString(rv, connectionData->mStatus);
|
||||
connectionData->mThread->Dispatch(NewRunnableMethod<RefPtr<ConnectionData>>
|
||||
(this, &Dashboard::GetConnectionStatus, connectionData),
|
||||
NS_DISPATCH_NORMAL);
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Dashboard::GetConnectionStatus(ConnectionData *aConnectionData)
|
||||
{
|
||||
RefPtr<ConnectionData> connectionData = aConnectionData;
|
||||
AutoSafeJSContext cx;
|
||||
|
||||
mozilla::dom::ConnStatusDict dict;
|
||||
dict.mStatus = connectionData->mStatus;
|
||||
|
||||
JS::RootedValue val(cx);
|
||||
if (!ToJSValue(cx, dict, &val))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
connectionData->mCallback->OnDashboardDataAvailable(val);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Dashboard::TestNewConnection(ConnectionData *aConnectionData)
|
||||
{
|
||||
RefPtr<ConnectionData> connectionData = aConnectionData;
|
||||
|
||||
nsresult rv;
|
||||
if (!connectionData->mHost.Length() ||
|
||||
!net_IsValidHostName(connectionData->mHost)) {
|
||||
return NS_ERROR_UNKNOWN_HOST;
|
||||
}
|
||||
|
||||
if (connectionData->mProtocol &&
|
||||
NS_LITERAL_STRING("ssl").EqualsASCII(connectionData->mProtocol)) {
|
||||
rv = gSocketTransportService->CreateTransport(
|
||||
&connectionData->mProtocol, 1, connectionData->mHost,
|
||||
connectionData->mPort, nullptr,
|
||||
getter_AddRefs(connectionData->mSocket));
|
||||
} else {
|
||||
rv = gSocketTransportService->CreateTransport(
|
||||
nullptr, 0, connectionData->mHost,
|
||||
connectionData->mPort, nullptr,
|
||||
getter_AddRefs(connectionData->mSocket));
|
||||
}
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = connectionData->mSocket->SetEventSink(connectionData,
|
||||
NS_GetCurrentThread());
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = connectionData->mSocket->OpenInputStream(
|
||||
nsITransport::OPEN_BLOCKING, 0, 0,
|
||||
getter_AddRefs(connectionData->mStreamIn));
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
connectionData->StartTimer(connectionData->mTimeout);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
nsresult key;
|
||||
const char *error;
|
||||
} ErrorEntry;
|
||||
|
||||
#undef ERROR
|
||||
#define ERROR(key, val) {key, #key}
|
||||
|
||||
ErrorEntry socketTransportStatuses[] = {
|
||||
ERROR(NS_NET_STATUS_RESOLVING_HOST, FAILURE(3)),
|
||||
ERROR(NS_NET_STATUS_RESOLVED_HOST, FAILURE(11)),
|
||||
ERROR(NS_NET_STATUS_CONNECTING_TO, FAILURE(7)),
|
||||
ERROR(NS_NET_STATUS_CONNECTED_TO, FAILURE(4)),
|
||||
ERROR(NS_NET_STATUS_SENDING_TO, FAILURE(5)),
|
||||
ERROR(NS_NET_STATUS_WAITING_FOR, FAILURE(10)),
|
||||
ERROR(NS_NET_STATUS_RECEIVING_FROM, FAILURE(6)),
|
||||
};
|
||||
#undef ERROR
|
||||
|
||||
|
||||
static void
|
||||
GetErrorString(nsresult rv, nsAString& errorString)
|
||||
{
|
||||
for (size_t i = 0; i < ArrayLength(socketTransportStatuses); ++i) {
|
||||
if (socketTransportStatuses[i].key == rv) {
|
||||
errorString.AssignASCII(socketTransportStatuses[i].error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
nsAutoCString errorCString;
|
||||
mozilla::GetErrorName(rv, errorCString);
|
||||
CopyUTF8toUTF16(errorCString, errorString);
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
105
netwerk/base/Dashboard.h
Normal file
105
netwerk/base/Dashboard.h
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsDashboard_h__
|
||||
#define nsDashboard_h__
|
||||
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/net/DashboardTypes.h"
|
||||
#include "nsIDashboard.h"
|
||||
#include "nsIDashboardEventNotifier.h"
|
||||
#include "nsIDNSListener.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsITransport.h"
|
||||
|
||||
class nsIDNSService;
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
class SocketData;
|
||||
class HttpData;
|
||||
class DnsData;
|
||||
class WebSocketRequest;
|
||||
class ConnectionData;
|
||||
|
||||
class Dashboard final
|
||||
: public nsIDashboard
|
||||
, public nsIDashboardEventNotifier
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIDASHBOARD
|
||||
NS_DECL_NSIDASHBOARDEVENTNOTIFIER
|
||||
|
||||
Dashboard();
|
||||
static const char *GetErrorString(nsresult rv);
|
||||
nsresult GetConnectionStatus(ConnectionData *aConnectionData);
|
||||
|
||||
private:
|
||||
|
||||
struct LogData
|
||||
{
|
||||
LogData(nsCString host, uint32_t serial, bool encryption):
|
||||
mHost(host),
|
||||
mSerial(serial),
|
||||
mMsgSent(0),
|
||||
mMsgReceived(0),
|
||||
mSizeSent(0),
|
||||
mSizeReceived(0),
|
||||
mEncrypted(encryption)
|
||||
{ }
|
||||
nsCString mHost;
|
||||
uint32_t mSerial;
|
||||
uint32_t mMsgSent;
|
||||
uint32_t mMsgReceived;
|
||||
uint64_t mSizeSent;
|
||||
uint64_t mSizeReceived;
|
||||
bool mEncrypted;
|
||||
bool operator==(const LogData& a) const
|
||||
{
|
||||
return mHost.Equals(a.mHost) && (mSerial == a.mSerial);
|
||||
}
|
||||
};
|
||||
|
||||
struct WebSocketData
|
||||
{
|
||||
WebSocketData():lock("Dashboard.webSocketData")
|
||||
{
|
||||
}
|
||||
uint32_t IndexOf(nsCString hostname, uint32_t mSerial)
|
||||
{
|
||||
LogData temp(hostname, mSerial, false);
|
||||
return data.IndexOf(temp);
|
||||
}
|
||||
nsTArray<LogData> data;
|
||||
mozilla::Mutex lock;
|
||||
};
|
||||
|
||||
|
||||
bool mEnableLogging;
|
||||
WebSocketData mWs;
|
||||
|
||||
private:
|
||||
virtual ~Dashboard();
|
||||
|
||||
nsresult GetSocketsDispatch(SocketData *);
|
||||
nsresult GetHttpDispatch(HttpData *);
|
||||
nsresult GetDnsInfoDispatch(DnsData *);
|
||||
nsresult TestNewConnection(ConnectionData *);
|
||||
|
||||
/* Helper methods that pass the JSON to the callback function. */
|
||||
nsresult GetSockets(SocketData *);
|
||||
nsresult GetHttpConnections(HttpData *);
|
||||
nsresult GetDNSCacheEntries(DnsData *);
|
||||
nsresult GetWebSocketConnections(WebSocketRequest *);
|
||||
|
||||
nsCOMPtr<nsIDNSService> mDnsService;
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // nsDashboard_h__
|
||||
63
netwerk/base/DashboardTypes.h
Normal file
63
netwerk/base/DashboardTypes.h
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_net_DashboardTypes_h_
|
||||
#define mozilla_net_DashboardTypes_h_
|
||||
|
||||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
struct SocketInfo
|
||||
{
|
||||
nsCString host;
|
||||
uint64_t sent;
|
||||
uint64_t received;
|
||||
uint16_t port;
|
||||
bool active;
|
||||
bool tcp;
|
||||
};
|
||||
|
||||
struct HalfOpenSockets
|
||||
{
|
||||
bool speculative;
|
||||
};
|
||||
|
||||
struct DNSCacheEntries
|
||||
{
|
||||
nsCString hostname;
|
||||
nsTArray<nsCString> hostaddr;
|
||||
uint16_t family;
|
||||
int64_t expiration;
|
||||
nsCString netInterface;
|
||||
};
|
||||
|
||||
struct HttpConnInfo
|
||||
{
|
||||
uint32_t ttl;
|
||||
uint32_t rtt;
|
||||
nsString protocolVersion;
|
||||
|
||||
void SetHTTP1ProtocolVersion(uint8_t pv);
|
||||
void SetHTTP2ProtocolVersion(uint8_t pv);
|
||||
};
|
||||
|
||||
struct HttpRetParams
|
||||
{
|
||||
nsCString host;
|
||||
nsTArray<HttpConnInfo> active;
|
||||
nsTArray<HttpConnInfo> idle;
|
||||
nsTArray<HalfOpenSockets> halfOpens;
|
||||
uint32_t counter;
|
||||
uint16_t port;
|
||||
bool spdy;
|
||||
bool ssl;
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_net_DashboardTypes_h_
|
||||
462
netwerk/base/EventTokenBucket.cpp
Normal file
462
netwerk/base/EventTokenBucket.cpp
Normal file
|
|
@ -0,0 +1,462 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "EventTokenBucket.h"
|
||||
|
||||
#include "nsICancelable.h"
|
||||
#include "nsIIOService.h"
|
||||
#include "nsNetCID.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsSocketTransportService2.h"
|
||||
#ifdef DEBUG
|
||||
#include "MainThreadUtils.h"
|
||||
#endif
|
||||
|
||||
#ifdef XP_WIN
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
////////////////////////////////////////////
|
||||
// EventTokenBucketCancelable
|
||||
////////////////////////////////////////////
|
||||
|
||||
class TokenBucketCancelable : public nsICancelable
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSICANCELABLE
|
||||
|
||||
explicit TokenBucketCancelable(class ATokenBucketEvent *event);
|
||||
void Fire();
|
||||
|
||||
private:
|
||||
virtual ~TokenBucketCancelable() {}
|
||||
|
||||
friend class EventTokenBucket;
|
||||
ATokenBucketEvent *mEvent;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(TokenBucketCancelable, nsICancelable)
|
||||
|
||||
TokenBucketCancelable::TokenBucketCancelable(ATokenBucketEvent *event)
|
||||
: mEvent(event)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TokenBucketCancelable::Cancel(nsresult reason)
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
mEvent = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
TokenBucketCancelable::Fire()
|
||||
{
|
||||
if (!mEvent)
|
||||
return;
|
||||
|
||||
ATokenBucketEvent *event = mEvent;
|
||||
mEvent = nullptr;
|
||||
event->OnTokenBucketAdmitted();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////
|
||||
// EventTokenBucket
|
||||
////////////////////////////////////////////
|
||||
|
||||
NS_IMPL_ISUPPORTS(EventTokenBucket, nsITimerCallback)
|
||||
|
||||
// by default 1hz with no burst
|
||||
EventTokenBucket::EventTokenBucket(uint32_t eventsPerSecond,
|
||||
uint32_t burstSize)
|
||||
: mUnitCost(kUsecPerSec)
|
||||
, mMaxCredit(kUsecPerSec)
|
||||
, mCredit(kUsecPerSec)
|
||||
, mPaused(false)
|
||||
, mStopped(false)
|
||||
, mTimerArmed(false)
|
||||
#ifdef XP_WIN
|
||||
, mFineGrainTimerInUse(false)
|
||||
, mFineGrainResetTimerArmed(false)
|
||||
#endif
|
||||
{
|
||||
mLastUpdate = TimeStamp::Now();
|
||||
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIEventTarget> sts;
|
||||
nsCOMPtr<nsIIOService> ioService = do_GetIOService(&rv);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
sts = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
mTimer = do_CreateInstance("@mozilla.org/timer;1");
|
||||
if (mTimer)
|
||||
mTimer->SetTarget(sts);
|
||||
SetRate(eventsPerSecond, burstSize);
|
||||
}
|
||||
|
||||
EventTokenBucket::~EventTokenBucket()
|
||||
{
|
||||
SOCKET_LOG(("EventTokenBucket::dtor %p events=%d\n",
|
||||
this, mEvents.GetSize()));
|
||||
|
||||
CleanupTimers();
|
||||
|
||||
// Complete any queued events to prevent hangs
|
||||
while (mEvents.GetSize()) {
|
||||
RefPtr<TokenBucketCancelable> cancelable =
|
||||
dont_AddRef(static_cast<TokenBucketCancelable *>(mEvents.PopFront()));
|
||||
cancelable->Fire();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EventTokenBucket::CleanupTimers()
|
||||
{
|
||||
if (mTimer && mTimerArmed) {
|
||||
mTimer->Cancel();
|
||||
}
|
||||
mTimer = nullptr;
|
||||
mTimerArmed = false;
|
||||
|
||||
#ifdef XP_WIN
|
||||
NormalTimers();
|
||||
if (mFineGrainResetTimer && mFineGrainResetTimerArmed) {
|
||||
mFineGrainResetTimer->Cancel();
|
||||
}
|
||||
mFineGrainResetTimer = nullptr;
|
||||
mFineGrainResetTimerArmed = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
EventTokenBucket::SetRate(uint32_t eventsPerSecond,
|
||||
uint32_t burstSize)
|
||||
{
|
||||
SOCKET_LOG(("EventTokenBucket::SetRate %p %u %u\n",
|
||||
this, eventsPerSecond, burstSize));
|
||||
|
||||
if (eventsPerSecond > kMaxHz) {
|
||||
eventsPerSecond = kMaxHz;
|
||||
SOCKET_LOG((" eventsPerSecond out of range\n"));
|
||||
}
|
||||
|
||||
if (!eventsPerSecond) {
|
||||
eventsPerSecond = 1;
|
||||
SOCKET_LOG((" eventsPerSecond out of range\n"));
|
||||
}
|
||||
|
||||
mUnitCost = kUsecPerSec / eventsPerSecond;
|
||||
mMaxCredit = mUnitCost * burstSize;
|
||||
if (mMaxCredit > kUsecPerSec * 60 * 15) {
|
||||
SOCKET_LOG((" burstSize out of range\n"));
|
||||
mMaxCredit = kUsecPerSec * 60 * 15;
|
||||
}
|
||||
mCredit = mMaxCredit;
|
||||
mLastUpdate = TimeStamp::Now();
|
||||
}
|
||||
|
||||
void
|
||||
EventTokenBucket::ClearCredits()
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
SOCKET_LOG(("EventTokenBucket::ClearCredits %p\n", this));
|
||||
mCredit = 0;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
EventTokenBucket::BurstEventsAvailable()
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
return static_cast<uint32_t>(mCredit / mUnitCost);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
EventTokenBucket::QueuedEvents()
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
return mEvents.GetSize();
|
||||
}
|
||||
|
||||
void
|
||||
EventTokenBucket::Pause()
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
SOCKET_LOG(("EventTokenBucket::Pause %p\n", this));
|
||||
if (mPaused || mStopped)
|
||||
return;
|
||||
|
||||
mPaused = true;
|
||||
if (mTimerArmed) {
|
||||
mTimer->Cancel();
|
||||
mTimerArmed = false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EventTokenBucket::UnPause()
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
SOCKET_LOG(("EventTokenBucket::UnPause %p\n", this));
|
||||
if (!mPaused || mStopped)
|
||||
return;
|
||||
|
||||
mPaused = false;
|
||||
DispatchEvents();
|
||||
UpdateTimer();
|
||||
}
|
||||
|
||||
void
|
||||
EventTokenBucket::Stop()
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
SOCKET_LOG(("EventTokenBucket::Stop %p armed=%d\n", this, mTimerArmed));
|
||||
mStopped = true;
|
||||
CleanupTimers();
|
||||
|
||||
// Complete any queued events to prevent hangs
|
||||
while (mEvents.GetSize()) {
|
||||
RefPtr<TokenBucketCancelable> cancelable =
|
||||
dont_AddRef(static_cast<TokenBucketCancelable *>(mEvents.PopFront()));
|
||||
cancelable->Fire();
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
EventTokenBucket::SubmitEvent(ATokenBucketEvent *event, nsICancelable **cancelable)
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
SOCKET_LOG(("EventTokenBucket::SubmitEvent %p\n", this));
|
||||
|
||||
if (mStopped || !mTimer)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
UpdateCredits();
|
||||
|
||||
RefPtr<TokenBucketCancelable> cancelEvent = new TokenBucketCancelable(event);
|
||||
// When this function exits the cancelEvent needs 2 references, one for the
|
||||
// mEvents queue and one for the caller of SubmitEvent()
|
||||
|
||||
NS_ADDREF(*cancelable = cancelEvent.get());
|
||||
|
||||
if (mPaused || !TryImmediateDispatch(cancelEvent.get())) {
|
||||
// queue it
|
||||
SOCKET_LOG((" queued\n"));
|
||||
mEvents.Push(cancelEvent.forget().take());
|
||||
UpdateTimer();
|
||||
}
|
||||
else {
|
||||
SOCKET_LOG((" dispatched synchronously\n"));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
EventTokenBucket::TryImmediateDispatch(TokenBucketCancelable *cancelable)
|
||||
{
|
||||
if (mCredit < mUnitCost)
|
||||
return false;
|
||||
|
||||
mCredit -= mUnitCost;
|
||||
cancelable->Fire();
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
EventTokenBucket::DispatchEvents()
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
SOCKET_LOG(("EventTokenBucket::DispatchEvents %p %d\n", this, mPaused));
|
||||
if (mPaused || mStopped)
|
||||
return;
|
||||
|
||||
while (mEvents.GetSize() && mUnitCost <= mCredit) {
|
||||
RefPtr<TokenBucketCancelable> cancelable =
|
||||
dont_AddRef(static_cast<TokenBucketCancelable *>(mEvents.PopFront()));
|
||||
if (cancelable->mEvent) {
|
||||
SOCKET_LOG(("EventTokenBucket::DispachEvents [%p] "
|
||||
"Dispatching queue token bucket event cost=%lu credit=%lu\n",
|
||||
this, mUnitCost, mCredit));
|
||||
mCredit -= mUnitCost;
|
||||
cancelable->Fire();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef XP_WIN
|
||||
if (!mEvents.GetSize())
|
||||
WantNormalTimers();
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
EventTokenBucket::UpdateTimer()
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
if (mTimerArmed || mPaused || mStopped || !mEvents.GetSize() || !mTimer)
|
||||
return;
|
||||
|
||||
if (mCredit >= mUnitCost)
|
||||
return;
|
||||
|
||||
// determine the time needed to wait to accumulate enough credits to admit
|
||||
// one more event and set the timer for that point. Always round it
|
||||
// up because firing early doesn't help.
|
||||
//
|
||||
uint64_t deficit = mUnitCost - mCredit;
|
||||
uint64_t msecWait = (deficit + (kUsecPerMsec - 1)) / kUsecPerMsec;
|
||||
|
||||
if (msecWait < 4) // minimum wait
|
||||
msecWait = 4;
|
||||
else if (msecWait > 60000) // maximum wait
|
||||
msecWait = 60000;
|
||||
|
||||
#ifdef XP_WIN
|
||||
FineGrainTimers();
|
||||
#endif
|
||||
|
||||
SOCKET_LOG(("EventTokenBucket::UpdateTimer %p for %dms\n",
|
||||
this, msecWait));
|
||||
nsresult rv = mTimer->InitWithCallback(this, static_cast<uint32_t>(msecWait),
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
mTimerArmed = NS_SUCCEEDED(rv);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
EventTokenBucket::Notify(nsITimer *timer)
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
|
||||
#ifdef XP_WIN
|
||||
if (timer == mFineGrainResetTimer) {
|
||||
FineGrainResetTimerNotify();
|
||||
return NS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
SOCKET_LOG(("EventTokenBucket::Notify() %p\n", this));
|
||||
mTimerArmed = false;
|
||||
if (mStopped)
|
||||
return NS_OK;
|
||||
|
||||
UpdateCredits();
|
||||
DispatchEvents();
|
||||
UpdateTimer();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
EventTokenBucket::UpdateCredits()
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
|
||||
TimeStamp now = TimeStamp::Now();
|
||||
TimeDuration elapsed = now - mLastUpdate;
|
||||
mLastUpdate = now;
|
||||
|
||||
mCredit += static_cast<uint64_t>(elapsed.ToMicroseconds());
|
||||
if (mCredit > mMaxCredit)
|
||||
mCredit = mMaxCredit;
|
||||
SOCKET_LOG(("EventTokenBucket::UpdateCredits %p to %lu (%lu each.. %3.2f)\n",
|
||||
this, mCredit, mUnitCost, (double)mCredit / mUnitCost));
|
||||
}
|
||||
|
||||
#ifdef XP_WIN
|
||||
void
|
||||
EventTokenBucket::FineGrainTimers()
|
||||
{
|
||||
SOCKET_LOG(("EventTokenBucket::FineGrainTimers %p mFineGrainTimerInUse=%d\n",
|
||||
this, mFineGrainTimerInUse));
|
||||
|
||||
mLastFineGrainTimerUse = TimeStamp::Now();
|
||||
|
||||
if (mFineGrainTimerInUse)
|
||||
return;
|
||||
|
||||
if (mUnitCost > kCostFineGrainThreshold)
|
||||
return;
|
||||
|
||||
SOCKET_LOG(("EventTokenBucket::FineGrainTimers %p timeBeginPeriod()\n",
|
||||
this));
|
||||
|
||||
mFineGrainTimerInUse = true;
|
||||
timeBeginPeriod(1);
|
||||
}
|
||||
|
||||
void
|
||||
EventTokenBucket::NormalTimers()
|
||||
{
|
||||
if (!mFineGrainTimerInUse)
|
||||
return;
|
||||
mFineGrainTimerInUse = false;
|
||||
|
||||
SOCKET_LOG(("EventTokenBucket::NormalTimers %p timeEndPeriod()\n", this));
|
||||
timeEndPeriod(1);
|
||||
}
|
||||
|
||||
void
|
||||
EventTokenBucket::WantNormalTimers()
|
||||
{
|
||||
if (!mFineGrainTimerInUse)
|
||||
return;
|
||||
if (mFineGrainResetTimerArmed)
|
||||
return;
|
||||
|
||||
TimeDuration elapsed(TimeStamp::Now() - mLastFineGrainTimerUse);
|
||||
static const TimeDuration fiveSeconds = TimeDuration::FromSeconds(5);
|
||||
|
||||
if (elapsed >= fiveSeconds) {
|
||||
NormalTimers();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mFineGrainResetTimer)
|
||||
mFineGrainResetTimer = do_CreateInstance("@mozilla.org/timer;1");
|
||||
|
||||
// if we can't delay the reset, just do it now
|
||||
if (!mFineGrainResetTimer) {
|
||||
NormalTimers();
|
||||
return;
|
||||
}
|
||||
|
||||
// pad the callback out 100ms to avoid having to round trip this again if the
|
||||
// timer calls back just a tad early.
|
||||
SOCKET_LOG(("EventTokenBucket::WantNormalTimers %p "
|
||||
"Will reset timer granularity after delay", this));
|
||||
|
||||
mFineGrainResetTimer->InitWithCallback(
|
||||
this,
|
||||
static_cast<uint32_t>((fiveSeconds - elapsed).ToMilliseconds()) + 100,
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
mFineGrainResetTimerArmed = true;
|
||||
}
|
||||
|
||||
void
|
||||
EventTokenBucket::FineGrainResetTimerNotify()
|
||||
{
|
||||
SOCKET_LOG(("EventTokenBucket::FineGrainResetTimerNotify() events = %d\n",
|
||||
this, mEvents.GetSize()));
|
||||
mFineGrainResetTimerArmed = false;
|
||||
|
||||
// If we are currently processing events then wait for the queue to drain
|
||||
// before trying to reset back to normal timers again
|
||||
if (!mEvents.GetSize())
|
||||
WantNormalTimers();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
149
netwerk/base/EventTokenBucket.h
Normal file
149
netwerk/base/EventTokenBucket.h
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef NetEventTokenBucket_h__
|
||||
#define NetEventTokenBucket_h__
|
||||
|
||||
#include "ARefBase.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsDeque.h"
|
||||
#include "nsITimer.h"
|
||||
|
||||
#include "mozilla/TimeStamp.h"
|
||||
|
||||
class nsICancelable;
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
/* A token bucket is used to govern the maximum rate a series of events
|
||||
can be executed at. For instance if your event was "eat a piece of cake"
|
||||
then a token bucket configured to allow "1 piece per day" would spread
|
||||
the eating of a 8 piece cake over 8 days even if you tried to eat the
|
||||
whole thing up front. In a practical sense it 'costs' 1 token to execute
|
||||
an event and tokens are 'earned' at a particular rate as time goes by.
|
||||
|
||||
The token bucket can be perfectly smooth or allow a configurable amount of
|
||||
burstiness. A bursty token bucket allows you to save up unused credits, while
|
||||
a perfectly smooth one would not. A smooth "1 per day" cake token bucket
|
||||
would require 9 days to eat that cake if you skipped a slice on day 4
|
||||
(use the token or lose it), while a token bucket configured with a burst
|
||||
of 2 would just let you eat 2 slices on day 5 (the credits for day 4 and day
|
||||
5) and finish the cake in the usual 8 days.
|
||||
|
||||
EventTokenBucket(hz=20, burst=5) creates a token bucket with the following properties:
|
||||
|
||||
+ events from an infinite stream will be admitted 20 times per second (i.e.
|
||||
hz=20 means 1 event per 50 ms). Timers will be used to space things evenly down to
|
||||
5ms gaps (i.e. up to 200hz). Token buckets with rates greater than 200hz will admit
|
||||
multiple events with 5ms gaps between them. 10000hz is the maximum rate and 1hz is
|
||||
the minimum rate.
|
||||
|
||||
+ The burst size controls the limit of 'credits' that a token bucket can accumulate
|
||||
when idle. For our (20,5) example each event requires 50ms of credit (again, 20hz = 50ms
|
||||
per event). a burst size of 5 means that the token bucket can accumulate a
|
||||
maximum of 250ms (5 * 50ms) for this bucket. If no events have been admitted for the
|
||||
last full second the bucket can still only accumulate 250ms of credit - but that credit
|
||||
means that 5 events can be admitted without delay. A burst size of 1 is the minimum.
|
||||
The EventTokenBucket is created with maximum credits already applied, but they
|
||||
can be cleared with the ClearCredits() method. The maximum burst size is
|
||||
15 minutes worth of events.
|
||||
|
||||
+ An event is submitted to the token bucket asynchronously through SubmitEvent().
|
||||
The OnTokenBucketAdmitted() method of the submitted event is used as a callback
|
||||
when the event is ready to run. A cancelable event is returned to the SubmitEvent() caller
|
||||
for use in the case they do not wish to wait for the callback.
|
||||
*/
|
||||
|
||||
class EventTokenBucket;
|
||||
|
||||
class ATokenBucketEvent
|
||||
{
|
||||
public:
|
||||
virtual void OnTokenBucketAdmitted() = 0;
|
||||
};
|
||||
|
||||
class TokenBucketCancelable;
|
||||
|
||||
class EventTokenBucket : public nsITimerCallback, public ARefBase
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSITIMERCALLBACK
|
||||
|
||||
// This should be constructed on the main thread
|
||||
EventTokenBucket(uint32_t eventsPerSecond, uint32_t burstSize);
|
||||
|
||||
// These public methods are all meant to be called from the socket thread
|
||||
void ClearCredits();
|
||||
uint32_t BurstEventsAvailable();
|
||||
uint32_t QueuedEvents();
|
||||
|
||||
// a paused token bucket will not process any events, but it will accumulate
|
||||
// credits. ClearCredits can be used before unpausing if desired.
|
||||
void Pause();
|
||||
void UnPause();
|
||||
void Stop();
|
||||
|
||||
// The returned cancelable event can only be canceled from the socket thread
|
||||
nsresult SubmitEvent(ATokenBucketEvent *event, nsICancelable **cancelable);
|
||||
|
||||
private:
|
||||
virtual ~EventTokenBucket();
|
||||
void CleanupTimers();
|
||||
|
||||
friend class RunNotifyEvent;
|
||||
friend class SetTimerEvent;
|
||||
|
||||
bool TryImmediateDispatch(TokenBucketCancelable *event);
|
||||
void SetRate(uint32_t eventsPerSecond, uint32_t burstSize);
|
||||
|
||||
void DispatchEvents();
|
||||
void UpdateTimer();
|
||||
void UpdateCredits();
|
||||
|
||||
const static uint64_t kUsecPerSec = 1000000;
|
||||
const static uint64_t kUsecPerMsec = 1000;
|
||||
const static uint64_t kMaxHz = 10000;
|
||||
|
||||
uint64_t mUnitCost; // usec of credit needed for 1 event (from eventsPerSecond)
|
||||
uint64_t mMaxCredit; // usec mCredit limit (from busrtSize)
|
||||
uint64_t mCredit; // usec of accumulated credit.
|
||||
|
||||
bool mPaused;
|
||||
bool mStopped;
|
||||
nsDeque mEvents;
|
||||
bool mTimerArmed;
|
||||
TimeStamp mLastUpdate;
|
||||
|
||||
// The timer is created on the main thread, but is armed and executes Notify()
|
||||
// callbacks on the socket thread in order to maintain low latency of event
|
||||
// delivery.
|
||||
nsCOMPtr<nsITimer> mTimer;
|
||||
|
||||
#ifdef XP_WIN
|
||||
// Windows timers are 15ms granularity by default. When we have active events
|
||||
// that need to be dispatched at 50ms or less granularity we change the OS
|
||||
// granularity to 1ms. 90 seconds after that need has elapsed we will change it
|
||||
// back
|
||||
const static uint64_t kCostFineGrainThreshold = 50 * kUsecPerMsec;
|
||||
|
||||
void FineGrainTimers(); // get 1ms granularity
|
||||
void NormalTimers(); // reset to default granularity
|
||||
void WantNormalTimers(); // reset after 90 seconds if not needed in interim
|
||||
void FineGrainResetTimerNotify(); // delayed callback to reset
|
||||
|
||||
TimeStamp mLastFineGrainTimerUse;
|
||||
bool mFineGrainTimerInUse;
|
||||
bool mFineGrainResetTimerArmed;
|
||||
nsCOMPtr<nsITimer> mFineGrainResetTimer;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
181
netwerk/base/LoadContextInfo.cpp
Normal file
181
netwerk/base/LoadContextInfo.cpp
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "LoadContextInfo.h"
|
||||
|
||||
#include "mozilla/dom/ToJSValue.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsILoadContext.h"
|
||||
#include "nsIWebNavigation.h"
|
||||
#include "nsNetUtil.h"
|
||||
|
||||
using namespace mozilla::dom;
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
// LoadContextInfo
|
||||
|
||||
NS_IMPL_ISUPPORTS(LoadContextInfo, nsILoadContextInfo)
|
||||
|
||||
LoadContextInfo::LoadContextInfo(bool aIsAnonymous, NeckoOriginAttributes aOriginAttributes)
|
||||
: mIsAnonymous(aIsAnonymous)
|
||||
, mOriginAttributes(aOriginAttributes)
|
||||
{
|
||||
}
|
||||
|
||||
LoadContextInfo::~LoadContextInfo()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP LoadContextInfo::GetIsPrivate(bool *aIsPrivate)
|
||||
{
|
||||
*aIsPrivate = mOriginAttributes.mPrivateBrowsingId > 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP LoadContextInfo::GetIsAnonymous(bool *aIsAnonymous)
|
||||
{
|
||||
*aIsAnonymous = mIsAnonymous;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NeckoOriginAttributes const* LoadContextInfo::OriginAttributesPtr()
|
||||
{
|
||||
return &mOriginAttributes;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP LoadContextInfo::GetOriginAttributes(JSContext *aCx,
|
||||
JS::MutableHandle<JS::Value> aVal)
|
||||
{
|
||||
if (NS_WARN_IF(!ToJSValue(aCx, mOriginAttributes, aVal))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// LoadContextInfoFactory
|
||||
|
||||
NS_IMPL_ISUPPORTS(LoadContextInfoFactory, nsILoadContextInfoFactory)
|
||||
|
||||
NS_IMETHODIMP LoadContextInfoFactory::GetDefault(nsILoadContextInfo * *aDefault)
|
||||
{
|
||||
nsCOMPtr<nsILoadContextInfo> info = GetLoadContextInfo(false, NeckoOriginAttributes());
|
||||
info.forget(aDefault);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP LoadContextInfoFactory::GetPrivate(nsILoadContextInfo * *aPrivate)
|
||||
{
|
||||
NeckoOriginAttributes attrs;
|
||||
attrs.SyncAttributesWithPrivateBrowsing(true);
|
||||
nsCOMPtr<nsILoadContextInfo> info = GetLoadContextInfo(false, attrs);
|
||||
info.forget(aPrivate);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP LoadContextInfoFactory::GetAnonymous(nsILoadContextInfo * *aAnonymous)
|
||||
{
|
||||
nsCOMPtr<nsILoadContextInfo> info = GetLoadContextInfo(true, NeckoOriginAttributes());
|
||||
info.forget(aAnonymous);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP LoadContextInfoFactory::Custom(bool aAnonymous,
|
||||
JS::HandleValue aOriginAttributes, JSContext *cx,
|
||||
nsILoadContextInfo * *_retval)
|
||||
{
|
||||
NeckoOriginAttributes attrs;
|
||||
bool status = attrs.Init(cx, aOriginAttributes);
|
||||
NS_ENSURE_TRUE(status, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<nsILoadContextInfo> info = GetLoadContextInfo(aAnonymous, attrs);
|
||||
info.forget(_retval);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP LoadContextInfoFactory::FromLoadContext(nsILoadContext *aLoadContext, bool aAnonymous,
|
||||
nsILoadContextInfo * *_retval)
|
||||
{
|
||||
nsCOMPtr<nsILoadContextInfo> info = GetLoadContextInfo(aLoadContext, aAnonymous);
|
||||
info.forget(_retval);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP LoadContextInfoFactory::FromWindow(nsIDOMWindow *aWindow, bool aAnonymous,
|
||||
nsILoadContextInfo * *_retval)
|
||||
{
|
||||
nsCOMPtr<nsILoadContextInfo> info = GetLoadContextInfo(aWindow, aAnonymous);
|
||||
info.forget(_retval);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Helper functions
|
||||
|
||||
LoadContextInfo *
|
||||
GetLoadContextInfo(nsIChannel * aChannel)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
DebugOnly<bool> pb = NS_UsePrivateBrowsing(aChannel);
|
||||
|
||||
bool anon = false;
|
||||
nsLoadFlags loadFlags;
|
||||
rv = aChannel->GetLoadFlags(&loadFlags);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
anon = !!(loadFlags & nsIChannel::LOAD_ANONYMOUS);
|
||||
}
|
||||
|
||||
NeckoOriginAttributes oa;
|
||||
NS_GetOriginAttributes(aChannel, oa);
|
||||
MOZ_ASSERT(pb == (oa.mPrivateBrowsingId > 0));
|
||||
|
||||
return new LoadContextInfo(anon, oa);
|
||||
}
|
||||
|
||||
LoadContextInfo *
|
||||
GetLoadContextInfo(nsILoadContext *aLoadContext, bool aIsAnonymous)
|
||||
{
|
||||
if (!aLoadContext) {
|
||||
return new LoadContextInfo(aIsAnonymous,
|
||||
NeckoOriginAttributes(nsILoadContextInfo::NO_APP_ID, false));
|
||||
}
|
||||
|
||||
DebugOnly<bool> pb = aLoadContext->UsePrivateBrowsing();
|
||||
DocShellOriginAttributes doa;
|
||||
aLoadContext->GetOriginAttributes(doa);
|
||||
MOZ_ASSERT(pb == (doa.mPrivateBrowsingId > 0));
|
||||
|
||||
NeckoOriginAttributes noa;
|
||||
noa.InheritFromDocShellToNecko(doa);
|
||||
|
||||
return new LoadContextInfo(aIsAnonymous, noa);
|
||||
}
|
||||
|
||||
LoadContextInfo*
|
||||
GetLoadContextInfo(nsIDOMWindow *aWindow,
|
||||
bool aIsAnonymous)
|
||||
{
|
||||
nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(aWindow);
|
||||
nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(webNav);
|
||||
|
||||
return GetLoadContextInfo(loadContext, aIsAnonymous);
|
||||
}
|
||||
|
||||
LoadContextInfo *
|
||||
GetLoadContextInfo(nsILoadContextInfo *aInfo)
|
||||
{
|
||||
return new LoadContextInfo(aInfo->IsAnonymous(),
|
||||
*aInfo->OriginAttributesPtr());
|
||||
}
|
||||
|
||||
LoadContextInfo *
|
||||
GetLoadContextInfo(bool const aIsAnonymous,
|
||||
NeckoOriginAttributes const &aOriginAttributes)
|
||||
{
|
||||
return new LoadContextInfo(aIsAnonymous,
|
||||
aOriginAttributes);
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
61
netwerk/base/LoadContextInfo.h
Normal file
61
netwerk/base/LoadContextInfo.h
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsLoadContextInfo_h__
|
||||
#define nsLoadContextInfo_h__
|
||||
|
||||
#include "nsILoadContextInfo.h"
|
||||
|
||||
class nsIChannel;
|
||||
class nsILoadContext;
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
class LoadContextInfo : public nsILoadContextInfo
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSILOADCONTEXTINFO
|
||||
|
||||
LoadContextInfo(bool aIsAnonymous, NeckoOriginAttributes aOriginAttributes);
|
||||
|
||||
private:
|
||||
virtual ~LoadContextInfo();
|
||||
|
||||
protected:
|
||||
bool mIsAnonymous : 1;
|
||||
NeckoOriginAttributes mOriginAttributes;
|
||||
};
|
||||
|
||||
class LoadContextInfoFactory : public nsILoadContextInfoFactory
|
||||
{
|
||||
virtual ~LoadContextInfoFactory() {}
|
||||
public:
|
||||
NS_DECL_ISUPPORTS // deliberately not thread-safe
|
||||
NS_DECL_NSILOADCONTEXTINFOFACTORY
|
||||
};
|
||||
|
||||
LoadContextInfo*
|
||||
GetLoadContextInfo(nsIChannel *aChannel);
|
||||
|
||||
LoadContextInfo*
|
||||
GetLoadContextInfo(nsILoadContext *aLoadContext,
|
||||
bool aIsAnonymous);
|
||||
|
||||
LoadContextInfo*
|
||||
GetLoadContextInfo(nsIDOMWindow *aLoadContext,
|
||||
bool aIsAnonymous);
|
||||
|
||||
LoadContextInfo*
|
||||
GetLoadContextInfo(nsILoadContextInfo *aInfo);
|
||||
|
||||
LoadContextInfo*
|
||||
GetLoadContextInfo(bool const aIsAnonymous,
|
||||
NeckoOriginAttributes const &aOriginAttributes);
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
925
netwerk/base/LoadInfo.cpp
Normal file
925
netwerk/base/LoadInfo.cpp
Normal file
|
|
@ -0,0 +1,925 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/LoadInfo.h"
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/dom/ToJSValue.h"
|
||||
#include "mozIThirdPartyUtil.h"
|
||||
#include "nsFrameLoader.h"
|
||||
#include "nsIContentSecurityPolicy.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIDOMDocument.h"
|
||||
#include "nsIFrameLoader.h"
|
||||
#include "nsIInterfaceRequestorUtils.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsISupportsUtils.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsDocShell.h"
|
||||
#include "nsGlobalWindow.h"
|
||||
#include "nsNullPrincipal.h"
|
||||
|
||||
using namespace mozilla::dom;
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
static void
|
||||
InheritOriginAttributes(nsIPrincipal* aLoadingPrincipal, NeckoOriginAttributes& aAttrs)
|
||||
{
|
||||
const PrincipalOriginAttributes attrs =
|
||||
BasePrincipal::Cast(aLoadingPrincipal)->OriginAttributesRef();
|
||||
aAttrs.InheritFromDocToNecko(attrs);
|
||||
}
|
||||
|
||||
LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal,
|
||||
nsIPrincipal* aTriggeringPrincipal,
|
||||
nsINode* aLoadingContext,
|
||||
nsSecurityFlags aSecurityFlags,
|
||||
nsContentPolicyType aContentPolicyType)
|
||||
: mLoadingPrincipal(aLoadingContext ?
|
||||
aLoadingContext->NodePrincipal() : aLoadingPrincipal)
|
||||
, mTriggeringPrincipal(aTriggeringPrincipal ?
|
||||
aTriggeringPrincipal : mLoadingPrincipal.get())
|
||||
, mPrincipalToInherit(nullptr)
|
||||
, mLoadingContext(do_GetWeakReference(aLoadingContext))
|
||||
, mSecurityFlags(aSecurityFlags)
|
||||
, mInternalContentPolicyType(aContentPolicyType)
|
||||
, mTainting(LoadTainting::Basic)
|
||||
, mUpgradeInsecureRequests(false)
|
||||
, mVerifySignedContent(false)
|
||||
, mEnforceSRI(false)
|
||||
, mForceInheritPrincipalDropped(false)
|
||||
, mInnerWindowID(0)
|
||||
, mOuterWindowID(0)
|
||||
, mParentOuterWindowID(0)
|
||||
, mFrameOuterWindowID(0)
|
||||
, mEnforceSecurity(false)
|
||||
, mInitialSecurityCheckDone(false)
|
||||
, mIsThirdPartyContext(false)
|
||||
, mForcePreflight(false)
|
||||
, mIsPreflight(false)
|
||||
, mForceHSTSPriming(false)
|
||||
, mMixedContentWouldBlock(false)
|
||||
{
|
||||
MOZ_ASSERT(mLoadingPrincipal);
|
||||
MOZ_ASSERT(mTriggeringPrincipal);
|
||||
|
||||
#ifdef DEBUG
|
||||
// TYPE_DOCUMENT loads initiated by javascript tests will go through
|
||||
// nsIOService and use the wrong constructor. Don't enforce the
|
||||
// !TYPE_DOCUMENT check in those cases
|
||||
bool skipContentTypeCheck = false;
|
||||
skipContentTypeCheck = Preferences::GetBool("network.loadinfo.skip_type_assertion");
|
||||
#endif
|
||||
|
||||
// This constructor shouldn't be used for TYPE_DOCUMENT loads that don't
|
||||
// have a loadingPrincipal
|
||||
MOZ_ASSERT(skipContentTypeCheck ||
|
||||
mInternalContentPolicyType != nsIContentPolicy::TYPE_DOCUMENT);
|
||||
|
||||
// TODO(bug 1259873): Above, we initialize mIsThirdPartyContext to false meaning
|
||||
// that consumers of LoadInfo that don't pass a context or pass a context from
|
||||
// which we can't find a window will default to assuming that they're 1st
|
||||
// party. It would be nice if we could default "safe" and assume that we are
|
||||
// 3rd party until proven otherwise.
|
||||
|
||||
// if consumers pass both, aLoadingContext and aLoadingPrincipal
|
||||
// then the loadingPrincipal must be the same as the node's principal
|
||||
MOZ_ASSERT(!aLoadingContext || !aLoadingPrincipal ||
|
||||
aLoadingContext->NodePrincipal() == aLoadingPrincipal);
|
||||
|
||||
// if the load is sandboxed, we can not also inherit the principal
|
||||
if (mSecurityFlags & nsILoadInfo::SEC_SANDBOXED) {
|
||||
mSecurityFlags ^= nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL;
|
||||
mForceInheritPrincipalDropped = true;
|
||||
}
|
||||
|
||||
if (aLoadingContext) {
|
||||
nsCOMPtr<nsPIDOMWindowOuter> contextOuter = aLoadingContext->OwnerDoc()->GetWindow();
|
||||
if (contextOuter) {
|
||||
ComputeIsThirdPartyContext(contextOuter);
|
||||
mOuterWindowID = contextOuter->WindowID();
|
||||
nsCOMPtr<nsPIDOMWindowOuter> parent = contextOuter->GetScriptableParent();
|
||||
mParentOuterWindowID = parent ? parent->WindowID() : mOuterWindowID;
|
||||
}
|
||||
|
||||
mInnerWindowID = aLoadingContext->OwnerDoc()->InnerWindowID();
|
||||
|
||||
// When the element being loaded is a frame, we choose the frame's window
|
||||
// for the window ID and the frame element's window as the parent
|
||||
// window. This is the behavior that Chrome exposes to add-ons.
|
||||
// NB: If the frameLoaderOwner doesn't have a frame loader, then the load
|
||||
// must be coming from an object (such as a plugin) that's loaded into it
|
||||
// instead of a document being loaded. In that case, treat this object like
|
||||
// any other non-document-loading element.
|
||||
nsCOMPtr<nsIFrameLoaderOwner> frameLoaderOwner =
|
||||
do_QueryInterface(aLoadingContext);
|
||||
nsCOMPtr<nsIFrameLoader> fl = frameLoaderOwner ?
|
||||
frameLoaderOwner->GetFrameLoader() : nullptr;
|
||||
if (fl) {
|
||||
nsCOMPtr<nsIDocShell> docShell;
|
||||
if (NS_SUCCEEDED(fl->GetDocShell(getter_AddRefs(docShell))) && docShell) {
|
||||
nsCOMPtr<nsPIDOMWindowOuter> outerWindow = do_GetInterface(docShell);
|
||||
if (outerWindow) {
|
||||
mFrameOuterWindowID = outerWindow->WindowID();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if the document forces all requests to be upgraded from http to https, then
|
||||
// we should do that for all requests. If it only forces preloads to be upgraded
|
||||
// then we should enforce upgrade insecure requests only for preloads.
|
||||
mUpgradeInsecureRequests =
|
||||
aLoadingContext->OwnerDoc()->GetUpgradeInsecureRequests(false) ||
|
||||
(nsContentUtils::IsPreloadType(mInternalContentPolicyType) &&
|
||||
aLoadingContext->OwnerDoc()->GetUpgradeInsecureRequests(true));
|
||||
|
||||
// if owner doc has content signature, we enforce SRI
|
||||
nsCOMPtr<nsIChannel> channel = aLoadingContext->OwnerDoc()->GetChannel();
|
||||
if (channel) {
|
||||
nsCOMPtr<nsILoadInfo> loadInfo = channel->GetLoadInfo();
|
||||
if (loadInfo) {
|
||||
mEnforceSRI = loadInfo->GetVerifySignedContent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If CSP requires SRI (require-sri-for), then store that information
|
||||
// in the loadInfo so we can enforce SRI before loading the subresource.
|
||||
if (!mEnforceSRI) {
|
||||
// do not look into the CSP if already true:
|
||||
// a CSP saying that SRI isn't needed should not
|
||||
// overrule GetVerifySignedContent
|
||||
if (aLoadingPrincipal) {
|
||||
nsCOMPtr<nsIContentSecurityPolicy> csp;
|
||||
aLoadingPrincipal->GetCsp(getter_AddRefs(csp));
|
||||
uint32_t externalType =
|
||||
nsContentUtils::InternalContentPolicyTypeToExternal(aContentPolicyType);
|
||||
// csp could be null if loading principal is system principal
|
||||
if (csp) {
|
||||
csp->RequireSRIForType(externalType, &mEnforceSRI);
|
||||
}
|
||||
// if CSP is delivered via a meta tag, it's speculatively available
|
||||
// as 'preloadCSP'. If we are preloading a script or style, we have
|
||||
// to apply that speculative 'preloadCSP' for such loads.
|
||||
if (!mEnforceSRI && nsContentUtils::IsPreloadType(aContentPolicyType)) {
|
||||
nsCOMPtr<nsIContentSecurityPolicy> preloadCSP;
|
||||
aLoadingPrincipal->GetPreloadCsp(getter_AddRefs(preloadCSP));
|
||||
if (preloadCSP) {
|
||||
preloadCSP->RequireSRIForType(externalType, &mEnforceSRI);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
InheritOriginAttributes(mLoadingPrincipal, mOriginAttributes);
|
||||
|
||||
// We need to do this after inheriting the document's origin attributes
|
||||
// above, in case the loading principal ends up being the system principal.
|
||||
if (aLoadingContext) {
|
||||
nsCOMPtr<nsILoadContext> loadContext =
|
||||
aLoadingContext->OwnerDoc()->GetLoadContext();
|
||||
nsCOMPtr<nsIDocShell> docShell = aLoadingContext->OwnerDoc()->GetDocShell();
|
||||
if (loadContext && docShell &&
|
||||
docShell->ItemType() == nsIDocShellTreeItem::typeContent) {
|
||||
bool usePrivateBrowsing;
|
||||
nsresult rv = loadContext->GetUsePrivateBrowsing(&usePrivateBrowsing);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mOriginAttributes.SyncAttributesWithPrivateBrowsing(usePrivateBrowsing);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For chrome docshell, the mPrivateBrowsingId remains 0 even its
|
||||
// UsePrivateBrowsing() is true, so we only update the mPrivateBrowsingId in
|
||||
// origin attributes if the type of the docshell is content.
|
||||
if (aLoadingContext) {
|
||||
nsCOMPtr<nsIDocShell> docShell = aLoadingContext->OwnerDoc()->GetDocShell();
|
||||
if (docShell) {
|
||||
if (docShell->ItemType() == nsIDocShellTreeItem::typeChrome) {
|
||||
MOZ_ASSERT(mOriginAttributes.mPrivateBrowsingId == 0,
|
||||
"chrome docshell shouldn't have mPrivateBrowsingId set.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Constructor takes an outer window, but no loadingNode or loadingPrincipal.
|
||||
* This constructor should only be used for TYPE_DOCUMENT loads, since they
|
||||
* have a null loadingNode and loadingPrincipal.
|
||||
*/
|
||||
LoadInfo::LoadInfo(nsPIDOMWindowOuter* aOuterWindow,
|
||||
nsIPrincipal* aTriggeringPrincipal,
|
||||
nsSecurityFlags aSecurityFlags)
|
||||
: mLoadingPrincipal(nullptr)
|
||||
, mTriggeringPrincipal(aTriggeringPrincipal)
|
||||
, mPrincipalToInherit(nullptr)
|
||||
, mSecurityFlags(aSecurityFlags)
|
||||
, mInternalContentPolicyType(nsIContentPolicy::TYPE_DOCUMENT)
|
||||
, mTainting(LoadTainting::Basic)
|
||||
, mUpgradeInsecureRequests(false)
|
||||
, mVerifySignedContent(false)
|
||||
, mEnforceSRI(false)
|
||||
, mForceInheritPrincipalDropped(false)
|
||||
, mInnerWindowID(0)
|
||||
, mOuterWindowID(0)
|
||||
, mParentOuterWindowID(0)
|
||||
, mFrameOuterWindowID(0)
|
||||
, mEnforceSecurity(false)
|
||||
, mInitialSecurityCheckDone(false)
|
||||
, mIsThirdPartyContext(false) // NB: TYPE_DOCUMENT implies not third-party.
|
||||
, mForcePreflight(false)
|
||||
, mIsPreflight(false)
|
||||
, mForceHSTSPriming(false)
|
||||
, mMixedContentWouldBlock(false)
|
||||
{
|
||||
// Top-level loads are never third-party
|
||||
// Grab the information we can out of the window.
|
||||
MOZ_ASSERT(aOuterWindow);
|
||||
MOZ_ASSERT(mTriggeringPrincipal);
|
||||
|
||||
// if the load is sandboxed, we can not also inherit the principal
|
||||
if (mSecurityFlags & nsILoadInfo::SEC_SANDBOXED) {
|
||||
mSecurityFlags ^= nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL;
|
||||
mForceInheritPrincipalDropped = true;
|
||||
}
|
||||
|
||||
// NB: Ignore the current inner window since we're navigating away from it.
|
||||
mOuterWindowID = aOuterWindow->WindowID();
|
||||
|
||||
// TODO We can have a parent without a frame element in some cases dealing
|
||||
// with the hidden window.
|
||||
nsCOMPtr<nsPIDOMWindowOuter> parent = aOuterWindow->GetScriptableParent();
|
||||
mParentOuterWindowID = parent ? parent->WindowID() : 0;
|
||||
|
||||
// get the docshell from the outerwindow, and then get the originattributes
|
||||
nsCOMPtr<nsIDocShell> docShell = aOuterWindow->GetDocShell();
|
||||
MOZ_ASSERT(docShell);
|
||||
const DocShellOriginAttributes attrs =
|
||||
nsDocShell::Cast(docShell)->GetOriginAttributes();
|
||||
|
||||
if (docShell->ItemType() == nsIDocShellTreeItem::typeChrome) {
|
||||
MOZ_ASSERT(attrs.mPrivateBrowsingId == 0,
|
||||
"chrome docshell shouldn't have mPrivateBrowsingId set.");
|
||||
}
|
||||
|
||||
mOriginAttributes.InheritFromDocShellToNecko(attrs);
|
||||
}
|
||||
|
||||
LoadInfo::LoadInfo(const LoadInfo& rhs)
|
||||
: mLoadingPrincipal(rhs.mLoadingPrincipal)
|
||||
, mTriggeringPrincipal(rhs.mTriggeringPrincipal)
|
||||
, mPrincipalToInherit(rhs.mPrincipalToInherit)
|
||||
, mLoadingContext(rhs.mLoadingContext)
|
||||
, mSecurityFlags(rhs.mSecurityFlags)
|
||||
, mInternalContentPolicyType(rhs.mInternalContentPolicyType)
|
||||
, mTainting(rhs.mTainting)
|
||||
, mUpgradeInsecureRequests(rhs.mUpgradeInsecureRequests)
|
||||
, mVerifySignedContent(rhs.mVerifySignedContent)
|
||||
, mEnforceSRI(rhs.mEnforceSRI)
|
||||
, mForceInheritPrincipalDropped(rhs.mForceInheritPrincipalDropped)
|
||||
, mInnerWindowID(rhs.mInnerWindowID)
|
||||
, mOuterWindowID(rhs.mOuterWindowID)
|
||||
, mParentOuterWindowID(rhs.mParentOuterWindowID)
|
||||
, mFrameOuterWindowID(rhs.mFrameOuterWindowID)
|
||||
, mEnforceSecurity(rhs.mEnforceSecurity)
|
||||
, mInitialSecurityCheckDone(rhs.mInitialSecurityCheckDone)
|
||||
, mIsThirdPartyContext(rhs.mIsThirdPartyContext)
|
||||
, mOriginAttributes(rhs.mOriginAttributes)
|
||||
, mRedirectChainIncludingInternalRedirects(
|
||||
rhs.mRedirectChainIncludingInternalRedirects)
|
||||
, mRedirectChain(rhs.mRedirectChain)
|
||||
, mCorsUnsafeHeaders(rhs.mCorsUnsafeHeaders)
|
||||
, mForcePreflight(rhs.mForcePreflight)
|
||||
, mIsPreflight(rhs.mIsPreflight)
|
||||
, mForceHSTSPriming(rhs.mForceHSTSPriming)
|
||||
, mMixedContentWouldBlock(rhs.mMixedContentWouldBlock)
|
||||
{
|
||||
}
|
||||
|
||||
LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal,
|
||||
nsIPrincipal* aTriggeringPrincipal,
|
||||
nsIPrincipal* aPrincipalToInherit,
|
||||
nsSecurityFlags aSecurityFlags,
|
||||
nsContentPolicyType aContentPolicyType,
|
||||
LoadTainting aTainting,
|
||||
bool aUpgradeInsecureRequests,
|
||||
bool aVerifySignedContent,
|
||||
bool aEnforceSRI,
|
||||
bool aForceInheritPrincipalDropped,
|
||||
uint64_t aInnerWindowID,
|
||||
uint64_t aOuterWindowID,
|
||||
uint64_t aParentOuterWindowID,
|
||||
uint64_t aFrameOuterWindowID,
|
||||
bool aEnforceSecurity,
|
||||
bool aInitialSecurityCheckDone,
|
||||
bool aIsThirdPartyContext,
|
||||
const NeckoOriginAttributes& aOriginAttributes,
|
||||
nsTArray<nsCOMPtr<nsIPrincipal>>& aRedirectChainIncludingInternalRedirects,
|
||||
nsTArray<nsCOMPtr<nsIPrincipal>>& aRedirectChain,
|
||||
const nsTArray<nsCString>& aCorsUnsafeHeaders,
|
||||
bool aForcePreflight,
|
||||
bool aIsPreflight,
|
||||
bool aForceHSTSPriming,
|
||||
bool aMixedContentWouldBlock)
|
||||
: mLoadingPrincipal(aLoadingPrincipal)
|
||||
, mTriggeringPrincipal(aTriggeringPrincipal)
|
||||
, mPrincipalToInherit(aPrincipalToInherit)
|
||||
, mSecurityFlags(aSecurityFlags)
|
||||
, mInternalContentPolicyType(aContentPolicyType)
|
||||
, mTainting(aTainting)
|
||||
, mUpgradeInsecureRequests(aUpgradeInsecureRequests)
|
||||
, mVerifySignedContent(aVerifySignedContent)
|
||||
, mEnforceSRI(aEnforceSRI)
|
||||
, mForceInheritPrincipalDropped(aForceInheritPrincipalDropped)
|
||||
, mInnerWindowID(aInnerWindowID)
|
||||
, mOuterWindowID(aOuterWindowID)
|
||||
, mParentOuterWindowID(aParentOuterWindowID)
|
||||
, mFrameOuterWindowID(aFrameOuterWindowID)
|
||||
, mEnforceSecurity(aEnforceSecurity)
|
||||
, mInitialSecurityCheckDone(aInitialSecurityCheckDone)
|
||||
, mIsThirdPartyContext(aIsThirdPartyContext)
|
||||
, mOriginAttributes(aOriginAttributes)
|
||||
, mCorsUnsafeHeaders(aCorsUnsafeHeaders)
|
||||
, mForcePreflight(aForcePreflight)
|
||||
, mIsPreflight(aIsPreflight)
|
||||
, mForceHSTSPriming (aForceHSTSPriming)
|
||||
, mMixedContentWouldBlock(aMixedContentWouldBlock)
|
||||
{
|
||||
// Only top level TYPE_DOCUMENT loads can have a null loadingPrincipal
|
||||
MOZ_ASSERT(mLoadingPrincipal || aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT);
|
||||
MOZ_ASSERT(mTriggeringPrincipal);
|
||||
|
||||
mRedirectChainIncludingInternalRedirects.SwapElements(
|
||||
aRedirectChainIncludingInternalRedirects);
|
||||
|
||||
mRedirectChain.SwapElements(aRedirectChain);
|
||||
}
|
||||
|
||||
LoadInfo::~LoadInfo()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
LoadInfo::ComputeIsThirdPartyContext(nsPIDOMWindowOuter* aOuterWindow)
|
||||
{
|
||||
nsContentPolicyType type =
|
||||
nsContentUtils::InternalContentPolicyTypeToExternal(mInternalContentPolicyType);
|
||||
if (type == nsIContentPolicy::TYPE_DOCUMENT) {
|
||||
// Top-level loads are never third-party.
|
||||
mIsThirdPartyContext = false;
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<mozIThirdPartyUtil> util(do_GetService(THIRDPARTYUTIL_CONTRACTID));
|
||||
if (NS_WARN_IF(!util)) {
|
||||
return;
|
||||
}
|
||||
|
||||
util->IsThirdPartyWindow(aOuterWindow, nullptr, &mIsThirdPartyContext);
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(LoadInfo, nsILoadInfo)
|
||||
|
||||
already_AddRefed<nsILoadInfo>
|
||||
LoadInfo::Clone() const
|
||||
{
|
||||
RefPtr<LoadInfo> copy(new LoadInfo(*this));
|
||||
return copy.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<nsILoadInfo>
|
||||
LoadInfo::CloneWithNewSecFlags(nsSecurityFlags aSecurityFlags) const
|
||||
{
|
||||
RefPtr<LoadInfo> copy(new LoadInfo(*this));
|
||||
copy->mSecurityFlags = aSecurityFlags;
|
||||
return copy.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<nsILoadInfo>
|
||||
LoadInfo::CloneForNewRequest() const
|
||||
{
|
||||
RefPtr<LoadInfo> copy(new LoadInfo(*this));
|
||||
copy->mEnforceSecurity = false;
|
||||
copy->mInitialSecurityCheckDone = false;
|
||||
copy->mRedirectChainIncludingInternalRedirects.Clear();
|
||||
copy->mRedirectChain.Clear();
|
||||
return copy.forget();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetLoadingPrincipal(nsIPrincipal** aLoadingPrincipal)
|
||||
{
|
||||
NS_IF_ADDREF(*aLoadingPrincipal = mLoadingPrincipal);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsIPrincipal*
|
||||
LoadInfo::LoadingPrincipal()
|
||||
{
|
||||
return mLoadingPrincipal;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetTriggeringPrincipal(nsIPrincipal** aTriggeringPrincipal)
|
||||
{
|
||||
NS_ADDREF(*aTriggeringPrincipal = mTriggeringPrincipal);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsIPrincipal*
|
||||
LoadInfo::TriggeringPrincipal()
|
||||
{
|
||||
return mTriggeringPrincipal;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetPrincipalToInherit(nsIPrincipal** aPrincipalToInherit)
|
||||
{
|
||||
NS_IF_ADDREF(*aPrincipalToInherit = mPrincipalToInherit);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::SetPrincipalToInherit(nsIPrincipal* aPrincipalToInherit)
|
||||
{
|
||||
MOZ_ASSERT(aPrincipalToInherit, "must be a valid principal to inherit");
|
||||
mPrincipalToInherit = aPrincipalToInherit;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsIPrincipal*
|
||||
LoadInfo::PrincipalToInherit()
|
||||
{
|
||||
return mPrincipalToInherit;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetLoadingDocument(nsIDOMDocument** aResult)
|
||||
{
|
||||
nsCOMPtr<nsINode> node = do_QueryReferent(mLoadingContext);
|
||||
if (node) {
|
||||
nsCOMPtr<nsIDOMDocument> context = do_QueryInterface(node->OwnerDoc());
|
||||
context.forget(aResult);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsINode*
|
||||
LoadInfo::LoadingNode()
|
||||
{
|
||||
nsCOMPtr<nsINode> node = do_QueryReferent(mLoadingContext);
|
||||
return node;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetSecurityFlags(nsSecurityFlags* aResult)
|
||||
{
|
||||
*aResult = mSecurityFlags;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetSecurityMode(uint32_t* aFlags)
|
||||
{
|
||||
*aFlags = (mSecurityFlags &
|
||||
(nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS |
|
||||
nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED |
|
||||
nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS |
|
||||
nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL |
|
||||
nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetIsInThirdPartyContext(bool* aIsInThirdPartyContext)
|
||||
{
|
||||
*aIsInThirdPartyContext = mIsThirdPartyContext;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static const uint32_t sCookiePolicyMask =
|
||||
nsILoadInfo::SEC_COOKIES_DEFAULT |
|
||||
nsILoadInfo::SEC_COOKIES_INCLUDE |
|
||||
nsILoadInfo::SEC_COOKIES_SAME_ORIGIN |
|
||||
nsILoadInfo::SEC_COOKIES_OMIT;
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetCookiePolicy(uint32_t *aResult)
|
||||
{
|
||||
uint32_t policy = mSecurityFlags & sCookiePolicyMask;
|
||||
if (policy == nsILoadInfo::SEC_COOKIES_DEFAULT) {
|
||||
policy = (mSecurityFlags & SEC_REQUIRE_CORS_DATA_INHERITS) ?
|
||||
nsILoadInfo::SEC_COOKIES_SAME_ORIGIN : nsILoadInfo::SEC_COOKIES_INCLUDE;
|
||||
}
|
||||
|
||||
*aResult = policy;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
LoadInfo::SetIncludeCookiesSecFlag()
|
||||
{
|
||||
MOZ_ASSERT(!mEnforceSecurity,
|
||||
"Request should not have been opened yet");
|
||||
MOZ_ASSERT((mSecurityFlags & sCookiePolicyMask) ==
|
||||
nsILoadInfo::SEC_COOKIES_DEFAULT);
|
||||
mSecurityFlags = (mSecurityFlags & ~sCookiePolicyMask) |
|
||||
nsILoadInfo::SEC_COOKIES_INCLUDE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetForceInheritPrincipal(bool* aInheritPrincipal)
|
||||
{
|
||||
*aInheritPrincipal =
|
||||
(mSecurityFlags & nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetForceInheritPrincipalOverruleOwner(bool* aInheritPrincipal)
|
||||
{
|
||||
*aInheritPrincipal =
|
||||
(mSecurityFlags & nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL_OVERRULE_OWNER);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetLoadingSandboxed(bool* aLoadingSandboxed)
|
||||
{
|
||||
*aLoadingSandboxed = (mSecurityFlags & nsILoadInfo::SEC_SANDBOXED);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetAboutBlankInherits(bool* aResult)
|
||||
{
|
||||
*aResult =
|
||||
(mSecurityFlags & nsILoadInfo::SEC_ABOUT_BLANK_INHERITS);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetAllowChrome(bool* aResult)
|
||||
{
|
||||
*aResult =
|
||||
(mSecurityFlags & nsILoadInfo::SEC_ALLOW_CHROME);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetDisallowScript(bool* aResult)
|
||||
{
|
||||
*aResult =
|
||||
(mSecurityFlags & nsILoadInfo::SEC_DISALLOW_SCRIPT);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetDontFollowRedirects(bool* aResult)
|
||||
{
|
||||
*aResult =
|
||||
(mSecurityFlags & nsILoadInfo::SEC_DONT_FOLLOW_REDIRECTS);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetLoadErrorPage(bool* aResult)
|
||||
{
|
||||
*aResult =
|
||||
(mSecurityFlags & nsILoadInfo::SEC_LOAD_ERROR_PAGE);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetExternalContentPolicyType(nsContentPolicyType* aResult)
|
||||
{
|
||||
*aResult = nsContentUtils::InternalContentPolicyTypeToExternal(mInternalContentPolicyType);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsContentPolicyType
|
||||
LoadInfo::InternalContentPolicyType()
|
||||
{
|
||||
return mInternalContentPolicyType;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetUpgradeInsecureRequests(bool* aResult)
|
||||
{
|
||||
*aResult = mUpgradeInsecureRequests;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::SetVerifySignedContent(bool aVerifySignedContent)
|
||||
{
|
||||
MOZ_ASSERT(mInternalContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT,
|
||||
"can only verify content for TYPE_DOCUMENT");
|
||||
mVerifySignedContent = aVerifySignedContent;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetVerifySignedContent(bool* aResult)
|
||||
{
|
||||
*aResult = mVerifySignedContent;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::SetEnforceSRI(bool aEnforceSRI)
|
||||
{
|
||||
mEnforceSRI = aEnforceSRI;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetEnforceSRI(bool* aResult)
|
||||
{
|
||||
*aResult = mEnforceSRI;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetForceInheritPrincipalDropped(bool* aResult)
|
||||
{
|
||||
*aResult = mForceInheritPrincipalDropped;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetInnerWindowID(uint64_t* aResult)
|
||||
{
|
||||
*aResult = mInnerWindowID;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetOuterWindowID(uint64_t* aResult)
|
||||
{
|
||||
*aResult = mOuterWindowID;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetParentOuterWindowID(uint64_t* aResult)
|
||||
{
|
||||
*aResult = mParentOuterWindowID;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetFrameOuterWindowID(uint64_t* aResult)
|
||||
{
|
||||
*aResult = mFrameOuterWindowID;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetScriptableOriginAttributes(JSContext* aCx,
|
||||
JS::MutableHandle<JS::Value> aOriginAttributes)
|
||||
{
|
||||
if (NS_WARN_IF(!ToJSValue(aCx, mOriginAttributes, aOriginAttributes))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::ResetPrincipalsToNullPrincipal()
|
||||
{
|
||||
// take the originAttributes from the LoadInfo and create
|
||||
// a new NullPrincipal using those origin attributes.
|
||||
PrincipalOriginAttributes pAttrs;
|
||||
pAttrs.InheritFromNecko(mOriginAttributes);
|
||||
nsCOMPtr<nsIPrincipal> newNullPrincipal = nsNullPrincipal::Create(pAttrs);
|
||||
|
||||
MOZ_ASSERT(mInternalContentPolicyType != nsIContentPolicy::TYPE_DOCUMENT ||
|
||||
!mLoadingPrincipal,
|
||||
"LoadingPrincipal should be null for toplevel loads");
|
||||
|
||||
// the loadingPrincipal for toplevel loads is always a nullptr;
|
||||
if (mInternalContentPolicyType != nsIContentPolicy::TYPE_DOCUMENT) {
|
||||
mLoadingPrincipal = newNullPrincipal;
|
||||
}
|
||||
mTriggeringPrincipal = newNullPrincipal;
|
||||
mPrincipalToInherit = newNullPrincipal;
|
||||
|
||||
// setting SEC_FORCE_INHERIT_PRINCIPAL_OVERRULE_OWNER will overrule
|
||||
// any non null owner set on the channel and will return the principal
|
||||
// form the loadinfo instead.
|
||||
mSecurityFlags |= SEC_FORCE_INHERIT_PRINCIPAL_OVERRULE_OWNER;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::SetScriptableOriginAttributes(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aOriginAttributes)
|
||||
{
|
||||
NeckoOriginAttributes attrs;
|
||||
if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
mOriginAttributes = attrs;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
LoadInfo::GetOriginAttributes(mozilla::NeckoOriginAttributes* aOriginAttributes)
|
||||
{
|
||||
NS_ENSURE_ARG(aOriginAttributes);
|
||||
*aOriginAttributes = mOriginAttributes;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
LoadInfo::SetOriginAttributes(const mozilla::NeckoOriginAttributes& aOriginAttributes)
|
||||
{
|
||||
mOriginAttributes = aOriginAttributes;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::SetEnforceSecurity(bool aEnforceSecurity)
|
||||
{
|
||||
// Indicates whether the channel was openend using AsyncOpen2. Once set
|
||||
// to true, it must remain true throughout the lifetime of the channel.
|
||||
// Setting it to anything else than true will be discarded.
|
||||
MOZ_ASSERT(aEnforceSecurity, "aEnforceSecurity must be true");
|
||||
mEnforceSecurity = mEnforceSecurity || aEnforceSecurity;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetEnforceSecurity(bool* aResult)
|
||||
{
|
||||
*aResult = mEnforceSecurity;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::SetInitialSecurityCheckDone(bool aInitialSecurityCheckDone)
|
||||
{
|
||||
// Indicates whether the channel was ever evaluated by the
|
||||
// ContentSecurityManager. Once set to true, this flag must
|
||||
// remain true throughout the lifetime of the channel.
|
||||
// Setting it to anything else than true will be discarded.
|
||||
MOZ_ASSERT(aInitialSecurityCheckDone, "aInitialSecurityCheckDone must be true");
|
||||
mInitialSecurityCheckDone = mInitialSecurityCheckDone || aInitialSecurityCheckDone;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetInitialSecurityCheckDone(bool* aResult)
|
||||
{
|
||||
*aResult = mInitialSecurityCheckDone;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::AppendRedirectedPrincipal(nsIPrincipal* aPrincipal, bool aIsInternalRedirect)
|
||||
{
|
||||
NS_ENSURE_ARG(aPrincipal);
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
mRedirectChainIncludingInternalRedirects.AppendElement(aPrincipal);
|
||||
if (!aIsInternalRedirect) {
|
||||
mRedirectChain.AppendElement(aPrincipal);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetRedirectChainIncludingInternalRedirects(JSContext* aCx, JS::MutableHandle<JS::Value> aChain)
|
||||
{
|
||||
if (!ToJSValue(aCx, mRedirectChainIncludingInternalRedirects, aChain)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
const nsTArray<nsCOMPtr<nsIPrincipal>>&
|
||||
LoadInfo::RedirectChainIncludingInternalRedirects()
|
||||
{
|
||||
return mRedirectChainIncludingInternalRedirects;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetRedirectChain(JSContext* aCx, JS::MutableHandle<JS::Value> aChain)
|
||||
{
|
||||
if (!ToJSValue(aCx, mRedirectChain, aChain)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
const nsTArray<nsCOMPtr<nsIPrincipal>>&
|
||||
LoadInfo::RedirectChain()
|
||||
{
|
||||
return mRedirectChain;
|
||||
}
|
||||
|
||||
void
|
||||
LoadInfo::SetCorsPreflightInfo(const nsTArray<nsCString>& aHeaders,
|
||||
bool aForcePreflight)
|
||||
{
|
||||
MOZ_ASSERT(GetSecurityMode() == nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS);
|
||||
MOZ_ASSERT(!mInitialSecurityCheckDone);
|
||||
mCorsUnsafeHeaders = aHeaders;
|
||||
mForcePreflight = aForcePreflight;
|
||||
}
|
||||
|
||||
const nsTArray<nsCString>&
|
||||
LoadInfo::CorsUnsafeHeaders()
|
||||
{
|
||||
return mCorsUnsafeHeaders;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetForcePreflight(bool* aForcePreflight)
|
||||
{
|
||||
*aForcePreflight = mForcePreflight;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
LoadInfo::SetIsPreflight()
|
||||
{
|
||||
MOZ_ASSERT(GetSecurityMode() == nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS);
|
||||
MOZ_ASSERT(!mInitialSecurityCheckDone);
|
||||
mIsPreflight = true;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetIsPreflight(bool* aIsPreflight)
|
||||
{
|
||||
*aIsPreflight = mIsPreflight;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetForceHSTSPriming(bool* aForceHSTSPriming)
|
||||
{
|
||||
*aForceHSTSPriming = mForceHSTSPriming;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetMixedContentWouldBlock(bool *aMixedContentWouldBlock)
|
||||
{
|
||||
*aMixedContentWouldBlock = mMixedContentWouldBlock;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
LoadInfo::SetHSTSPriming(bool aMixedContentWouldBlock)
|
||||
{
|
||||
mForceHSTSPriming = true;
|
||||
mMixedContentWouldBlock = aMixedContentWouldBlock;
|
||||
}
|
||||
|
||||
void
|
||||
LoadInfo::ClearHSTSPriming()
|
||||
{
|
||||
mForceHSTSPriming = false;
|
||||
mMixedContentWouldBlock = false;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetTainting(uint32_t* aTaintingOut)
|
||||
{
|
||||
MOZ_ASSERT(aTaintingOut);
|
||||
*aTaintingOut = static_cast<uint32_t>(mTainting);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::MaybeIncreaseTainting(uint32_t aTainting)
|
||||
{
|
||||
NS_ENSURE_ARG(aTainting <= TAINTING_OPAQUE);
|
||||
LoadTainting tainting = static_cast<LoadTainting>(aTainting);
|
||||
if (tainting > mTainting) {
|
||||
mTainting = tainting;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetIsTopLevelLoad(bool *aResult)
|
||||
{
|
||||
*aResult = mFrameOuterWindowID ? mFrameOuterWindowID == mOuterWindowID
|
||||
: mParentOuterWindowID == mOuterWindowID;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
163
netwerk/base/LoadInfo.h
Normal file
163
netwerk/base/LoadInfo.h
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_LoadInfo_h
|
||||
#define mozilla_LoadInfo_h
|
||||
|
||||
#include "nsIContentPolicy.h"
|
||||
#include "nsILoadInfo.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsIWeakReferenceUtils.h" // for nsWeakPtr
|
||||
#include "nsIURI.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
#include "mozilla/BasePrincipal.h"
|
||||
|
||||
class nsINode;
|
||||
class nsPIDOMWindowOuter;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace dom {
|
||||
class XMLHttpRequestMainThread;
|
||||
}
|
||||
|
||||
namespace net {
|
||||
class OptionalLoadInfoArgs;
|
||||
} // namespace net
|
||||
|
||||
namespace ipc {
|
||||
// we have to forward declare that function so we can use it as a friend.
|
||||
nsresult
|
||||
LoadInfoArgsToLoadInfo(const mozilla::net::OptionalLoadInfoArgs& aLoadInfoArgs,
|
||||
nsILoadInfo** outLoadInfo);
|
||||
} // namespace ipc
|
||||
|
||||
namespace net {
|
||||
|
||||
/**
|
||||
* Class that provides an nsILoadInfo implementation.
|
||||
*
|
||||
* Note that there is no reason why this class should be MOZ_EXPORT, but
|
||||
* Thunderbird relies on some insane hacks which require this, so we'll leave it
|
||||
* as is for now, but hopefully we'll be able to remove the MOZ_EXPORT keyword
|
||||
* from this class at some point. See bug 1149127 for the discussion.
|
||||
*/
|
||||
class MOZ_EXPORT LoadInfo final : public nsILoadInfo
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSILOADINFO
|
||||
|
||||
// aLoadingPrincipal MUST NOT BE NULL.
|
||||
LoadInfo(nsIPrincipal* aLoadingPrincipal,
|
||||
nsIPrincipal* aTriggeringPrincipal,
|
||||
nsINode* aLoadingContext,
|
||||
nsSecurityFlags aSecurityFlags,
|
||||
nsContentPolicyType aContentPolicyType);
|
||||
|
||||
// Constructor used for TYPE_DOCUMENT loads which have no reasonable
|
||||
// loadingNode or loadingPrincipal
|
||||
LoadInfo(nsPIDOMWindowOuter* aOuterWindow,
|
||||
nsIPrincipal* aTriggeringPrincipal,
|
||||
nsSecurityFlags aSecurityFlags);
|
||||
|
||||
// create an exact copy of the loadinfo
|
||||
already_AddRefed<nsILoadInfo> Clone() const;
|
||||
// hands off!!! don't use CloneWithNewSecFlags unless you know
|
||||
// exactly what you are doing - it should only be used within
|
||||
// nsBaseChannel::Redirect()
|
||||
already_AddRefed<nsILoadInfo>
|
||||
CloneWithNewSecFlags(nsSecurityFlags aSecurityFlags) const;
|
||||
// creates a copy of the loadinfo which is appropriate to use for a
|
||||
// separate request. I.e. not for a redirect or an inner channel, but
|
||||
// when a separate request is made with the same security properties.
|
||||
already_AddRefed<nsILoadInfo> CloneForNewRequest() const;
|
||||
|
||||
void SetIsPreflight();
|
||||
|
||||
private:
|
||||
// private constructor that is only allowed to be called from within
|
||||
// HttpChannelParent and FTPChannelParent declared as friends undeneath.
|
||||
// In e10s we can not serialize nsINode, hence we store the innerWindowID.
|
||||
// Please note that aRedirectChain uses swapElements.
|
||||
LoadInfo(nsIPrincipal* aLoadingPrincipal,
|
||||
nsIPrincipal* aTriggeringPrincipal,
|
||||
nsIPrincipal* aPrincipalToInherit,
|
||||
nsSecurityFlags aSecurityFlags,
|
||||
nsContentPolicyType aContentPolicyType,
|
||||
LoadTainting aTainting,
|
||||
bool aUpgradeInsecureRequests,
|
||||
bool aVerifySignedContent,
|
||||
bool aEnforceSRI,
|
||||
bool aForceInheritPrincipalDropped,
|
||||
uint64_t aInnerWindowID,
|
||||
uint64_t aOuterWindowID,
|
||||
uint64_t aParentOuterWindowID,
|
||||
uint64_t aFrameOuterWindowID,
|
||||
bool aEnforceSecurity,
|
||||
bool aInitialSecurityCheckDone,
|
||||
bool aIsThirdPartyRequest,
|
||||
const NeckoOriginAttributes& aOriginAttributes,
|
||||
nsTArray<nsCOMPtr<nsIPrincipal>>& aRedirectChainIncludingInternalRedirects,
|
||||
nsTArray<nsCOMPtr<nsIPrincipal>>& aRedirectChain,
|
||||
const nsTArray<nsCString>& aUnsafeHeaders,
|
||||
bool aForcePreflight,
|
||||
bool aIsPreflight,
|
||||
bool aForceHSTSPriming,
|
||||
bool aMixedContentWouldBlock);
|
||||
LoadInfo(const LoadInfo& rhs);
|
||||
|
||||
friend nsresult
|
||||
mozilla::ipc::LoadInfoArgsToLoadInfo(
|
||||
const mozilla::net::OptionalLoadInfoArgs& aLoadInfoArgs,
|
||||
nsILoadInfo** outLoadInfo);
|
||||
|
||||
~LoadInfo();
|
||||
|
||||
void ComputeIsThirdPartyContext(nsPIDOMWindowOuter* aOuterWindow);
|
||||
|
||||
// This function is the *only* function which can change the securityflags
|
||||
// of a loadinfo. It only exists because of the XHR code. Don't call it
|
||||
// from anywhere else!
|
||||
void SetIncludeCookiesSecFlag();
|
||||
friend class mozilla::dom::XMLHttpRequestMainThread;
|
||||
|
||||
// if you add a member, please also update the copy constructor
|
||||
nsCOMPtr<nsIPrincipal> mLoadingPrincipal;
|
||||
nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
|
||||
nsCOMPtr<nsIPrincipal> mPrincipalToInherit;
|
||||
nsWeakPtr mLoadingContext;
|
||||
nsSecurityFlags mSecurityFlags;
|
||||
nsContentPolicyType mInternalContentPolicyType;
|
||||
LoadTainting mTainting;
|
||||
bool mUpgradeInsecureRequests;
|
||||
bool mVerifySignedContent;
|
||||
bool mEnforceSRI;
|
||||
bool mForceInheritPrincipalDropped;
|
||||
uint64_t mInnerWindowID;
|
||||
uint64_t mOuterWindowID;
|
||||
uint64_t mParentOuterWindowID;
|
||||
uint64_t mFrameOuterWindowID;
|
||||
bool mEnforceSecurity;
|
||||
bool mInitialSecurityCheckDone;
|
||||
bool mIsThirdPartyContext;
|
||||
NeckoOriginAttributes mOriginAttributes;
|
||||
nsTArray<nsCOMPtr<nsIPrincipal>> mRedirectChainIncludingInternalRedirects;
|
||||
nsTArray<nsCOMPtr<nsIPrincipal>> mRedirectChain;
|
||||
nsTArray<nsCString> mCorsUnsafeHeaders;
|
||||
bool mForcePreflight;
|
||||
bool mIsPreflight;
|
||||
|
||||
bool mForceHSTSPriming : 1;
|
||||
bool mMixedContentWouldBlock : 1;
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_LoadInfo_h
|
||||
|
||||
43
netwerk/base/LoadTainting.h
Normal file
43
netwerk/base/LoadTainting.h
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_LoadTainting_h
|
||||
#define mozilla_LoadTainting_h
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// Define an enumeration to reflect the concept of response tainting from the
|
||||
// the fetch spec:
|
||||
//
|
||||
// https://fetch.spec.whatwg.org/#concept-request-response-tainting
|
||||
//
|
||||
// Roughly the tainting means:
|
||||
//
|
||||
// * Basic: the request resulted in a same-origin or non-http load
|
||||
// * CORS: the request resulted in a cross-origin load with CORS headers
|
||||
// * Opaque: the request resulted in a cross-origin load without CORS headers
|
||||
//
|
||||
// The enumeration is purposefully designed such that more restrictive tainting
|
||||
// corresponds to a higher integral value.
|
||||
//
|
||||
// NOTE: Checking the tainting is not currently adequate. You *must* still
|
||||
// check the final URL and CORS mode on the channel.
|
||||
//
|
||||
// These values are currently only set on the channel LoadInfo when the request
|
||||
// was initiated through fetch() or when a service worker interception occurs.
|
||||
// In the future we should set the tainting value within necko so that it is
|
||||
// consistently applied. Once that is done consumers can replace checks against
|
||||
// the final URL and CORS mode with checks against tainting.
|
||||
enum class LoadTainting : uint8_t
|
||||
{
|
||||
Basic = 0,
|
||||
CORS = 1,
|
||||
Opaque = 2
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_LoadTainting_h
|
||||
92
netwerk/base/MemoryDownloader.cpp
Normal file
92
netwerk/base/MemoryDownloader.cpp
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
/* -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "MemoryDownloader.h"
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "nsIInputStream.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
NS_IMPL_ISUPPORTS(MemoryDownloader,
|
||||
nsIStreamListener,
|
||||
nsIRequestObserver)
|
||||
|
||||
MemoryDownloader::MemoryDownloader(IObserver* aObserver)
|
||||
: mObserver(aObserver)
|
||||
{
|
||||
}
|
||||
|
||||
MemoryDownloader::~MemoryDownloader()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MemoryDownloader::OnStartRequest(nsIRequest* aRequest, nsISupports* aCtxt)
|
||||
{
|
||||
MOZ_ASSERT(!mData);
|
||||
mData.reset(new FallibleTArray<uint8_t>());
|
||||
mStatus = NS_OK;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MemoryDownloader::OnStopRequest(nsIRequest* aRequest,
|
||||
nsISupports* aCtxt,
|
||||
nsresult aStatus)
|
||||
{
|
||||
MOZ_ASSERT_IF(NS_FAILED(mStatus), NS_FAILED(aStatus));
|
||||
MOZ_ASSERT(!mData == NS_FAILED(mStatus));
|
||||
Data data;
|
||||
data.swap(mData);
|
||||
RefPtr<IObserver> observer;
|
||||
observer.swap(mObserver);
|
||||
observer->OnDownloadComplete(this, aRequest, aCtxt, aStatus,
|
||||
mozilla::Move(data));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
MemoryDownloader::ConsumeData(nsIInputStream* aIn,
|
||||
void* aClosure,
|
||||
const char* aFromRawSegment,
|
||||
uint32_t aToOffset,
|
||||
uint32_t aCount,
|
||||
uint32_t* aWriteCount)
|
||||
{
|
||||
MemoryDownloader* self = static_cast<MemoryDownloader*>(aClosure);
|
||||
if (!self->mData->AppendElements(aFromRawSegment, aCount, fallible)) {
|
||||
// The error returned by ConsumeData isn't propagated to the
|
||||
// return of ReadSegments, so it has to be passed as state.
|
||||
self->mStatus = NS_ERROR_OUT_OF_MEMORY;
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
*aWriteCount = aCount;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MemoryDownloader::OnDataAvailable(nsIRequest* aRequest,
|
||||
nsISupports* aCtxt,
|
||||
nsIInputStream* aInStr,
|
||||
uint64_t aSourceOffset,
|
||||
uint32_t aCount)
|
||||
{
|
||||
uint32_t n;
|
||||
MOZ_ASSERT(mData);
|
||||
nsresult rv = aInStr->ReadSegments(ConsumeData, this, aCount, &n);
|
||||
if (NS_SUCCEEDED(mStatus) && NS_FAILED(rv)) {
|
||||
mStatus = rv;
|
||||
}
|
||||
if (NS_WARN_IF(NS_FAILED(mStatus))) {
|
||||
mData.reset(nullptr);
|
||||
return mStatus;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
65
netwerk/base/MemoryDownloader.h
Normal file
65
netwerk/base/MemoryDownloader.h
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
/* -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_net_MemoryDownloader_h__
|
||||
#define mozilla_net_MemoryDownloader_h__
|
||||
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIStreamListener.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
/**
|
||||
* mozilla::net::MemoryDownloader
|
||||
*
|
||||
* This class is similar to nsIDownloader, but stores the downloaded
|
||||
* stream in memory instead of a file. Ownership of the temporary
|
||||
* memory is transferred to the observer when download is complete;
|
||||
* there is no need to retain a reference to the downloader.
|
||||
*/
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
class MemoryDownloader final : public nsIStreamListener
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
NS_DECL_NSISTREAMLISTENER
|
||||
|
||||
typedef mozilla::UniquePtr<FallibleTArray<uint8_t>> Data;
|
||||
|
||||
class IObserver : public nsISupports {
|
||||
public:
|
||||
// Note: aData may be null if (and only if) aStatus indicates failure.
|
||||
virtual void OnDownloadComplete(MemoryDownloader* aDownloader,
|
||||
nsIRequest* aRequest,
|
||||
nsISupports* aCtxt,
|
||||
nsresult aStatus,
|
||||
Data aData) = 0;
|
||||
};
|
||||
|
||||
explicit MemoryDownloader(IObserver* aObserver);
|
||||
|
||||
private:
|
||||
virtual ~MemoryDownloader();
|
||||
|
||||
static nsresult ConsumeData(nsIInputStream *in,
|
||||
void *closure,
|
||||
const char *fromRawSegment,
|
||||
uint32_t toOffset,
|
||||
uint32_t count,
|
||||
uint32_t *writeCount);
|
||||
|
||||
RefPtr<IObserver> mObserver;
|
||||
Data mData;
|
||||
nsresult mStatus;
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_net_MemoryDownloader_h__
|
||||
100
netwerk/base/NetStatistics.h
Normal file
100
netwerk/base/NetStatistics.h
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim:set ts=4 sw=4 sts=4 et cin: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef NetStatistics_h__
|
||||
#define NetStatistics_h__
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsError.h"
|
||||
#include "nsINetworkInterface.h"
|
||||
#include "nsINetworkManager.h"
|
||||
#include "nsINetworkStatsServiceProxy.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsProxyRelease.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
// The following members are used for network per-app metering.
|
||||
const static uint64_t NETWORK_STATS_THRESHOLD = 65536;
|
||||
const static char NETWORK_STATS_NO_SERVICE_TYPE[] = "";
|
||||
|
||||
inline nsresult
|
||||
GetActiveNetworkInfo(nsCOMPtr<nsINetworkInfo> &aNetworkInfo)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsINetworkManager> networkManager =
|
||||
do_GetService("@mozilla.org/network/manager;1", &rv);
|
||||
|
||||
if (NS_FAILED(rv) || !networkManager) {
|
||||
aNetworkInfo = nullptr;
|
||||
return rv;
|
||||
}
|
||||
|
||||
networkManager->GetActiveNetworkInfo(getter_AddRefs(aNetworkInfo));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
class SaveNetworkStatsEvent : public Runnable {
|
||||
public:
|
||||
SaveNetworkStatsEvent(uint32_t aAppId,
|
||||
bool aIsInIsolatedMozBrowser,
|
||||
nsMainThreadPtrHandle<nsINetworkInfo> &aActiveNetworkInfo,
|
||||
uint64_t aCountRecv,
|
||||
uint64_t aCountSent,
|
||||
bool aIsAccumulative)
|
||||
: mAppId(aAppId),
|
||||
mIsInIsolatedMozBrowser(aIsInIsolatedMozBrowser),
|
||||
mActiveNetworkInfo(aActiveNetworkInfo),
|
||||
mCountRecv(aCountRecv),
|
||||
mCountSent(aCountSent),
|
||||
mIsAccumulative(aIsAccumulative)
|
||||
{
|
||||
MOZ_ASSERT(mAppId != NECKO_NO_APP_ID);
|
||||
MOZ_ASSERT(mActiveNetworkInfo);
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsINetworkStatsServiceProxy> mNetworkStatsServiceProxy =
|
||||
do_GetService("@mozilla.org/networkstatsServiceProxy;1", &rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// save the network stats through NetworkStatsServiceProxy
|
||||
mNetworkStatsServiceProxy->SaveAppStats(mAppId,
|
||||
mIsInIsolatedMozBrowser,
|
||||
mActiveNetworkInfo,
|
||||
PR_Now() / 1000,
|
||||
mCountRecv,
|
||||
mCountSent,
|
||||
mIsAccumulative,
|
||||
nullptr);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
private:
|
||||
uint32_t mAppId;
|
||||
bool mIsInIsolatedMozBrowser;
|
||||
nsMainThreadPtrHandle<nsINetworkInfo> mActiveNetworkInfo;
|
||||
uint64_t mCountRecv;
|
||||
uint64_t mCountSent;
|
||||
bool mIsAccumulative;
|
||||
};
|
||||
|
||||
} // namespace mozilla:net
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // !NetStatistics_h__
|
||||
461
netwerk/base/NetUtil.jsm
Normal file
461
netwerk/base/NetUtil.jsm
Normal file
|
|
@ -0,0 +1,461 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 4 -*-
|
||||
* vim: sw=4 ts=4 sts=4 et filetype=javascript
|
||||
* 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/. */
|
||||
|
||||
this.EXPORTED_SYMBOLS = [
|
||||
"NetUtil",
|
||||
];
|
||||
|
||||
/**
|
||||
* Necko utilities
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Constants
|
||||
|
||||
const Ci = Components.interfaces;
|
||||
const Cc = Components.classes;
|
||||
const Cr = Components.results;
|
||||
const Cu = Components.utils;
|
||||
|
||||
const PR_UINT32_MAX = 0xffffffff;
|
||||
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// NetUtil Object
|
||||
|
||||
this.NetUtil = {
|
||||
/**
|
||||
* Function to perform simple async copying from aSource (an input stream)
|
||||
* to aSink (an output stream). The copy will happen on some background
|
||||
* thread. Both streams will be closed when the copy completes.
|
||||
*
|
||||
* @param aSource
|
||||
* The input stream to read from
|
||||
* @param aSink
|
||||
* The output stream to write to
|
||||
* @param aCallback [optional]
|
||||
* A function that will be called at copy completion with a single
|
||||
* argument: the nsresult status code for the copy operation.
|
||||
*
|
||||
* @return An nsIRequest representing the copy operation (for example, this
|
||||
* can be used to cancel the copying). The consumer can ignore the
|
||||
* return value if desired.
|
||||
*/
|
||||
asyncCopy: function NetUtil_asyncCopy(aSource, aSink,
|
||||
aCallback = null)
|
||||
{
|
||||
if (!aSource || !aSink) {
|
||||
let exception = new Components.Exception(
|
||||
"Must have a source and a sink",
|
||||
Cr.NS_ERROR_INVALID_ARG,
|
||||
Components.stack.caller
|
||||
);
|
||||
throw exception;
|
||||
}
|
||||
|
||||
// make a stream copier
|
||||
var copier = Cc["@mozilla.org/network/async-stream-copier;1"].
|
||||
createInstance(Ci.nsIAsyncStreamCopier2);
|
||||
copier.init(aSource, aSink,
|
||||
null /* Default event target */,
|
||||
0 /* Default length */,
|
||||
true, true /* Auto-close */);
|
||||
|
||||
var observer;
|
||||
if (aCallback) {
|
||||
observer = {
|
||||
onStartRequest: function(aRequest, aContext) {},
|
||||
onStopRequest: function(aRequest, aContext, aStatusCode) {
|
||||
aCallback(aStatusCode);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
observer = null;
|
||||
}
|
||||
|
||||
// start the copying
|
||||
copier.QueryInterface(Ci.nsIAsyncStreamCopier).asyncCopy(observer, null);
|
||||
return copier;
|
||||
},
|
||||
|
||||
/**
|
||||
* Asynchronously opens a source and fetches the response. While the fetch
|
||||
* is asynchronous, I/O may happen on the main thread. When reading from
|
||||
* a local file, prefer using "OS.File" methods instead.
|
||||
*
|
||||
* @param aSource
|
||||
* This argument can be one of the following:
|
||||
* - An options object that will be passed to NetUtil.newChannel.
|
||||
* - An existing nsIChannel.
|
||||
* - An existing nsIInputStream.
|
||||
* Using an nsIURI, nsIFile, or string spec directly is deprecated.
|
||||
* @param aCallback
|
||||
* The callback function that will be notified upon completion. It
|
||||
* will get these arguments:
|
||||
* 1) An nsIInputStream containing the data from aSource, if any.
|
||||
* 2) The status code from opening the source.
|
||||
* 3) Reference to the nsIRequest.
|
||||
*/
|
||||
asyncFetch: function NetUtil_asyncFetch(aSource, aCallback)
|
||||
{
|
||||
if (!aSource || !aCallback) {
|
||||
let exception = new Components.Exception(
|
||||
"Must have a source and a callback",
|
||||
Cr.NS_ERROR_INVALID_ARG,
|
||||
Components.stack.caller
|
||||
);
|
||||
throw exception;
|
||||
}
|
||||
|
||||
// Create a pipe that will create our output stream that we can use once
|
||||
// we have gotten all the data.
|
||||
let pipe = Cc["@mozilla.org/pipe;1"].
|
||||
createInstance(Ci.nsIPipe);
|
||||
pipe.init(true, true, 0, PR_UINT32_MAX, null);
|
||||
|
||||
// Create a listener that will give data to the pipe's output stream.
|
||||
let listener = Cc["@mozilla.org/network/simple-stream-listener;1"].
|
||||
createInstance(Ci.nsISimpleStreamListener);
|
||||
listener.init(pipe.outputStream, {
|
||||
onStartRequest: function(aRequest, aContext) {},
|
||||
onStopRequest: function(aRequest, aContext, aStatusCode) {
|
||||
pipe.outputStream.close();
|
||||
aCallback(pipe.inputStream, aStatusCode, aRequest);
|
||||
}
|
||||
});
|
||||
|
||||
// Input streams are handled slightly differently from everything else.
|
||||
if (aSource instanceof Ci.nsIInputStream) {
|
||||
let pump = Cc["@mozilla.org/network/input-stream-pump;1"].
|
||||
createInstance(Ci.nsIInputStreamPump);
|
||||
pump.init(aSource, -1, -1, 0, 0, true);
|
||||
pump.asyncRead(listener, null);
|
||||
return;
|
||||
}
|
||||
|
||||
let channel = aSource;
|
||||
if (!(channel instanceof Ci.nsIChannel)) {
|
||||
channel = this.newChannel(aSource);
|
||||
}
|
||||
|
||||
try {
|
||||
// Open the channel using asyncOpen2() if the loadinfo contains one
|
||||
// of the security mode flags, otherwise fall back to use asyncOpen().
|
||||
if (channel.loadInfo &&
|
||||
channel.loadInfo.securityMode != 0) {
|
||||
channel.asyncOpen2(listener);
|
||||
}
|
||||
else {
|
||||
// Log deprecation warning to console to make sure all channels
|
||||
// are created providing the correct security flags in the loadinfo.
|
||||
// See nsILoadInfo for all available security flags and also the API
|
||||
// of NetUtil.newChannel() for details above.
|
||||
Cu.reportError("NetUtil.jsm: asyncFetch() requires the channel to have " +
|
||||
"one of the security flags set in the loadinfo (see nsILoadInfo). " +
|
||||
"Please create channel using NetUtil.newChannel()");
|
||||
channel.asyncOpen(listener, null);
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
let exception = new Components.Exception(
|
||||
"Failed to open input source '" + channel.originalURI.spec + "'",
|
||||
e.result,
|
||||
Components.stack.caller,
|
||||
aSource,
|
||||
e
|
||||
);
|
||||
throw exception;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Constructs a new URI for the given spec, character set, and base URI, or
|
||||
* an nsIFile.
|
||||
*
|
||||
* @param aTarget
|
||||
* The string spec for the desired URI or an nsIFile.
|
||||
* @param aOriginCharset [optional]
|
||||
* The character set for the URI. Only used if aTarget is not an
|
||||
* nsIFile.
|
||||
* @param aBaseURI [optional]
|
||||
* The base URI for the spec. Only used if aTarget is not an
|
||||
* nsIFile.
|
||||
*
|
||||
* @return an nsIURI object.
|
||||
*/
|
||||
newURI: function NetUtil_newURI(aTarget, aOriginCharset, aBaseURI)
|
||||
{
|
||||
if (!aTarget) {
|
||||
let exception = new Components.Exception(
|
||||
"Must have a non-null string spec or nsIFile object",
|
||||
Cr.NS_ERROR_INVALID_ARG,
|
||||
Components.stack.caller
|
||||
);
|
||||
throw exception;
|
||||
}
|
||||
|
||||
if (aTarget instanceof Ci.nsIFile) {
|
||||
return this.ioService.newFileURI(aTarget);
|
||||
}
|
||||
|
||||
return this.ioService.newURI(aTarget, aOriginCharset, aBaseURI);
|
||||
},
|
||||
|
||||
/**
|
||||
* Constructs a new channel for the given source.
|
||||
*
|
||||
* Keep in mind that URIs coming from a webpage should *never* use the
|
||||
* systemPrincipal as the loadingPrincipal.
|
||||
*
|
||||
* @param aWhatToLoad
|
||||
* This argument used to be a string spec for the desired URI, an
|
||||
* nsIURI, or an nsIFile. Now it should be an options object with
|
||||
* the following properties:
|
||||
* {
|
||||
* uri:
|
||||
* The full URI spec string, nsIURI or nsIFile to create the
|
||||
* channel for.
|
||||
* Note that this cannot be an nsIFile if you have to specify a
|
||||
* non-default charset or base URI. Call NetUtil.newURI first if
|
||||
* you need to construct an URI using those options.
|
||||
* loadingNode:
|
||||
* loadingPrincipal:
|
||||
* triggeringPrincipal:
|
||||
* securityFlags:
|
||||
* contentPolicyType:
|
||||
* These will be used as values for the nsILoadInfo object on the
|
||||
* created channel. For details, see nsILoadInfo in nsILoadInfo.idl
|
||||
* loadUsingSystemPrincipal:
|
||||
* Set this to true to use the system principal as
|
||||
* loadingPrincipal. This must be omitted if loadingPrincipal or
|
||||
* loadingNode are present.
|
||||
* This should be used with care as it skips security checks.
|
||||
* }
|
||||
* @param aOriginCharset [deprecated]
|
||||
* The character set for the URI. Only used if aWhatToLoad is a
|
||||
* string, which is a deprecated API. Must be undefined otherwise.
|
||||
* Use NetUtil.newURI if you need to use this option.
|
||||
* @param aBaseURI [deprecated]
|
||||
* The base URI for the spec. Only used if aWhatToLoad is a string,
|
||||
* which is a deprecated API. Must be undefined otherwise. Use
|
||||
* NetUtil.newURI if you need to use this option.
|
||||
* @return an nsIChannel object.
|
||||
*/
|
||||
newChannel: function NetUtil_newChannel(aWhatToLoad, aOriginCharset, aBaseURI)
|
||||
{
|
||||
// Check for the deprecated API first.
|
||||
if (typeof aWhatToLoad == "string" ||
|
||||
(aWhatToLoad instanceof Ci.nsIFile) ||
|
||||
(aWhatToLoad instanceof Ci.nsIURI)) {
|
||||
|
||||
let uri = (aWhatToLoad instanceof Ci.nsIURI)
|
||||
? aWhatToLoad
|
||||
: this.newURI(aWhatToLoad, aOriginCharset, aBaseURI);
|
||||
|
||||
// log deprecation warning for developers.
|
||||
Services.console.logStringMessage(
|
||||
"Warning: NetUtil.newChannel(uri) deprecated, please provide argument 'aWhatToLoad'");
|
||||
|
||||
// Provide default loadinfo arguments and call the new API.
|
||||
let systemPrincipal =
|
||||
Services.scriptSecurityManager.getSystemPrincipal();
|
||||
|
||||
return this.ioService.newChannelFromURI2(
|
||||
uri,
|
||||
null, // loadingNode
|
||||
systemPrincipal, // loadingPrincipal
|
||||
null, // triggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
|
||||
Ci.nsIContentPolicy.TYPE_OTHER);
|
||||
}
|
||||
|
||||
// We are using the updated API, that requires only the options object.
|
||||
if (typeof aWhatToLoad != "object" ||
|
||||
aOriginCharset !== undefined ||
|
||||
aBaseURI !== undefined) {
|
||||
throw new Components.Exception(
|
||||
"newChannel requires a single object argument",
|
||||
Cr.NS_ERROR_INVALID_ARG,
|
||||
Components.stack.caller
|
||||
);
|
||||
}
|
||||
|
||||
let { uri,
|
||||
loadingNode,
|
||||
loadingPrincipal,
|
||||
loadUsingSystemPrincipal,
|
||||
triggeringPrincipal,
|
||||
securityFlags,
|
||||
contentPolicyType } = aWhatToLoad;
|
||||
|
||||
if (!uri) {
|
||||
throw new Components.Exception(
|
||||
"newChannel requires the 'uri' property on the options object.",
|
||||
Cr.NS_ERROR_INVALID_ARG,
|
||||
Components.stack.caller
|
||||
);
|
||||
}
|
||||
|
||||
if (typeof uri == "string" || uri instanceof Ci.nsIFile) {
|
||||
uri = this.newURI(uri);
|
||||
}
|
||||
|
||||
if (!loadingNode && !loadingPrincipal && !loadUsingSystemPrincipal) {
|
||||
throw new Components.Exception(
|
||||
"newChannel requires at least one of the 'loadingNode'," +
|
||||
" 'loadingPrincipal', or 'loadUsingSystemPrincipal'" +
|
||||
" properties on the options object.",
|
||||
Cr.NS_ERROR_INVALID_ARG,
|
||||
Components.stack.caller
|
||||
);
|
||||
}
|
||||
|
||||
if (loadUsingSystemPrincipal === true) {
|
||||
if (loadingNode || loadingPrincipal) {
|
||||
throw new Components.Exception(
|
||||
"newChannel does not accept 'loadUsingSystemPrincipal'" +
|
||||
" if the 'loadingNode' or 'loadingPrincipal' properties" +
|
||||
" are present on the options object.",
|
||||
Cr.NS_ERROR_INVALID_ARG,
|
||||
Components.stack.caller
|
||||
);
|
||||
}
|
||||
loadingPrincipal = Services.scriptSecurityManager
|
||||
.getSystemPrincipal();
|
||||
} else if (loadUsingSystemPrincipal !== undefined) {
|
||||
throw new Components.Exception(
|
||||
"newChannel requires the 'loadUsingSystemPrincipal'" +
|
||||
" property on the options object to be 'true' or 'undefined'.",
|
||||
Cr.NS_ERROR_INVALID_ARG,
|
||||
Components.stack.caller
|
||||
);
|
||||
}
|
||||
|
||||
if (securityFlags === undefined) {
|
||||
securityFlags = loadUsingSystemPrincipal
|
||||
? Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL
|
||||
: Ci.nsILoadInfo.SEC_NORMAL;
|
||||
}
|
||||
|
||||
if (contentPolicyType === undefined) {
|
||||
if (!loadUsingSystemPrincipal) {
|
||||
throw new Components.Exception(
|
||||
"newChannel requires the 'contentPolicyType' property on" +
|
||||
" the options object unless loading from system principal.",
|
||||
Cr.NS_ERROR_INVALID_ARG,
|
||||
Components.stack.caller
|
||||
);
|
||||
}
|
||||
contentPolicyType = Ci.nsIContentPolicy.TYPE_OTHER;
|
||||
}
|
||||
|
||||
return this.ioService.newChannelFromURI2(uri,
|
||||
loadingNode || null,
|
||||
loadingPrincipal || null,
|
||||
triggeringPrincipal || null,
|
||||
securityFlags,
|
||||
contentPolicyType);
|
||||
},
|
||||
|
||||
/**
|
||||
* Reads aCount bytes from aInputStream into a string.
|
||||
*
|
||||
* @param aInputStream
|
||||
* The input stream to read from.
|
||||
* @param aCount
|
||||
* The number of bytes to read from the stream.
|
||||
* @param aOptions [optional]
|
||||
* charset
|
||||
* The character encoding of stream data.
|
||||
* replacement
|
||||
* The character to replace unknown byte sequences.
|
||||
* If unset, it causes an exceptions to be thrown.
|
||||
*
|
||||
* @return the bytes from the input stream in string form.
|
||||
*
|
||||
* @throws NS_ERROR_INVALID_ARG if aInputStream is not an nsIInputStream.
|
||||
* @throws NS_BASE_STREAM_WOULD_BLOCK if reading from aInputStream would
|
||||
* block the calling thread (non-blocking mode only).
|
||||
* @throws NS_ERROR_FAILURE if there are not enough bytes available to read
|
||||
* aCount amount of data.
|
||||
* @throws NS_ERROR_ILLEGAL_INPUT if aInputStream has invalid sequences
|
||||
*/
|
||||
readInputStreamToString: function NetUtil_readInputStreamToString(aInputStream,
|
||||
aCount,
|
||||
aOptions)
|
||||
{
|
||||
if (!(aInputStream instanceof Ci.nsIInputStream)) {
|
||||
let exception = new Components.Exception(
|
||||
"First argument should be an nsIInputStream",
|
||||
Cr.NS_ERROR_INVALID_ARG,
|
||||
Components.stack.caller
|
||||
);
|
||||
throw exception;
|
||||
}
|
||||
|
||||
if (!aCount) {
|
||||
let exception = new Components.Exception(
|
||||
"Non-zero amount of bytes must be specified",
|
||||
Cr.NS_ERROR_INVALID_ARG,
|
||||
Components.stack.caller
|
||||
);
|
||||
throw exception;
|
||||
}
|
||||
|
||||
if (aOptions && "charset" in aOptions) {
|
||||
let cis = Cc["@mozilla.org/intl/converter-input-stream;1"].
|
||||
createInstance(Ci.nsIConverterInputStream);
|
||||
try {
|
||||
// When replacement is set, the character that is unknown sequence
|
||||
// replaces with aOptions.replacement character.
|
||||
if (!("replacement" in aOptions)) {
|
||||
// aOptions.replacement isn't set.
|
||||
// If input stream has unknown sequences for aOptions.charset,
|
||||
// throw NS_ERROR_ILLEGAL_INPUT.
|
||||
aOptions.replacement = 0;
|
||||
}
|
||||
|
||||
cis.init(aInputStream, aOptions.charset, aCount,
|
||||
aOptions.replacement);
|
||||
let str = {};
|
||||
cis.readString(-1, str);
|
||||
cis.close();
|
||||
return str.value;
|
||||
}
|
||||
catch (e) {
|
||||
// Adjust the stack so it throws at the caller's location.
|
||||
throw new Components.Exception(e.message, e.result,
|
||||
Components.stack.caller, e.data);
|
||||
}
|
||||
}
|
||||
|
||||
let sis = Cc["@mozilla.org/scriptableinputstream;1"].
|
||||
createInstance(Ci.nsIScriptableInputStream);
|
||||
sis.init(aInputStream);
|
||||
try {
|
||||
return sis.readBytes(aCount);
|
||||
}
|
||||
catch (e) {
|
||||
// Adjust the stack so it throws at the caller's location.
|
||||
throw new Components.Exception(e.message, e.result,
|
||||
Components.stack.caller, e.data);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns a reference to nsIIOService.
|
||||
*
|
||||
* @return a reference to nsIIOService.
|
||||
*/
|
||||
get ioService()
|
||||
{
|
||||
delete this.ioService;
|
||||
return this.ioService = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
},
|
||||
};
|
||||
300
netwerk/base/NetworkActivityMonitor.cpp
Normal file
300
netwerk/base/NetworkActivityMonitor.cpp
Normal file
|
|
@ -0,0 +1,300 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "NetworkActivityMonitor.h"
|
||||
#include "prmem.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsPISocketTransportService.h"
|
||||
#include "nsSocketTransportService2.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "prerror.h"
|
||||
|
||||
using namespace mozilla::net;
|
||||
|
||||
static PRStatus
|
||||
nsNetMon_Connect(PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
|
||||
{
|
||||
PRStatus ret;
|
||||
PRErrorCode code;
|
||||
ret = fd->lower->methods->connect(fd->lower, addr, timeout);
|
||||
if (ret == PR_SUCCESS || (code = PR_GetError()) == PR_WOULD_BLOCK_ERROR ||
|
||||
code == PR_IN_PROGRESS_ERROR)
|
||||
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
nsNetMon_Read(PRFileDesc *fd, void *buf, int32_t len)
|
||||
{
|
||||
int32_t ret;
|
||||
ret = fd->lower->methods->read(fd->lower, buf, len);
|
||||
if (ret >= 0)
|
||||
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kDownload);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
nsNetMon_Write(PRFileDesc *fd, const void *buf, int32_t len)
|
||||
{
|
||||
int32_t ret;
|
||||
ret = fd->lower->methods->write(fd->lower, buf, len);
|
||||
if (ret > 0)
|
||||
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
nsNetMon_Writev(PRFileDesc *fd,
|
||||
const PRIOVec *iov,
|
||||
int32_t size,
|
||||
PRIntervalTime timeout)
|
||||
{
|
||||
int32_t ret;
|
||||
ret = fd->lower->methods->writev(fd->lower, iov, size, timeout);
|
||||
if (ret > 0)
|
||||
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
nsNetMon_Recv(PRFileDesc *fd,
|
||||
void *buf,
|
||||
int32_t amount,
|
||||
int flags,
|
||||
PRIntervalTime timeout)
|
||||
{
|
||||
int32_t ret;
|
||||
ret = fd->lower->methods->recv(fd->lower, buf, amount, flags, timeout);
|
||||
if (ret >= 0)
|
||||
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kDownload);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
nsNetMon_Send(PRFileDesc *fd,
|
||||
const void *buf,
|
||||
int32_t amount,
|
||||
int flags,
|
||||
PRIntervalTime timeout)
|
||||
{
|
||||
int32_t ret;
|
||||
ret = fd->lower->methods->send(fd->lower, buf, amount, flags, timeout);
|
||||
if (ret > 0)
|
||||
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
nsNetMon_RecvFrom(PRFileDesc *fd,
|
||||
void *buf,
|
||||
int32_t amount,
|
||||
int flags,
|
||||
PRNetAddr *addr,
|
||||
PRIntervalTime timeout)
|
||||
{
|
||||
int32_t ret;
|
||||
ret = fd->lower->methods->recvfrom(fd->lower,
|
||||
buf,
|
||||
amount,
|
||||
flags,
|
||||
addr,
|
||||
timeout);
|
||||
if (ret >= 0)
|
||||
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kDownload);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
nsNetMon_SendTo(PRFileDesc *fd,
|
||||
const void *buf,
|
||||
int32_t amount,
|
||||
int flags,
|
||||
const PRNetAddr *addr,
|
||||
PRIntervalTime timeout)
|
||||
{
|
||||
int32_t ret;
|
||||
ret = fd->lower->methods->sendto(fd->lower,
|
||||
buf,
|
||||
amount,
|
||||
flags,
|
||||
addr,
|
||||
timeout);
|
||||
if (ret > 0)
|
||||
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
nsNetMon_AcceptRead(PRFileDesc *listenSock,
|
||||
PRFileDesc **acceptedSock,
|
||||
PRNetAddr **peerAddr,
|
||||
void *buf,
|
||||
int32_t amount,
|
||||
PRIntervalTime timeout)
|
||||
{
|
||||
int32_t ret;
|
||||
ret = listenSock->lower->methods->acceptread(listenSock->lower,
|
||||
acceptedSock,
|
||||
peerAddr,
|
||||
buf,
|
||||
amount,
|
||||
timeout);
|
||||
if (ret > 0)
|
||||
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kDownload);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
class NotifyNetworkActivity : public mozilla::Runnable {
|
||||
public:
|
||||
explicit NotifyNetworkActivity(NetworkActivityMonitor::Direction aDirection)
|
||||
: mDirection(aDirection)
|
||||
{}
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||
if (!obs)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
obs->NotifyObservers(nullptr,
|
||||
mDirection == NetworkActivityMonitor::kUpload
|
||||
? NS_NETWORK_ACTIVITY_BLIP_UPLOAD_TOPIC
|
||||
: NS_NETWORK_ACTIVITY_BLIP_DOWNLOAD_TOPIC,
|
||||
nullptr);
|
||||
return NS_OK;
|
||||
}
|
||||
private:
|
||||
NetworkActivityMonitor::Direction mDirection;
|
||||
};
|
||||
|
||||
NetworkActivityMonitor * NetworkActivityMonitor::gInstance = nullptr;
|
||||
static PRDescIdentity sNetActivityMonitorLayerIdentity;
|
||||
static PRIOMethods sNetActivityMonitorLayerMethods;
|
||||
static PRIOMethods *sNetActivityMonitorLayerMethodsPtr = nullptr;
|
||||
|
||||
NetworkActivityMonitor::NetworkActivityMonitor()
|
||||
: mBlipInterval(PR_INTERVAL_NO_TIMEOUT)
|
||||
{
|
||||
MOZ_COUNT_CTOR(NetworkActivityMonitor);
|
||||
|
||||
NS_ASSERTION(gInstance==nullptr,
|
||||
"multiple NetworkActivityMonitor instances!");
|
||||
}
|
||||
|
||||
NetworkActivityMonitor::~NetworkActivityMonitor()
|
||||
{
|
||||
MOZ_COUNT_DTOR(NetworkActivityMonitor);
|
||||
gInstance = nullptr;
|
||||
}
|
||||
|
||||
nsresult
|
||||
NetworkActivityMonitor::Init(int32_t blipInterval)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
if (gInstance)
|
||||
return NS_ERROR_ALREADY_INITIALIZED;
|
||||
|
||||
NetworkActivityMonitor * mon = new NetworkActivityMonitor();
|
||||
rv = mon->Init_Internal(blipInterval);
|
||||
if (NS_FAILED(rv)) {
|
||||
delete mon;
|
||||
return rv;
|
||||
}
|
||||
|
||||
gInstance = mon;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
NetworkActivityMonitor::Shutdown()
|
||||
{
|
||||
if (!gInstance)
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
delete gInstance;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
NetworkActivityMonitor::Init_Internal(int32_t blipInterval)
|
||||
{
|
||||
if (!sNetActivityMonitorLayerMethodsPtr) {
|
||||
sNetActivityMonitorLayerIdentity =
|
||||
PR_GetUniqueIdentity("network activity monitor layer");
|
||||
sNetActivityMonitorLayerMethods = *PR_GetDefaultIOMethods();
|
||||
sNetActivityMonitorLayerMethods.connect = nsNetMon_Connect;
|
||||
sNetActivityMonitorLayerMethods.read = nsNetMon_Read;
|
||||
sNetActivityMonitorLayerMethods.write = nsNetMon_Write;
|
||||
sNetActivityMonitorLayerMethods.writev = nsNetMon_Writev;
|
||||
sNetActivityMonitorLayerMethods.recv = nsNetMon_Recv;
|
||||
sNetActivityMonitorLayerMethods.send = nsNetMon_Send;
|
||||
sNetActivityMonitorLayerMethods.recvfrom = nsNetMon_RecvFrom;
|
||||
sNetActivityMonitorLayerMethods.sendto = nsNetMon_SendTo;
|
||||
sNetActivityMonitorLayerMethods.acceptread = nsNetMon_AcceptRead;
|
||||
sNetActivityMonitorLayerMethodsPtr = &sNetActivityMonitorLayerMethods;
|
||||
}
|
||||
|
||||
mBlipInterval = PR_MillisecondsToInterval(blipInterval);
|
||||
// Set the last notification times to time that has just expired, so any
|
||||
// activity even right now will trigger notification.
|
||||
mLastNotificationTime[kUpload] = PR_IntervalNow() - mBlipInterval;
|
||||
mLastNotificationTime[kDownload] = mLastNotificationTime[kUpload];
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
NetworkActivityMonitor::AttachIOLayer(PRFileDesc *fd)
|
||||
{
|
||||
if (!gInstance)
|
||||
return NS_OK;
|
||||
|
||||
PRFileDesc * layer;
|
||||
PRStatus status;
|
||||
|
||||
layer = PR_CreateIOLayerStub(sNetActivityMonitorLayerIdentity,
|
||||
sNetActivityMonitorLayerMethodsPtr);
|
||||
if (!layer) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
status = PR_PushIOLayer(fd, PR_NSPR_IO_LAYER, layer);
|
||||
|
||||
if (status == PR_FAILURE) {
|
||||
PR_DELETE(layer);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
NetworkActivityMonitor::DataInOut(Direction direction)
|
||||
{
|
||||
NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
|
||||
|
||||
if (gInstance) {
|
||||
PRIntervalTime now = PR_IntervalNow();
|
||||
if ((now - gInstance->mLastNotificationTime[direction]) >
|
||||
gInstance->mBlipInterval) {
|
||||
gInstance->mLastNotificationTime[direction] = now;
|
||||
gInstance->PostNotification(direction);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
NetworkActivityMonitor::PostNotification(Direction direction)
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> ev = new NotifyNetworkActivity(direction);
|
||||
NS_DispatchToMainThread(ev);
|
||||
}
|
||||
46
netwerk/base/NetworkActivityMonitor.h
Normal file
46
netwerk/base/NetworkActivityMonitor.h
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef NetworkActivityMonitor_h___
|
||||
#define NetworkActivityMonitor_h___
|
||||
|
||||
#include <stdint.h>
|
||||
#include "nscore.h"
|
||||
#include "prio.h"
|
||||
#include "prinrval.h"
|
||||
|
||||
namespace mozilla { namespace net {
|
||||
|
||||
class NetworkActivityMonitor
|
||||
{
|
||||
public:
|
||||
enum Direction {
|
||||
kUpload = 0,
|
||||
kDownload = 1
|
||||
};
|
||||
|
||||
NetworkActivityMonitor();
|
||||
~NetworkActivityMonitor();
|
||||
|
||||
static nsresult Init(int32_t blipInterval);
|
||||
static nsresult Shutdown();
|
||||
|
||||
static nsresult AttachIOLayer(PRFileDesc *fd);
|
||||
static nsresult DataInOut(Direction direction);
|
||||
|
||||
private:
|
||||
nsresult Init_Internal(int32_t blipInterval);
|
||||
void PostNotification(Direction direction);
|
||||
|
||||
static NetworkActivityMonitor * gInstance;
|
||||
PRIntervalTime mBlipInterval;
|
||||
PRIntervalTime mLastNotificationTime[2];
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* NetworkActivityMonitor_h___ */
|
||||
104
netwerk/base/NetworkInfoServiceCocoa.cpp
Normal file
104
netwerk/base/NetworkInfoServiceCocoa.cpp
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <net/if.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/ScopeExit.h"
|
||||
|
||||
#include "NetworkInfoServiceImpl.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
static nsresult
|
||||
ListInterfaceAddresses(int aFd, const char* aIface, AddrMapType& aAddrMap);
|
||||
|
||||
nsresult
|
||||
DoListAddresses(AddrMapType& aAddrMap)
|
||||
{
|
||||
int fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (fd < 0) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
auto autoCloseSocket = MakeScopeExit([&] {
|
||||
close(fd);
|
||||
});
|
||||
|
||||
struct ifconf ifconf;
|
||||
/* 16k of space should be enough to list all interfaces. Worst case, if it's
|
||||
* not then we will error out and fail to list addresses. This should only
|
||||
* happen on pathological machines with way too many interfaces.
|
||||
*/
|
||||
char buf[16384];
|
||||
|
||||
ifconf.ifc_len = sizeof(buf);
|
||||
ifconf.ifc_buf = buf;
|
||||
if (ioctl(fd, SIOCGIFCONF, &ifconf) != 0) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
struct ifreq* ifreq = ifconf.ifc_req;
|
||||
int i = 0;
|
||||
while (i < ifconf.ifc_len) {
|
||||
size_t len = IFNAMSIZ + ifreq->ifr_addr.sa_len;
|
||||
|
||||
DebugOnly<nsresult> rv =
|
||||
ListInterfaceAddresses(fd, ifreq->ifr_name, aAddrMap);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "ListInterfaceAddresses failed");
|
||||
|
||||
ifreq = (struct ifreq*) ((char*)ifreq + len);
|
||||
i += len;
|
||||
}
|
||||
|
||||
autoCloseSocket.release();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static nsresult
|
||||
ListInterfaceAddresses(int aFd, const char* aInterface, AddrMapType& aAddrMap)
|
||||
{
|
||||
struct ifreq ifreq;
|
||||
memset(&ifreq, 0, sizeof(struct ifreq));
|
||||
strncpy(ifreq.ifr_name, aInterface, IFNAMSIZ - 1);
|
||||
if (ioctl(aFd, SIOCGIFADDR, &ifreq) != 0) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
char host[128];
|
||||
int family;
|
||||
switch(family=ifreq.ifr_addr.sa_family) {
|
||||
case AF_INET:
|
||||
case AF_INET6:
|
||||
getnameinfo(&ifreq.ifr_addr, sizeof(ifreq.ifr_addr), host, sizeof(host), 0, 0, NI_NUMERICHOST);
|
||||
break;
|
||||
case AF_UNSPEC:
|
||||
return NS_OK;
|
||||
default:
|
||||
// Unknown family.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCString ifaceStr;
|
||||
ifaceStr.AssignASCII(aInterface);
|
||||
|
||||
nsCString addrStr;
|
||||
addrStr.AssignASCII(host);
|
||||
|
||||
aAddrMap.Put(ifaceStr, addrStr);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
18
netwerk/base/NetworkInfoServiceImpl.h
Normal file
18
netwerk/base/NetworkInfoServiceImpl.h
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsString.h"
|
||||
#include "nsDataHashtable.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
typedef nsDataHashtable<nsCStringHashKey, nsCString> AddrMapType;
|
||||
|
||||
nsresult DoListAddresses(AddrMapType& aAddrMap);
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
104
netwerk/base/NetworkInfoServiceLinux.cpp
Normal file
104
netwerk/base/NetworkInfoServiceLinux.cpp
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <net/if.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/ScopeExit.h"
|
||||
|
||||
#include "NetworkInfoServiceImpl.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
static nsresult
|
||||
ListInterfaceAddresses(int aFd, const char* aIface, AddrMapType& aAddrMap);
|
||||
|
||||
nsresult
|
||||
DoListAddresses(AddrMapType& aAddrMap)
|
||||
{
|
||||
int fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (fd < 0) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
auto autoCloseSocket = MakeScopeExit([&] {
|
||||
close(fd);
|
||||
});
|
||||
|
||||
struct ifconf ifconf;
|
||||
/* 16k of space should be enough to list all interfaces. Worst case, if it's
|
||||
* not then we will error out and fail to list addresses. This should only
|
||||
* happen on pathological machines with way too many interfaces.
|
||||
*/
|
||||
char buf[16384];
|
||||
|
||||
ifconf.ifc_len = sizeof(buf);
|
||||
ifconf.ifc_buf = buf;
|
||||
if (ioctl(fd, SIOCGIFCONF, &ifconf) != 0) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
struct ifreq* ifreq = ifconf.ifc_req;
|
||||
int i = 0;
|
||||
while (i < ifconf.ifc_len) {
|
||||
size_t len = sizeof(struct ifreq);
|
||||
|
||||
DebugOnly<nsresult> rv =
|
||||
ListInterfaceAddresses(fd, ifreq->ifr_name, aAddrMap);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "ListInterfaceAddresses failed");
|
||||
|
||||
ifreq = (struct ifreq*) ((char*)ifreq + len);
|
||||
i += len;
|
||||
}
|
||||
|
||||
autoCloseSocket.release();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static nsresult
|
||||
ListInterfaceAddresses(int aFd, const char* aInterface, AddrMapType& aAddrMap)
|
||||
{
|
||||
struct ifreq ifreq;
|
||||
memset(&ifreq, 0, sizeof(struct ifreq));
|
||||
strncpy(ifreq.ifr_name, aInterface, IFNAMSIZ - 1);
|
||||
if (ioctl(aFd, SIOCGIFADDR, &ifreq) != 0) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
char host[128];
|
||||
int family;
|
||||
switch(family=ifreq.ifr_addr.sa_family) {
|
||||
case AF_INET:
|
||||
case AF_INET6:
|
||||
getnameinfo(&ifreq.ifr_addr, sizeof(ifreq.ifr_addr), host, sizeof(host), 0, 0, NI_NUMERICHOST);
|
||||
break;
|
||||
case AF_UNSPEC:
|
||||
return NS_OK;
|
||||
default:
|
||||
// Unknown family.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCString ifaceStr;
|
||||
ifaceStr.AssignASCII(aInterface);
|
||||
|
||||
nsCString addrStr;
|
||||
addrStr.AssignASCII(host);
|
||||
|
||||
aAddrMap.Put(ifaceStr, addrStr);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
60
netwerk/base/NetworkInfoServiceWindows.cpp
Normal file
60
netwerk/base/NetworkInfoServiceWindows.cpp
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include <winsock2.h>
|
||||
#include <ws2ipdef.h>
|
||||
#include <iphlpapi.h>
|
||||
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
||||
#include "NetworkInfoServiceImpl.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
nsresult
|
||||
DoListAddresses(AddrMapType& aAddrMap)
|
||||
{
|
||||
UniquePtr<MIB_IPADDRTABLE> ipAddrTable;
|
||||
DWORD size = sizeof(MIB_IPADDRTABLE);
|
||||
|
||||
ipAddrTable.reset((MIB_IPADDRTABLE*) malloc(size));
|
||||
if (!ipAddrTable) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
DWORD retVal = GetIpAddrTable(ipAddrTable.get(), &size, 0);
|
||||
if (retVal == ERROR_INSUFFICIENT_BUFFER) {
|
||||
ipAddrTable.reset((MIB_IPADDRTABLE*) malloc(size));
|
||||
if (!ipAddrTable) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
retVal = GetIpAddrTable(ipAddrTable.get(), &size, 0);
|
||||
}
|
||||
if (retVal != NO_ERROR) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
for (DWORD i = 0; i < ipAddrTable->dwNumEntries; i++) {
|
||||
int index = ipAddrTable->table[i].dwIndex;
|
||||
uint32_t addrVal = (uint32_t) ipAddrTable->table[i].dwAddr;
|
||||
|
||||
nsCString indexString;
|
||||
indexString.AppendInt(index, 10);
|
||||
|
||||
nsCString addrString;
|
||||
addrString.AppendPrintf("%d.%d.%d.%d",
|
||||
(addrVal >> 0) & 0xff, (addrVal >> 8) & 0xff,
|
||||
(addrVal >> 16) & 0xff, (addrVal >> 24) & 0xff);
|
||||
|
||||
aAddrMap.Put(indexString, addrString);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
347
netwerk/base/PollableEvent.cpp
Normal file
347
netwerk/base/PollableEvent.cpp
Normal file
|
|
@ -0,0 +1,347 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsSocketTransportService2.h"
|
||||
#include "PollableEvent.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "prerror.h"
|
||||
#include "prio.h"
|
||||
#include "private/pprio.h"
|
||||
#include "prnetdb.h"
|
||||
|
||||
#ifdef XP_WIN
|
||||
#include "ShutdownLayer.h"
|
||||
#else
|
||||
#include <fcntl.h>
|
||||
#define USEPIPE 1
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
#ifndef USEPIPE
|
||||
static PRDescIdentity sPollableEventLayerIdentity;
|
||||
static PRIOMethods sPollableEventLayerMethods;
|
||||
static PRIOMethods *sPollableEventLayerMethodsPtr = nullptr;
|
||||
|
||||
static void LazyInitSocket()
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
if (sPollableEventLayerMethodsPtr) {
|
||||
return;
|
||||
}
|
||||
sPollableEventLayerIdentity = PR_GetUniqueIdentity("PollableEvent Layer");
|
||||
sPollableEventLayerMethods = *PR_GetDefaultIOMethods();
|
||||
sPollableEventLayerMethodsPtr = &sPollableEventLayerMethods;
|
||||
}
|
||||
|
||||
static bool NewTCPSocketPair(PRFileDesc *fd[], bool aSetRecvBuff)
|
||||
{
|
||||
// this is a replacement for PR_NewTCPSocketPair that manually
|
||||
// sets the recv buffer to 64K. A windows bug (1248358)
|
||||
// can result in using an incompatible rwin and window
|
||||
// scale option on localhost pipes if not set before connect.
|
||||
|
||||
SOCKET_LOG(("NewTCPSocketPair %s a recv buffer tuning\n", aSetRecvBuff ? "with" : "without"));
|
||||
|
||||
PRFileDesc *listener = nullptr;
|
||||
PRFileDesc *writer = nullptr;
|
||||
PRFileDesc *reader = nullptr;
|
||||
PRSocketOptionData recvBufferOpt;
|
||||
recvBufferOpt.option = PR_SockOpt_RecvBufferSize;
|
||||
recvBufferOpt.value.recv_buffer_size = 65535;
|
||||
|
||||
PRSocketOptionData nodelayOpt;
|
||||
nodelayOpt.option = PR_SockOpt_NoDelay;
|
||||
nodelayOpt.value.no_delay = true;
|
||||
|
||||
PRSocketOptionData noblockOpt;
|
||||
noblockOpt.option = PR_SockOpt_Nonblocking;
|
||||
noblockOpt.value.non_blocking = true;
|
||||
|
||||
listener = PR_OpenTCPSocket(PR_AF_INET);
|
||||
if (!listener) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (aSetRecvBuff) {
|
||||
PR_SetSocketOption(listener, &recvBufferOpt);
|
||||
}
|
||||
PR_SetSocketOption(listener, &nodelayOpt);
|
||||
|
||||
PRNetAddr listenAddr;
|
||||
memset(&listenAddr, 0, sizeof(listenAddr));
|
||||
if ((PR_InitializeNetAddr(PR_IpAddrLoopback, 0, &listenAddr) == PR_FAILURE) ||
|
||||
(PR_Bind(listener, &listenAddr) == PR_FAILURE) ||
|
||||
(PR_GetSockName(listener, &listenAddr) == PR_FAILURE) || // learn the dynamic port
|
||||
(PR_Listen(listener, 5) == PR_FAILURE)) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
writer = PR_OpenTCPSocket(PR_AF_INET);
|
||||
if (!writer) {
|
||||
goto failed;
|
||||
}
|
||||
if (aSetRecvBuff) {
|
||||
PR_SetSocketOption(writer, &recvBufferOpt);
|
||||
}
|
||||
PR_SetSocketOption(writer, &nodelayOpt);
|
||||
PR_SetSocketOption(writer, &noblockOpt);
|
||||
PRNetAddr writerAddr;
|
||||
if (PR_InitializeNetAddr(PR_IpAddrLoopback, ntohs(listenAddr.inet.port), &writerAddr) == PR_FAILURE) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (PR_Connect(writer, &writerAddr, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) {
|
||||
if ((PR_GetError() != PR_IN_PROGRESS_ERROR) ||
|
||||
(PR_ConnectContinue(writer, PR_POLL_WRITE) == PR_FAILURE)) {
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
|
||||
reader = PR_Accept(listener, &listenAddr, PR_MillisecondsToInterval(200));
|
||||
if (!reader) {
|
||||
goto failed;
|
||||
}
|
||||
if (aSetRecvBuff) {
|
||||
PR_SetSocketOption(reader, &recvBufferOpt);
|
||||
}
|
||||
PR_SetSocketOption(reader, &nodelayOpt);
|
||||
PR_SetSocketOption(reader, &noblockOpt);
|
||||
PR_Close(listener);
|
||||
|
||||
fd[0] = reader;
|
||||
fd[1] = writer;
|
||||
return true;
|
||||
|
||||
failed:
|
||||
if (listener) {
|
||||
PR_Close(listener);
|
||||
}
|
||||
if (reader) {
|
||||
PR_Close(reader);
|
||||
}
|
||||
if (writer) {
|
||||
PR_Close(writer);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
PollableEvent::PollableEvent()
|
||||
: mWriteFD(nullptr)
|
||||
, mReadFD(nullptr)
|
||||
, mSignaled(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(PollableEvent);
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
// create pair of prfiledesc that can be used as a poll()ble
|
||||
// signal. on windows use a localhost socket pair, and on
|
||||
// unix use a pipe.
|
||||
#ifdef USEPIPE
|
||||
SOCKET_LOG(("PollableEvent() using pipe\n"));
|
||||
if (PR_CreatePipe(&mReadFD, &mWriteFD) == PR_SUCCESS) {
|
||||
// make the pipe non blocking. NSPR asserts at
|
||||
// trying to use SockOpt here
|
||||
PROsfd fd = PR_FileDesc2NativeHandle(mReadFD);
|
||||
int flags = fcntl(fd, F_GETFL, 0);
|
||||
(void)fcntl(fd, F_SETFL, flags | O_NONBLOCK);
|
||||
fd = PR_FileDesc2NativeHandle(mWriteFD);
|
||||
flags = fcntl(fd, F_GETFL, 0);
|
||||
(void)fcntl(fd, F_SETFL, flags | O_NONBLOCK);
|
||||
} else {
|
||||
mReadFD = nullptr;
|
||||
mWriteFD = nullptr;
|
||||
SOCKET_LOG(("PollableEvent() pipe failed\n"));
|
||||
}
|
||||
#else
|
||||
SOCKET_LOG(("PollableEvent() using socket pair\n"));
|
||||
PRFileDesc *fd[2];
|
||||
LazyInitSocket();
|
||||
|
||||
// Try with a increased recv buffer first (bug 1248358).
|
||||
if (NewTCPSocketPair(fd, true)) {
|
||||
mReadFD = fd[0];
|
||||
mWriteFD = fd[1];
|
||||
// If the previous fails try without recv buffer increase (bug 1305436).
|
||||
} else if (NewTCPSocketPair(fd, false)) {
|
||||
mReadFD = fd[0];
|
||||
mWriteFD = fd[1];
|
||||
// If both fail, try the old version.
|
||||
} else if (PR_NewTCPSocketPair(fd) == PR_SUCCESS) {
|
||||
mReadFD = fd[0];
|
||||
mWriteFD = fd[1];
|
||||
|
||||
PRSocketOptionData socket_opt;
|
||||
DebugOnly<PRStatus> status;
|
||||
socket_opt.option = PR_SockOpt_NoDelay;
|
||||
socket_opt.value.no_delay = true;
|
||||
PR_SetSocketOption(mWriteFD, &socket_opt);
|
||||
PR_SetSocketOption(mReadFD, &socket_opt);
|
||||
socket_opt.option = PR_SockOpt_Nonblocking;
|
||||
socket_opt.value.non_blocking = true;
|
||||
status = PR_SetSocketOption(mWriteFD, &socket_opt);
|
||||
MOZ_ASSERT(status == PR_SUCCESS);
|
||||
status = PR_SetSocketOption(mReadFD, &socket_opt);
|
||||
MOZ_ASSERT(status == PR_SUCCESS);
|
||||
}
|
||||
|
||||
if (mReadFD && mWriteFD) {
|
||||
// compatibility with LSPs such as McAfee that assume a NSPR
|
||||
// layer for read ala the nspr Pollable Event - Bug 698882. This layer is a nop.
|
||||
PRFileDesc *topLayer =
|
||||
PR_CreateIOLayerStub(sPollableEventLayerIdentity,
|
||||
sPollableEventLayerMethodsPtr);
|
||||
if (topLayer) {
|
||||
if (PR_PushIOLayer(fd[0], PR_TOP_IO_LAYER, topLayer) == PR_FAILURE) {
|
||||
topLayer->dtor(topLayer);
|
||||
} else {
|
||||
SOCKET_LOG(("PollableEvent() nspr layer ok\n"));
|
||||
mReadFD = topLayer;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
SOCKET_LOG(("PollableEvent() socketpair failed\n"));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (mReadFD && mWriteFD) {
|
||||
// prime the system to deal with races invovled in [dc]tor cycle
|
||||
SOCKET_LOG(("PollableEvent() ctor ok\n"));
|
||||
mSignaled = true;
|
||||
PR_Write(mWriteFD, "I", 1);
|
||||
}
|
||||
}
|
||||
|
||||
PollableEvent::~PollableEvent()
|
||||
{
|
||||
MOZ_COUNT_DTOR(PollableEvent);
|
||||
if (mWriteFD) {
|
||||
#if defined(XP_WIN)
|
||||
AttachShutdownLayer(mWriteFD);
|
||||
#endif
|
||||
PR_Close(mWriteFD);
|
||||
}
|
||||
if (mReadFD) {
|
||||
#if defined(XP_WIN)
|
||||
AttachShutdownLayer(mReadFD);
|
||||
#endif
|
||||
PR_Close(mReadFD);
|
||||
}
|
||||
}
|
||||
|
||||
// we do not record signals on the socket thread
|
||||
// because the socket thread can reliably look at its
|
||||
// own runnable queue before selecting a poll time
|
||||
// this is the "service the network without blocking" comment in
|
||||
// nsSocketTransportService2.cpp
|
||||
bool
|
||||
PollableEvent::Signal()
|
||||
{
|
||||
SOCKET_LOG(("PollableEvent::Signal\n"));
|
||||
|
||||
if (!mWriteFD) {
|
||||
SOCKET_LOG(("PollableEvent::Signal Failed on no FD\n"));
|
||||
return false;
|
||||
}
|
||||
#ifndef XP_WIN
|
||||
// On windows poll can hang and this became worse when we introduced the
|
||||
// patch for bug 698882 (see also bug 1292181), therefore we reverted the
|
||||
// behavior on windows to be as before bug 698882, e.g. write to the socket
|
||||
// also if an event dispatch is on the socket thread and writing to the
|
||||
// socket for each event. See bug 1292181.
|
||||
if (PR_GetCurrentThread() == gSocketThread) {
|
||||
SOCKET_LOG(("PollableEvent::Signal OnSocketThread nop\n"));
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef XP_WIN
|
||||
// To wake up the poll writing once is enough, but for Windows that can cause
|
||||
// hangs so we will write for every event.
|
||||
// For non-Windows systems it is enough to write just once.
|
||||
if (mSignaled) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
mSignaled = true;
|
||||
int32_t status = PR_Write(mWriteFD, "M", 1);
|
||||
SOCKET_LOG(("PollableEvent::Signal PR_Write %d\n", status));
|
||||
if (status != 1) {
|
||||
NS_WARNING("PollableEvent::Signal Failed\n");
|
||||
SOCKET_LOG(("PollableEvent::Signal Failed\n"));
|
||||
mSignaled = false;
|
||||
}
|
||||
return (status == 1);
|
||||
}
|
||||
|
||||
bool
|
||||
PollableEvent::Clear()
|
||||
{
|
||||
// necessary because of the "dont signal on socket thread" optimization
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
|
||||
SOCKET_LOG(("PollableEvent::Clear\n"));
|
||||
mSignaled = false;
|
||||
if (!mReadFD) {
|
||||
SOCKET_LOG(("PollableEvent::Clear mReadFD is null\n"));
|
||||
return false;
|
||||
}
|
||||
char buf[2048];
|
||||
int32_t status;
|
||||
#ifdef XP_WIN
|
||||
// On Windows we are writing to the socket for each event, to be sure that we
|
||||
// do not have any deadlock read from the socket as much as we can.
|
||||
while (true) {
|
||||
status = PR_Read(mReadFD, buf, 2048);
|
||||
SOCKET_LOG(("PollableEvent::Signal PR_Read %d\n", status));
|
||||
if (status == 0) {
|
||||
SOCKET_LOG(("PollableEvent::Clear EOF!\n"));
|
||||
return false;
|
||||
}
|
||||
if (status < 0) {
|
||||
PRErrorCode code = PR_GetError();
|
||||
if (code == PR_WOULD_BLOCK_ERROR) {
|
||||
return true;
|
||||
} else {
|
||||
SOCKET_LOG(("PollableEvent::Clear unexpected error %d\n", code));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
status = PR_Read(mReadFD, buf, 2048);
|
||||
SOCKET_LOG(("PollableEvent::Signal PR_Read %d\n", status));
|
||||
|
||||
if (status == 1) {
|
||||
return true;
|
||||
}
|
||||
if (status == 0) {
|
||||
SOCKET_LOG(("PollableEvent::Clear EOF!\n"));
|
||||
return false;
|
||||
}
|
||||
if (status > 1) {
|
||||
MOZ_ASSERT(false);
|
||||
SOCKET_LOG(("PollableEvent::Clear Unexpected events\n"));
|
||||
Clear();
|
||||
return true;
|
||||
}
|
||||
PRErrorCode code = PR_GetError();
|
||||
if (code == PR_WOULD_BLOCK_ERROR) {
|
||||
return true;
|
||||
}
|
||||
SOCKET_LOG(("PollableEvent::Clear unexpected error %d\n", code));
|
||||
return false;
|
||||
#endif //XP_WIN
|
||||
|
||||
}
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
38
netwerk/base/PollableEvent.h
Normal file
38
netwerk/base/PollableEvent.h
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef PollableEvent_h__
|
||||
#define PollableEvent_h__
|
||||
|
||||
#include "mozilla/Mutex.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
// class must be called locked
|
||||
class PollableEvent
|
||||
{
|
||||
public:
|
||||
PollableEvent();
|
||||
~PollableEvent();
|
||||
|
||||
// Signal/Clear return false only if they fail
|
||||
bool Signal();
|
||||
bool Clear();
|
||||
bool Valid() { return mWriteFD && mReadFD; }
|
||||
|
||||
PRFileDesc *PollableFD() { return mReadFD; }
|
||||
|
||||
private:
|
||||
PRFileDesc *mWriteFD;
|
||||
PRFileDesc *mReadFD;
|
||||
bool mSignaled;
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
2550
netwerk/base/Predictor.cpp
Normal file
2550
netwerk/base/Predictor.cpp
Normal file
File diff suppressed because it is too large
Load diff
480
netwerk/base/Predictor.h
Normal file
480
netwerk/base/Predictor.h
Normal file
|
|
@ -0,0 +1,480 @@
|
|||
/* vim: set ts=2 sts=2 et sw=2: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_net_Predictor_h
|
||||
#define mozilla_net_Predictor_h
|
||||
|
||||
#include "nsINetworkPredictor.h"
|
||||
#include "nsINetworkPredictorVerifier.h"
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsICacheEntry.h"
|
||||
#include "nsICacheEntryOpenCallback.h"
|
||||
#include "nsICacheStorageVisitor.h"
|
||||
#include "nsIDNSListener.h"
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsISpeculativeConnect.h"
|
||||
#include "nsIStreamListener.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
#include "mozilla/TimeStamp.h"
|
||||
|
||||
class nsICacheStorage;
|
||||
class nsIDNSService;
|
||||
class nsIIOService;
|
||||
class nsILoadContextInfo;
|
||||
class nsITimer;
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
class nsHttpRequestHead;
|
||||
class nsHttpResponseHead;
|
||||
|
||||
class Predictor : public nsINetworkPredictor
|
||||
, public nsIObserver
|
||||
, public nsISpeculativeConnectionOverrider
|
||||
, public nsIInterfaceRequestor
|
||||
, public nsICacheEntryMetaDataVisitor
|
||||
, public nsINetworkPredictorVerifier
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSINETWORKPREDICTOR
|
||||
NS_DECL_NSIOBSERVER
|
||||
NS_DECL_NSISPECULATIVECONNECTIONOVERRIDER
|
||||
NS_DECL_NSIINTERFACEREQUESTOR
|
||||
NS_DECL_NSICACHEENTRYMETADATAVISITOR
|
||||
NS_DECL_NSINETWORKPREDICTORVERIFIER
|
||||
|
||||
Predictor();
|
||||
|
||||
nsresult Init();
|
||||
void Shutdown();
|
||||
static nsresult Create(nsISupports *outer, const nsIID& iid, void **result);
|
||||
|
||||
// Used to update whether a particular URI was cacheable or not.
|
||||
// sourceURI and targetURI are the same as the arguments to Learn
|
||||
// and httpStatus is the status code we got while loading targetURI.
|
||||
static void UpdateCacheability(nsIURI *sourceURI, nsIURI *targetURI,
|
||||
uint32_t httpStatus,
|
||||
nsHttpRequestHead &requestHead,
|
||||
nsHttpResponseHead *reqponseHead,
|
||||
nsILoadContextInfo *lci);
|
||||
|
||||
private:
|
||||
virtual ~Predictor();
|
||||
|
||||
// Stores callbacks for a child process predictor (for test purposes)
|
||||
nsCOMPtr<nsINetworkPredictorVerifier> mChildVerifier;
|
||||
|
||||
union Reason {
|
||||
PredictorLearnReason mLearn;
|
||||
PredictorPredictReason mPredict;
|
||||
};
|
||||
|
||||
class DNSListener : public nsIDNSListener
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIDNSLISTENER
|
||||
|
||||
DNSListener()
|
||||
{ }
|
||||
|
||||
private:
|
||||
virtual ~DNSListener()
|
||||
{ }
|
||||
};
|
||||
|
||||
class Action : public nsICacheEntryOpenCallback
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSICACHEENTRYOPENCALLBACK
|
||||
|
||||
Action(bool fullUri, bool predict, Reason reason,
|
||||
nsIURI *targetURI, nsIURI *sourceURI,
|
||||
nsINetworkPredictorVerifier *verifier, Predictor *predictor);
|
||||
Action(bool fullUri, bool predict, Reason reason,
|
||||
nsIURI *targetURI, nsIURI *sourceURI,
|
||||
nsINetworkPredictorVerifier *verifier, Predictor *predictor,
|
||||
uint8_t stackCount);
|
||||
|
||||
static const bool IS_FULL_URI = true;
|
||||
static const bool IS_ORIGIN = false;
|
||||
|
||||
static const bool DO_PREDICT = true;
|
||||
static const bool DO_LEARN = false;
|
||||
|
||||
private:
|
||||
virtual ~Action();
|
||||
|
||||
bool mFullUri : 1;
|
||||
bool mPredict : 1;
|
||||
union {
|
||||
PredictorPredictReason mPredictReason;
|
||||
PredictorLearnReason mLearnReason;
|
||||
};
|
||||
nsCOMPtr<nsIURI> mTargetURI;
|
||||
nsCOMPtr<nsIURI> mSourceURI;
|
||||
nsCOMPtr<nsINetworkPredictorVerifier> mVerifier;
|
||||
TimeStamp mStartTime;
|
||||
uint8_t mStackCount;
|
||||
RefPtr<Predictor> mPredictor;
|
||||
};
|
||||
|
||||
class CacheabilityAction : public nsICacheEntryOpenCallback
|
||||
, public nsICacheEntryMetaDataVisitor
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSICACHEENTRYOPENCALLBACK
|
||||
NS_DECL_NSICACHEENTRYMETADATAVISITOR
|
||||
|
||||
CacheabilityAction(nsIURI *targetURI, uint32_t httpStatus,
|
||||
const nsCString &method, Predictor *predictor)
|
||||
:mTargetURI(targetURI)
|
||||
,mHttpStatus(httpStatus)
|
||||
,mMethod(method)
|
||||
,mPredictor(predictor)
|
||||
{ }
|
||||
|
||||
private:
|
||||
virtual ~CacheabilityAction() { }
|
||||
|
||||
nsCOMPtr<nsIURI> mTargetURI;
|
||||
uint32_t mHttpStatus;
|
||||
nsCString mMethod;
|
||||
RefPtr<Predictor> mPredictor;
|
||||
nsTArray<nsCString> mKeysToCheck;
|
||||
nsTArray<nsCString> mValuesToCheck;
|
||||
};
|
||||
|
||||
class Resetter : public nsICacheEntryOpenCallback,
|
||||
public nsICacheEntryMetaDataVisitor,
|
||||
public nsICacheStorageVisitor
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSICACHEENTRYOPENCALLBACK
|
||||
NS_DECL_NSICACHEENTRYMETADATAVISITOR
|
||||
NS_DECL_NSICACHESTORAGEVISITOR
|
||||
|
||||
explicit Resetter(Predictor *predictor);
|
||||
|
||||
private:
|
||||
virtual ~Resetter() { }
|
||||
|
||||
void Complete();
|
||||
|
||||
uint32_t mEntriesToVisit;
|
||||
nsTArray<nsCString> mKeysToDelete;
|
||||
RefPtr<Predictor> mPredictor;
|
||||
nsTArray<nsCOMPtr<nsIURI>> mURIsToVisit;
|
||||
};
|
||||
|
||||
class SpaceCleaner : public nsICacheEntryMetaDataVisitor
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSICACHEENTRYMETADATAVISITOR
|
||||
|
||||
explicit SpaceCleaner(Predictor *predictor)
|
||||
:mLRUStamp(0)
|
||||
,mLRUKeyToDelete(nullptr)
|
||||
,mPredictor(predictor)
|
||||
{ }
|
||||
|
||||
void Finalize(nsICacheEntry *entry);
|
||||
|
||||
private:
|
||||
virtual ~SpaceCleaner() { }
|
||||
uint32_t mLRUStamp;
|
||||
const char *mLRUKeyToDelete;
|
||||
nsTArray<nsCString> mLongKeysToDelete;
|
||||
RefPtr<Predictor> mPredictor;
|
||||
};
|
||||
|
||||
class PrefetchListener : public nsIStreamListener
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
NS_DECL_NSISTREAMLISTENER
|
||||
|
||||
PrefetchListener(nsINetworkPredictorVerifier *verifier, nsIURI *uri,
|
||||
Predictor *predictor)
|
||||
:mVerifier(verifier)
|
||||
,mURI(uri)
|
||||
,mPredictor(predictor)
|
||||
{ }
|
||||
|
||||
private:
|
||||
virtual ~PrefetchListener() { }
|
||||
|
||||
nsCOMPtr<nsINetworkPredictorVerifier> mVerifier;
|
||||
nsCOMPtr<nsIURI> mURI;
|
||||
RefPtr<Predictor> mPredictor;
|
||||
TimeStamp mStartTime;
|
||||
};
|
||||
|
||||
// Observer-related stuff
|
||||
nsresult InstallObserver();
|
||||
void RemoveObserver();
|
||||
|
||||
// Service startup utilities
|
||||
void MaybeCleanupOldDBFiles();
|
||||
|
||||
// The guts of prediction
|
||||
|
||||
// This is the top-level driver for doing any prediction that needs
|
||||
// information from the cache. Returns true if any predictions were queued up
|
||||
// * reason - What kind of prediction this is/why this prediction is
|
||||
// happening (pageload, startup)
|
||||
// * entry - the cache entry with the information we need
|
||||
// * isNew - whether or not the cache entry is brand new and empty
|
||||
// * fullUri - whether we are doing predictions based on a full page URI, or
|
||||
// just the origin of the page
|
||||
// * targetURI - the URI that we are predicting based upon - IOW, the URI
|
||||
// that is being loaded or being redirected to
|
||||
// * verifier - used for testing to verify the expected predictions happen
|
||||
// * stackCount - used to ensure we don't recurse too far trying to find the
|
||||
// final redirection in a redirect chain
|
||||
bool PredictInternal(PredictorPredictReason reason, nsICacheEntry *entry,
|
||||
bool isNew, bool fullUri, nsIURI *targetURI,
|
||||
nsINetworkPredictorVerifier *verifier,
|
||||
uint8_t stackCount);
|
||||
|
||||
// Used when predicting because the user's mouse hovered over a link
|
||||
// * targetURI - the URI target of the link
|
||||
// * sourceURI - the URI of the page on which the link appears
|
||||
// * verifier - used for testing to verify the expected predictions happen
|
||||
void PredictForLink(nsIURI *targetURI,
|
||||
nsIURI *sourceURI,
|
||||
nsINetworkPredictorVerifier *verifier);
|
||||
|
||||
// Used when predicting because a page is being loaded (which may include
|
||||
// being the target of a redirect). All arguments are the same as for
|
||||
// PredictInternal. Returns true if any predictions were queued up.
|
||||
bool PredictForPageload(nsICacheEntry *entry,
|
||||
nsIURI *targetURI,
|
||||
uint8_t stackCount,
|
||||
bool fullUri,
|
||||
nsINetworkPredictorVerifier *verifier);
|
||||
|
||||
// Used when predicting pages that will be used near browser startup. All
|
||||
// arguments are the same as for PredictInternal. Returns true if any
|
||||
// predictions were queued up.
|
||||
bool PredictForStartup(nsICacheEntry *entry,
|
||||
bool fullUri,
|
||||
nsINetworkPredictorVerifier *verifier);
|
||||
|
||||
// Utilities related to prediction
|
||||
|
||||
// Used to update our rolling load count (how many of the last n loads was a
|
||||
// partular resource loaded on?)
|
||||
// * entry - cache entry of page we're loading
|
||||
// * flags - value that contains our rolling count as the top 20 bits (but
|
||||
// we may use fewer than those 20 bits for calculations)
|
||||
// * key - metadata key that we will update on entry
|
||||
// * hitCount - part of the metadata we need to preserve
|
||||
// * lastHit - part of the metadata we need to preserve
|
||||
void UpdateRollingLoadCount(nsICacheEntry *entry, const uint32_t flags,
|
||||
const char *key, const uint32_t hitCount,
|
||||
const uint32_t lastHit);
|
||||
|
||||
// Used to calculate how much to degrade our confidence for all resources
|
||||
// on a particular page, because of how long ago the most recent load of that
|
||||
// page was. Returns a value between 0 (very recent most recent load) and 100
|
||||
// (very distant most recent load)
|
||||
// * lastLoad - time stamp of most recent load of a page
|
||||
int32_t CalculateGlobalDegradation(uint32_t lastLoad);
|
||||
|
||||
// Used to calculate how confident we are that a particular resource will be
|
||||
// used. Returns a value between 0 (no confidence) and 100 (very confident)
|
||||
// * hitCount - number of times this resource has been seen when loading
|
||||
// this page
|
||||
// * hitsPossible - number of times this page has been loaded
|
||||
// * lastHit - timestamp of the last time this resource was seen when
|
||||
// loading this page
|
||||
// * lastPossible - timestamp of the last time this page was loaded
|
||||
// * globalDegradation - value calculated by CalculateGlobalDegradation for
|
||||
// this page
|
||||
int32_t CalculateConfidence(uint32_t hitCount, uint32_t hitsPossible,
|
||||
uint32_t lastHit, uint32_t lastPossible,
|
||||
int32_t globalDegradation);
|
||||
|
||||
// Used to calculate all confidence values for all resources associated with a
|
||||
// page.
|
||||
// * entry - the cache entry with all necessary information about this page
|
||||
// * referrer - the URI that we are loading (may be null)
|
||||
// * lastLoad - timestamp of the last time this page was loaded
|
||||
// * loadCount - number of times this page has been loaded
|
||||
// * gloablDegradation - value calculated by CalculateGlobalDegradation for
|
||||
// this page
|
||||
// * fullUri - whether we're predicting for a full URI or origin-only
|
||||
void CalculatePredictions(nsICacheEntry *entry, nsIURI *referrer,
|
||||
uint32_t lastLoad, uint32_t loadCount,
|
||||
int32_t globalDegradation, bool fullUri);
|
||||
|
||||
// Used to prepare any necessary prediction for a resource on a page
|
||||
// * confidence - value calculated by CalculateConfidence for this resource
|
||||
// * flags - the flags taken from the resource
|
||||
// * uri - the URI of the resource
|
||||
void SetupPrediction(int32_t confidence, uint32_t flags, nsIURI *uri);
|
||||
|
||||
// Used to kick off a prefetch from RunPredictions if necessary
|
||||
// * uri - the URI to prefetch
|
||||
// * referrer - the URI of the referring page
|
||||
// * verifier - used for testing to ensure the expected prefetch happens
|
||||
nsresult Prefetch(nsIURI *uri, nsIURI *referrer, nsINetworkPredictorVerifier *verifier);
|
||||
|
||||
// Used to actually perform any predictions set up via SetupPrediction.
|
||||
// Returns true if any predictions were performed.
|
||||
// * referrer - the URI we are predicting from
|
||||
// * verifier - used for testing to ensure the expected predictions happen
|
||||
bool RunPredictions(nsIURI *referrer, nsINetworkPredictorVerifier *verifier);
|
||||
|
||||
// Used to guess whether a page will redirect to another page or not. Returns
|
||||
// true if a redirection is likely.
|
||||
// * entry - cache entry with all necessary information about this page
|
||||
// * loadCount - number of times this page has been loaded
|
||||
// * lastLoad - timestamp of the last time this page was loaded
|
||||
// * globalDegradation - value calculated by CalculateGlobalDegradation for
|
||||
// this page
|
||||
// * redirectURI - if this returns true, the URI that is likely to be
|
||||
// redirected to, otherwise null
|
||||
bool WouldRedirect(nsICacheEntry *entry, uint32_t loadCount,
|
||||
uint32_t lastLoad, int32_t globalDegradation,
|
||||
nsIURI **redirectURI);
|
||||
|
||||
// The guts of learning information
|
||||
|
||||
// This is the top-level driver for doing any updating of our information in
|
||||
// the cache
|
||||
// * reason - why this learn is happening (pageload, startup, redirect)
|
||||
// * entry - the cache entry with the information we need
|
||||
// * isNew - whether or not the cache entry is brand new and empty
|
||||
// * fullUri - whether we are doing predictions based on a full page URI, or
|
||||
// just the origin of the page
|
||||
// * targetURI - the URI that we are adding to our data - most often a
|
||||
// resource loaded by a page the user navigated to
|
||||
// * sourceURI - the URI that caused targetURI to be loaded, usually the
|
||||
// page the user navigated to
|
||||
void LearnInternal(PredictorLearnReason reason, nsICacheEntry *entry,
|
||||
bool isNew, bool fullUri, nsIURI *targetURI,
|
||||
nsIURI *sourceURI);
|
||||
|
||||
// Used when learning about a resource loaded by a page
|
||||
// * entry - the cache entry with information that needs updating
|
||||
// * targetURI - the URI of the resource that was loaded by the page
|
||||
void LearnForSubresource(nsICacheEntry *entry, nsIURI *targetURI);
|
||||
|
||||
// Used when learning about a redirect from one page to another
|
||||
// * entry - the cache entry of the page that was redirected from
|
||||
// * targetURI - the URI of the redirect target
|
||||
void LearnForRedirect(nsICacheEntry *entry, nsIURI *targetURI);
|
||||
|
||||
// Used to learn about pages loaded close to browser startup. This results in
|
||||
// LearnForStartup being called if we are, in fact, near browser startup
|
||||
// * uri - the URI of a page that has been loaded (may not have been near
|
||||
// browser startup)
|
||||
// * fullUri - true if this is a full page uri, false if it's an origin
|
||||
void MaybeLearnForStartup(nsIURI *uri, bool fullUri);
|
||||
|
||||
// Used in conjunction with MaybeLearnForStartup to learn about pages loaded
|
||||
// close to browser startup
|
||||
// * entry - the cache entry that stores the startup page list
|
||||
// * targetURI - the URI of a page that was loaded near browser startup
|
||||
void LearnForStartup(nsICacheEntry *entry, nsIURI *targetURI);
|
||||
|
||||
// Used to parse the data we store in cache metadata
|
||||
// * key - the cache metadata key
|
||||
// * value - the cache metadata value
|
||||
// * uri - (out) the URI this metadata entry was about
|
||||
// * hitCount - (out) the number of times this URI has been seen
|
||||
// * lastHit - (out) timestamp of the last time this URI was seen
|
||||
// * flags - (out) flags for this metadata entry
|
||||
bool ParseMetaDataEntry(const char *key, const char *value, nsIURI **uri,
|
||||
uint32_t &hitCount, uint32_t &lastHit,
|
||||
uint32_t &flags);
|
||||
|
||||
// Used to update whether a particular URI was cacheable or not.
|
||||
// sourceURI and targetURI are the same as the arguments to Learn
|
||||
// and httpStatus is the status code we got while loading targetURI.
|
||||
void UpdateCacheabilityInternal(nsIURI *sourceURI, nsIURI *targetURI,
|
||||
uint32_t httpStatus, const nsCString &method);
|
||||
|
||||
// Make sure our prefs are in their expected range of values
|
||||
void SanitizePrefs();
|
||||
|
||||
// Our state
|
||||
bool mInitialized;
|
||||
|
||||
bool mEnabled;
|
||||
bool mEnableHoverOnSSL;
|
||||
bool mEnablePrefetch;
|
||||
|
||||
int32_t mPageDegradationDay;
|
||||
int32_t mPageDegradationWeek;
|
||||
int32_t mPageDegradationMonth;
|
||||
int32_t mPageDegradationYear;
|
||||
int32_t mPageDegradationMax;
|
||||
|
||||
int32_t mSubresourceDegradationDay;
|
||||
int32_t mSubresourceDegradationWeek;
|
||||
int32_t mSubresourceDegradationMonth;
|
||||
int32_t mSubresourceDegradationYear;
|
||||
int32_t mSubresourceDegradationMax;
|
||||
|
||||
int32_t mPrefetchRollingLoadCount;
|
||||
int32_t mPrefetchMinConfidence;
|
||||
int32_t mPreconnectMinConfidence;
|
||||
int32_t mPreresolveMinConfidence;
|
||||
int32_t mRedirectLikelyConfidence;
|
||||
|
||||
int32_t mPrefetchForceValidFor;
|
||||
|
||||
int32_t mMaxResourcesPerEntry;
|
||||
|
||||
bool mCleanedUp;
|
||||
nsCOMPtr<nsITimer> mCleanupTimer;
|
||||
|
||||
nsTArray<nsCString> mKeysToOperateOn;
|
||||
nsTArray<nsCString> mValuesToOperateOn;
|
||||
|
||||
nsCOMPtr<nsICacheStorage> mCacheDiskStorage;
|
||||
|
||||
nsCOMPtr<nsIIOService> mIOService;
|
||||
nsCOMPtr<nsISpeculativeConnect> mSpeculativeService;
|
||||
|
||||
nsCOMPtr<nsIURI> mStartupURI;
|
||||
uint32_t mStartupTime;
|
||||
uint32_t mLastStartupTime;
|
||||
int32_t mStartupCount;
|
||||
|
||||
uint32_t mMaxURILength;
|
||||
|
||||
nsCOMPtr<nsIDNSService> mDnsService;
|
||||
|
||||
RefPtr<DNSListener> mDNSListener;
|
||||
|
||||
nsTArray<nsCOMPtr<nsIURI>> mPrefetches;
|
||||
nsTArray<nsCOMPtr<nsIURI>> mPreconnects;
|
||||
nsTArray<nsCOMPtr<nsIURI>> mPreresolves;
|
||||
|
||||
bool mDoingTests;
|
||||
|
||||
static Predictor *sSelf;
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_net_Predictor_h
|
||||
132
netwerk/base/PrivateBrowsingChannel.h
Normal file
132
netwerk/base/PrivateBrowsingChannel.h
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim:set ts=4 sts=4 sw=4 et cin: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_net_PrivateBrowsingChannel_h__
|
||||
#define mozilla_net_PrivateBrowsingChannel_h__
|
||||
|
||||
#include "nsIPrivateBrowsingChannel.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsILoadGroup.h"
|
||||
#include "nsILoadContext.h"
|
||||
#include "nsIInterfaceRequestorUtils.h"
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "mozilla/Unused.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
template <class Channel>
|
||||
class PrivateBrowsingChannel : public nsIPrivateBrowsingChannel
|
||||
{
|
||||
public:
|
||||
PrivateBrowsingChannel() :
|
||||
mPrivateBrowsingOverriden(false),
|
||||
mPrivateBrowsing(false)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHOD SetPrivate(bool aPrivate)
|
||||
{
|
||||
// Make sure that we don't have a load context
|
||||
// This is a fatal error in debug builds, and a runtime error in release
|
||||
// builds.
|
||||
nsCOMPtr<nsILoadContext> loadContext;
|
||||
NS_QueryNotificationCallbacks(static_cast<Channel*>(this), loadContext);
|
||||
MOZ_ASSERT(!loadContext);
|
||||
if (loadContext) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mPrivateBrowsingOverriden = true;
|
||||
mPrivateBrowsing = aPrivate;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD GetIsChannelPrivate(bool *aResult)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aResult);
|
||||
*aResult = mPrivateBrowsing;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD IsPrivateModeOverriden(bool* aValue, bool *aResult)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aValue);
|
||||
NS_ENSURE_ARG_POINTER(aResult);
|
||||
*aResult = mPrivateBrowsingOverriden;
|
||||
if (mPrivateBrowsingOverriden) {
|
||||
*aValue = mPrivateBrowsing;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Must be called every time the channel's callbacks or loadGroup is updated
|
||||
void UpdatePrivateBrowsing()
|
||||
{
|
||||
// once marked as private we never go un-private
|
||||
if (mPrivateBrowsing) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto channel = static_cast<Channel*>(this);
|
||||
|
||||
nsCOMPtr<nsILoadContext> loadContext;
|
||||
NS_QueryNotificationCallbacks(channel, loadContext);
|
||||
if (loadContext) {
|
||||
mPrivateBrowsing = loadContext->UsePrivateBrowsing();
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsILoadInfo> loadInfo;
|
||||
Unused << channel->GetLoadInfo(getter_AddRefs(loadInfo));
|
||||
if (loadInfo) {
|
||||
NeckoOriginAttributes attrs = loadInfo->GetOriginAttributes();
|
||||
mPrivateBrowsing = attrs.mPrivateBrowsingId > 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool CanSetCallbacks(nsIInterfaceRequestor* aCallbacks) const
|
||||
{
|
||||
// Make sure that the private bit override flag is not set.
|
||||
// This is a fatal error in debug builds, and a runtime error in release
|
||||
// builds.
|
||||
if (!aCallbacks) {
|
||||
return true;
|
||||
}
|
||||
nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(aCallbacks);
|
||||
if (!loadContext) {
|
||||
return true;
|
||||
}
|
||||
MOZ_ASSERT(!mPrivateBrowsingOverriden);
|
||||
return !mPrivateBrowsingOverriden;
|
||||
}
|
||||
|
||||
bool CanSetLoadGroup(nsILoadGroup* aLoadGroup) const
|
||||
{
|
||||
// Make sure that the private bit override flag is not set.
|
||||
// This is a fatal error in debug builds, and a runtime error in release
|
||||
// builds.
|
||||
if (!aLoadGroup) {
|
||||
return true;
|
||||
}
|
||||
nsCOMPtr<nsIInterfaceRequestor> callbacks;
|
||||
aLoadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks));
|
||||
// From this point on, we just hand off the work to CanSetCallbacks,
|
||||
// because the logic is exactly the same.
|
||||
return CanSetCallbacks(callbacks);
|
||||
}
|
||||
|
||||
protected:
|
||||
bool mPrivateBrowsingOverriden;
|
||||
bool mPrivateBrowsing;
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
|
||||
1015
netwerk/base/ProxyAutoConfig.cpp
Normal file
1015
netwerk/base/ProxyAutoConfig.cpp
Normal file
File diff suppressed because it is too large
Load diff
104
netwerk/base/ProxyAutoConfig.h
Normal file
104
netwerk/base/ProxyAutoConfig.h
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef ProxyAutoConfig_h__
|
||||
#define ProxyAutoConfig_h__
|
||||
|
||||
#include "nsString.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
class nsITimer;
|
||||
namespace JS {
|
||||
class CallArgs;
|
||||
} // namespace JS
|
||||
|
||||
namespace mozilla { namespace net {
|
||||
|
||||
class JSContextWrapper;
|
||||
union NetAddr;
|
||||
|
||||
// The ProxyAutoConfig class is meant to be created and run on a
|
||||
// non main thread. It synchronously resolves PAC files by blocking that
|
||||
// thread and running nested event loops. GetProxyForURI is not re-entrant.
|
||||
|
||||
class ProxyAutoConfig {
|
||||
public:
|
||||
ProxyAutoConfig();
|
||||
~ProxyAutoConfig();
|
||||
|
||||
nsresult Init(const nsCString &aPACURI,
|
||||
const nsCString &aPACScript,
|
||||
bool aIncludePath);
|
||||
void SetThreadLocalIndex(uint32_t index);
|
||||
void Shutdown();
|
||||
void GC();
|
||||
bool MyIPAddress(const JS::CallArgs &aArgs);
|
||||
bool ResolveAddress(const nsCString &aHostName,
|
||||
NetAddr *aNetAddr, unsigned int aTimeout);
|
||||
|
||||
/**
|
||||
* Get the proxy string for the specified URI. The proxy string is
|
||||
* given by the following:
|
||||
*
|
||||
* result = proxy-spec *( proxy-sep proxy-spec )
|
||||
* proxy-spec = direct-type | proxy-type LWS proxy-host [":" proxy-port]
|
||||
* direct-type = "DIRECT"
|
||||
* proxy-type = "PROXY" | "HTTP" | "HTTPS" | "SOCKS" | "SOCKS4" | "SOCKS5"
|
||||
* proxy-sep = ";" LWS
|
||||
* proxy-host = hostname | ipv4-address-literal
|
||||
* proxy-port = <any 16-bit unsigned integer>
|
||||
* LWS = *( SP | HT )
|
||||
* SP = <US-ASCII SP, space (32)>
|
||||
* HT = <US-ASCII HT, horizontal-tab (9)>
|
||||
*
|
||||
* NOTE: direct-type and proxy-type are case insensitive
|
||||
* NOTE: SOCKS implies SOCKS4
|
||||
*
|
||||
* Examples:
|
||||
* "PROXY proxy1.foo.com:8080; PROXY proxy2.foo.com:8080; DIRECT"
|
||||
* "SOCKS socksproxy"
|
||||
* "DIRECT"
|
||||
*
|
||||
* XXX add support for IPv6 address literals.
|
||||
* XXX quote whatever the official standard is for PAC.
|
||||
*
|
||||
* @param aTestURI
|
||||
* The URI as an ASCII string to test.
|
||||
* @param aTestHost
|
||||
* The ASCII hostname to test.
|
||||
*
|
||||
* @param result
|
||||
* result string as defined above.
|
||||
*/
|
||||
nsresult GetProxyForURI(const nsCString &aTestURI,
|
||||
const nsCString &aTestHost,
|
||||
nsACString &result);
|
||||
|
||||
private:
|
||||
// allow 665ms for myipaddress dns queries. That's 95th percentile.
|
||||
const static unsigned int kTimeout = 665;
|
||||
|
||||
// used to compile the PAC file and setup the execution context
|
||||
nsresult SetupJS();
|
||||
|
||||
bool SrcAddress(const NetAddr *remoteAddress, nsCString &localAddress);
|
||||
bool MyIPAddressTryHost(const nsCString &hostName, unsigned int timeout,
|
||||
const JS::CallArgs &aArgs, bool* aResult);
|
||||
|
||||
JSContextWrapper *mJSContext;
|
||||
bool mJSNeedsSetup;
|
||||
bool mShutdown;
|
||||
nsCString mPACScript;
|
||||
nsCString mPACURI;
|
||||
bool mIncludePath;
|
||||
nsCString mRunningHost;
|
||||
nsCOMPtr<nsITimer> mTimer;
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // ProxyAutoConfig_h__
|
||||
87
netwerk/base/RedirectChannelRegistrar.cpp
Normal file
87
netwerk/base/RedirectChannelRegistrar.cpp
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "RedirectChannelRegistrar.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
NS_IMPL_ISUPPORTS(RedirectChannelRegistrar, nsIRedirectChannelRegistrar)
|
||||
|
||||
RedirectChannelRegistrar::RedirectChannelRegistrar()
|
||||
: mRealChannels(32)
|
||||
, mParentChannels(32)
|
||||
, mId(1)
|
||||
, mLock("RedirectChannelRegistrar")
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RedirectChannelRegistrar::RegisterChannel(nsIChannel *channel,
|
||||
uint32_t *_retval)
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
|
||||
mRealChannels.Put(mId, channel);
|
||||
*_retval = mId;
|
||||
|
||||
++mId;
|
||||
|
||||
// Ensure we always provide positive ids
|
||||
if (!mId)
|
||||
mId = 1;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RedirectChannelRegistrar::GetRegisteredChannel(uint32_t id,
|
||||
nsIChannel **_retval)
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
|
||||
if (!mRealChannels.Get(id, _retval))
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RedirectChannelRegistrar::LinkChannels(uint32_t id,
|
||||
nsIParentChannel *channel,
|
||||
nsIChannel** _retval)
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
|
||||
if (!mRealChannels.Get(id, _retval))
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
mParentChannels.Put(id, channel);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RedirectChannelRegistrar::GetParentChannel(uint32_t id,
|
||||
nsIParentChannel **_retval)
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
|
||||
if (!mParentChannels.Get(id, _retval))
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RedirectChannelRegistrar::DeregisterChannels(uint32_t id)
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
|
||||
mRealChannels.Remove(id);
|
||||
mParentChannels.Remove(id);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
44
netwerk/base/RedirectChannelRegistrar.h
Normal file
44
netwerk/base/RedirectChannelRegistrar.h
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef RedirectChannelRegistrar_h__
|
||||
#define RedirectChannelRegistrar_h__
|
||||
|
||||
#include "nsIRedirectChannelRegistrar.h"
|
||||
|
||||
#include "nsIChannel.h"
|
||||
#include "nsIParentChannel.h"
|
||||
#include "nsInterfaceHashtable.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
class RedirectChannelRegistrar final : public nsIRedirectChannelRegistrar
|
||||
{
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIREDIRECTCHANNELREGISTRAR
|
||||
|
||||
RedirectChannelRegistrar();
|
||||
|
||||
private:
|
||||
~RedirectChannelRegistrar() {}
|
||||
|
||||
protected:
|
||||
typedef nsInterfaceHashtable<nsUint32HashKey, nsIChannel>
|
||||
ChannelHashtable;
|
||||
typedef nsInterfaceHashtable<nsUint32HashKey, nsIParentChannel>
|
||||
ParentChannelHashtable;
|
||||
|
||||
ChannelHashtable mRealChannels;
|
||||
ParentChannelHashtable mParentChannels;
|
||||
uint32_t mId;
|
||||
Mutex mLock;
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
186
netwerk/base/ReferrerPolicy.h
Normal file
186
netwerk/base/ReferrerPolicy.h
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef ReferrerPolicy_h__
|
||||
#define ReferrerPolicy_h__
|
||||
|
||||
#include "nsStringGlue.h"
|
||||
#include "nsIHttpChannel.h"
|
||||
#include "nsUnicharUtils.h"
|
||||
|
||||
namespace mozilla { namespace net {
|
||||
|
||||
enum ReferrerPolicy {
|
||||
/* spec tokens: never no-referrer */
|
||||
RP_No_Referrer = nsIHttpChannel::REFERRER_POLICY_NO_REFERRER,
|
||||
|
||||
/* spec tokens: origin */
|
||||
RP_Origin = nsIHttpChannel::REFERRER_POLICY_ORIGIN,
|
||||
|
||||
/* spec tokens: default no-referrer-when-downgrade */
|
||||
RP_No_Referrer_When_Downgrade = nsIHttpChannel::REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE,
|
||||
RP_Default = nsIHttpChannel::REFERRER_POLICY_DEFAULT,
|
||||
|
||||
/* spec tokens: origin-when-cross-origin */
|
||||
RP_Origin_When_Crossorigin = nsIHttpChannel::REFERRER_POLICY_ORIGIN_WHEN_XORIGIN,
|
||||
|
||||
/* spec tokens: always unsafe-url */
|
||||
RP_Unsafe_URL = nsIHttpChannel::REFERRER_POLICY_UNSAFE_URL,
|
||||
|
||||
/* spec tokens: same-origin */
|
||||
RP_Same_Origin = nsIHttpChannel::REFERRER_POLICY_SAME_ORIGIN,
|
||||
|
||||
/* spec tokens: strict-origin */
|
||||
RP_Strict_Origin = nsIHttpChannel::REFERRER_POLICY_STRICT_ORIGIN,
|
||||
|
||||
/* spec tokens: strict-origin-when-cross-origin */
|
||||
RP_Strict_Origin_When_Cross_Origin = nsIHttpChannel::REFERRER_POLICY_STRICT_ORIGIN_WHEN_XORIGIN,
|
||||
|
||||
/* spec tokens: empty string */
|
||||
/* The empty string "" corresponds to no referrer policy, or unset policy */
|
||||
RP_Unset = nsIHttpChannel::REFERRER_POLICY_UNSET,
|
||||
};
|
||||
|
||||
/* spec tokens: never no-referrer */
|
||||
const char kRPS_Never[] = "never";
|
||||
const char kRPS_No_Referrer[] = "no-referrer";
|
||||
|
||||
/* spec tokens: origin */
|
||||
const char kRPS_Origin[] = "origin";
|
||||
|
||||
/* spec tokens: default no-referrer-when-downgrade */
|
||||
const char kRPS_Default[] = "default";
|
||||
const char kRPS_No_Referrer_When_Downgrade[] = "no-referrer-when-downgrade";
|
||||
|
||||
/* spec tokens: origin-when-cross-origin */
|
||||
const char kRPS_Origin_When_Cross_Origin[] = "origin-when-cross-origin";
|
||||
const char kRPS_Origin_When_Crossorigin[] = "origin-when-crossorigin";
|
||||
|
||||
/* spec tokens: same-origin */
|
||||
const char kRPS_Same_Origin[] = "same-origin";
|
||||
|
||||
/* spec tokens: strict-origin */
|
||||
const char kRPS_Strict_Origin[] = "strict-origin";
|
||||
|
||||
/* spec tokens: strict-origin-when-cross-origin */
|
||||
const char kRPS_Strict_Origin_When_Cross_Origin[] = "strict-origin-when-cross-origin";
|
||||
|
||||
/* spec tokens: always unsafe-url */
|
||||
const char kRPS_Always[] = "always";
|
||||
const char kRPS_Unsafe_URL[] = "unsafe-url";
|
||||
|
||||
inline ReferrerPolicy
|
||||
ReferrerPolicyFromString(const nsAString& content)
|
||||
{
|
||||
if (content.IsEmpty()) {
|
||||
return RP_No_Referrer;
|
||||
}
|
||||
|
||||
nsString lowerContent(content);
|
||||
ToLowerCase(lowerContent);
|
||||
// This is implemented step by step as described in the Referrer Policy
|
||||
// specification, section "Determine token's Policy".
|
||||
if (lowerContent.EqualsLiteral(kRPS_Never) ||
|
||||
lowerContent.EqualsLiteral(kRPS_No_Referrer)) {
|
||||
return RP_No_Referrer;
|
||||
}
|
||||
if (lowerContent.EqualsLiteral(kRPS_Origin)) {
|
||||
return RP_Origin;
|
||||
}
|
||||
if (lowerContent.EqualsLiteral(kRPS_Default) ||
|
||||
lowerContent.EqualsLiteral(kRPS_No_Referrer_When_Downgrade)) {
|
||||
return RP_No_Referrer_When_Downgrade;
|
||||
}
|
||||
if (lowerContent.EqualsLiteral(kRPS_Origin_When_Cross_Origin) ||
|
||||
lowerContent.EqualsLiteral(kRPS_Origin_When_Crossorigin)) {
|
||||
return RP_Origin_When_Crossorigin;
|
||||
}
|
||||
if (lowerContent.EqualsLiteral(kRPS_Same_Origin)) {
|
||||
return RP_Same_Origin;
|
||||
}
|
||||
if (lowerContent.EqualsLiteral(kRPS_Strict_Origin)) {
|
||||
return RP_Strict_Origin;
|
||||
}
|
||||
if (lowerContent.EqualsLiteral(kRPS_Strict_Origin_When_Cross_Origin)) {
|
||||
return RP_Strict_Origin_When_Cross_Origin;
|
||||
}
|
||||
if (lowerContent.EqualsLiteral(kRPS_Always) ||
|
||||
lowerContent.EqualsLiteral(kRPS_Unsafe_URL)) {
|
||||
return RP_Unsafe_URL;
|
||||
}
|
||||
// Spec says if none of the previous match, use empty string.
|
||||
return RP_Unset;
|
||||
|
||||
}
|
||||
|
||||
inline bool
|
||||
IsValidReferrerPolicy(const nsAString& content)
|
||||
{
|
||||
if (content.IsEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsString lowerContent(content);
|
||||
ToLowerCase(lowerContent);
|
||||
|
||||
return lowerContent.EqualsLiteral(kRPS_Never)
|
||||
|| lowerContent.EqualsLiteral(kRPS_No_Referrer)
|
||||
|| lowerContent.EqualsLiteral(kRPS_Origin)
|
||||
|| lowerContent.EqualsLiteral(kRPS_Default)
|
||||
|| lowerContent.EqualsLiteral(kRPS_No_Referrer_When_Downgrade)
|
||||
|| lowerContent.EqualsLiteral(kRPS_Origin_When_Cross_Origin)
|
||||
|| lowerContent.EqualsLiteral(kRPS_Origin_When_Crossorigin)
|
||||
|| lowerContent.EqualsLiteral(kRPS_Same_Origin)
|
||||
|| lowerContent.EqualsLiteral(kRPS_Strict_Origin)
|
||||
|| lowerContent.EqualsLiteral(kRPS_Strict_Origin_When_Cross_Origin)
|
||||
|| lowerContent.EqualsLiteral(kRPS_Always)
|
||||
|| lowerContent.EqualsLiteral(kRPS_Unsafe_URL);
|
||||
}
|
||||
|
||||
inline ReferrerPolicy
|
||||
AttributeReferrerPolicyFromString(const nsAString& content)
|
||||
{
|
||||
// Specs : https://html.spec.whatwg.org/multipage/infrastructure.html#referrer-policy-attribute
|
||||
// Spec says the empty string "" corresponds to no referrer policy, or RP_Unset
|
||||
if (content.IsEmpty()) {
|
||||
return RP_Unset;
|
||||
}
|
||||
|
||||
nsString lowerContent(content);
|
||||
ToLowerCase(lowerContent);
|
||||
|
||||
if (lowerContent.EqualsLiteral(kRPS_No_Referrer)) {
|
||||
return RP_No_Referrer;
|
||||
}
|
||||
if (lowerContent.EqualsLiteral(kRPS_Origin)) {
|
||||
return RP_Origin;
|
||||
}
|
||||
if (lowerContent.EqualsLiteral(kRPS_No_Referrer_When_Downgrade)) {
|
||||
return RP_No_Referrer_When_Downgrade;
|
||||
}
|
||||
if (lowerContent.EqualsLiteral(kRPS_Origin_When_Cross_Origin)) {
|
||||
return RP_Origin_When_Crossorigin;
|
||||
}
|
||||
if (lowerContent.EqualsLiteral(kRPS_Unsafe_URL)) {
|
||||
return RP_Unsafe_URL;
|
||||
}
|
||||
if (lowerContent.EqualsLiteral(kRPS_Strict_Origin)) {
|
||||
return RP_Strict_Origin;
|
||||
}
|
||||
if (lowerContent.EqualsLiteral(kRPS_Same_Origin)) {
|
||||
return RP_Same_Origin;
|
||||
}
|
||||
if (lowerContent.EqualsLiteral(kRPS_Strict_Origin_When_Cross_Origin)) {
|
||||
return RP_Strict_Origin_When_Cross_Origin;
|
||||
}
|
||||
|
||||
// Spec says invalid value default is empty string state
|
||||
// So, return RP_Unset if none of the previous match, return RP_Unset
|
||||
return RP_Unset;
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
217
netwerk/base/RequestContextService.cpp
Normal file
217
netwerk/base/RequestContextService.cpp
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 ;*; */
|
||||
/* vim: set sw=2 ts=8 et tw=80 : */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIUUIDGenerator.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "RequestContextService.h"
|
||||
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/Services.h"
|
||||
|
||||
#include "mozilla/net/PSpdyPush.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
// nsIRequestContext
|
||||
class RequestContext final : public nsIRequestContext
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIREQUESTCONTEXT
|
||||
|
||||
explicit RequestContext(const nsID& id);
|
||||
private:
|
||||
virtual ~RequestContext();
|
||||
|
||||
nsID mID;
|
||||
char mCID[NSID_LENGTH];
|
||||
Atomic<uint32_t> mBlockingTransactionCount;
|
||||
nsAutoPtr<SpdyPushCache> mSpdyCache;
|
||||
nsCString mUserAgentOverride;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(RequestContext, nsIRequestContext)
|
||||
|
||||
RequestContext::RequestContext(const nsID& aID)
|
||||
: mBlockingTransactionCount(0)
|
||||
{
|
||||
mID = aID;
|
||||
mID.ToProvidedString(mCID);
|
||||
}
|
||||
|
||||
RequestContext::~RequestContext()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RequestContext::GetBlockingTransactionCount(uint32_t *aBlockingTransactionCount)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aBlockingTransactionCount);
|
||||
*aBlockingTransactionCount = mBlockingTransactionCount;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RequestContext::AddBlockingTransaction()
|
||||
{
|
||||
mBlockingTransactionCount++;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RequestContext::RemoveBlockingTransaction(uint32_t *outval)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(outval);
|
||||
mBlockingTransactionCount--;
|
||||
*outval = mBlockingTransactionCount;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RequestContext::GetSpdyPushCache(mozilla::net::SpdyPushCache **aSpdyPushCache)
|
||||
{
|
||||
*aSpdyPushCache = mSpdyCache.get();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RequestContext::SetSpdyPushCache(mozilla::net::SpdyPushCache *aSpdyPushCache)
|
||||
{
|
||||
mSpdyCache = aSpdyPushCache;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RequestContext::GetID(nsID *outval)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(outval);
|
||||
*outval = mID;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RequestContext::GetUserAgentOverride(nsACString& aUserAgentOverride)
|
||||
{
|
||||
aUserAgentOverride = mUserAgentOverride;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RequestContext::SetUserAgentOverride(const nsACString& aUserAgentOverride)
|
||||
{
|
||||
mUserAgentOverride = aUserAgentOverride;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
//nsIRequestContextService
|
||||
RequestContextService *RequestContextService::sSelf = nullptr;
|
||||
|
||||
NS_IMPL_ISUPPORTS(RequestContextService, nsIRequestContextService, nsIObserver)
|
||||
|
||||
RequestContextService::RequestContextService()
|
||||
{
|
||||
MOZ_ASSERT(!sSelf, "multiple rcs instances!");
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
sSelf = this;
|
||||
}
|
||||
|
||||
RequestContextService::~RequestContextService()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
Shutdown();
|
||||
sSelf = nullptr;
|
||||
}
|
||||
|
||||
nsresult
|
||||
RequestContextService::Init()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||
if (!obs) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
return obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
|
||||
}
|
||||
|
||||
void
|
||||
RequestContextService::Shutdown()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mTable.Clear();
|
||||
}
|
||||
|
||||
/* static */ nsresult
|
||||
RequestContextService::Create(nsISupports *aOuter, const nsIID& aIID, void **aResult)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (aOuter != nullptr) {
|
||||
return NS_ERROR_NO_AGGREGATION;
|
||||
}
|
||||
|
||||
RefPtr<RequestContextService> svc = new RequestContextService();
|
||||
nsresult rv = svc->Init();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return svc->QueryInterface(aIID, aResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RequestContextService::GetRequestContext(const nsID& rcID, nsIRequestContext **rc)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
NS_ENSURE_ARG_POINTER(rc);
|
||||
*rc = nullptr;
|
||||
|
||||
if (!mTable.Get(rcID, rc)) {
|
||||
nsCOMPtr<nsIRequestContext> newSC = new RequestContext(rcID);
|
||||
mTable.Put(rcID, newSC);
|
||||
newSC.swap(*rc);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RequestContextService::NewRequestContextID(nsID *rcID)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (!mUUIDGen) {
|
||||
nsresult rv;
|
||||
mUUIDGen = do_GetService("@mozilla.org/uuid-generator;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
return mUUIDGen->GenerateUUIDInPlace(rcID);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RequestContextService::RemoveRequestContext(const nsID& rcID)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mTable.Remove(rcID);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RequestContextService::Observe(nsISupports *subject, const char *topic,
|
||||
const char16_t *data_unicode)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (!strcmp(NS_XPCOM_SHUTDOWN_OBSERVER_ID, topic)) {
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // ::mozilla::net
|
||||
} // ::mozilla
|
||||
47
netwerk/base/RequestContextService.h
Normal file
47
netwerk/base/RequestContextService.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 ;*; */
|
||||
/* vim: set sw=2 ts=8 et tw=80 : */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla__net__RequestContextService_h
|
||||
#define mozilla__net__RequestContextService_h
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsInterfaceHashtable.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsIRequestContext.h"
|
||||
|
||||
class nsIUUIDGenerator;
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
class RequestContextService final
|
||||
: public nsIRequestContextService
|
||||
, public nsIObserver
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIREQUESTCONTEXTSERVICE
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
RequestContextService();
|
||||
|
||||
nsresult Init();
|
||||
void Shutdown();
|
||||
static nsresult Create(nsISupports *outer, const nsIID& iid, void **result);
|
||||
|
||||
private:
|
||||
virtual ~RequestContextService();
|
||||
|
||||
static RequestContextService *sSelf;
|
||||
|
||||
nsInterfaceHashtable<nsIDHashKey, nsIRequestContext> mTable;
|
||||
nsCOMPtr<nsIUUIDGenerator> mUUIDGen;
|
||||
};
|
||||
|
||||
} // ::mozilla::net
|
||||
} // ::mozilla
|
||||
|
||||
#endif // mozilla__net__RequestContextService_h
|
||||
80
netwerk/base/ShutdownLayer.cpp
Normal file
80
netwerk/base/ShutdownLayer.cpp
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "ShutdownLayer.h"
|
||||
#include "prerror.h"
|
||||
#include "private/pprio.h"
|
||||
#include "prmem.h"
|
||||
#include <winsock2.h>
|
||||
|
||||
static PRDescIdentity sWinSockShutdownLayerIdentity;
|
||||
static PRIOMethods sWinSockShutdownLayerMethods;
|
||||
static PRIOMethods *sWinSockShutdownLayerMethodsPtr = nullptr;
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
extern PRDescIdentity nsNamedPipeLayerIdentity;
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
|
||||
PRStatus
|
||||
WinSockClose(PRFileDesc *aFd)
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(aFd->identity == sWinSockShutdownLayerIdentity,
|
||||
"Windows shutdown layer not on the top of the stack");
|
||||
|
||||
PROsfd osfd = PR_FileDesc2NativeHandle(aFd);
|
||||
if (osfd != -1) {
|
||||
shutdown(osfd, SD_BOTH);
|
||||
}
|
||||
|
||||
aFd->identity = PR_INVALID_IO_LAYER;
|
||||
|
||||
if (aFd->lower) {
|
||||
return aFd->lower->methods->close(aFd->lower);
|
||||
} else {
|
||||
return PR_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
nsresult mozilla::net::AttachShutdownLayer(PRFileDesc *aFd)
|
||||
{
|
||||
if (!sWinSockShutdownLayerMethodsPtr) {
|
||||
sWinSockShutdownLayerIdentity =
|
||||
PR_GetUniqueIdentity("windows shutdown call layer");
|
||||
sWinSockShutdownLayerMethods = *PR_GetDefaultIOMethods();
|
||||
sWinSockShutdownLayerMethods.close = WinSockClose;
|
||||
sWinSockShutdownLayerMethodsPtr = &sWinSockShutdownLayerMethods;
|
||||
}
|
||||
|
||||
if (mozilla::net::nsNamedPipeLayerIdentity &&
|
||||
PR_GetIdentitiesLayer(aFd, mozilla::net::nsNamedPipeLayerIdentity)) {
|
||||
// Do not attach shutdown layer on named pipe layer,
|
||||
// it is for PR_NSPR_IO_LAYER only.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRFileDesc * layer;
|
||||
PRStatus status;
|
||||
|
||||
layer = PR_CreateIOLayerStub(sWinSockShutdownLayerIdentity,
|
||||
sWinSockShutdownLayerMethodsPtr);
|
||||
if (!layer) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
status = PR_PushIOLayer(aFd, PR_NSPR_IO_LAYER, layer);
|
||||
|
||||
if (status == PR_FAILURE) {
|
||||
PR_DELETE(layer);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
22
netwerk/base/ShutdownLayer.h
Normal file
22
netwerk/base/ShutdownLayer.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef SHUTDOWNLAYER_H___
|
||||
#define SHUTDOWNLAYER_H___
|
||||
|
||||
#include "nscore.h"
|
||||
#include "prio.h"
|
||||
|
||||
namespace mozilla { namespace net {
|
||||
|
||||
// This is only for windows. This layer will be attached jus before PR_CLose
|
||||
// is call and it will only call shutdown(sock).
|
||||
extern nsresult AttachShutdownLayer(PRFileDesc *fd);
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* SHUTDOWN_H___ */
|
||||
95
netwerk/base/SimpleBuffer.cpp
Normal file
95
netwerk/base/SimpleBuffer.cpp
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "SimpleBuffer.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
SimpleBuffer::SimpleBuffer()
|
||||
: mStatus(NS_OK)
|
||||
, mAvailable(0)
|
||||
{
|
||||
mOwningThread = PR_GetCurrentThread();
|
||||
}
|
||||
|
||||
nsresult SimpleBuffer::Write(char *src, size_t len)
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == mOwningThread);
|
||||
if (NS_FAILED(mStatus)) {
|
||||
return mStatus;
|
||||
}
|
||||
|
||||
while (len > 0) {
|
||||
SimpleBufferPage *p = mBufferList.getLast();
|
||||
if (p && (p->mWriteOffset == SimpleBufferPage::kSimpleBufferPageSize)) {
|
||||
// no room.. make a new page
|
||||
p = nullptr;
|
||||
}
|
||||
if (!p) {
|
||||
p = new (fallible) SimpleBufferPage();
|
||||
if (!p) {
|
||||
mStatus = NS_ERROR_OUT_OF_MEMORY;
|
||||
return mStatus;
|
||||
}
|
||||
mBufferList.insertBack(p);
|
||||
}
|
||||
size_t roomOnPage = SimpleBufferPage::kSimpleBufferPageSize - p->mWriteOffset;
|
||||
size_t toWrite = std::min(roomOnPage, len);
|
||||
memcpy(p->mBuffer + p->mWriteOffset, src, toWrite);
|
||||
src += toWrite;
|
||||
len -= toWrite;
|
||||
p->mWriteOffset += toWrite;
|
||||
mAvailable += toWrite;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
size_t SimpleBuffer::Read(char *dest, size_t maxLen)
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == mOwningThread);
|
||||
if (NS_FAILED(mStatus)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t rv = 0;
|
||||
for (SimpleBufferPage *p = mBufferList.getFirst();
|
||||
p && (rv < maxLen); p = mBufferList.getFirst()) {
|
||||
size_t avail = p->mWriteOffset - p->mReadOffset;
|
||||
size_t toRead = std::min(avail, (maxLen - rv));
|
||||
memcpy(dest + rv, p->mBuffer + p->mReadOffset, toRead);
|
||||
rv += toRead;
|
||||
p->mReadOffset += toRead;
|
||||
if (p->mReadOffset == p->mWriteOffset) {
|
||||
p->remove();
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mAvailable >= rv);
|
||||
mAvailable -= rv;
|
||||
return rv;
|
||||
}
|
||||
|
||||
size_t SimpleBuffer::Available()
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == mOwningThread);
|
||||
return NS_SUCCEEDED(mStatus) ? mAvailable : 0;
|
||||
}
|
||||
|
||||
void SimpleBuffer::Clear()
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == mOwningThread);
|
||||
SimpleBufferPage *p;
|
||||
while ((p = mBufferList.popFirst())) {
|
||||
delete p;
|
||||
}
|
||||
mAvailable = 0;
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
57
netwerk/base/SimpleBuffer.h
Normal file
57
netwerk/base/SimpleBuffer.h
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef SimpleBuffer_h__
|
||||
#define SimpleBuffer_h__
|
||||
|
||||
/*
|
||||
This class is similar to a nsPipe except it does not have any locking, stores
|
||||
an unbounded amount of data, can only be used on one thread, and has much
|
||||
simpler result code semantics to deal with.
|
||||
*/
|
||||
|
||||
#include "prtypes.h"
|
||||
#include "mozilla/LinkedList.h"
|
||||
#include "nsIThreadInternal.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
class SimpleBufferPage : public LinkedListElement<SimpleBufferPage>
|
||||
{
|
||||
public:
|
||||
SimpleBufferPage() : mReadOffset(0), mWriteOffset(0) {}
|
||||
static const size_t kSimpleBufferPageSize = 32000;
|
||||
|
||||
private:
|
||||
friend class SimpleBuffer;
|
||||
char mBuffer[kSimpleBufferPageSize];
|
||||
size_t mReadOffset;
|
||||
size_t mWriteOffset;
|
||||
};
|
||||
|
||||
class SimpleBuffer
|
||||
{
|
||||
public:
|
||||
SimpleBuffer();
|
||||
~SimpleBuffer() {}
|
||||
|
||||
nsresult Write(char *stc, size_t len); // return OK or OUT_OF_MEMORY
|
||||
size_t Read(char *dest, size_t maxLen); // return bytes read
|
||||
size_t Available();
|
||||
void Clear();
|
||||
|
||||
private:
|
||||
PRThread *mOwningThread;
|
||||
nsresult mStatus;
|
||||
AutoCleanLinkedList<SimpleBufferPage> mBufferList;
|
||||
size_t mAvailable;
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
72
netwerk/base/StreamingProtocolService.cpp
Normal file
72
netwerk/base/StreamingProtocolService.cpp
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "StreamingProtocolService.h"
|
||||
#include "mozilla/net/NeckoChild.h"
|
||||
#include "nsIURI.h"
|
||||
#include "necko-config.h"
|
||||
|
||||
#ifdef NECKO_PROTOCOL_rtsp
|
||||
#include "RtspControllerChild.h"
|
||||
#include "RtspController.h"
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
NS_IMPL_ISUPPORTS(StreamingProtocolControllerService,
|
||||
nsIStreamingProtocolControllerService)
|
||||
|
||||
/* static */
|
||||
StaticRefPtr<StreamingProtocolControllerService> sSingleton;
|
||||
|
||||
/* static */
|
||||
already_AddRefed<StreamingProtocolControllerService>
|
||||
StreamingProtocolControllerService::GetInstance()
|
||||
{
|
||||
if (!sSingleton) {
|
||||
sSingleton = new StreamingProtocolControllerService();
|
||||
ClearOnShutdown(&sSingleton);
|
||||
}
|
||||
RefPtr<StreamingProtocolControllerService> service = sSingleton.get();
|
||||
return service.forget();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
StreamingProtocolControllerService::Create(nsIChannel *aChannel, nsIStreamingProtocolController **aResult)
|
||||
{
|
||||
RefPtr<nsIStreamingProtocolController> mediacontroller;
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsAutoCString scheme;
|
||||
|
||||
NS_ENSURE_ARG_POINTER(aChannel);
|
||||
aChannel->GetURI(getter_AddRefs(uri));
|
||||
|
||||
nsresult rv = uri->GetScheme(scheme);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
#ifdef NECKO_PROTOCOL_rtsp
|
||||
if (scheme.EqualsLiteral("rtsp")) {
|
||||
if (IsNeckoChild()) {
|
||||
mediacontroller = new RtspControllerChild(aChannel);
|
||||
} else {
|
||||
mediacontroller = new RtspController(aChannel);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!mediacontroller) {
|
||||
return NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
|
||||
mediacontroller->Init(uri);
|
||||
|
||||
mediacontroller.forget(aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
36
netwerk/base/StreamingProtocolService.h
Normal file
36
netwerk/base/StreamingProtocolService.h
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_net_StreamingProtocolControllerService_h
|
||||
#define mozilla_net_StreamingProtocolControllerService_h
|
||||
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "nsIStreamingProtocolService.h"
|
||||
#include "nsIStreamingProtocolController.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIChannel.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
/**
|
||||
* This class implements a service to help to create streaming protocol controller.
|
||||
*/
|
||||
class StreamingProtocolControllerService : public nsIStreamingProtocolControllerService
|
||||
{
|
||||
private:
|
||||
virtual ~StreamingProtocolControllerService() {};
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISTREAMINGPROTOCOLCONTROLLERSERVICE
|
||||
|
||||
StreamingProtocolControllerService() {};
|
||||
static already_AddRefed<StreamingProtocolControllerService> GetInstance();
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
#endif //mozilla_net_StreamingProtocolControllerService_h
|
||||
515
netwerk/base/TLSServerSocket.cpp
Normal file
515
netwerk/base/TLSServerSocket.cpp
Normal file
|
|
@ -0,0 +1,515 @@
|
|||
/* vim:set ts=2 sw=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "TLSServerSocket.h"
|
||||
|
||||
#include "mozilla/net/DNS.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsIServerSocket.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsIX509Cert.h"
|
||||
#include "nsIX509CertDB.h"
|
||||
#include "nsNetCID.h"
|
||||
#include "nsProxyRelease.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsSocketTransport2.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "ScopedNSSTypes.h"
|
||||
#include "ssl.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// TLSServerSocket
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
TLSServerSocket::TLSServerSocket()
|
||||
: mServerCert(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
TLSServerSocket::~TLSServerSocket()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED(TLSServerSocket,
|
||||
nsServerSocket,
|
||||
nsITLSServerSocket)
|
||||
|
||||
nsresult
|
||||
TLSServerSocket::SetSocketDefaults()
|
||||
{
|
||||
// Set TLS options on the listening socket
|
||||
mFD = SSL_ImportFD(nullptr, mFD);
|
||||
if (NS_WARN_IF(!mFD)) {
|
||||
return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
|
||||
}
|
||||
|
||||
SSL_OptionSet(mFD, SSL_SECURITY, true);
|
||||
SSL_OptionSet(mFD, SSL_HANDSHAKE_AS_CLIENT, false);
|
||||
SSL_OptionSet(mFD, SSL_HANDSHAKE_AS_SERVER, true);
|
||||
|
||||
// We don't currently notify the server API consumer of renegotiation events
|
||||
// (to revalidate peer certs, etc.), so disable it for now.
|
||||
SSL_OptionSet(mFD, SSL_ENABLE_RENEGOTIATION, SSL_RENEGOTIATE_NEVER);
|
||||
|
||||
SetSessionCache(true);
|
||||
SetSessionTickets(true);
|
||||
SetRequestClientCertificate(REQUEST_NEVER);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
TLSServerSocket::CreateClientTransport(PRFileDesc* aClientFD,
|
||||
const NetAddr& aClientAddr)
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
nsresult rv;
|
||||
|
||||
RefPtr<nsSocketTransport> trans = new nsSocketTransport;
|
||||
if (NS_WARN_IF(!trans)) {
|
||||
mCondition = NS_ERROR_OUT_OF_MEMORY;
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<TLSServerConnectionInfo> info = new TLSServerConnectionInfo();
|
||||
info->mServerSocket = this;
|
||||
info->mTransport = trans;
|
||||
nsCOMPtr<nsISupports> infoSupports =
|
||||
NS_ISUPPORTS_CAST(nsITLSServerConnectionInfo*, info);
|
||||
rv = trans->InitWithConnectedSocket(aClientFD, &aClientAddr, infoSupports);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
mCondition = rv;
|
||||
return;
|
||||
}
|
||||
|
||||
// Override the default peer certificate validation, so that server consumers
|
||||
// can make their own choice after the handshake completes.
|
||||
SSL_AuthCertificateHook(aClientFD, AuthCertificateHook, nullptr);
|
||||
// Once the TLS handshake has completed, the server consumer is notified and
|
||||
// has access to various TLS state details.
|
||||
// It's safe to pass info here because the socket transport holds it as
|
||||
// |mSecInfo| which keeps it alive for the lifetime of the socket.
|
||||
SSL_HandshakeCallback(aClientFD, TLSServerConnectionInfo::HandshakeCallback,
|
||||
info);
|
||||
|
||||
// Notify the consumer of the new client so it can manage the streams.
|
||||
// Security details aren't known yet. The security observer will be notified
|
||||
// later when they are ready.
|
||||
nsCOMPtr<nsIServerSocket> serverSocket =
|
||||
do_QueryInterface(NS_ISUPPORTS_CAST(nsITLSServerSocket*, this));
|
||||
mListener->OnSocketAccepted(serverSocket, trans);
|
||||
}
|
||||
|
||||
nsresult
|
||||
TLSServerSocket::OnSocketListen()
|
||||
{
|
||||
if (NS_WARN_IF(!mServerCert)) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
UniqueCERTCertificate cert(mServerCert->GetCert());
|
||||
if (NS_WARN_IF(!cert)) {
|
||||
return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
|
||||
}
|
||||
|
||||
UniqueSECKEYPrivateKey key(PK11_FindKeyByAnyCert(cert.get(), nullptr));
|
||||
if (NS_WARN_IF(!key)) {
|
||||
return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
|
||||
}
|
||||
|
||||
SSLKEAType certKEA = NSS_FindCertKEAType(cert.get());
|
||||
|
||||
nsresult rv = MapSECStatus(SSL_ConfigSecureServer(mFD, cert.get(), key.get(),
|
||||
certKEA));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
SECStatus
|
||||
TLSServerSocket::AuthCertificateHook(void* arg, PRFileDesc* fd, PRBool checksig,
|
||||
PRBool isServer)
|
||||
{
|
||||
// Allow any client cert here, server consumer code can decide whether it's
|
||||
// okay after being notified of the new client socket.
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// TLSServerSocket::nsITLSServerSocket
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
NS_IMETHODIMP
|
||||
TLSServerSocket::GetServerCert(nsIX509Cert** aCert)
|
||||
{
|
||||
if (NS_WARN_IF(!aCert)) {
|
||||
return NS_ERROR_INVALID_POINTER;
|
||||
}
|
||||
*aCert = mServerCert;
|
||||
NS_IF_ADDREF(*aCert);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TLSServerSocket::SetServerCert(nsIX509Cert* aCert)
|
||||
{
|
||||
// If AsyncListen was already called (and set mListener), it's too late to set
|
||||
// this.
|
||||
if (NS_WARN_IF(mListener)) {
|
||||
return NS_ERROR_IN_PROGRESS;
|
||||
}
|
||||
mServerCert = aCert;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TLSServerSocket::SetSessionCache(bool aEnabled)
|
||||
{
|
||||
// If AsyncListen was already called (and set mListener), it's too late to set
|
||||
// this.
|
||||
if (NS_WARN_IF(mListener)) {
|
||||
return NS_ERROR_IN_PROGRESS;
|
||||
}
|
||||
SSL_OptionSet(mFD, SSL_NO_CACHE, !aEnabled);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TLSServerSocket::SetSessionTickets(bool aEnabled)
|
||||
{
|
||||
// If AsyncListen was already called (and set mListener), it's too late to set
|
||||
// this.
|
||||
if (NS_WARN_IF(mListener)) {
|
||||
return NS_ERROR_IN_PROGRESS;
|
||||
}
|
||||
SSL_OptionSet(mFD, SSL_ENABLE_SESSION_TICKETS, aEnabled);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TLSServerSocket::SetRequestClientCertificate(uint32_t aMode)
|
||||
{
|
||||
// If AsyncListen was already called (and set mListener), it's too late to set
|
||||
// this.
|
||||
if (NS_WARN_IF(mListener)) {
|
||||
return NS_ERROR_IN_PROGRESS;
|
||||
}
|
||||
SSL_OptionSet(mFD, SSL_REQUEST_CERTIFICATE, aMode != REQUEST_NEVER);
|
||||
|
||||
switch (aMode) {
|
||||
case REQUEST_ALWAYS:
|
||||
SSL_OptionSet(mFD, SSL_REQUIRE_CERTIFICATE, SSL_REQUIRE_NO_ERROR);
|
||||
break;
|
||||
case REQUIRE_FIRST_HANDSHAKE:
|
||||
SSL_OptionSet(mFD, SSL_REQUIRE_CERTIFICATE, SSL_REQUIRE_FIRST_HANDSHAKE);
|
||||
break;
|
||||
case REQUIRE_ALWAYS:
|
||||
SSL_OptionSet(mFD, SSL_REQUIRE_CERTIFICATE, SSL_REQUIRE_ALWAYS);
|
||||
break;
|
||||
default:
|
||||
SSL_OptionSet(mFD, SSL_REQUIRE_CERTIFICATE, SSL_REQUIRE_NEVER);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TLSServerSocket::SetCipherSuites(uint16_t* aCipherSuites, uint32_t aLength)
|
||||
{
|
||||
// If AsyncListen was already called (and set mListener), it's too late to set
|
||||
// this.
|
||||
if (NS_WARN_IF(mListener)) {
|
||||
return NS_ERROR_IN_PROGRESS;
|
||||
}
|
||||
|
||||
for (uint16_t i = 0; i < SSL_NumImplementedCiphers; ++i) {
|
||||
uint16_t cipher_id = SSL_ImplementedCiphers[i];
|
||||
if (SSL_CipherPrefSet(mFD, cipher_id, false) != SECSuccess) {
|
||||
return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < aLength; ++i) {
|
||||
if (SSL_CipherPrefSet(mFD, aCipherSuites[i], true) != SECSuccess) {
|
||||
return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TLSServerSocket::SetVersionRange(uint16_t aMinVersion, uint16_t aMaxVersion)
|
||||
{
|
||||
// If AsyncListen was already called (and set mListener), it's too late to set
|
||||
// this.
|
||||
if (NS_WARN_IF(mListener)) {
|
||||
return NS_ERROR_IN_PROGRESS;
|
||||
}
|
||||
|
||||
SSLVersionRange range = {aMinVersion, aMaxVersion};
|
||||
if (SSL_VersionRangeSet(mFD, &range) != SECSuccess) {
|
||||
return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// TLSServerConnectionInfo
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
namespace {
|
||||
|
||||
class TLSServerSecurityObserverProxy final : public nsITLSServerSecurityObserver
|
||||
{
|
||||
~TLSServerSecurityObserverProxy() {}
|
||||
|
||||
public:
|
||||
explicit TLSServerSecurityObserverProxy(nsITLSServerSecurityObserver* aListener)
|
||||
: mListener(new nsMainThreadPtrHolder<nsITLSServerSecurityObserver>(aListener))
|
||||
{ }
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSITLSSERVERSECURITYOBSERVER
|
||||
|
||||
class OnHandshakeDoneRunnable : public Runnable
|
||||
{
|
||||
public:
|
||||
OnHandshakeDoneRunnable(const nsMainThreadPtrHandle<nsITLSServerSecurityObserver>& aListener,
|
||||
nsITLSServerSocket* aServer,
|
||||
nsITLSClientStatus* aStatus)
|
||||
: mListener(aListener)
|
||||
, mServer(aServer)
|
||||
, mStatus(aStatus)
|
||||
{ }
|
||||
|
||||
NS_DECL_NSIRUNNABLE
|
||||
|
||||
private:
|
||||
nsMainThreadPtrHandle<nsITLSServerSecurityObserver> mListener;
|
||||
nsCOMPtr<nsITLSServerSocket> mServer;
|
||||
nsCOMPtr<nsITLSClientStatus> mStatus;
|
||||
};
|
||||
|
||||
private:
|
||||
nsMainThreadPtrHandle<nsITLSServerSecurityObserver> mListener;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(TLSServerSecurityObserverProxy,
|
||||
nsITLSServerSecurityObserver)
|
||||
|
||||
NS_IMETHODIMP
|
||||
TLSServerSecurityObserverProxy::OnHandshakeDone(nsITLSServerSocket* aServer,
|
||||
nsITLSClientStatus* aStatus)
|
||||
{
|
||||
RefPtr<OnHandshakeDoneRunnable> r =
|
||||
new OnHandshakeDoneRunnable(mListener, aServer, aStatus);
|
||||
return NS_DispatchToMainThread(r);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TLSServerSecurityObserverProxy::OnHandshakeDoneRunnable::Run()
|
||||
{
|
||||
mListener->OnHandshakeDone(mServer, mStatus);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
NS_IMPL_ISUPPORTS(TLSServerConnectionInfo,
|
||||
nsITLSServerConnectionInfo,
|
||||
nsITLSClientStatus)
|
||||
|
||||
TLSServerConnectionInfo::TLSServerConnectionInfo()
|
||||
: mServerSocket(nullptr)
|
||||
, mTransport(nullptr)
|
||||
, mPeerCert(nullptr)
|
||||
, mTlsVersionUsed(TLS_VERSION_UNKNOWN)
|
||||
, mKeyLength(0)
|
||||
, mMacLength(0)
|
||||
, mLock("TLSServerConnectionInfo.mLock")
|
||||
, mSecurityObserver(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
TLSServerConnectionInfo::~TLSServerConnectionInfo()
|
||||
{
|
||||
if (!mSecurityObserver) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<nsITLSServerSecurityObserver> observer;
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
observer = mSecurityObserver.forget();
|
||||
}
|
||||
|
||||
if (observer) {
|
||||
NS_ReleaseOnMainThread(observer.forget());
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TLSServerConnectionInfo::SetSecurityObserver(nsITLSServerSecurityObserver* aObserver)
|
||||
{
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
mSecurityObserver = new TLSServerSecurityObserverProxy(aObserver);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TLSServerConnectionInfo::GetServerSocket(nsITLSServerSocket** aSocket)
|
||||
{
|
||||
if (NS_WARN_IF(!aSocket)) {
|
||||
return NS_ERROR_INVALID_POINTER;
|
||||
}
|
||||
*aSocket = mServerSocket;
|
||||
NS_IF_ADDREF(*aSocket);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TLSServerConnectionInfo::GetStatus(nsITLSClientStatus** aStatus)
|
||||
{
|
||||
if (NS_WARN_IF(!aStatus)) {
|
||||
return NS_ERROR_INVALID_POINTER;
|
||||
}
|
||||
*aStatus = this;
|
||||
NS_IF_ADDREF(*aStatus);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TLSServerConnectionInfo::GetPeerCert(nsIX509Cert** aCert)
|
||||
{
|
||||
if (NS_WARN_IF(!aCert)) {
|
||||
return NS_ERROR_INVALID_POINTER;
|
||||
}
|
||||
*aCert = mPeerCert;
|
||||
NS_IF_ADDREF(*aCert);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TLSServerConnectionInfo::GetTlsVersionUsed(int16_t* aTlsVersionUsed)
|
||||
{
|
||||
if (NS_WARN_IF(!aTlsVersionUsed)) {
|
||||
return NS_ERROR_INVALID_POINTER;
|
||||
}
|
||||
*aTlsVersionUsed = mTlsVersionUsed;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TLSServerConnectionInfo::GetCipherName(nsACString& aCipherName)
|
||||
{
|
||||
aCipherName.Assign(mCipherName);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TLSServerConnectionInfo::GetKeyLength(uint32_t* aKeyLength)
|
||||
{
|
||||
if (NS_WARN_IF(!aKeyLength)) {
|
||||
return NS_ERROR_INVALID_POINTER;
|
||||
}
|
||||
*aKeyLength = mKeyLength;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TLSServerConnectionInfo::GetMacLength(uint32_t* aMacLength)
|
||||
{
|
||||
if (NS_WARN_IF(!aMacLength)) {
|
||||
return NS_ERROR_INVALID_POINTER;
|
||||
}
|
||||
*aMacLength = mMacLength;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
TLSServerConnectionInfo::HandshakeCallback(PRFileDesc* aFD, void* aArg)
|
||||
{
|
||||
RefPtr<TLSServerConnectionInfo> info =
|
||||
static_cast<TLSServerConnectionInfo*>(aArg);
|
||||
nsISocketTransport* transport = info->mTransport;
|
||||
// No longer needed outside this function, so clear the weak ref
|
||||
info->mTransport = nullptr;
|
||||
nsresult rv = info->HandshakeCallback(aFD);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
transport->Close(rv);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
TLSServerConnectionInfo::HandshakeCallback(PRFileDesc* aFD)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
UniqueCERTCertificate clientCert(SSL_PeerCertificate(aFD));
|
||||
if (clientCert) {
|
||||
nsCOMPtr<nsIX509CertDB> certDB =
|
||||
do_GetService(NS_X509CERTDB_CONTRACTID, &rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIX509Cert> clientCertPSM;
|
||||
rv = certDB->ConstructX509(reinterpret_cast<char*>(clientCert->derCert.data),
|
||||
clientCert->derCert.len,
|
||||
getter_AddRefs(clientCertPSM));
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
mPeerCert = clientCertPSM;
|
||||
}
|
||||
|
||||
SSLChannelInfo channelInfo;
|
||||
rv = MapSECStatus(SSL_GetChannelInfo(aFD, &channelInfo, sizeof(channelInfo)));
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
mTlsVersionUsed = channelInfo.protocolVersion;
|
||||
|
||||
SSLCipherSuiteInfo cipherInfo;
|
||||
rv = MapSECStatus(SSL_GetCipherSuiteInfo(channelInfo.cipherSuite, &cipherInfo,
|
||||
sizeof(cipherInfo)));
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
mCipherName.Assign(cipherInfo.cipherSuiteName);
|
||||
mKeyLength = cipherInfo.effectiveKeyBits;
|
||||
mMacLength = cipherInfo.macBits;
|
||||
|
||||
if (!mSecurityObserver) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Notify consumer code that handshake is complete
|
||||
nsCOMPtr<nsITLSServerSecurityObserver> observer;
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
mSecurityObserver.swap(observer);
|
||||
}
|
||||
nsCOMPtr<nsITLSServerSocket> serverSocket;
|
||||
GetServerSocket(getter_AddRefs(serverSocket));
|
||||
observer->OnHandshakeDone(serverSocket, this);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
81
netwerk/base/TLSServerSocket.h
Normal file
81
netwerk/base/TLSServerSocket.h
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
/* vim:set ts=2 sw=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_net_TLSServerSocket_h
|
||||
#define mozilla_net_TLSServerSocket_h
|
||||
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsITLSServerSocket.h"
|
||||
#include "nsServerSocket.h"
|
||||
#include "nsString.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "seccomon.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
class TLSServerSocket final : public nsServerSocket
|
||||
, public nsITLSServerSocket
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_FORWARD_NSISERVERSOCKET(nsServerSocket::)
|
||||
NS_DECL_NSITLSSERVERSOCKET
|
||||
|
||||
// Override methods from nsServerSocket
|
||||
virtual void CreateClientTransport(PRFileDesc* clientFD,
|
||||
const NetAddr& clientAddr) override;
|
||||
virtual nsresult SetSocketDefaults() override;
|
||||
virtual nsresult OnSocketListen() override;
|
||||
|
||||
TLSServerSocket();
|
||||
|
||||
private:
|
||||
virtual ~TLSServerSocket();
|
||||
|
||||
static SECStatus AuthCertificateHook(void* arg, PRFileDesc* fd,
|
||||
PRBool checksig, PRBool isServer);
|
||||
|
||||
nsCOMPtr<nsIX509Cert> mServerCert;
|
||||
};
|
||||
|
||||
class TLSServerConnectionInfo : public nsITLSServerConnectionInfo
|
||||
, public nsITLSClientStatus
|
||||
{
|
||||
friend class TLSServerSocket;
|
||||
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSITLSSERVERCONNECTIONINFO
|
||||
NS_DECL_NSITLSCLIENTSTATUS
|
||||
|
||||
TLSServerConnectionInfo();
|
||||
|
||||
private:
|
||||
virtual ~TLSServerConnectionInfo();
|
||||
|
||||
static void HandshakeCallback(PRFileDesc* aFD, void* aArg);
|
||||
nsresult HandshakeCallback(PRFileDesc* aFD);
|
||||
|
||||
RefPtr<TLSServerSocket> mServerSocket;
|
||||
// Weak ref to the transport, to avoid cycles since the transport holds a
|
||||
// reference to the TLSServerConnectionInfo object. This is not handed out to
|
||||
// anyone, and is only used in HandshakeCallback to close the transport in
|
||||
// case of an error. After this, it's set to nullptr.
|
||||
nsISocketTransport* mTransport;
|
||||
nsCOMPtr<nsIX509Cert> mPeerCert;
|
||||
int16_t mTlsVersionUsed;
|
||||
nsCString mCipherName;
|
||||
uint32_t mKeyLength;
|
||||
uint32_t mMacLength;
|
||||
// lock protects access to mSecurityObserver
|
||||
mozilla::Mutex mLock;
|
||||
nsCOMPtr<nsITLSServerSecurityObserver> mSecurityObserver;
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_net_TLSServerSocket_h
|
||||
392
netwerk/base/ThrottleQueue.cpp
Normal file
392
netwerk/base/ThrottleQueue.cpp
Normal file
|
|
@ -0,0 +1,392 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ThrottleQueue.h"
|
||||
#include "nsISeekableStream.h"
|
||||
#include "nsIAsyncInputStream.h"
|
||||
#include "nsStreamUtils.h"
|
||||
#include "nsNetUtil.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class ThrottleInputStream final
|
||||
: public nsIAsyncInputStream
|
||||
, public nsISeekableStream
|
||||
{
|
||||
public:
|
||||
|
||||
ThrottleInputStream(nsIInputStream* aStream, ThrottleQueue* aQueue);
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIINPUTSTREAM
|
||||
NS_DECL_NSISEEKABLESTREAM
|
||||
NS_DECL_NSIASYNCINPUTSTREAM
|
||||
|
||||
void AllowInput();
|
||||
|
||||
private:
|
||||
|
||||
~ThrottleInputStream();
|
||||
|
||||
nsCOMPtr<nsIInputStream> mStream;
|
||||
RefPtr<ThrottleQueue> mQueue;
|
||||
nsresult mClosedStatus;
|
||||
|
||||
nsCOMPtr<nsIInputStreamCallback> mCallback;
|
||||
nsCOMPtr<nsIEventTarget> mEventTarget;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(ThrottleInputStream, nsIAsyncInputStream, nsIInputStream, nsISeekableStream)
|
||||
|
||||
ThrottleInputStream::ThrottleInputStream(nsIInputStream *aStream, ThrottleQueue* aQueue)
|
||||
: mStream(aStream)
|
||||
, mQueue(aQueue)
|
||||
, mClosedStatus(NS_OK)
|
||||
{
|
||||
MOZ_ASSERT(aQueue != nullptr);
|
||||
}
|
||||
|
||||
ThrottleInputStream::~ThrottleInputStream()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ThrottleInputStream::Close()
|
||||
{
|
||||
if (NS_FAILED(mClosedStatus)) {
|
||||
return mClosedStatus;
|
||||
}
|
||||
|
||||
if (mQueue) {
|
||||
mQueue->DequeueStream(this);
|
||||
mQueue = nullptr;
|
||||
mClosedStatus = NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
return mStream->Close();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ThrottleInputStream::Available(uint64_t* aResult)
|
||||
{
|
||||
if (NS_FAILED(mClosedStatus)) {
|
||||
return mClosedStatus;
|
||||
}
|
||||
|
||||
return mStream->Available(aResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ThrottleInputStream::Read(char* aBuf, uint32_t aCount, uint32_t* aResult)
|
||||
{
|
||||
if (NS_FAILED(mClosedStatus)) {
|
||||
return mClosedStatus;
|
||||
}
|
||||
|
||||
uint32_t realCount;
|
||||
nsresult rv = mQueue->Available(aCount, &realCount);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (realCount == 0) {
|
||||
return NS_BASE_STREAM_WOULD_BLOCK;
|
||||
}
|
||||
|
||||
rv = mStream->Read(aBuf, realCount, aResult);
|
||||
if (NS_SUCCEEDED(rv) && *aResult > 0) {
|
||||
mQueue->RecordRead(*aResult);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ThrottleInputStream::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
|
||||
uint32_t aCount, uint32_t* aResult)
|
||||
{
|
||||
if (NS_FAILED(mClosedStatus)) {
|
||||
return mClosedStatus;
|
||||
}
|
||||
|
||||
uint32_t realCount;
|
||||
nsresult rv = mQueue->Available(aCount, &realCount);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (realCount == 0) {
|
||||
return NS_BASE_STREAM_WOULD_BLOCK;
|
||||
}
|
||||
|
||||
rv = mStream->ReadSegments(aWriter, aClosure, realCount, aResult);
|
||||
if (NS_SUCCEEDED(rv) && *aResult > 0) {
|
||||
mQueue->RecordRead(*aResult);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ThrottleInputStream::IsNonBlocking(bool* aNonBlocking)
|
||||
{
|
||||
*aNonBlocking = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ThrottleInputStream::Seek(int32_t aWhence, int64_t aOffset)
|
||||
{
|
||||
if (NS_FAILED(mClosedStatus)) {
|
||||
return mClosedStatus;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISeekableStream> sstream = do_QueryInterface(mStream);
|
||||
if (!sstream) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return sstream->Seek(aWhence, aOffset);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ThrottleInputStream::Tell(int64_t* aResult)
|
||||
{
|
||||
if (NS_FAILED(mClosedStatus)) {
|
||||
return mClosedStatus;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISeekableStream> sstream = do_QueryInterface(mStream);
|
||||
if (!sstream) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return sstream->Tell(aResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ThrottleInputStream::SetEOF()
|
||||
{
|
||||
if (NS_FAILED(mClosedStatus)) {
|
||||
return mClosedStatus;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISeekableStream> sstream = do_QueryInterface(mStream);
|
||||
if (!sstream) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return sstream->SetEOF();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ThrottleInputStream::CloseWithStatus(nsresult aStatus)
|
||||
{
|
||||
if (NS_FAILED(mClosedStatus)) {
|
||||
// Already closed, ignore.
|
||||
return NS_OK;
|
||||
}
|
||||
if (NS_SUCCEEDED(aStatus)) {
|
||||
aStatus = NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
|
||||
mClosedStatus = Close();
|
||||
if (NS_SUCCEEDED(mClosedStatus)) {
|
||||
mClosedStatus = aStatus;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ThrottleInputStream::AsyncWait(nsIInputStreamCallback *aCallback,
|
||||
uint32_t aFlags,
|
||||
uint32_t aRequestedCount,
|
||||
nsIEventTarget *aEventTarget)
|
||||
{
|
||||
if (aFlags != 0) {
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
|
||||
mCallback = aCallback;
|
||||
mEventTarget = aEventTarget;
|
||||
if (mCallback) {
|
||||
mQueue->QueueStream(this);
|
||||
} else {
|
||||
mQueue->DequeueStream(this);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
ThrottleInputStream::AllowInput()
|
||||
{
|
||||
MOZ_ASSERT(mCallback);
|
||||
nsCOMPtr<nsIInputStreamCallback> callbackEvent =
|
||||
NS_NewInputStreamReadyEvent(mCallback, mEventTarget);
|
||||
mCallback = nullptr;
|
||||
mEventTarget = nullptr;
|
||||
callbackEvent->OnInputStreamReady(this);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
NS_IMPL_ISUPPORTS(ThrottleQueue, nsIInputChannelThrottleQueue, nsITimerCallback)
|
||||
|
||||
ThrottleQueue::ThrottleQueue()
|
||||
: mMeanBytesPerSecond(0)
|
||||
, mMaxBytesPerSecond(0)
|
||||
, mBytesProcessed(0)
|
||||
, mTimerArmed(false)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIEventTarget> sts;
|
||||
nsCOMPtr<nsIIOService> ioService = do_GetIOService(&rv);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
sts = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
mTimer = do_CreateInstance("@mozilla.org/timer;1");
|
||||
if (mTimer)
|
||||
mTimer->SetTarget(sts);
|
||||
}
|
||||
|
||||
ThrottleQueue::~ThrottleQueue()
|
||||
{
|
||||
if (mTimer && mTimerArmed) {
|
||||
mTimer->Cancel();
|
||||
}
|
||||
mTimer = nullptr;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ThrottleQueue::RecordRead(uint32_t aBytesRead)
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
ThrottleEntry entry;
|
||||
entry.mTime = TimeStamp::Now();
|
||||
entry.mBytesRead = aBytesRead;
|
||||
mReadEvents.AppendElement(entry);
|
||||
mBytesProcessed += aBytesRead;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ThrottleQueue::Available(uint32_t aRemaining, uint32_t* aAvailable)
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
TimeStamp now = TimeStamp::Now();
|
||||
TimeStamp oneSecondAgo = now - TimeDuration::FromSeconds(1);
|
||||
size_t i;
|
||||
|
||||
// Remove all stale events.
|
||||
for (i = 0; i < mReadEvents.Length(); ++i) {
|
||||
if (mReadEvents[i].mTime >= oneSecondAgo) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
mReadEvents.RemoveElementsAt(0, i);
|
||||
|
||||
uint32_t totalBytes = 0;
|
||||
for (i = 0; i < mReadEvents.Length(); ++i) {
|
||||
totalBytes += mReadEvents[i].mBytesRead;
|
||||
}
|
||||
|
||||
uint32_t spread = mMaxBytesPerSecond - mMeanBytesPerSecond;
|
||||
double prob = static_cast<double>(rand()) / RAND_MAX;
|
||||
uint32_t thisSliceBytes = mMeanBytesPerSecond - spread +
|
||||
static_cast<uint32_t>(2 * spread * prob);
|
||||
|
||||
if (totalBytes >= thisSliceBytes) {
|
||||
*aAvailable = 0;
|
||||
} else {
|
||||
*aAvailable = thisSliceBytes;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ThrottleQueue::Init(uint32_t aMeanBytesPerSecond, uint32_t aMaxBytesPerSecond)
|
||||
{
|
||||
// Can be called on any thread.
|
||||
if (aMeanBytesPerSecond == 0 || aMaxBytesPerSecond == 0 || aMaxBytesPerSecond < aMeanBytesPerSecond) {
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
|
||||
mMeanBytesPerSecond = aMeanBytesPerSecond;
|
||||
mMaxBytesPerSecond = aMaxBytesPerSecond;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ThrottleQueue::BytesProcessed(uint64_t* aResult)
|
||||
{
|
||||
*aResult = mBytesProcessed;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ThrottleQueue::WrapStream(nsIInputStream* aInputStream, nsIAsyncInputStream** aResult)
|
||||
{
|
||||
nsCOMPtr<nsIAsyncInputStream> result = new ThrottleInputStream(aInputStream, this);
|
||||
result.forget(aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ThrottleQueue::Notify(nsITimer* aTimer)
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
// A notified reader may need to push itself back on the queue.
|
||||
// Swap out the list of readers so that this works properly.
|
||||
nsTArray<RefPtr<ThrottleInputStream>> events;
|
||||
events.SwapElements(mAsyncEvents);
|
||||
|
||||
// Optimistically notify all the waiting readers, and then let them
|
||||
// requeue if there isn't enough bandwidth.
|
||||
for (size_t i = 0; i < events.Length(); ++i) {
|
||||
events[i]->AllowInput();
|
||||
}
|
||||
|
||||
mTimerArmed = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
ThrottleQueue::QueueStream(ThrottleInputStream* aStream)
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
if (mAsyncEvents.IndexOf(aStream) == mAsyncEvents.NoIndex) {
|
||||
mAsyncEvents.AppendElement(aStream);
|
||||
|
||||
if (!mTimerArmed) {
|
||||
uint32_t ms = 1000;
|
||||
if (mReadEvents.Length() > 0) {
|
||||
TimeStamp t = mReadEvents[0].mTime + TimeDuration::FromSeconds(1);
|
||||
TimeStamp now = TimeStamp::Now();
|
||||
|
||||
if (t > now) {
|
||||
ms = static_cast<uint32_t>((t - now).ToMilliseconds());
|
||||
} else {
|
||||
ms = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(mTimer->InitWithCallback(this, ms, nsITimer::TYPE_ONE_SHOT))) {
|
||||
mTimerArmed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ThrottleQueue::DequeueStream(ThrottleInputStream* aStream)
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
mAsyncEvents.RemoveElement(aStream);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
65
netwerk/base/ThrottleQueue.h
Normal file
65
netwerk/base/ThrottleQueue.h
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_net_ThrottleQueue_h
|
||||
#define mozilla_net_ThrottleQueue_h
|
||||
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "nsIThrottledInputChannel.h"
|
||||
#include "nsITimer.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
class ThrottleInputStream;
|
||||
|
||||
/**
|
||||
* An implementation of nsIInputChannelThrottleQueue that can be used
|
||||
* to throttle uploads. This class is not thread-safe.
|
||||
* Initialization and calls to WrapStream may be done on any thread;
|
||||
* but otherwise, after creation, it can only be used on the socket
|
||||
* thread. It currently throttles with a one second granularity, so
|
||||
* may be a bit choppy.
|
||||
*/
|
||||
|
||||
class ThrottleQueue final
|
||||
: public nsIInputChannelThrottleQueue
|
||||
, public nsITimerCallback
|
||||
{
|
||||
public:
|
||||
|
||||
ThrottleQueue();
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIINPUTCHANNELTHROTTLEQUEUE
|
||||
NS_DECL_NSITIMERCALLBACK
|
||||
|
||||
void QueueStream(ThrottleInputStream* aStream);
|
||||
void DequeueStream(ThrottleInputStream* aStream);
|
||||
|
||||
private:
|
||||
|
||||
~ThrottleQueue();
|
||||
|
||||
struct ThrottleEntry {
|
||||
TimeStamp mTime;
|
||||
uint32_t mBytesRead;
|
||||
};
|
||||
|
||||
nsTArray<ThrottleEntry> mReadEvents;
|
||||
uint32_t mMeanBytesPerSecond;
|
||||
uint32_t mMaxBytesPerSecond;
|
||||
uint64_t mBytesProcessed;
|
||||
|
||||
nsTArray<RefPtr<ThrottleInputStream>> mAsyncEvents;
|
||||
nsCOMPtr<nsITimer> mTimer;
|
||||
bool mTimerArmed;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // mozilla_net_ThrottleQueue_h
|
||||
277
netwerk/base/Tickler.cpp
Normal file
277
netwerk/base/Tickler.cpp
Normal file
|
|
@ -0,0 +1,277 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "Tickler.h"
|
||||
|
||||
#ifdef MOZ_USE_WIFI_TICKLER
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsIPrefBranch.h"
|
||||
#include "nsIPrefService.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "prnetdb.h"
|
||||
|
||||
#include "mozilla/jni/Utils.h"
|
||||
#include "GeneratedJNIWrappers.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
NS_IMPL_ISUPPORTS(Tickler, nsISupportsWeakReference, Tickler)
|
||||
|
||||
Tickler::Tickler()
|
||||
: mLock("Tickler::mLock")
|
||||
, mActive(false)
|
||||
, mCanceled(false)
|
||||
, mEnabled(false)
|
||||
, mDelay(16)
|
||||
, mDuration(TimeDuration::FromMilliseconds(400))
|
||||
, mFD(nullptr)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
}
|
||||
|
||||
Tickler::~Tickler()
|
||||
{
|
||||
// non main thread uses of the tickler should hold weak
|
||||
// references to it if they must hold a reference at all
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (mThread) {
|
||||
mThread->AsyncShutdown();
|
||||
mThread = nullptr;
|
||||
}
|
||||
|
||||
if (mTimer)
|
||||
mTimer->Cancel();
|
||||
if (mFD)
|
||||
PR_Close(mFD);
|
||||
}
|
||||
|
||||
nsresult
|
||||
Tickler::Init()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!mTimer);
|
||||
MOZ_ASSERT(!mActive);
|
||||
MOZ_ASSERT(!mThread);
|
||||
MOZ_ASSERT(!mFD);
|
||||
|
||||
if (jni::IsAvailable()) {
|
||||
java::GeckoAppShell::EnableNetworkNotifications();
|
||||
}
|
||||
|
||||
mFD = PR_OpenUDPSocket(PR_AF_INET);
|
||||
if (!mFD)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// make sure new socket has a ttl of 1
|
||||
// failure is not fatal.
|
||||
PRSocketOptionData opt;
|
||||
opt.option = PR_SockOpt_IpTimeToLive;
|
||||
opt.value.ip_ttl = 1;
|
||||
PR_SetSocketOption(mFD, &opt);
|
||||
|
||||
nsresult rv = NS_NewNamedThread("wifi tickler",
|
||||
getter_AddRefs(mThread));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
nsCOMPtr<nsITimer> tmpTimer(do_CreateInstance(NS_TIMER_CONTRACTID, &rv));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
rv = tmpTimer->SetTarget(mThread);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
mTimer.swap(tmpTimer);
|
||||
|
||||
mAddr.inet.family = PR_AF_INET;
|
||||
mAddr.inet.port = PR_htons (4886);
|
||||
mAddr.inet.ip = 0;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void Tickler::Tickle()
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
MOZ_ASSERT(mThread);
|
||||
mLastTickle = TimeStamp::Now();
|
||||
if (!mActive)
|
||||
MaybeStartTickler();
|
||||
}
|
||||
|
||||
void Tickler::PostCheckTickler()
|
||||
{
|
||||
mLock.AssertCurrentThreadOwns();
|
||||
mThread->Dispatch(NewRunnableMethod(this, &Tickler::CheckTickler),
|
||||
NS_DISPATCH_NORMAL);
|
||||
return;
|
||||
}
|
||||
|
||||
void Tickler::MaybeStartTicklerUnlocked()
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
MaybeStartTickler();
|
||||
}
|
||||
|
||||
void Tickler::MaybeStartTickler()
|
||||
{
|
||||
mLock.AssertCurrentThreadOwns();
|
||||
if (!NS_IsMainThread()) {
|
||||
NS_DispatchToMainThread(
|
||||
NewRunnableMethod(this, &Tickler::MaybeStartTicklerUnlocked));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mPrefs)
|
||||
mPrefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
|
||||
if (mPrefs) {
|
||||
int32_t val;
|
||||
bool boolVal;
|
||||
|
||||
if (NS_SUCCEEDED(mPrefs->GetBoolPref("network.tickle-wifi.enabled", &boolVal)))
|
||||
mEnabled = boolVal;
|
||||
|
||||
if (NS_SUCCEEDED(mPrefs->GetIntPref("network.tickle-wifi.duration", &val))) {
|
||||
if (val < 1)
|
||||
val = 1;
|
||||
if (val > 100000)
|
||||
val = 100000;
|
||||
mDuration = TimeDuration::FromMilliseconds(val);
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(mPrefs->GetIntPref("network.tickle-wifi.delay", &val))) {
|
||||
if (val < 1)
|
||||
val = 1;
|
||||
if (val > 1000)
|
||||
val = 1000;
|
||||
mDelay = static_cast<uint32_t>(val);
|
||||
}
|
||||
}
|
||||
|
||||
PostCheckTickler();
|
||||
}
|
||||
|
||||
void Tickler::CheckTickler()
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
MOZ_ASSERT(mThread == NS_GetCurrentThread());
|
||||
|
||||
bool shouldRun = (!mCanceled) &&
|
||||
((TimeStamp::Now() - mLastTickle) <= mDuration);
|
||||
|
||||
if ((shouldRun && mActive) || (!shouldRun && !mActive))
|
||||
return; // no change in state
|
||||
|
||||
if (mActive)
|
||||
StopTickler();
|
||||
else
|
||||
StartTickler();
|
||||
}
|
||||
|
||||
void Tickler::Cancel()
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mCanceled = true;
|
||||
if (mThread)
|
||||
PostCheckTickler();
|
||||
}
|
||||
|
||||
void Tickler::StopTickler()
|
||||
{
|
||||
mLock.AssertCurrentThreadOwns();
|
||||
MOZ_ASSERT(mThread == NS_GetCurrentThread());
|
||||
MOZ_ASSERT(mTimer);
|
||||
MOZ_ASSERT(mActive);
|
||||
|
||||
mTimer->Cancel();
|
||||
mActive = false;
|
||||
}
|
||||
|
||||
class TicklerTimer final : public nsITimerCallback
|
||||
{
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSITIMERCALLBACK
|
||||
|
||||
TicklerTimer(Tickler *aTickler)
|
||||
{
|
||||
mTickler = do_GetWeakReference(aTickler);
|
||||
}
|
||||
|
||||
private:
|
||||
~TicklerTimer() {}
|
||||
|
||||
nsWeakPtr mTickler;
|
||||
};
|
||||
|
||||
void Tickler::StartTickler()
|
||||
{
|
||||
mLock.AssertCurrentThreadOwns();
|
||||
MOZ_ASSERT(mThread == NS_GetCurrentThread());
|
||||
MOZ_ASSERT(!mActive);
|
||||
MOZ_ASSERT(mTimer);
|
||||
|
||||
if (NS_SUCCEEDED(mTimer->InitWithCallback(new TicklerTimer(this),
|
||||
mEnabled ? mDelay : 1000,
|
||||
nsITimer::TYPE_REPEATING_SLACK)))
|
||||
mActive = true;
|
||||
}
|
||||
|
||||
// argument should be in network byte order
|
||||
void Tickler::SetIPV4Address(uint32_t address)
|
||||
{
|
||||
mAddr.inet.ip = address;
|
||||
}
|
||||
|
||||
// argument should be in network byte order
|
||||
void Tickler::SetIPV4Port(uint16_t port)
|
||||
{
|
||||
mAddr.inet.port = port;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(TicklerTimer, nsITimerCallback)
|
||||
|
||||
NS_IMETHODIMP TicklerTimer::Notify(nsITimer *timer)
|
||||
{
|
||||
RefPtr<Tickler> tickler = do_QueryReferent(mTickler);
|
||||
if (!tickler)
|
||||
return NS_ERROR_FAILURE;
|
||||
MutexAutoLock lock(tickler->mLock);
|
||||
|
||||
if (!tickler->mFD) {
|
||||
tickler->StopTickler();
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (tickler->mCanceled ||
|
||||
((TimeStamp::Now() - tickler->mLastTickle) > tickler->mDuration)) {
|
||||
tickler->StopTickler();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!tickler->mEnabled)
|
||||
return NS_OK;
|
||||
|
||||
PR_SendTo(tickler->mFD, "", 0, 0, &tickler->mAddr, 0);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace mozilla::net
|
||||
} // namespace mozilla
|
||||
|
||||
#else // not defined MOZ_USE_WIFI_TICKLER
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
NS_IMPL_ISUPPORTS0(Tickler)
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // defined MOZ_USE_WIFI_TICKLER
|
||||
|
||||
131
netwerk/base/Tickler.h
Normal file
131
netwerk/base/Tickler.h
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_net_Tickler_h
|
||||
#define mozilla_net_Tickler_h
|
||||
|
||||
// The tickler sends a regular 0 byte UDP heartbeat out to a
|
||||
// particular address for a short time after it has been touched. This
|
||||
// is used on some mobile wifi chipsets to mitigate Power Save Polling
|
||||
// (PSP) Mode when we are anticipating a response packet
|
||||
// soon. Typically PSP adds 100ms of latency to a read event because
|
||||
// the packet delivery is not triggered until the 802.11 beacon is
|
||||
// delivered to the host (100ms is the standard Access Point
|
||||
// configuration for the beacon interval.) Requesting a frequent
|
||||
// transmission and getting a CTS frame from the AP at least that
|
||||
// frequently allows for low latency receives when we have reason to
|
||||
// expect them (e.g a SYN-ACK).
|
||||
//
|
||||
// The tickler is used to allow RTT based phases of web transport to
|
||||
// complete quickly when on wifi - ARP, DNS, TCP handshake, SSL
|
||||
// handshake, HTTP headers, and the TCP slow start phase. The
|
||||
// transaction is given up to 400 miliseconds by default to get
|
||||
// through those phases before the tickler is disabled.
|
||||
//
|
||||
// The tickler only applies to wifi on mobile right now. Hopefully it
|
||||
// can also be restricted to particular handset models in the future.
|
||||
|
||||
#if defined(ANDROID) && !defined(MOZ_B2G)
|
||||
#define MOZ_USE_WIFI_TICKLER
|
||||
#endif
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsISupports.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef MOZ_USE_WIFI_TICKLER
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsISupports.h"
|
||||
#include "nsIThread.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsWeakReference.h"
|
||||
#include "prio.h"
|
||||
|
||||
class nsIPrefBranch;
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
#ifdef MOZ_USE_WIFI_TICKLER
|
||||
|
||||
// 8f769ed6-207c-4af9-9f7e-9e832da3754e
|
||||
#define NS_TICKLER_IID \
|
||||
{ 0x8f769ed6, 0x207c, 0x4af9, \
|
||||
{ 0x9f, 0x7e, 0x9e, 0x83, 0x2d, 0xa3, 0x75, 0x4e } }
|
||||
|
||||
class Tickler final : public nsSupportsWeakReference
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_TICKLER_IID)
|
||||
|
||||
// These methods are main thread only
|
||||
Tickler();
|
||||
void Cancel();
|
||||
nsresult Init();
|
||||
void SetIPV4Address(uint32_t address);
|
||||
void SetIPV4Port(uint16_t port);
|
||||
|
||||
// Tickle the tickler to (re-)start the activity.
|
||||
// May call from any thread
|
||||
void Tickle();
|
||||
|
||||
private:
|
||||
~Tickler();
|
||||
|
||||
friend class TicklerTimer;
|
||||
Mutex mLock;
|
||||
nsCOMPtr<nsIThread> mThread;
|
||||
nsCOMPtr<nsITimer> mTimer;
|
||||
nsCOMPtr<nsIPrefBranch> mPrefs;
|
||||
|
||||
bool mActive;
|
||||
bool mCanceled;
|
||||
bool mEnabled;
|
||||
uint32_t mDelay;
|
||||
TimeDuration mDuration;
|
||||
PRFileDesc* mFD;
|
||||
|
||||
TimeStamp mLastTickle;
|
||||
PRNetAddr mAddr;
|
||||
|
||||
// These functions may be called from any thread
|
||||
void PostCheckTickler();
|
||||
void MaybeStartTickler();
|
||||
void MaybeStartTicklerUnlocked();
|
||||
|
||||
// Tickler thread only
|
||||
void CheckTickler();
|
||||
void StartTickler();
|
||||
void StopTickler();
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(Tickler, NS_TICKLER_IID)
|
||||
|
||||
#else // not defined MOZ_USE_WIFI_TICKLER
|
||||
|
||||
class Tickler final : public nsISupports
|
||||
{
|
||||
~Tickler() { }
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
Tickler() { }
|
||||
nsresult Init() { return NS_ERROR_NOT_IMPLEMENTED; }
|
||||
void Cancel() { }
|
||||
void SetIPV4Address(uint32_t) { };
|
||||
void SetIPV4Port(uint16_t) { }
|
||||
void Tickle() { }
|
||||
};
|
||||
|
||||
#endif // defined MOZ_USE_WIFI_TICKLER
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_net_Tickler_h
|
||||
316
netwerk/base/moz.build
Normal file
316
netwerk/base/moz.build
Normal file
|
|
@ -0,0 +1,316 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
'mozIThirdPartyUtil.idl',
|
||||
'nsIApplicationCache.idl',
|
||||
'nsIApplicationCacheChannel.idl',
|
||||
'nsIApplicationCacheContainer.idl',
|
||||
'nsIApplicationCacheService.idl',
|
||||
'nsIArrayBufferInputStream.idl',
|
||||
'nsIAsyncStreamCopier.idl',
|
||||
'nsIAsyncStreamCopier2.idl',
|
||||
'nsIAsyncVerifyRedirectCallback.idl',
|
||||
'nsIAuthInformation.idl',
|
||||
'nsIAuthModule.idl',
|
||||
'nsIAuthPrompt.idl',
|
||||
'nsIAuthPrompt2.idl',
|
||||
'nsIAuthPromptAdapterFactory.idl',
|
||||
'nsIAuthPromptCallback.idl',
|
||||
'nsIAuthPromptProvider.idl',
|
||||
'nsIBackgroundFileSaver.idl',
|
||||
'nsIBufferedStreams.idl',
|
||||
'nsIByteRangeRequest.idl',
|
||||
'nsICacheInfoChannel.idl',
|
||||
'nsICachingChannel.idl',
|
||||
'nsICancelable.idl',
|
||||
'nsICaptivePortalService.idl',
|
||||
'nsIChannel.idl',
|
||||
'nsIChannelEventSink.idl',
|
||||
'nsIChannelWithDivertableParentListener.idl',
|
||||
'nsIChildChannel.idl',
|
||||
'nsIClassOfService.idl',
|
||||
'nsIContentSniffer.idl',
|
||||
'nsICryptoFIPSInfo.idl',
|
||||
'nsICryptoHash.idl',
|
||||
'nsICryptoHMAC.idl',
|
||||
'nsIDashboard.idl',
|
||||
'nsIDashboardEventNotifier.idl',
|
||||
'nsIDeprecationWarner.idl',
|
||||
'nsIDivertableChannel.idl',
|
||||
'nsIDownloader.idl',
|
||||
'nsIEncodedChannel.idl',
|
||||
'nsIExternalProtocolHandler.idl',
|
||||
'nsIFileStreams.idl',
|
||||
'nsIFileURL.idl',
|
||||
'nsIForcePendingChannel.idl',
|
||||
'nsIFormPOSTActionChannel.idl',
|
||||
'nsIHttpAuthenticatorCallback.idl',
|
||||
'nsIHttpPushListener.idl',
|
||||
'nsIIncrementalDownload.idl',
|
||||
'nsIIncrementalStreamLoader.idl',
|
||||
'nsIInputStreamChannel.idl',
|
||||
'nsIInputStreamPump.idl',
|
||||
'nsIIOService.idl',
|
||||
'nsIIOService2.idl',
|
||||
'nsILoadContextInfo.idl',
|
||||
'nsILoadGroup.idl',
|
||||
'nsILoadGroupChild.idl',
|
||||
'nsILoadInfo.idl',
|
||||
'nsIMIMEInputStream.idl',
|
||||
'nsIMultiPartChannel.idl',
|
||||
'nsINestedURI.idl',
|
||||
'nsINetAddr.idl',
|
||||
'nsINetUtil.idl',
|
||||
'nsINetworkInfoService.idl',
|
||||
'nsINetworkInterceptController.idl',
|
||||
'nsINetworkLinkService.idl',
|
||||
'nsINetworkPredictor.idl',
|
||||
'nsINetworkPredictorVerifier.idl',
|
||||
'nsINetworkProperties.idl',
|
||||
'nsINSSErrorsService.idl',
|
||||
'nsINullChannel.idl',
|
||||
'nsIParentChannel.idl',
|
||||
'nsIParentRedirectingChannel.idl',
|
||||
'nsIPermission.idl',
|
||||
'nsIPermissionManager.idl',
|
||||
'nsIPrivateBrowsingChannel.idl',
|
||||
'nsIProgressEventSink.idl',
|
||||
'nsIPrompt.idl',
|
||||
'nsIProtocolHandler.idl',
|
||||
'nsIProtocolProxyCallback.idl',
|
||||
'nsIProtocolProxyFilter.idl',
|
||||
'nsIProtocolProxyService.idl',
|
||||
'nsIProtocolProxyService2.idl',
|
||||
'nsIProxiedChannel.idl',
|
||||
'nsIProxiedProtocolHandler.idl',
|
||||
'nsIProxyInfo.idl',
|
||||
'nsIRandomGenerator.idl',
|
||||
'nsIRedirectChannelRegistrar.idl',
|
||||
'nsIRedirectResultListener.idl',
|
||||
'nsIRequest.idl',
|
||||
'nsIRequestContext.idl',
|
||||
'nsIRequestObserver.idl',
|
||||
'nsIRequestObserverProxy.idl',
|
||||
'nsIResumableChannel.idl',
|
||||
'nsISecCheckWrapChannel.idl',
|
||||
'nsISecureBrowserUI.idl',
|
||||
'nsISecurityEventSink.idl',
|
||||
'nsISecurityInfoProvider.idl',
|
||||
'nsISensitiveInfoHiddenURI.idl',
|
||||
'nsISerializationHelper.idl',
|
||||
'nsIServerSocket.idl',
|
||||
'nsISimpleStreamListener.idl',
|
||||
'nsISocketFilter.idl',
|
||||
'nsISocketTransport.idl',
|
||||
'nsISocketTransportService.idl',
|
||||
'nsISpeculativeConnect.idl',
|
||||
'nsIStandardURL.idl',
|
||||
'nsIStreamingProtocolController.idl',
|
||||
'nsIStreamingProtocolService.idl',
|
||||
'nsIStreamListener.idl',
|
||||
'nsIStreamListenerTee.idl',
|
||||
'nsIStreamLoader.idl',
|
||||
'nsIStreamTransportService.idl',
|
||||
'nsISyncStreamListener.idl',
|
||||
'nsISystemProxySettings.idl',
|
||||
'nsIThreadRetargetableRequest.idl',
|
||||
'nsIThreadRetargetableStreamListener.idl',
|
||||
'nsIThrottledInputChannel.idl',
|
||||
'nsITimedChannel.idl',
|
||||
'nsITLSServerSocket.idl',
|
||||
'nsITraceableChannel.idl',
|
||||
'nsITransport.idl',
|
||||
'nsIUDPSocket.idl',
|
||||
'nsIUnicharStreamLoader.idl',
|
||||
'nsIUploadChannel.idl',
|
||||
'nsIUploadChannel2.idl',
|
||||
'nsIURI.idl',
|
||||
'nsIURIClassifier.idl',
|
||||
'nsIURIWithBlobImpl.idl',
|
||||
'nsIURIWithPrincipal.idl',
|
||||
'nsIURIWithQuery.idl',
|
||||
'nsIURL.idl',
|
||||
'nsIURLParser.idl',
|
||||
'nsPILoadGroupInternal.idl',
|
||||
'nsPISocketTransportService.idl',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_TOOLKIT_SEARCH']:
|
||||
XPIDL_SOURCES += [
|
||||
'nsIBrowserSearchService.idl',
|
||||
]
|
||||
|
||||
XPIDL_MODULE = 'necko'
|
||||
|
||||
EXPORTS += [
|
||||
'netCore.h',
|
||||
'nsASocketHandler.h',
|
||||
'nsAsyncRedirectVerifyHelper.h',
|
||||
'nsFileStreams.h',
|
||||
'nsInputStreamPump.h',
|
||||
'nsMIMEInputStream.h',
|
||||
'nsNetUtil.h',
|
||||
'nsNetUtilInlines.h',
|
||||
'nsReadLine.h',
|
||||
'nsSerializationHelper.h',
|
||||
'nsSimpleNestedURI.h',
|
||||
'nsSimpleURI.h',
|
||||
'nsStreamListenerWrapper.h',
|
||||
'nsTemporaryFileInputStream.h',
|
||||
'nsURIHashKey.h',
|
||||
'nsURLHelper.h',
|
||||
'nsURLParsers.h',
|
||||
]
|
||||
|
||||
EXPORTS.mozilla += [
|
||||
'LoadContextInfo.h',
|
||||
'LoadInfo.h',
|
||||
'LoadTainting.h',
|
||||
]
|
||||
|
||||
EXPORTS.mozilla.net += [
|
||||
'CaptivePortalService.h',
|
||||
'ChannelDiverterChild.h',
|
||||
'ChannelDiverterParent.h',
|
||||
'Dashboard.h',
|
||||
'DashboardTypes.h',
|
||||
'MemoryDownloader.h',
|
||||
'Predictor.h',
|
||||
'ReferrerPolicy.h',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
|
||||
EXPORTS += [
|
||||
'NetStatistics.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'ArrayBufferInputStream.cpp',
|
||||
'BackgroundFileSaver.cpp',
|
||||
'CaptivePortalService.cpp',
|
||||
'ChannelDiverterChild.cpp',
|
||||
'ChannelDiverterParent.cpp',
|
||||
'Dashboard.cpp',
|
||||
'EventTokenBucket.cpp',
|
||||
'LoadContextInfo.cpp',
|
||||
'LoadInfo.cpp',
|
||||
'MemoryDownloader.cpp',
|
||||
'NetworkActivityMonitor.cpp',
|
||||
'nsAsyncRedirectVerifyHelper.cpp',
|
||||
'nsAsyncStreamCopier.cpp',
|
||||
'nsAuthInformationHolder.cpp',
|
||||
'nsBase64Encoder.cpp',
|
||||
'nsBaseChannel.cpp',
|
||||
'nsBaseContentStream.cpp',
|
||||
'nsBufferedStreams.cpp',
|
||||
'nsChannelClassifier.cpp',
|
||||
'nsDirectoryIndexStream.cpp',
|
||||
'nsDNSPrefetch.cpp',
|
||||
'nsDownloader.cpp',
|
||||
'nsFileStreams.cpp',
|
||||
'nsIncrementalDownload.cpp',
|
||||
'nsIncrementalStreamLoader.cpp',
|
||||
'nsInputStreamChannel.cpp',
|
||||
'nsInputStreamPump.cpp',
|
||||
'nsIOService.cpp',
|
||||
'nsLoadGroup.cpp',
|
||||
'nsMediaFragmentURIParser.cpp',
|
||||
'nsMIMEInputStream.cpp',
|
||||
'nsNetAddr.cpp',
|
||||
'nsNetUtil.cpp',
|
||||
'nsPACMan.cpp',
|
||||
'nsPreloadedStream.cpp',
|
||||
'nsProtocolProxyService.cpp',
|
||||
'nsProxyInfo.cpp',
|
||||
'nsRequestObserverProxy.cpp',
|
||||
'nsSecCheckWrapChannel.cpp',
|
||||
'nsSerializationHelper.cpp',
|
||||
'nsServerSocket.cpp',
|
||||
'nsSimpleNestedURI.cpp',
|
||||
'nsSimpleStreamListener.cpp',
|
||||
'nsSimpleURI.cpp',
|
||||
'nsSocketTransport2.cpp',
|
||||
'nsSocketTransportService2.cpp',
|
||||
'nsStandardURL.cpp',
|
||||
'nsStreamListenerTee.cpp',
|
||||
'nsStreamListenerWrapper.cpp',
|
||||
'nsStreamLoader.cpp',
|
||||
'nsStreamTransportService.cpp',
|
||||
'nsSyncStreamListener.cpp',
|
||||
'nsTemporaryFileInputStream.cpp',
|
||||
'nsTransportUtils.cpp',
|
||||
'nsUDPSocket.cpp',
|
||||
'nsUnicharStreamLoader.cpp',
|
||||
'nsURLHelper.cpp',
|
||||
'nsURLParsers.cpp',
|
||||
'PollableEvent.cpp',
|
||||
'Predictor.cpp',
|
||||
'ProxyAutoConfig.cpp',
|
||||
'RedirectChannelRegistrar.cpp',
|
||||
'RequestContextService.cpp',
|
||||
'SimpleBuffer.cpp',
|
||||
'StreamingProtocolService.cpp',
|
||||
'ThrottleQueue.cpp',
|
||||
'Tickler.cpp',
|
||||
'TLSServerSocket.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
|
||||
SOURCES += [
|
||||
'nsURLHelperWin.cpp',
|
||||
'ShutdownLayer.cpp',
|
||||
]
|
||||
elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
||||
SOURCES += [
|
||||
'nsURLHelperOSX.cpp',
|
||||
]
|
||||
else:
|
||||
SOURCES += [
|
||||
'nsURLHelperUnix.cpp',
|
||||
]
|
||||
|
||||
# nsINetworkInfoService support.
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
|
||||
SOURCES += [
|
||||
'NetworkInfoServiceWindows.cpp',
|
||||
'nsNetworkInfoService.cpp',
|
||||
]
|
||||
elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
||||
SOURCES += [
|
||||
'NetworkInfoServiceCocoa.cpp',
|
||||
'nsNetworkInfoService.cpp',
|
||||
]
|
||||
elif CONFIG['OS_ARCH'] == 'Linux':
|
||||
SOURCES += [
|
||||
'NetworkInfoServiceLinux.cpp',
|
||||
'nsNetworkInfoService.cpp',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
'NetUtil.jsm',
|
||||
]
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'/docshell/base',
|
||||
'/dom/base',
|
||||
'/netwerk/protocol/http',
|
||||
'/netwerk/socket',
|
||||
'/security/pkix/include'
|
||||
]
|
||||
|
||||
if 'rtsp' in CONFIG['NECKO_PROTOCOLS']:
|
||||
LOCAL_INCLUDES += [
|
||||
'/netwerk/protocol/rtsp/controller',
|
||||
'/netwerk/protocol/rtsp/rtsp',
|
||||
]
|
||||
|
||||
if CONFIG['GNU_CXX']:
|
||||
CXXFLAGS += ['-Wno-error=shadow']
|
||||
167
netwerk/base/mozIThirdPartyUtil.idl
Normal file
167
netwerk/base/mozIThirdPartyUtil.idl
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIURI;
|
||||
interface mozIDOMWindowProxy;
|
||||
interface nsIChannel;
|
||||
|
||||
/**
|
||||
* Utility functions for determining whether a given URI, channel, or window
|
||||
* hierarchy is third party with respect to a known URI.
|
||||
*/
|
||||
[scriptable, uuid(fd82700e-ffb4-4932-b7d6-08f0b5697dda)]
|
||||
interface mozIThirdPartyUtil : nsISupports
|
||||
{
|
||||
/**
|
||||
* isThirdPartyURI
|
||||
*
|
||||
* Determine whether two URIs are third party with respect to each other.
|
||||
* This is determined by computing the base domain for both URIs. If they can
|
||||
* be determined, and the base domains match, the request is defined as first
|
||||
* party. If it cannot be determined because one or both URIs do not have a
|
||||
* base domain (for instance, in the case of IP addresses, host aliases such
|
||||
* as 'localhost', or a file:// URI), an exact string comparison on host is
|
||||
* performed.
|
||||
*
|
||||
* For example, the URI "http://mail.google.com/" is not third party with
|
||||
* respect to "http://images.google.com/", but "http://mail.yahoo.com/" and
|
||||
* "http://192.168.1.1/" are.
|
||||
*
|
||||
* @return true if aFirstURI is third party with respect to aSecondURI.
|
||||
*
|
||||
* @throws if either URI is null, has a malformed host, or has an empty host
|
||||
* and is not a file:// URI.
|
||||
*/
|
||||
boolean isThirdPartyURI(in nsIURI aFirstURI, in nsIURI aSecondURI);
|
||||
|
||||
/**
|
||||
* isThirdPartyWindow
|
||||
*
|
||||
* Determine whether the given window hierarchy is third party. This is done
|
||||
* as follows:
|
||||
*
|
||||
* 1) Obtain the URI of the principal associated with 'aWindow'. Call this the
|
||||
* 'bottom URI'.
|
||||
* 2) If 'aURI' is provided, determine if it is third party with respect to
|
||||
* the bottom URI. If so, return.
|
||||
* 3) Find the same-type parent window, if there is one, and its URI.
|
||||
* Determine whether it is third party with respect to the bottom URI. If
|
||||
* so, return.
|
||||
*
|
||||
* Therefore, each level in the window hierarchy is tested. (This means that
|
||||
* nested iframes with different base domains, even though the bottommost and
|
||||
* topmost URIs might be equal, will be considered third party.)
|
||||
*
|
||||
* @param aWindow
|
||||
* The bottommost window in the hierarchy.
|
||||
* @param aURI
|
||||
* A URI to test against. If null, the URI of the principal
|
||||
* associated with 'aWindow' will be used.
|
||||
*
|
||||
* For example, if 'aURI' is "http://mail.google.com/", 'aWindow' has a URI
|
||||
* of "http://google.com/", and its parent is the topmost content window with
|
||||
* a URI of "http://mozilla.com", the result will be true.
|
||||
*
|
||||
* @return true if 'aURI' is third party with respect to any of the URIs
|
||||
* associated with aWindow and its same-type parents.
|
||||
*
|
||||
* @throws if aWindow is null; the same-type parent of any window in the
|
||||
* hierarchy cannot be determined; or the URI associated with any
|
||||
* window in the hierarchy is null, has a malformed host, or has an
|
||||
* empty host and is not a file:// URI.
|
||||
*
|
||||
* @see isThirdPartyURI
|
||||
*/
|
||||
boolean isThirdPartyWindow(in mozIDOMWindowProxy aWindow, [optional] in nsIURI aURI);
|
||||
|
||||
/**
|
||||
* isThirdPartyChannel
|
||||
*
|
||||
* Determine whether the given channel and its content window hierarchy is
|
||||
* third party. This is done as follows:
|
||||
*
|
||||
* 1) If 'aChannel' is an nsIHttpChannel and has the
|
||||
* 'forceAllowThirdPartyCookie' property set, then:
|
||||
* a) If 'aURI' is null, return false.
|
||||
* b) Otherwise, find the URI of the channel, determine whether it is
|
||||
* foreign with respect to 'aURI', and return.
|
||||
* 2) Find the URI of the channel and determine whether it is third party with
|
||||
* respect to the URI of the channel. If so, return.
|
||||
* 3) Obtain the bottommost nsIDOMWindow, and its same-type parent if it
|
||||
* exists, from the channel's notification callbacks. Then:
|
||||
* a) If the parent is the same as the bottommost window, and the channel
|
||||
* has the LOAD_DOCUMENT_URI flag set, return false. This represents the
|
||||
* case where a toplevel load is occurring and the window's URI has not
|
||||
* yet been updated. (We have already checked that 'aURI' is not foreign
|
||||
* with respect to the channel URI.)
|
||||
* b) Otherwise, return the result of isThirdPartyWindow with arguments
|
||||
* of the channel's bottommost window and the channel URI, respectively.
|
||||
*
|
||||
* Therefore, both the channel's URI and each level in the window hierarchy
|
||||
* associated with the channel is tested.
|
||||
*
|
||||
* @param aChannel
|
||||
* The channel associated with the load.
|
||||
* @param aURI
|
||||
* A URI to test against. If null, the URI of the channel will be used.
|
||||
*
|
||||
* For example, if 'aURI' is "http://mail.google.com/", 'aChannel' has a URI
|
||||
* of "http://google.com/", and its parent is the topmost content window with
|
||||
* a URI of "http://mozilla.com", the result will be true.
|
||||
*
|
||||
* @return true if aURI is third party with respect to the channel URI or any
|
||||
* of the URIs associated with the same-type window hierarchy of the
|
||||
* channel.
|
||||
*
|
||||
* @throws if 'aChannel' is null; the channel has no notification callbacks or
|
||||
* an associated window; or isThirdPartyWindow throws.
|
||||
*
|
||||
* @see isThirdPartyWindow
|
||||
*/
|
||||
boolean isThirdPartyChannel(in nsIChannel aChannel, [optional] in nsIURI aURI);
|
||||
|
||||
/**
|
||||
* getBaseDomain
|
||||
*
|
||||
* Get the base domain for aHostURI; e.g. for "www.bbc.co.uk", this would be
|
||||
* "bbc.co.uk". Only properly-formed URI's are tolerated, though a trailing
|
||||
* dot may be present. If aHostURI is an IP address, an alias such as
|
||||
* 'localhost', an eTLD such as 'co.uk', or the empty string, aBaseDomain will
|
||||
* be the exact host. The result of this function should only be used in exact
|
||||
* string comparisons, since substring comparisons will not be valid for the
|
||||
* special cases elided above.
|
||||
*
|
||||
* @param aHostURI
|
||||
* The URI to analyze.
|
||||
*
|
||||
* @return the base domain.
|
||||
*/
|
||||
AUTF8String getBaseDomain(in nsIURI aHostURI);
|
||||
|
||||
/**
|
||||
* getURIFromWindow
|
||||
*
|
||||
* Returns the URI associated with the script object principal for the
|
||||
* window.
|
||||
*/
|
||||
nsIURI getURIFromWindow(in mozIDOMWindowProxy aWindow);
|
||||
|
||||
/**
|
||||
* getTopWindowForChannel
|
||||
*
|
||||
* Returns the top-level window associated with the given channel.
|
||||
*/
|
||||
mozIDOMWindowProxy getTopWindowForChannel(in nsIChannel aChannel);
|
||||
};
|
||||
|
||||
%{ C++
|
||||
/**
|
||||
* The mozIThirdPartyUtil implementation is an XPCOM service registered
|
||||
* under the ContractID:
|
||||
*/
|
||||
#define THIRDPARTYUTIL_CONTRACTID "@mozilla.org/thirdpartyutil;1"
|
||||
%}
|
||||
|
||||
14
netwerk/base/netCore.h
Normal file
14
netwerk/base/netCore.h
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef __netCore_h__
|
||||
#define __netCore_h__
|
||||
|
||||
#include "nsError.h"
|
||||
|
||||
// Where most necko status messages come from:
|
||||
#define NECKO_MSGS_URL "chrome://necko/locale/necko.properties"
|
||||
|
||||
#endif // __netCore_h__
|
||||
96
netwerk/base/nsASocketHandler.h
Normal file
96
netwerk/base/nsASocketHandler.h
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsASocketHandler_h__
|
||||
#define nsASocketHandler_h__
|
||||
|
||||
// socket handler used by nsISocketTransportService.
|
||||
// methods are only called on the socket thread.
|
||||
|
||||
class nsASocketHandler : public nsISupports
|
||||
{
|
||||
public:
|
||||
nsASocketHandler()
|
||||
: mCondition(NS_OK)
|
||||
, mPollFlags(0)
|
||||
, mPollTimeout(UINT16_MAX)
|
||||
, mIsPrivate(false)
|
||||
{}
|
||||
|
||||
//
|
||||
// this condition variable will be checked to determine if the socket
|
||||
// handler should be detached. it must only be accessed on the socket
|
||||
// thread.
|
||||
//
|
||||
nsresult mCondition;
|
||||
|
||||
//
|
||||
// these flags can only be modified on the socket transport thread.
|
||||
// the socket transport service will check these flags before calling
|
||||
// PR_Poll.
|
||||
//
|
||||
uint16_t mPollFlags;
|
||||
|
||||
//
|
||||
// this value specifies the maximum amount of time in seconds that may be
|
||||
// spent waiting for activity on this socket. if this timeout is reached,
|
||||
// then OnSocketReady will be called with outFlags = -1.
|
||||
//
|
||||
// the default value for this member is UINT16_MAX, which disables the
|
||||
// timeout error checking. (i.e., a timeout value of UINT16_MAX is
|
||||
// never reached.)
|
||||
//
|
||||
uint16_t mPollTimeout;
|
||||
|
||||
bool mIsPrivate;
|
||||
|
||||
//
|
||||
// called to service a socket
|
||||
//
|
||||
// params:
|
||||
// socketRef - socket identifier
|
||||
// fd - socket file descriptor
|
||||
// outFlags - value of PR_PollDesc::out_flags after PR_Poll returns
|
||||
// or -1 if a timeout occurred
|
||||
//
|
||||
virtual void OnSocketReady(PRFileDesc *fd, int16_t outFlags) = 0;
|
||||
|
||||
//
|
||||
// called when a socket is no longer under the control of the socket
|
||||
// transport service. the socket handler may close the socket at this
|
||||
// point. after this call returns, the handler will no longer be owned
|
||||
// by the socket transport service.
|
||||
//
|
||||
virtual void OnSocketDetached(PRFileDesc *fd) = 0;
|
||||
|
||||
//
|
||||
// called to determine if the socket is for a local peer.
|
||||
// when used for server sockets, indicates if it only accepts local
|
||||
// connections.
|
||||
//
|
||||
virtual void IsLocal(bool *aIsLocal) = 0;
|
||||
|
||||
//
|
||||
// called to determine if this socket should not be terminated when Gecko
|
||||
// is turned offline. This is mostly useful for the debugging server
|
||||
// socket.
|
||||
//
|
||||
virtual void KeepWhenOffline(bool *aKeepWhenOffline)
|
||||
{
|
||||
*aKeepWhenOffline = false;
|
||||
}
|
||||
|
||||
//
|
||||
// called when global pref for keepalive has changed.
|
||||
//
|
||||
virtual void OnKeepaliveEnabledPrefChange(bool aEnabled) { }
|
||||
|
||||
//
|
||||
// returns the number of bytes sent/transmitted over the socket
|
||||
//
|
||||
virtual uint64_t ByteCountSent() = 0;
|
||||
virtual uint64_t ByteCountReceived() = 0;
|
||||
};
|
||||
|
||||
#endif // !nsASocketHandler_h__
|
||||
288
netwerk/base/nsAsyncRedirectVerifyHelper.cpp
Normal file
288
netwerk/base/nsAsyncRedirectVerifyHelper.cpp
Normal file
|
|
@ -0,0 +1,288 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/Logging.h"
|
||||
#include "nsAsyncRedirectVerifyHelper.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsNetUtil.h"
|
||||
|
||||
#include "nsIOService.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsIHttpChannelInternal.h"
|
||||
#include "nsIAsyncVerifyRedirectCallback.h"
|
||||
#include "nsILoadInfo.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
static LazyLogModule gRedirectLog("nsRedirect");
|
||||
#undef LOG
|
||||
#define LOG(args) MOZ_LOG(gRedirectLog, LogLevel::Debug, args)
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsAsyncRedirectVerifyHelper,
|
||||
nsIAsyncVerifyRedirectCallback,
|
||||
nsIRunnable)
|
||||
|
||||
class nsAsyncVerifyRedirectCallbackEvent : public Runnable {
|
||||
public:
|
||||
nsAsyncVerifyRedirectCallbackEvent(nsIAsyncVerifyRedirectCallback *cb,
|
||||
nsresult result)
|
||||
: mCallback(cb), mResult(result) {
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
LOG(("nsAsyncVerifyRedirectCallbackEvent::Run() "
|
||||
"callback to %p with result %x",
|
||||
mCallback.get(), mResult));
|
||||
(void) mCallback->OnRedirectVerifyCallback(mResult);
|
||||
return NS_OK;
|
||||
}
|
||||
private:
|
||||
nsCOMPtr<nsIAsyncVerifyRedirectCallback> mCallback;
|
||||
nsresult mResult;
|
||||
};
|
||||
|
||||
nsAsyncRedirectVerifyHelper::nsAsyncRedirectVerifyHelper()
|
||||
: mFlags(0),
|
||||
mWaitingForRedirectCallback(false),
|
||||
mCallbackInitiated(false),
|
||||
mExpectedCallbacks(0),
|
||||
mResult(NS_OK)
|
||||
{
|
||||
}
|
||||
|
||||
nsAsyncRedirectVerifyHelper::~nsAsyncRedirectVerifyHelper()
|
||||
{
|
||||
NS_ASSERTION(NS_FAILED(mResult) || mExpectedCallbacks == 0,
|
||||
"Did not receive all required callbacks!");
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsAsyncRedirectVerifyHelper::Init(nsIChannel* oldChan, nsIChannel* newChan,
|
||||
uint32_t flags, bool synchronize)
|
||||
{
|
||||
LOG(("nsAsyncRedirectVerifyHelper::Init() "
|
||||
"oldChan=%p newChan=%p", oldChan, newChan));
|
||||
mOldChan = oldChan;
|
||||
mNewChan = newChan;
|
||||
mFlags = flags;
|
||||
mCallbackThread = do_GetCurrentThread();
|
||||
|
||||
if (!(flags & (nsIChannelEventSink::REDIRECT_INTERNAL |
|
||||
nsIChannelEventSink::REDIRECT_STS_UPGRADE))) {
|
||||
nsCOMPtr<nsILoadInfo> loadInfo = oldChan->GetLoadInfo();
|
||||
if (loadInfo && loadInfo->GetDontFollowRedirects()) {
|
||||
ExplicitCallback(NS_BINDING_ABORTED);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
if (synchronize)
|
||||
mWaitingForRedirectCallback = true;
|
||||
|
||||
nsresult rv;
|
||||
rv = NS_DispatchToMainThread(this);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (synchronize) {
|
||||
nsIThread *thread = NS_GetCurrentThread();
|
||||
while (mWaitingForRedirectCallback) {
|
||||
if (!NS_ProcessNextEvent(thread)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAsyncRedirectVerifyHelper::OnRedirectVerifyCallback(nsresult result)
|
||||
{
|
||||
LOG(("nsAsyncRedirectVerifyHelper::OnRedirectVerifyCallback() "
|
||||
"result=%x expectedCBs=%u mResult=%x",
|
||||
result, mExpectedCallbacks, mResult));
|
||||
|
||||
MOZ_DIAGNOSTIC_ASSERT(mExpectedCallbacks > 0,
|
||||
"OnRedirectVerifyCallback called more times than expected");
|
||||
if (mExpectedCallbacks <= 0) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
--mExpectedCallbacks;
|
||||
|
||||
// If response indicates failure we may call back immediately
|
||||
if (NS_FAILED(result)) {
|
||||
// We chose to store the first failure-value (as opposed to the last)
|
||||
if (NS_SUCCEEDED(mResult))
|
||||
mResult = result;
|
||||
|
||||
// If InitCallback() has been called, just invoke the callback and
|
||||
// return. Otherwise it will be invoked from InitCallback()
|
||||
if (mCallbackInitiated) {
|
||||
ExplicitCallback(mResult);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// If the expected-counter is in balance and InitCallback() was called, all
|
||||
// sinks have agreed that the redirect is ok and we can invoke our callback
|
||||
if (mCallbackInitiated && mExpectedCallbacks == 0) {
|
||||
ExplicitCallback(mResult);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsAsyncRedirectVerifyHelper::DelegateOnChannelRedirect(nsIChannelEventSink *sink,
|
||||
nsIChannel *oldChannel,
|
||||
nsIChannel *newChannel,
|
||||
uint32_t flags)
|
||||
{
|
||||
LOG(("nsAsyncRedirectVerifyHelper::DelegateOnChannelRedirect() "
|
||||
"sink=%p expectedCBs=%u mResult=%x",
|
||||
sink, mExpectedCallbacks, mResult));
|
||||
|
||||
++mExpectedCallbacks;
|
||||
|
||||
if (IsOldChannelCanceled()) {
|
||||
LOG((" old channel has been canceled, cancel the redirect by "
|
||||
"emulating OnRedirectVerifyCallback..."));
|
||||
(void) OnRedirectVerifyCallback(NS_BINDING_ABORTED);
|
||||
return NS_BINDING_ABORTED;
|
||||
}
|
||||
|
||||
nsresult rv =
|
||||
sink->AsyncOnChannelRedirect(oldChannel, newChannel, flags, this);
|
||||
|
||||
LOG((" result=%x expectedCBs=%u", rv, mExpectedCallbacks));
|
||||
|
||||
// If the sink returns failure from this call the redirect is vetoed. We
|
||||
// emulate a callback from the sink in this case in order to perform all
|
||||
// the necessary logic.
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG((" emulating OnRedirectVerifyCallback..."));
|
||||
(void) OnRedirectVerifyCallback(rv);
|
||||
}
|
||||
|
||||
return rv; // Return the actual status since our caller may need it
|
||||
}
|
||||
|
||||
void
|
||||
nsAsyncRedirectVerifyHelper::ExplicitCallback(nsresult result)
|
||||
{
|
||||
LOG(("nsAsyncRedirectVerifyHelper::ExplicitCallback() "
|
||||
"result=%x expectedCBs=%u mCallbackInitiated=%u mResult=%x",
|
||||
result, mExpectedCallbacks, mCallbackInitiated, mResult));
|
||||
|
||||
nsCOMPtr<nsIAsyncVerifyRedirectCallback>
|
||||
callback(do_QueryInterface(mOldChan));
|
||||
|
||||
if (!callback || !mCallbackThread) {
|
||||
LOG(("nsAsyncRedirectVerifyHelper::ExplicitCallback() "
|
||||
"callback=%p mCallbackThread=%p", callback.get(), mCallbackThread.get()));
|
||||
return;
|
||||
}
|
||||
|
||||
mCallbackInitiated = false; // reset to ensure only one callback
|
||||
mWaitingForRedirectCallback = false;
|
||||
|
||||
// Now, dispatch the callback on the event-target which called Init()
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
new nsAsyncVerifyRedirectCallbackEvent(callback, result);
|
||||
if (!event) {
|
||||
NS_WARNING("nsAsyncRedirectVerifyHelper::ExplicitCallback() "
|
||||
"failed creating callback event!");
|
||||
return;
|
||||
}
|
||||
nsresult rv = mCallbackThread->Dispatch(event, NS_DISPATCH_NORMAL);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("nsAsyncRedirectVerifyHelper::ExplicitCallback() "
|
||||
"failed dispatching callback event!");
|
||||
} else {
|
||||
LOG(("nsAsyncRedirectVerifyHelper::ExplicitCallback() "
|
||||
"dispatched callback event=%p", event.get()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
nsAsyncRedirectVerifyHelper::InitCallback()
|
||||
{
|
||||
LOG(("nsAsyncRedirectVerifyHelper::InitCallback() "
|
||||
"expectedCBs=%d mResult=%x", mExpectedCallbacks, mResult));
|
||||
|
||||
mCallbackInitiated = true;
|
||||
|
||||
// Invoke the callback if we are done
|
||||
if (mExpectedCallbacks == 0)
|
||||
ExplicitCallback(mResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAsyncRedirectVerifyHelper::Run()
|
||||
{
|
||||
/* If the channel got canceled after it fired AsyncOnChannelRedirect
|
||||
* and before we got here, mostly because docloader load has been canceled,
|
||||
* we must completely ignore this notification and prevent any further
|
||||
* notification.
|
||||
*/
|
||||
if (IsOldChannelCanceled()) {
|
||||
ExplicitCallback(NS_BINDING_ABORTED);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// First, the global observer
|
||||
NS_ASSERTION(gIOService, "Must have an IO service at this point");
|
||||
LOG(("nsAsyncRedirectVerifyHelper::Run() calling gIOService..."));
|
||||
nsresult rv = gIOService->AsyncOnChannelRedirect(mOldChan, mNewChan,
|
||||
mFlags, this);
|
||||
if (NS_FAILED(rv)) {
|
||||
ExplicitCallback(rv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Now, the per-channel observers
|
||||
nsCOMPtr<nsIChannelEventSink> sink;
|
||||
NS_QueryNotificationCallbacks(mOldChan, sink);
|
||||
if (sink) {
|
||||
LOG(("nsAsyncRedirectVerifyHelper::Run() calling sink..."));
|
||||
rv = DelegateOnChannelRedirect(sink, mOldChan, mNewChan, mFlags);
|
||||
}
|
||||
|
||||
// All invocations to AsyncOnChannelRedirect has been done - call
|
||||
// InitCallback() to flag this
|
||||
InitCallback();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
nsAsyncRedirectVerifyHelper::IsOldChannelCanceled()
|
||||
{
|
||||
bool canceled;
|
||||
nsCOMPtr<nsIHttpChannelInternal> oldChannelInternal =
|
||||
do_QueryInterface(mOldChan);
|
||||
if (oldChannelInternal) {
|
||||
oldChannelInternal->GetCanceled(&canceled);
|
||||
if (canceled) {
|
||||
return true;
|
||||
}
|
||||
} else if (mOldChan) {
|
||||
// For non-HTTP channels check on the status, failure
|
||||
// indicates the channel has probably been canceled.
|
||||
nsresult status = NS_ERROR_FAILURE;
|
||||
mOldChan->GetStatus(&status);
|
||||
if (NS_FAILED(status)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
129
netwerk/base/nsAsyncRedirectVerifyHelper.h
Normal file
129
netwerk/base/nsAsyncRedirectVerifyHelper.h
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsAsyncRedirectVerifyHelper_h
|
||||
#define nsAsyncRedirectVerifyHelper_h
|
||||
|
||||
#include "nsIRunnable.h"
|
||||
#include "nsIThread.h"
|
||||
#include "nsIChannelEventSink.h"
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
#include "nsIAsyncVerifyRedirectCallback.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
class nsIChannel;
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
/**
|
||||
* This class simplifies call of OnChannelRedirect of IOService and
|
||||
* the sink bound with the channel being redirected while the result of
|
||||
* redirect decision is returned through the callback.
|
||||
*/
|
||||
class nsAsyncRedirectVerifyHelper final : public nsIRunnable,
|
||||
public nsIAsyncVerifyRedirectCallback
|
||||
{
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIRUNNABLE
|
||||
NS_DECL_NSIASYNCVERIFYREDIRECTCALLBACK
|
||||
|
||||
public:
|
||||
nsAsyncRedirectVerifyHelper();
|
||||
|
||||
/*
|
||||
* Calls AsyncOnChannelRedirect() on the given sink with the given
|
||||
* channels and flags. Keeps track of number of async callbacks to expect.
|
||||
*/
|
||||
nsresult DelegateOnChannelRedirect(nsIChannelEventSink *sink,
|
||||
nsIChannel *oldChannel,
|
||||
nsIChannel *newChannel,
|
||||
uint32_t flags);
|
||||
|
||||
/**
|
||||
* Initialize and run the chain of AsyncOnChannelRedirect calls. OldChannel
|
||||
* is QI'ed for nsIAsyncVerifyRedirectCallback. The result of the redirect
|
||||
* decision is passed through this interface back to the oldChannel.
|
||||
*
|
||||
* @param oldChan
|
||||
* channel being redirected, MUST implement
|
||||
* nsIAsyncVerifyRedirectCallback
|
||||
* @param newChan
|
||||
* target of the redirect channel
|
||||
* @param flags
|
||||
* redirect flags
|
||||
* @param synchronize
|
||||
* set to TRUE if you want the Init method wait synchronously for
|
||||
* all redirect callbacks
|
||||
*/
|
||||
nsresult Init(nsIChannel* oldChan,
|
||||
nsIChannel* newChan,
|
||||
uint32_t flags,
|
||||
bool synchronize = false);
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsIChannel> mOldChan;
|
||||
nsCOMPtr<nsIChannel> mNewChan;
|
||||
uint32_t mFlags;
|
||||
bool mWaitingForRedirectCallback;
|
||||
nsCOMPtr<nsIThread> mCallbackThread;
|
||||
bool mCallbackInitiated;
|
||||
int32_t mExpectedCallbacks;
|
||||
nsresult mResult; // value passed to callback
|
||||
|
||||
void InitCallback();
|
||||
|
||||
/**
|
||||
* Calls back to |oldChan| as described in Init()
|
||||
*/
|
||||
void ExplicitCallback(nsresult result);
|
||||
|
||||
private:
|
||||
~nsAsyncRedirectVerifyHelper();
|
||||
|
||||
bool IsOldChannelCanceled();
|
||||
};
|
||||
|
||||
/*
|
||||
* Helper to make the call-stack handle some control-flow for us
|
||||
*/
|
||||
class nsAsyncRedirectAutoCallback
|
||||
{
|
||||
public:
|
||||
explicit nsAsyncRedirectAutoCallback(nsIAsyncVerifyRedirectCallback* aCallback)
|
||||
: mCallback(aCallback)
|
||||
{
|
||||
mResult = NS_OK;
|
||||
}
|
||||
~nsAsyncRedirectAutoCallback()
|
||||
{
|
||||
if (mCallback)
|
||||
mCallback->OnRedirectVerifyCallback(mResult);
|
||||
}
|
||||
/*
|
||||
* Call this is you want it to call back with a different result-code
|
||||
*/
|
||||
void SetResult(nsresult aRes)
|
||||
{
|
||||
mResult = aRes;
|
||||
}
|
||||
/*
|
||||
* Call this is you want to avoid the callback
|
||||
*/
|
||||
void DontCallback()
|
||||
{
|
||||
mCallback = nullptr;
|
||||
}
|
||||
private:
|
||||
nsIAsyncVerifyRedirectCallback* mCallback;
|
||||
nsresult mResult;
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
#endif
|
||||
419
netwerk/base/nsAsyncStreamCopier.cpp
Normal file
419
netwerk/base/nsAsyncStreamCopier.cpp
Normal file
|
|
@ -0,0 +1,419 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsAsyncStreamCopier.h"
|
||||
#include "nsIOService.h"
|
||||
#include "nsIEventTarget.h"
|
||||
#include "nsStreamUtils.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsNetCID.h"
|
||||
#include "nsIBufferedStreams.h"
|
||||
#include "nsIRequestObserver.h"
|
||||
#include "mozilla/Logging.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
#undef LOG
|
||||
//
|
||||
// MOZ_LOG=nsStreamCopier:5
|
||||
//
|
||||
static LazyLogModule gStreamCopierLog("nsStreamCopier");
|
||||
#define LOG(args) MOZ_LOG(gStreamCopierLog, mozilla::LogLevel::Debug, args)
|
||||
|
||||
/**
|
||||
* An event used to perform initialization off the main thread.
|
||||
*/
|
||||
class AsyncApplyBufferingPolicyEvent final: public Runnable
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @param aCopier
|
||||
* The nsAsyncStreamCopier requesting the information.
|
||||
*/
|
||||
explicit AsyncApplyBufferingPolicyEvent(nsAsyncStreamCopier* aCopier)
|
||||
: mCopier(aCopier)
|
||||
, mTarget(NS_GetCurrentThread())
|
||||
{ }
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
nsresult rv = mCopier->ApplyBufferingPolicy();
|
||||
if (NS_FAILED(rv)) {
|
||||
mCopier->Cancel(rv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
rv = mTarget->Dispatch(NewRunnableMethod(mCopier,
|
||||
&nsAsyncStreamCopier::AsyncCopyInternal),
|
||||
NS_DISPATCH_NORMAL);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
mCopier->Cancel(rv);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
private:
|
||||
RefPtr<nsAsyncStreamCopier> mCopier;
|
||||
nsCOMPtr<nsIEventTarget> mTarget;
|
||||
};
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
nsAsyncStreamCopier::nsAsyncStreamCopier()
|
||||
: mLock("nsAsyncStreamCopier.mLock")
|
||||
, mMode(NS_ASYNCCOPY_VIA_READSEGMENTS)
|
||||
, mChunkSize(nsIOService::gDefaultSegmentSize)
|
||||
, mStatus(NS_OK)
|
||||
, mIsPending(false)
|
||||
, mShouldSniffBuffering(false)
|
||||
{
|
||||
LOG(("Creating nsAsyncStreamCopier @%x\n", this));
|
||||
}
|
||||
|
||||
nsAsyncStreamCopier::~nsAsyncStreamCopier()
|
||||
{
|
||||
LOG(("Destroying nsAsyncStreamCopier @%x\n", this));
|
||||
}
|
||||
|
||||
bool
|
||||
nsAsyncStreamCopier::IsComplete(nsresult *status)
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
if (status)
|
||||
*status = mStatus;
|
||||
return !mIsPending;
|
||||
}
|
||||
|
||||
nsIRequest*
|
||||
nsAsyncStreamCopier::AsRequest()
|
||||
{
|
||||
return static_cast<nsIRequest*>(static_cast<nsIAsyncStreamCopier*>(this));
|
||||
}
|
||||
|
||||
void
|
||||
nsAsyncStreamCopier::Complete(nsresult status)
|
||||
{
|
||||
LOG(("nsAsyncStreamCopier::Complete [this=%p status=%x]\n", this, status));
|
||||
|
||||
nsCOMPtr<nsIRequestObserver> observer;
|
||||
nsCOMPtr<nsISupports> ctx;
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
mCopierCtx = nullptr;
|
||||
|
||||
if (mIsPending) {
|
||||
mIsPending = false;
|
||||
mStatus = status;
|
||||
|
||||
// setup OnStopRequest callback and release references...
|
||||
observer = mObserver;
|
||||
mObserver = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (observer) {
|
||||
LOG((" calling OnStopRequest [status=%x]\n", status));
|
||||
observer->OnStopRequest(AsRequest(), ctx, status);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsAsyncStreamCopier::OnAsyncCopyComplete(void *closure, nsresult status)
|
||||
{
|
||||
nsAsyncStreamCopier *self = (nsAsyncStreamCopier *) closure;
|
||||
self->Complete(status);
|
||||
NS_RELEASE(self); // addref'd in AsyncCopy
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsISupports
|
||||
|
||||
// We cannot use simply NS_IMPL_ISUPPORTSx as both
|
||||
// nsIAsyncStreamCopier and nsIAsyncStreamCopier2 implement nsIRequest
|
||||
|
||||
NS_IMPL_ADDREF(nsAsyncStreamCopier)
|
||||
NS_IMPL_RELEASE(nsAsyncStreamCopier)
|
||||
NS_INTERFACE_TABLE_HEAD(nsAsyncStreamCopier)
|
||||
NS_INTERFACE_TABLE_BEGIN
|
||||
NS_INTERFACE_TABLE_ENTRY(nsAsyncStreamCopier, nsIAsyncStreamCopier)
|
||||
NS_INTERFACE_TABLE_ENTRY(nsAsyncStreamCopier, nsIAsyncStreamCopier2)
|
||||
NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(nsAsyncStreamCopier, nsIRequest, nsIAsyncStreamCopier)
|
||||
NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(nsAsyncStreamCopier, nsISupports, nsIAsyncStreamCopier)
|
||||
NS_INTERFACE_TABLE_END
|
||||
NS_INTERFACE_TABLE_TAIL
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsIRequest
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAsyncStreamCopier::GetName(nsACString &name)
|
||||
{
|
||||
name.Truncate();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAsyncStreamCopier::IsPending(bool *result)
|
||||
{
|
||||
*result = !IsComplete();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAsyncStreamCopier::GetStatus(nsresult *status)
|
||||
{
|
||||
IsComplete(status);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAsyncStreamCopier::Cancel(nsresult status)
|
||||
{
|
||||
nsCOMPtr<nsISupports> copierCtx;
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
if (!mIsPending)
|
||||
return NS_OK;
|
||||
copierCtx.swap(mCopierCtx);
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(status)) {
|
||||
NS_WARNING("cancel with non-failure status code");
|
||||
status = NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
|
||||
if (copierCtx)
|
||||
NS_CancelAsyncCopy(copierCtx, status);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAsyncStreamCopier::Suspend()
|
||||
{
|
||||
NS_NOTREACHED("nsAsyncStreamCopier::Suspend");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAsyncStreamCopier::Resume()
|
||||
{
|
||||
NS_NOTREACHED("nsAsyncStreamCopier::Resume");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAsyncStreamCopier::GetLoadFlags(nsLoadFlags *aLoadFlags)
|
||||
{
|
||||
*aLoadFlags = LOAD_NORMAL;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAsyncStreamCopier::SetLoadFlags(nsLoadFlags aLoadFlags)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAsyncStreamCopier::GetLoadGroup(nsILoadGroup **aLoadGroup)
|
||||
{
|
||||
*aLoadGroup = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAsyncStreamCopier::SetLoadGroup(nsILoadGroup *aLoadGroup)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsAsyncStreamCopier::InitInternal(nsIInputStream *source,
|
||||
nsIOutputStream *sink,
|
||||
nsIEventTarget *target,
|
||||
uint32_t chunkSize,
|
||||
bool closeSource,
|
||||
bool closeSink)
|
||||
{
|
||||
NS_ASSERTION(!mSource && !mSink, "Init() called more than once");
|
||||
if (chunkSize == 0) {
|
||||
chunkSize = nsIOService::gDefaultSegmentSize;
|
||||
}
|
||||
mChunkSize = chunkSize;
|
||||
|
||||
mSource = source;
|
||||
mSink = sink;
|
||||
mCloseSource = closeSource;
|
||||
mCloseSink = closeSink;
|
||||
|
||||
if (target) {
|
||||
mTarget = target;
|
||||
} else {
|
||||
nsresult rv;
|
||||
mTarget = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsIAsyncStreamCopier
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAsyncStreamCopier::Init(nsIInputStream *source,
|
||||
nsIOutputStream *sink,
|
||||
nsIEventTarget *target,
|
||||
bool sourceBuffered,
|
||||
bool sinkBuffered,
|
||||
uint32_t chunkSize,
|
||||
bool closeSource,
|
||||
bool closeSink)
|
||||
{
|
||||
NS_ASSERTION(sourceBuffered || sinkBuffered, "at least one stream must be buffered");
|
||||
mMode = sourceBuffered ? NS_ASYNCCOPY_VIA_READSEGMENTS
|
||||
: NS_ASYNCCOPY_VIA_WRITESEGMENTS;
|
||||
|
||||
return InitInternal(source, sink, target, chunkSize, closeSource, closeSink);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsIAsyncStreamCopier2
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAsyncStreamCopier::Init(nsIInputStream *source,
|
||||
nsIOutputStream *sink,
|
||||
nsIEventTarget *target,
|
||||
uint32_t chunkSize,
|
||||
bool closeSource,
|
||||
bool closeSink)
|
||||
{
|
||||
mShouldSniffBuffering = true;
|
||||
|
||||
return InitInternal(source, sink, target, chunkSize, closeSource, closeSink);
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect whether the input or the output stream is buffered,
|
||||
* bufferize one of them if neither is buffered.
|
||||
*/
|
||||
nsresult
|
||||
nsAsyncStreamCopier::ApplyBufferingPolicy()
|
||||
{
|
||||
// This function causes I/O, it must not be executed on the main
|
||||
// thread.
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
if (NS_OutputStreamIsBuffered(mSink)) {
|
||||
// Sink is buffered, no need to perform additional buffering
|
||||
mMode = NS_ASYNCCOPY_VIA_WRITESEGMENTS;
|
||||
return NS_OK;
|
||||
}
|
||||
if (NS_InputStreamIsBuffered(mSource)) {
|
||||
// Source is buffered, no need to perform additional buffering
|
||||
mMode = NS_ASYNCCOPY_VIA_READSEGMENTS;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// No buffering, let's buffer the sink
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIBufferedOutputStream> sink =
|
||||
do_CreateInstance(NS_BUFFEREDOUTPUTSTREAM_CONTRACTID, &rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = sink->Init(mSink, mChunkSize);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
mMode = NS_ASYNCCOPY_VIA_WRITESEGMENTS;
|
||||
mSink = sink;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Both nsIAsyncStreamCopier and nsIAsyncStreamCopier2
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAsyncStreamCopier::AsyncCopy(nsIRequestObserver *observer, nsISupports *ctx)
|
||||
{
|
||||
LOG(("nsAsyncStreamCopier::AsyncCopy [this=%p observer=%x]\n", this, observer));
|
||||
|
||||
NS_ASSERTION(mSource && mSink, "not initialized");
|
||||
nsresult rv;
|
||||
|
||||
if (observer) {
|
||||
// build proxy for observer events
|
||||
rv = NS_NewRequestObserverProxy(getter_AddRefs(mObserver), observer, ctx);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
// from this point forward, AsyncCopy is going to return NS_OK. any errors
|
||||
// will be reported via OnStopRequest.
|
||||
mIsPending = true;
|
||||
|
||||
if (mObserver) {
|
||||
rv = mObserver->OnStartRequest(AsRequest(), nullptr);
|
||||
if (NS_FAILED(rv))
|
||||
Cancel(rv);
|
||||
}
|
||||
|
||||
if (!mShouldSniffBuffering) {
|
||||
// No buffer sniffing required, let's proceed
|
||||
AsyncCopyInternal();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (NS_IsMainThread()) {
|
||||
// Don't perform buffer sniffing on the main thread
|
||||
nsCOMPtr<nsIRunnable> event = new AsyncApplyBufferingPolicyEvent(this);
|
||||
rv = mTarget->Dispatch(event, NS_DISPATCH_NORMAL);
|
||||
if (NS_FAILED(rv)) {
|
||||
Cancel(rv);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// We're not going to block the main thread, so let's sniff here
|
||||
rv = ApplyBufferingPolicy();
|
||||
if (NS_FAILED(rv)) {
|
||||
Cancel(rv);
|
||||
}
|
||||
AsyncCopyInternal();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Launch async copy.
|
||||
// All errors are reported through the observer.
|
||||
void
|
||||
nsAsyncStreamCopier::AsyncCopyInternal()
|
||||
{
|
||||
MOZ_ASSERT(mMode == NS_ASYNCCOPY_VIA_READSEGMENTS
|
||||
|| mMode == NS_ASYNCCOPY_VIA_WRITESEGMENTS);
|
||||
|
||||
nsresult rv;
|
||||
// we want to receive progress notifications; release happens in
|
||||
// OnAsyncCopyComplete.
|
||||
NS_ADDREF_THIS();
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
rv = NS_AsyncCopy(mSource, mSink, mTarget, mMode, mChunkSize,
|
||||
OnAsyncCopyComplete, this, mCloseSource, mCloseSink,
|
||||
getter_AddRefs(mCopierCtx));
|
||||
}
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_RELEASE_THIS();
|
||||
Cancel(rv);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
83
netwerk/base/nsAsyncStreamCopier.h
Normal file
83
netwerk/base/nsAsyncStreamCopier.h
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsAsyncStreamCopier_h__
|
||||
#define nsAsyncStreamCopier_h__
|
||||
|
||||
#include "nsIAsyncStreamCopier.h"
|
||||
#include "nsIAsyncStreamCopier2.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "nsStreamUtils.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
class nsIRequestObserver;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class nsAsyncStreamCopier final : public nsIAsyncStreamCopier,
|
||||
nsIAsyncStreamCopier2
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIREQUEST
|
||||
NS_DECL_NSIASYNCSTREAMCOPIER
|
||||
|
||||
// nsIAsyncStreamCopier2
|
||||
// We declare it by hand instead of NS_DECL_NSIASYNCSTREAMCOPIER2
|
||||
// as nsIAsyncStreamCopier2 duplicates methods of nsIAsyncStreamCopier
|
||||
NS_IMETHOD Init(nsIInputStream *aSource,
|
||||
nsIOutputStream *aSink,
|
||||
nsIEventTarget *aTarget,
|
||||
uint32_t aChunkSize,
|
||||
bool aCloseSource,
|
||||
bool aCloseSink) override;
|
||||
|
||||
nsAsyncStreamCopier();
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// these methods may be called on any thread
|
||||
|
||||
bool IsComplete(nsresult *status = nullptr);
|
||||
void Complete(nsresult status);
|
||||
|
||||
private:
|
||||
virtual ~nsAsyncStreamCopier();
|
||||
|
||||
nsresult InitInternal(nsIInputStream *source,
|
||||
nsIOutputStream *sink,
|
||||
nsIEventTarget *target,
|
||||
uint32_t chunkSize,
|
||||
bool closeSource,
|
||||
bool closeSink);
|
||||
|
||||
static void OnAsyncCopyComplete(void *, nsresult);
|
||||
|
||||
void AsyncCopyInternal();
|
||||
nsresult ApplyBufferingPolicy();
|
||||
nsIRequest* AsRequest();
|
||||
|
||||
nsCOMPtr<nsIInputStream> mSource;
|
||||
nsCOMPtr<nsIOutputStream> mSink;
|
||||
|
||||
nsCOMPtr<nsIRequestObserver> mObserver;
|
||||
|
||||
nsCOMPtr<nsIEventTarget> mTarget;
|
||||
|
||||
nsCOMPtr<nsISupports> mCopierCtx;
|
||||
|
||||
mozilla::Mutex mLock;
|
||||
|
||||
nsAsyncCopyMode mMode;
|
||||
uint32_t mChunkSize;
|
||||
nsresult mStatus;
|
||||
bool mIsPending;
|
||||
bool mCloseSource;
|
||||
bool mCloseSink;
|
||||
bool mShouldSniffBuffering;
|
||||
|
||||
friend class ProceedWithAsyncCopy;
|
||||
friend class AsyncApplyBufferingPolicyEvent;
|
||||
};
|
||||
|
||||
#endif // !nsAsyncStreamCopier_h__
|
||||
74
netwerk/base/nsAuthInformationHolder.cpp
Normal file
74
netwerk/base/nsAuthInformationHolder.cpp
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsAuthInformationHolder.h"
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsAuthInformationHolder, nsIAuthInformation)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAuthInformationHolder::GetFlags(uint32_t* aFlags)
|
||||
{
|
||||
*aFlags = mFlags;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAuthInformationHolder::GetRealm(nsAString& aRealm)
|
||||
{
|
||||
aRealm = mRealm;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAuthInformationHolder::GetAuthenticationScheme(nsACString& aScheme)
|
||||
{
|
||||
aScheme = mAuthType;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAuthInformationHolder::GetUsername(nsAString& aUserName)
|
||||
{
|
||||
aUserName = mUser;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAuthInformationHolder::SetUsername(const nsAString& aUserName)
|
||||
{
|
||||
if (!(mFlags & ONLY_PASSWORD))
|
||||
mUser = aUserName;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAuthInformationHolder::GetPassword(nsAString& aPassword)
|
||||
{
|
||||
aPassword = mPassword;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAuthInformationHolder::SetPassword(const nsAString& aPassword)
|
||||
{
|
||||
mPassword = aPassword;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAuthInformationHolder::GetDomain(nsAString& aDomain)
|
||||
{
|
||||
aDomain = mDomain;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAuthInformationHolder::SetDomain(const nsAString& aDomain)
|
||||
{
|
||||
if (mFlags & NEED_DOMAIN)
|
||||
mDomain = aDomain;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
48
netwerk/base/nsAuthInformationHolder.h
Normal file
48
netwerk/base/nsAuthInformationHolder.h
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
|
||||
#ifndef NSAUTHINFORMATIONHOLDER_H_
|
||||
#define NSAUTHINFORMATIONHOLDER_H_
|
||||
|
||||
#include "nsIAuthInformation.h"
|
||||
#include "nsString.h"
|
||||
|
||||
class nsAuthInformationHolder : public nsIAuthInformation {
|
||||
|
||||
protected:
|
||||
virtual ~nsAuthInformationHolder() {}
|
||||
|
||||
public:
|
||||
// aAuthType must be ASCII
|
||||
nsAuthInformationHolder(uint32_t aFlags, const nsString& aRealm,
|
||||
const nsCString& aAuthType)
|
||||
: mFlags(aFlags), mRealm(aRealm), mAuthType(aAuthType) {}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIAUTHINFORMATION
|
||||
|
||||
const nsString& User() const { return mUser; }
|
||||
const nsString& Password() const { return mPassword; }
|
||||
const nsString& Domain() const { return mDomain; }
|
||||
|
||||
/**
|
||||
* This method can be used to initialize the username when the
|
||||
* ONLY_PASSWORD flag is set.
|
||||
*/
|
||||
void SetUserInternal(const nsString& aUsername) {
|
||||
mUser = aUsername;
|
||||
}
|
||||
private:
|
||||
nsString mUser;
|
||||
nsString mPassword;
|
||||
nsString mDomain;
|
||||
|
||||
uint32_t mFlags;
|
||||
nsString mRealm;
|
||||
nsCString mAuthType;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
67
netwerk/base/nsBase64Encoder.cpp
Normal file
67
netwerk/base/nsBase64Encoder.cpp
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsBase64Encoder.h"
|
||||
|
||||
#include "plbase64.h"
|
||||
#include "prmem.h"
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsBase64Encoder, nsIOutputStream)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBase64Encoder::Close()
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBase64Encoder::Flush()
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBase64Encoder::Write(const char* aBuf, uint32_t aCount, uint32_t* _retval)
|
||||
{
|
||||
mData.Append(aBuf, aCount);
|
||||
*_retval = aCount;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBase64Encoder::WriteFrom(nsIInputStream* aStream, uint32_t aCount,
|
||||
uint32_t* _retval)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBase64Encoder::WriteSegments(nsReadSegmentFun aReader,
|
||||
void* aClosure,
|
||||
uint32_t aCount,
|
||||
uint32_t* _retval)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBase64Encoder::IsNonBlocking(bool* aNonBlocking)
|
||||
{
|
||||
*aNonBlocking = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBase64Encoder::Finish(nsCSubstring& result)
|
||||
{
|
||||
char* b64 = PL_Base64Encode(mData.get(), mData.Length(), nullptr);
|
||||
if (!b64)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
result.Assign(b64);
|
||||
PR_Free(b64);
|
||||
// Free unneeded memory and allow reusing the object
|
||||
mData.Truncate();
|
||||
return NS_OK;
|
||||
}
|
||||
32
netwerk/base/nsBase64Encoder.h
Normal file
32
netwerk/base/nsBase64Encoder.h
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef NSBASE64ENCODER_H_
|
||||
#define NSBASE64ENCODER_H_
|
||||
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsString.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
/**
|
||||
* A base64 encoder. Usage: Instantiate class, write to it using
|
||||
* Write(), then call Finish() to get the base64-encoded data.
|
||||
*/
|
||||
class nsBase64Encoder final : public nsIOutputStream {
|
||||
public:
|
||||
nsBase64Encoder() {}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOUTPUTSTREAM
|
||||
|
||||
nsresult Finish(nsCSubstring& _result);
|
||||
private:
|
||||
~nsBase64Encoder() {}
|
||||
|
||||
/// The data written to this stream. nsCString can deal fine with
|
||||
/// binary data.
|
||||
nsCString mData;
|
||||
};
|
||||
|
||||
#endif
|
||||
937
netwerk/base/nsBaseChannel.cpp
Normal file
937
netwerk/base/nsBaseChannel.cpp
Normal file
|
|
@ -0,0 +1,937 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 sts=2 ts=8 et tw=80 : */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsBaseChannel.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsURLHelper.h"
|
||||
#include "nsNetCID.h"
|
||||
#include "nsMimeTypes.h"
|
||||
#include "nsIContentSniffer.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsMimeTypes.h"
|
||||
#include "nsIHttpEventSink.h"
|
||||
#include "nsIHttpChannel.h"
|
||||
#include "nsIChannelEventSink.h"
|
||||
#include "nsIStreamConverterService.h"
|
||||
#include "nsChannelClassifier.h"
|
||||
#include "nsAsyncRedirectVerifyHelper.h"
|
||||
#include "nsProxyRelease.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "nsContentSecurityManager.h"
|
||||
#include "LoadInfo.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
|
||||
// This class is used to suspend a request across a function scope.
|
||||
class ScopedRequestSuspender {
|
||||
public:
|
||||
explicit ScopedRequestSuspender(nsIRequest *request)
|
||||
: mRequest(request) {
|
||||
if (mRequest && NS_FAILED(mRequest->Suspend())) {
|
||||
NS_WARNING("Couldn't suspend pump");
|
||||
mRequest = nullptr;
|
||||
}
|
||||
}
|
||||
~ScopedRequestSuspender() {
|
||||
if (mRequest)
|
||||
mRequest->Resume();
|
||||
}
|
||||
private:
|
||||
nsIRequest *mRequest;
|
||||
};
|
||||
|
||||
// Used to suspend data events from mPump within a function scope. This is
|
||||
// usually needed when a function makes callbacks that could process events.
|
||||
#define SUSPEND_PUMP_FOR_SCOPE() \
|
||||
ScopedRequestSuspender pump_suspender__(mPump)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsBaseChannel
|
||||
|
||||
nsBaseChannel::nsBaseChannel()
|
||||
: mLoadFlags(LOAD_NORMAL)
|
||||
, mQueriedProgressSink(true)
|
||||
, mSynthProgressEvents(false)
|
||||
, mAllowThreadRetargeting(true)
|
||||
, mWaitingOnAsyncRedirect(false)
|
||||
, mStatus(NS_OK)
|
||||
, mContentDispositionHint(UINT32_MAX)
|
||||
, mContentLength(-1)
|
||||
, mWasOpened(false)
|
||||
{
|
||||
mContentType.AssignLiteral(UNKNOWN_CONTENT_TYPE);
|
||||
}
|
||||
|
||||
nsBaseChannel::~nsBaseChannel()
|
||||
{
|
||||
NS_ReleaseOnMainThread(mLoadInfo.forget());
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBaseChannel::Redirect(nsIChannel *newChannel, uint32_t redirectFlags,
|
||||
bool openNewChannel)
|
||||
{
|
||||
SUSPEND_PUMP_FOR_SCOPE();
|
||||
|
||||
// Transfer properties
|
||||
|
||||
newChannel->SetLoadGroup(mLoadGroup);
|
||||
newChannel->SetNotificationCallbacks(mCallbacks);
|
||||
newChannel->SetLoadFlags(mLoadFlags | LOAD_REPLACE);
|
||||
|
||||
// make a copy of the loadinfo, append to the redirectchain
|
||||
// and set it on the new channel
|
||||
if (mLoadInfo) {
|
||||
nsSecurityFlags secFlags = mLoadInfo->GetSecurityFlags() &
|
||||
~nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL;
|
||||
nsCOMPtr<nsILoadInfo> newLoadInfo =
|
||||
static_cast<mozilla::LoadInfo*>(mLoadInfo.get())->CloneWithNewSecFlags(secFlags);
|
||||
|
||||
nsCOMPtr<nsIPrincipal> uriPrincipal;
|
||||
nsIScriptSecurityManager *sm = nsContentUtils::GetSecurityManager();
|
||||
sm->GetChannelURIPrincipal(this, getter_AddRefs(uriPrincipal));
|
||||
bool isInternalRedirect =
|
||||
(redirectFlags & (nsIChannelEventSink::REDIRECT_INTERNAL |
|
||||
nsIChannelEventSink::REDIRECT_STS_UPGRADE));
|
||||
newLoadInfo->AppendRedirectedPrincipal(uriPrincipal, isInternalRedirect);
|
||||
newChannel->SetLoadInfo(newLoadInfo);
|
||||
}
|
||||
else {
|
||||
// the newChannel was created with a dummy loadInfo, we should clear
|
||||
// it in case the original channel does not have a loadInfo
|
||||
newChannel->SetLoadInfo(nullptr);
|
||||
}
|
||||
|
||||
// Preserve the privacy bit if it has been overridden
|
||||
if (mPrivateBrowsingOverriden) {
|
||||
nsCOMPtr<nsIPrivateBrowsingChannel> newPBChannel =
|
||||
do_QueryInterface(newChannel);
|
||||
if (newPBChannel) {
|
||||
newPBChannel->SetPrivate(mPrivateBrowsing);
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIWritablePropertyBag> bag = ::do_QueryInterface(newChannel);
|
||||
if (bag) {
|
||||
for (auto iter = mPropertyHash.Iter(); !iter.Done(); iter.Next()) {
|
||||
bag->SetProperty(iter.Key(), iter.UserData());
|
||||
}
|
||||
}
|
||||
|
||||
// Notify consumer, giving chance to cancel redirect. For backwards compat,
|
||||
// we support nsIHttpEventSink if we are an HTTP channel and if this is not
|
||||
// an internal redirect.
|
||||
|
||||
RefPtr<nsAsyncRedirectVerifyHelper> redirectCallbackHelper =
|
||||
new nsAsyncRedirectVerifyHelper();
|
||||
|
||||
bool checkRedirectSynchronously = !openNewChannel;
|
||||
|
||||
mRedirectChannel = newChannel;
|
||||
mRedirectFlags = redirectFlags;
|
||||
mOpenRedirectChannel = openNewChannel;
|
||||
nsresult rv = redirectCallbackHelper->Init(this, newChannel, redirectFlags,
|
||||
checkRedirectSynchronously);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
if (checkRedirectSynchronously && NS_FAILED(mStatus))
|
||||
return mStatus;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBaseChannel::ContinueRedirect()
|
||||
{
|
||||
// Backwards compat for non-internal redirects from a HTTP channel.
|
||||
// XXX Is our http channel implementation going to derive from nsBaseChannel?
|
||||
// If not, this code can be removed.
|
||||
if (!(mRedirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL)) {
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface();
|
||||
if (httpChannel) {
|
||||
nsCOMPtr<nsIHttpEventSink> httpEventSink;
|
||||
GetCallback(httpEventSink);
|
||||
if (httpEventSink) {
|
||||
nsresult rv = httpEventSink->OnRedirect(httpChannel, mRedirectChannel);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure to do this _after_ making all the OnChannelRedirect calls
|
||||
mRedirectChannel->SetOriginalURI(OriginalURI());
|
||||
|
||||
// If we fail to open the new channel, then we want to leave this channel
|
||||
// unaffected, so we defer tearing down our channel until we have succeeded
|
||||
// with the redirect.
|
||||
|
||||
if (mOpenRedirectChannel) {
|
||||
nsresult rv = NS_OK;
|
||||
if (mLoadInfo && mLoadInfo->GetEnforceSecurity()) {
|
||||
MOZ_ASSERT(!mListenerContext, "mListenerContext should be null!");
|
||||
rv = mRedirectChannel->AsyncOpen2(mListener);
|
||||
}
|
||||
else {
|
||||
rv = mRedirectChannel->AsyncOpen(mListener, mListenerContext);
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
mRedirectChannel = nullptr;
|
||||
|
||||
// close down this channel
|
||||
Cancel(NS_BINDING_REDIRECTED);
|
||||
ChannelDone();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
nsBaseChannel::HasContentTypeHint() const
|
||||
{
|
||||
NS_ASSERTION(!Pending(), "HasContentTypeHint called too late");
|
||||
return !mContentType.EqualsLiteral(UNKNOWN_CONTENT_TYPE);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBaseChannel::PushStreamConverter(const char *fromType,
|
||||
const char *toType,
|
||||
bool invalidatesContentLength,
|
||||
nsIStreamListener **result)
|
||||
{
|
||||
NS_ASSERTION(mListener, "no listener");
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIStreamConverterService> scs =
|
||||
do_GetService(NS_STREAMCONVERTERSERVICE_CONTRACTID, &rv);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
nsCOMPtr<nsIStreamListener> converter;
|
||||
rv = scs->AsyncConvertData(fromType, toType, mListener, mListenerContext,
|
||||
getter_AddRefs(converter));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mListener = converter;
|
||||
if (invalidatesContentLength)
|
||||
mContentLength = -1;
|
||||
if (result) {
|
||||
*result = nullptr;
|
||||
converter.swap(*result);
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBaseChannel::BeginPumpingData()
|
||||
{
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
nsresult rv = OpenContentStream(true, getter_AddRefs(stream),
|
||||
getter_AddRefs(channel));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
NS_ASSERTION(!stream || !channel, "Got both a channel and a stream?");
|
||||
|
||||
if (channel) {
|
||||
rv = NS_DispatchToCurrentThread(new RedirectRunnable(this, channel));
|
||||
if (NS_SUCCEEDED(rv))
|
||||
mWaitingOnAsyncRedirect = true;
|
||||
return rv;
|
||||
}
|
||||
|
||||
// By assigning mPump, we flag this channel as pending (see Pending). It's
|
||||
// important that the pending flag is set when we call into the stream (the
|
||||
// call to AsyncRead results in the stream's AsyncWait method being called)
|
||||
// and especially when we call into the loadgroup. Our caller takes care to
|
||||
// release mPump if we return an error.
|
||||
|
||||
rv = nsInputStreamPump::Create(getter_AddRefs(mPump), stream, -1, -1, 0, 0,
|
||||
true);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
rv = mPump->AsyncRead(this, nullptr);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
nsBaseChannel::HandleAsyncRedirect(nsIChannel* newChannel)
|
||||
{
|
||||
NS_ASSERTION(!mPump, "Shouldn't have gotten here");
|
||||
|
||||
nsresult rv = mStatus;
|
||||
if (NS_SUCCEEDED(mStatus)) {
|
||||
rv = Redirect(newChannel,
|
||||
nsIChannelEventSink::REDIRECT_TEMPORARY,
|
||||
true);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// OnRedirectVerifyCallback will be called asynchronously
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ContinueHandleAsyncRedirect(rv);
|
||||
}
|
||||
|
||||
void
|
||||
nsBaseChannel::ContinueHandleAsyncRedirect(nsresult result)
|
||||
{
|
||||
mWaitingOnAsyncRedirect = false;
|
||||
|
||||
if (NS_FAILED(result))
|
||||
Cancel(result);
|
||||
|
||||
if (NS_FAILED(result) && mListener) {
|
||||
// Notify our consumer ourselves
|
||||
mListener->OnStartRequest(this, mListenerContext);
|
||||
mListener->OnStopRequest(this, mListenerContext, mStatus);
|
||||
ChannelDone();
|
||||
}
|
||||
|
||||
if (mLoadGroup)
|
||||
mLoadGroup->RemoveRequest(this, nullptr, mStatus);
|
||||
|
||||
// Drop notification callbacks to prevent cycles.
|
||||
mCallbacks = nullptr;
|
||||
CallbacksChanged();
|
||||
}
|
||||
|
||||
void
|
||||
nsBaseChannel::ClassifyURI()
|
||||
{
|
||||
// For channels created in the child process, delegate to the parent to
|
||||
// classify URIs.
|
||||
if (!XRE_IsParentProcess()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mLoadFlags & LOAD_CLASSIFY_URI) {
|
||||
RefPtr<nsChannelClassifier> classifier = new nsChannelClassifier();
|
||||
if (classifier) {
|
||||
classifier->Start(this);
|
||||
} else {
|
||||
Cancel(NS_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsBaseChannel::nsISupports
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED(nsBaseChannel,
|
||||
nsHashPropertyBag,
|
||||
nsIRequest,
|
||||
nsIChannel,
|
||||
nsIThreadRetargetableRequest,
|
||||
nsIInterfaceRequestor,
|
||||
nsITransportEventSink,
|
||||
nsIRequestObserver,
|
||||
nsIStreamListener,
|
||||
nsIThreadRetargetableStreamListener,
|
||||
nsIAsyncVerifyRedirectCallback,
|
||||
nsIPrivateBrowsingChannel)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsBaseChannel::nsIRequest
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseChannel::GetName(nsACString &result)
|
||||
{
|
||||
if (!mURI) {
|
||||
result.Truncate();
|
||||
return NS_OK;
|
||||
}
|
||||
return mURI->GetSpec(result);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseChannel::IsPending(bool *result)
|
||||
{
|
||||
*result = Pending();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseChannel::GetStatus(nsresult *status)
|
||||
{
|
||||
if (mPump && NS_SUCCEEDED(mStatus)) {
|
||||
mPump->GetStatus(status);
|
||||
} else {
|
||||
*status = mStatus;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseChannel::Cancel(nsresult status)
|
||||
{
|
||||
// Ignore redundant cancelation
|
||||
if (NS_FAILED(mStatus))
|
||||
return NS_OK;
|
||||
|
||||
mStatus = status;
|
||||
|
||||
if (mPump)
|
||||
mPump->Cancel(status);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseChannel::Suspend()
|
||||
{
|
||||
NS_ENSURE_TRUE(mPump, NS_ERROR_NOT_INITIALIZED);
|
||||
return mPump->Suspend();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseChannel::Resume()
|
||||
{
|
||||
NS_ENSURE_TRUE(mPump, NS_ERROR_NOT_INITIALIZED);
|
||||
return mPump->Resume();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseChannel::GetLoadFlags(nsLoadFlags *aLoadFlags)
|
||||
{
|
||||
*aLoadFlags = mLoadFlags;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseChannel::SetLoadFlags(nsLoadFlags aLoadFlags)
|
||||
{
|
||||
mLoadFlags = aLoadFlags;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseChannel::GetLoadGroup(nsILoadGroup **aLoadGroup)
|
||||
{
|
||||
NS_IF_ADDREF(*aLoadGroup = mLoadGroup);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseChannel::SetLoadGroup(nsILoadGroup *aLoadGroup)
|
||||
{
|
||||
if (!CanSetLoadGroup(aLoadGroup)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mLoadGroup = aLoadGroup;
|
||||
CallbacksChanged();
|
||||
UpdatePrivateBrowsing();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsBaseChannel::nsIChannel
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseChannel::GetOriginalURI(nsIURI **aURI)
|
||||
{
|
||||
*aURI = OriginalURI();
|
||||
NS_ADDREF(*aURI);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseChannel::SetOriginalURI(nsIURI *aURI)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aURI);
|
||||
mOriginalURI = aURI;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseChannel::GetURI(nsIURI **aURI)
|
||||
{
|
||||
NS_IF_ADDREF(*aURI = mURI);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseChannel::GetOwner(nsISupports **aOwner)
|
||||
{
|
||||
NS_IF_ADDREF(*aOwner = mOwner);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseChannel::SetOwner(nsISupports *aOwner)
|
||||
{
|
||||
mOwner = aOwner;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseChannel::SetLoadInfo(nsILoadInfo* aLoadInfo)
|
||||
{
|
||||
mLoadInfo = aLoadInfo;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseChannel::GetLoadInfo(nsILoadInfo** aLoadInfo)
|
||||
{
|
||||
NS_IF_ADDREF(*aLoadInfo = mLoadInfo);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseChannel::GetNotificationCallbacks(nsIInterfaceRequestor **aCallbacks)
|
||||
{
|
||||
NS_IF_ADDREF(*aCallbacks = mCallbacks);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseChannel::SetNotificationCallbacks(nsIInterfaceRequestor *aCallbacks)
|
||||
{
|
||||
if (!CanSetCallbacks(aCallbacks)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mCallbacks = aCallbacks;
|
||||
CallbacksChanged();
|
||||
UpdatePrivateBrowsing();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseChannel::GetSecurityInfo(nsISupports **aSecurityInfo)
|
||||
{
|
||||
NS_IF_ADDREF(*aSecurityInfo = mSecurityInfo);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseChannel::GetContentType(nsACString &aContentType)
|
||||
{
|
||||
aContentType = mContentType;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseChannel::SetContentType(const nsACString &aContentType)
|
||||
{
|
||||
// mContentCharset is unchanged if not parsed
|
||||
bool dummy;
|
||||
net_ParseContentType(aContentType, mContentType, mContentCharset, &dummy);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseChannel::GetContentCharset(nsACString &aContentCharset)
|
||||
{
|
||||
aContentCharset = mContentCharset;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseChannel::SetContentCharset(const nsACString &aContentCharset)
|
||||
{
|
||||
mContentCharset = aContentCharset;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseChannel::GetContentDisposition(uint32_t *aContentDisposition)
|
||||
{
|
||||
// preserve old behavior, fail unless explicitly set.
|
||||
if (mContentDispositionHint == UINT32_MAX) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
*aContentDisposition = mContentDispositionHint;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseChannel::SetContentDisposition(uint32_t aContentDisposition)
|
||||
{
|
||||
mContentDispositionHint = aContentDisposition;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseChannel::GetContentDispositionFilename(nsAString &aContentDispositionFilename)
|
||||
{
|
||||
if (!mContentDispositionFilename) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
aContentDispositionFilename = *mContentDispositionFilename;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseChannel::SetContentDispositionFilename(const nsAString &aContentDispositionFilename)
|
||||
{
|
||||
mContentDispositionFilename = new nsString(aContentDispositionFilename);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseChannel::GetContentDispositionHeader(nsACString &aContentDispositionHeader)
|
||||
{
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseChannel::GetContentLength(int64_t *aContentLength)
|
||||
{
|
||||
*aContentLength = mContentLength;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseChannel::SetContentLength(int64_t aContentLength)
|
||||
{
|
||||
mContentLength = aContentLength;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseChannel::Open(nsIInputStream **result)
|
||||
{
|
||||
NS_ENSURE_TRUE(mURI, NS_ERROR_NOT_INITIALIZED);
|
||||
NS_ENSURE_TRUE(!mPump, NS_ERROR_IN_PROGRESS);
|
||||
NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_IN_PROGRESS);
|
||||
|
||||
nsCOMPtr<nsIChannel> chan;
|
||||
nsresult rv = OpenContentStream(false, result, getter_AddRefs(chan));
|
||||
NS_ASSERTION(!chan || !*result, "Got both a channel and a stream?");
|
||||
if (NS_SUCCEEDED(rv) && chan) {
|
||||
rv = Redirect(chan, nsIChannelEventSink::REDIRECT_INTERNAL, false);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
rv = chan->Open(result);
|
||||
} else if (rv == NS_ERROR_NOT_IMPLEMENTED)
|
||||
return NS_ImplementChannelOpen(this, result);
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mWasOpened = true;
|
||||
ClassifyURI();
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseChannel::Open2(nsIInputStream** aStream)
|
||||
{
|
||||
nsCOMPtr<nsIStreamListener> listener;
|
||||
nsresult rv = nsContentSecurityManager::doContentSecurityCheck(this, listener);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return Open(aStream);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctxt)
|
||||
{
|
||||
MOZ_ASSERT(!mLoadInfo ||
|
||||
mLoadInfo->GetSecurityMode() == 0 ||
|
||||
mLoadInfo->GetInitialSecurityCheckDone() ||
|
||||
(mLoadInfo->GetSecurityMode() == nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL &&
|
||||
nsContentUtils::IsSystemPrincipal(mLoadInfo->LoadingPrincipal())),
|
||||
"security flags in loadInfo but asyncOpen2() not called");
|
||||
|
||||
NS_ENSURE_TRUE(mURI, NS_ERROR_NOT_INITIALIZED);
|
||||
NS_ENSURE_TRUE(!mPump, NS_ERROR_IN_PROGRESS);
|
||||
NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
|
||||
NS_ENSURE_ARG(listener);
|
||||
|
||||
// Skip checking for chrome:// sub-resources.
|
||||
nsAutoCString scheme;
|
||||
mURI->GetScheme(scheme);
|
||||
if (!scheme.EqualsLiteral("file")) {
|
||||
NS_CompareLoadInfoAndLoadContext(this);
|
||||
}
|
||||
|
||||
// Ensure that this is an allowed port before proceeding.
|
||||
nsresult rv = NS_CheckPortSafety(mURI);
|
||||
if (NS_FAILED(rv)) {
|
||||
mCallbacks = nullptr;
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Store the listener and context early so that OpenContentStream and the
|
||||
// stream's AsyncWait method (called by AsyncRead) can have access to them
|
||||
// via PushStreamConverter and the StreamListener methods. However, since
|
||||
// this typically introduces a reference cycle between this and the listener,
|
||||
// we need to be sure to break the reference if this method does not succeed.
|
||||
mListener = listener;
|
||||
mListenerContext = ctxt;
|
||||
|
||||
// This method assigns mPump as a side-effect. We need to clear mPump if
|
||||
// this method fails.
|
||||
rv = BeginPumpingData();
|
||||
if (NS_FAILED(rv)) {
|
||||
mPump = nullptr;
|
||||
ChannelDone();
|
||||
mCallbacks = nullptr;
|
||||
return rv;
|
||||
}
|
||||
|
||||
// At this point, we are going to return success no matter what.
|
||||
|
||||
mWasOpened = true;
|
||||
|
||||
SUSPEND_PUMP_FOR_SCOPE();
|
||||
|
||||
if (mLoadGroup)
|
||||
mLoadGroup->AddRequest(this, nullptr);
|
||||
|
||||
ClassifyURI();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseChannel::AsyncOpen2(nsIStreamListener *aListener)
|
||||
{
|
||||
nsCOMPtr<nsIStreamListener> listener = aListener;
|
||||
nsresult rv = nsContentSecurityManager::doContentSecurityCheck(this, listener);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return AsyncOpen(listener, nullptr);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsBaseChannel::nsITransportEventSink
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseChannel::OnTransportStatus(nsITransport *transport, nsresult status,
|
||||
int64_t progress, int64_t progressMax)
|
||||
{
|
||||
// In some cases, we may wish to suppress transport-layer status events.
|
||||
|
||||
if (!mPump || NS_FAILED(mStatus)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
SUSPEND_PUMP_FOR_SCOPE();
|
||||
|
||||
// Lazily fetch mProgressSink
|
||||
if (!mProgressSink) {
|
||||
if (mQueriedProgressSink) {
|
||||
return NS_OK;
|
||||
}
|
||||
GetCallback(mProgressSink);
|
||||
mQueriedProgressSink = true;
|
||||
if (!mProgressSink) {
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
if (!HasLoadFlag(LOAD_BACKGROUND)) {
|
||||
nsAutoString statusArg;
|
||||
if (GetStatusArg(status, statusArg)) {
|
||||
mProgressSink->OnStatus(this, mListenerContext, status, statusArg.get());
|
||||
}
|
||||
}
|
||||
|
||||
if (progress) {
|
||||
mProgressSink->OnProgress(this, mListenerContext, progress, progressMax);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsBaseChannel::nsIInterfaceRequestor
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseChannel::GetInterface(const nsIID &iid, void **result)
|
||||
{
|
||||
NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup, iid, result);
|
||||
return *result ? NS_OK : NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsBaseChannel::nsIRequestObserver
|
||||
|
||||
static void
|
||||
CallTypeSniffers(void *aClosure, const uint8_t *aData, uint32_t aCount)
|
||||
{
|
||||
nsIChannel *chan = static_cast<nsIChannel*>(aClosure);
|
||||
|
||||
nsAutoCString newType;
|
||||
NS_SniffContent(NS_CONTENT_SNIFFER_CATEGORY, chan, aData, aCount, newType);
|
||||
if (!newType.IsEmpty()) {
|
||||
chan->SetContentType(newType);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
CallUnknownTypeSniffer(void *aClosure, const uint8_t *aData, uint32_t aCount)
|
||||
{
|
||||
nsIChannel *chan = static_cast<nsIChannel*>(aClosure);
|
||||
|
||||
nsCOMPtr<nsIContentSniffer> sniffer =
|
||||
do_CreateInstance(NS_GENERIC_CONTENT_SNIFFER);
|
||||
if (!sniffer)
|
||||
return;
|
||||
|
||||
nsAutoCString detected;
|
||||
nsresult rv = sniffer->GetMIMETypeFromContent(chan, aData, aCount, detected);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
chan->SetContentType(detected);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseChannel::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
|
||||
{
|
||||
MOZ_ASSERT(request == mPump);
|
||||
|
||||
// If our content type is unknown, use the content type
|
||||
// sniffer. If the sniffer is not available for some reason, then we just keep
|
||||
// going as-is.
|
||||
if (NS_SUCCEEDED(mStatus) &&
|
||||
mContentType.EqualsLiteral(UNKNOWN_CONTENT_TYPE)) {
|
||||
mPump->PeekStream(CallUnknownTypeSniffer, static_cast<nsIChannel*>(this));
|
||||
}
|
||||
|
||||
// Now, the general type sniffers. Skip this if we have none.
|
||||
if (mLoadFlags & LOAD_CALL_CONTENT_SNIFFERS)
|
||||
mPump->PeekStream(CallTypeSniffers, static_cast<nsIChannel*>(this));
|
||||
|
||||
SUSPEND_PUMP_FOR_SCOPE();
|
||||
|
||||
if (mListener) // null in case of redirect
|
||||
return mListener->OnStartRequest(this, mListenerContext);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseChannel::OnStopRequest(nsIRequest *request, nsISupports *ctxt,
|
||||
nsresult status)
|
||||
{
|
||||
// If both mStatus and status are failure codes, we keep mStatus as-is since
|
||||
// that is consistent with our GetStatus and Cancel methods.
|
||||
if (NS_SUCCEEDED(mStatus))
|
||||
mStatus = status;
|
||||
|
||||
// Cause Pending to return false.
|
||||
mPump = nullptr;
|
||||
|
||||
if (mListener) // null in case of redirect
|
||||
mListener->OnStopRequest(this, mListenerContext, mStatus);
|
||||
ChannelDone();
|
||||
|
||||
// No need to suspend pump in this scope since we will not be receiving
|
||||
// any more events from it.
|
||||
|
||||
if (mLoadGroup)
|
||||
mLoadGroup->RemoveRequest(this, nullptr, mStatus);
|
||||
|
||||
// Drop notification callbacks to prevent cycles.
|
||||
mCallbacks = nullptr;
|
||||
CallbacksChanged();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsBaseChannel::nsIStreamListener
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseChannel::OnDataAvailable(nsIRequest *request, nsISupports *ctxt,
|
||||
nsIInputStream *stream, uint64_t offset,
|
||||
uint32_t count)
|
||||
{
|
||||
SUSPEND_PUMP_FOR_SCOPE();
|
||||
|
||||
nsresult rv = mListener->OnDataAvailable(this, mListenerContext, stream,
|
||||
offset, count);
|
||||
if (mSynthProgressEvents && NS_SUCCEEDED(rv)) {
|
||||
int64_t prog = offset + count;
|
||||
if (NS_IsMainThread()) {
|
||||
OnTransportStatus(nullptr, NS_NET_STATUS_READING, prog, mContentLength);
|
||||
} else {
|
||||
class OnTransportStatusAsyncEvent : public mozilla::Runnable
|
||||
{
|
||||
RefPtr<nsBaseChannel> mChannel;
|
||||
int64_t mProgress;
|
||||
int64_t mContentLength;
|
||||
public:
|
||||
OnTransportStatusAsyncEvent(nsBaseChannel* aChannel,
|
||||
int64_t aProgress,
|
||||
int64_t aContentLength)
|
||||
: mChannel(aChannel),
|
||||
mProgress(aProgress),
|
||||
mContentLength(aContentLength)
|
||||
{ }
|
||||
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
return mChannel->OnTransportStatus(nullptr, NS_NET_STATUS_READING,
|
||||
mProgress, mContentLength);
|
||||
}
|
||||
};
|
||||
|
||||
nsCOMPtr<nsIRunnable> runnable =
|
||||
new OnTransportStatusAsyncEvent(this, prog, mContentLength);
|
||||
NS_DispatchToMainThread(runnable);
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseChannel::OnRedirectVerifyCallback(nsresult result)
|
||||
{
|
||||
if (NS_SUCCEEDED(result))
|
||||
result = ContinueRedirect();
|
||||
|
||||
if (NS_FAILED(result) && !mWaitingOnAsyncRedirect) {
|
||||
if (NS_SUCCEEDED(mStatus))
|
||||
mStatus = result;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (mWaitingOnAsyncRedirect)
|
||||
ContinueHandleAsyncRedirect(result);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseChannel::RetargetDeliveryTo(nsIEventTarget* aEventTarget)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
NS_ENSURE_TRUE(mPump, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
if (!mAllowThreadRetargeting) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
return mPump->RetargetDeliveryTo(aEventTarget);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseChannel::CheckListenerChain()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!mAllowThreadRetargeting) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIThreadRetargetableStreamListener> listener =
|
||||
do_QueryInterface(mListener);
|
||||
if (!listener) {
|
||||
return NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
|
||||
return listener->CheckListenerChain();
|
||||
}
|
||||
300
netwerk/base/nsBaseChannel.h
Normal file
300
netwerk/base/nsBaseChannel.h
Normal file
|
|
@ -0,0 +1,300 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsBaseChannel_h__
|
||||
#define nsBaseChannel_h__
|
||||
|
||||
#include "nsString.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsHashPropertyBag.h"
|
||||
#include "nsInputStreamPump.h"
|
||||
|
||||
#include "nsIChannel.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsILoadGroup.h"
|
||||
#include "nsILoadInfo.h"
|
||||
#include "nsIStreamListener.h"
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
#include "nsIProgressEventSink.h"
|
||||
#include "nsITransport.h"
|
||||
#include "nsIAsyncVerifyRedirectCallback.h"
|
||||
#include "nsIThreadRetargetableRequest.h"
|
||||
#include "nsIThreadRetargetableStreamListener.h"
|
||||
#include "PrivateBrowsingChannel.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
class nsIInputStream;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsBaseChannel is designed to be subclassed. The subclass is responsible for
|
||||
// implementing the OpenContentStream method, which will be called by the
|
||||
// nsIChannel::AsyncOpen and nsIChannel::Open implementations.
|
||||
//
|
||||
// nsBaseChannel implements nsIInterfaceRequestor to provide a convenient way
|
||||
// for subclasses to query both the nsIChannel::notificationCallbacks and
|
||||
// nsILoadGroup::notificationCallbacks for supported interfaces.
|
||||
//
|
||||
// nsBaseChannel implements nsITransportEventSink to support progress & status
|
||||
// notifications generated by the transport layer.
|
||||
|
||||
class nsBaseChannel : public nsHashPropertyBag
|
||||
, public nsIChannel
|
||||
, public nsIThreadRetargetableRequest
|
||||
, public nsIInterfaceRequestor
|
||||
, public nsITransportEventSink
|
||||
, public nsIAsyncVerifyRedirectCallback
|
||||
, public mozilla::net::PrivateBrowsingChannel<nsBaseChannel>
|
||||
, protected nsIStreamListener
|
||||
, protected nsIThreadRetargetableStreamListener
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIREQUEST
|
||||
NS_DECL_NSICHANNEL
|
||||
NS_DECL_NSIINTERFACEREQUESTOR
|
||||
NS_DECL_NSITRANSPORTEVENTSINK
|
||||
NS_DECL_NSIASYNCVERIFYREDIRECTCALLBACK
|
||||
NS_DECL_NSITHREADRETARGETABLEREQUEST
|
||||
NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
|
||||
|
||||
nsBaseChannel();
|
||||
|
||||
// This method must be called to initialize the basechannel instance.
|
||||
nsresult Init() {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
// -----------------------------------------------
|
||||
// Methods to be implemented by the derived class:
|
||||
|
||||
virtual ~nsBaseChannel();
|
||||
|
||||
private:
|
||||
// Implemented by subclass to supply data stream. The parameter, async, is
|
||||
// true when called from nsIChannel::AsyncOpen and false otherwise. When
|
||||
// async is true, the resulting stream will be used with a nsIInputStreamPump
|
||||
// instance. This means that if it is a non-blocking stream that supports
|
||||
// nsIAsyncInputStream that it will be read entirely on the main application
|
||||
// thread, and its AsyncWait method will be called whenever ReadSegments
|
||||
// returns NS_BASE_STREAM_WOULD_BLOCK. Otherwise, if the stream is blocking,
|
||||
// then it will be read on one of the background I/O threads, and it does not
|
||||
// need to implement ReadSegments. If async is false, this method may return
|
||||
// NS_ERROR_NOT_IMPLEMENTED to cause the basechannel to implement Open in
|
||||
// terms of AsyncOpen (see NS_ImplementChannelOpen).
|
||||
// A callee is allowed to return an nsIChannel instead of an nsIInputStream.
|
||||
// That case will be treated as a redirect to the new channel. By default
|
||||
// *channel will be set to null by the caller, so callees who don't want to
|
||||
// return one an just not touch it.
|
||||
virtual nsresult OpenContentStream(bool async, nsIInputStream **stream,
|
||||
nsIChannel** channel) = 0;
|
||||
|
||||
// The basechannel calls this method from its OnTransportStatus method to
|
||||
// determine whether to call nsIProgressEventSink::OnStatus in addition to
|
||||
// nsIProgressEventSink::OnProgress. This method may be overriden by the
|
||||
// subclass to enable nsIProgressEventSink::OnStatus events. If this method
|
||||
// returns true, then the statusArg out param specifies the "statusArg" value
|
||||
// to pass to the OnStatus method. By default, OnStatus messages are
|
||||
// suppressed. The status parameter passed to this method is the status value
|
||||
// from the OnTransportStatus method.
|
||||
virtual bool GetStatusArg(nsresult status, nsString &statusArg) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Called when the callbacks available to this channel may have changed.
|
||||
virtual void OnCallbacksChanged() {
|
||||
}
|
||||
|
||||
// Called when our channel is done, to allow subclasses to drop resources.
|
||||
virtual void OnChannelDone() {
|
||||
}
|
||||
|
||||
public:
|
||||
// ----------------------------------------------
|
||||
// Methods provided for use by the derived class:
|
||||
|
||||
// Redirect to another channel. This method takes care of notifying
|
||||
// observers of this redirect as well as of opening the new channel, if asked
|
||||
// to do so. It also cancels |this| with the status code
|
||||
// NS_BINDING_REDIRECTED. A failure return from this method means that the
|
||||
// redirect could not be performed (no channel was opened; this channel
|
||||
// wasn't canceled.) The redirectFlags parameter consists of the flag values
|
||||
// defined on nsIChannelEventSink.
|
||||
nsresult Redirect(nsIChannel *newChannel, uint32_t redirectFlags,
|
||||
bool openNewChannel);
|
||||
|
||||
// Tests whether a type hint was set. Subclasses can use this to decide
|
||||
// whether to call SetContentType.
|
||||
// NOTE: This is only reliable if the subclass didn't itself call
|
||||
// SetContentType, and should also not be called after OpenContentStream.
|
||||
bool HasContentTypeHint() const;
|
||||
|
||||
// The URI member should be initialized before the channel is used, and then
|
||||
// it should never be changed again until the channel is destroyed.
|
||||
nsIURI *URI() {
|
||||
return mURI;
|
||||
}
|
||||
void SetURI(nsIURI *uri) {
|
||||
NS_ASSERTION(uri, "must specify a non-null URI");
|
||||
NS_ASSERTION(!mURI, "must not modify URI");
|
||||
NS_ASSERTION(!mOriginalURI, "how did that get set so early?");
|
||||
mURI = uri;
|
||||
mOriginalURI = uri;
|
||||
}
|
||||
nsIURI *OriginalURI() {
|
||||
return mOriginalURI;
|
||||
}
|
||||
|
||||
// The security info is a property of the transport-layer, which should be
|
||||
// assigned by the subclass.
|
||||
nsISupports *SecurityInfo() {
|
||||
return mSecurityInfo;
|
||||
}
|
||||
void SetSecurityInfo(nsISupports *info) {
|
||||
mSecurityInfo = info;
|
||||
}
|
||||
|
||||
// Test the load flags
|
||||
bool HasLoadFlag(uint32_t flag) {
|
||||
return (mLoadFlags & flag) != 0;
|
||||
}
|
||||
|
||||
// This is a short-cut to calling nsIRequest::IsPending()
|
||||
virtual bool Pending() const {
|
||||
return mPump || mWaitingOnAsyncRedirect;
|
||||
}
|
||||
|
||||
// Helper function for querying the channel's notification callbacks.
|
||||
template <class T> void GetCallback(nsCOMPtr<T> &result) {
|
||||
GetInterface(NS_GET_TEMPLATE_IID(T), getter_AddRefs(result));
|
||||
}
|
||||
|
||||
// Helper function for calling QueryInterface on this.
|
||||
nsQueryInterface do_QueryInterface() {
|
||||
return nsQueryInterface(static_cast<nsIChannel *>(this));
|
||||
}
|
||||
// MSVC needs this:
|
||||
nsQueryInterface do_QueryInterface(nsISupports *obj) {
|
||||
return nsQueryInterface(obj);
|
||||
}
|
||||
|
||||
// If a subclass does not want to feed transport-layer progress events to the
|
||||
// base channel via nsITransportEventSink, then it may set this flag to cause
|
||||
// the base channel to synthesize progress events when it receives data from
|
||||
// the content stream. By default, progress events are not synthesized.
|
||||
void EnableSynthesizedProgressEvents(bool enable) {
|
||||
mSynthProgressEvents = enable;
|
||||
}
|
||||
|
||||
// Some subclasses may wish to manually insert a stream listener between this
|
||||
// and the channel's listener. The following methods make that possible.
|
||||
void SetStreamListener(nsIStreamListener *listener) {
|
||||
mListener = listener;
|
||||
}
|
||||
nsIStreamListener *StreamListener() {
|
||||
return mListener;
|
||||
}
|
||||
|
||||
// Pushes a new stream converter in front of the channel's stream listener.
|
||||
// The fromType and toType values are passed to nsIStreamConverterService's
|
||||
// AsyncConvertData method. If invalidatesContentLength is true, then the
|
||||
// channel's content-length property will be assigned a value of -1. This is
|
||||
// necessary when the converter changes the length of the resulting data
|
||||
// stream, which is almost always the case for a "stream converter" ;-)
|
||||
// This function optionally returns a reference to the new converter.
|
||||
nsresult PushStreamConverter(const char *fromType, const char *toType,
|
||||
bool invalidatesContentLength = true,
|
||||
nsIStreamListener **converter = nullptr);
|
||||
|
||||
protected:
|
||||
void DisallowThreadRetargeting() {
|
||||
mAllowThreadRetargeting = false;
|
||||
}
|
||||
|
||||
private:
|
||||
NS_DECL_NSISTREAMLISTENER
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
|
||||
// Called to setup mPump and call AsyncRead on it.
|
||||
nsresult BeginPumpingData();
|
||||
|
||||
// Called when the callbacks available to this channel may have changed.
|
||||
void CallbacksChanged() {
|
||||
mProgressSink = nullptr;
|
||||
mQueriedProgressSink = false;
|
||||
OnCallbacksChanged();
|
||||
}
|
||||
|
||||
// Called when our channel is done. This should drop no-longer-needed pointers.
|
||||
void ChannelDone() {
|
||||
mListener = nullptr;
|
||||
mListenerContext = nullptr;
|
||||
OnChannelDone();
|
||||
}
|
||||
|
||||
// Handle an async redirect callback. This will only be called if we
|
||||
// returned success from AsyncOpen while posting a redirect runnable.
|
||||
void HandleAsyncRedirect(nsIChannel* newChannel);
|
||||
void ContinueHandleAsyncRedirect(nsresult result);
|
||||
nsresult ContinueRedirect();
|
||||
|
||||
// start URI classifier if requested
|
||||
void ClassifyURI();
|
||||
|
||||
class RedirectRunnable : public mozilla::Runnable
|
||||
{
|
||||
public:
|
||||
RedirectRunnable(nsBaseChannel* chan, nsIChannel* newChannel)
|
||||
: mChannel(chan), mNewChannel(newChannel)
|
||||
{
|
||||
NS_PRECONDITION(newChannel, "Must have channel to redirect to");
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
mChannel->HandleAsyncRedirect(mNewChannel);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
RefPtr<nsBaseChannel> mChannel;
|
||||
nsCOMPtr<nsIChannel> mNewChannel;
|
||||
};
|
||||
friend class RedirectRunnable;
|
||||
|
||||
RefPtr<nsInputStreamPump> mPump;
|
||||
nsCOMPtr<nsIProgressEventSink> mProgressSink;
|
||||
nsCOMPtr<nsIURI> mOriginalURI;
|
||||
nsCOMPtr<nsISupports> mOwner;
|
||||
nsCOMPtr<nsISupports> mSecurityInfo;
|
||||
nsCOMPtr<nsIChannel> mRedirectChannel;
|
||||
nsCString mContentType;
|
||||
nsCString mContentCharset;
|
||||
uint32_t mLoadFlags;
|
||||
bool mQueriedProgressSink;
|
||||
bool mSynthProgressEvents;
|
||||
bool mAllowThreadRetargeting;
|
||||
bool mWaitingOnAsyncRedirect;
|
||||
bool mOpenRedirectChannel;
|
||||
uint32_t mRedirectFlags;
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsIURI> mURI;
|
||||
nsCOMPtr<nsILoadGroup> mLoadGroup;
|
||||
nsCOMPtr<nsILoadInfo> mLoadInfo;
|
||||
nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
|
||||
nsCOMPtr<nsIStreamListener> mListener;
|
||||
nsCOMPtr<nsISupports> mListenerContext;
|
||||
nsresult mStatus;
|
||||
uint32_t mContentDispositionHint;
|
||||
nsAutoPtr<nsString> mContentDispositionFilename;
|
||||
int64_t mContentLength;
|
||||
bool mWasOpened;
|
||||
|
||||
friend class mozilla::net::PrivateBrowsingChannel<nsBaseChannel>;
|
||||
};
|
||||
|
||||
#endif // !nsBaseChannel_h__
|
||||
137
netwerk/base/nsBaseContentStream.cpp
Normal file
137
netwerk/base/nsBaseContentStream.cpp
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsBaseContentStream.h"
|
||||
#include "nsStreamUtils.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void
|
||||
nsBaseContentStream::DispatchCallback(bool async)
|
||||
{
|
||||
if (!mCallback)
|
||||
return;
|
||||
|
||||
// It's important to clear mCallback and mCallbackTarget up-front because the
|
||||
// OnInputStreamReady implementation may call our AsyncWait method.
|
||||
|
||||
nsCOMPtr<nsIInputStreamCallback> callback;
|
||||
if (async) {
|
||||
callback = NS_NewInputStreamReadyEvent(mCallback, mCallbackTarget);
|
||||
mCallback = nullptr;
|
||||
} else {
|
||||
callback.swap(mCallback);
|
||||
}
|
||||
mCallbackTarget = nullptr;
|
||||
|
||||
callback->OnInputStreamReady(this);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsBaseContentStream::nsISupports
|
||||
|
||||
NS_IMPL_ADDREF(nsBaseContentStream)
|
||||
NS_IMPL_RELEASE(nsBaseContentStream)
|
||||
|
||||
// We only support nsIAsyncInputStream when we are in non-blocking mode.
|
||||
NS_INTERFACE_MAP_BEGIN(nsBaseContentStream)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIInputStream)
|
||||
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIAsyncInputStream, mNonBlocking)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream)
|
||||
NS_INTERFACE_MAP_END_THREADSAFE
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsBaseContentStream::nsIInputStream
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseContentStream::Close()
|
||||
{
|
||||
return IsClosed() ? NS_OK : CloseWithStatus(NS_BASE_STREAM_CLOSED);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseContentStream::Available(uint64_t *result)
|
||||
{
|
||||
*result = 0;
|
||||
return mStatus;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseContentStream::Read(char *buf, uint32_t count, uint32_t *result)
|
||||
{
|
||||
return ReadSegments(NS_CopySegmentToBuffer, buf, count, result);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseContentStream::ReadSegments(nsWriteSegmentFun fun, void *closure,
|
||||
uint32_t count, uint32_t *result)
|
||||
{
|
||||
*result = 0;
|
||||
|
||||
if (mStatus == NS_BASE_STREAM_CLOSED)
|
||||
return NS_OK;
|
||||
|
||||
// No data yet
|
||||
if (!IsClosed() && IsNonBlocking())
|
||||
return NS_BASE_STREAM_WOULD_BLOCK;
|
||||
|
||||
return mStatus;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseContentStream::IsNonBlocking(bool *result)
|
||||
{
|
||||
*result = mNonBlocking;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsBaseContentStream::nsIAsyncInputStream
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseContentStream::CloseWithStatus(nsresult status)
|
||||
{
|
||||
if (IsClosed())
|
||||
return NS_OK;
|
||||
|
||||
NS_ENSURE_ARG(NS_FAILED(status));
|
||||
mStatus = status;
|
||||
|
||||
DispatchCallback();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseContentStream::AsyncWait(nsIInputStreamCallback *callback,
|
||||
uint32_t flags, uint32_t requestedCount,
|
||||
nsIEventTarget *target)
|
||||
{
|
||||
// Our _only_ consumer is nsInputStreamPump, so we simplify things here by
|
||||
// making assumptions about how we will be called.
|
||||
NS_ASSERTION(target, "unexpected parameter");
|
||||
NS_ASSERTION(flags == 0, "unexpected parameter");
|
||||
NS_ASSERTION(requestedCount == 0, "unexpected parameter");
|
||||
|
||||
#ifdef DEBUG
|
||||
bool correctThread;
|
||||
target->IsOnCurrentThread(&correctThread);
|
||||
NS_ASSERTION(correctThread, "event target must be on the current thread");
|
||||
#endif
|
||||
|
||||
mCallback = callback;
|
||||
mCallbackTarget = target;
|
||||
|
||||
if (!mCallback)
|
||||
return NS_OK;
|
||||
|
||||
// If we're already closed, then dispatch this callback immediately.
|
||||
if (IsClosed()) {
|
||||
DispatchCallback();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
OnCallbackPending();
|
||||
return NS_OK;
|
||||
}
|
||||
82
netwerk/base/nsBaseContentStream.h
Normal file
82
netwerk/base/nsBaseContentStream.h
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsBaseContentStream_h__
|
||||
#define nsBaseContentStream_h__
|
||||
|
||||
#include "nsIAsyncInputStream.h"
|
||||
#include "nsIEventTarget.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsBaseContentStream is designed to be subclassed with the intention of being
|
||||
// used to satisfy the nsBaseChannel::OpenContentStream method.
|
||||
//
|
||||
// The subclass typically overrides the default Available, ReadSegments and
|
||||
// CloseWithStatus methods. By default, Read is implemented in terms of
|
||||
// ReadSegments, and Close is implemented in terms of CloseWithStatus. If
|
||||
// CloseWithStatus is overriden, then the subclass will usually want to call
|
||||
// the base class' CloseWithStatus method before returning.
|
||||
//
|
||||
// If the stream is non-blocking, then readSegments may return the exception
|
||||
// NS_BASE_STREAM_WOULD_BLOCK if there is no data available and the stream is
|
||||
// not at the "end-of-file" or already closed. This error code must not be
|
||||
// returned from the Available implementation. When the caller receives this
|
||||
// error code, he may choose to call the stream's AsyncWait method, in which
|
||||
// case the base stream will have a non-null PendingCallback. When the stream
|
||||
// has data or encounters an error, it should be sure to dispatch a pending
|
||||
// callback if one exists (see DispatchCallback). The implementation of the
|
||||
// base stream's CloseWithStatus (and Close) method will ensure that any
|
||||
// pending callback is dispatched. It is the responsibility of the subclass
|
||||
// to ensure that the pending callback is dispatched when it wants to have its
|
||||
// ReadSegments method called again.
|
||||
|
||||
class nsBaseContentStream : public nsIAsyncInputStream
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIINPUTSTREAM
|
||||
NS_DECL_NSIASYNCINPUTSTREAM
|
||||
|
||||
explicit nsBaseContentStream(bool nonBlocking)
|
||||
: mStatus(NS_OK)
|
||||
, mNonBlocking(nonBlocking) {
|
||||
}
|
||||
|
||||
nsresult Status() { return mStatus; }
|
||||
bool IsNonBlocking() { return mNonBlocking; }
|
||||
bool IsClosed() { return NS_FAILED(mStatus); }
|
||||
|
||||
// Called to test if the stream has a pending callback.
|
||||
bool HasPendingCallback() { return mCallback != nullptr; }
|
||||
|
||||
// The current dispatch target (may be null) for the pending callback if any.
|
||||
nsIEventTarget *CallbackTarget() { return mCallbackTarget; }
|
||||
|
||||
// Called to dispatch a pending callback. If there is no pending callback,
|
||||
// then this function does nothing. Pass true to this function to cause the
|
||||
// callback to occur asynchronously; otherwise, the callback will happen
|
||||
// before this function returns.
|
||||
void DispatchCallback(bool async = true);
|
||||
|
||||
// Helper function to make code more self-documenting.
|
||||
void DispatchCallbackSync() { DispatchCallback(false); }
|
||||
|
||||
protected:
|
||||
virtual ~nsBaseContentStream() {}
|
||||
|
||||
private:
|
||||
// Called from the base stream's AsyncWait method when a pending callback
|
||||
// is installed on the stream.
|
||||
virtual void OnCallbackPending() {}
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIInputStreamCallback> mCallback;
|
||||
nsCOMPtr<nsIEventTarget> mCallbackTarget;
|
||||
nsresult mStatus;
|
||||
bool mNonBlocking;
|
||||
};
|
||||
|
||||
#endif // nsBaseContentStream_h__
|
||||
832
netwerk/base/nsBufferedStreams.cpp
Normal file
832
netwerk/base/nsBufferedStreams.cpp
Normal file
|
|
@ -0,0 +1,832 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ipc/IPCMessageUtils.h"
|
||||
|
||||
#include "nsBufferedStreams.h"
|
||||
#include "nsStreamUtils.h"
|
||||
#include "nsNetCID.h"
|
||||
#include "nsIClassInfoImpl.h"
|
||||
#include "mozilla/ipc/InputStreamUtils.h"
|
||||
#include <algorithm>
|
||||
|
||||
#ifdef DEBUG_brendan
|
||||
# define METERING
|
||||
#endif
|
||||
|
||||
#ifdef METERING
|
||||
# include <stdio.h>
|
||||
# define METER(x) x
|
||||
# define MAX_BIG_SEEKS 20
|
||||
|
||||
static struct {
|
||||
uint32_t mSeeksWithinBuffer;
|
||||
uint32_t mSeeksOutsideBuffer;
|
||||
uint32_t mBufferReadUponSeek;
|
||||
uint32_t mBufferUnreadUponSeek;
|
||||
uint32_t mBytesReadFromBuffer;
|
||||
uint32_t mBigSeekIndex;
|
||||
struct {
|
||||
int64_t mOldOffset;
|
||||
int64_t mNewOffset;
|
||||
} mBigSeek[MAX_BIG_SEEKS];
|
||||
} bufstats;
|
||||
#else
|
||||
# define METER(x) /* nothing */
|
||||
#endif
|
||||
|
||||
using namespace mozilla::ipc;
|
||||
using mozilla::Maybe;
|
||||
using mozilla::Nothing;
|
||||
using mozilla::Some;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsBufferedStream
|
||||
|
||||
nsBufferedStream::nsBufferedStream()
|
||||
: mBuffer(nullptr),
|
||||
mBufferStartOffset(0),
|
||||
mCursor(0),
|
||||
mFillPoint(0),
|
||||
mStream(nullptr),
|
||||
mBufferDisabled(false),
|
||||
mEOF(false),
|
||||
mGetBufferCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
nsBufferedStream::~nsBufferedStream()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsBufferedStream, nsISeekableStream)
|
||||
|
||||
nsresult
|
||||
nsBufferedStream::Init(nsISupports* stream, uint32_t bufferSize)
|
||||
{
|
||||
NS_ASSERTION(stream, "need to supply a stream");
|
||||
NS_ASSERTION(mStream == nullptr, "already inited");
|
||||
mStream = stream;
|
||||
NS_IF_ADDREF(mStream);
|
||||
mBufferSize = bufferSize;
|
||||
mBufferStartOffset = 0;
|
||||
mCursor = 0;
|
||||
mBuffer = new (mozilla::fallible) char[bufferSize];
|
||||
if (mBuffer == nullptr)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBufferedStream::Close()
|
||||
{
|
||||
NS_IF_RELEASE(mStream);
|
||||
if (mBuffer) {
|
||||
delete[] mBuffer;
|
||||
mBuffer = nullptr;
|
||||
mBufferSize = 0;
|
||||
mBufferStartOffset = 0;
|
||||
mCursor = 0;
|
||||
mFillPoint = 0;
|
||||
}
|
||||
#ifdef METERING
|
||||
{
|
||||
static FILE *tfp;
|
||||
if (!tfp) {
|
||||
tfp = fopen("/tmp/bufstats", "w");
|
||||
if (tfp)
|
||||
setvbuf(tfp, nullptr, _IOLBF, 0);
|
||||
}
|
||||
if (tfp) {
|
||||
fprintf(tfp, "seeks within buffer: %u\n",
|
||||
bufstats.mSeeksWithinBuffer);
|
||||
fprintf(tfp, "seeks outside buffer: %u\n",
|
||||
bufstats.mSeeksOutsideBuffer);
|
||||
fprintf(tfp, "buffer read on seek: %u\n",
|
||||
bufstats.mBufferReadUponSeek);
|
||||
fprintf(tfp, "buffer unread on seek: %u\n",
|
||||
bufstats.mBufferUnreadUponSeek);
|
||||
fprintf(tfp, "bytes read from buffer: %u\n",
|
||||
bufstats.mBytesReadFromBuffer);
|
||||
for (uint32_t i = 0; i < bufstats.mBigSeekIndex; i++) {
|
||||
fprintf(tfp, "bigseek[%u] = {old: %u, new: %u}\n",
|
||||
i,
|
||||
bufstats.mBigSeek[i].mOldOffset,
|
||||
bufstats.mBigSeek[i].mNewOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBufferedStream::Seek(int32_t whence, int64_t offset)
|
||||
{
|
||||
if (mStream == nullptr)
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
|
||||
// If the underlying stream isn't a random access store, then fail early.
|
||||
// We could possibly succeed for the case where the seek position denotes
|
||||
// something that happens to be read into the buffer, but that would make
|
||||
// the failure data-dependent.
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsISeekableStream> ras = do_QueryInterface(mStream, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
int64_t absPos = 0;
|
||||
switch (whence) {
|
||||
case nsISeekableStream::NS_SEEK_SET:
|
||||
absPos = offset;
|
||||
break;
|
||||
case nsISeekableStream::NS_SEEK_CUR:
|
||||
absPos = mBufferStartOffset;
|
||||
absPos += mCursor;
|
||||
absPos += offset;
|
||||
break;
|
||||
case nsISeekableStream::NS_SEEK_END:
|
||||
absPos = -1;
|
||||
break;
|
||||
default:
|
||||
NS_NOTREACHED("bogus seek whence parameter");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
// Let mCursor point into the existing buffer if the new position is
|
||||
// between the current cursor and the mFillPoint "fencepost" -- the
|
||||
// client may never get around to a Read or Write after this Seek.
|
||||
// Read and Write worry about flushing and filling in that event.
|
||||
// But if we're at EOF, make sure to pass the seek through to the
|
||||
// underlying stream, because it may have auto-closed itself and
|
||||
// needs to reopen.
|
||||
uint32_t offsetInBuffer = uint32_t(absPos - mBufferStartOffset);
|
||||
if (offsetInBuffer <= mFillPoint && !mEOF) {
|
||||
METER(bufstats.mSeeksWithinBuffer++);
|
||||
mCursor = offsetInBuffer;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
METER(bufstats.mSeeksOutsideBuffer++);
|
||||
METER(bufstats.mBufferReadUponSeek += mCursor);
|
||||
METER(bufstats.mBufferUnreadUponSeek += mFillPoint - mCursor);
|
||||
rv = Flush();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = ras->Seek(whence, offset);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
mEOF = false;
|
||||
|
||||
// Recompute whether the offset we're seeking to is in our buffer.
|
||||
// Note that we need to recompute because Flush() might have
|
||||
// changed mBufferStartOffset.
|
||||
offsetInBuffer = uint32_t(absPos - mBufferStartOffset);
|
||||
if (offsetInBuffer <= mFillPoint) {
|
||||
// It's safe to just set mCursor to offsetInBuffer. In particular, we
|
||||
// want to avoid calling Fill() here since we already have the data that
|
||||
// was seeked to and calling Fill() might auto-close our underlying
|
||||
// stream in some cases.
|
||||
mCursor = offsetInBuffer;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
METER(if (bufstats.mBigSeekIndex < MAX_BIG_SEEKS)
|
||||
bufstats.mBigSeek[bufstats.mBigSeekIndex].mOldOffset =
|
||||
mBufferStartOffset + int64_t(mCursor));
|
||||
const int64_t minus1 = -1;
|
||||
if (absPos == minus1) {
|
||||
// then we had the SEEK_END case, above
|
||||
int64_t tellPos;
|
||||
rv = ras->Tell(&tellPos);
|
||||
mBufferStartOffset = tellPos;
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
else {
|
||||
mBufferStartOffset = absPos;
|
||||
}
|
||||
METER(if (bufstats.mBigSeekIndex < MAX_BIG_SEEKS)
|
||||
bufstats.mBigSeek[bufstats.mBigSeekIndex++].mNewOffset =
|
||||
mBufferStartOffset);
|
||||
|
||||
mFillPoint = mCursor = 0;
|
||||
return Fill();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBufferedStream::Tell(int64_t *result)
|
||||
{
|
||||
if (mStream == nullptr)
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
|
||||
int64_t result64 = mBufferStartOffset;
|
||||
result64 += mCursor;
|
||||
*result = result64;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBufferedStream::SetEOF()
|
||||
{
|
||||
if (mStream == nullptr)
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsISeekableStream> ras = do_QueryInterface(mStream, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = ras->SetEOF();
|
||||
if (NS_SUCCEEDED(rv))
|
||||
mEOF = true;
|
||||
return rv;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsBufferedInputStream
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(nsBufferedInputStream, nsBufferedStream)
|
||||
NS_IMPL_RELEASE_INHERITED(nsBufferedInputStream, nsBufferedStream)
|
||||
|
||||
NS_IMPL_CLASSINFO(nsBufferedInputStream, nullptr, nsIClassInfo::THREADSAFE,
|
||||
NS_BUFFEREDINPUTSTREAM_CID)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(nsBufferedInputStream)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIInputStream)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIBufferedInputStream)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIStreamBufferAccess)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIIPCSerializableInputStream)
|
||||
NS_IMPL_QUERY_CLASSINFO(nsBufferedInputStream)
|
||||
NS_INTERFACE_MAP_END_INHERITING(nsBufferedStream)
|
||||
|
||||
NS_IMPL_CI_INTERFACE_GETTER(nsBufferedInputStream,
|
||||
nsIInputStream,
|
||||
nsIBufferedInputStream,
|
||||
nsISeekableStream,
|
||||
nsIStreamBufferAccess)
|
||||
|
||||
nsresult
|
||||
nsBufferedInputStream::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
|
||||
{
|
||||
NS_ENSURE_NO_AGGREGATION(aOuter);
|
||||
|
||||
nsBufferedInputStream* stream = new nsBufferedInputStream();
|
||||
if (stream == nullptr)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(stream);
|
||||
nsresult rv = stream->QueryInterface(aIID, aResult);
|
||||
NS_RELEASE(stream);
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBufferedInputStream::Init(nsIInputStream* stream, uint32_t bufferSize)
|
||||
{
|
||||
return nsBufferedStream::Init(stream, bufferSize);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBufferedInputStream::Close()
|
||||
{
|
||||
nsresult rv1 = NS_OK, rv2;
|
||||
if (mStream) {
|
||||
rv1 = Source()->Close();
|
||||
NS_RELEASE(mStream);
|
||||
}
|
||||
rv2 = nsBufferedStream::Close();
|
||||
if (NS_FAILED(rv1)) return rv1;
|
||||
return rv2;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBufferedInputStream::Available(uint64_t *result)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
*result = 0;
|
||||
if (mStream) {
|
||||
rv = Source()->Available(result);
|
||||
}
|
||||
*result += (mFillPoint - mCursor);
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBufferedInputStream::Read(char * buf, uint32_t count, uint32_t *result)
|
||||
{
|
||||
if (mBufferDisabled) {
|
||||
if (!mStream) {
|
||||
*result = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
nsresult rv = Source()->Read(buf, count, result);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mBufferStartOffset += *result; // so nsBufferedStream::Tell works
|
||||
if (*result == 0) {
|
||||
mEOF = true;
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
return ReadSegments(NS_CopySegmentToBuffer, buf, count, result);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBufferedInputStream::ReadSegments(nsWriteSegmentFun writer, void *closure,
|
||||
uint32_t count, uint32_t *result)
|
||||
{
|
||||
*result = 0;
|
||||
|
||||
if (!mStream)
|
||||
return NS_OK;
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
while (count > 0) {
|
||||
uint32_t amt = std::min(count, mFillPoint - mCursor);
|
||||
if (amt > 0) {
|
||||
uint32_t read = 0;
|
||||
rv = writer(this, closure, mBuffer + mCursor, *result, amt, &read);
|
||||
if (NS_FAILED(rv)) {
|
||||
// errors returned from the writer end here!
|
||||
rv = NS_OK;
|
||||
break;
|
||||
}
|
||||
*result += read;
|
||||
count -= read;
|
||||
mCursor += read;
|
||||
}
|
||||
else {
|
||||
rv = Fill();
|
||||
if (NS_FAILED(rv) || mFillPoint == mCursor)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (*result > 0) ? NS_OK : rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBufferedInputStream::IsNonBlocking(bool *aNonBlocking)
|
||||
{
|
||||
if (mStream)
|
||||
return Source()->IsNonBlocking(aNonBlocking);
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBufferedInputStream::Fill()
|
||||
{
|
||||
if (mBufferDisabled)
|
||||
return NS_OK;
|
||||
NS_ENSURE_TRUE(mStream, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
nsresult rv;
|
||||
int32_t rem = int32_t(mFillPoint - mCursor);
|
||||
if (rem > 0) {
|
||||
// slide the remainder down to the start of the buffer
|
||||
// |<------------->|<--rem-->|<--->|
|
||||
// b c f s
|
||||
memcpy(mBuffer, mBuffer + mCursor, rem);
|
||||
}
|
||||
mBufferStartOffset += mCursor;
|
||||
mFillPoint = rem;
|
||||
mCursor = 0;
|
||||
|
||||
uint32_t amt;
|
||||
rv = Source()->Read(mBuffer + mFillPoint, mBufferSize - mFillPoint, &amt);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (amt == 0)
|
||||
mEOF = true;
|
||||
|
||||
mFillPoint += amt;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(char*)
|
||||
nsBufferedInputStream::GetBuffer(uint32_t aLength, uint32_t aAlignMask)
|
||||
{
|
||||
NS_ASSERTION(mGetBufferCount == 0, "nested GetBuffer!");
|
||||
if (mGetBufferCount != 0)
|
||||
return nullptr;
|
||||
|
||||
if (mBufferDisabled)
|
||||
return nullptr;
|
||||
|
||||
char* buf = mBuffer + mCursor;
|
||||
uint32_t rem = mFillPoint - mCursor;
|
||||
if (rem == 0) {
|
||||
if (NS_FAILED(Fill()))
|
||||
return nullptr;
|
||||
buf = mBuffer + mCursor;
|
||||
rem = mFillPoint - mCursor;
|
||||
}
|
||||
|
||||
uint32_t mod = (NS_PTR_TO_INT32(buf) & aAlignMask);
|
||||
if (mod) {
|
||||
uint32_t pad = aAlignMask + 1 - mod;
|
||||
if (pad > rem)
|
||||
return nullptr;
|
||||
|
||||
memset(buf, 0, pad);
|
||||
mCursor += pad;
|
||||
buf += pad;
|
||||
rem -= pad;
|
||||
}
|
||||
|
||||
if (aLength > rem)
|
||||
return nullptr;
|
||||
mGetBufferCount++;
|
||||
return buf;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(void)
|
||||
nsBufferedInputStream::PutBuffer(char* aBuffer, uint32_t aLength)
|
||||
{
|
||||
NS_ASSERTION(mGetBufferCount == 1, "stray PutBuffer!");
|
||||
if (--mGetBufferCount != 0)
|
||||
return;
|
||||
|
||||
NS_ASSERTION(mCursor + aLength <= mFillPoint, "PutBuffer botch");
|
||||
mCursor += aLength;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBufferedInputStream::DisableBuffering()
|
||||
{
|
||||
NS_ASSERTION(!mBufferDisabled, "redundant call to DisableBuffering!");
|
||||
NS_ASSERTION(mGetBufferCount == 0,
|
||||
"DisableBuffer call between GetBuffer and PutBuffer!");
|
||||
if (mGetBufferCount != 0)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
// Empty the buffer so nsBufferedStream::Tell works.
|
||||
mBufferStartOffset += mCursor;
|
||||
mFillPoint = mCursor = 0;
|
||||
mBufferDisabled = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBufferedInputStream::EnableBuffering()
|
||||
{
|
||||
NS_ASSERTION(mBufferDisabled, "gratuitous call to EnableBuffering!");
|
||||
mBufferDisabled = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBufferedInputStream::GetUnbufferedStream(nsISupports* *aStream)
|
||||
{
|
||||
// Empty the buffer so subsequent i/o trumps any buffered data.
|
||||
mBufferStartOffset += mCursor;
|
||||
mFillPoint = mCursor = 0;
|
||||
|
||||
*aStream = mStream;
|
||||
NS_IF_ADDREF(*aStream);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsBufferedInputStream::Serialize(InputStreamParams& aParams,
|
||||
FileDescriptorArray& aFileDescriptors)
|
||||
{
|
||||
BufferedInputStreamParams params;
|
||||
|
||||
if (mStream) {
|
||||
nsCOMPtr<nsIInputStream> stream = do_QueryInterface(mStream);
|
||||
MOZ_ASSERT(stream);
|
||||
|
||||
InputStreamParams wrappedParams;
|
||||
SerializeInputStream(stream, wrappedParams, aFileDescriptors);
|
||||
|
||||
params.optionalStream() = wrappedParams;
|
||||
}
|
||||
else {
|
||||
params.optionalStream() = mozilla::void_t();
|
||||
}
|
||||
|
||||
params.bufferSize() = mBufferSize;
|
||||
|
||||
aParams = params;
|
||||
}
|
||||
|
||||
bool
|
||||
nsBufferedInputStream::Deserialize(const InputStreamParams& aParams,
|
||||
const FileDescriptorArray& aFileDescriptors)
|
||||
{
|
||||
if (aParams.type() != InputStreamParams::TBufferedInputStreamParams) {
|
||||
NS_ERROR("Received unknown parameters from the other process!");
|
||||
return false;
|
||||
}
|
||||
|
||||
const BufferedInputStreamParams& params =
|
||||
aParams.get_BufferedInputStreamParams();
|
||||
const OptionalInputStreamParams& wrappedParams = params.optionalStream();
|
||||
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
if (wrappedParams.type() == OptionalInputStreamParams::TInputStreamParams) {
|
||||
stream = DeserializeInputStream(wrappedParams.get_InputStreamParams(),
|
||||
aFileDescriptors);
|
||||
if (!stream) {
|
||||
NS_WARNING("Failed to deserialize wrapped stream!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
NS_ASSERTION(wrappedParams.type() == OptionalInputStreamParams::Tvoid_t,
|
||||
"Unknown type for OptionalInputStreamParams!");
|
||||
}
|
||||
|
||||
nsresult rv = Init(stream, params.bufferSize());
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Maybe<uint64_t>
|
||||
nsBufferedInputStream::ExpectedSerializedLength()
|
||||
{
|
||||
nsCOMPtr<nsIIPCSerializableInputStream> stream = do_QueryInterface(mStream);
|
||||
if (stream) {
|
||||
return stream->ExpectedSerializedLength();
|
||||
}
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsBufferedOutputStream
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(nsBufferedOutputStream, nsBufferedStream)
|
||||
NS_IMPL_RELEASE_INHERITED(nsBufferedOutputStream, nsBufferedStream)
|
||||
// This QI uses NS_INTERFACE_MAP_ENTRY_CONDITIONAL to check for
|
||||
// non-nullness of mSafeStream.
|
||||
NS_INTERFACE_MAP_BEGIN(nsBufferedOutputStream)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIOutputStream)
|
||||
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsISafeOutputStream, mSafeStream)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIBufferedOutputStream)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIStreamBufferAccess)
|
||||
NS_INTERFACE_MAP_END_INHERITING(nsBufferedStream)
|
||||
|
||||
nsresult
|
||||
nsBufferedOutputStream::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
|
||||
{
|
||||
NS_ENSURE_NO_AGGREGATION(aOuter);
|
||||
|
||||
nsBufferedOutputStream* stream = new nsBufferedOutputStream();
|
||||
if (stream == nullptr)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(stream);
|
||||
nsresult rv = stream->QueryInterface(aIID, aResult);
|
||||
NS_RELEASE(stream);
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBufferedOutputStream::Init(nsIOutputStream* stream, uint32_t bufferSize)
|
||||
{
|
||||
// QI stream to an nsISafeOutputStream, to see if we should support it
|
||||
mSafeStream = do_QueryInterface(stream);
|
||||
|
||||
return nsBufferedStream::Init(stream, bufferSize);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBufferedOutputStream::Close()
|
||||
{
|
||||
nsresult rv1, rv2 = NS_OK, rv3;
|
||||
rv1 = Flush();
|
||||
// If we fail to Flush all the data, then we close anyway and drop the
|
||||
// remaining data in the buffer. We do this because it's what Unix does
|
||||
// for fclose and close. However, we report the error from Flush anyway.
|
||||
if (mStream) {
|
||||
rv2 = Sink()->Close();
|
||||
NS_RELEASE(mStream);
|
||||
}
|
||||
rv3 = nsBufferedStream::Close();
|
||||
if (NS_FAILED(rv1)) return rv1;
|
||||
if (NS_FAILED(rv2)) return rv2;
|
||||
return rv3;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBufferedOutputStream::Write(const char *buf, uint32_t count, uint32_t *result)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
uint32_t written = 0;
|
||||
while (count > 0) {
|
||||
uint32_t amt = std::min(count, mBufferSize - mCursor);
|
||||
if (amt > 0) {
|
||||
memcpy(mBuffer + mCursor, buf + written, amt);
|
||||
written += amt;
|
||||
count -= amt;
|
||||
mCursor += amt;
|
||||
if (mFillPoint < mCursor)
|
||||
mFillPoint = mCursor;
|
||||
}
|
||||
else {
|
||||
NS_ASSERTION(mFillPoint, "iloop in nsBufferedOutputStream::Write!");
|
||||
rv = Flush();
|
||||
if (NS_FAILED(rv)) break;
|
||||
}
|
||||
}
|
||||
*result = written;
|
||||
return (written > 0) ? NS_OK : rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBufferedOutputStream::Flush()
|
||||
{
|
||||
nsresult rv;
|
||||
uint32_t amt;
|
||||
if (!mStream) {
|
||||
// Stream already cancelled/flushed; probably because of previous error.
|
||||
return NS_OK;
|
||||
}
|
||||
rv = Sink()->Write(mBuffer, mFillPoint, &amt);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
mBufferStartOffset += amt;
|
||||
if (amt == mFillPoint) {
|
||||
mFillPoint = mCursor = 0;
|
||||
return NS_OK; // flushed everything
|
||||
}
|
||||
|
||||
// slide the remainder down to the start of the buffer
|
||||
// |<-------------->|<---|----->|
|
||||
// b a c s
|
||||
uint32_t rem = mFillPoint - amt;
|
||||
memmove(mBuffer, mBuffer + amt, rem);
|
||||
mFillPoint = mCursor = rem;
|
||||
return NS_ERROR_FAILURE; // didn't flush all
|
||||
}
|
||||
|
||||
// nsISafeOutputStream
|
||||
NS_IMETHODIMP
|
||||
nsBufferedOutputStream::Finish()
|
||||
{
|
||||
// flush the stream, to write out any buffered data...
|
||||
nsresult rv = nsBufferedOutputStream::Flush();
|
||||
if (NS_FAILED(rv))
|
||||
NS_WARNING("failed to flush buffered data! possible dataloss");
|
||||
|
||||
// ... and finish the underlying stream...
|
||||
if (NS_SUCCEEDED(rv))
|
||||
rv = mSafeStream->Finish();
|
||||
else
|
||||
Sink()->Close();
|
||||
|
||||
// ... and close the buffered stream, so any further attempts to flush/close
|
||||
// the buffered stream won't cause errors.
|
||||
nsBufferedStream::Close();
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static nsresult
|
||||
nsReadFromInputStream(nsIOutputStream* outStr,
|
||||
void* closure,
|
||||
char* toRawSegment,
|
||||
uint32_t offset,
|
||||
uint32_t count,
|
||||
uint32_t *readCount)
|
||||
{
|
||||
nsIInputStream* fromStream = (nsIInputStream*)closure;
|
||||
return fromStream->Read(toRawSegment, count, readCount);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBufferedOutputStream::WriteFrom(nsIInputStream *inStr, uint32_t count, uint32_t *_retval)
|
||||
{
|
||||
return WriteSegments(nsReadFromInputStream, inStr, count, _retval);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBufferedOutputStream::WriteSegments(nsReadSegmentFun reader, void * closure, uint32_t count, uint32_t *_retval)
|
||||
{
|
||||
*_retval = 0;
|
||||
nsresult rv;
|
||||
while (count > 0) {
|
||||
uint32_t left = std::min(count, mBufferSize - mCursor);
|
||||
if (left == 0) {
|
||||
rv = Flush();
|
||||
if (NS_FAILED(rv))
|
||||
return (*_retval > 0) ? NS_OK : rv;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t read = 0;
|
||||
rv = reader(this, closure, mBuffer + mCursor, *_retval, left, &read);
|
||||
|
||||
if (NS_FAILED(rv)) // If we have written some data, return ok
|
||||
return (*_retval > 0) ? NS_OK : rv;
|
||||
mCursor += read;
|
||||
*_retval += read;
|
||||
count -= read;
|
||||
mFillPoint = std::max(mFillPoint, mCursor);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBufferedOutputStream::IsNonBlocking(bool *aNonBlocking)
|
||||
{
|
||||
if (mStream)
|
||||
return Sink()->IsNonBlocking(aNonBlocking);
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(char*)
|
||||
nsBufferedOutputStream::GetBuffer(uint32_t aLength, uint32_t aAlignMask)
|
||||
{
|
||||
NS_ASSERTION(mGetBufferCount == 0, "nested GetBuffer!");
|
||||
if (mGetBufferCount != 0)
|
||||
return nullptr;
|
||||
|
||||
if (mBufferDisabled)
|
||||
return nullptr;
|
||||
|
||||
char* buf = mBuffer + mCursor;
|
||||
uint32_t rem = mBufferSize - mCursor;
|
||||
if (rem == 0) {
|
||||
if (NS_FAILED(Flush()))
|
||||
return nullptr;
|
||||
buf = mBuffer + mCursor;
|
||||
rem = mBufferSize - mCursor;
|
||||
}
|
||||
|
||||
uint32_t mod = (NS_PTR_TO_INT32(buf) & aAlignMask);
|
||||
if (mod) {
|
||||
uint32_t pad = aAlignMask + 1 - mod;
|
||||
if (pad > rem)
|
||||
return nullptr;
|
||||
|
||||
memset(buf, 0, pad);
|
||||
mCursor += pad;
|
||||
buf += pad;
|
||||
rem -= pad;
|
||||
}
|
||||
|
||||
if (aLength > rem)
|
||||
return nullptr;
|
||||
mGetBufferCount++;
|
||||
return buf;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(void)
|
||||
nsBufferedOutputStream::PutBuffer(char* aBuffer, uint32_t aLength)
|
||||
{
|
||||
NS_ASSERTION(mGetBufferCount == 1, "stray PutBuffer!");
|
||||
if (--mGetBufferCount != 0)
|
||||
return;
|
||||
|
||||
NS_ASSERTION(mCursor + aLength <= mBufferSize, "PutBuffer botch");
|
||||
mCursor += aLength;
|
||||
if (mFillPoint < mCursor)
|
||||
mFillPoint = mCursor;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBufferedOutputStream::DisableBuffering()
|
||||
{
|
||||
NS_ASSERTION(!mBufferDisabled, "redundant call to DisableBuffering!");
|
||||
NS_ASSERTION(mGetBufferCount == 0,
|
||||
"DisableBuffer call between GetBuffer and PutBuffer!");
|
||||
if (mGetBufferCount != 0)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
// Empty the buffer so nsBufferedStream::Tell works.
|
||||
nsresult rv = Flush();
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
mBufferDisabled = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBufferedOutputStream::EnableBuffering()
|
||||
{
|
||||
NS_ASSERTION(mBufferDisabled, "gratuitous call to EnableBuffering!");
|
||||
mBufferDisabled = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBufferedOutputStream::GetUnbufferedStream(nsISupports* *aStream)
|
||||
{
|
||||
// Empty the buffer so subsequent i/o trumps any buffered data.
|
||||
if (mFillPoint) {
|
||||
nsresult rv = Flush();
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
}
|
||||
|
||||
*aStream = mStream;
|
||||
NS_IF_ADDREF(*aStream);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#undef METER
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
122
netwerk/base/nsBufferedStreams.h
Normal file
122
netwerk/base/nsBufferedStreams.h
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsBufferedStreams_h__
|
||||
#define nsBufferedStreams_h__
|
||||
|
||||
#include "nsIBufferedStreams.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsISafeOutputStream.h"
|
||||
#include "nsISeekableStream.h"
|
||||
#include "nsIStreamBufferAccess.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIIPCSerializableInputStream.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class nsBufferedStream : public nsISeekableStream
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSISEEKABLESTREAM
|
||||
|
||||
nsBufferedStream();
|
||||
|
||||
nsresult Close();
|
||||
|
||||
protected:
|
||||
virtual ~nsBufferedStream();
|
||||
|
||||
nsresult Init(nsISupports* stream, uint32_t bufferSize);
|
||||
NS_IMETHOD Fill() = 0;
|
||||
NS_IMETHOD Flush() = 0;
|
||||
|
||||
uint32_t mBufferSize;
|
||||
char* mBuffer;
|
||||
|
||||
// mBufferStartOffset is the offset relative to the start of mStream.
|
||||
int64_t mBufferStartOffset;
|
||||
|
||||
// mCursor is the read cursor for input streams, or write cursor for
|
||||
// output streams, and is relative to mBufferStartOffset.
|
||||
uint32_t mCursor;
|
||||
|
||||
// mFillPoint is the amount available in the buffer for input streams,
|
||||
// or the high watermark of bytes written into the buffer, and therefore
|
||||
// is relative to mBufferStartOffset.
|
||||
uint32_t mFillPoint;
|
||||
|
||||
nsISupports* mStream; // cast to appropriate subclass
|
||||
|
||||
bool mBufferDisabled;
|
||||
bool mEOF; // True if mStream is at EOF
|
||||
uint8_t mGetBufferCount;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class nsBufferedInputStream : public nsBufferedStream,
|
||||
public nsIBufferedInputStream,
|
||||
public nsIStreamBufferAccess,
|
||||
public nsIIPCSerializableInputStream
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIINPUTSTREAM
|
||||
NS_DECL_NSIBUFFEREDINPUTSTREAM
|
||||
NS_DECL_NSISTREAMBUFFERACCESS
|
||||
NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM
|
||||
|
||||
nsBufferedInputStream() : nsBufferedStream() {}
|
||||
|
||||
static nsresult
|
||||
Create(nsISupports *aOuter, REFNSIID aIID, void **aResult);
|
||||
|
||||
nsIInputStream* Source() {
|
||||
return (nsIInputStream*)mStream;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~nsBufferedInputStream() {}
|
||||
|
||||
NS_IMETHOD Fill() override;
|
||||
NS_IMETHOD Flush() override { return NS_OK; } // no-op for input streams
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class nsBufferedOutputStream final : public nsBufferedStream,
|
||||
public nsISafeOutputStream,
|
||||
public nsIBufferedOutputStream,
|
||||
public nsIStreamBufferAccess
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIOUTPUTSTREAM
|
||||
NS_DECL_NSISAFEOUTPUTSTREAM
|
||||
NS_DECL_NSIBUFFEREDOUTPUTSTREAM
|
||||
NS_DECL_NSISTREAMBUFFERACCESS
|
||||
|
||||
nsBufferedOutputStream() : nsBufferedStream() {}
|
||||
|
||||
static nsresult
|
||||
Create(nsISupports *aOuter, REFNSIID aIID, void **aResult);
|
||||
|
||||
nsIOutputStream* Sink() {
|
||||
return (nsIOutputStream*)mStream;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~nsBufferedOutputStream() { nsBufferedOutputStream::Close(); }
|
||||
|
||||
NS_IMETHOD Fill() override { return NS_OK; } // no-op for output streams
|
||||
|
||||
nsCOMPtr<nsISafeOutputStream> mSafeStream; // QI'd from mStream
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#endif // nsBufferedStreams_h__
|
||||
696
netwerk/base/nsChannelClassifier.cpp
Normal file
696
netwerk/base/nsChannelClassifier.cpp
Normal file
|
|
@ -0,0 +1,696 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 sts=2 ts=8 et tw=80 : */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsChannelClassifier.h"
|
||||
|
||||
#include "mozIThirdPartyUtil.h"
|
||||
#include "nsCharSeparatedTokenizer.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsICacheEntry.h"
|
||||
#include "nsICachingChannel.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIDOMDocument.h"
|
||||
#include "nsIHttpChannelInternal.h"
|
||||
#include "nsIIOService.h"
|
||||
#include "nsIParentChannel.h"
|
||||
#include "nsIPermissionManager.h"
|
||||
#include "nsIPrivateBrowsingTrackingProtectionWhitelist.h"
|
||||
#include "nsIProtocolHandler.h"
|
||||
#include "nsIScriptError.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsISecureBrowserUI.h"
|
||||
#include "nsISecurityEventSink.h"
|
||||
#include "nsIURL.h"
|
||||
#include "nsIWebProgressListener.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
|
||||
#include "mozilla/ErrorNames.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
//
|
||||
// MOZ_LOG=nsChannelClassifier:5
|
||||
//
|
||||
static LazyLogModule gChannelClassifierLog("nsChannelClassifier");
|
||||
|
||||
#undef LOG
|
||||
#define LOG(args) MOZ_LOG(gChannelClassifierLog, LogLevel::Debug, args)
|
||||
#define LOG_ENABLED() MOZ_LOG_TEST(gChannelClassifierLog, LogLevel::Debug)
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsChannelClassifier,
|
||||
nsIURIClassifierCallback)
|
||||
|
||||
nsChannelClassifier::nsChannelClassifier()
|
||||
: mIsAllowListed(false),
|
||||
mSuspendedChannel(false)
|
||||
{
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsChannelClassifier::ShouldEnableTrackingProtection(nsIChannel *aChannel,
|
||||
bool *result)
|
||||
{
|
||||
// Should only be called in the parent process.
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
|
||||
NS_ENSURE_ARG(result);
|
||||
*result = false;
|
||||
|
||||
nsCOMPtr<nsILoadContext> loadContext;
|
||||
NS_QueryNotificationCallbacks(aChannel, loadContext);
|
||||
if (!loadContext || !(loadContext->UseTrackingProtection())) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
|
||||
do_GetService(THIRDPARTYUTIL_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIHttpChannelInternal> chan = do_QueryInterface(aChannel, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIURI> topWinURI;
|
||||
rv = chan->GetTopWindowURI(getter_AddRefs(topWinURI));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!topWinURI) {
|
||||
LOG(("nsChannelClassifier[%p]: No window URI\n", this));
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> chanURI;
|
||||
rv = aChannel->GetURI(getter_AddRefs(chanURI));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Third party checks don't work for chrome:// URIs in mochitests, so just
|
||||
// default to isThirdParty = true. We check isThirdPartyWindow to expand
|
||||
// the list of domains that are considered first party (e.g., if
|
||||
// facebook.com includes an iframe from fatratgames.com, all subsources
|
||||
// included in that iframe are considered third-party with
|
||||
// isThirdPartyChannel, even if they are not third-party w.r.t.
|
||||
// facebook.com), and isThirdPartyChannel to prevent top-level navigations
|
||||
// from being detected as third-party.
|
||||
bool isThirdPartyChannel = true;
|
||||
bool isThirdPartyWindow = true;
|
||||
thirdPartyUtil->IsThirdPartyURI(chanURI, topWinURI, &isThirdPartyWindow);
|
||||
thirdPartyUtil->IsThirdPartyChannel(aChannel, nullptr, &isThirdPartyChannel);
|
||||
if (!isThirdPartyWindow || !isThirdPartyChannel) {
|
||||
*result = false;
|
||||
if (LOG_ENABLED()) {
|
||||
LOG(("nsChannelClassifier[%p]: Skipping tracking protection checks "
|
||||
"for first party or top-level load channel[%p] with uri %s",
|
||||
this, aChannel, chanURI->GetSpecOrDefault().get()));
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIIOService> ios = do_GetService(NS_IOSERVICE_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
const char ALLOWLIST_EXAMPLE_PREF[] = "channelclassifier.allowlist_example";
|
||||
if (!topWinURI && Preferences::GetBool(ALLOWLIST_EXAMPLE_PREF, false)) {
|
||||
LOG(("nsChannelClassifier[%p]: Allowlisting test domain\n", this));
|
||||
rv = ios->NewURI(NS_LITERAL_CSTRING("http://allowlisted.example.com"),
|
||||
nullptr, nullptr, getter_AddRefs(topWinURI));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
// Take the host/port portion so we can allowlist by site. Also ignore the
|
||||
// scheme, since users who put sites on the allowlist probably don't expect
|
||||
// allowlisting to depend on scheme.
|
||||
nsCOMPtr<nsIURL> url = do_QueryInterface(topWinURI, &rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv; // normal for some loads, no need to print a warning
|
||||
}
|
||||
|
||||
nsCString escaped(NS_LITERAL_CSTRING("https://"));
|
||||
nsAutoCString temp;
|
||||
rv = url->GetHostPort(temp);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
escaped.Append(temp);
|
||||
|
||||
// Stuff the whole thing back into a URI for the permission manager.
|
||||
rv = ios->NewURI(escaped, nullptr, nullptr, getter_AddRefs(topWinURI));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIPermissionManager> permMgr =
|
||||
do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
uint32_t permissions = nsIPermissionManager::UNKNOWN_ACTION;
|
||||
rv = permMgr->TestPermission(topWinURI, "trackingprotection", &permissions);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (permissions == nsIPermissionManager::ALLOW_ACTION) {
|
||||
LOG(("nsChannelClassifier[%p]: Allowlisting channel[%p] for %s", this,
|
||||
aChannel, escaped.get()));
|
||||
mIsAllowListed = true;
|
||||
*result = false;
|
||||
} else {
|
||||
*result = true;
|
||||
}
|
||||
|
||||
// In Private Browsing Mode we also check against an in-memory list.
|
||||
if (NS_UsePrivateBrowsing(aChannel)) {
|
||||
nsCOMPtr<nsIPrivateBrowsingTrackingProtectionWhitelist> pbmtpWhitelist =
|
||||
do_GetService(NS_PBTRACKINGPROTECTIONWHITELIST_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
bool exists = false;
|
||||
rv = pbmtpWhitelist->ExistsInAllowList(topWinURI, &exists);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (exists) {
|
||||
mIsAllowListed = true;
|
||||
LOG(("nsChannelClassifier[%p]: Allowlisting channel[%p] in PBM for %s",
|
||||
this, aChannel, escaped.get()));
|
||||
}
|
||||
|
||||
*result = !exists;
|
||||
}
|
||||
|
||||
// Tracking protection will be enabled so return without updating
|
||||
// the security state. If any channels are subsequently cancelled
|
||||
// (page elements blocked) the state will be then updated.
|
||||
if (*result) {
|
||||
if (LOG_ENABLED()) {
|
||||
LOG(("nsChannelClassifier[%p]: Enabling tracking protection checks on "
|
||||
"channel[%p] with uri %s for toplevel window %s", this, aChannel,
|
||||
chanURI->GetSpecOrDefault().get(),
|
||||
topWinURI->GetSpecOrDefault().get()));
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Tracking protection will be disabled so update the security state
|
||||
// of the document and fire a secure change event. If we can't get the
|
||||
// window for the channel, then the shield won't show up so we can't send
|
||||
// an event to the securityUI anyway.
|
||||
return NotifyTrackingProtectionDisabled(aChannel);
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
nsChannelClassifier::NotifyTrackingProtectionDisabled(nsIChannel *aChannel)
|
||||
{
|
||||
// Can be called in EITHER the parent or child process.
|
||||
nsCOMPtr<nsIParentChannel> parentChannel;
|
||||
NS_QueryNotificationCallbacks(aChannel, parentChannel);
|
||||
if (parentChannel) {
|
||||
// This channel is a parent-process proxy for a child process request.
|
||||
// Tell the child process channel to do this instead.
|
||||
parentChannel->NotifyTrackingProtectionDisabled();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
|
||||
do_GetService(THIRDPARTYUTIL_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<mozIDOMWindowProxy> win;
|
||||
rv = thirdPartyUtil->GetTopWindowForChannel(aChannel, getter_AddRefs(win));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
auto* pwin = nsPIDOMWindowOuter::From(win);
|
||||
nsCOMPtr<nsIDocShell> docShell = pwin->GetDocShell();
|
||||
if (!docShell) {
|
||||
return NS_OK;
|
||||
}
|
||||
nsCOMPtr<nsIDocument> doc = docShell->GetDocument();
|
||||
NS_ENSURE_TRUE(doc, NS_OK);
|
||||
|
||||
// Notify nsIWebProgressListeners of this security event.
|
||||
// Can be used to change the UI state.
|
||||
nsCOMPtr<nsISecurityEventSink> eventSink = do_QueryInterface(docShell, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, NS_OK);
|
||||
uint32_t state = 0;
|
||||
nsCOMPtr<nsISecureBrowserUI> securityUI;
|
||||
docShell->GetSecurityUI(getter_AddRefs(securityUI));
|
||||
if (!securityUI) {
|
||||
return NS_OK;
|
||||
}
|
||||
doc->SetHasTrackingContentLoaded(true);
|
||||
securityUI->GetState(&state);
|
||||
state |= nsIWebProgressListener::STATE_LOADED_TRACKING_CONTENT;
|
||||
eventSink->OnSecurityChange(nullptr, state);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsChannelClassifier::Start(nsIChannel *aChannel)
|
||||
{
|
||||
mChannel = aChannel;
|
||||
|
||||
nsresult rv = StartInternal();
|
||||
if (NS_FAILED(rv)) {
|
||||
// If we aren't getting a callback for any reason, assume a good verdict and
|
||||
// make sure we resume the channel if necessary.
|
||||
OnClassifyComplete(NS_OK);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsChannelClassifier::StartInternal()
|
||||
{
|
||||
// Should only be called in the parent process.
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
|
||||
// Don't bother to run the classifier on a load that has already failed.
|
||||
// (this might happen after a redirect)
|
||||
nsresult status;
|
||||
mChannel->GetStatus(&status);
|
||||
if (NS_FAILED(status))
|
||||
return status;
|
||||
|
||||
// Don't bother to run the classifier on a cached load that was
|
||||
// previously classified as good.
|
||||
if (HasBeenClassified(mChannel)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsresult rv = mChannel->GetURI(getter_AddRefs(uri));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Don't bother checking certain types of URIs.
|
||||
bool hasFlags;
|
||||
rv = NS_URIChainHasFlags(uri,
|
||||
nsIProtocolHandler::URI_DANGEROUS_TO_LOAD,
|
||||
&hasFlags);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (hasFlags) return NS_ERROR_UNEXPECTED;
|
||||
|
||||
rv = NS_URIChainHasFlags(uri,
|
||||
nsIProtocolHandler::URI_IS_LOCAL_FILE,
|
||||
&hasFlags);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (hasFlags) return NS_ERROR_UNEXPECTED;
|
||||
|
||||
rv = NS_URIChainHasFlags(uri,
|
||||
nsIProtocolHandler::URI_IS_UI_RESOURCE,
|
||||
&hasFlags);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (hasFlags) return NS_ERROR_UNEXPECTED;
|
||||
|
||||
rv = NS_URIChainHasFlags(uri,
|
||||
nsIProtocolHandler::URI_IS_LOCAL_RESOURCE,
|
||||
&hasFlags);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (hasFlags) return NS_ERROR_UNEXPECTED;
|
||||
|
||||
// Skip whitelisted hostnames.
|
||||
nsAutoCString whitelisted;
|
||||
Preferences::GetCString("urlclassifier.skipHostnames", &whitelisted);
|
||||
if (!whitelisted.IsEmpty()) {
|
||||
ToLowerCase(whitelisted);
|
||||
LOG(("nsChannelClassifier[%p]:StartInternal whitelisted hostnames = %s",
|
||||
this, whitelisted.get()));
|
||||
if (IsHostnameWhitelisted(uri, whitelisted)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURIClassifier> uriClassifier =
|
||||
do_GetService(NS_URICLASSIFIERSERVICE_CONTRACTID, &rv);
|
||||
if (rv == NS_ERROR_FACTORY_NOT_REGISTERED ||
|
||||
rv == NS_ERROR_NOT_AVAILABLE) {
|
||||
// no URI classifier, ignore this failure.
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIScriptSecurityManager> securityManager =
|
||||
do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
rv = securityManager->GetChannelURIPrincipal(mChannel, getter_AddRefs(principal));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
bool expectCallback;
|
||||
bool trackingProtectionEnabled = false;
|
||||
(void)ShouldEnableTrackingProtection(mChannel, &trackingProtectionEnabled);
|
||||
|
||||
if (LOG_ENABLED()) {
|
||||
nsCOMPtr<nsIURI> principalURI;
|
||||
principal->GetURI(getter_AddRefs(principalURI));
|
||||
LOG(("nsChannelClassifier[%p]: Classifying principal %s on channel with "
|
||||
"uri %s", this, principalURI->GetSpecOrDefault().get(),
|
||||
uri->GetSpecOrDefault().get()));
|
||||
}
|
||||
rv = uriClassifier->Classify(principal, trackingProtectionEnabled, this,
|
||||
&expectCallback);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (expectCallback) {
|
||||
// Suspend the channel, it will be resumed when we get the classifier
|
||||
// callback.
|
||||
rv = mChannel->Suspend();
|
||||
if (NS_FAILED(rv)) {
|
||||
// Some channels (including nsJSChannel) fail on Suspend. This
|
||||
// shouldn't be fatal, but will prevent malware from being
|
||||
// blocked on these channels.
|
||||
LOG(("nsChannelClassifier[%p]: Couldn't suspend channel", this));
|
||||
return rv;
|
||||
}
|
||||
|
||||
mSuspendedChannel = true;
|
||||
LOG(("nsChannelClassifier[%p]: suspended channel %p",
|
||||
this, mChannel.get()));
|
||||
} else {
|
||||
LOG(("nsChannelClassifier[%p]: not expecting callback", this));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
nsChannelClassifier::IsHostnameWhitelisted(nsIURI *aUri,
|
||||
const nsACString &aWhitelisted)
|
||||
{
|
||||
nsAutoCString host;
|
||||
nsresult rv = aUri->GetHost(host);
|
||||
if (NS_FAILED(rv) || host.IsEmpty()) {
|
||||
return false;
|
||||
}
|
||||
ToLowerCase(host);
|
||||
|
||||
nsCCharSeparatedTokenizer tokenizer(aWhitelisted, ',');
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
const nsCSubstring& token = tokenizer.nextToken();
|
||||
if (token.Equals(host)) {
|
||||
LOG(("nsChannelClassifier[%p]:StartInternal skipping %s (whitelisted)",
|
||||
this, host.get()));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Note in the cache entry that this URL was classified, so that future
|
||||
// cached loads don't need to be checked.
|
||||
void
|
||||
nsChannelClassifier::MarkEntryClassified(nsresult status)
|
||||
{
|
||||
// Should only be called in the parent process.
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
|
||||
// Don't cache tracking classifications because we support allowlisting.
|
||||
if (status == NS_ERROR_TRACKING_URI || mIsAllowListed) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (LOG_ENABLED()) {
|
||||
nsAutoCString errorName;
|
||||
GetErrorName(status, errorName);
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
mChannel->GetURI(getter_AddRefs(uri));
|
||||
nsAutoCString spec;
|
||||
uri->GetAsciiSpec(spec);
|
||||
LOG(("nsChannelClassifier::MarkEntryClassified[%s] %s",
|
||||
errorName.get(), spec.get()));
|
||||
}
|
||||
|
||||
nsCOMPtr<nsICachingChannel> cachingChannel = do_QueryInterface(mChannel);
|
||||
if (!cachingChannel) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupports> cacheToken;
|
||||
cachingChannel->GetCacheToken(getter_AddRefs(cacheToken));
|
||||
if (!cacheToken) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsICacheEntry> cacheEntry =
|
||||
do_QueryInterface(cacheToken);
|
||||
if (!cacheEntry) {
|
||||
return;
|
||||
}
|
||||
|
||||
cacheEntry->SetMetaDataElement("necko:classified",
|
||||
NS_SUCCEEDED(status) ? "1" : nullptr);
|
||||
}
|
||||
|
||||
bool
|
||||
nsChannelClassifier::HasBeenClassified(nsIChannel *aChannel)
|
||||
{
|
||||
// Should only be called in the parent process.
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
|
||||
nsCOMPtr<nsICachingChannel> cachingChannel =
|
||||
do_QueryInterface(aChannel);
|
||||
if (!cachingChannel) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only check the tag if we are loading from the cache without
|
||||
// validation.
|
||||
bool fromCache;
|
||||
if (NS_FAILED(cachingChannel->IsFromCache(&fromCache)) || !fromCache) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupports> cacheToken;
|
||||
cachingChannel->GetCacheToken(getter_AddRefs(cacheToken));
|
||||
if (!cacheToken) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsICacheEntry> cacheEntry =
|
||||
do_QueryInterface(cacheToken);
|
||||
if (!cacheEntry) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsXPIDLCString tag;
|
||||
cacheEntry->GetMetaDataElement("necko:classified", getter_Copies(tag));
|
||||
return tag.EqualsLiteral("1");
|
||||
}
|
||||
|
||||
//static
|
||||
bool
|
||||
nsChannelClassifier::SameLoadingURI(nsIDocument *aDoc, nsIChannel *aChannel)
|
||||
{
|
||||
nsCOMPtr<nsIURI> docURI = aDoc->GetDocumentURI();
|
||||
nsCOMPtr<nsILoadInfo> channelLoadInfo = aChannel->GetLoadInfo();
|
||||
if (!channelLoadInfo || !docURI) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPrincipal> channelLoadingPrincipal = channelLoadInfo->LoadingPrincipal();
|
||||
if (!channelLoadingPrincipal) {
|
||||
// TYPE_DOCUMENT loads will not have a channelLoadingPrincipal. But top level
|
||||
// loads should not be blocked by Tracking Protection, so we will return
|
||||
// false
|
||||
return false;
|
||||
}
|
||||
nsCOMPtr<nsIURI> channelLoadingURI;
|
||||
channelLoadingPrincipal->GetURI(getter_AddRefs(channelLoadingURI));
|
||||
if (!channelLoadingURI) {
|
||||
return false;
|
||||
}
|
||||
bool equals = false;
|
||||
nsresult rv = docURI->EqualsExceptRef(channelLoadingURI, &equals);
|
||||
return NS_SUCCEEDED(rv) && equals;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
nsChannelClassifier::SetBlockedTrackingContent(nsIChannel *channel)
|
||||
{
|
||||
// Can be called in EITHER the parent or child process.
|
||||
nsCOMPtr<nsIParentChannel> parentChannel;
|
||||
NS_QueryNotificationCallbacks(channel, parentChannel);
|
||||
if (parentChannel) {
|
||||
// This channel is a parent-process proxy for a child process request. The
|
||||
// actual channel will be notified via the status passed to
|
||||
// nsIRequest::Cancel and do this for us.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<mozIDOMWindowProxy> win;
|
||||
nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
|
||||
do_GetService(THIRDPARTYUTIL_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, NS_OK);
|
||||
rv = thirdPartyUtil->GetTopWindowForChannel(channel, getter_AddRefs(win));
|
||||
NS_ENSURE_SUCCESS(rv, NS_OK);
|
||||
auto* pwin = nsPIDOMWindowOuter::From(win);
|
||||
nsCOMPtr<nsIDocShell> docShell = pwin->GetDocShell();
|
||||
if (!docShell) {
|
||||
return NS_OK;
|
||||
}
|
||||
nsCOMPtr<nsIDocument> doc = docShell->GetDocument();
|
||||
NS_ENSURE_TRUE(doc, NS_OK);
|
||||
|
||||
// This event might come after the user has navigated to another page.
|
||||
// To prevent showing the TrackingProtection UI on the wrong page, we need to
|
||||
// check that the loading URI for the channel is the same as the URI currently
|
||||
// loaded in the document.
|
||||
if (!SameLoadingURI(doc, channel)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Notify nsIWebProgressListeners of this security event.
|
||||
// Can be used to change the UI state.
|
||||
nsCOMPtr<nsISecurityEventSink> eventSink = do_QueryInterface(docShell, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, NS_OK);
|
||||
uint32_t state = 0;
|
||||
nsCOMPtr<nsISecureBrowserUI> securityUI;
|
||||
docShell->GetSecurityUI(getter_AddRefs(securityUI));
|
||||
if (!securityUI) {
|
||||
return NS_OK;
|
||||
}
|
||||
doc->SetHasTrackingContentBlocked(true);
|
||||
securityUI->GetState(&state);
|
||||
state |= nsIWebProgressListener::STATE_BLOCKED_TRACKING_CONTENT;
|
||||
eventSink->OnSecurityChange(nullptr, state);
|
||||
|
||||
// Log a warning to the web console.
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
channel->GetURI(getter_AddRefs(uri));
|
||||
NS_ConvertUTF8toUTF16 spec(uri->GetSpecOrDefault());
|
||||
const char16_t* params[] = { spec.get() };
|
||||
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
|
||||
NS_LITERAL_CSTRING("Tracking Protection"),
|
||||
doc,
|
||||
nsContentUtils::eNECKO_PROPERTIES,
|
||||
"TrackingUriBlocked",
|
||||
params, ArrayLength(params));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsChannelClassifier::IsTrackerWhitelisted()
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIURIClassifier> uriClassifier =
|
||||
do_GetService(NS_URICLASSIFIERSERVICE_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsAutoCString tables;
|
||||
Preferences::GetCString("urlclassifier.trackingWhitelistTable", &tables);
|
||||
|
||||
if (tables.IsEmpty()) {
|
||||
LOG(("nsChannelClassifier[%p]:IsTrackerWhitelisted whitelist disabled",
|
||||
this));
|
||||
return NS_ERROR_TRACKING_URI;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIHttpChannelInternal> chan = do_QueryInterface(mChannel, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIURI> topWinURI;
|
||||
rv = chan->GetTopWindowURI(getter_AddRefs(topWinURI));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (!topWinURI) {
|
||||
LOG(("nsChannelClassifier[%p]: No window URI", this));
|
||||
return NS_ERROR_TRACKING_URI;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIScriptSecurityManager> securityManager =
|
||||
do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsIPrincipal> chanPrincipal;
|
||||
rv = securityManager->GetChannelURIPrincipal(mChannel,
|
||||
getter_AddRefs(chanPrincipal));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Craft a whitelist URL like "toplevel.page/?resource=third.party.domain"
|
||||
nsAutoCString pageHostname, resourceDomain;
|
||||
rv = topWinURI->GetHost(pageHostname);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = chanPrincipal->GetBaseDomain(resourceDomain);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsAutoCString whitelistEntry = NS_LITERAL_CSTRING("http://") +
|
||||
pageHostname + NS_LITERAL_CSTRING("/?resource=") + resourceDomain;
|
||||
LOG(("nsChannelClassifier[%p]: Looking for %s in the whitelist",
|
||||
this, whitelistEntry.get()));
|
||||
|
||||
nsCOMPtr<nsIURI> whitelistURI;
|
||||
rv = NS_NewURI(getter_AddRefs(whitelistURI), whitelistEntry);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Check whether or not the tracker is in the entity whitelist
|
||||
nsAutoCString results;
|
||||
rv = uriClassifier->ClassifyLocalWithTables(whitelistURI, tables, results);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (!results.IsEmpty()) {
|
||||
return NS_OK; // found it on the whitelist, must not be blocked
|
||||
}
|
||||
|
||||
LOG(("nsChannelClassifier[%p]: %s is not in the whitelist",
|
||||
this, whitelistEntry.get()));
|
||||
return NS_ERROR_TRACKING_URI;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsChannelClassifier::OnClassifyComplete(nsresult aErrorCode)
|
||||
{
|
||||
// Should only be called in the parent process.
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
|
||||
if (aErrorCode == NS_ERROR_TRACKING_URI &&
|
||||
NS_SUCCEEDED(IsTrackerWhitelisted())) {
|
||||
LOG(("nsChannelClassifier[%p]:OnClassifyComplete tracker found "
|
||||
"in whitelist so we won't block it", this));
|
||||
aErrorCode = NS_OK;
|
||||
}
|
||||
|
||||
if (mSuspendedChannel) {
|
||||
nsAutoCString errorName;
|
||||
if (LOG_ENABLED()) {
|
||||
GetErrorName(aErrorCode, errorName);
|
||||
LOG(("nsChannelClassifier[%p]:OnClassifyComplete %s (suspended channel)",
|
||||
this, errorName.get()));
|
||||
}
|
||||
MarkEntryClassified(aErrorCode);
|
||||
|
||||
if (NS_FAILED(aErrorCode)) {
|
||||
if (LOG_ENABLED()) {
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
mChannel->GetURI(getter_AddRefs(uri));
|
||||
LOG(("nsChannelClassifier[%p]: cancelling channel %p for %s "
|
||||
"with error code %s", this, mChannel.get(),
|
||||
uri->GetSpecOrDefault().get(), errorName.get()));
|
||||
}
|
||||
|
||||
// Channel will be cancelled (page element blocked) due to tracking.
|
||||
// Do update the security state of the document and fire a security
|
||||
// change event.
|
||||
if (aErrorCode == NS_ERROR_TRACKING_URI) {
|
||||
SetBlockedTrackingContent(mChannel);
|
||||
}
|
||||
|
||||
mChannel->Cancel(aErrorCode);
|
||||
}
|
||||
LOG(("nsChannelClassifier[%p]: resuming channel %p from "
|
||||
"OnClassifyComplete", this, mChannel.get()));
|
||||
mChannel->Resume();
|
||||
}
|
||||
|
||||
mChannel = nullptr;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
65
netwerk/base/nsChannelClassifier.h
Normal file
65
netwerk/base/nsChannelClassifier.h
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsChannelClassifier_h__
|
||||
#define nsChannelClassifier_h__
|
||||
|
||||
#include "nsIURIClassifier.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
class nsIChannel;
|
||||
class nsIHttpChannelInternal;
|
||||
class nsIDocument;
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
class nsChannelClassifier final : public nsIURIClassifierCallback
|
||||
{
|
||||
public:
|
||||
nsChannelClassifier();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIURICLASSIFIERCALLBACK
|
||||
|
||||
// Calls nsIURIClassifier.Classify with the principal of the given channel,
|
||||
// and cancels the channel on a bad verdict.
|
||||
void Start(nsIChannel *aChannel);
|
||||
// Whether or not tracking protection should be enabled on this channel.
|
||||
nsresult ShouldEnableTrackingProtection(nsIChannel *aChannel, bool *result);
|
||||
|
||||
private:
|
||||
// True if the channel is on the allow list.
|
||||
bool mIsAllowListed;
|
||||
// True if the channel has been suspended.
|
||||
bool mSuspendedChannel;
|
||||
nsCOMPtr<nsIChannel> mChannel;
|
||||
|
||||
~nsChannelClassifier() {}
|
||||
// Caches good classifications for the channel principal.
|
||||
void MarkEntryClassified(nsresult status);
|
||||
bool HasBeenClassified(nsIChannel *aChannel);
|
||||
// Helper function so that we ensure we call ContinueBeginConnect once
|
||||
// Start is called. Returns NS_OK if and only if we will get a callback
|
||||
// from the classifier service.
|
||||
nsresult StartInternal();
|
||||
// Helper function to check a tracking URI against the whitelist
|
||||
nsresult IsTrackerWhitelisted();
|
||||
// Helper function to check a URI against the hostname whitelist
|
||||
bool IsHostnameWhitelisted(nsIURI *aUri, const nsACString &aWhitelisted);
|
||||
// Checks that the channel was loaded by the URI currently loaded in aDoc
|
||||
static bool SameLoadingURI(nsIDocument *aDoc, nsIChannel *aChannel);
|
||||
|
||||
public:
|
||||
// If we are blocking tracking content, update the corresponding flag in
|
||||
// the respective docshell and call nsISecurityEventSink::onSecurityChange.
|
||||
static nsresult SetBlockedTrackingContent(nsIChannel *channel);
|
||||
static nsresult NotifyTrackingProtectionDisabled(nsIChannel *aChannel);
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
106
netwerk/base/nsDNSPrefetch.cpp
Normal file
106
netwerk/base/nsDNSPrefetch.cpp
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsDNSPrefetch.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsString.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
#include "nsIDNSListener.h"
|
||||
#include "nsIDNSService.h"
|
||||
#include "nsICancelable.h"
|
||||
#include "nsIURI.h"
|
||||
|
||||
static nsIDNSService *sDNSService = nullptr;
|
||||
|
||||
nsresult
|
||||
nsDNSPrefetch::Initialize(nsIDNSService *aDNSService)
|
||||
{
|
||||
NS_IF_RELEASE(sDNSService);
|
||||
sDNSService = aDNSService;
|
||||
NS_IF_ADDREF(sDNSService);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDNSPrefetch::Shutdown()
|
||||
{
|
||||
NS_IF_RELEASE(sDNSService);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsDNSPrefetch::nsDNSPrefetch(nsIURI *aURI,
|
||||
nsIDNSListener *aListener,
|
||||
bool storeTiming)
|
||||
: mStoreTiming(storeTiming)
|
||||
, mListener(do_GetWeakReference(aListener))
|
||||
{
|
||||
aURI->GetAsciiHost(mHostname);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDNSPrefetch::Prefetch(uint16_t flags)
|
||||
{
|
||||
if (mHostname.IsEmpty())
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
if (!sDNSService)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
nsCOMPtr<nsICancelable> tmpOutstanding;
|
||||
|
||||
if (mStoreTiming)
|
||||
mStartTimestamp = mozilla::TimeStamp::Now();
|
||||
// If AsyncResolve fails, for example because prefetching is disabled,
|
||||
// then our timing will be useless. However, in such a case,
|
||||
// mEndTimestamp will be a null timestamp and callers should check
|
||||
// TimingsValid() before using the timing.
|
||||
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
|
||||
return sDNSService->AsyncResolve(mHostname,
|
||||
flags | nsIDNSService::RESOLVE_SPECULATE,
|
||||
this, mainThread,
|
||||
getter_AddRefs(tmpOutstanding));
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDNSPrefetch::PrefetchLow(bool refreshDNS)
|
||||
{
|
||||
return Prefetch(nsIDNSService::RESOLVE_PRIORITY_LOW |
|
||||
(refreshDNS ? nsIDNSService::RESOLVE_BYPASS_CACHE : 0));
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDNSPrefetch::PrefetchMedium(bool refreshDNS)
|
||||
{
|
||||
return Prefetch(nsIDNSService::RESOLVE_PRIORITY_MEDIUM |
|
||||
(refreshDNS ? nsIDNSService::RESOLVE_BYPASS_CACHE : 0));
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDNSPrefetch::PrefetchHigh(bool refreshDNS)
|
||||
{
|
||||
return Prefetch(refreshDNS ?
|
||||
nsIDNSService::RESOLVE_BYPASS_CACHE : 0);
|
||||
}
|
||||
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsDNSPrefetch, nsIDNSListener)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDNSPrefetch::OnLookupComplete(nsICancelable *request,
|
||||
nsIDNSRecord *rec,
|
||||
nsresult status)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Expecting DNS callback on main thread.");
|
||||
|
||||
if (mStoreTiming) {
|
||||
mEndTimestamp = mozilla::TimeStamp::Now();
|
||||
}
|
||||
nsCOMPtr<nsIDNSListener> listener = do_QueryReferent(mListener);
|
||||
if (listener) {
|
||||
listener->OnLookupComplete(request, rec, status);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
53
netwerk/base/nsDNSPrefetch.h
Normal file
53
netwerk/base/nsDNSPrefetch.h
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsDNSPrefetch_h___
|
||||
#define nsDNSPrefetch_h___
|
||||
|
||||
#include "nsWeakReference.h"
|
||||
#include "nsString.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
#include "nsIDNSListener.h"
|
||||
|
||||
class nsIURI;
|
||||
class nsIDNSService;
|
||||
|
||||
class nsDNSPrefetch final : public nsIDNSListener
|
||||
{
|
||||
~nsDNSPrefetch() {}
|
||||
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIDNSLISTENER
|
||||
|
||||
nsDNSPrefetch(nsIURI *aURI, nsIDNSListener *aListener, bool storeTiming);
|
||||
bool TimingsValid() const {
|
||||
return !mStartTimestamp.IsNull() && !mEndTimestamp.IsNull();
|
||||
}
|
||||
// Only use the two timings if TimingsValid() returns true
|
||||
const mozilla::TimeStamp& StartTimestamp() const { return mStartTimestamp; }
|
||||
const mozilla::TimeStamp& EndTimestamp() const { return mEndTimestamp; }
|
||||
|
||||
static nsresult Initialize(nsIDNSService *aDNSService);
|
||||
static nsresult Shutdown();
|
||||
|
||||
// Call one of the following methods to start the Prefetch.
|
||||
nsresult PrefetchHigh(bool refreshDNS = false);
|
||||
nsresult PrefetchMedium(bool refreshDNS = false);
|
||||
nsresult PrefetchLow(bool refreshDNS = false);
|
||||
|
||||
private:
|
||||
nsCString mHostname;
|
||||
bool mStoreTiming;
|
||||
mozilla::TimeStamp mStartTimestamp;
|
||||
mozilla::TimeStamp mEndTimestamp;
|
||||
nsWeakPtr mListener;
|
||||
|
||||
nsresult Prefetch(uint16_t flags);
|
||||
};
|
||||
|
||||
#endif
|
||||
359
netwerk/base/nsDirectoryIndexStream.cpp
Normal file
359
netwerk/base/nsDirectoryIndexStream.cpp
Normal file
|
|
@ -0,0 +1,359 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim:set sw=4 sts=4 et cin: */
|
||||
/* 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/. */
|
||||
|
||||
|
||||
/*
|
||||
|
||||
The converts a filesystem directory into an "HTTP index" stream per
|
||||
Lou Montulli's original spec:
|
||||
|
||||
http://www.mozilla.org/projects/netlib/dirindexformat.html
|
||||
|
||||
*/
|
||||
|
||||
#include "nsEscape.h"
|
||||
#include "nsDirectoryIndexStream.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "prtime.h"
|
||||
#include "nsISimpleEnumerator.h"
|
||||
#ifdef THREADSAFE_I18N
|
||||
#include "nsCollationCID.h"
|
||||
#include "nsICollation.h"
|
||||
#include "nsILocale.h"
|
||||
#include "nsILocaleService.h"
|
||||
#endif
|
||||
#include "nsIFile.h"
|
||||
#include "nsURLHelper.h"
|
||||
#include "nsNativeCharsetUtils.h"
|
||||
|
||||
// NOTE: This runs on the _file transport_ thread.
|
||||
// The problem is that now that we're actually doing something with the data,
|
||||
// we want to do stuff like i18n sorting. However, none of the collation stuff
|
||||
// is threadsafe.
|
||||
// So THIS CODE IS ASCII ONLY!!!!!!!! This is no worse than the current
|
||||
// behaviour, though. See bug 99382.
|
||||
// When this is fixed, #define THREADSAFE_I18N to get this code working
|
||||
|
||||
//#define THREADSAFE_I18N
|
||||
|
||||
using namespace mozilla;
|
||||
static LazyLogModule gLog("nsDirectoryIndexStream");
|
||||
|
||||
nsDirectoryIndexStream::nsDirectoryIndexStream()
|
||||
: mOffset(0), mStatus(NS_OK), mPos(0)
|
||||
{
|
||||
MOZ_LOG(gLog, LogLevel::Debug,
|
||||
("nsDirectoryIndexStream[%p]: created", this));
|
||||
}
|
||||
|
||||
static int compare(nsIFile* aElement1, nsIFile* aElement2, void* aData)
|
||||
{
|
||||
if (!NS_IsNativeUTF8()) {
|
||||
// don't check for errors, because we can't report them anyway
|
||||
nsAutoString name1, name2;
|
||||
aElement1->GetLeafName(name1);
|
||||
aElement2->GetLeafName(name2);
|
||||
|
||||
// Note - we should do the collation to do sorting. Why don't we?
|
||||
// Because that is _slow_. Using TestProtocols to list file:///dev/
|
||||
// goes from 3 seconds to 22. (This may be why nsXULSortService is
|
||||
// so slow as well).
|
||||
// Does this have bad effects? Probably, but since nsXULTree appears
|
||||
// to use the raw RDF literal value as the sort key (which ammounts to an
|
||||
// strcmp), it won't be any worse, I think.
|
||||
// This could be made faster, by creating the keys once,
|
||||
// but CompareString could still be smarter - see bug 99383 - bbaetz
|
||||
// NB - 99393 has been WONTFIXed. So if the I18N code is ever made
|
||||
// threadsafe so that this matters, we'd have to pass through a
|
||||
// struct { nsIFile*, uint8_t* } with the pre-calculated key.
|
||||
return Compare(name1, name2);
|
||||
}
|
||||
|
||||
nsAutoCString name1, name2;
|
||||
aElement1->GetNativeLeafName(name1);
|
||||
aElement2->GetNativeLeafName(name2);
|
||||
|
||||
return Compare(name1, name2);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDirectoryIndexStream::Init(nsIFile* aDir)
|
||||
{
|
||||
nsresult rv;
|
||||
bool isDir;
|
||||
rv = aDir->IsDirectory(&isDir);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
NS_PRECONDITION(isDir, "not a directory");
|
||||
if (!isDir)
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
|
||||
if (MOZ_LOG_TEST(gLog, LogLevel::Debug)) {
|
||||
nsAutoCString path;
|
||||
aDir->GetNativePath(path);
|
||||
MOZ_LOG(gLog, LogLevel::Debug,
|
||||
("nsDirectoryIndexStream[%p]: initialized on %s",
|
||||
this, path.get()));
|
||||
}
|
||||
|
||||
// Sigh. We have to allocate on the heap because there are no
|
||||
// assignment operators defined.
|
||||
nsCOMPtr<nsISimpleEnumerator> iter;
|
||||
rv = aDir->GetDirectoryEntries(getter_AddRefs(iter));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// Now lets sort, because clients expect it that way
|
||||
// XXX - should we do so here, or when the first item is requested?
|
||||
// XXX - use insertion sort instead?
|
||||
|
||||
bool more;
|
||||
nsCOMPtr<nsISupports> elem;
|
||||
while (NS_SUCCEEDED(iter->HasMoreElements(&more)) && more) {
|
||||
rv = iter->GetNext(getter_AddRefs(elem));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsCOMPtr<nsIFile> file = do_QueryInterface(elem);
|
||||
if (file)
|
||||
mArray.AppendObject(file); // addrefs
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef THREADSAFE_I18N
|
||||
nsCOMPtr<nsILocaleService> ls = do_GetService(NS_LOCALESERVICE_CONTRACTID,
|
||||
&rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCOMPtr<nsILocale> locale;
|
||||
rv = ls->GetApplicationLocale(getter_AddRefs(locale));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCOMPtr<nsICollationFactory> cf = do_CreateInstance(NS_COLLATIONFACTORY_CONTRACTID,
|
||||
&rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCOMPtr<nsICollation> coll;
|
||||
rv = cf->CreateCollation(locale, getter_AddRefs(coll));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
mArray.Sort(compare, coll);
|
||||
#else
|
||||
mArray.Sort(compare, nullptr);
|
||||
#endif
|
||||
|
||||
mBuf.AppendLiteral("300: ");
|
||||
nsAutoCString url;
|
||||
rv = net_GetURLSpecFromFile(aDir, url);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
mBuf.Append(url);
|
||||
mBuf.Append('\n');
|
||||
|
||||
mBuf.AppendLiteral("200: filename content-length last-modified file-type\n");
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsDirectoryIndexStream::~nsDirectoryIndexStream()
|
||||
{
|
||||
MOZ_LOG(gLog, LogLevel::Debug,
|
||||
("nsDirectoryIndexStream[%p]: destroyed", this));
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDirectoryIndexStream::Create(nsIFile* aDir, nsIInputStream** aResult)
|
||||
{
|
||||
RefPtr<nsDirectoryIndexStream> result = new nsDirectoryIndexStream();
|
||||
if (! result)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
nsresult rv = result->Init(aDir);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
result.forget(aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsDirectoryIndexStream, nsIInputStream)
|
||||
|
||||
// The below routines are proxied to the UI thread!
|
||||
NS_IMETHODIMP
|
||||
nsDirectoryIndexStream::Close()
|
||||
{
|
||||
mStatus = NS_BASE_STREAM_CLOSED;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDirectoryIndexStream::Available(uint64_t* aLength)
|
||||
{
|
||||
if (NS_FAILED(mStatus))
|
||||
return mStatus;
|
||||
|
||||
// If there's data in our buffer, use that
|
||||
if (mOffset < (int32_t)mBuf.Length()) {
|
||||
*aLength = mBuf.Length() - mOffset;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Returning one byte is not ideal, but good enough
|
||||
*aLength = (mPos < mArray.Count()) ? 1 : 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDirectoryIndexStream::Read(char* aBuf, uint32_t aCount, uint32_t* aReadCount)
|
||||
{
|
||||
if (mStatus == NS_BASE_STREAM_CLOSED) {
|
||||
*aReadCount = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
if (NS_FAILED(mStatus))
|
||||
return mStatus;
|
||||
|
||||
uint32_t nread = 0;
|
||||
|
||||
// If anything is enqueued (or left-over) in mBuf, then feed it to
|
||||
// the reader first.
|
||||
while (mOffset < (int32_t)mBuf.Length() && aCount != 0) {
|
||||
*(aBuf++) = char(mBuf.CharAt(mOffset++));
|
||||
--aCount;
|
||||
++nread;
|
||||
}
|
||||
|
||||
// Room left?
|
||||
if (aCount > 0) {
|
||||
mOffset = 0;
|
||||
mBuf.Truncate();
|
||||
|
||||
// Okay, now we'll suck stuff off of our iterator into the mBuf...
|
||||
while (uint32_t(mBuf.Length()) < aCount) {
|
||||
bool more = mPos < mArray.Count();
|
||||
if (!more) break;
|
||||
|
||||
// don't addref, for speed - an addref happened when it
|
||||
// was placed in the array, so it's not going to go stale
|
||||
nsIFile* current = mArray.ObjectAt(mPos);
|
||||
++mPos;
|
||||
|
||||
if (MOZ_LOG_TEST(gLog, LogLevel::Debug)) {
|
||||
nsAutoCString path;
|
||||
current->GetNativePath(path);
|
||||
MOZ_LOG(gLog, LogLevel::Debug,
|
||||
("nsDirectoryIndexStream[%p]: iterated %s",
|
||||
this, path.get()));
|
||||
}
|
||||
|
||||
// rjc: don't return hidden files/directories!
|
||||
// bbaetz: why not?
|
||||
nsresult rv;
|
||||
#ifndef XP_UNIX
|
||||
bool hidden = false;
|
||||
current->IsHidden(&hidden);
|
||||
if (hidden) {
|
||||
MOZ_LOG(gLog, LogLevel::Debug,
|
||||
("nsDirectoryIndexStream[%p]: skipping hidden file/directory",
|
||||
this));
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
int64_t fileSize = 0;
|
||||
current->GetFileSize( &fileSize );
|
||||
|
||||
PRTime fileInfoModifyTime = 0;
|
||||
current->GetLastModifiedTime( &fileInfoModifyTime );
|
||||
fileInfoModifyTime *= PR_USEC_PER_MSEC;
|
||||
|
||||
mBuf.AppendLiteral("201: ");
|
||||
|
||||
// The "filename" field
|
||||
if (!NS_IsNativeUTF8()) {
|
||||
nsAutoString leafname;
|
||||
rv = current->GetLeafName(leafname);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsAutoCString escaped;
|
||||
if (!leafname.IsEmpty() &&
|
||||
NS_Escape(NS_ConvertUTF16toUTF8(leafname), escaped, url_Path)) {
|
||||
mBuf.Append(escaped);
|
||||
mBuf.Append(' ');
|
||||
}
|
||||
} else {
|
||||
nsAutoCString leafname;
|
||||
rv = current->GetNativeLeafName(leafname);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsAutoCString escaped;
|
||||
if (!leafname.IsEmpty() &&
|
||||
NS_Escape(leafname, escaped, url_Path)) {
|
||||
mBuf.Append(escaped);
|
||||
mBuf.Append(' ');
|
||||
}
|
||||
}
|
||||
|
||||
// The "content-length" field
|
||||
mBuf.AppendInt(fileSize, 10);
|
||||
mBuf.Append(' ');
|
||||
|
||||
// The "last-modified" field
|
||||
PRExplodedTime tm;
|
||||
PR_ExplodeTime(fileInfoModifyTime, PR_GMTParameters, &tm);
|
||||
{
|
||||
char buf[64];
|
||||
PR_FormatTimeUSEnglish(buf, sizeof(buf), "%a,%%20%d%%20%b%%20%Y%%20%H:%M:%S%%20GMT ", &tm);
|
||||
mBuf.Append(buf);
|
||||
}
|
||||
|
||||
// The "file-type" field
|
||||
bool isFile = true;
|
||||
current->IsFile(&isFile);
|
||||
if (isFile) {
|
||||
mBuf.AppendLiteral("FILE ");
|
||||
}
|
||||
else {
|
||||
bool isDir;
|
||||
rv = current->IsDirectory(&isDir);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (isDir) {
|
||||
mBuf.AppendLiteral("DIRECTORY ");
|
||||
}
|
||||
else {
|
||||
bool isLink;
|
||||
rv = current->IsSymlink(&isLink);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (isLink) {
|
||||
mBuf.AppendLiteral("SYMBOLIC-LINK ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mBuf.Append('\n');
|
||||
}
|
||||
|
||||
// ...and once we've either run out of directory entries, or
|
||||
// filled up the buffer, then we'll push it to the reader.
|
||||
while (mOffset < (int32_t)mBuf.Length() && aCount != 0) {
|
||||
*(aBuf++) = char(mBuf.CharAt(mOffset++));
|
||||
--aCount;
|
||||
++nread;
|
||||
}
|
||||
}
|
||||
|
||||
*aReadCount = nread;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDirectoryIndexStream::ReadSegments(nsWriteSegmentFun writer, void * closure, uint32_t count, uint32_t *_retval)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDirectoryIndexStream::IsNonBlocking(bool *aNonBlocking)
|
||||
{
|
||||
*aNonBlocking = false;
|
||||
return NS_OK;
|
||||
}
|
||||
49
netwerk/base/nsDirectoryIndexStream.h
Normal file
49
netwerk/base/nsDirectoryIndexStream.h
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsDirectoryIndexStream_h__
|
||||
#define nsDirectoryIndexStream_h__
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
#include "nsString.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsCOMArray.h"
|
||||
|
||||
class nsIFile;
|
||||
|
||||
class nsDirectoryIndexStream final : public nsIInputStream
|
||||
{
|
||||
private:
|
||||
nsCString mBuf;
|
||||
int32_t mOffset;
|
||||
nsresult mStatus;
|
||||
|
||||
int32_t mPos; // position within mArray
|
||||
nsCOMArray<nsIFile> mArray; // file objects within the directory
|
||||
|
||||
nsDirectoryIndexStream();
|
||||
/**
|
||||
* aDir will only be used on the calling thread.
|
||||
*/
|
||||
nsresult Init(nsIFile* aDir);
|
||||
~nsDirectoryIndexStream();
|
||||
|
||||
public:
|
||||
/**
|
||||
* aDir will only be used on the calling thread.
|
||||
*/
|
||||
static nsresult
|
||||
Create(nsIFile* aDir, nsIInputStream** aStreamResult);
|
||||
|
||||
// nsISupportsInterface
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
// nsIInputStream interface
|
||||
NS_DECL_NSIINPUTSTREAM
|
||||
};
|
||||
|
||||
#endif // nsDirectoryIndexStream_h__
|
||||
|
||||
114
netwerk/base/nsDownloader.cpp
Normal file
114
netwerk/base/nsDownloader.cpp
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsDownloader.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsDirectoryServiceUtils.h"
|
||||
#include "nsDirectoryServiceDefs.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsCRTGlue.h"
|
||||
|
||||
nsDownloader::~nsDownloader()
|
||||
{
|
||||
if (mLocation && mLocationIsTemp) {
|
||||
// release the sink first since it may still hold an open file
|
||||
// descriptor to mLocation. this needs to happen before the
|
||||
// file can be removed otherwise the Remove call will fail.
|
||||
if (mSink) {
|
||||
mSink->Close();
|
||||
mSink = nullptr;
|
||||
}
|
||||
|
||||
nsresult rv = mLocation->Remove(false);
|
||||
if (NS_FAILED(rv))
|
||||
NS_ERROR("unable to remove temp file");
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsDownloader,
|
||||
nsIDownloader,
|
||||
nsIStreamListener,
|
||||
nsIRequestObserver)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDownloader::Init(nsIDownloadObserver *observer, nsIFile *location)
|
||||
{
|
||||
mObserver = observer;
|
||||
mLocation = location;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDownloader::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
|
||||
{
|
||||
nsresult rv;
|
||||
if (!mLocation) {
|
||||
nsCOMPtr<nsIFile> location;
|
||||
rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(location));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
char buf[13];
|
||||
NS_MakeRandomString(buf, 8);
|
||||
memcpy(buf+8, ".tmp", 5);
|
||||
rv = location->AppendNative(nsDependentCString(buf, 12));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = location->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
location.swap(mLocation);
|
||||
mLocationIsTemp = true;
|
||||
}
|
||||
|
||||
rv = NS_NewLocalFileOutputStream(getter_AddRefs(mSink), mLocation);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// we could wrap this output stream with a buffered output stream,
|
||||
// but it shouldn't be necessary since we will be writing large
|
||||
// chunks given to us via OnDataAvailable.
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDownloader::OnStopRequest(nsIRequest *request,
|
||||
nsISupports *ctxt,
|
||||
nsresult status)
|
||||
{
|
||||
if (mSink) {
|
||||
mSink->Close();
|
||||
mSink = nullptr;
|
||||
}
|
||||
|
||||
mObserver->OnDownloadComplete(this, request, ctxt, status, mLocation);
|
||||
mObserver = nullptr;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDownloader::ConsumeData(nsIInputStream* in,
|
||||
void* closure,
|
||||
const char* fromRawSegment,
|
||||
uint32_t toOffset,
|
||||
uint32_t count,
|
||||
uint32_t *writeCount)
|
||||
{
|
||||
nsDownloader *self = (nsDownloader *) closure;
|
||||
if (self->mSink)
|
||||
return self->mSink->Write(fromRawSegment, count, writeCount);
|
||||
|
||||
*writeCount = count;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDownloader::OnDataAvailable(nsIRequest *request, nsISupports *ctxt,
|
||||
nsIInputStream *inStr,
|
||||
uint64_t sourceOffset, uint32_t count)
|
||||
{
|
||||
uint32_t n;
|
||||
return inStr->ReadSegments(ConsumeData, this, count, &n);
|
||||
}
|
||||
40
netwerk/base/nsDownloader.h
Normal file
40
netwerk/base/nsDownloader.h
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsDownloader_h__
|
||||
#define nsDownloader_h__
|
||||
|
||||
#include "nsIDownloader.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
class nsIFile;
|
||||
class nsIOutputStream;
|
||||
|
||||
class nsDownloader : public nsIDownloader
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIDOWNLOADER
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
NS_DECL_NSISTREAMLISTENER
|
||||
|
||||
nsDownloader() : mLocationIsTemp(false) {}
|
||||
|
||||
protected:
|
||||
virtual ~nsDownloader();
|
||||
|
||||
static nsresult ConsumeData(nsIInputStream *in,
|
||||
void *closure,
|
||||
const char *fromRawSegment,
|
||||
uint32_t toOffset,
|
||||
uint32_t count,
|
||||
uint32_t *writeCount);
|
||||
|
||||
nsCOMPtr<nsIDownloadObserver> mObserver;
|
||||
nsCOMPtr<nsIFile> mLocation;
|
||||
nsCOMPtr<nsIOutputStream> mSink;
|
||||
bool mLocationIsTemp;
|
||||
};
|
||||
|
||||
#endif // nsDownloader_h__
|
||||
1153
netwerk/base/nsFileStreams.cpp
Normal file
1153
netwerk/base/nsFileStreams.cpp
Normal file
File diff suppressed because it is too large
Load diff
333
netwerk/base/nsFileStreams.h
Normal file
333
netwerk/base/nsFileStreams.h
Normal file
|
|
@ -0,0 +1,333 @@
|
|||
// /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsFileStreams_h__
|
||||
#define nsFileStreams_h__
|
||||
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsIFileStreams.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsISafeOutputStream.h"
|
||||
#include "nsISeekableStream.h"
|
||||
#include "nsILineInputStream.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIIPCSerializableInputStream.h"
|
||||
#include "nsReadLine.h"
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class nsFileStreamBase : public nsISeekableStream,
|
||||
public nsIFileMetadata
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSISEEKABLESTREAM
|
||||
NS_DECL_NSIFILEMETADATA
|
||||
|
||||
nsFileStreamBase();
|
||||
|
||||
protected:
|
||||
virtual ~nsFileStreamBase();
|
||||
|
||||
nsresult Close();
|
||||
nsresult Available(uint64_t* _retval);
|
||||
nsresult Read(char* aBuf, uint32_t aCount, uint32_t* _retval);
|
||||
nsresult ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
|
||||
uint32_t aCount, uint32_t* _retval);
|
||||
nsresult IsNonBlocking(bool* _retval);
|
||||
nsresult Flush();
|
||||
nsresult Write(const char* aBuf, uint32_t aCount, uint32_t* _retval);
|
||||
nsresult WriteFrom(nsIInputStream* aFromStream, uint32_t aCount,
|
||||
uint32_t* _retval);
|
||||
nsresult WriteSegments(nsReadSegmentFun aReader, void* aClosure,
|
||||
uint32_t aCount, uint32_t* _retval);
|
||||
|
||||
PRFileDesc* mFD;
|
||||
|
||||
/**
|
||||
* Flags describing our behavior. See the IDL file for possible values.
|
||||
*/
|
||||
int32_t mBehaviorFlags;
|
||||
|
||||
/**
|
||||
* Whether we have a pending open (see DEFER_OPEN in the IDL file).
|
||||
*/
|
||||
bool mDeferredOpen;
|
||||
|
||||
struct OpenParams {
|
||||
nsCOMPtr<nsIFile> localFile;
|
||||
int32_t ioFlags;
|
||||
int32_t perm;
|
||||
};
|
||||
|
||||
/**
|
||||
* Data we need to do an open.
|
||||
*/
|
||||
OpenParams mOpenParams;
|
||||
|
||||
/**
|
||||
* Prepares the data we need to open the file, and either does the open now
|
||||
* by calling DoOpen(), or leaves it to be opened later by a call to
|
||||
* DoPendingOpen().
|
||||
*/
|
||||
nsresult MaybeOpen(nsIFile* aFile, int32_t aIoFlags, int32_t aPerm,
|
||||
bool aDeferred);
|
||||
|
||||
/**
|
||||
* Cleans up data prepared in MaybeOpen.
|
||||
*/
|
||||
void CleanUpOpen();
|
||||
|
||||
/**
|
||||
* Open the file. This is called either from MaybeOpen (during Init)
|
||||
* or from DoPendingOpen (if DEFER_OPEN is used when initializing this
|
||||
* stream). The default behavior of DoOpen is to open the file and save the
|
||||
* file descriptor.
|
||||
*/
|
||||
virtual nsresult DoOpen();
|
||||
|
||||
/**
|
||||
* If there is a pending open, do it now. It's important for this to be
|
||||
* inline since we do it in almost every stream API call.
|
||||
*/
|
||||
inline nsresult DoPendingOpen();
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class nsFileInputStream : public nsFileStreamBase,
|
||||
public nsIFileInputStream,
|
||||
public nsILineInputStream,
|
||||
public nsIIPCSerializableInputStream
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIFILEINPUTSTREAM
|
||||
NS_DECL_NSILINEINPUTSTREAM
|
||||
NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM
|
||||
|
||||
NS_IMETHOD Close() override;
|
||||
NS_IMETHOD Tell(int64_t *aResult) override;
|
||||
NS_IMETHOD Available(uint64_t* _retval) override;
|
||||
NS_IMETHOD Read(char* aBuf, uint32_t aCount, uint32_t* _retval) override;
|
||||
NS_IMETHOD ReadSegments(nsWriteSegmentFun aWriter, void *aClosure,
|
||||
uint32_t aCount, uint32_t* _retval) override
|
||||
{
|
||||
return nsFileStreamBase::ReadSegments(aWriter, aClosure, aCount,
|
||||
_retval);
|
||||
}
|
||||
NS_IMETHOD IsNonBlocking(bool* _retval) override
|
||||
{
|
||||
return nsFileStreamBase::IsNonBlocking(_retval);
|
||||
}
|
||||
|
||||
// Overrided from nsFileStreamBase
|
||||
NS_IMETHOD Seek(int32_t aWhence, int64_t aOffset) override;
|
||||
|
||||
nsFileInputStream()
|
||||
: mLineBuffer(nullptr), mIOFlags(0), mPerm(0), mCachedPosition(0)
|
||||
{}
|
||||
|
||||
static nsresult
|
||||
Create(nsISupports *aOuter, REFNSIID aIID, void **aResult);
|
||||
|
||||
protected:
|
||||
virtual ~nsFileInputStream()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
nsresult SeekInternal(int32_t aWhence, int64_t aOffset, bool aClearBuf=true);
|
||||
|
||||
nsAutoPtr<nsLineBuffer<char> > mLineBuffer;
|
||||
|
||||
/**
|
||||
* The file being opened.
|
||||
*/
|
||||
nsCOMPtr<nsIFile> mFile;
|
||||
/**
|
||||
* The IO flags passed to Init() for the file open.
|
||||
*/
|
||||
int32_t mIOFlags;
|
||||
/**
|
||||
* The permissions passed to Init() for the file open.
|
||||
*/
|
||||
int32_t mPerm;
|
||||
|
||||
/**
|
||||
* Cached position for Tell for automatically reopening streams.
|
||||
*/
|
||||
int64_t mCachedPosition;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Internal, called to open a file. Parameters are the same as their
|
||||
* Init() analogues.
|
||||
*/
|
||||
nsresult Open(nsIFile* file, int32_t ioFlags, int32_t perm);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class nsPartialFileInputStream : public nsFileInputStream,
|
||||
public nsIPartialFileInputStream
|
||||
{
|
||||
public:
|
||||
using nsFileInputStream::Init;
|
||||
using nsFileInputStream::Read;
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIPARTIALFILEINPUTSTREAM
|
||||
NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM
|
||||
|
||||
nsPartialFileInputStream()
|
||||
: mStart(0), mLength(0), mPosition(0), mDeferredSeek(false)
|
||||
{ }
|
||||
|
||||
NS_IMETHOD Tell(int64_t *aResult) override;
|
||||
NS_IMETHOD Available(uint64_t *aResult) override;
|
||||
NS_IMETHOD Read(char* aBuf, uint32_t aCount, uint32_t* aResult) override;
|
||||
NS_IMETHOD Seek(int32_t aWhence, int64_t aOffset) override;
|
||||
|
||||
static nsresult
|
||||
Create(nsISupports *aOuter, REFNSIID aIID, void **aResult);
|
||||
|
||||
protected:
|
||||
~nsPartialFileInputStream()
|
||||
{ }
|
||||
|
||||
inline nsresult DoPendingSeek();
|
||||
|
||||
private:
|
||||
uint64_t TruncateSize(uint64_t aSize) {
|
||||
return std::min<uint64_t>(mLength - mPosition, aSize);
|
||||
}
|
||||
|
||||
uint64_t mStart;
|
||||
uint64_t mLength;
|
||||
uint64_t mPosition;
|
||||
bool mDeferredSeek;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class nsFileOutputStream : public nsFileStreamBase,
|
||||
public nsIFileOutputStream
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIFILEOUTPUTSTREAM
|
||||
NS_FORWARD_NSIOUTPUTSTREAM(nsFileStreamBase::)
|
||||
|
||||
static nsresult
|
||||
Create(nsISupports *aOuter, REFNSIID aIID, void **aResult);
|
||||
|
||||
protected:
|
||||
virtual ~nsFileOutputStream()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* A safe file output stream that overwrites the destination file only
|
||||
* once writing is complete. This protects against incomplete writes
|
||||
* due to the process or the thread being interrupted or crashed.
|
||||
*/
|
||||
class nsAtomicFileOutputStream : public nsFileOutputStream,
|
||||
public nsISafeOutputStream
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSISAFEOUTPUTSTREAM
|
||||
|
||||
nsAtomicFileOutputStream() :
|
||||
mTargetFileExists(true),
|
||||
mWriteResult(NS_OK) {}
|
||||
|
||||
virtual nsresult DoOpen() override;
|
||||
|
||||
NS_IMETHOD Close() override;
|
||||
NS_IMETHOD Write(const char *buf, uint32_t count, uint32_t *result) override;
|
||||
NS_IMETHOD Init(nsIFile* file, int32_t ioFlags, int32_t perm, int32_t behaviorFlags) override;
|
||||
|
||||
protected:
|
||||
virtual ~nsAtomicFileOutputStream()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> mTargetFile;
|
||||
nsCOMPtr<nsIFile> mTempFile;
|
||||
|
||||
bool mTargetFileExists;
|
||||
nsresult mWriteResult; // Internally set in Write()
|
||||
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* A safe file output stream that overwrites the destination file only
|
||||
* once writing + flushing is complete. This protects against more
|
||||
* classes of software/hardware errors than nsAtomicFileOutputStream,
|
||||
* at the expense of being more costly to the disk, OS and battery.
|
||||
*/
|
||||
class nsSafeFileOutputStream : public nsAtomicFileOutputStream
|
||||
{
|
||||
public:
|
||||
|
||||
NS_IMETHOD Finish() override;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class nsFileStream : public nsFileStreamBase,
|
||||
public nsIInputStream,
|
||||
public nsIOutputStream,
|
||||
public nsIFileStream
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIFILESTREAM
|
||||
NS_FORWARD_NSIINPUTSTREAM(nsFileStreamBase::)
|
||||
|
||||
// Can't use NS_FORWARD_NSIOUTPUTSTREAM due to overlapping methods
|
||||
// Close() and IsNonBlocking()
|
||||
NS_IMETHOD Flush() override
|
||||
{
|
||||
return nsFileStreamBase::Flush();
|
||||
}
|
||||
NS_IMETHOD Write(const char* aBuf, uint32_t aCount, uint32_t* _retval) override
|
||||
{
|
||||
return nsFileStreamBase::Write(aBuf, aCount, _retval);
|
||||
}
|
||||
NS_IMETHOD WriteFrom(nsIInputStream* aFromStream, uint32_t aCount,
|
||||
uint32_t* _retval) override
|
||||
{
|
||||
return nsFileStreamBase::WriteFrom(aFromStream, aCount, _retval);
|
||||
}
|
||||
NS_IMETHOD WriteSegments(nsReadSegmentFun aReader, void* aClosure,
|
||||
uint32_t aCount, uint32_t* _retval) override
|
||||
{
|
||||
return nsFileStreamBase::WriteSegments(aReader, aClosure, aCount,
|
||||
_retval);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~nsFileStream()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#endif // nsFileStreams_h__
|
||||
205
netwerk/base/nsIApplicationCache.idl
Normal file
205
netwerk/base/nsIApplicationCache.idl
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIArray;
|
||||
interface nsIFile;
|
||||
interface nsIURI;
|
||||
|
||||
/**
|
||||
* Application caches can store a set of namespace entries that affect
|
||||
* loads from the application cache. If a load from the cache fails
|
||||
* to match an exact cache entry, namespaces entries will be searched
|
||||
* for a substring match, and should be applied appropriately.
|
||||
*/
|
||||
[scriptable, uuid(96e4c264-2065-4ce9-93bb-43734c62c4eb)]
|
||||
interface nsIApplicationCacheNamespace : nsISupports
|
||||
{
|
||||
/**
|
||||
* Items matching this namespace can be fetched from the network
|
||||
* when loading from this cache. The "data" attribute is unused.
|
||||
*/
|
||||
const unsigned long NAMESPACE_BYPASS = 1 << 0;
|
||||
|
||||
/**
|
||||
* Items matching this namespace can be fetched from the network
|
||||
* when loading from this cache. If the load fails, the cache entry
|
||||
* specified by the "data" attribute should be loaded instead.
|
||||
*/
|
||||
const unsigned long NAMESPACE_FALLBACK = 1 << 1;
|
||||
|
||||
/**
|
||||
* Items matching this namespace should be cached
|
||||
* opportunistically. Successful toplevel loads of documents
|
||||
* in this namespace should be placed in the application cache.
|
||||
* Namespaces specifying NAMESPACE_OPPORTUNISTIC may also specify
|
||||
* NAMESPACE_FALLBACK to supply a fallback entry.
|
||||
*/
|
||||
const unsigned long NAMESPACE_OPPORTUNISTIC = 1 << 2;
|
||||
|
||||
/**
|
||||
* Initialize the namespace.
|
||||
*/
|
||||
void init(in unsigned long itemType,
|
||||
in ACString namespaceSpec,
|
||||
in ACString data);
|
||||
|
||||
/**
|
||||
* The namespace type.
|
||||
*/
|
||||
readonly attribute unsigned long itemType;
|
||||
|
||||
/**
|
||||
* The prefix of this namespace. This should be the asciiSpec of the
|
||||
* URI prefix.
|
||||
*/
|
||||
readonly attribute ACString namespaceSpec;
|
||||
|
||||
/**
|
||||
* Data associated with this namespace, such as a fallback. URI data should
|
||||
* use the asciiSpec of the URI.
|
||||
*/
|
||||
readonly attribute ACString data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Application caches store resources for offline use. Each
|
||||
* application cache has a unique client ID for use with
|
||||
* nsICacheService::openSession() to access the cache's entries.
|
||||
*
|
||||
* Each entry in the application cache can be marked with a set of
|
||||
* types, as discussed in the WHAT-WG offline applications
|
||||
* specification.
|
||||
*
|
||||
* All application caches with the same group ID belong to a cache
|
||||
* group. Each group has one "active" cache that will service future
|
||||
* loads. Inactive caches will be removed from the cache when they are
|
||||
* no longer referenced.
|
||||
*/
|
||||
[scriptable, uuid(06568DAE-C374-4383-A122-0CC96C7177F2)]
|
||||
interface nsIApplicationCache : nsISupports
|
||||
{
|
||||
/**
|
||||
* Init this application cache instance to just hold the group ID and
|
||||
* the client ID to work just as a handle to the real cache. Used on
|
||||
* content process to simplify the application cache code.
|
||||
*/
|
||||
void initAsHandle(in ACString groupId, in ACString clientId);
|
||||
|
||||
/**
|
||||
* Entries in an application cache can be marked as one or more of
|
||||
* the following types.
|
||||
*/
|
||||
|
||||
/* This item is the application manifest. */
|
||||
const unsigned long ITEM_MANIFEST = 1 << 0;
|
||||
|
||||
/* This item was explicitly listed in the application manifest. */
|
||||
const unsigned long ITEM_EXPLICIT = 1 << 1;
|
||||
|
||||
/* This item was navigated in a toplevel browsing context, and
|
||||
* named this cache's group as its manifest. */
|
||||
const unsigned long ITEM_IMPLICIT = 1 << 2;
|
||||
|
||||
/* This item was added by the dynamic scripting API */
|
||||
const unsigned long ITEM_DYNAMIC = 1 << 3;
|
||||
|
||||
/* This item was listed in the application manifest, but named a
|
||||
* different cache group as its manifest. */
|
||||
const unsigned long ITEM_FOREIGN = 1 << 4;
|
||||
|
||||
/* This item was listed as a fallback entry. */
|
||||
const unsigned long ITEM_FALLBACK = 1 << 5;
|
||||
|
||||
/* This item matched an opportunistic cache namespace and was
|
||||
* cached accordingly. */
|
||||
const unsigned long ITEM_OPPORTUNISTIC = 1 << 6;
|
||||
|
||||
/**
|
||||
* URI of the manfiest specifying this application cache.
|
||||
**/
|
||||
readonly attribute nsIURI manifestURI;
|
||||
|
||||
/**
|
||||
* The group ID for this cache group. It is an internally generated string
|
||||
* and cannot be used as manifest URL spec.
|
||||
**/
|
||||
readonly attribute ACString groupID;
|
||||
|
||||
/**
|
||||
* The client ID for this application cache. Clients can open a
|
||||
* session with nsICacheService::createSession() using this client
|
||||
* ID and a storage policy of STORE_OFFLINE to access this cache.
|
||||
*/
|
||||
readonly attribute ACString clientID;
|
||||
|
||||
/**
|
||||
* TRUE if the cache is the active cache for this group.
|
||||
*/
|
||||
readonly attribute boolean active;
|
||||
|
||||
/**
|
||||
* The disk usage of the application cache, in bytes.
|
||||
*/
|
||||
readonly attribute unsigned long usage;
|
||||
|
||||
/**
|
||||
* Makes this cache the active application cache for this group.
|
||||
* Future loads associated with this group will come from this
|
||||
* cache. Other caches from this cache group will be deactivated.
|
||||
*/
|
||||
void activate();
|
||||
|
||||
/**
|
||||
* Discard this application cache. Removes all cached resources
|
||||
* for this cache. If this is the active application cache for the
|
||||
* group, the group will be removed.
|
||||
*/
|
||||
void discard();
|
||||
|
||||
/**
|
||||
* Adds item types to a given entry.
|
||||
*/
|
||||
void markEntry(in ACString key, in unsigned long typeBits);
|
||||
|
||||
/**
|
||||
* Removes types from a given entry. If the resulting entry has
|
||||
* no types left, the entry is removed.
|
||||
*/
|
||||
void unmarkEntry(in ACString key, in unsigned long typeBits);
|
||||
|
||||
/**
|
||||
* Gets the types for a given entry.
|
||||
*/
|
||||
unsigned long getTypes(in ACString key);
|
||||
|
||||
/**
|
||||
* Returns any entries in the application cache whose type matches
|
||||
* one or more of the bits in typeBits.
|
||||
*/
|
||||
void gatherEntries(in uint32_t typeBits,
|
||||
out unsigned long count,
|
||||
[array, size_is(count)] out string keys);
|
||||
|
||||
/**
|
||||
* Add a set of namespace entries to the application cache.
|
||||
* @param namespaces
|
||||
* An nsIArray of nsIApplicationCacheNamespace entries.
|
||||
*/
|
||||
void addNamespaces(in nsIArray namespaces);
|
||||
|
||||
/**
|
||||
* Get the most specific namespace matching a given key.
|
||||
*/
|
||||
nsIApplicationCacheNamespace getMatchingNamespace(in ACString key);
|
||||
|
||||
/**
|
||||
* If set, this offline cache is placed in a different directory
|
||||
* than the current application profile.
|
||||
*/
|
||||
readonly attribute nsIFile profileDirectory;
|
||||
};
|
||||
57
netwerk/base/nsIApplicationCacheChannel.idl
Normal file
57
netwerk/base/nsIApplicationCacheChannel.idl
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsIApplicationCacheContainer.idl"
|
||||
|
||||
/**
|
||||
* Interface implemented by channels that support application caches.
|
||||
*/
|
||||
[scriptable, uuid(6FA816B1-6D5F-4380-9704-054D0908CFA3)]
|
||||
interface nsIApplicationCacheChannel : nsIApplicationCacheContainer
|
||||
{
|
||||
/**
|
||||
* TRUE when the resource came from the application cache. This
|
||||
* might be false even there is assigned an application cache
|
||||
* e.g. in case of fallback of load of an entry matching bypass
|
||||
* namespace.
|
||||
*/
|
||||
readonly attribute boolean loadedFromApplicationCache;
|
||||
|
||||
/**
|
||||
* When true, the channel will ask its notification callbacks for
|
||||
* an application cache if one is not explicitly provided. Default
|
||||
* value is true.
|
||||
*
|
||||
* NS_ERROR_ALREADY_OPENED will be thrown if set after AsyncOpen()
|
||||
* is called.
|
||||
*/
|
||||
attribute boolean inheritApplicationCache;
|
||||
|
||||
/**
|
||||
* When true, the channel will choose an application cache if one
|
||||
* was not explicitly provided and none is available from the
|
||||
* notification callbacks. Default value is false.
|
||||
*
|
||||
* This attribute will not be transferred through a redirect.
|
||||
*
|
||||
* NS_ERROR_ALREADY_OPENED will be thrown if set after AsyncOpen()
|
||||
* is called.
|
||||
*/
|
||||
attribute boolean chooseApplicationCache;
|
||||
|
||||
/**
|
||||
* A shortcut method to mark the cache item of this channel as 'foreign'.
|
||||
* See the 'cache selection algorithm' and CACHE_SELECTION_RELOAD
|
||||
* action handling in nsContentSink.
|
||||
*/
|
||||
void markOfflineCacheEntryAsForeign();
|
||||
|
||||
/**
|
||||
* Set offline application cache object to instruct the channel
|
||||
* to cache for offline use using this application cache.
|
||||
*/
|
||||
attribute nsIApplicationCache applicationCacheForWrite;
|
||||
};
|
||||
19
netwerk/base/nsIApplicationCacheContainer.idl
Normal file
19
netwerk/base/nsIApplicationCacheContainer.idl
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIApplicationCache;
|
||||
|
||||
/**
|
||||
* Interface used by objects that can be associated with an
|
||||
* application cache.
|
||||
*/
|
||||
[scriptable, uuid(bbb80700-1f7f-4258-aff4-1743cc5a7d23)]
|
||||
interface nsIApplicationCacheContainer : nsISupports
|
||||
{
|
||||
attribute nsIApplicationCache applicationCache;
|
||||
};
|
||||
110
netwerk/base/nsIApplicationCacheService.idl
Normal file
110
netwerk/base/nsIApplicationCacheService.idl
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIApplicationCache;
|
||||
interface nsIFile;
|
||||
interface nsIURI;
|
||||
interface nsILoadContextInfo;
|
||||
|
||||
/**
|
||||
* The application cache service manages the set of application cache
|
||||
* groups.
|
||||
*/
|
||||
[scriptable, uuid(b8b6546c-6cec-4bda-82df-08e006a97b56)]
|
||||
interface nsIApplicationCacheService : nsISupports
|
||||
{
|
||||
/**
|
||||
* Create group string identifying cache group according the manifest
|
||||
* URL and the given principal.
|
||||
*/
|
||||
ACString buildGroupIDForInfo(in nsIURI aManifestURL,
|
||||
in nsILoadContextInfo aLoadContextInfo);
|
||||
ACString buildGroupIDForSuffix(in nsIURI aManifestURL,
|
||||
in ACString aOriginSuffix);
|
||||
|
||||
/**
|
||||
* Create a new, empty application cache for the given cache
|
||||
* group.
|
||||
*/
|
||||
nsIApplicationCache createApplicationCache(in ACString group);
|
||||
|
||||
/**
|
||||
* Create a new, empty application cache for the given cache
|
||||
* group residing in a custom directory with a custom quota.
|
||||
*
|
||||
* @param group
|
||||
* URL of the manifest
|
||||
* @param directory
|
||||
* Actually a reference to a profile directory where to
|
||||
* create the OfflineCache sub-dir.
|
||||
* @param quota
|
||||
* Optional override of the default quota.
|
||||
*/
|
||||
nsIApplicationCache createCustomApplicationCache(in ACString group,
|
||||
in nsIFile profileDir,
|
||||
in int32_t quota);
|
||||
|
||||
/**
|
||||
* Get an application cache object for the given client ID.
|
||||
*/
|
||||
nsIApplicationCache getApplicationCache(in ACString clientID);
|
||||
|
||||
/**
|
||||
* Get the currently active cache object for a cache group.
|
||||
*/
|
||||
nsIApplicationCache getActiveCache(in ACString group);
|
||||
|
||||
/**
|
||||
* Deactivate the currently-active cache object for a cache group.
|
||||
*/
|
||||
void deactivateGroup(in ACString group);
|
||||
|
||||
/**
|
||||
* Evict offline cache entries, either all of them or those belonging
|
||||
* to the given origin.
|
||||
*/
|
||||
void evict(in nsILoadContextInfo aLoadContextInfo);
|
||||
|
||||
/**
|
||||
* Delete caches whom origin attributes matches the given pattern.
|
||||
*/
|
||||
void evictMatchingOriginAttributes(in AString aPattern);
|
||||
|
||||
/**
|
||||
* Try to find the best application cache to serve a resource.
|
||||
*/
|
||||
nsIApplicationCache chooseApplicationCache(in ACString key,
|
||||
[optional] in nsILoadContextInfo aLoadContextInfo);
|
||||
|
||||
/**
|
||||
* Flags the key as being opportunistically cached.
|
||||
*
|
||||
* This method should also propagate the entry to other
|
||||
* application caches with the same opportunistic namespace, but
|
||||
* this is not currently implemented.
|
||||
*
|
||||
* @param cache
|
||||
* The cache in which the entry is cached now.
|
||||
* @param key
|
||||
* The cache entry key.
|
||||
*/
|
||||
void cacheOpportunistically(in nsIApplicationCache cache, in ACString key);
|
||||
|
||||
/**
|
||||
* Get the list of application cache groups.
|
||||
*/
|
||||
void getGroups([optional] out unsigned long count,
|
||||
[array, size_is(count), retval] out string groupIDs);
|
||||
|
||||
/**
|
||||
* Get the list of application cache groups in the order of
|
||||
* activating time.
|
||||
*/
|
||||
void getGroupsTimeOrdered([optional] out unsigned long count,
|
||||
[array, size_is(count), retval] out string groupIDs);
|
||||
};
|
||||
26
netwerk/base/nsIArrayBufferInputStream.idl
Normal file
26
netwerk/base/nsIArrayBufferInputStream.idl
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsIInputStream.idl"
|
||||
|
||||
/**
|
||||
* nsIArrayBufferInputStream
|
||||
*
|
||||
* Provides scriptable methods for initializing a nsIInputStream
|
||||
* implementation with an ArrayBuffer.
|
||||
*/
|
||||
[scriptable, uuid(3014dde6-aa1c-41db-87d0-48764a3710f6)]
|
||||
interface nsIArrayBufferInputStream : nsIInputStream
|
||||
{
|
||||
/**
|
||||
* SetData - assign an ArrayBuffer to the input stream.
|
||||
*
|
||||
* @param buffer - stream data
|
||||
* @param byteOffset - stream data offset
|
||||
* @param byteLen - stream data length
|
||||
*/
|
||||
[implicit_jscontext]
|
||||
void setData(in jsval buffer, in unsigned long byteOffset, in unsigned long byteLen);
|
||||
};
|
||||
64
netwerk/base/nsIAsyncStreamCopier.idl
Normal file
64
netwerk/base/nsIAsyncStreamCopier.idl
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsIRequest.idl"
|
||||
|
||||
interface nsIInputStream;
|
||||
interface nsIOutputStream;
|
||||
interface nsIRequestObserver;
|
||||
interface nsIEventTarget;
|
||||
|
||||
// You should prefer nsIAsyncStreamCopier2
|
||||
[scriptable, uuid(5a19ca27-e041-4aca-8287-eb248d4c50c0)]
|
||||
interface nsIAsyncStreamCopier : nsIRequest
|
||||
{
|
||||
/**
|
||||
* Initialize the stream copier.
|
||||
*
|
||||
* @param aSource
|
||||
* contains the data to be copied.
|
||||
* @param aSink
|
||||
* specifies the destination for the data.
|
||||
* @param aTarget
|
||||
* specifies the thread on which the copy will occur. a null value
|
||||
* is permitted and will cause the copy to occur on an unspecified
|
||||
* background thread.
|
||||
* @param aSourceBuffered
|
||||
* true if aSource implements ReadSegments.
|
||||
* @param aSinkBuffered
|
||||
* true if aSink implements WriteSegments.
|
||||
* @param aChunkSize
|
||||
* specifies how many bytes to read/write at a time. this controls
|
||||
* the granularity of the copying. it should match the segment size
|
||||
* of the "buffered" streams involved.
|
||||
* @param aCloseSource
|
||||
* true if aSource should be closed after copying.
|
||||
* @param aCloseSink
|
||||
* true if aSink should be closed after copying.
|
||||
*
|
||||
* NOTE: at least one of the streams must be buffered. If you do not know
|
||||
* whether your streams are buffered, you should use nsIAsyncStreamCopier2
|
||||
* instead.
|
||||
*/
|
||||
void init(in nsIInputStream aSource,
|
||||
in nsIOutputStream aSink,
|
||||
in nsIEventTarget aTarget,
|
||||
in boolean aSourceBuffered,
|
||||
in boolean aSinkBuffered,
|
||||
in unsigned long aChunkSize,
|
||||
in boolean aCloseSource,
|
||||
in boolean aCloseSink);
|
||||
|
||||
/**
|
||||
* asyncCopy triggers the start of the copy. The observer will be notified
|
||||
* when the copy completes.
|
||||
*
|
||||
* @param aObserver
|
||||
* receives notifications.
|
||||
* @param aObserverContext
|
||||
* passed to observer methods.
|
||||
*/
|
||||
void asyncCopy(in nsIRequestObserver aObserver,
|
||||
in nsISupports aObserverContext);
|
||||
};
|
||||
59
netwerk/base/nsIAsyncStreamCopier2.idl
Normal file
59
netwerk/base/nsIAsyncStreamCopier2.idl
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsIRequest.idl"
|
||||
|
||||
interface nsIInputStream;
|
||||
interface nsIOutputStream;
|
||||
interface nsIRequestObserver;
|
||||
interface nsIEventTarget;
|
||||
|
||||
[scriptable, uuid(a5b2decf-4ede-4801-8b38-e5fe5db46bf2)]
|
||||
interface nsIAsyncStreamCopier2 : nsIRequest
|
||||
{
|
||||
/**
|
||||
* Initialize the stream copier.
|
||||
*
|
||||
* If neither the source nor the sink are buffered, buffering will
|
||||
* be automatically added to the sink.
|
||||
*
|
||||
*
|
||||
* @param aSource
|
||||
* contains the data to be copied.
|
||||
* @param aSink
|
||||
* specifies the destination for the data.
|
||||
* @param aTarget
|
||||
* specifies the thread on which the copy will occur. a null value
|
||||
* is permitted and will cause the copy to occur on an unspecified
|
||||
* background thread.
|
||||
* @param aChunkSize
|
||||
* specifies how many bytes to read/write at a time. this controls
|
||||
* the granularity of the copying. it should match the segment size
|
||||
* of the "buffered" streams involved.
|
||||
* @param aCloseSource
|
||||
* true if aSource should be closed after copying (this is generally
|
||||
* the desired behavior).
|
||||
* @param aCloseSink
|
||||
* true if aSink should be closed after copying (this is generally
|
||||
* the desired behavior).
|
||||
*/
|
||||
void init(in nsIInputStream aSource,
|
||||
in nsIOutputStream aSink,
|
||||
in nsIEventTarget aTarget,
|
||||
in unsigned long aChunkSize,
|
||||
in boolean aCloseSource,
|
||||
in boolean aCloseSink);
|
||||
|
||||
/**
|
||||
* asyncCopy triggers the start of the copy. The observer will be notified
|
||||
* when the copy completes.
|
||||
*
|
||||
* @param aObserver
|
||||
* receives notifications.
|
||||
* @param aObserverContext
|
||||
* passed to observer methods.
|
||||
*/
|
||||
void asyncCopy(in nsIRequestObserver aObserver,
|
||||
in nsISupports aObserverContext);
|
||||
};
|
||||
19
netwerk/base/nsIAsyncVerifyRedirectCallback.idl
Normal file
19
netwerk/base/nsIAsyncVerifyRedirectCallback.idl
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
[scriptable, uuid(8d171460-a716-41f1-92be-8c659db39b45)]
|
||||
interface nsIAsyncVerifyRedirectCallback : nsISupports
|
||||
{
|
||||
/**
|
||||
* Complement to nsIChannelEventSink asynchronous callback. The result of
|
||||
* the redirect decision is passed through this callback.
|
||||
*
|
||||
* @param result
|
||||
* Result of the redirect veto decision. If FAILED the redirect has been
|
||||
* vetoed. If SUCCEEDED the redirect has been allowed by all consumers.
|
||||
*/
|
||||
void onRedirectVerifyCallback(in nsresult result);
|
||||
};
|
||||
118
netwerk/base/nsIAuthInformation.idl
Normal file
118
netwerk/base/nsIAuthInformation.idl
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
/**
|
||||
* A object that hold authentication information. The caller of
|
||||
* nsIAuthPrompt2::promptUsernameAndPassword or
|
||||
* nsIAuthPrompt2::promptPasswordAsync provides an object implementing this
|
||||
* interface; the prompt implementation can then read the values here to prefill
|
||||
* the dialog. After the user entered the authentication information, it should
|
||||
* set the attributes of this object to indicate to the caller what was entered
|
||||
* by the user.
|
||||
*/
|
||||
[scriptable, uuid(0d73639c-2a92-4518-9f92-28f71fea5f20)]
|
||||
interface nsIAuthInformation : nsISupports
|
||||
{
|
||||
/** @name Flags */
|
||||
/* @{ */
|
||||
/**
|
||||
* This dialog belongs to a network host.
|
||||
*/
|
||||
const uint32_t AUTH_HOST = 1;
|
||||
|
||||
/**
|
||||
* This dialog belongs to a proxy.
|
||||
*/
|
||||
const uint32_t AUTH_PROXY = 2;
|
||||
|
||||
/**
|
||||
* This dialog needs domain information. The user interface should show a
|
||||
* domain field, prefilled with the domain attribute's value.
|
||||
*/
|
||||
const uint32_t NEED_DOMAIN = 4;
|
||||
|
||||
/**
|
||||
* This dialog only asks for password information. Authentication prompts
|
||||
* SHOULD NOT show a username field. Attempts to change the username field
|
||||
* will have no effect. nsIAuthPrompt2 implementations should, however, show
|
||||
* its initial value to the user in some form. For example, a paragraph in
|
||||
* the dialog might say "Please enter your password for user jsmith at
|
||||
* server intranet".
|
||||
*
|
||||
* This flag is mutually exclusive with #NEED_DOMAIN.
|
||||
*/
|
||||
const uint32_t ONLY_PASSWORD = 8;
|
||||
|
||||
/**
|
||||
* We have already tried to log in for this channel
|
||||
* (with auth values from a previous promptAuth call),
|
||||
* but it failed, so we now ask the user to provide a new, correct login.
|
||||
*
|
||||
* @see also RFC 2616, Section 10.4.2
|
||||
*/
|
||||
const uint32_t PREVIOUS_FAILED = 16;
|
||||
|
||||
/**
|
||||
* A cross-origin sub-resource requests an authentication.
|
||||
* The message presented to users must reflect that.
|
||||
*/
|
||||
const uint32_t CROSS_ORIGIN_SUB_RESOURCE = 32;
|
||||
/* @} */
|
||||
|
||||
/**
|
||||
* Flags describing this dialog. A bitwise OR of the flag values
|
||||
* above.
|
||||
*
|
||||
* It is possible that neither #AUTH_HOST nor #AUTH_PROXY are set.
|
||||
*
|
||||
* Auth prompts should ignore flags they don't understand; especially, they
|
||||
* should not throw an exception because of an unsupported flag.
|
||||
*/
|
||||
readonly attribute unsigned long flags;
|
||||
|
||||
/**
|
||||
* The server-supplied realm of the authentication as defined in RFC 2617.
|
||||
* Can be the empty string if the protocol does not support realms.
|
||||
* Otherwise, this is a human-readable string like "Secret files".
|
||||
*/
|
||||
readonly attribute AString realm;
|
||||
|
||||
/**
|
||||
* The authentication scheme used for this request, if applicable. If the
|
||||
* protocol for this authentication does not support schemes, this will be
|
||||
* the empty string. Otherwise, this will be a string such as "basic" or
|
||||
* "digest". This string will always be in lowercase.
|
||||
*/
|
||||
readonly attribute AUTF8String authenticationScheme;
|
||||
|
||||
/**
|
||||
* The initial value should be used to prefill the dialog or be shown
|
||||
* in some other way to the user.
|
||||
* On return, this parameter should contain the username entered by
|
||||
* the user.
|
||||
* This field can only be changed if the #ONLY_PASSWORD flag is not set.
|
||||
*/
|
||||
attribute AString username;
|
||||
|
||||
/**
|
||||
* The initial value should be used to prefill the dialog or be shown
|
||||
* in some other way to the user.
|
||||
* The password should not be shown in clear.
|
||||
* On return, this parameter should contain the password entered by
|
||||
* the user.
|
||||
*/
|
||||
attribute AString password;
|
||||
|
||||
/**
|
||||
* The initial value should be used to prefill the dialog or be shown
|
||||
* in some other way to the user.
|
||||
* On return, this parameter should contain the domain entered by
|
||||
* the user.
|
||||
* This attribute is only used if flags include #NEED_DOMAIN.
|
||||
*/
|
||||
attribute AString domain;
|
||||
};
|
||||
|
||||
145
netwerk/base/nsIAuthModule.idl
Normal file
145
netwerk/base/nsIAuthModule.idl
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
/* vim:set ts=4 sw=4 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
[uuid(6e35dbc0-49ef-4e2c-b1ea-b72ec64450a2)]
|
||||
interface nsIAuthModule : nsISupports
|
||||
{
|
||||
/**
|
||||
* Default behavior.
|
||||
*/
|
||||
const unsigned long REQ_DEFAULT = 0;
|
||||
|
||||
/**
|
||||
* Client and server will be authenticated.
|
||||
*/
|
||||
const unsigned long REQ_MUTUAL_AUTH = (1 << 0);
|
||||
|
||||
/**
|
||||
* The server is allowed to impersonate the client. The REQ_MUTUAL_AUTH
|
||||
* flag may also need to be specified in order for this flag to take
|
||||
* effect.
|
||||
*/
|
||||
const unsigned long REQ_DELEGATE = (1 << 1);
|
||||
|
||||
/**
|
||||
* The authentication is required for a proxy connection.
|
||||
*/
|
||||
const unsigned long REQ_PROXY_AUTH = (1 << 2);
|
||||
|
||||
/**
|
||||
* Flags used for telemetry.
|
||||
*/
|
||||
const unsigned long NTLM_MODULE_SAMBA_AUTH_PROXY = 0;
|
||||
const unsigned long NTLM_MODULE_SAMBA_AUTH_DIRECT = 1;
|
||||
const unsigned long NTLM_MODULE_WIN_API_PROXY = 2;
|
||||
const unsigned long NTLM_MODULE_WIN_API_DIRECT = 3;
|
||||
const unsigned long NTLM_MODULE_GENERIC_PROXY = 4;
|
||||
const unsigned long NTLM_MODULE_GENERIC_DIRECT = 5;
|
||||
const unsigned long NTLM_MODULE_KERBEROS_PROXY = 6;
|
||||
const unsigned long NTLM_MODULE_KERBEROS_DIRECT = 7;
|
||||
|
||||
/** Other flags may be defined in the future */
|
||||
|
||||
/**
|
||||
* Called to initialize an auth module. The other methods cannot be called
|
||||
* unless this method succeeds.
|
||||
*
|
||||
* @param aServiceName
|
||||
* the service name, which may be null if not applicable (e.g., for
|
||||
* NTLM, this parameter should be null).
|
||||
* @param aServiceFlags
|
||||
* a bitwise-or of the REQ_ flags defined above (pass REQ_DEFAULT
|
||||
* for default behavior).
|
||||
* @param aDomain
|
||||
* the authentication domain, which may be null if not applicable.
|
||||
* @param aUsername
|
||||
* the user's login name
|
||||
* @param aPassword
|
||||
* the user's password
|
||||
*/
|
||||
void init(in string aServiceName,
|
||||
in unsigned long aServiceFlags,
|
||||
in wstring aDomain,
|
||||
in wstring aUsername,
|
||||
in wstring aPassword);
|
||||
|
||||
/**
|
||||
* Called to get the next token in a sequence of authentication steps.
|
||||
*
|
||||
* @param aInToken
|
||||
* A buffer containing the input token (e.g., a challenge from a
|
||||
* server). This may be null.
|
||||
* @param aInTokenLength
|
||||
* The length of the input token.
|
||||
* @param aOutToken
|
||||
* If getNextToken succeeds, then aOutToken will point to a buffer
|
||||
* to be sent in response to the server challenge. The length of
|
||||
* this buffer is given by aOutTokenLength. The buffer at aOutToken
|
||||
* must be recycled with a call to free.
|
||||
* @param aOutTokenLength
|
||||
* If getNextToken succeeds, then aOutTokenLength contains the
|
||||
* length of the buffer (number of bytes) pointed to by aOutToken.
|
||||
*/
|
||||
void getNextToken([const] in voidPtr aInToken,
|
||||
in unsigned long aInTokenLength,
|
||||
out voidPtr aOutToken,
|
||||
out unsigned long aOutTokenLength);
|
||||
/**
|
||||
* Once a security context has been established through calls to GetNextToken()
|
||||
* it may be used to protect data exchanged between client and server. Calls
|
||||
* to Wrap() are used to protect items of data to be sent to the server.
|
||||
*
|
||||
* @param aInToken
|
||||
* A buffer containing the data to be sent to the server
|
||||
* @param aInTokenLength
|
||||
* The length of the input token
|
||||
* @param confidential
|
||||
* If set to true, Wrap() will encrypt the data, otherwise data will
|
||||
* just be integrity protected (checksummed)
|
||||
* @param aOutToken
|
||||
* A buffer containing the resulting data to be sent to the server
|
||||
* @param aOutTokenLength
|
||||
* The length of the output token buffer
|
||||
*
|
||||
* Wrap() may return NS_ERROR_NOT_IMPLEMENTED, if the underlying authentication
|
||||
* mechanism does not support security layers.
|
||||
*/
|
||||
void wrap([const] in voidPtr aInToken,
|
||||
in unsigned long aInTokenLength,
|
||||
in boolean confidential,
|
||||
out voidPtr aOutToken,
|
||||
out unsigned long aOutTokenLength);
|
||||
|
||||
/**
|
||||
* Unwrap() is used to unpack, decrypt, and verify the checksums on data
|
||||
* returned by a server when security layers are in use.
|
||||
*
|
||||
* @param aInToken
|
||||
* A buffer containing the data received from the server
|
||||
* @param aInTokenLength
|
||||
* The length of the input token
|
||||
* @param aOutToken
|
||||
* A buffer containing the plaintext data from the server
|
||||
* @param aOutTokenLength
|
||||
* The length of the output token buffer
|
||||
*
|
||||
* Unwrap() may return NS_ERROR_NOT_IMPLEMENTED, if the underlying
|
||||
* authentication mechanism does not support security layers.
|
||||
*/
|
||||
void unwrap([const] in voidPtr aInToken,
|
||||
in unsigned long aInTokenLength,
|
||||
out voidPtr aOutToken,
|
||||
out unsigned long aOutTokenLength);
|
||||
};
|
||||
|
||||
%{C++
|
||||
/**
|
||||
* nsIAuthModule implementations are registered under the following contract
|
||||
* ID prefix:
|
||||
*/
|
||||
#define NS_AUTH_MODULE_CONTRACTID_PREFIX \
|
||||
"@mozilla.org/network/auth-module;1?name="
|
||||
%}
|
||||
80
netwerk/base/nsIAuthPrompt.idl
Normal file
80
netwerk/base/nsIAuthPrompt.idl
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIPrompt;
|
||||
|
||||
[scriptable, uuid(358089f9-ee4b-4711-82fd-bcd07fc62061)]
|
||||
interface nsIAuthPrompt : nsISupports
|
||||
{
|
||||
const uint32_t SAVE_PASSWORD_NEVER = 0;
|
||||
const uint32_t SAVE_PASSWORD_FOR_SESSION = 1;
|
||||
const uint32_t SAVE_PASSWORD_PERMANENTLY = 2;
|
||||
|
||||
/**
|
||||
* Puts up a text input dialog with OK and Cancel buttons.
|
||||
* Note: prompt uses separate args for the "in" and "out" values of the
|
||||
* input field, whereas the other functions use a single inout arg.
|
||||
* @param dialogText The title for the dialog.
|
||||
* @param text The text to display in the dialog.
|
||||
* @param passwordRealm The "realm" the password belongs to: e.g.
|
||||
* ldap://localhost/dc=test
|
||||
* @param savePassword One of the SAVE_PASSWORD_* options above.
|
||||
* @param defaultText The default text to display in the text input box.
|
||||
* @param result The value entered by the user if OK was
|
||||
* selected.
|
||||
* @return true for OK, false for Cancel
|
||||
*/
|
||||
boolean prompt(in wstring dialogTitle,
|
||||
in wstring text,
|
||||
in wstring passwordRealm,
|
||||
in uint32_t savePassword,
|
||||
in wstring defaultText,
|
||||
out wstring result);
|
||||
|
||||
/**
|
||||
* Puts up a username/password dialog with OK and Cancel buttons.
|
||||
* Puts up a password dialog with OK and Cancel buttons.
|
||||
* @param dialogText The title for the dialog.
|
||||
* @param text The text to display in the dialog.
|
||||
* @param passwordRealm The "realm" the password belongs to: e.g.
|
||||
* ldap://localhost/dc=test
|
||||
* @param savePassword One of the SAVE_PASSWORD_* options above.
|
||||
* @param user The username entered in the dialog.
|
||||
* @param pwd The password entered by the user if OK was
|
||||
* selected.
|
||||
* @return true for OK, false for Cancel
|
||||
*/
|
||||
boolean promptUsernameAndPassword(in wstring dialogTitle,
|
||||
in wstring text,
|
||||
in wstring passwordRealm,
|
||||
in uint32_t savePassword,
|
||||
inout wstring user,
|
||||
inout wstring pwd);
|
||||
|
||||
/**
|
||||
* Puts up a password dialog with OK and Cancel buttons.
|
||||
* @param dialogText The title for the dialog.
|
||||
* @param text The text to display in the dialog.
|
||||
* @param passwordRealm The "realm" the password belongs to: e.g.
|
||||
* ldap://localhost/dc=test. If a username is
|
||||
* specified (http://user@site.com) it will be used
|
||||
* when matching existing logins or saving new ones.
|
||||
* If no username is specified, only password-only
|
||||
* logins will be matched or saved.
|
||||
* Note: if a username is specified, the username
|
||||
* should be escaped.
|
||||
* @param savePassword One of the SAVE_PASSWORD_* options above.
|
||||
* @param pwd The password entered by the user if OK was
|
||||
* selected.
|
||||
* @return true for OK, false for Cancel
|
||||
*/
|
||||
boolean promptPassword(in wstring dialogTitle,
|
||||
in wstring text,
|
||||
in wstring passwordRealm,
|
||||
in uint32_t savePassword,
|
||||
inout wstring pwd);
|
||||
};
|
||||
103
netwerk/base/nsIAuthPrompt2.idl
Normal file
103
netwerk/base/nsIAuthPrompt2.idl
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIAuthPromptCallback;
|
||||
interface nsIChannel;
|
||||
interface nsICancelable;
|
||||
interface nsIAuthInformation;
|
||||
|
||||
/**
|
||||
* An interface allowing to prompt for a username and password. This interface
|
||||
* is usually acquired using getInterface on notification callbacks or similar.
|
||||
* It can be used to prompt users for authentication information, either
|
||||
* synchronously or asynchronously.
|
||||
*/
|
||||
[scriptable, uuid(651395EB-8612-4876-8AC0-A88D4DCE9E1E)]
|
||||
interface nsIAuthPrompt2 : nsISupports
|
||||
{
|
||||
/** @name Security Levels */
|
||||
/* @{ */
|
||||
/**
|
||||
* The password will be sent unencrypted. No security provided.
|
||||
*/
|
||||
const uint32_t LEVEL_NONE = 0;
|
||||
/**
|
||||
* Password will be sent encrypted, but the connection is otherwise
|
||||
* insecure.
|
||||
*/
|
||||
const uint32_t LEVEL_PW_ENCRYPTED = 1;
|
||||
/**
|
||||
* The connection, both for password and data, is secure.
|
||||
*/
|
||||
const uint32_t LEVEL_SECURE = 2;
|
||||
/* @} */
|
||||
|
||||
/**
|
||||
* Requests a username and a password. Implementations will commonly show a
|
||||
* dialog with a username and password field, depending on flags also a
|
||||
* domain field.
|
||||
*
|
||||
* @param aChannel
|
||||
* The channel that requires authentication.
|
||||
* @param level
|
||||
* One of the level constants from above. See there for descriptions
|
||||
* of the levels.
|
||||
* @param authInfo
|
||||
* Authentication information object. The implementation should fill in
|
||||
* this object with the information entered by the user before
|
||||
* returning.
|
||||
*
|
||||
* @retval true
|
||||
* Authentication can proceed using the values in the authInfo
|
||||
* object.
|
||||
* @retval false
|
||||
* Authentication should be cancelled, usually because the user did
|
||||
* not provide username/password.
|
||||
*
|
||||
* @note Exceptions thrown from this function will be treated like a
|
||||
* return value of false.
|
||||
*/
|
||||
boolean promptAuth(in nsIChannel aChannel,
|
||||
in uint32_t level,
|
||||
in nsIAuthInformation authInfo);
|
||||
|
||||
/**
|
||||
* Asynchronously prompt the user for a username and password.
|
||||
* This has largely the same semantics as promptUsernameAndPassword(),
|
||||
* but must return immediately after calling and return the entered
|
||||
* data in a callback.
|
||||
*
|
||||
* If the user closes the dialog using a cancel button or similar,
|
||||
* the callback's nsIAuthPromptCallback::onAuthCancelled method must be
|
||||
* called.
|
||||
* Calling nsICancelable::cancel on the returned object SHOULD close the
|
||||
* dialog and MUST call nsIAuthPromptCallback::onAuthCancelled on the provided
|
||||
* callback.
|
||||
*
|
||||
* This implementation may:
|
||||
*
|
||||
* 1) Coalesce identical prompts. This means prompts that are guaranteed to
|
||||
* want the same auth information from the user. A single prompt will be
|
||||
* shown; then the callbacks for all the coalesced prompts will be notified
|
||||
* with the resulting auth information.
|
||||
* 2) Serialize prompts that are all in the same "context" (this might mean
|
||||
* application-wide, for a given window, or something else depending on
|
||||
* the user interface) so that the user is not deluged with prompts.
|
||||
*
|
||||
* @throw
|
||||
* This method may throw any exception when the prompt fails to queue e.g
|
||||
* because of out-of-memory error. It must not throw when the prompt
|
||||
* could already be potentially shown to the user. In that case information
|
||||
* about the failure has to come through the callback. This way we
|
||||
* prevent multiple dialogs shown to the user because consumer may fall
|
||||
* back to synchronous prompt on synchronous failure of this method.
|
||||
*/
|
||||
nsICancelable asyncPromptAuth(in nsIChannel aChannel,
|
||||
in nsIAuthPromptCallback aCallback,
|
||||
in nsISupports aContext,
|
||||
in uint32_t level,
|
||||
in nsIAuthInformation authInfo);
|
||||
};
|
||||
22
netwerk/base/nsIAuthPromptAdapterFactory.idl
Normal file
22
netwerk/base/nsIAuthPromptAdapterFactory.idl
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIAuthPrompt;
|
||||
interface nsIAuthPrompt2;
|
||||
|
||||
/**
|
||||
* An interface for wrapping nsIAuthPrompt interfaces to make
|
||||
* them usable via an nsIAuthPrompt2 interface.
|
||||
*/
|
||||
[scriptable, uuid(60e46383-bb9a-4860-8962-80d9c5c05ddc)]
|
||||
interface nsIAuthPromptAdapterFactory : nsISupports
|
||||
{
|
||||
/**
|
||||
* Wrap an object implementing nsIAuthPrompt so that it's usable via
|
||||
* nsIAuthPrompt2.
|
||||
*/
|
||||
nsIAuthPrompt2 createAdapter(in nsIAuthPrompt aPrompt);
|
||||
};
|
||||
44
netwerk/base/nsIAuthPromptCallback.idl
Normal file
44
netwerk/base/nsIAuthPromptCallback.idl
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIAuthInformation;
|
||||
|
||||
/**
|
||||
* Interface for callback methods for the asynchronous nsIAuthPrompt2 method.
|
||||
* Callers MUST call exactly one method if nsIAuthPrompt2::promptPasswordAsync
|
||||
* returns successfully. They MUST NOT call any method on this interface before
|
||||
* promptPasswordAsync returns.
|
||||
*/
|
||||
[scriptable, uuid(bdc387d7-2d29-4cac-92f1-dd75d786631d)]
|
||||
interface nsIAuthPromptCallback : nsISupports
|
||||
{
|
||||
/**
|
||||
* Authentication information is available.
|
||||
*
|
||||
* @param aContext
|
||||
* The context as passed to promptPasswordAsync
|
||||
* @param aAuthInfo
|
||||
* Authentication information. Must be the same object that was passed
|
||||
* to promptPasswordAsync.
|
||||
*
|
||||
* @note Any exceptions thrown from this method should be ignored.
|
||||
*/
|
||||
void onAuthAvailable(in nsISupports aContext,
|
||||
in nsIAuthInformation aAuthInfo);
|
||||
|
||||
/**
|
||||
* Notification that the prompt was cancelled.
|
||||
*
|
||||
* @param aContext
|
||||
* The context that was passed to promptPasswordAsync.
|
||||
* @param userCancel
|
||||
* If false, this prompt was cancelled by calling the
|
||||
* the cancel method on the nsICancelable; otherwise,
|
||||
* it was cancelled by the user.
|
||||
*/
|
||||
void onAuthCancelled(in nsISupports aContext, in boolean userCancel);
|
||||
};
|
||||
|
||||
34
netwerk/base/nsIAuthPromptProvider.idl
Normal file
34
netwerk/base/nsIAuthPromptProvider.idl
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/* -*- Mode: idl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
[scriptable, uuid(bd9dc0fa-68ce-47d0-8859-6418c2ae8576)]
|
||||
interface nsIAuthPromptProvider : nsISupports
|
||||
{
|
||||
/**
|
||||
* Normal (non-proxy) prompt request.
|
||||
*/
|
||||
const uint32_t PROMPT_NORMAL = 0;
|
||||
|
||||
/**
|
||||
* Proxy auth request.
|
||||
*/
|
||||
const uint32_t PROMPT_PROXY = 1;
|
||||
|
||||
/**
|
||||
* Request a prompt interface for the given prompt reason;
|
||||
* @throws NS_ERROR_NOT_AVAILABLE if no prompt is allowed or
|
||||
* available for the given reason.
|
||||
*
|
||||
* @param aPromptReason The reason for the auth prompt;
|
||||
* one of #PROMPT_NORMAL or #PROMPT_PROXY
|
||||
* @param iid The desired interface, e.g.
|
||||
* NS_GET_IID(nsIAuthPrompt2).
|
||||
* @returns an nsIAuthPrompt2 interface, or throws NS_ERROR_NOT_AVAILABLE
|
||||
*/
|
||||
void getAuthPrompt(in uint32_t aPromptReason, in nsIIDRef iid,
|
||||
[iid_is(iid),retval] out nsQIResult result);
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue