Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
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 "use strict";
6 module.metadata = {
7 "stability": "experimental",
8 "engines": {
9 "Firefox": "> 28"
10 }
11 };
13 const { Class } = require("../../core/heritage");
14 const { EventTarget } = require("../../event/target");
15 const { emit, off, setListeners } = require("../../event/core");
16 const { Reactor, foldp, send, merges } = require("../../event/utils");
17 const { Disposable } = require("../../core/disposable");
18 const { OutputPort } = require("../../output/system");
19 const { InputPort } = require("../../input/system");
20 const { identify } = require("../id");
21 const { pairs, object, map, each } = require("../../util/sequence");
22 const { patch, diff } = require("diffpatcher/index");
23 const { isLocalURL } = require("../../url");
24 const { compose } = require("../../lang/functional");
25 const { contract } = require("../../util/contract");
26 const { id: addonID, data: { url: resolve }} = require("../../self");
27 const { Frames } = require("../../input/frame");
30 const output = new OutputPort({ id: "frame-change" });
31 const mailbox = new OutputPort({ id: "frame-mailbox" });
32 const input = Frames;
35 const makeID = url =>
36 ("frame-" + addonID + "-" + url).
37 split("/").join("-").
38 split(".").join("-").
39 replace(/[^A-Za-z0-9_\-]/g, "");
41 const validate = contract({
42 name: {
43 is: ["string", "undefined"],
44 ok: x => /^[a-z][a-z0-9-_]+$/i.test(x),
45 msg: "The `option.name` must be a valid alphanumeric string (hyphens and " +
46 "underscores are allowed) starting with letter."
47 },
48 url: {
49 map: x => x.toString(),
50 is: ["string"],
51 ok: x => isLocalURL(x),
52 msg: "The `options.url` must be a valid local URI."
53 }
54 });
56 const Source = function({id, ownerID}) {
57 this.id = id;
58 this.ownerID = ownerID;
59 };
60 Source.postMessage = ({id, ownerID}, data, origin) => {
61 send(mailbox, object([id, {
62 inbox: {
63 target: {id: id, ownerID: ownerID},
64 timeStamp: Date.now(),
65 data: data,
66 origin: origin
67 }
68 }]));
69 };
70 Source.prototype.postMessage = function(data, origin) {
71 Source.postMessage(this, data, origin);
72 };
74 const Message = function({type, data, source, origin, timeStamp}) {
75 this.type = type;
76 this.data = data;
77 this.origin = origin;
78 this.timeStamp = timeStamp;
79 this.source = new Source(source);
80 };
83 const frames = new Map();
84 const sources = new Map();
86 const Frame = Class({
87 extends: EventTarget,
88 implements: [Disposable, Source],
89 initialize: function(params={}) {
90 const options = validate(params);
91 const id = makeID(options.name || options.url);
93 if (frames.has(id))
94 throw Error("Frame with this id already exists: " + id);
96 const initial = { id: id, url: resolve(options.url) };
97 this.id = id;
99 setListeners(this, params);
101 frames.set(this.id, this);
103 send(output, object([id, initial]));
104 },
105 get url() {
106 const state = reactor.value[this.id];
107 return state && state.url;
108 },
109 destroy: function() {
110 send(output, object([this.id, null]));
111 frames.delete(this.id);
112 off(this);
113 },
114 // `JSON.stringify` serializes objects based of the return
115 // value of this method. For convinienc we provide this method
116 // to serialize actual state data.
117 toJSON: function() {
118 return { id: this.id, url: this.url };
119 }
120 });
121 identify.define(Frame, frame => frame.id);
123 exports.Frame = Frame;
125 const reactor = new Reactor({
126 onStep: (present, past) => {
127 const delta = diff(past, present);
129 each(([id, update]) => {
130 const frame = frames.get(id);
131 if (update) {
132 if (!past[id])
133 emit(frame, "register");
135 if (update.outbox)
136 emit(frame, "message", new Message(present[id].outbox));
138 each(([ownerID, state]) => {
139 const readyState = state ? state.readyState : "detach";
140 const type = readyState === "loading" ? "attach" :
141 readyState === "interactive" ? "ready" :
142 readyState === "complete" ? "load" :
143 readyState;
145 // TODO: Cache `Source` instances somewhere to preserve
146 // identity.
147 emit(frame, type, {type: type,
148 source: new Source({id: id, ownerID: ownerID})});
149 }, pairs(update.owners));
150 }
151 }, pairs(delta));
152 }
153 });
154 reactor.run(input);