implement navigator.pendingOfflineLoads. b=372969, r=biesi, r+sr=jst

This commit is contained in:
dcamp%mozilla.com 2007-07-09 06:19:29 +00:00
Родитель b329ef5c40
Коммит f6d4f9ff68
22 изменённых файлов: 1599 добавлений и 194 удалений

Просмотреть файл

@ -673,14 +673,14 @@ nsContentSink::ProcessLink(nsIContent* aElement,
PRBool hasPrefetch = (linkTypes.IndexOf(NS_LITERAL_STRING("prefetch")) != -1);
// prefetch href if relation is "next" or "prefetch"
if (hasPrefetch || linkTypes.IndexOf(NS_LITERAL_STRING("next")) != -1) {
PrefetchHref(aHref, hasPrefetch, PR_FALSE);
PrefetchHref(aHref, aElement, hasPrefetch, PR_FALSE);
}
// fetch href into the offline cache if relation is "offline-resource"
if (linkTypes.IndexOf(NS_LITERAL_STRING("offline-resource")) != -1) {
AddOfflineResource(aHref);
if (mSaveOfflineResources)
PrefetchHref(aHref, PR_TRUE, PR_TRUE);
PrefetchHref(aHref, aElement, PR_TRUE, PR_TRUE);
}
// is it a stylesheet link?
@ -764,6 +764,7 @@ nsContentSink::ProcessMETATag(nsIContent* aContent)
void
nsContentSink::PrefetchHref(const nsAString &aHref,
nsIContent *aSource,
PRBool aExplicit,
PRBool aOffline)
{
@ -808,10 +809,14 @@ nsContentSink::PrefetchHref(const nsAString &aHref,
charset.IsEmpty() ? nsnull : PromiseFlatCString(charset).get(),
mDocumentBaseURI);
if (uri) {
nsCOMPtr<nsIDOMNode> domNode = do_QueryInterface(aSource);
if (aOffline)
prefetchService->PrefetchURIForOfflineUse(uri, mDocumentURI, aExplicit);
prefetchService->PrefetchURIForOfflineUse(uri,
mDocumentURI,
domNode,
aExplicit);
else
prefetchService->PrefetchURI(uri, mDocumentURI, aExplicit);
prefetchService->PrefetchURI(uri, mDocumentURI, domNode, aExplicit);
}
}
}

Просмотреть файл

@ -167,7 +167,8 @@ protected:
const nsSubstring& aType,
const nsSubstring& aMedia);
void PrefetchHref(const nsAString &aHref, PRBool aExplicit, PRBool aOffline);
void PrefetchHref(const nsAString &aHref, nsIContent *aSource,
PRBool aExplicit, PRBool aOffline);
nsresult GetOfflineCacheSession(nsIOfflineCacheSession **aSession);
nsresult AddOfflineResource(const nsAString &aHref);

Просмотреть файл

@ -3004,7 +3004,7 @@ HTMLContentSink::ProcessLINKTag(const nsIParserNode& aNode)
nsAutoString hrefVal;
element->GetAttr(kNameSpaceID_None, nsGkAtoms::href, hrefVal);
if (!hrefVal.IsEmpty()) {
PrefetchHref(hrefVal, hasPrefetch, PR_FALSE);
PrefetchHref(hrefVal, element, hasPrefetch, PR_FALSE);
}
}
if (linkTypes.IndexOf(NS_LITERAL_STRING("offline-resource")) != -1) {
@ -3013,7 +3013,7 @@ HTMLContentSink::ProcessLINKTag(const nsIParserNode& aNode)
if (!hrefVal.IsEmpty()) {
AddOfflineResource(hrefVal);
if (mSaveOfflineResources)
PrefetchHref(hrefVal, PR_TRUE, PR_TRUE);
PrefetchHref(hrefVal, element, PR_TRUE, PR_TRUE);
}
}
}

Просмотреть файл

