gecko-dev/netwerk/protocol/file/src/nsFileChannel.cpp

539 lines
14 KiB
C++
Raw Normal View History

1999-06-11 01:37:24 +00:00
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape 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/NPL/
1999-06-11 01:37:24 +00:00
*
* 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.
1999-06-11 01:37:24 +00:00
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
1999-06-11 01:37:24 +00:00
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
1999-06-11 01:37:24 +00:00
*/
#include "nsFileChannel.h"
#include "nsIURL.h"
#include "nsXPIDLString.h"
2000-01-24 21:28:28 +00:00
#include "nsIServiceManager.h"
1999-07-03 00:59:51 +00:00
#include "nsIMIMEService.h"
2000-01-24 21:28:28 +00:00
#include "netCore.h"
#include "nsIFileTransportService.h"
2000-01-24 21:28:28 +00:00
#include "nsIFile.h"
#include "nsInt64.h"
#include "nsMimeTypes.h"
2000-01-24 21:28:28 +00:00
#include "prio.h" // Need to pick up def of PR_RDONLY
1999-07-03 00:59:51 +00:00
static NS_DEFINE_CID(kFileTransportServiceCID, NS_FILETRANSPORTSERVICE_CID);
2000-01-24 21:28:28 +00:00
static NS_DEFINE_CID(kMIMEServiceCID, NS_MIMESERVICE_CID);
static NS_DEFINE_CID(kStandardURLCID, NS_STANDARDURL_CID);
1999-06-11 01:37:24 +00:00
////////////////////////////////////////////////////////////////////////////////
nsFileChannel::nsFileChannel()
: mLoadAttributes(LOAD_NORMAL)
1999-06-11 01:37:24 +00:00
{
NS_INIT_REFCNT();
}
nsresult
2000-01-24 21:28:28 +00:00
nsFileChannel::Init(const char* command,
nsIURI* uri,
nsILoadGroup* aLoadGroup,
nsIInterfaceRequestor* notificationCallbacks,
nsLoadFlags loadAttributes,
nsIURI* originalURI,
PRUint32 bufferSegmentSize,
PRUint32 bufferMaxSize)
1999-06-11 01:37:24 +00:00
{
1999-06-12 01:41:12 +00:00
nsresult rv;
mOriginalURI = originalURI ? originalURI : uri;
1999-06-12 01:41:12 +00:00
mURI = uri;
mCommand = nsCRT::strdup(command);
mBufferSegmentSize = bufferSegmentSize;
mBufferMaxSize = bufferMaxSize;
if (mCommand == nsnull)
return NS_ERROR_OUT_OF_MEMORY;
1999-06-12 01:41:12 +00:00
rv = SetLoadAttributes(loadAttributes);
if (NS_FAILED(rv)) return rv;
rv = SetLoadGroup(aLoadGroup);
if (NS_FAILED(rv)) return rv;
rv = SetNotificationCallbacks(notificationCallbacks);
if (NS_FAILED(rv)) return rv;
1999-08-26 22:45:55 +00:00
// if we support the nsIURL interface then use it to get just
// the file path with no other garbage!
2000-01-24 21:28:28 +00:00
nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(mURI, &rv);
if (NS_FAILED(rv)) {
// this URL doesn't denote a file
return NS_ERROR_MALFORMED_URI;
}
1999-06-12 01:41:12 +00:00
2000-01-24 21:28:28 +00:00
rv = fileURL->GetFile(getter_AddRefs(mFile));
if (NS_FAILED(rv)) return rv;
return rv;
1999-06-11 01:37:24 +00:00
}
nsFileChannel::~nsFileChannel()
{
1999-09-20 20:53:13 +00:00
if (mCommand) nsCRT::free(mCommand);
1999-06-11 01:37:24 +00:00
}
NS_IMPL_THREADSAFE_ISUPPORTS5(nsFileChannel,
nsIFileChannel,
nsIChannel,
nsIRequest,
nsIStreamListener,
nsIStreamObserver)
1999-06-11 01:37:24 +00:00
NS_METHOD
nsFileChannel::Create(nsISupports* aOuter, const nsIID& aIID, void* *aResult)
{
nsFileChannel* fc = new nsFileChannel();
if (fc == nsnull)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(fc);
nsresult rv = fc->QueryInterface(aIID, aResult);
NS_RELEASE(fc);
return rv;
}
////////////////////////////////////////////////////////////////////////////////
// From nsIRequest
////////////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP
nsFileChannel::IsPending(PRBool *result)
{
if (mFileTransport)
return mFileTransport->IsPending(result);
*result = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP
nsFileChannel::Cancel()
{
if (mFileTransport)
return mFileTransport->Cancel();
return NS_OK;
}
NS_IMETHODIMP
nsFileChannel::Suspend()
{
if (mFileTransport)
return mFileTransport->Suspend();
return NS_OK;
}
NS_IMETHODIMP
nsFileChannel::Resume()
{
if (mFileTransport)
return mFileTransport->Resume();
return NS_OK;
}
1999-06-11 01:37:24 +00:00
////////////////////////////////////////////////////////////////////////////////
// From nsIChannel
////////////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP
nsFileChannel::GetOriginalURI(nsIURI * *aURI)
{
*aURI = mOriginalURI;
NS_ADDREF(*aURI);
return NS_OK;
}
1999-06-11 01:37:24 +00:00
NS_IMETHODIMP
nsFileChannel::GetURI(nsIURI * *aURI)
{
1999-06-12 01:41:12 +00:00
*aURI = mURI;
NS_ADDREF(*aURI);
1999-06-12 01:41:12 +00:00
return NS_OK;
1999-06-11 01:37:24 +00:00
}
NS_IMETHODIMP
nsFileChannel::OpenInputStream(PRUint32 startPosition, PRInt32 readCount,
nsIInputStream **result)
1999-06-11 01:37:24 +00:00
{
nsresult rv;
if (mFileTransport)
return NS_ERROR_IN_PROGRESS;
NS_WITH_SERVICE(nsIFileTransportService, fts, kFileTransportServiceCID, &rv);
if (NS_FAILED(rv)) return rv;
2000-01-24 21:28:28 +00:00
rv = fts->CreateTransport(mFile, PR_RDONLY, mCommand, 0, 0, getter_AddRefs(mFileTransport));
if (NS_FAILED(rv)) goto done;
rv = mFileTransport->SetNotificationCallbacks(mCallbacks);
if (NS_FAILED(rv)) goto done;
rv = mFileTransport->OpenInputStream(startPosition, readCount, result);
done:
if (NS_FAILED(rv)) {
// release the transport so that we don't think we're in progress
mFileTransport = nsnull;
}
return rv;
}
NS_IMETHODIMP
nsFileChannel::OpenOutputStream(PRUint32 startPosition, nsIOutputStream **result)
{
nsresult rv;
if (mFileTransport)
return NS_ERROR_IN_PROGRESS;
NS_WITH_SERVICE(nsIFileTransportService, fts, kFileTransportServiceCID, &rv);
if (NS_FAILED(rv)) return rv;
2000-01-24 21:28:28 +00:00
rv = fts->CreateTransport(mFile, PR_RDONLY, mCommand, mBufferSegmentSize, mBufferMaxSize,
getter_AddRefs(mFileTransport));
if (NS_FAILED(rv)) goto done;
rv = mFileTransport->SetNotificationCallbacks(mCallbacks);
if (NS_FAILED(rv)) goto done;
rv = mFileTransport->OpenOutputStream(startPosition, result);
done:
if (NS_FAILED(rv)) {
// release the transport so that we don't think we're in progress
mFileTransport = nsnull;
}
return rv;
1999-06-11 01:37:24 +00:00
}
NS_IMETHODIMP
nsFileChannel::AsyncOpen(nsIStreamObserver *observer, nsISupports* ctxt)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
1999-06-11 01:37:24 +00:00
NS_IMETHODIMP
nsFileChannel::AsyncRead(PRUint32 startPosition, PRInt32 readCount,
nsISupports *ctxt,
nsIStreamListener *listener)
1999-06-11 01:37:24 +00:00
{
nsresult rv;
if (mFileTransport)
return NS_ERROR_IN_PROGRESS;
mRealListener = listener;
nsCOMPtr<nsIStreamListener> tempListener = this;
1999-08-26 22:45:55 +00:00
if (mLoadGroup) {
nsCOMPtr<nsILoadGroupListenerFactory> factory;
//
// Create a load group "proxy" listener...
//
rv = mLoadGroup->GetGroupListenerFactory(getter_AddRefs(factory));
if (factory) {
nsIStreamListener *newListener;
rv = factory->CreateLoadGroupListener(mRealListener, &newListener);
if (NS_SUCCEEDED(rv)) {
mRealListener = newListener;
NS_RELEASE(newListener);
}
1999-08-26 22:45:55 +00:00
}
rv = mLoadGroup->AddChannel(this, nsnull);
if (NS_FAILED(rv)) return rv;
}
NS_WITH_SERVICE(nsIFileTransportService, fts, kFileTransportServiceCID, &rv);
if (NS_FAILED(rv)) return rv;
2000-01-24 21:28:28 +00:00
rv = fts->CreateTransport(mFile, PR_RDONLY, mCommand, mBufferSegmentSize, mBufferMaxSize,
getter_AddRefs(mFileTransport));
if (NS_FAILED(rv)) goto done;
rv = mFileTransport->SetNotificationCallbacks(mCallbacks);
if (NS_FAILED(rv)) goto done;
rv = mFileTransport->AsyncRead(startPosition, readCount, ctxt, tempListener);
done:
if (NS_FAILED(rv)) {
// release the transport so that we don't think we're in progress
mFileTransport = nsnull;
}
return rv;
1999-06-11 01:37:24 +00:00
}
NS_IMETHODIMP
nsFileChannel::AsyncWrite(nsIInputStream *fromStream,
PRUint32 startPosition, PRInt32 writeCount,
nsISupports *ctxt,
nsIStreamObserver *observer)
1999-06-11 01:37:24 +00:00
{
nsresult rv;
if (mFileTransport)
return NS_ERROR_IN_PROGRESS;
NS_WITH_SERVICE(nsIFileTransportService, fts, kFileTransportServiceCID, &rv);
if (NS_FAILED(rv)) return rv;
2000-01-24 21:28:28 +00:00
rv = fts->CreateTransport(mFile, PR_RDONLY, mCommand, mBufferSegmentSize, mBufferMaxSize,
getter_AddRefs(mFileTransport));
if (NS_FAILED(rv)) goto done;
rv = mFileTransport->SetNotificationCallbacks(mCallbacks);
if (NS_FAILED(rv)) goto done;
rv = mFileTransport->AsyncWrite(fromStream, startPosition, writeCount, ctxt, observer);
done:
if (NS_FAILED(rv)) {
// release the transport so that we don't think we're in progress
mFileTransport = nsnull;
}
return rv;
1999-06-11 01:37:24 +00:00
}
NS_IMETHODIMP
nsFileChannel::GetLoadAttributes(PRUint32 *aLoadAttributes)
{
*aLoadAttributes = mLoadAttributes;
return NS_OK;
}
NS_IMETHODIMP
nsFileChannel::SetLoadAttributes(PRUint32 aLoadAttributes)
{
mLoadAttributes = aLoadAttributes;
return NS_OK;
}
NS_IMETHODIMP
nsFileChannel::GetContentType(char * *aContentType)
{
nsresult rv = NS_OK;
*aContentType = nsnull;
if (mContentType.IsEmpty()) {
2000-01-24 21:28:28 +00:00
PRBool directory;
mFile->IsDirectory(&directory);
if (directory) {
mContentType = "application/http-index-format";
}
else {
NS_WITH_SERVICE(nsIMIMEService, MIMEService, kMIMEServiceCID, &rv);
if (NS_FAILED(rv)) return rv;
rv = MIMEService->GetTypeFromURI(mURI, aContentType);
if (NS_SUCCEEDED(rv)) {
mContentType = *aContentType;
return rv;
}
}
1999-07-03 00:59:51 +00:00
if (mContentType.IsEmpty()) {
mContentType = UNKNOWN_CONTENT_TYPE;
}
}
*aContentType = mContentType.ToNewCString();
1999-07-03 00:59:51 +00:00
if (!*aContentType) {
return NS_ERROR_OUT_OF_MEMORY;
} else {
return NS_OK;
1999-07-03 00:59:51 +00:00
}
}
NS_IMETHODIMP
nsFileChannel::SetContentType(const char *aContentType)
{
mContentType = aContentType;
return NS_OK;
}
NS_IMETHODIMP
nsFileChannel::GetContentLength(PRInt32 *aContentLength)
{
nsresult rv;
2000-01-24 21:28:28 +00:00
PRInt64 size;
rv = mFile->GetFileSize(&size);
if (NS_SUCCEEDED(rv)) {
2000-01-24 21:28:28 +00:00
*aContentLength = nsInt64(size);
} else {
*aContentLength = -1;
}
return rv;
}
NS_IMETHODIMP
nsFileChannel::GetLoadGroup(nsILoadGroup* *aLoadGroup)
{
*aLoadGroup = mLoadGroup;
NS_IF_ADDREF(*aLoadGroup);
return NS_OK;
}
NS_IMETHODIMP
nsFileChannel::SetLoadGroup(nsILoadGroup* aLoadGroup)
{
mLoadGroup = aLoadGroup;
return NS_OK;
}
NS_IMETHODIMP
nsFileChannel::GetOwner(nsISupports* *aOwner)
{
*aOwner = mOwner.get();
NS_IF_ADDREF(*aOwner);
return NS_OK;
}
NS_IMETHODIMP
nsFileChannel::SetOwner(nsISupports* aOwner)
{
mOwner = aOwner;
return NS_OK;
}
NS_IMETHODIMP
nsFileChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aNotificationCallbacks)
{
*aNotificationCallbacks = mCallbacks.get();
NS_IF_ADDREF(*aNotificationCallbacks);
return NS_OK;
}
NS_IMETHODIMP
nsFileChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aNotificationCallbacks)
{
mCallbacks = aNotificationCallbacks;
return NS_OK;
}
NS_IMETHODIMP
nsFileChannel::GetSecurityInfo(nsISupports * *aSecurityInfo)
{
*aSecurityInfo = nsnull;
return NS_OK;
}
1999-08-26 22:45:55 +00:00
////////////////////////////////////////////////////////////////////////////////
// nsIStreamListener methods:
////////////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP
nsFileChannel::OnStartRequest(nsIChannel* transportChannel, nsISupports* context)
1999-08-26 22:45:55 +00:00
{
NS_ASSERTION(mRealListener, "No listener...");
return mRealListener->OnStartRequest(this, context);
1999-08-26 22:45:55 +00:00
}
NS_IMETHODIMP
nsFileChannel::OnStopRequest(nsIChannel* transportChannel, nsISupports* context,
nsresult aStatus, const PRUnichar* aMsg)
1999-08-26 22:45:55 +00:00
{
nsresult rv;
rv = mRealListener->OnStopRequest(this, context, aStatus, aMsg);
1999-08-26 22:45:55 +00:00
if (mLoadGroup) {
if (NS_SUCCEEDED(rv)) {
mLoadGroup->RemoveChannel(this, context, aStatus, aMsg);
}
1999-08-26 22:45:55 +00:00
}
// Release the reference to the consumer stream listener...
mRealListener = null_nsCOMPtr();
mFileTransport = null_nsCOMPtr();
1999-08-26 22:45:55 +00:00
return rv;
}
NS_IMETHODIMP
nsFileChannel::OnDataAvailable(nsIChannel* transportChannel, nsISupports* context,
nsIInputStream *aIStream, PRUint32 aSourceOffset,
PRUint32 aLength)
{
nsresult rv;
rv = mRealListener->OnDataAvailable(this, context, aIStream,
aSourceOffset, aLength);
//
// If the connection is being aborted cancel the transport. This will
// insure that the transport will go away even if it is blocked waiting
// for the consumer to empty the pipe...
//
if (NS_FAILED(rv)) {
mFileTransport->Cancel();
}
return rv;
}
1999-06-11 01:37:24 +00:00
////////////////////////////////////////////////////////////////////////////////
// From nsIFileChannel
////////////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP
2000-01-24 21:28:28 +00:00
nsFileChannel::Init(nsIFile* file,
PRInt32 mode,
const char* contentType,
PRInt32 contentLength,
nsILoadGroup* aLoadGroup,
nsIInterfaceRequestor* notificationCallbacks,
nsLoadFlags loadAttributes,
nsIURI* originalURI,
PRUint32 bufferSegmentSize,
PRUint32 bufferMaxSize)
{
nsresult rv;
2000-01-24 21:28:28 +00:00
nsCOMPtr<nsIFileURL> url;
rv = nsComponentManager::CreateInstance(kStandardURLCID, nsnull,
NS_GET_IID(nsIFileURL),
getter_AddRefs(url));
if (NS_FAILED(rv)) return rv;
1999-06-11 01:37:24 +00:00
2000-01-24 21:28:28 +00:00
rv = url->SetFile(file);
if (NS_FAILED(rv)) return rv;
2000-01-24 21:28:28 +00:00
return Init("load", // XXX
url,
aLoadGroup,
notificationCallbacks,
loadAttributes,
originalURI,
bufferSegmentSize,
bufferMaxSize);
}
NS_IMETHODIMP
2000-01-24 21:28:28 +00:00
nsFileChannel::GetFile(nsIFile* *result)
{
2000-01-24 21:28:28 +00:00
*result = mFile;
NS_ADDREF(*result);
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
1999-08-25 21:21:22 +00:00
2000-01-24 21:28:28 +00:00