Changed NDN to take getTransport and added WebSocketTransport.js which defines the default transport.  Make NDN.expressInterest take the Name and call the specified transport's expressInterest.
diff --git a/js/WebSocketTransport.js b/js/WebSocketTransport.js
new file mode 100644
index 0000000..0b9543e
--- /dev/null
+++ b/js/WebSocketTransport.js
@@ -0,0 +1,257 @@
+/* 
+ * @author: Wentao Shang
+ * See COPYING for copyright and distribution information.
+ * Implement getAsync and putAsync used by NDN using nsISocketTransportService.
+ * This is used inside Firefox XPCOM modules.
+ */
+
+var WebSocketTransport = function WebSocketTransport() {    
+	this.ws = null;
+	this.ccndid = null;
+	this.maxBufferSize = 10000;  // Currently support 10000 bytes data input, consistent with BinaryXMLEncoder
+	this.buffer = new Uint8Array(this.maxBufferSize);
+	this.structureDecoder = new BinaryXMLStructureDecoder();
+};
+
+WebSocketTransport.prototype.expressInterest = function(ndn, interest, closure) {
+	if (this.ws != null) {
+		//TODO: check local content store first
+
+        var binaryInterest = encodeToBinaryInterest(interest);
+		var bytearray = new Uint8Array(binaryInterest.length);
+		bytearray.set(binaryInterest);
+		
+		var pitEntry = new PITEntry(interest.name.getName(), closure);
+		PITTable.push(pitEntry);
+		
+		this.ws.send(bytearray.buffer);
+		console.log('ws.send() returned.');
+	}
+	else{
+		console.log('WebSocket connection is not established.');
+		return null;
+	}
+};
+
+
+var ccndIdFetcher = '/%C1.M.S.localhost/%C1.M.SRV/ccnd/KEY';
+
+WebSocketTransport.prototype.connectWebSocket = function(ndn) {
+	if (this.ws != null)
+		delete this.ws;
+	
+	this.ws = new WebSocket('ws://' + ndn.host + ':' + ndn.port);
+	console.log('ws connection created.');
+	
+	this.ws.binaryType = "arraybuffer";
+	
+	var self = this;
+	this.ws.onmessage = function(ev) {
+		var result = ev.data;
+		//console.log('RecvHandle called.');
+			
+		if(result == null || result == undefined || result == "" ) {
+			console.log('INVALID ANSWER');
+		} else if (result instanceof ArrayBuffer) {
+	        var bytearray = new Uint8Array(result);
+	        
+			if (LOG>3) console.log('BINARY RESPONSE IS ' + bytearray);
+			
+			try {
+				if (bytearray.length + self.buffer.byteOffset >= self.buffer.byteLength) {
+					console.log("NDN.ws.onmessage: buffer overflow. Accumulate received length: " + self.buffer.byteOffset 
+						+ ". Current packet length: " + bytearray.length + ".");
+					// Purge and quit.
+					delete self.structureDecoder;
+					delete self.buffer;
+					self.structureDecoder = new BinaryXMLStructureDecoder();
+					self.buffer = new Uint8Array(self.maxBufferSize);
+					return;
+				}
+				
+				/*for (var i = 0; i < bytearray.length; i++) {
+					self.buffer.push(bytearray[i]);
+				}*/
+				self.buffer.set(bytearray, self.buffer.byteOffset);
+				
+				if (!self.structureDecoder.findElementEnd(self.buffer)) {
+					// Need more data to decode
+					console.log('Incomplete packet received. Length ' + bytearray.length + '. Wait for more input.');
+					console.log('self.buffer length: ' + self.buffer.length);
+					return;
+				}
+			} catch (ex) {
+				console.log("NDN.ws.onmessage exception: " + ex);
+				return;
+			}
+			
+			var decoder = new BinaryXMLDecoder(self.buffer);
+			// Dispatch according to packet type
+			if (decoder.peekStartElement(CCNProtocolDTags.Interest)) {  // Interest packet
+				console.log('Interest packet received.');
+				
+				var interest = new Interest();
+				interest.from_ccnb(decoder);
+				if (LOG>3) console.log(interest);
+				var nameStr = escape(interest.name.getName());
+				console.log(nameStr);
+				
+				var entry = getEntryForRegisteredPrefix(nameStr);
+				if (entry != null) {
+					//console.log(entry);
+					entry.closure.upcall(Closure.UPCALL_INTEREST, new UpcallInfo(ndn, interest, 0, null));
+				}
+				
+			} else if (decoder.peekStartElement(CCNProtocolDTags.ContentObject)) {  // Content packet
+				console.log('ContentObject packet received.');
+				
+				var co = new ContentObject();
+				co.from_ccnb(decoder);
+				if (LOG>3) console.log(co);
+				nameStr = co.name.getName();
+				console.log(nameStr);
+				
+				if (self.ccndid == null && nameStr.match(ccndIdFetcher) != null) {
+					// We are in starting phase, record publisherPublicKeyDigest in self.ccndid
+					if(!co.signedInfo || !co.signedInfo.publisher 
+						|| !co.signedInfo.publisher.publisherPublicKeyDigest) {
+						console.log("Cannot contact router");
+					} else {
+						console.log('Connected to ccnd.');
+						self.ccndid = co.signedInfo.publisher.publisherPublicKeyDigest;
+						if (LOG>3) console.log(self.ccndid);
+					}
+				} else {
+					var pitEntry = getEntryForExpressedInterest(nameStr);
+					if (pitEntry != null) {
+						//console.log(pitEntry);
+						pitEntry.closure.upcall(Closure.UPCALL_CONTENT, new UpcallInfo(ndn, null, 0, co));
+					}
+				}
+			} else {
+				console.log('Incoming packet is not Interest or ContentObject. Discard now.');
+			}
+			
+			delete decoder;
+			
+			// Renew StrcutureDecoder and buffer after we process a full packet
+			delete self.structureDecoder;
+			delete self.buffer;
+			self.structureDecoder = new BinaryXMLStructureDecoder();
+			self.buffer = new Uint8Array(self.maxBufferSize);
+		}
+	}
+	
+	this.ws.onopen = function(ev) {
+		console.log(ev);
+		console.log('ws.onopen: WebSocket connection opened.');
+		console.log('ws.onopen: ReadyState: ' + this.readyState);
+
+		// Fetch ccndid now
+		interest = new Interest(new Name(ccndIdFetcher));
+		interest.InterestLifetime = 4200;
+		//var hex = encodeToHexInterest(interest);
+		var hex = encodeToBinaryInterest(interest);
+		
+		/*var bytes = new Uint8Array(hex.length / 2);
+		for (var i = 0; i < hex.length; i = i + 2) {
+	    	bytes[i / 2] = '0x' + hex.substr(i, 2);
+		}*/
+		var bytes = new Uint8Array(hex.length);
+		bytes.set(hex);
+		
+		self.ws.send(bytes.buffer);
+		console.log('ws.onopen: ws.send() returned.');
+	}
+	
+	this.ws.onerror = function(ev) {
+		console.log('ws.onerror: ReadyState: ' + this.readyState);
+		console.log(ev);
+		console.log('ws.onerror: WebSocket error: ' + ev.data);
+	}
+	
+	this.ws.onclose = function(ev) {
+		console.log('ws.onclose: WebSocket connection closed.');
+		self.ws = null;
+	}
+}
+
+
+// For fetching data
+var PITTable = new Array();
+
+var PITEntry = function PITEntry(interest, closure) {
+	this.interest = interest;  // String
+	this.closure = closure;    // Closure
+}
+
+function getEntryForExpressedInterest(name) {
+	for (var i = 0; i < PITTable.length; i++) {
+		if (name.match(PITTable[i].interest) != null)
+			return PITTable[i];
+			// TODO: handle multiple matching prefixes
+	}
+	return null;
+}
+
+
+// For publishing data
+var CSTable = new Array();
+
+var CSEntry = function CSEntry(name, closure) {
+	this.name = name;        // String
+	this.closure = closure;  // Closure
+}
+
+function getEntryForRegisteredPrefix(name) {
+	for (var i = 0; i < CSTable.length; i++) {
+		if (CSTable[i].name.match(name) != null)
+			return CSTable[i];
+	}
+	return null;
+}
+
+WebSocketTransport.prototype.registerPrefix = function(ndn, name, closure, flag) {
+	if (this.ws != null) {
+		if (this.ccndid == null) {
+			console.log('ccnd node ID unkonwn. Cannot register prefix.');
+			return;
+		}
+		
+		name = name.trim();
+		
+		var fe = new ForwardingEntry('selfreg', new Name(name), null, null, 3, 2147483647);
+		var bytes = encodeForwardingEntry(fe);
+		
+		var si = new SignedInfo();
+		si.setFields();
+		
+		var co = new ContentObject(new Name(), si, bytes, new Signature()); 
+		co.sign();
+		var coBinary = encodeToBinaryContentObject(co);
+		
+		//var ccnxnodename = unescape('%00%88%E2%F4%9C%91%16%16%D6%21%8E%A0c%95%A5%A6r%11%E0%A0%82%89%A6%A9%85%AB%D6%E2%065%DB%AF');
+		var ccnxnodename = this.ccndid;
+		var interestName = new Name(['ccnx', ccnxnodename, 'selfreg', coBinary]);
+
+		var interest = new Interest(interestName);
+		interest.scope = 1;
+		//var hex = encodeToHexInterest(int);
+		var binaryInterest = encodeToBinaryInterest(interest);
+    	var bytearray = new Uint8Array(binaryInterest.length);
+		bytearray.set(binaryInterest);
+		console.log('Send Interest registration packet.');
+    	
+    	var csEntry = new CSEntry(name, closure);
+		CSTable.push(csEntry);
+    	
+    	this.ws.send(bytearray.buffer);
+		console.log('ws.send() returned.');
+		
+		return 0;
+	} else {
+		console.log('WebSocket connection is not established.');
+		return -1;
+	}
+}
+