@ -38,8 +38,9 @@
#include "domstubs.idl"
interface nsIDOMOfflineResourceList;
interface nsIDOMLoadStatusList;
[scriptable, uuid(21c6561e-4778-47ed-96d0-eadc46d6a3ec)]
[scriptable, uuid(02bb1271-05dd-4bde-a9ca-68571bf8c702)]
interface nsIDOMClientInformation : nsISupports
{
/**
@ -54,6 +55,7 @@ interface nsIDOMClientInformation : nsISupports
boolean isLocallyAvailable(in DOMString uri, in boolean whenOffline);
readonly attribute nsIDOMOfflineResourceList offlineResources;
readonly attribute nsIDOMLoadStatusList pendingOfflineLoads;
};

Просмотреть файл

@ -48,6 +48,9 @@ GRE_MODULE = 1
SDK_XPIDLSRCS = \
nsIDOMOfflineResourceList.idl \
$(NULL)
nsIDOMLoadStatusList.idl \
nsIDOMLoadStatus.idl \
nsIDOMLoadStatusEvent.idl \
$(NULL)
include $(topsrcdir)/config/rules.mk

Просмотреть файл

@ -0,0 +1,55 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation
* Portions created by the Initial Developer are Copyright (C) 2007
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Dave Camp <dcamp@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "domstubs.idl"
[scriptable, uuid(2cb53a8a-d2f4-4ddf-874f-3bc2d595c41a)]
interface nsIDOMLoadStatus : nsISupports
{
readonly attribute nsIDOMNode source;
readonly attribute DOMString uri;
readonly attribute long totalSize;
readonly attribute long loadedSize;
readonly attribute unsigned short readyState;
readonly attribute unsigned short status;
const unsigned short UNINITIALIZED = 0;
const unsigned short REQUESTED = 1;
const unsigned short RECEIVING = 2;
const unsigned short LOADED = 3;
};

Просмотреть файл

@ -0,0 +1,58 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation
* Portions created by the Initial Developer are Copyright (C) 2007
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Dave Camp <dcamp@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "domstubs.idl"
#include "nsIDOMEvent.idl"
interface nsIDOMLoadStatus;
[scriptable, uuid(f14431b1-efb6-436c-a272-312f087b1459)]
interface nsIDOMLoadStatusEvent : nsIDOMEvent
{
readonly attribute nsIDOMLoadStatus status;
void initLoadStatusEvent(in DOMString typeArg,
in boolean canBubbleArg,
in boolean cancellableArg,
in nsIDOMLoadStatus statusArg);
void initLoadStatusEventNS(in DOMString namespaceURIArg,
in DOMString typeArg,
in boolean canBubbleArg,
in boolean cancellableArg,
in nsIDOMLoadStatus statusArg);
};

Просмотреть файл

@ -0,0 +1,48 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation
* Portions created by the Initial Developer are Copyright (C) 2007
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Dave Camp <dcamp@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "domstubs.idl"
interface nsIDOMLoadStatus;
[scriptable, uuid(d58bc0cf-e35c-4d22-9e21-9ada8fc4203a)]
interface nsIDOMLoadStatusList : nsISupports
{
readonly attribute unsigned long length;
nsIDOMLoadStatus item(in unsigned long index);
};

Просмотреть файл

@ -398,6 +398,9 @@ enum nsDOMClassInfoID {
eDOMClassInfo_CommandEvent_id,
eDOMClassInfo_OfflineResourceList_id,
eDOMClassInfo_LoadStatusList_id,
eDOMClassInfo_LoadStatus_id,
eDOMClassInfo_LoadStatusEvent_id,
// This one better be the last one in this list
eDOMClassInfoIDCount

Просмотреть файл

@ -431,6 +431,11 @@
#include "nsIDOMStorageEvent.h"
#include "nsIDOMToString.h"
// Offline includes
#include "nsIDOMLoadStatusList.h"
#include "nsIDOMLoadStatus.h"
#include "nsIDOMLoadStatusEvent.h"
static NS_DEFINE_CID(kCPluginManagerCID, NS_PLUGINMANAGER_CID);
static NS_DEFINE_CID(kDOMSOF_CID, NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
@ -1179,6 +1184,13 @@ static nsDOMClassInfoData sClassInfoData[] = {
NS_DEFINE_CLASSINFO_DATA(OfflineResourceList, nsOfflineResourceListSH,
ARRAY_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(LoadStatusList, nsLoadStatusListSH,
ARRAY_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(LoadStatus, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(LoadStatusEvent, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
};
// Objects that shuld be constructable through |new Name();|
@ -3196,6 +3208,20 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_ENTRY(nsIDOMOfflineResourceList)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(LoadStatusList, nsIDOMLoadStatusList)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMLoadStatusList)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(LoadStatus, nsIDOMLoadStatus)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMLoadStatus)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(LoadStatusEvent, nsIDOMLoadStatusEvent)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMLoadStatusEvent)
DOM_CLASSINFO_EVENT_MAP_ENTRIES
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(TextRectangle, nsIDOMTextRectangle)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMTextRectangle)
DOM_CLASSINFO_MAP_END
@ -10069,3 +10095,19 @@ nsOfflineResourceListSH::GetStringAt(nsISupports *aNative, PRInt32 aIndex,
return list->Item(aIndex, aResult);
}
// nsLoadStatusListSH
nsresult
nsLoadStatusListSH::GetItemAt(nsISupports *aNative, PRUint32 aIndex,
nsISupports **aResult)
{
nsCOMPtr<nsIDOMLoadStatusList> list(do_QueryInterface(aNative));
NS_ENSURE_TRUE(list, NS_ERROR_UNEXPECTED);
nsIDOMLoadStatus *status = nsnull; // Weak, transfer the ownership over to aResult
nsresult rv = list->Item(aIndex, &status);
*aResult = status;
return rv;
}

Просмотреть файл

@ -1623,6 +1623,26 @@ public:
}
};
class nsLoadStatusListSH : public nsArraySH
{
protected:
nsLoadStatusListSH(nsDOMClassInfoData *aData) : nsArraySH(aData)
{
}
virtual ~nsLoadStatusListSH()
{
}
virtual nsresult GetItemAt(nsISupports *aNative, PRUint32 aIndex,
nsISupports **aResult);
public:
static nsIClassInfo *doCreate(nsDOMClassInfoData* aData)
{
return new nsLoadStatusListSH(aData);
}
};
void InvalidateContextAndWrapperCache();

Просмотреть файл

@ -51,6 +51,7 @@
#include "nsBarProps.h"
#include "nsDOMStorage.h"
#include "nsDOMOfflineResourceList.h"
#include "nsDOMOfflineLoadStatusList.h"
#include "nsDOMError.h"
// Helper Classes
@ -8455,6 +8456,7 @@ nsNavigator::LoadingNewDocument()
mMimeTypes = nsnull;
mPlugins = nsnull;
mOfflineResources = nsnull;
mPendingOfflineLoads = nsnull;
}
nsresult
@ -8599,3 +8601,27 @@ nsNavigator::GetOfflineResources(nsIDOMOfflineResourceList **aList)
return NS_OK;
}
NS_IMETHODIMP
nsNavigator::GetPendingOfflineLoads(nsIDOMLoadStatusList **aList)
{
NS_ENSURE_ARG_POINTER(aList);
if (!mPendingOfflineLoads) {
nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(GetDocShell()));
if (!webNav) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIURI> uri;
nsresult rv = webNav->GetCurrentURI(getter_AddRefs(uri));
NS_ENSURE_SUCCESS(rv, rv);
mPendingOfflineLoads = new nsDOMOfflineLoadStatusList(uri);
if (!mPendingOfflineLoads) return NS_ERROR_OUT_OF_MEMORY;
}
NS_IF_ADDREF(*aList = mPendingOfflineLoads);
return NS_OK;
}

Просмотреть файл

@ -119,6 +119,7 @@ class nsGlobalWindowObserver;
class nsGlobalWindow;
class nsDOMOfflineResourceList;
class nsDOMOfflineLoadStatusList;
// permissible values for CheckOpenAllow
enum OpenAllowValue {
@ -758,6 +759,7 @@ protected:
nsRefPtr<nsMimeTypeArray> mMimeTypes;
nsRefPtr<nsPluginArray> mPlugins;
nsRefPtr<nsDOMOfflineResourceList> mOfflineResources;
nsRefPtr<nsDOMOfflineLoadStatusList> mPendingOfflineLoads;
nsIDocShell* mDocShell; // weak reference
static jsval sPrefInternal_id;

Просмотреть файл

@ -50,8 +50,10 @@ REQUIRES = xpcom \
string \
content \
caps \
gfx \
js \
layout \
locale \
necko \
nkcache \
pref \
@ -60,8 +62,9 @@ REQUIRES = xpcom \
xpconnect \
$(NULL)
CPPSRCS = \
nsDOMOfflineResourceList.cpp \
CPPSRCS = \
nsDOMOfflineResourceList.cpp \
nsDOMOfflineLoadStatusList.cpp \
$(NULL)
# we don't want the shared lib, but we want to force the creation of a static lib.

Просмотреть файл

@ -0,0 +1,611 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation
* Portions created by the Initial Developer are Copyright (C) 2007
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Dave Camp <dcamp@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsDOMOfflineLoadStatusList.h"
#include "nsDOMClassInfo.h"
#include "nsIMutableArray.h"
#include "nsCPrefetchService.h"
#include "nsIObserverService.h"
#include "nsIJSContextStack.h"
#include "nsIScriptSecurityManager.h"
#include "nsIContent.h"
#include "nsNetCID.h"
#include "nsICacheService.h"
#include "nsICacheSession.h"
#include "nsContentUtils.h"
#include "nsDOMError.h"
#include "nsNetUtil.h"
#include "nsAutoPtr.h"
#define LOADREQUESTED_STR "loadrequested"
#define LOADCOMPLETED_STR "loadcompleted"
//
// nsDOMOfflineLoadStatus
//
// XXX
//
// nsDOMOfflineLoadStatusList has an array wrapper in its classinfo struct
// (LoadStatusList) that exposes nsDOMOfflineLoadStatusList::Item() as
// array items.
//
// For scripts to recognize these as nsIDOMLoadStatus objects, I needed
// to add a LoadStatus classinfo.
//
// Because the prefetch service is outside the dom module, it can't
// actually use the LoadStatus classinfo.
//
// nsDOMOfflineLoadStatus is just a simple wrapper around the
// nsIDOMLoadStatus objects returned by the prefetch service that adds the
// LoadStatus classinfo implementation.
//
// Is there a better way around this?
class nsDOMOfflineLoadStatus : public nsIDOMLoadStatus
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMLOADSTATUS
nsDOMOfflineLoadStatus(nsIDOMLoadStatus *status);
virtual ~nsDOMOfflineLoadStatus();
const nsIDOMLoadStatus *Implementation() { return mStatus; }
private:
nsCOMPtr<nsIDOMLoadStatus> mStatus;
};
NS_INTERFACE_MAP_BEGIN(nsDOMOfflineLoadStatus)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMLoadStatus)
NS_INTERFACE_MAP_ENTRY(nsIDOMLoadStatus)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(LoadStatus)
NS_INTERFACE_MAP_END
NS_IMPL_ADDREF(nsDOMOfflineLoadStatus)
NS_IMPL_RELEASE(nsDOMOfflineLoadStatus)
nsDOMOfflineLoadStatus::nsDOMOfflineLoadStatus(nsIDOMLoadStatus *aStatus)
: mStatus(aStatus)
{
}
nsDOMOfflineLoadStatus::~nsDOMOfflineLoadStatus()
{
}
NS_IMETHODIMP
nsDOMOfflineLoadStatus::GetSource(nsIDOMNode **aSource)
{
return mStatus->GetSource(aSource);
}
NS_IMETHODIMP
nsDOMOfflineLoadStatus::GetUri(nsAString &aURI)
{
return mStatus->GetUri(aURI);
}
NS_IMETHODIMP
nsDOMOfflineLoadStatus::GetTotalSize(PRInt32 *aTotalSize)
{
return mStatus->GetTotalSize(aTotalSize);
}
NS_IMETHODIMP
nsDOMOfflineLoadStatus::GetLoadedSize(PRInt32 *aLoadedSize)
{
return mStatus->GetLoadedSize(aLoadedSize);
}
NS_IMETHODIMP
nsDOMOfflineLoadStatus::GetReadyState(PRUint16 *aReadyState)
{
return mStatus->GetReadyState(aReadyState);
}
NS_IMETHODIMP
nsDOMOfflineLoadStatus::GetStatus(PRUint16 *aStatus)
{
return mStatus->GetStatus(aStatus);
}
//
// nsDOMOfflineLoadStatusList
//
NS_INTERFACE_MAP_BEGIN(nsDOMOfflineLoadStatusList)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMLoadStatusList)
NS_INTERFACE_MAP_ENTRY(nsIDOMLoadStatusList)
NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
NS_INTERFACE_MAP_ENTRY(nsIObserver)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(LoadStatusList)
NS_INTERFACE_MAP_END
NS_IMPL_ADDREF(nsDOMOfflineLoadStatusList)
NS_IMPL_RELEASE(nsDOMOfflineLoadStatusList)
nsDOMOfflineLoadStatusList::nsDOMOfflineLoadStatusList(nsIURI *aURI)
: mInitialized(PR_FALSE)
, mURI(aURI)
{
}
nsDOMOfflineLoadStatusList::~nsDOMOfflineLoadStatusList()
{
mLoadRequestedEventListeners.Clear();
mLoadCompletedEventListeners.Clear();
}
nsresult
nsDOMOfflineLoadStatusList::Init()
{
if (mInitialized) {
return NS_OK;
}
mInitialized = PR_TRUE;
nsresult rv = mURI->GetHostPort(mHostPort);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsICacheService> serv =
do_GetService(NS_CACHESERVICE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsICacheSession> session;
rv = serv->CreateSession("HTTP-offline",
nsICache::STORE_OFFLINE,
nsICache::STREAM_BASED,
getter_AddRefs(session));
NS_ENSURE_SUCCESS(rv, rv);
mCacheSession = do_QueryInterface(session, &rv);
NS_ENSURE_SUCCESS(rv, rv);
// get the current list of loads from the prefetch queue
nsCOMPtr<nsIPrefetchService> prefetchService =
do_GetService(NS_PREFETCHSERVICE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsISimpleEnumerator> e;
rv = prefetchService->EnumerateQueue(PR_FALSE, PR_TRUE, getter_AddRefs(e));
NS_ENSURE_SUCCESS(rv, rv);
PRBool more;
while (NS_SUCCEEDED(rv = e->HasMoreElements(&more)) && more) {
nsCOMPtr<nsIDOMLoadStatus> status;
rv = e->GetNext(getter_AddRefs(status));
NS_ENSURE_SUCCESS(rv, rv);
PRBool shouldInclude;
rv = ShouldInclude(status, &shouldInclude);
NS_ENSURE_SUCCESS(rv, rv);
if (!shouldInclude) {
continue;
}
nsDOMOfflineLoadStatus *wrapper = new nsDOMOfflineLoadStatus(status);
if (!wrapper) return NS_ERROR_OUT_OF_MEMORY;
mItems.AppendObject(wrapper);
}
NS_ENSURE_SUCCESS(rv, rv);
// watch for changes in the prefetch queue
nsCOMPtr<nsIObserverService> observerServ =
do_GetService("@mozilla.org/observer-service;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = observerServ->AddObserver(this, "offline-load-requested", PR_TRUE);
NS_ENSURE_SUCCESS(rv, rv);
rv = observerServ->AddObserver(this, "offline-load-completed", PR_TRUE);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
nsresult
nsDOMOfflineLoadStatusList::ShouldInclude(nsIDOMLoadStatus *aStatus,
PRBool *aShouldInclude)
{
*aShouldInclude = PR_FALSE;
nsAutoString uriStr;
nsresult rv = aStatus->GetUri(uriStr);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIURI> uri;
rv = NS_NewURI(getter_AddRefs(uri), uriStr);
NS_ENSURE_SUCCESS(rv, rv);
nsCAutoString hostport;
rv = uri->GetHostPort(hostport);
NS_ENSURE_SUCCESS(rv, rv);
if (hostport != mHostPort)
return NS_OK;
// Check that the URL is owned by this domain
nsCAutoString spec;
rv = uri->GetSpec(spec);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDOMNode> source;
rv = aStatus->GetSource(getter_AddRefs(source));
NS_ENSURE_SUCCESS(rv, rv);
nsCAutoString ownerURI;
if (source) {
// Came from a <link> element, check that it's owned by this URI
rv = mURI->GetSpec(ownerURI);
NS_ENSURE_SUCCESS(rv, rv);
} else {
// Didn't come from a <link> element, check that it's owned by
// resource list (no owner URI)
ownerURI.Truncate();
}
PRBool owned;
rv = mCacheSession->KeyIsOwned(mHostPort, ownerURI, spec, &owned);
NS_ENSURE_SUCCESS(rv, rv);
if (!owned) {
return NS_OK;
}
*aShouldInclude = PR_TRUE;
return NS_OK;
}
nsIDOMLoadStatus *
nsDOMOfflineLoadStatusList::FindWrapper(nsIDOMLoadStatus *aStatus,
PRUint32 *index)
{
for (int i = 0; i < mItems.Count(); i++) {
nsDOMOfflineLoadStatus *item = NS_STATIC_CAST(nsDOMOfflineLoadStatus*,
mItems[i]);
if (item->Implementation() == aStatus) {
*index = i;
return mItems[i];
}
}
return nsnull;
}
//
// nsDOMOfflineLoadStatusList::nsIDOMLoadStatusList
//
NS_IMETHODIMP
nsDOMOfflineLoadStatusList::GetLength(PRUint32 *aLength)
{
nsresult rv = Init();
NS_ENSURE_SUCCESS(rv, rv);
*aLength = mItems.Count();
return NS_OK;
}
NS_IMETHODIMP
nsDOMOfflineLoadStatusList::Item(PRUint32 aItem, nsIDOMLoadStatus **aStatus)
{
nsresult rv = Init();
NS_ENSURE_SUCCESS(rv, rv);
if ((PRInt32)aItem > mItems.Count()) return NS_ERROR_DOM_INDEX_SIZE_ERR;
NS_ADDREF(*aStatus = mItems[aItem]);
return NS_OK;
}
//
// nsDOMOfflineLoadStatusList::nsIDOMEventTarget
//
static nsIScriptContext *
GetCurrentContext()
{
// Get JSContext from stack.
nsCOMPtr<nsIJSContextStack> stack =
do_GetService("@mozilla.org/js/xpc/ContextStack;1");
if (!stack) {
return nsnull;
}
JSContext *cx;
if (NS_FAILED(stack->Peek(&cx)) || !cx) {
return nsnull;
}
return GetScriptContextFromJSContext(cx);
}
NS_IMETHODIMP
nsDOMOfflineLoadStatusList::AddEventListener(const nsAString& aType,
nsIDOMEventListener *aListener,
PRBool aUseCapture)
{
nsresult rv = Init();
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_ARG(aListener);
nsCOMArray<nsIDOMEventListener> *array;
#define IMPL_ADD_LISTENER(_type, _member) \
if (aType.EqualsLiteral(_type)) { \
array = &(_member); \
} else
IMPL_ADD_LISTENER(LOADREQUESTED_STR, mLoadRequestedEventListeners)
IMPL_ADD_LISTENER(LOADCOMPLETED_STR, mLoadCompletedEventListeners)
{
return NS_ERROR_INVALID_ARG;
}
array->AppendObject(aListener);
mScriptContext = GetCurrentContext();
#undef IMPL_ADD_LISTENER
return NS_OK;
}
NS_IMETHODIMP
nsDOMOfflineLoadStatusList::RemoveEventListener(const nsAString &aType,
nsIDOMEventListener *aListener,
PRBool aUseCapture)
{
nsresult rv = Init();
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_ARG(aListener);
nsCOMArray<nsIDOMEventListener> *array;
#define IMPL_REMOVE_LISTENER(_type, _member) \
if (aType.EqualsLiteral(_type)) { \
array = &(_member); \
} else
IMPL_REMOVE_LISTENER(LOADREQUESTED_STR, mLoadRequestedEventListeners)
IMPL_REMOVE_LISTENER(LOADCOMPLETED_STR, mLoadCompletedEventListeners)
{
return NS_ERROR_INVALID_ARG;
}
// Allow a caller to remove O(N^2) behavior by removing end-to-start.
for (PRUint32 i = array->Count() - 1; i != PRUint32(-1); --i) {
if (array->ObjectAt(i) == aListener) {
array->RemoveObjectAt(i);
break;
}
}
#undef IMPL_ADD_LISTENER
return NS_OK;
}
NS_IMETHODIMP
nsDOMOfflineLoadStatusList::DispatchEvent(nsIDOMEvent *evt, PRBool *_retval)
{
// Ignored
return NS_OK;
}
void
nsDOMOfflineLoadStatusList::NotifyEventListeners(const nsCOMArray<nsIDOMEventListener>& aListeners,
nsIDOMEvent* aEvent)
{
// XXXbz wouldn't it be easier to just have an actual nsEventListenerManager
// to work with or something? I feel like we're duplicating code here...
//
// (and this was duplicated from XMLHttpRequest)
if (!aEvent)
return;
nsCOMPtr<nsIJSContextStack> stack;
JSContext *cx = nsnull;
if (mScriptContext) {
stack = do_GetService("@mozilla.org/js/xpc/ContextStack;1");
if (stack) {
cx = (JSContext *)mScriptContext->GetNativeContext();
if (cx) {
stack->Push(cx);
}
}
}
PRInt32 count = aListeners.Count();
for (PRInt32 index = 0; index < count; ++index) {
nsIDOMEventListener* listener = aListeners[index];
if (listener) {
listener->HandleEvent(aEvent);
}
}
if (cx) {
stack->Pop(&cx);
}
}
nsresult
nsDOMOfflineLoadStatusList::SendLoadEvent(const nsAString &aEventName,
const nsCOMArray<nsIDOMEventListener> &aListeners,
nsIDOMLoadStatus *aStatus)
{
NS_ENSURE_ARG(aStatus);
if (aListeners.Count() == 0) return NS_OK;
nsRefPtr<nsDOMLoadStatusEvent> event = new nsDOMLoadStatusEvent(aEventName,
aStatus);
if (!event) return NS_ERROR_OUT_OF_MEMORY;
nsresult rv = event->Init();
NS_ENSURE_SUCCESS(rv, rv);
NotifyEventListeners(aListeners,
NS_STATIC_CAST(nsIDOMLoadStatusEvent*, event));
return NS_OK;
}
//
// nsDOMLoadStatusList::nsIObserver
//
NS_IMETHODIMP
nsDOMOfflineLoadStatusList::Observe(nsISupports *aSubject,
const char *aTopic,
const PRUnichar *aData)
{
nsresult rv;
if (!strcmp(aTopic, "offline-load-requested")) {
nsCOMPtr<nsIDOMLoadStatus> status = do_QueryInterface(aSubject);
if (status) {
PRBool shouldInclude;
rv = ShouldInclude(status, &shouldInclude);
NS_ENSURE_SUCCESS(rv, rv);
if (!shouldInclude) return NS_OK;
nsDOMOfflineLoadStatus *wrapper = new nsDOMOfflineLoadStatus(status);
if (!wrapper) return NS_ERROR_OUT_OF_MEMORY;
mItems.AppendObject(wrapper);
rv = SendLoadEvent(NS_LITERAL_STRING(LOADREQUESTED_STR),
mLoadRequestedEventListeners,
wrapper);
NS_ENSURE_SUCCESS(rv, rv);
}
} else if (!strcmp(aTopic, "offline-load-completed")) {
nsCOMPtr<nsIDOMLoadStatus> status = do_QueryInterface(aSubject);
if (status) {
PRUint32 index;
nsCOMPtr<nsIDOMLoadStatus> wrapper = FindWrapper(status, &index);
if (wrapper) {
mItems.RemoveObjectAt(index);
rv = SendLoadEvent(NS_LITERAL_STRING(LOADCOMPLETED_STR),
mLoadCompletedEventListeners,
wrapper);
NS_ENSURE_SUCCESS(rv, rv);
}
}
}
return NS_OK;
}
//
// nsDOMLoadStatusEvent
//
NS_INTERFACE_MAP_BEGIN(nsDOMLoadStatusEvent)
NS_INTERFACE_MAP_ENTRY(nsIDOMLoadStatusEvent)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(LoadStatusEvent)
NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
NS_IMPL_ADDREF_INHERITED(nsDOMLoadStatusEvent, nsDOMEvent)
NS_IMPL_RELEASE_INHERITED(nsDOMLoadStatusEvent, nsDOMEvent)
nsresult
nsDOMLoadStatusEvent::Init()
{
nsresult rv = InitEvent(mEventName, PR_TRUE, PR_FALSE);
NS_ENSURE_SUCCESS(rv, rv);
// This init method is only called by native code, so set the
// trusted flag there.
SetTrusted(PR_TRUE);
return NS_OK;
}
NS_IMETHODIMP
nsDOMLoadStatusEvent::InitLoadStatusEvent(const nsAString& aTypeArg,
PRBool aCanBubbleArg,
PRBool aCancelableArg,
nsIDOMLoadStatus* aStatusArg)
{
nsresult rv = InitEvent(aTypeArg, aCanBubbleArg, aCancelableArg);
NS_ENSURE_SUCCESS(rv, rv);
mStatus = aStatusArg;
return NS_OK;
}
NS_IMETHODIMP
nsDOMLoadStatusEvent::InitLoadStatusEventNS(const nsAString& aNamespaceURIArg,
const nsAString& aTypeArg,
PRBool aCanBubbleArg,
PRBool aCancelableArg,
nsIDOMLoadStatus* aStatusArg)
{
// XXX: Figure out what to do with aNamespaceURIArg here!
nsresult rv = InitEvent(aTypeArg, aCanBubbleArg, aCancelableArg);
NS_ENSURE_SUCCESS(rv, rv);
mStatus = aStatusArg;
return NS_OK;
}
NS_IMETHODIMP
nsDOMLoadStatusEvent::GetStatus(nsIDOMLoadStatus **aStatus)
{
NS_ADDREF(*aStatus = mStatus);
return NS_OK;
}

Просмотреть файл

@ -0,0 +1,123 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code mozilla.org code.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation
* Portions created by the Initial Developer are Copyright (C) 2007
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Dave Camp <dcamp@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef nsDOMOfflineLoadStatusList_h___
#define nsDOMOfflineLoadStatusList_h___
#include "nscore.h"
#include "nsIDOMLoadStatus.h"
#include "nsIDOMLoadStatusEvent.h"
#include "nsIDOMLoadStatusList.h"
#include "nsIOfflineCacheSession.h"
#include "nsCOMPtr.h"
#include "nsCOMArray.h"
#include "nsIURI.h"
#include "nsDOMEvent.h"
#include "nsIDOMEventTarget.h"
#include "nsIDOMEventListener.h"
#include "nsIObserver.h"
#include "nsWeakReference.h"
#include "nsIScriptContext.h"
class nsDOMOfflineLoadStatus;
class nsDOMOfflineLoadStatusList : public nsIDOMLoadStatusList,
public nsIDOMEventTarget,
public nsIObserver,
public nsSupportsWeakReference
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMLOADSTATUSLIST
NS_DECL_NSIDOMEVENTTARGET
NS_DECL_NSIOBSERVER
nsDOMOfflineLoadStatusList(nsIURI *aURI);
virtual ~nsDOMOfflineLoadStatusList();
nsresult Init();
private :
nsresult ShouldInclude (nsIDOMLoadStatus *aStatus,
PRBool *aInclude);
nsIDOMLoadStatus *FindWrapper (nsIDOMLoadStatus *aStatus,
PRUint32 *aIndex);
void NotifyEventListeners(const nsCOMArray<nsIDOMEventListener>& aListeners,
nsIDOMEvent* aEvent);
nsresult SendLoadEvent (const nsAString& aEventName,
const nsCOMArray<nsIDOMEventListener>& aListeners,
nsIDOMLoadStatus *aStatus);
PRBool mInitialized;
nsCOMPtr<nsIURI> mURI;
nsCOMArray<nsIDOMLoadStatus> mItems;
nsCString mHostPort;
nsCOMPtr<nsIOfflineCacheSession> mCacheSession;
nsCOMPtr<nsIScriptContext> mScriptContext;
nsCOMArray<nsIDOMEventListener> mLoadRequestedEventListeners;
nsCOMArray<nsIDOMEventListener> mLoadCompletedEventListeners;
};
class nsDOMLoadStatusEvent : public nsDOMEvent,
public nsIDOMLoadStatusEvent
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMLOADSTATUSEVENT
NS_FORWARD_NSIDOMEVENT(nsDOMEvent::)
nsDOMLoadStatusEvent(const nsAString& aEventName, nsIDOMLoadStatus *aStatus)
: nsDOMEvent(nsnull, nsnull), mEventName(aEventName), mStatus(aStatus)
{
}
virtual ~nsDOMLoadStatusEvent() { }
nsresult Init();
private:
nsAutoString mEventName;
nsCOMPtr<nsIDOMLoadStatus> mStatus;
};
#endif

Просмотреть файл

@ -200,6 +200,7 @@ nsDOMOfflineResourceList::Add(const nsAString& aURI)
return prefetchService->PrefetchURIForOfflineUse(requestedURI,
mURI,
nsnull,
PR_TRUE);
}
@ -269,6 +270,7 @@ nsDOMOfflineResourceList::Refresh()
rv = prefetchService->PrefetchURIForOfflineUse(requestedURI,
mURI,
nsnull,
PR_TRUE);
NS_ENSURE_SUCCESS(rv, rv);
}

Просмотреть файл

@ -48,6 +48,7 @@ include $(topsrcdir)/config/rules.mk
_TEST_FILES = \
test_offlineResources.html \
test_isLocallyAvailable.html \
test_pendingOfflineLoads.html \
$(NULL)
libs:: $(_TEST_FILES)

Просмотреть файл

@ -0,0 +1,131 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>navigator.pendingOfflineLoads Test</title>
<link id="load1" rel="offline-resource" href="http://localhost:8888/unknown1">
<link id="load2" rel="offline-resource" href="http://localhost:8888/MochiKit/packed.js">
<script type="text/javascript" src="/MochiKit/packed.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript">
var base = window.location.protocol + "//" + window.location.host;
var thisURL = base + window.location.pathname;
var expectedCompletions = {};
expectedCompletions["http://localhost:8888/unknown1"] = {
"source": document.getElementById("load1"),
"status": 404
};
expectedCompletions["http://localhost:8888/unknown2"] = {
"source": null,
"status": 404
};
expectedCompletions["http://localhost:8888/MochiKit/packed.js"] = {
"source": document.getElementById("load2"),
"status": 200
};
expectedCompletions[thisURL] = {
"source": null,
"status": 200
};
var expectedAdditions = { };
for (var uri in expectedCompletions) {
expectedAdditions[uri] = expectedCompletions[uri];
}
function check_load_added(load)
{
var source = load.source;
var uri = load.uri;
ok(expectedAdditions[uri], uri + " should be in the expected addition list");
ok(expectedAdditions[uri].source == source,
uri + " should come from the expected source");
ok(load.status == 0, "status should be 0");
delete expectedAdditions[uri];
}
function load_requested(e)
{
check_load_added(e.status);
}
function load_completed(e)
{
var load = e.status;
var uri = load.uri;
ok(expectedCompletions[uri],
uri + " should be in the expected completion list");
ok(expectedCompletions[uri].source == load.source,
uri + " should come from the expected source");
ok(expectedCompletions[uri].status == load.status,
uri + " should have a load status of " + expectedCompletions[uri].status);
delete expectedCompletions[uri];
if (navigator.pendingOfflineLoads.length == 0) {
for (var name in expectedAdditions) {
ok(false, name + " did not receive a request event");
}
for (var name in expectedCompletions) {
ok(false, name + " did not receive a completed event");
}
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
// Clear the ownership list
var cacheService = Components.classes["@mozilla.org/network/cache-service;1"]
.getService(Components.interfaces.nsICacheService);
var cacheSession = cacheService.createSession("HTTP-offline",
Components.interfaces.nsICache.STORE_OFFLINE,
true)
.QueryInterface(Components.interfaces.nsIOfflineCacheSession);
cacheSession.setOwnedKeys(window.location.host, thisURL, 0, []);
cacheSession.setOwnedKeys(window.location.host, "", 0, []);
cacheSession.evictUnownedEntries();
SimpleTest.finish();
}
}
function run_test()
{
navigator.pendingOfflineLoads.addEventListener("loadrequested",
load_requested,
false);
navigator.pendingOfflineLoads.addEventListener("loadcompleted",
load_completed,
false);
// The <link rel="offline-resource"> should already be in the queue
ok(navigator.pendingOfflineLoads.length == 2,
"<link rel=\"offline-resource\"> loads should already be in the queue");
for (var i = 0; i < navigator.pendingOfflineLoads.length; i++) {
var load = navigator.pendingOfflineLoads[i];
check_load_added(navigator.pendingOfflineLoads[i]);
}
// Add the correct resources
navigator.offlineResources.add("http://localhost:8888/unknown2");
navigator.offlineResources.add(thisURL);
}
SimpleTest.waitForExplicitFinish();
</script>
</head>
<body onload="run_test()">
</body>
</html>

Просмотреть файл

@ -38,8 +38,10 @@
#include "nsISupports.idl"
interface nsIURI;
interface nsIDOMNode;
interface nsISimpleEnumerator;
[scriptable, uuid(ae241be6-3cb6-47ec-9e38-2d89bc22042a)]
[scriptable, uuid(cba513eb-c457-4b93-832c-1a979e66edd1)]
interface nsIPrefetchService : nsISupports
{
/**
@ -47,9 +49,14 @@ interface nsIPrefetchService : nsISupports
*
* @param aURI the URI of the document to prefetch
* @param aReferrerURI the URI of the referring page
* @param aSource the DOM node (such as a <link> tag) that requested this
* fetch, or null if the prefetch was not requested by a DOM node.
* @param aExplicit the link element has an explicit prefetch link type
*/
void prefetchURI(in nsIURI aURI, in nsIURI aReferrerURI, in boolean aExplicit);
void prefetchURI(in nsIURI aURI,
in nsIURI aReferrerURI,
in nsIDOMNode aSource,
in boolean aExplicit);
/**
* Enqueue a request to prefetch the specified URI, making sure it's in the
@ -57,11 +64,25 @@ interface nsIPrefetchService : nsISupports
*
* @param aURI the URI of the document to prefetch
* @param aReferrerURI the URI of the referring page
* @param aSource the DOM node (such as a <link> tag) that requested this
* fetch, or null if the prefetch was not requested by a DOM node.
* @param aExplicit the link element has an explicit offline link type
*/
void prefetchURIForOfflineUse(in nsIURI aURI,
in nsIURI aReferrerURI,
in nsIDOMNode aSource,
in boolean aExplicit);
/**
* Enumerate the items in the prefetch queue. Each element in the
* enumeration is an nsIDOMLoadStatus.
*
* @param aIncludeNormalItems include normal prefetch items in the list.
* @param aIncludeOfflineItems include items being fetched for offline
* use.
*/
nsISimpleEnumerator enumerateQueue(in boolean aIncludeNormalItems,
in boolean aIncludeOfflineItems);
// XXX do we need a way to cancel prefetch requests?
};

