Back to index

enigmail  1.4.3
nsPipeFilterListener.cpp
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public
00005  * License Version 1.1 (the "MPL"); you may not use this file
00006  * except in compliance with the MPL. You may obtain a copy of
00007  * the MPL at http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the MPL is distributed on an "AS
00010  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
00011  * implied. See the MPL for the specific language governing
00012  * rights and limitations under the MPL.
00013  *
00014  * The Original Code is protoZilla.
00015  *
00016  * The Initial Developer of the Original Code is Ramalingam Saravanan.
00017  * Portions created by Ramalingam Saravanan <sarava@sarava.net> are
00018  * Copyright (C) 2000 Ramalingam Saravanan. All Rights Reserved.
00019  *
00020  * Contributor(s):
00021  * Patrick Brunschwig <patrick@mozilla-enigmail.org>
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  * ***** END LICENSE BLOCK ***** */
00035 
00036 
00037 // Logging of debug output
00038 // The following define statement should occur before any include statements
00039 #define FORCE_PR_LOG       /* Allow logging even in release build */
00040 
00041 #include "enigmail.h"
00042 
00043 #include "nsStringGlue.h"
00044 
00045 #include "prlog.h"
00046 #include "nsCOMPtr.h"
00047 #include "nsIInputStream.h"
00048 #include "nsIThread.h"
00049 #include "nsIHttpChannel.h"
00050 #include "nsNetUtil.h"
00051 #include "nsMimeTypes.h"
00052 
00053 
00054 #include "nsPipeFilterListener.h"
00055 
00056 #ifdef PR_LOGGING
00057 PRLogModuleInfo* gPipeFilterListenerLog = NULL;
00058 #endif
00059 
00060 #define ERROR_LOG(args)    PR_LOG(gPipeFilterListenerLog,PR_LOG_ERROR,args)
00061 #define WARNING_LOG(args)  PR_LOG(gPipeFilterListenerLog,PR_LOG_WARNING,args)
00062 #define DEBUG_LOG(args)    PR_LOG(gPipeFilterListenerLog,PR_LOG_DEBUG,args)
00063 
00064 #define NS_PIPE_CONSOLE_BUFFER_SIZE   (1024)
00065 
00066 static const PRUint32 kCharMax = NS_PIPE_CONSOLE_BUFFER_SIZE;
00067 
00068 #define MK_MIME_ERROR_WRITING_FILE -1
00069 
00071 
00072 // nsPipeFilterListener implementation
00073 
00074 // nsISupports implementation
00075 NS_IMPL_THREADSAFE_ISUPPORTS4(nsPipeFilterListener,
00076                               nsIPipeFilterListener,
00077                               nsIRequestObserver,
00078                               nsIStreamListener,
00079                               nsIInputStream)
00080 
00081 
00082 // nsPipeFilterListener implementation
00083 nsPipeFilterListener::nsPipeFilterListener()
00084   : mInitialized(PR_FALSE),
00085     mRequestStarted(PR_FALSE),
00086     mRequestEnded(PR_FALSE),
00087     mTailRequestStarted(PR_FALSE),
00088 
00089     mStartDelimiter(""),
00090     mEndDelimiter(""),
00091 
00092     mStartLine(""),
00093     mEndLine(""),
00094 
00095     mKeepDelimiters(PR_FALSE),
00096     mMimeMultipart(PR_FALSE),
00097 
00098     mAutoMimeBoundary(PR_FALSE),
00099     mFirstMatch(PR_TRUE),
00100     mLastMatch(PR_FALSE),
00101     mSavePartMatch(PR_FALSE),
00102 
00103     mOldPartMatch(""),
00104     mPartMatch(""),
00105     mLinebreak(0),
00106 
00107     mStreamBuf(nsnull),
00108     mStreamOffset(0),
00109     mStreamLength(0),
00110 
00111     mListener(nsnull),
00112     mTailListener(nsnull),
00113     mContext(nsnull)
00114 {
00115     NS_INIT_ISUPPORTS();
00116 
00117 #ifdef PR_LOGGING
00118   if (gPipeFilterListenerLog == nsnull) {
00119     gPipeFilterListenerLog = PR_NewLogModule("nsPipeFilterListener");
00120   }
00121 #endif
00122 
00123 #ifdef FORCE_PR_LOG
00124   nsresult rv;
00125   nsCOMPtr<nsIThread> myThread;
00126   rv = ENIG_GET_THREAD(myThread);
00127   DEBUG_LOG(("nsPipeFilterListener:: <<<<<<<<< CTOR(%p): myThread=%p\n",
00128          this, myThread.get()));
00129 #endif
00130 }
00131 
00132 
00133 nsPipeFilterListener::~nsPipeFilterListener()
00134 {
00135   nsresult rv;
00136 #ifdef FORCE_PR_LOG
00137   nsCOMPtr<nsIThread> myThread;
00138   rv = ENIG_GET_THREAD(myThread);
00139   DEBUG_LOG(("nsPipeFilterListener:: >>>>>>>>> DTOR(%p): myThread=%p\n",
00140          this, myThread.get()));
00141 #endif
00142 
00143   // Release owning refs
00144   mListener = nsnull;
00145   mTailListener = nsnull;
00146   mContext = nsnull;
00147 }
00148 
00149 
00151 // nsIPipeFilterListener methods
00153 
00154 NS_IMETHODIMP
00155 nsPipeFilterListener::Init(nsIStreamListener* listener, nsISupports* ctxt,
00156                            const char *startDelimiter,
00157                            const char *endDelimiter,
00158                            PRUint32 skipCount,
00159                            EMBool keepDelimiters,
00160                            EMBool mimeMultipart,
00161                            nsIStreamListener* tailListener)
00162 {
00163   DEBUG_LOG(("nsPipeFilterListener::Init: (%p)\n", this));
00164 
00165   mListener = listener;
00166   mTailListener = tailListener;
00167   mContext = ctxt;
00168 
00169   mStartDelimiter = startDelimiter;
00170   mEndDelimiter = endDelimiter;
00171 
00172   mMimeMultipart = mimeMultipart;
00173 
00174   if (mMimeMultipart && mStartDelimiter.IsEmpty()) {
00175     mAutoMimeBoundary = PR_TRUE;
00176     mStartDelimiter = "--";
00177     mEndDelimiter   = "--";
00178   }
00179 
00180   mStart.skipCount   = mStartDelimiter.IsEmpty() ? 0 : skipCount;
00181   mStart.matchedLine = PR_FALSE;
00182   mStart.matchedCR   = PR_FALSE;
00183   mStart.matchOffset = 0;
00184   mStart.matchCount  = mStartDelimiter.IsEmpty() ? 1 : 0;
00185 
00186   mEnd.skipCount     = 0;
00187   mEnd.matchedLine   = PR_FALSE;
00188   mEnd.matchedCR     = PR_FALSE;
00189   mEnd.matchOffset   = 0;
00190   mEnd.matchCount    = 0;
00191 
00192   mKeepDelimiters = keepDelimiters;
00193 
00194   mInitialized = PR_TRUE;
00195 
00196   return NS_OK;
00197 }
00198 
00199 
00200 NS_IMETHODIMP
00201 nsPipeFilterListener::TransmitData(const char* buf, PRUint32 count,
00202                                    nsIStreamListener* listener,
00203                                    nsIRequest* aRequest, nsISupports* aContext)
00204 {
00205   nsresult rv;
00206 
00207   DEBUG_LOG(("nsPipeFilterListener::TransmitData: (%p) %d\n", this, count));
00208 
00209   if (!listener)
00210     return NS_OK;
00211 
00212   mStreamBuf = buf;
00213   mStreamOffset = 0;
00214   mStreamLength = count;
00215 
00216   rv = listener->OnDataAvailable(aRequest,
00217                                  mContext ? mContext.get() : aContext,
00218                                  (nsIInputStream*)(this),
00219                                  0, count);
00220   if (NS_FAILED(rv)) {
00221     DEBUG_LOG(("nsPipeFilterListener::TransmitData: (%p) rv=%p\n", this, rv));
00222     return rv;
00223   }
00224 
00225   Close();
00226 
00227   return NS_OK;
00228 }
00229 
00230 
00231 NS_IMETHODIMP
00232 nsPipeFilterListener::GetStartDelimiter(nsACString &aStartDelimiter)
00233 {
00234   aStartDelimiter = mStartDelimiter;
00235   DEBUG_LOG(("nsPipeFilterListener::GetStartDelimiter: %s\n", mStartDelimiter.get()));
00236   return NS_OK;
00237 }
00238 
00239 
00240 NS_IMETHODIMP
00241 nsPipeFilterListener::GetEndDelimiter(nsACString &aEndDelimiter)
00242 {
00243   aEndDelimiter = mEndDelimiter;
00244   DEBUG_LOG(("nsPipeFilterListener::GetEndDelimiter: %s\n", mEndDelimiter.get()));
00245   return NS_OK;
00246 }
00247 
00248 NS_IMETHODIMP
00249 nsPipeFilterListener::GetStartLine(nsACString &aStartLine)
00250 {
00251   aStartLine = mStartLine;
00252   DEBUG_LOG(("nsPipeFilterListener::GetStartLine: %s\n", mStartLine.get()));
00253   return NS_OK;
00254 }
00255 
00256 
00257 NS_IMETHODIMP
00258 nsPipeFilterListener::GetEndLine(nsACString &aEndLine)
00259 {
00260   aEndLine = mEndLine;
00261   DEBUG_LOG(("nsPipeFilterListener::GetEndLine: %s\n", mEndLine.get()));
00262   return NS_OK;
00263 }
00264 
00265 const char* const nsPipeFilterListener::LineBreaks[] = {
00266   "\r",
00267   "\r\n",
00268   "\n"
00269 };
00270 
00271 NS_IMETHODIMP
00272 nsPipeFilterListener::Write(const char* buf, PRUint32 count,
00273                             nsIRequest* aRequest, nsISupports* aContext)
00274 {
00275   nsresult rv;
00276 
00277   DEBUG_LOG(("nsPipeFilterListener::Write: (%p) %d\n", this, count));
00278 
00279   if (count <= 0)
00280     return NS_OK;
00281 
00282   PRInt32 consumed;
00283   if (mStart.matchCount <= mStart.skipCount) {
00284     consumed = MatchDelimiter(buf, count, mStart, mStartDelimiter, mStartLine);
00285     if (consumed < 0)
00286       return NS_ERROR_FAILURE;
00287     buf += consumed;
00288     count -= consumed;
00289   }
00290 
00291   if (!mRequestStarted && (mStart.matchCount > mStart.skipCount)) {
00292     mRequestStarted = PR_TRUE;
00293     DEBUG_LOG(("nsPipeFilterListener::Write: RequestStarted\n", count));
00294 
00295     if (mListener) {
00296       rv = mListener->OnStartRequest(aRequest,
00297                                      mContext ? mContext.get() : aContext);
00298 
00299       NS_ENSURE_SUCCESS(rv, rv);
00300 
00301       if (mKeepDelimiters && !mStartLine.IsEmpty()) {
00302         rv = TransmitData(mStartLine.get(), mStartLine.Length(),
00303                           mListener, aRequest, aContext);
00304         NS_ENSURE_SUCCESS(rv, rv);
00305       }
00306     }
00307   }
00308 
00309   DEBUG_LOG(("nsPipeFilterListener::Write: after start, count %d\n", count));
00310 
00311   if (count <= 0)
00312     return NS_OK;
00313 
00314   if (mEndDelimiter.IsEmpty()) {
00315     return TransmitData(buf, count, mListener, aRequest, aContext);
00316   }
00317 
00318   if (mEnd.matchCount > mEnd.skipCount) {
00319     // End delimiter match complete
00320 
00321     if (mTailListener) {
00322       DEBUG_LOG(("nsPipeFilterListener::Write: TAIL count %d\n", count));
00323       rv = TransmitData(buf, count, mTailListener, aRequest, aContext);
00324       NS_ENSURE_SUCCESS(rv, rv);
00325     }
00326 
00327     return NS_OK;
00328   }
00329 
00330   mLastMatch = PR_TRUE;
00331   mSavePartMatch = PR_TRUE;
00332   PRUint32 savedPartMatchLen = mPartMatch.Length();
00333 
00334   consumed = MatchDelimiter(buf, count, mEnd, mEndDelimiter, mEndLine);
00335   if (consumed < 0)
00336     return NS_ERROR_FAILURE;
00337 
00338   if (!mSavePartMatch && savedPartMatchLen &&
00339       (mOldPartMatch.Length() >= savedPartMatchLen)) {
00340 
00341     rv = TransmitData(mOldPartMatch.get(), savedPartMatchLen,
00342                       mListener, aRequest, aContext);
00343     NS_ENSURE_SUCCESS(rv, rv);
00344 
00345     mOldPartMatch = "";
00346   }
00347 
00348   PRInt32 transCount = consumed - mPartMatch.Length() - mEndLine.Length();
00349 
00350   if (transCount > 0) {
00351     rv = TransmitData(buf, transCount, mListener, aRequest, aContext);
00352     NS_ENSURE_SUCCESS(rv, rv);
00353   }
00354 
00355   if (mTailListener && (mEnd.matchCount > mEnd.skipCount)) {
00356     // End delimiter match complete
00357     mTailRequestStarted = PR_TRUE;
00358     rv = mTailListener->OnStartRequest(aRequest,
00359                                        mContext ? mContext.get() : aContext);
00360     NS_ENSURE_SUCCESS(rv, rv);
00361 
00362     buf   += consumed;
00363     count -= consumed;
00364     if (count > 0) {
00365       DEBUG_LOG(("nsPipeFilterListener::Write: TAIL START count %d\n", count));
00366       rv = TransmitData(buf, count, mTailListener, aRequest, aContext);
00367       NS_ENSURE_SUCCESS(rv, rv);
00368     }
00369   }
00370 
00371   return NS_OK;
00372 }
00373 
00374 
00375 // Return number of bytes consumed (>= 0) or -1 on error
00376 PRInt32
00377 nsPipeFilterListener::MatchDelimiter(const char* buf, PRUint32 bufLen,
00378                                      LineMatchStatus& delim,
00379                                      nsCString& delimStr,
00380                                      nsCString& delimLine)
00381 {
00382   //DEBUG_LOG(("nsPipeFilterListener::MatchDelimiter: bufLen=%d\n", bufLen));
00383 
00384   PRUint32 count = bufLen;
00385 
00386   while ((count > 0) && (delim.matchCount <= delim.skipCount)) {
00387 
00388     if (delim.matchOffset < delimStr.Length()) {
00389       PRUint32 consumed = MatchString(buf, count, delimStr.get(),
00390                                       delimStr.Length(),
00391                                       delim.matchOffset);
00392       //DEBUG_LOG(("nsPipeFilterListener::MatchDelimiter: consumed=%d\n", consumed));
00393       if (!consumed) {
00394           ERROR_LOG(("nsPipeFilterListener::MatchDelimiter: consumed=%d\n", consumed));
00395         return -1;
00396       }
00397 
00398       buf   += consumed;
00399       count -= consumed;
00400 
00401       if (delim.matchOffset >= delimStr.Length()) {
00402         DEBUG_LOG(("nsPipeFilterListener::MatchDelimiter: delimStr='%s'\n", delimStr.get()));
00403         if (mLastMatch) {
00404           delimLine = mPartMatch;
00405           mPartMatch = "";
00406         } else {
00407           delimLine = delimStr;
00408         }
00409         mLinebreak = 0;
00410       }
00411 
00412       if (!count)
00413         return bufLen;
00414 
00415       if (delim.matchOffset < delimStr.Length()) {
00416         ERROR_LOG(("nsPipeFilterListener::MatchDelimiter: count=%d, delim.matchOffset=%d, delimStr='%s'\n", count, delim.matchOffset, delimStr.get() ));
00417         return -1;
00418       }
00419     }
00420 
00421     // Match to end of line
00422     while (count > 0) {
00423       char ch = buf[0];
00424 
00425       if (delim.matchedCR) {
00426         // Already matched a CR
00427 
00428         if (ch == '\n') {
00429           // Consume LF following CR
00430           delimLine.Append(ch);
00431           buf++;
00432           count--;
00433         }
00434 
00435         delim.matchedLine = PR_TRUE;
00436         break;
00437       }
00438 
00439       delimLine.Append(ch);
00440       buf++;
00441       count--;
00442 
00443       if (ch == '\n') {
00444         delim.matchedLine = PR_TRUE;
00445         break;
00446       }
00447 
00448       if (ch == '\r') {
00449         delim.matchedCR = PR_TRUE;
00450       }
00451     }
00452 
00453     if (delim.matchedLine) {
00454       delim.matchCount++;
00455       delim.matchOffset = 0;
00456       delim.matchedCR = PR_FALSE;
00457       delim.matchedLine = PR_FALSE;
00458 
00459       DEBUG_LOG(("nsPipeFilterListener::MatchDelimiter: delimLine(%d)='%s'\n", delimLine.Length(), delimLine.get()));
00460       DEBUG_LOG(("nsPipeFilterListener::MatchDelimiter: matchCount=%d\n", delim.matchCount));
00461 
00462       if (mAutoMimeBoundary) {
00463         // Eliminate all trailing whitespace (including linebreaks) for delimiter
00464         mAutoMimeBoundary = PR_FALSE;
00465         mStartDelimiter = mStartLine;
00466         mStartDelimiter.Trim(" \t\r\n", PR_FALSE, PR_TRUE);
00467         mEndDelimiter = mStartDelimiter;
00468         DEBUG_LOG(("nsPipeFilterListener::MatchDelimiter: Mime Boundary='%s'\n", mStartDelimiter.get()));
00469       }
00470 
00471     }
00472   }
00473 
00474   return bufLen - count;
00475 }
00476 
00477 
00478 // Matches a string against characters in a buffer, taking into account
00479 // a previous substring match up to strOffset. strOffset is updated to reflect
00480 // the new match state, and the count of consumed bytes in buf is returned.
00481 // mLinebreak = 1, if CR encountered previously
00482 //            = 2, if CRLF encountered previously
00483 //            = 3, if LF encountered previously,
00484 //            = 0, otherwise
00485 // (New matches only start at the beginning of a line)
00486 PRUint32
00487 nsPipeFilterListener::MatchString(const char* buf, PRUint32 count,
00488                                   const char* str, PRUint32 length,
00489                                   PRUint32& strOffset)
00490 {
00491   //DEBUG_LOG(("nsPipeFilterListener::MatchString: strOffset=%d, length=%d\n", strOffset, length));
00492 
00493   if (strOffset >= length) {
00494     // Complete match
00495     return 0;
00496   }
00497 
00498   PRUint32 consumed = count;
00499 
00500   PRUint32 j;
00501   char ch;
00502   for (j=0; j < count; j++) {
00503 
00504     ch = buf[j];
00505     if ( (ch == str[strOffset]) &&
00506          ((strOffset > 0) || (mLinebreak > 0) || (mFirstMatch && (j == 0)) )) {
00507       // Extend match
00508       strOffset++;
00509       if (mLastMatch)
00510         mPartMatch += ch;
00511 
00512       if (strOffset >= length) {
00513         // Complete match
00514         consumed = j+1;
00515         break;
00516       }
00517 
00518     } else {
00519       // Match again from beginning of string
00520       strOffset = 0;
00521 
00522       if ((mLinebreak == 1) && (ch == '\n')) {
00523         mLinebreak = 2;
00524         if (mLastMatch)
00525           mPartMatch += '\n';
00526 
00527       } else {
00528         if (mLastMatch && mSavePartMatch) {
00529           mOldPartMatch = mPartMatch;
00530           mSavePartMatch = PR_FALSE;
00531         }
00532 
00533         if (ch == '\r') {
00534           mLinebreak = 1;
00535           if (mLastMatch)
00536             mPartMatch = '\r';
00537 
00538         } else if (ch == '\n') {
00539           mLinebreak = 3;
00540           if (mLastMatch)
00541             mPartMatch = '\n';
00542 
00543         } else if (mLinebreak > 0) {
00544           mLinebreak = 0;
00545           if (mLastMatch)
00546             mPartMatch = "";
00547         }
00548       }
00549     }
00550   }
00551 
00552   mFirstMatch = PR_FALSE;
00553 
00554   return consumed;
00555 }
00556 
00557 
00559 // nsIRequestObserver methods
00561 
00562 NS_IMETHODIMP
00563 nsPipeFilterListener::OnStartRequest(nsIRequest *aRequest,
00564                                      nsISupports *aContext)
00565 {
00566   DEBUG_LOG(("nsPipeFilterListener::OnStartRequest: (%p)\n", this));
00567 
00568   if (!mInitialized)
00569     return NS_ERROR_NOT_INITIALIZED;
00570 
00571   return NS_OK;
00572 }
00573 
00574 NS_IMETHODIMP
00575 nsPipeFilterListener::EndRequest(nsIRequest* aRequest, nsISupports* aContext)
00576 {
00577   nsresult rv;
00578   DEBUG_LOG(("nsPipeFilterListener::EndRequest:(%p)\n", this));
00579 
00580   mRequestEnded = PR_TRUE;
00581 
00582   if (mListener) {
00583     if (!mRequestStarted) {
00584       mRequestStarted = PR_TRUE;
00585 
00586       rv = mListener->OnStartRequest(aRequest,
00587                                      mContext ? mContext.get() : aContext);
00588       NS_ENSURE_SUCCESS(rv, rv);
00589 
00590       if (mKeepDelimiters && !mStartLine.IsEmpty()) {
00591         rv = TransmitData(mStartLine.get(), mStartLine.Length(),
00592                           mListener, aRequest, aContext);
00593         NS_ENSURE_SUCCESS(rv, rv);
00594       }
00595     }
00596 
00597     if (!mPartMatch.IsEmpty()) {
00598       // Transmit any partially matched line
00599       DEBUG_LOG(("nsPipeFilterListener::EndRequest: PARTIALLY MATCHED LINE '%s'\n", mPartMatch.get()));
00600       rv = TransmitData(mPartMatch.get(), mPartMatch.Length(),
00601                         mListener, aRequest, aContext);
00602       NS_ENSURE_SUCCESS(rv, rv);
00603 
00604       mPartMatch = "";
00605     }
00606 
00607     if (mKeepDelimiters && !mEndLine.IsEmpty()) {
00608       rv = TransmitData(mEndLine.get(), mEndLine.Length(),
00609                         mListener, aRequest, aContext);
00610       NS_ENSURE_SUCCESS(rv, rv);
00611     }
00612   }
00613 
00614   return NS_OK;
00615 }
00616 
00617 
00618 NS_IMETHODIMP
00619 nsPipeFilterListener::OnStopRequest(nsIRequest* aRequest,
00620                                     nsISupports* aContext,
00621                                     nsresult aStatus)
00622 {
00623   nsresult rv = NS_OK;
00624 
00625   DEBUG_LOG(("nsPipeFilterListener::OnStopRequest: (%p)\n", this));
00626 
00627   // Ensure that OnStopRequest call chain does not break by failing softly
00628 
00629   if (!mEndDelimiter.IsEmpty() && mEndLine.IsEmpty()) {
00630     // Failed to match end delimiter
00631     aStatus = NS_BINDING_ABORTED;
00632   }
00633 
00634   if (!mRequestEnded) {
00635     rv = EndRequest(aRequest, aContext);
00636     if (NS_FAILED(rv))
00637       aStatus = NS_BINDING_ABORTED;
00638   }
00639 
00640   if (mTailListener) {
00641 
00642     if (!mTailRequestStarted) {
00643       mTailRequestStarted = PR_TRUE;
00644       rv = mTailListener->OnStartRequest(aRequest,
00645                                          mContext ? mContext.get() : aContext);
00646       if (NS_FAILED(rv))
00647         aStatus = NS_BINDING_ABORTED;
00648     }
00649 
00650     rv = mTailListener->OnStopRequest(aRequest,
00651                                       mContext ? mContext.get() : aContext,
00652                                       aStatus);
00653     if (NS_FAILED(rv))
00654       aStatus = NS_BINDING_ABORTED;
00655   }
00656 
00657   if (mListener) {
00658     rv = mListener->OnStopRequest(aRequest,
00659                                   mContext ? mContext.get() : aContext,
00660                                   aStatus);
00661     if (NS_FAILED(rv))
00662       aStatus = NS_BINDING_ABORTED;
00663   }
00664 
00665   // Release owning refs
00666   mListener = nsnull;
00667   mTailListener = nsnull;
00668   mContext = nsnull;
00669 
00670   return (aStatus == NS_BINDING_ABORTED) ? NS_ERROR_FAILURE : NS_OK;
00671 }
00672 
00674 // nsIStreamListener method
00676 
00677 NS_IMETHODIMP
00678 nsPipeFilterListener::OnDataAvailable(nsIRequest* aRequest,
00679                                       nsISupports* aContext,
00680                                       nsIInputStream *aInputStream,
00681                                       PRUint32 aSourceOffset,
00682                                       PRUint32 aLength)
00683 {
00684   nsresult rv = NS_OK;
00685 
00686   DEBUG_LOG(("nsPipeFilterListener::OnDataAvailable: (%p) %d\n", this, aLength));
00687 
00688   char buf[kCharMax];
00689   PRUint32 readCount, readMax;
00690 
00691   while (aLength > 0) {
00692     readMax = (aLength < kCharMax) ? aLength : kCharMax;
00693     rv = aInputStream->Read((char *) buf, readMax, &readCount);
00694     if (NS_FAILED(rv)){
00695       ERROR_LOG(("nsPipeFilterListener::OnDataAvailable: Error in reading from input stream, %x\n", rv));
00696       return rv;
00697     }
00698 
00699     if (readCount == 0) {
00700       DEBUG_LOG(("nsPipeFilterListener::OnDataAvailable: (%p) readCount=%d\n", this, readCount));
00701     }
00702 
00703     if (readCount <= 0)
00704       break;
00705 
00706     aLength -= readCount;
00707     aSourceOffset += readCount;
00708 
00709     rv = Write(buf, readCount, aRequest, aContext);
00710 
00711     if (NS_FAILED(rv)) {
00712       DEBUG_LOG(("nsPipeFilterListener::OnDataAvailable: (%p) rv=%p\n", this, rv));
00713       return rv;
00714     }
00715   }
00716 
00717   return NS_OK;
00718 }
00719 
00721 // nsIInputStream methods
00723 
00724 NS_IMETHODIMP
00725 nsPipeFilterListener::Available(PRUint32* _retval)
00726 {
00727   if (!_retval)
00728     return NS_ERROR_NULL_POINTER;
00729 
00730   *_retval = (mStreamLength > mStreamOffset) ?
00731               mStreamLength - mStreamOffset : 0;
00732 
00733   DEBUG_LOG(("nsPipeFilterListener::Available: (%p) %d\n", this, *_retval));
00734 
00735   return NS_OK;
00736 }
00737 
00738 NS_IMETHODIMP
00739 nsPipeFilterListener::Read(char* buf, PRUint32 count,
00740                          PRUint32 *readCount)
00741 {
00742   DEBUG_LOG(("nsPipeFilterListener::Read: (%p) %d\n", this, count));
00743 
00744   if (!buf || !readCount)
00745     return NS_ERROR_NULL_POINTER;
00746 
00747   PRInt32 avail = (mStreamLength > mStreamOffset) ?
00748                    mStreamLength - mStreamOffset : 0;
00749 
00750   *readCount = ((PRUint32) avail > count) ? count : avail;
00751 
00752   if (*readCount) {
00753     memcpy(buf, mStreamBuf+mStreamOffset, *readCount);
00754     mStreamOffset += *readCount;
00755   }
00756 
00757   if (mStreamOffset >= mStreamLength) {
00758     Close();
00759   }
00760 
00761   return NS_OK;
00762 }
00763 
00764 NS_IMETHODIMP
00765 nsPipeFilterListener::ReadSegments(nsWriteSegmentFun writer,
00766                                  void * aClosure, PRUint32 count,
00767                                  PRUint32 *readCount)
00768 {
00769   nsresult rv;
00770 
00771   DEBUG_LOG(("nsPipeFilterListener::ReadSegments: %d\n", count));
00772 
00773   if (!readCount)
00774     return NS_ERROR_NULL_POINTER;
00775 
00776   PRUint32 avail, readyCount, writeCount;
00777 
00778   *readCount = 0;
00779 
00780   while ((count > 0) && (mStreamOffset < mStreamLength)) {
00781     avail = mStreamLength - mStreamOffset;
00782     readyCount = ((PRUint32) avail > count) ? count : avail;
00783 
00784     rv = writer((nsIInputStream*)(this),
00785                 aClosure, mStreamBuf+mStreamOffset,
00786                 mStreamOffset, readyCount, &writeCount);
00787     NS_ENSURE_SUCCESS(rv, rv);
00788     if (!writeCount)
00789       return NS_ERROR_FAILURE;
00790 
00791     DEBUG_LOG(("nsPipeFilterListener::ReadSegments: writer %d\n", writeCount));
00792 
00793     *readCount    += writeCount;
00794     mStreamOffset += writeCount;
00795     count         -= writeCount;
00796   }
00797 
00798   if (mStreamOffset >= mStreamLength) {
00799     Close();
00800   }
00801 
00802   return NS_OK;
00803 }
00804 
00805 NS_IMETHODIMP
00806 nsPipeFilterListener::IsNonBlocking(EMBool *aNonBlocking)
00807 {
00808   DEBUG_LOG(("nsPipeFilterListener::IsNonBlocking: \n"));
00809 
00810   *aNonBlocking = PR_TRUE;
00811   return NS_OK;
00812 }
00813 
00814 NS_IMETHODIMP
00815 nsPipeFilterListener::Close()
00816 {
00817   DEBUG_LOG(("nsPipeFilterListener::Close: (%p)\n", this));
00818   mStreamBuf = nsnull;
00819   mStreamOffset = 0;
00820   mStreamLength = 0;
00821   return NS_OK;
00822 }