зеркало из https://github.com/mozilla/pjs.git
implement navigator.pendingOfflineLoads. b=372969, r=biesi, r+sr=jst
This commit is contained in:
Родитель
b329ef5c40
Коммит
f6d4f9ff68
|
@ -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__
|
||||
|
|
Загрузка…
Ссылка в новой задаче