netwerk/protocol/ftp/nsFtpProtocolHandler.cpp

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
permissions
-rw-r--r--

Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  * This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
     5  *
     6  *
     7  * This Original Code has been modified by IBM Corporation.
     8  * Modifications made by IBM described herein are
     9  * Copyright (c) International Business Machines
    10  * Corporation, 2000
    11  *
    12  * Modifications to Mozilla code or documentation
    13  * identified per MPL Section 3.3
    14  *
    15  * Date         Modified by     Description of modification
    16  * 03/27/2000   IBM Corp.       Added PR_CALLBACK for Optlink
    17  *                               use in OS2
    18  */
    20 #include "mozilla/net/NeckoChild.h"
    21 #include "mozilla/net/FTPChannelChild.h"
    22 using namespace mozilla;
    23 using namespace mozilla::net;
    25 #include "nsFtpProtocolHandler.h"
    26 #include "nsFTPChannel.h"
    27 #include "nsIStandardURL.h"
    28 #include "prlog.h"
    29 #include "nsIPrefService.h"
    30 #include "nsIPrefBranch.h"
    31 #include "nsIObserverService.h"
    32 #include "nsEscape.h"
    33 #include "nsAlgorithm.h"
    34 #include "nsICacheSession.h"
    36 //-----------------------------------------------------------------------------
    38 #if defined(PR_LOGGING)
    39 //
    40 // Log module for FTP Protocol logging...
    41 //
    42 // To enable logging (see prlog.h for full details):
    43 //
    44 //    set NSPR_LOG_MODULES=nsFtp:5
    45 //    set NSPR_LOG_FILE=nspr.log
    46 //
    47 // this enables PR_LOG_DEBUG level information and places all output in
    48 // the file nspr.log
    49 //
    50 PRLogModuleInfo* gFTPLog = nullptr;
    51 #endif
    52 #undef LOG
    53 #define LOG(args) PR_LOG(gFTPLog, PR_LOG_DEBUG, args)
    55 //-----------------------------------------------------------------------------
    57 #define IDLE_TIMEOUT_PREF     "network.ftp.idleConnectionTimeout"
    58 #define IDLE_CONNECTION_LIMIT 8 /* TODO pref me */
    60 #define QOS_DATA_PREF         "network.ftp.data.qos"
    61 #define QOS_CONTROL_PREF      "network.ftp.control.qos"
    63 nsFtpProtocolHandler *gFtpHandler = nullptr;
    65 //-----------------------------------------------------------------------------
    67 nsFtpProtocolHandler::nsFtpProtocolHandler()
    68     : mIdleTimeout(-1)
    69     , mSessionId(0)
    70     , mControlQoSBits(0x00)
    71     , mDataQoSBits(0x00)
    72 {
    73 #if defined(PR_LOGGING)
    74     if (!gFTPLog)
    75         gFTPLog = PR_NewLogModule("nsFtp");
    76 #endif
    77     LOG(("FTP:creating handler @%x\n", this));
    79     gFtpHandler = this;
    80 }
    82 nsFtpProtocolHandler::~nsFtpProtocolHandler()
    83 {
    84     LOG(("FTP:destroying handler @%x\n", this));
    86     NS_ASSERTION(mRootConnectionList.Length() == 0, "why wasn't Observe called?");
    88     gFtpHandler = nullptr;
    89 }
    91 NS_IMPL_ISUPPORTS(nsFtpProtocolHandler,
    92                   nsIProtocolHandler,
    93                   nsIProxiedProtocolHandler,
    94                   nsIObserver,
    95                   nsISupportsWeakReference)
    97 nsresult
    98 nsFtpProtocolHandler::Init()
    99 {
   100     if (IsNeckoChild())
   101         NeckoChild::InitNeckoChild();
   103     if (mIdleTimeout == -1) {
   104         nsresult rv;
   105         nsCOMPtr<nsIPrefBranch> branch = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
   106         if (NS_FAILED(rv)) return rv;
   108         rv = branch->GetIntPref(IDLE_TIMEOUT_PREF, &mIdleTimeout);
   109         if (NS_FAILED(rv))
   110             mIdleTimeout = 5*60; // 5 minute default
   112         rv = branch->AddObserver(IDLE_TIMEOUT_PREF, this, true);
   113         if (NS_FAILED(rv)) return rv;
   115 	int32_t val;
   116 	rv = branch->GetIntPref(QOS_DATA_PREF, &val);
   117 	if (NS_SUCCEEDED(rv))
   118 	    mDataQoSBits = (uint8_t) clamped(val, 0, 0xff);
   120 	rv = branch->AddObserver(QOS_DATA_PREF, this, true);
   121 	if (NS_FAILED(rv)) return rv;
   123 	rv = branch->GetIntPref(QOS_CONTROL_PREF, &val);
   124 	if (NS_SUCCEEDED(rv))
   125 	    mControlQoSBits = (uint8_t) clamped(val, 0, 0xff);
   127 	rv = branch->AddObserver(QOS_CONTROL_PREF, this, true);
   128 	if (NS_FAILED(rv)) return rv;
   129     }
   131     nsCOMPtr<nsIObserverService> observerService =
   132         mozilla::services::GetObserverService();
   133     if (observerService) {
   134         observerService->AddObserver(this,
   135                                      "network:offline-about-to-go-offline",
   136                                      true);
   138         observerService->AddObserver(this,
   139                                      "net:clear-active-logins",
   140                                      true);
   141     }
   143     return NS_OK;
   144 }
   147 //-----------------------------------------------------------------------------
   148 // nsIProtocolHandler methods:
   150 NS_IMETHODIMP
   151 nsFtpProtocolHandler::GetScheme(nsACString &result)
   152 {
   153     result.AssignLiteral("ftp");
   154     return NS_OK;
   155 }
   157 NS_IMETHODIMP
   158 nsFtpProtocolHandler::GetDefaultPort(int32_t *result)
   159 {
   160     *result = 21; 
   161     return NS_OK;
   162 }
   164 NS_IMETHODIMP
   165 nsFtpProtocolHandler::GetProtocolFlags(uint32_t *result)
   166 {
   167     *result = URI_STD | ALLOWS_PROXY | ALLOWS_PROXY_HTTP |
   168         URI_LOADABLE_BY_ANYONE; 
   169     return NS_OK;
   170 }
   172 NS_IMETHODIMP
   173 nsFtpProtocolHandler::NewURI(const nsACString &aSpec,
   174                              const char *aCharset,
   175                              nsIURI *aBaseURI,
   176                              nsIURI **result)
   177 {
   178     nsAutoCString spec(aSpec);
   179     spec.Trim(" \t\n\r"); // Match NS_IsAsciiWhitespace instead of HTML5
   181     char *fwdPtr = spec.BeginWriting();
   183     // now unescape it... %xx reduced inline to resulting character
   185     int32_t len = NS_UnescapeURL(fwdPtr);
   187     // NS_UnescapeURL() modified spec's buffer, truncate to ensure
   188     // spec knows its new length.
   189     spec.Truncate(len);
   191     // return an error if we find a NUL, CR, or LF in the path
   192     if (spec.FindCharInSet(CRLF) >= 0 || spec.FindChar('\0') >= 0)
   193         return NS_ERROR_MALFORMED_URI;
   195     nsresult rv;
   196     nsCOMPtr<nsIStandardURL> url = do_CreateInstance(NS_STANDARDURL_CONTRACTID, &rv);
   197     if (NS_FAILED(rv)) return rv;
   199     rv = url->Init(nsIStandardURL::URLTYPE_AUTHORITY, 21, aSpec, aCharset, aBaseURI);
   200     if (NS_FAILED(rv)) return rv;
   202     return CallQueryInterface(url, result);
   203 }
   205 NS_IMETHODIMP
   206 nsFtpProtocolHandler::NewChannel(nsIURI* url, nsIChannel* *result)
   207 {
   208     return NewProxiedChannel(url, nullptr, 0, nullptr, result);
   209 }
   211 NS_IMETHODIMP
   212 nsFtpProtocolHandler::NewProxiedChannel(nsIURI* uri, nsIProxyInfo* proxyInfo,
   213                                         uint32_t proxyResolveFlags,
   214                                         nsIURI *proxyURI,
   215                                         nsIChannel* *result)
   216 {
   217     NS_ENSURE_ARG_POINTER(uri);
   218     nsRefPtr<nsBaseChannel> channel;
   219     if (IsNeckoChild())
   220         channel = new FTPChannelChild(uri);
   221     else
   222         channel = new nsFtpChannel(uri, proxyInfo);
   224     nsresult rv = channel->Init();
   225     if (NS_FAILED(rv)) {
   226         return rv;
   227     }
   229     channel.forget(result);
   230     return rv;
   231 }
   233 NS_IMETHODIMP 
   234 nsFtpProtocolHandler::AllowPort(int32_t port, const char *scheme, bool *_retval)
   235 {
   236     *_retval = (port == 21 || port == 22);
   237     return NS_OK;
   238 }
   240 // connection cache methods
   242 void
   243 nsFtpProtocolHandler::Timeout(nsITimer *aTimer, void *aClosure)
   244 {
   245     LOG(("FTP:timeout reached for %p\n", aClosure));
   247     bool found = gFtpHandler->mRootConnectionList.RemoveElement(aClosure);
   248     if (!found) {
   249         NS_ERROR("timerStruct not found");
   250         return;
   251     }
   253     timerStruct* s = (timerStruct*)aClosure;
   254     delete s;
   255 }
   257 nsresult
   258 nsFtpProtocolHandler::RemoveConnection(nsIURI *aKey, nsFtpControlConnection* *_retval)
   259 {
   260     NS_ASSERTION(_retval, "null pointer");
   261     NS_ASSERTION(aKey, "null pointer");
   263     *_retval = nullptr;
   265     nsAutoCString spec;
   266     aKey->GetPrePath(spec);
   268     LOG(("FTP:removing connection for %s\n", spec.get()));
   270     timerStruct* ts = nullptr;
   271     uint32_t i;
   272     bool found = false;
   274     for (i=0;i<mRootConnectionList.Length();++i) {
   275         ts = mRootConnectionList[i];
   276         if (strcmp(spec.get(), ts->key) == 0) {
   277             found = true;
   278             mRootConnectionList.RemoveElementAt(i);
   279             break;
   280         }
   281     }
   283     if (!found)
   284         return NS_ERROR_FAILURE;
   286     // swap connection ownership
   287     *_retval = ts->conn;
   288     ts->conn = nullptr;
   289     delete ts;
   291     return NS_OK;
   292 }
   294 nsresult
   295 nsFtpProtocolHandler::InsertConnection(nsIURI *aKey, nsFtpControlConnection *aConn)
   296 {
   297     NS_ASSERTION(aConn, "null pointer");
   298     NS_ASSERTION(aKey, "null pointer");
   300     if (aConn->mSessionId != mSessionId)
   301         return NS_ERROR_FAILURE;
   303     nsAutoCString spec;
   304     aKey->GetPrePath(spec);
   306     LOG(("FTP:inserting connection for %s\n", spec.get()));
   308     nsresult rv;
   309     nsCOMPtr<nsITimer> timer = do_CreateInstance("@mozilla.org/timer;1", &rv);
   310     if (NS_FAILED(rv)) return rv;
   312     timerStruct* ts = new timerStruct();
   313     if (!ts)
   314         return NS_ERROR_OUT_OF_MEMORY;
   316     rv = timer->InitWithFuncCallback(nsFtpProtocolHandler::Timeout,
   317                                      ts,
   318                                      mIdleTimeout*1000,
   319                                      nsITimer::TYPE_REPEATING_SLACK);
   320     if (NS_FAILED(rv)) {
   321         delete ts;
   322         return rv;
   323     }
   325     ts->key = ToNewCString(spec);
   326     if (!ts->key) {
   327         delete ts;
   328         return NS_ERROR_OUT_OF_MEMORY;
   329     }
   331     NS_ADDREF(aConn);
   332     ts->conn = aConn;
   333     ts->timer = timer;
   335     //
   336     // limit number of idle connections.  if limit is reached, then prune
   337     // eldest connection with matching key.  if none matching, then prune
   338     // eldest connection.
   339     //
   340     if (mRootConnectionList.Length() == IDLE_CONNECTION_LIMIT) {
   341         uint32_t i;
   342         for (i=0;i<mRootConnectionList.Length();++i) {
   343             timerStruct *candidate = mRootConnectionList[i];
   344             if (strcmp(candidate->key, ts->key) == 0) {
   345                 mRootConnectionList.RemoveElementAt(i);
   346                 delete candidate;
   347                 break;
   348             }
   349         }
   350         if (mRootConnectionList.Length() == IDLE_CONNECTION_LIMIT) {
   351             timerStruct *eldest = mRootConnectionList[0];
   352             mRootConnectionList.RemoveElementAt(0);
   353             delete eldest;
   354         }
   355     }
   357     mRootConnectionList.AppendElement(ts);
   358     return NS_OK;
   359 }
   361 //-----------------------------------------------------------------------------
   362 // nsIObserver
   364 NS_IMETHODIMP
   365 nsFtpProtocolHandler::Observe(nsISupports *aSubject,
   366                               const char *aTopic,
   367                               const char16_t *aData)
   368 {
   369     LOG(("FTP:observing [%s]\n", aTopic));
   371     if (!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
   372         nsCOMPtr<nsIPrefBranch> branch = do_QueryInterface(aSubject);
   373         if (!branch) {
   374             NS_ERROR("no prefbranch");
   375             return NS_ERROR_UNEXPECTED;
   376         }
   377         int32_t val;
   378         nsresult rv = branch->GetIntPref(IDLE_TIMEOUT_PREF, &val);
   379         if (NS_SUCCEEDED(rv))
   380             mIdleTimeout = val;
   382 	rv = branch->GetIntPref(QOS_DATA_PREF, &val);
   383 	if (NS_SUCCEEDED(rv))
   384 	    mDataQoSBits = (uint8_t) clamped(val, 0, 0xff);
   386 	rv = branch->GetIntPref(QOS_CONTROL_PREF, &val);
   387 	if (NS_SUCCEEDED(rv))
   388 	    mControlQoSBits = (uint8_t) clamped(val, 0, 0xff);
   389     } else if (!strcmp(aTopic, "network:offline-about-to-go-offline")) {
   390         ClearAllConnections();
   391     } else if (!strcmp(aTopic, "net:clear-active-logins")) {
   392         ClearAllConnections();
   393         mSessionId++;
   394     } else {
   395         NS_NOTREACHED("unexpected topic");
   396     }
   398     return NS_OK;
   399 }
   401 void
   402 nsFtpProtocolHandler::ClearAllConnections()
   403 {
   404     uint32_t i;
   405     for (i=0;i<mRootConnectionList.Length();++i)
   406         delete mRootConnectionList[i];
   407     mRootConnectionList.Clear();
   408 }

mercurial