Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2
 *
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 "nsWyciwyg.h"
8
#include "nsWyciwygChannel.h"
9
#include "nsILoadGroup.h"
10
#include "nsNetUtil.h"
11
#include "nsNetCID.h"
12
#include "LoadContextInfo.h"
13
#include "nsICacheService.h" // only to initialize
14
#include "nsICacheStorageService.h"
15
#include "nsICacheStorage.h"
16
#include "nsICacheEntry.h"
17
#include "nsCharsetSource.h"
18
#include "nsProxyRelease.h"
19
#include "nsThreadUtils.h"
20
#include "nsIInputStream.h"
21
#include "nsIInputStreamPump.h"
22
#include "nsIOutputStream.h"
23
#include "nsIProgressEventSink.h"
24
#include "nsIURI.h"
25
#include "mozilla/DebugOnly.h"
26
#include "mozilla/Unused.h"
27
#include "mozilla/BasePrincipal.h"
28
#include "nsProxyRelease.h"
29
#include "nsContentSecurityManager.h"
30
#include "nsContentUtils.h"
31
32
typedef mozilla::net::LoadContextInfo LoadContextInfo;
33
34
// nsWyciwygChannel methods
35
nsWyciwygChannel::nsWyciwygChannel()
36
  : mMode(NONE),
37
    mStatus(NS_OK),
38
    mIsPending(false),
39
    mNeedToWriteCharset(false),
40
    mCharsetSource(kCharsetUninitialized),
41
    mContentLength(-1),
42
    mLoadFlags(LOAD_NORMAL),
43
    mNeedToSetSecurityInfo(false)
44
0
{
45
0
}
46
47
nsWyciwygChannel::~nsWyciwygChannel()
48
0
{
49
0
  if (mLoadInfo) {
50
0
    NS_ReleaseOnMainThreadSystemGroup(
51
0
      "nsWyciwygChannel::mLoadInfo", mLoadInfo.forget(), false);
52
0
  }
53
0
}
54
55
NS_IMPL_ISUPPORTS(nsWyciwygChannel,
56
                  nsIChannel,
57
                  nsIRequest,
58
                  nsIStreamListener,
59
                  nsIRequestObserver,
60
                  nsICacheEntryOpenCallback,
61
                  nsIWyciwygChannel,
62
                  nsIPrivateBrowsingChannel)
