зеркало из https://github.com/mozilla/pjs.git
Bug 70707. Pulled generic transport implementation out of new memory cache
and created netwerk/base/src/nsStorageTransport.{h,cpp}
This commit is contained in:
Родитель
e06eff1a36
Коммит
18d9e7803f
|
@ -59,6 +59,7 @@ CPPSRCS = \
|
|||
nsProtocolProxyService.cpp \
|
||||
nsProxyAutoConfigUtils.cpp \
|
||||
nsAsyncStreamListener.cpp \
|
||||
nsStorageTransport.cpp \
|
||||
$(NULL)
|
||||
|
||||
# we don't want the shared lib, but we want to force the creation of a
|
||||
|
|
|
@ -55,6 +55,7 @@ CPP_OBJS = \
|
|||
.\$(OBJDIR)\nsProtocolProxyService.obj \
|
||||
.\$(OBJDIR)\nsProxyAutoConfigUtils.obj \
|
||||
.\$(OBJDIR)\nsAsyncStreamListener.obj \
|
||||
.\$(OBJDIR)\nsStorageTransport.obj \
|
||||
$(NULL)
|
||||
|
||||
INCS = $(INCS) \
|
||||
|
|
|
@ -0,0 +1,858 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* 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 nsStorageTransport.cpp, released February 26, 2001.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 2001 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@netscape.com> (original author)
|
||||
*/
|
||||
|
||||
#include "nsStorageTransport.h"
|
||||
#include "nsIProxyObjectManager.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsCRT.h"
|
||||
#include "prmem.h"
|
||||
#include "netCore.h"
|
||||
|
||||
#define MAX_IO_CHUNK 8192 // maximum count reported per OnDataAvailable
|
||||
#define MAX_COUNT ((PRUint32) -1)
|
||||
|
||||
static NS_DEFINE_CID(kProxyObjectManagerCID, NS_PROXYEVENT_MANAGER_CID);
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// helper functions...
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
static NS_METHOD
|
||||
nsWriteToBuffer(nsIInputStream *aInput,
|
||||
void *aClosure,
|
||||
const char *aFromBuf,
|
||||
PRUint32 aOffset,
|
||||
PRUint32 aCount,
|
||||
PRUint32 *aWriteCount)
|
||||
{
|
||||
char *toBuf = NS_REINTERPRET_CAST(char *, aClosure);
|
||||
nsCRT::memcpy(toBuf + aOffset, aFromBuf, aCount);
|
||||
*aWriteCount = aCount;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static NS_METHOD
|
||||
nsReadFromBuffer(nsIOutputStream *aOutput,
|
||||
void *aClosure,
|
||||
char *aToBuf,
|
||||
PRUint32 aOffset,
|
||||
PRUint32 aCount,
|
||||
PRUint32 *aReadCount)
|
||||
{
|
||||
const char *fromBuf = NS_REINTERPRET_CAST(const char *, aClosure);
|
||||
nsCRT::memcpy(aToBuf, fromBuf + aOffset, aCount);
|
||||
*aReadCount = aCount;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static NS_METHOD
|
||||
nsReadFromInputStream(nsIOutputStream *aOutput,
|
||||
void *aClosure,
|
||||
char *aToBuf,
|
||||
PRUint32 aOffset,
|
||||
PRUint32 aCount,
|
||||
PRUint32 *aReadCount)
|
||||
{
|
||||
nsIInputStream *fromStream = NS_REINTERPRET_CAST(nsIInputStream *, aClosure);
|
||||
return fromStream->Read(aToBuf, aCount, aReadCount);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// nsStorageTransport
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
nsStorageTransport::nsStorageTransport()
|
||||
: mOutputStream(nsnull)
|
||||
, mSegmentSize(DEFAULT_SEGMENT_SIZE)
|
||||
, mMaxSize(DEFAULT_BUFFER_SIZE)
|
||||
, mSegments(nsnull)
|
||||
, mWriteSegment(nsnull)
|
||||
, mWriteCursor(0)
|
||||
{
|
||||
NS_INIT_ISUPPORTS();
|
||||
|
||||
PR_INIT_CLIST(&mReadRequests);
|
||||
PR_INIT_CLIST(&mInputStreams);
|
||||
}
|
||||
|
||||
nsStorageTransport::~nsStorageTransport()
|
||||
{
|
||||
if (mOutputStream)
|
||||
CloseOutputStream();
|
||||
|
||||
DeleteAllSegments();
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsStorageTransport::Init(PRUint32 aBufSegmentSize, PRUint32 aBufMaxSize)
|
||||
{
|
||||
mSegmentSize = aBufSegmentSize;
|
||||
mMaxSize = aBufMaxSize;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsStorageTransport::GetReadSegment(PRUint32 aOffset, char **aPtr, PRUint32 *aCount)
|
||||
{
|
||||
*aPtr = nsnull;
|
||||
*aCount = 0;
|
||||
|
||||
if (aOffset < mWriteCursor) {
|
||||
PRUint32 index = aOffset / mSegmentSize;
|
||||
nsSegment *s = GetNthSegment(index);
|
||||
if (s) {
|
||||
PRUint32 offset = aOffset % mSegmentSize;
|
||||
*aPtr = s->Data() + offset;
|
||||
*aCount = mSegmentSize - offset;
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsStorageTransport::GetWriteSegment(char **aPtr, PRUint32 *aCount)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aPtr);
|
||||
NS_ENSURE_ARG_POINTER(aCount);
|
||||
|
||||
if (mWriteSegment) {
|
||||
PRUint32 offset = mWriteCursor % mSegmentSize;
|
||||
*aPtr = mWriteSegment->Data() + offset;
|
||||
*aCount = mSegmentSize - offset;
|
||||
return NS_OK;
|
||||
}
|
||||
else {
|
||||
// add a new segment for writing and redo...
|
||||
nsresult rv = AddWriteSegment();
|
||||
return NS_FAILED(rv) ? rv : GetWriteSegment(aPtr, aCount);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsStorageTransport::AddToBytesWritten(PRUint32 aCount)
|
||||
{
|
||||
// advance write cursor
|
||||
mWriteCursor += aCount;
|
||||
|
||||
// clear write segment if we have written to the end
|
||||
if (!(mWriteCursor % mSegmentSize))
|
||||
mWriteSegment = nsnull;
|
||||
|
||||
// process waiting readers
|
||||
PRCList *link = PR_LIST_HEAD(&mReadRequests);
|
||||
for (; link != &mReadRequests; link = PR_NEXT_LINK(link)) {
|
||||
nsReadRequest *req = NS_STATIC_CAST(nsReadRequest *, link);
|
||||
if (req->IsWaitingForWrite())
|
||||
req->Process();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsStorageTransport::CloseOutputStream()
|
||||
{
|
||||
if (mOutputStream) {
|
||||
mOutputStream->SetTransport(nsnull);
|
||||
mOutputStream = nsnull;
|
||||
|
||||
// XXX wake up blocked reads
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsStorageTransport::ReadRequestCompleted(nsReadRequest *aReader)
|
||||
{
|
||||
// remove the reader from the list of readers
|
||||
PR_REMOVE_AND_INIT_LINK(aReader);
|
||||
aReader->SetTransport(nsnull);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsStorageTransport::Available(PRUint32 aStartingFrom, PRUint32 *aCount)
|
||||
{
|
||||
*aCount = mWriteCursor - aStartingFrom;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsStorageTransport::AddWriteSegment()
|
||||
{
|
||||
NS_ASSERTION(mWriteSegment == nsnull, "write segment is non-null");
|
||||
|
||||
mWriteSegment = (nsSegment *) PR_Malloc(sizeof(nsSegment) + mSegmentSize);
|
||||
if (!mWriteSegment)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
mWriteSegment->next = nsnull;
|
||||
|
||||
AppendSegment(mWriteSegment);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsStorageTransport::AppendSegment(nsSegment *aSegment)
|
||||
{
|
||||
if (!mSegments)
|
||||
mSegments = aSegment;
|
||||
else {
|
||||
nsSegment *s = mSegments;
|
||||
for (; s && s->next; s = s->next);
|
||||
s->next = aSegment;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsStorageTransport::DeleteSegments(nsSegment *segments)
|
||||
{
|
||||
while (segments) {
|
||||
nsSegment *s = segments->next;
|
||||
PR_Free(segments);
|
||||
segments = s;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsStorageTransport::TruncateTo(PRUint32 aOffset)
|
||||
{
|
||||
if (aOffset < mWriteCursor) {
|
||||
if (aOffset == 0) {
|
||||
DeleteSegments(mSegments);
|
||||
mSegments = nsnull;
|
||||
mWriteSegment = nsnull;
|
||||
}
|
||||
else {
|
||||
PRUint32 offset = 0;
|
||||
nsSegment *s = mSegments;
|
||||
for (; s; s = s->next) {
|
||||
if ((offset + mSegmentSize) > aOffset)
|
||||
break;
|
||||
offset += mSegmentSize;
|
||||
}
|
||||
// "s" now points to the last segment that we should keep
|
||||
if (s->next) {
|
||||
DeleteSegments(s->next);
|
||||
s->next = nsnull;
|
||||
}
|
||||
mWriteSegment = s;
|
||||
}
|
||||
}
|
||||
mWriteCursor = aOffset;
|
||||
}
|
||||
|
||||
nsStorageTransport::nsSegment *
|
||||
nsStorageTransport::GetNthSegment(PRUint32 index)
|
||||
{
|
||||
nsSegment *s = mSegments;
|
||||
for (; s && index; s = s->next, --index);
|
||||
return s;
|
||||
}
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(nsStorageTransport,
|
||||
nsITransport)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStorageTransport::GetSecurityInfo(nsISupports **aSecurityInfo)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aSecurityInfo);
|
||||
*aSecurityInfo = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStorageTransport::GetProgressEventSink(nsIProgressEventSink **aSink)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aSink);
|
||||
*aSink = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStorageTransport::SetProgressEventSink(nsIProgressEventSink *aSink)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStorageTransport::OpenInputStream(PRUint32 aOffset,
|
||||
PRUint32 aCount,
|
||||
PRUint32 aFlags,
|
||||
nsIInputStream **aInput)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStorageTransport::OpenOutputStream(PRUint32 aOffset,
|
||||
PRUint32 aCount,
|
||||
PRUint32 aFlags,
|
||||
nsIOutputStream **aOutput)
|
||||
{
|
||||
NS_ENSURE_TRUE(!mOutputStream, NS_ERROR_IN_PROGRESS);
|
||||
|
||||
if (!PR_CLIST_IS_EMPTY(&mInputStreams) || !PR_CLIST_IS_EMPTY(&mReadRequests)) {
|
||||
NS_NOTREACHED("Attempt to open a memory cache output stream while "
|
||||
"read is in progress!");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_NEWXPCOM(mOutputStream, nsOutputStream);
|
||||
if (!mOutputStream)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
mOutputStream->SetTransport(this);
|
||||
mOutputStream->SetTransferCount(aCount);
|
||||
|
||||
TruncateTo(aOffset);
|
||||
|
||||
NS_ADDREF(*aOutput = mOutputStream);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStorageTransport::AsyncRead(nsIStreamListener *aListener,
|
||||
nsISupports *aContext,
|
||||
PRUint32 aOffset,
|
||||
PRUint32 aCount,
|
||||
PRUint32 aFlags,
|
||||
nsIRequest **aRequest)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
nsReadRequest *reader;
|
||||
NS_NEWXPCOM(reader, nsReadRequest);
|
||||
if (!reader)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
reader->SetTransport(this);
|
||||
reader->SetTransferOffset(aOffset);
|
||||
reader->SetTransferCount(aCount);
|
||||
|
||||
// append the read request to the list of existing read requests.
|
||||
// it is important to do this before the possibility of failure.
|
||||
PR_APPEND_LINK(reader, &mReadRequests);
|
||||
|
||||
rv = reader->SetListener(aListener, aContext);
|
||||
if (NS_FAILED(rv)) goto error;
|
||||
|
||||
rv = reader->Process();
|
||||
if (NS_FAILED(rv)) goto error;
|
||||
|
||||
NS_ADDREF(*aRequest = reader);
|
||||
return NS_OK;
|
||||
|
||||
error:
|
||||
NS_DELETEXPCOM(reader);
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStorageTransport::AsyncWrite(nsIStreamProvider *aProvider,
|
||||
nsISupports *aContext,
|
||||
PRUint32 aOffset,
|
||||
PRUint32 aCount,
|
||||
PRUint32 aFlags,
|
||||
nsIRequest **aRequest)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// nsStorageTransport::nsReadRequest
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
nsStorageTransport::nsReadRequest::nsReadRequest()
|
||||
: mTransport(nsnull)
|
||||
, mTransferOffset(0)
|
||||
, mTransferCount(MAX_COUNT)
|
||||
, mStatus(NS_OK)
|
||||
, mCanceled(PR_FALSE)
|
||||
, mOnStartFired(PR_FALSE)
|
||||
, mWaitingForWrite(PR_FALSE)
|
||||
{
|
||||
NS_INIT_ISUPPORTS();
|
||||
PR_INIT_CLIST(this);
|
||||
}
|
||||
|
||||
nsStorageTransport::nsReadRequest::~nsReadRequest()
|
||||
{
|
||||
if (mTransport)
|
||||
mTransport->ReadRequestCompleted(this);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsStorageTransport::nsReadRequest::SetListener(nsIStreamListener *aListener,
|
||||
nsISupports *aListenerContext)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
mListener = aListener;
|
||||
mListenerContext = aListenerContext;
|
||||
|
||||
// We proxy listener events to ourself and then forward them onto
|
||||
// the real listener (on the listener's thread).
|
||||
|
||||
nsCOMPtr<nsIProxyObjectManager> proxyMgr =
|
||||
do_GetService(kProxyObjectManagerCID, &rv);
|
||||
|
||||
if (NS_SUCCEEDED(rv))
|
||||
rv = proxyMgr->GetProxyForObject(NS_CURRENT_EVENTQ,
|
||||
NS_GET_IID(nsIStreamListener),
|
||||
NS_STATIC_CAST(nsIStreamListener *, this),
|
||||
PROXY_ASYNC | PROXY_ALWAYS,
|
||||
getter_AddRefs(mListenerProxy));
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsStorageTransport::nsReadRequest::Process()
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
// this method must always be called on the client's thread
|
||||
|
||||
NS_ENSURE_TRUE(mTransport, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
// always clear this flag initially
|
||||
mWaitingForWrite = PR_FALSE;
|
||||
|
||||
PRUint32 count = 0;
|
||||
|
||||
rv = mTransport->Available(mTransferOffset, &count);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (!mOnStartFired) {
|
||||
// no need to proxy this callback
|
||||
(void) mListener->OnStartRequest(this, mListenerContext);
|
||||
mOnStartFired = PR_TRUE;
|
||||
}
|
||||
|
||||
count = PR_MIN(count, mTransferCount);
|
||||
|
||||
if (count) {
|
||||
count = PR_MIN(count, MAX_IO_CHUNK);
|
||||
|
||||
// proxy this callback
|
||||
(void) mListenerProxy->OnDataAvailable(this, mListenerContext,
|
||||
this,
|
||||
mTransferOffset,
|
||||
count);
|
||||
}
|
||||
else if ((mTransferCount == 0) || !mTransport->HasWriter()) {
|
||||
|
||||
// there is no more data to read and there is no writer, so we
|
||||
// must stop this read request.
|
||||
|
||||
// first let the transport know that we are done
|
||||
mTransport->ReadRequestCompleted(this);
|
||||
|
||||
// no need to proxy this callback
|
||||
(void) mListener->OnStopRequest(this, mListenerContext, mStatus, nsnull);
|
||||
}
|
||||
else
|
||||
mWaitingForWrite = PR_TRUE;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS5(nsStorageTransport::nsReadRequest,
|
||||
nsITransportRequest,
|
||||
nsIRequest,
|
||||
nsIStreamListener,
|
||||
nsIStreamObserver,
|
||||
nsIInputStream)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStorageTransport::nsReadRequest::GetTransport(nsITransport **aTransport)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aTransport);
|
||||
NS_IF_ADDREF(*aTransport = mTransport);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStorageTransport::nsReadRequest::GetName(PRUnichar **aName)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aName);
|
||||
*aName = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStorageTransport::nsReadRequest::IsPending(PRBool *aResult)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aResult);
|
||||
*aResult = (mTransport ? PR_TRUE : PR_FALSE);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStorageTransport::nsReadRequest::GetStatus(nsresult *aStatus)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aStatus);
|
||||
*aStatus = mStatus;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStorageTransport::nsReadRequest::Cancel(nsresult aStatus)
|
||||
{
|
||||
mCanceled = PR_TRUE;
|
||||
mStatus = aStatus;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStorageTransport::nsReadRequest::Suspend()
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStorageTransport::nsReadRequest::Resume()
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStorageTransport::nsReadRequest::OnStartRequest(nsIRequest *aRequest,
|
||||
nsISupports *aContext)
|
||||
{
|
||||
NS_NOTREACHED("nsStorageTransport::nsReadRequest::OnStartRequest");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStorageTransport::nsReadRequest::OnStopRequest(nsIRequest *aRequest,
|
||||
nsISupports *aContext,
|
||||
nsresult aStatus,
|
||||
const PRUnichar *aStatusText)
|
||||
{
|
||||
NS_NOTREACHED("nsStorageTransport::nsReadRequest::OnStopRequest");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStorageTransport::nsReadRequest::OnDataAvailable(nsIRequest *aRequest,
|
||||
nsISupports *aContext,
|
||||
nsIInputStream *aInput,
|
||||
PRUint32 aOffset,
|
||||
PRUint32 aCount)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
rv = mListener->OnDataAvailable(aRequest, aContext, aInput, aOffset, aCount);
|
||||
|
||||
NS_ASSERTION(rv != NS_BASE_STREAM_WOULD_BLOCK, "not implemented");
|
||||
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// post the next message...
|
||||
return Process();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStorageTransport::nsReadRequest::Close()
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStorageTransport::nsReadRequest::Available(PRUint32 *aCount)
|
||||
{
|
||||
NS_ENSURE_TRUE(mTransport, NS_BASE_STREAM_CLOSED);
|
||||
return mTransport->Available(mTransferOffset, aCount);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStorageTransport::nsReadRequest::Read(char *aBuf, PRUint32 aCount, PRUint32 *aBytesRead)
|
||||
{
|
||||
return ReadSegments(nsWriteToBuffer, aBuf, aCount, aBytesRead);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStorageTransport::nsReadRequest::ReadSegments(nsWriteSegmentFun aWriter,
|
||||
void *aClosure,
|
||||
PRUint32 aCount,
|
||||
PRUint32 *aBytesRead)
|
||||
{
|
||||
NS_ENSURE_TRUE(mTransport, NS_BASE_STREAM_CLOSED);
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
*aBytesRead = 0;
|
||||
|
||||
// limit the number of bytes that can be read
|
||||
aCount = PR_MIN(aCount, mTransferCount);
|
||||
|
||||
while (aCount) {
|
||||
char *ptr = nsnull;
|
||||
PRUint32 count = 0;
|
||||
|
||||
rv = mTransport->GetReadSegment(mTransferOffset, &ptr, &count);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
count = PR_MIN(count, aCount);
|
||||
|
||||
while (count) {
|
||||
PRUint32 writeCount = 0;
|
||||
|
||||
rv = aWriter(this, aClosure, ptr, *aBytesRead, count, &writeCount);
|
||||
|
||||
if (rv == NS_BASE_STREAM_WOULD_BLOCK)
|
||||
return NS_OK; // mask this error
|
||||
else if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
ptr += writeCount;
|
||||
count -= writeCount;
|
||||
aCount -= writeCount;
|
||||
*aBytesRead += writeCount;
|
||||
|
||||
// decrement the total number of bytes remaining to be read
|
||||
mTransferCount -= writeCount;
|
||||
mTransferOffset += writeCount;
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStorageTransport::nsReadRequest::GetNonBlocking(PRBool *aNonBlocking)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aNonBlocking);
|
||||
*aNonBlocking = PR_FALSE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStorageTransport::nsReadRequest::GetObserver(nsIInputStreamObserver **aObserver)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aObserver);
|
||||
*aObserver = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStorageTransport::nsReadRequest::SetObserver(nsIInputStreamObserver *aObserver)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// nsStorageTransport::nsBlockingStream
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
nsStorageTransport::nsBlockingStream::nsBlockingStream()
|
||||
: mTransport(nsnull)
|
||||
, mTransferCount(MAX_COUNT)
|
||||
{
|
||||
}
|
||||
|
||||
nsStorageTransport::nsBlockingStream::~nsBlockingStream()
|
||||
{
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// nsStorageTransport::nsInputStream
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
nsStorageTransport::nsInputStream::nsInputStream()
|
||||
: mOffset(0)
|
||||
{
|
||||
NS_INIT_ISUPPORTS();
|
||||
}
|
||||
|
||||
nsStorageTransport::nsInputStream::~nsInputStream()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(nsStorageTransport::nsInputStream,
|
||||
nsIInputStream)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStorageTransport::nsInputStream::Close()
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStorageTransport::nsInputStream::Available(PRUint32 *aCount)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStorageTransport::nsInputStream::Read(char *aBuf, PRUint32 aCount, PRUint32 *aBytesRead)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStorageTransport::nsInputStream::ReadSegments(nsWriteSegmentFun aWriter,
|
||||
void *aClosure,
|
||||
PRUint32 aCount,
|
||||
PRUint32 *aBytesRead)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStorageTransport::nsInputStream::GetNonBlocking(PRBool *aNonBlocking)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aNonBlocking);
|
||||
*aNonBlocking = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStorageTransport::nsInputStream::GetObserver(nsIInputStreamObserver **aObserver)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aObserver);
|
||||
*aObserver = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStorageTransport::nsInputStream::SetObserver(nsIInputStreamObserver *aObserver)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// nsStorageTransport::nsOutputStream
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
nsStorageTransport::nsOutputStream::nsOutputStream()
|
||||
{
|
||||
NS_INIT_ISUPPORTS();
|
||||
}
|
||||
|
||||
nsStorageTransport::nsOutputStream::~nsOutputStream()
|
||||
{
|
||||
if (mTransport)
|
||||
mTransport->CloseOutputStream();
|
||||
}
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(nsStorageTransport::nsOutputStream,
|
||||
nsIOutputStream)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStorageTransport::nsOutputStream::Close()
|
||||
{
|
||||
NS_ENSURE_TRUE(mTransport, NS_BASE_STREAM_CLOSED);
|
||||
return mTransport->CloseOutputStream();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStorageTransport::nsOutputStream::Flush()
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStorageTransport::nsOutputStream::Write(const char *aBuf,
|
||||
PRUint32 aCount,
|
||||
PRUint32 *aBytesWritten)
|
||||
{
|
||||
return WriteSegments(nsReadFromBuffer, (void *) aBuf, aCount, aBytesWritten);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStorageTransport::nsOutputStream::WriteFrom(nsIInputStream *aInput,
|
||||
PRUint32 aCount,
|
||||
PRUint32 *aBytesWritten)
|
||||
{
|
||||
return WriteSegments(nsReadFromInputStream, aInput, aCount, aBytesWritten);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStorageTransport::nsOutputStream::WriteSegments(nsReadSegmentFun aReader,
|
||||
void *aClosure,
|
||||
PRUint32 aCount,
|
||||
PRUint32 *aBytesWritten)
|
||||
{
|
||||
NS_ENSURE_TRUE(mTransport, NS_BASE_STREAM_CLOSED);
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
*aBytesWritten = 0;
|
||||
|
||||
// XXX need to honor mTransferCount
|
||||
|
||||
while (aCount) {
|
||||
char *ptr;
|
||||
PRUint32 count;
|
||||
|
||||
rv = mTransport->GetWriteSegment(&ptr, &count);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
count = PR_MIN(count, aCount);
|
||||
|
||||
while (count) {
|
||||
PRUint32 readCount;
|
||||
|
||||
rv = aReader(this, aClosure, ptr, *aBytesWritten, count, &readCount);
|
||||
|
||||
if (NS_FAILED(rv))
|
||||
break;
|
||||
|
||||
count -= readCount;
|
||||
aCount -= readCount;
|
||||
*aBytesWritten += readCount;
|
||||
|
||||
rv = mTransport->AddToBytesWritten(readCount);
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStorageTransport::nsOutputStream::GetNonBlocking(PRBool *aNonBlocking)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aNonBlocking);
|
||||
*aNonBlocking = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStorageTransport::nsOutputStream::SetNonBlocking(PRBool aNonBlocking)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStorageTransport::nsOutputStream::GetObserver(nsIOutputStreamObserver **aObserver)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aObserver);
|
||||
*aObserver = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStorageTransport::nsOutputStream::SetObserver(nsIOutputStreamObserver *aObserver)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
|
@ -0,0 +1,202 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* 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 nsStorageTransport.h, released February 26, 2001.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 2001 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@netscape.com> (original author)
|
||||
*/
|
||||
|
||||
#ifndef nsStorageTransport_h__
|
||||
#define nsStorageTransport_h__
|
||||
|
||||
#include "nsITransport.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsIStreamListener.h"
|
||||
#include "prclist.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
/**
|
||||
* Each "stream-based" memory cache entry has one transport
|
||||
* associated with it. The transport supports multiple
|
||||
* simultaneous read requests and a single write request.
|
||||
*/
|
||||
class nsStorageTransport : public nsITransport
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSITRANSPORT
|
||||
|
||||
enum { DEFAULT_SEGMENT_SIZE = 1024 };
|
||||
enum { DEFAULT_BUFFER_SIZE = 1024 * 1024 };
|
||||
|
||||
nsStorageTransport();
|
||||
virtual ~nsStorageTransport();
|
||||
|
||||
nsresult Init(PRUint32 aSegmentSize = DEFAULT_SEGMENT_SIZE,
|
||||
PRUint32 aBufferSize = DEFAULT_BUFFER_SIZE);
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* The transport request object returned by AsyncRead
|
||||
*/
|
||||
class nsReadRequest : public PRCList
|
||||
, public nsITransportRequest
|
||||
, public nsIStreamListener
|
||||
, public nsIInputStream
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSITRANSPORTREQUEST
|
||||
NS_DECL_NSIREQUEST
|
||||
NS_DECL_NSISTREAMLISTENER
|
||||
NS_DECL_NSISTREAMOBSERVER
|
||||
NS_DECL_NSIINPUTSTREAM
|
||||
|
||||
nsReadRequest();
|
||||
virtual ~nsReadRequest();
|
||||
|
||||
void SetTransport(nsStorageTransport *t) { mTransport = t; }
|
||||
void SetTransferOffset(PRUint32 o) { mTransferOffset = o; }
|
||||
void SetTransferCount(PRUint32 c) { mTransferCount = c; }
|
||||
|
||||
nsresult SetListener(nsIStreamListener *, nsISupports *);
|
||||
nsresult Process();
|
||||
|
||||
PRBool IsWaitingForWrite() { return mWaitingForWrite; }
|
||||
|
||||
private:
|
||||
nsStorageTransport *mTransport; // weak ref
|
||||
PRUint32 mTransferOffset;
|
||||
PRUint32 mTransferCount;
|
||||
nsresult mStatus;
|
||||
nsCOMPtr<nsIStreamListener> mListenerProxy;
|
||||
nsCOMPtr<nsIStreamListener> mListener;
|
||||
nsCOMPtr<nsISupports> mListenerContext;
|
||||
PRPackedBool mCanceled;
|
||||
PRPackedBool mOnStartFired;
|
||||
PRPackedBool mWaitingForWrite;
|
||||
};
|
||||
|
||||
/**
|
||||
* A base class for the blocking streams
|
||||
*/
|
||||
class nsBlockingStream
|
||||
{
|
||||
public:
|
||||
nsBlockingStream();
|
||||
virtual ~nsBlockingStream();
|
||||
|
||||
void SetTransport(nsStorageTransport *t) { mTransport = t; }
|
||||
void SetTransferCount(PRUint32 c) { mTransferCount = c; }
|
||||
|
||||
protected:
|
||||
nsStorageTransport *mTransport; // weak ref
|
||||
PRUint32 mTransferCount;
|
||||
};
|
||||
|
||||
/**
|
||||
* The blocking input stream object returned by OpenInputStream
|
||||
*/
|
||||
class nsInputStream : public PRCList
|
||||
, public nsBlockingStream
|
||||
, public nsIInputStream
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIINPUTSTREAM
|
||||
|
||||
nsInputStream();
|
||||
virtual ~nsInputStream();
|
||||
|
||||
private:
|
||||
PRUint32 mOffset;
|
||||
};
|
||||
|
||||
/**
|
||||
* The blocking output stream object returned by OpenOutputStream
|
||||
*/
|
||||
class nsOutputStream : public nsBlockingStream
|
||||
, public nsIOutputStream
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOUTPUTSTREAM
|
||||
|
||||
nsOutputStream();
|
||||
virtual ~nsOutputStream();
|
||||
};
|
||||
|
||||
friend class nsReadRequest;
|
||||
friend class nsBlockingStream;
|
||||
friend class nsInputStream;
|
||||
friend class nsOutputStream;
|
||||
|
||||
/**
|
||||
* Methods called from the friend classes
|
||||
*/
|
||||
nsresult GetReadSegment(PRUint32 aOffset, char **aPtr, PRUint32 *aCount);
|
||||
nsresult GetWriteSegment(char **aPtr, PRUint32 *aCount);
|
||||
nsresult AddToBytesWritten(PRUint32 aCount);
|
||||
nsresult CloseOutputStream();
|
||||
nsresult ReadRequestCompleted(nsReadRequest *);
|
||||
nsresult Available(PRUint32 aStartingFrom, PRUint32 *aCount);
|
||||
|
||||
PRBool HasWriter() { return (mOutputStream != nsnull); }
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Data is stored in a singly-linked list of segments
|
||||
*/
|
||||
struct nsSegment
|
||||
{
|
||||
struct nsSegment *next;
|
||||
|
||||
char *Data() { return NS_REINTERPRET_CAST(char *, this) + sizeof(*this); }
|
||||
// the data follows this structure (the two are allocated together)
|
||||
};
|
||||
|
||||
/**
|
||||
* Internal methods
|
||||
*/
|
||||
nsresult AddWriteSegment();
|
||||
|
||||
void AppendSegment(nsSegment *);
|
||||
void DeleteSegments(nsSegment *);
|
||||
void DeleteAllSegments() { TruncateTo(0); }
|
||||
void TruncateTo(PRUint32 aOffset);
|
||||
|
||||
nsSegment *GetNthSegment(PRUint32 aIndex);
|
||||
|
||||
private:
|
||||
nsOutputStream *mOutputStream; // weak ref
|
||||
PRCList mInputStreams; // weak ref to objects
|
||||
PRCList mReadRequests; // weak ref to objects
|
||||
|
||||
PRUint32 mSegmentSize;
|
||||
PRUint32 mMaxSize;
|
||||
|
||||
nsSegment *mSegments;
|
||||
|
||||
nsSegment *mWriteSegment;
|
||||
PRUint32 mWriteCursor;
|
||||
};
|
||||
|
||||
#endif
|
Загрузка…
Ссылка в новой задаче