Bug 107552 - backend for resuming ftp downloads

r=dougt, sr=darin, mac build patches by zach
This commit is contained in:
bbaetz%student.usyd.edu.au 2002-02-14 03:10:19 +00:00
parent fb3c11fe91
commit dc31ade623
21 changed files with 721 additions and 41 deletions

View File

@ -25,6 +25,8 @@ nsIFileStreams.idl
nsITransport.idl
nsIStreamLoader.idl
nsIDownloader.idl
nsIResumableChannel.idl
nsIResumableEntityID.idl
nsIRequestObserver.idl
nsIRequestObserverProxy.idl
nsIStreamProvider.idl

View File

@ -57,6 +57,8 @@ XPIDLSRCS = \
nsISocketTransportService.idl \
nsIStreamIO.idl \
nsIStreamIOChannel.idl \
nsIResumableChannel.idl \
nsIResumableEntityID.idl \
nsIRequestObserver.idl \
nsIRequestObserverProxy.idl \
nsIStreamListener.idl \

View File

@ -58,7 +58,9 @@ XPIDLSRCS = \
.\nsISocketTransport.idl \
.\nsISocketTransportService.idl \
.\nsIStreamIO.idl \
.\nsIStreamIOChannel.idl \
.\nsIStreamIOChannel.idl \
.\nsIResumableChannel.idl \
.\nsIResumableEntityID.idl \
.\nsIRequestObserver.idl \
.\nsIRequestObserverProxy.idl \
.\nsIStreamListener.idl \

View File

@ -68,6 +68,11 @@
#define NS_ERROR_PORT_ACCESS_NOT_ALLOWED \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 19)
/* 20 - 24 defined in ftpCore.h */
#define NS_ERROR_NOT_RESUMABLE \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 25)
#define NS_ERROR_REDIRECT_LOOP \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 31)

View File

@ -0,0 +1,69 @@
/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** 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 Bradley Baetz
* Portions created by the Initial Developer are Copyright (C) 2001, 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s): Bradley Baetz <bbaetz@student.usyd.edu.au>
*
* 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 "nsISupports.idl"
interface nsIStreamListener;
interface nsIResumableEntityID;
[scriptable, uuid(87cccd68-1dd2-11b2-8b66-cbf10a1b6438)]
interface nsIResumableChannel : nsISupports {
/**
* Open this channel, and read starting at the specified offset.
* @param listener - As for asyncOpen
* @param ctxt - As for asyncOpen
* @param startPos - the starting offset, in bytes, to use to download
* @param info - information about the file, to match before obtaining
* the file. Pass null to use anything.
* OnStartRequest wil have a status of NS_ERROR_NOT_RESUMABLE if the file
* cannot be resumed, eg because the server doesn't support this, or the
* nsIFileInfo doesn't match. This error may be occur even if startPos
* is 0, so that the front end can warn the user.
*
* The request given to the nsIStreamListener will be QIable to
* nsIResumableInfo
*/
void asyncOpenAt(in nsIStreamListener listener,
in nsISupports ctxt,
in unsigned long startPos,
in nsIResumableEntityID entityID);
/**
* The nsIResumableEntityID for this uri. Available after OnStartRequest
* If this attribute is null, then this load is not resumable.
*/
readonly attribute nsIResumableEntityID entityID;
};

View File

@ -0,0 +1,60 @@
/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** 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 Bradley Baetz
* Portions created by the Initial Developer are Copyright (C) 2001, 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s): Bradley Baetz <bbaetz@student.usyd.edu.au>
*
* 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 "nsISupports.idl"
/** This is an interface for resumable entities
* @see nsIResumableChannel
*/
[scriptable, uuid(c9df38d4-1dd1-11b2-81ae-c9e767256d1b)]
interface nsIResumableEntityID : nsISupports {
/** Size of the entity, -1 if unknown */
attribute unsigned long size;
/** Last modified time, in seconds since epoch. Note that the timezone
* these are in may not be known
*/
attribute PRTime lastModified;
/** Entity, may be empty. This is meant to hold the E-Tag for http */
// currently we only support ftp; add this in when its utility can be
// checked
//attribute string entity;
/** Compare to another nsIResumableEntityID */
boolean equals(in nsIResumableEntityID other);
};

View File

@ -19,7 +19,7 @@
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Contributor(s): Bradley Baetz <bbaetz@student.usyd.edu.au>
*
* 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
@ -58,6 +58,7 @@
#include "nsMemory.h"
#include "nsCOMPtr.h"
#include "nsIDownloader.h"
#include "nsIResumableEntityID.h"
#include "nsIStreamLoader.h"
#include "nsIStreamIO.h"
#include "nsIPipe.h"
@ -729,4 +730,22 @@ NS_GetURLSpecFromFile(nsIFile* aFile, char **aUrl,
return ioService->GetURLSpecFromFile(aFile, aUrl);
}
inline nsresult
NS_NewResumableEntityID(nsIResumableEntityID** aRes,
PRUint32 size,
PRTime lastModified)
{
nsresult rv;
nsCOMPtr<nsIResumableEntityID> ent =
do_CreateInstance(NS_RESUMABLEENTITYID_CONTRACTID,&rv);
if (NS_FAILED(rv)) return rv;
ent->SetSize(size);
ent->SetLastModified(lastModified);
*aRes = ent;
NS_ADDREF(*aRes);
return NS_OK;
}
#endif // nsNetUtil_h__

