bug 243974 can't download files larger than 4 GB
Also changes nsIResumableChannel to have a resumeAt function, that does not open the channel immediately, and changes its size parameter to a 64 bit integer r=darin sr=bryner git-svn-id: svn://10.0.0.236/trunk@157978 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
@@ -42,27 +42,29 @@ 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.
|
||||
* Prepare this channel for resuming. The request will not start until
|
||||
* asyncOpen or open is called. Calling resumeAt after open or asyncOpen
|
||||
* has been called has undefined behaviour.
|
||||
*
|
||||
* The request given to the nsIStreamListener will be QIable to
|
||||
* nsIResumableInfo
|
||||
* @param startPos the starting offset, in bytes, to use to download
|
||||
* @param entityID information about the file, to match before obtaining
|
||||
* the file. Pass null to use anything.
|
||||
*
|
||||
* During OnStartRequest, this channel will have a status of
|
||||
* NS_ERROR_NOT_RESUMABLE if the file cannot be resumed, eg because the
|
||||
* server doesn't support this. This error may occur even if startPos
|
||||
* is 0, so that the front end can warn the user.
|
||||
* Similarly, the status of this channel during OnStartRequest may be
|
||||
* NS_ERROR_ENTITY_CHANGED, which indicates that the entity has changed,
|
||||
* as indicated by a changed entityID.
|
||||
* In both of these cases, no OnDataAvailable will be called, and
|
||||
* OnStopRequest will immediately follow with the same status code.
|
||||
*/
|
||||
void asyncOpenAt(in nsIStreamListener listener,
|
||||
in nsISupports ctxt,
|
||||
in unsigned long startPos,
|
||||
in nsIResumableEntityID entityID);
|
||||
void resumeAt(in unsigned long long startPos,
|
||||
in nsIResumableEntityID entityID);
|
||||
|
||||
/**
|
||||
* The nsIResumableEntityID for this uri. Available after OnStartRequest
|
||||
* The nsIResumableEntityID for this URI. Available after OnStartRequest.
|
||||
* If this attribute is null, then this load is not resumable.
|
||||
*/
|
||||
readonly attribute nsIResumableEntityID entityID;
|
||||
|
||||
@@ -46,7 +46,7 @@ interface nsIResumableEntityID : nsISupports {
|
||||
* Size of the entity.
|
||||
* @throw NS_ERROR_NOT_AVAILABLE if the size is not known.
|
||||
*/
|
||||
attribute unsigned long size;
|
||||
attribute unsigned long long size;
|
||||
|
||||
/**
|
||||
* An opaque, but human-readable ASCII string specifying the date when the
|
||||
|
||||
@@ -200,11 +200,19 @@
|
||||
|
||||
|
||||
/**
|
||||
* XXX document me
|
||||
* This request is not resumable, but it was tried to resume it, or to
|
||||
* request resume-specific data.
|
||||
*/
|
||||
#define NS_ERROR_NOT_RESUMABLE \
|
||||
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 25)
|
||||
|
||||
/**
|
||||
* It was attempted to resume the request, but the entity has changed in the
|
||||
* meantime.
|
||||
*/
|
||||
#define NS_ERROR_ENTITY_CHANGED \
|
||||
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 32)
|
||||
|
||||
/**
|
||||
* The request failed as a result of a detected redirection loop.
|
||||
*/
|
||||
|
||||
@@ -618,7 +618,7 @@ NS_GetURLSpecFromFile(nsIFile *aFile,
|
||||
|
||||
inline nsresult
|
||||
NS_NewResumableEntityID(nsIResumableEntityID **aRes,
|
||||
PRUint32 size,
|
||||
PRUint64 size,
|
||||
const nsACString &lastModified,
|
||||
const nsACString &entityTag)
|
||||
{
|
||||
|
||||
@@ -65,7 +65,7 @@ static PRLogModuleInfo *gStreamPumpLog = nsnull;
|
||||
nsInputStreamPump::nsInputStreamPump()
|
||||
: mState(STATE_IDLE)
|
||||
, mStreamOffset(0)
|
||||
, mStreamLength(PR_UINT32_MAX)
|
||||
, mStreamLength(LL_MaxInt())
|
||||
, mStatus(NS_OK)
|
||||
, mSuspendCount(0)
|
||||
, mLoadFlags(LOAD_NORMAL)
|
||||
@@ -220,8 +220,9 @@ nsInputStreamPump::Init(nsIInputStream *stream,
|
||||
{
|
||||
NS_ENSURE_TRUE(mState == STATE_IDLE, NS_ERROR_IN_PROGRESS);
|
||||
|
||||
mStreamOffset = (PRUint32) streamPos;
|
||||
mStreamLength = (PRUint32) streamLen;
|
||||
mStreamOffset = streamPos;
|
||||
if (streamLen >= 0)
|
||||
mStreamLength = streamLen;
|
||||
mStream = stream;
|
||||
mSegSize = segsize;
|
||||
mSegCount = segcount;
|
||||
@@ -256,7 +257,7 @@ nsInputStreamPump::AsyncRead(nsIStreamListener *listener, nsISupports *ctxt)
|
||||
// stream case, the stream transport service will take care of seeking
|
||||
// for us.
|
||||
//
|
||||
if (mAsyncStream && (mStreamOffset != PR_UINT32_MAX)) {
|
||||
if (mAsyncStream && (mStreamOffset != nsInt64(-1))) {
|
||||
nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mStream);
|
||||
if (seekable)
|
||||
seekable->Seek(nsISeekableStream::NS_SEEK_SET, mStreamOffset);
|
||||
@@ -406,7 +407,7 @@ nsInputStreamPump::OnStateTransfer()
|
||||
}
|
||||
else if (NS_SUCCEEDED(rv) && avail) {
|
||||
// figure out how much data to report (XXX detect overflow??)
|
||||
if (avail + mStreamOffset > mStreamLength)
|
||||
if (nsInt64(avail) + mStreamOffset > mStreamLength)
|
||||
avail = mStreamLength - mStreamOffset;
|
||||
|
||||
if (avail) {
|
||||
@@ -430,7 +431,7 @@ nsInputStreamPump::OnStateTransfer()
|
||||
if (seekable)
|
||||
seekable->Tell(&offsetBefore);
|
||||
|
||||
LOG((" calling OnDataAvailable [offset=%u count=%u]\n", mStreamOffset, avail));
|
||||
LOG((" calling OnDataAvailable [offset=%lld count=%u]\n", PRInt64(mStreamOffset), avail));
|
||||
rv = mListener->OnDataAvailable(this, mListenerContext, mAsyncStream, mStreamOffset, avail);
|
||||
|
||||
// don't enter this code if ODA failed or called Cancel
|
||||
@@ -443,9 +444,7 @@ nsInputStreamPump::OnStateTransfer()
|
||||
nsInt64 offsetAfter64 = offsetAfter;
|
||||
if (offsetAfter64 > offsetBefore64) {
|
||||
nsInt64 offsetDelta = offsetAfter64 - offsetBefore64;
|
||||
const nsInt64 maxUint32 = PR_UINT32_MAX;
|
||||
NS_ASSERTION(offsetDelta < maxUint32, "offset overflows PRUint32");
|
||||
mStreamOffset += (PRUint32) offsetDelta;
|
||||
mStreamOffset += offsetDelta;
|
||||
}
|
||||
else if (mSuspendCount == 0) {
|
||||
//
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
#include "nsIAsyncInputStream.h"
|
||||
#include "nsIEventQueue.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsInt64.h"
|
||||
|
||||
class nsInputStreamPump : public nsIInputStreamPump
|
||||
, public nsIInputStreamCallback
|
||||
@@ -82,8 +83,8 @@ protected:
|
||||
nsCOMPtr<nsIEventQueue> mEventQ;
|
||||
nsCOMPtr<nsIInputStream> mStream;
|
||||
nsCOMPtr<nsIAsyncInputStream> mAsyncStream;
|
||||
PRUint32 mStreamOffset;
|
||||
PRUint32 mStreamLength;
|
||||
nsInt64 mStreamOffset;
|
||||
nsInt64 mStreamLength;
|
||||
PRUint32 mSegSize;
|
||||
PRUint32 mSegCount;
|
||||
nsresult mStatus;
|
||||
|
||||
@@ -44,21 +44,21 @@
|
||||
NS_IMPL_ISUPPORTS1(nsResumableEntityID, nsIResumableEntityID)
|
||||
|
||||
nsResumableEntityID::nsResumableEntityID() :
|
||||
mSize(PR_UINT32_MAX) {
|
||||
mSize(LL_MaxUint()) {
|
||||
}
|
||||
|
||||
nsResumableEntityID::~nsResumableEntityID() {}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsResumableEntityID::GetSize(PRUint32 *aSize) {
|
||||
if (mSize == PR_UINT32_MAX)
|
||||
nsResumableEntityID::GetSize(PRUint64 *aSize) {
|
||||
if (LL_EQ(mSize, LL_MaxUint()))
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
*aSize = mSize;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsResumableEntityID::SetSize(PRUint32 aSize) {
|
||||
nsResumableEntityID::SetSize(PRUint64 aSize) {
|
||||
mSize = aSize;
|
||||
return NS_OK;
|
||||
}
|
||||
@@ -89,13 +89,13 @@ nsResumableEntityID::GetEntityTag(nsACString& aTag) {
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsResumableEntityID::Equals(nsIResumableEntityID *other, PRBool *ret) {
|
||||
PRUint32 size;
|
||||
PRUint64 size;
|
||||
nsCAutoString lastMod;
|
||||
nsCAutoString entityTag;
|
||||
|
||||
nsresult rv = other->GetSize(&size);
|
||||
if (NS_FAILED(rv))
|
||||
size = PR_UINT32_MAX;
|
||||
size = LL_MaxUint();
|
||||
|
||||
rv = other->GetLastModified(lastMod);
|
||||
if (NS_FAILED(rv))
|
||||
@@ -109,7 +109,7 @@ nsResumableEntityID::Equals(nsIResumableEntityID *other, PRBool *ret) {
|
||||
// exactly the same way for both of these entity IDs (same timezone, same
|
||||
// format, etc).
|
||||
*ret = mEntityTag.Equals(entityTag) && lastMod.Equals(mLastModified) &&
|
||||
(mSize == size);
|
||||
LL_EQ(mSize, size);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ public:
|
||||
~nsResumableEntityID();
|
||||
|
||||
private:
|
||||
PRUint32 mSize;
|
||||
PRUint64 mSize;
|
||||
nsCString mLastModified;
|
||||
nsCString mEntityTag;
|
||||
};
|
||||
|
||||
@@ -86,7 +86,8 @@ nsFTPChannel::nsFTPChannel()
|
||||
mFTPState(nsnull),
|
||||
mLock(nsnull),
|
||||
mStatus(NS_OK),
|
||||
mCanceled(PR_FALSE)
|
||||
mCanceled(PR_FALSE),
|
||||
mStartPos(LL_MaxUint())
|
||||
{
|
||||
}
|
||||
|
||||
@@ -275,7 +276,19 @@ nsFTPChannel::GenerateCacheKey(nsACString &cacheKey)
|
||||
NS_IMETHODIMP
|
||||
nsFTPChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctxt)
|
||||
{
|
||||
return AsyncOpenAt(listener, ctxt, PRUint32(-1), nsnull);
|
||||
nsresult rv = AsyncOpenAt(listener, ctxt, mStartPos, mEntityID);
|
||||
// mEntityID no longer needed, clear it to avoid returning a wrong entity
|
||||
// id when someone asks us
|
||||
mEntityID = nsnull;
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFTPChannel::ResumeAt(PRUint64 aStartPos, nsIResumableEntityID* aEntityID)
|
||||
{
|
||||
mEntityID = aEntityID;
|
||||
mStartPos = aStartPos;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@@ -286,9 +299,9 @@ nsFTPChannel::GetEntityID(nsIResumableEntityID **entityID)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsresult
|
||||
nsFTPChannel::AsyncOpenAt(nsIStreamListener *listener, nsISupports *ctxt,
|
||||
PRUint32 startPos, nsIResumableEntityID* entityID)
|
||||
PRUint64 startPos, nsIResumableEntityID* entityID)
|
||||
{
|
||||
PRInt32 port;
|
||||
nsresult rv = mURL->GetPort(&port);
|
||||
|
||||
@@ -111,6 +111,8 @@ public:
|
||||
nsresult SetupState(PRUint32 startPos, nsIResumableEntityID* entityID);
|
||||
nsresult GenerateCacheKey(nsACString &cacheKey);
|
||||
|
||||
nsresult AsyncOpenAt(nsIStreamListener *listener, nsISupports *ctxt,
|
||||
PRUint64 startPos, nsIResumableEntityID* entityID);
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsIURI> mOriginalURI;
|
||||
@@ -153,6 +155,7 @@ protected:
|
||||
nsCOMPtr<nsICacheEntryDescriptor> mCacheEntry;
|
||||
nsCOMPtr<nsIProxyInfo> mProxyInfo;
|
||||
nsCOMPtr<nsIResumableEntityID> mEntityID;
|
||||
PRUint64 mStartPos;
|
||||
};
|
||||
|
||||
#endif /* nsFTPChannel_h___ */
|
||||
|
||||
@@ -243,14 +243,12 @@ DataRequestForwarder::GetEntityID(nsIResumableEntityID* *aEntityID)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DataRequestForwarder::AsyncOpenAt(nsIStreamListener *,
|
||||
nsISupports *,
|
||||
unsigned int,
|
||||
nsIResumableEntityID *)
|
||||
DataRequestForwarder::ResumeAt(PRUint64,
|
||||
nsIResumableEntityID *)
|
||||
{
|
||||
// We shouldn't get here. This class only exists in the middle of a
|
||||
// request
|
||||
NS_NOTREACHED("DataRequestForwarder::AsyncOpenAt");
|
||||
NS_NOTREACHED("DataRequestForwarder::ResumeAt");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
@@ -384,7 +382,7 @@ nsFtpState::nsFtpState()
|
||||
|
||||
mControlConnection = nsnull;
|
||||
mDRequestForwarder = nsnull;
|
||||
mFileSize = PRUint32(-1);
|
||||
mFileSize = LL_MaxUint();
|
||||
|
||||
// make sure handler stays around
|
||||
NS_ADDREF(gFtpHandler);
|
||||
@@ -1330,8 +1328,10 @@ nsFtpState::S_size() {
|
||||
FTP_STATE
|
||||
nsFtpState::R_size() {
|
||||
if (mResponseCode/100 == 2) {
|
||||
mFileSize = atoi(mResponseMsg.get()+4);
|
||||
if (NS_FAILED(mChannel->SetContentLength(mFileSize))) return FTP_ERROR;
|
||||
PR_sscanf(mResponseMsg.get() + 4, "%llu", &mFileSize);
|
||||
PRUint32 size32;
|
||||
LL_L2UI(size32, mFileSize);
|
||||
if (NS_FAILED(mChannel->SetContentLength(size32))) return FTP_ERROR;
|
||||
}
|
||||
|
||||
// We may want to be able to resume this
|
||||
@@ -1386,7 +1386,7 @@ nsFtpState::R_mdtm() {
|
||||
entEqual)) {
|
||||
return FTP_S_REST;
|
||||
} else {
|
||||
mInternalError = NS_ERROR_NOT_RESUMABLE;
|
||||
mInternalError = NS_ERROR_ENTITY_CHANGED;
|
||||
mResponseMsg.Truncate();
|
||||
return FTP_ERROR;
|
||||
}
|
||||
|
||||
@@ -194,7 +194,7 @@ private:
|
||||
nsCOMPtr<nsISocketTransport> mDPipe; // the data transport
|
||||
nsCOMPtr<nsIRequest> mDPipeRequest;
|
||||
DataRequestForwarder* mDRequestForwarder;
|
||||
PRUint32 mFileSize;
|
||||
PRUint64 mFileSize;
|
||||
nsCString mModTime;
|
||||
|
||||
// ****** consumer vars
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
|
||||
@@ -68,6 +68,7 @@
|
||||
#include "nsEscape.h"
|
||||
#include "nsICookieService.h"
|
||||
#include "nsIResumableChannel.h"
|
||||
#include "nsInt64.h"
|
||||
|
||||
static NS_DEFINE_CID(kStreamListenerTeeCID, NS_STREAMLISTENERTEE_CID);
|
||||
|
||||
@@ -99,7 +100,7 @@ nsHttpChannel::nsHttpChannel()
|
||||
, mPostID(0)
|
||||
, mRequestTime(0)
|
||||
, mAuthContinuationState(nsnull)
|
||||
, mStartPos(0)
|
||||
, mStartPos(LL_MaxUint())
|
||||
, mRedirectionLimit(gHttpHandler->RedirectionLimit())
|
||||
, mIsPending(PR_FALSE)
|
||||
, mApplyConversion(PR_TRUE)
|
||||
@@ -537,7 +538,7 @@ nsHttpChannel::SetupTransaction()
|
||||
|
||||
if (mResuming) {
|
||||
char buf[32];
|
||||
PR_snprintf(buf, sizeof(buf), "bytes=%u-", mStartPos);
|
||||
PR_snprintf(buf, sizeof(buf), "bytes=%llu-", mStartPos);
|
||||
mRequestHead.SetHeader(nsHttp::Range, nsDependentCString(buf));
|
||||
|
||||
if (mEntityID) {
|
||||
@@ -760,7 +761,7 @@ nsHttpChannel::ProcessResponse()
|
||||
case 412: // Precondition failed
|
||||
case 416: // Invalid range
|
||||
if (mResuming) {
|
||||
Cancel(NS_ERROR_NOT_RESUMABLE);
|
||||
Cancel(NS_ERROR_ENTITY_CHANGED);
|
||||
rv = CallOnStartRequest();
|
||||
break;
|
||||
}
|
||||
@@ -829,7 +830,7 @@ nsHttpChannel::ProcessNormal()
|
||||
PRBool equal;
|
||||
rv = mEntityID->Equals(id, &equal);
|
||||
if (NS_FAILED(rv) || !equal)
|
||||
Cancel(NS_ERROR_NOT_RESUMABLE);
|
||||
Cancel(NS_ERROR_ENTITY_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1346,16 +1347,16 @@ nsHttpChannel::CheckCache()
|
||||
// of the cached content, then the cached response is partial...
|
||||
// either we need to issue a byte range request or we need to refetch the
|
||||
// entire document.
|
||||
PRUint32 contentLength = (PRUint32) mCachedResponseHead->ContentLength();
|
||||
if (contentLength != PRUint32(-1)) {
|
||||
nsInt64 contentLength = mCachedResponseHead->ContentLength();
|
||||
if (contentLength != nsInt64(-1)) {
|
||||
PRUint32 size;
|
||||
rv = mCacheEntry->GetDataSize(&size);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (size != contentLength) {
|
||||
if (nsInt64(size) != contentLength) {
|
||||
LOG(("Cached data size does not match the Content-Length header "
|
||||
"[content-length=%u size=%u]\n", contentLength, size));
|
||||
if ((size < contentLength) && mCachedResponseHead->IsResumable()) {
|
||||
"[content-length=%lld size=%u]\n", PRInt64(contentLength), size));
|
||||
if ((nsInt64(size) < contentLength) && mCachedResponseHead->IsResumable()) {
|
||||
// looks like a partial entry.
|
||||
rv = SetupByteRangeRequest(size);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
@@ -1820,6 +1821,16 @@ nsHttpChannel::SetupReplacementChannel(nsIURI *newURI,
|
||||
if (encodedChannel)
|
||||
encodedChannel->SetApplyConversion(mApplyConversion);
|
||||
|
||||
// transfer the resume information
|
||||
if (mResuming) {
|
||||
nsCOMPtr<nsIResumableChannel> resumableChannel(do_QueryInterface(newChannel));
|
||||
if (!resumableChannel) {
|
||||
NS_WARNING("Got asked to resume, but redirected to non-resumable channel!");
|
||||
return NS_ERROR_NOT_RESUMABLE;
|
||||
}
|
||||
resumableChannel->ResumeAt(mStartPos, mEntityID);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -2950,7 +2961,8 @@ nsHttpChannel::GetContentLength(PRInt32 *value)
|
||||
if (!mResponseHead)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
*value = mResponseHead->ContentLength();
|
||||
// XXX truncates to 32 bit
|
||||
LL_L2I(*value, mResponseHead->ContentLength());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -3688,8 +3700,8 @@ nsHttpChannel::OnDataAvailable(nsIRequest *request, nsISupports *ctxt,
|
||||
// of a byte range request, the content length stored in the cached
|
||||
// response headers is what we want to use here.
|
||||
|
||||
PRUint32 progressMax = mResponseHead->ContentLength();
|
||||
PRUint32 progress = mLogicalOffset + count;
|
||||
nsInt64 progressMax(mResponseHead->ContentLength());
|
||||
nsInt64 progress = mLogicalOffset + nsInt64(count);
|
||||
NS_ASSERTION(progress <= progressMax, "unexpected progress values");
|
||||
|
||||
OnTransportStatus(nsnull, transportStatus, progress, progressMax);
|
||||
@@ -3856,15 +3868,13 @@ nsHttpChannel::IsFromCache(PRBool *value)
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHttpChannel::AsyncOpenAt(nsIStreamListener* aListener,
|
||||
nsISupports* aCtxt,
|
||||
PRUint32 aStartPos,
|
||||
nsIResumableEntityID* aEntityID)
|
||||
nsHttpChannel::ResumeAt(PRUint64 aStartPos,
|
||||
nsIResumableEntityID* aEntityID)
|
||||
{
|
||||
mEntityID = aEntityID;
|
||||
mStartPos = aStartPos;
|
||||
mResuming = PR_TRUE;
|
||||
return AsyncOpen(aListener, aCtxt);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@@ -3881,7 +3891,7 @@ nsHttpChannel::GetEntityID(nsIResumableEntityID** aEntityID)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRUint32 size = PR_UINT32_MAX;
|
||||
PRUint64 size = LL_MaxUint();
|
||||
nsCAutoString etag, lastmod;
|
||||
if (mResponseHead) {
|
||||
size = mResponseHead->TotalEntitySize();
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
#include "nsHttpAuthCache.h"
|
||||
#include "nsXPIDLString.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsInt64.h"
|
||||
|
||||
#include "nsIHttpChannel.h"
|
||||
#include "nsIHttpChannelInternal.h"
|
||||
@@ -211,7 +212,7 @@ private:
|
||||
|
||||
PRUint32 mLoadFlags;
|
||||
PRUint32 mStatus;
|
||||
PRUint32 mLogicalOffset;
|
||||
nsInt64 mLogicalOffset;
|
||||
PRUint8 mCaps;
|
||||
|
||||
nsCString mContentTypeHint;
|
||||
@@ -232,7 +233,7 @@ private:
|
||||
|
||||
// Resumable channel specific data
|
||||
nsCOMPtr<nsIResumableEntityID> mEntityID;
|
||||
PRUint32 mStartPos;
|
||||
PRUint64 mStartPos;
|
||||
|
||||
// redirection specific data.
|
||||
PRUint8 mRedirectionLimit;
|
||||
|
||||
@@ -69,13 +69,13 @@ nsHttpResponseHead::SetHeader(nsHttpAtom hdr,
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpResponseHead::SetContentLength(PRInt32 len)
|
||||
nsHttpResponseHead::SetContentLength(PRInt64 len)
|
||||
{
|
||||
mContentLength = len;
|
||||
if (len < 0)
|
||||
if (!LL_GE_ZERO(len)) // < 0
|
||||
mHeaders.ClearHeader(nsHttp::Content_Length);
|
||||
else
|
||||
mHeaders.SetHeader(nsHttp::Content_Length, nsPrintfCString("%d", len));
|
||||
mHeaders.SetHeader(nsHttp::Content_Length, nsPrintfCString(20, "%lld", len));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -207,7 +207,7 @@ nsHttpResponseHead::ParseHeaderLine(char *line)
|
||||
|
||||
// handle some special case headers...
|
||||
if (hdr == nsHttp::Content_Length)
|
||||
mContentLength = atoi(val);
|
||||
PR_sscanf(val, "%lld", &mContentLength);
|
||||
else if (hdr == nsHttp::Content_Type)
|
||||
ParseContentType(val);
|
||||
else if (hdr == nsHttp::Cache_Control)
|
||||
@@ -440,7 +440,7 @@ nsHttpResponseHead::Reset()
|
||||
|
||||
mVersion = NS_HTTP_VERSION_1_1;
|
||||
mStatus = 200;
|
||||
mContentLength = -1;
|
||||
mContentLength = LL_MaxUint();
|
||||
mCacheControlNoStore = PR_FALSE;
|
||||
mCacheControlNoCache = PR_FALSE;
|
||||
mPragmaNoCache = PR_FALSE;
|
||||
@@ -520,7 +520,7 @@ nsHttpResponseHead::GetExpiresValue(PRUint32 *result)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRInt32
|
||||
PRInt64
|
||||
nsHttpResponseHead::TotalEntitySize()
|
||||
{
|
||||
const char* contentRange = PeekHeader(nsHttp::Content_Range);
|
||||
@@ -536,7 +536,11 @@ nsHttpResponseHead::TotalEntitySize()
|
||||
if (*slash == '*') // Server doesn't know the length
|
||||
return -1;
|
||||
|
||||
return atoi(slash);
|
||||
PRInt64 size;
|
||||
PRInt32 items = PR_sscanf(slash, "%lld", &size);
|
||||
if (items <= 0)
|
||||
size = LL_MaxUint();
|
||||
return size;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@@ -53,7 +53,7 @@ class nsHttpResponseHead
|
||||
public:
|
||||
nsHttpResponseHead() : mVersion(NS_HTTP_VERSION_1_1)
|
||||
, mStatus(200)
|
||||
, mContentLength(-1)
|
||||
, mContentLength(LL_MaxUint())
|
||||
, mCacheControlNoStore(PR_FALSE)
|
||||
, mCacheControlNoCache(PR_FALSE)
|
||||
, mPragmaNoCache(PR_FALSE) {}
|
||||
@@ -66,7 +66,7 @@ public:
|
||||
nsHttpVersion Version() { return mVersion; }
|
||||
PRUint16 Status() { return mStatus; }
|
||||
const nsAFlatCString &StatusText() { return mStatusText; }
|
||||
PRInt32 ContentLength() { return mContentLength; }
|
||||
PRInt64 ContentLength() { return mContentLength; }
|
||||
const nsAFlatCString &ContentType() { return mContentType; }
|
||||
const nsAFlatCString &ContentCharset() { return mContentCharset; }
|
||||
PRBool NoStore() { return mCacheControlNoStore; }
|
||||
@@ -76,7 +76,7 @@ public:
|
||||
* than ContentLength(), which will only represent the requested part of the
|
||||
* entity.
|
||||
*/
|
||||
PRInt32 TotalEntitySize();
|
||||
PRInt64 TotalEntitySize();
|
||||
|
||||
const char *PeekHeader(nsHttpAtom h) { return mHeaders.PeekHeader(h); }
|
||||
nsresult SetHeader(nsHttpAtom h, const nsACString &v, PRBool m=PR_FALSE);
|
||||
@@ -86,7 +86,7 @@ public:
|
||||
|
||||
void SetContentType(const nsACString &s) { mContentType = s; }
|
||||
void SetContentCharset(const nsACString &s) { mContentCharset = s; }
|
||||
void SetContentLength(PRInt32);
|
||||
void SetContentLength(PRInt64);
|
||||
|
||||
// write out the response status line and headers as a single text block,
|
||||
// optionally pruning out transient headers (ie. headers that only make
|
||||
@@ -141,7 +141,7 @@ private:
|
||||
nsHttpVersion mVersion;
|
||||
PRUint16 mStatus;
|
||||
nsCString mStatusText;
|
||||
PRInt32 mContentLength;
|
||||
PRInt64 mContentLength;
|
||||
nsCString mContentType;
|
||||
nsCString mContentCharset;
|
||||
PRPackedBool mCacheControlNoStore;
|
||||
|
||||
@@ -762,7 +762,7 @@ nsHttpTransaction::HandleContentStart()
|
||||
mContentLength = -1;
|
||||
}
|
||||
#if defined(PR_LOGGING)
|
||||
else if (mContentLength == -1)
|
||||
else if (mContentLength == nsInt64(-1))
|
||||
LOG(("waiting for the server to close the connection.\n"));
|
||||
#endif
|
||||
}
|
||||
@@ -799,20 +799,20 @@ nsHttpTransaction::HandleContent(char *buf,
|
||||
rv = mChunkedDecoder->HandleChunkedContent(buf, count, contentRead, contentRemaining);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
else if (mContentLength >= 0) {
|
||||
else if (mContentLength >= nsInt64(0)) {
|
||||
// HTTP/1.0 servers have been known to send erroneous Content-Length
|
||||
// headers. So, unless the connection is persistent, we must make
|
||||
// allowances for a possibly invalid Content-Length header. Thus, if
|
||||
// NOT persistent, we simply accept everything in |buf|.
|
||||
if (mConnection->IsPersistent()) {
|
||||
*contentRead = PRUint32(mContentLength) - mContentRead;
|
||||
*contentRead = mContentLength - mContentRead;
|
||||
*contentRead = PR_MIN(count, *contentRead);
|
||||
}
|
||||
else {
|
||||
*contentRead = count;
|
||||
// mContentLength might need to be increased...
|
||||
if (*contentRead + mContentRead > (PRUint32) mContentLength) {
|
||||
mContentLength = *contentRead + mContentRead;
|
||||
if (nsInt64(*contentRead) + mContentRead > mContentLength) {
|
||||
mContentLength = nsInt64(*contentRead) + mContentRead;
|
||||
//mResponseHead->SetContentLength(mContentLength);
|
||||
}
|
||||
}
|
||||
@@ -832,11 +832,11 @@ nsHttpTransaction::HandleContent(char *buf,
|
||||
*/
|
||||
}
|
||||
|
||||
LOG(("nsHttpTransaction [this=%x count=%u read=%u mContentRead=%u mContentLength=%d]\n",
|
||||
this, count, *contentRead, mContentRead, mContentLength));
|
||||
LOG(("nsHttpTransaction [this=%x count=%u read=%u mContentRead=%lld mContentLength=%lld]\n",
|
||||
this, count, *contentRead, mContentRead.mValue, mContentLength.mValue));
|
||||
|
||||
// check for end-of-file
|
||||
if ((mContentRead == PRUint32(mContentLength)) ||
|
||||
if ((mContentRead == mContentLength) ||
|
||||
(mChunkedDecoder && mChunkedDecoder->ReachedEOF())) {
|
||||
// the transaction is done with a complete response.
|
||||
mTransactionDone = PR_TRUE;
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
#include "nsAHttpTransaction.h"
|
||||
#include "nsAHttpConnection.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsInt64.h"
|
||||
|
||||
#include "nsIPipe.h"
|
||||
#include "nsIInputStream.h"
|
||||
@@ -170,8 +171,8 @@ private:
|
||||
|
||||
nsCString mLineBuf; // may contain a partial line
|
||||
|
||||
PRInt32 mContentLength; // equals -1 if unknown
|
||||
PRUint32 mContentRead; // count of consumed content bytes
|
||||
nsInt64 mContentLength; // equals -1 if unknown
|
||||
nsInt64 mContentRead; // count of consumed content bytes
|
||||
|
||||
nsHttpChunkedDecoder *mChunkedDecoder;
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ public:
|
||||
NS_DECL_NSIMULTIPARTCHANNEL
|
||||
|
||||
protected:
|
||||
virtual ~nsPartChannel();
|
||||
~nsPartChannel();
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsIChannel> mMultipartChannel;
|
||||
@@ -190,6 +190,7 @@ nsPartChannel::Cancel(nsresult aStatus)
|
||||
{
|
||||
// Cancelling an individual part must not cancel the underlying
|
||||
// multipart channel...
|
||||
// XXX but we should stop sending data for _this_ part channel!
|
||||
mStatus = aStatus;
|
||||
return NS_OK;
|
||||
}
|
||||
@@ -199,6 +200,7 @@ nsPartChannel::Suspend(void)
|
||||
{
|
||||
// Suspending an individual part must not suspend the underlying
|
||||
// multipart channel...
|
||||
// XXX why not?
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -207,6 +209,7 @@ nsPartChannel::Resume(void)
|
||||
{
|
||||
// Resuming an individual part must not resume the underlying
|
||||
// multipart channel...
|
||||
// XXX why not?
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -83,6 +83,8 @@
|
||||
#include "prlog.h"
|
||||
#include "prtime.h"
|
||||
|
||||
#include "nsInt64.h"
|
||||
|
||||
#if defined(PR_LOGGING)
|
||||
//
|
||||
// set NSPR_LOG_MODULES=Test:5
|
||||
@@ -100,7 +102,7 @@ static PRBool gVerbose = PR_FALSE;
|
||||
static nsIEventQueue* gEventQ = nsnull;
|
||||
static PRBool gAskUserForInput = PR_FALSE;
|
||||
static PRBool gResume = PR_FALSE;
|
||||
static PRUint32 gStartAt = 0;
|
||||
static PRUint64 gStartAt = 0;
|
||||
|
||||
static const char* gLastMod = NULL;
|
||||
static const char* gETag = NULL;
|
||||
@@ -178,7 +180,7 @@ public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
const char* Name() { return mURLString.get(); }
|
||||
PRInt32 mBytesRead;
|
||||
nsInt64 mBytesRead;
|
||||
PRTime mTotalTime;
|
||||
PRTime mConnectTime;
|
||||
nsCString mURLString;
|
||||
@@ -418,10 +420,10 @@ InputTestConsumer::OnStartRequest(nsIRequest *request, nsISupports* context)
|
||||
nsCOMPtr<nsIResumableEntityID> entityID;
|
||||
nsresult rv = resChannel->GetEntityID(getter_AddRefs(entityID));
|
||||
if (NS_SUCCEEDED(rv) && entityID) {
|
||||
PRUint32 size;
|
||||
PRUint64 size;
|
||||
if (NS_SUCCEEDED(entityID->GetSize(&size)) &&
|
||||
size != PRUint32(-1))
|
||||
LOG(("\tSize: %d\n", size));
|
||||
LL_NE(size, LL_MaxUint()))
|
||||
LOG(("\tSize: %llu\n", size));
|
||||
else
|
||||
LOG(("\tSize: Unknown\n"));
|
||||
nsCAutoString lastModified;
|
||||
@@ -533,10 +535,10 @@ InputTestConsumer::OnStopRequest(nsIRequest *request, nsISupports* context,
|
||||
}
|
||||
LOG(("\tTime to connect: %.3f seconds\n", connectTime));
|
||||
LOG(("\tTime to read: %.3f seconds.\n", readTime));
|
||||
LOG(("\tRead: %d bytes.\n", info->mBytesRead));
|
||||
if (!info->mBytesRead) {
|
||||
LOG(("\tRead: %lld bytes.\n", info->mBytesRead.mValue));
|
||||
if (info->mBytesRead == nsInt64(0)) {
|
||||
} else if (readTime > 0.0) {
|
||||
LOG(("\tThroughput: %.0f bps.\n", (info->mBytesRead*8)/readTime));
|
||||
LOG(("\tThroughput: %.0f bps.\n", (PRFloat64)(info->mBytesRead*nsInt64(8))/readTime));
|
||||
} else {
|
||||
LOG(("\tThroughput: REAL FAST!!\n"));
|
||||
}
|
||||
@@ -676,14 +678,10 @@ nsresult StartLoadingURL(const char* aUrlString)
|
||||
id->SetSize(gTotalSize);
|
||||
}
|
||||
}
|
||||
rv = res->AsyncOpenAt(listener,
|
||||
info,
|
||||
gStartAt,
|
||||
id);
|
||||
} else {
|
||||
rv = pChannel->AsyncOpen(listener, // IStreamListener consumer
|
||||
info);
|
||||
res->ResumeAt(gStartAt, id);
|
||||
}
|
||||
rv = pChannel->AsyncOpen(listener, // IStreamListener consumer
|
||||
info);
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
gKeepRunning += 1;
|
||||
@@ -807,7 +805,7 @@ main(int argc, char* argv[])
|
||||
|
||||
if (PL_strcasecmp(argv[i], "-resume") == 0) {
|
||||
gResume = PR_TRUE;
|
||||
gStartAt = atoi(argv[++i]);
|
||||
PR_sscanf(argv[++i], "%llu", &gStartAt);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsCRT.h"
|
||||
#include "prlog.h"
|
||||
#include "nsInt64.h"
|
||||
|
||||
#if defined(PR_LOGGING)
|
||||
//
|
||||
@@ -146,7 +147,7 @@ private:
|
||||
|
||||
// separate refcnt so that we know when to close the consumer
|
||||
nsrefcnt mReaderRefCnt;
|
||||
PRUint32 mLogicalOffset;
|
||||
nsInt64 mLogicalOffset;
|
||||
PRPackedBool mBlocking;
|
||||
|
||||
// these variables can only be accessed while inside the pipe's monitor
|
||||
@@ -200,7 +201,7 @@ private:
|
||||
|
||||
// separate refcnt so that we know when to close the producer
|
||||
nsrefcnt mWriterRefCnt;
|
||||
PRUint32 mLogicalOffset;
|
||||
nsInt64 mLogicalOffset;
|
||||
PRPackedBool mBlocking;
|
||||
|
||||
// these variables can only be accessed while inside the pipe's monitor
|
||||
@@ -858,7 +859,7 @@ nsPipeInputStream::Seek(PRInt32 whence, PRInt64 offset)
|
||||
NS_IMETHODIMP
|
||||
nsPipeInputStream::Tell(PRInt64 *offset)
|
||||
{
|
||||
LL_UI2L(*offset, mLogicalOffset);
|
||||
*offset = mLogicalOffset;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user