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 id12888
push userbturner@mozilla.com
push dateTue, 20 Apr 2010 16:45:38 +0000
treeherdermozilla-central@10d5c11a5b9a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewershonza
bugs545869
milestone1.9.3a5pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
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