View File

@ -54,6 +54,7 @@ CPPSRCS = \
nsProtocolProxyService.cpp \
nsProxyAutoConfigUtils.cpp \
nsRequestObserverProxy.cpp \
nsResumableEntityID.cpp \
nsSimpleStreamListener.cpp \
nsSimpleStreamProvider.cpp \
nsSimpleURI.cpp \

View File

@ -48,6 +48,7 @@ CPP_OBJS = \
.\$(OBJDIR)\nsSimpleStreamListener.obj \
.\$(OBJDIR)\nsSimpleStreamProvider.obj \
.\$(OBJDIR)\nsRequestObserverProxy.obj \
.\$(OBJDIR)\nsResumableEntityID.obj \
.\$(OBJDIR)\nsStreamListenerProxy.obj \
.\$(OBJDIR)\nsStreamProviderProxy.obj \
.\$(OBJDIR)\nsURLParsers.obj \

View File

@ -0,0 +1,87 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** 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
* Bradley Baetz
* Portions created by the Initial Developer are Copyright (C) 2002
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s): Bradley Baetz <bbaetz@student.usyd.edu.au>
*
* 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 "nsResumableEntityID.h"
NS_IMPL_ISUPPORTS1(nsResumableEntityID, nsIResumableEntityID)
nsResumableEntityID::nsResumableEntityID() :
mSize(PRUint32(-1)),
mLastModified(PRTime(LL_INIT(-1,-1))) {
NS_INIT_ISUPPORTS();
}
nsResumableEntityID::~nsResumableEntityID() {}
NS_IMETHODIMP
nsResumableEntityID::GetSize(PRUint32 *aSize) {
*aSize = mSize;
return NS_OK;
}
NS_IMETHODIMP
nsResumableEntityID::SetSize(PRUint32 aSize) {
mSize = aSize;
return NS_OK;
}
NS_IMETHODIMP
nsResumableEntityID::GetLastModified(PRTime *aLastModified) {
*aLastModified = mLastModified;
return NS_OK;
}
NS_IMETHODIMP
nsResumableEntityID::SetLastModified(PRTime aLastModified) {
mLastModified = aLastModified;
return NS_OK;
}
NS_IMETHODIMP
nsResumableEntityID::Equals(nsIResumableEntityID *other, PRBool *ret) {
PRUint32 size;
PRInt64 lastMod;
nsresult rv = other->GetSize(&size);
if (NS_FAILED(rv)) return rv;
rv = other->GetLastModified(&lastMod);
if (NS_FAILED(rv)) return rv;
return NS_OK;
}

View File

@ -0,0 +1,51 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** 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 Bradley Baetz
* Portions created by the Initial Developer are Copyright (C) 2002
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s): Bradley Baetz <bbaetz@student.usyd.edu.au>
*
* 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 "nsIResumableEntityID.h"
class nsResumableEntityID : public nsIResumableEntityID {
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIRESUMABLEENTITYID
nsResumableEntityID();
virtual ~nsResumableEntityID();
private:
PRUint32 mSize;
PRTime mLastModified;
};

View File

