Source code

Revision control

Other Tools

1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set sw=2 sts=2 ts=8 et tw=80 : */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
* License, v. 2.0. If a copy of the MPL was not distributed with this
5
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "nsBaseChannel.h"
8
#include "nsContentUtils.h"
9
#include "nsURLHelper.h"
10
#include "nsNetCID.h"
11
#include "nsMimeTypes.h"
12
#include "nsUnknownDecoder.h"
13
#include "nsIScriptSecurityManager.h"
14
#include "nsMimeTypes.h"
15
#include "nsIHttpChannel.h"
16
#include "nsIChannelEventSink.h"
17
#include "nsIStreamConverterService.h"
18
#include "nsChannelClassifier.h"
19
#include "nsAsyncRedirectVerifyHelper.h"
20
#include "nsProxyRelease.h"
21
#include "nsXULAppAPI.h"
22
#include "nsContentSecurityManager.h"
23
#include "LoadInfo.h"
24
#include "nsServiceManagerUtils.h"
25
#include "nsRedirectHistoryEntry.h"
26
27
using namespace mozilla;
28
29
// This class is used to suspend a request across a function scope.
30
class ScopedRequestSuspender {
31
public:
32
explicit ScopedRequestSuspender(nsIRequest* request) : mRequest(request) {
33
if (mRequest && NS_FAILED(mRequest->Suspend())) {
34
NS_WARNING("Couldn't suspend pump");
35
mRequest = nullptr;
36
}
37
}
38
~ScopedRequestSuspender() {
39
if (mRequest) mRequest->Resume();
40
}
41
42
private:
43
nsIRequest* mRequest;
44
};
45
46
// Used to suspend data events from mRequest within a function scope. This is
47
// usually needed when a function makes callbacks that could process events.
48
#define SUSPEND_PUMP_FOR_SCOPE() \
49
ScopedRequestSuspender pump_suspender__(mRequest)
50
51
//-----------------------------------------------------------------------------
52
// nsBaseChannel
53
54
nsBaseChannel::nsBaseChannel()
55
: NeckoTargetHolder(nullptr),
56
mPumpingData(false),
57
mLoadFlags(LOAD_NORMAL),
58
mQueriedProgressSink(true),
59
mSynthProgressEvents(false),
60
mAllowThreadRetargeting(true),
61
mWaitingOnAsyncRedirect(false),
62
mOpenRedirectChannel(false),
63
mRedirectFlags{0},
64
mStatus(NS_OK),
65
mContentDispositionHint(UINT32_MAX),
66
mContentLength(-1),
67
mWasOpened(false) {
68
mContentType.AssignLiteral(UNKNOWN_CONTENT_TYPE);
69
}
70
71
nsBaseChannel::~nsBaseChannel() {
72
NS_ReleaseOnMainThreadSystemGroup("nsBaseChannel::mLoadInfo",
73
mLoadInfo.forget());
74
}
75
76
nsresult nsBaseChannel::Redirect(nsIChannel* newChannel, uint32_t redirectFlags,
77
bool openNewChannel) {
78
SUSPEND_PUMP_FOR_SCOPE();
79
80
// Transfer properties
81
82
newChannel->SetLoadGroup(mLoadGroup);
83
newChannel->SetNotificationCallbacks(mCallbacks);
84
newChannel->SetLoadFlags(mLoadFlags | LOAD_REPLACE);
85
86
// make a copy of the loadinfo, append to the redirectchain
87
// and set it on the new channel
88
nsSecurityFlags secFlags =
89
mLoadInfo->GetSecurityFlags() & ~nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL;
90
nsCOMPtr<nsILoadInfo> newLoadInfo =
91
static_cast<net::LoadInfo*>(mLoadInfo.get())
92
->CloneWithNewSecFlags(secFlags);
93
94
nsCOMPtr<nsIPrincipal> uriPrincipal;
95
nsIScriptSecurityManager* sm = nsContentUtils::GetSecurityManager();
96
sm->GetChannelURIPrincipal(this, getter_AddRefs(uriPrincipal));
97
bool isInternalRedirect =
98
(redirectFlags & (nsIChannelEventSink::REDIRECT_INTERNAL |
99
nsIChannelEventSink::REDIRECT_STS_UPGRADE));
100
101
// nsBaseChannel hst no thing to do with HttpBaseChannel, we would not care
102
// about referrer and remote address in this case
103
nsCOMPtr<nsIRedirectHistoryEntry> entry =
104
new net::nsRedirectHistoryEntry(uriPrincipal, nullptr, EmptyCString());
105
106
newLoadInfo->AppendRedirectHistoryEntry(entry, isInternalRedirect);
107
108
// Ensure the channel's loadInfo's result principal URI so that it's
109
// either non-null or updated to the redirect target URI.
110
// We must do this because in case the loadInfo's result principal URI
111
// is null, it would be taken from OriginalURI of the channel. But we
112
// overwrite it with the whole redirect chain first URI before opening
113
// the target channel, hence the information would be lost.
114
// If the protocol handler that created the channel wants to use
115
// the originalURI of the channel as the principal URI, it has left
116
// the result principal URI on the load info null.
117
nsCOMPtr<nsIURI> resultPrincipalURI;
118
119
nsCOMPtr<nsILoadInfo> existingLoadInfo = newChannel->LoadInfo();
120
if (existingLoadInfo) {
121
existingLoadInfo->GetResultPrincipalURI(getter_AddRefs(resultPrincipalURI));
122
}
123
if (!resultPrincipalURI) {
124
newChannel->GetOriginalURI(getter_AddRefs(resultPrincipalURI));
125
}
126
127
newLoadInfo->SetResultPrincipalURI(resultPrincipalURI);
128
129
newChannel->SetLoadInfo(newLoadInfo);
130
131
// Preserve the privacy bit if it has been overridden
132
if (mPrivateBrowsingOverriden) {
133
nsCOMPtr<nsIPrivateBrowsingChannel> newPBChannel =
134
do_QueryInterface(newChannel);
135
if (newPBChannel) {
136
newPBChannel->SetPrivate(mPrivateBrowsing);
137
}
138
}
139
140
nsCOMPtr<nsIWritablePropertyBag> bag = ::do_QueryInterface(newChannel);
141
if (bag) {
142
for (auto iter = mPropertyHash.Iter(); !iter.Done(); iter.Next()) {
143
bag->SetProperty(iter.Key(), iter.UserData());
144
}
145
}
146
147
// Notify consumer, giving chance to cancel redirect.
148
149
auto redirectCallbackHelper = MakeRefPtr<net::nsAsyncRedirectVerifyHelper>();
150
151
bool checkRedirectSynchronously = !openNewChannel;
152
nsCOMPtr<nsIEventTarget> target = GetNeckoTarget();
153
154
mRedirectChannel = newChannel;
155
mRedirectFlags = redirectFlags;
156
mOpenRedirectChannel = openNewChannel;
157
nsresult rv = redirectCallbackHelper->Init(
158
this, newChannel, redirectFlags, target, checkRedirectSynchronously);
159
if (NS_FAILED(rv)) return rv;
160
161
if (checkRedirectSynchronously && NS_FAILED(mStatus)) return mStatus;
162
163
return NS_OK;
164
}
165
166
nsresult nsBaseChannel::ContinueRedirect() {
167
// Make sure to do this _after_ making all the OnChannelRedirect calls
168
mRedirectChannel->SetOriginalURI(OriginalURI());
169
170
// If we fail to open the new channel, then we want to leave this channel
171
// unaffected, so we defer tearing down our channel until we have succeeded
172
// with the redirect.
173
174
if (mOpenRedirectChannel) {
175
nsresult rv = NS_OK;
176
rv = mRedirectChannel->AsyncOpen(mListener);
177
NS_ENSURE_SUCCESS(rv, rv);
178
}
179
180
mRedirectChannel = nullptr;
181
182
// close down this channel
183
Cancel(NS_BINDING_REDIRECTED);
184
ChannelDone();
185
186
return NS_OK;
187
}
188
189
bool nsBaseChannel::HasContentTypeHint() const {
190
NS_ASSERTION(!Pending(), "HasContentTypeHint called too late");
191
return !mContentType.EqualsLiteral(UNKNOWN_CONTENT_TYPE);
192
}
193
194
nsresult nsBaseChannel::PushStreamConverter(const char* fromType,
195
const char* toType,
196
bool invalidatesContentLength,
197
nsIStreamListener** result) {
198
NS_ASSERTION(mListener, "no listener");
199
200
nsresult rv;
201
nsCOMPtr<nsIStreamConverterService> scs =
202
do_GetService(NS_STREAMCONVERTERSERVICE_CONTRACTID, &rv);
203
if (NS_FAILED(rv)) return rv;
204
205
nsCOMPtr<nsIStreamListener> converter;
206
rv = scs->AsyncConvertData(fromType, toType, mListener, nullptr,
207
getter_AddRefs(converter));
208
if (NS_SUCCEEDED(rv)) {
209
mListener = converter;
210
if (invalidatesContentLength) mContentLength = -1;
211
if (result) {
212
*result = nullptr;
213
converter.swap(*result);
214
}
215
}
216
return rv;
217
}
218
219
nsresult nsBaseChannel::BeginPumpingData() {
220
nsresult rv;
221
222
rv = BeginAsyncRead(this, getter_AddRefs(mRequest));
223
if (NS_SUCCEEDED(rv)) {
224
mPumpingData = true;
225
return NS_OK;
226
}
227
if (rv != NS_ERROR_NOT_IMPLEMENTED) {
228
return rv;
229
}
230
231
nsCOMPtr<nsIInputStream> stream;
232
nsCOMPtr<nsIChannel> channel;
233
rv = OpenContentStream(true, getter_AddRefs(stream), getter_AddRefs(channel));
234
if (NS_FAILED(rv)) return rv;
235
236
NS_ASSERTION(!stream || !channel, "Got both a channel and a stream?");
237
238
if (channel) {
239
nsCOMPtr<nsIRunnable> runnable = new RedirectRunnable(this, channel);
240
rv = Dispatch(runnable.forget());
241
if (NS_SUCCEEDED(rv)) mWaitingOnAsyncRedirect = true;
242
return rv;
243
}
244
245
// By assigning mPump, we flag this channel as pending (see Pending). It's
246
// important that the pending flag is set when we call into the stream (the
247
// call to AsyncRead results in the stream's AsyncWait method being called)
248
// and especially when we call into the loadgroup. Our caller takes care to
249
// release mPump if we return an error.
250
251
nsCOMPtr<nsIEventTarget> target = GetNeckoTarget();
252
rv = nsInputStreamPump::Create(getter_AddRefs(mPump), stream, 0, 0, true,
253
target);
254
if (NS_FAILED(rv)) {
255
return rv;
256
}
257
258
mPumpingData = true;
259
mRequest = mPump;
260
rv = mPump->AsyncRead(this, nullptr);
261
if (NS_FAILED(rv)) {
262
return rv;
263
}
264
265
RefPtr<BlockingPromise> promise;
266
rv = ListenerBlockingPromise(getter_AddRefs(promise));
267
if (NS_FAILED(rv)) {
268
return rv;
269
}
270
271
if (promise) {
272
mPump->Suspend();
273
274
RefPtr<nsBaseChannel> self(this);
275
nsCOMPtr<nsISerialEventTarget> serialTarget(do_QueryInterface(target));
276
MOZ_ASSERT(serialTarget);
277
278
promise->Then(
279
serialTarget, __func__,
280
[self, this](nsresult rv) {
281
MOZ_ASSERT(mPump);
282
MOZ_ASSERT(NS_SUCCEEDED(rv));
283
mPump->Resume();
284
},
285
[self, this](nsresult rv) {
286
MOZ_ASSERT(mPump);
287
MOZ_ASSERT(NS_FAILED(rv));
288
Cancel(rv);
289
mPump->Resume();
290
});
291
}
292
293
return NS_OK;
294
}
295
296
void nsBaseChannel::HandleAsyncRedirect(nsIChannel* newChannel) {
297
NS_ASSERTION(!mPumpingData, "Shouldn't have gotten here");
298
299
nsresult rv = mStatus;
300
if (NS_SUCCEEDED(mStatus)) {
301
rv = Redirect(newChannel, nsIChannelEventSink::REDIRECT_TEMPORARY, true);
302
if (NS_SUCCEEDED(rv)) {
303
// OnRedirectVerifyCallback will be called asynchronously
304
return;
305
}
306
}
307
308
ContinueHandleAsyncRedirect(rv);
309
}
310
311
void nsBaseChannel::ContinueHandleAsyncRedirect(nsresult result) {
312
mWaitingOnAsyncRedirect = false;
313
314
if (NS_FAILED(result)) Cancel(result);
315
316
if (NS_FAILED(result) && mListener) {
317
// Notify our consumer ourselves
318
mListener->OnStartRequest(this);
319
mListener->OnStopRequest(this, mStatus);
320
ChannelDone();
321
}
322
323
if (mLoadGroup) mLoadGroup->RemoveRequest(this, nullptr, mStatus);
324
325
// Drop notification callbacks to prevent cycles.
326
mCallbacks = nullptr;
327
CallbacksChanged();
328
}
329
330
void nsBaseChannel::ClassifyURI() {
331
// For channels created in the child process, delegate to the parent to
332
// classify URIs.
333
if (!XRE_IsParentProcess()) {
334
return;
335
}
336
337
if (NS_ShouldClassifyChannel(this)) {
338
auto classifier = MakeRefPtr<net::nsChannelClassifier>(this);
339
if (classifier) {
340
classifier->Start();
341
} else {
342
Cancel(NS_ERROR_OUT_OF_MEMORY);
343
}
344
}
345
}
346
347
//-----------------------------------------------------------------------------
348
// nsBaseChannel::nsISupports
349
350
NS_IMPL_ADDREF(nsBaseChannel)
351
NS_IMPL_RELEASE(nsBaseChannel)
352
353
NS_INTERFACE_MAP_BEGIN(nsBaseChannel)
354
NS_INTERFACE_MAP_ENTRY(nsIRequest)
355
NS_INTERFACE_MAP_ENTRY(nsIChannel)
356
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIIdentChannel, mChannelId.isSome())
357
NS_INTERFACE_MAP_ENTRY(nsIThreadRetargetableRequest)
358
NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
359
NS_INTERFACE_MAP_ENTRY(nsITransportEventSink)
360
NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
361
NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
362
NS_INTERFACE_MAP_ENTRY(nsIThreadRetargetableStreamListener)
363
NS_INTERFACE_MAP_ENTRY(nsIAsyncVerifyRedirectCallback)
364
NS_INTERFACE_MAP_ENTRY(nsIPrivateBrowsingChannel)
365
NS_INTERFACE_MAP_END_INHERITING(nsHashPropertyBag)
366
367
//-----------------------------------------------------------------------------
368
// nsBaseChannel::nsIRequest
369
370
NS_IMETHODIMP
371
nsBaseChannel::GetName(nsACString& result) {
372
if (!mURI) {
373
result.Truncate();
374
return NS_OK;
375
}
376
return mURI->GetSpec(result);
377
}
378
379
NS_IMETHODIMP
380
nsBaseChannel::IsPending(bool* result) {
381
*result = Pending();
382
return NS_OK;
383
}
384
385
NS_IMETHODIMP
386
nsBaseChannel::GetStatus(nsresult* status) {
387
if (mRequest && NS_SUCCEEDED(mStatus)) {
388
mRequest->GetStatus(status);
389
} else {
390
*status = mStatus;
391
}
392
return NS_OK;
393
}
394
395
NS_IMETHODIMP
396
nsBaseChannel::Cancel(nsresult status) {
397
// Ignore redundant cancelation
398
if (NS_FAILED(mStatus)) return NS_OK;
399
400
mStatus = status;
401
402
if (mRequest) mRequest->Cancel(status);
403
404
return NS_OK;
405
}
406
407
NS_IMETHODIMP
408
nsBaseChannel::Suspend() {
409
NS_ENSURE_TRUE(mPumpingData, NS_ERROR_NOT_INITIALIZED);
410
NS_ENSURE_TRUE(mRequest, NS_ERROR_NOT_IMPLEMENTED);
411
return mRequest->Suspend();
412
}
413
414
NS_IMETHODIMP
415
nsBaseChannel::Resume() {
416
NS_ENSURE_TRUE(mPumpingData, NS_ERROR_NOT_INITIALIZED);
417
NS_ENSURE_TRUE(mRequest, NS_ERROR_NOT_IMPLEMENTED);
418
return mRequest->Resume();
419
}
420
421
NS_IMETHODIMP
422
nsBaseChannel::GetLoadFlags(nsLoadFlags* aLoadFlags) {
423
*aLoadFlags = mLoadFlags;
424
return NS_OK;
425
}
426
427
NS_IMETHODIMP
428
nsBaseChannel::SetLoadFlags(nsLoadFlags aLoadFlags) {
429
mLoadFlags = aLoadFlags;
430
return NS_OK;
431
}
432
433
NS_IMETHODIMP
434
nsBaseChannel::GetLoadGroup(nsILoadGroup** aLoadGroup) {
435
NS_IF_ADDREF(*aLoadGroup = mLoadGroup);
436
return NS_OK;
437
}
438
439
NS_IMETHODIMP
440
nsBaseChannel::SetLoadGroup(nsILoadGroup* aLoadGroup) {
441
if (!CanSetLoadGroup(aLoadGroup)) {
442
return NS_ERROR_FAILURE;
443
}
444
445
mLoadGroup = aLoadGroup;
446
CallbacksChanged();
447
UpdatePrivateBrowsing();
448
return NS_OK;
449
}
450
451
//-----------------------------------------------------------------------------
452
// nsBaseChannel::nsIChannel
453
454
NS_IMETHODIMP
455
nsBaseChannel::GetOriginalURI(nsIURI** aURI) {
456
*aURI = OriginalURI();
457
NS_ADDREF(*aURI);
458
return NS_OK;
459
}
460
461
NS_IMETHODIMP
462
nsBaseChannel::SetOriginalURI(nsIURI* aURI) {
463
NS_ENSURE_ARG_POINTER(aURI);
464
mOriginalURI = aURI;
465
return NS_OK;
466
}
467
468
NS_IMETHODIMP
469
nsBaseChannel::GetURI(nsIURI** aURI) {
470
NS_IF_ADDREF(*aURI = mURI);
471
return NS_OK;
472
}
473
474
NS_IMETHODIMP
475
nsBaseChannel::GetOwner(nsISupports** aOwner) {
476
NS_IF_ADDREF(*aOwner = mOwner);
477
return NS_OK;
478
}
479
480
NS_IMETHODIMP
481
nsBaseChannel::SetOwner(nsISupports* aOwner) {
482
mOwner = aOwner;
483
return NS_OK;
484
}
485
486
NS_IMETHODIMP
487
nsBaseChannel::SetLoadInfo(nsILoadInfo* aLoadInfo) {
488
MOZ_RELEASE_ASSERT(aLoadInfo, "loadinfo can't be null");
489
mLoadInfo = aLoadInfo;
490
491
// Need to update |mNeckoTarget| when load info has changed.
492
SetupNeckoTarget();
493
return NS_OK;
494
}
495
496
NS_IMETHODIMP
497
nsBaseChannel::GetLoadInfo(nsILoadInfo** aLoadInfo) {
498
NS_IF_ADDREF(*aLoadInfo = mLoadInfo);
499
return NS_OK;
500
}
501
502
NS_IMETHODIMP
503
nsBaseChannel::GetIsDocument(bool* aIsDocument) {
504
return NS_GetIsDocumentChannel(this, aIsDocument);
505
}
506
507
NS_IMETHODIMP
508
nsBaseChannel::GetNotificationCallbacks(nsIInterfaceRequestor** aCallbacks) {
509
NS_IF_ADDREF(*aCallbacks = mCallbacks);
510
return NS_OK;
511
}
512
513
NS_IMETHODIMP
514
nsBaseChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aCallbacks) {
515
if (!CanSetCallbacks(aCallbacks)) {
516
return NS_ERROR_FAILURE;
517
}
518
519
mCallbacks = aCallbacks;
520
CallbacksChanged();
521
UpdatePrivateBrowsing();
522
return NS_OK;
523
}
524
525
NS_IMETHODIMP
526
nsBaseChannel::GetSecurityInfo(nsISupports** aSecurityInfo) {
527
NS_IF_ADDREF(*aSecurityInfo = mSecurityInfo);
528
return NS_OK;
529
}
530
531
NS_IMETHODIMP
532
nsBaseChannel::GetContentType(nsACString& aContentType) {
533
aContentType = mContentType;
534
return NS_OK;
535
}
536
537
NS_IMETHODIMP
538
nsBaseChannel::SetContentType(const nsACString& aContentType) {
539
// mContentCharset is unchanged if not parsed
540
bool dummy;
541
net_ParseContentType(aContentType, mContentType, mContentCharset, &dummy);
542
return NS_OK;
543
}
544
545
NS_IMETHODIMP
546
nsBaseChannel::GetContentCharset(nsACString& aContentCharset) {
547
aContentCharset = mContentCharset;
548
return NS_OK;
549
}
550
551
NS_IMETHODIMP
552
nsBaseChannel::SetContentCharset(const nsACString& aContentCharset) {
553
mContentCharset = aContentCharset;
554
return NS_OK;
555
}
556
557
NS_IMETHODIMP
558
nsBaseChannel::GetContentDisposition(uint32_t* aContentDisposition) {
559
// preserve old behavior, fail unless explicitly set.
560
if (mContentDispositionHint == UINT32_MAX) {
561
return NS_ERROR_NOT_AVAILABLE;
562
}
563
564
*aContentDisposition = mContentDispositionHint;
565
return NS_OK;
566
}
567
568
NS_IMETHODIMP
569
nsBaseChannel::SetContentDisposition(uint32_t aContentDisposition) {
570
mContentDispositionHint = aContentDisposition;
571
return NS_OK;
572
}
573
574
NS_IMETHODIMP
575
nsBaseChannel::GetContentDispositionFilename(
576
nsAString& aContentDispositionFilename) {
577
if (!mContentDispositionFilename) {
578
return NS_ERROR_NOT_AVAILABLE;
579
}
580
581
aContentDispositionFilename = *mContentDispositionFilename;
582
return NS_OK;
583
}
584
585
NS_IMETHODIMP
586
nsBaseChannel::SetContentDispositionFilename(
587
const nsAString& aContentDispositionFilename) {
588
mContentDispositionFilename = new nsString(aContentDispositionFilename);
589
return NS_OK;
590
}
591
592
NS_IMETHODIMP
593
nsBaseChannel::GetContentDispositionHeader(
594
nsACString& aContentDispositionHeader) {
595
return NS_ERROR_NOT_AVAILABLE;
596
}
597
598
NS_IMETHODIMP
599
nsBaseChannel::GetContentLength(int64_t* aContentLength) {
600
*aContentLength = mContentLength;
601
return NS_OK;
602
}
603
604
NS_IMETHODIMP
605
nsBaseChannel::SetContentLength(int64_t aContentLength) {
606
mContentLength = aContentLength;
607
return NS_OK;
608
}
609
610
NS_IMETHODIMP
611
nsBaseChannel::Open(nsIInputStream** aStream) {
612
nsCOMPtr<nsIStreamListener> listener;
613
nsresult rv =
614
nsContentSecurityManager::doContentSecurityCheck(this, listener);
615
NS_ENSURE_SUCCESS(rv, rv);
616
617
NS_ENSURE_TRUE(mURI, NS_ERROR_NOT_INITIALIZED);
618
NS_ENSURE_TRUE(!mPumpingData, NS_ERROR_IN_PROGRESS);
619
NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_IN_PROGRESS);
620
621
nsCOMPtr<nsIChannel> chan;
622
rv = OpenContentStream(false, aStream, getter_AddRefs(chan));
623
NS_ASSERTION(!chan || !*aStream, "Got both a channel and a stream?");
624
if (NS_SUCCEEDED(rv) && chan) {
625
rv = Redirect(chan, nsIChannelEventSink::REDIRECT_INTERNAL, false);
626
if (NS_FAILED(rv)) return rv;
627
rv = chan->Open(aStream);
628
} else if (rv == NS_ERROR_NOT_IMPLEMENTED)
629
return NS_ImplementChannelOpen(this, aStream);
630
631
if (NS_SUCCEEDED(rv)) {
632
mWasOpened = true;
633
ClassifyURI();
634
}
635
636
return rv;
637
}
638
639
NS_IMETHODIMP
640
nsBaseChannel::AsyncOpen(nsIStreamListener* aListener) {
641
nsCOMPtr<nsIStreamListener> listener = aListener;
642
643
nsresult rv =
644
nsContentSecurityManager::doContentSecurityCheck(this, listener);
645
if (NS_FAILED(rv)) {
646
mCallbacks = nullptr;
647
return rv;
648
}
649
650
MOZ_ASSERT(
651
!mLoadInfo || mLoadInfo->GetSecurityMode() == 0 ||
652
mLoadInfo->GetInitialSecurityCheckDone() ||
653
(mLoadInfo->GetSecurityMode() ==
654
nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL &&
655
nsContentUtils::IsSystemPrincipal(mLoadInfo->LoadingPrincipal())),
656
"security flags in loadInfo but doContentSecurityCheck() not called");
657
658
NS_ENSURE_TRUE(mURI, NS_ERROR_NOT_INITIALIZED);
659
NS_ENSURE_TRUE(!mPumpingData, NS_ERROR_IN_PROGRESS);
660
NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
661
NS_ENSURE_ARG(listener);
662
663
SetupNeckoTarget();
664
665
// Skip checking for chrome:// sub-resources.
666
nsAutoCString scheme;
667
mURI->GetScheme(scheme);
668
if (!scheme.EqualsLiteral("file")) {
669
NS_CompareLoadInfoAndLoadContext(this);
670
}
671
672
// Ensure that this is an allowed port before proceeding.
673
rv = NS_CheckPortSafety(mURI);
674
if (NS_FAILED(rv)) {
675
mCallbacks = nullptr;
676
return rv;
677
}
678
679
// Store the listener and context early so that OpenContentStream and the
680
// stream's AsyncWait method (called by AsyncRead) can have access to them
681
// via PushStreamConverter and the StreamListener methods. However, since
682
// this typically introduces a reference cycle between this and the listener,
683
// we need to be sure to break the reference if this method does not succeed.
684
mListener = listener;
685
686
// This method assigns mPump as a side-effect. We need to clear mPump if
687
// this method fails.
688
rv = BeginPumpingData();
689
if (NS_FAILED(rv)) {
690
mPump = nullptr;
691
mRequest = nullptr;
692
mPumpingData = false;
693
ChannelDone();
694
mCallbacks = nullptr;
695
return rv;
696
}
697
698
// At this point, we are going to return success no matter what.
699
700
mWasOpened = true;
701
702
SUSPEND_PUMP_FOR_SCOPE();
703
704
if (mLoadGroup) mLoadGroup->AddRequest(this, nullptr);
705
706
ClassifyURI();
707
708
return NS_OK;
709
}
710
711
//-----------------------------------------------------------------------------
712
// nsBaseChannel::nsIIdentChannel
713
714
NS_IMETHODIMP
715
nsBaseChannel::GetChannelId(uint64_t* aChannelId) {
716
if (!mChannelId) {
717
return NS_ERROR_NOT_IMPLEMENTED;
718
}
719
*aChannelId = *mChannelId;
720
return NS_OK;
721
}
722
723
NS_IMETHODIMP
724
nsBaseChannel::SetChannelId(uint64_t aChannelId) {
725
if (!mChannelId) {
726
return NS_ERROR_NOT_IMPLEMENTED;
727
}
728
*mChannelId = aChannelId;
729
return NS_OK;
730
}
731
732
//-----------------------------------------------------------------------------
733
// nsBaseChannel::nsITransportEventSink
734
735
NS_IMETHODIMP
736
nsBaseChannel::OnTransportStatus(nsITransport* transport, nsresult status,
737
int64_t progress, int64_t progressMax) {
738
// In some cases, we may wish to suppress transport-layer status events.
739
740
if (!mPumpingData || NS_FAILED(mStatus)) {
741
return NS_OK;
742
}
743
744
SUSPEND_PUMP_FOR_SCOPE();
745
746
// Lazily fetch mProgressSink
747
if (!mProgressSink) {
748
if (mQueriedProgressSink) {
749
return NS_OK;
750
}
751
GetCallback(mProgressSink);
752
mQueriedProgressSink = true;
753
if (!mProgressSink) {
754
return NS_OK;
755
}
756
}
757
758
if (!HasLoadFlag(LOAD_BACKGROUND)) {
759
nsAutoString statusArg;
760
if (GetStatusArg(status, statusArg)) {
761
mProgressSink->OnStatus(this, nullptr, status, statusArg.get());
762
}
763
}
764
765
if (progress) {
766
mProgressSink->OnProgress(this, nullptr, progress, progressMax);
767
}
768
769
return NS_OK;
770
}
771
772
//-----------------------------------------------------------------------------
773
// nsBaseChannel::nsIInterfaceRequestor
774
775
NS_IMETHODIMP
776
nsBaseChannel::GetInterface(const nsIID& iid, void** result) {
777
NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup, iid, result);
778
return *result ? NS_OK : NS_ERROR_NO_INTERFACE;
779
}
780
781
//-----------------------------------------------------------------------------
782
// nsBaseChannel::nsIRequestObserver
783
784
static void CallTypeSniffers(void* aClosure, const uint8_t* aData,
785
uint32_t aCount) {
786
nsIChannel* chan = static_cast<nsIChannel*>(aClosure);
787
788
nsAutoCString newType;
789
NS_SniffContent(NS_CONTENT_SNIFFER_CATEGORY, chan, aData, aCount, newType);
790
if (!newType.IsEmpty()) {
791
chan->SetContentType(newType);
792
}
793
}
794
795
static void CallUnknownTypeSniffer(void* aClosure, const uint8_t* aData,
796
uint32_t aCount) {
797
nsIChannel* chan = static_cast<nsIChannel*>(aClosure);
798
799
RefPtr<nsUnknownDecoder> sniffer = new nsUnknownDecoder();
800
801
nsAutoCString detected;
802
nsresult rv = sniffer->GetMIMETypeFromContent(chan, aData, aCount, detected);
803
if (NS_SUCCEEDED(rv)) chan->SetContentType(detected);
804
}
805
806
NS_IMETHODIMP
807
nsBaseChannel::OnStartRequest(nsIRequest* request) {
808
MOZ_ASSERT_IF(mRequest, request == mRequest);
809
810
nsAutoCString scheme;
811
mURI->GetScheme(scheme);
812
813
if (mPump && !scheme.EqualsLiteral("ftp")) {
814
// If our content type is unknown, use the content type
815
// sniffer. If the sniffer is not available for some reason, then we just
816
// keep going as-is.
817
if (NS_SUCCEEDED(mStatus) &&
818
mContentType.EqualsLiteral(UNKNOWN_CONTENT_TYPE)) {
819
mPump->PeekStream(CallUnknownTypeSniffer, static_cast<nsIChannel*>(this));
820
}
821
822
// Now, the general type sniffers. Skip this if we have none.
823
if (mLoadFlags & LOAD_CALL_CONTENT_SNIFFERS)
824
mPump->PeekStream(CallTypeSniffers, static_cast<nsIChannel*>(this));
825
}
826
827
SUSPEND_PUMP_FOR_SCOPE();
828
829
if (mListener) // null in case of redirect
830
return mListener->OnStartRequest(this);
831
return NS_OK;
832
}
833
834
NS_IMETHODIMP
835
nsBaseChannel::OnStopRequest(nsIRequest* request, nsresult status) {
836
// If both mStatus and status are failure codes, we keep mStatus as-is since
837
// that is consistent with our GetStatus and Cancel methods.
838
if (NS_SUCCEEDED(mStatus)) mStatus = status;
839
840
// Cause Pending to return false.
841
mPump = nullptr;
842
mRequest = nullptr;
843
mPumpingData = false;
844
845
if (mListener) // null in case of redirect
846
mListener->OnStopRequest(this, mStatus);
847
ChannelDone();
848
849
// No need to suspend pump in this scope since we will not be receiving
850
// any more events from it.
851
852
if (mLoadGroup) mLoadGroup->RemoveRequest(this, nullptr, mStatus);
853
854
// Drop notification callbacks to prevent cycles.
855
mCallbacks = nullptr;
856
CallbacksChanged();
857
858
return NS_OK;
859
}
860
861
//-----------------------------------------------------------------------------
862
// nsBaseChannel::nsIStreamListener
863
864
NS_IMETHODIMP
865
nsBaseChannel::OnDataAvailable(nsIRequest* request, nsIInputStream* stream,
866
uint64_t offset, uint32_t count) {
867
SUSPEND_PUMP_FOR_SCOPE();
868
869
nsresult rv = mListener->OnDataAvailable(this, stream, offset, count);
870
if (mSynthProgressEvents && NS_SUCCEEDED(rv)) {
871
int64_t prog = offset + count;
872
if (NS_IsMainThread()) {
873
OnTransportStatus(nullptr, NS_NET_STATUS_READING, prog, mContentLength);
874
} else {
875
class OnTransportStatusAsyncEvent : public Runnable {
876
RefPtr<nsBaseChannel> mChannel;
877
int64_t mProgress;
878
int64_t mContentLength;
879
880
public:
881
OnTransportStatusAsyncEvent(nsBaseChannel* aChannel, int64_t aProgress,
882
int64_t aContentLength)
883
: Runnable("OnTransportStatusAsyncEvent"),
884
mChannel(aChannel),
885
mProgress(aProgress),
886
mContentLength(aContentLength) {}
887
888
NS_IMETHOD Run() override {
889
return mChannel->OnTransportStatus(nullptr, NS_NET_STATUS_READING,
890
mProgress, mContentLength);
891
}
892
};
893
894
nsCOMPtr<nsIRunnable> runnable =
895
new OnTransportStatusAsyncEvent(this, prog, mContentLength);
896
Dispatch(runnable.forget());
897
}
898
}
899
900
return rv;
901
}
902
903
NS_IMETHODIMP
904
nsBaseChannel::OnRedirectVerifyCallback(nsresult result) {
905
if (NS_SUCCEEDED(result)) result = ContinueRedirect();
906
907
if (NS_FAILED(result) && !mWaitingOnAsyncRedirect) {
908
if (NS_SUCCEEDED(mStatus)) mStatus = result;
909
return NS_OK;
910
}
911
912
if (mWaitingOnAsyncRedirect) ContinueHandleAsyncRedirect(result);
913
914
return NS_OK;
915
}
916
917
NS_IMETHODIMP
918
nsBaseChannel::RetargetDeliveryTo(nsIEventTarget* aEventTarget) {
919
MOZ_ASSERT(NS_IsMainThread());
920
921
NS_ENSURE_TRUE(mRequest, NS_ERROR_NOT_INITIALIZED);
922
923
nsCOMPtr<nsIThreadRetargetableRequest> req;
924
if (mAllowThreadRetargeting) {
925
req = do_QueryInterface(mRequest);
926
}
927
928
NS_ENSURE_TRUE(req, NS_ERROR_NOT_IMPLEMENTED);
929
930
return req->RetargetDeliveryTo(aEventTarget);
931
}
932
933
NS_IMETHODIMP
934
nsBaseChannel::GetDeliveryTarget(nsIEventTarget** aEventTarget) {
935
MOZ_ASSERT(NS_IsMainThread());
936
937
NS_ENSURE_TRUE(mRequest, NS_ERROR_NOT_INITIALIZED);
938
939
nsCOMPtr<nsIThreadRetargetableRequest> req;
940
req = do_QueryInterface(mRequest);
941
942
NS_ENSURE_TRUE(req, NS_ERROR_NOT_IMPLEMENTED);
943
return req->GetDeliveryTarget(aEventTarget);
944
}
945
946
NS_IMETHODIMP
947
nsBaseChannel::CheckListenerChain() {
948
MOZ_ASSERT(NS_IsMainThread());
949
950
if (!mAllowThreadRetargeting) {
951
return NS_ERROR_NOT_IMPLEMENTED;
952
}
953
954
nsCOMPtr<nsIThreadRetargetableStreamListener> listener =
955
do_QueryInterface(mListener);
956
if (!listener) {
957
return NS_ERROR_NO_INTERFACE;
958
}
959
960
return listener->CheckListenerChain();
961
}
962
963
void nsBaseChannel::SetupNeckoTarget() {
964
mNeckoTarget =
965
nsContentUtils::GetEventTargetByLoadInfo(mLoadInfo, TaskCategory::Other);
966
}