LCOV - code coverage report
Current view: directory - netwerk/protocol/ftp - nsFtpProtocolHandler.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 174 78 44.8 %
Date: 2012-06-02 Functions: 19 14 73.7 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2                 :  * ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is mozilla.org code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Netscape Communications Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *
      24                 :  * Alternatively, the contents of this file may be used under the terms of
      25                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      26                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      27                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      28                 :  * of those above. If you wish to allow use of your version of this file only
      29                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      30                 :  * use your version of this file under the terms of the MPL, indicate your
      31                 :  * decision by deleting the provisions above and replace them with the notice
      32                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      33                 :  * the provisions above, a recipient may use your version of this file under
      34                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      35                 :  *
      36                 :  * ***** END LICENSE BLOCK *****
      37                 :  *
      38                 :  *
      39                 :  * This Original Code has been modified by IBM Corporation.
      40                 :  * Modifications made by IBM described herein are
      41                 :  * Copyright (c) International Business Machines
      42                 :  * Corporation, 2000
      43                 :  *
      44                 :  * Modifications to Mozilla code or documentation
      45                 :  * identified per MPL Section 3.3
      46                 :  *
      47                 :  * Date         Modified by     Description of modification
      48                 :  * 03/27/2000   IBM Corp.       Added PR_CALLBACK for Optlink
      49                 :  *                               use in OS2
      50                 :  */
      51                 : 
      52                 : #include "mozilla/net/NeckoChild.h"
      53                 : #include "mozilla/net/FTPChannelChild.h"
      54                 : using namespace mozilla;
      55                 : using namespace mozilla::net;
      56                 : 
      57                 : #include "nsFtpProtocolHandler.h"
      58                 : #include "nsFTPChannel.h"
      59                 : #include "nsIURL.h"
      60                 : #include "nsIStandardURL.h"
      61                 : #include "nsCRT.h"
      62                 : #include "nsIComponentManager.h"
      63                 : #include "nsIInterfaceRequestor.h"
      64                 : #include "nsIInterfaceRequestorUtils.h"
      65                 : #include "nsIProgressEventSink.h"
      66                 : #include "prlog.h"
      67                 : #include "nsNetUtil.h"
      68                 : #include "nsIPrefService.h"
      69                 : #include "nsIPrefBranch.h"
      70                 : #include "nsIObserverService.h"
      71                 : #include "nsEscape.h"
      72                 : #include "nsAlgorithm.h"
      73                 : 
      74                 : //-----------------------------------------------------------------------------
      75                 : 
      76                 : #if defined(PR_LOGGING)
      77                 : //
      78                 : // Log module for FTP Protocol logging...
      79                 : //
      80                 : // To enable logging (see prlog.h for full details):
      81                 : //
      82                 : //    set NSPR_LOG_MODULES=nsFtp:5
      83                 : //    set NSPR_LOG_FILE=nspr.log
      84                 : //
      85                 : // this enables PR_LOG_DEBUG level information and places all output in
      86                 : // the file nspr.log
      87                 : //
      88                 : PRLogModuleInfo* gFTPLog = nsnull;
      89                 : #endif
      90                 : #undef LOG
      91                 : #define LOG(args) PR_LOG(gFTPLog, PR_LOG_DEBUG, args)
      92                 : 
      93                 : //-----------------------------------------------------------------------------
      94                 : 
      95                 : #define IDLE_TIMEOUT_PREF     "network.ftp.idleConnectionTimeout"
      96                 : #define IDLE_CONNECTION_LIMIT 8 /* TODO pref me */
      97                 : 
      98                 : #define QOS_DATA_PREF         "network.ftp.data.qos"
      99                 : #define QOS_CONTROL_PREF      "network.ftp.control.qos"
     100                 : 
     101                 : nsFtpProtocolHandler *gFtpHandler = nsnull;
     102                 : 
     103                 : //-----------------------------------------------------------------------------
     104                 : 
     105              18 : nsFtpProtocolHandler::nsFtpProtocolHandler()
     106                 :     : mIdleTimeout(-1)
     107                 :     , mSessionId(0)
     108                 :     , mControlQoSBits(0x00)
     109              18 :     , mDataQoSBits(0x00)
     110                 : {
     111                 : #if defined(PR_LOGGING)
     112              18 :     if (!gFTPLog)
     113              18 :         gFTPLog = PR_NewLogModule("nsFtp");
     114                 : #endif
     115              18 :     LOG(("FTP:creating handler @%x\n", this));
     116                 : 
     117              18 :     gFtpHandler = this;
     118              18 : }
     119                 : 
     120              54 : nsFtpProtocolHandler::~nsFtpProtocolHandler()
     121                 : {
     122              18 :     LOG(("FTP:destroying handler @%x\n", this));
     123                 : 
     124              18 :     NS_ASSERTION(mRootConnectionList.Length() == 0, "why wasn't Observe called?");
     125                 : 
     126              18 :     gFtpHandler = nsnull;
     127              72 : }
     128                 : 
     129            3428 : NS_IMPL_THREADSAFE_ISUPPORTS4(nsFtpProtocolHandler,
     130                 :                               nsIProtocolHandler,
     131                 :                               nsIProxiedProtocolHandler,
     132                 :                               nsIObserver,
     133                 :                               nsISupportsWeakReference)
     134                 : 
     135                 : nsresult
     136              18 : nsFtpProtocolHandler::Init()
     137                 : {
     138              18 :     if (IsNeckoChild())
     139               0 :         NeckoChild::InitNeckoChild();
     140                 : 
     141              18 :     if (mIdleTimeout == -1) {
     142                 :         nsresult rv;
     143              36 :         nsCOMPtr<nsIPrefBranch> branch = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
     144              18 :         if (NS_FAILED(rv)) return rv;
     145                 : 
     146              18 :         rv = branch->GetIntPref(IDLE_TIMEOUT_PREF, &mIdleTimeout);
     147              18 :         if (NS_FAILED(rv))
     148               0 :             mIdleTimeout = 5*60; // 5 minute default
     149                 : 
     150              18 :         rv = branch->AddObserver(IDLE_TIMEOUT_PREF, this, true);
     151              18 :         if (NS_FAILED(rv)) return rv;
     152                 : 
     153                 :         PRInt32 val;
     154              18 :         rv = branch->GetIntPref(QOS_DATA_PREF, &val);
     155              18 :         if (NS_SUCCEEDED(rv))
     156              18 :             mDataQoSBits = (PRUint8) clamped(val, 0, 0xff);
     157                 : 
     158              18 :         rv = branch->AddObserver(QOS_DATA_PREF, this, true);
     159              18 :         if (NS_FAILED(rv)) return rv;
     160                 : 
     161              18 :         rv = branch->GetIntPref(QOS_CONTROL_PREF, &val);
     162              18 :         if (NS_SUCCEEDED(rv))
     163              18 :             mControlQoSBits = (PRUint8) clamped(val, 0, 0xff);
     164                 : 
     165              18 :         rv = branch->AddObserver(QOS_CONTROL_PREF, this, true);
     166              18 :         if (NS_FAILED(rv)) return rv;
     167                 :     }
     168                 : 
     169                 :     nsCOMPtr<nsIObserverService> observerService =
     170              36 :         mozilla::services::GetObserverService();
     171              18 :     if (observerService) {
     172              18 :         observerService->AddObserver(this,
     173                 :                                      "network:offline-about-to-go-offline",
     174              18 :                                      true);
     175                 : 
     176              18 :         observerService->AddObserver(this,
     177                 :                                      "net:clear-active-logins",
     178              18 :                                      true);
     179                 :     }
     180                 : 
     181              18 :     return NS_OK;
     182                 : }
     183                 : 
     184                 :     
     185                 : //-----------------------------------------------------------------------------
     186                 : // nsIProtocolHandler methods:
     187                 : 
     188                 : NS_IMETHODIMP
     189               0 : nsFtpProtocolHandler::GetScheme(nsACString &result)
     190                 : {
     191               0 :     result.AssignLiteral("ftp");
     192               0 :     return NS_OK;
     193                 : }
     194                 : 
     195                 : NS_IMETHODIMP
     196              19 : nsFtpProtocolHandler::GetDefaultPort(PRInt32 *result)
     197                 : {
     198              19 :     *result = 21; 
     199              19 :     return NS_OK;
     200                 : }
     201                 : 
     202                 : NS_IMETHODIMP
     203              38 : nsFtpProtocolHandler::GetProtocolFlags(PRUint32 *result)
     204                 : {
     205                 :     *result = URI_STD | ALLOWS_PROXY | ALLOWS_PROXY_HTTP |
     206              38 :         URI_LOADABLE_BY_ANYONE; 
     207              38 :     return NS_OK;
     208                 : }
     209                 : 
     210                 : NS_IMETHODIMP
     211             285 : nsFtpProtocolHandler::NewURI(const nsACString &aSpec,
     212                 :                              const char *aCharset,
     213                 :                              nsIURI *aBaseURI,
     214                 :                              nsIURI **result)
     215                 : {
     216             570 :     nsCAutoString spec(aSpec);
     217             285 :     spec.Trim(" \t\n\r"); // Match NS_IsAsciiWhitespace instead of HTML5
     218                 : 
     219             285 :     char *fwdPtr = spec.BeginWriting();
     220                 : 
     221                 :     // now unescape it... %xx reduced inline to resulting character
     222                 : 
     223             285 :     PRInt32 len = NS_UnescapeURL(fwdPtr);
     224                 : 
     225                 :     // NS_UnescapeURL() modified spec's buffer, truncate to ensure
     226                 :     // spec knows its new length.
     227             285 :     spec.Truncate(len);
     228                 : 
     229                 :     // return an error if we find a NUL, CR, or LF in the path
     230             285 :     if (spec.FindCharInSet(CRLF) >= 0 || spec.FindChar('\0') >= 0)
     231               0 :         return NS_ERROR_MALFORMED_URI;
     232                 : 
     233                 :     nsresult rv;
     234             570 :     nsCOMPtr<nsIStandardURL> url = do_CreateInstance(NS_STANDARDURL_CONTRACTID, &rv);
     235             285 :     if (NS_FAILED(rv)) return rv;
     236                 : 
     237             285 :     rv = url->Init(nsIStandardURL::URLTYPE_AUTHORITY, 21, aSpec, aCharset, aBaseURI);
     238             285 :     if (NS_FAILED(rv)) return rv;
     239                 : 
     240             285 :     return CallQueryInterface(url, result);
     241                 : }
     242                 : 
     243                 : NS_IMETHODIMP
     244              19 : nsFtpProtocolHandler::NewChannel(nsIURI* url, nsIChannel* *result)
     245                 : {
     246              19 :     return NewProxiedChannel(url, nsnull, result);
     247                 : }
     248                 : 
     249                 : NS_IMETHODIMP
     250              19 : nsFtpProtocolHandler::NewProxiedChannel(nsIURI* uri, nsIProxyInfo* proxyInfo,
     251                 :                                         nsIChannel* *result)
     252                 : {
     253              19 :     NS_ENSURE_ARG_POINTER(uri);
     254              38 :     nsRefPtr<nsBaseChannel> channel;
     255              19 :     if (IsNeckoChild())
     256               0 :         channel = new FTPChannelChild(uri);
     257                 :     else
     258              19 :         channel = new nsFtpChannel(uri, proxyInfo);
     259                 : 
     260              19 :     nsresult rv = channel->Init();
     261              19 :     if (NS_FAILED(rv)) {
     262               0 :         return rv;
     263                 :     }
     264                 :     
     265              19 :     channel.forget(result);
     266              19 :     return rv;
     267                 : }
     268                 : 
     269                 : NS_IMETHODIMP 
     270               0 : nsFtpProtocolHandler::AllowPort(PRInt32 port, const char *scheme, bool *_retval)
     271                 : {
     272               0 :     *_retval = (port == 21 || port == 22);
     273               0 :     return NS_OK;
     274                 : }
     275                 : 
     276                 : // connection cache methods
     277                 : 
     278                 : void
     279               0 : nsFtpProtocolHandler::Timeout(nsITimer *aTimer, void *aClosure)
     280                 : {
     281               0 :     LOG(("FTP:timeout reached for %p\n", aClosure));
     282                 : 
     283               0 :     bool found = gFtpHandler->mRootConnectionList.RemoveElement(aClosure);
     284               0 :     if (!found) {
     285               0 :         NS_ERROR("timerStruct not found");
     286               0 :         return;
     287                 :     }
     288                 : 
     289               0 :     timerStruct* s = (timerStruct*)aClosure;
     290               0 :     delete s;
     291                 : }
     292                 : 
     293                 : nsresult
     294               0 : nsFtpProtocolHandler::RemoveConnection(nsIURI *aKey, nsFtpControlConnection* *_retval)
     295                 : {
     296               0 :     NS_ASSERTION(_retval, "null pointer");
     297               0 :     NS_ASSERTION(aKey, "null pointer");
     298                 :     
     299               0 :     *_retval = nsnull;
     300                 : 
     301               0 :     nsCAutoString spec;
     302               0 :     aKey->GetPrePath(spec);
     303                 :     
     304               0 :     LOG(("FTP:removing connection for %s\n", spec.get()));
     305                 :    
     306               0 :     timerStruct* ts = nsnull;
     307                 :     PRUint32 i;
     308               0 :     bool found = false;
     309                 :     
     310               0 :     for (i=0;i<mRootConnectionList.Length();++i) {
     311               0 :         ts = mRootConnectionList[i];
     312               0 :         if (strcmp(spec.get(), ts->key) == 0) {
     313               0 :             found = true;
     314               0 :             mRootConnectionList.RemoveElementAt(i);
     315               0 :             break;
     316                 :         }
     317                 :     }
     318                 : 
     319               0 :     if (!found)
     320               0 :         return NS_ERROR_FAILURE;
     321                 : 
     322                 :     // swap connection ownership
     323               0 :     *_retval = ts->conn;
     324               0 :     ts->conn = nsnull;
     325               0 :     delete ts;
     326                 : 
     327               0 :     return NS_OK;
     328                 : }
     329                 : 
     330                 : nsresult
     331               0 : nsFtpProtocolHandler::InsertConnection(nsIURI *aKey, nsFtpControlConnection *aConn)
     332                 : {
     333               0 :     NS_ASSERTION(aConn, "null pointer");
     334               0 :     NS_ASSERTION(aKey, "null pointer");
     335                 : 
     336               0 :     if (aConn->mSessionId != mSessionId)
     337               0 :         return NS_ERROR_FAILURE;
     338                 : 
     339               0 :     nsCAutoString spec;
     340               0 :     aKey->GetPrePath(spec);
     341                 : 
     342               0 :     LOG(("FTP:inserting connection for %s\n", spec.get()));
     343                 : 
     344                 :     nsresult rv;
     345               0 :     nsCOMPtr<nsITimer> timer = do_CreateInstance("@mozilla.org/timer;1", &rv);
     346               0 :     if (NS_FAILED(rv)) return rv;
     347                 :     
     348               0 :     timerStruct* ts = new timerStruct();
     349               0 :     if (!ts)
     350               0 :         return NS_ERROR_OUT_OF_MEMORY;
     351                 : 
     352               0 :     rv = timer->InitWithFuncCallback(nsFtpProtocolHandler::Timeout,
     353                 :                                      ts,
     354                 :                                      mIdleTimeout*1000,
     355               0 :                                      nsITimer::TYPE_REPEATING_SLACK);
     356               0 :     if (NS_FAILED(rv)) {
     357               0 :         delete ts;
     358               0 :         return rv;
     359                 :     }
     360                 :     
     361               0 :     ts->key = ToNewCString(spec);
     362               0 :     if (!ts->key) {
     363               0 :         delete ts;
     364               0 :         return NS_ERROR_OUT_OF_MEMORY;
     365                 :     }
     366                 : 
     367               0 :     NS_ADDREF(aConn);
     368               0 :     ts->conn = aConn;
     369               0 :     ts->timer = timer;
     370                 : 
     371                 :     //
     372                 :     // limit number of idle connections.  if limit is reached, then prune
     373                 :     // eldest connection with matching key.  if none matching, then prune
     374                 :     // eldest connection.
     375                 :     //
     376               0 :     if (mRootConnectionList.Length() == IDLE_CONNECTION_LIMIT) {
     377                 :         PRUint32 i;
     378               0 :         for (i=0;i<mRootConnectionList.Length();++i) {
     379               0 :             timerStruct *candidate = mRootConnectionList[i];
     380               0 :             if (strcmp(candidate->key, ts->key) == 0) {
     381               0 :                 mRootConnectionList.RemoveElementAt(i);
     382               0 :                 delete candidate;
     383               0 :                 break;
     384                 :             }
     385                 :         }
     386               0 :         if (mRootConnectionList.Length() == IDLE_CONNECTION_LIMIT) {
     387               0 :             timerStruct *eldest = mRootConnectionList[0];
     388               0 :             mRootConnectionList.RemoveElementAt(0);
     389               0 :             delete eldest;
     390                 :         }
     391                 :     }
     392                 : 
     393               0 :     mRootConnectionList.AppendElement(ts);
     394               0 :     return NS_OK;
     395                 : }
     396                 : 
     397                 : //-----------------------------------------------------------------------------
     398                 : // nsIObserver
     399                 : 
     400                 : NS_IMETHODIMP
     401              18 : nsFtpProtocolHandler::Observe(nsISupports *aSubject,
     402                 :                               const char *aTopic,
     403                 :                               const PRUnichar *aData)
     404                 : {
     405              18 :     LOG(("FTP:observing [%s]\n", aTopic));
     406                 : 
     407              18 :     if (!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
     408               0 :         nsCOMPtr<nsIPrefBranch> branch = do_QueryInterface(aSubject);
     409               0 :         if (!branch) {
     410               0 :             NS_ERROR("no prefbranch");
     411               0 :             return NS_ERROR_UNEXPECTED;
     412                 :         }
     413                 :         PRInt32 val;
     414               0 :         nsresult rv = branch->GetIntPref(IDLE_TIMEOUT_PREF, &val);
     415               0 :         if (NS_SUCCEEDED(rv))
     416               0 :             mIdleTimeout = val;
     417                 : 
     418               0 :         rv = branch->GetIntPref(QOS_DATA_PREF, &val);
     419               0 :         if (NS_SUCCEEDED(rv))
     420               0 :             mDataQoSBits = (PRUint8) clamped(val, 0, 0xff);
     421                 : 
     422               0 :         rv = branch->GetIntPref(QOS_CONTROL_PREF, &val);
     423               0 :         if (NS_SUCCEEDED(rv))
     424               0 :             mControlQoSBits = (PRUint8) clamped(val, 0, 0xff);
     425              18 :     } else if (!strcmp(aTopic, "network:offline-about-to-go-offline")) {
     426              18 :         ClearAllConnections();
     427               0 :     } else if (!strcmp(aTopic, "net:clear-active-logins")) {
     428               0 :         ClearAllConnections();
     429               0 :         mSessionId++;
     430                 :     } else {
     431               0 :         NS_NOTREACHED("unexpected topic");
     432                 :     }
     433                 : 
     434              18 :     return NS_OK;
     435                 : }
     436                 : 
     437                 : void
     438              18 : nsFtpProtocolHandler::ClearAllConnections()
     439                 : {
     440                 :     PRUint32 i;
     441              18 :     for (i=0;i<mRootConnectionList.Length();++i)
     442               0 :         delete mRootConnectionList[i];
     443              18 :     mRootConnectionList.Clear();
     444              18 : }

Generated by: LCOV version 1.7