LCOV - code coverage report
Current view: directory - netwerk/streamconv/converters - nsFTPDirListingConv.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 143 119 83.2 %
Date: 2012-06-02 Functions: 15 14 93.3 %

       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                 :  *   Bradley Baetz <bbaetz@student.usyd.edu.au>
      24                 :  *
      25                 :  * Alternatively, the contents of this file may be used under the terms of
      26                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      27                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      29                 :  * of those above. If you wish to allow use of your version of this file only
      30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      31                 :  * use your version of this file under the terms of the MPL, indicate your
      32                 :  * decision by deleting the provisions above and replace them with the notice
      33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      34                 :  * the provisions above, a recipient may use your version of this file under
      35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      36                 :  *
      37                 :  * ***** END LICENSE BLOCK ***** */
      38                 : 
      39                 : #include "nsFTPDirListingConv.h"
      40                 : #include "nsMemory.h"
      41                 : #include "plstr.h"
      42                 : #include "prlog.h"
      43                 : #include "nsIServiceManager.h"
      44                 : #include "nsXPIDLString.h"
      45                 : #include "nsReadableUtils.h"
      46                 : #include "nsCOMPtr.h"
      47                 : #include "nsEscape.h"
      48                 : #include "nsNetUtil.h"
      49                 : #include "nsStringStream.h"
      50                 : #include "nsIComponentManager.h"
      51                 : #include "nsDateTimeFormatCID.h"
      52                 : #include "nsIStreamListener.h"
      53                 : #include "nsCRT.h"
      54                 : #include "nsMimeTypes.h"
      55                 : #include "nsAutoPtr.h"
      56                 : 
      57                 : #include "ParseFTPList.h"
      58                 : 
      59                 : #if defined(PR_LOGGING)
      60                 : //
      61                 : // Log module for FTP dir listing stream converter logging...
      62                 : //
      63                 : // To enable logging (see prlog.h for full details):
      64                 : //
      65                 : //    set NSPR_LOG_MODULES=nsFTPDirListConv:5
      66                 : //    set NSPR_LOG_FILE=nspr.log
      67                 : //
      68                 : // this enables PR_LOG_DEBUG level information and places all output in
      69                 : // the file nspr.log
      70                 : //
      71                 : PRLogModuleInfo* gFTPDirListConvLog = nsnull;
      72                 : 
      73                 : #endif /* PR_LOGGING */
      74                 : 
      75                 : // nsISupports implementation
      76             255 : NS_IMPL_ISUPPORTS3(nsFTPDirListingConv,
      77                 :                    nsIStreamConverter,
      78                 :                    nsIStreamListener, 
      79                 :                    nsIRequestObserver)
      80                 : 
      81                 : 
      82                 : // nsIStreamConverter implementation
      83                 : NS_IMETHODIMP
      84               0 : nsFTPDirListingConv::Convert(nsIInputStream *aFromStream,
      85                 :                              const char *aFromType,
      86                 :                              const char *aToType,
      87                 :                              nsISupports *aCtxt, nsIInputStream **_retval) {
      88               0 :     return NS_ERROR_NOT_IMPLEMENTED;
      89                 : }
      90                 : 
      91                 : 
      92                 : // Stream converter service calls this to initialize the actual stream converter (us).
      93                 : NS_IMETHODIMP
      94              17 : nsFTPDirListingConv::AsyncConvertData(const char *aFromType, const char *aToType,
      95                 :                                       nsIStreamListener *aListener, nsISupports *aCtxt) {
      96              17 :     NS_ASSERTION(aListener && aFromType && aToType, "null pointer passed into FTP dir listing converter");
      97                 : 
      98                 :     // hook up our final listener. this guy gets the various On*() calls we want to throw
      99                 :     // at him.
     100              17 :     mFinalListener = aListener;
     101              17 :     NS_ADDREF(mFinalListener);
     102                 : 
     103              17 :     PR_LOG(gFTPDirListConvLog, PR_LOG_DEBUG, 
     104                 :         ("nsFTPDirListingConv::AsyncConvertData() converting FROM raw, TO application/http-index-format\n"));
     105                 : 
     106              17 :     return NS_OK;
     107                 : }
     108                 : 
     109                 : 
     110                 : // nsIStreamListener implementation
     111                 : NS_IMETHODIMP
     112              17 : nsFTPDirListingConv::OnDataAvailable(nsIRequest* request, nsISupports *ctxt,
     113                 :                                   nsIInputStream *inStr, PRUint32 sourceOffset, PRUint32 count) {
     114              17 :     NS_ASSERTION(request, "FTP dir listing stream converter needs a request");
     115                 :     
     116                 :     nsresult rv;
     117                 : 
     118              34 :     nsCOMPtr<nsIChannel> channel = do_QueryInterface(request, &rv);
     119              17 :     NS_ENSURE_SUCCESS(rv, rv);
     120                 :     
     121                 :     PRUint32 read, streamLen;
     122                 : 
     123              17 :     rv = inStr->Available(&streamLen);
     124              17 :     NS_ENSURE_SUCCESS(rv, rv);
     125                 : 
     126              51 :     nsAutoArrayPtr<char> buffer(new char[streamLen + 1]);
     127              17 :     NS_ENSURE_TRUE(buffer, NS_ERROR_OUT_OF_MEMORY);
     128                 : 
     129              17 :     rv = inStr->Read(buffer, streamLen, &read);
     130              17 :     NS_ENSURE_SUCCESS(rv, rv);
     131                 : 
     132                 :     // the dir listings are ascii text, null terminate this sucker.
     133              17 :     buffer[streamLen] = '\0';
     134                 : 
     135              17 :     PR_LOG(gFTPDirListConvLog, PR_LOG_DEBUG, ("nsFTPDirListingConv::OnData(request = %x, ctxt = %x, inStr = %x, sourceOffset = %d, count = %d)\n", request, ctxt, inStr, sourceOffset, count));
     136                 : 
     137              17 :     if (!mBuffer.IsEmpty()) {
     138                 :         // we have data left over from a previous OnDataAvailable() call.
     139                 :         // combine the buffers so we don't lose any data.
     140               0 :         mBuffer.Append(buffer);
     141                 : 
     142               0 :         buffer = new char[mBuffer.Length()+1];
     143               0 :         NS_ENSURE_TRUE(buffer, NS_ERROR_OUT_OF_MEMORY);
     144                 : 
     145               0 :         strncpy(buffer, mBuffer.get(), mBuffer.Length()+1);
     146               0 :         mBuffer.Truncate();
     147                 :     }
     148                 : 
     149                 : #ifndef DEBUG_dougt
     150              17 :     PR_LOG(gFTPDirListConvLog, PR_LOG_DEBUG, ("::OnData() received the following %d bytes...\n\n%s\n\n", streamLen, buffer.get()) );
     151                 : #else
     152                 :     printf("::OnData() received the following %d bytes...\n\n%s\n\n", streamLen, buffer);
     153                 : #endif // DEBUG_dougt
     154                 : 
     155              34 :     nsCAutoString indexFormat;
     156              17 :     if (!mSentHeading) {
     157                 :         // build up the 300: line
     158              34 :         nsCOMPtr<nsIURI> uri;
     159              17 :         rv = channel->GetURI(getter_AddRefs(uri));
     160              17 :         NS_ENSURE_SUCCESS(rv, rv);
     161                 : 
     162              17 :         rv = GetHeaders(indexFormat, uri);
     163              17 :         NS_ENSURE_SUCCESS(rv, rv);
     164                 : 
     165              34 :         mSentHeading = true;
     166                 :     }
     167                 : 
     168              17 :     char *line = buffer;
     169              17 :     line = DigestBufferLines(line, indexFormat);
     170                 : 
     171                 : #ifndef DEBUG_dougt
     172              17 :     PR_LOG(gFTPDirListConvLog, PR_LOG_DEBUG, ("::OnData() sending the following %d bytes...\n\n%s\n\n", 
     173                 :         indexFormat.Length(), indexFormat.get()) );
     174                 : #else
     175                 :     char *unescData = ToNewCString(indexFormat);
     176                 :     NS_ENSURE_TRUE(unescData, NS_ERROR_OUT_OF_MEMORY);
     177                 :     
     178                 :     nsUnescape(unescData);
     179                 :     printf("::OnData() sending the following %d bytes...\n\n%s\n\n", indexFormat.Length(), unescData);
     180                 :     nsMemory::Free(unescData);
     181                 : #endif // DEBUG_dougt
     182                 : 
     183                 :     // if there's any data left over, buffer it.
     184              17 :     if (line && *line) {
     185               0 :         mBuffer.Append(line);
     186               0 :         PR_LOG(gFTPDirListConvLog, PR_LOG_DEBUG, ("::OnData() buffering the following %d bytes...\n\n%s\n\n",
     187                 :             PL_strlen(line), line) );
     188                 :     }
     189                 : 
     190                 :     // send the converted data out.
     191              34 :     nsCOMPtr<nsIInputStream> inputData;
     192                 : 
     193              17 :     rv = NS_NewCStringInputStream(getter_AddRefs(inputData), indexFormat);
     194              17 :     NS_ENSURE_SUCCESS(rv, rv);
     195                 : 
     196              17 :     rv = mFinalListener->OnDataAvailable(request, ctxt, inputData, 0, indexFormat.Length());
     197                 : 
     198              17 :     return rv;
     199                 : }
     200                 : 
     201                 : 
     202                 : // nsIRequestObserver implementation
     203                 : NS_IMETHODIMP
     204              17 : nsFTPDirListingConv::OnStartRequest(nsIRequest* request, nsISupports *ctxt) {
     205                 :     // we don't care about start. move along... but start masqeurading 
     206                 :     // as the http-index channel now.
     207              17 :     return mFinalListener->OnStartRequest(request, ctxt);
     208                 : }
     209                 : 
     210                 : NS_IMETHODIMP
     211              17 : nsFTPDirListingConv::OnStopRequest(nsIRequest* request, nsISupports *ctxt,
     212                 :                                    nsresult aStatus) {
     213                 :     // we don't care about stop. move along...
     214                 : 
     215              17 :     return mFinalListener->OnStopRequest(request, ctxt, aStatus);
     216                 : }
     217                 : 
     218                 : 
     219                 : // nsFTPDirListingConv methods
     220              17 : nsFTPDirListingConv::nsFTPDirListingConv() {
     221              17 :     mFinalListener      = nsnull;
     222              17 :     mSentHeading        = false;
     223              17 : }
     224                 : 
     225              51 : nsFTPDirListingConv::~nsFTPDirListingConv() {
     226              17 :     NS_IF_RELEASE(mFinalListener);
     227              68 : }
     228                 : 
     229                 : nsresult
     230              17 : nsFTPDirListingConv::Init() {
     231                 : #if defined(PR_LOGGING)
     232                 :     //
     233                 :     // Initialize the global PRLogModule for FTP Protocol logging 
     234                 :     // if necessary...
     235                 :     //
     236              17 :     if (nsnull == gFTPDirListConvLog) {
     237               4 :         gFTPDirListConvLog = PR_NewLogModule("nsFTPDirListingConv");
     238                 :     }
     239                 : #endif /* PR_LOGGING */
     240                 : 
     241              17 :     return NS_OK;
     242                 : }
     243                 : 
     244                 : nsresult
     245              17 : nsFTPDirListingConv::GetHeaders(nsACString& headers,
     246                 :                                 nsIURI* uri)
     247                 : {
     248              17 :     nsresult rv = NS_OK;
     249                 :     // build up 300 line
     250              17 :     headers.AppendLiteral("300: ");
     251                 : 
     252                 :     // Bug 111117 - don't print the password
     253              34 :     nsCAutoString pw;
     254              34 :     nsCAutoString spec;
     255              17 :     uri->GetPassword(pw);
     256              17 :     if (!pw.IsEmpty()) {
     257               0 :          rv = uri->SetPassword(EmptyCString());
     258               0 :          if (NS_FAILED(rv)) return rv;
     259               0 :          rv = uri->GetAsciiSpec(spec);
     260               0 :          if (NS_FAILED(rv)) return rv;
     261               0 :          headers.Append(spec);
     262               0 :          rv = uri->SetPassword(pw);
     263               0 :          if (NS_FAILED(rv)) return rv;
     264                 :     } else {
     265              17 :         rv = uri->GetAsciiSpec(spec);
     266              17 :         if (NS_FAILED(rv)) return rv;
     267                 :         
     268              17 :         headers.Append(spec);
     269                 :     }
     270              17 :     headers.Append(char(nsCRT::LF));
     271                 :     // END 300:
     272                 : 
     273                 :     // build up the column heading; 200:
     274              17 :     headers.AppendLiteral("200: filename content-length last-modified file-type\n");
     275                 :     // END 200:
     276              17 :     return rv;
     277                 : }
     278                 : 
     279                 : char *
     280              17 : nsFTPDirListingConv::DigestBufferLines(char *aBuffer, nsCString &aString) {
     281              17 :     char *line = aBuffer;
     282                 :     char *eol;
     283              17 :     bool cr = false;
     284                 : 
     285                 :     list_state state;
     286              17 :     state.magic = 0;
     287                 : 
     288                 :     // while we have new lines, parse 'em into application/http-index-format.
     289              83 :     while ( line && (eol = PL_strchr(line, nsCRT::LF)) ) {
     290                 :         // yank any carriage returns too.
     291              49 :         if (eol > line && *(eol-1) == nsCRT::CR) {
     292              49 :             eol--;
     293              49 :             *eol = '\0';
     294              49 :             cr = true;
     295                 :         } else {
     296               0 :             *eol = '\0';
     297               0 :             cr = false;
     298                 :         }
     299                 : 
     300                 :         list_result result;
     301                 : 
     302              49 :         int type = ParseFTPList(line, &state, &result );
     303                 : 
     304                 :         // if it is other than a directory, file, or link -OR- if it is a 
     305                 :         // directory named . or .., skip over this line.
     306              56 :         if ((type != 'd' && type != 'f' && type != 'l') || 
     307               7 :             (result.fe_type == 'd' && result.fe_fname[0] == '.' &&
     308               0 :             (result.fe_fnlen == 1 || (result.fe_fnlen == 2 &&  result.fe_fname[1] == '.'))) )
     309                 :         {
     310               7 :             if (cr)
     311               7 :                 line = eol+2;
     312                 :             else
     313               0 :                 line = eol+1;
     314                 :             
     315               7 :             continue;
     316                 :         }
     317                 : 
     318                 :         // blast the index entry into the indexFormat buffer as a 201: line.
     319              42 :         aString.AppendLiteral("201: ");
     320                 :         // FILENAME
     321                 : 
     322                 :         // parsers for styles 'U' and 'W' handle sequence " -> " themself
     323              42 :         if (state.lstyle != 'U' && state.lstyle != 'W') {
     324               2 :             const char* offset = strstr(result.fe_fname, " -> ");
     325               2 :             if (offset) {
     326               0 :                 result.fe_fnlen = offset - result.fe_fname;
     327                 :             }
     328                 :         }
     329                 : 
     330              84 :         nsCAutoString buf;
     331              42 :         aString.Append('\"');
     332                 :         aString.Append(NS_EscapeURL(Substring(result.fe_fname, 
     333              42 :                                               result.fe_fname+result.fe_fnlen),
     334              42 :                                     esc_Minimal|esc_OnlyASCII|esc_Forced,buf));
     335              42 :         aString.AppendLiteral("\" ");
     336                 :  
     337                 :         // CONTENT LENGTH
     338                 :         
     339              42 :         if (type != 'd') 
     340                 :         {
     341            1435 :             for (int i = 0; i < int(sizeof(result.fe_size)); ++i)
     342                 :             {
     343            1400 :                 if (result.fe_size[i] != '\0')
     344              85 :                     aString.Append((const char*)&result.fe_size[i], 1);
     345                 :             }
     346                 :             
     347              35 :             aString.Append(' ');
     348                 :         }
     349                 :         else
     350               7 :             aString.AppendLiteral("0 ");
     351                 : 
     352                 : 
     353                 :         // MODIFIED DATE
     354              42 :         char buffer[256] = "";
     355                 :         // Note: The below is the RFC822/1123 format, as required by
     356                 :         // the application/http-index-format specs
     357                 :         // viewers of such a format can then reformat this into the
     358                 :         // current locale (or anything else they choose)
     359                 :         PR_FormatTimeUSEnglish(buffer, sizeof(buffer),
     360              42 :                                "%a, %d %b %Y %H:%M:%S", &result.fe_time );
     361                 : 
     362              42 :         char *escapedDate = nsEscape(buffer, url_Path);
     363              42 :         aString.Append(escapedDate);
     364              42 :         nsMemory::Free(escapedDate);
     365              42 :         aString.Append(' ');
     366                 : 
     367                 :         // ENTRY TYPE
     368              42 :         if (type == 'd')
     369               7 :             aString.AppendLiteral("DIRECTORY");
     370              35 :         else if (type == 'l')
     371               8 :             aString.AppendLiteral("SYMBOLIC-LINK");
     372                 :         else
     373              27 :             aString.AppendLiteral("FILE");
     374                 :         
     375              42 :         aString.Append(' ');
     376                 : 
     377              42 :         aString.Append(char(nsCRT::LF)); // complete this line
     378                 :         // END 201:
     379                 : 
     380              42 :         if (cr)
     381              42 :             line = eol+2;
     382                 :         else
     383               0 :             line = eol+1;
     384                 :     } // end while(eol)
     385                 : 
     386              17 :     return line;
     387                 : }
     388                 : 
     389                 : nsresult
     390              17 : NS_NewFTPDirListingConv(nsFTPDirListingConv** aFTPDirListingConv)
     391                 : {
     392              17 :     NS_PRECONDITION(aFTPDirListingConv != nsnull, "null ptr");
     393              17 :     if (! aFTPDirListingConv)
     394               0 :         return NS_ERROR_NULL_POINTER;
     395                 : 
     396              17 :     *aFTPDirListingConv = new nsFTPDirListingConv();
     397              17 :     if (! *aFTPDirListingConv)
     398               0 :         return NS_ERROR_OUT_OF_MEMORY;
     399                 : 
     400              17 :     NS_ADDREF(*aFTPDirListingConv);
     401              17 :     return (*aFTPDirListingConv)->Init();
     402                 : }

Generated by: LCOV version 1.7