Thu, 15 Jan 2015 21:03:48 +0100
Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)
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/. */
7 #include "nsWyciwyg.h"
8 #include "nsWyciwygChannel.h"
9 #include "nsILoadGroup.h"
10 #include "nsNetUtil.h"
11 #include "LoadContextInfo.h"
12 #include "nsICacheService.h" // only to initialize
13 #include "nsICacheStorageService.h"
14 #include "nsICacheStorage.h"
15 #include "nsICacheEntry.h"
16 #include "CacheObserver.h"
17 #include "nsCharsetSource.h"
18 #include "nsProxyRelease.h"
19 #include "nsThreadUtils.h"
20 #include "nsIEventTarget.h"
21 #include "nsIInputStream.h"
22 #include "nsIInputStreamPump.h"
23 #include "nsIOutputStream.h"
24 #include "nsIProgressEventSink.h"
25 #include "nsIURI.h"
26 #include "mozilla/DebugOnly.h"
27 #include "mozilla/unused.h"
29 typedef mozilla::net::LoadContextInfo LoadContextInfo;
31 // Must release mChannel on the main thread
32 class nsWyciwygAsyncEvent : public nsRunnable {
33 public:
34 nsWyciwygAsyncEvent(nsWyciwygChannel *aChannel) : mChannel(aChannel) {}
36 ~nsWyciwygAsyncEvent()
37 {
38 nsCOMPtr<nsIThread> thread = do_GetMainThread();
39 NS_WARN_IF_FALSE(thread, "Couldn't get the main thread!");
40 if (thread) {
41 nsIWyciwygChannel *chan = static_cast<nsIWyciwygChannel *>(mChannel);
42 mozilla::unused << mChannel.forget();
43 NS_ProxyRelease(thread, chan);
44 }
45 }
46 protected:
47 nsRefPtr<nsWyciwygChannel> mChannel;
48 };
50 class nsWyciwygSetCharsetandSourceEvent : public nsWyciwygAsyncEvent {
51 public:
52 nsWyciwygSetCharsetandSourceEvent(nsWyciwygChannel *aChannel)
53 : nsWyciwygAsyncEvent(aChannel) {}
55 NS_IMETHOD Run()
56 {
57 mChannel->SetCharsetAndSourceInternal();
58 return NS_OK;
59 }
60 };
62 class nsWyciwygWriteEvent : public nsWyciwygAsyncEvent {
63 public:
64 nsWyciwygWriteEvent(nsWyciwygChannel *aChannel, const nsAString &aData)
65 : nsWyciwygAsyncEvent(aChannel), mData(aData) {}
67 NS_IMETHOD Run()
68 {
69 mChannel->WriteToCacheEntryInternal(mData);
70 return NS_OK;
71 }
72 private:
73 nsString mData;
74 };
76 class nsWyciwygCloseEvent : public nsWyciwygAsyncEvent {
77 public:
78 nsWyciwygCloseEvent(nsWyciwygChannel *aChannel, nsresult aReason)
79 : nsWyciwygAsyncEvent(aChannel), mReason(aReason) {}
81 NS_IMETHOD Run()
82 {
83 mChannel->CloseCacheEntryInternal(mReason);
84 return NS_OK;
85 }
86 private:
87 nsresult mReason;
88 };
91 // nsWyciwygChannel methods
92 nsWyciwygChannel::nsWyciwygChannel()
93 : mMode(NONE),
94 mStatus(NS_OK),
95 mIsPending(false),
96 mCharsetAndSourceSet(false),
97 mNeedToWriteCharset(false),
98 mCharsetSource(kCharsetUninitialized),
99 mContentLength(-1),
100 mLoadFlags(LOAD_NORMAL),
101 mAppId(NECKO_NO_APP_ID),
102 mInBrowser(false)
103 {
104 }
106 nsWyciwygChannel::~nsWyciwygChannel()
107 {
108 }
110 NS_IMPL_ISUPPORTS(nsWyciwygChannel,
111 nsIChannel,
112 nsIRequest,
113 nsIStreamListener,
114 nsIRequestObserver,
115 nsICacheEntryOpenCallback,
116 nsIWyciwygChannel,
117 nsIPrivateBrowsingChannel)
119 nsresult
120 nsWyciwygChannel::Init(nsIURI* uri)
121 {
122 NS_ENSURE_ARG_POINTER(uri);
124 nsresult rv;
126 if (!mozilla::net::CacheObserver::UseNewCache()) {
127 // Since nsWyciwygChannel can use the new cache API off the main thread
128 // and that API normally does this initiation, we need to take care
129 // of initiating the old cache service here manually. Will be removed
130 // with bug 913828.
131 MOZ_ASSERT(NS_IsMainThread());
132 nsCOMPtr<nsICacheService> service =
133 do_GetService(NS_CACHESERVICE_CONTRACTID, &rv);
134 }
136 mURI = uri;
137 mOriginalURI = uri;
139 nsCOMPtr<nsICacheStorageService> serv =
140 do_GetService("@mozilla.org/netwerk/cache-storage-service;1", &rv);
141 NS_ENSURE_SUCCESS(rv, rv);
143 rv = serv->GetIoTarget(getter_AddRefs(mCacheIOTarget));
144 NS_ENSURE_SUCCESS(rv, rv);
146 return NS_OK;
147 }
149 ///////////////////////////////////////////////////////////////////////////////
150 // nsIRequest methods:
151 ///////////////////////////////////////////////////////////////////////////////
153 NS_IMETHODIMP
154 nsWyciwygChannel::GetName(nsACString &aName)
155 {
156 return mURI->GetSpec(aName);
157 }
159 NS_IMETHODIMP
160 nsWyciwygChannel::IsPending(bool *aIsPending)
161 {
162 *aIsPending = mIsPending;
163 return NS_OK;
164 }
166 NS_IMETHODIMP
167 nsWyciwygChannel::GetStatus(nsresult *aStatus)
168 {
169 if (NS_SUCCEEDED(mStatus) && mPump)
170 mPump->GetStatus(aStatus);
171 else
172 *aStatus = mStatus;
173 return NS_OK;
174 }
176 NS_IMETHODIMP
177 nsWyciwygChannel::Cancel(nsresult status)
178 {
179 mStatus = status;
180 if (mPump)
181 mPump->Cancel(status);
182 // else we're waiting for OnCacheEntryAvailable
183 return NS_OK;
184 }
186 NS_IMETHODIMP
187 nsWyciwygChannel::Suspend()
188 {
189 if (mPump)
190 mPump->Suspend();
191 // XXX else, we'll ignore this ... and that's probably bad!
192 return NS_OK;
193 }
195 NS_IMETHODIMP
196 nsWyciwygChannel::Resume()
197 {
198 if (mPump)
199 mPump->Resume();
200 // XXX else, we'll ignore this ... and that's probably bad!
201 return NS_OK;
202 }
204 NS_IMETHODIMP
205 nsWyciwygChannel::GetLoadGroup(nsILoadGroup* *aLoadGroup)
206 {
207 *aLoadGroup = mLoadGroup;
208 NS_IF_ADDREF(*aLoadGroup);
209 return NS_OK;
210 }
212 NS_IMETHODIMP
213 nsWyciwygChannel::SetLoadGroup(nsILoadGroup* aLoadGroup)
214 {
215 if (!CanSetLoadGroup(aLoadGroup)) {
216 return NS_ERROR_FAILURE;
217 }
219 mLoadGroup = aLoadGroup;
220 NS_QueryNotificationCallbacks(mCallbacks,
221 mLoadGroup,
222 NS_GET_IID(nsIProgressEventSink),
223 getter_AddRefs(mProgressSink));
224 mPrivateBrowsing = NS_UsePrivateBrowsing(this);
225 NS_GetAppInfo(this, &mAppId, &mInBrowser);
226 return NS_OK;
227 }
229 NS_IMETHODIMP
230 nsWyciwygChannel::SetLoadFlags(uint32_t aLoadFlags)
231 {
232 mLoadFlags = aLoadFlags;
233 return NS_OK;
234 }
236 NS_IMETHODIMP
237 nsWyciwygChannel::GetLoadFlags(uint32_t * aLoadFlags)
238 {
239 *aLoadFlags = mLoadFlags;
240 return NS_OK;
241 }
243 ////////////////////////////////////////////////////////////////////////////////
244 // nsIChannel methods:
245 ///////////////////////////////////////////////////////////////////////////////
247 NS_IMETHODIMP
248 nsWyciwygChannel::GetOriginalURI(nsIURI* *aURI)
249 {
250 *aURI = mOriginalURI;
251 NS_ADDREF(*aURI);
252 return NS_OK;
253 }
255 NS_IMETHODIMP
256 nsWyciwygChannel::SetOriginalURI(nsIURI* aURI)
257 {
258 NS_ENSURE_ARG_POINTER(aURI);
259 mOriginalURI = aURI;
260 return NS_OK;
261 }
263 NS_IMETHODIMP
264 nsWyciwygChannel::GetURI(nsIURI* *aURI)
265 {
266 *aURI = mURI;
267 NS_IF_ADDREF(*aURI);
268 return NS_OK;
269 }
271 NS_IMETHODIMP
272 nsWyciwygChannel::GetOwner(nsISupports **aOwner)
273 {
274 NS_PRECONDITION(mOwner, "Must have a principal!");
275 NS_ENSURE_STATE(mOwner);
277 NS_ADDREF(*aOwner = mOwner);
278 return NS_OK;
279 }
281 NS_IMETHODIMP
282 nsWyciwygChannel::SetOwner(nsISupports* aOwner)
283 {
284 mOwner = aOwner;
285 return NS_OK;
286 }
288 NS_IMETHODIMP
289 nsWyciwygChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aCallbacks)
290 {
291 *aCallbacks = mCallbacks.get();
292 NS_IF_ADDREF(*aCallbacks);
293 return NS_OK;
294 }
296 NS_IMETHODIMP
297 nsWyciwygChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aNotificationCallbacks)
298 {
299 if (!CanSetCallbacks(aNotificationCallbacks)) {
300 return NS_ERROR_FAILURE;
301 }
303 mCallbacks = aNotificationCallbacks;
304 NS_QueryNotificationCallbacks(mCallbacks,
305 mLoadGroup,
306 NS_GET_IID(nsIProgressEventSink),
307 getter_AddRefs(mProgressSink));
309 mPrivateBrowsing = NS_UsePrivateBrowsing(this);
310 NS_GetAppInfo(this, &mAppId, &mInBrowser);
312 return NS_OK;
313 }
315 NS_IMETHODIMP
316 nsWyciwygChannel::GetSecurityInfo(nsISupports * *aSecurityInfo)
317 {
318 NS_IF_ADDREF(*aSecurityInfo = mSecurityInfo);
320 return NS_OK;
321 }
323 NS_IMETHODIMP
324 nsWyciwygChannel::GetContentType(nsACString &aContentType)
325 {
326 aContentType.AssignLiteral(WYCIWYG_TYPE);
327 return NS_OK;
328 }
330 NS_IMETHODIMP
331 nsWyciwygChannel::SetContentType(const nsACString &aContentType)
332 {
333 return NS_ERROR_NOT_IMPLEMENTED;
334 }
336 NS_IMETHODIMP
337 nsWyciwygChannel::GetContentCharset(nsACString &aContentCharset)
338 {
339 aContentCharset.Assign("UTF-16");
340 return NS_OK;
341 }
343 NS_IMETHODIMP
344 nsWyciwygChannel::SetContentCharset(const nsACString &aContentCharset)
345 {
346 return NS_ERROR_NOT_IMPLEMENTED;
347 }
349 NS_IMETHODIMP
350 nsWyciwygChannel::GetContentDisposition(uint32_t *aContentDisposition)
351 {
352 return NS_ERROR_NOT_AVAILABLE;
353 }
355 NS_IMETHODIMP
356 nsWyciwygChannel::SetContentDisposition(uint32_t aContentDisposition)
357 {
358 return NS_ERROR_NOT_AVAILABLE;
359 }
361 NS_IMETHODIMP
362 nsWyciwygChannel::GetContentDispositionFilename(nsAString &aContentDispositionFilename)
363 {
364 return NS_ERROR_NOT_AVAILABLE;
365 }
367 NS_IMETHODIMP
368 nsWyciwygChannel::SetContentDispositionFilename(const nsAString &aContentDispositionFilename)
369 {
370 return NS_ERROR_NOT_AVAILABLE;
371 }
373 NS_IMETHODIMP
374 nsWyciwygChannel::GetContentDispositionHeader(nsACString &aContentDispositionHeader)
375 {
376 return NS_ERROR_NOT_AVAILABLE;
377 }
379 NS_IMETHODIMP
380 nsWyciwygChannel::GetContentLength(int64_t *aContentLength)
381 {
382 *aContentLength = mContentLength;
383 return NS_OK;
384 }
386 NS_IMETHODIMP
387 nsWyciwygChannel::SetContentLength(int64_t aContentLength)
388 {
389 mContentLength = aContentLength;
391 return NS_OK;
392 }
394 NS_IMETHODIMP
395 nsWyciwygChannel::Open(nsIInputStream ** aReturn)
396 {
397 return NS_ERROR_NOT_IMPLEMENTED;
398 }
400 NS_IMETHODIMP
401 nsWyciwygChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctx)
402 {
403 LOG(("nsWyciwygChannel::AsyncOpen [this=%p]\n", this));
404 MOZ_ASSERT(mMode == NONE, "nsWyciwygChannel already open");
406 NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
407 NS_ENSURE_TRUE(mMode == NONE, NS_ERROR_IN_PROGRESS);
408 NS_ENSURE_ARG_POINTER(listener);
410 mMode = READING;
412 // open a cache entry for this channel...
413 // mIsPending set to true since OnCacheEntryAvailable may be called
414 // synchronously and fails when mIsPending found false.
415 mIsPending = true;
416 nsresult rv = OpenCacheEntry(mURI, nsICacheStorage::OPEN_READONLY |
417 nsICacheStorage::CHECK_MULTITHREADED);
418 if (NS_FAILED(rv)) {
419 LOG(("nsWyciwygChannel::OpenCacheEntry failed [rv=%x]\n", rv));
420 mIsPending = false;
421 return rv;
422 }
424 // There is no code path that would invoke the listener sooner than
425 // we get to this line in case OnCacheEntryAvailable is invoked
426 // synchronously.
427 mListener = listener;
428 mListenerContext = ctx;
430 if (mLoadGroup)
431 mLoadGroup->AddRequest(this, nullptr);
433 return NS_OK;
434 }
436 //////////////////////////////////////////////////////////////////////////////
437 // nsIWyciwygChannel
438 //////////////////////////////////////////////////////////////////////////////
440 nsresult
441 nsWyciwygChannel::EnsureWriteCacheEntry()
442 {
443 MOZ_ASSERT(mMode == WRITING, "nsWyciwygChannel not open for writing");
445 if (!mCacheEntry) {
446 // OPEN_TRUNCATE will give us the entry instantly
447 nsresult rv = OpenCacheEntry(mURI, nsICacheStorage::OPEN_TRUNCATE);
448 if (NS_FAILED(rv) || !mCacheEntry) {
449 LOG((" could not synchronously open cache entry for write!"));
450 return NS_ERROR_FAILURE;
451 }
452 }
454 return NS_OK;
455 }
457 NS_IMETHODIMP
458 nsWyciwygChannel::WriteToCacheEntry(const nsAString &aData)
459 {
460 if (mMode == READING) {
461 LOG(("nsWyciwygChannel::WriteToCacheEntry already open for reading"));
462 MOZ_ASSERT(false);
463 return NS_ERROR_UNEXPECTED;
464 }
466 mMode = WRITING;
468 if (mozilla::net::CacheObserver::UseNewCache()) {
469 nsresult rv = EnsureWriteCacheEntry();
470 if (NS_FAILED(rv)) return rv;
471 }
473 return mCacheIOTarget->Dispatch(new nsWyciwygWriteEvent(this, aData),
474 NS_DISPATCH_NORMAL);
475 }
477 nsresult
478 nsWyciwygChannel::WriteToCacheEntryInternal(const nsAString &aData)
479 {
480 LOG(("nsWyciwygChannel::WriteToCacheEntryInternal [this=%p]", this));
481 NS_ASSERTION(IsOnCacheIOThread(), "wrong thread");
483 nsresult rv;
485 // With the new cache entry this will just pass as a no-op since we
486 // are opening the entry in WriteToCacheEntry.
487 rv = EnsureWriteCacheEntry();
488 if (NS_WARN_IF(NS_FAILED(rv))) {
489 return rv;
490 }
492 if (mLoadFlags & INHIBIT_PERSISTENT_CACHING) {
493 rv = mCacheEntry->SetMetaDataElement("inhibit-persistent-caching", "1");
494 if (NS_FAILED(rv)) return rv;
495 }
497 if (mSecurityInfo) {
498 mCacheEntry->SetSecurityInfo(mSecurityInfo);
499 }
501 if (mNeedToWriteCharset) {
502 WriteCharsetAndSourceToCache(mCharsetSource, mCharset);
503 mNeedToWriteCharset = false;
504 }
506 uint32_t out;
507 if (!mCacheOutputStream) {
508 // Get the outputstream from the cache entry.
509 rv = mCacheEntry->OpenOutputStream(0, getter_AddRefs(mCacheOutputStream));
510 if (NS_FAILED(rv)) return rv;
512 // Write out a Byte Order Mark, so that we'll know if the data is
513 // BE or LE when we go to read it.
514 char16_t bom = 0xFEFF;
515 rv = mCacheOutputStream->Write((char *)&bom, sizeof(bom), &out);
516 if (NS_FAILED(rv)) return rv;
517 }
519 return mCacheOutputStream->Write((const char *)PromiseFlatString(aData).get(),
520 aData.Length() * sizeof(char16_t), &out);
521 }
524 NS_IMETHODIMP
525 nsWyciwygChannel::CloseCacheEntry(nsresult reason)
526 {
527 return mCacheIOTarget->Dispatch(new nsWyciwygCloseEvent(this, reason),
528 NS_DISPATCH_NORMAL);
529 }
531 nsresult
532 nsWyciwygChannel::CloseCacheEntryInternal(nsresult reason)
533 {
534 NS_ASSERTION(IsOnCacheIOThread(), "wrong thread");
536 if (mCacheEntry) {
537 LOG(("nsWyciwygChannel::CloseCacheEntryInternal [this=%p ]", this));
538 mCacheOutputStream = 0;
539 mCacheInputStream = 0;
541 if (NS_FAILED(reason))
542 mCacheEntry->AsyncDoom(nullptr); // here we were calling Doom() ...
544 mCacheEntry = 0;
545 }
546 return NS_OK;
547 }
549 NS_IMETHODIMP
550 nsWyciwygChannel::SetSecurityInfo(nsISupports *aSecurityInfo)
551 {
552 mSecurityInfo = aSecurityInfo;
554 return NS_OK;
555 }
557 NS_IMETHODIMP
558 nsWyciwygChannel::SetCharsetAndSource(int32_t aSource,
559 const nsACString& aCharset)
560 {
561 NS_ENSURE_ARG(!aCharset.IsEmpty());
563 mCharsetAndSourceSet = true;
564 mCharset = aCharset;
565 mCharsetSource = aSource;
567 return mCacheIOTarget->Dispatch(new nsWyciwygSetCharsetandSourceEvent(this),
568 NS_DISPATCH_NORMAL);
569 }
571 void
572 nsWyciwygChannel::SetCharsetAndSourceInternal()
573 {
574 NS_ASSERTION(IsOnCacheIOThread(), "wrong thread");
576 if (mCacheEntry) {
577 WriteCharsetAndSourceToCache(mCharsetSource, mCharset);
578 } else {
579 mNeedToWriteCharset = true;
580 }
581 }
583 NS_IMETHODIMP
584 nsWyciwygChannel::GetCharsetAndSource(int32_t* aSource, nsACString& aCharset)
585 {
586 if (mCharsetAndSourceSet) {
587 *aSource = mCharsetSource;
588 aCharset = mCharset;
589 return NS_OK;
590 }
592 if (!mCacheEntry) {
593 return NS_ERROR_NOT_AVAILABLE;
594 }
596 nsXPIDLCString data;
597 mCacheEntry->GetMetaDataElement("charset", getter_Copies(data));
599 if (data.IsEmpty()) {
600 return NS_ERROR_NOT_AVAILABLE;
601 }
603 nsXPIDLCString sourceStr;
604 mCacheEntry->GetMetaDataElement("charset-source", getter_Copies(sourceStr));
606 int32_t source;
607 nsresult err;
608 source = sourceStr.ToInteger(&err);
609 if (NS_FAILED(err) || source == 0) {
610 return NS_ERROR_NOT_AVAILABLE;
611 }
613 *aSource = source;
614 aCharset = data;
615 return NS_OK;
616 }
618 //////////////////////////////////////////////////////////////////////////////
619 // nsICacheEntryOpenCallback
620 //////////////////////////////////////////////////////////////////////////////
622 NS_IMETHODIMP
623 nsWyciwygChannel::OnCacheEntryCheck(nsICacheEntry* entry, nsIApplicationCache* appCache,
624 uint32_t* aResult)
625 {
626 *aResult = ENTRY_WANTED;
627 return NS_OK;
628 }
630 NS_IMETHODIMP
631 nsWyciwygChannel::OnCacheEntryAvailable(nsICacheEntry *aCacheEntry,
632 bool aNew,
633 nsIApplicationCache* aAppCache,
634 nsresult aStatus)
635 {
636 LOG(("nsWyciwygChannel::OnCacheEntryAvailable [this=%p entry=%p "
637 "new=%d status=%x]\n", this, aCacheEntry, aNew, aStatus));
639 // if the channel's already fired onStopRequest,
640 // then we should ignore this event.
641 if (!mIsPending && !aNew)
642 return NS_OK;
644 // otherwise, we have to handle this event.
645 if (NS_SUCCEEDED(aStatus))
646 mCacheEntry = aCacheEntry;
647 else if (NS_SUCCEEDED(mStatus))
648 mStatus = aStatus;
650 nsresult rv = NS_OK;
651 if (NS_FAILED(mStatus)) {
652 LOG(("channel was canceled [this=%p status=%x]\n", this, mStatus));
653 rv = mStatus;
654 }
655 else if (!aNew) { // advance to the next state...
656 rv = ReadFromCache();
657 }
659 // a failure from Connect means that we have to abort the channel.
660 if (NS_FAILED(rv)) {
661 CloseCacheEntry(rv);
663 if (!aNew) {
664 // Since OnCacheEntryAvailable can be called directly from AsyncOpen
665 // we must dispatch.
666 NS_DispatchToCurrentThread(NS_NewRunnableMethod(
667 this, &nsWyciwygChannel::NotifyListener));
668 }
669 }
671 return NS_OK;
672 }
674 //-----------------------------------------------------------------------------
675 // nsWyciwygChannel::nsIStreamListener
676 //-----------------------------------------------------------------------------
678 NS_IMETHODIMP
679 nsWyciwygChannel::OnDataAvailable(nsIRequest *request, nsISupports *ctx,
680 nsIInputStream *input,
681 uint64_t offset, uint32_t count)
682 {
683 LOG(("nsWyciwygChannel::OnDataAvailable [this=%p request=%x offset=%llu count=%u]\n",
684 this, request, offset, count));
686 nsresult rv;
688 rv = mListener->OnDataAvailable(this, mListenerContext, input, offset, count);
690 // XXX handle 64-bit stuff for real
691 if (mProgressSink && NS_SUCCEEDED(rv) && !(mLoadFlags & LOAD_BACKGROUND))
692 mProgressSink->OnProgress(this, nullptr, offset + count,
693 uint64_t(mContentLength));
695 return rv; // let the pump cancel on failure
696 }
698 //////////////////////////////////////////////////////////////////////////////
699 // nsIRequestObserver
700 //////////////////////////////////////////////////////////////////////////////
702 NS_IMETHODIMP
703 nsWyciwygChannel::OnStartRequest(nsIRequest *request, nsISupports *ctx)
704 {
705 LOG(("nsWyciwygChannel::OnStartRequest [this=%p request=%x\n",
706 this, request));
708 return mListener->OnStartRequest(this, mListenerContext);
709 }
712 NS_IMETHODIMP
713 nsWyciwygChannel::OnStopRequest(nsIRequest *request, nsISupports *ctx, nsresult status)
714 {
715 LOG(("nsWyciwygChannel::OnStopRequest [this=%p request=%x status=%d\n",
716 this, request, status));
718 if (NS_SUCCEEDED(mStatus))
719 mStatus = status;
721 mListener->OnStopRequest(this, mListenerContext, mStatus);
722 mListener = 0;
723 mListenerContext = 0;
725 if (mLoadGroup)
726 mLoadGroup->RemoveRequest(this, nullptr, mStatus);
728 CloseCacheEntry(mStatus);
729 mPump = 0;
730 mIsPending = false;
732 // Drop notification callbacks to prevent cycles.
733 mCallbacks = 0;
734 mProgressSink = 0;
736 return NS_OK;
737 }
739 //////////////////////////////////////////////////////////////////////////////
740 // Helper functions
741 //////////////////////////////////////////////////////////////////////////////
743 nsresult
744 nsWyciwygChannel::OpenCacheEntry(nsIURI *aURI,
745 uint32_t aOpenFlags)
746 {
747 nsresult rv;
749 nsCOMPtr<nsICacheStorageService> cacheService =
750 do_GetService("@mozilla.org/netwerk/cache-storage-service;1", &rv);
751 NS_ENSURE_SUCCESS(rv, rv);
753 bool anonymous = mLoadFlags & LOAD_ANONYMOUS;
754 nsRefPtr<LoadContextInfo> loadInfo = mozilla::net::GetLoadContextInfo(
755 mPrivateBrowsing, mAppId, mInBrowser, anonymous);
757 nsCOMPtr<nsICacheStorage> cacheStorage;
758 if (mLoadFlags & INHIBIT_PERSISTENT_CACHING)
759 rv = cacheService->MemoryCacheStorage(loadInfo, getter_AddRefs(cacheStorage));
760 else
761 rv = cacheService->DiskCacheStorage(loadInfo, false, getter_AddRefs(cacheStorage));
762 NS_ENSURE_SUCCESS(rv, rv);
764 rv = cacheStorage->AsyncOpenURI(aURI, EmptyCString(), aOpenFlags, this);
765 NS_ENSURE_SUCCESS(rv, rv);
767 return NS_OK;
768 }
770 nsresult
771 nsWyciwygChannel::ReadFromCache()
772 {
773 LOG(("nsWyciwygChannel::ReadFromCache [this=%p] ", this));
775 NS_ENSURE_TRUE(mCacheEntry, NS_ERROR_FAILURE);
776 nsresult rv;
778 // Get the stored security info
779 mCacheEntry->GetSecurityInfo(getter_AddRefs(mSecurityInfo));
781 nsAutoCString tmpStr;
782 rv = mCacheEntry->GetMetaDataElement("inhibit-persistent-caching",
783 getter_Copies(tmpStr));
784 if (NS_SUCCEEDED(rv) && tmpStr == NS_LITERAL_CSTRING("1"))
785 mLoadFlags |= INHIBIT_PERSISTENT_CACHING;
787 // Get a transport to the cached data...
788 rv = mCacheEntry->OpenInputStream(0, getter_AddRefs(mCacheInputStream));
789 if (NS_FAILED(rv))
790 return rv;
791 NS_ENSURE_TRUE(mCacheInputStream, NS_ERROR_UNEXPECTED);
793 rv = NS_NewInputStreamPump(getter_AddRefs(mPump), mCacheInputStream);
794 if (NS_FAILED(rv)) return rv;
796 // Pump the cache data downstream
797 return mPump->AsyncRead(this, nullptr);
798 }
800 void
801 nsWyciwygChannel::WriteCharsetAndSourceToCache(int32_t aSource,
802 const nsCString& aCharset)
803 {
804 NS_ASSERTION(IsOnCacheIOThread(), "wrong thread");
805 NS_PRECONDITION(mCacheEntry, "Better have cache entry!");
807 mCacheEntry->SetMetaDataElement("charset", aCharset.get());
809 nsAutoCString source;
810 source.AppendInt(aSource);
811 mCacheEntry->SetMetaDataElement("charset-source", source.get());
812 }
814 void
815 nsWyciwygChannel::NotifyListener()
816 {
817 if (mListener) {
818 mListener->OnStartRequest(this, mListenerContext);
819 mListener->OnStopRequest(this, mListenerContext, mStatus);
820 mListener = 0;
821 mListenerContext = 0;
822 }
824 mIsPending = false;
826 // Remove ourselves from the load group.
827 if (mLoadGroup) {
828 mLoadGroup->RemoveRequest(this, nullptr, mStatus);
829 }
830 }
832 bool
833 nsWyciwygChannel::IsOnCacheIOThread()
834 {
835 bool correctThread;
836 mCacheIOTarget->IsOnCurrentThread(&correctThread);
837 return correctThread;
838 }
840 // vim: ts=2 sw=2