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.

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

mercurial