Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : #include "WebBrowserPersistLocalDocument.h"
7 : #include "WebBrowserPersistDocumentParent.h"
8 :
9 : #include "mozilla/dom/HTMLInputElement.h"
10 : #include "mozilla/dom/HTMLSharedElement.h"
11 : #include "mozilla/dom/HTMLSharedObjectElement.h"
12 : #include "mozilla/dom/TabParent.h"
13 : #include "nsComponentManagerUtils.h"
14 : #include "nsContentUtils.h"
15 : #include "nsContentCID.h"
16 : #include "nsCycleCollectionParticipant.h"
17 : #include "nsFrameLoader.h"
18 : #include "nsIComponentRegistrar.h"
19 : #include "nsIContent.h"
20 : #include "nsIDOMAttr.h"
21 : #include "nsIDOMComment.h"
22 : #include "nsIDOMDocument.h"
23 : #include "nsIDOMHTMLAnchorElement.h"
24 : #include "nsIDOMHTMLAppletElement.h"
25 : #include "nsIDOMHTMLAreaElement.h"
26 : #include "nsIDOMHTMLBaseElement.h"
27 : #include "nsIDOMHTMLCollection.h"
28 : #include "nsIDOMHTMLDocument.h"
29 : #include "nsIDOMHTMLEmbedElement.h"
30 : #include "nsIDOMHTMLFrameElement.h"
31 : #include "nsIDOMHTMLIFrameElement.h"
32 : #include "nsIDOMHTMLImageElement.h"
33 : #include "nsIDOMHTMLInputElement.h"
34 : #include "nsIDOMHTMLLinkElement.h"
35 : #include "nsIDOMHTMLMediaElement.h"
36 : #include "nsIDOMHTMLObjectElement.h"
37 : #include "nsIDOMHTMLOptionElement.h"
38 : #include "nsIDOMHTMLScriptElement.h"
39 : #include "nsIDOMHTMLSourceElement.h"
40 : #include "nsIDOMHTMLTextAreaElement.h"
41 : #include "nsIDOMMozNamedAttrMap.h"
42 : #include "nsIDOMNode.h"
43 : #include "nsIDOMNodeFilter.h"
44 : #include "nsIDOMNodeList.h"
45 : #include "nsIDOMProcessingInstruction.h"
46 : #include "nsIDOMTreeWalker.h"
47 : #include "nsIDOMWindowUtils.h"
48 : #include "nsIDocShell.h"
49 : #include "nsIDocument.h"
50 : #include "nsIDocumentEncoder.h"
51 : #include "nsILoadContext.h"
52 : #include "nsIProtocolHandler.h"
53 : #include "nsISHEntry.h"
54 : #include "nsISupportsPrimitives.h"
55 : #include "nsITabParent.h"
56 : #include "nsIWebBrowserPersist.h"
57 : #include "nsIWebNavigation.h"
58 : #include "nsIWebPageDescriptor.h"
59 : #include "nsNetUtil.h"
60 :
61 : namespace mozilla {
62 :
63 0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(WebBrowserPersistLocalDocument)
64 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(WebBrowserPersistLocalDocument)
65 :
66 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WebBrowserPersistLocalDocument)
67 0 : NS_INTERFACE_MAP_ENTRY(nsIWebBrowserPersistDocument)
68 0 : NS_INTERFACE_MAP_ENTRY(nsISupports)
69 0 : NS_INTERFACE_MAP_END
70 :
71 0 : NS_IMPL_CYCLE_COLLECTION(WebBrowserPersistLocalDocument, mDocument)
72 :
73 :
74 0 : WebBrowserPersistLocalDocument::WebBrowserPersistLocalDocument(nsIDocument* aDocument)
75 : : mDocument(aDocument)
76 0 : , mPersistFlags(0)
77 : {
78 0 : MOZ_ASSERT(mDocument);
79 0 : }
80 :
81 : WebBrowserPersistLocalDocument::~WebBrowserPersistLocalDocument() = default;
82 :
83 : NS_IMETHODIMP
84 0 : WebBrowserPersistLocalDocument::SetPersistFlags(uint32_t aFlags)
85 : {
86 0 : mPersistFlags = aFlags;
87 0 : return NS_OK;
88 : }
89 :
90 : NS_IMETHODIMP
91 0 : WebBrowserPersistLocalDocument::GetPersistFlags(uint32_t* aFlags)
92 : {
93 0 : *aFlags = mPersistFlags;
94 0 : return NS_OK;
95 : }
96 :
97 : NS_IMETHODIMP
98 0 : WebBrowserPersistLocalDocument::GetIsPrivate(bool* aIsPrivate)
99 : {
100 0 : nsCOMPtr<nsILoadContext> privacyContext = mDocument->GetLoadContext();
101 0 : *aIsPrivate = privacyContext && privacyContext->UsePrivateBrowsing();
102 0 : return NS_OK;
103 : }
104 :
105 : NS_IMETHODIMP
106 0 : WebBrowserPersistLocalDocument::GetDocumentURI(nsACString& aURISpec)
107 : {
108 0 : nsCOMPtr<nsIURI> uri = mDocument->GetDocumentURI();
109 0 : if (!uri) {
110 0 : return NS_ERROR_UNEXPECTED;
111 : }
112 0 : return uri->GetSpec(aURISpec);
113 : }
114 :
115 : NS_IMETHODIMP
116 0 : WebBrowserPersistLocalDocument::GetBaseURI(nsACString& aURISpec)
117 : {
118 0 : nsCOMPtr<nsIURI> uri = GetBaseURI();
119 0 : if (!uri) {
120 0 : return NS_ERROR_UNEXPECTED;
121 : }
122 0 : return uri->GetSpec(aURISpec);
123 : }
124 :
125 : NS_IMETHODIMP
126 0 : WebBrowserPersistLocalDocument::GetContentType(nsACString& aContentType)
127 : {
128 0 : nsAutoString utf16Type;
129 : nsresult rv;
130 :
131 0 : rv = mDocument->GetContentType(utf16Type);
132 0 : NS_ENSURE_SUCCESS(rv, rv);
133 0 : aContentType = NS_ConvertUTF16toUTF8(utf16Type);
134 0 : return NS_OK;
135 : }
136 :
137 : NS_IMETHODIMP
138 0 : WebBrowserPersistLocalDocument::GetCharacterSet(nsACString& aCharSet)
139 : {
140 0 : GetCharacterSet()->Name(aCharSet);
141 0 : return NS_OK;
142 : }
143 :
144 : NS_IMETHODIMP
145 0 : WebBrowserPersistLocalDocument::GetTitle(nsAString& aTitle)
146 : {
147 0 : nsAutoString titleBuffer;
148 0 : mDocument->GetTitle(titleBuffer);
149 0 : aTitle = titleBuffer;
150 0 : return NS_OK;
151 : }
152 :
153 : NS_IMETHODIMP
154 0 : WebBrowserPersistLocalDocument::GetReferrer(nsAString& aReferrer)
155 : {
156 0 : mDocument->GetReferrer(aReferrer);
157 0 : return NS_OK;
158 : }
159 :
160 : NS_IMETHODIMP
161 0 : WebBrowserPersistLocalDocument::GetContentDisposition(nsAString& aCD)
162 : {
163 0 : nsCOMPtr<nsPIDOMWindowOuter> window = mDocument->GetDefaultView();
164 0 : if (NS_WARN_IF(!window)) {
165 0 : aCD.SetIsVoid(true);
166 0 : return NS_OK;
167 : }
168 0 : nsCOMPtr<nsIDOMWindowUtils> utils = do_GetInterface(window);
169 0 : if (NS_WARN_IF(!utils)) {
170 0 : aCD.SetIsVoid(true);
171 0 : return NS_OK;
172 : }
173 0 : nsresult rv = utils->GetDocumentMetadata(
174 0 : NS_LITERAL_STRING("content-disposition"), aCD);
175 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
176 0 : aCD.SetIsVoid(true);
177 : }
178 0 : return NS_OK;
179 : }
180 :
181 : NS_IMETHODIMP
182 0 : WebBrowserPersistLocalDocument::GetCacheKey(uint32_t* aKey)
183 : {
184 0 : nsCOMPtr<nsISHEntry> history = GetHistory();
185 0 : if (!history) {
186 0 : *aKey = 0;
187 0 : return NS_OK;
188 : }
189 0 : nsCOMPtr<nsISupports> abstractKey;
190 0 : nsresult rv = history->GetCacheKey(getter_AddRefs(abstractKey));
191 0 : if (NS_WARN_IF(NS_FAILED(rv)) || !abstractKey) {
192 0 : *aKey = 0;
193 0 : return NS_OK;
194 : }
195 0 : nsCOMPtr<nsISupportsPRUint32> u32 = do_QueryInterface(abstractKey);
196 0 : if (NS_WARN_IF(!u32)) {
197 0 : *aKey = 0;
198 0 : return NS_OK;
199 : }
200 0 : return u32->GetData(aKey);
201 : }
202 :
203 : NS_IMETHODIMP
204 0 : WebBrowserPersistLocalDocument::GetPostData(nsIInputStream** aStream)
205 : {
206 0 : nsCOMPtr<nsISHEntry> history = GetHistory();
207 0 : if (!history) {
208 0 : *aStream = nullptr;
209 0 : return NS_OK;
210 : }
211 0 : return history->GetPostData(aStream);
212 : }
213 :
214 : already_AddRefed<nsISHEntry>
215 0 : WebBrowserPersistLocalDocument::GetHistory()
216 : {
217 0 : nsCOMPtr<nsPIDOMWindowOuter> window = mDocument->GetDefaultView();
218 0 : if (NS_WARN_IF(!window)) {
219 0 : return nullptr;
220 : }
221 0 : nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(window);
222 0 : if (NS_WARN_IF(!webNav)) {
223 0 : return nullptr;
224 : }
225 0 : nsCOMPtr<nsIWebPageDescriptor> desc = do_QueryInterface(webNav);
226 0 : if (NS_WARN_IF(!desc)) {
227 0 : return nullptr;
228 : }
229 0 : nsCOMPtr<nsISupports> curDesc;
230 0 : nsresult rv = desc->GetCurrentDescriptor(getter_AddRefs(curDesc));
231 : // This can fail if, e.g., the document is a Print Preview.
232 0 : if (NS_FAILED(rv) || NS_WARN_IF(!curDesc)) {
233 0 : return nullptr;
234 : }
235 0 : nsCOMPtr<nsISHEntry> history = do_QueryInterface(curDesc);
236 0 : return history.forget();
237 : }
238 :
239 : NotNull<const Encoding*>
240 0 : WebBrowserPersistLocalDocument::GetCharacterSet() const
241 : {
242 0 : return mDocument->GetDocumentCharacterSet();
243 : }
244 :
245 : uint32_t
246 0 : WebBrowserPersistLocalDocument::GetPersistFlags() const
247 : {
248 0 : return mPersistFlags;
249 : }
250 :
251 :
252 : already_AddRefed<nsIURI>
253 0 : WebBrowserPersistLocalDocument::GetBaseURI() const
254 : {
255 0 : return mDocument->GetBaseURI();
256 : }
257 :
258 : namespace {
259 :
260 : // Helper class for ReadResources().
261 : class ResourceReader final : public nsIWebBrowserPersistDocumentReceiver {
262 : public:
263 : ResourceReader(WebBrowserPersistLocalDocument* aParent,
264 : nsIWebBrowserPersistResourceVisitor* aVisitor);
265 : nsresult OnWalkDOMNode(nsIDOMNode* aNode);
266 :
267 : // This is called both to indicate the end of the document walk
268 : // and when a subdocument is (maybe asynchronously) sent to the
269 : // visitor. The call to EndVisit needs to happen after both of
270 : // those have finished.
271 : void DocumentDone(nsresult aStatus);
272 :
273 : NS_DECL_NSIWEBBROWSERPERSISTDOCUMENTRECEIVER
274 : NS_DECL_ISUPPORTS
275 :
276 : private:
277 : RefPtr<WebBrowserPersistLocalDocument> mParent;
278 : nsCOMPtr<nsIWebBrowserPersistResourceVisitor> mVisitor;
279 : nsCOMPtr<nsIURI> mCurrentBaseURI;
280 : uint32_t mPersistFlags;
281 :
282 : // The number of DocumentDone calls after which EndVisit will be
283 : // called on the visitor. Counts the main document if it's still
284 : // being walked and any outstanding asynchronous subdocument
285 : // StartPersistence calls.
286 : size_t mOutstandingDocuments;
287 : // Collects the status parameters to DocumentDone calls.
288 : nsresult mEndStatus;
289 :
290 : nsresult OnWalkURI(const nsACString& aURISpec);
291 : nsresult OnWalkURI(nsIURI* aURI);
292 : nsresult OnWalkAttribute(nsIDOMNode* aNode,
293 : const char* aAttribute,
294 : const char* aNamespaceURI = "");
295 : nsresult OnWalkSubframe(nsIDOMNode* aNode);
296 :
297 : ~ResourceReader();
298 :
299 : using IWBP = nsIWebBrowserPersist;
300 : };
301 :
302 0 : NS_IMPL_ISUPPORTS(ResourceReader, nsIWebBrowserPersistDocumentReceiver)
303 :
304 0 : ResourceReader::ResourceReader(WebBrowserPersistLocalDocument* aParent,
305 0 : nsIWebBrowserPersistResourceVisitor* aVisitor)
306 : : mParent(aParent)
307 : , mVisitor(aVisitor)
308 0 : , mCurrentBaseURI(aParent->GetBaseURI())
309 0 : , mPersistFlags(aParent->GetPersistFlags())
310 : , mOutstandingDocuments(1)
311 0 : , mEndStatus(NS_OK)
312 : {
313 0 : MOZ_ASSERT(mCurrentBaseURI);
314 0 : }
315 :
316 0 : ResourceReader::~ResourceReader()
317 : {
318 0 : MOZ_ASSERT(mOutstandingDocuments == 0);
319 0 : }
320 :
321 : void
322 0 : ResourceReader::DocumentDone(nsresult aStatus)
323 : {
324 0 : MOZ_ASSERT(mOutstandingDocuments > 0);
325 0 : if (NS_SUCCEEDED(mEndStatus)) {
326 0 : mEndStatus = aStatus;
327 : }
328 0 : if (--mOutstandingDocuments == 0) {
329 0 : mVisitor->EndVisit(mParent, mEndStatus);
330 : }
331 0 : }
332 :
333 : nsresult
334 0 : ResourceReader::OnWalkSubframe(nsIDOMNode* aNode)
335 : {
336 0 : nsCOMPtr<nsIFrameLoaderOwner> loaderOwner = do_QueryInterface(aNode);
337 0 : NS_ENSURE_STATE(loaderOwner);
338 0 : RefPtr<nsFrameLoader> loader = loaderOwner->GetFrameLoader();
339 0 : NS_ENSURE_STATE(loader);
340 :
341 0 : ++mOutstandingDocuments;
342 : // Pass in 0 as the outer window ID so that we start
343 : // persisting the root of this subframe, and not some other
344 : // subframe child of this subframe.
345 0 : nsresult rv = loader->StartPersistence(0, this);
346 0 : if (NS_FAILED(rv)) {
347 0 : if (rv == NS_ERROR_NO_CONTENT) {
348 : // Just ignore frames with no content document.
349 0 : rv = NS_OK;
350 : }
351 : // StartPersistence won't eventually call this if it failed,
352 : // so this does so (to keep mOutstandingDocuments correct).
353 0 : DocumentDone(rv);
354 : }
355 0 : return rv;
356 : }
357 :
358 : NS_IMETHODIMP
359 0 : ResourceReader::OnDocumentReady(nsIWebBrowserPersistDocument* aDocument)
360 : {
361 0 : mVisitor->VisitDocument(mParent, aDocument);
362 0 : DocumentDone(NS_OK);
363 0 : return NS_OK;
364 : }
365 :
366 : NS_IMETHODIMP
367 0 : ResourceReader::OnError(nsresult aFailure)
368 : {
369 0 : DocumentDone(aFailure);
370 0 : return NS_OK;
371 : }
372 :
373 : nsresult
374 0 : ResourceReader::OnWalkURI(nsIURI* aURI)
375 : {
376 : // Test if this URI should be persisted. By default
377 : // we should assume the URI is persistable.
378 : bool doNotPersistURI;
379 : nsresult rv = NS_URIChainHasFlags(aURI,
380 : nsIProtocolHandler::URI_NON_PERSISTABLE,
381 0 : &doNotPersistURI);
382 0 : if (NS_SUCCEEDED(rv) && doNotPersistURI) {
383 0 : return NS_OK;
384 : }
385 :
386 0 : nsAutoCString stringURI;
387 0 : rv = aURI->GetSpec(stringURI);
388 0 : NS_ENSURE_SUCCESS(rv, rv);
389 0 : return mVisitor->VisitResource(mParent, stringURI);
390 : }
391 :
392 : nsresult
393 0 : ResourceReader::OnWalkURI(const nsACString& aURISpec)
394 : {
395 : nsresult rv;
396 0 : nsCOMPtr<nsIURI> uri;
397 :
398 0 : rv = NS_NewURI(getter_AddRefs(uri),
399 : aURISpec,
400 : mParent->GetCharacterSet(),
401 0 : mCurrentBaseURI);
402 0 : NS_ENSURE_SUCCESS(rv, rv);
403 0 : return OnWalkURI(uri);
404 : }
405 :
406 : static nsresult
407 0 : ExtractAttribute(nsIDOMNode* aNode,
408 : const char* aAttribute,
409 : const char* aNamespaceURI,
410 : nsCString& aValue)
411 : {
412 0 : nsCOMPtr<nsIDOMElement> element = do_QueryInterface(aNode);
413 0 : MOZ_ASSERT(element);
414 :
415 : // Find the named URI attribute on the (element) node and store
416 : // a reference to the URI that maps onto a local file name
417 :
418 0 : nsCOMPtr<nsIDOMMozNamedAttrMap> attrMap;
419 0 : nsresult rv = element->GetAttributes(getter_AddRefs(attrMap));
420 0 : NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
421 :
422 0 : NS_ConvertASCIItoUTF16 namespaceURI(aNamespaceURI);
423 0 : NS_ConvertASCIItoUTF16 attribute(aAttribute);
424 0 : nsCOMPtr<nsIDOMAttr> attr;
425 0 : rv = attrMap->GetNamedItemNS(namespaceURI, attribute, getter_AddRefs(attr));
426 0 : NS_ENSURE_SUCCESS(rv, rv);
427 0 : if (attr) {
428 0 : nsAutoString value;
429 0 : rv = attr->GetValue(value);
430 0 : NS_ENSURE_SUCCESS(rv, rv);
431 0 : aValue = NS_ConvertUTF16toUTF8(value);
432 : } else {
433 0 : aValue.Truncate();
434 : }
435 0 : return NS_OK;
436 : }
437 :
438 : nsresult
439 0 : ResourceReader::OnWalkAttribute(nsIDOMNode* aNode,
440 : const char* aAttribute,
441 : const char* aNamespaceURI)
442 : {
443 0 : nsAutoCString uriSpec;
444 0 : nsresult rv = ExtractAttribute(aNode, aAttribute, aNamespaceURI, uriSpec);
445 0 : NS_ENSURE_SUCCESS(rv, rv);
446 0 : if (uriSpec.IsEmpty()) {
447 0 : return NS_OK;
448 : }
449 0 : return OnWalkURI(uriSpec);
450 : }
451 :
452 : static nsresult
453 0 : GetXMLStyleSheetLink(nsIDOMProcessingInstruction *aPI, nsAString &aHref)
454 : {
455 : nsresult rv;
456 0 : nsAutoString data;
457 0 : rv = aPI->GetData(data);
458 0 : NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
459 :
460 0 : nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::href, aHref);
461 0 : return NS_OK;
462 : }
463 :
464 : nsresult
465 0 : ResourceReader::OnWalkDOMNode(nsIDOMNode* aNode)
466 : {
467 : nsresult rv;
468 :
469 : // Fixup xml-stylesheet processing instructions
470 0 : nsCOMPtr<nsIDOMProcessingInstruction> nodeAsPI = do_QueryInterface(aNode);
471 0 : if (nodeAsPI) {
472 0 : nsAutoString target;
473 0 : rv = nodeAsPI->GetTarget(target);
474 0 : NS_ENSURE_SUCCESS(rv, rv);
475 0 : if (target.EqualsLiteral("xml-stylesheet")) {
476 0 : nsAutoString href;
477 0 : GetXMLStyleSheetLink(nodeAsPI, href);
478 0 : if (!href.IsEmpty()) {
479 0 : return OnWalkURI(NS_ConvertUTF16toUTF8(href));
480 : }
481 : }
482 0 : return NS_OK;
483 : }
484 :
485 0 : nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
486 0 : if (!content) {
487 0 : return NS_OK;
488 : }
489 :
490 : // Test the node to see if it's an image, frame, iframe, css, js
491 0 : nsCOMPtr<nsIDOMHTMLImageElement> nodeAsImage = do_QueryInterface(aNode);
492 0 : if (nodeAsImage) {
493 0 : return OnWalkAttribute(aNode, "src");
494 : }
495 :
496 0 : if (content->IsSVGElement(nsGkAtoms::img)) {
497 0 : return OnWalkAttribute(aNode, "href", "http://www.w3.org/1999/xlink");
498 : }
499 :
500 0 : nsCOMPtr<nsIDOMHTMLMediaElement> nodeAsMedia = do_QueryInterface(aNode);
501 0 : if (nodeAsMedia) {
502 0 : return OnWalkAttribute(aNode, "src");
503 : }
504 0 : nsCOMPtr<nsIDOMHTMLSourceElement> nodeAsSource = do_QueryInterface(aNode);
505 0 : if (nodeAsSource) {
506 0 : return OnWalkAttribute(aNode, "src");
507 : }
508 :
509 0 : if (content->IsHTMLElement(nsGkAtoms::body)) {
510 0 : return OnWalkAttribute(aNode, "background");
511 : }
512 :
513 0 : if (content->IsHTMLElement(nsGkAtoms::table)) {
514 0 : return OnWalkAttribute(aNode, "background");
515 : }
516 :
517 0 : if (content->IsHTMLElement(nsGkAtoms::tr)) {
518 0 : return OnWalkAttribute(aNode, "background");
519 : }
520 :
521 0 : if (content->IsAnyOfHTMLElements(nsGkAtoms::td, nsGkAtoms::th)) {
522 0 : return OnWalkAttribute(aNode, "background");
523 : }
524 :
525 0 : nsCOMPtr<nsIDOMHTMLScriptElement> nodeAsScript = do_QueryInterface(aNode);
526 0 : if (nodeAsScript) {
527 0 : return OnWalkAttribute(aNode, "src");
528 : }
529 :
530 0 : if (content->IsSVGElement(nsGkAtoms::script)) {
531 0 : return OnWalkAttribute(aNode, "href", "http://www.w3.org/1999/xlink");
532 : }
533 :
534 0 : nsCOMPtr<nsIDOMHTMLEmbedElement> nodeAsEmbed = do_QueryInterface(aNode);
535 0 : if (nodeAsEmbed) {
536 0 : return OnWalkAttribute(aNode, "src");
537 : }
538 :
539 0 : nsCOMPtr<nsIDOMHTMLObjectElement> nodeAsObject = do_QueryInterface(aNode);
540 0 : if (nodeAsObject) {
541 0 : return OnWalkAttribute(aNode, "data");
542 : }
543 :
544 0 : nsCOMPtr<nsIDOMHTMLAppletElement> nodeAsApplet = do_QueryInterface(aNode);
545 0 : if (nodeAsApplet) {
546 : // For an applet, relative URIs are resolved relative to the
547 : // codebase (which is resolved relative to the base URI).
548 0 : nsCOMPtr<nsIURI> oldBase = mCurrentBaseURI;
549 0 : nsAutoString codebase;
550 0 : rv = nodeAsApplet->GetCodeBase(codebase);
551 0 : NS_ENSURE_SUCCESS(rv, rv);
552 0 : if (!codebase.IsEmpty()) {
553 0 : nsCOMPtr<nsIURI> baseURI;
554 0 : rv = NS_NewURI(getter_AddRefs(baseURI), codebase,
555 0 : mParent->GetCharacterSet(), mCurrentBaseURI);
556 0 : NS_ENSURE_SUCCESS(rv, rv);
557 0 : if (baseURI) {
558 0 : mCurrentBaseURI = baseURI;
559 : // Must restore this before returning (or ENSURE'ing).
560 : }
561 : }
562 :
563 : // We only store 'code' locally if there is no 'archive',
564 : // otherwise we assume the archive file(s) contains it (bug 430283).
565 0 : nsAutoCString archiveAttr;
566 0 : rv = ExtractAttribute(aNode, "archive", "", archiveAttr);
567 0 : if (NS_SUCCEEDED(rv)) {
568 0 : if (!archiveAttr.IsEmpty()) {
569 0 : rv = OnWalkURI(archiveAttr);
570 : } else {
571 0 : rv = OnWalkAttribute(aNode, "core");
572 : }
573 : }
574 :
575 : // restore the base URI we really want to have
576 0 : mCurrentBaseURI = oldBase;
577 0 : return rv;
578 : }
579 :
580 0 : nsCOMPtr<nsIDOMHTMLLinkElement> nodeAsLink = do_QueryInterface(aNode);
581 0 : if (nodeAsLink) {
582 : // Test if the link has a rel value indicating it to be a stylesheet
583 0 : nsAutoString linkRel;
584 0 : if (NS_SUCCEEDED(nodeAsLink->GetRel(linkRel)) && !linkRel.IsEmpty()) {
585 0 : nsReadingIterator<char16_t> start;
586 0 : nsReadingIterator<char16_t> end;
587 0 : nsReadingIterator<char16_t> current;
588 :
589 0 : linkRel.BeginReading(start);
590 0 : linkRel.EndReading(end);
591 :
592 : // Walk through space delimited string looking for "stylesheet"
593 0 : for (current = start; current != end; ++current) {
594 : // Ignore whitespace
595 0 : if (nsCRT::IsAsciiSpace(*current)) {
596 0 : continue;
597 : }
598 :
599 : // Grab the next space delimited word
600 0 : nsReadingIterator<char16_t> startWord = current;
601 0 : do {
602 0 : ++current;
603 0 : } while (current != end && !nsCRT::IsAsciiSpace(*current));
604 :
605 : // Store the link for fix up if it says "stylesheet"
606 0 : if (Substring(startWord, current)
607 : .LowerCaseEqualsLiteral("stylesheet")) {
608 0 : OnWalkAttribute(aNode, "href");
609 0 : return NS_OK;
610 : }
611 0 : if (current == end) {
612 0 : break;
613 : }
614 : }
615 : }
616 0 : return NS_OK;
617 : }
618 :
619 0 : nsCOMPtr<nsIDOMHTMLFrameElement> nodeAsFrame = do_QueryInterface(aNode);
620 0 : if (nodeAsFrame) {
621 0 : return OnWalkSubframe(aNode);
622 : }
623 :
624 0 : nsCOMPtr<nsIDOMHTMLIFrameElement> nodeAsIFrame = do_QueryInterface(aNode);
625 0 : if (nodeAsIFrame && !(mPersistFlags &
626 0 : IWBP::PERSIST_FLAGS_IGNORE_IFRAMES)) {
627 0 : return OnWalkSubframe(aNode);
628 : }
629 :
630 0 : nsCOMPtr<nsIDOMHTMLInputElement> nodeAsInput = do_QueryInterface(aNode);
631 0 : if (nodeAsInput) {
632 0 : return OnWalkAttribute(aNode, "src");
633 : }
634 :
635 0 : return NS_OK;
636 : }
637 :
638 : // Helper class for node rewriting in writeContent().
639 : class PersistNodeFixup final : public nsIDocumentEncoderNodeFixup {
640 : public:
641 : PersistNodeFixup(WebBrowserPersistLocalDocument* aParent,
642 : nsIWebBrowserPersistURIMap* aMap,
643 : nsIURI* aTargetURI);
644 :
645 : NS_DECL_ISUPPORTS
646 : NS_DECL_NSIDOCUMENTENCODERNODEFIXUP
647 : private:
648 0 : virtual ~PersistNodeFixup() = default;
649 : RefPtr<WebBrowserPersistLocalDocument> mParent;
650 : nsClassHashtable<nsCStringHashKey, nsCString> mMap;
651 : nsCOMPtr<nsIURI> mCurrentBaseURI;
652 : nsCOMPtr<nsIURI> mTargetBaseURI;
653 :
654 0 : bool IsFlagSet(uint32_t aFlag) const {
655 0 : return mParent->GetPersistFlags() & aFlag;
656 : }
657 :
658 : nsresult GetNodeToFixup(nsIDOMNode* aNodeIn, nsIDOMNode** aNodeOut);
659 : nsresult FixupURI(nsAString& aURI);
660 : nsresult FixupAttribute(nsIDOMNode* aNode,
661 : const char* aAttribute,
662 : const char* aNamespaceURI = "");
663 : nsresult FixupAnchor(nsIDOMNode* aNode);
664 : nsresult FixupXMLStyleSheetLink(nsIDOMProcessingInstruction* aPI,
665 : const nsAString& aHref);
666 :
667 : using IWBP = nsIWebBrowserPersist;
668 : };
669 :
670 0 : NS_IMPL_ISUPPORTS(PersistNodeFixup, nsIDocumentEncoderNodeFixup)
671 :
672 0 : PersistNodeFixup::PersistNodeFixup(WebBrowserPersistLocalDocument* aParent,
673 : nsIWebBrowserPersistURIMap* aMap,
674 0 : nsIURI* aTargetURI)
675 : : mParent(aParent)
676 0 : , mCurrentBaseURI(aParent->GetBaseURI())
677 0 : , mTargetBaseURI(aTargetURI)
678 : {
679 0 : if (aMap) {
680 : uint32_t mapSize;
681 0 : nsresult rv = aMap->GetNumMappedURIs(&mapSize);
682 0 : MOZ_ASSERT(NS_SUCCEEDED(rv));
683 0 : NS_ENSURE_SUCCESS_VOID(rv);
684 0 : for (uint32_t i = 0; i < mapSize; ++i) {
685 0 : nsAutoCString urlFrom;
686 0 : auto* urlTo = new nsCString();
687 :
688 0 : rv = aMap->GetURIMapping(i, urlFrom, *urlTo);
689 0 : MOZ_ASSERT(NS_SUCCEEDED(rv));
690 0 : if (NS_SUCCEEDED(rv)) {
691 0 : mMap.Put(urlFrom, urlTo);
692 : }
693 : }
694 : }
695 : }
696 :
697 : nsresult
698 0 : PersistNodeFixup::GetNodeToFixup(nsIDOMNode *aNodeIn, nsIDOMNode **aNodeOut)
699 : {
700 : // Avoid mixups in FixupNode that could leak objects; this goes
701 : // against the usual out parameter convention, but it's a private
702 : // method so shouldn't be a problem.
703 0 : MOZ_ASSERT(!*aNodeOut);
704 :
705 0 : if (!IsFlagSet(IWBP::PERSIST_FLAGS_FIXUP_ORIGINAL_DOM)) {
706 0 : nsresult rv = aNodeIn->CloneNode(false, 1, aNodeOut);
707 0 : NS_ENSURE_SUCCESS(rv, rv);
708 : } else {
709 0 : NS_ADDREF(*aNodeOut = aNodeIn);
710 : }
711 0 : return NS_OK;
712 : }
713 :
714 : nsresult
715 0 : PersistNodeFixup::FixupURI(nsAString &aURI)
716 : {
717 : // get the current location of the file (absolutized)
718 0 : nsCOMPtr<nsIURI> uri;
719 0 : nsresult rv = NS_NewURI(getter_AddRefs(uri), aURI,
720 0 : mParent->GetCharacterSet(), mCurrentBaseURI);
721 0 : NS_ENSURE_SUCCESS(rv, rv);
722 0 : nsAutoCString spec;
723 0 : rv = uri->GetSpec(spec);
724 0 : NS_ENSURE_SUCCESS(rv, rv);
725 :
726 0 : const nsCString* replacement = mMap.Get(spec);
727 0 : if (!replacement) {
728 : // Note that most callers ignore this "failure".
729 0 : return NS_ERROR_FAILURE;
730 : }
731 0 : if (!replacement->IsEmpty()) {
732 0 : aURI = NS_ConvertUTF8toUTF16(*replacement);
733 : }
734 0 : return NS_OK;
735 : }
736 :
737 : nsresult
738 0 : PersistNodeFixup::FixupAttribute(nsIDOMNode* aNode,
739 : const char* aAttribute,
740 : const char* aNamespaceURI)
741 : {
742 0 : nsCOMPtr<nsIDOMElement> element = do_QueryInterface(aNode);
743 0 : MOZ_ASSERT(element);
744 :
745 0 : nsCOMPtr<nsIDOMMozNamedAttrMap> attrMap;
746 0 : nsresult rv = element->GetAttributes(getter_AddRefs(attrMap));
747 0 : NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
748 :
749 0 : NS_ConvertASCIItoUTF16 attribute(aAttribute);
750 0 : NS_ConvertASCIItoUTF16 namespaceURI(aNamespaceURI);
751 0 : nsCOMPtr<nsIDOMAttr> attr;
752 0 : rv = attrMap->GetNamedItemNS(namespaceURI, attribute, getter_AddRefs(attr));
753 0 : if (attr) {
754 0 : nsString uri;
755 0 : attr->GetValue(uri);
756 0 : rv = FixupURI(uri);
757 0 : if (NS_SUCCEEDED(rv)) {
758 0 : attr->SetValue(uri);
759 : }
760 : }
761 :
762 0 : return rv;
763 : }
764 :
765 : nsresult
766 0 : PersistNodeFixup::FixupAnchor(nsIDOMNode *aNode)
767 : {
768 0 : if (IsFlagSet(IWBP::PERSIST_FLAGS_DONT_FIXUP_LINKS)) {
769 0 : return NS_OK;
770 : }
771 :
772 0 : nsCOMPtr<nsIDOMElement> element = do_QueryInterface(aNode);
773 0 : MOZ_ASSERT(element);
774 :
775 0 : nsCOMPtr<nsIDOMMozNamedAttrMap> attrMap;
776 0 : nsresult rv = element->GetAttributes(getter_AddRefs(attrMap));
777 0 : NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
778 :
779 : // Make all anchor links absolute so they point off onto the Internet
780 0 : nsString attribute(NS_LITERAL_STRING("href"));
781 0 : nsCOMPtr<nsIDOMAttr> attr;
782 0 : rv = attrMap->GetNamedItem(attribute, getter_AddRefs(attr));
783 0 : if (attr) {
784 0 : nsString oldValue;
785 0 : attr->GetValue(oldValue);
786 0 : NS_ConvertUTF16toUTF8 oldCValue(oldValue);
787 :
788 : // Skip empty values and self-referencing bookmarks
789 0 : if (oldCValue.IsEmpty() || oldCValue.CharAt(0) == '#') {
790 0 : return NS_OK;
791 : }
792 :
793 : // if saving file to same location, we don't need to do any fixup
794 : bool isEqual;
795 0 : if (mTargetBaseURI &&
796 0 : NS_SUCCEEDED(mCurrentBaseURI->Equals(mTargetBaseURI, &isEqual)) &&
797 : isEqual) {
798 0 : return NS_OK;
799 : }
800 :
801 0 : nsCOMPtr<nsIURI> relativeURI;
802 0 : relativeURI = IsFlagSet(IWBP::PERSIST_FLAGS_FIXUP_LINKS_TO_DESTINATION)
803 0 : ? mTargetBaseURI : mCurrentBaseURI;
804 : // Make a new URI to replace the current one
805 0 : nsCOMPtr<nsIURI> newURI;
806 0 : rv = NS_NewURI(getter_AddRefs(newURI), oldCValue,
807 0 : mParent->GetCharacterSet(), relativeURI);
808 0 : if (NS_SUCCEEDED(rv) && newURI) {
809 0 : newURI->SetUserPass(EmptyCString());
810 0 : nsAutoCString uriSpec;
811 0 : rv = newURI->GetSpec(uriSpec);
812 0 : NS_ENSURE_SUCCESS(rv, rv);
813 0 : attr->SetValue(NS_ConvertUTF8toUTF16(uriSpec));
814 : }
815 : }
816 :
817 0 : return NS_OK;
818 : }
819 :
820 : static void
821 0 : AppendXMLAttr(const nsAString& key, const nsAString& aValue, nsAString& aBuffer)
822 : {
823 0 : if (!aBuffer.IsEmpty()) {
824 0 : aBuffer.Append(' ');
825 : }
826 0 : aBuffer.Append(key);
827 0 : aBuffer.AppendLiteral(R"(=")");
828 0 : for (size_t i = 0; i < aValue.Length(); ++i) {
829 0 : switch (aValue[i]) {
830 : case '&':
831 0 : aBuffer.AppendLiteral("&");
832 0 : break;
833 : case '<':
834 0 : aBuffer.AppendLiteral("<");
835 0 : break;
836 : case '>':
837 0 : aBuffer.AppendLiteral(">");
838 0 : break;
839 : case '"':
840 0 : aBuffer.AppendLiteral(""");
841 0 : break;
842 : default:
843 0 : aBuffer.Append(aValue[i]);
844 0 : break;
845 : }
846 : }
847 0 : aBuffer.Append('"');
848 0 : }
849 :
850 : nsresult
851 0 : PersistNodeFixup::FixupXMLStyleSheetLink(nsIDOMProcessingInstruction* aPI,
852 : const nsAString& aHref)
853 : {
854 0 : NS_ENSURE_ARG_POINTER(aPI);
855 0 : nsresult rv = NS_OK;
856 :
857 0 : nsAutoString data;
858 0 : rv = aPI->GetData(data);
859 0 : NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
860 :
861 0 : nsAutoString href;
862 : nsContentUtils::GetPseudoAttributeValue(data,
863 : nsGkAtoms::href,
864 0 : href);
865 :
866 : // Construct and set a new data value for the xml-stylesheet
867 0 : if (!aHref.IsEmpty() && !href.IsEmpty())
868 : {
869 0 : nsAutoString alternate;
870 0 : nsAutoString charset;
871 0 : nsAutoString title;
872 0 : nsAutoString type;
873 0 : nsAutoString media;
874 :
875 : nsContentUtils::GetPseudoAttributeValue(data,
876 : nsGkAtoms::alternate,
877 0 : alternate);
878 : nsContentUtils::GetPseudoAttributeValue(data,
879 : nsGkAtoms::charset,
880 0 : charset);
881 : nsContentUtils::GetPseudoAttributeValue(data,
882 : nsGkAtoms::title,
883 0 : title);
884 : nsContentUtils::GetPseudoAttributeValue(data,
885 : nsGkAtoms::type,
886 0 : type);
887 : nsContentUtils::GetPseudoAttributeValue(data,
888 : nsGkAtoms::media,
889 0 : media);
890 :
891 0 : nsAutoString newData;
892 0 : AppendXMLAttr(NS_LITERAL_STRING("href"), aHref, newData);
893 0 : if (!title.IsEmpty()) {
894 0 : AppendXMLAttr(NS_LITERAL_STRING("title"), title, newData);
895 : }
896 0 : if (!media.IsEmpty()) {
897 0 : AppendXMLAttr(NS_LITERAL_STRING("media"), media, newData);
898 : }
899 0 : if (!type.IsEmpty()) {
900 0 : AppendXMLAttr(NS_LITERAL_STRING("type"), type, newData);
901 : }
902 0 : if (!charset.IsEmpty()) {
903 0 : AppendXMLAttr(NS_LITERAL_STRING("charset"), charset, newData);
904 : }
905 0 : if (!alternate.IsEmpty()) {
906 0 : AppendXMLAttr(NS_LITERAL_STRING("alternate"), alternate, newData);
907 : }
908 0 : aPI->SetData(newData);
909 : }
910 :
911 0 : return rv;
912 : }
913 :
914 : NS_IMETHODIMP
915 0 : PersistNodeFixup::FixupNode(nsIDOMNode *aNodeIn,
916 : bool *aSerializeCloneKids,
917 : nsIDOMNode **aNodeOut)
918 : {
919 0 : *aNodeOut = nullptr;
920 0 : *aSerializeCloneKids = false;
921 :
922 : uint16_t type;
923 0 : nsresult rv = aNodeIn->GetNodeType(&type);
924 0 : NS_ENSURE_SUCCESS(rv, rv);
925 0 : if (type != nsIDOMNode::ELEMENT_NODE &&
926 0 : type != nsIDOMNode::PROCESSING_INSTRUCTION_NODE) {
927 0 : return NS_OK;
928 : }
929 :
930 : // Fixup xml-stylesheet processing instructions
931 0 : nsCOMPtr<nsIDOMProcessingInstruction> nodeAsPI = do_QueryInterface(aNodeIn);
932 0 : if (nodeAsPI) {
933 0 : nsAutoString target;
934 0 : nodeAsPI->GetTarget(target);
935 0 : if (target.EqualsLiteral("xml-stylesheet"))
936 : {
937 0 : rv = GetNodeToFixup(aNodeIn, aNodeOut);
938 0 : if (NS_SUCCEEDED(rv) && *aNodeOut) {
939 : nsCOMPtr<nsIDOMProcessingInstruction> outNode =
940 0 : do_QueryInterface(*aNodeOut);
941 0 : nsAutoString href;
942 0 : GetXMLStyleSheetLink(nodeAsPI, href);
943 0 : if (!href.IsEmpty()) {
944 0 : FixupURI(href);
945 0 : FixupXMLStyleSheetLink(outNode, href);
946 : }
947 : }
948 : }
949 0 : return NS_OK;
950 : }
951 :
952 : // BASE elements are replaced by a comment so relative links are not hosed.
953 0 : if (!IsFlagSet(IWBP::PERSIST_FLAGS_NO_BASE_TAG_MODIFICATIONS)) {
954 0 : nsCOMPtr<nsIDOMHTMLBaseElement> nodeAsBase = do_QueryInterface(aNodeIn);
955 0 : if (nodeAsBase) {
956 0 : nsCOMPtr<nsIDOMDocument> ownerDocument;
957 0 : auto* base = static_cast<dom::HTMLSharedElement*>(nodeAsBase.get());
958 0 : base->GetOwnerDocument(getter_AddRefs(ownerDocument));
959 0 : if (ownerDocument) {
960 0 : nsAutoString href;
961 0 : base->GetHref(href); // Doesn't matter if this fails
962 0 : nsCOMPtr<nsIDOMComment> comment;
963 0 : nsAutoString commentText;
964 0 : commentText.AssignLiteral(" base ");
965 0 : if (!href.IsEmpty()) {
966 0 : commentText += NS_LITERAL_STRING("href=\"") + href
967 0 : + NS_LITERAL_STRING("\" ");
968 : }
969 0 : rv = ownerDocument->CreateComment(commentText,
970 0 : getter_AddRefs(comment));
971 0 : if (comment) {
972 0 : return CallQueryInterface(comment, aNodeOut);
973 : }
974 : }
975 0 : return NS_OK;
976 : }
977 : }
978 :
979 0 : nsCOMPtr<nsIContent> content = do_QueryInterface(aNodeIn);
980 0 : if (!content) {
981 0 : return NS_OK;
982 : }
983 :
984 : // Fix up href and file links in the elements
985 0 : nsCOMPtr<nsIDOMHTMLAnchorElement> nodeAsAnchor = do_QueryInterface(aNodeIn);
986 0 : if (nodeAsAnchor) {
987 0 : rv = GetNodeToFixup(aNodeIn, aNodeOut);
988 0 : if (NS_SUCCEEDED(rv) && *aNodeOut) {
989 0 : FixupAnchor(*aNodeOut);
990 : }
991 0 : return rv;
992 : }
993 :
994 0 : nsCOMPtr<nsIDOMHTMLAreaElement> nodeAsArea = do_QueryInterface(aNodeIn);
995 0 : if (nodeAsArea) {
996 0 : rv = GetNodeToFixup(aNodeIn, aNodeOut);
997 0 : if (NS_SUCCEEDED(rv) && *aNodeOut) {
998 0 : FixupAnchor(*aNodeOut);
999 : }
1000 0 : return rv;
1001 : }
1002 :
1003 0 : if (content->IsHTMLElement(nsGkAtoms::body)) {
1004 0 : rv = GetNodeToFixup(aNodeIn, aNodeOut);
1005 0 : if (NS_SUCCEEDED(rv) && *aNodeOut) {
1006 0 : FixupAttribute(*aNodeOut, "background");
1007 : }
1008 0 : return rv;
1009 : }
1010 :
1011 0 : if (content->IsHTMLElement(nsGkAtoms::table)) {
1012 0 : rv = GetNodeToFixup(aNodeIn, aNodeOut);
1013 0 : if (NS_SUCCEEDED(rv) && *aNodeOut) {
1014 0 : FixupAttribute(*aNodeOut, "background");
1015 : }
1016 0 : return rv;
1017 : }
1018 :
1019 0 : if (content->IsHTMLElement(nsGkAtoms::tr)) {
1020 0 : rv = GetNodeToFixup(aNodeIn, aNodeOut);
1021 0 : if (NS_SUCCEEDED(rv) && *aNodeOut) {
1022 0 : FixupAttribute(*aNodeOut, "background");
1023 : }
1024 0 : return rv;
1025 : }
1026 :
1027 0 : if (content->IsAnyOfHTMLElements(nsGkAtoms::td, nsGkAtoms::th)) {
1028 0 : rv = GetNodeToFixup(aNodeIn, aNodeOut);
1029 0 : if (NS_SUCCEEDED(rv) && *aNodeOut) {
1030 0 : FixupAttribute(*aNodeOut, "background");
1031 : }
1032 0 : return rv;
1033 : }
1034 :
1035 0 : nsCOMPtr<nsIDOMHTMLImageElement> nodeAsImage = do_QueryInterface(aNodeIn);
1036 0 : if (nodeAsImage) {
1037 0 : rv = GetNodeToFixup(aNodeIn, aNodeOut);
1038 0 : if (NS_SUCCEEDED(rv) && *aNodeOut) {
1039 : // Disable image loads
1040 : nsCOMPtr<nsIImageLoadingContent> imgCon =
1041 0 : do_QueryInterface(*aNodeOut);
1042 0 : if (imgCon) {
1043 0 : imgCon->SetLoadingEnabled(false);
1044 : }
1045 0 : FixupAnchor(*aNodeOut);
1046 0 : FixupAttribute(*aNodeOut, "src");
1047 : }
1048 0 : return rv;
1049 : }
1050 :
1051 0 : nsCOMPtr<nsIDOMHTMLMediaElement> nodeAsMedia = do_QueryInterface(aNodeIn);
1052 0 : if (nodeAsMedia) {
1053 0 : rv = GetNodeToFixup(aNodeIn, aNodeOut);
1054 0 : if (NS_SUCCEEDED(rv) && *aNodeOut) {
1055 0 : FixupAttribute(*aNodeOut, "src");
1056 : }
1057 0 : return rv;
1058 : }
1059 :
1060 0 : nsCOMPtr<nsIDOMHTMLSourceElement> nodeAsSource = do_QueryInterface(aNodeIn);
1061 0 : if (nodeAsSource) {
1062 0 : rv = GetNodeToFixup(aNodeIn, aNodeOut);
1063 0 : if (NS_SUCCEEDED(rv) && *aNodeOut) {
1064 0 : FixupAttribute(*aNodeOut, "src");
1065 : }
1066 0 : return rv;
1067 : }
1068 :
1069 0 : if (content->IsSVGElement(nsGkAtoms::img)) {
1070 0 : rv = GetNodeToFixup(aNodeIn, aNodeOut);
1071 0 : if (NS_SUCCEEDED(rv) && *aNodeOut) {
1072 : // Disable image loads
1073 : nsCOMPtr<nsIImageLoadingContent> imgCon =
1074 0 : do_QueryInterface(*aNodeOut);
1075 0 : if (imgCon)
1076 0 : imgCon->SetLoadingEnabled(false);
1077 :
1078 : // FixupAnchor(*aNodeOut); // XXXjwatt: is this line needed?
1079 0 : FixupAttribute(*aNodeOut, "href", "http://www.w3.org/1999/xlink");
1080 : }
1081 0 : return rv;
1082 : }
1083 :
1084 0 : nsCOMPtr<nsIDOMHTMLScriptElement> nodeAsScript = do_QueryInterface(aNodeIn);
1085 0 : if (nodeAsScript) {
1086 0 : rv = GetNodeToFixup(aNodeIn, aNodeOut);
1087 0 : if (NS_SUCCEEDED(rv) && *aNodeOut) {
1088 0 : FixupAttribute(*aNodeOut, "src");
1089 : }
1090 0 : return rv;
1091 : }
1092 :
1093 0 : if (content->IsSVGElement(nsGkAtoms::script)) {
1094 0 : rv = GetNodeToFixup(aNodeIn, aNodeOut);
1095 0 : if (NS_SUCCEEDED(rv) && *aNodeOut) {
1096 0 : FixupAttribute(*aNodeOut, "href", "http://www.w3.org/1999/xlink");
1097 : }
1098 0 : return rv;
1099 : }
1100 :
1101 0 : nsCOMPtr<nsIDOMHTMLEmbedElement> nodeAsEmbed = do_QueryInterface(aNodeIn);
1102 0 : if (nodeAsEmbed) {
1103 0 : rv = GetNodeToFixup(aNodeIn, aNodeOut);
1104 0 : if (NS_SUCCEEDED(rv) && *aNodeOut) {
1105 0 : FixupAttribute(*aNodeOut, "src");
1106 : }
1107 0 : return rv;
1108 : }
1109 :
1110 0 : nsCOMPtr<nsIDOMHTMLObjectElement> nodeAsObject = do_QueryInterface(aNodeIn);
1111 0 : if (nodeAsObject) {
1112 0 : rv = GetNodeToFixup(aNodeIn, aNodeOut);
1113 0 : if (NS_SUCCEEDED(rv) && *aNodeOut) {
1114 0 : FixupAttribute(*aNodeOut, "data");
1115 : }
1116 0 : return rv;
1117 : }
1118 :
1119 0 : nsCOMPtr<nsIDOMHTMLAppletElement> nodeAsApplet = do_QueryInterface(aNodeIn);
1120 0 : if (nodeAsApplet) {
1121 0 : rv = GetNodeToFixup(aNodeIn, aNodeOut);
1122 0 : if (NS_SUCCEEDED(rv) && *aNodeOut) {
1123 : nsCOMPtr<nsIDOMHTMLAppletElement> newApplet =
1124 0 : do_QueryInterface(*aNodeOut);
1125 : // For an applet, relative URIs are resolved relative to the
1126 : // codebase (which is resolved relative to the base URI).
1127 0 : nsCOMPtr<nsIURI> oldBase = mCurrentBaseURI;
1128 0 : nsAutoString codebase;
1129 0 : nodeAsApplet->GetCodeBase(codebase);
1130 0 : if (!codebase.IsEmpty()) {
1131 0 : nsCOMPtr<nsIURI> baseURI;
1132 0 : NS_NewURI(getter_AddRefs(baseURI), codebase,
1133 0 : mParent->GetCharacterSet(), mCurrentBaseURI);
1134 0 : if (baseURI) {
1135 0 : mCurrentBaseURI = baseURI;
1136 : }
1137 : }
1138 : // Unset the codebase too, since we'll correctly relativize the
1139 : // code and archive paths.
1140 0 : IgnoredErrorResult ignored;
1141 0 : static_cast<dom::HTMLSharedObjectElement*>(newApplet.get())->
1142 0 : RemoveAttribute(NS_LITERAL_STRING("codebase"), ignored);
1143 0 : FixupAttribute(*aNodeOut, "code");
1144 0 : FixupAttribute(*aNodeOut, "archive");
1145 : // restore the base URI we really want to have
1146 0 : mCurrentBaseURI = oldBase;
1147 : }
1148 0 : return rv;
1149 : }
1150 :
1151 0 : nsCOMPtr<nsIDOMHTMLLinkElement> nodeAsLink = do_QueryInterface(aNodeIn);
1152 0 : if (nodeAsLink) {
1153 0 : rv = GetNodeToFixup(aNodeIn, aNodeOut);
1154 0 : if (NS_SUCCEEDED(rv) && *aNodeOut) {
1155 : // First see if the link represents linked content
1156 0 : rv = FixupAttribute(*aNodeOut, "href");
1157 0 : if (NS_FAILED(rv)) {
1158 : // Perhaps this link is actually an anchor to related content
1159 0 : FixupAnchor(*aNodeOut);
1160 : }
1161 : // TODO if "type" attribute == "text/css"
1162 : // fixup stylesheet
1163 : }
1164 0 : return rv;
1165 : }
1166 :
1167 0 : nsCOMPtr<nsIDOMHTMLFrameElement> nodeAsFrame = do_QueryInterface(aNodeIn);
1168 0 : if (nodeAsFrame) {
1169 0 : rv = GetNodeToFixup(aNodeIn, aNodeOut);
1170 0 : if (NS_SUCCEEDED(rv) && *aNodeOut) {
1171 0 : FixupAttribute(*aNodeOut, "src");
1172 : }
1173 0 : return rv;
1174 : }
1175 :
1176 0 : nsCOMPtr<nsIDOMHTMLIFrameElement> nodeAsIFrame = do_QueryInterface(aNodeIn);
1177 0 : if (nodeAsIFrame) {
1178 0 : rv = GetNodeToFixup(aNodeIn, aNodeOut);
1179 0 : if (NS_SUCCEEDED(rv) && *aNodeOut) {
1180 0 : FixupAttribute(*aNodeOut, "src");
1181 : }
1182 0 : return rv;
1183 : }
1184 :
1185 : RefPtr<dom::HTMLInputElement> nodeAsInput =
1186 0 : dom::HTMLInputElement::FromContentOrNull(content);
1187 0 : if (nodeAsInput) {
1188 0 : rv = GetNodeToFixup(aNodeIn, aNodeOut);
1189 0 : if (NS_SUCCEEDED(rv) && *aNodeOut) {
1190 : // Disable image loads
1191 : nsCOMPtr<nsIImageLoadingContent> imgCon =
1192 0 : do_QueryInterface(*aNodeOut);
1193 0 : if (imgCon) {
1194 0 : imgCon->SetLoadingEnabled(false);
1195 : }
1196 :
1197 0 : FixupAttribute(*aNodeOut, "src");
1198 :
1199 0 : nsAutoString valueStr;
1200 0 : NS_NAMED_LITERAL_STRING(valueAttr, "value");
1201 : // Update element node attributes with user-entered form state
1202 0 : nsCOMPtr<nsIContent> content = do_QueryInterface(*aNodeOut);
1203 : RefPtr<dom::HTMLInputElement> outElt =
1204 0 : dom::HTMLInputElement::FromContentOrNull(content);
1205 0 : nsCOMPtr<nsIFormControl> formControl = do_QueryInterface(*aNodeOut);
1206 0 : switch (formControl->ControlType()) {
1207 : case NS_FORM_INPUT_EMAIL:
1208 : case NS_FORM_INPUT_SEARCH:
1209 : case NS_FORM_INPUT_TEXT:
1210 : case NS_FORM_INPUT_TEL:
1211 : case NS_FORM_INPUT_URL:
1212 : case NS_FORM_INPUT_NUMBER:
1213 : case NS_FORM_INPUT_RANGE:
1214 : case NS_FORM_INPUT_DATE:
1215 : case NS_FORM_INPUT_TIME:
1216 : case NS_FORM_INPUT_COLOR:
1217 0 : nodeAsInput->GetValue(valueStr, dom::CallerType::System);
1218 : // Avoid superfluous value="" serialization
1219 0 : if (valueStr.IsEmpty()) {
1220 0 : IgnoredErrorResult ignored;
1221 0 : outElt->RemoveAttribute(valueAttr, ignored);
1222 : } else {
1223 0 : outElt->SetAttribute(valueAttr, valueStr);
1224 : }
1225 0 : break;
1226 : case NS_FORM_INPUT_CHECKBOX:
1227 : case NS_FORM_INPUT_RADIO:
1228 : {
1229 0 : bool checked = nodeAsInput->Checked();
1230 0 : outElt->SetDefaultChecked(checked);
1231 : }
1232 0 : break;
1233 : default:
1234 0 : break;
1235 : }
1236 : }
1237 0 : return rv;
1238 : }
1239 :
1240 0 : nsCOMPtr<nsIDOMHTMLTextAreaElement> nodeAsTextArea = do_QueryInterface(aNodeIn);
1241 0 : if (nodeAsTextArea) {
1242 0 : rv = GetNodeToFixup(aNodeIn, aNodeOut);
1243 0 : if (NS_SUCCEEDED(rv) && *aNodeOut) {
1244 : // Tell the document encoder to serialize the text child we create below
1245 0 : *aSerializeCloneKids = true;
1246 :
1247 0 : nsAutoString valueStr;
1248 0 : nodeAsTextArea->GetValue(valueStr);
1249 :
1250 0 : (*aNodeOut)->SetTextContent(valueStr);
1251 : }
1252 0 : return rv;
1253 : }
1254 :
1255 0 : nsCOMPtr<nsIDOMHTMLOptionElement> nodeAsOption = do_QueryInterface(aNodeIn);
1256 0 : if (nodeAsOption) {
1257 0 : rv = GetNodeToFixup(aNodeIn, aNodeOut);
1258 0 : if (NS_SUCCEEDED(rv) && *aNodeOut) {
1259 0 : nsCOMPtr<nsIDOMHTMLOptionElement> outElt = do_QueryInterface(*aNodeOut);
1260 : bool selected;
1261 0 : nodeAsOption->GetSelected(&selected);
1262 0 : outElt->SetDefaultSelected(selected);
1263 : }
1264 0 : return rv;
1265 : }
1266 :
1267 0 : return NS_OK;
1268 : }
1269 :
1270 : } // unnamed namespace
1271 :
1272 : NS_IMETHODIMP
1273 0 : WebBrowserPersistLocalDocument::ReadResources(nsIWebBrowserPersistResourceVisitor* aVisitor)
1274 : {
1275 0 : nsresult rv = NS_OK;
1276 0 : nsCOMPtr<nsIWebBrowserPersistResourceVisitor> visitor = aVisitor;
1277 :
1278 0 : nsCOMPtr<nsIDOMNode> docAsNode = do_QueryInterface(mDocument);
1279 0 : NS_ENSURE_TRUE(docAsNode, NS_ERROR_FAILURE);
1280 :
1281 0 : nsCOMPtr<nsIDOMTreeWalker> walker;
1282 0 : nsCOMPtr<nsIDOMDocument> oldStyleDoc = do_QueryInterface(mDocument);
1283 0 : MOZ_ASSERT(oldStyleDoc);
1284 0 : rv = oldStyleDoc->CreateTreeWalker(docAsNode,
1285 : nsIDOMNodeFilter::SHOW_ELEMENT |
1286 : nsIDOMNodeFilter::SHOW_DOCUMENT |
1287 : nsIDOMNodeFilter::SHOW_PROCESSING_INSTRUCTION,
1288 0 : nullptr, 1, getter_AddRefs(walker));
1289 0 : NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
1290 0 : MOZ_ASSERT(walker);
1291 :
1292 0 : RefPtr<ResourceReader> reader = new ResourceReader(this, aVisitor);
1293 0 : nsCOMPtr<nsIDOMNode> currentNode;
1294 0 : walker->GetCurrentNode(getter_AddRefs(currentNode));
1295 0 : while (currentNode) {
1296 0 : rv = reader->OnWalkDOMNode(currentNode);
1297 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
1298 0 : break;
1299 : }
1300 0 : rv = walker->NextNode(getter_AddRefs(currentNode));
1301 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
1302 0 : break;
1303 : }
1304 : }
1305 0 : reader->DocumentDone(rv);
1306 : // If NS_FAILED(rv), it was / will be reported by an EndVisit call
1307 : // via DocumentDone. This method must return a failure if and
1308 : // only if visitor won't be invoked.
1309 0 : return NS_OK;
1310 : }
1311 :
1312 : static uint32_t
1313 0 : ConvertEncoderFlags(uint32_t aEncoderFlags)
1314 : {
1315 0 : uint32_t encoderFlags = 0;
1316 :
1317 0 : if (aEncoderFlags & nsIWebBrowserPersist::ENCODE_FLAGS_SELECTION_ONLY)
1318 0 : encoderFlags |= nsIDocumentEncoder::OutputSelectionOnly;
1319 0 : if (aEncoderFlags & nsIWebBrowserPersist::ENCODE_FLAGS_FORMATTED)
1320 0 : encoderFlags |= nsIDocumentEncoder::OutputFormatted;
1321 0 : if (aEncoderFlags & nsIWebBrowserPersist::ENCODE_FLAGS_RAW)
1322 0 : encoderFlags |= nsIDocumentEncoder::OutputRaw;
1323 0 : if (aEncoderFlags & nsIWebBrowserPersist::ENCODE_FLAGS_BODY_ONLY)
1324 0 : encoderFlags |= nsIDocumentEncoder::OutputBodyOnly;
1325 0 : if (aEncoderFlags & nsIWebBrowserPersist::ENCODE_FLAGS_PREFORMATTED)
1326 0 : encoderFlags |= nsIDocumentEncoder::OutputPreformatted;
1327 0 : if (aEncoderFlags & nsIWebBrowserPersist::ENCODE_FLAGS_WRAP)
1328 0 : encoderFlags |= nsIDocumentEncoder::OutputWrap;
1329 0 : if (aEncoderFlags & nsIWebBrowserPersist::ENCODE_FLAGS_FORMAT_FLOWED)
1330 0 : encoderFlags |= nsIDocumentEncoder::OutputFormatFlowed;
1331 0 : if (aEncoderFlags & nsIWebBrowserPersist::ENCODE_FLAGS_ABSOLUTE_LINKS)
1332 0 : encoderFlags |= nsIDocumentEncoder::OutputAbsoluteLinks;
1333 0 : if (aEncoderFlags & nsIWebBrowserPersist::ENCODE_FLAGS_ENCODE_BASIC_ENTITIES)
1334 0 : encoderFlags |= nsIDocumentEncoder::OutputEncodeBasicEntities;
1335 0 : if (aEncoderFlags & nsIWebBrowserPersist::ENCODE_FLAGS_ENCODE_LATIN1_ENTITIES)
1336 0 : encoderFlags |= nsIDocumentEncoder::OutputEncodeLatin1Entities;
1337 0 : if (aEncoderFlags & nsIWebBrowserPersist::ENCODE_FLAGS_ENCODE_HTML_ENTITIES)
1338 0 : encoderFlags |= nsIDocumentEncoder::OutputEncodeHTMLEntities;
1339 0 : if (aEncoderFlags & nsIWebBrowserPersist::ENCODE_FLAGS_ENCODE_W3C_ENTITIES)
1340 0 : encoderFlags |= nsIDocumentEncoder::OutputEncodeW3CEntities;
1341 0 : if (aEncoderFlags & nsIWebBrowserPersist::ENCODE_FLAGS_CR_LINEBREAKS)
1342 0 : encoderFlags |= nsIDocumentEncoder::OutputCRLineBreak;
1343 0 : if (aEncoderFlags & nsIWebBrowserPersist::ENCODE_FLAGS_LF_LINEBREAKS)
1344 0 : encoderFlags |= nsIDocumentEncoder::OutputLFLineBreak;
1345 0 : if (aEncoderFlags & nsIWebBrowserPersist::ENCODE_FLAGS_NOSCRIPT_CONTENT)
1346 0 : encoderFlags |= nsIDocumentEncoder::OutputNoScriptContent;
1347 0 : if (aEncoderFlags & nsIWebBrowserPersist::ENCODE_FLAGS_NOFRAMES_CONTENT)
1348 0 : encoderFlags |= nsIDocumentEncoder::OutputNoFramesContent;
1349 :
1350 0 : return encoderFlags;
1351 : }
1352 :
1353 : static bool
1354 0 : ContentTypeEncoderExists(const nsACString& aType)
1355 : {
1356 0 : nsAutoCString contractID(NS_DOC_ENCODER_CONTRACTID_BASE);
1357 0 : contractID.Append(aType);
1358 :
1359 0 : nsCOMPtr<nsIComponentRegistrar> registrar;
1360 0 : nsresult rv = NS_GetComponentRegistrar(getter_AddRefs(registrar));
1361 0 : MOZ_ASSERT(NS_SUCCEEDED(rv));
1362 0 : if (NS_SUCCEEDED(rv) && registrar) {
1363 : bool result;
1364 0 : rv = registrar->IsContractIDRegistered(contractID.get(), &result);
1365 0 : MOZ_ASSERT(NS_SUCCEEDED(rv));
1366 0 : return NS_SUCCEEDED(rv) && result;
1367 : }
1368 0 : return false;
1369 : }
1370 :
1371 : void
1372 0 : WebBrowserPersistLocalDocument::DecideContentType(nsACString& aContentType)
1373 : {
1374 0 : if (aContentType.IsEmpty()) {
1375 0 : if (NS_WARN_IF(NS_FAILED(GetContentType(aContentType)))) {
1376 0 : aContentType.Truncate();
1377 : }
1378 : }
1379 0 : if (!aContentType.IsEmpty() &&
1380 0 : !ContentTypeEncoderExists(aContentType)) {
1381 0 : aContentType.Truncate();
1382 : }
1383 0 : if (aContentType.IsEmpty()) {
1384 0 : aContentType.AssignLiteral("text/html");
1385 : }
1386 0 : }
1387 :
1388 : nsresult
1389 0 : WebBrowserPersistLocalDocument::GetDocEncoder(const nsACString& aContentType,
1390 : uint32_t aEncoderFlags,
1391 : nsIDocumentEncoder** aEncoder)
1392 : {
1393 : nsresult rv;
1394 0 : nsAutoCString contractID(NS_DOC_ENCODER_CONTRACTID_BASE);
1395 0 : contractID.Append(aContentType);
1396 : nsCOMPtr<nsIDocumentEncoder> encoder =
1397 0 : do_CreateInstance(contractID.get(), &rv);
1398 0 : NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
1399 :
1400 0 : rv = encoder->NativeInit(mDocument,
1401 0 : NS_ConvertASCIItoUTF16(aContentType),
1402 0 : ConvertEncoderFlags(aEncoderFlags));
1403 0 : NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
1404 :
1405 0 : nsAutoCString charSet;
1406 0 : rv = GetCharacterSet(charSet);
1407 0 : NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
1408 0 : rv = encoder->SetCharset(charSet);
1409 0 : NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
1410 :
1411 0 : encoder.forget(aEncoder);
1412 0 : return NS_OK;
1413 : }
1414 :
1415 :
1416 : NS_IMETHODIMP
1417 0 : WebBrowserPersistLocalDocument::WriteContent(
1418 : nsIOutputStream* aStream,
1419 : nsIWebBrowserPersistURIMap* aMap,
1420 : const nsACString& aRequestedContentType,
1421 : uint32_t aEncoderFlags,
1422 : uint32_t aWrapColumn,
1423 : nsIWebBrowserPersistWriteCompletion* aCompletion)
1424 : {
1425 0 : NS_ENSURE_ARG_POINTER(aStream);
1426 0 : NS_ENSURE_ARG_POINTER(aCompletion);
1427 0 : nsAutoCString contentType(aRequestedContentType);
1428 0 : DecideContentType(contentType);
1429 :
1430 0 : nsCOMPtr<nsIDocumentEncoder> encoder;
1431 0 : nsresult rv = GetDocEncoder(contentType, aEncoderFlags,
1432 0 : getter_AddRefs(encoder));
1433 0 : NS_ENSURE_SUCCESS(rv, rv);
1434 :
1435 0 : if (aWrapColumn != 0 && (aEncoderFlags
1436 0 : & nsIWebBrowserPersist::ENCODE_FLAGS_WRAP)) {
1437 0 : encoder->SetWrapColumn(aWrapColumn);
1438 : }
1439 :
1440 0 : nsCOMPtr<nsIURI> targetURI;
1441 0 : if (aMap) {
1442 0 : nsAutoCString targetURISpec;
1443 0 : rv = aMap->GetTargetBaseURI(targetURISpec);
1444 0 : if (NS_SUCCEEDED(rv) && !targetURISpec.IsEmpty()) {
1445 0 : rv = NS_NewURI(getter_AddRefs(targetURI), targetURISpec,
1446 0 : /* charset: */ nullptr, /* base: */ nullptr);
1447 0 : NS_ENSURE_SUCCESS(rv, NS_ERROR_UNEXPECTED);
1448 0 : } else if (mPersistFlags & nsIWebBrowserPersist::PERSIST_FLAGS_FIXUP_LINKS_TO_DESTINATION) {
1449 0 : return NS_ERROR_UNEXPECTED;
1450 : }
1451 : }
1452 0 : rv = encoder->SetNodeFixup(new PersistNodeFixup(this, aMap, targetURI));
1453 0 : NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
1454 :
1455 0 : rv = encoder->EncodeToStream(aStream);
1456 0 : aCompletion->OnFinish(this, aStream, contentType, rv);
1457 0 : return NS_OK;
1458 : }
1459 :
1460 : } // namespace mozilla
|