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 /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 "use strict";
9 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
11 Cu.import("resource://gre/modules/Services.jsm");
13 this.EXPORTED_SYMBOLS = ["StateMachine"];
15 const DEBUG = false;
17 this.StateMachine = function(aDebugTag) {
18 function debug(aMsg) {
19 dump('-------------- StateMachine:' + aDebugTag + ': ' + aMsg);
20 }
22 var sm = {};
24 var _initialState;
25 var _curState;
26 var _prevState;
27 var _paused;
28 var _eventQueue = [];
29 var _deferredEventQueue = [];
30 var _defaultEventHandler;
32 // Public interfaces.
34 sm.setDefaultEventHandler = function(aDefaultEventHandler) {
35 _defaultEventHandler = aDefaultEventHandler;
36 };
38 sm.start = function(aInitialState) {
39 _initialState = aInitialState;
40 sm.gotoState(_initialState);
41 };
43 sm.sendEvent = function (aEvent) {
44 if (!_initialState) {
45 if (DEBUG) {
46 debug('StateMachine is not running. Call StateMachine.start() first.');
47 }
48 return;
49 }
50 _eventQueue.push(aEvent);
51 asyncCall(handleFirstEvent);
52 };
54 sm.getPreviousState = function() {
55 return _prevState;
56 };
58 sm.getCurrentState = function() {
59 return _curState;
60 };
62 // State object maker.
63 // @param aName string for this state's name.
64 // @param aDelegate object:
65 // .handleEvent: required.
66 // .enter: called before entering this state (optional).
67 // .exit: called before exiting this state (optional).
68 sm.makeState = function (aName, aDelegate) {
69 if (!aDelegate.handleEvent) {
70 throw "handleEvent is a required delegate function.";
71 }
72 var nop = function() {};
73 return {
74 name: aName,
75 enter: (aDelegate.enter || nop),
76 exit: (aDelegate.exit || nop),
77 handleEvent: aDelegate.handleEvent
78 };
79 };
81 sm.deferEvent = function (aEvent) {
82 // The definition of a 'deferred event' is:
83 // We are not able to handle this event now but after receiving
84 // certain event or entering a new state, we might be able to handle
85 // it. For example, we couldn't handle CONNECT_EVENT in the
86 // diconnecting state. But once we finish doing "disconnecting", we
87 // could then handle CONNECT_EVENT!
88 //
89 // So, the deferred event may be handled in the following cases:
90 // 1. Once we entered a new state.
91 // 2. Once we handled a regular event.
92 if (DEBUG) {
93 debug('Deferring event: ' + JSON.stringify(aEvent));
94 }
95 _deferredEventQueue.push(aEvent);
96 };
98 // Goto the new state. If the current state is null, the exit
99 // function won't be called.
100 sm.gotoState = function (aNewState) {
101 if (_curState) {
102 if (DEBUG) {
103 debug("exiting state: " + _curState.name);
104 }
105 _curState.exit();
106 }
108 _prevState = _curState;
109 _curState = aNewState;
111 if (DEBUG) {
112 debug("entering state: " + _curState.name);
113 }
114 _curState.enter();
116 // We are in the new state now. We got a chance to handle the
117 // deferred events.
118 handleDeferredEvents();
120 sm.resume();
121 };
123 // No incoming event will be handled after you call pause().
124 // (But they will be queued.)
125 sm.pause = function() {
126 _paused = true;
127 };
129 // Continue to handle incoming events.
130 sm.resume = function() {
131 _paused = false;
132 asyncCall(handleFirstEvent);
133 };
135 //----------------------------------------------------------
136 // Private stuff
137 //----------------------------------------------------------
139 function asyncCall(f) {
140 Services.tm.currentThread.dispatch(f, Ci.nsIThread.DISPATCH_NORMAL);
141 }
143 function handleFirstEvent() {
144 var hadDeferredEvents;
146 if (0 === _eventQueue.length) {
147 return;
148 }
150 if (_paused) {
151 return; // The state machine is paused now.
152 }
154 hadDeferredEvents = _deferredEventQueue.length > 0;
156 handleOneEvent(_eventQueue.shift()); // The handler may defer this event.
158 // We've handled one event. If we had deferred events before, now is
159 // a good chance to handle them.
160 if (hadDeferredEvents) {
161 handleDeferredEvents();
162 }
164 // Continue to handle the next regular event.
165 handleFirstEvent();
166 }
168 function handleDeferredEvents() {
169 if (_deferredEventQueue.length && DEBUG) {
170 debug('Handle deferred events: ' + _deferredEventQueue.length);
171 }
172 for (let i = 0; i < _deferredEventQueue.length; i++) {
173 handleOneEvent(_deferredEventQueue.shift());
174 }
175 }
177 function handleOneEvent(aEvent)
178 {
179 if (DEBUG) {
180 debug('Handling event: ' + JSON.stringify(aEvent));
181 }
183 var handled = _curState.handleEvent(aEvent);
185 if (undefined === handled) {
186 throw "handleEvent returns undefined: " + _curState.name;
187 }
188 if (!handled) {
189 // Event is not handled in the current state. Try handleEventCommon().
190 handled = (_defaultEventHandler ? _defaultEventHandler(aEvent) : handled);
191 }
192 if (undefined === handled) {
193 throw "handleEventCommon returns undefined: " + _curState.name;
194 }
195 if (!handled) {
196 if (DEBUG) {
197 debug('!!!!!!!!! FIXME !!!!!!!!! Event not handled: ' + JSON.stringify(aEvent));
198 }
199 }
201 return handled;
202 }
204 return sm;
205 };