Bug Summary

File:root/firefox-clang/obj-x86_64-pc-linux-gnu/dom/webbrowserpersist/./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp
Warning:line 1656, column 9
Value stored to 'rv' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -O2 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name Unified_cpp_webbrowserpersist0.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/dom/webbrowserpersist -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/dom/webbrowserpersist -resource-dir /usr/lib/llvm-23/lib/clang/23 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -D _GLIBCXX_ASSERTIONS=1 -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /root/firefox-clang/dom/webbrowserpersist -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dom/webbrowserpersist -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/ipc/ipdl/_ipdlheaders -I /root/firefox-clang/ipc/chromium/src -I /root/firefox-clang/third_party/abseil-cpp -I /root/firefox-clang/toolkit/components/telemetry -I /root/firefox-clang/xpcom/base -I /root/firefox-clang/docshell/shistory -I /root/firefox-clang/dom/base -I /root/firefox-clang/dom/html -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/x86_64-linux-gnu/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16/backward -internal-isystem /usr/lib/llvm-23/lib/clang/23/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-error=pessimizing-move -Wno-error=large-by-value-copy=128 -Wno-error=implicit-int-float-conversion -Wno-error=thread-safety-analysis -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -Wno-character-conversion -std=gnu++20 -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fno-implicit-modules -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -fdiagnostics-absolute-paths -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -mllvm -dwarf-linkage-names=Abstract -faddrsig -fdwarf2-cfi-asm -o /tmp/scan-build-2026-09-01-224014-2642839-1 -x c++ Unified_cpp_webbrowserpersist0.cpp
1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5#include "nsWebBrowserPersist.h"
6
7#include <algorithm>
8
9#include "ReferrerInfo.h"
10#include "WebBrowserPersistLocalDocument.h"
11#include "mozilla/Base64.h"
12#include "mozilla/Mutex.h"
13#include "mozilla/Printf.h"
14#include "mozilla/RandomNum.h"
15#include "mozilla/TextUtils.h"
16#include "mozilla/WebBrowserPersistDocumentParent.h"
17#include "mozilla/dom/BrowserParent.h"
18#include "mozilla/dom/CanonicalBrowsingContext.h"
19#include "mozilla/dom/ContentParent.h"
20#include "mozilla/dom/Document.h"
21#include "mozilla/dom/PContentParent.h"
22#include "mozilla/dom/WindowGlobalParent.h"
23#include "mozilla/net/CookieJarSettings.h"
24#include "nsCExternalHandlerService.h"
25#include "nsComponentManagerUtils.h"
26#include "nsContentUtils.h"
27#include "nsEscape.h"
28#include "nsIAuthPrompt.h"
29#include "nsICacheInfoChannel.h"
30#include "nsIClassOfService.h"
31#include "nsIContent.h"
32#include "nsIDocumentEncoder.h"
33#include "nsIEncodedChannel.h"
34#include "nsIFileChannel.h"
35#include "nsIFileStreams.h" // New Necko file streams
36#include "nsIFileURL.h"
37#include "nsIHttpChannel.h"
38#include "nsIInterfaceRequestorUtils.h"
39#include "nsIMIMEInfo.h"
40#include "nsIPrivateBrowsingChannel.h"
41#include "nsIPrompt.h"
42#include "nsIProtocolHandler.h"
43#include "nsISeekableStream.h"
44#include "nsIStorageStream.h"
45#include "nsIStringBundle.h"
46#include "nsIStringEnumerator.h"
47#include "nsIThreadRetargetableRequest.h"
48#include "nsIURIMutator.h"
49#include "nsIURL.h"
50#include "nsIUploadChannel.h"
51#include "nsIWebProgressListener.h"
52#include "nsNetCID.h"
53#include "nsNetUtil.h"
54#include "nsStreamUtils.h"
55#include "nspr.h"
56
57#ifdef XP_WIN
58# include "WinUtils.h"
59#endif // XP_WIN
60
61using namespace mozilla;
62using namespace mozilla::dom;
63
64// Buffer file writes in 32kb chunks
65#define BUFFERED_OUTPUT_SIZE(1024 * 32) (1024 * 32)
66
67struct nsWebBrowserPersist::WalkData {
68 nsCOMPtr<nsIWebBrowserPersistDocument> mDocument;
69 nsCOMPtr<nsIURI> mFile;
70 nsCOMPtr<nsIURI> mDataPath;
71};
72
73// Information about a DOM document
74struct nsWebBrowserPersist::DocData {
75 nsCOMPtr<nsIURI> mBaseURI;
76 nsCOMPtr<nsIWebBrowserPersistDocument> mDocument;
77 nsCOMPtr<nsIURI> mFile;
78 nsCString mCharset;
79};
80
81// Information about a URI
82struct nsWebBrowserPersist::URIData {
83 bool mNeedsPersisting;
84 bool mSaved;
85 bool mIsSubFrame;
86 bool mDataPathIsRelative;
87 bool mNeedsFixup;
88 nsString mFilename;
89 nsString mSubFrameExt;
90 nsCOMPtr<nsIURI> mFile;
91 nsCOMPtr<nsIURI> mDataPath;
92 nsCOMPtr<nsIURI> mRelativeDocumentURI;
93 nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
94 nsCOMPtr<nsICookieJarSettings> mCookieJarSettings;
95 nsContentPolicyType mContentPolicyType;
96 nsCString mRelativePathToData;
97 nsCString mCharset;
98
99 nsresult GetLocalURI(nsIURI* targetBaseURI, nsCString& aSpecOut);
100};
101
102// Information about the output stream
103// Note that this data structure (and the map that nsWebBrowserPersist keeps,
104// where these are values) is used from two threads: the main thread,
105// and the background task thread.
106// The background thread only writes to mStream (from OnDataAvailable), and
107// this access is guarded using mStreamMutex. It reads the mFile member, which
108// is only written to on the main thread when the object is constructed and
109// from OnStartRequest (if mCalcFileExt), both guaranteed to happen before
110// OnDataAvailable is fired.
111// The main thread gets OnStartRequest, OnStopRequest, and progress sink events,
112// and accesses the other members.
113struct nsWebBrowserPersist::OutputData {
114 nsCOMPtr<nsIURI> mFile;
115 nsCOMPtr<nsIURI> mOriginalLocation;
116 nsCOMPtr<nsIOutputStream> mStream;
117 Mutex mStreamMutex MOZ_UNANNOTATED;
118 int64_t mSelfProgress;
119 int64_t mSelfProgressMax;
120 bool mCalcFileExt;
121
122 OutputData(nsIURI* aFile, nsIURI* aOriginalLocation, bool aCalcFileExt)
123 : mFile(aFile),
124 mOriginalLocation(aOriginalLocation),
125 mStreamMutex("nsWebBrowserPersist::OutputData::mStreamMutex"),
126 mSelfProgress(0),
127 mSelfProgressMax(10000),
128 mCalcFileExt(aCalcFileExt) {}
129 ~OutputData() {
130 // Gaining this lock in the destructor is pretty icky. It should be OK
131 // because the only other place we lock the mutex is in OnDataAvailable,
132 // which will never itself cause the OutputData instance to be
133 // destroyed.
134 MutexAutoLock lock(mStreamMutex);
135 if (mStream) {
136 mStream->Close();
137 }
138 }
139};
140
141struct nsWebBrowserPersist::UploadData {
142 nsCOMPtr<nsIURI> mFile;
143 int64_t mSelfProgress;
144 int64_t mSelfProgressMax;
145
146 explicit UploadData(nsIURI* aFile)
147 : mFile(aFile), mSelfProgress(0), mSelfProgressMax(10000) {}
148};
149
150struct nsWebBrowserPersist::CleanupData {
151 nsCOMPtr<nsIFile> mFile;
152 // Snapshot of what the file actually is at the time of creation so that if
153 // it transmutes into something else later on it can be ignored. For example,
154 // catch files that turn into dirs or vice versa.
155 bool mIsDirectory;
156};
157
158class nsWebBrowserPersist::OnWalk final
159 : public nsIWebBrowserPersistResourceVisitor {
160 public:
161 OnWalk(nsWebBrowserPersist* aParent, nsIURI* aFile, nsIFile* aDataPath)
162 : mParent(aParent),
163 mFile(aFile),
164 mDataPath(aDataPath),
165 mPendingDocuments(1),
166 mStatus(NS_OK) {}
167
168 NS_DECL_NSIWEBBROWSERPERSISTRESOURCEVISITORvirtual nsresult VisitResource(nsIWebBrowserPersistDocument *
aDocument, const nsACString& aURI, nsContentPolicyType aContentPolicyType
) override; virtual nsresult VisitDocument(nsIWebBrowserPersistDocument
*aDocument, nsIWebBrowserPersistDocument *aSubDocument) override
; virtual nsresult VisitBrowsingContext(nsIWebBrowserPersistDocument
*aDocument, mozilla::dom::BrowsingContext *aContext) override
; virtual nsresult EndVisit(nsIWebBrowserPersistDocument *aDocument
, nsresult aStatus) override;
169 NS_DECL_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID
, void** aInstancePtr) override; virtual MozExternalRefCountType
AddRef(void) override; virtual MozExternalRefCountType Release
(void) override; using HasThreadSafeRefCnt = std::false_type;
protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread _mOwningThread
; public:
170 private:
171 RefPtr<nsWebBrowserPersist> mParent;
172 nsCOMPtr<nsIURI> mFile;
173 nsCOMPtr<nsIFile> mDataPath;
174
175 uint32_t mPendingDocuments;
176 nsresult mStatus;
177
178 virtual ~OnWalk() = default;
179};
180
181NS_IMPL_ISUPPORTS(nsWebBrowserPersist::OnWalk,MozExternalRefCountType nsWebBrowserPersist::OnWalk::AddRef(void
) { static_assert(!std::is_destructible_v<nsWebBrowserPersist
::OnWalk>, "Reference-counted class " "nsWebBrowserPersist::OnWalk"
" should not have a public destructor. " "Make this class's destructor non-public"
); do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 182); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 182
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsWebBrowserPersist::OnWalk" != nullptr)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!("nsWebBrowserPersist::OnWalk" != nullptr))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("\"nsWebBrowserPersist::OnWalk\" != nullptr"
" (" "Must specify a name" ")", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 182); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsWebBrowserPersist::OnWalk\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 182); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("nsWebBrowserPersist::OnWalk" " not thread-safe"); nsrefcnt count
= ++mRefCnt; NS_LogAddRef((this), (count), ("nsWebBrowserPersist::OnWalk"
), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType
nsWebBrowserPersist::OnWalk::Release(void) { do { static_assert
( mozilla::detail::AssertionConditionType<decltype(int32_t
(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 182); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 182
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsWebBrowserPersist::OnWalk" != nullptr)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!("nsWebBrowserPersist::OnWalk" != nullptr))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("\"nsWebBrowserPersist::OnWalk\" != nullptr"
" (" "Must specify a name" ")", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 182); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsWebBrowserPersist::OnWalk\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 182); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("nsWebBrowserPersist::OnWalk" " not thread-safe"); const char
* const nametmp = "nsWebBrowserPersist::OnWalk"; nsrefcnt count
= --mRefCnt; NS_LogRelease((this), (count), (nametmp)); if (
count == 0) { mRefCnt = 1; delete (this); return 0; } return count
; } nsresult nsWebBrowserPersist::OnWalk::QueryInterface(const
nsIID& aIID, void** aInstancePtr) { do { if (!(aInstancePtr
)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 182); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(1 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<nsWebBrowserPersist::OnWalk, nsIWebBrowserPersistResourceVisitor
>, int32_t( reinterpret_cast<char*>(static_cast<nsIWebBrowserPersistResourceVisitor
*>((nsWebBrowserPersist::OnWalk*)0x1000)) - reinterpret_cast
<char*>((nsWebBrowserPersist::OnWalk*)0x1000))}, {&
mozilla::detail::kImplementedIID<nsWebBrowserPersist::OnWalk
, nsISupports>, int32_t(reinterpret_cast<char*>(static_cast
<nsISupports*>( static_cast<nsIWebBrowserPersistResourceVisitor
*>((nsWebBrowserPersist::OnWalk*)0x1000))) - reinterpret_cast
<char*>((nsWebBrowserPersist::OnWalk*)0x1000))}, { nullptr
, 0 } } ; static_assert(std::size(table) > 1, "need at least 1 interface"
); rv = NS_TableDrivenQI(static_cast<void*>(this), aIID
, aInstancePtr, table); return rv; }
182 nsIWebBrowserPersistResourceVisitor)MozExternalRefCountType nsWebBrowserPersist::OnWalk::AddRef(void
) { static_assert(!std::is_destructible_v<nsWebBrowserPersist
::OnWalk>, "Reference-counted class " "nsWebBrowserPersist::OnWalk"
" should not have a public destructor. " "Make this class's destructor non-public"
); do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 182); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 182
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsWebBrowserPersist::OnWalk" != nullptr)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!("nsWebBrowserPersist::OnWalk" != nullptr))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("\"nsWebBrowserPersist::OnWalk\" != nullptr"
" (" "Must specify a name" ")", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 182); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsWebBrowserPersist::OnWalk\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 182); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("nsWebBrowserPersist::OnWalk" " not thread-safe"); nsrefcnt count
= ++mRefCnt; NS_LogAddRef((this), (count), ("nsWebBrowserPersist::OnWalk"
), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType
nsWebBrowserPersist::OnWalk::Release(void) { do { static_assert
( mozilla::detail::AssertionConditionType<decltype(int32_t
(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 182); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 182
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsWebBrowserPersist::OnWalk" != nullptr)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!("nsWebBrowserPersist::OnWalk" != nullptr))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("\"nsWebBrowserPersist::OnWalk\" != nullptr"
" (" "Must specify a name" ")", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 182); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsWebBrowserPersist::OnWalk\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 182); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("nsWebBrowserPersist::OnWalk" " not thread-safe"); const char
* const nametmp = "nsWebBrowserPersist::OnWalk"; nsrefcnt count
= --mRefCnt; NS_LogRelease((this), (count), (nametmp)); if (
count == 0) { mRefCnt = 1; delete (this); return 0; } return count
; } nsresult nsWebBrowserPersist::OnWalk::QueryInterface(const
nsIID& aIID, void** aInstancePtr) { do { if (!(aInstancePtr
)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 182); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(1 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<nsWebBrowserPersist::OnWalk, nsIWebBrowserPersistResourceVisitor
>, int32_t( reinterpret_cast<char*>(static_cast<nsIWebBrowserPersistResourceVisitor
*>((nsWebBrowserPersist::OnWalk*)0x1000)) - reinterpret_cast
<char*>((nsWebBrowserPersist::OnWalk*)0x1000))}, {&
mozilla::detail::kImplementedIID<nsWebBrowserPersist::OnWalk
, nsISupports>, int32_t(reinterpret_cast<char*>(static_cast
<nsISupports*>( static_cast<nsIWebBrowserPersistResourceVisitor
*>((nsWebBrowserPersist::OnWalk*)0x1000))) - reinterpret_cast
<char*>((nsWebBrowserPersist::OnWalk*)0x1000))}, { nullptr
, 0 } } ; static_assert(std::size(table) > 1, "need at least 1 interface"
); rv = NS_TableDrivenQI(static_cast<void*>(this), aIID
, aInstancePtr, table); return rv; }
183
184class nsWebBrowserPersist::OnRemoteWalk final
185 : public nsIWebBrowserPersistDocumentReceiver {
186 public:
187 OnRemoteWalk(nsIWebBrowserPersistResourceVisitor* aVisitor,
188 nsIWebBrowserPersistDocument* aDocument)
189 : mVisitor(aVisitor), mDocument(aDocument) {}
190
191 NS_DECL_NSIWEBBROWSERPERSISTDOCUMENTRECEIVERvirtual nsresult OnDocumentReady(nsIWebBrowserPersistDocument
*aDocument) override; virtual nsresult OnError(nsresult aFailure
) override;
192 NS_DECL_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID
, void** aInstancePtr) override; virtual MozExternalRefCountType
AddRef(void) override; virtual MozExternalRefCountType Release
(void) override; using HasThreadSafeRefCnt = std::false_type;
protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread _mOwningThread
; public:
193 private:
194 nsCOMPtr<nsIWebBrowserPersistResourceVisitor> mVisitor;
195 nsCOMPtr<nsIWebBrowserPersistDocument> mDocument;
196
197 virtual ~OnRemoteWalk() = default;
198};
199
200NS_IMPL_ISUPPORTS(nsWebBrowserPersist::OnRemoteWalk,MozExternalRefCountType nsWebBrowserPersist::OnRemoteWalk::AddRef
(void) { static_assert(!std::is_destructible_v<nsWebBrowserPersist
::OnRemoteWalk>, "Reference-counted class " "nsWebBrowserPersist::OnRemoteWalk"
" should not have a public destructor. " "Make this class's destructor non-public"
); do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 201); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 201
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsWebBrowserPersist::OnRemoteWalk" != nullptr)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!("nsWebBrowserPersist::OnRemoteWalk" != nullptr))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("\"nsWebBrowserPersist::OnRemoteWalk\" != nullptr"
" (" "Must specify a name" ")", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 201); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsWebBrowserPersist::OnRemoteWalk\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 201); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("nsWebBrowserPersist::OnRemoteWalk" " not thread-safe"); nsrefcnt
count = ++mRefCnt; NS_LogAddRef((this), (count), ("nsWebBrowserPersist::OnRemoteWalk"
), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType
nsWebBrowserPersist::OnRemoteWalk::Release(void) { do { static_assert
( mozilla::detail::AssertionConditionType<decltype(int32_t
(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 201); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 201
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsWebBrowserPersist::OnRemoteWalk" != nullptr)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!("nsWebBrowserPersist::OnRemoteWalk" != nullptr))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("\"nsWebBrowserPersist::OnRemoteWalk\" != nullptr"
" (" "Must specify a name" ")", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 201); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsWebBrowserPersist::OnRemoteWalk\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 201); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("nsWebBrowserPersist::OnRemoteWalk" " not thread-safe"); const
char* const nametmp = "nsWebBrowserPersist::OnRemoteWalk"; nsrefcnt
count = --mRefCnt; NS_LogRelease((this), (count), (nametmp))
; if (count == 0) { mRefCnt = 1; delete (this); return 0; } return
count; } nsresult nsWebBrowserPersist::OnRemoteWalk::QueryInterface
(const nsIID& aIID, void** aInstancePtr) { do { if (!(aInstancePtr
)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 201); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(1 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<nsWebBrowserPersist::OnRemoteWalk, nsIWebBrowserPersistDocumentReceiver
>, int32_t( reinterpret_cast<char*>(static_cast<nsIWebBrowserPersistDocumentReceiver
*>((nsWebBrowserPersist::OnRemoteWalk*)0x1000)) - reinterpret_cast
<char*>((nsWebBrowserPersist::OnRemoteWalk*)0x1000))}, {
&mozilla::detail::kImplementedIID<nsWebBrowserPersist::
OnRemoteWalk, nsISupports>, int32_t(reinterpret_cast<char
*>(static_cast<nsISupports*>( static_cast<nsIWebBrowserPersistDocumentReceiver
*>((nsWebBrowserPersist::OnRemoteWalk*)0x1000))) - reinterpret_cast
<char*>((nsWebBrowserPersist::OnRemoteWalk*)0x1000))}, {
nullptr, 0 } } ; static_assert(std::size(table) > 1, "need at least 1 interface"
); rv = NS_TableDrivenQI(static_cast<void*>(this), aIID
, aInstancePtr, table); return rv; }
201 nsIWebBrowserPersistDocumentReceiver)MozExternalRefCountType nsWebBrowserPersist::OnRemoteWalk::AddRef
(void) { static_assert(!std::is_destructible_v<nsWebBrowserPersist
::OnRemoteWalk>, "Reference-counted class " "nsWebBrowserPersist::OnRemoteWalk"
" should not have a public destructor. " "Make this class's destructor non-public"
); do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 201); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 201
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsWebBrowserPersist::OnRemoteWalk" != nullptr)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!("nsWebBrowserPersist::OnRemoteWalk" != nullptr))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("\"nsWebBrowserPersist::OnRemoteWalk\" != nullptr"
" (" "Must specify a name" ")", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 201); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsWebBrowserPersist::OnRemoteWalk\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 201); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("nsWebBrowserPersist::OnRemoteWalk" " not thread-safe"); nsrefcnt
count = ++mRefCnt; NS_LogAddRef((this), (count), ("nsWebBrowserPersist::OnRemoteWalk"
), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType
nsWebBrowserPersist::OnRemoteWalk::Release(void) { do { static_assert
( mozilla::detail::AssertionConditionType<decltype(int32_t
(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 201); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 201
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsWebBrowserPersist::OnRemoteWalk" != nullptr)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!("nsWebBrowserPersist::OnRemoteWalk" != nullptr))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("\"nsWebBrowserPersist::OnRemoteWalk\" != nullptr"
" (" "Must specify a name" ")", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 201); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsWebBrowserPersist::OnRemoteWalk\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 201); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("nsWebBrowserPersist::OnRemoteWalk" " not thread-safe"); const
char* const nametmp = "nsWebBrowserPersist::OnRemoteWalk"; nsrefcnt
count = --mRefCnt; NS_LogRelease((this), (count), (nametmp))
; if (count == 0) { mRefCnt = 1; delete (this); return 0; } return
count; } nsresult nsWebBrowserPersist::OnRemoteWalk::QueryInterface
(const nsIID& aIID, void** aInstancePtr) { do { if (!(aInstancePtr
)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 201); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(1 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<nsWebBrowserPersist::OnRemoteWalk, nsIWebBrowserPersistDocumentReceiver
>, int32_t( reinterpret_cast<char*>(static_cast<nsIWebBrowserPersistDocumentReceiver
*>((nsWebBrowserPersist::OnRemoteWalk*)0x1000)) - reinterpret_cast
<char*>((nsWebBrowserPersist::OnRemoteWalk*)0x1000))}, {
&mozilla::detail::kImplementedIID<nsWebBrowserPersist::
OnRemoteWalk, nsISupports>, int32_t(reinterpret_cast<char
*>(static_cast<nsISupports*>( static_cast<nsIWebBrowserPersistDocumentReceiver
*>((nsWebBrowserPersist::OnRemoteWalk*)0x1000))) - reinterpret_cast
<char*>((nsWebBrowserPersist::OnRemoteWalk*)0x1000))}, {
nullptr, 0 } } ; static_assert(std::size(table) > 1, "need at least 1 interface"
); rv = NS_TableDrivenQI(static_cast<void*>(this), aIID
, aInstancePtr, table); return rv; }
202
203class nsWebBrowserPersist::OnWrite final
204 : public nsIWebBrowserPersistWriteCompletion {
205 public:
206 OnWrite(nsWebBrowserPersist* aParent, nsIURI* aFile, nsIFile* aLocalFile)
207 : mParent(aParent), mFile(aFile), mLocalFile(aLocalFile) {}
208
209 NS_DECL_NSIWEBBROWSERPERSISTWRITECOMPLETIONvirtual nsresult OnFinish(nsIWebBrowserPersistDocument *aDocument
, nsIOutputStream *aStream, const nsACString& aContentType
, nsresult aStatus) override;
210 NS_DECL_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID
, void** aInstancePtr) override; virtual MozExternalRefCountType
AddRef(void) override; virtual MozExternalRefCountType Release
(void) override; using HasThreadSafeRefCnt = std::false_type;
protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread _mOwningThread
; public:
211 private:
212 RefPtr<nsWebBrowserPersist> mParent;
213 nsCOMPtr<nsIURI> mFile;
214 nsCOMPtr<nsIFile> mLocalFile;
215
216 virtual ~OnWrite() = default;
217};
218
219NS_IMPL_ISUPPORTS(nsWebBrowserPersist::OnWrite,MozExternalRefCountType nsWebBrowserPersist::OnWrite::AddRef(
void) { static_assert(!std::is_destructible_v<nsWebBrowserPersist
::OnWrite>, "Reference-counted class " "nsWebBrowserPersist::OnWrite"
" should not have a public destructor. " "Make this class's destructor non-public"
); do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 220); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 220
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsWebBrowserPersist::OnWrite" != nullptr)>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!("nsWebBrowserPersist::OnWrite" != nullptr))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("\"nsWebBrowserPersist::OnWrite\" != nullptr"
" (" "Must specify a name" ")", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 220); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsWebBrowserPersist::OnWrite\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 220); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("nsWebBrowserPersist::OnWrite" " not thread-safe"); nsrefcnt
count = ++mRefCnt; NS_LogAddRef((this), (count), ("nsWebBrowserPersist::OnWrite"
), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType
nsWebBrowserPersist::OnWrite::Release(void) { do { static_assert
( mozilla::detail::AssertionConditionType<decltype(int32_t
(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 220); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 220
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsWebBrowserPersist::OnWrite" != nullptr)>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!("nsWebBrowserPersist::OnWrite" != nullptr))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("\"nsWebBrowserPersist::OnWrite\" != nullptr"
" (" "Must specify a name" ")", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 220); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsWebBrowserPersist::OnWrite\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 220); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("nsWebBrowserPersist::OnWrite" " not thread-safe"); const char
* const nametmp = "nsWebBrowserPersist::OnWrite"; nsrefcnt count
= --mRefCnt; NS_LogRelease((this), (count), (nametmp)); if (
count == 0) { mRefCnt = 1; delete (this); return 0; } return count
; } nsresult nsWebBrowserPersist::OnWrite::QueryInterface(const
nsIID& aIID, void** aInstancePtr) { do { if (!(aInstancePtr
)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 220); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(1 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<nsWebBrowserPersist::OnWrite, nsIWebBrowserPersistWriteCompletion
>, int32_t( reinterpret_cast<char*>(static_cast<nsIWebBrowserPersistWriteCompletion
*>((nsWebBrowserPersist::OnWrite*)0x1000)) - reinterpret_cast
<char*>((nsWebBrowserPersist::OnWrite*)0x1000))}, {&
mozilla::detail::kImplementedIID<nsWebBrowserPersist::OnWrite
, nsISupports>, int32_t(reinterpret_cast<char*>(static_cast
<nsISupports*>( static_cast<nsIWebBrowserPersistWriteCompletion
*>((nsWebBrowserPersist::OnWrite*)0x1000))) - reinterpret_cast
<char*>((nsWebBrowserPersist::OnWrite*)0x1000))}, { nullptr
, 0 } } ; static_assert(std::size(table) > 1, "need at least 1 interface"
); rv = NS_TableDrivenQI(static_cast<void*>(this), aIID
, aInstancePtr, table); return rv; }
220 nsIWebBrowserPersistWriteCompletion)MozExternalRefCountType nsWebBrowserPersist::OnWrite::AddRef(
void) { static_assert(!std::is_destructible_v<nsWebBrowserPersist
::OnWrite>, "Reference-counted class " "nsWebBrowserPersist::OnWrite"
" should not have a public destructor. " "Make this class's destructor non-public"
); do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 220); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 220
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsWebBrowserPersist::OnWrite" != nullptr)>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!("nsWebBrowserPersist::OnWrite" != nullptr))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("\"nsWebBrowserPersist::OnWrite\" != nullptr"
" (" "Must specify a name" ")", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 220); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsWebBrowserPersist::OnWrite\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 220); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("nsWebBrowserPersist::OnWrite" " not thread-safe"); nsrefcnt
count = ++mRefCnt; NS_LogAddRef((this), (count), ("nsWebBrowserPersist::OnWrite"
), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType
nsWebBrowserPersist::OnWrite::Release(void) { do { static_assert
( mozilla::detail::AssertionConditionType<decltype(int32_t
(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 220); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 220
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsWebBrowserPersist::OnWrite" != nullptr)>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!("nsWebBrowserPersist::OnWrite" != nullptr))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("\"nsWebBrowserPersist::OnWrite\" != nullptr"
" (" "Must specify a name" ")", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 220); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsWebBrowserPersist::OnWrite\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 220); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("nsWebBrowserPersist::OnWrite" " not thread-safe"); const char
* const nametmp = "nsWebBrowserPersist::OnWrite"; nsrefcnt count
= --mRefCnt; NS_LogRelease((this), (count), (nametmp)); if (
count == 0) { mRefCnt = 1; delete (this); return 0; } return count
; } nsresult nsWebBrowserPersist::OnWrite::QueryInterface(const
nsIID& aIID, void** aInstancePtr) { do { if (!(aInstancePtr
)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 220); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(1 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<nsWebBrowserPersist::OnWrite, nsIWebBrowserPersistWriteCompletion
>, int32_t( reinterpret_cast<char*>(static_cast<nsIWebBrowserPersistWriteCompletion
*>((nsWebBrowserPersist::OnWrite*)0x1000)) - reinterpret_cast
<char*>((nsWebBrowserPersist::OnWrite*)0x1000))}, {&
mozilla::detail::kImplementedIID<nsWebBrowserPersist::OnWrite
, nsISupports>, int32_t(reinterpret_cast<char*>(static_cast
<nsISupports*>( static_cast<nsIWebBrowserPersistWriteCompletion
*>((nsWebBrowserPersist::OnWrite*)0x1000))) - reinterpret_cast
<char*>((nsWebBrowserPersist::OnWrite*)0x1000))}, { nullptr
, 0 } } ; static_assert(std::size(table) > 1, "need at least 1 interface"
); rv = NS_TableDrivenQI(static_cast<void*>(this), aIID
, aInstancePtr, table); return rv; }
221
222class nsWebBrowserPersist::FlatURIMap final
223 : public nsIWebBrowserPersistURIMap {
224 public:
225 explicit FlatURIMap(const nsACString& aTargetBase)
226 : mTargetBase(aTargetBase) {}
227
228 void Add(const nsACString& aMapFrom, const nsACString& aMapTo) {
229 mMapFrom.AppendElement(aMapFrom);
230 mMapTo.AppendElement(aMapTo);
231 }
232
233 NS_DECL_NSIWEBBROWSERPERSISTURIMAPvirtual nsresult GetNumMappedURIs(uint32_t *aNumMappedURIs) override
; virtual nsresult GetURIMapping(uint32_t aIndex, nsACString&
aMapFrom, nsACString& aMapTo) override; virtual nsresult
GetTargetBaseURI(nsACString& aTargetBaseURI) override;
234 NS_DECL_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID
, void** aInstancePtr) override; virtual MozExternalRefCountType
AddRef(void) override; virtual MozExternalRefCountType Release
(void) override; using HasThreadSafeRefCnt = std::false_type;
protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread _mOwningThread
; public:
235
236 private:
237 nsTArray<nsCString> mMapFrom;
238 nsTArray<nsCString> mMapTo;
239 nsCString mTargetBase;
240
241 virtual ~FlatURIMap() = default;
242};
243
244NS_IMPL_ISUPPORTS(nsWebBrowserPersist::FlatURIMap, nsIWebBrowserPersistURIMap)MozExternalRefCountType nsWebBrowserPersist::FlatURIMap::AddRef
(void) { static_assert(!std::is_destructible_v<nsWebBrowserPersist
::FlatURIMap>, "Reference-counted class " "nsWebBrowserPersist::FlatURIMap"
" should not have a public destructor. " "Make this class's destructor non-public"
); do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 244); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 244
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsWebBrowserPersist::FlatURIMap" != nullptr)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!("nsWebBrowserPersist::FlatURIMap" != nullptr))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("\"nsWebBrowserPersist::FlatURIMap\" != nullptr"
" (" "Must specify a name" ")", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 244); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsWebBrowserPersist::FlatURIMap\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 244); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("nsWebBrowserPersist::FlatURIMap" " not thread-safe"); nsrefcnt
count = ++mRefCnt; NS_LogAddRef((this), (count), ("nsWebBrowserPersist::FlatURIMap"
), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType
nsWebBrowserPersist::FlatURIMap::Release(void) { do { static_assert
( mozilla::detail::AssertionConditionType<decltype(int32_t
(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 244); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 244
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsWebBrowserPersist::FlatURIMap" != nullptr)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!("nsWebBrowserPersist::FlatURIMap" != nullptr))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("\"nsWebBrowserPersist::FlatURIMap\" != nullptr"
" (" "Must specify a name" ")", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 244); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsWebBrowserPersist::FlatURIMap\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 244); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("nsWebBrowserPersist::FlatURIMap" " not thread-safe"); const
char* const nametmp = "nsWebBrowserPersist::FlatURIMap"; nsrefcnt
count = --mRefCnt; NS_LogRelease((this), (count), (nametmp))
; if (count == 0) { mRefCnt = 1; delete (this); return 0; } return
count; } nsresult nsWebBrowserPersist::FlatURIMap::QueryInterface
(const nsIID& aIID, void** aInstancePtr) { do { if (!(aInstancePtr
)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 244); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(1 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<nsWebBrowserPersist::FlatURIMap, nsIWebBrowserPersistURIMap
>, int32_t( reinterpret_cast<char*>(static_cast<nsIWebBrowserPersistURIMap
*>((nsWebBrowserPersist::FlatURIMap*)0x1000)) - reinterpret_cast
<char*>((nsWebBrowserPersist::FlatURIMap*)0x1000))}, {&
mozilla::detail::kImplementedIID<nsWebBrowserPersist::FlatURIMap
, nsISupports>, int32_t(reinterpret_cast<char*>(static_cast
<nsISupports*>( static_cast<nsIWebBrowserPersistURIMap
*>((nsWebBrowserPersist::FlatURIMap*)0x1000))) - reinterpret_cast
<char*>((nsWebBrowserPersist::FlatURIMap*)0x1000))}, { nullptr
, 0 } } ; static_assert(std::size(table) > 1, "need at least 1 interface"
); rv = NS_TableDrivenQI(static_cast<void*>(this), aIID
, aInstancePtr, table); return rv; }
245
246NS_IMETHODIMPnsresult
247nsWebBrowserPersist::FlatURIMap::GetNumMappedURIs(uint32_t* aNum) {
248 MOZ_ASSERT(mMapFrom.Length() == mMapTo.Length())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mMapFrom.Length() == mMapTo.Length())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mMapFrom.Length() == mMapTo.
Length()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mMapFrom.Length() == mMapTo.Length()", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 248); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mMapFrom.Length() == mMapTo.Length()"
")"); do { MOZ_CrashSequence(__null, 248); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
249 *aNum = mMapTo.Length();
250 return NS_OK;
251}
252
253NS_IMETHODIMPnsresult
254nsWebBrowserPersist::FlatURIMap::GetTargetBaseURI(nsACString& aTargetBase) {
255 aTargetBase = mTargetBase;
256 return NS_OK;
257}
258
259NS_IMETHODIMPnsresult
260nsWebBrowserPersist::FlatURIMap::GetURIMapping(uint32_t aIndex,
261 nsACString& aMapFrom,
262 nsACString& aMapTo) {
263 MOZ_ASSERT(mMapFrom.Length() == mMapTo.Length())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mMapFrom.Length() == mMapTo.Length())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mMapFrom.Length() == mMapTo.
Length()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mMapFrom.Length() == mMapTo.Length()", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 263); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mMapFrom.Length() == mMapTo.Length()"
")"); do { MOZ_CrashSequence(__null, 263); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
264 if (aIndex >= mMapTo.Length()) {
265 return NS_ERROR_INVALID_ARG;
266 }
267 aMapFrom = mMapFrom[aIndex];
268 aMapTo = mMapTo[aIndex];
269 return NS_OK;
270}
271
272// Maximum file length constant. The max file name length is
273// volume / server dependent but it is difficult to obtain
274// that information. Instead this constant is a reasonable value that
275// modern systems should able to cope with.
276const uint32_t kDefaultMaxFilenameLength = 64;
277
278// Default flags for persistence
279const uint32_t kDefaultPersistFlags =
280 nsIWebBrowserPersist::PERSIST_FLAGS_NO_CONVERSION |
281 nsIWebBrowserPersist::PERSIST_FLAGS_REPLACE_EXISTING_FILES;
282
283// String bundle where error messages come from
284const char* kWebBrowserPersistStringBundle =
285 "chrome://global/locale/nsWebBrowserPersist.properties";
286
287namespace {
288
289nsCString GenerateRandomSeed() {
290 constexpr size_t SEED_LEN = 3;
291 uint8_t buffer[SEED_LEN];
292 if (!mozilla::GenerateRandomBytesFromOS(buffer, SEED_LEN)) {
293 for (uint8_t& entry : buffer) {
294 Maybe<uint64_t> maybeSeed = mozilla::RandomUint64();
295 if (maybeSeed.isNothing()) {
296 return EmptyCString();
297 }
298 entry = static_cast<uint8_t>(maybeSeed.value());
299 }
300 }
301
302 nsAutoCString seed;
303 nsresult rv = Base64URLEncode(SEED_LEN, buffer,
304 Base64URLEncodePaddingPolicy::Omit, seed);
305 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 305)
) {
306 return EmptyCString();
307 }
308
309 // 3 bytes produce exactly 4 base64url chars (no padding needed); keep all
310 // 4 so the seed is distinguishable from the 3-digit uniqueness counter.
311 seed.Insert('_', 0);
312 return seed;
313}
314
315} // namespace
316
317nsWebBrowserPersist::nsWebBrowserPersist()
318 : mCurrentDataPathIsRelative(false),
319 mCurrentThingsToPersist(0),
320 mOutputMapMutex("nsWebBrowserPersist::mOutputMapMutex"),
321 mFirstAndOnlyUse(true),
322 mSavingDocument(false),
323 mCancel(false),
324 mEndCalled(false),
325 mCompleted(false),
326 mStartSaving(false),
327 mReplaceExisting(true),
328 mSerializingOutput(false),
329 mIsPrivate(false),
330 mPersistFlags(kDefaultPersistFlags),
331 mPersistResult(NS_OK),
332 mTotalCurrentProgress(0),
333 mTotalMaxProgress(0),
334 mWrapColumn(72),
335 mEncodingFlags(0),
336 mFilenameRandomSeed(GenerateRandomSeed()) {
337 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mFilenameRandomSeed.IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mFilenameRandomSeed.IsEmpty
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!mFilenameRandomSeed.IsEmpty()" " (" "Failed to generate random seed; saved filenames will be predictable"
")", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 339); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mFilenameRandomSeed.IsEmpty()"
") (" "Failed to generate random seed; saved filenames will be predictable"
")"); do { MOZ_CrashSequence(__null, 339); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
338 !mFilenameRandomSeed.IsEmpty(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mFilenameRandomSeed.IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mFilenameRandomSeed.IsEmpty
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!mFilenameRandomSeed.IsEmpty()" " (" "Failed to generate random seed; saved filenames will be predictable"
")", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 339); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mFilenameRandomSeed.IsEmpty()"
") (" "Failed to generate random seed; saved filenames will be predictable"
")"); do { MOZ_CrashSequence(__null, 339); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
339 "Failed to generate random seed; saved filenames will be predictable")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mFilenameRandomSeed.IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mFilenameRandomSeed.IsEmpty
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!mFilenameRandomSeed.IsEmpty()" " (" "Failed to generate random seed; saved filenames will be predictable"
")", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 339); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mFilenameRandomSeed.IsEmpty()"
") (" "Failed to generate random seed; saved filenames will be predictable"
")"); do { MOZ_CrashSequence(__null, 339); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
340}
341
342nsWebBrowserPersist::~nsWebBrowserPersist() { Cleanup(); }
343
344//*****************************************************************************
345// nsWebBrowserPersist::nsISupports
346//*****************************************************************************
347
348NS_IMPL_ADDREF(nsWebBrowserPersist)MozExternalRefCountType nsWebBrowserPersist::AddRef(void) { static_assert
(!std::is_destructible_v<nsWebBrowserPersist>, "Reference-counted class "
"nsWebBrowserPersist" " should not have a public destructor. "
"Make this class's destructor non-public"); do { static_assert
( mozilla::detail::AssertionConditionType<decltype(int32_t
(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 348); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 348
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsWebBrowserPersist" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("nsWebBrowserPersist" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"nsWebBrowserPersist\" != nullptr" " (" "Must specify a name"
")", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 348); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsWebBrowserPersist\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 348); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("nsWebBrowserPersist" " not thread-safe"); nsrefcnt count = ++
mRefCnt; NS_LogAddRef((this), (count), ("nsWebBrowserPersist"
), (uint32_t)(sizeof(*this))); return count; }
349NS_IMPL_RELEASE(nsWebBrowserPersist)MozExternalRefCountType nsWebBrowserPersist::Release(void) { do
{ static_assert( mozilla::detail::AssertionConditionType<
decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 349); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 349
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsWebBrowserPersist" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("nsWebBrowserPersist" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"nsWebBrowserPersist\" != nullptr" " (" "Must specify a name"
")", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 349); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsWebBrowserPersist\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 349); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("nsWebBrowserPersist" " not thread-safe"); const char* const
nametmp = "nsWebBrowserPersist"; nsrefcnt count = --mRefCnt;
NS_LogRelease((this), (count), (nametmp)); if (count == 0) {
mRefCnt = 1; delete (this); return 0; } return count; }
350
351NS_INTERFACE_MAP_BEGIN(nsWebBrowserPersist)nsresult nsWebBrowserPersist::QueryInterface(const nsIID&
aIID, void** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 351); MOZ_PretendNoReturn(); } } while (0); nsISupports* foundInterface
;
352 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWebBrowserPersist)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsISupports>)) foundInterface = static_cast
<nsISupports*>(static_cast<nsIWebBrowserPersist*>
(this)); else
353 NS_INTERFACE_MAP_ENTRY(nsIWebBrowserPersist)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIWebBrowserPersist>)) foundInterface
= static_cast<nsIWebBrowserPersist*>(this); else
354 NS_INTERFACE_MAP_ENTRY(nsICancelable)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsICancelable>)) foundInterface =
static_cast<nsICancelable*>(this); else
355 NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIInterfaceRequestor>)) foundInterface
= static_cast<nsIInterfaceRequestor*>(this); else
356 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsISupportsWeakReference>)) foundInterface
= static_cast<nsISupportsWeakReference*>(this); else
357 NS_INTERFACE_MAP_ENTRY(nsIStreamListener)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIStreamListener>)) foundInterface
= static_cast<nsIStreamListener*>(this); else
358 NS_INTERFACE_MAP_ENTRY(nsIThreadRetargetableStreamListener)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIThreadRetargetableStreamListener>
)) foundInterface = static_cast<nsIThreadRetargetableStreamListener
*>(this); else
359 NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIRequestObserver>)) foundInterface
= static_cast<nsIRequestObserver*>(this); else
360 NS_INTERFACE_MAP_ENTRY(nsIProgressEventSink)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIProgressEventSink>)) foundInterface
= static_cast<nsIProgressEventSink*>(this); else
361NS_INTERFACE_MAP_ENDfoundInterface = 0; nsresult status; if (!foundInterface) { do
{ static_assert( mozilla::detail::AssertionConditionType<
decltype(!aIID.Equals((nsISupports::kIID)))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aIID.Equals((nsISupports::kIID
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!aIID.Equals((nsISupports::kIID))", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 361); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aIID.Equals((nsISupports::kIID))"
")"); do { MOZ_CrashSequence(__null, 361); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); status = NS_NOINTERFACE
; } else { (foundInterface)->AddRef(); status = NS_OK; } *
aInstancePtr = foundInterface; return status; }
362
363//*****************************************************************************
364// nsWebBrowserPersist::nsIInterfaceRequestor
365//*****************************************************************************
366
367NS_IMETHODIMPnsresult nsWebBrowserPersist::GetInterface(const nsIID& aIID,
368 void** aIFace) {
369 NS_ENSURE_ARG_POINTER(aIFace)do { if ((__builtin_expect(!!(!(aIFace)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aIFace" ") failed", nullptr
, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp",
369); return NS_ERROR_INVALID_POINTER; } } while (false)
;
370
371 *aIFace = nullptr;
372
373 nsresult rv = QueryInterface(aIID, aIFace);
374 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
375 return rv;
376 }
377
378 if (mProgressListener && (aIID.Equals(NS_GET_IID(nsIAuthPrompt)(nsIAuthPrompt::kIID)) ||
379 aIID.Equals(NS_GET_IID(nsIPrompt)(nsIPrompt::kIID)))) {
380 mProgressListener->QueryInterface(aIID, aIFace);
381 if (*aIFace) return NS_OK;
382 }
383
384 nsCOMPtr<nsIInterfaceRequestor> req = do_QueryInterface(mProgressListener);
385 if (req) {
386 return req->GetInterface(aIID, aIFace);
387 }
388
389 return NS_ERROR_NO_INTERFACE;
390}
391
392//*****************************************************************************
393// nsWebBrowserPersist::nsIWebBrowserPersist
394//*****************************************************************************
395
396NS_IMETHODIMPnsresult nsWebBrowserPersist::GetPersistFlags(uint32_t* aPersistFlags) {
397 NS_ENSURE_ARG_POINTER(aPersistFlags)do { if ((__builtin_expect(!!(!(aPersistFlags)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPersistFlags" ") failed"
, nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 397); return NS_ERROR_INVALID_POINTER; } } while (false)
;
398 *aPersistFlags = mPersistFlags;
399 return NS_OK;
400}
401NS_IMETHODIMPnsresult nsWebBrowserPersist::SetPersistFlags(uint32_t aPersistFlags) {
402 mPersistFlags = aPersistFlags;
403 mReplaceExisting = (mPersistFlags & PERSIST_FLAGS_REPLACE_EXISTING_FILES);
404 mSerializingOutput = (mPersistFlags & PERSIST_FLAGS_SERIALIZE_OUTPUT);
405 return NS_OK;
406}
407
408NS_IMETHODIMPnsresult nsWebBrowserPersist::GetCurrentState(uint32_t* aCurrentState) {
409 NS_ENSURE_ARG_POINTER(aCurrentState)do { if ((__builtin_expect(!!(!(aCurrentState)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aCurrentState" ") failed"
, nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 409); return NS_ERROR_INVALID_POINTER; } } while (false)
;
410 if (mCompleted) {
411 *aCurrentState = PERSIST_STATE_FINISHED;
412 } else if (mFirstAndOnlyUse) {
413 *aCurrentState = PERSIST_STATE_SAVING;
414 } else {
415 *aCurrentState = PERSIST_STATE_READY;
416 }
417 return NS_OK;
418}
419
420NS_IMETHODIMPnsresult nsWebBrowserPersist::GetResult(nsresult* aResult) {
421 NS_ENSURE_ARG_POINTER(aResult)do { if ((__builtin_expect(!!(!(aResult)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aResult" ") failed", nullptr
, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp",
421); return NS_ERROR_INVALID_POINTER; } } while (false)
;
422 *aResult = mPersistResult;
423 return NS_OK;
424}
425
426NS_IMETHODIMPnsresult nsWebBrowserPersist::GetProgressListener(
427 nsIWebProgressListener** aProgressListener) {
428 NS_ENSURE_ARG_POINTER(aProgressListener)do { if ((__builtin_expect(!!(!(aProgressListener)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aProgressListener" ") failed"
, nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 428); return NS_ERROR_INVALID_POINTER; } } while (false)
;
429 *aProgressListener = mProgressListener;
430 NS_IF_ADDREF(*aProgressListener)ns_if_addref(*aProgressListener);
431 return NS_OK;
432}
433
434NS_IMETHODIMPnsresult nsWebBrowserPersist::SetProgressListener(
435 nsIWebProgressListener* aProgressListener) {
436 mProgressListener = aProgressListener;
437 mProgressListener2 = do_QueryInterface(aProgressListener);
438 mEventSink = do_GetInterface(aProgressListener);
439 return NS_OK;
440}
441
442NS_IMETHODIMPnsresult nsWebBrowserPersist::SaveURI(
443 nsIURI* aURI, nsIPrincipal* aPrincipal, uint32_t aCacheKey,
444 nsIReferrerInfo* aReferrerInfo, nsICookieJarSettings* aCookieJarSettings,
445 nsIInputStream* aPostData, const char* aExtraHeaders, nsISupports* aFile,
446 nsContentPolicyType aContentPolicy, bool aIsPrivate) {
447 NS_ENSURE_TRUE(mFirstAndOnlyUse, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(mFirstAndOnlyUse)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mFirstAndOnlyUse" ") failed"
, nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 447); return NS_ERROR_FAILURE; } } while (false)
;
448 mFirstAndOnlyUse = false; // Stop people from reusing this object!
449
450 nsCOMPtr<nsIURI> fileAsURI;
451 nsresult rv;
452 rv = GetValidURIFromObject(aFile, getter_AddRefs(fileAsURI));
453 NS_ENSURE_SUCCESS(rv, NS_ERROR_INVALID_ARG)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "NS_ERROR_INVALID_ARG", static_cast
<uint32_t>(__rv), name ? " (" : "", name ? name : "", name
? ")" : ""); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr
, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp",
453); return NS_ERROR_INVALID_ARG; } } while (false)
;
454
455 // SaveURIInternal doesn't like broken uris.
456 mPersistFlags |= PERSIST_FLAGS_FAIL_ON_BROKEN_LINKS;
457 rv = SaveURIInternal(aURI, aPrincipal, aContentPolicy, aCacheKey,
458 aReferrerInfo, aCookieJarSettings, aPostData,
459 aExtraHeaders, fileAsURI, false, aIsPrivate);
460 return NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) ? rv : NS_OK;
461}
462
463NS_IMETHODIMPnsresult nsWebBrowserPersist::SaveChannel(nsIChannel* aChannel,
464 nsISupports* aFile) {
465 NS_ENSURE_TRUE(mFirstAndOnlyUse, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(mFirstAndOnlyUse)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mFirstAndOnlyUse" ") failed"
, nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 465); return NS_ERROR_FAILURE; } } while (false)
;
466 mFirstAndOnlyUse = false; // Stop people from reusing this object!
467
468 nsCOMPtr<nsIURI> fileAsURI;
469 nsresult rv;
470 rv = GetValidURIFromObject(aFile, getter_AddRefs(fileAsURI));
471 NS_ENSURE_SUCCESS(rv, NS_ERROR_INVALID_ARG)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "NS_ERROR_INVALID_ARG", static_cast
<uint32_t>(__rv), name ? " (" : "", name ? name : "", name
? ")" : ""); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr
, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp",
471); return NS_ERROR_INVALID_ARG; } } while (false)
;
472
473 rv = aChannel->GetURI(getter_AddRefs(mURI));
474 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 474); return rv; } } while (false)
;
475
476 // SaveChannelInternal doesn't like broken uris.
477 mPersistFlags |= PERSIST_FLAGS_FAIL_ON_BROKEN_LINKS;
478 rv = SaveChannelInternal(aChannel, fileAsURI, false);
479 return NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) ? rv : NS_OK;
480}
481
482NS_IMETHODIMPnsresult nsWebBrowserPersist::SaveDocument(nsISupports* aDocument,
483 nsISupports* aFile,
484 nsISupports* aDataPath,
485 const char* aOutputContentType,
486 uint32_t aEncodingFlags,
487 uint32_t aWrapColumn) {
488 NS_ENSURE_TRUE(mFirstAndOnlyUse, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(mFirstAndOnlyUse)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mFirstAndOnlyUse" ") failed"
, nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 488); return NS_ERROR_FAILURE; } } while (false)
;
489 mFirstAndOnlyUse = false; // Stop people from reusing this object!
490
491 // We need a STATE_IS_NETWORK start/stop pair to bracket the
492 // notification callbacks. For a whole document we generate those
493 // here and in EndDownload(), but for the single-request methods
494 // that's done in On{Start,Stop}Request instead.
495 mSavingDocument = true;
496
497 NS_ENSURE_ARG_POINTER(aDocument)do { if ((__builtin_expect(!!(!(aDocument)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aDocument" ") failed", nullptr
, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp",
497); return NS_ERROR_INVALID_POINTER; } } while (false)
;
498 NS_ENSURE_ARG_POINTER(aFile)do { if ((__builtin_expect(!!(!(aFile)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aFile" ") failed", nullptr
, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp",
498); return NS_ERROR_INVALID_POINTER; } } while (false)
;
499
500 nsCOMPtr<nsIURI> fileAsURI;
501 nsCOMPtr<nsIURI> datapathAsURI;
502 nsresult rv;
503
504 rv = GetValidURIFromObject(aFile, getter_AddRefs(fileAsURI));
505 NS_ENSURE_SUCCESS(rv, NS_ERROR_INVALID_ARG)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "NS_ERROR_INVALID_ARG", static_cast
<uint32_t>(__rv), name ? " (" : "", name ? name : "", name
? ")" : ""); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr
, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp",
505); return NS_ERROR_INVALID_ARG; } } while (false)
;
506 if (aDataPath) {
507 rv = GetValidURIFromObject(aDataPath, getter_AddRefs(datapathAsURI));
508 NS_ENSURE_SUCCESS(rv, NS_ERROR_INVALID_ARG)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "NS_ERROR_INVALID_ARG", static_cast
<uint32_t>(__rv), name ? " (" : "", name ? name : "", name
? ")" : ""); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr
, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp",
508); return NS_ERROR_INVALID_ARG; } } while (false)
;
509 }
510
511 mWrapColumn = aWrapColumn;
512 mEncodingFlags = aEncodingFlags;
513
514 if (aOutputContentType) {
515 mContentType.AssignASCII(aOutputContentType);
516 }
517
518 // State start notification
519 if (mProgressListener) {
520 mProgressListener->OnStateChange(
521 nullptr, nullptr,
522 nsIWebProgressListener::STATE_START |
523 nsIWebProgressListener::STATE_IS_NETWORK,
524 NS_OK);
525 }
526
527 nsCOMPtr<nsIWebBrowserPersistDocument> doc = do_QueryInterface(aDocument);
528 if (!doc) {
529 nsCOMPtr<Document> localDoc = do_QueryInterface(aDocument);
530 if (localDoc) {
531 doc = new mozilla::WebBrowserPersistLocalDocument(localDoc);
532 } else {
533 rv = NS_ERROR_NO_INTERFACE;
534 }
535 }
536
537 bool closed = false;
538 if (doc && NS_SUCCEEDED(doc->GetIsClosed(&closed))((bool)(__builtin_expect(!!(!NS_FAILED_impl(doc->GetIsClosed
(&closed))), 1)))
&& !closed) {
539 rv = SaveDocumentInternal(doc, fileAsURI, datapathAsURI);
540 }
541
542 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) || closed) {
543 SendErrorStatusChange(true, rv, nullptr, mURI);
544 EndDownload(rv);
545 }
546 return rv;
547}
548
549NS_IMETHODIMPnsresult nsWebBrowserPersist::Cancel(nsresult aReason) {
550 // No point cancelling if we're already complete.
551 if (mEndCalled) {
552 return NS_OK;
553 }
554 mCancel = true;
555 EndDownload(aReason);
556 return NS_OK;
557}
558
559NS_IMETHODIMPnsresult nsWebBrowserPersist::CancelSave() {
560 return Cancel(NS_BINDING_ABORTED);
561}
562
563nsresult nsWebBrowserPersist::StartUpload(nsIStorageStream* storStream,
564 nsIURI* aDestinationURI,
565 const nsACString& aContentType) {
566 // setup the upload channel if the destination is not local
567 nsCOMPtr<nsIInputStream> inputstream;
568 nsresult rv = storStream->NewInputStream(0, getter_AddRefs(inputstream));
569 NS_ENSURE_TRUE(inputstream, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(inputstream)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "inputstream" ") failed"
, nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 569); return NS_ERROR_FAILURE; } } while (false)
;
570 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "NS_ERROR_FAILURE", static_cast
<uint32_t>(__rv), name ? " (" : "", name ? name : "", name
? ")" : ""); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr
, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp",
570); return NS_ERROR_FAILURE; } } while (false)
;
571 return StartUpload(inputstream, aDestinationURI, aContentType);
572}
573
574nsresult nsWebBrowserPersist::StartUpload(nsIInputStream* aInputStream,
575 nsIURI* aDestinationURI,
576 const nsACString& aContentType) {
577 nsCOMPtr<nsIChannel> destChannel;
578 CreateChannelFromURI(aDestinationURI, getter_AddRefs(destChannel));
579 nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(destChannel));
580 NS_ENSURE_TRUE(uploadChannel, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(uploadChannel)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "uploadChannel" ") failed"
, nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 580); return NS_ERROR_FAILURE; } } while (false)
;
581
582 // Set the upload stream
583 // NOTE: ALL data must be available in "inputstream"
584 nsresult rv = uploadChannel->SetUploadStream(aInputStream, aContentType, -1);
585 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "NS_ERROR_FAILURE", static_cast
<uint32_t>(__rv), name ? " (" : "", name ? name : "", name
? ")" : ""); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr
, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp",
585); return NS_ERROR_FAILURE; } } while (false)
;
586 rv = destChannel->AsyncOpen(this);
587 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "NS_ERROR_FAILURE", static_cast
<uint32_t>(__rv), name ? " (" : "", name ? name : "", name
? ")" : ""); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr
, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp",
587); return NS_ERROR_FAILURE; } } while (false)
;
588
589 // add this to the upload list
590 nsCOMPtr<nsISupports> keyPtr = do_QueryInterface(destChannel);
591 mUploadList.InsertOrUpdate(keyPtr, MakeUnique<UploadData>(aDestinationURI));
592
593 return NS_OK;
594}
595
596void nsWebBrowserPersist::SerializeNextFile() {
597 nsresult rv = NS_OK;
598 MOZ_ASSERT(mWalkStack.Length() == 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mWalkStack.Length() == 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mWalkStack.Length() == 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("mWalkStack.Length() == 0"
, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp",
598); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mWalkStack.Length() == 0"
")"); do { MOZ_CrashSequence(__null, 598); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
599
600 // First, handle gathered URIs.
601 // This is potentially O(n^2), when taking into account the
602 // number of times this method is called. If it becomes a
603 // bottleneck, the count of not-yet-persisted URIs could be
604 // maintained separately, and we can skip iterating mURIMap if there are none.
605
606 // Persist each file in the uri map. The document(s)
607 // will be saved after the last one of these is saved.
608 for (const auto& entry : mURIMap) {
609 URIData* data = entry.GetWeak();
610
611 if (!data->mNeedsPersisting || data->mSaved) {
612 continue;
613 }
614
615 // Create a URI from the key.
616 nsCOMPtr<nsIURI> uri;
617 rv = NS_NewURI(getter_AddRefs(uri), entry.GetKey(), data->mCharset.get());
618 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 618)
) {
619 break;
620 }
621
622 // Make a URI to save the data to.
623 nsCOMPtr<nsIURI> fileAsURI = data->mDataPath;
624 rv = AppendPathToURI(fileAsURI, data->mFilename, fileAsURI);
625 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 625)
) {
626 break;
627 }
628
629 rv = SaveURIInternal(uri, data->mTriggeringPrincipal,
630 data->mContentPolicyType, 0, nullptr,
631 data->mCookieJarSettings, nullptr, nullptr, fileAsURI,
632 true, mIsPrivate);
633 // If SaveURIInternal fails, then it will have called EndDownload,
634 // which means that |data| is no longer valid memory. We MUST bail.
635 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 635)
) {
636 break;
637 }
638
639 if (rv == NS_OK) {
640 // URIData.mFile will be updated to point to the correct
641 // URI object when it is fixed up with the right file extension
642 // in OnStartRequest
643 data->mFile = fileAsURI;
644 data->mSaved = true;
645 } else {
646 data->mNeedsFixup = false;
647 }
648
649 if (mSerializingOutput) {
650 break;
651 }
652 }
653
654 // If there are downloads happening, wait until they're done; the
655 // OnStopRequest handler will call this method again.
656 if (mOutputMap.Count() > 0) {
657 return;
658 }
659
660 // If serializing, also wait until last upload is done.
661 if (mSerializingOutput && mUploadList.Count() > 0) {
662 return;
663 }
664
665 // If there are also no more documents, then we're done.
666 if (mDocList.Length() == 0) {
667 // ...or not quite done, if there are still uploads.
668 if (mUploadList.Count() > 0) {
669 return;
670 }
671 // Finish and clean things up. Defer this because the caller
672 // may have been expecting to use the listeners that that
673 // method will clear.
674 NS_DispatchToCurrentThread(
675 NewRunnableMethod("nsWebBrowserPersist::FinishDownload", this,
676 &nsWebBrowserPersist::FinishDownload));
677 return;
678 }
679
680 // There are no URIs to save, so just save the next document.
681 mStartSaving = true;
682 mozilla::UniquePtr<DocData> docData(mDocList.ElementAt(0));
683 mDocList.RemoveElementAt(0); // O(n^2) but probably doesn't matter.
684 MOZ_ASSERT(docData)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(docData)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(docData))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("docData", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 684); AnnotateMozCrashReason("MOZ_ASSERT" "(" "docData" ")"
); do { MOZ_CrashSequence(__null, 684); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
685 if (!docData) {
686 EndDownload(NS_ERROR_FAILURE);
687 return;
688 }
689
690 mCurrentBaseURI = docData->mBaseURI;
691 mCurrentCharset = docData->mCharset;
692 mTargetBaseURI = docData->mFile;
693
694 // Save the document, fixing it up with the new URIs as we do
695
696 nsAutoCString targetBaseSpec;
697 if (mTargetBaseURI) {
698 rv = mTargetBaseURI->GetSpec(targetBaseSpec);
699 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
700 SendErrorStatusChange(true, rv, nullptr, nullptr);
701 EndDownload(rv);
702 return;
703 }
704 }
705
706 // mFlatURIMap must be rebuilt each time through SerializeNextFile, as
707 // mTargetBaseURI is used to create the relative URLs and will be different
708 // with each serialized document.
709 RefPtr<FlatURIMap> flatMap = new FlatURIMap(targetBaseSpec);
710 for (const auto& uriEntry : mURIMap) {
711 nsAutoCString mapTo;
712 nsresult rv = uriEntry.GetWeak()->GetLocalURI(mTargetBaseURI, mapTo);
713 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) || !mapTo.IsVoid()) {
714 flatMap->Add(uriEntry.GetKey(), mapTo);
715 }
716 }
717 mFlatURIMap = std::move(flatMap);
718
719 nsCOMPtr<nsIFile> localFile;
720 GetLocalFileFromURI(docData->mFile, getter_AddRefs(localFile));
721 if (localFile) {
722 // if we're not replacing an existing file but the file
723 // exists, something is wrong
724 bool fileExists = false;
725 rv = localFile->Exists(&fileExists);
726 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && !mReplaceExisting && fileExists) {
727 rv = NS_ERROR_FILE_ALREADY_EXISTS;
728 }
729 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
730 SendErrorStatusChange(false, rv, nullptr, docData->mFile);
731 EndDownload(rv);
732 return;
733 }
734 }
735 nsAutoCString docURISpec;
736 nsCOMPtr<nsIURI> docURI;
737 if (NS_SUCCEEDED(docData->mDocument->GetDocumentURI(docURISpec))((bool)(__builtin_expect(!!(!NS_FAILED_impl(docData->mDocument
->GetDocumentURI(docURISpec))), 1)))
) {
738 NS_NewURI(getter_AddRefs(docURI), docURISpec);
739 }
740 nsCOMPtr<nsIOutputStream> outputStream;
741 rv = MakeOutputStream(docData->mFile, docURI, getter_AddRefs(outputStream));
742 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && !outputStream) {
743 rv = NS_ERROR_FAILURE;
744 }
745 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
746 SendErrorStatusChange(false, rv, nullptr, docData->mFile);
747 EndDownload(rv);
748 return;
749 }
750
751 RefPtr<OnWrite> finish = new OnWrite(this, docData->mFile, localFile);
752 rv = docData->mDocument->WriteContent(outputStream, mFlatURIMap,
753 NS_ConvertUTF16toUTF8(mContentType),
754 mEncodingFlags, mWrapColumn, finish);
755 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
756 SendErrorStatusChange(false, rv, nullptr, docData->mFile);
757 EndDownload(rv);
758 }
759}
760
761NS_IMETHODIMPnsresult
762nsWebBrowserPersist::OnWrite::OnFinish(nsIWebBrowserPersistDocument* aDoc,
763 nsIOutputStream* aStream,
764 const nsACString& aContentType,
765 nsresult aStatus) {
766 nsresult rv = aStatus;
767
768 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
769 mParent->SendErrorStatusChange(false, rv, nullptr, mFile);
770 mParent->EndDownload(rv);
771 return NS_OK;
772 }
773 if (!mLocalFile) {
774 nsCOMPtr<nsIStorageStream> storStream(do_QueryInterface(aStream));
775 if (storStream) {
776 aStream->Close();
777 rv = mParent->StartUpload(storStream, mFile, aContentType);
778 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
779 mParent->SendErrorStatusChange(false, rv, nullptr, mFile);
780 mParent->EndDownload(rv);
781 }
782 // Either we failed and we're done, or we're uploading and
783 // the OnStopRequest callback is responsible for the next
784 // SerializeNextFile().
785 return NS_OK;
786 }
787 }
788 NS_DispatchToCurrentThread(
789 NewRunnableMethod("nsWebBrowserPersist::SerializeNextFile", mParent,
790 &nsWebBrowserPersist::SerializeNextFile));
791 return NS_OK;
792}
793
794//*****************************************************************************
795// nsWebBrowserPersist::nsIRequestObserver
796//*****************************************************************************
797
798NS_IMETHODIMPnsresult nsWebBrowserPersist::OnStartRequest(nsIRequest* request) {
799 if (mProgressListener) {
800 uint32_t stateFlags = nsIWebProgressListener::STATE_START |
801 nsIWebProgressListener::STATE_IS_REQUEST;
802 if (!mSavingDocument) {
803 stateFlags |= nsIWebProgressListener::STATE_IS_NETWORK;
804 }
805 mProgressListener->OnStateChange(nullptr, request, stateFlags, NS_OK);
806 }
807
808 nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
809 NS_ENSURE_TRUE(channel, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(channel)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "channel" ") failed", nullptr
, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp",
809); return NS_ERROR_FAILURE; } } while (false)
;
810
811 nsCOMPtr<nsISupports> keyPtr = do_QueryInterface(request);
812 OutputData* data = mOutputMap.Get(keyPtr);
813
814 // NOTE: This code uses the channel as a hash key so it will not
815 // recognize redirected channels because the key is not the same.
816 // When that happens we remove and add the data entry to use the
817 // new channel as the hash key.
818 if (!data) {
819 UploadData* upData = mUploadList.Get(keyPtr);
820 if (!upData) {
821 // Redirect? Try and fixup the output table
822 nsresult rv = FixRedirectedChannelEntry(channel);
823 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "NS_ERROR_FAILURE", static_cast
<uint32_t>(__rv), name ? " (" : "", name ? name : "", name
? ")" : ""); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr
, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp",
823); return NS_ERROR_FAILURE; } } while (false)
;
824
825 // Should be able to find the data after fixup unless redirects
826 // are disabled.
827 data = mOutputMap.Get(keyPtr);
828 if (!data) {
829 return NS_ERROR_FAILURE;
830 }
831 }
832 }
833
834 if (data && data->mFile) {
835 nsCOMPtr<nsIThreadRetargetableRequest> r = do_QueryInterface(request);
836 // Determine if we're uploading. Only use OMT onDataAvailable if not.
837 nsCOMPtr<nsIFile> localFile;
838 GetLocalFileFromURI(data->mFile, getter_AddRefs(localFile));
839 if (r && localFile) {
840 if (!mBackgroundQueue) {
841 NS_CreateBackgroundTaskQueue("WebBrowserPersist",
842 getter_AddRefs(mBackgroundQueue));
843 }
844 if (mBackgroundQueue) {
845 r->RetargetDeliveryTo(mBackgroundQueue);
846 }
847 }
848
849 // If PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION is set in mPersistFlags,
850 // try to determine whether this channel needs to apply Content-Encoding
851 // conversions.
852 NS_ASSERTION(do { if (!(!((mPersistFlags & PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION
) && (mPersistFlags & PERSIST_FLAGS_NO_CONVERSION
)))) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Conflict in persist flags: both AUTODETECT and NO_CONVERSION set"
, "!((mPersistFlags & PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION) && (mPersistFlags & PERSIST_FLAGS_NO_CONVERSION))"
, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp",
855); MOZ_PretendNoReturn(); } } while (0)
853 !((mPersistFlags & PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION) &&do { if (!(!((mPersistFlags & PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION
) && (mPersistFlags & PERSIST_FLAGS_NO_CONVERSION
)))) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Conflict in persist flags: both AUTODETECT and NO_CONVERSION set"
, "!((mPersistFlags & PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION) && (mPersistFlags & PERSIST_FLAGS_NO_CONVERSION))"
, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp",
855); MOZ_PretendNoReturn(); } } while (0)
854 (mPersistFlags & PERSIST_FLAGS_NO_CONVERSION)),do { if (!(!((mPersistFlags & PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION
) && (mPersistFlags & PERSIST_FLAGS_NO_CONVERSION
)))) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Conflict in persist flags: both AUTODETECT and NO_CONVERSION set"
, "!((mPersistFlags & PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION) && (mPersistFlags & PERSIST_FLAGS_NO_CONVERSION))"
, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp",
855); MOZ_PretendNoReturn(); } } while (0)
855 "Conflict in persist flags: both AUTODETECT and NO_CONVERSION set")do { if (!(!((mPersistFlags & PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION
) && (mPersistFlags & PERSIST_FLAGS_NO_CONVERSION
)))) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Conflict in persist flags: both AUTODETECT and NO_CONVERSION set"
, "!((mPersistFlags & PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION) && (mPersistFlags & PERSIST_FLAGS_NO_CONVERSION))"
, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp",
855); MOZ_PretendNoReturn(); } } while (0)
;
856 if (mPersistFlags & PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION)
857 SetApplyConversionIfNeeded(channel);
858
859 if (data->mCalcFileExt &&
860 !(mPersistFlags & PERSIST_FLAGS_DONT_CHANGE_FILENAMES)) {
861 nsCOMPtr<nsIURI> uriWithExt;
862 // this is the first point at which the server can tell us the mimetype
863 nsresult rv = CalculateAndAppendFileExt(
864 data->mFile, channel, data->mOriginalLocation, uriWithExt);
865 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
866 data->mFile = std::move(uriWithExt);
867 }
868
869 // now make filename conformant and unique
870 nsCOMPtr<nsIURI> uniqueFilenameURI;
871 rv = CalculateUniqueFilename(data->mFile, uniqueFilenameURI);
872 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
873 data->mFile = std::move(uniqueFilenameURI);
874 }
875
876 // The URIData entry is pointing to the old unfixed URI, so we need
877 // to update it.
878 nsCOMPtr<nsIURI> chanURI;
879 rv = channel->GetOriginalURI(getter_AddRefs(chanURI));
880 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
881 nsAutoCString spec;
882 chanURI->GetSpec(spec);
883 URIData* uridata;
884 if (mURIMap.Get(spec, &uridata)) {
885 uridata->mFile = data->mFile;
886 }
887 }
888 }
889
890 // compare uris and bail before we add to output map if they are equal
891 bool isEqual = false;
892 if (NS_SUCCEEDED(data->mFile->Equals(data->mOriginalLocation, &isEqual))((bool)(__builtin_expect(!!(!NS_FAILED_impl(data->mFile->
Equals(data->mOriginalLocation, &isEqual))), 1)))
&&
893 isEqual) {
894 {
895 MutexAutoLock lock(mOutputMapMutex);
896 // remove from output map
897 mOutputMap.Remove(keyPtr);
898 }
899
900 // cancel; we don't need to know any more
901 // stop request will get called
902 request->Cancel(NS_BINDING_ABORTED);
903 }
904 }
905
906 return NS_OK;
907}
908
909NS_IMETHODIMPnsresult nsWebBrowserPersist::OnStopRequest(nsIRequest* request,
910 nsresult status) {
911 nsCOMPtr<nsISupports> keyPtr = do_QueryInterface(request);
912 OutputData* data = mOutputMap.Get(keyPtr);
913 if (data) {
914 if (NS_SUCCEEDED(mPersistResult)((bool)(__builtin_expect(!!(!NS_FAILED_impl(mPersistResult)),
1)))
&& NS_FAILED(status)((bool)(__builtin_expect(!!(NS_FAILED_impl(status)), 0)))) {
915 SendErrorStatusChange(true, status, request, data->mFile);
916 }
917
918 // If there is a stream ref and we weren't canceled,
919 // close it away from the main thread.
920 // We don't do this when there's an error/cancelation,
921 // because our consumer may try to delete the file, which will error
922 // if we're still holding on to it, so we have to close it pronto.
923 {
924 MutexAutoLock lock(data->mStreamMutex);
925 if (data->mStream && NS_SUCCEEDED(status)((bool)(__builtin_expect(!!(!NS_FAILED_impl(status)), 1))) && !mCancel) {
926 if (!mBackgroundQueue) {
927 nsresult rv = NS_CreateBackgroundTaskQueue(
928 "WebBrowserPersist", getter_AddRefs(mBackgroundQueue));
929 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
930 return rv;
931 }
932 }
933 // Now steal the stream ref and close it away from the main thread,
934 // keeping the promise around so we don't finish before all files
935 // are flushed and closed.
936 mFileClosePromises.AppendElement(InvokeAsync(
937 mBackgroundQueue, __func__, [stream = std::move(data->mStream)]() {
938 nsresult rv = stream->Close();
939 // We don't care if closing failed; we don't care in the
940 // destructor either...
941 return ClosePromise::CreateAndResolve(rv, __func__);
942 }));
943 }
944 }
945 MutexAutoLock lock(mOutputMapMutex);
946 mOutputMap.Remove(keyPtr);
947 } else {
948 // if we didn't find the data in mOutputMap, try mUploadList
949 UploadData* upData = mUploadList.Get(keyPtr);
950 if (upData) {
951 mUploadList.Remove(keyPtr);
952 }
953 }
954
955 // Do more work.
956 SerializeNextFile();
957
958 if (mProgressListener) {
959 uint32_t stateFlags = nsIWebProgressListener::STATE_STOP |
960 nsIWebProgressListener::STATE_IS_REQUEST;
961 if (!mSavingDocument) {
962 stateFlags |= nsIWebProgressListener::STATE_IS_NETWORK;
963 }
964 mProgressListener->OnStateChange(nullptr, request, stateFlags, status);
965 }
966
967 return NS_OK;
968}
969
970//*****************************************************************************
971// nsWebBrowserPersist::nsIStreamListener
972//*****************************************************************************
973
974// Note: this is supposed to (but not guaranteed to) fire on a background
975// thread when used to save to local disk (channels not using local files will
976// use the main thread).
977// (Read) Access to mOutputMap is guarded via mOutputMapMutex.
978// Access to individual OutputData::mStream is guarded via its mStreamMutex.
979// mCancel is atomic, as is mPersistFlags (accessed via MakeOutputStream).
980// If you end up touching this method and needing other member access, bear
981// this in mind.
982NS_IMETHODIMPnsresult
983nsWebBrowserPersist::OnDataAvailable(nsIRequest* request,
984 nsIInputStream* aIStream, uint64_t aOffset,
985 uint32_t aLength) {
986 // MOZ_ASSERT(!NS_IsMainThread()); // no guarantees, but it's likely.
987
988 bool cancel = mCancel;
989 if (!cancel) {
990 nsresult rv = NS_OK;
991 uint32_t bytesRemaining = aLength;
992
993 nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
994 NS_ENSURE_TRUE(channel, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(channel)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "channel" ") failed", nullptr
, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp",
994); return NS_ERROR_FAILURE; } } while (false)
;
995
996 MutexAutoLock lock(mOutputMapMutex);
997 nsCOMPtr<nsISupports> keyPtr = do_QueryInterface(request);
998 OutputData* data = mOutputMap.Get(keyPtr);
999 if (!data) {
1000 // might be uploadData; consume necko's buffer and bail...
1001 uint32_t n;
1002 return aIStream->ReadSegments(NS_DiscardSegment, nullptr, aLength, &n);
1003 }
1004
1005 bool readError = true;
1006
1007 MutexAutoLock streamLock(data->mStreamMutex);
1008 // Make the output stream
1009 if (!data->mStream) {
1010 rv = MakeOutputStream(data->mFile, data->mOriginalLocation,
1011 getter_AddRefs(data->mStream));
1012 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1013 readError = false;
1014 cancel = true;
1015 }
1016 }
1017
1018 // Read data from the input and write to the output
1019 char buffer[8192];
1020 uint32_t bytesRead;
1021 while (!cancel && bytesRemaining) {
1022 readError = true;
1023 rv = aIStream->Read(buffer,
1024 std::min(uint32_t(sizeof(buffer)), bytesRemaining),
1025 &bytesRead);
1026 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
1027 readError = false;
1028 // Write out the data until something goes wrong, or, it is
1029 // all written. We loop because for some errors (e.g., disk
1030 // full), we get NS_OK with some bytes written, then an error.
1031 // So, we want to write again in that case to get the actual
1032 // error code.
1033 const char* bufPtr = buffer; // Where to write from.
1034 while (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && bytesRead) {
1035 uint32_t bytesWritten = 0;
1036 rv = data->mStream->Write(bufPtr, bytesRead, &bytesWritten);
1037 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
1038 bytesRead -= bytesWritten;
1039 bufPtr += bytesWritten;
1040 bytesRemaining -= bytesWritten;
1041 // Force an error if (for some reason) we get NS_OK but
1042 // no bytes written.
1043 if (!bytesWritten) {
1044 rv = NS_ERROR_FAILURE;
1045 cancel = true;
1046 }
1047 } else {
1048 // Disaster - can't write out the bytes - disk full / permission?
1049 cancel = true;
1050 }
1051 }
1052 } else {
1053 // Disaster - can't read the bytes - broken link / file error?
1054 cancel = true;
1055 }
1056 }
1057
1058 int64_t channelContentLength = -1;
1059 if (!cancel &&
1060 NS_SUCCEEDED(channel->GetContentLength(&channelContentLength))((bool)(__builtin_expect(!!(!NS_FAILED_impl(channel->GetContentLength
(&channelContentLength))), 1)))
) {
1061 // if we get -1 at this point, we didn't get content-length header
1062 // assume that we got all of the data and push what we have;
1063 // that's the best we can do now
1064 if ((-1 == channelContentLength) ||
1065 ((channelContentLength - (aOffset + aLength)) == 0)) {
1066 NS_WARNING_ASSERTION(do { if (!(channelContentLength != -1)) { NS_DebugBreak(NS_DEBUG_WARNING
, "nsWebBrowserPersist::OnDataAvailable() no content length "
"header, pushing what we have", "channelContentLength != -1"
, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp",
1069); } } while (false)
1067 channelContentLength != -1,do { if (!(channelContentLength != -1)) { NS_DebugBreak(NS_DEBUG_WARNING
, "nsWebBrowserPersist::OnDataAvailable() no content length "
"header, pushing what we have", "channelContentLength != -1"
, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp",
1069); } } while (false)
1068 "nsWebBrowserPersist::OnDataAvailable() no content length "do { if (!(channelContentLength != -1)) { NS_DebugBreak(NS_DEBUG_WARNING
, "nsWebBrowserPersist::OnDataAvailable() no content length "
"header, pushing what we have", "channelContentLength != -1"
, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp",
1069); } } while (false)
1069 "header, pushing what we have")do { if (!(channelContentLength != -1)) { NS_DebugBreak(NS_DEBUG_WARNING
, "nsWebBrowserPersist::OnDataAvailable() no content length "
"header, pushing what we have", "channelContentLength != -1"
, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp",
1069); } } while (false)
;
1070 // we're done with this pass; see if we need to do upload
1071 nsAutoCString contentType;
1072 channel->GetContentType(contentType);
1073 // if we don't have the right type of output stream then it's a local
1074 // file
1075 nsCOMPtr<nsIStorageStream> storStream(do_QueryInterface(data->mStream));
1076 if (storStream) {
1077 data->mStream->Close();
1078 data->mStream =
1079 nullptr; // null out stream so we don't close it later
1080 MOZ_ASSERT(NS_IsMainThread(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "Uploads should be on the main thread." ")", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 1081); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "Uploads should be on the main thread." ")"); do { MOZ_CrashSequence
(__null, 1081); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
1081 "Uploads should be on the main thread.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "Uploads should be on the main thread." ")", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 1081); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "Uploads should be on the main thread." ")"); do { MOZ_CrashSequence
(__null, 1081); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1082 rv = StartUpload(storStream, data->mFile, contentType);
1083 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1084 readError = false;
1085 cancel = true;
1086 }
1087 }
1088 }
1089 }
1090
1091 // Notify listener if an error occurred.
1092 if (cancel) {
1093 RefPtr<nsIRequest> req = readError ? request : nullptr;
1094 nsCOMPtr<nsIURI> file = data->mFile;
1095 RefPtr<Runnable> errorOnMainThread = NS_NewRunnableFunction(
1096 "nsWebBrowserPersist::SendErrorStatusChange",
1097 [self = RefPtr{this}, req, file, readError, rv]() {
1098 self->SendErrorStatusChange(readError, rv, req, file);
1099 });
1100 NS_DispatchToMainThread(errorOnMainThread);
1101
1102 // And end the download on the main thread.
1103 nsCOMPtr<nsIRunnable> endOnMainThread = NewRunnableMethod<nsresult>(
1104 "nsWebBrowserPersist::EndDownload", this,
1105 &nsWebBrowserPersist::EndDownload, NS_BINDING_ABORTED);
1106 NS_DispatchToMainThread(endOnMainThread);
1107 }
1108 }
1109
1110 return cancel ? NS_BINDING_ABORTED : NS_OK;
1111}
1112
1113//*****************************************************************************
1114// nsWebBrowserPersist::nsIThreadRetargetableStreamListener
1115//*****************************************************************************
1116
1117NS_IMETHODIMPnsresult nsWebBrowserPersist::CheckListenerChain() { return NS_OK; }
1118
1119NS_IMETHODIMPnsresult
1120nsWebBrowserPersist::OnDataFinished(nsresult) { return NS_OK; }
1121
1122//*****************************************************************************
1123// nsWebBrowserPersist::nsIProgressEventSink
1124//*****************************************************************************
1125
1126NS_IMETHODIMPnsresult nsWebBrowserPersist::OnProgress(nsIRequest* request,
1127 int64_t aProgress,
1128 int64_t aProgressMax) {
1129 if (!mProgressListener) {
1130 return NS_OK;
1131 }
1132
1133 // Store the progress of this request
1134 nsCOMPtr<nsISupports> keyPtr = do_QueryInterface(request);
1135 OutputData* data = mOutputMap.Get(keyPtr);
1136 if (data) {
1137 data->mSelfProgress = aProgress;
1138 data->mSelfProgressMax = aProgressMax;
1139 } else {
1140 UploadData* upData = mUploadList.Get(keyPtr);
1141 if (upData) {
1142 upData->mSelfProgress = aProgress;
1143 upData->mSelfProgressMax = aProgressMax;
1144 }
1145 }
1146
1147 // Notify listener of total progress
1148 CalcTotalProgress();
1149 if (mProgressListener2) {
1150 mProgressListener2->OnProgressChange64(nullptr, request, aProgress,
1151 aProgressMax, mTotalCurrentProgress,
1152 mTotalMaxProgress);
1153 } else {
1154 // have to truncate 64-bit to 32bit
1155 mProgressListener->OnProgressChange(
1156 nullptr, request, uint64_t(aProgress), uint64_t(aProgressMax),
1157 mTotalCurrentProgress, mTotalMaxProgress);
1158 }
1159
1160 // If our progress listener implements nsIProgressEventSink,
1161 // forward the notification
1162 if (mEventSink) {
1163 mEventSink->OnProgress(request, aProgress, aProgressMax);
1164 }
1165
1166 return NS_OK;
1167}
1168
1169NS_IMETHODIMPnsresult nsWebBrowserPersist::OnStatus(nsIRequest* request,
1170 nsresult status,
1171 const char16_t* statusArg) {
1172 if (mProgressListener) {
1173 // We need to filter out non-error error codes.
1174 // Is the only NS_SUCCEEDED value NS_OK?
1175 switch (status) {
1176 case NS_NET_STATUS_RESOLVING_HOST:
1177 case NS_NET_STATUS_RESOLVED_HOST:
1178 case NS_NET_STATUS_CONNECTING_TO:
1179 case NS_NET_STATUS_CONNECTED_TO:
1180 case NS_NET_STATUS_TLS_HANDSHAKE_STARTING:
1181 case NS_NET_STATUS_TLS_HANDSHAKE_ENDED:
1182 case NS_NET_STATUS_SENDING_TO:
1183 case NS_NET_STATUS_RECEIVING_FROM:
1184 case NS_NET_STATUS_WAITING_FOR:
1185 case NS_NET_STATUS_READING:
1186 case NS_NET_STATUS_WRITING:
1187 break;
1188
1189 default:
1190 // Pass other notifications (for legitimate errors) along.
1191 mProgressListener->OnStatusChange(nullptr, request, status, statusArg);
1192 break;
1193 }
1194 }
1195
1196 // If our progress listener implements nsIProgressEventSink,
1197 // forward the notification
1198 if (mEventSink) {
1199 mEventSink->OnStatus(request, status, statusArg);
1200 }
1201
1202 return NS_OK;
1203}
1204
1205//*****************************************************************************
1206// nsWebBrowserPersist private methods
1207//*****************************************************************************
1208
1209// Convert error info into proper message text and send OnStatusChange
1210// notification to the web progress listener.
1211nsresult nsWebBrowserPersist::SendErrorStatusChange(bool aIsReadError,
1212 nsresult aResult,
1213 nsIRequest* aRequest,
1214 nsIURI* aURI) {
1215 NS_ENSURE_ARG_POINTER(aURI)do { if ((__builtin_expect(!!(!(aURI)), 0))) { NS_DebugBreak(
NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aURI" ") failed", nullptr
, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp",
1215); return NS_ERROR_INVALID_POINTER; } } while (false)
;
1216
1217 if (!mProgressListener) {
1218 // Do nothing
1219 return NS_OK;
1220 }
1221
1222 // Get the file path or spec from the supplied URI
1223 nsCOMPtr<nsIFile> file;
1224 GetLocalFileFromURI(aURI, getter_AddRefs(file));
1225 AutoTArray<nsString, 1> strings;
1226 nsresult rv;
1227 if (file) {
1228 file->GetPath(*strings.AppendElement());
1229 } else {
1230 nsAutoCString fileurl;
1231 rv = aURI->GetSpec(fileurl);
1232 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 1232); return rv; } } while (false)
;
1233 CopyUTF8toUTF16(fileurl, *strings.AppendElement());
1234 }
1235
1236 const char* msgId;
1237 switch (aResult) {
1238 case NS_ERROR_FILE_NAME_TOO_LONG:
1239 // File name too long.
1240 msgId = "fileNameTooLongError";
1241 break;
1242 case NS_ERROR_FILE_ALREADY_EXISTS:
1243 // File exists with same name as directory.
1244 msgId = "fileAlreadyExistsError";
1245 break;
1246 case NS_ERROR_FILE_NO_DEVICE_SPACE:
1247 // Out of space on target volume.
1248 msgId = "diskFull";
1249 break;
1250
1251 case NS_ERROR_FILE_READ_ONLY:
1252 // Attempt to write to read/only file.
1253 msgId = "readOnly";
1254 break;
1255
1256 case NS_ERROR_FILE_ACCESS_DENIED:
1257 // Attempt to write without sufficient permissions.
1258 msgId = "accessError";
1259 break;
1260
1261 default:
1262 // Generic read/write error message.
1263 if (aIsReadError)
1264 msgId = "readError";
1265 else
1266 msgId = "writeError";
1267 break;
1268 }
1269 // Get properties file bundle and extract status string.
1270 nsCOMPtr<nsIStringBundleService> s =
1271 do_GetService(NS_STRINGBUNDLE_CONTRACTID"@mozilla.org/intl/stringbundle;1", &rv);
1272 NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && s, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(((bool)(__builtin_expect(!!(!
NS_FAILED_impl(rv)), 1))) && s)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "NS_SUCCEEDED(rv) && s"
") failed", nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 1272); return NS_ERROR_FAILURE; } } while (false)
;
1273
1274 nsCOMPtr<nsIStringBundle> bundle;
1275 rv = s->CreateBundle(kWebBrowserPersistStringBundle, getter_AddRefs(bundle));
1276 NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && bundle, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(((bool)(__builtin_expect(!!(!
NS_FAILED_impl(rv)), 1))) && bundle)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "NS_SUCCEEDED(rv) && bundle"
") failed", nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 1276); return NS_ERROR_FAILURE; } } while (false)
;
1277
1278 nsAutoString msgText;
1279 rv = bundle->FormatStringFromName(msgId, strings, msgText);
1280 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "NS_ERROR_FAILURE", static_cast
<uint32_t>(__rv), name ? " (" : "", name ? name : "", name
? ")" : ""); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr
, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp",
1280); return NS_ERROR_FAILURE; } } while (false)
;
1281
1282 mProgressListener->OnStatusChange(nullptr, aRequest, aResult, msgText.get());
1283
1284 return NS_OK;
1285}
1286
1287nsresult nsWebBrowserPersist::GetValidURIFromObject(nsISupports* aObject,
1288 nsIURI** aURI) const {
1289 NS_ENSURE_ARG_POINTER(aObject)do { if ((__builtin_expect(!!(!(aObject)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aObject" ") failed", nullptr
, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp",
1289); return NS_ERROR_INVALID_POINTER; } } while (false)
;
1290 NS_ENSURE_ARG_POINTER(aURI)do { if ((__builtin_expect(!!(!(aURI)), 0))) { NS_DebugBreak(
NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aURI" ") failed", nullptr
, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp",
1290); return NS_ERROR_INVALID_POINTER; } } while (false)
;
1291
1292 nsCOMPtr<nsIFile> objAsFile = do_QueryInterface(aObject);
1293 if (objAsFile) {
1294 return NS_NewFileURI(aURI, objAsFile);
1295 }
1296 nsCOMPtr<nsIURI> objAsURI = do_QueryInterface(aObject);
1297 if (objAsURI) {
1298 *aURI = objAsURI;
1299 NS_ADDREF(*aURI)(*aURI)->AddRef();
1300 return NS_OK;
1301 }
1302
1303 return NS_ERROR_FAILURE;
1304}
1305
1306/* static */
1307nsresult nsWebBrowserPersist::GetLocalFileFromURI(nsIURI* aURI,
1308 nsIFile** aLocalFile) {
1309 nsresult rv;
1310
1311 nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(aURI, &rv);
1312 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return rv;
1313
1314 nsCOMPtr<nsIFile> file;
1315 rv = fileURL->GetFile(getter_AddRefs(file));
1316 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1317 return rv;
1318 }
1319
1320 file.forget(aLocalFile);
1321 return NS_OK;
1322}
1323
1324/* static */
1325nsresult nsWebBrowserPersist::AppendPathToURI(nsIURI* aURI,
1326 const nsAString& aPath,
1327 nsCOMPtr<nsIURI>& aOutURI) {
1328 NS_ENSURE_ARG_POINTER(aURI)do { if ((__builtin_expect(!!(!(aURI)), 0))) { NS_DebugBreak(
NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aURI" ") failed", nullptr
, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp",
1328); return NS_ERROR_INVALID_POINTER; } } while (false)
;
1329
1330 nsAutoCString newPath;
1331 nsresult rv = aURI->GetPathQueryRef(newPath);
1332 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "NS_ERROR_FAILURE", static_cast
<uint32_t>(__rv), name ? " (" : "", name ? name : "", name
? ")" : ""); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr
, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp",
1332); return NS_ERROR_FAILURE; } } while (false)
;
1333
1334 // Append a forward slash if necessary
1335 int32_t len = newPath.Length();
1336 if (len > 0 && newPath.CharAt(len - 1) != '/') {
1337 newPath.Append('/');
1338 }
1339
1340 // Store the path back on the URI
1341 AppendUTF16toUTF8(aPath, newPath);
1342
1343 return NS_MutateURI(aURI).SetPathQueryRef(newPath).Finalize(aOutURI);
1344}
1345
1346nsresult nsWebBrowserPersist::SaveURIInternal(
1347 nsIURI* aURI, nsIPrincipal* aTriggeringPrincipal,
1348 nsContentPolicyType aContentPolicyType, uint32_t aCacheKey,
1349 nsIReferrerInfo* aReferrerInfo, nsICookieJarSettings* aCookieJarSettings,
1350 nsIInputStream* aPostData, const char* aExtraHeaders, nsIURI* aFile,
1351 bool aCalcFileExt, bool aIsPrivate) {
1352 NS_ENSURE_ARG_POINTER(aURI)do { if ((__builtin_expect(!!(!(aURI)), 0))) { NS_DebugBreak(
NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aURI" ") failed", nullptr
, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp",
1352); return NS_ERROR_INVALID_POINTER; } } while (false)
;
1353 NS_ENSURE_ARG_POINTER(aFile)do { if ((__builtin_expect(!!(!(aFile)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aFile" ") failed", nullptr
, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp",
1353); return NS_ERROR_INVALID_POINTER; } } while (false)
;
1354 NS_ENSURE_ARG_POINTER(aTriggeringPrincipal)do { if ((__builtin_expect(!!(!(aTriggeringPrincipal)), 0))) {
NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aTriggeringPrincipal"
") failed", nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 1354); return NS_ERROR_INVALID_POINTER; } } while (false)
;
1355
1356 nsresult rv = NS_OK;
1357
1358 mURI = aURI;
1359 mReferrerInfo = aReferrerInfo;
1360
1361 nsLoadFlags loadFlags = nsIRequest::LOAD_NORMAL;
1362 if (mPersistFlags & PERSIST_FLAGS_BYPASS_CACHE) {
1363 loadFlags |= nsIRequest::LOAD_BYPASS_CACHE;
1364 } else if (mPersistFlags & PERSIST_FLAGS_FROM_CACHE) {
1365 loadFlags |= nsIRequest::LOAD_FROM_CACHE;
1366 }
1367
1368 // If there is no cookieJarSetting given, we need to create a new
1369 // cookieJarSettings for this download in order to send cookies based on the
1370 // current state of the prefs/permissions.
1371 nsCOMPtr<nsICookieJarSettings> cookieJarSettings = aCookieJarSettings;
1372 if (!cookieJarSettings) {
1373 // Although the variable is called 'triggering principal', it is used as the
1374 // loading principal in the download channel, so we treat it as a loading
1375 // principal also.
1376 bool shouldResistFingerprinting =
1377 nsContentUtils::ShouldResistFingerprinting_dangerous(
1378 aTriggeringPrincipal,
1379 "We are creating a new CookieJar Settings, so none exists "
1380 "currently. Although the variable is called 'triggering principal',"
1381 "it is used as the loading principal in the download channel, so we"
1382 "treat it as a loading principal also.",
1383 RFPTarget::IsAlwaysEnabledForPrecompute);
1384 cookieJarSettings =
1385 aIsPrivate
1386 ? net::CookieJarSettings::Create(net::CookieJarSettings::ePrivate,
1387 shouldResistFingerprinting)
1388 : net::CookieJarSettings::Create(net::CookieJarSettings::eRegular,
1389 shouldResistFingerprinting);
1390 }
1391
1392 // Open a channel to the URI
1393 nsCOMPtr<nsIChannel> inputChannel;
1394 rv = NS_NewChannel(getter_AddRefs(inputChannel), aURI, aTriggeringPrincipal,
1395 nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
1396 aContentPolicyType, cookieJarSettings,
1397 nullptr, // aPerformanceStorage
1398 nullptr, // aLoadGroup
1399 static_cast<nsIInterfaceRequestor*>(this), loadFlags);
1400
1401 nsCOMPtr<nsIPrivateBrowsingChannel> pbChannel =
1402 do_QueryInterface(inputChannel);
1403 if (pbChannel) {
1404 pbChannel->SetPrivate(aIsPrivate);
1405 }
1406
1407 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) || inputChannel == nullptr) {
1408 EndDownload(NS_ERROR_FAILURE);
1409 return NS_ERROR_FAILURE;
1410 }
1411
1412 // Disable content conversion
1413 if (mPersistFlags & PERSIST_FLAGS_NO_CONVERSION) {
1414 nsCOMPtr<nsIEncodedChannel> encodedChannel(do_QueryInterface(inputChannel));
1415 if (encodedChannel) {
1416 encodedChannel->SetApplyConversion(false);
1417 }
1418 }
1419
1420 nsCOMPtr<nsILoadInfo> loadInfo = inputChannel->LoadInfo();
1421 loadInfo->SetIsUserTriggeredSave(true);
1422 if (mPersistFlags & nsIWebBrowserPersist::PERSIST_FLAGS_DISABLE_HTTPS_ONLY) {
1423 loadInfo->SetHttpsOnlyStatus(nsILoadInfo::HTTPS_ONLY_EXEMPT);
1424 }
1425
1426 // Set the referrer, post data and headers if any
1427 nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(inputChannel));
1428 if (httpChannel) {
1429 if (aReferrerInfo) {
1430 DebugOnly<nsresult> success = httpChannel->SetReferrerInfo(aReferrerInfo);
1431 MOZ_ASSERT(NS_SUCCEEDED(success))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(success)
), 1))))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(success)
), 1)))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(success)), 1)))"
, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp",
1431); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(success)), 1)))"
")"); do { MOZ_CrashSequence(__null, 1431); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1432 }
1433
1434 // Post data
1435 if (aPostData) {
1436 nsCOMPtr<nsISeekableStream> stream(do_QueryInterface(aPostData));
1437 if (stream) {
1438 // Rewind the postdata stream
1439 stream->Seek(nsISeekableStream::NS_SEEK_SET, 0);
1440 nsCOMPtr<nsIUploadChannel> uploadChannel(
1441 do_QueryInterface(httpChannel));
1442 NS_ASSERTION(uploadChannel, "http must support nsIUploadChannel")do { if (!(uploadChannel)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "http must support nsIUploadChannel", "uploadChannel", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 1442); MOZ_PretendNoReturn(); } } while (0)
;
1443 // Attach the postdata to the http channel
1444 uploadChannel->SetUploadStream(aPostData, ""_ns, -1);
1445 }
1446 }
1447
1448 // Cache key
1449 nsCOMPtr<nsICacheInfoChannel> cacheChannel(do_QueryInterface(httpChannel));
1450 if (cacheChannel && aCacheKey != 0) {
1451 cacheChannel->SetCacheKey(aCacheKey);
1452 }
1453
1454 // Headers
1455 if (aExtraHeaders) {
1456 rv = mozilla::net::AddExtraHeaders(httpChannel,
1457 nsDependentCString(aExtraHeaders));
1458 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1459 EndDownload(NS_ERROR_FAILURE);
1460 return NS_ERROR_FAILURE;
1461 }
1462 }
1463 }
1464 return SaveChannelInternal(inputChannel, aFile, aCalcFileExt);
1465}
1466
1467nsresult nsWebBrowserPersist::SaveChannelInternal(nsIChannel* aChannel,
1468 nsIURI* aFile,
1469 bool aCalcFileExt) {
1470 NS_ENSURE_ARG_POINTER(aChannel)do { if ((__builtin_expect(!!(!(aChannel)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aChannel" ") failed", nullptr
, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp",
1470); return NS_ERROR_INVALID_POINTER; } } while (false)
;
1471 NS_ENSURE_ARG_POINTER(aFile)do { if ((__builtin_expect(!!(!(aFile)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aFile" ") failed", nullptr
, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp",
1471); return NS_ERROR_INVALID_POINTER; } } while (false)
;
1472
1473 // The default behaviour of SaveChannelInternal is to download the source
1474 // into a storage stream and upload that to the target. MakeOutputStream
1475 // special-cases a file target and creates a file output stream directly.
1476 // We want to special-case a file source and create a file input stream,
1477 // but we don't need to do this in the case of a file target.
1478 nsCOMPtr<nsIFileChannel> fc(do_QueryInterface(aChannel));
1479 nsCOMPtr<nsIFileURL> fu(do_QueryInterface(aFile));
1480
1481 if (fc && !fu) {
1482 nsCOMPtr<nsIInputStream> fileInputStream, bufferedInputStream;
1483 nsresult rv = aChannel->Open(getter_AddRefs(fileInputStream));
1484 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 1484); return rv; } } while (false)
;
1485 rv = NS_NewBufferedInputStream(getter_AddRefs(bufferedInputStream),
1486 fileInputStream.forget(),
1487 BUFFERED_OUTPUT_SIZE(1024 * 32));
1488 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 1488); return rv; } } while (false)
;
1489 nsAutoCString contentType;
1490 aChannel->GetContentType(contentType);
1491 return StartUpload(bufferedInputStream, aFile, contentType);
1492 }
1493
1494 // Mark save channel as throttleable.
1495 nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(aChannel));
1496 if (cos) {
1497 cos->AddClassFlags(nsIClassOfService::Throttleable);
1498 }
1499
1500 // Read from the input channel
1501 nsresult rv = aChannel->AsyncOpen(this);
1502 if (rv == NS_ERROR_NO_CONTENT) {
1503 // Assume this is a protocol such as mailto: which does not feed out
1504 // data and just ignore it.
1505 return NS_SUCCESS_DONT_FIXUP;
1506 }
1507
1508 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1509 // Opening failed, but do we care?
1510 if (mPersistFlags & PERSIST_FLAGS_FAIL_ON_BROKEN_LINKS) {
1511 SendErrorStatusChange(true, rv, aChannel, aFile);
1512 EndDownload(NS_ERROR_FAILURE);
1513 return NS_ERROR_FAILURE;
1514 }
1515 return NS_SUCCESS_DONT_FIXUP;
1516 }
1517
1518 MutexAutoLock lock(mOutputMapMutex);
1519 // Add the output transport to the output map with the channel as the key
1520 nsCOMPtr<nsISupports> keyPtr = do_QueryInterface(aChannel);
1521 mOutputMap.InsertOrUpdate(keyPtr,
1522 MakeUnique<OutputData>(aFile, mURI, aCalcFileExt));
1523
1524 return NS_OK;
1525}
1526
1527nsresult nsWebBrowserPersist::GetExtensionForContentType(
1528 const char16_t* aContentType, char16_t** aExt) {
1529 NS_ENSURE_ARG_POINTER(aContentType)do { if ((__builtin_expect(!!(!(aContentType)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aContentType" ") failed"
, nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 1529); return NS_ERROR_INVALID_POINTER; } } while (false)
;
1530 NS_ENSURE_ARG_POINTER(aExt)do { if ((__builtin_expect(!!(!(aExt)), 0))) { NS_DebugBreak(
NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aExt" ") failed", nullptr
, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp",
1530); return NS_ERROR_INVALID_POINTER; } } while (false)
;
1531
1532 *aExt = nullptr;
1533
1534 nsresult rv;
1535 if (!mMIMEService) {
1536 mMIMEService = do_GetService(NS_MIMESERVICE_CONTRACTID"@mozilla.org/mime;1", &rv);
1537 NS_ENSURE_TRUE(mMIMEService, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(mMIMEService)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mMIMEService" ") failed"
, nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 1537); return NS_ERROR_FAILURE; } } while (false)
;
1538 }
1539
1540 nsAutoCString contentType;
1541 LossyCopyUTF16toASCII(MakeStringSpan(aContentType), contentType);
1542 nsAutoCString ext;
1543 rv = mMIMEService->GetPrimaryExtension(contentType, ""_ns, ext);
1544 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
1545 *aExt = UTF8ToNewUnicode(ext);
1546 NS_ENSURE_TRUE(*aExt, NS_ERROR_OUT_OF_MEMORY)do { if ((__builtin_expect(!!(!(*aExt)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "*aExt" ") failed", nullptr
, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp",
1546); return NS_ERROR_OUT_OF_MEMORY; } } while (false)
;
1547 return NS_OK;
1548 }
1549
1550 return NS_ERROR_FAILURE;
1551}
1552
1553nsresult nsWebBrowserPersist::SaveDocumentDeferred(
1554 mozilla::UniquePtr<WalkData>&& aData) {
1555 nsresult rv =
1556 SaveDocumentInternal(aData->mDocument, aData->mFile, aData->mDataPath);
1557 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1558 SendErrorStatusChange(true, rv, nullptr, mURI);
1559 EndDownload(rv);
1560 }
1561 return rv;
1562}
1563
1564nsresult nsWebBrowserPersist::SaveDocumentInternal(
1565 nsIWebBrowserPersistDocument* aDocument, nsIURI* aFile, nsIURI* aDataPath) {
1566 mURI = nullptr;
1567 mReferrerInfo = nullptr;
1568 NS_ENSURE_ARG_POINTER(aDocument)do { if ((__builtin_expect(!!(!(aDocument)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aDocument" ") failed", nullptr
, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp",
1568); return NS_ERROR_INVALID_POINTER; } } while (false)
;
1569 NS_ENSURE_ARG_POINTER(aFile)do { if ((__builtin_expect(!!(!(aFile)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aFile" ") failed", nullptr
, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp",
1569); return NS_ERROR_INVALID_POINTER; } } while (false)
;
1570
1571 nsresult rv = aDocument->SetPersistFlags(mPersistFlags);
1572 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 1572); return rv; } } while (false)
;
1573
1574 rv = aDocument->GetIsPrivate(&mIsPrivate);
1575 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 1575); return rv; } } while (false)
;
1576
1577 rv = aDocument->GetReferrerInfo(getter_AddRefs(mReferrerInfo));
1578 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 1578); return rv; } } while (false)
;
1579
1580 // See if we can get the local file representation of this URI
1581 nsCOMPtr<nsIFile> localFile;
1582 rv = GetLocalFileFromURI(aFile, getter_AddRefs(localFile));
1583
1584 nsCOMPtr<nsIFile> localDataPath;
1585 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && aDataPath) {
1586 // See if we can get the local file representation of this URI
1587 rv = GetLocalFileFromURI(aDataPath, getter_AddRefs(localDataPath));
1588 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "NS_ERROR_FAILURE", static_cast
<uint32_t>(__rv), name ? " (" : "", name ? name : "", name
? ")" : ""); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr
, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp",
1588); return NS_ERROR_FAILURE; } } while (false)
;
1589 }
1590
1591 // Persist the main document
1592 rv = aDocument->GetCharacterSet(mCurrentCharset);
1593 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 1593); return rv; } } while (false)
;
1594 nsAutoCString uriSpec;
1595 rv = aDocument->GetDocumentURI(uriSpec);
1596 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 1596); return rv; } } while (false)
;
1597 rv = NS_NewURI(getter_AddRefs(mURI), uriSpec, mCurrentCharset.get());
1598 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 1598); return rv; } } while (false)
;
1599 rv = aDocument->GetBaseURI(uriSpec);
1600 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 1600); return rv; } } while (false)
;
1601 rv = NS_NewURI(getter_AddRefs(mCurrentBaseURI), uriSpec,
1602 mCurrentCharset.get());
1603 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 1603); return rv; } } while (false)
;
1604
1605 // Does the caller want to fixup the referenced URIs and save those too?
1606 if (aDataPath) {
1607 // Basic steps are these.
1608 //
1609 // 1. Iterate through the document (and subdocuments) building a list
1610 // of unique URIs.
1611 // 2. For each URI create an OutputData entry and open a channel to save
1612 // it. As each URI is saved, discover the mime type and fix up the
1613 // local filename with the correct extension.
1614 // 3. Store the document in a list and wait for URI persistence to finish
1615 // 4. After URI persistence completes save the list of documents,
1616 // fixing it up as it goes out to file.
1617
1618 mCurrentDataPathIsRelative = false;
1619 mCurrentDataPath = aDataPath;
1620 mCurrentRelativePathToData = "";
1621 mCurrentThingsToPersist = 0;
1622 mTargetBaseURI = aFile;
1623
1624 // Determine if the specified data path is relative to the
1625 // specified file, (e.g. c:\docs\htmldata is relative to
1626 // c:\docs\myfile.htm, but not to d:\foo\data.
1627
1628 // Starting with the data dir work back through its parents
1629 // checking if one of them matches the base directory.
1630
1631 if (localDataPath && localFile) {
1632 nsCOMPtr<nsIFile> baseDir;
1633 localFile->GetParent(getter_AddRefs(baseDir));
1634
1635 nsAutoCString relativePathToData;
1636 nsCOMPtr<nsIFile> dataDirParent;
1637 dataDirParent = localDataPath;
1638 while (dataDirParent) {
1639 bool sameDir = false;
1640 dataDirParent->Equals(baseDir, &sameDir);
1641 if (sameDir) {
1642 mCurrentRelativePathToData = relativePathToData;
1643 mCurrentDataPathIsRelative = true;
1644 break;
1645 }
1646
1647 nsAutoString dirName;
1648 dataDirParent->GetLeafName(dirName);
1649
1650 nsAutoCString newRelativePathToData;
1651 newRelativePathToData =
1652 NS_ConvertUTF16toUTF8(dirName) + "/"_ns + relativePathToData;
1653 relativePathToData = newRelativePathToData;
1654
1655 nsCOMPtr<nsIFile> newDataDirParent;
1656 rv = dataDirParent->GetParent(getter_AddRefs(newDataDirParent));
Value stored to 'rv' is never read
1657 dataDirParent = newDataDirParent;
1658 }
1659 } else {
1660 // generate a relative path if possible
1661 nsCOMPtr<nsIURL> pathToBaseURL(do_QueryInterface(aFile));
1662 if (pathToBaseURL) {
1663 nsAutoCString relativePath; // nsACString
1664 if (NS_SUCCEEDED(((bool)(__builtin_expect(!!(!NS_FAILED_impl(pathToBaseURL->
GetRelativeSpec(aDataPath, relativePath))), 1)))
1665 pathToBaseURL->GetRelativeSpec(aDataPath, relativePath))((bool)(__builtin_expect(!!(!NS_FAILED_impl(pathToBaseURL->
GetRelativeSpec(aDataPath, relativePath))), 1)))
) {
1666 mCurrentDataPathIsRelative = true;
1667 mCurrentRelativePathToData = relativePath;
1668 }
1669 }
1670 }
1671
1672 // Store the document in a list so when URI persistence is done and the
1673 // filenames of saved URIs are known, the documents can be fixed up and
1674 // saved
1675
1676 auto* docData = new DocData;
1677 docData->mBaseURI = mCurrentBaseURI;
1678 docData->mCharset = mCurrentCharset;
1679 docData->mDocument = aDocument;
1680 docData->mFile = aFile;
1681 mDocList.AppendElement(docData);
1682
1683 // Walk the DOM gathering a list of externally referenced URIs in the uri
1684 // map
1685 nsCOMPtr<nsIWebBrowserPersistResourceVisitor> visit =
1686 new OnWalk(this, aFile, localDataPath);
1687 return aDocument->ReadResources(visit);
1688 } else {
1689 auto* docData = new DocData;
1690 docData->mBaseURI = mCurrentBaseURI;
1691 docData->mCharset = mCurrentCharset;
1692 docData->mDocument = aDocument;
1693 docData->mFile = aFile;
1694 mDocList.AppendElement(docData);
1695
1696 // Not walking DOMs, so go directly to serialization.
1697 SerializeNextFile();
1698 return NS_OK;
1699 }
1700}
1701
1702NS_IMETHODIMPnsresult
1703nsWebBrowserPersist::OnWalk::VisitResource(
1704 nsIWebBrowserPersistDocument* aDoc, const nsACString& aURI,
1705 nsContentPolicyType aContentPolicyType) {
1706 return mParent->StoreURI(aURI, aDoc, aContentPolicyType);
1707}
1708
1709NS_IMETHODIMPnsresult
1710nsWebBrowserPersist::OnWalk::VisitDocument(
1711 nsIWebBrowserPersistDocument* aDoc, nsIWebBrowserPersistDocument* aSubDoc) {
1712 URIData* data = nullptr;
1713 nsAutoCString uriSpec;
1714 nsresult rv = aSubDoc->GetDocumentURI(uriSpec);
1715 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 1715); return rv; } } while (false)
;
1716 rv = mParent->StoreURI(uriSpec, aDoc, nsIContentPolicy::TYPE_SUBDOCUMENT,
1717 false, &data);
1718 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 1718); return rv; } } while (false)
;
1719 if (!data) {
1720 // If the URI scheme isn't persistable, then don't persist.
1721 return NS_OK;
1722 }
1723 data->mIsSubFrame = true;
1724 return mParent->SaveSubframeContent(aSubDoc, aDoc, uriSpec, data);
1725}
1726
1727NS_IMETHODIMPnsresult
1728nsWebBrowserPersist::OnWalk::VisitBrowsingContext(
1729 nsIWebBrowserPersistDocument* aDoc, BrowsingContext* aContext) {
1730 RefPtr<dom::CanonicalBrowsingContext> context = aContext->Canonical();
1731
1732 if (NS_WARN_IF(!context->GetCurrentWindowGlobal())NS_warn_if_impl(!context->GetCurrentWindowGlobal(), "!context->GetCurrentWindowGlobal()"
, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp",
1732)
) {
1733 EndVisit(nullptr, NS_ERROR_FAILURE);
1734 return NS_ERROR_FAILURE;
1735 }
1736
1737 RefPtr<WebBrowserPersistDocumentParent> actor(
1738 new WebBrowserPersistDocumentParent());
1739
1740 nsCOMPtr<nsIWebBrowserPersistDocumentReceiver> receiver =
1741 new OnRemoteWalk(this, aDoc);
1742 actor->SetOnReady(receiver);
1743
1744 RefPtr<dom::BrowserParent> browserParent =
1745 context->GetCurrentWindowGlobal()->GetBrowserParent();
1746
1747 bool ok =
1748 context->GetContentParent()->SendPWebBrowserPersistDocumentConstructor(
1749 actor, browserParent, context);
1750
1751 if (NS_WARN_IF(!ok)NS_warn_if_impl(!ok, "!ok", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 1751)
) {
1752 // (The actor will be destroyed on constructor failure.)
1753 EndVisit(nullptr, NS_ERROR_FAILURE);
1754 return NS_ERROR_FAILURE;
1755 }
1756
1757 ++mPendingDocuments;
1758
1759 return NS_OK;
1760}
1761
1762NS_IMETHODIMPnsresult
1763nsWebBrowserPersist::OnWalk::EndVisit(nsIWebBrowserPersistDocument* aDoc,
1764 nsresult aStatus) {
1765 if (NS_FAILED(mStatus)((bool)(__builtin_expect(!!(NS_FAILED_impl(mStatus)), 0)))) {
1766 return mStatus;
1767 }
1768
1769 if (NS_FAILED(aStatus)((bool)(__builtin_expect(!!(NS_FAILED_impl(aStatus)), 0)))) {
1770 mStatus = aStatus;
1771 mParent->SendErrorStatusChange(true, aStatus, nullptr, mFile);
1772 mParent->EndDownload(aStatus);
1773 return aStatus;
1774 }
1775
1776 if (--mPendingDocuments) {
1777 // We're not done yet, wait for more.
1778 return NS_OK;
1779 }
1780
1781 mParent->FinishSaveDocumentInternal(mFile, mDataPath);
1782 return NS_OK;
1783}
1784
1785NS_IMETHODIMPnsresult
1786nsWebBrowserPersist::OnRemoteWalk::OnDocumentReady(
1787 nsIWebBrowserPersistDocument* aSubDocument) {
1788 mVisitor->VisitDocument(mDocument, aSubDocument);
1789 mVisitor->EndVisit(mDocument, NS_OK);
1790 return NS_OK;
1791}
1792
1793NS_IMETHODIMPnsresult
1794nsWebBrowserPersist::OnRemoteWalk::OnError(nsresult aFailure) {
1795 mVisitor->EndVisit(nullptr, aFailure);
1796 return NS_OK;
1797}
1798
1799void nsWebBrowserPersist::FinishSaveDocumentInternal(nsIURI* aFile,
1800 nsIFile* aDataPath) {
1801 // If there are things to persist, create a directory to hold them
1802 if (mCurrentThingsToPersist > 0) {
1803 if (aDataPath) {
1804 bool exists = false;
1805 bool haveDir = false;
1806
1807 aDataPath->Exists(&exists);
1808 if (exists) {
1809 aDataPath->IsDirectory(&haveDir);
1810 }
1811 if (!haveDir) {
1812 nsresult rv = aDataPath->Create(nsIFile::DIRECTORY_TYPE, 0755);
1813 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
1814 haveDir = true;
1815 } else {
1816 SendErrorStatusChange(false, rv, nullptr, aFile);
1817 }
1818 }
1819 if (!haveDir) {
1820 EndDownload(NS_ERROR_FAILURE);
1821 return;
1822 }
1823 if (mPersistFlags & PERSIST_FLAGS_CLEANUP_ON_FAILURE) {
1824 // Add to list of things to delete later if all goes wrong
1825 auto* cleanupData = new CleanupData;
1826 cleanupData->mFile = aDataPath;
1827 cleanupData->mIsDirectory = true;
1828 mCleanupList.AppendElement(cleanupData);
1829 }
1830 }
1831 }
1832
1833 if (mWalkStack.Length() > 0) {
1834 mozilla::UniquePtr<WalkData> toWalk = mWalkStack.PopLastElement();
1835 // Bounce this off the event loop to avoid stack overflow.
1836 using WalkStorage = StoreCopyPassByRRef<decltype(toWalk)>;
1837 auto saveMethod = &nsWebBrowserPersist::SaveDocumentDeferred;
1838 nsCOMPtr<nsIRunnable> saveLater = NewRunnableMethod<WalkStorage>(
1839 "nsWebBrowserPersist::FinishSaveDocumentInternal", this, saveMethod,
1840 std::move(toWalk));
1841 NS_DispatchToCurrentThread(saveLater);
1842 } else {
1843 // Done walking DOMs; on to the serialization phase.
1844 SerializeNextFile();
1845 }
1846}
1847
1848void nsWebBrowserPersist::Cleanup() {
1849 mURIMap.Clear();
1850 nsClassHashtable<nsISupportsHashKey, OutputData> outputMapCopy;
1851 {
1852 MutexAutoLock lock(mOutputMapMutex);
1853 mOutputMap.SwapElements(outputMapCopy);
1854 }
1855 for (const auto& key : outputMapCopy.Keys()) {
1856 nsCOMPtr<nsIChannel> channel = do_QueryInterface(key);
1857 if (channel) {
1858 channel->Cancel(NS_BINDING_ABORTED);
1859 }
1860 }
1861 outputMapCopy.Clear();
1862
1863 for (const auto& key : mUploadList.Keys()) {
1864 nsCOMPtr<nsIChannel> channel = do_QueryInterface(key);
1865 if (channel) {
1866 channel->Cancel(NS_BINDING_ABORTED);
1867 }
1868 }
1869 mUploadList.Clear();
1870
1871 uint32_t i;
1872 for (i = 0; i < mDocList.Length(); i++) {
1873 DocData* docData = mDocList.ElementAt(i);
1874 delete docData;
1875 }
1876 mDocList.Clear();
1877
1878 for (i = 0; i < mCleanupList.Length(); i++) {
1879 CleanupData* cleanupData = mCleanupList.ElementAt(i);
1880 delete cleanupData;
1881 }
1882 mCleanupList.Clear();
1883
1884 mFilenameList.Clear();
1885}
1886
1887void nsWebBrowserPersist::CleanupLocalFiles() {
1888 // Two passes, the first pass cleans up files, the second pass tests
1889 // for and then deletes empty directories. Directories that are not
1890 // empty after the first pass must contain files from something else
1891 // and are not deleted.
1892 int pass;
1893 for (pass = 0; pass < 2; pass++) {
1894 uint32_t i;
1895 for (i = 0; i < mCleanupList.Length(); i++) {
1896 CleanupData* cleanupData = mCleanupList.ElementAt(i);
1897 nsCOMPtr<nsIFile> file = cleanupData->mFile;
1898
1899 // Test if the dir / file exists (something in an earlier loop
1900 // may have already removed it)
1901 bool exists = false;
1902 file->Exists(&exists);
1903 if (!exists) continue;
1904
1905 // Test if the file has changed in between creation and deletion
1906 // in some way that means it should be ignored
1907 bool isDirectory = false;
1908 file->IsDirectory(&isDirectory);
1909 if (isDirectory != cleanupData->mIsDirectory)
1910 continue; // A file has become a dir or vice versa !
1911
1912 if (pass == 0 && !isDirectory) {
1913 file->Remove(false);
1914 } else if (pass == 1 && isDirectory) // Directory
1915 {
1916 // Directories are more complicated. Enumerate through
1917 // children looking for files. Any files created by the
1918 // persist object would have been deleted by the first
1919 // pass so if there are any there at this stage, the dir
1920 // cannot be deleted because it has someone else's files
1921 // in it. Empty child dirs are deleted but they must be
1922 // recursed through to ensure they are actually empty.
1923
1924 bool isEmptyDirectory = true;
1925 nsCOMArray<nsIDirectoryEnumerator> dirStack;
1926 int32_t stackSize = 0;
1927
1928 // Push the top level enum onto the stack
1929 nsCOMPtr<nsIDirectoryEnumerator> pos;
1930 if (NS_SUCCEEDED(file->GetDirectoryEntries(getter_AddRefs(pos)))((bool)(__builtin_expect(!!(!NS_FAILED_impl(file->GetDirectoryEntries
(getter_AddRefs(pos)))), 1)))
)
1931 dirStack.AppendObject(pos);
1932
1933 while (isEmptyDirectory && (stackSize = dirStack.Count())) {
1934 // Pop the last element
1935 nsCOMPtr<nsIDirectoryEnumerator> curPos;
1936 curPos = dirStack[stackSize - 1];
1937 dirStack.RemoveObjectAt(stackSize - 1);
1938
1939 nsCOMPtr<nsIFile> child;
1940 if (NS_FAILED(curPos->GetNextFile(getter_AddRefs(child)))((bool)(__builtin_expect(!!(NS_FAILED_impl(curPos->GetNextFile
(getter_AddRefs(child)))), 0)))
|| !child) {
1941 continue;
1942 }
1943
1944 bool childIsSymlink = false;
1945 child->IsSymlink(&childIsSymlink);
1946 bool childIsDir = false;
1947 child->IsDirectory(&childIsDir);
1948 if (!childIsDir || childIsSymlink) {
1949 // Some kind of file or symlink which means dir
1950 // is not empty so just drop out.
1951 isEmptyDirectory = false;
1952 break;
1953 }
1954 // Push parent enumerator followed by child enumerator
1955 nsCOMPtr<nsIDirectoryEnumerator> childPos;
1956 child->GetDirectoryEntries(getter_AddRefs(childPos));
1957 dirStack.AppendObject(curPos);
1958 if (childPos) dirStack.AppendObject(childPos);
1959 }
1960 dirStack.Clear();
1961
1962 // If after all that walking the dir is deemed empty, delete it
1963 if (isEmptyDirectory) {
1964 file->Remove(true);
1965 }
1966 }
1967 }
1968 }
1969}
1970
1971nsresult nsWebBrowserPersist::CalculateUniqueFilename(
1972 nsIURI* aURI, nsCOMPtr<nsIURI>& aOutURI) {
1973 nsCOMPtr<nsIURL> url(do_QueryInterface(aURI));
1974 NS_ENSURE_TRUE(url, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(url)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING
, "NS_ENSURE_TRUE(" "url" ") failed", nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 1974); return NS_ERROR_FAILURE; } } while (false)
;
1975
1976 // Get the old filename
1977 nsAutoCString filename;
1978 nsresult rv = url->GetFileName(filename);
1979 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "NS_ERROR_FAILURE", static_cast
<uint32_t>(__rv), name ? " (" : "", name ? name : "", name
? ")" : ""); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr
, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp",
1979); return NS_ERROR_FAILURE; } } while (false)
;
1980 nsAutoCString directory;
1981 rv = url->GetDirectory(directory);
1982 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "NS_ERROR_FAILURE", static_cast
<uint32_t>(__rv), name ? " (" : "", name ? name : "", name
? ")" : ""); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr
, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp",
1982); return NS_ERROR_FAILURE; } } while (false)
;
1983
1984 // URL-decode and sanitize the filename to prevent dangerous characters
1985 // (path separators, control characters, bidi marks, etc.).
1986 NS_UnescapeURL(filename);
1987 if (!mMIMEService) {
1988 mMIMEService = do_GetService(NS_MIMESERVICE_CONTRACTID"@mozilla.org/mime;1", &rv);
1989 }
1990 if (mMIMEService) {
1991 nsAutoString filenameU16;
1992 CopyUTF8toUTF16(filename, filenameU16);
1993 nsAutoString sanitized;
1994 if (NS_SUCCEEDED(mMIMEService->ValidateFileNameForSaving(((bool)(__builtin_expect(!!(!NS_FAILED_impl(mMIMEService->
ValidateFileNameForSaving( filenameU16, EmptyCString(), nsIMIMEService
::VALIDATE_SANITIZE_ONLY | nsIMIMEService::VALIDATE_DONT_TRUNCATE
| nsIMIMEService::VALIDATE_NO_DEFAULT_FILENAME, sanitized)))
, 1)))
1995 filenameU16, EmptyCString(),((bool)(__builtin_expect(!!(!NS_FAILED_impl(mMIMEService->
ValidateFileNameForSaving( filenameU16, EmptyCString(), nsIMIMEService
::VALIDATE_SANITIZE_ONLY | nsIMIMEService::VALIDATE_DONT_TRUNCATE
| nsIMIMEService::VALIDATE_NO_DEFAULT_FILENAME, sanitized)))
, 1)))
1996 nsIMIMEService::VALIDATE_SANITIZE_ONLY |((bool)(__builtin_expect(!!(!NS_FAILED_impl(mMIMEService->
ValidateFileNameForSaving( filenameU16, EmptyCString(), nsIMIMEService
::VALIDATE_SANITIZE_ONLY | nsIMIMEService::VALIDATE_DONT_TRUNCATE
| nsIMIMEService::VALIDATE_NO_DEFAULT_FILENAME, sanitized)))
, 1)))
1997 nsIMIMEService::VALIDATE_DONT_TRUNCATE |((bool)(__builtin_expect(!!(!NS_FAILED_impl(mMIMEService->
ValidateFileNameForSaving( filenameU16, EmptyCString(), nsIMIMEService
::VALIDATE_SANITIZE_ONLY | nsIMIMEService::VALIDATE_DONT_TRUNCATE
| nsIMIMEService::VALIDATE_NO_DEFAULT_FILENAME, sanitized)))
, 1)))
1998 nsIMIMEService::VALIDATE_NO_DEFAULT_FILENAME,((bool)(__builtin_expect(!!(!NS_FAILED_impl(mMIMEService->
ValidateFileNameForSaving( filenameU16, EmptyCString(), nsIMIMEService
::VALIDATE_SANITIZE_ONLY | nsIMIMEService::VALIDATE_DONT_TRUNCATE
| nsIMIMEService::VALIDATE_NO_DEFAULT_FILENAME, sanitized)))
, 1)))
1999 sanitized))((bool)(__builtin_expect(!!(!NS_FAILED_impl(mMIMEService->
ValidateFileNameForSaving( filenameU16, EmptyCString(), nsIMIMEService
::VALIDATE_SANITIZE_ONLY | nsIMIMEService::VALIDATE_DONT_TRUNCATE
| nsIMIMEService::VALIDATE_NO_DEFAULT_FILENAME, sanitized)))
, 1)))
) {
2000 CopyUTF16toUTF8(sanitized, filename);
2001 }
2002 }
2003
2004 // Split the filename into a base and an extension.
2005 // e.g. "foo.html" becomes "foo" & ".html"
2006 //
2007 // The nsIURL methods GetFileBaseName & GetFileExtension don't
2008 // preserve the dot whereas this code does to save some effort
2009 // later when everything is put back together.
2010 int32_t lastDot = filename.RFind(".");
2011 nsAutoCString base;
2012 nsAutoCString ext;
2013 if (lastDot >= 0) {
2014 filename.Mid(base, 0, lastDot);
2015 filename.Mid(ext, lastDot, filename.Length() - lastDot); // includes dot
2016 } else {
2017 // filename contains no dot
2018 base = filename;
2019 }
2020
2021 // Add random seed suffix to file names.
2022 filename.Assign(base);
2023 filename.Append(mFilenameRandomSeed);
2024 filename.Append(ext);
2025
2026 // Test if the filename is longer than allowed by the OS
2027 int32_t needToChop = filename.Length() - kDefaultMaxFilenameLength;
2028 if (needToChop > 0) {
2029 // Truncate the base first and then the ext if necessary
2030 if (base.Length() > (uint32_t)needToChop) {
2031 base.Truncate(base.Length() - needToChop);
2032 } else {
2033 needToChop -= base.Length() - 1;
2034 base.Truncate(1);
2035 if (ext.Length() > (uint32_t)needToChop) {
2036 ext.Truncate(ext.Length() - needToChop);
2037 } else {
2038 ext.Truncate(0);
2039 }
2040 // If kDefaultMaxFilenameLength were 1 we'd be in trouble here,
2041 // but that won't happen because it will be set to a sensible
2042 // value.
2043 }
2044
2045 filename.Assign(base);
2046 filename.Append(mFilenameRandomSeed);
2047 filename.Append(ext);
2048 }
2049
2050 // Ensure the filename is unique
2051 // Create a filename if it's empty, or if the filename / datapath is
2052 // already taken by another URI and create an alternate name.
2053
2054 if (base.IsEmpty() || !mFilenameList.IsEmpty()) {
2055 nsAutoCString tmpPath;
2056 nsAutoCString tmpBase;
2057 uint32_t duplicateCounter = 1;
2058 while (true) {
2059 // Make a file name,
2060 // Foo become foo_001, foo_002, etc.
2061 // Empty files become _001, _002 etc.
2062
2063 if (base.IsEmpty() || duplicateCounter > 1) {
2064 SmprintfPointer tmp = mozilla::Smprintf("_%03d", duplicateCounter);
2065 NS_ENSURE_TRUE(tmp, NS_ERROR_OUT_OF_MEMORY)do { if ((__builtin_expect(!!(!(tmp)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING
, "NS_ENSURE_TRUE(" "tmp" ") failed", nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 2065); return NS_ERROR_OUT_OF_MEMORY; } } while (false)
;
2066 // filename already includes the 5-char seed, so the threshold
2067 // kDefaultMaxFilenameLength - 4 correctly leaves room for the
2068 // 4-char counter suffix (_001) without exceeding the limit.
2069 if (filename.Length() < kDefaultMaxFilenameLength - 4) {
2070 tmpBase = base;
2071 } else {
2072 base.Mid(tmpBase, 0, base.Length() - 4);
2073 }
2074 tmpBase.Append(tmp.get());
2075 } else {
2076 tmpBase = base;
2077 }
2078
2079 tmpPath.Assign(directory);
2080 tmpPath.Append(tmpBase);
2081 tmpPath.Append(mFilenameRandomSeed);
2082 tmpPath.Append(ext);
2083
2084 // Test if the name is a duplicate
2085 if (!mFilenameList.Contains(tmpPath)) {
2086 if (!base.Equals(tmpBase)) {
2087 filename.Assign(tmpBase);
2088 filename.Append(mFilenameRandomSeed);
2089 filename.Append(ext);
2090 }
2091 break;
2092 }
2093 duplicateCounter++;
2094 }
2095 }
2096
2097 // Add name to list of those already used
2098 nsAutoCString newFilepath(directory);
2099 newFilepath.Append(filename);
2100 mFilenameList.AppendElement(std::move(newFilepath));
2101
2102 // Update the uri accordingly since the filename changed.
2103 // Final sanity test
2104 if (filename.Length() > kDefaultMaxFilenameLength) {
2105 NS_WARNING(NS_DebugBreak(NS_DEBUG_WARNING, "Filename wasn't truncated less than the max file length - how can "
"that be?", nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 2107)
2106 "Filename wasn't truncated less than the max file length - how can "NS_DebugBreak(NS_DEBUG_WARNING, "Filename wasn't truncated less than the max file length - how can "
"that be?", nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 2107)
2107 "that be?")NS_DebugBreak(NS_DEBUG_WARNING, "Filename wasn't truncated less than the max file length - how can "
"that be?", nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 2107)
;
2108 return NS_ERROR_FAILURE;
2109 }
2110
2111 nsCOMPtr<nsIFile> localFile;
2112 GetLocalFileFromURI(aURI, getter_AddRefs(localFile));
2113
2114 if (localFile) {
2115 nsAutoString filenameAsUnichar;
2116 CopyUTF8toUTF16(filename, filenameAsUnichar);
2117 localFile->SetLeafName(filenameAsUnichar);
2118
2119 // Resync the URI with the file after the extension has been appended
2120 return NS_MutateURI(aURI)
2121 .Apply(&nsIFileURLMutator::SetFile, localFile)
2122 .Finalize(aOutURI);
2123 }
2124 return NS_MutateURI(url)
2125 .Apply(&nsIURLMutator::SetFileName, filename, nullptr)
2126 .Finalize(aOutURI);
2127}
2128
2129nsresult nsWebBrowserPersist::MakeFilenameFromURI(nsIURI* aURI,
2130 nsString& aFilename) {
2131 // Try to get filename from the URI.
2132 nsAutoString fileName;
2133
2134 // Get a suggested file name from the URL but strip it of characters
2135 // likely to cause the name to be illegal.
2136
2137 nsCOMPtr<nsIURL> url(do_QueryInterface(aURI));
2138 if (url) {
2139 nsAutoCString nameFromURL;
2140 url->GetFileName(nameFromURL);
2141 if (mPersistFlags & PERSIST_FLAGS_DONT_CHANGE_FILENAMES) {
2142 CopyASCIItoUTF16(NS_UnescapeURL(nameFromURL), fileName);
2143 aFilename = fileName;
2144 return NS_OK;
2145 }
2146 if (!nameFromURL.IsEmpty()) {
2147 // Unescape the file name (GetFileName escapes it)
2148 NS_UnescapeURL(nameFromURL);
2149 uint32_t nameLength = 0;
2150 const char* p = nameFromURL.get();
2151 for (; *p && *p != ';' && *p != '?' && *p != '#' && *p != '.'; p++) {
2152 if (IsAsciiAlpha(*p) || IsAsciiDigit(*p) || *p == '.' || *p == '-' ||
2153 *p == '_' || (*p == ' ')) {
2154 fileName.Append(char16_t(*p));
2155 if (++nameLength == kDefaultMaxFilenameLength) {
2156 // Note:
2157 // There is no point going any further since it will be
2158 // truncated in CalculateUniqueFilename anyway.
2159 // More importantly, certain implementations of
2160 // nsIFile (e.g. the Mac impl) might truncate
2161 // names in undesirable ways, such as truncating from
2162 // the middle, inserting ellipsis and so on.
2163 break;
2164 }
2165 }
2166 }
2167 }
2168 }
2169
2170 // Empty filenames can confuse the local file object later
2171 // when it attempts to set the leaf name in CalculateUniqueFilename
2172 // for duplicates and ends up replacing the parent dir. To avoid
2173 // the problem, all filenames are made at least one character long.
2174 if (fileName.IsEmpty()) {
2175 fileName.Append(char16_t('a')); // 'a' is for arbitrary
2176 }
2177
2178 aFilename = std::move(fileName);
2179 return NS_OK;
2180}
2181
2182nsresult nsWebBrowserPersist::CalculateAndAppendFileExt(
2183 nsIURI* aURI, nsIChannel* aChannel, nsIURI* aOriginalURIWithExtension,
2184 nsCOMPtr<nsIURI>& aOutURI) {
2185 nsresult rv = NS_OK;
2186
2187 if (!mMIMEService) {
2188 mMIMEService = do_GetService(NS_MIMESERVICE_CONTRACTID"@mozilla.org/mime;1", &rv);
2189 NS_ENSURE_TRUE(mMIMEService, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(mMIMEService)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mMIMEService" ") failed"
, nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 2189); return NS_ERROR_FAILURE; } } while (false)
;
2190 }
2191
2192 nsAutoCString contentType;
2193
2194 // Get the content type from the channel
2195 aChannel->GetContentType(contentType);
2196
2197 // Get the content type from the MIME service
2198 if (contentType.IsEmpty()) {
2199 nsCOMPtr<nsIURI> uri;
2200 aChannel->GetOriginalURI(getter_AddRefs(uri));
2201 mMIMEService->GetTypeFromURI(uri, contentType);
2202 }
2203
2204 // Validate the filename
2205 if (!contentType.IsEmpty()) {
2206 nsAutoString newFileName;
2207 if (NS_SUCCEEDED(mMIMEService->GetValidFileName(((bool)(__builtin_expect(!!(!NS_FAILED_impl(mMIMEService->
GetValidFileName( aChannel, contentType, aOriginalURIWithExtension
, nsIMIMEService::VALIDATE_DEFAULT, newFileName))), 1)))
2208 aChannel, contentType, aOriginalURIWithExtension,((bool)(__builtin_expect(!!(!NS_FAILED_impl(mMIMEService->
GetValidFileName( aChannel, contentType, aOriginalURIWithExtension
, nsIMIMEService::VALIDATE_DEFAULT, newFileName))), 1)))
2209 nsIMIMEService::VALIDATE_DEFAULT, newFileName))((bool)(__builtin_expect(!!(!NS_FAILED_impl(mMIMEService->
GetValidFileName( aChannel, contentType, aOriginalURIWithExtension
, nsIMIMEService::VALIDATE_DEFAULT, newFileName))), 1)))
) {
2210 nsCOMPtr<nsIFile> localFile;
2211 GetLocalFileFromURI(aURI, getter_AddRefs(localFile));
2212 if (localFile) {
2213 localFile->SetLeafName(newFileName);
2214
2215 // Resync the URI with the file after the extension has been appended
2216 return NS_MutateURI(aURI)
2217 .Apply(&nsIFileURLMutator::SetFile, localFile)
2218 .Finalize(aOutURI);
2219 }
2220 return NS_MutateURI(aURI)
2221 .Apply(&nsIURLMutator::SetFileName,
2222 NS_ConvertUTF16toUTF8(newFileName), nullptr)
2223 .Finalize(aOutURI);
2224 }
2225 }
2226
2227 // TODO (:valentin) This method should always clone aURI
2228 aOutURI = aURI;
2229 return NS_OK;
2230}
2231
2232// Note: the MakeOutputStream helpers can be called from a background thread.
2233nsresult nsWebBrowserPersist::MakeOutputStream(
2234 nsIURI* aURI, nsIURI* aSourceURI, nsIOutputStream** aOutputStream) {
2235 nsresult rv;
2236
2237 nsCOMPtr<nsIFile> localFile;
2238 GetLocalFileFromURI(aURI, getter_AddRefs(localFile));
2239 if (localFile)
2240 rv = MakeOutputStreamFromFile(localFile, aSourceURI, aOutputStream);
2241 else
2242 rv = MakeOutputStreamFromURI(aURI, aOutputStream);
2243
2244 return rv;
2245}
2246
2247nsresult nsWebBrowserPersist::MakeOutputStreamFromFile(
2248 nsIFile* aFile, nsIURI* aSourceURI, nsIOutputStream** aOutputStream) {
2249 nsresult rv = NS_OK;
2250
2251 nsCOMPtr<nsIFileOutputStream> fileOutputStream =
2252 do_CreateInstance(NS_LOCALFILEOUTPUTSTREAM_CONTRACTID"@mozilla.org/network/file-output-stream;1", &rv);
2253 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "NS_ERROR_FAILURE", static_cast
<uint32_t>(__rv), name ? " (" : "", name ? name : "", name
? ")" : ""); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr
, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp",
2253); return NS_ERROR_FAILURE; } } while (false)
;
2254
2255 // XXX brade: get the right flags here!
2256 int32_t ioFlags = -1;
2257 if (mPersistFlags & nsIWebBrowserPersist::PERSIST_FLAGS_APPEND_TO_FILE)
2258 ioFlags = PR_APPEND0x10 | PR_CREATE_FILE0x08 | PR_WRONLY0x02;
2259 rv = fileOutputStream->Init(aFile, ioFlags, -1, 0);
2260 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 2260); return rv; } } while (false)
;
2261
2262#ifdef XP_WIN
2263 // Mark the file as coming from the correct zone for the URL, so the Windows
2264 // UAC prompt shows for untrusted origins when the user opens it.
2265 (void)mozilla::widget::WinUtils::MaybeWriteFileZoneIdSync(
2266 aFile, aSourceURI, mReferrerInfo, !mIsPrivate);
2267#endif
2268
2269 rv = NS_NewBufferedOutputStream(aOutputStream, fileOutputStream.forget(),
2270 BUFFERED_OUTPUT_SIZE(1024 * 32));
2271 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 2271); return rv; } } while (false)
;
2272
2273 if (mPersistFlags & PERSIST_FLAGS_CLEANUP_ON_FAILURE) {
2274 // Add to cleanup list in event of failure
2275 auto* cleanupData = new CleanupData;
2276 cleanupData->mFile = aFile;
2277 cleanupData->mIsDirectory = false;
2278 if (NS_IsMainThread()) {
2279 mCleanupList.AppendElement(cleanupData);
2280 } else {
2281 // If we're on a background thread, add the cleanup back on the main
2282 // thread.
2283 RefPtr<Runnable> addCleanup = NS_NewRunnableFunction(
2284 "nsWebBrowserPersist::AddCleanupToList",
2285 [self = RefPtr{this}, cleanup = std::move(cleanupData)]() {
2286 self->mCleanupList.AppendElement(cleanup);
2287 });
2288 NS_DispatchToMainThread(addCleanup);
2289 }
2290 }
2291
2292 return NS_OK;
2293}
2294
2295nsresult nsWebBrowserPersist::MakeOutputStreamFromURI(
2296 nsIURI* aURI, nsIOutputStream** aOutputStream) {
2297 uint32_t segsize = 8192;
2298 uint32_t maxsize = uint32_t(-1);
2299 nsCOMPtr<nsIStorageStream> storStream;
2300 nsresult rv =
2301 NS_NewStorageStream(segsize, maxsize, getter_AddRefs(storStream));
2302 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 2302); return rv; } } while (false)
;
2303
2304 NS_ENSURE_SUCCESS(CallQueryInterface(storStream, aOutputStream),do { nsresult __rv = CallQueryInterface(storStream, aOutputStream
); if (((bool)(__builtin_expect(!!(NS_FAILED_impl(__rv)), 0))
)) { const char* name = mozilla::GetStaticErrorName(__rv); mozilla
::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "CallQueryInterface(storStream, aOutputStream)"
, "NS_ERROR_FAILURE", static_cast<uint32_t>(__rv), name
? " (" : "", name ? name : "", name ? ")" : ""); NS_DebugBreak
(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 2305); return NS_ERROR_FAILURE; } } while (false)
2305 NS_ERROR_FAILURE)do { nsresult __rv = CallQueryInterface(storStream, aOutputStream
); if (((bool)(__builtin_expect(!!(NS_FAILED_impl(__rv)), 0))
)) { const char* name = mozilla::GetStaticErrorName(__rv); mozilla
::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "CallQueryInterface(storStream, aOutputStream)"
, "NS_ERROR_FAILURE", static_cast<uint32_t>(__rv), name
? " (" : "", name ? name : "", name ? ")" : ""); NS_DebugBreak
(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 2305); return NS_ERROR_FAILURE; } } while (false)
;
2306 return NS_OK;
2307}
2308
2309void nsWebBrowserPersist::FinishDownload() {
2310 // We call FinishDownload when we run out of things to download for this
2311 // persist operation, by dispatching this method to the main thread. By now,
2312 // it's possible that we have been canceled or encountered an error earlier
2313 // in the download, or something else called EndDownload. In that case, don't
2314 // re-run EndDownload.
2315 if (mEndCalled) {
2316 return;
2317 }
2318 EndDownload(NS_OK);
2319}
2320
2321void nsWebBrowserPersist::EndDownload(nsresult aResult) {
2322 MOZ_ASSERT(NS_IsMainThread(), "Should end download on the main thread.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "Should end download on the main thread." ")", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 2322); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "Should end download on the main thread." ")"); do { MOZ_CrashSequence
(__null, 2322); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2323
2324 // Really this should just never happen, but if it does, at least avoid
2325 // no-op notifications or pretending we succeeded if we already failed.
2326 if (mEndCalled && (NS_SUCCEEDED(aResult)((bool)(__builtin_expect(!!(!NS_FAILED_impl(aResult)), 1))) || mPersistResult == aResult)) {
2327 return;
2328 }
2329
2330 // Store the error code in the result if it is an error
2331 if (NS_SUCCEEDED(mPersistResult)((bool)(__builtin_expect(!!(!NS_FAILED_impl(mPersistResult)),
1)))
&& NS_FAILED(aResult)((bool)(__builtin_expect(!!(NS_FAILED_impl(aResult)), 0)))) {
2332 mPersistResult = aResult;
2333 }
2334
2335 if (mEndCalled) {
2336 MOZ_ASSERT(!mEndCalled, "Should only end the download once.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mEndCalled)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mEndCalled))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("!mEndCalled" " ("
"Should only end the download once." ")", "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 2336); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mEndCalled"
") (" "Should only end the download once." ")"); do { MOZ_CrashSequence
(__null, 2336); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2337 return;
2338 }
2339 mEndCalled = true;
2340
2341 ClosePromise::All(GetCurrentSerialEventTarget(), mFileClosePromises)
2342 ->Then(GetCurrentSerialEventTarget(), __func__,
2343 [self = RefPtr{this}, aResult]() {
2344 self->EndDownloadInternal(aResult);
2345 });
2346}
2347
2348void nsWebBrowserPersist::EndDownloadInternal(nsresult aResult) {
2349 // mCompleted needs to be set before issuing the stop notification.
2350 // (Bug 1224437)
2351 mCompleted = true;
2352 // State stop notification
2353 if (mProgressListener) {
2354 mProgressListener->OnStateChange(
2355 nullptr, nullptr,
2356 nsIWebProgressListener::STATE_STOP |
2357 nsIWebProgressListener::STATE_IS_NETWORK,
2358 mPersistResult);
2359 }
2360
2361 // Do file cleanup if required
2362 if (NS_FAILED(aResult)((bool)(__builtin_expect(!!(NS_FAILED_impl(aResult)), 0))) &&
2363 (mPersistFlags & PERSIST_FLAGS_CLEANUP_ON_FAILURE)) {
2364 CleanupLocalFiles();
2365 }
2366
2367 // Since filenames are randomized per save session, re-saving a page to the
2368 // same location leaves behind files from the previous save that now have
2369 // different names. Remove any entry in the data directory that was not
2370 // written in this session.
2371 if (NS_SUCCEEDED(aResult)((bool)(__builtin_expect(!!(!NS_FAILED_impl(aResult)), 1))) && mCurrentDataPath) {
2372 nsCOMPtr<nsIFile> localDataPath;
2373 if (NS_SUCCEEDED(GetLocalFileFromURI(mCurrentDataPath,((bool)(__builtin_expect(!!(!NS_FAILED_impl(GetLocalFileFromURI
(mCurrentDataPath, getter_AddRefs(localDataPath)))), 1)))
2374 getter_AddRefs(localDataPath)))((bool)(__builtin_expect(!!(!NS_FAILED_impl(GetLocalFileFromURI
(mCurrentDataPath, getter_AddRefs(localDataPath)))), 1)))
) {
2375 bool exists = false;
2376 localDataPath->Exists(&exists);
2377 nsCOMPtr<nsIURL> dataPathURL(do_QueryInterface(mCurrentDataPath));
2378 nsAutoCString dataDir;
2379 if (exists && dataPathURL &&
2380 NS_SUCCEEDED(dataPathURL->GetFilePath(dataDir))((bool)(__builtin_expect(!!(!NS_FAILED_impl(dataPathURL->GetFilePath
(dataDir))), 1)))
) {
2381 if (!dataDir.IsEmpty() && dataDir.Last() != '/') {
2382 dataDir.Append('/');
2383 }
2384 nsCOMPtr<nsIDirectoryEnumerator> entries;
2385 if (NS_SUCCEEDED(((bool)(__builtin_expect(!!(!NS_FAILED_impl(localDataPath->
GetDirectoryEntries(getter_AddRefs(entries)))), 1)))
2386 localDataPath->GetDirectoryEntries(getter_AddRefs(entries)))((bool)(__builtin_expect(!!(!NS_FAILED_impl(localDataPath->
GetDirectoryEntries(getter_AddRefs(entries)))), 1)))
) {
2387 // Collect stale entries synchronously, then delete asynchronously to
2388 // avoid blocking the main thread on I/O. Enumeration must be
2389 // synchronous so that files created by a concurrent new save (after
2390 // this point) are not included in the deletion list.
2391 nsTArray<std::pair<nsString, bool>> toDelete;
2392 nsCOMPtr<nsIFile> entry;
2393 while (NS_SUCCEEDED(entries->GetNextFile(getter_AddRefs(entry)))((bool)(__builtin_expect(!!(!NS_FAILED_impl(entries->GetNextFile
(getter_AddRefs(entry)))), 1)))
&&
2394 entry) {
2395 nsAutoString leafNameU16;
2396 entry->GetLeafName(leafNameU16);
2397 nsAutoCString leafName;
2398 CopyUTF16toUTF8(leafNameU16, leafName);
2399 // entryPath is built from GetFilePath() (URL path, forward
2400 // slashes) + nsIFile leaf name (UTF-8), matching the format used
2401 // by CalculateUniqueFilename and SaveSubframeContent when they
2402 // insert entries into mFilenameList.
2403 nsAutoCString entryPath(dataDir);
2404 entryPath.Append(leafName);
2405 if (!mFilenameList.Contains(entryPath)) {
2406 bool isDir = false;
2407 entry->IsDirectory(&isDir);
2408 nsAutoString path;
2409 entry->GetPath(path);
2410 toDelete.AppendElement(std::pair{nsString(path), isDir});
2411 }
2412 }
2413 if (!toDelete.IsEmpty()) {
2414 NS_DispatchBackgroundTask(
2415 NS_NewRunnableFunction(
2416 "nsWebBrowserPersist::CleanupStaleFiles",
2417 [paths = std::move(toDelete)]() {
2418 for (const auto& [path, isDir] : paths) {
2419 nsCOMPtr<nsIFile> file;
2420 if (NS_SUCCEEDED(((bool)(__builtin_expect(!!(!NS_FAILED_impl(NS_NewLocalFile(path
, getter_AddRefs(file)))), 1)))
2421 NS_NewLocalFile(path, getter_AddRefs(file)))((bool)(__builtin_expect(!!(!NS_FAILED_impl(NS_NewLocalFile(path
, getter_AddRefs(file)))), 1)))
) {
2422 file->Remove(isDir);
2423 }
2424 }
2425 }),
2426 NS_DISPATCH_EVENT_MAY_BLOCKnsIEventTarget::DISPATCH_EVENT_MAY_BLOCK);
2427 }
2428 }
2429 }
2430 }
2431 }
2432
2433 // Cleanup the channels
2434 Cleanup();
2435
2436 mProgressListener = nullptr;
2437 mProgressListener2 = nullptr;
2438 mEventSink = nullptr;
2439}
2440
2441nsresult nsWebBrowserPersist::FixRedirectedChannelEntry(
2442 nsIChannel* aNewChannel) {
2443 NS_ENSURE_ARG_POINTER(aNewChannel)do { if ((__builtin_expect(!!(!(aNewChannel)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aNewChannel" ") failed"
, nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 2443); return NS_ERROR_INVALID_POINTER; } } while (false)
;
2444
2445 // Iterate through existing open channels looking for one with a URI
2446 // matching the one specified.
2447 nsCOMPtr<nsIURI> originalURI;
2448 aNewChannel->GetOriginalURI(getter_AddRefs(originalURI));
2449 nsISupports* matchingKey = nullptr;
2450 for (nsISupports* key : mOutputMap.Keys()) {
2451 nsCOMPtr<nsIChannel> thisChannel = do_QueryInterface(key);
2452 nsCOMPtr<nsIURI> thisURI;
2453
2454 thisChannel->GetOriginalURI(getter_AddRefs(thisURI));
2455
2456 // Compare this channel's URI to the one passed in.
2457 bool matchingURI = false;
2458 thisURI->Equals(originalURI, &matchingURI);
2459 if (matchingURI) {
2460 matchingKey = key;
2461 break;
2462 }
2463 }
2464
2465 if (matchingKey) {
2466 // We only get called from OnStartRequest, so this is always on the
2467 // main thread. Make sure we don't pull the rug from under anything else.
2468 MutexAutoLock lock(mOutputMapMutex);
2469 // If a match was found, remove the data entry with the old channel
2470 // key and re-add it with the new channel key.
2471 mozilla::UniquePtr<OutputData> outputData;
2472 mOutputMap.Remove(matchingKey, &outputData);
2473 NS_ENSURE_TRUE(outputData, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(outputData)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "outputData" ") failed",
nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 2473); return NS_ERROR_FAILURE; } } while (false)
;
2474
2475 // Store data again with new channel unless told to ignore redirects.
2476 if (!(mPersistFlags & PERSIST_FLAGS_IGNORE_REDIRECTED_DATA)) {
2477 nsCOMPtr<nsISupports> keyPtr = do_QueryInterface(aNewChannel);
2478 mOutputMap.InsertOrUpdate(keyPtr, std::move(outputData));
2479 }
2480 }
2481
2482 return NS_OK;
2483}
2484
2485void nsWebBrowserPersist::CalcTotalProgress() {
2486 mTotalCurrentProgress = 0;
2487 mTotalMaxProgress = 0;
2488
2489 if (mOutputMap.Count() > 0) {
2490 // Total up the progress of each output stream
2491 for (const auto& data : mOutputMap.Values()) {
2492 // Only count toward total progress if destination file is local.
2493 nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(data->mFile);
2494 if (fileURL) {
2495 mTotalCurrentProgress += data->mSelfProgress;
2496 mTotalMaxProgress += data->mSelfProgressMax;
2497 }
2498 }
2499 }
2500
2501 if (mUploadList.Count() > 0) {
2502 // Total up the progress of each upload
2503 for (const auto& data : mUploadList.Values()) {
2504 if (data) {
2505 mTotalCurrentProgress += data->mSelfProgress;
2506 mTotalMaxProgress += data->mSelfProgressMax;
2507 }
2508 }
2509 }
2510
2511 // XXX this code seems pretty bogus and pointless
2512 if (mTotalCurrentProgress == 0 && mTotalMaxProgress == 0) {
2513 // No output streams so we must be complete
2514 mTotalCurrentProgress = 10000;
2515 mTotalMaxProgress = 10000;
2516 }
2517}
2518
2519nsresult nsWebBrowserPersist::StoreURI(const nsACString& aURI,
2520 nsIWebBrowserPersistDocument* aDoc,
2521 nsContentPolicyType aContentPolicyType,
2522 bool aNeedsPersisting, URIData** aData) {
2523 nsCOMPtr<nsIURI> uri;
2524 nsresult rv = NS_NewURI(getter_AddRefs(uri), aURI, mCurrentCharset.get(),
2525 mCurrentBaseURI);
2526 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 2526); return rv; } } while (false)
;
2527
2528 return StoreURI(uri, aDoc, aContentPolicyType, aNeedsPersisting, aData);
2529}
2530
2531nsresult nsWebBrowserPersist::StoreURI(nsIURI* aURI,
2532 nsIWebBrowserPersistDocument* aDoc,
2533 nsContentPolicyType aContentPolicyType,
2534 bool aNeedsPersisting, URIData** aData) {
2535 NS_ENSURE_ARG_POINTER(aURI)do { if ((__builtin_expect(!!(!(aURI)), 0))) { NS_DebugBreak(
NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aURI" ") failed", nullptr
, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp",
2535); return NS_ERROR_INVALID_POINTER; } } while (false)
;
2536 if (aData) {
2537 *aData = nullptr;
2538 }
2539
2540 // Test if this URI should be persisted. By default
2541 // we should assume the URI is persistable.
2542 bool doNotPersistURI;
2543 nsresult rv = NS_URIChainHasFlags(
2544 aURI, nsIProtocolHandler::URI_NON_PERSISTABLE, &doNotPersistURI);
2545 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2546 doNotPersistURI = false;
2547 }
2548
2549 if (doNotPersistURI) {
2550 return NS_OK;
2551 }
2552
2553 URIData* data = nullptr;
2554 MakeAndStoreLocalFilenameInURIMap(aURI, aDoc, aContentPolicyType,
2555 aNeedsPersisting, &data);
2556 if (aData) {
2557 *aData = data;
2558 }
2559
2560 return NS_OK;
2561}
2562
2563nsresult nsWebBrowserPersist::URIData::GetLocalURI(nsIURI* targetBaseURI,
2564 nsCString& aSpecOut) {
2565 aSpecOut.SetIsVoid(true);
2566 if (!mNeedsFixup) {
2567 return NS_OK;
2568 }
2569 nsresult rv;
2570 nsCOMPtr<nsIURI> fileAsURI;
2571 if (mFile) {
2572 fileAsURI = mFile;
2573 } else {
2574 fileAsURI = mDataPath;
2575 rv = AppendPathToURI(fileAsURI, mFilename, fileAsURI);
2576 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 2576); return rv; } } while (false)
;
2577 }
2578
2579 // remove username/password if present
2580 (void)NS_MutateURI(fileAsURI).SetUserPass(""_ns).Finalize(fileAsURI);
2581
2582 // reset node attribute
2583 // Use relative or absolute links
2584 if (mDataPathIsRelative) {
2585 bool isEqual = false;
2586 if (NS_SUCCEEDED(mRelativeDocumentURI->Equals(targetBaseURI, &isEqual))((bool)(__builtin_expect(!!(!NS_FAILED_impl(mRelativeDocumentURI
->Equals(targetBaseURI, &isEqual))), 1)))
&&
2587 isEqual) {
2588 nsCOMPtr<nsIURL> url(do_QueryInterface(fileAsURI));
2589 if (!url) {
2590 return NS_ERROR_FAILURE;
2591 }
2592
2593 nsAutoCString filename;
2594 url->GetFileName(filename);
2595
2596 nsAutoCString rawPathURL(mRelativePathToData);
2597 rawPathURL.Append(filename);
2598
2599 rv = NS_EscapeURL(rawPathURL, esc_FilePath, aSpecOut, fallible);
2600 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 2600); return rv; } } while (false)
;
2601 } else {
2602 nsAutoCString rawPathURL;
2603
2604 nsCOMPtr<nsIFile> dataFile;
2605 rv = GetLocalFileFromURI(mFile, getter_AddRefs(dataFile));
2606 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 2606); return rv; } } while (false)
;
2607
2608 nsCOMPtr<nsIFile> docFile;
2609 rv = GetLocalFileFromURI(targetBaseURI, getter_AddRefs(docFile));
2610 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 2610); return rv; } } while (false)
;
2611
2612 nsCOMPtr<nsIFile> parentDir;
2613 rv = docFile->GetParent(getter_AddRefs(parentDir));
2614 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 2614); return rv; } } while (false)
;
2615
2616 rv = dataFile->GetRelativePath(parentDir, rawPathURL);
2617 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 2617); return rv; } } while (false)
;
2618
2619 rv = NS_EscapeURL(rawPathURL, esc_FilePath, aSpecOut, fallible);
2620 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 2620); return rv; } } while (false)
;
2621 }
2622 } else {
2623 fileAsURI->GetSpec(aSpecOut);
2624 }
2625 if (mIsSubFrame) {
2626 AppendUTF16toUTF8(mSubFrameExt, aSpecOut);
2627 }
2628
2629 return NS_OK;
2630}
2631
2632bool nsWebBrowserPersist::DocumentEncoderExists(const char* aContentType) {
2633 return do_getDocumentTypeSupportedForEncoding(aContentType);
2634}
2635
2636nsresult nsWebBrowserPersist::SaveSubframeContent(
2637 nsIWebBrowserPersistDocument* aFrameContent,
2638 nsIWebBrowserPersistDocument* aParentDocument, const nsCString& aURISpec,
2639 URIData* aData) {
2640 NS_ENSURE_ARG_POINTER(aData)do { if ((__builtin_expect(!!(!(aData)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aData" ") failed", nullptr
, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp",
2640); return NS_ERROR_INVALID_POINTER; } } while (false)
;
2641
2642 // Extract the content type for the frame's contents.
2643 nsAutoCString contentType;
2644 nsresult rv = aFrameContent->GetContentType(contentType);
2645 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 2645); return rv; } } while (false)
;
2646
2647 nsString ext;
2648 GetExtensionForContentType(NS_ConvertASCIItoUTF16(contentType).get(),
2649 getter_Copies(ext));
2650
2651 // We must always have an extension so we will try to re-assign
2652 // the original extension if GetExtensionForContentType fails.
2653 if (ext.IsEmpty()) {
2654 nsCOMPtr<nsIURI> docURI;
2655 rv = NS_NewURI(getter_AddRefs(docURI), aURISpec, mCurrentCharset.get());
2656 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 2656); return rv; } } while (false)
;
2657
2658 nsCOMPtr<nsIURL> url(do_QueryInterface(docURI, &rv));
2659 nsAutoCString extension;
2660 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
2661 url->GetFileExtension(extension);
2662 } else {
2663 extension.AssignLiteral("htm");
2664 }
2665 aData->mSubFrameExt.Assign(char16_t('.'));
2666 AppendUTF8toUTF16(extension, aData->mSubFrameExt);
2667 } else {
2668 aData->mSubFrameExt.Assign(char16_t('.'));
2669 aData->mSubFrameExt.Append(ext);
2670 }
2671
2672 nsString filenameWithExt = aData->mFilename;
2673 filenameWithExt.Append(aData->mSubFrameExt);
2674
2675 // Work out the path for the subframe
2676 nsCOMPtr<nsIURI> frameURI = mCurrentDataPath;
2677 rv = AppendPathToURI(frameURI, filenameWithExt, frameURI);
2678 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 2678); return rv; } } while (false)
;
2679
2680 // Work out the path for the subframe data. The _data directory is a local
2681 // organizational folder never fetched from the server, and the files inside
2682 // it will be randomized individually, so its name does not need seeding.
2683 nsCOMPtr<nsIURI> frameDataURI = mCurrentDataPath;
2684 nsAutoString newFrameDataPath(aData->mFilename);
2685
2686 // Append _data
2687 newFrameDataPath.AppendLiteral("_data");
2688 rv = AppendPathToURI(frameDataURI, newFrameDataPath, frameDataURI);
2689 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 2689); return rv; } } while (false)
;
2690
2691 // Register the data directory in mFilenameList so the stale-file cleanup
2692 // in EndDownloadInternal does not remove it after a successful save.
2693 nsCOMPtr<nsIURL> dataURL(do_QueryInterface(frameDataURI));
2694 if (dataURL) {
2695 nsAutoCString directory, filename;
2696 if (NS_SUCCEEDED(dataURL->GetDirectory(directory))((bool)(__builtin_expect(!!(!NS_FAILED_impl(dataURL->GetDirectory
(directory))), 1)))
&&
2697 NS_SUCCEEDED(dataURL->GetFileName(filename))((bool)(__builtin_expect(!!(!NS_FAILED_impl(dataURL->GetFileName
(filename))), 1)))
) {
2698 NS_UnescapeURL(filename);
2699 directory.Append(filename);
2700 mFilenameList.AppendElement(directory);
2701 }
2702 }
2703
2704 // Make frame document path conformant and unique
2705 nsCOMPtr<nsIURI> out;
2706 rv = CalculateUniqueFilename(frameURI, out);
2707 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 2707); return rv; } } while (false)
;
2708 frameURI = out;
2709
2710 mCurrentThingsToPersist++;
2711
2712 // We shouldn't use SaveDocumentInternal for the contents
2713 // of frames that are not documents, e.g. images.
2714 if (DocumentEncoderExists(contentType.get())) {
2715 auto toWalk = mozilla::MakeUnique<WalkData>();
2716 toWalk->mDocument = aFrameContent;
2717 toWalk->mFile = frameURI;
2718 toWalk->mDataPath = frameDataURI;
2719 mWalkStack.AppendElement(std::move(toWalk));
2720 } else {
2721 nsContentPolicyType policyType = nsIContentPolicy::TYPE_OTHER;
2722 if (StringBeginsWith(contentType, "image/"_ns)) {
2723 policyType = nsIContentPolicy::TYPE_IMAGE;
2724 } else if (StringBeginsWith(contentType, "audio/"_ns) ||
2725 StringBeginsWith(contentType, "video/"_ns)) {
2726 policyType = nsIContentPolicy::TYPE_MEDIA;
2727 }
2728 rv = StoreURI(aURISpec, aParentDocument, policyType);
2729 }
2730 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 2730); return rv; } } while (false)
;
2731
2732 // Store the updated uri to the frame
2733 aData->mFile = std::move(frameURI);
2734 aData->mSubFrameExt.Truncate(); // we already put this in frameURI
2735
2736 return NS_OK;
2737}
2738
2739nsresult nsWebBrowserPersist::CreateChannelFromURI(nsIURI* aURI,
2740 nsIChannel** aChannel) {
2741 nsresult rv = NS_OK;
2742 *aChannel = nullptr;
2743
2744 rv = NS_NewChannel(aChannel, aURI, nsContentUtils::GetSystemPrincipal(),
2745 nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
2746 nsIContentPolicy::TYPE_OTHER);
2747 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 2747); return rv; } } while (false)
;
2748 NS_ENSURE_ARG_POINTER(*aChannel)do { if ((__builtin_expect(!!(!(*aChannel)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "*aChannel" ") failed", nullptr
, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp",
2748); return NS_ERROR_INVALID_POINTER; } } while (false)
;
2749
2750 rv = (*aChannel)->SetNotificationCallbacks(
2751 static_cast<nsIInterfaceRequestor*>(this));
2752 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp"
, 2752); return rv; } } while (false)
;
2753 return NS_OK;
2754}
2755
2756// we store the current location as the key (absolutized version of domnode's
2757// attribute's value)
2758nsresult nsWebBrowserPersist::MakeAndStoreLocalFilenameInURIMap(
2759 nsIURI* aURI, nsIWebBrowserPersistDocument* aDoc,
2760 nsContentPolicyType aContentPolicyType, bool aNeedsPersisting,
2761 URIData** aData) {
2762 NS_ENSURE_ARG_POINTER(aURI)do { if ((__builtin_expect(!!(!(aURI)), 0))) { NS_DebugBreak(
NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aURI" ") failed", nullptr
, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp",
2762); return NS_ERROR_INVALID_POINTER; } } while (false)
;
2763
2764 nsAutoCString spec;
2765 nsresult rv = aURI->GetSpec(spec);
2766 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "NS_ERROR_FAILURE", static_cast
<uint32_t>(__rv), name ? " (" : "", name ? name : "", name
? ")" : ""); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr
, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp",
2766); return NS_ERROR_FAILURE; } } while (false)
;
2767
2768 // Create a sensibly named filename for the URI and store in the URI map
2769 URIData* data;
2770 if (mURIMap.Get(spec, &data)) {
2771 if (aNeedsPersisting) {
2772 data->mNeedsPersisting = true;
2773 }
2774 if (aData) {
2775 *aData = data;
2776 }
2777 return NS_OK;
2778 }
2779
2780 // Create a unique file name for the uri
2781 nsString filename;
2782 rv = MakeFilenameFromURI(aURI, filename);
2783 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "NS_ERROR_FAILURE", static_cast
<uint32_t>(__rv), name ? " (" : "", name ? name : "", name
? ")" : ""); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr
, "./../../../dom/webbrowserpersist/nsWebBrowserPersist.cpp",
2783); return NS_ERROR_FAILURE; } } while (false)
;
2784
2785 // Store the file name
2786 data = new URIData;
2787
2788 data->mContentPolicyType = aContentPolicyType;
2789 data->mNeedsPersisting = aNeedsPersisting;
2790 data->mNeedsFixup = true;
2791 data->mFilename = std::move(filename);
2792 data->mSaved = false;
2793 data->mIsSubFrame = false;
2794 data->mDataPath = mCurrentDataPath;
2795 data->mDataPathIsRelative = mCurrentDataPathIsRelative;
2796 data->mRelativePathToData = mCurrentRelativePathToData;
2797 data->mRelativeDocumentURI = mTargetBaseURI;
2798 data->mCharset = mCurrentCharset;
2799
2800 aDoc->GetPrincipal(getter_AddRefs(data->mTriggeringPrincipal));
2801 aDoc->GetCookieJarSettings(getter_AddRefs(data->mCookieJarSettings));
2802
2803 if (aNeedsPersisting) mCurrentThingsToPersist++;
2804
2805 mURIMap.InsertOrUpdate(spec, UniquePtr<URIData>(data));
2806 if (aData) {
2807 *aData = data;
2808 }
2809
2810 return NS_OK;
2811}
2812
2813// Decide if we need to apply conversion to the passed channel.
2814void nsWebBrowserPersist::SetApplyConversionIfNeeded(nsIChannel* aChannel) {
2815 nsresult rv = NS_OK;
2816 nsCOMPtr<nsIEncodedChannel> encChannel = do_QueryInterface(aChannel, &rv);
2817 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return;
2818
2819 // Set the default conversion preference:
2820 encChannel->SetApplyConversion(false);
2821
2822 nsCOMPtr<nsIURI> thisURI;
2823 aChannel->GetURI(getter_AddRefs(thisURI));
2824 nsCOMPtr<nsIURL> sourceURL(do_QueryInterface(thisURI));
2825 if (!sourceURL) return;
2826 nsAutoCString extension;
2827 sourceURL->GetFileExtension(extension);
2828
2829 nsCOMPtr<nsIUTF8StringEnumerator> encEnum;
2830 encChannel->GetContentEncodings(getter_AddRefs(encEnum));
2831 if (!encEnum) return;
2832 nsCOMPtr<nsIExternalHelperAppService> helperAppService =
2833 do_GetService(NS_EXTERNALHELPERAPPSERVICE_CONTRACTID"@mozilla.org/uriloader/external-helper-app-service;1", &rv);
2834 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return;
2835 bool hasMore;
2836 rv = encEnum->HasMore(&hasMore);
2837 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && hasMore) {
2838 nsAutoCString encType;
2839 rv = encEnum->GetNext(encType);
2840 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
2841 bool applyConversion = false;
2842 rv = helperAppService->ApplyDecodingForExtension(extension, encType,
2843 &applyConversion);
2844 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) encChannel->SetApplyConversion(applyConversion);
2845 }
2846 }
2847}