63
64
nsresult
65
nsWyciwygChannel::Init(nsIURI* uri)
66
0
{
67
0
  NS_ENSURE_ARG_POINTER(uri);
68
0
69
0
  mURI = uri;
70
0
  mOriginalURI = uri;
71
0
72
0
  return NS_OK;
73
0
}
74
75
///////////////////////////////////////////////////////////////////////////////
76
// nsIRequest methods:
77
///////////////////////////////////////////////////////////////////////////////
78
79
NS_IMETHODIMP
80
nsWyciwygChannel::GetName(nsACString &aName)
81
0
{
82
0
  return mURI->GetSpec(aName);
83
0
}
84
85
NS_IMETHODIMP
86
nsWyciwygChannel::IsPending(bool *aIsPending)
87
0
{
88
0
  *aIsPending = mIsPending;
89
0
  return NS_OK;
90
0
}
91
92
NS_IMETHODIMP
93
nsWyciwygChannel::GetStatus(nsresult *aStatus)
94
0
{
95
0
  if (NS_SUCCEEDED(mStatus) && mPump)
96
0
    mPump->GetStatus(aStatus);
97
0
  else
98
0
    *aStatus = mStatus;
99
0
  return NS_OK;
100
0
}
101
102
NS_IMETHODIMP
103
nsWyciwygChannel::Cancel(nsresult status)
104
0
{
105
0
  mStatus = status;
106
0
  if (mPump)
107
0
    mPump->Cancel(status);
108
0
  // else we're waiting for OnCacheEntryAvailable
109
0
  return NS_OK;
110
0
}
111
112
NS_IMETHODIMP
113
nsWyciwygChannel::Suspend()
114
0
{
115
0
  if (mPump)
116
0
    mPump->Suspend();
117
0
  // XXX else, we'll ignore this ... and that's probably bad!
118
0
  return NS_OK;
119
0
}
120
121
NS_IMETHODIMP
122
nsWyciwygChannel::Resume()
123
0
{
124
0
  if (mPump)
125
0
    mPump->Resume();
126
0
  // XXX else, we'll ignore this ... and that's probably bad!
127
0
  return NS_OK;
128
0
}
129
130
NS_IMETHODIMP
131
nsWyciwygChannel::GetLoadGroup(nsILoadGroup* *aLoadGroup)
132
0
{
133
0
  *aLoadGroup = mLoadGroup;
134
0
  NS_IF_ADDREF(*aLoadGroup);
135
0
  return NS_OK;
136
0
}
137
138
NS_IMETHODIMP
139
nsWyciwygChannel::SetLoadGroup(nsILoadGroup* aLoadGroup)
140
0
{
141
0
  if (!CanSetLoadGroup(aLoadGroup)) {
142
0
    return NS_ERROR_FAILURE;
143
0
  }
144
0
145
0
  mLoadGroup = aLoadGroup;
146
0
  NS_QueryNotificationCallbacks(mCallbacks,
147
0
                                mLoadGroup,
148
0
                                NS_GET_IID(nsIProgressEventSink),
149
0
                                getter_AddRefs(mProgressSink));
150
0
  UpdatePrivateBrowsing();
151
0
  NS_GetOriginAttributes(this, mOriginAttributes);
152
0
153
0
  return NS_OK;
154
0
}
155
156
NS_IMETHODIMP
157
nsWyciwygChannel::SetLoadFlags(uint32_t aLoadFlags)
158
0
{
159
0
  mLoadFlags = aLoadFlags;
160
0
  return NS_OK;
161
0
}
162
163
NS_IMETHODIMP
164
nsWyciwygChannel::GetLoadFlags(uint32_t * aLoadFlags)
165
0
{
166
0
  *aLoadFlags = mLoadFlags;
167
0
  return NS_OK;
168
0
}
169
170
NS_IMETHODIMP
171
nsWyciwygChannel::GetIsDocument(bool *aIsDocument)
172
0
{
173
0
  return NS_GetIsDocumentChannel(this, aIsDocument);
174
0
}
175
176
////////////////////////////////////////////////////////////////////////////////
177
// nsIChannel methods:
178
///////////////////////////////////////////////////////////////////////////////
179
180
NS_IMETHODIMP
181
nsWyciwygChannel::GetOriginalURI(nsIURI* *aURI)
182
0
{
183
0
  *aURI = mOriginalURI;
184
0
  NS_ADDREF(*aURI);
185
0
  return NS_OK;
186
0
}
187
188
NS_IMETHODIMP
189
nsWyciwygChannel::SetOriginalURI(nsIURI* aURI)
190
0
{
191
0
  NS_ENSURE_ARG_POINTER(aURI);
192
0
  mOriginalURI = aURI;
193
0
  return NS_OK;
194
0
}
195
196
NS_IMETHODIMP
197
nsWyciwygChannel::GetURI(nsIURI* *aURI)
198
0
{
199
0
  *aURI = mURI;
200
0
  NS_IF_ADDREF(*aURI);
201
0
  return NS_OK;
202
0
}
203
204
NS_IMETHODIMP
205
nsWyciwygChannel::GetOwner(nsISupports **aOwner)
206
0
{
207
0
  NS_IF_ADDREF(*aOwner = mOwner);
208
0
  return NS_OK;
209
0
}
210
211
NS_IMETHODIMP
212
nsWyciwygChannel::SetOwner(nsISupports* aOwner)
213
0
{
214
0
  mOwner = aOwner;
215
0
  return NS_OK;
216
0
}
217
218
NS_IMETHODIMP
219
nsWyciwygChannel::GetLoadInfo(nsILoadInfo **aLoadInfo)
220
0
{
221
0
  NS_IF_ADDREF(*aLoadInfo = mLoadInfo);
222
0
  return NS_OK;
223
0
}
224
225
NS_IMETHODIMP
226
nsWyciwygChannel::SetLoadInfo(nsILoadInfo* aLoadInfo)
227
0
{
228
0
  mLoadInfo = aLoadInfo;
229
0
  return NS_OK;
230
0
}
231
232
NS_IMETHODIMP
233
nsWyciwygChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aCallbacks)
234
0
{
235
0
  *aCallbacks = mCallbacks.get();
236
0
  NS_IF_ADDREF(*aCallbacks);
237
0
  return NS_OK;
238
0
}
239
240
NS_IMETHODIMP
241
nsWyciwygChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aNotificationCallbacks)
242
0
{
243
0
  if (!CanSetCallbacks(aNotificationCallbacks)) {
244
0
    return NS_ERROR_FAILURE;
245
0
  }
246
0
247
0
  mCallbacks = aNotificationCallbacks;
248
0
  NS_QueryNotificationCallbacks(mCallbacks,
249
0
                                mLoadGroup,
250
0
                                NS_GET_IID(nsIProgressEventSink),
251
0
                                getter_AddRefs(mProgressSink));
252
0
253
0
  UpdatePrivateBrowsing();
254
0
  NS_GetOriginAttributes(this, mOriginAttributes);
255
0
256
0
  return NS_OK;
257
0
}
258
259
NS_IMETHODIMP
260
nsWyciwygChannel::GetSecurityInfo(nsISupports * *aSecurityInfo)
261
0
{
262
0
  NS_IF_ADDREF(*aSecurityInfo = mSecurityInfo);
263
0
264
0
  return NS_OK;
265
0
}
266
267
NS_IMETHODIMP
268
nsWyciwygChannel::GetContentType(nsACString &aContentType)
269
0
{
270
0
  aContentType.AssignLiteral(WYCIWYG_TYPE);
271
0
  return NS_OK;
272
0
}
273
274
NS_IMETHODIMP
275
nsWyciwygChannel::SetContentType(const nsACString &aContentType)
276
0
{
277
0
  return NS_ERROR_NOT_IMPLEMENTED;
278
0
}
279
280
NS_IMETHODIMP
281
nsWyciwygChannel::GetContentCharset(nsACString &aContentCharset)
282
0
{
283
0
  aContentCharset.AssignLiteral("UTF-16LE");
284
0
  return NS_OK;
285
0
}
286
287
NS_IMETHODIMP
288
nsWyciwygChannel::SetContentCharset(const nsACString &aContentCharset)
289
0
{
290
0
  return NS_ERROR_NOT_IMPLEMENTED;
291
0
}
292
293
NS_IMETHODIMP
294
nsWyciwygChannel::GetContentDisposition(uint32_t *aContentDisposition)
295
0
{
296
0
  return NS_ERROR_NOT_AVAILABLE;
297
0
}
298
299
NS_IMETHODIMP
300
nsWyciwygChannel::SetContentDisposition(uint32_t aContentDisposition)
301
0
{
302
0
  return NS_ERROR_NOT_AVAILABLE;
303
0
}
304
305
NS_IMETHODIMP
306
nsWyciwygChannel::GetContentDispositionFilename(nsAString &aContentDispositionFilename)
307
0
{
308
0
  return NS_ERROR_NOT_AVAILABLE;
309
0
}
310
311
NS_IMETHODIMP
312
nsWyciwygChannel::SetContentDispositionFilename(const nsAString &aContentDispositionFilename)
313
0
{
314
0
  return NS_ERROR_NOT_AVAILABLE;
315
0
}
316
317
NS_IMETHODIMP
318
nsWyciwygChannel::GetContentDispositionHeader(nsACString &aContentDispositionHeader)
319
0
{
320
0
  return NS_ERROR_NOT_AVAILABLE;
321
0
}
322
323
NS_IMETHODIMP
324
nsWyciwygChannel::GetContentLength(int64_t *aContentLength)
325
0
{
326
0
  *aContentLength = mContentLength;
327
0
  return NS_OK;
328
0
}
329
330
NS_IMETHODIMP
331
nsWyciwygChannel::SetContentLength(int64_t aContentLength)
332
0
{
333
0
  mContentLength = aContentLength;
334
0
335
0
  return NS_OK;
336
0
}
337
338
NS_IMETHODIMP
339
nsWyciwygChannel::Open(nsIInputStream ** aReturn)
340
0
{
341
0
  return NS_ERROR_NOT_IMPLEMENTED;
342
0
}
343
344
NS_IMETHODIMP
345
nsWyciwygChannel::Open2(nsIInputStream** aStream)
346
0
{
347
0
  nsCOMPtr<nsIStreamListener> listener;
348
0
  nsresult rv = nsContentSecurityManager::doContentSecurityCheck(this, listener);
349
0
  NS_ENSURE_SUCCESS(rv, rv);
350
0
  return Open(aStream);
351
0
}
352
353
NS_IMETHODIMP
354
nsWyciwygChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctx)
355
0
{
356
0
  MOZ_ASSERT(!mLoadInfo ||
357
0
             mLoadInfo->GetSecurityMode() == 0 ||
358
0
             mLoadInfo->GetInitialSecurityCheckDone() ||
359
0
             (mLoadInfo->GetSecurityMode() == nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL &&
360
0
              nsContentUtils::IsSystemPrincipal(mLoadInfo->LoadingPrincipal())),
361
0
             "security flags in loadInfo but asyncOpen2() not called");
362
0
363
0
  LOG(("nsWyciwygChannel::AsyncOpen [this=%p]\n", this));
364
0
  MOZ_ASSERT(mMode == NONE, "nsWyciwygChannel already open");
365
0
366
0
  NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
367
0
  NS_ENSURE_TRUE(mMode == NONE, NS_ERROR_IN_PROGRESS);
368
0
  NS_ENSURE_ARG_POINTER(listener);
369
0
370
0
  mMode = READING;
371
0
372
0
  // open a cache entry for this channel...
373
0
  // mIsPending set to true since OnCacheEntryAvailable may be called
374
0
  // synchronously and fails when mIsPending found false.
375
0
  mIsPending = true;
376
0
  nsresult rv = OpenCacheEntryForReading(mURI);
377
0
  if (NS_FAILED(rv)) {
378
0
    LOG(("nsWyciwygChannel::OpenCacheEntryForReading failed [rv=%" PRIx32 "]\n",
379
0
         static_cast<uint32_t>(rv)));
380
0
    mIsPending = false;
381
0
    mCallbacks = nullptr;
382
0
    return rv;
383
0
  }
384
0
385
0
  // There is no code path that would invoke the listener sooner than
386
0
  // we get to this line in case OnCacheEntryAvailable is invoked
387
0
  // synchronously.
388
0
  mListener = listener;
389
0
  mListenerContext = ctx;
390
0
391
0
  if (mLoadGroup)
392
0
    mLoadGroup->AddRequest(this, nullptr);
393
0
394
0
  return NS_OK;
395
0
}
396
397
NS_IMETHODIMP
398
nsWyciwygChannel::AsyncOpen2(nsIStreamListener *aListener)
399
0
{
400
0
  nsCOMPtr<nsIStreamListener> listener = aListener;
401
0
  nsresult rv = nsContentSecurityManager::doContentSecurityCheck(this, listener);
402
0
  if (NS_FAILED(rv)) {
403
0
    mIsPending = false;
404
0
    mCallbacks = nullptr;
405
0
    return rv;
406
0
  }
407
0
  return AsyncOpen(listener, nullptr);
408
0
}
409
410
//////////////////////////////////////////////////////////////////////////////
411
// nsIWyciwygChannel
412
//////////////////////////////////////////////////////////////////////////////
413
414
NS_IMETHODIMP
415
nsWyciwygChannel::WriteToCacheEntry(const nsAString &aData)
416
0
{
417
0
  LOG(("nsWyciwygChannel::WriteToCacheEntry [this=%p]", this));
418
0
419
0
  nsresult rv;
420
0
421
0
  if (mMode == READING) {
422
0
    LOG(("nsWyciwygChannel::WriteToCacheEntry already open for reading"));
423
0
    MOZ_ASSERT(false);
424
0
    return NS_ERROR_UNEXPECTED;
425
0
  }
426
0
427
0
  mMode = WRITING;
428
0
429
0
  if (!mCacheEntry) {
430
0
    nsresult rv = OpenCacheEntryForWriting(mURI);
431
0
    if (NS_FAILED(rv) || !mCacheEntry) {
432
0
      LOG(("  could not synchronously open cache entry for write!"));
433
0
      return NS_ERROR_FAILURE;
434
0
    }
435
0
  }
436
0
437
0
  if (mLoadFlags & INHIBIT_PERSISTENT_CACHING) {
438
0
    rv = mCacheEntry->SetMetaDataElement("inhibit-persistent-caching", "1");
439
0
    if (NS_FAILED(rv)) return rv;
440
0
  }
441
0
442
0
  if (mNeedToSetSecurityInfo) {
443
0
    mCacheEntry->SetSecurityInfo(mSecurityInfo);
444
0
    mNeedToSetSecurityInfo = false;
445
0
  }
446
0
447
0
  if (mNeedToWriteCharset) {
448
0
    WriteCharsetAndSourceToCache(mCharsetSource, mCharset);
449
0
    mNeedToWriteCharset = false;
450
0
  }
451
0
452
0
  uint32_t out;
453
0
  if (!mCacheOutputStream) {
454
0
    // Get the outputstream from the cache entry.
455
0
    rv = mCacheEntry->OpenOutputStream(0, -1, getter_AddRefs(mCacheOutputStream));
456
0
    if (NS_FAILED(rv)) return rv;
457
0
458
0
    // Write out a Byte Order Mark, so that we'll know if the data is
459
0
    // BE or LE when we go to read it.
460
0
    char16_t bom = 0xFEFF;
461
0
    rv = mCacheOutputStream->Write((char *)&bom, sizeof(bom), &out);
462
0
    if (NS_FAILED(rv)) return rv;
463
0
  }
464
0
465
0
  return mCacheOutputStream->Write((const char *)PromiseFlatString(aData).get(),
466
0
                                   aData.Length() * sizeof(char16_t), &out);
467
0
}
468
469
470
NS_IMETHODIMP
471
nsWyciwygChannel::CloseCacheEntry(nsresult reason)
472
0
{
473
0
  if (mCacheEntry) {
474
0
    LOG(("nsWyciwygChannel::CloseCacheEntry [this=%p ]", this));
475
0
    mCacheOutputStream = nullptr;
476
0
477
0
    if (NS_FAILED(reason)) {
478
0
      mCacheEntry->AsyncDoom(nullptr);
479
0
    }
480
0
481
0
    mCacheEntry = nullptr;
482
0
  }
483
0
  return NS_OK;
484
0
}
485
486
NS_IMETHODIMP
487
nsWyciwygChannel::SetSecurityInfo(nsISupports *aSecurityInfo)
488
0
{
489
0
  if (mMode == READING) {
490
0
    MOZ_ASSERT(false);
491
0
    return NS_ERROR_UNEXPECTED;
492
0
  }
493
0
494
0
  mSecurityInfo = aSecurityInfo;
495
0
496
0
  if (mCacheEntry) {
497
0
    return mCacheEntry->SetSecurityInfo(mSecurityInfo);
498
0
  }
499
0
500
0
  mNeedToSetSecurityInfo = true;
501
0
502
0
  return NS_OK;
503
0
}
504
505
NS_IMETHODIMP
506
nsWyciwygChannel::SetCharsetAndSource(int32_t aSource,
507
                                      const nsACString& aCharset)
