Commit ca152164 authored by Dragana Damjanovic's avatar Dragana Damjanovic Committed by Georg Koppen
Browse files

Bug 918827 - Remove caching for ftp connections. r=michal

--HG--
extra : amend_source : 2e31431e4227fdf3f88d31a8efa14aab8e793cd2

This is actually bug 913827.
parent 5a0e2bc7
Loading
Loading
Loading
Loading
+1 −297
Original line number Diff line number Diff line
@@ -22,7 +22,6 @@
#include "nsNetUtil.h"
#include "nsThreadUtils.h"
#include "nsStreamUtils.h"
#include "nsICacheService.h"
#include "nsIURL.h"
#include "nsISocketTransport.h"
#include "nsIStreamListenerTee.h"
@@ -32,7 +31,6 @@
#include "nsAuthInformationHolder.h"
#include "nsIProtocolProxyService.h"
#include "nsICancelable.h"
#include "nsICacheEntryDescriptor.h"
#include "nsIOutputStream.h"
#include "nsIPrompt.h"
#include "nsIProtocolHandler.h"
@@ -40,7 +38,6 @@
#include "nsIRunnable.h"
#include "nsISocketTransportService.h"
#include "nsIURI.h"
#include "nsICacheSession.h"
#include "nsILoadInfo.h"
#include "nsNullPrincipal.h"

@@ -70,7 +67,6 @@ NS_IMPL_ISUPPORTS_INHERITED(nsFtpState,
                            nsBaseContentStream,
                            nsIInputStreamCallback, 
                            nsITransportEventSink,
                            nsICacheListener,
                            nsIRequestObserver,
                            nsIProtocolProxyCallback)