@ -267,6 +267,17 @@
{0xa9, 0x04, 0xac, 0x1d, 0x6d, 0xa7, 0x7a, 0x02} \
}
#define NS_RESUMABLEENTITYID_CLASSNAME \
"ResumableEntityID"
#define NS_RESUMABLEENTITYID_CONTRACTID \
"@mozilla.org/network/resumable-entity-id;1"
#define NS_RESUMABLEENTITYID_CID \
{ /* e744a9a6-1dd1-11b2-b95c-e5d67a34e6b3 */ \
0xe744a9a6, \
0x1d11, \
0x11b2, \
{0xb9, 0x5c, 0xe5, 0xd6, 0x7a, 0x34, 0xe6, 0xb3} \
}
/******************************************************************************
* netwerk/cache/ classes

View File

@ -138,6 +138,11 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsStandardURL)
///////////////////////////////////////////////////////////////////////////////
#include "nsResumableEntityID.h"
NS_GENERIC_FACTORY_CONSTRUCTOR(nsResumableEntityID)
///////////////////////////////////////////////////////////////////////////////
static NS_METHOD
RegisterBuiltInURLParsers(nsIComponentManager *aCompMgr,
nsIFile *aPath,
@ -683,6 +688,12 @@ static const nsModuleComponentInfo gNetModuleInfo[] = {
nsURICheckerConstructor
},
{ NS_RESUMABLEENTITYID_CLASSNAME,
NS_RESUMABLEENTITYID_CID,
NS_RESUMABLEENTITYID_CONTRACTID,
nsResumableEntityIDConstructor
},
// The register functions for the built-in
// parsers just need to be called once.
{ NS_STDURLPARSER_CLASSNAME,

View File

@ -1590,6 +1590,13 @@
<FILEKIND>Text</FILEKIND>
<FILEFLAGS>Debug</FILEFLAGS>
</FILE>
<FILE>
<PATHTYPE>Name</PATHTYPE>
<PATH>nsResumableEntityID.cpp</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
<FILEKIND>Text</FILEKIND>
<FILEFLAGS>Debug</FILEFLAGS>
</FILE>
</FILELIST>
<LINKORDER>
<FILEREF>
@ -2037,6 +2044,11 @@
<PATH>nsIOServiceMac.cpp</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
</FILEREF>
<FILEREF>
<PATHTYPE>Name</PATHTYPE>
<PATH>nsResumableEntityID.cpp</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
</FILEREF>
</LINKORDER>
</TARGET>
<TARGET>
@ -3576,6 +3588,13 @@
<FILEKIND>Text</FILEKIND>
<FILEFLAGS>Debug</FILEFLAGS>
</FILE>
<FILE>
<PATHTYPE>Name</PATHTYPE>
<PATH>nsResumableEntityID.cpp</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
<FILEKIND>Text</FILEKIND>
<FILEFLAGS>Debug</FILEFLAGS>
</FILE>
</FILELIST>
<LINKORDER>
<FILEREF>
@ -4023,6 +4042,11 @@
<PATH>nsIOServiceMac.cpp</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
</FILEREF>
<FILEREF>
<PATHTYPE>Name</PATHTYPE>
<PATH>nsResumableEntityID.cpp</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
</FILEREF>
</LINKORDER>
</TARGET>
<TARGET>
@ -5548,6 +5572,13 @@
<FILEKIND>Text</FILEKIND>
<FILEFLAGS>Debug</FILEFLAGS>
</FILE>
<FILE>
<PATHTYPE>Name</PATHTYPE>
<PATH>nsResumableEntityID.cpp</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
<FILEKIND>Text</FILEKIND>
<FILEFLAGS>Debug</FILEFLAGS>
</FILE>
</FILELIST>
<LINKORDER>
<FILEREF>
@ -5985,6 +6016,11 @@
<PATH>nsIOServiceMac.cpp</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
</FILEREF>
<FILEREF>
<PATHTYPE>Name</PATHTYPE>
<PATH>nsResumableEntityID.cpp</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
</FILEREF>
</LINKORDER>
</TARGET>
<TARGET>
@ -7510,6 +7546,13 @@
<FILEKIND>Text</FILEKIND>
<FILEFLAGS>Debug</FILEFLAGS>
</FILE>
<FILE>
<PATHTYPE>Name</PATHTYPE>
<PATH>nsResumableEntityID.cpp</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
<FILEKIND>Text</FILEKIND>
<FILEFLAGS>Debug</FILEFLAGS>
</FILE>
</FILELIST>
<LINKORDER>
<FILEREF>
@ -7947,6 +7990,11 @@
<PATH>nsIOServiceMac.cpp</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
</FILEREF>
<FILEREF>
<PATHTYPE>Name</PATHTYPE>
<PATH>nsResumableEntityID.cpp</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
</FILEREF>
</LINKORDER>
</TARGET>
</TARGETLIST>
@ -7960,6 +8008,12 @@
<GROUPLIST>
<GROUP><NAME>base</NAME>
<FILEREF>
<TARGETNAME>Necko.shlb</TARGETNAME>
<PATHTYPE>Name</PATHTYPE>
<PATH>nsResumableEntityID.cpp</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
</FILEREF>
<FILEREF>
<TARGETNAME>Necko.shlb</TARGETNAME>
<PATHTYPE>Name</PATHTYPE>

View File

@ -1414,6 +1414,20 @@
<FILEKIND>Text</FILEKIND>
<FILEFLAGS></FILEFLAGS>
</FILE>
<FILE>
<PATHTYPE>Name</PATHTYPE>
<PATH>nsIResumableChannel.idl</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
<FILEKIND>Text</FILEKIND>
<FILEFLAGS></FILEFLAGS>
</FILE>
<FILE>
<PATHTYPE>Name</PATHTYPE>
<PATH>nsIResumableEntityID.idl</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
<FILEKIND>Text</FILEKIND>
<FILEFLAGS></FILEFLAGS>
</FILE>
</FILELIST>
<LINKORDER>
<FILEREF>
@ -1826,6 +1840,16 @@
<PATH>nsIFileProtocolHandler.idl</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
</FILEREF>
<FILEREF>
<PATHTYPE>Name</PATHTYPE>
<PATH>nsIResumableChannel.idl</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
</FILEREF>
<FILEREF>
<PATHTYPE>Name</PATHTYPE>
<PATH>nsIResumableEntityID.idl</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
</FILEREF>
</LINKORDER>
</TARGET>
<TARGET>
@ -3182,6 +3206,20 @@
<FILEKIND>Text</FILEKIND>
<FILEFLAGS></FILEFLAGS>
</FILE>
<FILE>
<PATHTYPE>Name</PATHTYPE>
<PATH>nsIResumableChannel.idl</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
<FILEKIND>Text</FILEKIND>
<FILEFLAGS></FILEFLAGS>
</FILE>
<FILE>
<PATHTYPE>Name</PATHTYPE>
<PATH>nsIResumableEntityID.idl</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
<FILEKIND>Text</FILEKIND>
<FILEFLAGS></FILEFLAGS>
</FILE>
</FILELIST>
<LINKORDER>
<FILEREF>
@ -3589,6 +3627,16 @@
<PATH>nsIFileProtocolHandler.idl</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
</FILEREF>
<FILEREF>
<PATHTYPE>Name</PATHTYPE>
<PATH>nsIResumableChannel.idl</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
</FILEREF>
<FILEREF>
<PATHTYPE>Name</PATHTYPE>
<PATH>nsIResumableEntityID.idl</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
</FILEREF>
</LINKORDER>
</TARGET>
</TARGETLIST>
@ -3620,6 +3668,18 @@
</FILEREF>
</GROUP>
<GROUP><NAME>base</NAME>
<FILEREF>
<TARGETNAME>headers</TARGETNAME>
<PATHTYPE>Name</PATHTYPE>
<PATH>nsIResumableChannel.idl</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
</FILEREF>
<FILEREF>
<TARGETNAME>headers</TARGETNAME>
<PATHTYPE>Name</PATHTYPE>
<PATH>nsIResumableEntityID.idl</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
</FILEREF>
<FILEREF>
<TARGETNAME>headers</TARGETNAME>
<PATHTYPE>Name</PATHTYPE>

View File

@ -99,16 +99,22 @@ nsFTPChannel::~nsFTPChannel()
if (mLock) PR_DestroyLock(mLock);
}
NS_IMPL_THREADSAFE_ISUPPORTS9(nsFTPChannel,
nsIChannel,
nsIFTPChannel,
nsIUploadChannel,
nsIRequest,
nsIInterfaceRequestor,
nsIProgressEventSink,
nsIStreamListener,
nsIRequestObserver,
nsICacheListener);
NS_IMPL_ADDREF(nsFTPChannel)
NS_IMPL_RELEASE(nsFTPChannel)
NS_INTERFACE_MAP_BEGIN(nsFTPChannel)
NS_INTERFACE_MAP_ENTRY(nsIChannel)
NS_INTERFACE_MAP_ENTRY(nsIFTPChannel)
NS_INTERFACE_MAP_ENTRY(nsIResumableChannel)
NS_INTERFACE_MAP_ENTRY(nsIUploadChannel)
NS_INTERFACE_MAP_ENTRY(nsIRequest)
NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
NS_INTERFACE_MAP_ENTRY(nsIProgressEventSink)
NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
NS_INTERFACE_MAP_ENTRY(nsICacheListener)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIChannel)
NS_INTERFACE_MAP_END
nsresult
nsFTPChannel::Init(nsIURI* uri, nsIProxyInfo* proxyInfo, nsICacheSession* session)
@ -285,6 +291,21 @@ nsFTPChannel::GenerateCacheKey(nsACString &cacheKey)
NS_IMETHODIMP
nsFTPChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctxt)
{
return AsyncOpenAt(listener, ctxt, PRUint32(-1), nsnull);
}
NS_IMETHODIMP
nsFTPChannel::GetEntityID(nsIResumableEntityID **entityID)
{
*entityID = mEntityID;
NS_IF_ADDREF(*entityID);
return NS_OK;
}
NS_IMETHODIMP
nsFTPChannel::AsyncOpenAt(nsIStreamListener *listener, nsISupports *ctxt,
PRUint32 startPos, nsIResumableEntityID* entityID)
{
PRInt32 port;
nsresult rv = mURL->GetPort(&port);
@ -307,7 +328,14 @@ nsFTPChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctxt)
}
PRBool offline;
if (mCacheSession && !mUploadStream) {
// If we're starting from the beginning, then its OK to use the cache,
// because the entire file must be there (the cache doesn't support
// partial entries yet)
// Note that ftp doesn't store metadata, so disable caching if there was
// an entityID. Storing this metadata isn't worth it until we can
// get partial data out of the cache anyway...
if (mCacheSession && !mUploadStream && !entityID &&
(startPos==0 || startPos==PRUint32(-1))) {
mIOService->GetOffline(&offline);
// Set the desired cache access mode accordingly...
@ -334,11 +362,11 @@ nsFTPChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctxt)
("Opening cache entry failed [rv=%x]", rv));
}
return SetupState();
return SetupState(startPos, entityID);
}
nsresult
nsFTPChannel::SetupState()
nsFTPChannel::SetupState(PRUint32 startPos, nsIResumableEntityID* entityID)
{
if (!mFTPState) {
NS_NEWXPCOM(mFTPState, nsFtpState);
@ -350,7 +378,9 @@ nsFTPChannel::SetupState()
mAuthPrompter,
mFTPEventSink,
mCacheEntry,
mProxyInfo);
mProxyInfo,
startPos,
entityID);
if (NS_FAILED(rv)) return rv;
(void) mFTPState->SetWriteStream(mUploadStream);
@ -634,7 +664,10 @@ nsFTPChannel::OnStartRequest(nsIRequest *request, nsISupports *aContext)
nsresult rv = NS_OK;
request->GetStatus(&mStatus);
nsCOMPtr<nsIResumableChannel> resumable = do_QueryInterface(request);
if (resumable)
resumable->GetEntityID(getter_AddRefs(mEntityID));
if (mListener) {
rv = mListener->OnStartRequest(this, mUserContext);
if (NS_FAILED(rv)) return rv;
@ -673,7 +706,7 @@ nsFTPChannel::OnCacheEntryAvailable(nsICacheEntryDescriptor *entry,
mCacheEntry = entry;
}
rv = SetupState();
rv = SetupState(PRUint32(-1),nsnull);
if (NS_FAILED(rv)) {
Cancel(rv);

View File

@ -60,6 +60,8 @@
#include "nsIFTPChannel.h"
#include "nsIUploadChannel.h"
#include "nsIProxyInfo.h"
#include "nsIResumableChannel.h"
#include "nsIResumableEntityID.h"
#include "nsICacheService.h"
#include "nsICacheEntryDescriptor.h"
@ -79,7 +81,8 @@ class nsFTPChannel : public nsIFTPChannel,
public nsIInterfaceRequestor,
public nsIProgressEventSink,
public nsIStreamListener,
public nsICacheListener
public nsICacheListener,
public nsIResumableChannel
{
public:
NS_DECL_ISUPPORTS
@ -92,6 +95,7 @@ public:
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSICACHELISTENER
NS_DECL_NSIRESUMABLECHANNEL
// nsFTPChannel methods:
nsFTPChannel();
@ -106,7 +110,7 @@ public:
nsIProxyInfo* proxyInfo,
nsICacheSession* session);
nsresult SetupState();
nsresult SetupState(PRUint32 startPos, nsIResumableEntityID* entityID);
nsresult GenerateCacheKey(nsACString &cacheKey);
@ -148,6 +152,7 @@ protected:
nsCOMPtr<nsICacheSession> mCacheSession;
nsCOMPtr<nsICacheEntryDescriptor> mCacheEntry;
nsCOMPtr<nsIProxyInfo> mProxyInfo;
nsCOMPtr<nsIResumableEntityID> mEntityID;
};
#endif /* nsFTPChannel_h___ */

