1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/* ***** BEGIN LICENSE BLOCK *****
3
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
5
* The contents of this file are subject to the Netscape Public License
6
* Version 1.1 (the "License"); you may not use this file except in
7
* compliance with the License. You may obtain a copy of the License at
8
* http://www.mozilla.org/NPL/
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 mozilla.org code.
17
* The Initial Developer of the Original Code is
18
* Netscape Communications Corporation.
19
* Portions created by the Initial Developer are Copyright (C) 1998
20
* the Initial Developer. All Rights Reserved.
24
* Alternatively, the contents of this file may be used under the terms of
25
* either the GNU General Public License Version 2 or later (the "GPL"), or
26
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27
* in which case the provisions of the GPL or the LGPL are applicable instead
28
* of those above. If you wish to allow use of your version of this file only
29
* under the terms of either the GPL or the LGPL, and not to allow others to
30
* use your version of this file under the terms of the NPL, indicate your
31
* decision by deleting the provisions above and replace them with the notice
32
* and other provisions required by the GPL or the LGPL. If you do not delete
33
* the provisions above, a recipient may use your version of this file under
34
* the terms of any one of the NPL, the GPL or the LGPL.
36
* ***** END LICENSE BLOCK ***** */
38
#include "nsMultiMixedConv.h"
41
#include "nsIHttpChannel.h"
42
#include "nsIServiceManager.h"
43
#include "nsNetUtil.h"
44
#include "nsMimeTypes.h"
45
#include "nsIStringStream.h"
46
#include "nsReadableUtils.h"
47
#include "nsIMultiPartChannel.h"
49
#include "nsIHttpChannelInternal.h"
52
// Helper function for determining the length of data bytes up to
53
// the next multipart token. A token is usually preceded by a LF
57
LengthToToken(const char *cursor, const char *token)
59
PRUint32 len = token - cursor;
60
// Trim off any LF or CRLF preceding the token
61
if (len && *(token-1) == '\n') {
63
if (len && *(token-2) == '\r')
70
// nsPartChannel is a "dummy" channel which represents an individual part of
71
// a multipart/mixed stream...
73
// Instances on this channel are passed out to the consumer through the
74
// nsIStreamListener interface.
76
class nsPartChannel : public nsIChannel,
77
public nsIByteRangeRequest,
78
public nsIMultiPartChannel
81
nsPartChannel(nsIChannel *aMultipartChannel);
83
void InitializeByteRange(PRInt32 aStart, PRInt32 aEnd);
88
NS_DECL_NSIBYTERANGEREQUEST
89
NS_DECL_NSIMULTIPARTCHANNEL
92
virtual ~nsPartChannel();
95
nsCOMPtr<nsIChannel> mMultipartChannel;
98
nsLoadFlags mLoadFlags;
100
nsCOMPtr<nsILoadGroup> mLoadGroup;
102
nsCString mContentType;
103
nsCString mContentCharset;
104
nsCString mContentDisposition;
105
PRInt32 mContentLength;
107
PRBool mIsByteRangeRequest;
108
PRInt32 mByteRangeStart;
109
PRInt32 mByteRangeEnd;
112
nsPartChannel::nsPartChannel(nsIChannel *aMultipartChannel) :
115
mIsByteRangeRequest(PR_FALSE),
119
mMultipartChannel = aMultipartChannel;
121
// Inherit the load flags from the original channel...
122
mMultipartChannel->GetLoadFlags(&mLoadFlags);
124
mMultipartChannel->GetLoadGroup(getter_AddRefs(mLoadGroup));
127
nsPartChannel::~nsPartChannel()
131
void nsPartChannel::InitializeByteRange(PRInt32 aStart, PRInt32 aEnd)
133
mIsByteRangeRequest = PR_TRUE;
135
mByteRangeStart = aStart;
136
mByteRangeEnd = aEnd;
141
// nsISupports implementation...
144
NS_IMPL_ADDREF(nsPartChannel)
145
NS_IMPL_RELEASE(nsPartChannel)
147
NS_INTERFACE_MAP_BEGIN(nsPartChannel)
148
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIChannel)
149
NS_INTERFACE_MAP_ENTRY(nsIRequest)
150
NS_INTERFACE_MAP_ENTRY(nsIChannel)
151
NS_INTERFACE_MAP_ENTRY(nsIByteRangeRequest)
152
NS_INTERFACE_MAP_ENTRY(nsIMultiPartChannel)
156
// nsIRequest implementation...
160
nsPartChannel::GetName(nsACString &aResult)
162
return mMultipartChannel->GetName(aResult);
166
nsPartChannel::IsPending(PRBool *aResult)
168
// For now, consider the active lifetime of each part the same as
169
// the underlying multipart channel... This is not exactly right,
170
// but it is good enough :-)
171
return mMultipartChannel->IsPending(aResult);
175
nsPartChannel::GetStatus(nsresult *aResult)
179
if (NS_FAILED(mStatus)) {
182
rv = mMultipartChannel->GetStatus(aResult);
189
nsPartChannel::Cancel(nsresult aStatus)
191
// Cancelling an individual part must not cancel the underlying
192
// multipart channel...
198
nsPartChannel::Suspend(void)
200
// Suspending an individual part must not suspend the underlying
201
// multipart channel...
206
nsPartChannel::Resume(void)
208
// Resuming an individual part must not resume the underlying
209
// multipart channel...
214
// nsIChannel implementation
218
nsPartChannel::GetOriginalURI(nsIURI * *aURI)
220
return mMultipartChannel->GetOriginalURI(aURI);
224
nsPartChannel::SetOriginalURI(nsIURI *aURI)
226
return mMultipartChannel->SetOriginalURI(aURI);
230
nsPartChannel::GetURI(nsIURI * *aURI)
232
return mMultipartChannel->GetURI(aURI);
236
nsPartChannel::Open(nsIInputStream **result)
238
// This channel cannot be opened!
239
return NS_ERROR_FAILURE;
243
nsPartChannel::AsyncOpen(nsIStreamListener *aListener, nsISupports *aContext)
245
// This channel cannot be opened!
246
return NS_ERROR_FAILURE;
250
nsPartChannel::GetLoadFlags(nsLoadFlags *aLoadFlags)
252
*aLoadFlags = mLoadFlags;
257
nsPartChannel::SetLoadFlags(nsLoadFlags aLoadFlags)
259
mLoadFlags = aLoadFlags;
264
nsPartChannel::GetLoadGroup(nsILoadGroup* *aLoadGroup)
266
*aLoadGroup = mLoadGroup;
267
NS_IF_ADDREF(*aLoadGroup);
273
nsPartChannel::SetLoadGroup(nsILoadGroup* aLoadGroup)
275
mLoadGroup = aLoadGroup;
281
nsPartChannel::GetOwner(nsISupports* *aOwner)
283
return mMultipartChannel->GetOwner(aOwner);
287
nsPartChannel::SetOwner(nsISupports* aOwner)
289
return mMultipartChannel->SetOwner(aOwner);
293
nsPartChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aCallbacks)
295
return mMultipartChannel->GetNotificationCallbacks(aCallbacks);
299
nsPartChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aCallbacks)
301
return mMultipartChannel->SetNotificationCallbacks(aCallbacks);
305
nsPartChannel::GetSecurityInfo(nsISupports * *aSecurityInfo)
307
return mMultipartChannel->GetSecurityInfo(aSecurityInfo);
311
nsPartChannel::GetContentType(nsACString &aContentType)
313
aContentType = mContentType;
318
nsPartChannel::SetContentType(const nsACString &aContentType)
320
NS_ParseContentType(aContentType, mContentType, mContentCharset);
325
nsPartChannel::GetContentCharset(nsACString &aContentCharset)
327
aContentCharset = mContentCharset;
332
nsPartChannel::SetContentCharset(const nsACString &aContentCharset)
334
mContentCharset = aContentCharset;
339
nsPartChannel::GetContentLength(PRInt32 *aContentLength)
341
*aContentLength = mContentLength;
346
nsPartChannel::SetContentLength(PRInt32 aContentLength)
348
mContentLength = aContentLength;
353
nsPartChannel::GetContentDisposition(nsACString &aContentDisposition)
355
aContentDisposition = mContentDisposition;
360
nsPartChannel::SetContentDisposition(const nsACString &aContentDisposition)
362
mContentDisposition = aContentDisposition;
367
// nsIByteRangeRequest implementation...
371
nsPartChannel::GetIsByteRangeRequest(PRBool *aIsByteRangeRequest)
373
*aIsByteRangeRequest = mIsByteRangeRequest;
380
nsPartChannel::GetStartRange(PRInt32 *aStartRange)
382
*aStartRange = mByteRangeStart;
388
nsPartChannel::GetEndRange(PRInt32 *aEndRange)
390
*aEndRange = mByteRangeEnd;
395
nsPartChannel::GetBaseChannel(nsIChannel ** aReturn)
397
NS_ENSURE_ARG_POINTER(aReturn);
399
*aReturn = mMultipartChannel;
400
NS_IF_ADDREF(*aReturn);
405
// nsISupports implementation
406
NS_IMPL_THREADSAFE_ISUPPORTS3(nsMultiMixedConv,
412
// nsIStreamConverter implementation
414
// No syncronous conversion at this time.
416
nsMultiMixedConv::Convert(nsIInputStream *aFromStream,
417
const PRUnichar *aFromType,
418
const PRUnichar *aToType,
419
nsISupports *aCtxt, nsIInputStream **_retval) {
420
return NS_ERROR_NOT_IMPLEMENTED;
423
// Stream converter service calls this to initialize the actual stream converter (us).
425
nsMultiMixedConv::AsyncConvertData(const PRUnichar *aFromType, const PRUnichar *aToType,
426
nsIStreamListener *aListener, nsISupports *aCtxt) {
427
NS_ASSERTION(aListener && aFromType && aToType, "null pointer passed into multi mixed converter");
429
// hook up our final listener. this guy gets the various On*() calls we want to throw
432
// WARNING: this listener must be able to handle multiple OnStartRequest, OnDataAvail()
433
// and OnStopRequest() call combinations. We call of series of these for each sub-part
434
// in the raw stream.
435
mFinalListener = aListener;
439
#define ERR_OUT { free(buffer); return rv; }
441
// nsIStreamListener implementation
443
nsMultiMixedConv::OnDataAvailable(nsIRequest *request, nsISupports *context,
444
nsIInputStream *inStr, PRUint32 sourceOffset, PRUint32 count) {
446
if (mToken.IsEmpty()) // no token, no love.
447
return NS_ERROR_FAILURE;
450
char *buffer = nsnull;
451
PRUint32 bufLen = 0, read = 0;
453
NS_ASSERTION(request, "multimixed converter needs a request");
455
nsCOMPtr<nsIChannel> channel = do_QueryInterface(request, &rv);
456
if (NS_FAILED(rv)) return rv;
460
bufLen = count + mBufLen;
461
buffer = (char *) malloc(bufLen);
463
return NS_ERROR_OUT_OF_MEMORY;
466
// incorporate any buffered data into the parsing
467
memcpy(buffer, mBuffer, mBufLen);
473
rv = inStr->Read(buffer + (bufLen - count), count, &read);
475
if (NS_FAILED(rv) || read == 0) return rv;
476
NS_ASSERTION(read == count, "poor data size assumption");
479
char *cursor = buffer;
482
// this is the first OnData() for this request. some servers
483
// don't bother sending a token in the first "part." This is
484
// illegal, but we'll handle the case anyway by shoving the
485
// boundary token in for the server.
486
mFirstOnData = PR_FALSE;
487
NS_ASSERTION(!mBufLen, "this is our first time through, we can't have buffered data");
488
const char * token = mToken.get();
490
PushOverLine(cursor, bufLen);
492
if (bufLen < mTokenLen+2) {
493
// we don't have enough data yet to make this comparison.
494
// skip this check, and try again the next time OnData()
496
mFirstOnData = PR_TRUE;
498
else if (!PL_strnstr(cursor, token, mTokenLen+2)) {
499
buffer = (char *) realloc(buffer, bufLen + mTokenLen + 1);
501
return NS_ERROR_OUT_OF_MEMORY;
503
memmove(buffer + mTokenLen + 1, buffer, bufLen);
504
memcpy(buffer, token, mTokenLen);
505
buffer[mTokenLen] = '\n';
507
bufLen += (mTokenLen + 1);
509
// need to reset cursor to the buffer again (bug 100595)
514
char *token = nsnull;
516
if (mProcessingHeaders) {
517
// we were not able to process all the headers
518
// for this "part" given the previous buffer given to
519
// us in the previous OnDataAvailable callback.
520
PRBool done = PR_FALSE;
521
rv = ParseHeaders(channel, cursor, bufLen, &done);
522
if (NS_FAILED(rv)) ERR_OUT
525
mProcessingHeaders = PR_FALSE;
526
rv = SendStart(channel);
527
if (NS_FAILED(rv)) ERR_OUT
531
PRInt32 tokenLinefeed = 1;
532
while ( (token = FindToken(cursor, bufLen)) ) {
534
if (*(token+mTokenLen+1) == '-') {
535
// This was the last delimiter so we can stop processing
536
rv = SendData(cursor, LengthToToken(cursor, token));
538
if (NS_FAILED(rv)) return rv;
539
return SendStop(NS_OK);
542
if (!mNewPart && token > cursor) {
543
// headers are processed, we're pushing data now.
544
NS_ASSERTION(!mProcessingHeaders, "we should be pushing raw data");
545
rv = SendData(cursor, LengthToToken(cursor, token));
546
bufLen -= token - cursor;
547
if (NS_FAILED(rv)) ERR_OUT
549
// XXX else NS_ASSERTION(token == cursor, "?");
552
tokenLinefeed = PushOverLine(token, bufLen);
558
PRBool done = PR_FALSE;
559
rv = ParseHeaders(channel, cursor, bufLen, &done);
560
if (NS_FAILED(rv)) ERR_OUT
562
rv = SendStart(channel);
563
if (NS_FAILED(rv)) ERR_OUT
566
// we haven't finished processing header info.
567
// we'll break out and try to process later.
568
mProcessingHeaders = PR_TRUE;
574
// Reset state so we don't carry it over from part to part
575
mContentType.Truncate();
577
mContentDisposition.Truncate();
578
mIsByteRangeRequest = PR_FALSE;
582
rv = SendStop(NS_OK);
583
if (NS_FAILED(rv)) ERR_OUT
584
// reset the token to front. this allows us to treat
585
// the token as a starting token.
586
token -= mTokenLen + tokenLinefeed;
587
bufLen += mTokenLen + tokenLinefeed;
592
// at this point, we want to buffer up whatever amount (bufLen)
593
// we have leftover. However, we *always* want to ensure that
594
// we buffer enough data to handle a broken token.
598
if (mProcessingHeaders)
601
// if the data ends in a linefeed, and we're in the middle
602
// of a "part" (ie. mPartChannel exists) don't bother
603
// buffering, go ahead and send the data we have. Otherwise
604
// if we don't have a channel already, then we don't even
605
// have enough info to start a part, go ahead and buffer
606
// enough to collect a boundary token.
607
if (!mPartChannel || !(cursor[bufLen-1] == nsCRT::LF) )
608
bufAmt = PR_MIN(mTokenLen - 1, bufLen);
612
rv = BufferData(cursor + (bufLen - bufAmt), bufAmt);
613
if (NS_FAILED(rv)) ERR_OUT
618
rv = SendData(cursor, bufLen);
619
if (NS_FAILED(rv)) ERR_OUT
627
// nsIRequestObserver implementation
629
nsMultiMixedConv::OnStartRequest(nsIRequest *request, nsISupports *ctxt) {
630
// we're assuming the content-type is available at this stage
631
NS_ASSERTION(mToken.IsEmpty(), "a second on start???");
632
const char *bndry = nsnull;
633
nsCAutoString delimiter;
637
mFirstOnData = PR_TRUE;
640
nsCOMPtr<nsIChannel> channel = do_QueryInterface(request, &rv);
641
if (NS_FAILED(rv)) return rv;
643
// ask the HTTP channel for the content-type and extract the boundary from it.
644
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel, &rv);
645
if (NS_SUCCEEDED(rv)) {
646
rv = httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("content-type"), delimiter);
647
if (NS_FAILED(rv)) return rv;
649
// try asking the channel directly
650
rv = channel->GetContentType(delimiter);
651
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
654
bndry = strstr(delimiter.BeginWriting(), "boundary");
655
if (!bndry) return NS_ERROR_FAILURE;
657
bndry = strchr(bndry, '=');
658
if (!bndry) return NS_ERROR_FAILURE;
660
bndry++; // move past the equals sign
662
char *attrib = (char *) strchr(bndry, ';');
663
if (attrib) *attrib = '\0';
665
nsCAutoString boundaryString(bndry);
666
if (attrib) *attrib = ';';
668
boundaryString.Trim(" \"");
670
mToken = boundaryString;
671
mTokenLen = boundaryString.Length();
674
return NS_ERROR_FAILURE;
680
nsMultiMixedConv::OnStopRequest(nsIRequest *request, nsISupports *ctxt,
683
if (mToken.IsEmpty()) // no token, no love.
684
return NS_ERROR_FAILURE;
687
// we've already called SendStart() (which sets up the mPartChannel,
688
// and fires an OnStart()) send any data left over, and then fire the stop.
689
if (mBufLen > 0 && mBuffer) {
690
(void) SendData(mBuffer, mBufLen);
691
// don't bother checking the return value here, if the send failed
692
// we're done anyway as we're in the OnStop() callback.
697
(void) SendStop(aStatus);
698
} else if (NS_FAILED(aStatus)) {
699
// underlying data production problem. we should not be in
700
// the middle of sending data. if we were, mPartChannel,
701
// above, would have been true.
703
// if we send the start, the URI Loader's m_targetStreamListener, may
704
// be pointing at us causing a nice stack overflow. So, don't call
705
// OnStartRequest! - This breaks necko's semantecs.
706
//(void) mFinalListener->OnStartRequest(request, ctxt);
708
(void) mFinalListener->OnStopRequest(request, ctxt, aStatus);
715
// nsMultiMixedConv methods
716
nsMultiMixedConv::nsMultiMixedConv() {
722
mProcessingHeaders = PR_FALSE;
726
mIsByteRangeRequest = PR_FALSE;
729
nsMultiMixedConv::~nsMultiMixedConv() {
730
NS_ASSERTION(!mBuffer, "all buffered data should be gone");
738
nsMultiMixedConv::BufferData(char *aData, PRUint32 aLen) {
739
NS_ASSERTION(!mBuffer, "trying to over-write buffer");
741
char *buffer = (char *) malloc(aLen);
742
if (!buffer) return NS_ERROR_OUT_OF_MEMORY;
744
memcpy(buffer, aData, aLen);
752
nsMultiMixedConv::SendStart(nsIChannel *aChannel) {
755
if (mContentType.IsEmpty())
756
mContentType = NS_LITERAL_CSTRING(UNKNOWN_CONTENT_TYPE);
758
// if we already have an mPartChannel, that means we never sent a Stop()
759
// before starting up another "part." that would be bad.
760
NS_ASSERTION(!mPartChannel, "tisk tisk, shouldn't be overwriting a channel");
762
nsPartChannel *newChannel;
763
newChannel = new nsPartChannel(aChannel);
765
return NS_ERROR_OUT_OF_MEMORY;
767
if (mIsByteRangeRequest) {
768
newChannel->InitializeByteRange(mByteRangeStart, mByteRangeEnd);
773
// Set up the new part channel...
774
mPartChannel = newChannel;
776
rv = mPartChannel->SetContentType(mContentType);
777
if (NS_FAILED(rv)) return rv;
779
rv = mPartChannel->SetContentLength(mContentLength);
780
if (NS_FAILED(rv)) return rv;
782
nsCOMPtr<nsIMultiPartChannel> partChannel(do_QueryInterface(mPartChannel));
784
rv = partChannel->SetContentDisposition(mContentDisposition);
785
if (NS_FAILED(rv)) return rv;
788
nsLoadFlags loadFlags = 0;
789
mPartChannel->GetLoadFlags(&loadFlags);
790
loadFlags |= nsIChannel::LOAD_REPLACE;
791
mPartChannel->SetLoadFlags(loadFlags);
793
nsCOMPtr<nsILoadGroup> loadGroup;
794
(void)mPartChannel->GetLoadGroup(getter_AddRefs(loadGroup));
796
// Add the new channel to the load group (if any)
798
rv = loadGroup->AddRequest(mPartChannel, nsnull);
799
if (NS_FAILED(rv)) return rv;
802
// Let's start off the load. NOTE: we don't forward on the channel passed
803
// into our OnDataAvailable() as it's the root channel for the raw stream.
804
return mFinalListener->OnStartRequest(mPartChannel, mContext);
809
nsMultiMixedConv::SendStop(nsresult aStatus) {
813
rv = mFinalListener->OnStopRequest(mPartChannel, mContext, aStatus);
814
// don't check for failure here, we need to remove the channel from
817
// Remove the channel from its load group (if any)
818
nsCOMPtr<nsILoadGroup> loadGroup;
819
(void) mPartChannel->GetLoadGroup(getter_AddRefs(loadGroup));
821
(void) loadGroup->RemoveRequest(mPartChannel, mContext, aStatus);
829
nsMultiMixedConv::SendData(char *aBuffer, PRUint32 aLen) {
833
if (!mPartChannel) return NS_ERROR_FAILURE; // something went wrong w/ processing
835
if (mContentLength != -1) {
836
// make sure that we don't send more than the mContentLength
837
// XXX why? perhaps the Content-Length header was actually wrong!!
838
if ((aLen + mTotalSent) > PRUint32(mContentLength))
839
aLen = mContentLength - mTotalSent;
845
PRUint32 offset = mTotalSent;
848
nsCOMPtr<nsIStringInputStream> ss(
849
do_CreateInstance("@mozilla.org/io/string-input-stream;1", &rv));
853
rv = ss->ShareData(aBuffer, aLen);
857
nsCOMPtr<nsIInputStream> inStream(do_QueryInterface(ss, &rv));
858
if (NS_FAILED(rv)) return rv;
860
return mFinalListener->OnDataAvailable(mPartChannel, mContext, inStream, offset, aLen);
864
nsMultiMixedConv::PushOverLine(char *&aPtr, PRUint32 &aLen) {
866
if ((aLen > 0) && (*aPtr == nsCRT::CR || *aPtr == nsCRT::LF)) {
867
if ((aLen > 1) && (aPtr[1] == nsCRT::LF))
877
nsMultiMixedConv::ParseHeaders(nsIChannel *aChannel, char *&aPtr,
878
PRUint32 &aLen, PRBool *_retval) {
879
// NOTE: this data must be ascii.
880
// NOTE: aPtr is NOT null terminated!
882
char *cursor = aPtr, *newLine = nsnull;
883
PRUint32 cursorLen = aLen;
884
PRBool done = PR_FALSE;
885
PRUint32 lineFeedIncrement = 1;
887
mContentLength = -1; // XXX what if we were already called?
888
while (cursorLen && (newLine = (char *) memchr(cursor, nsCRT::LF, cursorLen))) {
889
// adjust for linefeeds
890
if ((newLine > cursor) && (newLine[-1] == nsCRT::CR) ) { // CRLF
891
lineFeedIncrement = 2;
895
lineFeedIncrement = 1; // reset
897
if (newLine == cursor) {
898
// move the newLine beyond the linefeed marker
899
NS_ASSERTION(cursorLen >= lineFeedIncrement, "oops!");
901
cursor += lineFeedIncrement;
902
cursorLen -= lineFeedIncrement;
908
char tmpChar = *newLine;
909
*newLine = '\0'; // cursor is now null terminated
910
char *colon = (char *) strchr(cursor, ':');
913
nsCAutoString headerStr(cursor);
914
headerStr.CompressWhitespace();
917
nsCAutoString headerVal(colon + 1);
918
headerVal.CompressWhitespace();
921
if (headerStr.EqualsIgnoreCase("content-type")) {
922
mContentType = headerVal;
923
} else if (headerStr.EqualsIgnoreCase("content-length")) {
924
mContentLength = atoi(headerVal.get());
925
} else if (headerStr.EqualsIgnoreCase("content-disposition")) {
926
mContentDisposition = headerVal;
927
} else if (headerStr.EqualsIgnoreCase("set-cookie")) {
928
nsCOMPtr<nsIHttpChannelInternal> httpInternal =
929
do_QueryInterface(aChannel);
931
httpInternal->SetCookie(headerVal.get());
933
} else if (headerStr.EqualsIgnoreCase("content-range") ||
934
headerStr.EqualsIgnoreCase("range") ) {
935
// something like: Content-range: bytes 7000-7999/8000
938
tmpPtr = (char *) strchr(colon + 1, '/');
942
// pass the bytes-unit and the SP
943
char *range = (char *) strchr(colon + 2, ' ');
946
return NS_ERROR_FAILURE;
948
if (range[0] == '*'){
949
mByteRangeStart = mByteRangeEnd = 0;
952
tmpPtr = (char *) strchr(range, '-');
954
return NS_ERROR_FAILURE;
958
mByteRangeStart = atoi(range);
960
mByteRangeEnd = atoi(tmpPtr);
963
mIsByteRangeRequest = PR_TRUE;
964
if (mContentLength == -1)
965
mContentLength = mByteRangeEnd - mByteRangeStart + 1;
969
newLine += lineFeedIncrement;
970
cursorLen -= (newLine - cursor);
982
nsMultiMixedConv::FindToken(char *aCursor, PRUint32 aLen) {
983
// strnstr without looking for null termination
984
const char *token = mToken.get();
987
if (!(token && aCursor && *token)) {
988
NS_WARNING("bad data");
992
for (; aLen >= mTokenLen; aCursor++, aLen--) {
993
if (!memcmp(aCursor, token, mTokenLen) ) {
994
if ((aCursor - cur) >= 2) {
995
// back the cursor up over a double dash for backwards compat.
996
if ((*(aCursor-1) == '-') && (*(aCursor-2) == '-')) {
1000
// we're playing w/ double dash tokens, adjust.
1001
mToken.Assign(aCursor, mTokenLen + 2);
1002
mTokenLen = mToken.Length();
1013
NS_NewMultiMixedConv(nsMultiMixedConv** aMultiMixedConv)
1015
NS_PRECONDITION(aMultiMixedConv != nsnull, "null ptr");
1016
if (! aMultiMixedConv)
1017
return NS_ERROR_NULL_POINTER;
1019
*aMultiMixedConv = new nsMultiMixedConv();
1020
if (! *aMultiMixedConv)
1021
return NS_ERROR_OUT_OF_MEMORY;
1023
NS_ADDREF(*aMultiMixedConv);