@@ -96,7 +92,6 @@ nsFtpState::nsFtpState()
    , mServerIsIPv6(false)
    , mUseUTF8(false)
    , mControlStatus(NS_OK)
    , mDoomCache(false)
    , mDeferredCallbackPending(false)
{
    LOG_ALWAYS(("FTP:(%x) nsFtpState created", this));
@@ -1142,8 +1137,7 @@ nsFtpState::SetContentType()
    // FTP directory URLs don't always end in a slash.  Make sure they do.
    // This check needs to be here rather than a more obvious place
    // (e.g. LIST command processing) so that it ensures the terminating
    // slash is appended for the new request case, as well as the case
    // where the URL is being loaded from the cache.
    // slash is appended for the new request case.

    if (!mPath.IsEmpty() && mPath.Last() != '/') {
        nsCOMPtr<nsIURL> url = (do_QueryInterface(mChannel->URI()));
@@ -1174,23 +1168,6 @@ nsFtpState::S_list() {
        return rv;
    }

    if (mCacheEntry) {
        // save off the server type if we are caching.
        nsAutoCString serverType;
        serverType.AppendInt(mServerType);
        mCacheEntry->SetMetaDataElement("servertype", serverType.get());

        nsAutoCString useUTF8;
        useUTF8.AppendInt(mUseUTF8);
        mCacheEntry->SetMetaDataElement("useUTF8", useUTF8.get());

        // open cache entry for writing, and configure it to receive data.
        if (NS_FAILED(InstallCacheListener())) {
            mCacheEntry->AsyncDoom(nullptr);
            mCacheEntry = nullptr;
        }
    }

    // dir listings aren't resumable
    NS_ENSURE_TRUE(!mChannel->ResumeRequested(), NS_ERROR_NOT_RESUMABLE);

@@ -1218,7 +1195,6 @@ nsFtpState::R_list() {
    if (mResponseCode/100 == 2) {
        //(DONE)
        mNextState = FTP_COMPLETE;
        mDoomCache = false;
        return FTP_COMPLETE;
    }
    return FTP_ERROR;
@@ -1245,13 +1221,6 @@ nsFtpState::R_retr() {
    }

    if (mResponseCode/100 == 1) {
        // We're going to grab a file, not a directory. So we need to clear
        // any cache entry, otherwise we'll have problems reading it later.
        // See bug 122548
        if (mCacheEntry) {
            (void)mCacheEntry->AsyncDoom(nullptr);
            mCacheEntry = nullptr;
        }
        if (mDataStream && HasPendingCallback())
            mDataStream->AsyncWait(this, 0, 0, CallbackTarget());
        return FTP_READ_BUF;
@@ -1644,123 +1613,6 @@ uint32_t GetFtpTime()

uint32_t nsFtpState::mSessionStartTime = GetFtpTime();

/* Is this cache entry valid to use for reading?
 * Since we make up an expiration time for ftp, use the following rules:
 * (see bug 103726)
 *
 * LOAD_FROM_CACHE                    : always use cache entry, even if expired
 * LOAD_BYPASS_CACHE                  : overwrite cache entry
 * LOAD_NORMAL|VALIDATE_ALWAYS        : overwrite cache entry
 * LOAD_NORMAL                        : honor expiration time
 * LOAD_NORMAL|VALIDATE_ONCE_PER_SESSION : overwrite cache entry if first access 
 *                                         this session, otherwise use cache entry 
 *                                         even if expired.
 * LOAD_NORMAL|VALIDATE_NEVER         : always use cache entry, even if expired
 *
 * Note that in theory we could use the mdtm time on the directory
 * In practice, the lack of a timezone plus the general lack of support for that
 * on directories means that its not worth it, I suspect. Revisit if we start
 * caching files - bbaetz
 */
bool
nsFtpState::CanReadCacheEntry()
{
    NS_ASSERTION(mCacheEntry, "must have a cache entry");

    nsCacheAccessMode access;
    nsresult rv = mCacheEntry->GetAccessGranted(&access);
    if (NS_FAILED(rv))
        return false;
    
    // If I'm not granted read access, then I can't reuse it...
    if (!(access & nsICache::ACCESS_READ))
        return false;

    if (mChannel->HasLoadFlag(nsIRequest::LOAD_FROM_CACHE))
        return true;

    if (mChannel->HasLoadFlag(nsIRequest::LOAD_BYPASS_CACHE))
        return false;
    
    if (mChannel->HasLoadFlag(nsIRequest::VALIDATE_ALWAYS))
        return false;
    
    uint32_t time;
    if (mChannel->HasLoadFlag(nsIRequest::VALIDATE_ONCE_PER_SESSION)) {
        rv = mCacheEntry->GetLastModified(&time);
        if (NS_FAILED(rv))
            return false;
        return (mSessionStartTime > time);
    }

    if (mChannel->HasLoadFlag(nsIRequest::VALIDATE_NEVER))
        return true;

    // OK, now we just check the expiration time as usual
    rv = mCacheEntry->GetExpirationTime(&time);
    if (NS_FAILED(rv))
        return false;

    return (GetFtpTime() <= time);
}

nsresult
nsFtpState::InstallCacheListener()
{
    NS_ASSERTION(mCacheEntry, "must have a cache entry");

    nsCOMPtr<nsIOutputStream> out;
    mCacheEntry->OpenOutputStream(0, getter_AddRefs(out));
    NS_ENSURE_STATE(out);

    nsCOMPtr<nsIStreamListenerTee> tee =
            do_CreateInstance(NS_STREAMLISTENERTEE_CONTRACTID);
    NS_ENSURE_STATE(tee);

    nsresult rv = tee->Init(mChannel->StreamListener(), out, nullptr);
    NS_ENSURE_SUCCESS(rv, rv);

    mChannel->SetStreamListener(tee);
    return NS_OK;
}

nsresult
nsFtpState::OpenCacheDataStream()
{
    NS_ASSERTION(mCacheEntry, "must have a cache entry");

    // Get a transport to the cached data...
    nsCOMPtr<nsIInputStream> input;
    mCacheEntry->OpenInputStream(0, getter_AddRefs(input));
    NS_ENSURE_STATE(input);

    nsCOMPtr<nsIStreamTransportService> sts =
            do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
    NS_ENSURE_STATE(sts);

    nsCOMPtr<nsITransport> transport;
    sts->CreateInputTransport(input, -1, -1, true,
                              getter_AddRefs(transport));
    NS_ENSURE_STATE(transport);

    nsresult rv = transport->SetEventSink(this, NS_GetCurrentThread());
    NS_ENSURE_SUCCESS(rv, rv);

    // Open a non-blocking, buffered input stream...
    nsCOMPtr<nsIInputStream> transportInput;
    transport->OpenInputStream(0,
                               nsIOService::gDefaultSegmentSize,
                               nsIOService::gDefaultSegmentCount,
                               getter_AddRefs(transportInput));
    NS_ENSURE_STATE(transportInput);

    mDataStream = do_QueryInterface(transportInput);
    NS_ENSURE_STATE(mDataStream);

    mDataTransport = transport;
    return NS_OK;
}

nsresult
nsFtpState::Init(nsFtpChannel *channel)
{
@@ -1859,8 +1711,6 @@ nsFtpState::Init(nsFtpChannel *channel)
    if (mPassword.FindCharInSet(CRLF) >= 0)
        return NS_ERROR_MALFORMED_URI;

    // setup the connection cache key

    int32_t port;
    rv = mChannel->URI()->GetPort(&port);
    if (NS_FAILED(rv))
@@ -2198,39 +2048,6 @@ nsFtpState::OnTransportStatus(nsITransport *transport, nsresult status,

//-----------------------------------------------------------------------------


NS_IMETHODIMP
nsFtpState::OnCacheEntryAvailable(nsICacheEntryDescriptor *entry,
                                  nsCacheAccessMode access,
                                  nsresult status)
{
    // We may have been closed while we were waiting for this cache entry.
    if (IsClosed())
        return NS_OK;

    if (NS_SUCCEEDED(status) && entry) {
        mDoomCache = true;
        mCacheEntry = entry;
        if (CanReadCacheEntry() && ReadCacheEntry()) {
            mState = FTP_READ_CACHE;
            return NS_OK;
        }
    }

    Connect();
    return NS_OK;
}

//-----------------------------------------------------------------------------

NS_IMETHODIMP
nsFtpState::OnCacheEntryDoomed(nsresult status)
{
    return NS_ERROR_NOT_IMPLEMENTED;
}

//-----------------------------------------------------------------------------

NS_IMETHODIMP
nsFtpState::OnStartRequest(nsIRequest *request, nsISupports *context)
{
@@ -2356,9 +2173,6 @@ nsFtpState::CloseWithStatus(nsresult status)
    }

    mDataStream = nullptr;
    if (mDoomCache && mCacheEntry)
        mCacheEntry->AsyncDoom(nullptr);
    mCacheEntry = nullptr;

    return nsBaseContentStream::CloseWithStatus(status);
}
@@ -2433,124 +2247,14 @@ nsFtpState::OnProxyAvailable(nsICancelable *request, nsIChannel *channel,
void
nsFtpState::OnCallbackPending()
{
    // If this is the first call, then see if we could use the cache.  If we
    // aren't going to read from (or write to) the cache, then just proceed to
    // connect to the server.

    if (mState == FTP_INIT) {
        if (mProxyRequest) {
            mDeferredCallbackPending = true;
            return;
        }

        if (CheckCache()) {
            mState = FTP_WAIT_CACHE;
            return;
        } 
        if (mCacheEntry && CanReadCacheEntry() && ReadCacheEntry()) {
            mState = FTP_READ_CACHE;
            return;
        }
        Connect();
    } else if (mDataStream) {
        mDataStream->AsyncWait(this, 0, 0, CallbackTarget());
    }
}
bool
nsFtpState::ReadCacheEntry()
{
    NS_ASSERTION(mCacheEntry, "should have a cache entry");

    // make sure the channel knows wassup
    SetContentType();

    nsXPIDLCString serverType;
    mCacheEntry->GetMetaDataElement("servertype", getter_Copies(serverType));
    nsAutoCString serverNum(serverType.get());
    nsresult err;
    mServerType = serverNum.ToInteger(&err);

    nsXPIDLCString charset;
    mCacheEntry->GetMetaDataElement("useUTF8", getter_Copies(charset));
    const char *useUTF8 = charset.get();
    if (useUTF8 && atoi(useUTF8) == 1)
        mChannel->SetContentCharset(NS_LITERAL_CSTRING("UTF-8"));
    
    mChannel->PushStreamConverter("text/ftp-dir",
                                  APPLICATION_HTTP_INDEX_FORMAT);
    
    mChannel->SetEntityID(EmptyCString());

    if (NS_FAILED(OpenCacheDataStream()))
        return false;

    if (mDataStream && HasPendingCallback())
        mDataStream->AsyncWait(this, 0, 0, CallbackTarget());

    mDoomCache = false;
    return true;
}

bool
nsFtpState::CheckCache()
{
    // This function is responsible for setting mCacheEntry if there is a cache
    // entry that we can use.  It returns true if we end up waiting for access
    // to the cache.

    // In some cases, we don't want to use the cache:
    if (mChannel->UploadStream() || mChannel->ResumeRequested())
        return false;

    nsCOMPtr<nsICacheService> cache = do_GetService(NS_CACHESERVICE_CONTRACTID);
    if (!cache)
        return false;

    bool isPrivate = NS_UsePrivateBrowsing(mChannel);
    const char* sessionName = isPrivate ? "FTP-private" : "FTP";
    nsCacheStoragePolicy policy =
        isPrivate ? nsICache::STORE_IN_MEMORY : nsICache::STORE_ANYWHERE;
    nsCOMPtr<nsICacheSession> session;
    cache->CreateSession(sessionName,
                         policy,
                         nsICache::STREAM_BASED,
                         getter_AddRefs(session));
    if (!session)
        return false;
    session->SetDoomEntriesIfExpired(false);
    session->SetIsPrivate(isPrivate);

    // Set cache access requested:
    nsCacheAccessMode accessReq;
    uint32_t appId;
    bool isInBrowser;
    NS_GetAppInfo(mChannel, &appId, &isInBrowser);

    if (NS_IsOffline() || NS_IsAppOffline(appId)) {
        accessReq = nsICache::ACCESS_READ; // can only read
    } else if (mChannel->HasLoadFlag(nsIRequest::LOAD_BYPASS_CACHE)) {
        accessReq = nsICache::ACCESS_WRITE; // replace cache entry
    } else {
        accessReq = nsICache::ACCESS_READ_WRITE; // normal browsing
    }

    // Check to see if we are not allowed to write to the cache:
    if (mChannel->HasLoadFlag(nsIRequest::INHIBIT_CACHING)) {
        accessReq &= ~nsICache::ACCESS_WRITE;
        if (accessReq == nsICache::ACCESS_NONE)
            return false;
    }

    // Generate cache key (remove trailing #ref if any):
    nsAutoCString key;
    mChannel->URI()->GetAsciiSpec(key);
    int32_t pos = key.RFindChar('#');
    if (pos != kNotFound)
        key.Truncate(pos);
    NS_ENSURE_FALSE(key.IsEmpty(), false);

    nsresult rv = session->AsyncOpenCacheEntry(key, accessReq, this, false);
    return NS_SUCCEEDED(rv);

}
+0 −49
Original line number Diff line number Diff line
@@ -8,7 +8,6 @@

#include "nsBaseContentStream.h"

#include "nsICacheListener.h"
#include "nsString.h"
#include "nsCOMPtr.h"
#include "nsIAsyncInputStream.h"
@@ -35,8 +34,6 @@ typedef enum _FTP_STATE {
///////////////////////
//// Internal states
    FTP_INIT,
    FTP_WAIT_CACHE,
    FTP_READ_CACHE,
    FTP_COMMAND_CONNECT,
    FTP_READ_BUF,
    FTP_ERROR,
@@ -67,7 +64,6 @@ typedef enum _FTP_ACTION {GET, PUT} FTP_ACTION;

class nsFtpChannel;
class nsICancelable;
class nsICacheEntryDescriptor;
class nsIProxyInfo;
class nsIStreamListener;

@@ -79,7 +75,6 @@ class nsIStreamListener;
class nsFtpState final : public nsBaseContentStream,
                             public nsIInputStreamCallback,
                             public nsITransportEventSink,
                             public nsICacheListener,
                             public nsIRequestObserver,
                             public nsFtpControlConnectionListener,
                             public nsIProtocolProxyCallback
@@ -88,7 +83,6 @@ public:
    NS_DECL_ISUPPORTS_INHERITED
    NS_DECL_NSIINPUTSTREAMCALLBACK
    NS_DECL_NSITRANSPORTEVENTSINK
    NS_DECL_NSICACHELISTENER
    NS_DECL_NSIREQUESTOBSERVER
    NS_DECL_NSIPROTOCOLPROXYCALLBACK

@@ -158,46 +152,6 @@ private:
     */
    void Connect();

    /**
     * This method opens a cache entry for reading or writing depending on the
     * state of the channel and of the system (e.g., opened for reading if we
     * are offline).  This method is responsible for setting mCacheEntry if
     * there is a cache entry that can be used.  It returns true if it ends up
     * waiting (asynchronously) for access to the cache entry.  In that case,
     * the nsFtpState's OnCacheEntryAvailable method will be called once the
     * cache entry is available or if an error occurs.
     */
    bool CheckCache();

    /**
     * This method returns true if the data for this URL can be read from the
     * cache.  This method assumes that mCacheEntry is non-null.
     */
    bool CanReadCacheEntry();

    /**
     * This method causes the cache entry to be read.  Data from the cache
     * entry will be fed to the channel's listener.  This method returns true
     * if successfully reading from the cache.  This method assumes that
     * mCacheEntry is non-null and opened with read access.
     */
    bool ReadCacheEntry();

    /**
     * This method configures mDataStream with an asynchronous input stream to
     * the cache entry.  The cache entry is read on a background thread.  This
     * method assumes that mCacheEntry is non-null and opened with read access.
     */
    nsresult OpenCacheDataStream();

    /**
     * This method inserts the cache entry's output stream into the stream
     * listener chain for the FTP channel.  As a result, the cache entry
     * receives data as data is pushed to the channel's listener.  This method
     * assumes that mCacheEntry is non-null and opened with write access. 
     */
    nsresult InstallCacheListener();

    ///////////////////////////////////
    // Private members

@@ -257,9 +211,6 @@ private:
    nsresult                mControlStatus;
    nsCString               mControlReadCarryOverBuf;

    nsCOMPtr<nsICacheEntryDescriptor> mCacheEntry;
    bool                    mDoomCache;

    nsCString mSuppliedEntityID;

    nsCOMPtr<nsICancelable>  mProxyRequest;
+0 −1
Original line number Diff line number Diff line
@@ -31,7 +31,6 @@ using namespace mozilla::net;
#include "nsIObserverService.h"
#include "nsEscape.h"
#include "nsAlgorithm.h"
#include "nsICacheSession.h"

//-----------------------------------------------------------------------------

+0 −3
Original line number Diff line number Diff line
@@ -13,8 +13,6 @@
#include "nsIObserver.h"
#include "nsWeakReference.h"

class nsICacheSession;

//-----------------------------------------------------------------------------

class nsFtpProtocolHandler final : public nsIProxiedProtocolHandler
@@ -67,7 +65,6 @@ private:

    nsTArray<timerStruct*> mRootConnectionList;

    nsCOMPtr<nsICacheSession> mCacheSession;
    int32_t mIdleTimeout;

    // When "clear active logins" is performed, all idle connection are dropped