Bug 1198669 - Add nsIMultiPartChannel.originalResponseHeader support. r=valentin
authorHenry Chang <hchang@mozilla.com>
Tue, 08 Sep 2015 10:53:27 +0800
changeset 293886 ee49a5d7058cfe381655fafa39f290e0f6a07cd5
parent 293885 772e70e430885a69dca581ac647f7c1b6d0f54cc
child 293887 74e6798a38a4de824660363017f3d83f9c91401a
push id5245
push userraliiev@mozilla.com
push dateThu, 29 Oct 2015 11:30:51 +0000
treeherdermozilla-beta@dac831dc1bd0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersvalentin
bugs1198669
milestone43.0a1
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 1198669 - Add nsIMultiPartChannel.originalResponseHeader support. r=valentin
netwerk/base/nsIMultiPartChannel.idl
netwerk/streamconv/converters/nsMultiMixedConv.cpp
netwerk/streamconv/converters/nsMultiMixedConv.h
netwerk/test/unit/test_multipart_streamconv_application_package.js
uriloader/exthandler/ExternalHelperAppParent.cpp
--- a/netwerk/base/nsIMultiPartChannel.idl
+++ b/netwerk/base/nsIMultiPartChannel.idl
@@ -7,17 +7,17 @@
 
 interface nsIChannel;
 
 /**
  * An interface to access the the base channel 
  * associated with a MultiPartChannel.
  */
 
-[scriptable, uuid(3c329c90-2ee0-11e5-a2cb-0800200c9a66)]
+[scriptable, uuid(4fefb490-5567-11e5-a837-0800200c9a66)]
 interface nsIMultiPartChannel : nsISupports
 {
     /**
      * readonly attribute to access the underlying channel
      */
     readonly attribute nsIChannel baseChannel;
 
     /**
@@ -33,9 +33,14 @@ interface nsIMultiPartChannel : nsISuppo
      */
     readonly attribute boolean isLastPart;
 
     /**
      * ASCII-encoding content prior to the first resource. Only valid for
      * content-type=application/package.
      */
     readonly attribute ACString preamble;
+
+    /**
+     * The original http response header in each part.
+     */
+    readonly attribute ACString originalResponseHeader;
 };
--- a/netwerk/streamconv/converters/nsMultiMixedConv.cpp
+++ b/netwerk/streamconv/converters/nsMultiMixedConv.cpp
@@ -467,16 +467,29 @@ nsPartChannel::GetPreamble(nsACString & 
 }
 
 void
 nsPartChannel::SetPreamble(const nsACString& aPreamble)
 {
     mPreamble = aPreamble;
 }
 
+NS_IMETHODIMP
+nsPartChannel::GetOriginalResponseHeader(nsACString & aOriginalResponseHeader)
+{
+    aOriginalResponseHeader = mOriginalResponseHeader;
+    return NS_OK;
+}
+
+void
+nsPartChannel::SetOriginalResponseHeader(const nsACString& aOriginalResponseHeader)
+{
+    mOriginalResponseHeader = aOriginalResponseHeader;
+}
+
 // nsISupports implementation
 NS_IMPL_ISUPPORTS(nsMultiMixedConv,
                   nsIStreamConverter,
                   nsIStreamListener,
                   nsIRequestObserver)
 
 
 // nsIStreamConverter implementation