Просмотреть файл

@ -51,10 +51,12 @@
#include "nsICacheVisitor.h"
#include "nsIHttpChannel.h"
#include "nsIURL.h"
#include "nsISimpleEnumerator.h"
#include "nsNetUtil.h"
#include "nsString.h"
#include "nsXPIDLString.h"
#include "nsReadableUtils.h"
#include "nsStreamUtils.h"
#include "nsAutoPtr.h"
#include "prtime.h"
#include "prlog.h"
@ -95,52 +97,196 @@ PRTimeToSeconds(PRTime t_usec)
#define NowInSeconds() PRTimeToSeconds(PR_Now())
//-----------------------------------------------------------------------------
// nsPrefetchListener <public>
// nsPrefetchQueueEnumerator
//-----------------------------------------------------------------------------
nsPrefetchListener::nsPrefetchListener(nsPrefetchService *aService)
class nsPrefetchQueueEnumerator : public nsISimpleEnumerator
{
NS_ADDREF(mService = aService);
public:
NS_DECL_ISUPPORTS
NS_DECL_NSISIMPLEENUMERATOR
nsPrefetchQueueEnumerator(nsPrefetchService *aService,
PRBool aIncludeNormal,
PRBool aIncludeOffline);
~nsPrefetchQueueEnumerator();
private:
void Increment();
nsRefPtr<nsPrefetchService> mService;
nsRefPtr<nsPrefetchNode> mCurrent;
PRBool mIncludeNormal;
PRBool mIncludeOffline;
PRBool mStarted;
};
//-----------------------------------------------------------------------------
// nsPrefetchQueueEnumerator <public>
//-----------------------------------------------------------------------------
nsPrefetchQueueEnumerator::nsPrefetchQueueEnumerator(nsPrefetchService *aService,
PRBool aIncludeNormal,
PRBool aIncludeOffline)
: mService(aService)
, mIncludeNormal(aIncludeNormal)
, mIncludeOffline(aIncludeOffline)
, mStarted(PR_FALSE)
{
Increment();
}
nsPrefetchListener::~nsPrefetchListener()
nsPrefetchQueueEnumerator::~nsPrefetchQueueEnumerator()
{
NS_RELEASE(mService);
}
//-----------------------------------------------------------------------------
// nsPrefetchListener <private>
// nsPrefetchQueueEnumerator::nsISimpleEnumerator
//-----------------------------------------------------------------------------
NS_METHOD
nsPrefetchListener::ConsumeSegments(nsIInputStream *aInputStream,
void *aClosure,
const char *aFromSegment,
PRUint32 aOffset,
PRUint32 aCount,
PRUint32 *aBytesConsumed)
NS_IMETHODIMP
nsPrefetchQueueEnumerator::HasMoreElements(PRBool *aHasMore)
{
*aBytesConsumed = aCount;
*aHasMore = (mCurrent != nsnull);
return NS_OK;
}
NS_IMETHODIMP
nsPrefetchQueueEnumerator::GetNext(nsISupports **aItem)
{
if (!mCurrent) return NS_ERROR_FAILURE;
NS_ADDREF(*aItem = static_cast<nsIDOMLoadStatus*>(mCurrent.get()));
Increment();
return NS_OK;
}
//-----------------------------------------------------------------------------
// nsPrefetchListener::nsISupports
// nsPrefetchQueueEnumerator <private>
//-----------------------------------------------------------------------------
NS_IMPL_ISUPPORTS4(nsPrefetchListener,
void
nsPrefetchQueueEnumerator::Increment()
{
do {
if (!mStarted) {
// If the service is currently serving a request, it won't be
// in the pending queue, so we return it first. If it isn't,
// we'll just start with the pending queue.
mStarted = PR_TRUE;
mCurrent = mService->GetCurrentNode();
if (!mCurrent)
mCurrent = mService->GetQueueHead();
}
else if (mCurrent) {
if (mCurrent == mService->GetCurrentNode()) {
// If we just returned the node being processed by the service,
// start with the pending queue
mCurrent = mService->GetQueueHead();
}
else {
// Otherwise just advance to the next item in the queue
mCurrent = mCurrent->mNext;
}
}
} while (mCurrent && mIncludeOffline != mCurrent->mOffline &&
mIncludeNormal == mCurrent->mOffline);
}
//-----------------------------------------------------------------------------
// nsPrefetchQueueEnumerator::nsISupports
//-----------------------------------------------------------------------------
NS_IMPL_ISUPPORTS1(nsPrefetchQueueEnumerator, nsISimpleEnumerator)
//-----------------------------------------------------------------------------
// nsPrefetchNode <public>
//-----------------------------------------------------------------------------
nsPrefetchNode::nsPrefetchNode(nsPrefetchService *aService,
nsIURI *aURI,
nsIURI *aReferrerURI,
nsIDOMNode *aSource,
PRBool aOffline)
: mNext(nsnull)
, mURI(aURI)
, mReferrerURI(aReferrerURI)
, mOffline(aOffline)
, mService(aService)
, mChannel(nsnull)
, mState(nsIDOMLoadStatus::UNINITIALIZED)
, mBytesRead(0)
{
mSource = do_GetWeakReference(aSource);
}
nsresult
nsPrefetchNode::OpenChannel()
{
nsresult rv = NS_NewChannel(getter_AddRefs(mChannel),
mURI,
nsnull, nsnull, this,
nsIRequest::LOAD_BACKGROUND |
nsICachingChannel::LOAD_ONLY_IF_MODIFIED);
NS_ENSURE_SUCCESS(rv, rv);
// configure HTTP specific stuff
nsCOMPtr<nsIHttpChannel> httpChannel =
do_QueryInterface(mChannel);
if (httpChannel) {
httpChannel->SetReferrer(mReferrerURI);
httpChannel->SetRequestHeader(
NS_LITERAL_CSTRING("X-Moz"),
mOffline ?
NS_LITERAL_CSTRING("offline-resource") :
NS_LITERAL_CSTRING("prefetch"),
PR_FALSE);
}
if (mOffline) {
nsCOMPtr<nsICachingChannel> cachingChannel =
do_QueryInterface(mChannel);
if (cachingChannel) {
rv = cachingChannel->SetCacheForOfflineUse(PR_TRUE);
NS_ENSURE_SUCCESS(rv, rv);
}
}
rv = mChannel->AsyncOpen(this, nsnull);
NS_ENSURE_SUCCESS(rv, rv);
mState = nsIDOMLoadStatus::REQUESTED;
return NS_OK;
}
nsresult
nsPrefetchNode::CancelChannel(nsresult error)
{
mChannel->Cancel(error);
mChannel = nsnull;
mState = nsIDOMLoadStatus::UNINITIALIZED;
return NS_OK;
}
//-----------------------------------------------------------------------------
// nsPrefetchNode::nsISupports
//-----------------------------------------------------------------------------
NS_IMPL_ISUPPORTS5(nsPrefetchNode,
nsIDOMLoadStatus,
nsIRequestObserver,
nsIStreamListener,
nsIInterfaceRequestor,
nsIChannelEventSink)
//-----------------------------------------------------------------------------
// nsPrefetchListener::nsIStreamListener
// nsPrefetchNode::nsIStreamListener
//-----------------------------------------------------------------------------
NS_IMETHODIMP
nsPrefetchListener::OnStartRequest(nsIRequest *aRequest,
nsISupports *aContext)
nsPrefetchNode::OnStartRequest(nsIRequest *aRequest,
nsISupports *aContext)
{
nsresult rv;
@ -183,39 +329,54 @@ nsPrefetchListener::OnStartRequest(nsIRequest *aRequest,
}
}
}
mState = nsIDOMLoadStatus::RECEIVING;
return NS_OK;
}
NS_IMETHODIMP
nsPrefetchListener::OnDataAvailable(nsIRequest *aRequest,
nsISupports *aContext,
nsIInputStream *aStream,
PRUint32 aOffset,
PRUint32 aCount)
nsPrefetchNode::OnDataAvailable(nsIRequest *aRequest,
nsISupports *aContext,
nsIInputStream *aStream,
PRUint32 aOffset,
PRUint32 aCount)
{
PRUint32 bytesRead = 0;
aStream->ReadSegments(ConsumeSegments, nsnull, aCount, &bytesRead);
aStream->ReadSegments(NS_DiscardSegment, nsnull, aCount, &bytesRead);
mBytesRead += bytesRead;
LOG(("prefetched %u bytes [offset=%u]\n", bytesRead, aOffset));
return NS_OK;
}
NS_IMETHODIMP
nsPrefetchListener::OnStopRequest(nsIRequest *aRequest,
nsISupports *aContext,
nsresult aStatus)
nsPrefetchNode::OnStopRequest(nsIRequest *aRequest,
nsISupports *aContext,
nsresult aStatus)
{
LOG(("done prefetching [status=%x]\n", aStatus));
mState = nsIDOMLoadStatus::LOADED;
if (mBytesRead == 0 && aStatus == NS_OK) {
// we didn't need to read (because LOAD_ONLY_IF_MODIFIED was
// specified), but the object should report loadedSize as if it
// did.
mChannel->GetContentLength(&mBytesRead);
}
mService->NotifyLoadCompleted(this);
mService->ProcessNextURI();
return NS_OK;
}
//-----------------------------------------------------------------------------
// nsPrefetchListener::nsIInterfaceRequestor
// nsPrefetchNode::nsIInterfaceRequestor
//-----------------------------------------------------------------------------
NS_IMETHODIMP
nsPrefetchListener::GetInterface(const nsIID &aIID, void **aResult)
nsPrefetchNode::GetInterface(const nsIID &aIID, void **aResult)
{
if (aIID.Equals(NS_GET_IID(nsIChannelEventSink))) {
NS_ADDREF_THIS();
@ -227,13 +388,13 @@ nsPrefetchListener::GetInterface(const nsIID &aIID, void **aResult)
}
//-----------------------------------------------------------------------------
// nsPrefetchListener::nsIChannelEventSink
// nsPrefetchNode::nsIChannelEventSink
//-----------------------------------------------------------------------------
NS_IMETHODIMP
nsPrefetchListener::OnChannelRedirect(nsIChannel *aOldChannel,
nsIChannel *aNewChannel,
PRUint32 aFlags)
nsPrefetchNode::OnChannelRedirect(nsIChannel *aOldChannel,
nsIChannel *aNewChannel,
PRUint32 aFlags)
{
nsCOMPtr<nsIURI> newURI;
nsresult rv = aNewChannel->GetURI(getter_AddRefs(newURI));
@ -272,10 +433,12 @@ nsPrefetchListener::OnChannelRedirect(nsIChannel *aOldChannel,
NS_LITERAL_CSTRING("prefetch"),
PR_FALSE);
mService->UpdateCurrentChannel(aNewChannel);
mChannel = aNewChannel;
return NS_OK;
}
//-----------------------------------------------------------------------------
// nsPrefetchService <public>
//-----------------------------------------------------------------------------
@ -338,15 +501,10 @@ nsPrefetchService::ProcessNextURI()
nsresult rv;
nsCOMPtr<nsIURI> uri, referrer;
mCurrentChannel = nsnull;
nsRefPtr<nsPrefetchListener> listener(new nsPrefetchListener(this));
if (!listener) return;
mCurrentNode = nsnull;
do {
PRBool offline;
rv = DequeueURI(getter_AddRefs(uri), getter_AddRefs(referrer),
&offline);
rv = DequeueNode(getter_AddRefs(mCurrentNode));
if (rv == NS_ERROR_NOT_AVAILABLE && mFetchedOffline) {
// done loading stuff, go ahead and evict unowned entries from
// the offline cache
@ -365,7 +523,7 @@ nsPrefetchService::ProcessNextURI()
#if defined(PR_LOGGING)
if (LOG_ENABLED()) {
nsCAutoString spec;
uri->GetSpec(spec);
mCurrentNode->mURI->GetSpec(spec);
LOG(("ProcessNextURI [%s]\n", spec.get()));
}
#endif
@ -373,42 +531,45 @@ nsPrefetchService::ProcessNextURI()
//
// if opening the channel fails, then just skip to the next uri
//
rv = NS_NewChannel(getter_AddRefs(mCurrentChannel), uri,
nsnull, nsnull, listener,
nsIRequest::LOAD_BACKGROUND |
nsICachingChannel::LOAD_ONLY_IF_MODIFIED);
if (NS_FAILED(rv)) continue;
// configure HTTP specific stuff
nsCOMPtr<nsIHttpChannel> httpChannel =
do_QueryInterface(mCurrentChannel);
if (httpChannel) {
httpChannel->SetReferrer(referrer);
httpChannel->SetRequestHeader(
NS_LITERAL_CSTRING("X-Moz"),
offline ?
NS_LITERAL_CSTRING("offline-resource") :
NS_LITERAL_CSTRING("prefetch"),
PR_FALSE);
}
if (offline) {
nsCOMPtr<nsICachingChannel> cachingChannel =
do_QueryInterface(mCurrentChannel);
if (cachingChannel) {
if (NS_FAILED(cachingChannel->SetCacheForOfflineUse(PR_TRUE))) {
continue;
}
}
rv = mCurrentNode->OpenChannel();
if (NS_SUCCEEDED(rv) && mCurrentNode->mOffline)
mFetchedOffline = PR_TRUE;
}
rv = mCurrentChannel->AsyncOpen(listener, nsnull);
}
while (NS_FAILED(rv));
}
void
nsPrefetchService::NotifyLoadRequested(nsPrefetchNode *node)
{
nsresult rv;
nsCOMPtr<nsIObserverService> observerService =
do_GetService("@mozilla.org/observer-service;1", &rv);
if (NS_FAILED(rv)) return;
const char *topic = node->mOffline ? "offline-load-requested" :
"prefetch-load-requested";
observerService->NotifyObservers(static_cast<nsIDOMLoadStatus*>(node),
topic, nsnull);
}
void
nsPrefetchService::NotifyLoadCompleted(nsPrefetchNode *node)
{
nsresult rv;
nsCOMPtr<nsIObserverService> observerService =
do_GetService("@mozilla.org/observer-service;1", &rv);
if (NS_FAILED(rv)) return;
const char *topic = node->mOffline ? "offline-load-completed" :
"prefetch-load-completed";
observerService->NotifyObservers(static_cast<nsIDOMLoadStatus*>(node),
topic, nsnull);
}
//-----------------------------------------------------------------------------
// nsPrefetchService <private>
//-----------------------------------------------------------------------------
@ -434,42 +595,49 @@ nsPrefetchService::RemoveProgressListener()
}
nsresult
nsPrefetchService::EnqueueURI(nsIURI *aURI,
nsIURI *aReferrerURI,
PRBool aOffline)
nsPrefetchService::EnqueueNode(nsPrefetchNode *aNode)
{
nsPrefetchNode *node = new nsPrefetchNode(aURI, aReferrerURI, aOffline);
if (!node)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(aNode);
if (!mQueueTail) {
mQueueHead = node;
mQueueTail = node;
mQueueHead = aNode;
mQueueTail = aNode;
}
else {
mQueueTail->mNext = node;
mQueueTail = node;
mQueueTail->mNext = aNode;
mQueueTail = aNode;
}
return NS_OK;
}
nsresult
nsPrefetchService::DequeueURI(nsIURI **aURI,
nsIURI **aReferrerURI,
PRBool *aOffline)
nsPrefetchService::EnqueueURI(nsIURI *aURI,
nsIURI *aReferrerURI,
nsIDOMNode *aSource,
PRBool aOffline,
nsPrefetchNode **aNode)
{
nsPrefetchNode *node = new nsPrefetchNode(this, aURI, aReferrerURI,
aSource, aOffline);
if (!node)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(*aNode = node);
return EnqueueNode(node);
}
nsresult
nsPrefetchService::DequeueNode(nsPrefetchNode **node)
{
if (!mQueueHead)
return NS_ERROR_NOT_AVAILABLE;
// remove from the head
NS_ADDREF(*aURI = mQueueHead->mURI);
NS_ADDREF(*aReferrerURI = mQueueHead->mReferrerURI);
*aOffline = mQueueHead->mOffline;
nsPrefetchNode *node = mQueueHead;
// give the ref to the caller
*node = mQueueHead;
mQueueHead = mQueueHead->mNext;
delete node;
(*node)->mNext = nsnull;
if (!mQueueHead)
mQueueTail = nsnull;
@ -490,7 +658,7 @@ nsPrefetchService::EmptyQueue(PRBool includeOffline)
prev->mNext = next;
else
mQueueHead = next;
delete node;
NS_RELEASE(node);
}
else
prev = node;
@ -540,7 +708,7 @@ nsPrefetchService::StartPrefetching()
// only start prefetching after we've received enough DOCUMENT
// STOP notifications. we do this inorder to defer prefetching
// until after all sub-frames have finished loading.
if (mStopCount == 0 && !mCurrentChannel) {
if (mStopCount == 0 && !mCurrentNode) {
mHaveProcessed = PR_TRUE;
ProcessNextURI();
}
@ -554,29 +722,16 @@ nsPrefetchService::StopPrefetching()
LOG(("StopPrefetching [stopcount=%d]\n", mStopCount));
// only kill the prefetch queue if we've actually started prefetching.
if (!mCurrentChannel)
if (!mCurrentNode)
return;
// if it's an offline prefetch, requeue it for when prefetching starts
// again
nsCOMPtr<nsICachingChannel> cachingChannel =
do_QueryInterface(mCurrentChannel);
PRBool offline;
if (cachingChannel &&
NS_SUCCEEDED(cachingChannel->GetCacheForOfflineUse(&offline)) &&
offline) {
nsCOMPtr<nsIHttpChannel> httpChannel =
do_QueryInterface(mCurrentChannel);
nsCOMPtr<nsIURI> uri;
nsCOMPtr<nsIURI> referrerURI;
if (NS_SUCCEEDED(mCurrentChannel->GetURI(getter_AddRefs(uri))) &&
NS_SUCCEEDED(httpChannel->GetReferrer(getter_AddRefs(referrerURI)))) {
EnqueueURI(uri, referrerURI, PR_TRUE);
}
}
if (mCurrentNode->mOffline)
EnqueueNode(mCurrentNode);
mCurrentChannel->Cancel(NS_BINDING_ABORTED);
mCurrentChannel = nsnull;
mCurrentNode->CancelChannel(NS_BINDING_ABORTED);
mCurrentNode = nsnull;
EmptyQueue(PR_FALSE);
}
@ -597,6 +752,7 @@ NS_IMPL_ISUPPORTS4(nsPrefetchService,
nsresult
nsPrefetchService::Prefetch(nsIURI *aURI,
nsIURI *aReferrerURI,
nsIDOMNode *aSource,
PRBool aExplicit,
PRBool aOffline)
{
@ -672,33 +828,17 @@ nsPrefetchService::Prefetch(nsIURI *aURI,
}
}
//
//
// cancel if being prefetched
//
if (mCurrentChannel) {
nsCOMPtr<nsIURI> currentURI;
mCurrentChannel->GetURI(getter_AddRefs(currentURI));
if (currentURI) {
PRBool equals;
if (NS_SUCCEEDED(currentURI->Equals(aURI, &equals)) && equals) {
if (aOffline) {
// We may still need to put it on the queue if the channel
// isn't fetching to the offline cache
nsCOMPtr<nsICachingChannel> cachingChannel =
do_QueryInterface(mCurrentChannel, &rv);
if (NS_SUCCEEDED(rv)) {
PRBool offline;
rv = cachingChannel->GetCacheForOfflineUse(&offline);
if (NS_SUCCEEDED(rv) && offline) {
LOG(("rejected: URL is already being prefetched\n"));
return NS_ERROR_ABORT;
}
}
}
else {
LOG(("rejected: URL is already being prefetched\n"));
return NS_ERROR_ABORT;
}
if (mCurrentNode) {
PRBool equals;
if (NS_SUCCEEDED(mCurrentNode->mURI->Equals(aURI, &equals)) && equals) {
// We may still need to put it on the queue if the channel
// isn't fetching to the offline cache
if (!aOffline || mCurrentNode->mOffline) {
LOG(("rejected: URL is already being prefetched\n"));
return NS_ERROR_ABORT;
}
}
}
@ -719,9 +859,13 @@ nsPrefetchService::Prefetch(nsIURI *aURI,
}
}
rv = EnqueueURI(aURI, aReferrerURI, aOffline);
nsRefPtr<nsPrefetchNode> enqueuedNode;
rv = EnqueueURI(aURI, aReferrerURI, aSource, aOffline,
getter_AddRefs(enqueuedNode));
NS_ENSURE_SUCCESS(rv, rv);
NotifyLoadRequested(enqueuedNode);
// if there are no pages loading, kick off the request immediately
if (mStopCount == 0 && mHaveProcessed)
ProcessNextURI();
@ -732,17 +876,117 @@ nsPrefetchService::Prefetch(nsIURI *aURI,
NS_IMETHODIMP
nsPrefetchService::PrefetchURI(nsIURI *aURI,
nsIURI *aReferrerURI,
nsIDOMNode *aSource,
PRBool aExplicit)
{
return Prefetch(aURI, aReferrerURI, aExplicit, PR_FALSE);
return Prefetch(aURI, aReferrerURI, aSource, aExplicit, PR_FALSE);
}
NS_IMETHODIMP
nsPrefetchService::PrefetchURIForOfflineUse(nsIURI *aURI,
nsIURI *aReferrerURI,
nsIDOMNode *aSource,
PRBool aExplicit)
{
return Prefetch(aURI, aReferrerURI, aExplicit, PR_TRUE);
return Prefetch(aURI, aReferrerURI, aSource, aExplicit, PR_TRUE);
}
NS_IMETHODIMP
nsPrefetchService::EnumerateQueue(PRBool aIncludeNormalItems,
PRBool aIncludeOfflineItems,
nsISimpleEnumerator **aEnumerator)
{
*aEnumerator = new nsPrefetchQueueEnumerator(this,
aIncludeNormalItems,
aIncludeOfflineItems);
if (!*aEnumerator) return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(*aEnumerator);
return NS_OK;
}
//-----------------------------------------------------------------------------
// nsPrefetchNode::nsIDOMLoadStatus
//-----------------------------------------------------------------------------
NS_IMETHODIMP
nsPrefetchNode::GetSource(nsIDOMNode **aSource)
{
*aSource = nsnull;
nsCOMPtr<nsIDOMNode> source = do_QueryReferent(mSource);
if (source)
source.swap(*aSource);
return NS_OK;
}
NS_IMETHODIMP
nsPrefetchNode::GetUri(nsAString &aURI)
{
nsCAutoString spec;
nsresult rv = mURI->GetSpec(spec);
NS_ENSURE_SUCCESS(rv, rv);
CopyUTF8toUTF16(spec, aURI);
return NS_OK;
}
NS_IMETHODIMP
nsPrefetchNode::GetTotalSize(PRInt32 *aTotalSize)
{
if (mChannel) {
return mChannel->GetContentLength(aTotalSize);
}
*aTotalSize = -1;
return NS_OK;
}
NS_IMETHODIMP
nsPrefetchNode::GetLoadedSize(PRInt32 *aLoadedSize)
{
*aLoadedSize = mBytesRead;
return NS_OK;
}
NS_IMETHODIMP
nsPrefetchNode::GetReadyState(PRUint16 *aReadyState)
{
*aReadyState = mState;
return NS_OK;
}
NS_IMETHODIMP
nsPrefetchNode::GetStatus(PRUint16 *aStatus)
{
if (!mChannel) {
*aStatus = 0;
return NS_OK;
}
nsresult rv;
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(mChannel, &rv);
NS_ENSURE_SUCCESS(rv, rv);
PRUint32 httpStatus;
rv = httpChannel->GetResponseStatus(&httpStatus);
if (rv == NS_ERROR_NOT_AVAILABLE) {
// Someone's calling this before we got a response... Check our
// ReadyState. If we're at RECEIVING or LOADED, then this means the
// connection errored before we got any data; return a somewhat
// sensible error code in that case.
if (mState >= nsIDOMLoadStatus::RECEIVING) {
*aStatus = NS_ERROR_NOT_AVAILABLE;
return NS_OK;
}
*aStatus = 0;
return NS_OK;
}
NS_ENSURE_SUCCESS(rv, rv);
*aStatus = PRUint16(httpStatus);
return NS_OK;
}
//-----------------------------------------------------------------------------

Просмотреть файл

@ -48,8 +48,10 @@
#include "nsIChannel.h"
#include "nsIURI.h"
#include "nsIDOMDocument.h"
#include "nsIDOMLoadStatus.h"
#include "nsWeakReference.h"
#include "nsCOMPtr.h"
#include "nsAutoPtr.h"
class nsPrefetchService;
class nsPrefetchListener;
@ -75,20 +77,29 @@ public:
nsresult Init();
void ProcessNextURI();
void UpdateCurrentChannel(nsIChannel *c) { mCurrentChannel = c; }
nsPrefetchNode *GetCurrentNode() { return mCurrentNode.get(); }
nsPrefetchNode *GetQueueHead() { return mQueueHead; }
void NotifyLoadRequested(nsPrefetchNode *node);
void NotifyLoadCompleted(nsPrefetchNode *node);
private:
~nsPrefetchService();
nsresult Prefetch(nsIURI *aURI,
nsIURI *aReferrerURI,
nsIDOMNode *aSource,
PRBool aExplicit,
PRBool aOffline);
void AddProgressListener();
void RemoveProgressListener();
nsresult EnqueueURI(nsIURI *aURI, nsIURI *aReferrerURI, PRBool aOffline);
nsresult DequeueURI(nsIURI **aURI, nsIURI **aReferrerURI, PRBool *aOffline);
nsresult EnqueueURI(nsIURI *aURI, nsIURI *aReferrerURI,
nsIDOMNode *aSource, PRBool aOffline,
nsPrefetchNode **node);
nsresult EnqueueNode(nsPrefetchNode *node);
nsresult DequeueNode(nsPrefetchNode **node);
void EmptyQueue(PRBool includeOffline);
nsresult SaveOfflineList(nsIURI *aDocumentUri,
nsIDOMDocument *aDoc);
@ -100,7 +111,7 @@ private:
nsCOMPtr<nsIOfflineCacheSession> mOfflineCacheSession;
nsPrefetchNode *mQueueHead;
nsPrefetchNode *mQueueTail;
nsCOMPtr<nsIChannel> mCurrentChannel;
nsRefPtr<nsPrefetchNode> mCurrentNode;
PRInt32 mStopCount;
// true if pending document loads have ever reached zero.
PRInt32 mHaveProcessed;
@ -110,51 +121,44 @@ private:
};
//-----------------------------------------------------------------------------
// nsPrefetchListener
// nsPrefetchNode
//-----------------------------------------------------------------------------
class nsPrefetchListener : public nsIStreamListener
, public nsIInterfaceRequestor
, public nsIChannelEventSink
class nsPrefetchNode : public nsIDOMLoadStatus
, public nsIStreamListener
, public nsIInterfaceRequestor
, public nsIChannelEventSink
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMLOADSTATUS
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSIINTERFACEREQUESTOR
NS_DECL_NSICHANNELEVENTSINK
nsPrefetchListener(nsPrefetchService *aPrefetchService);
nsPrefetchNode(nsPrefetchService *aPrefetchService,
nsIURI *aURI,
nsIURI *aReferrerURI,
nsIDOMNode *aSource,
PRBool aOffline);
~nsPrefetchNode() {}
nsresult OpenChannel();
nsresult CancelChannel(nsresult error);
nsPrefetchNode *mNext;
nsCOMPtr<nsIURI> mURI;
nsCOMPtr<nsIURI> mReferrerURI;
nsCOMPtr<nsIWeakReference> mSource;
PRBool mOffline;
private:
~nsPrefetchListener();
static NS_METHOD ConsumeSegments(nsIInputStream *, void *, const char *,
PRUint32, PRUint32, PRUint32 *);
nsPrefetchService *mService;
};
//-----------------------------------------------------------------------------
// nsPrefetchNode
//-----------------------------------------------------------------------------
class nsPrefetchNode
{
public:
nsPrefetchNode(nsIURI *aURI,
nsIURI *aReferrerURI,
PRBool aOffline)
: mNext(nsnull)
, mURI(aURI)
, mReferrerURI(aReferrerURI)
, mOffline(aOffline)
{ }
nsPrefetchNode *mNext;
nsCOMPtr<nsIURI> mURI;
nsCOMPtr<nsIURI> mReferrerURI;
PRBool mOffline;
nsRefPtr<nsPrefetchService> mService;
nsCOMPtr<nsIChannel> mChannel;
PRUint16 mState;
PRInt32 mBytesRead;
};
#endif // !nsPrefetchService_h__