Browse Source

Binary HTTP bodies for both requests and responses.

v0.7.4-release
Ryan 16 years ago
parent
commit
103a8800c7
  1. 44
      src/http.cc
  2. 103
      src/http.js

44
src/http.cc

@ -4,19 +4,22 @@
#include <assert.h>
#include <stdio.h>
#include <strings.h>
#define ON_MESSAGE_SYMBOL String::NewSymbol("onMessage")
#define MESSAGE_HANDLER_SYMBOL String::NewSymbol("messageHandler")
#define ON_HEADERS_COMPLETE_SYMBOL String::NewSymbol("onHeadersComplete")
#define ON_BODY_SYMBOL String::NewSymbol("onBody")
#define ON_MESSAGE_COMPLETE_SYMBOL String::NewSymbol("onMessageComplete")
#define ENCODING_SYMBOL String::NewSymbol("encoding")
#define ON_PATH_SYMBOL String::NewSymbol("onPath")
#define ON_QUERY_STRING_SYMBOL String::NewSymbol("onQueryString")
#define ON_URI_SYMBOL String::NewSymbol("onURI")
#define ON_FRAGMENT_SYMBOL String::NewSymbol("onFragment")
#define ON_HEADER_FIELD_SYMBOL String::NewSymbol("onHeaderField")
#define ON_HEADER_VALUE_SYMBOL String::NewSymbol("onHeaderValue")
#define MESSAGE_HANDLER_SYMBOL String::NewSymbol("messageHandler")
#define ON_MESSAGE_SYMBOL String::NewSymbol("onMessage")
#define ON_PATH_SYMBOL String::NewSymbol("onPath")
#define ON_QUERY_STRING_SYMBOL String::NewSymbol("onQueryString")
#define ON_URI_SYMBOL String::NewSymbol("onURI")
#define ON_FRAGMENT_SYMBOL String::NewSymbol("onFragment")
#define ON_HEADER_FIELD_SYMBOL String::NewSymbol("onHeaderField")
#define ON_HEADER_VALUE_SYMBOL String::NewSymbol("onHeaderValue")
#define ON_HEADERS_COMPLETE_SYMBOL String::NewSymbol("onHeadersComplete")
#define ON_BODY_SYMBOL String::NewSymbol("onBody")
#define ON_MESSAGE_COMPLETE_SYMBOL String::NewSymbol("onMessageComplete")
#define STATUS_CODE_SYMBOL String::NewSymbol("status_code")
#define HTTP_VERSION_SYMBOL String::NewSymbol("http_version")
@ -180,7 +183,7 @@ HTTPConnection::on_headers_complete (http_parser *parser)
int
HTTPConnection::on_body (http_parser *parser, const char *buf, size_t len)
{
if(len == 0) return 0;
assert(len != 0);
HTTPConnection *connection = static_cast<HTTPConnection*> (parser->data);
HandleScope scope;
@ -193,11 +196,24 @@ HTTPConnection::on_body (http_parser *parser, const char *buf, size_t len)
if (on_body_v->IsFunction() == false) return 0;
Handle<Function> on_body = Handle<Function>::Cast(on_body_v);
Handle<Value> argv[1];
/* Look at the value of message_handler.encoding to decide how to
* send the body chunk. This is rather sloppy and unnecesary. FIXME
*/
enum encoding encoding = RAW;
Local<Value> encoding_v = message_handler->Get(ENCODING_SYMBOL);
if (encoding_v->IsString()) {
Local<String> encoding_string = encoding_v->ToString();
char buf[5]; // need enough room for "utf8" or "raw"
encoding_string->WriteAscii(buf, 0, 4);
buf[4] = '\0';
if(strcasecmp(buf, "utf8") == 0)
encoding = UTF8;
}
Handle<Value> argv[1];
// TODO each message should have their encoding.
// don't look at the conneciton for encoding
if(connection->encoding_ == UTF8) {
if(encoding == UTF8) {
// utf8 encoding
Handle<String> chunk = String::New((const char*)buf, len);
argv[0] = chunk;

103
src/http.js

@ -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";

Loading…
Cancel
Save