508
0
{
509
0
  NS_ENSURE_ARG(!aCharset.IsEmpty());
510
0
511
0
  if (mCacheEntry) {
512
0
    WriteCharsetAndSourceToCache(mCharsetSource, mCharset);
513
0
  } else {
514
0
    MOZ_ASSERT(mMode != WRITING, "We must have an entry!");
515
0
    if (mMode == READING) {
516
0
      return NS_ERROR_NOT_AVAILABLE;
517
0
    }
518
0
    mNeedToWriteCharset = true;
519
0
    mCharsetSource = aSource;
520
0
    mCharset = aCharset;
521
0
  }
522
0
523
0
  return NS_OK;
524
0
}
525
526
NS_IMETHODIMP
527
nsWyciwygChannel::GetCharsetAndSource(int32_t* aSource, nsACString& aCharset)
528
0
{
529
0
  MOZ_ASSERT(mMode == READING);
530
0
531
0
  if (!mCacheEntry) {
532
0
    return NS_ERROR_NOT_AVAILABLE;
533
0
  }
534
0
535
0
  nsCString data;
536
0
  mCacheEntry->GetMetaDataElement("charset", getter_Copies(data));
537
0
538
0
  if (data.IsEmpty()) {
539
0
    return NS_ERROR_NOT_AVAILABLE;
540
0
  }
541
0
542
0
  nsCString sourceStr;
543
0
  mCacheEntry->GetMetaDataElement("charset-source", getter_Copies(sourceStr));
544
0
545
0
  int32_t source;
546
0
  nsresult err;
547
0
  source = sourceStr.ToInteger(&err);
548
0
  if (NS_FAILED(err) || source == 0) {
549
0
    return NS_ERROR_NOT_AVAILABLE;
550
0
  }
551
0
552
0
  *aSource = source;
553
0
  aCharset = data;
554
0
  return NS_OK;
555
0
}
556
557
//////////////////////////////////////////////////////////////////////////////
558
// nsICacheEntryOpenCallback
559
//////////////////////////////////////////////////////////////////////////////
560
561
NS_IMETHODIMP
562
nsWyciwygChannel::OnCacheEntryCheck(nsICacheEntry* entry, nsIApplicationCache* appCache,
563
                                    uint32_t* aResult)
