Added handling of query in url.parse - still not fully compatible though (fix #205)

This commit is contained in:
Gordon Williams 2014-02-05 13:52:21 +00:00
parent 2015b467da
commit 6d5136f325
6 changed files with 101 additions and 23 deletions

View File

@ -10,6 +10,7 @@
Lower USB interrupt priority, remove pesky PriorityGroupConfig that was breaking other IRQ priorities
Until we sort out SPI RX and IRQs, lower default SPI baud rate to stop timeouts
console.log and print output JSON now (part of #206)
Added handling of query in url.parse (fix #205)
1v48 : Fix issue where the size of command history is being reported wrong and so process.memory().free is reported wrong too
We now loop without a seek to position inside the string (much faster if loop is not near the start of a fn) (fix #53)

View File

@ -105,7 +105,7 @@ JsVar *jswrap_http_request(JsVar *options, JsVar *callback) {
if (!checkOnline()) return 0;
bool unlockOptions = false;
if (jsvIsString(options)) {
options = jswrap_url_parse(options);
options = jswrap_url_parse(options, false);
unlockOptions = true;
}
if (!jsvIsObject(options)) {
@ -237,10 +237,11 @@ void jswrap_httpCRq_end(JsVar *parent, JsVar *data) {
/*JSON{ "type":"staticmethod",
"class" : "url", "name" : "parse",
"generate" : "jswrap_url_parse",
"params" : [ [ "urlStr", "JsVar", "A URL to be parsed"] ],
"return" : ["JsVar", "An object containing options for ```http.request``` or ```http.get```"]
"params" : [ [ "urlStr", "JsVar", "A URL to be parsed"],
[ "parseQuery", "bool", "Whether to parse the query string or not (default = false)"] ],
"return" : ["JsVar", ["An object containing options for ```http.request``` or ```http.get```"] ]
}*/
JsVar *jswrap_url_parse(JsVar *url) {
JsVar *jswrap_url_parse(JsVar *url, bool parseQuery) {
if (!jsvIsString(url)) return 0;
JsVar *obj = jsvNewWithFlags(JSV_OBJECT);
if (!obj) return 0; // out of memory
@ -253,16 +254,19 @@ JsVar *jswrap_url_parse(JsVar *url) {
int addrStart = -1;
int portStart = -1;
int pathStart = -1;
int searchStart = -1;
int charIdx = 0;
int portNumber = 0;
while (jsvStringIteratorHasChar(&it)) {
char ch = jsvStringIteratorGetChar(&it);
if (ch == '/') {
slashes++;
if (addrStart>=0)
pathStart = charIdx;
if (colons==1 && slashes==2 && addrStart<0)
pathStart = charIdx;
if (colons==1 && slashes==2 && addrStart<0) {
addrStart = charIdx;
pathStart = -1;
searchStart = -1;
}
}
if (ch == ':') {
colons++;
@ -274,6 +278,10 @@ JsVar *jswrap_url_parse(JsVar *url) {
portNumber = portNumber*10 + (ch-'0');
}
if (ch == '?' && pathStart>=0) {
searchStart = charIdx;
}
jsvStringIteratorNext(&it);
charIdx++;
}
@ -283,23 +291,67 @@ JsVar *jswrap_url_parse(JsVar *url) {
if (pathStart<0) pathStart = charIdx;
int addrEnd = (portStart>=0) ? portStart : pathStart;
// pull out details
JsVar *method = jsvNewFromString("GET");
jsvUnLock(jsvAddNamedChild(obj, method, "method"));
jsvUnLock(method);
JsVar *host = jsvNewFromEmptyString();
jsvAppendStringVar(host, url, addrStart+1, addrEnd-(addrStart+1));
jsvUnLock(jsvAddNamedChild(obj, host, "host"));
jsvUnLock(host);
JsVar *path = jsvNewFromEmptyString();
jsvAppendStringVar(path, url, pathStart, JSVAPPENDSTRINGVAR_MAXLENGTH);
if (jsvGetStringLength(path)==0) jsvAppendString(path, "/");
jsvUnLock(jsvAddNamedChild(obj, path, "path"));
jsvUnLock(path);
jsvUnLock(jsvObjectSetChild(obj, "method", jsvNewFromString("GET")));
jsvUnLock(jsvObjectSetChild(obj, "host", jsvNewFromStringVar(url, addrStart+1, addrEnd-(addrStart+1))));
JsVar *v;
v= jsvNewFromStringVar(url, pathStart, JSVAPPENDSTRINGVAR_MAXLENGTH);
if (jsvGetStringLength(v)==0) jsvAppendString(v, "/");
jsvUnLock(jsvObjectSetChild(obj, "path", v));
v = jsvNewFromStringVar(url, pathStart, (searchStart>=0)?(searchStart-pathStart):JSVAPPENDSTRINGVAR_MAXLENGTH);
if (jsvGetStringLength(v)==0) jsvAppendString(v, "/");
jsvUnLock(jsvObjectSetChild(obj, "pathname", v));
jsvUnLock(jsvObjectSetChild(obj, "search", (searchStart>=0)?jsvNewFromStringVar(url, searchStart, JSVAPPENDSTRINGVAR_MAXLENGTH):jsvNewNull()));
if (portNumber<=0 || portNumber>65535) portNumber=80;
JsVar *port = jsvNewFromInteger(portNumber);
jsvUnLock(jsvAddNamedChild(obj, port, "port"));
jsvUnLock(port);
jsvUnLock(jsvObjectSetChild(obj, "port", jsvNewFromInteger(portNumber)));
JsVar *query = (searchStart>=0)?jsvNewFromStringVar(url, searchStart+1, JSVAPPENDSTRINGVAR_MAXLENGTH):jsvNewNull();
if (parseQuery && !jsvIsNull(query)) {
jsvStringIteratorNew(&it, query, 0);
jsvUnLock(query);
query = jsvNewWithFlags(JSV_OBJECT);
JsVar *key = jsvNewFromEmptyString();
JsVar *val = jsvNewFromEmptyString();
bool hadEquals = false;
while (jsvStringIteratorHasChar(&it)) {
char ch = jsvStringIteratorGetChar(&it);
if (ch=='&') {
if (jsvGetStringLength(key)>0 || jsvGetStringLength(val)>0) {
jsvMakeIntoVariableName(key, val);
jsvAddName(query, key);
jsvUnLock(key);
jsvUnLock(val);
key = jsvNewFromEmptyString();
val = jsvNewFromEmptyString();
hadEquals = false;
}
} else if (!hadEquals && ch=='=') {
hadEquals = true;
} else {
if (hadEquals) jsvAppendCharacter(val, ch);
else jsvAppendCharacter(key, ch);
}
jsvStringIteratorNext(&it);
charIdx++;
}
jsvStringIteratorFree(&it);
if (jsvGetStringLength(key)>0 || jsvGetStringLength(val)>0) {
jsvMakeIntoVariableName(key, val);
jsvAddName(query, key);
}
jsvUnLock(key);
jsvUnLock(val);
}
jsvUnLock(jsvObjectSetChild(obj, "query", query));
return obj;
}

View File

@ -30,4 +30,4 @@ void jswrap_httpCRq_end(JsVar *parent, JsVar *data);
void jswrap_httpCRs_on(JsVar *parent, JsVar *event, JsVar *callback);
JsVar *jswrap_url_parse(JsVar *url);
JsVar *jswrap_url_parse(JsVar *url, bool parseQuery);

View File

@ -934,6 +934,14 @@ void jsvAppendStringVar(JsVar *var, const JsVar *str, int stridx, int maxLength)
jsvUnLock(block);
}
/** Create a new variable from a substring. argument must be a string. stridx = start char or str, maxLength = max number of characters (can be JSVAPPENDSTRINGVAR_MAXLENGTH).
* stridx can be negative to go from end of string */
JsVar *jsvNewFromStringVar(const JsVar *str, int stridx, int maxLength) {
JsVar *var = jsvNewFromEmptyString();
if (var) jsvAppendStringVar(var, str, stridx, maxLength);
return var;
}
/** Append all of str to var. Both must be strings. */
void jsvAppendStringVarComplete(JsVar *var, const JsVar *str) {
jsvAppendStringVar(var, str, 0, JSVAPPENDSTRINGVAR_MAXLENGTH);

View File

@ -141,6 +141,10 @@ JsVar *jsvNewWithFlags(JsVarFlags flags);
JsVar *jsvNewFromString(const char *str); ///< Create a new string
JsVar *jsvNewStringOfLength(unsigned int byteLength); ///< Create a new string of the given length - full of 0s
static inline JsVar *jsvNewFromEmptyString() { return jsvNewWithFlags(JSV_STRING); } ;///< Create a new empty string
static inline JsVar *jsvNewNull() { return jsvNewWithFlags(JSV_NULL); } ;///< Create a new null variable
/** Create a new variable from a substring. argument must be a string. stridx = start char or str, maxLength = max number of characters (can be JSVAPPENDSTRINGVAR_MAXLENGTH).
* stridx can be negative to go from end of string */
JsVar *jsvNewFromStringVar(const JsVar *str, int stridx, int maxLength);
JsVar *jsvNewFromInteger(JsVarInt value);
JsVar *jsvNewFromBool(bool value);
JsVar *jsvNewFromFloat(JsVarFloat value);

13
tests/test_url_parse.js Normal file
View File

@ -0,0 +1,13 @@
result=1;
function test(a,b) {
if (JSON.stringify(a)!=JSON.stringify(b)) {
console.log("FAIL",a,"vs",b);
result = 0;
}
}
test(url.parse("/hello?a=b"), {"method":"GET","host":"","path":"/hello?a=b","pathname":"/hello","search":"?a=b","port":80,"query":"a=b"})
test(url.parse("/hello?a=b&c=dd",false), {"method":"GET","host":"","path":"/hello?a=b&c=dd","pathname":"/hello","search":"?a=b&c=dd","port":80,"query":"a=b&c=dd"})
test(url.parse("/hello?a=b&c=dd",true), {"method":"GET","host":"","path":"/hello?a=b&c=dd","pathname":"/hello","search":"?a=b&c=dd","port":80,"query":{"a":"b","c":"dd"}})