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.
		
		
		
		
		
			
		
			
				
					
					
						
							141 lines
						
					
					
						
							3.7 KiB
						
					
					
				
			
		
		
	
	
							141 lines
						
					
					
						
							3.7 KiB
						
					
					
				'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;
 | 
						|
 |