564
0
{
565
0
  *aResult = ENTRY_WANTED;
566
0
  return NS_OK;
567
0
}
568
569
NS_IMETHODIMP
570
nsWyciwygChannel::OnCacheEntryAvailable(nsICacheEntry *aCacheEntry,
571
                                        bool aNew,
572
                                        nsIApplicationCache* aAppCache,
573
                                        nsresult aStatus)
574
0
{
575
0
  LOG(("nsWyciwygChannel::OnCacheEntryAvailable [this=%p entry=%p "
576
0
       "new=%d status=%" PRIx32 "]\n", this, aCacheEntry, aNew, static_cast<uint32_t>(aStatus)));
577
0
578
0
  MOZ_RELEASE_ASSERT(!aNew, "New entry must not be returned when flag "
579
0
                            "OPEN_READONLY is used!");
580
0
581
0
  // if the channel's already fired onStopRequest,
582
0
  // then we should ignore this event.
583
0
  if (!mIsPending)
584
0
    return NS_OK;
585
0
586
0
  if (NS_SUCCEEDED(mStatus)) {
587
0
    if (NS_SUCCEEDED(aStatus)) {
588
0
      MOZ_ASSERT(aCacheEntry);
589
0
      mCacheEntry = aCacheEntry;
590
0
      nsresult rv = ReadFromCache();
591
0
      if (NS_FAILED(rv)) {
592
0
        mStatus = rv;
593
0
      }
594
0
    } else {
595
0
      mStatus = aStatus;
596
0
    }
597
0
  }
598
0
599
0
  if (NS_FAILED(mStatus)) {
600
0
    LOG(("channel was canceled [this=%p status=%" PRIx32 "]\n", this, static_cast<uint32_t>(mStatus)));
601
0
    // Since OnCacheEntryAvailable can be called directly from AsyncOpen
602
0
    // we must dispatch.
603
0
    NS_DispatchToCurrentThread(
604
0
      mozilla::NewRunnableMethod("nsWyciwygChannel::NotifyListener",
605
0
                                 this,
606
0
                                 &nsWyciwygChannel::NotifyListener));
607
0
  }
608
0
609
0
  return NS_OK;
610
0
}
611
612
//-----------------------------------------------------------------------------
613
// nsWyciwygChannel::nsIStreamListener
614
//-----------------------------------------------------------------------------
615
616
NS_IMETHODIMP
617
nsWyciwygChannel::OnDataAvailable(nsIRequest *request, nsISupports *ctx,
618
                                  nsIInputStream *input,
619
                                  uint64_t offset, uint32_t count)
