Bug 785860 - fix sts preload list tests to skip private mode tests if private browsin...
[gecko.git] / netwerk / base / src / nsMIMEInputStream.cpp
blobe1127e1e93aa5270b244d90b3bd9575525ae3256
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
31 public:
32 nsMIMEInputStream();
33 virtual ~nsMIMEInputStream();
35 NS_DECL_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;
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;
68 NS_IMPL_THREADSAFE_ADDREF(nsMIMEInputStream)
69 NS_IMPL_THREADSAFE_RELEASE(nsMIMEInputStream)
71 NS_IMPL_CLASSINFO(nsMIMEInputStream, NULL, nsIClassInfo::THREADSAFE,
72 NS_MIMEINPUTSTREAM_CID)
74 NS_IMPL_QUERY_INTERFACE4_CI(nsMIMEInputStream,
75 nsIMIMEInputStream,
76 nsIInputStream,
77 nsISeekableStream,
78 nsIIPCSerializableInputStream)
79 NS_IMPL_CI_INTERFACE_GETTER3(nsMIMEInputStream,
80 nsIMIMEInputStream,
81 nsIInputStream,
82 nsISeekableStream)
84 nsMIMEInputStream::nsMIMEInputStream() : mAddContentLength(false),
85 mStartedReading(false)
89 nsMIMEInputStream::~nsMIMEInputStream()
93 NS_METHOD nsMIMEInputStream::Init()
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;
116 /* attribute boolean addContentLength; */
117 NS_IMETHODIMP
118 nsMIMEInputStream::GetAddContentLength(bool *aAddContentLength)
120 *aAddContentLength = mAddContentLength;
121 return NS_OK;
123 NS_IMETHODIMP
124 nsMIMEInputStream::SetAddContentLength(bool aAddContentLength)
126 NS_ENSURE_FALSE(mStartedReading, NS_ERROR_FAILURE);
127 mAddContentLength = aAddContentLength;
128 return NS_OK;
131 /* void addHeader ([const] in string name, [const] in string value); */
132 NS_IMETHODIMP
133 nsMIMEInputStream::AddHeader(const char *aName, const char *aValue)
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;
149 /* void setData (in nsIInputStream stream); */
150 NS_IMETHODIMP
151 nsMIMEInputStream::SetData(nsIInputStream *aStream)
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;
164 // set up the internal streams
165 void nsMIMEInputStream::InitStreams()
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);
178 mContentLength.AssignLiteral("Content-Length: ");
179 mContentLength.AppendInt(cl);
180 mContentLength.AppendLiteral("\r\n\r\n");
182 else {
183 mContentLength.AssignLiteral("\r\n");
185 mCLStream->ShareData(mContentLength.get(), -1);
186 mHeaderStream->ShareData(mHeaders.get(), -1);
191 #define INITSTREAMS \
192 if (!mStartedReading) { \
193 InitStreams(); \
196 // Reset mStartedReading when Seek-ing to start
197 NS_IMETHODIMP
198 nsMIMEInputStream::Seek(int32_t whence, int64_t offset)
200 nsresult rv;
201 nsCOMPtr<nsISeekableStream> stream = do_QueryInterface(mStream);
202 if (whence == NS_SEEK_SET && LL_EQ(offset, LL_Zero())) {
203 rv = stream->Seek(whence, offset);
204 if (NS_SUCCEEDED(rv))
205 mStartedReading = false;
207 else {
208 INITSTREAMS;
209 rv = stream->Seek(whence, offset);
212 return rv;
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)
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);
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)
234 ReadSegmentsState* state = (ReadSegmentsState*)aClosure;
235 return (state->mWriter)(state->mThisStream,
236 state->mClosure,
237 aFromRawSegment,
238 aToOffset,
239 aCount,
240 aWriteCount);
244 * Forward everything else to the mStream after calling InitStreams()
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)
256 INITSTREAMS;
257 nsCOMPtr<nsISeekableStream> stream = do_QueryInterface(mStream);
258 return stream->Tell(_retval);
260 NS_IMETHODIMP nsMIMEInputStream::SetEOF(void) {
261 INITSTREAMS;
262 nsCOMPtr<nsISeekableStream> stream = do_QueryInterface(mStream);
263 return stream->SetEOF();
268 * Factory method used by do_CreateInstance
271 nsresult
272 nsMIMEInputStreamConstructor(nsISupports *outer, REFNSIID iid, void **result)
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;
291 rv = inst->QueryInterface(iid, result);
292 NS_RELEASE(inst);
294 return rv;
297 void
298 nsMIMEInputStream::Serialize(InputStreamParams& aParams)
300 MIMEInputStreamParams params;
302 if (mData) {
303 nsCOMPtr<nsIIPCSerializableInputStream> stream =
304 do_QueryInterface(mData);
305 NS_ASSERTION(stream, "Wrapped stream is not serializable!");
307 InputStreamParams wrappedParams;
308 stream->Serialize(wrappedParams);
310 NS_ASSERTION(wrappedParams.type() != InputStreamParams::T__None,
311 "Wrapped stream failed to serialize!");
313 params.optionalStream() = wrappedParams;
315 else {
316 params.optionalStream() = mozilla::void_t();
319 params.headers() = mHeaders;
320 params.contentLength() = mContentLength;
321 params.startedReading() = mStartedReading;
322 params.addContentLength() = mAddContentLength;
324 aParams = params;
327 bool
328 nsMIMEInputStream::Deserialize(const InputStreamParams& aParams)
330 if (aParams.type() != InputStreamParams::TMIMEInputStreamParams) {
331 NS_ERROR("Received unknown parameters from the other process!");
332 return false;
335 const MIMEInputStreamParams& params =
336 aParams.get_MIMEInputStreamParams();
337 const OptionalInputStreamParams& wrappedParams = params.optionalStream();
339 mHeaders = params.headers();
340 mContentLength = params.contentLength();
341 mStartedReading = params.startedReading();
343 // nsMIMEInputStream::Init() already appended mHeaderStream & mCLStream
344 mHeaderStream->ShareData(mHeaders.get(),
345 mStartedReading ? mHeaders.Length() : 0);
346 mCLStream->ShareData(mContentLength.get(),
347 mStartedReading ? mContentLength.Length() : 0);
349 nsCOMPtr<nsIInputStream> stream;
350 if (wrappedParams.type() == OptionalInputStreamParams::TInputStreamParams) {
351 stream = DeserializeInputStream(wrappedParams.get_InputStreamParams());
352 if (!stream) {
353 NS_WARNING("Failed to deserialize wrapped stream!");
354 return false;
357 mData = stream;
359 if (NS_FAILED(mStream->AppendStream(mData))) {
360 NS_WARNING("Failed to append stream!");
361 return false;
364 else {
365 NS_ASSERTION(wrappedParams.type() == OptionalInputStreamParams::Tvoid_t,
366 "Unknown type for OptionalInputStreamParams!");
369 mAddContentLength = params.addContentLength();
371 return true;