Created
April 25, 2012 16:57
-
-
Save lightsofapollo/2491286 to your computer and use it in GitHub Desktop.
httpd
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const CC = Components.Constructor; | |
const LocalFile = CC('@mozilla.org/file/local;1', | |
'nsILocalFile', | |
'initWithPath'); | |
const ScriptableInputStream = CC( | |
"@mozilla.org/scriptableinputstream;1", | |
"nsIScriptableInputStream"); | |
Components.utils.import('resource:///modules/devtools/dbg-client.jsm'); | |
function startupHttpd(baseDir, port) { | |
const httpdURL = 'chrome://httpd.js/content/httpd.js'; | |
let httpd = {}; | |
Services.scriptloader.loadSubScript(httpdURL, httpd); | |
let server = new httpd.nsHttpServer(); | |
server.registerDirectory('/', new LocalFile(baseDir)); | |
server.registerContentType('appcache', 'text/cache-manifest'); | |
server.start(port); | |
// Add {appname}.domain.tld:port to the list of domains handle by httpd | |
let identity = server.identity; | |
let scheme = 'http'; | |
let host = 'gaiamobile.org'; | |
identity.add(scheme, host, port); | |
let directories = getDirectories(baseDir); | |
directories.forEach(function appendDir(name) { | |
identity.add(scheme, name + '.' + host, port); | |
}); | |
try { | |
Components.utils.import('resource:///modules/devtools/dbg-server.jsm'); | |
// DebuggerServer.addBrowserActors(); | |
DebuggerServer.addActors('chrome://httpd.js/content/marionette-actors.js'); | |
DebuggerServer.init(); | |
DebuggerServer.openListener(2828, true); | |
} catch (e) { | |
// already open if running in b2g desktop | |
} | |
server.registerPathHandler('/marionette', handleMarionette); | |
} | |
function getDirectories(dir) { | |
let appsDir = Cc["@mozilla.org/file/local;1"] | |
.createInstance(Ci.nsILocalFile); | |
appsDir.initWithPath(dir); | |
appsDir.append('apps'); | |
let dirs = []; | |
let files = appsDir.directoryEntries; | |
while (files.hasMoreElements()) { | |
let file = files.getNext().QueryInterface(Ci.nsILocalFile); | |
if (file.isDirectory()) { | |
dirs.push(file.leafName); | |
} | |
} | |
return dirs; | |
} | |
function LongPoll(connid, transport) { | |
this.transport = transport; | |
this.connid = connid; | |
this.buffer = []; | |
this.outstanding_push = null; | |
} | |
LongPoll.prototype = { | |
cast: function cast(msg) { | |
this.buffer.push(msg); | |
dump("cast "+JSON.stringify(msg)+ " " + this.outstanding_push + "\n"); | |
if (this.outstanding_push !== null) { | |
this.drain_queue(this.outstanding_push); | |
this.outstanding_push.finish(); | |
this.outstanding_push = null; | |
} | |
}, | |
drain_queue: function drain_queue(res) { | |
let queue = this.buffer, | |
response = { messages: [] }; | |
this.buffer = []; | |
queue.forEach(function(chunk) { | |
response.messages.push({ | |
id: this.connid, | |
response: chunk | |
}) | |
}.bind(this)); | |
}, | |
send: function send(obj) { | |
this.transport.send(obj); | |
} | |
} | |
let connections = {}, | |
connection_num = 0, | |
scriptable = new ScriptableInputStream(); | |
function handleMarionette(req, res) { | |
try { | |
if (req.method === "GET") { | |
if (req.queryString.length === 0) { | |
res.setStatusLine("1.1", 404, "Not Found"); | |
res.write(JSON.stringify({ | |
error: 'connection not found' | |
})); | |
} else { | |
// render event stream | |
let connid = req.queryString.split('=')[0], | |
me = connections[connid]; | |
res.setStatusLine("1.1", 200, "OK"); | |
res.setHeader("Content-Type", "application/javascript"); | |
if (me.buffer.length === 0) { | |
dump("waiting /marionette?" + req.queryString + "\n"); | |
res.processAsync(); | |
me.outstanding_push = res; | |
} else { | |
dump("messages /marionette?" + req.queryString + "\n"); | |
me.drain_queue(res); | |
} | |
} | |
} else if (req.method === "POST") { | |
// parse login screen | |
// render connection stream | |
let connid = connection_num++; | |
res.setStatusLine("1.1", 200, "OK"); | |
res.setHeader("Content-Type", "application/json"); | |
res.write(JSON.stringify({ id: connid})); | |
req.bodyInputStream.asyncWait(function (stream) { | |
scriptable.init(stream); | |
let bytes = scriptable.read(scriptable.available()), | |
parsed = JSON.parse(bytes); | |
dump("BYTES "+bytes+"\n"); | |
let transport = debuggerSocketConnect(parsed.server, parseInt(parsed.port)), | |
me = new LongPoll(connid, transport); | |
connections[connid] = me; | |
transport.hooks = { | |
onPacket: function onPacket(pack) { | |
me.cast(pack); | |
dump("ONPACKET"+JSON.stringify(pack)+"\n"); | |
}, | |
onClosed: function onClosed(status) { | |
dump("CLOSED"+JSON.stringify(status)+"\n"); | |
} | |
} | |
transport.ready(); | |
dump("transport\n"); | |
}, 0, 0, Services.tm.currentThread); | |
} else if (req.method === "PUT") { | |
let connid = req.queryString.split('=')[0], | |
me = connections[connid]; | |
dump("put\n"); | |
res.setStatusLine("1.1", 201, "Accepted"); | |
res.setHeader("Content-Type", "text/plain", false); | |
res.write(''); | |
req.bodyInputStream.asyncWait(function (stream) { | |
scriptable.init(stream); | |
let bytes = scriptable.read(scriptable.available()), | |
parsed = null; | |
try { | |
parsed = JSON.parse(bytes); | |
dump("PARSED!\n"); | |
} catch (e) { | |
} | |
dump("stream " + bytes+"\n"); | |
me.send(parsed); | |
}, 0, 0, Services.tm.currentThread); | |
} else { | |
res.setStatusLine("1.1", 405, "Method Not Allowed"); | |
res.write(''); | |
} | |
} catch (e) { | |
res.setStatusLine("1.1", 500, "Internal Server Error"); | |
if(e.stack === undefined) { | |
res.write(e.toString()); | |
} else { | |
res.write(e.toString() + " " + e.stack); | |
} | |
} | |
} | |
startupHttpd('/Users/jlal/workspace/marionette_js_client', 8080); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment