netwerk/base/src/nsMIMEInputStream.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 /**
     7  * The MIME stream separates headers and a datastream. It also allows
     8  * automatic creation of the content-length header.
     9  */
    11 #include "ipc/IPCMessageUtils.h"
    13 #include "nsCOMPtr.h"
    14 #include "nsComponentManagerUtils.h"
    15 #include "nsIMultiplexInputStream.h"
    16 #include "nsIMIMEInputStream.h"
    17 #include "nsISeekableStream.h"
    18 #include "nsIStringStream.h"
    19 #include "nsString.h"
    20 #include "nsMIMEInputStream.h"
    21 #include "nsIClassInfoImpl.h"
    22 #include "nsIIPCSerializableInputStream.h"
    23 #include "mozilla/ipc/InputStreamUtils.h"
    25 using namespace mozilla::ipc;
    27 class nsMIMEInputStream : public nsIMIMEInputStream,
    28                           public nsISeekableStream,
    29                           public nsIIPCSerializableInputStream
    30 {
    31 public:
    32     nsMIMEInputStream();
    33     virtual ~nsMIMEInputStream();
    35     NS_DECL_THREADSAFE_ISUPPORTS
    36     NS_DECL_NSIINPUTSTREAM
    37     NS_DECL_NSIMIMEINPUTSTREAM
    38     NS_DECL_NSISEEKABLESTREAM
    39     NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM
    41     NS_METHOD Init();
    43 private:
    45     void InitStreams();
    47     struct ReadSegmentsState {
    48         nsIInputStream* mThisStream;
    49         nsWriteSegmentFun mWriter;
    50         void* mClosure;
    51     };
    52     static NS_METHOD ReadSegCb(nsIInputStream* aIn, void* aClosure,
    53                                const char* aFromRawSegment, uint32_t aToOffset,
    54                                uint32_t aCount, uint32_t *aWriteCount);
    56     nsCString mHeaders;
    57     nsCOMPtr<nsIStringInputStream> mHeaderStream;
    59     nsCString mContentLength;
    60     nsCOMPtr<nsIStringInputStream> mCLStream;
    62     nsCOMPtr<nsIInputStream> mData;
    63     nsCOMPtr<nsIMultiplexInputStream> mStream;
    64     bool mAddContentLength;
    65     bool mStartedReading;
    66 };
    68 NS_IMPL_ADDREF(nsMIMEInputStream)
    69 NS_IMPL_RELEASE(nsMIMEInputStream)
    71 NS_IMPL_CLASSINFO(nsMIMEInputStream, nullptr, nsIClassInfo::THREADSAFE,
    72                   NS_MIMEINPUTSTREAM_CID)
    74 NS_IMPL_QUERY_INTERFACE_CI(nsMIMEInputStream,
    75                            nsIMIMEInputStream,
    76                            nsIInputStream,
    77                            nsISeekableStream,
    78                            nsIIPCSerializableInputStream)
    79 NS_IMPL_CI_INTERFACE_GETTER(nsMIMEInputStream,
    80                             nsIMIMEInputStream,
    81                             nsIInputStream,
    82                             nsISeekableStream)
    84 nsMIMEInputStream::nsMIMEInputStream() : mAddContentLength(false),
    85                                          mStartedReading(false)
    86 {
    87 }
    89 nsMIMEInputStream::~nsMIMEInputStream()
    90 {
    91 }
    93 NS_METHOD nsMIMEInputStream::Init()
    94 {
    95     nsresult rv = NS_OK;
    96     mStream = do_CreateInstance("@mozilla.org/io/multiplex-input-stream;1",
    97                                 &rv);
    98     NS_ENSURE_SUCCESS(rv, rv);
   100     mHeaderStream = do_CreateInstance("@mozilla.org/io/string-input-stream;1",
   101                                       &rv);
   102     NS_ENSURE_SUCCESS(rv, rv);
   103     mCLStream = do_CreateInstance("@mozilla.org/io/string-input-stream;1", &rv);
   104     NS_ENSURE_SUCCESS(rv, rv);
   106     rv = mStream->AppendStream(mHeaderStream);
   107     NS_ENSURE_SUCCESS(rv, rv);
   109     rv = mStream->AppendStream(mCLStream);
   110     NS_ENSURE_SUCCESS(rv, rv);
   112     return NS_OK;
   113 }
   116 /* attribute boolean addContentLength; */
   117 NS_IMETHODIMP
   118 nsMIMEInputStream::GetAddContentLength(bool *aAddContentLength)
   119 {
   120     *aAddContentLength = mAddContentLength;
   121     return NS_OK;
   122 }
   123 NS_IMETHODIMP
   124 nsMIMEInputStream::SetAddContentLength(bool aAddContentLength)
   125 {
   126     NS_ENSURE_FALSE(mStartedReading, NS_ERROR_FAILURE);
   127     mAddContentLength = aAddContentLength;
   128     return NS_OK;
   129 }
   131 /* void addHeader ([const] in string name, [const] in string value); */
   132 NS_IMETHODIMP
   133 nsMIMEInputStream::AddHeader(const char *aName, const char *aValue)
   134 {
   135     NS_ENSURE_FALSE(mStartedReading, NS_ERROR_FAILURE);
   136     mHeaders.Append(aName);
   137     mHeaders.AppendLiteral(": ");
   138     mHeaders.Append(aValue);
   139     mHeaders.AppendLiteral("\r\n");
   141     // Just in case someone somehow uses our stream, lets at least
   142     // let the stream have a valid pointer. The stream will be properly
   143     // initialized in nsMIMEInputStream::InitStreams
   144     mHeaderStream->ShareData(mHeaders.get(), 0);
   146     return NS_OK;
   147 }
   149 /* void setData (in nsIInputStream stream); */
   150 NS_IMETHODIMP
   151 nsMIMEInputStream::SetData(nsIInputStream *aStream)
   152 {
   153     NS_ENSURE_FALSE(mStartedReading, NS_ERROR_FAILURE);
   154     // Remove the old stream if there is one
   155     if (mData)
   156         mStream->RemoveStream(2);
   158     mData = aStream;
   159     if (aStream)
   160         mStream->AppendStream(mData);
   161     return NS_OK;
   162 }
   164 // set up the internal streams
   165 void nsMIMEInputStream::InitStreams()
   166 {
   167     NS_ASSERTION(!mStartedReading,
   168                  "Don't call initStreams twice without rewinding");
   170     mStartedReading = true;
   172     // We'll use the content-length stream to add the final \r\n
   173     if (mAddContentLength) {
   174         uint64_t cl = 0;
   175         if (mData) {
   176             mData->Available(&cl);
   177         }
   178         mContentLength.AssignLiteral("Content-Length: ");
   179         mContentLength.AppendInt(cl);
   180         mContentLength.AppendLiteral("\r\n\r\n");
   181     }
   182     else {
   183         mContentLength.AssignLiteral("\r\n");
   184     }
   185     mCLStream->ShareData(mContentLength.get(), -1);
   186     mHeaderStream->ShareData(mHeaders.get(), -1);
   187 }
   191 #define INITSTREAMS         \
   192 if (!mStartedReading) {     \
   193     InitStreams();          \
   194 }
   196 // Reset mStartedReading when Seek-ing to start
   197 NS_IMETHODIMP
   198 nsMIMEInputStream::Seek(int32_t whence, int64_t offset)
   199 {
   200     nsresult rv;
   201     nsCOMPtr<nsISeekableStream> stream = do_QueryInterface(mStream);
   202     if (whence == NS_SEEK_SET && offset == 0) {
   203         rv = stream->Seek(whence, offset);
   204         if (NS_SUCCEEDED(rv))
   205             mStartedReading = false;
   206     }
   207     else {
   208         INITSTREAMS;
   209         rv = stream->Seek(whence, offset);
   210     }
   212     return rv;
   213 }
   215 // Proxy ReadSegments since we need to be a good little nsIInputStream
   216 NS_IMETHODIMP nsMIMEInputStream::ReadSegments(nsWriteSegmentFun aWriter,
   217                                               void *aClosure, uint32_t aCount,
   218                                               uint32_t *_retval)
   219 {
   220     INITSTREAMS;
   221     ReadSegmentsState state;
   222     state.mThisStream = this;
   223     state.mWriter = aWriter;
   224     state.mClosure = aClosure;
   225     return mStream->ReadSegments(ReadSegCb, &state, aCount, _retval);
   226 }
   228 NS_METHOD
   229 nsMIMEInputStream::ReadSegCb(nsIInputStream* aIn, void* aClosure,
   230                              const char* aFromRawSegment,
   231                              uint32_t aToOffset, uint32_t aCount,
   232                              uint32_t *aWriteCount)
   233 {
   234     ReadSegmentsState* state = (ReadSegmentsState*)aClosure;
   235     return  (state->mWriter)(state->mThisStream,
   236                              state->mClosure,
   237                              aFromRawSegment,
   238                              aToOffset,
   239                              aCount,
   240                              aWriteCount);
   241 }
   243 /**
   244  * Forward everything else to the mStream after calling InitStreams()
   245  */
   247 // nsIInputStream
   248 NS_IMETHODIMP nsMIMEInputStream::Close(void) { INITSTREAMS; return mStream->Close(); }
   249 NS_IMETHODIMP nsMIMEInputStream::Available(uint64_t *_retval) { INITSTREAMS; return mStream->Available(_retval); }
   250 NS_IMETHODIMP nsMIMEInputStream::Read(char * buf, uint32_t count, uint32_t *_retval) { INITSTREAMS; return mStream->Read(buf, count, _retval); }
   251 NS_IMETHODIMP nsMIMEInputStream::IsNonBlocking(bool *aNonBlocking) { INITSTREAMS; return mStream->IsNonBlocking(aNonBlocking); }
   253 // nsISeekableStream
   254 NS_IMETHODIMP nsMIMEInputStream::Tell(int64_t *_retval)
   255 {
   256     INITSTREAMS;
   257     nsCOMPtr<nsISeekableStream> stream = do_QueryInterface(mStream);
   258     return stream->Tell(_retval);
   259 }
   260 NS_IMETHODIMP nsMIMEInputStream::SetEOF(void) {
   261     INITSTREAMS;
   262     nsCOMPtr<nsISeekableStream> stream = do_QueryInterface(mStream);
   263     return stream->SetEOF();
   264 }
   267 /**
   268  * Factory method used by do_CreateInstance
   269  */
   271 nsresult
   272 nsMIMEInputStreamConstructor(nsISupports *outer, REFNSIID iid, void **result)
   273 {
   274     *result = nullptr;
   276     if (outer)
   277         return NS_ERROR_NO_AGGREGATION;
   279     nsMIMEInputStream *inst = new nsMIMEInputStream();
   280     if (!inst)
   281         return NS_ERROR_OUT_OF_MEMORY;
   283     NS_ADDREF(inst);
   285     nsresult rv = inst->Init();
   286     if (NS_FAILED(rv)) {
   287         NS_RELEASE(inst);
   288         return rv;
   289     }
   291     rv = inst->QueryInterface(iid, result);
   292     NS_RELEASE(inst);
   294     return rv;
   295 }
   297 void
   298 nsMIMEInputStream::Serialize(InputStreamParams& aParams,
   299                              FileDescriptorArray& aFileDescriptors)
   300 {
   301     MIMEInputStreamParams params;
   303     if (mData) {
   304         nsCOMPtr<nsIInputStream> stream = do_QueryInterface(mData);
   305         MOZ_ASSERT(stream);
   307         InputStreamParams wrappedParams;
   308         SerializeInputStream(stream, wrappedParams, aFileDescriptors);
   310         NS_ASSERTION(wrappedParams.type() != InputStreamParams::T__None,
   311                      "Wrapped stream failed to serialize!");
   313         params.optionalStream() = wrappedParams;
   314     }
   315     else {
   316         params.optionalStream() = mozilla::void_t();
   317     }
   319     params.headers() = mHeaders;
   320     params.contentLength() = mContentLength;
   321     params.startedReading() = mStartedReading;
   322     params.addContentLength() = mAddContentLength;
   324     aParams = params;
   325 }
   327 bool
   328 nsMIMEInputStream::Deserialize(const InputStreamParams& aParams,
   329                                const FileDescriptorArray& aFileDescriptors)
   330 {
   331     if (aParams.type() != InputStreamParams::TMIMEInputStreamParams) {
   332         NS_ERROR("Received unknown parameters from the other process!");
   333         return false;
   334     }
   336     const MIMEInputStreamParams& params =
   337         aParams.get_MIMEInputStreamParams();
   338     const OptionalInputStreamParams& wrappedParams = params.optionalStream();
   340     mHeaders = params.headers();
   341     mContentLength = params.contentLength();
   342     mStartedReading = params.startedReading();
   344     // nsMIMEInputStream::Init() already appended mHeaderStream & mCLStream
   345     mHeaderStream->ShareData(mHeaders.get(),
   346                              mStartedReading ? mHeaders.Length() : 0);
   347     mCLStream->ShareData(mContentLength.get(),
   348                          mStartedReading ? mContentLength.Length() : 0);
   350     nsCOMPtr<nsIInputStream> stream;
   351     if (wrappedParams.type() == OptionalInputStreamParams::TInputStreamParams) {
   352         stream = DeserializeInputStream(wrappedParams.get_InputStreamParams(),
   353                                         aFileDescriptors);
   354         if (!stream) {
   355             NS_WARNING("Failed to deserialize wrapped stream!");
   356             return false;
   357         }
   359         mData = stream;
   361         if (NS_FAILED(mStream->AppendStream(mData))) {
   362             NS_WARNING("Failed to append stream!");
   363             return false;
   364         }
   365     }
   366     else {
   367         NS_ASSERTION(wrappedParams.type() == OptionalInputStreamParams::Tvoid_t,
   368                      "Unknown type for OptionalInputStreamParams!");
   369     }
   371     mAddContentLength = params.addContentLength();
   373     return true;
   374 }

mercurial