Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
SeleniumHQ
GitHub Repository: SeleniumHQ/Selenium
Path: blob/trunk/third_party/closure/goog/net/xpc/frameelementmethodtransport.js
1865 views
1
// Copyright 2007 The Closure Library Authors. All Rights Reserved.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
// http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS-IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
/**
16
* @fileoverview Contains the frame element method transport for cross-domain
17
* communication. It exploits the fact that FF lets a page in an
18
* iframe call a method on the iframe-element it is contained in, even if the
19
* containing page is from a different domain.
20
*
21
*/
22
23
24
goog.provide('goog.net.xpc.FrameElementMethodTransport');
25
26
goog.require('goog.log');
27
goog.require('goog.net.xpc');
28
goog.require('goog.net.xpc.CrossPageChannelRole');
29
goog.require('goog.net.xpc.Transport');
30
goog.require('goog.net.xpc.TransportTypes');
31
32
33
34
/**
35
* Frame-element method transport.
36
*
37
* Firefox allows a document within an iframe to call methods on the
38
* iframe-element added by the containing document.
39
* NOTE(user): Tested in all FF versions starting from 1.0
40
*
41
* @param {goog.net.xpc.CrossPageChannel} channel The channel this transport
42
* belongs to.
43
* @param {goog.dom.DomHelper=} opt_domHelper The dom helper to use for finding
44
* the correct window.
45
* @constructor
46
* @extends {goog.net.xpc.Transport}
47
* @final
48
*/
49
goog.net.xpc.FrameElementMethodTransport = function(channel, opt_domHelper) {
50
goog.net.xpc.FrameElementMethodTransport.base(
51
this, 'constructor', opt_domHelper);
52
53
/**
54
* The channel this transport belongs to.
55
* @type {goog.net.xpc.CrossPageChannel}
56
* @private
57
*/
58
this.channel_ = channel;
59
60
// To transfer messages, this transport basically uses normal function calls,
61
// which are synchronous. To avoid endless recursion, the delivery has to
62
// be artificially made asynchronous.
63
64
/**
65
* Array for queued messages.
66
* @type {Array<{serviceName: string, payload: string}>}
67
* @private
68
*/
69
this.queue_ = [];
70
71
/**
72
* Callback function which wraps deliverQueued_.
73
* @type {Function}
74
* @private
75
*/
76
this.deliverQueuedCb_ = goog.bind(this.deliverQueued_, this);
77
};
78
goog.inherits(goog.net.xpc.FrameElementMethodTransport, goog.net.xpc.Transport);
79
80
81
/**
82
* The transport type.
83
* @type {number}
84
* @protected
85
* @override
86
*/
87
goog.net.xpc.FrameElementMethodTransport.prototype.transportType =
88
goog.net.xpc.TransportTypes.FRAME_ELEMENT_METHOD;
89
90
91
/** @private {!Function|undefined} */
92
goog.net.xpc.FrameElementMethodTransport.prototype.attemptSetupCb_;
93
94
95
/** @private */
96
goog.net.xpc.FrameElementMethodTransport.prototype.outgoing_;
97
98
99
/** @private */
100
goog.net.xpc.FrameElementMethodTransport.prototype.iframeElm_;
101
102
103
/**
104
* Flag used to enforce asynchronous messaging semantics.
105
* @type {boolean}
106
* @private
107
*/
108
goog.net.xpc.FrameElementMethodTransport.prototype.recursive_ = false;
109
110
111
/**
112
* Holds the function to send messages to the peer
113
* (once it becomes available).
114
* @type {Function}
115
* @private
116
*/
117
goog.net.xpc.FrameElementMethodTransport.outgoing_ = null;
118
119
120
/**
121
* Connect this transport.
122
* @override
123
*/
124
goog.net.xpc.FrameElementMethodTransport.prototype.connect = function() {
125
if (this.channel_.getRole() == goog.net.xpc.CrossPageChannelRole.OUTER) {
126
// get shortcut to iframe-element
127
this.iframeElm_ = this.channel_.getIframeElement();
128
129
// add the gateway function to the iframe-element
130
// (to be called by the peer)
131
this.iframeElm_['XPC_toOuter'] = goog.bind(this.incoming_, this);
132
133
// at this point we just have to wait for a notification from the peer...
134
135
} else {
136
this.attemptSetup_();
137
}
138
};
139
140
141
/**
142
* Only used from within an iframe. Attempts to attach the method
143
* to be used for sending messages by the containing document. Has to
144
* wait until the containing document has finished. Therefore calls
145
* itself in a timeout if not successful.
146
* @private
147
*/
148
goog.net.xpc.FrameElementMethodTransport.prototype.attemptSetup_ = function() {
149
var retry = true;
150
151
try {
152
if (!this.iframeElm_) {
153
// throws security exception when called too early
154
this.iframeElm_ = this.getWindow().frameElement;
155
}
156
// check if iframe-element and the gateway-function to the
157
// outer-frame are present
158
// TODO(user) Make sure the following code doesn't throw any exceptions
159
if (this.iframeElm_ && this.iframeElm_['XPC_toOuter']) {
160
// get a reference to the gateway function
161
this.outgoing_ = this.iframeElm_['XPC_toOuter'];
162
// attach the gateway function the other document will use
163
this.iframeElm_['XPC_toOuter']['XPC_toInner'] =
164
goog.bind(this.incoming_, this);
165
// stop retrying
166
retry = false;
167
// notify outer frame
168
this.send(goog.net.xpc.TRANSPORT_SERVICE_, goog.net.xpc.SETUP_ACK_);
169
// notify channel that the transport is ready
170
this.channel_.notifyConnected();
171
}
172
} catch (e) {
173
goog.log.error(
174
goog.net.xpc.logger, 'exception caught while attempting setup: ' + e);
175
}
176
// retry necessary?
177
if (retry) {
178
if (!this.attemptSetupCb_) {
179
this.attemptSetupCb_ = goog.bind(this.attemptSetup_, this);
180
}
181
this.getWindow().setTimeout(this.attemptSetupCb_, 100);
182
}
183
};
184
185
186
/**
187
* Handles transport service messages.
188
* @param {string} payload The message content.
189
* @override
190
*/
191
goog.net.xpc.FrameElementMethodTransport.prototype.transportServiceHandler =
192
function(payload) {
193
if (this.channel_.getRole() == goog.net.xpc.CrossPageChannelRole.OUTER &&
194
!this.channel_.isConnected() && payload == goog.net.xpc.SETUP_ACK_) {
195
// get a reference to the gateway function
196
this.outgoing_ = this.iframeElm_['XPC_toOuter']['XPC_toInner'];
197
// notify the channel we're ready
198
this.channel_.notifyConnected();
199
} else {
200
throw Error('Got unexpected transport message.');
201
}
202
};
203
204
205
/**
206
* Process incoming message.
207
* @param {string} serviceName The name of the service the message is to be
208
* delivered to.
209
* @param {string} payload The message to process.
210
* @private
211
*/
212
goog.net.xpc.FrameElementMethodTransport.prototype.incoming_ = function(
213
serviceName, payload) {
214
if (!this.recursive_ && this.queue_.length == 0) {
215
this.channel_.xpcDeliver(serviceName, payload);
216
} else {
217
this.queue_.push({serviceName: serviceName, payload: payload});
218
if (this.queue_.length == 1) {
219
this.getWindow().setTimeout(this.deliverQueuedCb_, 1);
220
}
221
}
222
};
223
224
225
/**
226
* Delivers queued messages.
227
* @private
228
*/
229
goog.net.xpc.FrameElementMethodTransport.prototype.deliverQueued_ = function() {
230
while (this.queue_.length) {
231
var msg = this.queue_.shift();
232
this.channel_.xpcDeliver(msg.serviceName, msg.payload);
233
}
234
};
235
236
237
/**
238
* Send a message
239
* @param {string} service The name off the service the message is to be
240
* delivered to.
241
* @param {string} payload The message content.
242
* @override
243
*/
244
goog.net.xpc.FrameElementMethodTransport.prototype.send = function(
245
service, payload) {
246
this.recursive_ = true;
247
this.outgoing_(service, payload);
248
this.recursive_ = false;
249
};
250
251
252
/** @override */
253
goog.net.xpc.FrameElementMethodTransport.prototype.disposeInternal =
254
function() {
255
goog.net.xpc.FrameElementMethodTransport.superClass_.disposeInternal.call(
256
this);
257
this.outgoing_ = null;
258
this.iframeElm_ = null;
259
};
260
261