620
0
{
621
0
  LOG(("nsWyciwygChannel::OnDataAvailable [this=%p request=%p offset=%" PRIu64 " count=%u]\n",
622
0
      this, request, offset, count));
623
0
624
0
  nsresult rv;
625
0
626
0
  nsCOMPtr<nsIStreamListener> listener = mListener;
627
0
  nsCOMPtr<nsISupports> listenerContext = mListenerContext;
628
0
629
0
  if (listener) {
630
0
    rv = listener->OnDataAvailable(this, listenerContext, input, offset, count);
631
0
  } else {
632
0
    MOZ_ASSERT(false, "We must have a listener!");
633
0
    rv = NS_ERROR_UNEXPECTED;
634
0
  }
635
0
636
0
  // XXX handle 64-bit stuff for real
637
0
  if (mProgressSink && NS_SUCCEEDED(rv)) {
638
0
    mProgressSink->OnProgress(this, nullptr, offset + count, mContentLength);
639
0
  }
640
0
641
0
  return rv; // let the pump cancel on failure
642
0
}
643
644
//////////////////////////////////////////////////////////////////////////////
645
// nsIRequestObserver
646
//////////////////////////////////////////////////////////////////////////////
647
648
NS_IMETHODIMP
649
nsWyciwygChannel::OnStartRequest(nsIRequest *request, nsISupports *ctx)
650
0
{
651
0
  LOG(("nsWyciwygChannel::OnStartRequest [this=%p request=%p]\n",
652
0
      this, request));
653
0
654
0
  nsCOMPtr<nsIStreamListener> listener = mListener;
655
0
  nsCOMPtr<nsISupports> listenerContext = mListenerContext;
656
0
657
0
  if (listener) {
658
0
    return listener->OnStartRequest(this, listenerContext);
659
0
  }
660
0
661
0
  MOZ_ASSERT(false, "We must have a listener!");
662
0
  return NS_ERROR_UNEXPECTED;
663
0
}
664
665
666
NS_IMETHODIMP
667
nsWyciwygChannel::OnStopRequest(nsIRequest *request, nsISupports *ctx, nsresult status)
668
0
{
669
0
  LOG(("nsWyciwygChannel::OnStopRequest [this=%p request=%p status=%" PRIu32 "]\n",
670
0
       this, request, static_cast<uint32_t>(status)));
671
0
672
0
  if (NS_SUCCEEDED(mStatus))
673
0
    mStatus = status;
674
0
675
0
  mIsPending = false;
676
0
677
0
  nsCOMPtr<nsIStreamListener> listener;
678
0
  nsCOMPtr<nsISupports> listenerContext;
679
0
  listener.swap(mListener);
680
0
  listenerContext.swap(mListenerContext);
681
0
682
0
  if (listener) {
683
0
    listener->OnStopRequest(this, listenerContext, mStatus);
684
0
  } else {
685
0
    MOZ_ASSERT(false, "We must have a listener!");
686
0
  }
687
0
688
0
  if (mLoadGroup)
689
0
    mLoadGroup->RemoveRequest(this, nullptr, mStatus);
690
0
691
0
  CloseCacheEntry(mStatus);
692
0
  mPump = nullptr;
693
0
694
0
  // Drop notification callbacks to prevent cycles.
695
0
  mCallbacks = nullptr;
696
0
  mProgressSink = nullptr;
697
0
698
0
  return NS_OK;
699
0
}
700
701
//////////////////////////////////////////////////////////////////////////////
702
// Helper functions
703
//////////////////////////////////////////////////////////////////////////////
704
705
nsresult
706
nsWyciwygChannel::GetCacheStorage(nsICacheStorage **_retval)
707
0
{
708
0
  nsresult rv;
709
0
710
0
  nsCOMPtr<nsICacheStorageService> cacheService =
711
0
    do_GetService("@mozilla.org/netwerk/cache-storage-service;1", &rv);
712
0
  NS_ENSURE_SUCCESS(rv, rv);
713
0
714
0
  bool anonymous = mLoadFlags & LOAD_ANONYMOUS;
715
0
  mOriginAttributes.SyncAttributesWithPrivateBrowsing(mPrivateBrowsing);
716
0
  RefPtr<LoadContextInfo> loadInfo = mozilla::net::GetLoadContextInfo(anonymous, mOriginAttributes);
717
0
718
0
  if (mLoadFlags & INHIBIT_PERSISTENT_CACHING) {
719
0
    return cacheService->MemoryCacheStorage(loadInfo, _retval);
720
0
  }
721
0
722
0
  return cacheService->DiskCacheStorage(loadInfo, false, _retval);
723
0
}
724
725
nsresult
726
nsWyciwygChannel::OpenCacheEntryForReading(nsIURI *aURI)
727
0
{
728
0
  nsresult rv;
729
0
730
0
  nsCOMPtr<nsICacheStorage> cacheStorage;
731
0
  rv = GetCacheStorage(getter_AddRefs(cacheStorage));
732
0
  NS_ENSURE_SUCCESS(rv, rv);
733
0
734
0
  return cacheStorage->AsyncOpenURI(aURI, EmptyCString(),
735
0
                                    nsICacheStorage::OPEN_READONLY |
736
0
                                    nsICacheStorage::CHECK_MULTITHREADED,
737
0
                                    this);
738
0
}
739
740
nsresult
741
nsWyciwygChannel::OpenCacheEntryForWriting(nsIURI *aURI)
742
0
{
743
0
  nsresult rv;
744
0
745
0
  nsCOMPtr<nsICacheStorage> cacheStorage;
746
0
  rv = GetCacheStorage(getter_AddRefs(cacheStorage));
747
0
  NS_ENSURE_SUCCESS(rv, rv);
748
0
749
0
  return cacheStorage->OpenTruncate(aURI, EmptyCString(),
750
0
                                    getter_AddRefs(mCacheEntry));
751
0
}
752
753
nsresult
754
nsWyciwygChannel::ReadFromCache()
755
0
{
756
0
  LOG(("nsWyciwygChannel::ReadFromCache [this=%p] ", this));
757
0
758
0
  NS_ENSURE_TRUE(mCacheEntry, NS_ERROR_FAILURE);
759
0
  nsresult rv;
760
0
761
0
  // Get the stored security info
762
0
  mCacheEntry->GetSecurityInfo(getter_AddRefs(mSecurityInfo));
763
0
764
0
  nsAutoCString tmpStr;
765
0
  rv = mCacheEntry->GetMetaDataElement("inhibit-persistent-caching",
766
0
                                       getter_Copies(tmpStr));
767
0
  if (NS_SUCCEEDED(rv) && tmpStr.EqualsLiteral("1"))
768
0
    mLoadFlags |= INHIBIT_PERSISTENT_CACHING;
769
0
770
0
  // Get a transport to the cached data...
771
0
  nsCOMPtr<nsIInputStream> inputStream;
772
0
  rv = mCacheEntry->OpenInputStream(0, getter_AddRefs(inputStream));
773
0
  if (NS_FAILED(rv))
774
0
    return rv;
775
0
  NS_ENSURE_TRUE(inputStream, NS_ERROR_UNEXPECTED);
776
0
777
0
  rv = NS_NewInputStreamPump(getter_AddRefs(mPump), inputStream.forget());
778
0
  if (NS_FAILED(rv)) return rv;
779
0
780
0
  // Pump the cache data downstream
781
0
  return mPump->AsyncRead(this, nullptr);
782
0
}
783
784
void
785
nsWyciwygChannel::WriteCharsetAndSourceToCache(int32_t aSource,
786
                                               const nsCString& aCharset)
