1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is frightening to behold.
17 * The Initial Developer of the Original Code is
19 * Portions created by the Initial Developer are Copyright (C) 2001
20 * the Initial Developer. All Rights Reserved.
23 * Jonas Sicking <sicking@bigfoot.com>
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
40 * The MIME stream separates headers and a datastream. It also allows
41 * automatic creation of the content-length header.
45 #include "nsComponentManagerUtils.h"
46 #include "nsIMultiplexInputStream.h"
47 #include "nsIMIMEInputStream.h"
48 #include "nsISeekableStream.h"
49 #include "nsIStringStream.h"
52 class nsMIMEInputStream
: public nsIMIMEInputStream
,
53 public nsISeekableStream
57 virtual ~nsMIMEInputStream();
60 NS_DECL_NSIINPUTSTREAM
61 NS_DECL_NSIMIMEINPUTSTREAM
62 NS_DECL_NSISEEKABLESTREAM
70 struct ReadSegmentsState
{
71 nsIInputStream
* mThisStream
;
72 nsWriteSegmentFun mWriter
;
75 static NS_METHOD
ReadSegCb(nsIInputStream
* aIn
, void* aClosure
,
76 const char* aFromRawSegment
, PRUint32 aToOffset
,
77 PRUint32 aCount
, PRUint32
*aWriteCount
);
80 nsCOMPtr
<nsIStringInputStream
> mHeaderStream
;
82 nsCString mContentLength
;
83 nsCOMPtr
<nsIStringInputStream
> mCLStream
;
85 nsCOMPtr
<nsIInputStream
> mData
;
86 nsCOMPtr
<nsIMultiplexInputStream
> mStream
;
87 PRPackedBool mAddContentLength
;
88 PRPackedBool mStartedReading
;
91 NS_IMPL_THREADSAFE_ISUPPORTS3(nsMIMEInputStream
,
96 nsMIMEInputStream::nsMIMEInputStream() : mAddContentLength(PR_FALSE
),
97 mStartedReading(PR_FALSE
)
101 nsMIMEInputStream::~nsMIMEInputStream()
105 NS_METHOD
nsMIMEInputStream::Init()
108 mStream
= do_CreateInstance("@mozilla.org/io/multiplex-input-stream;1",
110 NS_ENSURE_SUCCESS(rv
, rv
);
112 mHeaderStream
= do_CreateInstance("@mozilla.org/io/string-input-stream;1",
114 NS_ENSURE_SUCCESS(rv
, rv
);
115 mCLStream
= do_CreateInstance("@mozilla.org/io/string-input-stream;1", &rv
);
116 NS_ENSURE_SUCCESS(rv
, rv
);
118 rv
= mStream
->AppendStream(mHeaderStream
);
119 NS_ENSURE_SUCCESS(rv
, rv
);
121 rv
= mStream
->AppendStream(mCLStream
);
122 NS_ENSURE_SUCCESS(rv
, rv
);
128 /* attribute boolean addContentLength; */
130 nsMIMEInputStream::GetAddContentLength(PRBool
*aAddContentLength
)
132 *aAddContentLength
= mAddContentLength
;
136 nsMIMEInputStream::SetAddContentLength(PRBool aAddContentLength
)
138 NS_ENSURE_FALSE(mStartedReading
, NS_ERROR_FAILURE
);
139 mAddContentLength
= aAddContentLength
;
143 /* void addHeader ([const] in string name, [const] in string value); */
145 nsMIMEInputStream::AddHeader(const char *aName
, const char *aValue
)
147 NS_ENSURE_FALSE(mStartedReading
, NS_ERROR_FAILURE
);
148 mHeaders
.Append(aName
);
149 mHeaders
.AppendLiteral(": ");
150 mHeaders
.Append(aValue
);
151 mHeaders
.AppendLiteral("\r\n");
153 // Just in case someone somehow uses our stream, lets at least
154 // let the stream have a valid pointer. The stream will be properly
155 // initialized in nsMIMEInputStream::InitStreams
156 mHeaderStream
->ShareData(mHeaders
.get(), 0);
161 /* void setData (in nsIInputStream stream); */
163 nsMIMEInputStream::SetData(nsIInputStream
*aStream
)
165 NS_ENSURE_FALSE(mStartedReading
, NS_ERROR_FAILURE
);
166 // Remove the old stream if there is one
168 mStream
->RemoveStream(2);
172 mStream
->AppendStream(mData
);
176 // set up the internal streams
177 void nsMIMEInputStream::InitStreams()
179 NS_ASSERTION(!mStartedReading
,
180 "Don't call initStreams twice without rewinding");
182 mStartedReading
= PR_TRUE
;
184 // We'll use the content-length stream to add the final \r\n
185 if (mAddContentLength
) {
188 mData
->Available(&cl
);
190 mContentLength
.AssignLiteral("Content-Length: ");
191 mContentLength
.AppendInt((PRInt32
)cl
);
192 mContentLength
.AppendLiteral("\r\n\r\n");
195 mContentLength
.AssignLiteral("\r\n");
197 mCLStream
->ShareData(mContentLength
.get(), -1);
198 mHeaderStream
->ShareData(mHeaders
.get(), -1);
203 #define INITSTREAMS \
204 if (!mStartedReading) { \
208 // Reset mStartedReading when Seek-ing to start
210 nsMIMEInputStream::Seek(PRInt32 whence
, PRInt64 offset
)
213 nsCOMPtr
<nsISeekableStream
> stream
= do_QueryInterface(mStream
);
214 if (whence
== NS_SEEK_SET
&& LL_EQ(offset
, LL_Zero())) {
215 rv
= stream
->Seek(whence
, offset
);
216 if (NS_SUCCEEDED(rv
))
217 mStartedReading
= PR_FALSE
;
221 rv
= stream
->Seek(whence
, offset
);
227 // Proxy ReadSegments since we need to be a good little nsIInputStream
228 NS_IMETHODIMP
nsMIMEInputStream::ReadSegments(nsWriteSegmentFun aWriter
,
229 void *aClosure
, PRUint32 aCount
,
233 ReadSegmentsState state
;
234 state
.mThisStream
= this;
235 state
.mWriter
= aWriter
;
236 state
.mClosure
= aClosure
;
237 return mStream
->ReadSegments(ReadSegCb
, &state
, aCount
, _retval
);
241 nsMIMEInputStream::ReadSegCb(nsIInputStream
* aIn
, void* aClosure
,
242 const char* aFromRawSegment
,
243 PRUint32 aToOffset
, PRUint32 aCount
,
244 PRUint32
*aWriteCount
)
246 ReadSegmentsState
* state
= (ReadSegmentsState
*)aClosure
;
247 return (state
->mWriter
)(state
->mThisStream
,
256 * Forward everything else to the mStream after calling InitStreams()
260 NS_IMETHODIMP
nsMIMEInputStream::Close(void) { INITSTREAMS
; return mStream
->Close(); }
261 NS_IMETHODIMP
nsMIMEInputStream::Available(PRUint32
*_retval
) { INITSTREAMS
; return mStream
->Available(_retval
); }
262 NS_IMETHODIMP
nsMIMEInputStream::Read(char * buf
, PRUint32 count
, PRUint32
*_retval
) { INITSTREAMS
; return mStream
->Read(buf
, count
, _retval
); }
263 NS_IMETHODIMP
nsMIMEInputStream::IsNonBlocking(PRBool
*aNonBlocking
) { INITSTREAMS
; return mStream
->IsNonBlocking(aNonBlocking
); }
266 NS_IMETHODIMP
nsMIMEInputStream::Tell(PRInt64
*_retval
)
269 nsCOMPtr
<nsISeekableStream
> stream
= do_QueryInterface(mStream
);
270 return stream
->Tell(_retval
);
272 NS_IMETHODIMP
nsMIMEInputStream::SetEOF(void) {
274 nsCOMPtr
<nsISeekableStream
> stream
= do_QueryInterface(mStream
);
275 return stream
->SetEOF();
280 * Factory method used by do_CreateInstance
284 nsMIMEInputStreamConstructor(nsISupports
*outer
, REFNSIID iid
, void **result
)
289 return NS_ERROR_NO_AGGREGATION
;
291 nsMIMEInputStream
*inst
;
292 NS_NEWXPCOM(inst
, nsMIMEInputStream
);
294 return NS_ERROR_OUT_OF_MEMORY
;
298 nsresult rv
= inst
->Init();
304 rv
= inst
->QueryInterface(iid
, result
);