Bug 545869 - Remove small buffer #defines and use preferences. r=honza
authorDoug Turner <dougt@dougt.org>
Tue, 20 Apr 2010 09:32:28 -0700
changeset 41031 10d5c11a5b9af8b8789810c77c58059d10acecbf
parent 41030 b0a280657e232b28123ea84597c166863ad5963c
child 41032 ab2dbfc1d099189a664dfa0e8fa48b8f8dc4e97d
push idunknown
push userunknown
push dateunknown
reviewershonza
bugs545869
milestone1.9.3a5pre
Bug 545869 - Remove small buffer #defines and use preferences. r=honza
config/autoconf.mk.in
configure.in
modules/libpref/src/init/all.js
netwerk/base/src/nsAsyncStreamCopier.cpp
netwerk/base/src/nsIOService.cpp
netwerk/base/src/nsIOService.h
netwerk/base/src/nsInputStreamPump.cpp
netwerk/base/src/nsNetSegmentUtils.h
netwerk/base/src/nsSyncStreamListener.cpp
netwerk/necko-config.h.in
netwerk/protocol/data/src/nsDataChannel.cpp
netwerk/protocol/file/src/nsFileChannel.cpp
netwerk/protocol/ftp/src/nsFTPChannel.h
netwerk/protocol/ftp/src/nsFtpConnectionThread.cpp
netwerk/protocol/ftp/src/nsFtpControlConnection.cpp
netwerk/protocol/http/src/nsHttp.h
netwerk/protocol/http/src/nsHttpChannel.cpp
netwerk/protocol/http/src/nsHttpConnection.cpp
netwerk/protocol/http/src/nsHttpPipeline.cpp
netwerk/protocol/http/src/nsHttpPipeline.h
netwerk/protocol/http/src/nsHttpTransaction.cpp
netwerk/streamconv/converters/nsBinHexDecoder.cpp
uriloader/exthandler/nsExternalHelperAppService.cpp
uriloader/exthandler/nsExternalHelperAppService.h
--- a/config/autoconf.mk.in
+++ b/config/autoconf.mk.in
@@ -205,17 +205,16 @@ MOZ_POST_PROGRAM_COMMAND = @MOZ_POST_PRO
 
 MOZ_BUILD_ROOT             = @MOZ_BUILD_ROOT@
 
 MOZ_XUL                    = @MOZ_XUL@
 MOZ_RDF                    = @MOZ_RDF@
 
 NECKO_PROTOCOLS = @NECKO_PROTOCOLS@
 NECKO_DISK_CACHE = @NECKO_DISK_CACHE@
-NECKO_SMALL_BUFFERS = @NECKO_SMALL_BUFFERS@
 NECKO_COOKIES = @NECKO_COOKIES@
 NECKO_WIFI = @NECKO_WIFI@
 MOZ_AUTH_EXTENSION = @MOZ_AUTH_EXTENSION@
 
 MOZ_NATIVE_HUNSPELL = @SYSTEM_HUNSPELL@
 MOZ_HUNSPELL_LIBS = @MOZ_HUNSPELL_LIBS@
 MOZ_HUNSPELL_CFLAGS = @MOZ_HUNSPELL_CFLAGS@
 
--- a/configure.in
+++ b/configure.in
@@ -4811,17 +4811,16 @@ MOZ_XSLT_STANDALONE=
 MOZ_XTF=1
 MOZ_XUL=1
 MOZ_ZIPWRITER=1
 NS_PRINTING=1
 NECKO_WIFI=1
 NECKO_COOKIES=1
 NECKO_DISK_CACHE=1
 NECKO_PROTOCOLS_DEFAULT="about data file ftp gopher http res viewsource"
-NECKO_SMALL_BUFFERS=
 BUILD_CTYPES=1
 XPC_IDISPATCH_SUPPORT=
 
 
 case "$target_os" in
 darwin*|*wince*|*winmo*)
     ACCESSIBILITY=
     ;;
@@ -8142,29 +8141,16 @@ then
 fi
 
 if test "$NECKO_WIFI"; then
   AC_DEFINE(NECKO_WIFI)
 fi
 AC_SUBST(NECKO_WIFI)
 
 dnl
