|
|
@ -20,76 +20,109 @@ node.http.Server = function (RequestHandler, options) { |
|
|
|
* are writing to responses out of order! HTTP requires that responses |
|
|
|
* are returned in the same order the requests come. |
|
|
|
*/ |
|
|
|
this.output = ""; |
|
|
|
|
|
|
|
var output = []; |
|
|
|
|
|
|
|
function toRaw(string) { |
|
|
|
var a = []; |
|
|
|
for (var i = 0; i < string.length; i++) |
|
|
|
a.push(string.charCodeAt(i)); |
|
|
|
return a; |
|
|
|
} |
|
|
|
|
|
|
|
// The send method appends data onto the output array. The deal is,
|
|
|
|
// the data is either an array of integer, representing binary or it
|
|
|
|
// is a string in which case it's UTF8 encoded.
|
|
|
|
// Two things to considered:
|
|
|
|
// - we should be able to send mixed encodings.
|
|
|
|
// - we don't want to call connection.send("smallstring") because that
|
|
|
|
// is wasteful. *I think* its rather faster to concat inside of JS
|
|
|
|
// Thus I attempt to concat as much as possible.
|
|
|
|
function send (data) { |
|
|
|
if (responses[0] === this) { |
|
|
|
connection.send(data); |
|
|
|
} else { |
|
|
|
this.output += data; |
|
|
|
if (output.length == 0) { |
|
|
|
output.push(data); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
var li = output.length-1; |
|
|
|
|
|
|
|
if (data.constructor == String && output[li].constructor == String) { |
|
|
|
output[li] += data; |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if (data.constructor == Array && output[li].constructor == Array) { |
|
|
|
output[li] = output[li].concat(data); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// If the string is small enough, just convert it to binary
|
|
|
|
if (data.constructor == String |
|
|
|
&& data.length < 128 |
|
|
|
&& output[li].constructor == Array) |
|
|
|
{ |
|
|
|
output[li] = output[li].concat(toRaw(data)); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
output.push(data); |
|
|
|
}; |
|
|
|
|
|
|
|
this.flush = function () { |
|
|
|
if (responses.length > 0 && responses[0] === this) |
|
|
|
while (output.length > 0) |
|
|
|
connection.send(output.shift()); |
|
|
|
}; |
|
|
|
|
|
|
|
this.sendStatus = function (status, reason) { |
|
|
|
// XXX http/1.0 until i get the keep-alive logic below working.
|
|
|
|
this.output += "HTTP/1.0 " + status.toString() + " " + reason + "\r\n"; |
|
|
|
send("HTTP/1.0 " + status.toString() + " " + reason + "\r\n"); |
|
|
|
}; |
|
|
|
|
|
|
|
var chunked_encoding = false; |
|
|
|
var connection_close = false; |
|
|
|
|
|
|
|
this.sendHeader = function (field, value) { |
|
|
|
this.output += field + ": " + value.toString() + "\r\n"; |
|
|
|
send(field + ": " + value.toString() + "\r\n"); |
|
|
|
|
|
|
|
if (/Connection/i.exec(field) && /close/i.exec(value)) |
|
|
|
connection_close = true; |
|
|
|
|
|
|
|
else if (/Transfer-Encoding/i.exec(field) && /chunk/i.exec(value)) |
|
|
|
chunked_encoding = true; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
var bodyBegan = false; |
|
|
|
|
|
|
|
function toRaw(string) { |
|
|
|
var a = []; |
|
|
|
for (var i = 0; i < string.length; i++) |
|
|
|
a.push(string.charCodeAt(i)); |
|
|
|
return i; |
|
|
|
} |
|
|
|
|
|
|
|
function chunkEncode (chunk) { |
|
|
|
var hexlen = chunk.length.toString(16); |
|
|
|
if (chunk.constructor === String) |
|
|
|
return hexlen + "\r\n" + chunk + "\r\n"; |
|
|
|
// er..
|
|
|
|
} |
|
|
|
|
|
|
|
this.sendBody = function (chunk) { |
|
|
|
if (bodyBegan === false) { |
|
|
|
this.output += "\r\n"; |
|
|
|
send("\r\n"); |
|
|
|
bodyBegan = true; |
|
|
|
} |
|
|
|
|
|
|
|
if (chunked_encoding) |
|
|
|
this.output += chunkEncode(chunk) |
|
|
|
else |
|
|
|
this.output += chunk; |
|
|
|
|
|
|
|
if (responses[0] === this) { |
|
|
|
connection.send(this.output); |
|
|
|
this.output = ""; |
|
|
|
if (chunked_encoding) { |
|
|
|
send(chunk.length.toString(16)); |
|
|
|
send("\r\n"); |
|
|
|
send(chunk); |
|
|
|
send("\r\n"); |
|
|
|
} else { |
|
|
|
send(chunk); |
|
|
|
} |
|
|
|
|
|
|
|
this.flush(); |
|
|
|
}; |
|
|
|
|
|
|
|
var finished = false; |
|
|
|
this.finish = function () { |
|
|
|
if (chunked_encoding) |
|
|
|
this.output += "0\r\n\r\n"; // last chunk
|
|
|
|
send("0\r\n\r\n"); // last chunk
|
|
|
|
|
|
|
|
this.finished = true; |
|
|
|
|
|
|
|
while (responses.length > 0 && responses[0].finished) { |
|
|
|
var res = responses.shift(); |
|
|
|
connection.send(res.output); |
|
|
|
var res = responses[0]; |
|
|
|
res.flush(); |
|
|
|
responses.shift(); |
|
|
|
} |
|
|
|
|
|
|
|
if (responses.length == 0) { |
|
|
@ -104,7 +137,7 @@ node.http.Server = function (RequestHandler, options) { |
|
|
|
|
|
|
|
this.onMessage = function ( ) { |
|
|
|
var res = new Response(); |
|
|
|
var req = new RequestHandler(res); |
|
|
|
var req = new RequestHandler(res, connection); |
|
|
|
|
|
|
|
this.encoding = req.encoding || "raw"; |
|
|
|
|
|
|
|