summaryrefslogtreecommitdiffstats
path: root/toolkit/actors/BackgroundThumbnailsChild.jsm
blob: da365a42883c5e52b47dfbc8bb3d3b1ef9078f99 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/* vim: set ts=2 sw=2 sts=2 et tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";

var EXPORTED_SYMBOLS = ["BackgroundThumbnailsChild"];
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");

ChromeUtils.defineModuleGetter(
  this,
  "PageThumbUtils",
  "resource://gre/modules/PageThumbUtils.jsm"
);

// NOTE: Copied from nsSandboxFlags.h
/**
 * This flag prevents content from creating new auxiliary browsing contexts,
 * e.g. using the target attribute, or the window.open() method.
 */
const SANDBOXED_AUXILIARY_NAVIGATION = 0x2;

class BackgroundThumbnailsChild extends JSWindowActorChild {
  receiveMessage(message) {
    switch (message.name) {
      case "Browser:Thumbnail:ContentInfo": {
        if (
          message.data.isImage ||
          this.document instanceof this.contentWindow.ImageDocument
        ) {
          // To avoid sending additional messages between processes, we return
          // the image data directly with the size info.
          return PageThumbUtils.createImageThumbnailCanvas(
            this.contentWindow,
            this.document.location,
            message.data.targetWidth,
            message.data.backgroundColor
          );
        }

        let [width, height] = PageThumbUtils.getContentSize(this.contentWindow);
        return { width, height };
      }

      case "Browser:Thumbnail:LoadURL": {
        let docShell = this.docShell.QueryInterface(Ci.nsIWebNavigation);

        // We want a low network priority for this service - lower than b/g tabs
        // etc - so set it to the lowest priority available.
        docShell
          .QueryInterface(Ci.nsIDocumentLoader)
          .loadGroup.QueryInterface(Ci.nsISupportsPriority).priority =
          Ci.nsISupportsPriority.PRIORITY_LOWEST;

        docShell.allowMedia = false;
        docShell.allowPlugins = false;
        docShell.allowContentRetargeting = false;
        let defaultFlags =
          Ci.nsIRequest.LOAD_ANONYMOUS |
          Ci.nsIRequest.LOAD_BYPASS_CACHE |
          Ci.nsIRequest.INHIBIT_CACHING |
          Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_HISTORY;
        docShell.defaultLoadFlags = defaultFlags;
        this.browsingContext.sandboxFlags |= SANDBOXED_AUXILIARY_NAVIGATION;
        docShell.useTrackingProtection = true;

        // Get the document to force a content viewer to be created, otherwise
        // the first load can fail.
        if (!this.document) {
          return false;
        }

        let loadURIOptions = {
          // Bug 1498603 verify usages of systemPrincipal here
          triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
          loadFlags: Ci.nsIWebNavigation.LOAD_FLAGS_STOP_CONTENT,
        };
        try {
          docShell.loadURI(message.data.url, loadURIOptions);
        } catch (ex) {
          return false;
        }

        return true;
      }
    }

    return undefined;
  }

  handleEvent(event) {
    if (event.type == "DOMDocElementInserted") {
      // Arrange to prevent (most) popup dialogs for this window - popups done
      // in the parent (eg, auth) aren't prevented, but alert() etc are.
      // disableDialogs only works on the current inner window, so it has
      // to be called every page load, but before scripts run.
      this.contentWindow.windowUtils.disableDialogs();
    }
  }
}