View File

@ -19,7 +19,7 @@
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s): Bradley Baetz <bbaetz@cs.mcgill.ca>
* Contributor(s): Bradley Baetz <bbaetz@student.usyd.edu.au>
*
* 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
@ -48,6 +48,7 @@
#include "nsReadableUtils.h"
#include "prprf.h"
#include "prlog.h"
#include "prtime.h"
#include "prnetdb.h"
#include "netCore.h"
#include "ftpCore.h"
@ -69,6 +70,9 @@
#include "nsICacheEntryDescriptor.h"
#include "nsICacheListener.h"
#include "nsIResumableChannel.h"
#include "nsIResumableEntityID.h"
static NS_DEFINE_CID(kPrefCID, NS_PREF_CID);
static NS_DEFINE_CID(kStreamConverterServiceCID, NS_STREAMCONVERTERSERVICE_CID);
static NS_DEFINE_CID(kStreamListenerTeeCID, NS_STREAMLISTENERTEE_CID);
@ -82,7 +86,8 @@ extern PRLogModuleInfo* gFTPLog;
class DataRequestForwarder : public nsIFTPChannel,
public nsIStreamListener,
public nsIInterfaceRequestor,
public nsIProgressEventSink
public nsIProgressEventSink,
public nsIResumableChannel
{
public:
DataRequestForwarder();
@ -91,12 +96,14 @@ public:
nsresult SetStreamListener(nsIStreamListener *listener);
nsresult SetCacheEntry(nsICacheEntryDescriptor *entry, PRBool writing);
nsresult SetEntityID(nsIResumableEntityID *entity);
NS_DECL_ISUPPORTS
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSIINTERFACEREQUESTOR
NS_DECL_NSIPROGRESSEVENTSINK
NS_DECL_NSIRESUMABLECHANNEL
NS_FORWARD_NSIREQUEST(mRequest->)
NS_FORWARD_NSICHANNEL(mFTPChannel->)
@ -113,6 +120,7 @@ protected:
nsCOMPtr<nsIStreamListener> mListener;
nsCOMPtr<nsIProgressEventSink> mEventSink;
nsCOMPtr<nsICacheEntryDescriptor> mCacheEntry;
nsCOMPtr<nsIResumableEntityID> mEntityID;
PRUint32 mBytesTransfered;
PRPackedBool mDelayedOnStartFired;
@ -127,10 +135,11 @@ protected:
// the socket transport so that clients only see
// the same nsIChannel/nsIRequest that they started.
NS_IMPL_THREADSAFE_ISUPPORTS7(DataRequestForwarder,
NS_IMPL_THREADSAFE_ISUPPORTS8(DataRequestForwarder,
nsIStreamListener,
nsIRequestObserver,
nsIFTPChannel,
nsIResumableChannel,
nsIChannel,
nsIRequest,
nsIInterfaceRequestor,
@ -233,6 +242,33 @@ DataRequestForwarder::SetStreamListener(nsIStreamListener *listener)
return NS_OK;
}
nsresult
DataRequestForwarder::SetEntityID(nsIResumableEntityID *aEntityID)
{
mEntityID = aEntityID;
return NS_OK;
}
NS_IMETHODIMP
DataRequestForwarder::GetEntityID(nsIResumableEntityID* *aEntityID)
{
*aEntityID = mEntityID;
NS_IF_ADDREF(*aEntityID);
return NS_OK;
}
NS_IMETHODIMP
DataRequestForwarder::AsyncOpenAt(nsIStreamListener *,
nsISupports *,
unsigned int,
nsIResumableEntityID *)
{
// We shouldn't get here. This class only exists in the middle of a
// request
NS_NOTREACHED("DataRequestForwarder::AsyncOpenAt");
return NS_ERROR_NOT_IMPLEMENTED;
}
nsresult
DataRequestForwarder::DelayedOnStartRequest(nsIRequest *request, nsISupports *ctxt)
{
@ -348,7 +384,7 @@ DataRequestForwarder::OnProgress(nsIRequest *request, nsISupports* aContext,
NS_IMPL_THREADSAFE_ISUPPORTS3(nsFtpState,
NS_IMPL_THREADSAFE_ISUPPORTS3(nsFtpState,
nsIStreamListener,
nsIRequestObserver,
nsIRequest);
@ -378,6 +414,8 @@ nsFtpState::nsFtpState() {
mControlConnection = nsnull;
mDRequestForwarder = nsnull;
mFileSize = PRUint32(-1);
mModTime = -1;
mGenerateRawContent = PR_FALSE;
nsresult rv;
@ -395,6 +433,13 @@ nsFtpState::~nsFtpState()
NS_IF_RELEASE(mDRequestForwarder);
}
nsresult
nsFtpState::GetEntityID(nsIResumableEntityID** aEntityID)
{
*aEntityID = mEntityID;
NS_IF_ADDREF(*aEntityID);
return NS_OK;
}
// nsIStreamListener implementation
NS_IMETHODIMP
@ -829,6 +874,22 @@ nsFtpState::Process()
mInternalError = NS_ERROR_FAILURE;
break;
// MDTM
case FTP_S_MDTM:
rv = S_mdtm();
if (NS_FAILED(rv))
mInternalError = rv;
MoveToNextState(FTP_R_MDTM);
break;
case FTP_R_MDTM:
mState = R_mdtm();
if (FTP_ERROR == mState)
mInternalError = NS_ERROR_FAILURE;
break;
// RETR
case FTP_S_RETR:
@ -1266,14 +1327,76 @@ nsFtpState::R_size() {
if (NS_FAILED(mChannel->SetContentLength(length))) return FTP_ERROR;
}
if (mResponseCode == 550) // File unavailable (e.g., file not found, no access).
return FTP_S_RETR; // Even if the file reports zero size, lets try retr (91292)
if (mResponseCode == 213)
mFileSize = atoi(mResponseMsg.get());
// We may want to be able to resume this
return FTP_S_MDTM;
}
nsresult
nsFtpState::S_mdtm() {
nsCAutoString mdtmBuf(mPath);
if (mdtmBuf.IsEmpty() || mdtmBuf.First() != '/')
mdtmBuf.Insert(mPwd,0);
mdtmBuf.Insert("MDTM ",0);
mdtmBuf.Append(CRLF);
return SendFTPCommand(mdtmBuf);
}
FTP_STATE
nsFtpState::R_mdtm() {
if (mResponseCode == 213) {
mResponseMsg.Trim(" \t\r\n");
// yyyymmddhhmmss
if (mResponseMsg.Length() != 14) {
NS_ASSERTION(mResponseMsg.Length() == 14, "Unknown MDTM response");
} else {
const char* date = mResponseMsg.get();
PRExplodedTime exp;
exp.tm_year = (date[0]-'0')*1000 + (date[1]-'0')*100 +
(date[2]-'0')*10 + (date[3]-'0');
exp.tm_month = (date[4]-'0')*10 + (date[5]-'0');
exp.tm_mday = (date[6]-'0')*10 + (date[7]-'0');
exp.tm_hour = (date[8]-'0')*10 + (date[9]-'0');
exp.tm_min = (date[10]-'0')*10 + (date[11]-'0');
exp.tm_sec = (date[12]-'0')*10 + (date[13]-'0');
exp.tm_usec = 0;
exp.tm_wday = 0;
exp.tm_yday = 0;
exp.tm_params.tp_gmt_offset = 0;
exp.tm_params.tp_dst_offset = 0;
mModTime = PR_ImplodeTime(&exp);
}
}
nsresult rv = NS_NewResumableEntityID(getter_AddRefs(mEntityID),
mFileSize, mModTime);
if (NS_FAILED(rv)) return FTP_ERROR;
mDRequestForwarder->SetEntityID(mEntityID);
// if we tried downloading this, lets try restarting it...
if (mDRequestForwarder && mDRequestForwarder->GetBytesTransfered() > 0)
if (mDRequestForwarder && mDRequestForwarder->GetBytesTransfered() > 0) {
mStartPos = mDRequestForwarder->GetBytesTransfered();
return FTP_S_REST;
}
return FTP_S_RETR;
// We weren't asked to resume
if (mStartPos == PRUint32(-1))
return FTP_S_RETR;
//if (our entityID == supplied one (if any))
PRBool entEqual = PR_FALSE;
if (!mSuppliedEntityID ||
(NS_SUCCEEDED(mEntityID->Equals(mSuppliedEntityID, &entEqual)) &&
entEqual)) {
return FTP_S_REST;
} else {
mInternalError = NS_ERROR_NOT_RESUMABLE;
mResponseMsg.Truncate();
return FTP_ERROR;
}
}
nsresult
@ -1325,6 +1448,17 @@ nsFtpState::S_list() {
// to the stream converter.
mDRequestForwarder->SetStreamListener(converter);
mDRequestForwarder->SetCacheEntry(mCacheEntry, PR_TRUE);
// dir listings aren't resumable
NS_ASSERTION(!mSuppliedEntityID,
"Entity ID given to directory request");
NS_ASSERTION(mStartPos == PRUint32(-1) || mStartPos == 0,
"Non-intial start position given to directory request");
if (mSuppliedEntityID || (mStartPos != PRUint32(-1) && mStartPos != 0)) {
// If we reach this code, then the caller is in error
return NS_ERROR_NOT_RESUMABLE;
}
mDRequestForwarder->SetEntityID(nsnull);
nsCAutoString listString("LIST" CRLF);
@ -1408,7 +1542,7 @@ nsresult
nsFtpState::S_rest() {
nsCAutoString restString("REST ");
restString.AppendInt(mDRequestForwarder->GetBytesTransfered(), 10);
restString.AppendInt(mStartPos, 10);
restString.Append(CRLF);
return SendFTPCommand(restString);
@ -1416,9 +1550,15 @@ nsFtpState::S_rest() {
FTP_STATE
nsFtpState::R_rest() {
// only if something terrible happens do we want to error out in this state.
if (mResponseCode/100 == 4)
if (mResponseCode/100 == 4) {
// If REST fails, then we can't resume
mEntityID = nsnull;
mInternalError = NS_ERROR_NOT_RESUMABLE;
mResponseMsg.Truncate();
return FTP_ERROR;
}
return FTP_S_RETR;
}
@ -1874,7 +2014,9 @@ nsFtpState::Init(nsIFTPChannel* aChannel,
nsIAuthPrompt* aAuthPrompter,
nsIFTPEventSink* sink,
nsICacheEntryDescriptor* cacheEntry,
nsIProxyInfo* proxyInfo)
nsIProxyInfo* proxyInfo,
PRUint32 startPos,
nsIResumableEntityID* entity)
{
nsresult rv = NS_OK;
@ -1894,6 +2036,8 @@ nsFtpState::Init(nsIFTPChannel* aChannel,
mAuthPrompter = aAuthPrompter;
mCacheEntry = cacheEntry;
mProxyInfo = proxyInfo;
mStartPos = startPos;
mSuppliedEntityID = entity;
// parameter validation
NS_ASSERTION(aChannel, "FTP: needs a channel");
@ -1927,9 +2071,10 @@ nsFtpState::Init(nsIFTPChannel* aChannel,
nsCOMPtr<nsIStreamListener> converter;
rv = BuildStreamConverter(getter_AddRefs(converter));
if (NS_FAILED(rv)) return rv;
mDRequestForwarder->SetStreamListener(converter);
mDRequestForwarder->SetCacheEntry(mCacheEntry, PR_FALSE);
mDRequestForwarder->SetEntityID(nsnull);
// Get a transport to the cached data...
nsCOMPtr<nsITransport> transport;

View File

@ -19,7 +19,7 @@
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Contributor(s): Bradley Baetz <bbaetz@student.usyd.edu.au>
*
* 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
@ -59,6 +59,7 @@
#include "nsIAuthPrompt.h"
#include "nsITransport.h"
#include "nsIProxyInfo.h"
#include "nsIResumableEntityID.h"
#include "nsFtpControlConnection.h"
@ -88,6 +89,7 @@ typedef enum _FTP_STATE {
FTP_S_TYPE, FTP_R_TYPE,
FTP_S_CWD, FTP_R_CWD,
FTP_S_SIZE, FTP_R_SIZE,
FTP_S_MDTM, FTP_R_MDTM,
FTP_S_REST, FTP_R_REST,
FTP_S_RETR, FTP_R_RETR,
FTP_S_STOR, FTP_R_STOR,
@ -117,11 +119,15 @@ public:
nsIAuthPrompt *aAuthPrompter,
nsIFTPEventSink *sink,
nsICacheEntryDescriptor* cacheEntry,
nsIProxyInfo* proxyInfo);
nsIProxyInfo* proxyInfo,
PRUint32 startPos,
nsIResumableEntityID* entity);
// use this to provide a stream to be written to the server.
nsresult SetWriteStream(nsIInputStream* aInStream);
nsresult GetEntityID(nsIResumableEntityID* *aEntityID);
nsresult Connect();
// lets the data forwarder tell us when the the data pipe has been created.
@ -138,6 +144,7 @@ private:
nsresult S_cwd(); FTP_STATE R_cwd();
nsresult S_size(); FTP_STATE R_size();
nsresult S_mdtm(); FTP_STATE R_mdtm();
nsresult S_list(); FTP_STATE R_list();
nsresult S_rest(); FTP_STATE R_rest();
@ -180,7 +187,8 @@ private:
nsCOMPtr<nsITransport> mDPipe; // the data transport
nsCOMPtr<nsIRequest> mDPipeRequest;
DataRequestForwarder* mDRequestForwarder;
PRUint32 mFileSize;
PRTime mModTime;
// ****** consumer vars
nsCOMPtr<nsIFTPChannel> mChannel; // our owning FTP channel we pass through our events
@ -227,6 +235,10 @@ private:
nsCAutoString mControlReadCarryOverBuf;
nsCOMPtr<nsICacheEntryDescriptor> mCacheEntry;
PRUint32 mStartPos;
nsCOMPtr<nsIResumableEntityID> mSuppliedEntityID;
nsCOMPtr<nsIResumableEntityID> mEntityID;
};

View File

@ -261,7 +261,7 @@ nsFtpProtocolHandler::RemoveConnection(nsIURI *aKey, nsISupports* *_retval) {
nsXPIDLCString spec;
aKey->GetPrePath(getter_Copies(spec));
PR_LOG(gFTPLog, PR_LOG_DEBUG, ("Removing connection for %s\b", spec.get()));
PR_LOG(gFTPLog, PR_LOG_DEBUG, ("Removing connection for %s\n", spec.get()));
timerStruct* ts = nsnull;
PRInt32 i;
@ -296,7 +296,7 @@ nsFtpProtocolHandler::InsertConnection(nsIURI *aKey, nsISupports *aConn)
nsXPIDLCString spec;
aKey->GetPrePath(getter_Copies(spec));
PR_LOG(gFTPLog, PR_LOG_DEBUG, ("Inserting connection for %s\b", spec.get()));
PR_LOG(gFTPLog, PR_LOG_DEBUG, ("Inserting connection for %s\n", spec.get()));
if (!mRootConnectionList)
return NS_ERROR_FAILURE;

View File

@ -58,6 +58,8 @@
#include "nsIInputStream.h"
#include "nsCRT.h"
#include "nsIChannel.h"
#include "nsIResumableChannel.h"
#include "nsIResumableEntityID.h"
#include "nsIURL.h"
#include "nsIHttpChannel.h"
#include "nsIHttpEventSink.h"
@ -77,6 +79,8 @@ static int gKeepRunning = 0;
static PRBool gVerbose = PR_FALSE;
static nsIEventQueue* gEventQ = nsnull;
static PRBool gAskUserForInput = PR_FALSE;
static PRBool gResume = PR_FALSE;
static PRUint32 gStartAt = 0;
//-----------------------------------------------------------------------------
// HeaderVisitor
@ -251,6 +255,34 @@ InputTestConsumer::OnStartRequest(nsIRequest *request, nsISupports* context)
NS_RELEASE(visitor);
}
nsCOMPtr<nsIResumableChannel> resChannel = do_QueryInterface(request);
if (resChannel) {
printf("Resumable entity identification:\n");
nsCOMPtr<nsIResumableEntityID> entityID;
nsresult rv = resChannel->GetEntityID(getter_AddRefs(entityID));
if (NS_SUCCEEDED(rv) && entityID) {
PRUint32 size;
if (NS_SUCCEEDED(entityID->GetSize(&size)) &&
size != PRUint32(-1))
printf("\tSize: %d\n", size);
else
printf("\tSize: Unknown\n");
PRTime lastModified;
if (NS_SUCCEEDED(entityID->GetLastModified(&lastModified)) &&
lastModified != -1) {
PRExplodedTime exploded;
PR_ExplodeTime(lastModified, PR_LocalTimeParameters, &exploded);
char buf[100];
PR_FormatTime(buf, 100, "%c", &exploded);
printf("\tLast Modified: %s\n", buf);
} else
printf("\tLast Modified: Unknown\n");
}
}
return NS_OK;
}
@ -453,9 +485,21 @@ nsresult StartLoadingURL(const char* aUrlString)
NS_ERROR("Failed to create a load info!");
return NS_ERROR_OUT_OF_MEMORY;
}
rv = pChannel->AsyncOpen(listener, // IStreamListener consumer
info);
if (gResume) {
nsCOMPtr<nsIResumableChannel> res = do_QueryInterface(pChannel);
if (!res) {
NS_ERROR("Channel is not resumable!");
return NS_ERROR_UNEXPECTED;
}
rv = res->AsyncOpenAt(listener,
info,
gStartAt,
nsnull);
} else {
rv = pChannel->AsyncOpen(listener, // IStreamListener consumer
info);
}
if (NS_SUCCEEDED(rv)) {
gKeepRunning += 1;
@ -572,6 +616,12 @@ main(int argc, char* argv[])
gAskUserForInput = PR_TRUE;
continue;
}
if (PL_strcasecmp(argv[i], "-resume") == 0) {
gResume = PR_TRUE;
gStartAt = atoi(argv[++i]);
continue;
}
printf("\t%s\n", argv[i]);
rv = StartLoadingURL(argv[i]);