Created
May 20, 2010 15:20
-
-
Save ry/407686 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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