787
0
{
788
0
  MOZ_ASSERT(mCacheEntry, "Better have cache entry!");
789
0
790
0
  mCacheEntry->SetMetaDataElement("charset", aCharset.get());
791
0
792
0
  nsAutoCString source;
793
0
  source.AppendInt(aSource);
794
0
  mCacheEntry->SetMetaDataElement("charset-source", source.get());
795
0
}
796
797
void
798
nsWyciwygChannel::NotifyListener()
799
0
{
800
0
  nsCOMPtr<nsIStreamListener> listener;
801
0
  nsCOMPtr<nsISupports> listenerContext;
802
0
803
0
  listener.swap(mListener);
804
0
  listenerContext.swap(mListenerContext);
805
0
806
0
  if (listener) {
807
0
    listener->OnStartRequest(this, listenerContext);
808
0
    mIsPending = false;
809
0
    listener->OnStopRequest(this, listenerContext, mStatus);
810
0
  } else {
811
0
    MOZ_ASSERT(false, "We must have the listener!");
812
0
    mIsPending = false;
813
0
  }
814
0
815
0
  CloseCacheEntry(mStatus);
816
0
817
0
  // Remove ourselves from the load group.
818
0
  if (mLoadGroup) {
819
0
    mLoadGroup->RemoveRequest(this, nullptr, mStatus);
820
0
  }
821
0
}
822
823
// vim: ts=2 sw=2