зеркало из https://github.com/mozilla/gecko-dev.git
fixes bug 151867 - file channel should implement nsIUploadChannel
r=dougt sr=alecf
This commit is contained in:
Родитель
5985d87d73
Коммит
24fd40bd6f
|
@ -1041,7 +1041,7 @@ nsFileTransport::Process(nsIProgressEventSink *progressSink)
|
|||
// see http://bugzilla.mozilla.org/show_bug.cgi?id=139556#c64
|
||||
// for the reason behind this evil reference counting.
|
||||
nsISupports* doomed = mContext.get();
|
||||
NS_ADDREF(doomed);
|
||||
NS_IF_ADDREF(doomed);
|
||||
mContext = 0;
|
||||
if (mProvider) {
|
||||
nsCOMPtr <nsIStreamProvider> provider = do_QueryInterface(mProvider);
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#include "nsIMIMEService.h"
|
||||
#include "nsIFileTransportService.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsInt64.h"
|
||||
#include "nsMimeTypes.h"
|
||||
#include "nsNetUtil.h"
|
||||
|
@ -129,14 +130,20 @@ nsFileChannel::SetStreamConverter()
|
|||
return rv;
|
||||
}
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS7(nsFileChannel,
|
||||
nsIFileChannel,
|
||||
nsIChannel,
|
||||
nsIRequest,
|
||||
nsIStreamListener,
|
||||
nsIRequestObserver,
|
||||
nsIProgressEventSink,
|
||||
nsIInterfaceRequestor)
|
||||
NS_IMPL_THREADSAFE_ADDREF(nsFileChannel)
|
||||
NS_IMPL_THREADSAFE_RELEASE(nsFileChannel)
|
||||
NS_INTERFACE_MAP_BEGIN(nsFileChannel)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIFileChannel)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIChannel)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIRequest)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIStreamProvider)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIProgressEventSink)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIUploadChannel)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIRequestObserver, nsIStreamListener)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIFileChannel)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_METHOD
|
||||
nsFileChannel::Create(nsISupports* aOuter, const nsIID& aIID, void* *aResult)
|
||||
|
@ -247,7 +254,7 @@ nsFileChannel::GetURI(nsIURI* *aURI)
|
|||
}
|
||||
|
||||
nsresult
|
||||
nsFileChannel::EnsureTransport()
|
||||
nsFileChannel::GetFileTransport(nsITransport **trans)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
|
@ -255,12 +262,11 @@ nsFileChannel::EnsureTransport()
|
|||
do_GetService(kFileTransportServiceCID, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = fts->CreateTransport(mFile, mIOFlags, mPerm, PR_TRUE,
|
||||
getter_AddRefs(mFileTransport));
|
||||
rv = fts->CreateTransport(mFile, mIOFlags, mPerm, PR_TRUE, trans);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
mFileTransport->SetNotificationCallbacks(mCallbacks,
|
||||
(mLoadFlags & LOAD_BACKGROUND));
|
||||
// XXX why should file:// URLs be loaded in the background?
|
||||
(*trans)->SetNotificationCallbacks(mCallbacks, (mLoadFlags & LOAD_BACKGROUND));
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -270,17 +276,44 @@ nsFileChannel::Open(nsIInputStream **result)
|
|||
nsresult rv;
|
||||
|
||||
if (mFileTransport)
|
||||
return NS_ERROR_IN_PROGRESS;
|
||||
return NS_ERROR_IN_PROGRESS; // AsyncOpen in progress
|
||||
|
||||
rv = EnsureTransport();
|
||||
if (NS_FAILED(rv)) goto done;
|
||||
nsCOMPtr<nsITransport> fileTransport;
|
||||
rv = GetFileTransport(getter_AddRefs(fileTransport));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = mFileTransport->OpenInputStream(0, PRUint32(-1), 0, result);
|
||||
done:
|
||||
if (NS_FAILED(rv)) {
|
||||
// release the transport so that we don't think we're in progress
|
||||
mFileTransport = nsnull;
|
||||
if (mUploadStream) {
|
||||
// open output stream for "uploading"
|
||||
nsCOMPtr<nsIOutputStream> fileOut;
|
||||
rv = fileTransport->OpenOutputStream(0, PRUint32(-1), 0, getter_AddRefs(fileOut));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// write all of mUploadStream to fileOut before returning
|
||||
while (mUploadStreamLength) {
|
||||
PRUint32 bytesWritten = 0;
|
||||
|
||||
rv = fileOut->WriteFrom(mUploadStream, mUploadStreamLength, &bytesWritten);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (bytesWritten == 0) {
|
||||
NS_WARNING("wrote zero bytes");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
mUploadStreamLength -= bytesWritten;
|
||||
}
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// return empty stream to caller...
|
||||
nsCOMPtr<nsISupports> emptyIn;
|
||||
rv = NS_NewByteInputStream(getter_AddRefs(emptyIn), "", 0);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = CallQueryInterface(emptyIn, result);
|
||||
}
|
||||
else
|
||||
rv = fileTransport->OpenInputStream(0, PRUint32(-1), 0, result);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -296,9 +329,10 @@ nsFileChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctxt)
|
|||
#endif
|
||||
|
||||
if (mFileTransport)
|
||||
return NS_ERROR_IN_PROGRESS;
|
||||
return NS_ERROR_IN_PROGRESS; // AsyncOpen in progress
|
||||
|
||||
rv = EnsureTransport();
|
||||
nsCOMPtr<nsITransport> fileTransport;
|
||||
rv = GetFileTransport(getter_AddRefs(fileTransport));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
|
@ -310,20 +344,27 @@ nsFileChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctxt)
|
|||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
rv = mFileTransport->AsyncRead(this, ctxt, 0, PRUint32(-1), 0,
|
||||
getter_AddRefs(mCurrentRequest));
|
||||
nsCOMPtr<nsIRequest> request;
|
||||
if (mUploadStream)
|
||||
rv = fileTransport->AsyncWrite(this, ctxt, 0, PRUint32(-1), 0,
|
||||
getter_AddRefs(request));
|
||||
else
|
||||
rv = fileTransport->AsyncRead(this, ctxt, 0, PRUint32(-1), 0,
|
||||
getter_AddRefs(request));
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
if (mLoadGroup) {
|
||||
(void) mLoadGroup->RemoveRequest(this, ctxt, rv);
|
||||
}
|
||||
// release the transport so that we don't think we're in progress
|
||||
mFileTransport = nsnull;
|
||||
mCurrentRequest = nsnull;
|
||||
}
|
||||
if (mLoadGroup)
|
||||
mLoadGroup->RemoveRequest(this, ctxt, rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
// remember the transport and request; these will be released when
|
||||
// OnStopRequest is called.
|
||||
mFileTransport = fileTransport;
|
||||
mCurrentRequest = request;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFileChannel::GetLoadFlags(PRUint32 *aLoadFlags)
|
||||
{
|
||||
|
@ -472,7 +513,7 @@ nsFileChannel::GetSecurityInfo(nsISupports * *aSecurityInfo)
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsIStreamListener methods:
|
||||
// nsIRequestObserver methods:
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -507,29 +548,35 @@ NS_IMETHODIMP
|
|||
nsFileChannel::OnStopRequest(nsIRequest* request, nsISupports* context,
|
||||
nsresult aStatus)
|
||||
{
|
||||
// unconditionally inherit the status of the file transport
|
||||
// if we were canceled, we should not overwrite the cancelation status
|
||||
// since that could break security assumptions made in upper layers.
|
||||
if (NS_SUCCEEDED(mStatus))
|
||||
mStatus = aStatus;
|
||||
|
||||
#ifdef DEBUG
|
||||
NS_ASSERTION(mInitiator == PR_CurrentThread(),
|
||||
"wrong thread calling this routine");
|
||||
#endif
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
if (mRealListener) {
|
||||
rv = mRealListener->OnStopRequest(this, context, aStatus);
|
||||
}
|
||||
NS_ENSURE_TRUE(mRealListener, NS_ERROR_UNEXPECTED);
|
||||
|
||||
if (mLoadGroup) {
|
||||
mLoadGroup->RemoveRequest(this, context, aStatus);
|
||||
}
|
||||
// no point to capturing the return value of OnStopRequest
|
||||
mRealListener->OnStopRequest(this, context, mStatus);
|
||||
|
||||
if (mLoadGroup)
|
||||
mLoadGroup->RemoveRequest(this, context, mStatus);
|
||||
|
||||
// Release the reference to the consumer stream listener...
|
||||
mRealListener = 0;
|
||||
mFileTransport = 0;
|
||||
mCurrentRequest = 0;
|
||||
return rv;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsIStreamListener methods:
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFileChannel::OnDataAvailable(nsIRequest* request, nsISupports* context,
|
||||
nsIInputStream *aIStream, PRUint32 aSourceOffset,
|
||||
|
@ -540,12 +587,44 @@ nsFileChannel::OnDataAvailable(nsIRequest* request, nsISupports* context,
|
|||
"wrong thread calling this routine");
|
||||
#endif
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
if (mRealListener) {
|
||||
rv = mRealListener->OnDataAvailable(this, context, aIStream,
|
||||
NS_ENSURE_TRUE(mRealListener, NS_ERROR_UNEXPECTED);
|
||||
|
||||
return mRealListener->OnDataAvailable(this, context, aIStream,
|
||||
aSourceOffset, aLength);
|
||||
}
|
||||
return rv;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsIStreamProvider methods:
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFileChannel::OnDataWritable(nsIRequest *aRequest, nsISupports *aContext,
|
||||
nsIOutputStream *aOStream, PRUint32 aOffset,
|
||||
PRUint32 aLength)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
NS_ASSERTION(mInitiator == PR_CurrentThread(),
|
||||
"wrong thread calling this routine");
|
||||
#endif
|
||||
|
||||
NS_ENSURE_TRUE(mUploadStream, NS_ERROR_UNEXPECTED);
|
||||
|
||||
if (mUploadStreamLength == 0)
|
||||
return NS_BASE_STREAM_CLOSED; // done writing
|
||||
|
||||
PRUint32 bytesToWrite = PR_MIN(mUploadStreamLength, aLength);
|
||||
PRUint32 bytesWritten = 0;
|
||||
|
||||
nsresult rv = aOStream->WriteFrom(mUploadStream, bytesToWrite, &bytesWritten);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (bytesWritten == 0) {
|
||||
NS_WARNING("wrote zero bytes");
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
|
||||
mUploadStreamLength -= bytesWritten;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -656,3 +735,52 @@ nsFileChannel::SetPermissions(PRInt32 aPermissions)
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// From nsIUploadChannel
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFileChannel::SetUploadStream(nsIInputStream *aStream,
|
||||
const char *aContentType,
|
||||
PRInt32 aContentLength)
|
||||
{
|
||||
if (mFileTransport)
|
||||
return NS_ERROR_IN_PROGRESS; // channel is pending, so we can't add
|
||||
// or remove an upload stream.
|
||||
|
||||
// ignore aContentType argument; query the stream for its length if not
|
||||
// specified (allow upload of a partial stream).
|
||||
|
||||
if (aContentLength < 0) {
|
||||
nsresult rv = aStream->Available(&mUploadStreamLength);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
else
|
||||
mUploadStreamLength = aContentLength;
|
||||
mUploadStream = aStream;
|
||||
|
||||
if (mUploadStream) {
|
||||
// configure mIOFlags for writing
|
||||
mIOFlags = PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE;
|
||||
if (mPerm == -1)
|
||||
mPerm = PR_IRUSR | PR_IWUSR; // pick something reasonable
|
||||
}
|
||||
else {
|
||||
// configure mIOFlags for reading
|
||||
mIOFlags = PR_RDONLY;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFileChannel::SetUploadFile(nsIFile *aFile,
|
||||
const char *aContentType,
|
||||
PRInt32 aContentLength)
|
||||
{
|
||||
nsCOMPtr<nsIInputStream> inStream;
|
||||
nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(inStream), aFile);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
return SetUploadStream(inStream, aContentType, aContentLength);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include "nsIInterfaceRequestorUtils.h"
|
||||
#include "nsILoadGroup.h"
|
||||
#include "nsIStreamListener.h"
|
||||
#include "nsIStreamProvider.h"
|
||||
#include "nsFileSpec.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
@ -54,12 +55,16 @@
|
|||
#include "nsCOMPtr.h"
|
||||
#include "nsIFile.h" /* Solaris/gcc needed this here. */
|
||||
#include "nsIFileChannel.h"
|
||||
#include "nsIUploadChannel.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsIProgressEventSink.h"
|
||||
#include "nsITransport.h"
|
||||
|
||||
class nsFileChannel : public nsIFileChannel,
|
||||
public nsIUploadChannel,
|
||||
public nsIInterfaceRequestor,
|
||||
public nsIStreamListener,
|
||||
public nsIStreamProvider,
|
||||
public nsIProgressEventSink
|
||||
{
|
||||
public:
|
||||
|
@ -67,9 +72,11 @@ public:
|
|||
NS_DECL_NSIREQUEST
|
||||
NS_DECL_NSICHANNEL
|
||||
NS_DECL_NSIFILECHANNEL
|
||||
NS_DECL_NSIUPLOADCHANNEL
|
||||
NS_DECL_NSIINTERFACEREQUESTOR
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
NS_DECL_NSISTREAMLISTENER
|
||||
NS_DECL_NSISTREAMPROVIDER
|
||||
NS_DECL_NSIPROGRESSEVENTSINK
|
||||
|
||||
nsFileChannel();
|
||||
|
@ -81,7 +88,7 @@ public:
|
|||
Create(nsISupports* aOuter, const nsIID& aIID, void* *aResult);
|
||||
|
||||
nsresult Init(PRInt32 ioFlags, PRInt32 perm, nsIURI* uri, PRBool generateHTMLDirs = PR_FALSE);
|
||||
nsresult EnsureTransport();
|
||||
nsresult GetFileTransport(nsITransport **);
|
||||
nsresult SetStreamConverter();
|
||||
|
||||
protected:
|
||||
|
@ -105,6 +112,8 @@ protected:
|
|||
nsresult mStatus;
|
||||
nsCOMPtr<nsIProgressEventSink> mProgress;
|
||||
nsCOMPtr<nsIRequest> mCurrentRequest;
|
||||
nsCOMPtr<nsIInputStream> mUploadStream;
|
||||
PRUint32 mUploadStreamLength;
|
||||
PRBool mGenerateHTMLDirs;
|
||||
|
||||
#ifdef DEBUG
|
||||
|
|
Загрузка…
Ссылка в новой задаче