Created
August 3, 2012 01:46
-
-
Save kyo-ago/3243320 to your computer and use it in GitHub Desktop.
Android2系でXHRのLong Pollingができない問題の検証コード(ざっくり内容)
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
<html> | |
<head> | |
<title></title> | |
<script type="text/javascript"> | |
/* | |
// mxhr.js | |
// BSD license | |
var mxhr = new MXHR; | |
mxhr.listen(mime, function(body){ process(body) }); | |
mxhr.listen('complete', function(status_code){ ... }); // 2xx response | |
mxhr.listen('error', function(status_code){ ... }); // other case | |
mxhr.open("GET", url, true); // or mxhr.open("POST", url, true); | |
mxhr.send(""); | |
*/ | |
function MXHR() { | |
this.listeners = {}; | |
this.watcher_interval = 15; | |
this.parsed = 0; | |
this.aborted = 0; | |
this.boundary = ''; | |
this._watcher_id = null; | |
} | |
(function(p){ | |
function open(method, path, async){ | |
var self = this; | |
this.aborted = 0; | |
var req = new XMLHttpRequest(); | |
['progresss', 'loadstart', 'abort', 'error', 'load', 'timeout', 'loadend', 'readystatechange'].forEach(function (name) { | |
req.addEventListener(name, (function (name) { | |
return function () { | |
log.innerHTML += req.readyState + name + '\n'; | |
} | |
})(name), false); | |
}); | |
req.onloadstart = function () { | |
setTimeout(function () { | |
self.abort(); | |
log.innerHTML += req.responseText.length + 'length\n'; | |
}, 2000); | |
}; | |
var res = req.open(method, path, async); | |
this.req = req; | |
return res; | |
} | |
function send(query){ | |
var req = this.req; | |
return req.send(query); | |
} | |
function abort(){ | |
this.aborted = 1; | |
this.finish_stream("ABORTED"); | |
var req = this.req; | |
return req.abort(); | |
} | |
function init_stream(){ | |
var self = this; | |
var contentTypeHeader = this.req.getResponseHeader("Content-Type"); | |
if (contentTypeHeader.indexOf("multipart/mixed") === -1) { | |
this.req.onreadystatechange = function() { | |
self.req.onreadystatechange = function() {}; | |
self.invoke_callback('error', self.req.status); | |
}; | |
} else { | |
this.boundary = '--' + contentTypeHeader.split('"')[1]; | |
this.start_watcher(); | |
} | |
} | |
function finish_stream(status){ | |
this.stop_watcher(); | |
this.process_chunk(); | |
if (status >= 200 && status < 300) { | |
this.invoke_callback('complete', status); | |
} else { | |
this.invoke_callback('error', status); | |
} | |
} | |
function start_watcher() { | |
var self = this; | |
this._watcher_id = window.setInterval(function(){ | |
self.process_chunk(); | |
}, this.watcher_interval); | |
} | |
function stop_watcher() { | |
window.clearInterval(this._watcher_id); | |
this._watcher_id = null; | |
} | |
function listen(mime, callback){ | |
if(typeof this.listeners[mime] === 'undefined') { | |
this.listeners[mime] = []; | |
} | |
if(typeof callback !== 'undefined' && callback.constructor === Function) { | |
this.listeners[mime].push(callback); | |
} | |
} | |
function process_chunk(){ | |
var length = this.req.responseText.length; | |
var rbuf = this.req.responseText.substring(this.parsed, length); | |
// [parsed_length, header_and_body] | |
var res = this.incr_parse(rbuf); | |
if (res[0] > 0) { | |
this.process_part(res[1]); | |
this.parsed += res[0]; | |
if (length > this.parsed) { this.process_chunk(); } | |
} | |
} | |
function process_part(part) { | |
var self = this; | |
part = part.replace(this.boundary + "\n", ''); | |
var lines = part.split("\n"); | |
var mime = lines.shift().split('Content-Type:', 2)[1].split(";", 1)[0].replace(' ', ''); | |
mime = mime ? mime : null; | |
var body = lines.join("\n"); | |
this.invoke_callback(mime, body); | |
} | |
function invoke_callback(mime, body) { | |
var i; | |
var self = this; | |
if(typeof this.listeners[mime] !== 'undefined') { | |
for (i = this.listeners[mime].length; i--;) { | |
this.listeners[mime][i].call(self, body); | |
} | |
} | |
} | |
function incr_parse(buf) { | |
if (buf.length < 1) { return [-1]; } | |
var start = buf.indexOf(this.boundary); | |
if (start === -1) { return [-1]; } | |
var end = buf.indexOf(this.boundary, start + this.boundary.length); | |
// SUCCESS | |
if (start > -1 && end > -1) { | |
var part = buf.substring(start, end); | |
// end != part.length in wrong response, ignore it | |
return [end, part]; | |
} | |
// INCOMPLETE | |
return [-1]; | |
} | |
var i; | |
var methods = ("open,send,abort,init_stream,finish_stream,start_watcher,stop_watcher,listen," + | |
"process_chunk,process_part,invoke_callback,incr_parse").split(","); | |
var code = ""; | |
for (i = 0; i < methods.length; i++) { | |
code += ('p.' + methods[i] + '=' + methods[i] + ';'); | |
} | |
eval(code); | |
}(MXHR.prototype)); | |
</script> | |
<script type="text/javascript"> | |
var qs = function (obj) { | |
var k, q = []; | |
for (k in obj) { | |
if (obj.hasOwnProperty(k)) { | |
q.push(k + "=" + obj[k]); | |
} | |
} | |
return (q.length > 0) ? q.join("&") : null; | |
}; | |
var handler = { | |
PING: function (data, source, origin) { | |
var message = JSON.stringify({ | |
id: data.id, | |
rid: data.rid, | |
body: "PONG" | |
}); | |
source.postMessage(message, origin); | |
}, | |
STREAM: function (data, source, origin) { | |
var api = data.path; | |
data.params.prelude = 1; | |
var query = qs(data.params); | |
if (query) { | |
api += "?" + query; | |
} | |
var mxhr; | |
var connect = function () { | |
if (mxhr) { | |
mxhr.abort(); | |
} | |
mxhr = new MXHR(); | |
mxhr.listen("application/json", function (body) { | |
var message = JSON.stringify({ | |
id: data.id, | |
rid: data.rid, | |
body: body | |
}); | |
source.postMessage(message, origin); | |
}); | |
mxhr.listen("complete", connect); | |
mxhr.listen("error", function (status) { | |
setTimeout(connect, 5000); | |
}); | |
mxhr.open("GET", api, true); | |
mxhr.send(); | |
}; | |
connect(); | |
}, | |
REST: function (data, source, origin) { | |
var xhr = new XMLHttpRequest(); | |
var path = data.path; | |
var query = qs(data.params); | |
if (data.method === "GET" && query) { | |
path += "?" + query; | |
} | |
xhr.open(data.method, path); | |
xhr.onreadystatechange = function () { | |
if (xhr.readyState === 4) { | |
var message = JSON.stringify({ | |
id: data.id, | |
rid: data.rid, | |
body: xhr.responseText | |
}); | |
source.postMessage(message, origin); | |
} | |
}; | |
if (data.method === "POST" && query) { | |
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); | |
xhr.send(query); | |
} else { | |
xhr.send(null); | |
} | |
} | |
}; | |
var listener = function (e) { | |
var source = e.source; | |
var origin = e.origin; | |
var data = JSON.parse(e.data); | |
handler[data.type](data, source, origin); | |
}; | |
if (window.attachEvent) { | |
window.attachEvent("onmessage", listener); | |
} else { | |
window.addEventListener("message", listener, false); | |
} | |
</script> | |
</head> | |
<body> | |
<div id="log"></div> | |
</body> | |
</html> |
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
var http = require('http'); | |
var fs = require('fs'); | |
var url = require('url'); | |
http.createServer(function (request, response) { | |
var req = url.parse(request.url, true); | |
var path = '../' + req.pathname.replace(/^\//g, ''); | |
console.log(path); | |
if (fs.existsSync(path) && fs.statSync(path).isFile()) { | |
var ext = (path.match(/\.(\w+)$/) || [''])[1]; | |
var mime = ({ | |
'html' : 'text/html', | |
'css' : 'text/css', | |
'xml' : 'text/xml', | |
'js' : 'application/x-javascript' | |
})[ext] || 'text/plain'; | |
console.log(ext, mime); | |
response.writeHead(200, {'Content-Type': mime}); | |
response.end(fs.readFileSync(path)); | |
return; | |
}; | |
response.writeHead(200, { | |
'Content-Type': 'multipart/mixed; boundary="boundary_str"' | |
}); | |
var count = 5; | |
var interval = setInterval(function () { | |
response.write('--boundary_str\nContent-Type: application/json\n\n'); | |
response.write('res' + count); | |
console.log(count); | |
if (!count--) { | |
response.end(''); | |
clearInterval(interval); | |
console.log('end'); | |
} | |
}, 2000); | |
}).listen(8125); | |
console.log('Server running at http://127.0.0.1:8125/'); |
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
<html><head></head><body> | |
<iframe src="hoge.html"></iframe> | |
<div id="log"></div> | |
<script type="text/javascript"> | |
window.onload = function () { | |
var iframe = document.getElementsByTagName('iframe')[0]; | |
iframe.contentWindow.postMessage(JSON.stringify({ | |
'type' : 'STREAM', | |
'method' : 'GET', | |
'path' : '/hoge' + Date.now(), | |
'params' : {} | |
}), '*'); | |
window.addEventListener('message', function () { | |
log.innerHTML = arguments[0].data; | |
}, false); | |
} | |
</script> | |
</body></html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment