You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					142 lines
				
				3.7 KiB
			
		
		
			
		
	
	
					142 lines
				
				3.7 KiB
			| 
								 
											4 years ago
										 
									 | 
							
								'use strict';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Few cool transports do work only for same-origin. In order to make
							 | 
						||
| 
								 | 
							
								// them work cross-domain we shall use iframe, served from the
							 | 
						||
| 
								 | 
							
								// remote domain. New browsers have capabilities to communicate with
							 | 
						||
| 
								 | 
							
								// cross domain iframe using postMessage(). In IE it was implemented
							 | 
						||
| 
								 | 
							
								// from IE 8+, but of course, IE got some details wrong:
							 | 
						||
| 
								 | 
							
								//    http://msdn.microsoft.com/en-us/library/cc197015(v=VS.85).aspx
							 | 
						||
| 
								 | 
							
								//    http://stevesouders.com/misc/test-postmessage.php
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var inherits = require('inherits')
							 | 
						||
| 
								 | 
							
								  , JSON3 = require('json3')
							 | 
						||
| 
								 | 
							
								  , EventEmitter = require('events').EventEmitter
							 | 
						||
| 
								 | 
							
								  , version = require('../version')
							 | 
						||
| 
								 | 
							
								  , urlUtils = require('../utils/url')
							 | 
						||
| 
								 | 
							
								  , iframeUtils = require('../utils/iframe')
							 | 
						||
| 
								 | 
							
								  , eventUtils = require('../utils/event')
							 | 
						||
| 
								 | 
							
								  , random = require('../utils/random')
							 | 
						||
| 
								 | 
							
								  ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var debug = function() {};
							 | 
						||
