var self = this;
options = options || {};
- if (options.encoding === undefined)
+ if (options.encoding === "utf8") {
+ self.encoding = node.fs.UTF8;
+ } else {
self.encoding = node.fs.RAW;
- else
- self.encoding = options.encoding
+ }
//node.debug("encoding: opts=" + options.encoding + " self=" + self.encoding);
self.fd = options.fd || null;
return a;
}
-node.http.ServerResponse = function (connection, responses) {
- responses.push(this);
- this.connection = connection;
- this.closeOnFinish = false;
- var output = [];
+// 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 be 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.
+//
+// XXX this function is extremely ugly
+function send (output, data, encoding) {
+ if (data.constructor === String)
+ encoding = encoding || "ascii";
+ else
+ encoding = "raw";
+
+ if (output.length == 0) {
+ output.push([data, encoding]);
+ return;
+ }
- // 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 (connection.readyState === "closed" || connection.readyState === "readOnly")
- {
- responses = [];
- return;
- }
+ var li = output.length-1;
+ var last_encoding = output[li][1];
- if (output.length == 0) {
- output.push(data);
+ if (data.constructor === String) {
+ if ( last_encoding === encoding
+ || (last_encoding === "utf8" && encoding === "ascii")
+ )
+ {
+ output[li][0] += data;
return;
}
+ }
- var li = output.length-1;
-
- if (data.constructor == String && output[li].constructor == String) {
- output[li] += data;
- return;
- }
+ if (data.constructor === Array && last_encoding === encoding) {
+ output[li][0] = output[li][0].concat(data);
+ return;
+ }
- if (data.constructor == Array && output[li].constructor == Array) {
- output[li] = output[li].concat(data);
- return;
- }
+ output.push([data, encoding]);
+};
- // 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;
- }
+node.http.ServerResponse = function (connection, responses) {
+ responses.push(this);
+ this.connection = connection;
+ this.closeOnFinish = false;
+ var output = [];
- output.push(data);
- };
var chunked_encoding = false;
header += CRLF;
- send(header);
+ send(output, header);
};
- this.sendBody = function (chunk) {
+ this.sendBody = function (chunk, encoding) {
if (chunked_encoding) {
- send(chunk.length.toString(16));
- send(CRLF);
- send(chunk);
- send(CRLF);
+ send(output, chunk.length.toString(16));
+ send(output, CRLF);
+ send(output, chunk, encoding);
+ send(output, CRLF);
} else {
- send(chunk);
+ send(output, chunk, encoding);
}
this.flush();
};
this.flush = function () {
+ if (connection.readyState === "closed" || connection.readyState === "readOnly")
+ {
+ responses = [];
+ return;
+ }
if (responses.length > 0 && responses[0] === this)
while (output.length > 0) {
var out = output.shift();
- connection.send(out);
+ connection.send(out[0], out[1]);
}
};
this.finished = false;
this.finish = function () {
if (chunked_encoding)
- send("0\r\n\r\n"); // last chunk
+ send(output, "0\r\n\r\n"); // last chunk
this.finished = true;
var output = [header];
- function send (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.sendBody = function (chunk) {
+ this.sendBody = function (chunk, encoding) {
if (chunked_encoding) {
- send(chunk.length.toString(16));
- send(CRLF);
- send(chunk);
- send(CRLF);
+ send(output, chunk.length.toString(16));
+ send(output, CRLF);
+ send(output, chunk, encoding);
+ send(output, CRLF);
} else {
- send(chunk);
+ send(output, chunk, encoding);
}
this.flush();
this.finish = function (responseHandler) {
this.responseHandler = responseHandler;
if (chunked_encoding)
- send("0\r\n\r\n"); // last chunk
+ send(output, "0\r\n\r\n"); // last chunk
this.flush();
};
NODE_SET_PROTOTYPE_METHOD(constructor_template, "connect", Connect);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "send", Send);
- NODE_SET_PROTOTYPE_METHOD(constructor_template, "sendUtf8", SendUtf8);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "close", Close);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "fullClose", FullClose);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "forceClose", ForceClose);
}
Handle<Value>
-Connection::SendUtf8 (const Arguments& args)
-{
- HandleScope scope;
- Connection *connection = NODE_UNWRAP(Connection, args.Holder());
- if (!connection) return Handle<Value>();
-
- if ( connection->ReadyState() != OPEN
- && connection->ReadyState() != WRITE_ONLY
- )
- return ThrowException(String::New("Socket is not open for writing"));
-
- if (!args[0]->IsString())
- return ThrowException(String::New("Must have string argument"));
-
- // utf8 encoding
- Local<String> s = args[0]->ToString();
- size_t length = s->Utf8Length();
- oi_buf *buf = new_buf(length);
- s->WriteUtf8(buf->base, length);
- connection->Send(buf);
-
- return Undefined();
-}
-
-Handle<Value>
Connection::Send (const Arguments& args)
{
HandleScope scope;
// addressed.
if (args[0]->IsString()) {
- // ASCII encoding
+ enum encoding enc = ParseEncoding(args[1]);
Local<String> s = args[0]->ToString();
- size_t length = s->Utf8Length();
- oi_buf *buf = new_buf(length);
- s->WriteAscii(buf->base, 0, length);
+ size_t len = s->Utf8Length();
+ oi_buf *buf = new_buf(len);
+ switch (enc) {
+ case RAW:
+ case ASCII:
+ s->WriteAscii(buf->base, 0, len);
+ break;
+
+ case UTF8:
+ s->WriteUtf8(buf->base, len);
+ break;
+
+ default:
+ assert(0 && "unhandled string encoding");
+ }
connection->Send(buf);
} else if (args[0]->IsArray()) {
- // raw encoding
Handle<Array> array = Handle<Array>::Cast(args[0]);
- size_t length = array->Length();
- oi_buf *buf = new_buf(length);
- for (size_t i = 0; i < length; i++) {
+ size_t len = array->Length();
+ oi_buf *buf = new_buf(len);
+ for (size_t i = 0; i < len; i++) {
Local<Value> int_value = array->Get(Integer::New(i));
buf->base[i] = int_value->IntegerValue();
}
ev_async_start(EV_DEFAULT_UC_ &eio_watcher);
}
+enum encoding
+node::ParseEncoding (Handle<Value> encoding_v)
+{
+ HandleScope scope;
+
+ if (!encoding_v->IsString())
+ return RAW;
+
+ String::Utf8Value encoding(encoding_v->ToString());
+
+ if(strcasecmp(*encoding, "utf8") == 0) {
+ return UTF8;
+ } else if (strcasecmp(*encoding, "ascii") == 0) {
+ return ASCII;
+ } else {
+ return RAW;
+ }
+}
+
int
main (int argc, char *argv[])
{
templ->PrototypeTemplate()->Set(NODE_SYMBOL(name), __callback##_TEM); \
} while(0)
-enum encoding {UTF8, RAW};
+enum encoding {ASCII, UTF8, RAW};
+enum encoding ParseEncoding (v8::Handle<v8::Value> encoding_v);
void fatal_exception (v8::TryCatch &try_catch);
void eio_warmup (void); // call this before creating a new eio event.
}
function loadScript (filename, target, callback) {
- node.fs.cat(filename, node.fs.UTF8, function (status, content) {
+ node.fs.cat(filename, "utf8", function (status, content) {
if (status != 0) {
stderr.puts("Error reading " + filename + ": " + node.fs.strerror(status));
node.exit(1);
margin: 2em 0;
}
-h1 a { color: inherit; }
+h1 code, h2 code, h3 code, h4 code { color: inherit; }
+h1 a, h2 a, h3 a, h4 a { color: inherit; }
pre, code {
<code>on</code>. All methods and members are camel cased. Constructors
always have a capital first letter.
-<p>Node uses strings to represent ASCII or UTF-8 encoded data. For the
-moment, arrays of integers are used to represent raw binary data—this
-representation is rather inefficient. In the future, <a
-href="http://code.google.com/p/v8/issues/detail?id=270">when V8 natively supports binary
-Blob objects</a>, Node will use them.
+<p>
+Node supports 3 byte-string encodings:
+ASCII (<code>"ascii"</code>),
+UTF-8 (<code>"utf8"</code>), and
+raw binary (<code>"raw"</code>).
+It uses strings to represent ASCII and UTF-8 encoded data. For the moment,
+arrays of integers are used to represent raw binary data—this
+representation is rather inefficient. This will change in the future, when <a
+ href="http://code.google.com/p/v8/issues/detail?id=270">V8 supports Blob objects</a>.
<p>The following are global functions:</p>
<dd>Creates a new connection object.
</dd>
+ <dt><code>connection.readyState</code></dt>
+ <dd>Either <code>"closed"</code>, <code>"open"</code>,
+ <code>"readOnly"</code>, or <code>"writeOnly"</code>.
+ </dd>
+
<dt><code>connection.setEncoding(encoding)</code></dt>
<dd>Sets the encoding (either <code>"utf8"</code> or <code>"raw"</code>)
for data that is received.
</dd>
- <dt><code>connection.send(data)</code></dt>
- <dd>sends data on the connection
+ <dt><code>connection.send(data, encoding="ascii")</code></dt>
+ <dd>Sends data on the connection. The data should be eithre an array of
+ integers (for raw binary) or a string (for utf8 or ascii). The second
+ parameter specifies the encoding in the case of a string—it defaults
+ to ASCII because encoding to UTF8 is rather slow.
</dd>
<dt><code>connection.close()</code></dt>
<dd>Half-closes the connection. I.E. sends a FIN packet. It is possible
the server will still send some data.
+ After calling this <code>readyState</code> will be <code>"readOnly"</code>.
</dd>
<dt><code>connection.fullClose()</code></dt>
<dt><code>conneciton.onEOF = function () { };</code></dt>
<dd>Called when the other end of the connection sends a FIN packet.
<code>onReceive</code> will not be called after this.
+ After receiving this <code>readyState</code> will be <code>"writeOnly"</code>.
You should probably just call <code>connection.close()</code> in this
- callback.
+ callback.
<dt><code>conneciton.onDisconnect = function () { };</code></dt>
<dd>Called once the connection is fully disconnected.</dd>
};
</pre>
A chunk of the body is given as the single argument. The transfer-encoding
- has been removed.
+ has been decoded.
<p>The body chunk is either a String in the case of UTF-8 encoding or an
array of numbers in the case of raw encoding. The body encoding is set with
before <code>res.finish()</code> is called.
</dd>
- <dt><code>res.sendBody(chunk)</code></dt>
+ <dt><code>res.sendBody(chunk, encoding="ascii")</code></dt>
<dd>
This method must be called after <code>sendHeader</code> was called. It
sends a chunk of the response body. This method may be called multiple
times to provide successive parts of the body.
+
+ <p>If <code>chunk</code> is a string, the second parameter specifies how
+ to encode it into a byte stream. By default the <code>encoding</code> is
+ <code>"ascii"</code>.
</dd>
<dt><code>res.finish()</code></dt>
whose header has already been sent.
<dl>
- <dt><code>req.sendBody(chunk, encoding)</code></dt>
+ <dt><code>req.sendBody(chunk, encoding="ascii")</code></dt>
<dd> Sends a sucessive peice of the body. By calling this method many times,
the user can stream a request body to a server—in that case it is
suggested to use the <code>["Transfer-Encoding",
<code>"utf8"</code> or <code>"ascii"</code>. By default the body uses ASCII
encoding, as it is faster.
- <p> TODO
-
<dt><code>req.finish(response_handler)</code></dt>
<dd> Finishes sending the request. If any parts of the body are