colorplane
Programmer
Although Firefox and Opera support streaming Javascript commands sent by an HTTP server (Comet), I can't figure out why my server/client code is not streaming in Internet Explorer.
The concept of Comet as I understand it is that IE runs the <script> tags generated by the server as it receives them. This technique is used because IE does not allow access to responseTEXT or innerHTML while loading. I just can't get it to work.
I have been working on this for a long time, so I decided to make a very well-documented, self-contained Perl HTTP server to see if anyone could help me track down the issue. This is not the application that I am developing, but it exhibits the exact same peculiarities in IE.
When the code below is running in the command line, it will listen on port 9090, so you should be able to run the server script and connect to Basically the alert boxes should appear at 2-second intervals, but IE clumps them all together at the end of the request.
Please, if anyone can take a look at this and find anything fishy - endlines, html tags, socket problems, anything...
The clearest working example and my glimmer of hope is here:
Thank you, any feedback is appreciated.
The concept of Comet as I understand it is that IE runs the <script> tags generated by the server as it receives them. This technique is used because IE does not allow access to responseTEXT or innerHTML while loading. I just can't get it to work.
I have been working on this for a long time, so I decided to make a very well-documented, self-contained Perl HTTP server to see if anyone could help me track down the issue. This is not the application that I am developing, but it exhibits the exact same peculiarities in IE.
When the code below is running in the command line, it will listen on port 9090, so you should be able to run the server script and connect to Basically the alert boxes should appear at 2-second intervals, but IE clumps them all together at the end of the request.
Please, if anyone can take a look at this and find anything fishy - endlines, html tags, socket problems, anything...
The clearest working example and my glimmer of hope is here:
Thank you, any feedback is appreciated.
Code:
#!/usr/bin/perl --
# IE streaming server-push problem demonstration ###############################
################################################################################
# This script is meant to demonstrate strange IE behavior when working with
# streaming data. When directed to [URL unfurl="true"]http://localhost:9090/,[/URL] the browser should
# print a page which simply displays the following:
#
# Awaiting commands...
# Connecting... (script should start alerting soon)
# Executing command: alert('a' + 0)
# Executing command: alert('b' + 0)
# Executing command: alert('c' + 1)
# Disconnected.
# Connecting... (script should start alerting soon)
#
# Each command should be accompanied by an alert box with the specified message.
# The script should print these messages in Firefox, but in Internet Explorer,
# the printing of Executing command: is not expected to occur since IE is not
# expected to allow access to the responseText until the server has closed the
# socket. It /should/, however, signal alerts, but this is not happening.
#
# After the server prints the three commands, it closes the socket. The
# client re-establishes the connection and it begins again. Only at this point
# does IE print the alert messages.
#
# Javascript below is adapted from [URL unfurl="true"]http://empireenterprises.com/_comet.html[/URL]
use IO::Socket;
use strict;
$| = 1;
my $sock = new IO::Socket::INET(
LocalPort => 9090,
Proto => 'tcp',
Listen => SOMAXCONN,
Reuse => 1
);
# Demo supports one client at a time, wait for connections.
while (my $client = $sock->accept) {
print "\nReceived a connection\n";
my $request = <$client>;
# PRINT THE COMET SCRIPT SNIPPETS ############################################
# This code is run when connecting to localhost:9090/?ajax
if ($request =~ /comet/) {
print $client "HTTP/1.0 200 OK\nContent-type: text/html\n\n";
$_ = int(rand() * 5);
print "a $_\n";
print $client "<script>alert('a ' + $_)</script>\n";
sleep(2); # wait 2 seconds
$_ = int(rand() * 5);
print "b $_\n";
print $client "<script>alert('b ' + $_)</script>\n";
sleep(2); # wait 2 seconds
$_ = int(rand() * 5);
print "c $_\n";
print $client "<script>alert('c ' + $_)</script>\n";
}
# PRINT THE HTML PAGE ########################################################
# This code is run when connecting to localhost:9090
else {
print $client "HTTP/1.0 200 OK\nContent-type: text/html\n\n";
print $client qq{
<html>
<body>
<input type="button" value="Stop connection attempts" onclick="reconnect = 0;">
<div id="status">
Awaiting commands...<br>
</div>
<script>
// Change the server address here if you cannot use localhost:9090
var server = '[URL unfurl="true"]http://localhost:9090/';[/URL]
var interval = 0;
var status = document.getElementById('status');
var pos = 0;
var reconnect = 1;
// Adapted from [URL unfurl="true"]http://empireenterprises.com/_comet.html[/URL]
// Removed Opera support for this demo
function connect() {
status.innerHTML += 'Connecting... (script should start alerting soon)<br>';
pos = 0;
// Internet Explorer (just a quick IE vs FF check)
if (document.all) {
// By creating a new ActiveXObject('htmlfile'), there is no load bar.
var doc = new ActiveXObject('htmlfile');
doc.open();
doc.write('<html>');
doc.write('<html>');
doc.write('<script>document.domain = \\'' + document.domain + '\\'');
doc.write('</html>');
doc.close();
var div = doc.createElement('DIV');
doc.appendChild(div);
// This /should/ just run the Javascript commands as it receives them,
// but unfortunately it is not.
div.innerHTML = '<iframe name=\\'ifr\\' src=\\'' + server + '/?comet\\'></iframe>';
// It should not be useful to poll the iframe. From what I understand
// about IE, the content WILL NOT be available until the DOM is
// complete. Unfortunately that doesn't happen when streaming.
// Hence, the messages are printed as <script> tags because I
// believe that somehow (perhaps if the message is printed /just right/)
// that IE will actually call the Javascript functions as it receives
// them.
// Nevertheless, I am leaving this code in because it is also in the
// example.
if(!interval) {
interval = setInterval( function() {
var xmlhttp = doc.frames['ifr'].document;
if(xmlhttp.readyState == 'complete') {
clearInterval(interval);
interval = false;
status.innerHTML += 'Disconnected.<br>';
if (reconnect)
connect();
}
var data;
try {
data = xmlhttp.firstChild.innerHTML;
}
catch(error) {
return;
}
data = data.substring(pos);
if(data.indexOf('<SCRIPT>') < 0) {
return;
}
var start = data.indexOf('<SCRIPT>') + 8;
var stop = data.indexOf('<\\/SCRIPT>') - start;
data = data.substr(start, stop);
try {
// Uncomment these two lines to see that IE only receives the
// innerHTML after the server closes the socket.
//status.innerHTML += ' Executing command: ' + data.replace(/</g,'<') + '<br>';
//eval(data);
}
catch(error) {
}
pos += start + 8 + stop - 1;
}, 500 );
}
}
// Firefox. Opera implementation works, too - it just isn't included
// (use an interval to poll xmlhttp.responseText)
else {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if(xmlhttp.readyState == 4) {
status.innerHTML += 'Disconnected.<br>';
if (reconnect)
connect();
return false;
}
if(xmlhttp.readyState == 3) {
var data = xmlhttp.responseText;
data = data.substr(pos);
if(data.indexOf('<script>') < 0) {
return(false);
}
var start = data.indexOf('<script>') + 8;
var stop = data.indexOf('<\\/script>') - start;
data = data.substr(start, stop);
status.innerHTML += ' Executing command: ' + data.replace(/</g,'<') + '<br>';
try {
eval(data);
}
catch(error) {
}
pos += start + 8 + stop;
}
};
xmlhttp.open('GET', server + '/?comet', true);
xmlhttp.send('');
}
}
connect();
</script>
</body>
</html>
};
close o;
}
close $client;
}
1;