Skip to content

Instantly share code, notes, and snippets.

@ry
Created May 20, 2010 15:20
Show Gist options
  • Save ry/407686 to your computer and use it in GitHub Desktop.
Save ry/407686 to your computer and use it in GitHub Desktop.
diff --git a/lib/querystring.js b/lib/querystring.js
index df19123..8ab4e56 100644
--- a/lib/querystring.js
+++ b/lib/querystring.js
@@ -1,10 +1,13 @@
// Query String Utilities
+var sys = require('sys');
+
var QueryString = exports;
+var Buffer = require("buffer").Buffer;
+var urlDecode = process.binding('http_parser').urlDecode;
-QueryString.unescape = function (str, decodeSpaces) {
- return decodeURIComponent(decodeSpaces ? str.replace(/\+/g, " ") : str);
-};
+// a safe fast alternative to decodeURIComponent
+QueryString.unescape = urlDecode;
QueryString.escape = function (str) {
return encodeURIComponent(str);
@@ -25,17 +28,17 @@ var stack = [];
* @param name {String} (optional) Name of the current key, for handling children recursively.
* @static
*/
-QueryString.stringify = function (obj, sep, eq, munge, name) {
+QueryString.stringify = QueryString.encode = function (obj, sep, eq, munge, name) {
munge = typeof(munge) == "undefined" ? true : munge;
sep = sep || "&";
eq = eq || "=";
if (isA(obj, null) || isA(obj, undefined) || typeof(obj) === 'function') {
- return name ? encodeURIComponent(name) + eq : '';
+ return name ? QueryString.escape(name) + eq : '';
}
if (isBool(obj)) obj = +obj;
if (isNumber(obj) || isString(obj)) {
- return encodeURIComponent(name) + eq + encodeURIComponent(obj);
+ return QueryString.escape(name) + eq + QueryString.escape(obj);
}
if (isA(obj, [])) {
var s = [];
@@ -71,11 +74,11 @@ QueryString.stringify = function (obj, sep, eq, munge, name) {
return s;
};
-QueryString.parseQuery = QueryString.parse = function (qs, sep, eq) {
+QueryString.parse = QueryString.decode = function (qs, sep, eq) {
return (qs || '')
.split(sep||"&")
.map(pieceParser(eq||"="))
- .reduce(mergeParams);
+ .reduce(mergeParams)
};
// Parse a key=val string.
@@ -87,8 +90,7 @@ QueryString.parseQuery = QueryString.parse = function (qs, sep, eq) {
// return parse(foo[bar], [{bla:"baz"}])
// return parse(foo, {bar:[{bla:"baz"}]})
// return {foo:{bar:[{bla:"baz"}]}}
-var trimmerPattern = /^\s+|\s+$/g,
- slicerPattern = /(.*)\[([^\]]*)\]$/;
+var slicerPattern = /(.*)\[([^\]]*)\]$/;
var pieceParser = function (eq) {
return function parsePiece (key, val) {
if (arguments.length !== 2) {
@@ -96,18 +98,9 @@ var pieceParser = function (eq) {
key = key.split(eq);
return parsePiece(
QueryString.unescape(key.shift(), true),
- QueryString.unescape(key.join(eq), true)
+ ''+QueryString.unescape(key.join(eq), true)
);
}
- key = key.replace(trimmerPattern, '');
- if (isString(val)) {
- val = val.replace(trimmerPattern, '');
- // convert numerals to numbers
- if (!isNaN(val)) {
- var numVal = +val;
- if (val === numVal.toString(10)) val = numVal;
- }
- }
var sliced = slicerPattern.exec(key);
if (!sliced) {
var ret = {};
diff --git a/src/node_http_parser.cc b/src/node_http_parser.cc
index 8171067..17354f7 100644
--- a/src/node_http_parser.cc
+++ b/src/node_http_parser.cc
@@ -298,6 +298,84 @@ class Parser : public ObjectWrap {
};
+static Handle<Value> UrlDecode (const Arguments& args) {
+ HandleScope scope;
+
+ if (!args[0]->IsString()) {
+ return ThrowException(Exception::TypeError(
+ String::New("First arg must be a string")));
+ }
+
+ bool decode_spaces = args[1]->IsTrue();
+
+ String::Utf8Value in_v(args[0]->ToString());
+ size_t l = in_v.length();
+ char* out = strdup(*in_v);
+
+ enum { CHAR, HEX0, HEX1 } state = CHAR;
+
+ int n, m;
+ size_t in_index = 0, out_index = 0;
+ char c;
+ for (; in_index <= l; in_index++) {
+ c = out[in_index];
+ switch (state) {
+ case CHAR:
+ switch (c) {
+ case '%':
+ n = 0;
+ m = 0;
+ state = HEX0;
+ break;
+ case '+':
+ if (decode_spaces) out[in_index] = ' ';
+ // pass thru
+ default:
+ out_index++;
+ break;
+ }
+ break;
+
+ case HEX0:
+ state = HEX1;
+ if ('0' <= c && c <= '9') {
+ n = c - '0';
+ } else if ('a' <= c && c <= 'z') {
+ n = c - 'a';
+ } else if ('A' <= c && c <= 'Z') {
+ n = c - 'A';
+ } else {
+ out_index += 2;
+ state = CHAR;
+ }
+ break;
+
+ case HEX1:
+ state = CHAR;
+ if ('0' <= c && c <= '9') {
+ m = c - '0';
+ } else if ('a' <= c && c <= 'z') {
+ m = c - 'a';
+ } else if ('A' <= c && c <= 'Z') {
+ m = c - 'A';
+ } else {
+ out_index += 3;
+ break;
+ }
+ out[out_index++] = 16*n + m;
+ break;
+ }
+ }
+
+ out[out_index] = '\0';
+
+ Local<String> out_v = String::New(out, out_index-1);
+ delete out;
+
+ return scope.Close(out_v);
+}
+
+
void InitHttpParser(Handle<Object> target) {
HandleScope scope;
@@ -310,6 +388,7 @@ void InitHttpParser(Handle<Object> target) {
NODE_SET_PROTOTYPE_METHOD(t, "reinitialize", Parser::Reinitialize);
target->Set(String::NewSymbol("HTTPParser"), t->GetFunction());
+ NODE_SET_METHOD(target, "urlDecode", UrlDecode);
on_message_begin_sym = NODE_PSYMBOL("onMessageBegin");
on_path_sym = NODE_PSYMBOL("onPath");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment