Bug 589292 - e10s necko: add contentDisposition prop to nsIChannel. r=jduell, sr=biesi, a=beta5+
authorDan Witte <dwitte@mozilla.com>
Wed, 25 Aug 2010 17:51:21 -0700
changeset 51565 f9a4a332f637a90823089877cda98ef16dae5fed
parent 51342 b663f595d29a9ae3f07fa30dd24ed56f3ea1c98d
child 51566 bc673993154227191bda73683b814324429671d2
push id15358
push userdwitte@mozilla.com
push dateFri, 27 Aug 2010 15:04:10 +0000
treeherderautoland@db88acba9e11 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjduell, biesi, beta5
bugs589292
milestone2.0b5pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 589292 - e10s necko: add contentDisposition prop to nsIChannel. r=jduell, sr=biesi, a=beta5+
content/base/src/nsDocument.cpp
content/base/src/nsWebSocket.cpp
content/html/document/src/nsWyciwygChannel.cpp
dom/src/jsurl/nsJSProtocolHandler.cpp
modules/libjar/nsJARChannel.cpp
modules/libjar/nsJARChannel.h
modules/libpr0n/decoders/icon/beos/nsIconChannel.cpp
modules/libpr0n/decoders/icon/mac/nsIconChannelCocoa.mm
modules/libpr0n/decoders/icon/os2/nsIconChannel.cpp
modules/libpr0n/decoders/icon/win/nsIconChannel.cpp
modules/libpr0n/src/imgRequest.cpp
netwerk/base/public/nsChannelProperties.h
netwerk/base/public/nsIChannel.idl
netwerk/base/public/nsIMultiPartChannel.idl
netwerk/base/public/nsNetStrings.h
netwerk/base/public/nsNetUtil.h
netwerk/base/src/nsBaseChannel.cpp
netwerk/base/src/nsBaseChannel.h
netwerk/base/src/nsNetStrings.cpp
netwerk/protocol/http/HttpBaseChannel.cpp
netwerk/protocol/http/HttpBaseChannel.h
netwerk/protocol/viewsource/nsViewSourceChannel.cpp
netwerk/streamconv/converters/nsMultiMixedConv.cpp
netwerk/streamconv/converters/nsMultiMixedConv.h
uriloader/base/nsURILoader.cpp
uriloader/exthandler/ExternalHelperAppParent.cpp
uriloader/exthandler/nsExternalHelperAppService.cpp
uriloader/exthandler/nsExternalProtocolHandler.cpp
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -6689,24 +6689,21 @@ nsDocument::RetrieveRelevantHeaders(nsIC
 
         if (NS_SUCCEEDED(rv)) {
           PRInt64 intermediateValue;
           LL_I2L(intermediateValue, PR_USEC_PER_MSEC);
           LL_MUL(modDate, msecs, intermediateValue);
         }
       }
     } else {
-      nsCOMPtr<nsIMultiPartChannel> partChannel = do_QueryInterface(aChannel);
-      if (partChannel) {
-        nsCAutoString contentDisp;
-        rv = partChannel->GetContentDisposition(contentDisp);
-        if (NS_SUCCEEDED(rv) && !contentDisp.IsEmpty()) {
-          SetHeaderData(nsGkAtoms::headerContentDisposition,
-                        NS_ConvertASCIItoUTF16(contentDisp));
-        }
+      nsCAutoString contentDisp;
+      rv = aChannel->GetContentDisposition(contentDisp);
+      if (NS_SUCCEEDED(rv) && !contentDisp.IsEmpty()) {
+        SetHeaderData(nsGkAtoms::headerContentDisposition,
+                      NS_ConvertASCIItoUTF16(contentDisp));
       }
     }
   }
 
   if (LL_IS_ZERO(modDate)) {
     // We got nothing from our attempt to ask nsIFileChannel and
     // nsIHttpChannel for the last modified time. Return the current
     // time.
--- a/content/base/src/nsWebSocket.cpp
+++ b/content/base/src/nsWebSocket.cpp
@@ -2402,16 +2402,17 @@ NOT_IMPLEMENTED_IF_FUNC_1(GetOwner, nsIS
 NOT_IMPLEMENTED_IF_FUNC_1(SetOwner, nsISupports *owner)
 NOT_IMPLEMENTED_IF_FUNC_1(SetNotificationCallbacks,
                           nsIInterfaceRequestor *callbacks)
 NOT_IMPLEMENTED_IF_FUNC_1(GetSecurityInfo, nsISupports **securityInfo)
 NOT_IMPLEMENTED_IF_FUNC_1(GetContentType, nsACString &value)
 NOT_IMPLEMENTED_IF_FUNC_1(SetContentType, const nsACString &value)
 NOT_IMPLEMENTED_IF_FUNC_1(GetContentCharset, nsACString &value)
 NOT_IMPLEMENTED_IF_FUNC_1(SetContentCharset, const nsACString &value)
+NOT_IMPLEMENTED_IF_FUNC_1(GetContentDisposition, nsACString &value)
 NOT_IMPLEMENTED_IF_FUNC_1(GetContentLength, PRInt64 *value)
 NOT_IMPLEMENTED_IF_FUNC_1(SetContentLength, PRInt64 value)
 NOT_IMPLEMENTED_IF_FUNC_1(Open, nsIInputStream **_retval)
 NOT_IMPLEMENTED_IF_FUNC_2(AsyncOpen, nsIStreamListener *listener,
                           nsISupports *context)
 
 //-----------------------------------------------------------------------------
 // nsWebSocketEstablishedConnection::nsIHttpAuthenticableChannel
--- a/content/html/document/src/nsWyciwygChannel.cpp
+++ b/content/html/document/src/nsWyciwygChannel.cpp
@@ -260,16 +260,23 @@ nsWyciwygChannel::GetContentCharset(nsAC
 
 NS_IMETHODIMP
 nsWyciwygChannel::SetContentCharset(const nsACString &aContentCharset)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
+nsWyciwygChannel::GetContentDisposition(nsACString &aContentDisposition)
+{
+  aContentDisposition.Truncate();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsWyciwygChannel::GetContentLength(PRInt64 *aContentLength)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 nsWyciwygChannel::SetContentLength(PRInt64 aContentLength)
 {
--- a/dom/src/jsurl/nsJSProtocolHandler.cpp
+++ b/dom/src/jsurl/nsJSProtocolHandler.cpp
@@ -1007,16 +1007,22 @@ nsJSChannel::GetContentCharset(nsACStrin
 
 NS_IMETHODIMP
 nsJSChannel::SetContentCharset(const nsACString &aContentCharset)
 {
     return mStreamChannel->SetContentCharset(aContentCharset);
 }
 
 NS_IMETHODIMP
+nsJSChannel::GetContentDisposition(nsACString &aContentDisposition)
+{
+    return mStreamChannel->GetContentDisposition(aContentDisposition);
+}
+
+NS_IMETHODIMP
 nsJSChannel::GetContentLength(PRInt64 *aContentLength)
 {
     return mStreamChannel->GetContentLength(aContentLength);
 }
 
 NS_IMETHODIMP
 nsJSChannel::SetContentLength(PRInt64 aContentLength)
 {
--- a/modules/libjar/nsJARChannel.cpp
+++ b/modules/libjar/nsJARChannel.cpp
@@ -627,16 +627,23 @@ nsJARChannel::GetContentCharset(nsACStri
 NS_IMETHODIMP
 nsJARChannel::SetContentCharset(const nsACString &aContentCharset)
 {
     mContentCharset = aContentCharset;
     return NS_OK;
 }
 
 NS_IMETHODIMP
+nsJARChannel::GetContentDisposition(nsACString &result)
+{
+    result = mContentDisposition;
+    return NS_OK;
+}
+
+NS_IMETHODIMP
 nsJARChannel::GetContentLength(PRInt64 *result)
 {
     // if content length is unknown, query mJarInput...
     if (mContentLength < 0 && mJarInput)
         mContentLength = mJarInput->GetContentLength();
 
     *result = mContentLength;
     return NS_OK;
@@ -766,51 +773,45 @@ nsJARChannel::OnDownloadComplete(nsIDown
             }
             if (NS_SUCCEEDED(status)) {
                 status = rv;
             }
         }
     }
 
     if (NS_SUCCEEDED(status) && channel) {
-        nsCAutoString header;
         // Grab the security info from our base channel
         channel->GetSecurityInfo(getter_AddRefs(mSecurityInfo));
 
         nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
         if (httpChannel) {
             // We only want to run scripts if the server really intended to
             // send us a JAR file.  Check the server-supplied content type for
             // a JAR type.
+            nsCAutoString header;
             httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("Content-Type"),
                                            header);
             nsCAutoString contentType;
             nsCAutoString charset;
             NS_ParseContentType(header, contentType, charset);
             nsCAutoString channelContentType;
             channel->GetContentType(channelContentType);
             mIsUnsafe = !(contentType.Equals(channelContentType) &&
                           (contentType.EqualsLiteral("application/java-archive") ||
                            contentType.EqualsLiteral("application/x-jar")));
-            rv = httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("Content-Disposition"),
-                                                header);
-            if (NS_SUCCEEDED(rv))
-                SetPropertyAsACString(NS_CHANNEL_PROP_CONTENT_DISPOSITION, header);
         } else {
             nsCOMPtr<nsIJARChannel> innerJARChannel(do_QueryInterface(channel));
             if (innerJARChannel) {
                 PRBool unsafe;
                 innerJARChannel->GetIsUnsafe(&unsafe);
                 mIsUnsafe = unsafe;
             }
-            // Soon-to-be common way to get Disposition: right now only nsIJARChannel
-            rv = NS_GetContentDisposition(request, header);
-            if (NS_SUCCEEDED(rv))
-                SetPropertyAsACString(NS_CHANNEL_PROP_CONTENT_DISPOSITION, header);
         }
+
+        channel->GetContentDisposition(mContentDisposition);
     }
 
     if (NS_SUCCEEDED(status) && mIsUnsafe) {
         PRBool allowUnpack = PR_FALSE;
 
         nsCOMPtr<nsIPrefBranch> prefs =
             do_GetService(NS_PREFSERVICE_CONTRACTID);
         if (prefs) {
--- a/modules/libjar/nsJARChannel.h
+++ b/modules/libjar/nsJARChannel.h
@@ -91,16 +91,17 @@ private:
     nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
     nsCOMPtr<nsISupports>           mSecurityInfo;
     nsCOMPtr<nsIProgressEventSink>  mProgressSink;
     nsCOMPtr<nsILoadGroup>          mLoadGroup;
     nsCOMPtr<nsIStreamListener>     mListener;
     nsCOMPtr<nsISupports>           mListenerContext;
     nsCString                       mContentType;
     nsCString                       mContentCharset;
+    nsCString                       mContentDisposition;
     PRInt64                         mContentLength;
     PRUint32                        mLoadFlags;
     nsresult                        mStatus;
     PRPackedBool                    mIsPending;
     PRPackedBool                    mIsUnsafe;
 
     nsJARInputThunk                *mJarInput;
     nsCOMPtr<nsIStreamListener>     mDownloader;
--- a/modules/libpr0n/decoders/icon/beos/nsIconChannel.cpp
+++ b/modules/libpr0n/decoders/icon/beos/nsIconChannel.cpp
@@ -402,16 +402,23 @@ NS_IMETHODIMP nsIconChannel::GetContentC
 NS_IMETHODIMP
 nsIconChannel::SetContentCharset(const nsACString &aContentCharset)
 {
   // It doesn't make sense to set the content-charset on this type
   // of channel...
   return NS_ERROR_FAILURE;
 }
 
+NS_IMETHODIMP
+nsIconChannel::GetContentDisposition(nsACString &aContentDisposition)
+{
+  aContentDisposition.Truncate();
+  return NS_OK;
+}
+
 NS_IMETHODIMP nsIconChannel::GetContentLength(PRInt64 *aContentLength)
 {
   *aContentLength = mContentLength;
   return NS_OK;
 }
 
 NS_IMETHODIMP nsIconChannel::SetContentLength(PRInt64 aContentLength)
 {
--- a/modules/libpr0n/decoders/icon/mac/nsIconChannelCocoa.mm
+++ b/modules/libpr0n/decoders/icon/mac/nsIconChannelCocoa.mm
@@ -394,16 +394,23 @@ NS_IMETHODIMP nsIconChannel::GetContentC
 NS_IMETHODIMP
 nsIconChannel::SetContentCharset(const nsACString &aContentCharset)
 {
   //It doesn't make sense to set the content-type on this type
   // of channel...
   return NS_ERROR_FAILURE;
 }
 
+NS_IMETHODIMP
+nsIconChannel::GetContentDisposition(nsACString &aContentDisposition)
+{
+  aContentDisposition.Truncate();
+  return NS_OK;
+}
+
 NS_IMETHODIMP nsIconChannel::GetContentLength(PRInt64 *aContentLength)
 {
   *aContentLength = mContentLength;
   return NS_OK;
 }
 
 NS_IMETHODIMP nsIconChannel::SetContentLength(PRInt64 aContentLength)
 {
--- a/modules/libpr0n/decoders/icon/os2/nsIconChannel.cpp
+++ b/modules/libpr0n/decoders/icon/os2/nsIconChannel.cpp
@@ -631,16 +631,23 @@ NS_IMETHODIMP nsIconChannel::GetContentC
 NS_IMETHODIMP
 nsIconChannel::SetContentCharset(const nsACString &aContentCharset)
 {
   // It doesn't make sense to set the content-charset on this type
   // of channel...
   return NS_ERROR_FAILURE;
 }
 
+NS_IMETHODIMP
+nsIconChannel::GetContentDisposition(nsACString &aContentDisposition)
+{
+  aContentDisposition.Truncate();
+  return NS_OK;
+}
+
 NS_IMETHODIMP nsIconChannel::GetContentLength(PRInt64 *aContentLength)
 {
   *aContentLength = mContentLength;
   return NS_OK;
 }
 
 NS_IMETHODIMP nsIconChannel::SetContentLength(PRInt64 aContentLength)
 {
--- a/modules/libpr0n/decoders/icon/win/nsIconChannel.cpp
+++ b/modules/libpr0n/decoders/icon/win/nsIconChannel.cpp
@@ -688,16 +688,23 @@ NS_IMETHODIMP nsIconChannel::GetContentC
 NS_IMETHODIMP
 nsIconChannel::SetContentCharset(const nsACString &aContentCharset)
 {
   // It doesn't make sense to set the content-charset on this type
   // of channel...
   return NS_ERROR_FAILURE;
 }
 
+NS_IMETHODIMP
+nsIconChannel::GetContentDisposition(nsACString &aContentDisposition)
+{
+  aContentDisposition.Truncate();
+  return NS_OK;
+}
+
 NS_IMETHODIMP nsIconChannel::GetContentLength(PRInt64 *aContentLength)
 {
   *aContentLength = mContentLength;
   return NS_OK;
 }
 
 NS_IMETHODIMP nsIconChannel::SetContentLength(PRInt64 aContentLength)
 {
--- a/modules/libpr0n/src/imgRequest.cpp
+++ b/modules/libpr0n/src/imgRequest.cpp
@@ -968,21 +968,20 @@ NS_IMETHODIMP imgRequest::OnDataAvailabl
      */
     PRUint32 out;
     inStr->ReadSegments(sniff_mimetype_callback, this, count, &out);
 
 #ifdef NS_DEBUG
     /* NS_WARNING if the content type from the channel isn't the same if the sniffing */
 #endif
 
+    nsCOMPtr<nsIChannel> chan(do_QueryInterface(aRequest));
     if (mContentType.IsEmpty()) {
       LOG_SCOPE(gImgLog, "imgRequest::OnDataAvailable |sniffing of mimetype failed|");
 
-      nsCOMPtr<nsIChannel> chan(do_QueryInterface(aRequest));
-
       rv = NS_ERROR_FAILURE;
       if (chan) {
         rv = chan->GetContentType(mContentType);
       }
 
       if (NS_FAILED(rv)) {
         PR_LOG(gImgLog, PR_LOG_ERROR,
                ("[this=%p] imgRequest::OnDataAvailable -- Content type unavailable from the channel\n",
@@ -1012,24 +1011,18 @@ NS_IMETHODIMP imgRequest::OnDataAvailabl
     nsCOMPtr<nsISupportsCString> contentType(do_CreateInstance("@mozilla.org/supports-cstring;1"));
     if (contentType) {
       contentType->SetData(mContentType);
       mProperties->Set("type", contentType);
     }
 
     /* set our content disposition as a property */
     nsCAutoString disposition;
-    nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aRequest));
-    if (httpChannel) {
-      httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("content-disposition"), disposition);
-    } else {
-      nsCOMPtr<nsIMultiPartChannel> multiPartChannel(do_QueryInterface(aRequest));
-      if (multiPartChannel) {
-        multiPartChannel->GetContentDisposition(disposition);
-      }
+    if (chan) {
+      chan->GetContentDisposition(disposition);
     }
     if (!disposition.IsEmpty()) {
       nsCOMPtr<nsISupportsCString> contentDisposition(do_CreateInstance("@mozilla.org/supports-cstring;1"));
       if (contentDisposition) {
         contentDisposition->SetData(disposition);
         mProperties->Set("content-disposition", contentDisposition);
       }
     }
@@ -1079,16 +1072,17 @@ NS_IMETHODIMP imgRequest::OnDataAvailabl
     if (NS_FAILED(rv)) { // Probably bad mimetype
 
       this->Cancel(rv);
       return NS_BINDING_ABORTED;
     }
 
     if (imageType == imgIContainer::TYPE_RASTER) {
       /* Use content-length as a size hint for http channels. */
+      nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aRequest));
       if (httpChannel) {
         PRInt64 contentLength;
         rv = httpChannel->GetContentLength(&contentLength);
         if (NS_SUCCEEDED(rv)) {
           // Pass anything usable on so that the RasterImage can preallocate
           // its source buffer
           if (contentLength > 0) {
             PRUint32 sizeHint = (PRUint32) contentLength;
--- a/netwerk/base/public/nsChannelProperties.h
+++ b/netwerk/base/public/nsChannelProperties.h
@@ -46,32 +46,22 @@
  * @file
  * This file contains constants for properties channels can expose.
  * They can be accessed by using QueryInterface to access the nsIPropertyBag
  * or nsIPropertyBag2 interface on a channel and reading the value.
  */
 
 
 /**
- * MIME Content-Disposition header of channel.  
- * Not available before onStartRequest. 
- * Type: nsACString
- */
-#define NS_CHANNEL_PROP_CONTENT_DISPOSITION_STR "content-disposition"
-
-/**
  * Exists to allow content policy mechanism to function properly during channel
  * redirects.  Contains security contextual information about the load.
  * Type: nsIChannelPolicy
  */
 #define NS_CHANNEL_PROP_CHANNEL_POLICY_STR "channel-policy"
 
 #ifdef IMPL_NS_NET
-#define NS_CHANNEL_PROP_CONTENT_DISPOSITION gNetStrings->kContentDisposition
 #define NS_CHANNEL_PROP_CHANNEL_POLICY gNetStrings->kChannelPolicy
 #else
-#define NS_CHANNEL_PROP_CONTENT_DISPOSITION \
-  NS_LITERAL_STRING(NS_CHANNEL_PROP_CONTENT_DISPOSITION_STR)
 #define NS_CHANNEL_PROP_CHANNEL_POLICY \
   NS_LITERAL_STRING(NS_CHANNEL_PROP_CHANNEL_POLICY_STR)
 #endif
 
 #endif
--- a/netwerk/base/public/nsIChannel.idl
+++ b/netwerk/base/public/nsIChannel.idl
@@ -51,17 +51,17 @@ interface nsIStreamListener;
  * by calling nsIChannel::open or nsIChannel::asyncOpen.
  *
  * After a request has been completed, the channel is still valid for accessing
  * protocol-specific results.  For example, QI'ing to nsIHttpChannel allows
  * response headers to be retrieved for the corresponding http transaction.
  *
  * This interface must be used only from the XPCOM main thread.
  */
-[scriptable, uuid(e0bb5c49-c54e-4efb-8f0d-6a7edd926fab)]
+[scriptable, uuid(3906f857-3d79-4716-be55-ed2455d666f4)]
 interface nsIChannel : nsIRequest
 {
     /**
      * The original URI used to construct the channel. This is used in
      * the case of a redirect or URI "resolution" (e.g. resolving a
      * resource: URI to a file: URI) so that the original pre-redirect
      * URI can still be obtained.  This is never null.  Attempts to
      * set it to null must throw.
@@ -153,16 +153,23 @@ interface nsIChannel : nsIRequest
      * The length of the data associated with the channel if available.  A value
      * of -1 indicates that the content length is unknown. Note that this
      * is a 64-bit value and obsoletes the "content-length" property used on
      * some channels.
      */
     attribute PRInt64 contentLength;
 
     /**
+     * Access to the Content-Disposition header if available and if applicable.
+     * This allows getting the preferred handling method, preferred filename,
+     * etc.  See RFC 2183.
+     */
+    readonly attribute ACString contentDisposition;
+
+    /**
      * Synchronously open the channel.
      *
      * @return blocking input stream to the channel's data.
      *
      * NOTE: nsIChannel implementations are not required to implement this
      * method.  Moreover, since this method may block the calling thread, it
      * should not be called on a thread that processes UI events.  Like any
      * other nsIChannel method it must not be called on any thread other
--- a/netwerk/base/public/nsIMultiPartChannel.idl
+++ b/netwerk/base/public/nsIMultiPartChannel.idl
@@ -40,32 +40,25 @@
 
 interface nsIChannel;
 
 /**
  * An interface to access the the base channel 
  * associated with a MultiPartChannel.
  */
 
-[scriptable, uuid(ba78db7b-b88c-4b76-baf9-3c2296a585ae)]
+[scriptable, uuid(51698f28-c975-4bce-a951-25130cda0113)]
 interface nsIMultiPartChannel : nsISupports
 {
     /**
      * readonly attribute to access the underlying channel
      */
     readonly attribute nsIChannel baseChannel;
 
     /**
-     * Access to the Content-Disposition header field of this part of
-     * a multipart message.  This allows getting the preferred
-     * handling method, preferred filename, etc.  See RFC 2183.
-     */
-    attribute ACString contentDisposition;
-
-    /**
      * Attribute guaranteed to be different for different parts of
      * the same multipart document.
      */
     readonly attribute PRUint32 partID;
 
     /**
      * Set to true when onStopRequest is received from the base channel.
      * The listener can check this from its onStopRequest to determine
--- a/netwerk/base/public/nsNetStrings.h
+++ b/netwerk/base/public/nsNetStrings.h
@@ -42,16 +42,15 @@
 /**
  * Class on which wide strings are available, to avoid constructing strings
  * wherever these strings are used.
  */
 class nsNetStrings {
 public:
   nsNetStrings();
 
-  const nsLiteralString kContentDisposition;
   const nsLiteralString kChannelPolicy;
 };
 
 extern NS_HIDDEN_(nsNetStrings*) gNetStrings;
 
 
 #endif
--- a/netwerk/base/public/nsNetUtil.h
+++ b/netwerk/base/public/nsNetUtil.h
@@ -233,29 +233,16 @@ NS_NewChannel(nsIChannel           **res
             }
             if (NS_SUCCEEDED(rv))
                 chan.forget(result);
         }
     }
     return rv;
 }
 
-// For now, works only with JARChannel.  Future: with all channels that may
-// have Content-Disposition header (JAR, nsIHttpChannel, and nsIMultiPartChannel).
-inline nsresult
-NS_GetContentDisposition(nsIRequest     *channel,
-                         nsACString     &result)
-{
-    nsCOMPtr<nsIPropertyBag2> props(do_QueryInterface(channel));
-    if (props)
-        return props->GetPropertyAsACString(NS_CHANNEL_PROP_CONTENT_DISPOSITION,
-                                            result);
-    return NS_ERROR_NOT_AVAILABLE;
-}
-
 // Use this function with CAUTION. It creates a stream that blocks when you
 // Read() from it and blocking the UI thread is a bad idea. If you don't want
 // to implement a full blown asynchronous consumer (via nsIStreamListener) look
 // at nsIStreamLoader instead.
 inline nsresult
 NS_OpenURI(nsIInputStream       **result,
            nsIURI                *uri,
            nsIIOService          *ioService = nsnull,     // pass in nsIIOService to optimize callers
--- a/netwerk/base/src/nsBaseChannel.cpp
+++ b/netwerk/base/src/nsBaseChannel.cpp
@@ -499,16 +499,23 @@ nsBaseChannel::GetContentCharset(nsACStr
 NS_IMETHODIMP
 nsBaseChannel::SetContentCharset(const nsACString &aContentCharset)
 {
   mContentCharset = aContentCharset;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsBaseChannel::GetContentDisposition(nsACString &aContentDisposition)
+{
+  aContentDisposition = mContentDisposition;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsBaseChannel::GetContentLength(PRInt64 *aContentLength)
 {
   *aContentLength = mContentLength;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsBaseChannel::SetContentLength(PRInt64 aContentLength)
--- a/netwerk/base/src/nsBaseChannel.h
+++ b/netwerk/base/src/nsBaseChannel.h
@@ -285,16 +285,17 @@ private:
   nsCOMPtr<nsILoadGroup>              mLoadGroup;
   nsCOMPtr<nsISupports>               mOwner;
   nsCOMPtr<nsISupports>               mSecurityInfo;
   nsCOMPtr<nsIStreamListener>         mListener;
   nsCOMPtr<nsISupports>               mListenerContext;
   nsCOMPtr<nsIChannel>                mRedirectChannel;
   nsCString                           mContentType;
   nsCString                           mContentCharset;
+  nsCString                           mContentDisposition;
   PRInt64                             mContentLength;
   PRUint32                            mLoadFlags;
   nsresult                            mStatus;
   PRPackedBool                        mQueriedProgressSink;
   PRPackedBool                        mSynthProgressEvents;
   PRPackedBool                        mWasOpened;
   PRPackedBool                        mWaitingOnAsyncRedirect;
   PRPackedBool                        mOpenRedirectChannel;
--- a/netwerk/base/src/nsNetStrings.cpp
+++ b/netwerk/base/src/nsNetStrings.cpp
@@ -35,13 +35,12 @@
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsNetStrings.h"
 #include "nsChannelProperties.h"
 
 NS_HIDDEN_(nsNetStrings*) gNetStrings;
 
 nsNetStrings::nsNetStrings()
-  : NS_LITERAL_STRING_INIT(kContentDisposition, NS_CHANNEL_PROP_CONTENT_DISPOSITION_STR),
-    NS_LITERAL_STRING_INIT(kChannelPolicy, NS_CHANNEL_PROP_CHANNEL_POLICY_STR)
+  : NS_LITERAL_STRING_INIT(kChannelPolicy, NS_CHANNEL_PROP_CHANNEL_POLICY_STR)
 {}
 
 
--- a/netwerk/protocol/http/HttpBaseChannel.cpp
+++ b/netwerk/protocol/http/HttpBaseChannel.cpp
@@ -354,16 +354,28 @@ HttpBaseChannel::SetContentCharset(const
   } else {
     // Charset hint
     mContentCharsetHint = aContentCharset;
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
+HttpBaseChannel::GetContentDisposition(nsACString& aContentDisposition)
+{
+  aContentDisposition.Truncate();
+
+  if (!mResponseHead)
+    return NS_ERROR_NOT_AVAILABLE;
+
+  mResponseHead->GetHeader(nsHttp::Content_Disposition, aContentDisposition);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 HttpBaseChannel::GetContentLength(PRInt64 *aContentLength)
 {
   if (!mResponseHead)
     return NS_ERROR_NOT_AVAILABLE;
 
   *aContentLength = mResponseHead->ContentLength();
   return NS_OK;
 }
--- a/netwerk/protocol/http/HttpBaseChannel.h
+++ b/netwerk/protocol/http/HttpBaseChannel.h
@@ -124,16 +124,17 @@ public:
   NS_IMETHOD GetOwner(nsISupports **aOwner);
   NS_IMETHOD SetOwner(nsISupports *aOwner);
   NS_IMETHOD GetNotificationCallbacks(nsIInterfaceRequestor **aCallbacks);
   NS_IMETHOD SetNotificationCallbacks(nsIInterfaceRequestor *aCallbacks);
   NS_IMETHOD GetContentType(nsACString& aContentType);
   NS_IMETHOD SetContentType(const nsACString& aContentType);
   NS_IMETHOD GetContentCharset(nsACString& aContentCharset);
   NS_IMETHOD SetContentCharset(const nsACString& aContentCharset);
+  NS_IMETHOD GetContentDisposition(nsACString& aContentDisposition);
   NS_IMETHOD GetContentLength(PRInt64 *aContentLength);
   NS_IMETHOD SetContentLength(PRInt64 aContentLength);
   NS_IMETHOD Open(nsIInputStream **aResult);
 
   // HttpBaseChannel::nsIHttpChannel
   NS_IMETHOD GetRequestMethod(nsACString& aMethod);
   NS_IMETHOD SetRequestMethod(const nsACString& aMethod);
   NS_IMETHOD GetReferrer(nsIURI **referrer);
--- a/netwerk/protocol/viewsource/nsViewSourceChannel.cpp
+++ b/netwerk/protocol/viewsource/nsViewSourceChannel.cpp
@@ -365,16 +365,24 @@ NS_IMETHODIMP
 nsViewSourceChannel::SetContentCharset(const nsACString &aContentCharset)
 {
     NS_ENSURE_TRUE(mChannel, NS_ERROR_FAILURE);
 
     return mChannel->SetContentCharset(aContentCharset);
 }
 
 NS_IMETHODIMP
+nsViewSourceChannel::GetContentDisposition(nsACString &aContentDisposition)
+{
+    NS_ENSURE_TRUE(mChannel, NS_ERROR_FAILURE);
+
+    return mChannel->GetContentDisposition(aContentDisposition);
+}
+
+NS_IMETHODIMP
 nsViewSourceChannel::GetContentLength(PRInt64 *aContentLength)
 {
     NS_ENSURE_TRUE(mChannel, NS_ERROR_FAILURE);
 
     return mChannel->GetContentLength(aContentLength);
 }
 
 NS_IMETHODIMP
--- a/netwerk/streamconv/converters/nsMultiMixedConv.cpp
+++ b/netwerk/streamconv/converters/nsMultiMixedConv.cpp
@@ -340,23 +340,16 @@ nsPartChannel::SetContentLength(PRInt64 
 NS_IMETHODIMP
 nsPartChannel::GetContentDisposition(nsACString &aContentDisposition)
 {
     aContentDisposition = mContentDisposition;
     return NS_OK;
 }
 
 NS_IMETHODIMP
-nsPartChannel::SetContentDisposition(const nsACString &aContentDisposition)
-{
-    mContentDisposition = aContentDisposition;
-    return NS_OK;
-}
-
-NS_IMETHODIMP
 nsPartChannel::GetPartID(PRUint32 *aPartID)
 {
     *aPartID = mPartID;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsPartChannel::GetIsLastPart(PRBool *aIsLastPart)
@@ -795,18 +788,17 @@ nsMultiMixedConv::SendStart(nsIChannel *
     mPartChannel = newChannel;
 
     rv = mPartChannel->SetContentType(mContentType);
     if (NS_FAILED(rv)) return rv;
 
     rv = mPartChannel->SetContentLength(mContentLength);
     if (NS_FAILED(rv)) return rv;
 
-    rv = mPartChannel->SetContentDisposition(mContentDisposition);
-    if (NS_FAILED(rv)) return rv;
+    mPartChannel->SetContentDisposition(mContentDisposition);
 
     nsLoadFlags loadFlags = 0;
     mPartChannel->GetLoadFlags(&loadFlags);
     loadFlags |= nsIChannel::LOAD_REPLACE;
     mPartChannel->SetLoadFlags(loadFlags);
 
     nsCOMPtr<nsILoadGroup> loadGroup;
     (void)mPartChannel->GetLoadGroup(getter_AddRefs(loadGroup));
--- a/netwerk/streamconv/converters/nsMultiMixedConv.h
+++ b/netwerk/streamconv/converters/nsMultiMixedConv.h
@@ -72,16 +72,21 @@ public:
 
   void InitializeByteRange(PRInt64 aStart, PRInt64 aEnd);
   void SetIsLastPart() { mIsLastPart = PR_TRUE; }
   nsresult SendOnStartRequest(nsISupports* aContext);
   nsresult SendOnDataAvailable(nsISupports* aContext, nsIInputStream* aStream,
                                PRUint32 aOffset, PRUint32 aLen);
   nsresult SendOnStopRequest(nsISupports* aContext, nsresult aStatus);
 
+  void SetContentDisposition(const nsACString& aDisposition)
+  {
+    mContentDisposition = aDisposition;
+  }
+
   NS_DECL_ISUPPORTS
   NS_DECL_NSIREQUEST
   NS_DECL_NSICHANNEL
   NS_DECL_NSIBYTERANGEREQUEST
   NS_DECL_NSIMULTIPARTCHANNEL
 
 protected:
   ~nsPartChannel();
--- a/uriloader/base/nsURILoader.cpp
+++ b/uriloader/base/nsURILoader.cpp
@@ -381,45 +381,31 @@ nsresult nsDocumentOpenInfo::DispatchCon
     aChannel->SetContentType(NS_LITERAL_CSTRING(APPLICATION_OCTET_STREAM));
   }
 
   // Check whether the data should be forced to be handled externally.  This
   // could happen because the Content-Disposition header is set so, or, in the
   // future, because the user has specified external handling for the MIME
   // type.
   PRBool forceExternalHandling = PR_FALSE;
+  nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(request));
   nsCAutoString disposition;
-  nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(request));
-  nsCOMPtr<nsIURI> uri;
-  if (httpChannel)
-  {
-    rv = httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("content-disposition"),
-                                        disposition);
-    httpChannel->GetURI(getter_AddRefs(uri));
-  }
-  else
-  {
-    nsCOMPtr<nsIMultiPartChannel> multipartChannel(do_QueryInterface(request));
-    if (multipartChannel)
-    {
-      rv = multipartChannel->GetContentDisposition(disposition);
-    } else {
-      // Soon-to-be common way to get Disposition: right now only JARChannel
-      rv = NS_GetContentDisposition(request, disposition);
-    }
-  }
+  rv = aChannel->GetContentDisposition(disposition);
 
   LOG(("  Disposition header: '%s'", disposition.get()));
 
   if (NS_SUCCEEDED(rv) && !disposition.IsEmpty())
   {
     nsCOMPtr<nsIMIMEHeaderParam> mimehdrpar = do_GetService(NS_MIMEHEADERPARAM_CONTRACTID, &rv);
     if (NS_SUCCEEDED(rv))
     {
       nsCAutoString fallbackCharset;
+      nsCOMPtr<nsIURI> uri;
+      if (httpChannel)
+        httpChannel->GetURI(getter_AddRefs(uri));
       if (uri)
         uri->GetOriginCharset(fallbackCharset);
       nsAutoString dispToken;
       // Get the disposition type
       rv = mimehdrpar->GetParameter(disposition, "", fallbackCharset,
                                     PR_TRUE, nsnull, dispToken);
       // RFC 2183, section 2.8 says that an unknown disposition
       // value should be treated as "attachment"
--- a/uriloader/exthandler/ExternalHelperAppParent.cpp
+++ b/uriloader/exthandler/ExternalHelperAppParent.cpp
@@ -291,16 +291,23 @@ ExternalHelperAppParent::GetContentChars
 
 NS_IMETHODIMP
 ExternalHelperAppParent::SetContentCharset(const nsACString& aContentCharset)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
+ExternalHelperAppParent::GetContentDisposition(nsACString& aContentDisposition)
+{
+  aContentDisposition.Truncate();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 ExternalHelperAppParent::GetContentLength(PRInt64 *aContentLength)
 {
   *aContentLength = mContentLength;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 ExternalHelperAppParent::SetContentLength(PRInt64 aContentLength)
--- a/uriloader/exthandler/nsExternalHelperAppService.cpp
+++ b/uriloader/exthandler/nsExternalHelperAppService.cpp
@@ -217,41 +217,16 @@ static nsresult UnescapeFragment(const n
 {
   nsAutoString result;
   nsresult rv = UnescapeFragment(aFragment, aURI, result);
   if (NS_SUCCEEDED(rv))
     CopyUTF16toUTF8(result, aResult);
   return rv;
 }
 
-/** Gets the content-disposition header from a channel, using nsIHttpChannel
- * or nsIMultipartChannel if available
- * @param aChannel The channel to extract the disposition header from
- * @param aDisposition Reference to a string where the header is to be stored
- */
-static void ExtractDisposition(nsIChannel* aChannel, nsACString& aDisposition)
-{
-  aDisposition.Truncate();
-  // First see whether this is an http channel
-  nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
-  if (httpChannel) 
-  {
-    httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("content-disposition"), aDisposition);
-  }
-  if (aDisposition.IsEmpty())
-  {
-    nsCOMPtr<nsIMultiPartChannel> multipartChannel(do_QueryInterface(aChannel));
-    if (multipartChannel)
-    {
-      multipartChannel->GetContentDisposition(aDisposition);
-    }
-  }
-
-}
-
 /** Extracts the filename out of a content-disposition header
  * @param aFilename [out] The filename. Can be empty on error.
  * @param aDisposition Value of a Content-Disposition header
  * @param aURI Optional. Will be used to get a fallback charset for the
  *        filename, if it is QI'able to nsIURL
  * @param aMIMEHeaderParam Optional. Pointer to a nsIMIMEHeaderParam class, so
  *        that it doesn't need to be fetched by this function.
  */
@@ -309,17 +284,17 @@ static PRBool GetFilenameAndExtensionFro
   /*
    * If the channel is an http or part of a multipart channel and we
    * have a content disposition header set, then use the file name
    * suggested there as the preferred file name to SUGGEST to the
    * user.  we shouldn't actually use that without their
    * permission... otherwise just use our temp file
    */
   nsCAutoString disp;
-  ExtractDisposition(aChannel, disp);
+  aChannel->GetContentDisposition(disp);
   PRBool handleExternally = PR_FALSE;
   nsCOMPtr<nsIURI> uri;
   nsresult rv;
   aChannel->GetURI(getter_AddRefs(uri));
   // content-disposition: has format:
   // disposition-type < ; name=value >* < ; filename=value > < ; name=value >*
   if (!disp.IsEmpty()) 
   {
--- a/uriloader/exthandler/nsExternalProtocolHandler.cpp
+++ b/uriloader/exthandler/nsExternalProtocolHandler.cpp
@@ -242,16 +242,22 @@ NS_IMETHODIMP nsExtProtocolChannel::GetC
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP nsExtProtocolChannel::SetContentCharset(const nsACString &aContentCharset)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
+NS_IMETHODIMP nsExtProtocolChannel::GetContentDisposition(nsACString &aContentDisposition)
+{
+  aContentDisposition.Truncate();
+  return NS_OK;
+}
+
 NS_IMETHODIMP nsExtProtocolChannel::GetContentLength(PRInt64 * aContentLength)
 {
   *aContentLength = -1;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsExtProtocolChannel::SetContentLength(PRInt64 aContentLength)