-dnl option to minimize size of necko's i/o buffers
-dnl
-MOZ_ARG_ENABLE_BOOL(necko-small-buffers,
-[  --enable-necko-small-buffers
-                          Minimize size of necko's i/o buffers],
-    NECKO_SMALL_BUFFERS=1,
-    NECKO_SMALL_BUFFERS=)
-AC_SUBST(NECKO_SMALL_BUFFERS)
-if test "$NECKO_SMALL_BUFFERS"; then
-    AC_DEFINE(NECKO_SMALL_BUFFERS)
-fi 
-
-dnl
 dnl option to disable cookies
 dnl
 MOZ_ARG_DISABLE_BOOL(cookies,
 [  --disable-cookies       Disable cookie support],
     NECKO_COOKIES=,
     NECKO_COOKIES=1)
 AC_SUBST(NECKO_COOKIES)
 if test "$NECKO_COOKIES"; then
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -2883,8 +2883,11 @@ pref("html5.flushtimer.continuedelay", 1
 // firing.
 pref("html5.flushtimer.interval", 120);
 
 // Push/Pop/Replace State prefs
 pref("browser.history.allowPushState", true);
 pref("browser.history.allowReplaceState", true);
 pref("browser.history.allowPopState", true);
 pref("browser.history.maxStateObjectSize", 655360);
+
+pref("network.buffer.cache.count", 24);
+pref("network.buffer.cache.size",  4096);
--- a/netwerk/base/src/nsAsyncStreamCopier.cpp
+++ b/netwerk/base/src/nsAsyncStreamCopier.cpp
@@ -30,16 +30,17 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+#include "nsIOService.h"
 #include "nsAsyncStreamCopier.h"
 #include "nsIEventTarget.h"
 #include "nsStreamUtils.h"
 #include "nsNetSegmentUtils.h"
 #include "nsNetUtil.h"
 #include "nsAutoLock.h"
 #include "prlog.h"
 
@@ -51,17 +52,17 @@ static PRLogModuleInfo *gStreamCopierLog
 #endif
 #define LOG(args) PR_LOG(gStreamCopierLog, PR_LOG_DEBUG, args)
 
 //-----------------------------------------------------------------------------
 
 nsAsyncStreamCopier::nsAsyncStreamCopier()
     : mLock(nsnull)
     , mMode(NS_ASYNCCOPY_VIA_READSEGMENTS)
-    , mChunkSize(NET_DEFAULT_SEGMENT_SIZE)
+    , mChunkSize(nsIOService::gDefaultSegmentSize)
     , mStatus(NS_OK)
     , mIsPending(PR_FALSE)
 {
 #if defined(PR_LOGGING)
     if (!gStreamCopierLog)
         gStreamCopierLog = PR_NewLogModule("nsStreamCopier");
 #endif
     LOG(("Creating nsAsyncStreamCopier @%x\n", this));
@@ -229,17 +230,17 @@ nsAsyncStreamCopier::Init(nsIInputStream
     NS_ASSERTION(sourceBuffered || sinkBuffered, "at least one stream must be buffered");
 
     NS_ASSERTION(!mLock, "already initialized");
     mLock = PR_NewLock();
     if (!mLock)
         return NS_ERROR_OUT_OF_MEMORY;
 
     if (chunkSize == 0)
-        chunkSize = NET_DEFAULT_SEGMENT_SIZE;
+        chunkSize = nsIOService::gDefaultSegmentSize;
     mChunkSize = chunkSize;
 
     mSource = source;
     mSink = sink;
     mCloseSource = closeSource;
     mCloseSink = closeSink;
 
     mMode = sourceBuffered ? NS_ASYNCCOPY_VIA_READSEGMENTS
--- a/netwerk/base/src/nsIOService.cpp
+++ b/netwerk/base/src/nsIOService.cpp
@@ -79,16 +79,19 @@
 #include "nsNativeConnectionHelper.h"
 #endif
 
 #define PORT_PREF_PREFIX           "network.security.ports."
 #define PORT_PREF(x)               PORT_PREF_PREFIX x
 #define AUTODIAL_PREF              "network.autodial-helper.enabled"
 #define MANAGE_OFFLINE_STATUS_PREF "network.manage-offline-status"
 
+#define NECKO_BUFFER_CACHE_COUNT_PREF "network.buffer.cache.count"
+#define NECKO_BUFFER_CACHE_SIZE_PREF  "network.buffer.cache.size"
+
 #define MAX_RECURSION_COUNT 50
 
 nsIOService* gIOService = nsnull;
 static PRBool gHasWarnedUploadChannel2;
 
 // A general port blacklist.  Connections to these ports will not be allowed unless 
 // the protocol overrides.
 //
@@ -157,46 +160,31 @@ PRInt16 gBadPortList[] = {
   0,    // This MUST be zero so that we can populating the array
 };
 
 static const char kProfileChangeNetTeardownTopic[] = "profile-change-net-teardown";
 static const char kProfileChangeNetRestoreTopic[] = "profile-change-net-restore";
 
 // Necko buffer cache
 nsIMemory* nsIOService::gBufferCache = nsnull;
+PRUint32   nsIOService::gDefaultSegmentSize = 4096;
+PRUint32   nsIOService::gDefaultSegmentCount = 24;
 
 ////////////////////////////////////////////////////////////////////////////////
 
 nsIOService::nsIOService()
     : mOffline(PR_FALSE)
     , mOfflineForProfileChange(PR_FALSE)
     , mManageOfflineStatus(PR_TRUE)
     , mSettingOffline(PR_FALSE)
     , mSetOfflineValue(PR_FALSE)
     , mShutdown(PR_FALSE)
     , mChannelEventSinks(NS_CHANNEL_EVENT_SINK_CATEGORY)
     , mContentSniffers(NS_CONTENT_SNIFFER_CATEGORY)
 {
-    // Get the allocator ready
-    if (!gBufferCache)
-    {
-        nsresult rv = NS_OK;
-        nsCOMPtr<nsIRecyclingAllocator> recyclingAllocator =
-            do_CreateInstance(NS_RECYCLINGALLOCATOR_CONTRACTID, &rv);
-        if (NS_FAILED(rv))
-            return;
-        rv = recyclingAllocator->Init(NS_NECKO_BUFFER_CACHE_COUNT,
-                                      NS_NECKO_15_MINS, "necko");
-        if (NS_FAILED(rv))
-            return;
-
-        nsCOMPtr<nsIMemory> eyeMemory = do_QueryInterface(recyclingAllocator);
-        gBufferCache = eyeMemory.get();
-        NS_IF_ADDREF(gBufferCache);
-    }
 }
 
 nsresult
 nsIOService::Init()
 {
     nsresult rv;
     
     // We need to get references to these services so that we can shut them
@@ -246,16 +234,32 @@ nsIOService::Init()
         observerService->AddObserver(this, kProfileChangeNetTeardownTopic, PR_TRUE);
         observerService->AddObserver(this, kProfileChangeNetRestoreTopic, PR_TRUE);
         observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_TRUE);
         observerService->AddObserver(this, NS_NETWORK_LINK_TOPIC, PR_TRUE);
     }
     else
         NS_WARNING("failed to get observer service");
         
+    // Get the allocator ready
+    if (!gBufferCache) {
+        nsresult rv = NS_OK;
+        nsCOMPtr<nsIRecyclingAllocator> recyclingAllocator =
+            do_CreateInstance(NS_RECYCLINGALLOCATOR_CONTRACTID, &rv);
+
+        if (NS_FAILED(rv))
+            return rv;
+        rv = recyclingAllocator->Init(gDefaultSegmentCount,
+                                      (15 * 60), // 15 minutes
+                                      "necko");
+
+        NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Was unable to allocate.  No gBufferCache.");
+        CallQueryInterface(recyclingAllocator, &gBufferCache);
+    }
+
     gIOService = this;
     
     // go into managed mode if we can
     mNetworkLinkService = do_GetService(NS_NETWORK_LINK_SERVICE_CONTRACTID);
     if (!mNetworkLinkService)
         mManageOfflineStatus = PR_FALSE;
 
     if (mManageOfflineStatus)
@@ -786,16 +790,39 @@ nsIOService::PrefsChanged(nsIPrefBranch 
     }
 
     if (!pref || strcmp(pref, MANAGE_OFFLINE_STATUS_PREF) == 0) {
         PRBool manage;
         if (NS_SUCCEEDED(prefs->GetBoolPref(MANAGE_OFFLINE_STATUS_PREF,
                                             &manage)))
             SetManageOfflineStatus(manage);
     }
+
+    if (!pref || strcmp(pref, NECKO_BUFFER_CACHE_COUNT_PREF) == 0) {
+        PRInt32 count;
+        if (NS_SUCCEEDED(prefs->GetIntPref(NECKO_BUFFER_CACHE_COUNT_PREF,
+                                           &count)))
+            /* check for bogus values and default if we find such a value */
+            if (count > 0)
+                gDefaultSegmentCount = count;
+    }
+    
+    if (!pref || strcmp(pref, NECKO_BUFFER_CACHE_SIZE_PREF) == 0) {
+        PRInt32 size;
+        if (NS_SUCCEEDED(prefs->GetIntPref(NECKO_BUFFER_CACHE_SIZE_PREF,
+                                           &size)))
+            /* check for bogus values and default if we find such a value
+             * the upper limit here is arbitrary. having a 1mb segment size
+             * is pretty crazy.  if you remove this, consider adding some
+             * integer rollover test.
+             */
+            if (size > 0 && size < 1024*1024)
+                gDefaultSegmentSize = size;
+        NS_WARN_IF_FALSE( (!(size & (size - 1))) , "network buffer cache size is not a power of 2!");
+    }
 }
 
 void
 nsIOService::ParsePortList(nsIPrefBranch *prefBranch, const char *pref, PRBool remove)
 {
     nsXPIDLCString portList;
 
     // Get a pref string and chop it up into a list of ports.
--- a/netwerk/base/src/nsIOService.h
+++ b/netwerk/base/src/nsIOService.h
@@ -55,23 +55,16 @@
 #include "nsINetUtil.h"
 #include "nsIChannelEventSink.h"
 #include "nsIContentSniffer.h"
 #include "nsCategoryCache.h"
 #include "nsINetworkLinkService.h"
 
 #define NS_N(x) (sizeof(x)/sizeof(*x))
 
-#ifdef NECKO_SMALL_BUFFERS
-#define NS_NECKO_BUFFER_CACHE_COUNT (10)  // Max holdings: 10 * 2k = 20k
-#else
-#define NS_NECKO_BUFFER_CACHE_COUNT (24)  // Max holdings: 24 * 4k = 96k
-#endif
-#define NS_NECKO_15_MINS (15 * 60)
-
 static const char gScheme[][sizeof("resource")] =
     {"chrome", "file", "http", "jar", "resource"};
 
 class nsIPrefBranch;
 class nsIPrefBranch2;
 
 class nsIOService : public nsIIOService2
                   , public nsIObserver
@@ -154,16 +147,18 @@ private:
     nsCategoryCache<nsIContentSniffer>   mContentSniffers;
 
     nsTArray<PRInt32>                    mRestrictedPortList;
 
 public:
     // Necko buffer cache. Used for all default buffer sizes that necko
     // allocates.
     static nsIMemory *gBufferCache;
+    static PRUint32   gDefaultSegmentSize;
+    static PRUint32   gDefaultSegmentCount;
 };
 
 /**
  * Reference to the IO service singleton. May be null.
  */
 extern nsIOService* gIOService;
 
 #endif // nsIOService_h__
--- a/netwerk/base/src/nsInputStreamPump.cpp
+++ b/netwerk/base/src/nsInputStreamPump.cpp
@@ -31,25 +31,25 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+#include "nsIOService.h"
 #include "nsInputStreamPump.h"
 #include "nsIServiceManager.h"
 #include "nsIStreamTransportService.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsISeekableStream.h"
 #include "nsITransport.h"
 #include "nsNetUtil.h"
 #include "nsThreadUtils.h"
-#include "nsNetSegmentUtils.h"
 #include "nsCOMPtr.h"
 #include "prlog.h"
 
 static NS_DEFINE_CID(kStreamTransportServiceCID, NS_STREAMTRANSPORTSERVICE_CID);
 
 #if defined(PR_LOGGING)
 //
 // NSPR_LOG_MODULES=nsStreamPump:5
@@ -133,18 +133,20 @@ nsInputStreamPump::PeekStream(PeekSegmen
 
   // See if the pipe is closed by checking the return of Available.
   PRUint32 dummy;
   nsresult rv = mAsyncStream->Available(&dummy);
   if (NS_FAILED(rv))
     return rv;
 
   PeekData data(callback, closure);
-  return mAsyncStream->ReadSegments(CallPeekFunc, &data,
-                                    NET_DEFAULT_SEGMENT_SIZE, &dummy);
+  return mAsyncStream->ReadSegments(CallPeekFunc,
+                                    &data,
+                                    nsIOService::gDefaultSegmentSize,
+                                    &dummy);
 }
 
 nsresult
 nsInputStreamPump::EnsureWaiting()
 {
     // no need to worry about multiple threads... an input stream pump lives
     // on only one thread.
 
--- a/netwerk/base/src/nsNetSegmentUtils.h
+++ b/netwerk/base/src/nsNetSegmentUtils.h
@@ -33,44 +33,36 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef nsNetSegmentUtils_h__
 #define nsNetSegmentUtils_h__
 
-#include "necko-config.h"
 #include "nsIOService.h"
 
-#ifdef NECKO_SMALL_BUFFERS
-#define NET_DEFAULT_SEGMENT_SIZE  2048
-#define NET_DEFAULT_SEGMENT_COUNT 4
-#else
-#define NET_DEFAULT_SEGMENT_SIZE  4096
-#define NET_DEFAULT_SEGMENT_COUNT 16
-#endif
-
 /**
  * returns preferred allocator for given segment size.  NULL implies
  * system allocator.  this result can be used when allocating a pipe.
  */
+
 static inline nsIMemory *
 net_GetSegmentAlloc(PRUint32 segsize)
 {
-    return (segsize == NET_DEFAULT_SEGMENT_SIZE)
-                     ? nsIOService::gBufferCache
-                     : nsnull;
+    return (segsize == nsIOService::gDefaultSegmentSize)
+                     ? nsIOService::gBufferCache : nsnull;
 }
 
 /**
  * applies defaults to segment params in a consistent way.
  */
 static inline void
 net_ResolveSegmentParams(PRUint32 &segsize, PRUint32 &segcount)
 {
     if (!segsize)
-        segsize = NET_DEFAULT_SEGMENT_SIZE;
+        segsize = nsIOService::gDefaultSegmentSize;
+
     if (!segcount)
-        segcount = NET_DEFAULT_SEGMENT_COUNT;
+        segcount = nsIOService::gDefaultSegmentCount;
 }
 
 #endif // !nsNetSegmentUtils_h__
--- a/netwerk/base/src/nsSyncStreamListener.cpp
+++ b/netwerk/base/src/nsSyncStreamListener.cpp
@@ -29,26 +29,26 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+#include "nsIOService.h"
 #include "nsSyncStreamListener.h"
 #include "nsIPipe.h"
-#include "nsNetSegmentUtils.h"
 
 nsresult
 nsSyncStreamListener::Init()
 {
     return NS_NewPipe(getter_AddRefs(mPipeIn),
                       getter_AddRefs(mPipeOut),
-                      NET_DEFAULT_SEGMENT_SIZE,
+                      nsIOService::gDefaultSegmentSize,
                       PR_UINT32_MAX, // no size limit
                       PR_FALSE,
                       PR_FALSE);
 }
 
 nsresult
 nsSyncStreamListener::WaitForData()
 {
--- a/netwerk/necko-config.h.in
+++ b/netwerk/necko-config.h.in
@@ -34,18 +34,16 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef _NECKO_CONFIG_H_
 #define _NECKO_CONFIG_H_
 
 #undef NECKO_DISK_CACHE
 
-#undef NECKO_SMALL_BUFFERS
-
 #undef NECKO_COOKIES
 
 #undef NECKO_WIFI
 
 #undef NECKO_PROTOCOL_about
 #undef NECKO_PROTOCOL_data
 #undef NECKO_PROTOCOL_file
 #undef NECKO_PROTOCOL_ftp
--- a/netwerk/protocol/data/src/nsDataChannel.cpp
+++ b/netwerk/protocol/data/src/nsDataChannel.cpp
@@ -32,24 +32,24 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 // data implementation
 
+#include "nsIOService.h"
 #include "nsDataChannel.h"
 #include "nsDataHandler.h"
 #include "nsNetUtil.h"
 #include "nsIPipe.h"
 #include "nsIInputStream.h"
 #include "nsIOutputStream.h"
 #include "nsReadableUtils.h"
-#include "nsNetSegmentUtils.h"
 #include "nsEscape.h"
 #include "plbase64.h"
 #include "plstr.h"
 #include "prmem.h"
 
 nsresult
 nsDataChannel::OpenContentStream(PRBool async, nsIInputStream **result,
                                  nsIChannel** channel)
@@ -77,17 +77,18 @@ nsDataChannel::OpenContentStream(PRBool 
     }
     
     nsCOMPtr<nsIInputStream> bufInStream;
     nsCOMPtr<nsIOutputStream> bufOutStream;
     
     // create an unbounded pipe.
     rv = NS_NewPipe(getter_AddRefs(bufInStream),
                     getter_AddRefs(bufOutStream),
-                    NET_DEFAULT_SEGMENT_SIZE, PR_UINT32_MAX,
+                    nsIOService::gDefaultSegmentSize,
+                    PR_UINT32_MAX,
                     async, PR_TRUE);
     if (NS_FAILED(rv))
         return rv;
 
     PRUint32 contentLen;
     if (lBase64) {
         const PRUint32 dataLen = dataBuffer.Length();
         PRInt32 resultLen = 0;
--- a/netwerk/protocol/file/src/nsFileChannel.cpp
+++ b/netwerk/protocol/file/src/nsFileChannel.cpp
@@ -32,26 +32,26 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+#include "nsIOService.h"
 #include "nsFileChannel.h"
 #include "nsBaseContentStream.h"
 #include "nsDirectoryIndexStream.h"
 #include "nsThreadUtils.h"
 #include "nsTransportUtils.h"
 #include "nsStreamUtils.h"
 #include "nsURLHelper.h"
 #include "nsMimeTypes.h"
 #include "nsNetUtil.h"
-#include "nsNetSegmentUtils.h"
 #include "nsProxyRelease.h"
 #include "nsAutoPtr.h"
 #include "nsStandardURL.h"
 
 #include "nsIFileURL.h"
 #include "nsIMIMEService.h"
 
 //-----------------------------------------------------------------------------
@@ -102,17 +102,17 @@ private:
   nsresult mInterruptStatus;  // modified on main thread only
 };
 
 void
 nsFileCopyEvent::DoCopy()
 {
   // We'll copy in chunks this large by default.  This size affects how
   // frequently we'll check for interrupts.
-  const PRInt32 chunk = NET_DEFAULT_SEGMENT_SIZE * NET_DEFAULT_SEGMENT_COUNT;
+  const PRInt32 chunk = nsIOService::gDefaultSegmentSize * nsIOService::gDefaultSegmentCount;
 
   nsresult rv = NS_OK;
 
   PRInt64 len = mLen, progress = 0;
   while (len) {
     // If we've been interrupted, then stop copying.
     rv = mInterruptStatus;
     if (NS_FAILED(rv))
--- a/netwerk/protocol/ftp/src/nsFTPChannel.h
+++ b/netwerk/protocol/ftp/src/nsFTPChannel.h
@@ -58,22 +58,16 @@
 #include "nsAutoLock.h"
 #include "nsIFTPChannel.h"
 #include "nsIUploadChannel.h"
 #include "nsIProxyInfo.h"
 #include "nsIProxiedChannel.h"
 #include "nsIResumableChannel.h"
 #include "nsHashPropertyBag.h"
 
-#define FTP_COMMAND_CHANNEL_SEG_SIZE 64
-#define FTP_COMMAND_CHANNEL_SEG_COUNT 8
-
-#define FTP_DATA_CHANNEL_SEG_SIZE  (4*1024)
-#define FTP_DATA_CHANNEL_SEG_COUNT 8
-
 class nsFtpChannel : public nsBaseChannel,
                      public nsIFTPChannel,
                      public nsIUploadChannel,
                      public nsIResumableChannel,
                      public nsIProxiedChannel
 {
 public:
     NS_DECL_ISUPPORTS_INHERITED
--- a/netwerk/protocol/ftp/src/nsFtpConnectionThread.cpp
+++ b/netwerk/protocol/ftp/src/nsFtpConnectionThread.cpp
@@ -40,16 +40,17 @@
 
 #include <limits.h>
 #include <ctype.h>
 
 #include "prprf.h"
 #include "prlog.h"
 #include "prtime.h"
 
+#include "nsIOService.h"
 #include "nsFTPChannel.h"
 #include "nsFtpConnectionThread.h"
 #include "nsFtpControlConnection.h"
 #include "nsFtpProtocolHandler.h"
 #include "ftpCore.h"
 #include "netCore.h"
 #include "nsCRT.h"
 #include "nsEscape.h"
@@ -1523,18 +1524,18 @@ nsFtpState::R_pasv() {
 
         //
         // else, we are reading from the data connection...
         //
 
         // open a buffered, asynchronous socket input stream
         nsCOMPtr<nsIInputStream> input;
         rv = mDataTransport->OpenInputStream(0,
-                                             FTP_DATA_CHANNEL_SEG_SIZE,
-                                             FTP_DATA_CHANNEL_SEG_COUNT,
+                                             nsIOService::gDefaultSegmentSize,
+                                             nsIOService::gDefaultSegmentCount,
                                              getter_AddRefs(input));
         NS_ENSURE_SUCCESS(rv, FTP_ERROR);
         mDataStream = do_QueryInterface(input);
     }
 
     if (mRETRFailed || (!mPath.IsEmpty() && mPath.Last() == '/'))
         return FTP_S_CWD;
     return FTP_S_SIZE;
@@ -1650,19 +1651,20 @@ nsFtpState::OpenCacheDataStream()
                               getter_AddRefs(transport));
     NS_ENSURE_STATE(transport);
 
     nsresult rv = transport->SetEventSink(this, NS_GetCurrentThread());
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Open a non-blocking, buffered input stream...
     nsCOMPtr<nsIInputStream> transportInput;
-    transport->OpenInputStream(0, FTP_DATA_CHANNEL_SEG_SIZE,
-                                  FTP_DATA_CHANNEL_SEG_COUNT,
-                                  getter_AddRefs(transportInput));
+    transport->OpenInputStream(0,
+                               nsIOService::gDefaultSegmentSize,
+                               nsIOService::gDefaultSegmentCount,
+                               getter_AddRefs(transportInput));
     NS_ENSURE_STATE(transportInput);
 
     mDataStream = do_QueryInterface(transportInput);
     NS_ENSURE_STATE(mDataStream);
 
     mDataTransport = transport;
     return NS_OK;
 }
--- a/netwerk/protocol/ftp/src/nsFtpControlConnection.cpp
+++ b/netwerk/protocol/ftp/src/nsFtpControlConnection.cpp
@@ -30,17 +30,17 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-
+#include "nsIOService.h"
 #include "nsFTPChannel.h"
 #include "nsFtpControlConnection.h"
 #include "nsFtpProtocolHandler.h"
 #include "prlog.h"
 #include "nsIPipe.h"
 #include "nsIInputStream.h"
 #include "nsISocketTransportService.h"
 #include "nsISocketTransport.h"
@@ -148,18 +148,18 @@ nsFtpControlConnection::Connect(nsIProxy
     rv = mSocket->OpenOutputStream(nsITransport::OPEN_BLOCKING, 1024, 1,
                                    getter_AddRefs(mSocketOutput));
     if (NS_FAILED(rv))
         return rv;
 
     // open buffered, non-blocking/asynchronous input stream to socket.
     nsCOMPtr<nsIInputStream> inStream;
     rv = mSocket->OpenInputStream(0,
-                                  FTP_COMMAND_CHANNEL_SEG_SIZE, 
-                                  FTP_COMMAND_CHANNEL_SEG_COUNT,
+                                  nsIOService::gDefaultSegmentSize,
+                                  nsIOService::gDefaultSegmentCount,
                                   getter_AddRefs(inStream));
     if (NS_SUCCEEDED(rv))
         mSocketInput = do_QueryInterface(inStream);
     
     return rv;
 }
 
 nsresult
--- a/netwerk/protocol/http/src/nsHttp.h
+++ b/netwerk/protocol/http/src/nsHttp.h
@@ -75,21 +75,16 @@ extern PRLogModuleInfo *gHttpLog;
 #define LOG(args) LOG4(args)
 
 #define LOG1_ENABLED() PR_LOG_TEST(gHttpLog, 1)
 #define LOG2_ENABLED() PR_LOG_TEST(gHttpLog, 2)
 #define LOG3_ENABLED() PR_LOG_TEST(gHttpLog, 3)
 #define LOG4_ENABLED() PR_LOG_TEST(gHttpLog, 4)
 #define LOG_ENABLED() LOG4_ENABLED()
 
-// http default buffer geometry
-#define NS_HTTP_SEGMENT_SIZE  4096
-#define NS_HTTP_SEGMENT_COUNT 16   // 64k maximum
-#define NS_HTTP_MAX_ODA_SIZE  (NS_HTTP_SEGMENT_SIZE * 4) // 16k
-
 // http version codes
 #define NS_HTTP_VERSION_UNKNOWN  0
 #define NS_HTTP_VERSION_0_9      9
 #define NS_HTTP_VERSION_1_0     10
 #define NS_HTTP_VERSION_1_1     11
 
 typedef PRUint8 nsHttpVersion;
 
--- a/netwerk/protocol/http/src/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/src/nsHttpChannel.cpp
@@ -78,17 +78,16 @@
 #include "nsInt64.h"
 #include "nsIVariant.h"
 #include "nsChannelProperties.h"
 #include "nsStreamUtils.h"
 #include "nsIOService.h"
 #include "nsAuthInformationHolder.h"
 #include "nsICacheService.h"
 #include "nsDNSPrefetch.h"
-#include "nsNetSegmentUtils.h"
 
 // True if the local cache should be bypassed when processing a request.
 #define BYPASS_LOCAL_CACHE(loadFlags) \
         (loadFlags & (nsIRequest::LOAD_BYPASS_CACHE | \
                       nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE))
 
 static NS_DEFINE_CID(kStreamListenerTeeCID, NS_STREAMLISTENERTEE_CID);
 
--- a/netwerk/protocol/http/src/nsHttpConnection.cpp
+++ b/netwerk/protocol/http/src/nsHttpConnection.cpp
@@ -37,16 +37,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsHttpConnection.h"
 #include "nsHttpTransaction.h"
 #include "nsHttpRequestHead.h"
 #include "nsHttpResponseHead.h"
 #include "nsHttpHandler.h"
+#include "nsIOService.h"
 #include "nsISocketTransportService.h"
 #include "nsISocketTransport.h"
 #include "nsIServiceManager.h"
 #include "nsISSLSocketControl.h"
 #include "nsStringStream.h"
 #include "netCore.h"
 #include "nsNetCID.h"
 #include "nsAutoLock.h"
@@ -562,21 +563,22 @@ nsHttpConnection::OnSocketWritable()
         //
         // NOTE: this code path can't be shared since the transaction doesn't
         // implement nsIInputStream.  doing so is not worth the added cost of
         // extra indirections during normal reading.
         //
         if (mSSLProxyConnectStream) {
             LOG(("  writing CONNECT request stream\n"));
             rv = mSSLProxyConnectStream->ReadSegments(ReadFromStream, this,
-                                                      NS_HTTP_SEGMENT_SIZE, &n);
+                                                      nsIOService::gDefaultSegmentSize,
+                                                      &n);
         }
         else {
             LOG(("  writing transaction request stream\n"));
-            rv = mTransaction->ReadSegments(this, NS_HTTP_SEGMENT_SIZE, &n);
+            rv = mTransaction->ReadSegments(this, nsIOService::gDefaultSegmentSize, &n);
         }
 
         LOG(("  ReadSegments returned [rv=%x read=%u sock-cond=%x]\n",
             rv, n, mSocketOutCondition));
 
         // XXX some streams return NS_BASE_STREAM_CLOSED to indicate EOF.
         if (rv == NS_BASE_STREAM_CLOSED) {
             rv = NS_OK;
@@ -656,17 +658,17 @@ nsHttpConnection::OnSocketReadable()
     }
     mLastReadTime = now;
 
     nsresult rv;
     PRUint32 n;
     PRBool again = PR_TRUE;
 
     do {
-        rv = mTransaction->WriteSegments(this, NS_HTTP_SEGMENT_SIZE, &n);
+        rv = mTransaction->WriteSegments(this, nsIOService::gDefaultSegmentSize, &n);
         if (NS_FAILED(rv)) {
             // if the transaction didn't want to take any more data, then
             // wait for the transaction to call ResumeRecv.
             if (rv == NS_BASE_STREAM_WOULD_BLOCK)
                 rv = NS_OK;
             again = PR_FALSE;
         }
         else if (NS_FAILED(mSocketInCondition)) {
--- a/netwerk/protocol/http/src/nsHttpPipeline.cpp
+++ b/netwerk/protocol/http/src/nsHttpPipeline.cpp
@@ -272,17 +272,17 @@ nsHttpPipeline::PushBack(const char *dat
     if (!mPushBackBuf) {
         mPushBackMax = length;
         mPushBackBuf = (char *) malloc(mPushBackMax);
         if (!mPushBackBuf)
             return NS_ERROR_OUT_OF_MEMORY;
     }
     else if (length > mPushBackMax) {
         // grow push back buffer as necessary.
-        NS_ASSERTION(length <= NS_HTTP_SEGMENT_SIZE, "too big");
+        NS_ASSERTION(length <= nsIOService::gDefaultSegmentSize, "too big");
         mPushBackMax = length;
         mPushBackBuf = (char *) realloc(mPushBackBuf, mPushBackMax);
         if (!mPushBackBuf)
             return NS_ERROR_OUT_OF_MEMORY;
     }
  
     memcpy(mPushBackBuf, data, length);
     mPushBackLen = length;
@@ -553,18 +553,18 @@ nsHttpPipeline::FillSendBuf()
     // when they have been completely read.
 
     nsresult rv;
     
     if (!mSendBufIn) {
         // allocate a single-segment pipe
         rv = NS_NewPipe(getter_AddRefs(mSendBufIn),
                         getter_AddRefs(mSendBufOut),
-                        NS_HTTP_SEGMENT_SIZE,
-                        NS_HTTP_SEGMENT_SIZE,
+                        nsIOService::gDefaultSegmentSize,  /* segment size */
+                        nsIOService::gDefaultSegmentSize,  /* max size */
                         PR_TRUE, PR_TRUE,
                         nsIOService::gBufferCache);
         if (NS_FAILED(rv)) return rv;
     }
 
     PRUint32 n, avail;
     nsAHttpTransaction *trans;
     while ((trans = Request(0)) != nsnull) {
--- a/netwerk/protocol/http/src/nsHttpPipeline.h
+++ b/netwerk/protocol/http/src/nsHttpPipeline.h
@@ -102,15 +102,15 @@ private:
     // used when calling ReadSegments/WriteSegments on a transaction.
     nsAHttpSegmentReader *mReader;
     nsAHttpSegmentWriter *mWriter;
 
     // send buffer
     nsCOMPtr<nsIInputStream>  mSendBufIn;
     nsCOMPtr<nsIOutputStream> mSendBufOut;
 
-    // the push back buffer.  not exceeding NS_HTTP_SEGMENT_SIZE bytes.
+    // the push back buffer.  not exceeding nsIOService::gDefaultSegmentSize bytes.
     char     *mPushBackBuf;
     PRUint32  mPushBackLen;
     PRUint32  mPushBackMax;
 };
 
 #endif // nsHttpPipeline_h__
--- a/netwerk/protocol/http/src/nsHttpTransaction.cpp
+++ b/netwerk/protocol/http/src/nsHttpTransaction.cpp
@@ -33,23 +33,23 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+#include "nsIOService.h"
 #include "nsHttpHandler.h"
 #include "nsHttpTransaction.h"
 #include "nsHttpConnection.h"
 #include "nsHttpRequestHead.h"
 #include "nsHttpResponseHead.h"
 #include "nsHttpChunkedDecoder.h"
-#include "nsNetSegmentUtils.h"
 #include "nsTransportUtils.h"
 #include "nsNetUtil.h"
 #include "nsProxyRelease.h"
 #include "nsIOService.h"
 #include "nsAutoLock.h"
 #include "pratom.h"
 
 #include "nsISeekableStream.h"
@@ -286,31 +286,31 @@ nsHttpTransaction::Init(PRUint8 caps,
 
         rv = multi->AppendStream(requestBody);
         if (NS_FAILED(rv)) return rv;
 
         // wrap the multiplexed input stream with a buffered input stream, so
         // that we write data in the largest chunks possible.  this is actually
         // necessary to workaround some common server bugs (see bug 137155).
         rv = NS_NewBufferedInputStream(getter_AddRefs(mRequestStream), multi,
-                                       NET_DEFAULT_SEGMENT_SIZE);
+                                       nsIOService::gDefaultSegmentSize);
         if (NS_FAILED(rv)) return rv;
     }
     else
         mRequestStream = headers;
 
     rv = mRequestStream->Available(&mRequestSize);
     if (NS_FAILED(rv)) return rv;
 
     // create pipe for response stream
     rv = NS_NewPipe2(getter_AddRefs(mPipeIn),
                      getter_AddRefs(mPipeOut),
                      PR_TRUE, PR_TRUE,
-                     NS_HTTP_SEGMENT_SIZE,
-                     NS_HTTP_SEGMENT_COUNT,
+                     nsIOService::gDefaultSegmentSize,
+                     nsIOService::gDefaultSegmentCount,
                      nsIOService::gBufferCache);
     if (NS_FAILED(rv)) return rv;
 
     NS_ADDREF(*responseBody = mPipeIn);
     return NS_OK;
 }
 
 nsHttpResponseHead *
--- a/netwerk/streamconv/converters/nsBinHexDecoder.cpp
+++ b/netwerk/streamconv/converters/nsBinHexDecoder.cpp
@@ -31,37 +31,33 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+#include "nsIOService.h"
 #include "nsBinHexDecoder.h"
 #include "nsIServiceManager.h"
 #include "nsIStreamConverterService.h"
 #include "nsCRT.h"
 #include "nsIPipe.h"
 #include "nsMimeTypes.h"
 #include "netCore.h"
 #include "nsXPIDLString.h"
 #include "prnetdb.h"
 #include "nsIURI.h"
 #include "nsIURL.h"
 
 #include "nsIMIMEService.h"
 #include "nsMimeTypes.h"
 
 
-#define DATA_BUFFER_SIZE (4096*2)
-
-#define NS_STREAM_CONVERTER_SEGMENT_SIZE   (4*1024)
-#define NS_STREAM_CONVERTER_BUFFER_SIZE    (32*1024)
-
 // sadly I couldn't find char defintions for CR LF elsehwere in the code (they are defined as strings in nsCRT.h)
 #define CR  '\015'
 #define LF '\012'
 
 nsBinHexDecoder::nsBinHexDecoder() :
   mState(0), mCRC(0), mFileCRC(0), mOctetin(26),
   mDonePos(3), mInCRC(0), mCount(0), mMarker(0), mPosInbuff(0),
   mPosOutputBuff(0)
@@ -162,17 +158,17 @@ nsBinHexDecoder::OnDataAvailable(nsIRequ
 {
   nsresult rv = NS_OK;
 
   if (mOutputStream && mDataBuffer && aCount > 0)
   {
     PRUint32 numBytesRead = 0;
     while (aCount > 0) // while we still have bytes to copy...
     {
-      aStream->Read(mDataBuffer, PR_MIN(aCount, DATA_BUFFER_SIZE - 1), &numBytesRead);
+      aStream->Read(mDataBuffer, PR_MIN(aCount, nsIOService::gDefaultSegmentSize - 1), &numBytesRead);
       if (aCount >= numBytesRead)
         aCount -= numBytesRead; // subtract off the number of bytes we just read
       else
         aCount = 0;
 
       // Process this new chunk of bin hex data...
       ProcessNextChunk(request, aCtxt, numBytesRead);
     }
@@ -271,17 +267,17 @@ nsresult nsBinHexDecoder::ProcessNextSta
 
         if (status != NS_OK)
           mState = BINHEX_STATE_DONE;
         else
           ++mState;
 
         mInCRC = 1;
       }
-      else if (mPosOutputBuff >= DATA_BUFFER_SIZE)
+      else if (mPosOutputBuff >= (PRInt32) nsIOService::gDefaultSegmentSize)
       {
         if (mState == BINHEX_STATE_DFORK)
         {
           PRUint32 numBytesWritten = 0;
           mOutputStream->Write(mOutgoingBuffer, mPosOutputBuff, &numBytesWritten);
           if (PRInt32(numBytesWritten) != mPosOutputBuff)
             status = NS_ERROR_FAILURE;
 
@@ -478,24 +474,24 @@ PRInt16 nsBinHexDecoder::GetNextChar(PRU
 
 NS_IMETHODIMP
 nsBinHexDecoder::OnStartRequest(nsIRequest* request, nsISupports *aCtxt)
 {
   nsresult rv = NS_OK;
 
   NS_ENSURE_TRUE(mNextListener, NS_ERROR_FAILURE);
 
-  mDataBuffer = (char *) nsMemory::Alloc((sizeof(char) * DATA_BUFFER_SIZE));
-  mOutgoingBuffer = (char *) nsMemory::Alloc((sizeof(char) * DATA_BUFFER_SIZE));
+  mDataBuffer = (char *) nsMemory::Alloc((sizeof(char) * nsIOService::gDefaultSegmentSize));
+  mOutgoingBuffer = (char *) nsMemory::Alloc((sizeof(char) * nsIOService::gDefaultSegmentSize));
   if (!mDataBuffer || !mOutgoingBuffer) return NS_ERROR_FAILURE; // out of memory;
 
   // now we want to create a pipe which we'll use to write our converted data...
   rv = NS_NewPipe(getter_AddRefs(mInputStream), getter_AddRefs(mOutputStream),
-                  NS_STREAM_CONVERTER_SEGMENT_SIZE,
-                  NS_STREAM_CONVERTER_BUFFER_SIZE,
+                  nsIOService::gDefaultSegmentSize,
+                  nsIOService::gDefaultSegmentSize,
                   PR_TRUE, PR_TRUE);
 
   // don't propagate the on start request to mNextListener until we have determined the content type.
   return rv;
 }
 
 // Given the fileName we discovered inside the bin hex decoding, figure out the
 // content type and set it on the channel associated with the request.  If the
--- a/uriloader/exthandler/nsExternalHelperAppService.cpp
+++ b/uriloader/exthandler/nsExternalHelperAppService.cpp
@@ -1105,16 +1105,17 @@ nsExternalAppHandler::nsExternalAppHandl
 , mShouldCloseWindow(PR_FALSE)
 , mReceivedDispositionInfo(PR_FALSE)
 , mStopRequestIssued(PR_FALSE)
 , mProgressListenerInitialized(PR_FALSE)
 , mReason(aReason)
 , mContentLength(-1)
 , mProgress(0)
 , mRequest(nsnull)
+, mDataBuffer(nsnull)
 {
 
   // make sure the extention includes the '.'
   if (!aTempFileExtension.IsEmpty() && aTempFileExtension.First() != '.')
     mTempFileExtension = PRUnichar('.');
   AppendUTF8toUTF16(aTempFileExtension, mTempFileExtension);
 
   // replace platform specific path separator and illegal characters to avoid any confusion
@@ -1133,22 +1134,40 @@ nsExternalAppHandler::nsExternalAppHandl
     mSuggestedFileName.ReplaceChar(unsafeBidiCharacters[i], '_');
     mTempFileExtension.ReplaceChar(unsafeBidiCharacters[i], '_');
   }
   
   // Make sure extension is correct.
   EnsureSuggestedFileName();
 
   gExtProtSvc->AddRef();
+
+  nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
+  if (!prefs)
+    return;
+
+  mBufferSize = 8192;
+  PRInt32 size;
+  nsresult rv = prefs->GetIntPref("network.buffer.cache.size", &size);
+  if (NS_SUCCEEDED(rv)) {
+    mBufferSize = size;
+  }
+
+  mDataBuffer = (char*) malloc(mBufferSize);
+  if (!mDataBuffer)
+    return;
 }
 
 nsExternalAppHandler::~nsExternalAppHandler()
 {
   // Not using NS_RELEASE, since we don't want to set gExtProtSvc to NULL
   gExtProtSvc->Release();
+
+  if (mDataBuffer)
+    free(mDataBuffer);
 }
 
 NS_IMETHODIMP nsExternalAppHandler::SetWebProgressListener(nsIWebProgressListener2 * aWebProgressListener)
 { 
   // this call back means we've successfully brought up the 
   // progress window so set the appropriate flag, even though
   // aWebProgressListener might be null
   
@@ -1753,30 +1772,30 @@ void nsExternalAppHandler::SendStatusCha
     }
 }
 
 NS_IMETHODIMP nsExternalAppHandler::OnDataAvailable(nsIRequest *request, nsISupports * aCtxt,
                                                   nsIInputStream * inStr, PRUint32 sourceOffset, PRUint32 count)
 {
   nsresult rv = NS_OK;
   // first, check to see if we've been canceled....
-  if (mCanceled) // then go cancel our underlying channel too
+  if (mCanceled || !mDataBuffer) // then go cancel our underlying channel too
     return request->Cancel(NS_BINDING_ABORTED);
 
   // read the data out of the stream and write it to the temp file.
   if (mOutStream && count > 0)
   {
     PRUint32 numBytesRead = 0; 
     PRUint32 numBytesWritten = 0;
     mProgress += count;
     PRBool readError = PR_TRUE;
     while (NS_SUCCEEDED(rv) && count > 0) // while we still have bytes to copy...
     {
       readError = PR_TRUE;
-      rv = inStr->Read(mDataBuffer, PR_MIN(count, DATA_BUFFER_SIZE - 1), &numBytesRead);
+      rv = inStr->Read(mDataBuffer, PR_MIN(count, mBufferSize - 1), &numBytesRead);
       if (NS_SUCCEEDED(rv))
       {
         if (count >= numBytesRead)
           count -= numBytesRead; // subtract off the number of bytes we just read
         else
           count = 0;
         readError = PR_FALSE;
         // Write out the data until something goes wrong, or, it is
--- a/uriloader/exthandler/nsExternalHelperAppService.h
+++ b/uriloader/exthandler/nsExternalHelperAppService.h
@@ -233,23 +233,16 @@ protected:
   nsCOMArray<nsILocalFile> mTemporaryPrivateFilesList;
   /**
    * Whether we are in private browsing mode
    */
   PRBool mInPrivateBrowsing;
 };
 
 /**
- * We need to read the data out of the incoming stream into a buffer which we
- * can then use to write the data into the output stream representing the
- * temp file.
- */
-#define DATA_BUFFER_SIZE (4096*2) 
-
-/**
  * An external app handler is just a small little class that presents itself as
  * a nsIStreamListener. It saves the incoming data into a temp file. The handler
  * is bound to an application when it is created. When it receives an
  * OnStopRequest it launches the application using the temp file it has
  * stored the data into.  We create a handler every time we have to process
  * data using a helper app.
  */
 class nsExternalAppHandler : public nsIStreamListener,
@@ -354,17 +347,18 @@ protected:
 
   /**
    * When we are told to save the temp file to disk (in a more permament
    * location) before we are done writing the content to a temp file, then
    * we need to remember the final destination until we are ready to use it.
    */
   nsCOMPtr<nsIFile> mFinalFileDestination;
 
-  char mDataBuffer[DATA_BUFFER_SIZE];
+  PRUint32 mBufferSize;
+  char    *mDataBuffer;
 
   /**
    * Creates the temporary file for the download and an output stream for it.
    * Upon successful return, both mTempFile and mOutStream will be valid.
    */
   nsresult SetUpTempFile(nsIChannel * aChannel);
   /**
    * When we download a helper app, we are going to retarget all load