2
* The contents of this file are subject to the Mozilla Public
3
* License Version 1.1 (the "MPL"); you may not use this file
4
* except in compliance with the MPL. You may obtain a copy of
5
* the MPL at http://www.mozilla.org/MPL/
7
* Software distributed under the MPL is distributed on an "AS
8
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
9
* implied. See the MPL for the specific language governing
10
* rights and limitations under the MPL.
12
* The Original Code is protoZilla.
14
* The Initial Developer of the Original Code is Ramalingam Saravanan.
15
* Portions created by Ramalingam Saravanan <svn@xmlterm.org> are
16
* Copyright (C) 2000 Ramalingam Saravanan. All Rights Reserved.
19
* Patrick Brunschwig <patrick@mozilla-enigmail.org>
21
* Alternatively, the contents of this file may be used under the
22
* terms of the GNU General Public License (the "GPL"), in which case
23
* the provisions of the GPL are applicable instead of
24
* those above. If you wish to allow use of your version of this
25
* file only under the terms of the GPL and not to allow
26
* others to use your version of this file under the MPL, indicate
27
* your decision by deleting the provisions above and replace them
28
* with the notice and other provisions required by the GPL.
29
* If you do not delete the provisions above, a recipient
30
* may use your version of this file under either the MPL or the
34
// NOTE: nsPipeChannel is not a thread-safe class
36
// Logging of debug output
37
// The following define statement should occur before any include statements
38
#define FORCE_PR_LOG /* Allow logging even in release build */
42
#include "nsAutoLock.h"
45
#ifndef _IPC_FORCE_INTERNAL_API
46
#include "nsStringAPI.h"
51
#include "nsIProxyObjectManager.h"
52
#include "nsIThread.h"
55
#include "nsIHttpChannel.h"
57
#include "nsNetUtil.h"
59
#include "nsMimeTypes.h"
60
#include "nsIMIMEService.h"
62
#include "nsXPCOMCIDInternal.h"
64
#include "nsPipeChannel.h"
67
PRLogModuleInfo* gPipeChannelLog = NULL;
70
#define ERROR_LOG(args) PR_LOG(gPipeChannelLog,PR_LOG_ERROR,args)
71
#define WARNING_LOG(args) PR_LOG(gPipeChannelLog,PR_LOG_WARNING,args)
72
#define DEBUG_LOG(args) PR_LOG(gPipeChannelLog,PR_LOG_DEBUG,args)
75
#define NS_NET_STATUS_RECEIVING_FROM NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 6)
77
///////////////////////////////////////////////////////////////////////////////
79
nsPipeChannel::nsPipeChannel()
80
: mFinalized(PR_FALSE),
81
mRestricted(PR_FALSE),
82
mChannelState(CHANNEL_NOT_YET_OPENED),
83
mPostingData(PR_FALSE),
86
mNoMimeHeaders(PR_FALSE),
88
mBufferSegmentSize(-1),
91
mLoadFlags(LOAD_NORMAL),
93
mContentType(UNKNOWN_CONTENT_TYPE),
96
mHeaderContentType(UNKNOWN_CONTENT_TYPE),
97
mHeaderContentLength(-1),
106
if (gPipeChannelLog == nsnull) {
107
gPipeChannelLog = PR_NewLogModule("nsPipeChannel");
111
DEBUG_LOG(("nsPipeChannel:: <<<<<<<<< CTOR(%p)\n", this));
115
nsPipeChannel::~nsPipeChannel()
118
DEBUG_LOG(("nsPipeChannel:: >>>>>>>>> DTOR(%p)\n", this));
124
nsPipeChannel::Finalize(PRBool destructor)
128
DEBUG_LOG(("nsPipeChannel::Finalize:\n"));
133
mFinalized = PR_TRUE;
135
mChannelState = CHANNEL_CLOSED;
137
if (mStatus == NS_OK)
138
mStatus = NS_BINDING_ABORTED;
140
nsCOMPtr<nsIPipeChannel> self;
142
// Hold a reference to ourselves to prevent our DTOR from being called
143
// while finalizing. Automatically released upon returning.
147
if (mPipeTransport) {
148
mPipeTransport->Terminate();
151
// Release owning refs
153
mOriginalURI = nsnull;
155
mPipeTransport = nsnull;
156
mPipeRequest = nsnull;
169
// --------------------------------------------------------------------------
170
// nsISupports implementation...
171
// --------------------------------------------------------------------------
174
NS_IMPL_THREADSAFE_ISUPPORTS5(nsPipeChannel,
179
nsIPipeTransportHeaders)
181
///////////////////////////////////////////////////////////////////////////////
182
// nsIPipeChannel methods
183
///////////////////////////////////////////////////////////////////////////////
186
nsPipeChannel::Init(nsIURI* aURI,
193
const char *killString,
194
PRBool noMimeHeaders,
197
nsIPipeListener* console)
201
DEBUG_LOG(("nsPipeChannel::Init:\n"));
203
mRestricted = restricted;
207
mNoMimeHeaders = noMimeHeaders;
209
// Try to get URL from URI.
210
nsCOMPtr<nsIURL> url( do_QueryInterface( aURI, &rv ) );
213
// Try to get MIME content type from URL (i.e., from file extension)
214
// Note: We don't try to get content type from URIs which are not URLs,
215
// because we have a very loose interpretation of an URI
217
nsCOMPtr<nsIMIMEService> MIMEService (do_GetService("@mozilla.org/mime;1", &rv));
218
NS_ENSURE_SUCCESS(rv, rv);
220
nsCString contentType;
221
rv = MIMEService->GetTypeFromURI(url, contentType);
223
if (NS_SUCCEEDED(rv) && (contentType.Length() > 0)) {
224
mContentType.Assign(contentType);
228
// Create an instance of pipe transport
229
mPipeTransport = do_CreateInstance(NS_PIPETRANSPORT_CONTRACTID, &rv);
232
DEBUG_LOG(("nsPipeChannel::Init: Failed to create pipe transport instance\n"));
236
PRBool noProxy = PR_FALSE;
237
rv = mPipeTransport->Init(executable, args, argCount, env, envCount,
238
timeoutMS, killString, noProxy,
239
mergeStderr, console);
242
DEBUG_LOG(("nsPipeChannel::Init: Failed to initialize pipe transport\n"));
246
// Close process STDIN
247
rv = mPipeTransport->CloseStdin();
248
NS_ENSURE_SUCCESS(rv, rv);
250
mChannelState = CHANNEL_OPEN;
254
///////////////////////////////////////////////////////////////////////////////
255
// nsIRequest methods
256
///////////////////////////////////////////////////////////////////////////////
259
nsPipeChannel::GetName(nsACString &result)
261
DEBUG_LOG(("nsPipeChannel::GetName: \n"));
264
return NS_ERROR_FAILURE;
266
return mURI->GetSpec(result);
270
nsPipeChannel::IsPending(PRBool *result)
273
DEBUG_LOG(("nsPipeChannel::IsPending: \n"));
274
*result = (mChannelState == CHANNEL_OPEN);
279
nsPipeChannel::GetStatus(nsresult *status)
282
DEBUG_LOG(("nsPipeChannel::GetStatus: \n"));
288
nsPipeChannel::Cancel(nsresult status)
290
DEBUG_LOG(("nsPipeChannel::Cancel: \n"));
291
// Need a non-zero status code to cancel
293
return NS_ERROR_FAILURE;
295
if (mStatus == NS_OK)
299
mPipeRequest->Cancel(mStatus);
301
return Finalize(PR_FALSE);
305
nsPipeChannel::Suspend(void)
308
DEBUG_LOG(("nsPipeChannel::Suspend: \n"));
314
nsPipeChannel::Resume(void)
317
DEBUG_LOG(("nsPipeChannel::Resume: \n"));
323
nsPipeChannel::GetLoadGroup(nsILoadGroup * *aLoadGroup)
326
DEBUG_LOG(("nsPipeChannel::GetLoadGroup: \n"));
327
NS_IF_ADDREF(*aLoadGroup = mLoadGroup);
332
nsPipeChannel::SetLoadGroup(nsILoadGroup* aLoadGroup)
335
DEBUG_LOG(("nsPipeChannel::SetLoadGroup: \n"));
336
mLoadGroup = aLoadGroup;
341
nsPipeChannel::GetLoadFlags(nsLoadFlags *aLoadFlags)
344
DEBUG_LOG(("nsPipeChannel::GetLoadFlags: \n"));
345
*aLoadFlags = mLoadFlags;
350
nsPipeChannel::SetLoadFlags(nsLoadFlags aLoadFlags)
353
DEBUG_LOG(("nsPipeChannel::SetLoadFlags: \n"));
354
mLoadFlags = aLoadFlags;
358
///////////////////////////////////////////////////////////////////////////////
359
// nsIChannel methods:
360
///////////////////////////////////////////////////////////////////////////////
363
nsPipeChannel::GetOriginalURI(nsIURI* *aURI)
366
DEBUG_LOG(("nsPipeChannel::GetOriginalURI: \n"));
367
NS_IF_ADDREF(*aURI = mOriginalURI.get());
372
nsPipeChannel::SetOriginalURI(nsIURI* aURI)
375
DEBUG_LOG(("nsPipeChannel::SetOriginalURI: \n"));
377
// Change original URI only for unrestricted channels
384
nsPipeChannel::GetURI(nsIURI* *aURI)
387
DEBUG_LOG(("nsPipeChannel::GetURI: \n"));
388
NS_IF_ADDREF(*aURI = mURI.get());
393
nsPipeChannel::GetContentType(nsACString &aContentType)
395
if (mContentType.IsEmpty() || mContentType.Equals(UNKNOWN_CONTENT_TYPE)) {
396
aContentType = TEXT_PLAIN;
398
aContentType = mContentType;
401
DEBUG_LOG(("nsPipeChannel::GetContentType: content-type: %s\n", mContentType.get()));
406
nsPipeChannel::SetContentType(const nsACString &aContentType)
409
NS_ParseContentType(aContentType, mContentType, mContentCharset);
410
DEBUG_LOG(("nsPipeChannel::SetContentType: %s\n", mContentType.get()));
415
nsPipeChannel::GetContentCharset(nsACString &aContentCharset)
417
aContentCharset = mContentCharset;
418
DEBUG_LOG(("nsPipeChannel::GetContentCharset: content-type: %s\n", mContentCharset.get()));
423
nsPipeChannel::SetContentCharset(const nsACString &aContentCharset)
426
mContentCharset = aContentCharset;
427
DEBUG_LOG(("nsPipeChannel::SetContentCharset: %s\n", mContentCharset.get()));
432
nsPipeChannel::GetContentLength(PRInt32 *aContentLength)
434
DEBUG_LOG(("nsPipeChannel::GetContentLength: \n"));
435
*aContentLength = mContentLength;
440
nsPipeChannel::SetContentLength(PRInt32 aContentLength)
442
DEBUG_LOG(("nsPipeChannel::SetContentLength: %d\n", aContentLength));
443
mContentLength = aContentLength;
448
nsPipeChannel::GetOwner(nsISupports * *aOwner)
450
DEBUG_LOG(("nsPipeChannel::GetOwner: \n"));
451
NS_IF_ADDREF(*aOwner = mOwner);
456
nsPipeChannel::SetOwner(nsISupports * aOwner)
458
DEBUG_LOG(("nsPipeChannel::SetOwner: \n"));
464
nsPipeChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aNotificationCallbacks)
466
DEBUG_LOG(("nsPipeChannel::GetNotificationCallbacks: \n"));
467
NS_IF_ADDREF(*aNotificationCallbacks = mCallbacks.get());
472
nsPipeChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aNotificationCallbacks)
475
DEBUG_LOG(("nsPipeChannel::SetNotificationCallbacks: \n"));
476
mCallbacks = aNotificationCallbacks;
478
// Get a nsIProgressEventSink so that we can fire status/progress on it-
480
nsCOMPtr<nsISupports> sink;
481
nsresult rv = mCallbacks->GetInterface(NS_GET_IID(nsIProgressEventSink),
482
getter_AddRefs(sink));
483
if (NS_FAILED(rv)) return NS_OK; // don't need a progress event sink
485
// Now generate a proxied event sink
486
nsCOMPtr<nsIProxyObjectManager> proxyMgr =
487
do_GetService(NS_XPCOMPROXY_CONTRACTID, &rv);
489
NS_ENSURE_SUCCESS(rv, rv);
491
rv = proxyMgr->GetProxyForObject(NS_PROXY_TO_MAIN_THREAD, // primordial thread
492
NS_GET_IID(nsIProgressEventSink),
494
NS_PROXY_ASYNC | NS_PROXY_ALWAYS,
495
getter_AddRefs(mProgress));
496
// TODO: ignore rv value here on purpose??
504
nsPipeChannel::GetSecurityInfo(nsISupports * *aSecurityInfo)
507
DEBUG_LOG(("nsPipeChannel:GetSecurityInfo:: \n"));
508
*aSecurityInfo = nsnull;
514
nsPipeChannel::Open(nsIInputStream **result)
517
DEBUG_LOG(("nsPipeChannel::Open: \n"));
518
return mPipeTransport->OpenInputStream(0, PRUint32(-1), 0, result);
523
nsPipeChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctxt)
527
DEBUG_LOG(("nsPipeChannel::AsyncOpen:\n"));
530
nsCOMPtr<nsIProxyObjectManager> proxyMgr =
531
do_GetService(NS_XPCOMPROXY_CONTRACTID, &rv);
533
NS_ENSURE_SUCCESS(rv, rv);
535
rv = proxyMgr->GetProxyForObject(nsnull /* will that work?? */,
536
NS_GET_IID(nsIStreamListener),
538
NS_PROXY_ASYNC | NS_PROXY_ALWAYS,
539
getter_AddRefs(mListener));
540
NS_ENSURE_SUCCESS(rv, rv);
543
rv = mPipeTransport->SetHeaderProcessor(mNoMimeHeaders ? nsnull : (nsIPipeTransportHeaders*) this);
544
NS_ENSURE_SUCCESS(rv, rv);
546
return mPipeTransport->AsyncRead(this, ctxt, 0, PRUint32(-1), 0,
547
getter_AddRefs(mPipeRequest));
550
///////////////////////////////////////////////////////////////////////////////
551
// nsIRequestObserver methods
552
///////////////////////////////////////////////////////////////////////////////
555
nsPipeChannel::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext)
560
nsCOMPtr<nsIThread> myThread;
561
rv = IPC_GET_THREAD(myThread);
562
DEBUG_LOG(("nsPipeChannel::OnStartRequest: myThread=%p\n", myThread.get()));
569
DEBUG_LOG(("nsPipeChannel::OnStartRequest: AddRequest\n"));
570
rv = mLoadGroup->AddRequest(this, nsnull);
571
NS_ENSURE_SUCCESS(rv, rv);
574
return mListener->OnStartRequest(this, aContext);
576
// Posting data; ignore OnStartRequest from AyncWrite
582
nsPipeChannel::OnStopRequest(nsIRequest* aRequest, nsISupports* aContext,
588
nsCOMPtr<nsIThread> myThread;
589
rv = IPC_GET_THREAD(myThread);
590
DEBUG_LOG(("nsPipeChannel::OnStopRequest: myThread=%p\n", myThread.get()));
593
if (mChannelState == CHANNEL_CLOSED)
596
if (NS_SUCCEEDED(aStatus) && mPostingData) {
597
// Posting data; posting has been successfully completed
598
mPostingData = PR_FALSE;
604
mChannelState = CHANNEL_CLOSED;
606
// Error status or not posting data; stop request
607
if (mLoadGroup && !mPostingData) {
609
DEBUG_LOG(("nsPipeChannel::OnStopRequest: RemoveRequest\n"));
610
rv = mLoadGroup->RemoveRequest(this, nsnull, aStatus);
611
NS_ENSURE_SUCCESS(rv, rv);
614
rv = mListener->OnStopRequest(this, aContext, aStatus);
616
if (mProgress && !(mLoadFlags & LOAD_BACKGROUND)) {
617
nsAutoString statusStr;
618
statusStr.Assign(NS_LITERAL_STRING(""));
620
nsCAutoString urlSpec;
621
rv = mURI->GetSpec(urlSpec);
622
if (NS_SUCCEEDED(rv))
623
statusStr.Assign(NS_ConvertUTF8toUTF16(urlSpec));
626
rv = mProgress->OnStatus(this, mContext,
627
NS_NET_STATUS_RECEIVING_FROM,
629
NS_ASSERTION(NS_SUCCEEDED(rv), "unexpected OnStopRequest failure");
632
// Release owning references to PipeTransport, PipeRequest, Listener,
634
// (Use Finalize instead?)
635
mPipeTransport = nsnull;
636
mPipeRequest = nsnull;
643
///////////////////////////////////////////////////////////////////////////////
644
// nsIStreamListener method
645
///////////////////////////////////////////////////////////////////////////////
648
nsPipeChannel::OnDataAvailable(nsIRequest* aRequest, nsISupports* aContext,
649
nsIInputStream *aInputStream,
650
PRUint32 aSourceOffset,
655
if (mChannelState != CHANNEL_OPEN)
656
return NS_ERROR_FAILURE;
659
nsCOMPtr<nsIThread> myThread;
660
rv = IPC_GET_THREAD(myThread);
661
DEBUG_LOG(("nsPipeChannel::OnDataAvailable: myThread=%p, offset=%d, length=%d\n",
662
myThread.get(), aSourceOffset, aLength));
665
mContentReceived += aLength;
667
if (mProgress && !(mLoadFlags & LOAD_BACKGROUND)) {
668
PRUint32 contentMax = (mContentLength >= 0) ? mContentLength : 0;
669
rv = mProgress->OnProgress(this, aContext,
670
mContentReceived, contentMax);
671
NS_ASSERTION(NS_SUCCEEDED(rv), "unexpected OnProgress failure");
674
rv = mListener->OnDataAvailable(this, aContext, aInputStream,
675
aSourceOffset, aLength);
680
///////////////////////////////////////////////////////////////////////////////
681
// nsIPipeTransportHeaders methods:
682
///////////////////////////////////////////////////////////////////////////////
685
nsPipeChannel::ParseMimeHeaders(const char* mimeHeaders, PRUint32 count,
690
DEBUG_LOG(("nsPipeChannel::ParseMimeHeaders, count=%d\n", count));
691
if (!mimeHeaders || !retval)
692
return NS_ERROR_NULL_POINTER;
694
// Create headers string
695
nsCAutoString headers(mimeHeaders, count);
697
PRBool foundStatusLine = PR_FALSE;
698
if ((headers.Length() >= 5)
699
&& (PL_strncmp(headers.get(), "HTTP/", 5) == 0)) {
700
// Look for possible HTTP header line preceding MIME headers
702
PRInt32 lineEnd = headers.Find("\n");
705
// Strip HTTP header line
706
headers.Cut(0, lineEnd+1);
707
foundStatusLine = PR_TRUE;
711
// Replace CRLF with just LF
712
PRInt32 lineIndex = 0;
714
while (lineIndex != -1) {
715
lineIndex = headers.Find("\r\n");
716
if (lineIndex != -1) {
717
headers.Replace(lineIndex, 2, "\n", 1);
721
if (headers.Length() < 2)
722
return NS_ERROR_FAILURE;
724
PRBool noHeaders = PR_FALSE;
725
if (headers.CharAt(0) == '\n') {
726
// First line is empty; no headers
729
} else if ( (headers.CharAt(headers.Length()-2) != '\n') ||
730
(headers.CharAt(headers.Length()-1) != '\n') ) {
731
// No empty line terminating header
735
// Eliminate all leading whitespace (including linefeeds)
736
headers.Trim(" \t\n", PR_TRUE, PR_FALSE);
738
if (mContentType.Equals(UNKNOWN_CONTENT_TYPE)) {
739
// Use some heuristics to guess type of unknown content even before
740
// trying to parse the headers
742
if (headers.CharAt(0) == '<') {
744
if (headers.Find("<html>", PR_TRUE) == 0) {
745
// Set content type to text/html
746
mContentType = TEXT_HTML;
748
// TO BE IMPLEMENTED: Look for doctype, xml, ...
752
if (mContentType.Equals(UNKNOWN_CONTENT_TYPE)) {
753
// Still unknown content type; check if headers are all printable ASCII
754
PRBool printableAscii = PR_TRUE;
756
for (PRUint32 j=0; j<count; j++) {
757
char ch = (char) mimeHeaders[j];
759
((ch > '\r') && (ch < ' ')) ||
761
printableAscii = PR_FALSE;
766
if (printableAscii) {
767
// Treat unknown content as plain text by default
768
mContentType = TEXT_PLAIN;
770
// Treat unknown content as octet stream by default
771
mContentType = APPLICATION_OCTET_STREAM;
776
return NS_ERROR_FAILURE;
778
// Handle continuation of MIME headers, i.e., newline followed by a space
781
while (lineIndex != -1) {
782
lineIndex = headers.Find("\n");
783
if (lineIndex != -1) {
784
headers.Replace(lineIndex, 1, " ", 1);
788
// Default values for header content type/length (to be overridden by header)
789
mHeaderContentType = UNKNOWN_CONTENT_TYPE;
790
mHeaderContentLength = mContentLength;
794
while (offset < headers.Length()) {
795
PRInt32 lineEnd = headers.Find("\n", offset);
798
// Header line terminator not found
799
NS_NOTREACHED("lineEnd == kNotFound");
800
return NS_ERROR_FAILURE;
803
// Normal exit if empty header line
804
if (lineEnd == (int)offset)
808
rv = ParseHeader((headers.get())+offset, lineEnd - offset);
809
NS_ENSURE_SUCCESS(rv, rv);
814
// If content type not found, assume header not found
815
if (mHeaderContentType.Equals(UNKNOWN_CONTENT_TYPE))
816
return NS_ERROR_FAILURE;
818
// Copy back content type/length after successful parsing of headers
819
mContentType = mHeaderContentType;
820
mContentLength = mHeaderContentLength;
823
DEBUG_LOG(("nsPipeChannel::ParseMimeHeaders END: cType=%s, clen=%d\n",
824
mContentType.get(), mContentLength));
829
nsPipeChannel::ParseHeader(const char* header, PRUint32 count)
832
DEBUG_LOG(("nsPipeChannel::ParseHeader, count=%d\n", count));
834
if (!header || (count <= 0) )
837
// Create header string
838
nsCAutoString headerStr(header, count);
841
colonOffset = headerStr.Find(":");
842
if (colonOffset == -1) {
843
// Malformed headerStr ... simulate NS4.x/IE behaviour trying SPC/TAB as delimiters
845
colonOffset = headerStr.Find(" ");
846
if (colonOffset == -1) {
848
colonOffset = headerStr.Find("\t");
849
if (colonOffset == -1) {
850
return NS_ERROR_FAILURE;
855
// Null header key not allowed
856
if (colonOffset == 0)
857
return NS_ERROR_FAILURE;
859
// Extract header key (not case-sensitive)
860
nsCAutoString headerKey;
861
// headerStr.Left(headerKey, colonOffset);
862
headerStr = Substring(headerStr, 0, colonOffset);
864
ToLowerCase(headerKey);
866
// Extract header value, trimming leading/trailing whitespace
867
nsCAutoString headerValue;
868
// headerStr.Right(headerValue, headerStr.Length() - colonOffset - 1);
869
headerValue = Substring(headerStr, colonOffset + 1, headerStr.Length());
870
headerValue.Trim(" ");
873
DEBUG_LOG(("nsPipeChannel::ParseHeader, key='%s', value='%s'\n",
874
headerKey.get(), headerValue.get()));
876
if (headerKey.Equals("content-type")) {
878
PRInt32 parenOffset = headerValue.Find("(");
879
if (parenOffset > -1) {
880
// headerValue.Truncate(parenOffset);
881
headerValue = Substring(headerValue, 0, parenOffset);
882
headerValue.Trim(" ", PR_FALSE);
885
if (!headerValue.IsEmpty()) {
886
PRInt32 semicolonOffset = headerValue.Find(";");
887
if (semicolonOffset == -1) {
889
mHeaderContentType = headerValue.get();
893
// headerValue.Left(buf, semicolonOffset);
894
// mHeaderContentType = buf.get();
896
mHeaderContentType = Substring(headerValue, semicolonOffset);
899
// headerValue.Right(buf, headerValue.Length() - semicolonOffset - 1);
900
buf = Substring(headerValue, semicolonOffset + 1, headerValue.Length());
902
if (buf.Find("charset=", PR_TRUE) == 0) {
905
mHeaderCharset = buf.get();
911
if (headerKey.Equals("content-length")) {
912
#if _IPC_FORCE_INTERNAL_API
917
mHeaderContentLength = headerValue.ToInteger(&status);
918
if (NS_FAILED((nsresult) status))
919
return NS_ERROR_FAILURE;