LCOV - code coverage report
Current view: top level - netwerk/protocol/ftp - nsFtpProtocolHandler.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 178 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 21 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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             :  */
      19             : 
      20             : #include "mozilla/net/NeckoChild.h"
      21             : #include "mozilla/net/FTPChannelChild.h"
      22             : using namespace mozilla;
      23             : using namespace mozilla::net;
      24             : 
      25             : #include "nsFtpProtocolHandler.h"
      26             : #include "nsFTPChannel.h"
      27             : #include "nsIStandardURL.h"
      28             : #include "mozilla/Logging.h"
      29             : #include "nsIPrefService.h"
      30             : #include "nsIPrefBranch.h"
      31             : #include "nsIObserverService.h"
      32             : #include "nsEscape.h"
      33             : #include "nsAlgorithm.h"
      34             : 
      35             : //-----------------------------------------------------------------------------
      36             : 
      37             : //
      38             : // Log module for FTP Protocol logging...
      39             : //
      40             : // To enable logging (see prlog.h for full details):
      41             : //
      42             : //    set MOZ_LOG=nsFtp:5
      43             : //    set MOZ_LOG_FILE=ftp.log
      44             : //
      45             : // This enables LogLevel::Debug level information and places all output in
      46             : // the file ftp.log.
      47             : //
      48             : LazyLogModule gFTPLog("nsFtp");
      49             : #undef LOG
      50             : #define LOG(args) MOZ_LOG(gFTPLog, mozilla::LogLevel::Debug, args)
      51             : 
      52             : //-----------------------------------------------------------------------------
      53             : 
      54             : #define IDLE_TIMEOUT_PREF     "network.ftp.idleConnectionTimeout"
      55             : #define IDLE_CONNECTION_LIMIT 8 /* TODO pref me */
      56             : 
      57             : #define QOS_DATA_PREF         "network.ftp.data.qos"
      58             : #define QOS_CONTROL_PREF      "network.ftp.control.qos"
      59             : 
      60             : nsFtpProtocolHandler *gFtpHandler = nullptr;
      61             : 
      62             : //-----------------------------------------------------------------------------
      63             : 
      64           0 : nsFtpProtocolHandler::nsFtpProtocolHandler()
      65             :     : mIdleTimeout(-1)
      66             :     , mSessionId(0)
      67             :     , mControlQoSBits(0x00)
      68           0 :     , mDataQoSBits(0x00)
      69             : {
      70           0 :     LOG(("FTP:creating handler @%p\n", this));
      71             : 
      72           0 :     gFtpHandler = this;
      73           0 : }
      74             : 
      75           0 : nsFtpProtocolHandler::~nsFtpProtocolHandler()
      76             : {
      77           0 :     LOG(("FTP:destroying handler @%p\n", this));
      78             : 
      79           0 :     NS_ASSERTION(mRootConnectionList.Length() == 0, "why wasn't Observe called?");
      80             : 
      81           0 :     gFtpHandler = nullptr;
      82           0 : }
      83             : 
      84           0 : NS_IMPL_ISUPPORTS(nsFtpProtocolHandler,
      85             :                   nsIProtocolHandler,
      86             :                   nsIProxiedProtocolHandler,
      87             :                   nsIObserver,
      88             :                   nsISupportsWeakReference)
      89             : 
      90             : nsresult
      91           0 : nsFtpProtocolHandler::Init()
      92             : {
      93           0 :     if (IsNeckoChild())
      94           0 :         NeckoChild::InitNeckoChild();
      95             : 
      96           0 :     if (mIdleTimeout == -1) {
      97             :         nsresult rv;
      98           0 :         nsCOMPtr<nsIPrefBranch> branch = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
      99           0 :         if (NS_FAILED(rv)) return rv;
     100             : 
     101           0 :         rv = branch->GetIntPref(IDLE_TIMEOUT_PREF, &mIdleTimeout);
     102           0 :         if (NS_FAILED(rv))
     103           0 :             mIdleTimeout = 5*60; // 5 minute default
     104             : 
     105           0 :         rv = branch->AddObserver(IDLE_TIMEOUT_PREF, this, true);
     106           0 :         if (NS_FAILED(rv)) return rv;
     107             : 
     108             :         int32_t val;
     109           0 :         rv = branch->GetIntPref(QOS_DATA_PREF, &val);
     110           0 :         if (NS_SUCCEEDED(rv))
     111           0 :             mDataQoSBits = (uint8_t) clamped(val, 0, 0xff);
     112             : 
     113           0 :         rv = branch->AddObserver(QOS_DATA_PREF, this, true);
     114           0 :         if (NS_FAILED(rv)) return rv;
     115             : 
     116           0 :         rv = branch->GetIntPref(QOS_CONTROL_PREF, &val);
     117           0 :         if (NS_SUCCEEDED(rv))
     118           0 :             mControlQoSBits = (uint8_t) clamped(val, 0, 0xff);
     119             : 
     120           0 :         rv = branch->AddObserver(QOS_CONTROL_PREF, this, true);
     121           0 :         if (NS_FAILED(rv)) return rv;
     122             :     }
     123             : 
     124             :     nsCOMPtr<nsIObserverService> observerService =
     125           0 :         mozilla::services::GetObserverService();
     126           0 :     if (observerService) {
     127           0 :         observerService->AddObserver(this,
     128             :                                      "network:offline-about-to-go-offline",
     129           0 :                                      true);
     130             : 
     131           0 :         observerService->AddObserver(this,
     132             :                                      "net:clear-active-logins",
     133           0 :                                      true);
     134             :     }
     135             : 
     136           0 :     return NS_OK;
     137             : }
     138             : 
     139             : 
     140             : //-----------------------------------------------------------------------------
     141             : // nsIProtocolHandler methods:
     142             : 
     143             : NS_IMETHODIMP
     144           0 : nsFtpProtocolHandler::GetScheme(nsACString &result)
     145             : {
     146           0 :     result.AssignLiteral("ftp");
     147           0 :     return NS_OK;
     148             : }
     149             : 
     150             : NS_IMETHODIMP
     151           0 : nsFtpProtocolHandler::GetDefaultPort(int32_t *result)
     152             : {
     153           0 :     *result = 21;
     154           0 :     return NS_OK;
     155             : }
     156             : 
     157             : NS_IMETHODIMP
     158           0 : nsFtpProtocolHandler::GetProtocolFlags(uint32_t *result)
     159             : {
     160           0 :     *result = URI_STD | ALLOWS_PROXY | ALLOWS_PROXY_HTTP |
     161             :         URI_LOADABLE_BY_ANYONE;
     162           0 :     return NS_OK;
     163             : }
     164             : 
     165             : NS_IMETHODIMP
     166           0 : nsFtpProtocolHandler::NewURI(const nsACString &aSpec,
     167             :                              const char *aCharset,
     168             :                              nsIURI *aBaseURI,
     169             :                              nsIURI **result)
     170             : {
     171           0 :     nsAutoCString spec(aSpec);
     172           0 :     spec.Trim(" \t\n\r"); // Match NS_IsAsciiWhitespace instead of HTML5
     173             : 
     174           0 :     char *fwdPtr = spec.BeginWriting();
     175             : 
     176             :     // now unescape it... %xx reduced inline to resulting character
     177             : 
     178           0 :     int32_t len = NS_UnescapeURL(fwdPtr);
     179             : 
     180             :     // NS_UnescapeURL() modified spec's buffer, truncate to ensure
     181             :     // spec knows its new length.
     182           0 :     spec.Truncate(len);
     183             : 
     184             :     // return an error if we find a NUL, CR, or LF in the path
     185           0 :     if (spec.FindCharInSet(CRLF) >= 0 || spec.FindChar('\0') >= 0)
     186           0 :         return NS_ERROR_MALFORMED_URI;
     187             : 
     188             :     nsresult rv;
     189           0 :     nsCOMPtr<nsIStandardURL> url = do_CreateInstance(NS_STANDARDURL_CONTRACTID, &rv);
     190           0 :     if (NS_FAILED(rv)) return rv;
     191             : 
     192           0 :     rv = url->Init(nsIStandardURL::URLTYPE_AUTHORITY, 21, aSpec, aCharset, aBaseURI);
     193           0 :     if (NS_FAILED(rv)) return rv;
     194             : 
     195           0 :     return CallQueryInterface(url, result);
     196             : }
     197             : 
     198             : NS_IMETHODIMP
     199           0 : nsFtpProtocolHandler::NewChannel2(nsIURI* url,
     200             :                                   nsILoadInfo* aLoadInfo,
     201             :                                   nsIChannel** result)
     202             : {
     203           0 :     return NewProxiedChannel2(url, nullptr, 0, nullptr, aLoadInfo, result);
     204             : }
     205             : 
     206             : NS_IMETHODIMP
     207           0 : nsFtpProtocolHandler::NewChannel(nsIURI* url, nsIChannel* *result)
     208             : {
     209           0 :     return NewChannel2(url, nullptr, result);
     210             : }
     211             : 
     212             : NS_IMETHODIMP
     213           0 : nsFtpProtocolHandler::NewProxiedChannel2(nsIURI* uri, nsIProxyInfo* proxyInfo,
     214             :                                          uint32_t proxyResolveFlags,
     215             :                                          nsIURI *proxyURI,
     216             :                                          nsILoadInfo* aLoadInfo,
     217             :                                          nsIChannel* *result)
     218             : {
     219           0 :     NS_ENSURE_ARG_POINTER(uri);
     220           0 :     RefPtr<nsBaseChannel> channel;
     221           0 :     if (IsNeckoChild())
     222           0 :         channel = new FTPChannelChild(uri);
     223             :     else
     224           0 :         channel = new nsFtpChannel(uri, proxyInfo);
     225             : 
     226           0 :     nsresult rv = channel->Init();
     227           0 :     if (NS_FAILED(rv)) {
     228           0 :         return rv;
     229             :     }
     230             : 
     231             :     // set the loadInfo on the new channel
     232           0 :     rv = channel->SetLoadInfo(aLoadInfo);
     233           0 :     if (NS_FAILED(rv)) {
     234           0 :         return rv;
     235             :     }
     236             : 
     237           0 :     channel.forget(result);
     238           0 :     return rv;
     239             : }
     240             : 
     241             : NS_IMETHODIMP
     242           0 : nsFtpProtocolHandler::NewProxiedChannel(nsIURI* uri, nsIProxyInfo* proxyInfo,
     243             :                                         uint32_t proxyResolveFlags,
     244             :                                         nsIURI *proxyURI,
     245             :                                         nsIChannel* *result)
     246             : {
     247             :   return NewProxiedChannel2(uri, proxyInfo, proxyResolveFlags,
     248             :                             proxyURI, nullptr /*loadinfo*/,
     249           0 :                             result);
     250             : }
     251             : 
     252             : NS_IMETHODIMP
     253           0 : nsFtpProtocolHandler::AllowPort(int32_t port, const char *scheme, bool *_retval)
     254             : {
     255           0 :     *_retval = (port == 21 || port == 22);
     256           0 :     return NS_OK;
     257             : }
     258             : 
     259             : // connection cache methods
     260             : 
     261             : void
     262           0 : nsFtpProtocolHandler::Timeout(nsITimer *aTimer, void *aClosure)
     263             : {
     264           0 :     LOG(("FTP:timeout reached for %p\n", aClosure));
     265             : 
     266           0 :     bool found = gFtpHandler->mRootConnectionList.RemoveElement(aClosure);
     267           0 :     if (!found) {
     268           0 :         NS_ERROR("timerStruct not found");
     269           0 :         return;
     270             :     }
     271             : 
     272           0 :     timerStruct* s = (timerStruct*)aClosure;
     273           0 :     delete s;
     274             : }
     275             : 
     276             : nsresult
     277           0 : nsFtpProtocolHandler::RemoveConnection(nsIURI *aKey, nsFtpControlConnection* *_retval)
     278             : {
     279           0 :     NS_ASSERTION(_retval, "null pointer");
     280           0 :     NS_ASSERTION(aKey, "null pointer");
     281             : 
     282           0 :     *_retval = nullptr;
     283             : 
     284           0 :     nsAutoCString spec;
     285           0 :     aKey->GetPrePath(spec);
     286             : 
     287           0 :     LOG(("FTP:removing connection for %s\n", spec.get()));
     288             : 
     289           0 :     timerStruct* ts = nullptr;
     290             :     uint32_t i;
     291           0 :     bool found = false;
     292             : 
     293           0 :     for (i=0;i<mRootConnectionList.Length();++i) {
     294           0 :         ts = mRootConnectionList[i];
     295           0 :         if (strcmp(spec.get(), ts->key) == 0) {
     296           0 :             found = true;
     297           0 :             mRootConnectionList.RemoveElementAt(i);
     298           0 :             break;
     299             :         }
     300             :     }
     301             : 
     302           0 :     if (!found)
     303           0 :         return NS_ERROR_FAILURE;
     304             : 
     305             :     // swap connection ownership
     306           0 :     ts->conn.forget(_retval);
     307           0 :     delete ts;
     308             : 
     309           0 :     return NS_OK;
     310             : }
     311             : 
     312             : nsresult
     313           0 : nsFtpProtocolHandler::InsertConnection(nsIURI *aKey, nsFtpControlConnection *aConn)
     314             : {
     315           0 :     NS_ASSERTION(aConn, "null pointer");
     316           0 :     NS_ASSERTION(aKey, "null pointer");
     317             : 
     318           0 :     if (aConn->mSessionId != mSessionId)
     319           0 :         return NS_ERROR_FAILURE;
     320             : 
     321           0 :     nsAutoCString spec;
     322           0 :     aKey->GetPrePath(spec);
     323             : 
     324           0 :     LOG(("FTP:inserting connection for %s\n", spec.get()));
     325             : 
     326             :     nsresult rv;
     327           0 :     nsCOMPtr<nsITimer> timer = do_CreateInstance("@mozilla.org/timer;1", &rv);
     328           0 :     if (NS_FAILED(rv)) return rv;
     329             : 
     330           0 :     timerStruct* ts = new timerStruct();
     331           0 :     if (!ts)
     332           0 :         return NS_ERROR_OUT_OF_MEMORY;
     333             : 
     334           0 :     rv = timer->InitWithNamedFuncCallback(
     335             :       nsFtpProtocolHandler::Timeout,
     336             :       ts,
     337           0 :       mIdleTimeout * 1000,
     338             :       nsITimer::TYPE_REPEATING_SLACK,
     339           0 :       "nsFtpProtocolHandler::InsertConnection");
     340           0 :     if (NS_FAILED(rv)) {
     341           0 :         delete ts;
     342           0 :         return rv;
     343             :     }
     344             : 
     345           0 :     ts->key = ToNewCString(spec);
     346           0 :     if (!ts->key) {
     347           0 :         delete ts;
     348           0 :         return NS_ERROR_OUT_OF_MEMORY;
     349             :     }
     350             : 
     351             :     // ts->conn is a RefPtr
     352           0 :     ts->conn = aConn;
     353           0 :     ts->timer = timer;
     354             : 
     355             :     //
     356             :     // limit number of idle connections.  if limit is reached, then prune
     357             :     // eldest connection with matching key.  if none matching, then prune
     358             :     // eldest connection.
     359             :     //
     360           0 :     if (mRootConnectionList.Length() == IDLE_CONNECTION_LIMIT) {
     361             :         uint32_t i;
     362           0 :         for (i=0;i<mRootConnectionList.Length();++i) {
     363           0 :             timerStruct *candidate = mRootConnectionList[i];
     364           0 :             if (strcmp(candidate->key, ts->key) == 0) {
     365           0 :                 mRootConnectionList.RemoveElementAt(i);
     366           0 :                 delete candidate;
     367           0 :                 break;
     368             :             }
     369             :         }
     370           0 :         if (mRootConnectionList.Length() == IDLE_CONNECTION_LIMIT) {
     371           0 :             timerStruct *eldest = mRootConnectionList[0];
     372           0 :             mRootConnectionList.RemoveElementAt(0);
     373           0 :             delete eldest;
     374             :         }
     375             :     }
     376             : 
     377           0 :     mRootConnectionList.AppendElement(ts);
     378           0 :     return NS_OK;
     379             : }
     380             : 
     381             : //-----------------------------------------------------------------------------
     382             : // nsIObserver
     383             : 
     384             : NS_IMETHODIMP
     385           0 : nsFtpProtocolHandler::Observe(nsISupports *aSubject,
     386             :                               const char *aTopic,
     387             :                               const char16_t *aData)
     388             : {
     389           0 :     LOG(("FTP:observing [%s]\n", aTopic));
     390             : 
     391           0 :     if (!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
     392           0 :         nsCOMPtr<nsIPrefBranch> branch = do_QueryInterface(aSubject);
     393           0 :         if (!branch) {
     394           0 :             NS_ERROR("no prefbranch");
     395           0 :             return NS_ERROR_UNEXPECTED;
     396             :         }
     397             :         int32_t val;
     398           0 :         nsresult rv = branch->GetIntPref(IDLE_TIMEOUT_PREF, &val);
     399           0 :         if (NS_SUCCEEDED(rv))
     400           0 :             mIdleTimeout = val;
     401             : 
     402           0 :         rv = branch->GetIntPref(QOS_DATA_PREF, &val);
     403           0 :         if (NS_SUCCEEDED(rv))
     404           0 :             mDataQoSBits = (uint8_t) clamped(val, 0, 0xff);
     405             : 
     406           0 :         rv = branch->GetIntPref(QOS_CONTROL_PREF, &val);
     407           0 :         if (NS_SUCCEEDED(rv))
     408           0 :             mControlQoSBits = (uint8_t) clamped(val, 0, 0xff);
     409           0 :     } else if (!strcmp(aTopic, "network:offline-about-to-go-offline")) {
     410           0 :         ClearAllConnections();
     411           0 :     } else if (!strcmp(aTopic, "net:clear-active-logins")) {
     412           0 :         ClearAllConnections();
     413           0 :         mSessionId++;
     414             :     } else {
     415           0 :         NS_NOTREACHED("unexpected topic");
     416             :     }
     417             : 
     418           0 :     return NS_OK;
     419             : }
     420             : 
     421             : void
     422           0 : nsFtpProtocolHandler::ClearAllConnections()
     423             : {
     424             :     uint32_t i;
     425           0 :     for (i=0;i<mRootConnectionList.Length();++i)
     426           0 :         delete mRootConnectionList[i];
     427           0 :     mRootConnectionList.Clear();
     428           0 : }

Generated by: LCOV version 1.13