| 
								 | 
							
								if (process.env.NODE_ENV !== 'production') {
							 | 
						||
| 
								 | 
							
								  debug = require('debug')('sockjs-client:transport:iframe');
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function IframeTransport(transport, transUrl, baseUrl) {
							 | 
						||
| 
								 | 
							
								  if (!IframeTransport.enabled()) {
							 | 
						||
| 
								 | 
							
								    throw new Error('Transport created when disabled');
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  EventEmitter.call(this);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var self = this;
							 | 
						||
| 
								 | 
							
								  this.origin = urlUtils.getOrigin(baseUrl);
							 | 
						||
| 
								 | 
							
								  this.baseUrl = baseUrl;
							 | 
						||
| 
								 | 
							
								  this.transUrl = transUrl;
							 | 
						||
| 
								 | 
							
								  this.transport = transport;
							 | 
						||
| 
								 | 
							
								  this.windowId = random.string(8);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var iframeUrl = urlUtils.addPath(baseUrl, '/iframe.html') + '#' + this.windowId;
							 | 
						||
| 
								 | 
							
								  debug(transport, transUrl, iframeUrl);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  this.iframeObj = iframeUtils.createIframe(iframeUrl, function(r) {
							 | 
						||
| 
								 | 
							
								    debug('err callback');
							 | 
						||
| 
								 | 
							
								    self.emit('close', 1006, 'Unable to load an iframe (' + r + ')');
							 | 
						||
| 
								 | 
							
								    self.close();
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  this.onmessageCallback = this._message.bind(this);
							 | 
						||
| 
								 | 
							
								  eventUtils.attachEvent('message', this.onmessageCallback);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								inherits(IframeTransport, EventEmitter);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								IframeTransport.prototype.close = function() {
							 | 
						||
| 
								 | 
							
								  debug('close');
							 | 
						||
| 
								 | 
							
								  this.removeAllListeners();
							 | 
						||
| 
								 | 
							
								  if (this.iframeObj) {
							 | 
						||
| 
								 | 
							
								    eventUtils.detachEvent('message', this.onmessageCallback);
							 | 
						||
| 
								 | 
							
								    try {
							 | 
						||
| 
								 | 
							
								      // When the iframe is not loaded, IE raises an exception
							 | 
						||
| 
								 | 
							
								      // on 'contentWindow'.
							 | 
						||
| 
								 | 
							
								      this.postMessage('c');
							 | 
						||
| 
								 | 
							
								    } catch (x) {
							 | 
						||
| 
								 | 
							
								      // intentionally empty
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    this.iframeObj.cleanup();
							 | 
						||
| 
								 | 
							
								    this.iframeObj = null;
							 | 
						||
| 
								 | 
							
								    this.onmessageCallback = this.iframeObj = null;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								IframeTransport.prototype._message = function(e) {
							 | 
						||
| 
								 | 
							
								  debug('message', e.data);
							 | 
						||
| 
								 | 
							
								  if (!urlUtils.isOriginEqual(e.origin, this.origin)) {
							 | 
						||
| 
								 | 
							
								    debug('not same origin', e.origin, this.origin);
							 | 
						||
| 
								 | 
							
								    return;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var iframeMessage;
							 | 
						||
| 
								 | 
							
								  try {
							 | 
						||
| 
								 | 
							
								    iframeMessage = JSON3.parse(e.data);
							 | 
						||
| 
								 | 
							
								  } catch (ignored) {
							 | 
						||
| 
								 | 
							
								    debug('bad json', e.data);
							 | 
						||
| 
								 | 
							
								    return;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (iframeMessage.windowId !== this.windowId) {
							 | 
						||
| 
								 | 
							
								    debug('mismatched window id', iframeMessage.windowId, this.windowId);
							 | 
						||
| 
								 | 
							
								    return;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  switch (iframeMessage.type) {
							 | 
						||
| 
								 | 
							
								  case 's':
							 | 
						||
| 
								 | 
							
								    this.iframeObj.loaded();
							 | 
						||
| 
								 | 
							
								    // window global dependency
							 | 
						||
| 
								 | 
							
								    this.postMessage('s', JSON3.stringify([
							 | 
						||
| 
								 | 
							
								      version
							 | 
						||
| 
								 | 
							
								    , this.transport
							 | 
						||
| 
								 | 
							
								    , this.transUrl
							 | 
						||
| 
								 | 
							
								    , this.baseUrl
							 | 
						||
| 
								 | 
							
								    ]));
							 | 
						||
| 
								 | 
							
								    break;
							 | 
						||
| 
								 | 
							
								  case 't':
							 | 
						||
| 
								 | 
							
								    this.emit('message', iframeMessage.data);
							 | 
						||
| 
								 | 
							
								    break;
							 | 
						||
| 
								 | 
							
								  case 'c':
							 | 
						||
| 
								 | 
							
								    var cdata;
							 | 
						||
| 
								 | 
							
								    try {
							 | 
						||
| 
								 | 
							
								      cdata = JSON3.parse(iframeMessage.data);
							 | 
						||
| 
								 | 
							
								    } catch (ignored) {
							 | 
						||
| 
								 | 
							
								      debug('bad json', iframeMessage.data);
							 | 
						||
| 
								 | 
							
								      return;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    this.emit('close', cdata[0], cdata[1]);
							 | 
						||
| 
								 | 
							
								    this.close();
							 | 
						||
| 
								 | 
							
								    break;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								IframeTransport.prototype.postMessage = function(type, data) {
							 | 
						||
| 
								 | 
							
								  debug('postMessage', type, data);
							 | 
						||
| 
								 | 
							
								  this.iframeObj.post(JSON3.stringify({
							 | 
						||
| 
								 | 
							
								    windowId: this.windowId
							 | 
						||
| 
								 | 
							
								  , type: type
							 | 
						||
| 
								 | 
							
								  , data: data || ''
							 | 
						||
| 
								 | 
							
								  }), this.origin);
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								IframeTransport.prototype.send = function(message) {
							 | 
						||
| 
								 | 
							
								  debug('send', message);
							 | 
						||
| 
								 | 
							
								  this.postMessage('m', message);
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								IframeTransport.enabled = function() {
							 | 
						||
| 
								 | 
							
								  return iframeUtils.iframeEnabled;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								IframeTransport.transportName = 'iframe';
							 | 
						||
| 
								 | 
							
								IframeTransport.roundTrips = 2;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								module.exports = IframeTransport;
							 |