@@ -691,19 +704,25 @@ nsMultiMixedConv::OnDataAvailable(nsIReq
     // This may get initialized by ParseHeaders and the resulting
     // HttpResponseHead will be passed to nsPartChannel by SendStart
 
     if (mProcessingHeaders) {
         // we were not able to process all the headers
         // for this "part" given the previous buffer given to 
         // us in the previous OnDataAvailable callback.
         bool done = false;
+        const char* originalCursor = cursor;
         rv = ParseHeaders(channel, cursor, bufLen, &done);
         if (NS_FAILED(rv)) return rv;
 
+        // Append the content to the original header.
+        if (cursor > originalCursor) {
+            mOriginalResponseHeader.Append(originalCursor, cursor - originalCursor);
+        }
+
         if (done) {
             mProcessingHeaders = false;
             rv = SendStart(channel);
             if (NS_FAILED(rv)) return rv;
         }
     }
 
     int32_t tokenLinefeed = 1;
@@ -731,19 +750,26 @@ nsMultiMixedConv::OnDataAvailable(nsIReq
         token += mTokenLen;
         bufLen -= mTokenLen;
         tokenLinefeed = PushOverLine(token, bufLen);
 
         if (mNewPart) {
             // parse headers
             mNewPart = false;
             cursor = token;
-            bool done = false; 
+            bool done = false;
+            const char* originalCursor = cursor;
             rv = ParseHeaders(channel, cursor, bufLen, &done);
             if (NS_FAILED(rv)) return rv;
+
+            // Append the content to the original header.
+            if (cursor > originalCursor) {
+                mOriginalResponseHeader.Append(originalCursor, cursor - originalCursor);
+            }
+
             if (done) {
                 rv = SendStart(channel);
                 if (NS_FAILED(rv)) return rv;
             }
             else {
                 // we haven't finished processing header info.
                 // we'll break out and try to process later.
                 mProcessingHeaders = true;
@@ -1030,16 +1056,20 @@ nsMultiMixedConv::SendStart(nsIChannel *
     mTotalSent = 0;
 
     // Set up the new part channel...
     mPartChannel = newChannel;
 
     // Pass preamble to the channel.
     mPartChannel->SetPreamble(mPreamble);
 
+    // Pass original http header.
+    mPartChannel->SetOriginalResponseHeader(mOriginalResponseHeader);
+    mOriginalResponseHeader = EmptyCString();
+
     // We pass the headers to the nsPartChannel
     mPartChannel->SetResponseHead(mResponseHead.forget());
 
     rv = mPartChannel->SetContentType(mContentType);
     if (NS_FAILED(rv)) return rv;
 
     rv = mPartChannel->SetContentLength(mContentLength);
     if (NS_FAILED(rv)) return rv;
--- a/netwerk/streamconv/converters/nsMultiMixedConv.h
+++ b/netwerk/streamconv/converters/nsMultiMixedConv.h
@@ -39,16 +39,17 @@ class nsPartChannel final : public nsICh
 {
 public:
   nsPartChannel(nsIChannel *aMultipartChannel, uint32_t aPartID,
                 nsIStreamListener* aListener);
 
   void InitializeByteRange(int64_t aStart, int64_t aEnd);
   void SetIsLastPart() { mIsLastPart = true; }
   void SetPreamble(const nsACString& aPreamble);
+  void SetOriginalResponseHeader(const nsACString& aOriginalResponseHeader);
   nsresult SendOnStartRequest(nsISupports* aContext);
   nsresult SendOnDataAvailable(nsISupports* aContext, nsIInputStream* aStream,
                                uint64_t aOffset, uint32_t aLen);
   nsresult SendOnStopRequest(nsISupports* aContext, nsresult aStatus);
   /* SetContentDisposition expects the full value of the Content-Disposition
    * header */
   void SetContentDisposition(const nsACString& aContentDispositionHeader);
   void SetResponseHead(mozilla::net::nsHttpResponseHead * head) { mResponseHead = head; }
@@ -84,16 +85,19 @@ protected:
   int64_t                 mByteRangeStart;
   int64_t                 mByteRangeEnd;
 
   uint32_t                mPartID; // unique ID that can be used to identify
                                    // this part of the multipart document
   bool                    mIsLastPart;
 
   nsCString               mPreamble;
+
+  // The original http response header.
+  nsCString               mOriginalResponseHeader;
 };
 
 // The nsMultiMixedConv stream converter converts a stream of type "multipart/x-mixed-replace"
 // to it's subparts. There was some debate as to whether or not the functionality desired
 // when HTTP confronted this type required a stream converter. After all, this type really
 // prompts various viewer related actions rather than stream conversion. There simply needs
 // to be a piece in place that can strip out the multiple parts of a stream of this type, and 
 // "display" them accordingly.
@@ -191,11 +195,14 @@ protected:
     // for packaged apps, in the case that only metadata is saved in the cache
     // entry and OnDataAvailable never gets called.
     bool                mIsFromCache;
 
     // Preamble is defined as the ASCII-encoding string which appears before the
     // first boundary. It's only supported by 'application/package' content type
     // and requires the boundary is defined in the HTTP header.
     nsCString           mPreamble;
+
+    // The original http response header of each subresource.
+    nsCString           mOriginalResponseHeader;
 };
 
 #endif /* __nsmultimixedconv__h__ */
--- a/netwerk/test/unit/test_multipart_streamconv_application_package.js
+++ b/netwerk/test/unit/test_multipart_streamconv_application_package.js
@@ -144,16 +144,23 @@ multipartListener.prototype.onStartReque
   }
 
   this._buffer = "";
   this.headerListener = new headerListener(this.test.content[this.testNum].headers, this.badContentType);
   let headerProvider = request.QueryInterface(Ci.nsIResponseHeadProvider);
   if (headerProvider) {
     headerProvider.visitResponseHeaders(this.headerListener);
   }
+
+  // Verify the original header if the request is a multipart channel.
+  let partChannel = request.QueryInterface(Ci.nsIMultiPartChannel);
+  if (partChannel) {
+    let originalHeader = this.test.content[this.testNum].headers.join("\r\n") + "\r\n\r\n";
+    equal(originalHeader, partChannel.originalResponseHeader, "Oringinal header check.");
+  }
 }
 
 multipartListener.prototype.onDataAvailable = function(request, context, stream, offset, count) {
   try {
     this._buffer = this._buffer.concat(read_stream(stream, count));
   } catch (ex) {
     do_throw("Error in onDataAvailable: " + ex);
   }
--- a/uriloader/exthandler/ExternalHelperAppParent.cpp
+++ b/uriloader/exthandler/ExternalHelperAppParent.cpp
@@ -494,10 +494,16 @@ ExternalHelperAppParent::GetIsLastPart(b
 }
 
 NS_IMETHODIMP
 ExternalHelperAppParent::GetPreamble(nsACString & aPreamble)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
+NS_IMETHODIMP
+ExternalHelperAppParent::GetOriginalResponseHeader(nsACString & aOriginalResponseHeader)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
 } // namespace dom
 } // namespace mozilla