From 9d2dce25d22f5f4d1605e61ab458234442879b06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Grzegorz=20=C5=81yczba?= Date: Tue, 15 Oct 2013 15:32:37 +0200 Subject: [PATCH 01/22] support for array arguments in query string --- src/node-uriparser.cc | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/src/node-uriparser.cc b/src/node-uriparser.cc index 1dfaaae..7545a81 100644 --- a/src/node-uriparser.cc +++ b/src/node-uriparser.cc @@ -23,11 +23,16 @@ #include #include #include +#include +#include +#include #define THROW_IF_NULL(var) if (var.afterLast == NULL) { \ return v8::ThrowException(v8::Exception::SyntaxError(v8::String::New("Bad string given"))); \ } +#define ENCODED_BRACKETS "%5B%5D" + enum parseOptions { kProtocol = 1, kAuth = 1 << 1, @@ -117,11 +122,12 @@ static v8::Handle parse(const v8::Arguments& args){ if (uri.query.first && opts & kQuery) { THROW_IF_NULL(uri.query) + std::map > paramsMap; char *query = (char *) uri.query.first; const char *amp = "&", *sum = "="; char *queryParamPairPtr, *queryParam, *queryParamKey, *queryParamValue, *queryParamPtr; bool empty = true; - + query[uri.query.afterLast - uri.query.first] = '\0'; queryParam = strtok_r(query, amp, &queryParamPairPtr); @@ -129,14 +135,41 @@ static v8::Handle parse(const v8::Arguments& args){ while (queryParam) { if (*queryParam != *sum) { + bool array = false; + int len; empty = false; queryParamKey = strtok_r(queryParam, sum, &queryParamPtr); + len = strlen(queryParamKey); + if (len > (sizeof(ENCODED_BRACKETS) - 1) && + !strncmp(queryParamKey + len - (sizeof(ENCODED_BRACKETS) - 1), + ENCODED_BRACKETS, + sizeof(ENCODED_BRACKETS) - 1)) { + array = true; + queryParamKey[len - (sizeof(ENCODED_BRACKETS) - 1)] = '\0'; + } queryParamValue = strtok_r(NULL, sum, &queryParamPtr); - queryData->Set(v8::String::New(queryParamKey), v8::String::New(queryParamValue ? queryParamValue : ""), attrib); + v8::Local queryKey = v8::String::New(queryParamKey); + if (!array) { + queryData->Set(queryKey, v8::String::New(queryParamValue ? queryParamValue : ""), attrib); + } else { + paramsMap[queryParamKey].push_back(queryParamValue ? queryParamValue : ""); + } } queryParam = strtok_r(NULL, amp, &queryParamPairPtr); } + for (std::map >::iterator it=paramsMap.begin(); it!=paramsMap.end(); ++it) { + std::list vals = it->second; + v8::Local key = v8::String::New(it->first.c_str()); + v8::Local arrVal = v8::Array::New(vals.size()); + int i = 0; + for (std::list::iterator it2 = vals.begin(); it2 != vals.end(); ++it2) { + arrVal->Set(i, v8::String::New(*it2)); + i++; + } + queryData->Set(key, arrVal); + } + //no need for empty object if the query string is going to be wrong if (!empty) { data->Set(query_symbol, queryData, attrib); From 6556bc2f7e30f7ff3c423f358f9ca71785c3b6a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Grzegorz=20=C5=81yczba?= Date: Tue, 15 Oct 2013 15:32:47 +0200 Subject: [PATCH 02/22] NPM --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 379b627..de682f6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "uriparser", - "version": "1.2.8", + "version": "1.2.9", "description": "Fastest uriparser, written in C", "keywords": ["uriparser", "uri", "parser", "url"], "author": "Jakub Lekstan ", From d8ec3c65f2d76569d712c673d8c3449ccbc88c5f Mon Sep 17 00:00:00 2001 From: Jakub Lekstan Date: Tue, 15 Apr 2014 09:49:15 +0200 Subject: [PATCH 03/22] Changed uriparser repo url --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 3a63130..da2ed8d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "deps/uriparser"] path = deps/uriparser - url = git://uriparser.git.sourceforge.net/gitroot/uriparser/uriparser + url = git://git.code.sf.net/p/uriparser/git From a4f9146c4fb5f71a988695b8d1e1fda1e7663b68 Mon Sep 17 00:00:00 2001 From: Jakub Lekstan Date: Tue, 15 Apr 2014 09:50:45 +0200 Subject: [PATCH 04/22] Bumped npm version, more precise defined node engines --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index de682f6..1ed267a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "uriparser", - "version": "1.2.9", + "version": "1.2.10", "description": "Fastest uriparser, written in C", "keywords": ["uriparser", "uri", "parser", "url"], "author": "Jakub Lekstan ", @@ -14,6 +14,6 @@ "preinstall": "node-waf clean || true; node-waf configure build" }, "engines": { - "node": ">= 0.4.0" + "node": ">= 0.4.0 < 0.8.0" } } From 1fe92e25a959f62d29a5e6379857590f6c8cdcda Mon Sep 17 00:00:00 2001 From: Jakub Lekstan Date: Tue, 15 Apr 2014 10:48:53 +0200 Subject: [PATCH 05/22] Fixed warnings --- src/node-uriparser.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/node-uriparser.cc b/src/node-uriparser.cc index 7545a81..93d8e7b 100644 --- a/src/node-uriparser.cc +++ b/src/node-uriparser.cc @@ -103,7 +103,7 @@ static v8::Handle parse(const v8::Arguments& args){ if (authUser != NULL && authPassword != NULL) { v8::Local authData = v8::Object::New(); - authData->Set(user_symbol, v8::String::New(authUser)), attrib; + authData->Set(user_symbol, v8::String::New(authUser), attrib); authData->Set(password_symbol, v8::String::New(authPassword), attrib); data->Set(auth_symbol, authData, attrib); @@ -136,7 +136,7 @@ static v8::Handle parse(const v8::Arguments& args){ while (queryParam) { if (*queryParam != *sum) { bool array = false; - int len; + size_t len; empty = false; queryParamKey = strtok_r(queryParam, sum, &queryParamPtr); len = strlen(queryParamKey); From 274f5cdc14d9c68479cad0a9f9c8a2935213bb00 Mon Sep 17 00:00:00 2001 From: Jakub Lekstan Date: Tue, 15 Apr 2014 10:56:27 +0200 Subject: [PATCH 06/22] Version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1ed267a..119baff 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "uriparser", - "version": "1.2.10", + "version": "1.2.11", "description": "Fastest uriparser, written in C", "keywords": ["uriparser", "uri", "parser", "url"], "author": "Jakub Lekstan ", From ada0eee0c925d2ca5d32946511a03632fd408e5a Mon Sep 17 00:00:00 2001 From: Marcin Kaciuba Date: Sat, 2 Jan 2016 13:58:27 +0100 Subject: [PATCH 07/22] Added parsers --- examples/benchmark1-NGX.js | 28 +++++ examples/example.js | 27 +++++ src/node-uriparser.cc | 169 ++++++++++++++---------------- src/parser.hpp | 204 +++++++++++++++++++++++++++++++++++++ wscript | 7 +- 5 files changed, 341 insertions(+), 94 deletions(-) create mode 100644 examples/benchmark1-NGX.js create mode 100644 examples/example.js create mode 100644 src/parser.hpp diff --git a/examples/benchmark1-NGX.js b/examples/benchmark1-NGX.js new file mode 100644 index 0000000..20df8af --- /dev/null +++ b/examples/benchmark1-NGX.js @@ -0,0 +1,28 @@ +/* + * Copyright (C) DreamLab Onet.pl Sp. z o. o. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +var uriparser = require('../bin/uriparser'), url = "http://10.177.51.76:1337//example/dir/hi", matches; + +for (var i = 0; i < 2000000; i++) { + matches = uriparser.parse(url, uriparser.kAll, uriparser.eNgxParser); +} + diff --git a/examples/example.js b/examples/example.js new file mode 100644 index 0000000..405b575 --- /dev/null +++ b/examples/example.js @@ -0,0 +1,27 @@ +/* + * Copyright (C) DreamLab Onet.pl Sp. z o. o. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +var uriparser = require('../bin/uriparser'), url = "http://10.177.51.76:1337//example/dir/hi", matches; + +matches = uriparser.parse(url); +console.info(matches); + diff --git a/src/node-uriparser.cc b/src/node-uriparser.cc index 93d8e7b..90eabef 100644 --- a/src/node-uriparser.cc +++ b/src/node-uriparser.cc @@ -26,11 +26,9 @@ #include #include #include +#include "parser.hpp" -#define THROW_IF_NULL(var) if (var.afterLast == NULL) { \ - return v8::ThrowException(v8::Exception::SyntaxError(v8::String::New("Bad string given"))); \ - } - +#define BRACKETS "[]" #define ENCODED_BRACKETS "%5B%5D" enum parseOptions { @@ -44,11 +42,17 @@ enum parseOptions { kAll = kProtocol | kAuth | kHost | kPort | kQuery | kFragment | kPath }; +enum Engines { + eRfcParser = 1, + eNgxParser +}; + static v8::Persistent protocol_symbol = NODE_PSYMBOL("protocol"); static v8::Persistent auth_symbol = NODE_PSYMBOL("auth"); static v8::Persistent host_symbol = NODE_PSYMBOL("host"); static v8::Persistent port_symbol = NODE_PSYMBOL("port"); static v8::Persistent query_symbol = NODE_PSYMBOL("query"); +static v8::Persistent query_arr_suffix = NODE_PSYMBOL("queryArraySuffix"); static v8::Persistent fragment_symbol = NODE_PSYMBOL("fragment"); static v8::Persistent path_symbol = NODE_PSYMBOL("path"); static v8::Persistent user_symbol = NODE_PSYMBOL("user"); @@ -58,6 +62,7 @@ static v8::Handle parse(const v8::Arguments& args){ v8::HandleScope scope; parseOptions opts = kAll; + Engines engine = eRfcParser; if (args.Length() == 0 || !args[0]->IsString()) { return v8::ThrowException(v8::Exception::TypeError(v8::String::New("First argument has to be string"))); @@ -67,38 +72,43 @@ static v8::Handle parse(const v8::Arguments& args){ opts = static_cast(args[1]->Int32Value()); } - v8::String::AsciiValue url (args[0]->ToString()); + v8::String::Utf8Value url(args[0]->ToString()); if (url.length() == 0) { return v8::ThrowException(v8::Exception::TypeError(v8::String::New("String mustn't be empty"))); } - UriParserStateA state; - UriUriA uri; + if (args[2]->IsNumber()) { + engine = static_cast(args[2]->Int32Value()); + } + + v8::PropertyAttribute attrib = (v8::PropertyAttribute) (v8::ReadOnly | v8::DontDelete); + v8::Local data = v8::Object::New(); + + Url uri; + Parser *parser; - state.uri = &uri; + if (engine == eNgxParser) { + parser = new NgxParser(*url); + } else { + parser = new RfcParser(*url); + } - if (uriParseUriA(&state, *url) != URI_SUCCESS) { + if (parser->status != Parser::OK) { return v8::ThrowException(v8::Exception::Error(v8::String::New("Unable to parse given url"))); } - v8::PropertyAttribute attrib = (v8::PropertyAttribute) (v8::ReadOnly | v8::DontDelete); - v8::Local data = v8::Object::New(); + uri = parser->url; - if (uri.scheme.first && opts & kProtocol) { - THROW_IF_NULL(uri.scheme) - // +1 here because we need : after protocol - data->Set(protocol_symbol, v8::String::New(uri.scheme.first, (uri.scheme.afterLast - uri.scheme.first) + 1), attrib); + if (uri.schema && (opts & kProtocol)) { + data->Set(protocol_symbol, v8::String::New(std::strcat(uri.schema, ":")), attrib); } - if (uri.userInfo.first && opts & kAuth) { - THROW_IF_NULL(uri.userInfo) - char *auth = (char *) uri.userInfo.first; - char *authPtr, *authUser, *authPassword; + if (uri.userpass && (opts & kAuth)) { const char *delim = ":"; - auth[uri.userInfo.afterLast - uri.userInfo.first] = '\0'; + char *authPtr, *authUser, *authPassword; - authUser = strtok_r(auth, delim, &authPtr); + authUser = strtok_r(uri.userpass, delim, &authPtr); authPassword = strtok_r(NULL, delim, &authPtr); if (authUser != NULL && authPassword != NULL) { @@ -110,32 +120,30 @@ static v8::Handle parse(const v8::Arguments& args){ } } - if (uri.hostText.first && opts & kHost) { - THROW_IF_NULL(uri.hostText) - data->Set(host_symbol, v8::String::New(uri.hostText.first, uri.hostText.afterLast - uri.hostText.first), attrib); + if (uri.host && (opts & kHost)) { + data->Set(host_symbol, v8::String::New(uri.host), attrib); } - if (uri.portText.first && opts & kPort) { - THROW_IF_NULL(uri.portText) - data->Set(port_symbol, v8::String::New(uri.portText.first, uri.portText.afterLast - uri.portText.first), attrib); + if (uri.port && (opts & kPort)) { + data->Set(port_symbol, v8::String::New(uri.port), attrib); } - if (uri.query.first && opts & kQuery) { - THROW_IF_NULL(uri.query) + if (uri.query && (opts & kQuery)) { std::map > paramsMap; - char *query = (char *) uri.query.first; + std::vector paramsOrder; + char *query = uri.query; const char *amp = "&", *sum = "="; char *queryParamPairPtr, *queryParam, *queryParamKey, *queryParamValue, *queryParamPtr; bool empty = true; + v8::Local qsSuffix = v8::Object::New(); query[uri.query.afterLast - uri.query.first] = '\0'; queryParam = strtok_r(query, amp, &queryParamPairPtr); v8::Local queryData = v8::Object::New(); - + bool arrayBrackets = false; while (queryParam) { if (*queryParam != *sum) { - bool array = false; size_t len; empty = false; queryParamKey = strtok_r(queryParam, sum, &queryParamPtr); @@ -144,28 +152,41 @@ static v8::Handle parse(const v8::Arguments& args){ !strncmp(queryParamKey + len - (sizeof(ENCODED_BRACKETS) - 1), ENCODED_BRACKETS, sizeof(ENCODED_BRACKETS) - 1)) { - array = true; + arrayBrackets = true; queryParamKey[len - (sizeof(ENCODED_BRACKETS) - 1)] = '\0'; + qsSuffix->Set(v8::String::New(queryParamKey), v8::String::New(ENCODED_BRACKETS)); + } else if (len > (sizeof(BRACKETS) - 1) && + !strncmp(queryParamKey + len - (sizeof(BRACKETS) - 1), + BRACKETS, + sizeof(BRACKETS) - 1)) { + arrayBrackets = true; + queryParamKey[len - (sizeof(BRACKETS) - 1)] = '\0'; + qsSuffix->Set(v8::String::New(queryParamKey), v8::String::New(BRACKETS)); } queryParamValue = strtok_r(NULL, sum, &queryParamPtr); - v8::Local queryKey = v8::String::New(queryParamKey); - if (!array) { - queryData->Set(queryKey, v8::String::New(queryParamValue ? queryParamValue : ""), attrib); - } else { - paramsMap[queryParamKey].push_back(queryParamValue ? queryParamValue : ""); + if (paramsMap.find(queryParamKey) == paramsMap.end()) { + paramsOrder.push_back(queryParamKey); } + paramsMap[queryParamKey].push_back(queryParamValue ? queryParamValue : ""); } queryParam = strtok_r(NULL, amp, &queryParamPairPtr); } - for (std::map >::iterator it=paramsMap.begin(); it!=paramsMap.end(); ++it) { - std::list vals = it->second; - v8::Local key = v8::String::New(it->first.c_str()); - v8::Local arrVal = v8::Array::New(vals.size()); - int i = 0; - for (std::list::iterator it2 = vals.begin(); it2 != vals.end(); ++it2) { - arrVal->Set(i, v8::String::New(*it2)); - i++; + for (std::vector::iterator it=paramsOrder.begin(); it!=paramsOrder.end(); ++it) { + v8::Local key = v8::String::New(it->c_str()); + std::list vals = paramsMap[*it]; + int arrSize = vals.size(); + if (arrSize > 1 || qsSuffix->Has(key)) { + v8::Local arrVal = v8::Array::New(arrSize); + + int i = 0; + for (std::list::iterator it2 = vals.begin(); it2 != vals.end(); ++it2) { + arrVal->Set(i, v8::String::New(*it2)); + i++; + } + queryData->Set(key, arrVal); + } else { + queryData->Set(key, v8::String::New((vals.front()))); } queryData->Set(key, arrVal); } @@ -173,63 +194,26 @@ static v8::Handle parse(const v8::Arguments& args){ //no need for empty object if the query string is going to be wrong if (!empty) { data->Set(query_symbol, queryData, attrib); + if (arrayBrackets) { + data->Set(query_arr_suffix, qsSuffix, attrib); + } } //parsing the path will be easier query--; *query = '\0'; } - if (uri.fragment.first && opts & kFragment) { - THROW_IF_NULL(uri.fragment); - data->Set(fragment_symbol, v8::String::New(uri.fragment.first, uri.fragment.afterLast - uri.fragment.first), attrib); + if (uri.fragment && opts & kFragment) { + data->Set(fragment_symbol, v8::String::New(uri.fragment), attrib); } - if (uri.pathHead && uri.pathHead->text.first && opts & kPath) { - int len = 0; - - - UriPathSegmentA *pathHead = uri.pathHead; - do { - THROW_IF_NULL(pathHead->text) - if (pathHead->text.first == pathHead->text.afterLast) { - len++; - } else { - //len +1 because we need to add slash - len += pathHead->text.afterLast - pathHead->text.first + 1; - } - pathHead = pathHead->next; - } while (pathHead); - - char *path, *p, *tmp; - path = p = tmp = (char *) malloc(len + 1); - path[len] = '\0'; - - pathHead = uri.pathHead; - do { - //adding slash no matter what - *path = '/'; - path++; - //copying text only in case when path segment is not empty - if (pathHead->text.first != pathHead->text.afterLast) { - int len = pathHead->text.afterLast - pathHead->text.first; - memcpy(path, pathHead->text.first, len); - path += len; - } - pathHead = pathHead->next; - } while (pathHead); - - //path is always prefixed with / in case of relative url we move pointer further - if (!uri.absolutePath && !uri.hostText.first) { - p++; - } - - data->Set(path_symbol, v8::String::New(p), attrib); - free(tmp); + if (uri.path && (opts & kPath)) { + data->Set(path_symbol, v8::String::New(uri.path), attrib); } else if (opts & kPath) { data->Set(path_symbol, v8::String::New("/"), attrib); } - uriFreeUriMembersA(&uri); + delete parser; return scope.Close(data); } @@ -246,4 +230,7 @@ extern "C" void init (v8::Handle target){ NODE_DEFINE_CONSTANT(target, kFragment); NODE_DEFINE_CONSTANT(target, kPath); NODE_DEFINE_CONSTANT(target, kAll); + + NODE_DEFINE_CONSTANT(target, eNgxParser); + NODE_DEFINE_CONSTANT(target, eRfcParser); } diff --git a/src/parser.hpp b/src/parser.hpp new file mode 100644 index 0000000..e0b79aa --- /dev/null +++ b/src/parser.hpp @@ -0,0 +1,204 @@ +extern "C" { + #include +} +#include + +// base structure for url properties +typedef struct { + char * schema; + char * host; + char * path; + char * query; + char * fragment; + char * port; + char * auth; +} Url; + + +class Parser { + public: + Parser(const char * str): m_str(str) { + url.schema = NULL; + url.host = NULL; + url.path = NULL; + url.query = NULL; + url.fragment = NULL; + url.port = NULL; + url.auth = NULL; + } + + virtual ~Parser() { + } + + enum Status { + ERROR = -1, + OK, + }; + + Status status; + Url url; + protected: + const char * m_str; +}; + +class NgxParser: public Parser { + public: + NgxParser(const char * str): Parser(str), ngx_url() { + if (ngx_url_parser(&ngx_url, str) == NGX_URL_OK) { + status = Parser::OK; + } else { + status = Parser::ERROR; + return; + } + + url.schema = ngx_url.schema; + url.host = ngx_url.host; + url.path = ngx_url.path; + url.query = ngx_url.query; + url.fragment = ngx_url.fragment; + url.port = ngx_url.port; + url.auth = ngx_url.auth; + } + + virtual ~NgxParser() { + ngx_url_free(&ngx_url); + } + + protected: + ngx_http_url ngx_url; +}; + +class RfcParser: public Parser { + public: + RfcParser(const char *str): Parser(str) { + UriParserStateA state; + UriUriA uri; + + state.uri = &uri; + if (uriParseUriA(&state, str) == URI_SUCCESS) { + status = Parser::OK; + } else { + status = Parser::ERROR; + return; + } + + if (uri.scheme.first) { + copyFromMeta(&url.schema, uri.scheme); + } + + if (uri.userInfo.first) { + copyFromMeta(&url.auth, uri.userInfo); + } + + if (uri.hostText.first) { + copyFromMeta(&url.host, uri.hostText); + } + + if (uri.portText.first) { + copyFromMeta(&url.port, uri.portText); + } + + if (uri.query.first) { + copyFromMeta(&url.query, uri.query); + } + + if (uri.fragment.first) { + copyFromMeta(&url.fragment, uri.fragment); + } + + if (uri.pathHead && uri.pathHead->text.first) { + int len = 0; + + UriPathSegmentA *pathHead = uri.pathHead; + do { + if (pathHead->text.first == pathHead->text.afterLast) { + len++; + } else { + //len +1 because we need to add slash + len += pathHead->text.afterLast - pathHead->text.first + 1; + } + pathHead = pathHead->next; + } while (pathHead); + + char *path, *p, *tmp; + path = p = tmp = new char[len + 1]; + path[len] = '\0'; + + pathHead = uri.pathHead; + do { + // adding slash no matter what + *path = '/'; + path++; + // copying text only in case when path segment is not empty + if (pathHead->text.first != pathHead->text.afterLast) { + int localLen = pathHead->text.afterLast - pathHead->text.first; + memcpy(path, pathHead->text.first, localLen); + path += localLen; + } + pathHead = pathHead->next; + } while (pathHead); + + // path is always prefixed with / in case of relative url we move pointer further + if (!uri.absolutePath && !uri.hostText.first) { + p++; + } + + int pathLen = std::strlen(p); + url.path = new char[pathLen]; + std::strcpy(url.path, p); + delete[] tmp; + + } else { + url.path = new char[2]; + url.path[0] = '/'; + url.path[1] = '\0'; + } + + uriFreeUriMembersA(&uri); + } + + virtual ~RfcParser() { + if (url.schema != NULL) { + delete[] url.schema; + url.schema = NULL; + } + + if (url.host != NULL) { + delete[] url.host; + url.host = NULL; + } + + if (url.path != NULL) { + delete url.path; + url.path = NULL; + } + + if (url.query != NULL) { + delete[] url.query; + url.query= NULL; + } + + if (url.fragment != NULL) { + delete[] url.fragment; + url.fragment = NULL; + } + + if (url.port != NULL) { + delete[] url.port; + url.port = NULL; + } + + if (url.auth != NULL) { + delete[] url.auth; + url.auth = NULL; + } + } + + private: + void copyFromMeta(char ** dest, UriTextRangeStructA &src) { + uint32_t len = src.afterLast - src.first + 1; + *dest = new char[len]; + std::memcpy(*dest, src.first, len - 1); + (*dest)[len - 1] = '\0'; + } +}; diff --git a/wscript b/wscript index 030bf14..e97385c 100644 --- a/wscript +++ b/wscript @@ -24,12 +24,13 @@ def do_clean(): def build(bld): if Options.options.buildUri == True and do_clean() == False: bld.exec_command("mkdir -p uriparser; cd ../deps/uriparser && ./autogen.sh && ./configure --with-pic --disable-test --disable-doc --disable-shared --prefix=%s && make clean install" % (bld.bdir + "/uriparser")) + bld.exec_command("cd ../deps/ngx_url_parser && make static-lib") obj = bld.new_task_gen("cxx", "shlib", "node_addon") obj.target = "uriparser" obj.source = "src/node-uriparser.cc" - obj.lib = ["uriparser"] - obj.includes = [bld.bdir + "/uriparser/include/uriparser"] - obj.libpath = [bld.bdir + "/uriparser/lib"] + obj.lib = ["uriparser", "ngx_url_parser"] + obj.includes = [bld.bdir + "/uriparser/include/uriparser", "deps/ngx_url_parser/"] + obj.libpath = [bld.bdir + "/uriparser/lib", 'deps/ngx_url_parser/lib/'] obj.cxxflags = ["-g"] obj.cflags = ["-g"] From 943425e0e37afa31797c0e68bac5f999067a9e89 Mon Sep 17 00:00:00 2001 From: Marcin Kaciuba Date: Mon, 4 Jan 2016 18:59:21 +0100 Subject: [PATCH 08/22] Fixed wscript, added tests --- .gitmodules | 3 + deps/ngx_url_parser | 1 + src/node-uriparser.cc | 7 +- src/parser.hpp | 2 + tests/parseSpec.js | 229 +++++++++++++++++++++++++++--------------- wscript | 4 +- 6 files changed, 159 insertions(+), 87 deletions(-) create mode 160000 deps/ngx_url_parser diff --git a/.gitmodules b/.gitmodules index da2ed8d..35d3794 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "deps/uriparser"] path = deps/uriparser url = git://git.code.sf.net/p/uriparser/git +[submodule "deps/ngx_url_parser"] + path = deps/ngx_url_parser + url = https://github.com/Aldor007/ngx_url_parser diff --git a/deps/ngx_url_parser b/deps/ngx_url_parser new file mode 160000 index 0000000..2ab2ed1 --- /dev/null +++ b/deps/ngx_url_parser @@ -0,0 +1 @@ +Subproject commit 2ab2ed11a57fa901745301df6d9fe4cda4a1931d diff --git a/src/node-uriparser.cc b/src/node-uriparser.cc index 90eabef..e84336a 100644 --- a/src/node-uriparser.cc +++ b/src/node-uriparser.cc @@ -26,6 +26,7 @@ #include #include #include +#include #include "parser.hpp" #define BRACKETS "[]" @@ -104,11 +105,11 @@ static v8::Handle parse(const v8::Arguments& args){ data->Set(protocol_symbol, v8::String::New(std::strcat(uri.schema, ":")), attrib); } - if (uri.userpass && (opts & kAuth)) { + if (uri.auth && (opts & kAuth)) { const char *delim = ":"; char *authPtr, *authUser, *authPassword; - authUser = strtok_r(uri.userpass, delim, &authPtr); + authUser = strtok_r(uri.auth, delim, &authPtr); authPassword = strtok_r(NULL, delim, &authPtr); if (authUser != NULL && authPassword != NULL) { @@ -137,7 +138,6 @@ static v8::Handle parse(const v8::Arguments& args){ bool empty = true; v8::Local qsSuffix = v8::Object::New(); - query[uri.query.afterLast - uri.query.first] = '\0'; queryParam = strtok_r(query, amp, &queryParamPairPtr); v8::Local queryData = v8::Object::New(); @@ -188,7 +188,6 @@ static v8::Handle parse(const v8::Arguments& args){ } else { queryData->Set(key, v8::String::New((vals.front()))); } - queryData->Set(key, arrVal); } //no need for empty object if the query string is going to be wrong diff --git a/src/parser.hpp b/src/parser.hpp index e0b79aa..507dbf4 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -1,6 +1,8 @@ extern "C" { #include } + +#include #include // base structure for url properties diff --git a/tests/parseSpec.js b/tests/parseSpec.js index 3edd8a9..a7e2270 100644 --- a/tests/parseSpec.js +++ b/tests/parseSpec.js @@ -2,7 +2,7 @@ * Copyright (C) DreamLab Onet.pl Sp. z o. o. * * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal + * of this software and associated documentation files (the 'Software'), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is @@ -11,7 +11,7 @@ * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER @@ -19,142 +19,209 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -var uriparser = require("../lib/bindings.js"); +var uriparser = require('../lib/bindings.js'); - -describe("uriparser - parse", function () { - it("http://dreamlab.pl", function () { - var url = uriparser.parse("http://dreamlab.pl"); +describe('uriparser - parse', function () { + it('http://dreamlab.pl', function () { + var url = uriparser.parse('http://dreamlab.pl'); expect(Object.keys(url).length).toEqual(3); - expect(url.protocol).toEqual("http:"); - expect(url.host).toEqual("dreamlab.pl"); - expect(url.path).toEqual("/"); + expect(url.protocol).toEqual('http:'); + expect(url.host).toEqual('dreamlab.pl'); + expect(url.path).toEqual('/'); }); - it("http://dreamlab.pl/", function () { - var url = uriparser.parse("http://dreamlab.pl/"); + it('http://dreamlab.pl/', function () { + var url = uriparser.parse('http://dreamlab.pl/'); expect(Object.keys(url).length).toEqual(3); - expect(url.protocol).toEqual("http:"); - expect(url.host).toEqual("dreamlab.pl"); - expect(url.path).toEqual("/"); + expect(url.protocol).toEqual('http:'); + expect(url.host).toEqual('dreamlab.pl'); + expect(url.path).toEqual('/'); }); - it("/1.txt?test1=okok", function () { - var url = uriparser.parse("/1.txt?test1=okok"); + it('1.txt?test1=okok', function () { + var url = uriparser.parse('1.txt?test1=okok'); expect(Object.keys(url).length).toEqual(2); - expect(url.path).toEqual("/1.txt"); - expect(url.query).toEqual({"test1": "okok"}); + expect(url.path).toEqual('1.txt'); + expect(url.query).toEqual({'test1': 'okok'}); }); - it("1.txt?test1=okok", function () { - var url = uriparser.parse("1.txt?test1=okok"); + it('/1.txt?test1=okok', function () { + var url = uriparser.parse('/1.txt?test1=okok'); expect(Object.keys(url).length).toEqual(2); - expect(url.path).toEqual("1.txt"); - expect(url.query).toEqual({"test1": "okok"}); + expect(url.path).toEqual('/1.txt'); + expect(url.query).toEqual({'test1': 'okok'}); }); - it("http://dreamlab.pl/X?X", function () { - var url = uriparser.parse("http://dreamlab.pl/X?X"); + it('http://dreamlab.pl/X?X', function () { + var url = uriparser.parse('http://dreamlab.pl/X?X'); expect(Object.keys(url).length).toEqual(4); - expect(url.protocol).toEqual("http:"); - expect(url.host).toEqual("dreamlab.pl"); - expect(url.path).toEqual("/X"); - expect(url.query).toEqual({"X": ""}); + expect(url.protocol).toEqual('http:'); + expect(url.host).toEqual('dreamlab.pl'); + expect(url.path).toEqual('/X'); + expect(url.query).toEqual({'X': ""}); }); - it("http://dreamlab.pl/X", function () { - var url = uriparser.parse("http://dreamlab.pl/X"); + it('http://dreamlab.pl/X', function () { + var url = uriparser.parse('http://dreamlab.pl/X'); expect(Object.keys(url).length).toEqual(3); - expect(url.protocol).toEqual("http:"); - expect(url.host).toEqual("dreamlab.pl"); - expect(url.path).toEqual("/X"); + expect(url.protocol).toEqual('http:'); + expect(url.host).toEqual('dreamlab.pl'); + expect(url.path).toEqual('/X'); }); - it("http://dreamlab.pl/hejka/", function () { - var url = uriparser.parse("http://dreamlab.pl/hejka/"); + it('http://dreamlab.pl/hejka/', function () { + var url = uriparser.parse('http://dreamlab.pl/hejka/'); expect(Object.keys(url).length).toEqual(3); - expect(url.protocol).toEqual("http:"); - expect(url.host).toEqual("dreamlab.pl"); - expect(url.path).toEqual("/hejka/"); + expect(url.protocol).toEqual('http:'); + expect(url.host).toEqual('dreamlab.pl'); + expect(url.path).toEqual('/hejka/'); }); - it("http://dreamlab.pl/hejka/?hejka=123", function () { - var url = uriparser.parse("http://dreamlab.pl/hejka/?hejka=123"); + it('http://dreamlab.pl/hejka/?hejka=123', function () { + var url = uriparser.parse('http://dreamlab.pl/hejka/?hejka=123'); expect(Object.keys(url).length).toEqual(4); - expect(url.protocol).toEqual("http:"); - expect(url.host).toEqual("dreamlab.pl"); - expect(url.path).toEqual("/hejka/"); - expect(url.query).toEqual({"hejka": "123"}) + expect(url.protocol).toEqual('http:'); + expect(url.host).toEqual('dreamlab.pl'); + expect(url.path).toEqual('/hejka/'); + expect(url.query).toEqual({'hejka': "123"}) }); - it("http://:@www.dreamlab.pl/?", function () { - var url = uriparser.parse("http://:@www.dreamlab.pl/?"); + it('http://:@www.dreamlab.pl/?', function () { + var url = uriparser.parse('http://:@www.dreamlab.pl/?'); expect(Object.keys(url).length).toEqual(3); - expect(url.protocol).toEqual("http:"); - expect(url.host).toEqual("www.dreamlab.pl"); - expect(url.path).toEqual("/"); + expect(url.protocol).toEqual('http:'); + expect(url.host).toEqual('www.dreamlab.pl'); + expect(url.path).toEqual('/'); }); - it("http://user:@www.dreamlab.pl/?", function () { - var url = uriparser.parse("http://user:@www.dreamlab.pl/?"); + it('http://user:@www.dreamlab.pl/?', function () { + var url = uriparser.parse('http://user:@www.dreamlab.pl/?'); expect(Object.keys(url).length).toEqual(3); - expect(url.protocol).toEqual("http:"); - expect(url.host).toEqual("www.dreamlab.pl"); - expect(url.path).toEqual("/"); + expect(url.protocol).toEqual('http:'); + expect(url.host).toEqual('www.dreamlab.pl'); + expect(url.path).toEqual('/'); }); - it("http://:pw@www.dreamlab.pl/?", function () { - var url = uriparser.parse("http://:pw@www.dreamlab.pl/?"); + it('http://:pw@www.dreamlab.pl/?', function () { + var url = uriparser.parse('http://:pw@www.dreamlab.pl/?'); expect(Object.keys(url).length).toEqual(3); - expect(url.protocol).toEqual("http:"); - expect(url.host).toEqual("www.dreamlab.pl"); - expect(url.path).toEqual("/"); + expect(url.protocol).toEqual('http:'); + expect(url.host).toEqual('www.dreamlab.pl'); + expect(url.path).toEqual('/'); }); - it("http://user:pw@www.dreamlab.pl/?", function () { - var url = uriparser.parse("http://user:pw@www.dreamlab.pl/?"); + it('http://user:pw@www.dreamlab.pl/?', function () { + var url = uriparser.parse('http://user:pw@www.dreamlab.pl/?'); expect(Object.keys(url).length).toEqual(4); - expect(url.protocol).toEqual("http:"); - expect(url.auth).toEqual({"user": "user", "password": "pw"}); - expect(url.host).toEqual("www.dreamlab.pl"); - expect(url.path).toEqual("/"); + expect(url.protocol).toEqual('http:'); + expect(url.auth).toEqual({'user': "user", "password": "pw"}); + expect(url.host).toEqual('www.dreamlab.pl'); + expect(url.path).toEqual('/'); }); - it("http://www.dreamlab.pl/?=&=", function () { - var url = uriparser.parse("http://www.dreamlab.pl/?=&="); + it('http://www.dreamlab.pl/?=&=', function () { + var url = uriparser.parse('http://www.dreamlab.pl/?=&='); expect(Object.keys(url).length).toEqual(3); - expect(url.protocol).toEqual("http:"); - expect(url.host).toEqual("www.dreamlab.pl"); - expect(url.path).toEqual("/"); + expect(url.protocol).toEqual('http:'); + expect(url.host).toEqual('www.dreamlab.pl'); + expect(url.path).toEqual('/'); }); - it("http://www.dreamlab.pl//test/123", function () { - var url = uriparser.parse("http://www.dreamlab.pl//test/123"); + it('http://www.dreamlab.pl//test/123', function () { + var url = uriparser.parse('http://www.dreamlab.pl//test/123'); expect(Object.keys(url).length).toEqual(3); - expect(url.protocol).toEqual("http:"); - expect(url.host).toEqual("www.dreamlab.pl"); - expect(url.path).toEqual("//test/123"); + expect(url.protocol).toEqual('http:'); + expect(url.host).toEqual('www.dreamlab.pl'); + expect(url.path).toEqual('//test/123'); }); - it("http://www.dreamlab.pl/test//123", function () { - var url = uriparser.parse("http://www.dreamlab.pl/test//123"); + it('http://www.dreamlab.pl/test//123', function () { + var url = uriparser.parse('http://www.dreamlab.pl/test//123'); expect(Object.keys(url).length).toEqual(3); - expect(url.protocol).toEqual("http:"); - expect(url.host).toEqual("www.dreamlab.pl"); - expect(url.path).toEqual("/test//123"); + expect(url.protocol).toEqual('http:'); + expect(url.host).toEqual('www.dreamlab.pl'); + expect(url.path).toEqual('/test//123'); + }); + + it('http://www.dreamlab.pl/test/?a=1&b=1&a=2&c=3', function () { + var url = uriparser.parse('http://www.dreamlab.pl/test/?a=1&b=4&a=2&c=3'); + + expect(Object.keys(url).length).toEqual(4); + expect(url.protocol).toEqual('http:'); + expect(url.host).toEqual('www.dreamlab.pl'); + expect(url.query).toEqual({a: ['1', '2'], b: '4', c: '3'}); + }); + + it('http://www.dreamlab.pl/test/?b=1&c=3&a%5B%5D=1&a%5B%5D=1', function () { + var url = uriparser.parse('http://www.dreamlab.pl/test/?b=1&c=3&a%5B%5D=1&a%5B%5D=2'); + + expect(Object.keys(url).length).toEqual(5); + expect(url.protocol).toEqual('http:'); + expect(url.host).toEqual('www.dreamlab.pl'); + expect(url.query).toEqual({b: '1', c: '3', a: ['1', '2']}); + expect(url.queryArraySuffix).toEqual({a: '%5B%5D'}); }); + + + it('http://www.dreamlab.pl/test/test1/a[]=1&a[]=2', function () { + var url = uriparser.parse('http://www.dreamlab.pl/test/test1/?a[]=1&a[]=2', null, uriparser.eNgxParser); + + expect(Object.keys(url).length).toEqual(5); + expect(url.protocol).toEqual('http:'); + expect(url.host).toEqual('www.dreamlab.pl'); + expect(url.path).toEqual('/test/test1/'); + expect(url.query).toEqual({a: ['1', '2']}); + expect(url.queryArraySuffix).toEqual({a: '[]'}); + }); + + it('http://www.dreamlab.pl/test/test1/?b=3&a=1&a=2', function () { + var url = uriparser.parse('http://www.dreamlab.pl/test/test1/?b=3&a=1&a=2', null, uriparser.eNgxParser); + + expect(Object.keys(url).length).toEqual(4); + expect(url.protocol).toEqual('http:'); + expect(url.host).toEqual('www.dreamlab.pl'); + expect(url.path).toEqual('/test/test1/'); + expect(url.query).toEqual({b:'3', a: ['1', '2']}); + }); + + it('http://dreamlab.pl:/', function () { + var url = uriparser.parse('http://www.dreamlab.pl:/', null, uriparser.eNgxParser); + + expect(Object.keys(url).length).toEqual(4); + expect(url.protocol).toEqual('http:'); + expect(url.host).toEqual('www.dreamlab.pl'); + expect(url.port).toEqual(''); + }); + + it('http://dreamlab.pl:', function () { + var url = uriparser.parse('http://www.dreamlab.pl:', null, uriparser.eNgxParser); + + expect(Object.keys(url).length).toEqual(4); + expect(url.protocol).toEqual('http:'); + expect(url.host).toEqual('www.dreamlab.pl'); + expect(url.port).toEqual(''); + }); + + it('http:////', function () { + var url = uriparser.parse('http:////', null, uriparser.eNgxParser); + + expect(Object.keys(url).length).toEqual(2); + expect(url.protocol).toEqual('http:'); + expect(url.path).toEqual('//'); + }); + }); diff --git a/wscript b/wscript index e97385c..6ad5a09 100644 --- a/wscript +++ b/wscript @@ -18,7 +18,7 @@ def do_clean(): for arg in sys.argv: if arg == 'clean': return True - + return False def build(bld): @@ -31,6 +31,6 @@ def build(bld): obj.source = "src/node-uriparser.cc" obj.lib = ["uriparser", "ngx_url_parser"] obj.includes = [bld.bdir + "/uriparser/include/uriparser", "deps/ngx_url_parser/"] - obj.libpath = [bld.bdir + "/uriparser/lib", 'deps/ngx_url_parser/lib/'] + obj.libpath = [bld.bdir + "/uriparser/lib", '../deps/ngx_url_parser/lib'] obj.cxxflags = ["-g"] obj.cflags = ["-g"] From 2173865fcbee870b41bc406209231f39b2662050 Mon Sep 17 00:00:00 2001 From: Marcin Kaciuba Date: Mon, 4 Jan 2016 20:16:39 +0100 Subject: [PATCH 09/22] Updated ngx_url_parser --- deps/ngx_url_parser | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/ngx_url_parser b/deps/ngx_url_parser index 2ab2ed1..c5764a9 160000 --- a/deps/ngx_url_parser +++ b/deps/ngx_url_parser @@ -1 +1 @@ -Subproject commit 2ab2ed11a57fa901745301df6d9fe4cda4a1931d +Subproject commit c5764a957ac9108996a370a20661c3924d578d03 From fb1558910ff7bb3906c47cf966520f12fb31d486 Mon Sep 17 00:00:00 2001 From: Marcin Kaciuba Date: Tue, 12 Jan 2016 12:09:47 +0100 Subject: [PATCH 10/22] Update to new ngx_url_parser --- .gitmodules | 2 +- deps/ngx_url_parser | 2 +- examples/benchmark1-NGX.js | 4 +- package.json | 2 +- src/node-uriparser.cc | 89 +++++++++++++++++++++++++------------- tests/parseSpec.js | 43 ++++++++++++++---- wscript | 9 ++-- 7 files changed, 103 insertions(+), 48 deletions(-) diff --git a/.gitmodules b/.gitmodules index 35d3794..94e50e5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -3,4 +3,4 @@ url = git://git.code.sf.net/p/uriparser/git [submodule "deps/ngx_url_parser"] path = deps/ngx_url_parser - url = https://github.com/Aldor007/ngx_url_parser + url = https://github.com/DreamLab/ngx_url_parser diff --git a/deps/ngx_url_parser b/deps/ngx_url_parser index c5764a9..2d22184 160000 --- a/deps/ngx_url_parser +++ b/deps/ngx_url_parser @@ -1 +1 @@ -Subproject commit c5764a957ac9108996a370a20661c3924d578d03 +Subproject commit 2d221846f989273542b3d1e432f17e84f14f15f2 diff --git a/examples/benchmark1-NGX.js b/examples/benchmark1-NGX.js index 20df8af..242d126 100644 --- a/examples/benchmark1-NGX.js +++ b/examples/benchmark1-NGX.js @@ -20,9 +20,9 @@ * THE SOFTWARE. */ -var uriparser = require('../bin/uriparser'), url = "http://10.177.51.76:1337//example/dir/hi", matches; +var uriparser = require('../build/default/uriparser'), url = "http://10.177.51.76:1337//example/dir/hi", matches; for (var i = 0; i < 2000000; i++) { - matches = uriparser.parse(url, uriparser.kAll, uriparser.eNgxParser); + matches = uriparser.parse(url, uriparser.Uri.PROTOCOL, uriparser.Engines.NGINX); } diff --git a/package.json b/package.json index 119baff..e42a464 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "uriparser", - "version": "1.2.11", + "version": "1.2.12", "description": "Fastest uriparser, written in C", "keywords": ["uriparser", "uri", "parser", "url"], "author": "Jakub Lekstan ", diff --git a/src/node-uriparser.cc b/src/node-uriparser.cc index e84336a..47be96a 100644 --- a/src/node-uriparser.cc +++ b/src/node-uriparser.cc @@ -22,15 +22,16 @@ #include #include -#include #include #include #include +#include #include -#include "parser.hpp" -#define BRACKETS "[]" +#include "parsers.hpp" + #define ENCODED_BRACKETS "%5B%5D" +#define BRACKETS "[]" enum parseOptions { kProtocol = 1, @@ -44,7 +45,7 @@ enum parseOptions { }; enum Engines { - eRfcParser = 1, + eUriParser = 1, eNgxParser }; @@ -61,9 +62,8 @@ static v8::Persistent password_symbol = NODE_PSYMBOL("password"); static v8::Handle parse(const v8::Arguments& args){ v8::HandleScope scope; - parseOptions opts = kAll; - Engines engine = eRfcParser; + Engines engine = eUriParser; if (args.Length() == 0 || !args[0]->IsString()) { return v8::ThrowException(v8::Exception::TypeError(v8::String::New("First argument has to be string"))); @@ -92,24 +92,27 @@ static v8::Handle parse(const v8::Arguments& args){ if (engine == eNgxParser) { parser = new NgxParser(*url); } else { - parser = new RfcParser(*url); + parser = new UriParser(*url); } if (parser->status != Parser::OK) { return v8::ThrowException(v8::Exception::Error(v8::String::New("Unable to parse given url"))); } - uri = parser->url; - if (uri.schema && (opts & kProtocol)) { - data->Set(protocol_symbol, v8::String::New(std::strcat(uri.schema, ":")), attrib); + if (uri.scheme.start && (opts & kProtocol)) { + // +1 becasue we need ":" in scheme/protocol + data->Set(protocol_symbol, v8::String::New(uri.scheme.start, uri.scheme.len + 1), attrib); } - if (uri.auth && (opts & kAuth)) { + if (uri.auth.start && (opts & kAuth)) { const char *delim = ":"; char *authPtr, *authUser, *authPassword; - authUser = strtok_r(uri.auth, delim, &authPtr); + char * auth = new char[uri.auth.len + 1]; + std::strncpy(auth, uri.auth.start, uri.auth.len); + + authUser = strtok_r(auth, delim, &authPtr); authPassword = strtok_r(NULL, delim, &authPtr); if (authUser != NULL && authPassword != NULL) { @@ -119,20 +122,25 @@ static v8::Handle parse(const v8::Arguments& args){ data->Set(auth_symbol, authData, attrib); } + + delete[] auth; } - if (uri.host && (opts & kHost)) { - data->Set(host_symbol, v8::String::New(uri.host), attrib); + if (uri.host.start && (opts & kHost)) { + data->Set(host_symbol, v8::String::New(uri.host.start, uri.host.len), attrib); } - if (uri.port && (opts & kPort)) { - data->Set(port_symbol, v8::String::New(uri.port), attrib); + if (uri.port.start && (opts & kPort)) { + data->Set(port_symbol, v8::String::New(uri.port.start, uri.port.len), attrib); } - if (uri.query && (opts & kQuery)) { + if (uri.query.start && (opts & kQuery)) { std::map > paramsMap; std::vector paramsOrder; - char *query = uri.query; + char *query = new char[uri.query.len + 1]; + std::strncpy(query, uri.query.start, uri.query.len); + query[uri.query.len] = '\0'; + const char *amp = "&", *sum = "="; char *queryParamPairPtr, *queryParam, *queryParamKey, *queryParamValue, *queryParamPtr; bool empty = true; @@ -163,6 +171,7 @@ static v8::Handle parse(const v8::Arguments& args){ queryParamKey[len - (sizeof(BRACKETS) - 1)] = '\0'; qsSuffix->Set(v8::String::New(queryParamKey), v8::String::New(BRACKETS)); } + queryParamValue = strtok_r(NULL, sum, &queryParamPtr); if (paramsMap.find(queryParamKey) == paramsMap.end()) { paramsOrder.push_back(queryParamKey); @@ -186,7 +195,7 @@ static v8::Handle parse(const v8::Arguments& args){ } queryData->Set(key, arrVal); } else { - queryData->Set(key, v8::String::New((vals.front()))); + queryData->Set(key, v8::String::New(vals.front())); } } @@ -197,19 +206,20 @@ static v8::Handle parse(const v8::Arguments& args){ data->Set(query_arr_suffix, qsSuffix, attrib); } } - //parsing the path will be easier - query--; - *query = '\0'; + + delete[] query; } - if (uri.fragment && opts & kFragment) { - data->Set(fragment_symbol, v8::String::New(uri.fragment), attrib); + if (uri.fragment.start && (opts & kFragment)) { + data->Set(fragment_symbol, v8::String::New(uri.fragment.start, uri.fragment.len), attrib); } - if (uri.path && (opts & kPath)) { - data->Set(path_symbol, v8::String::New(uri.path), attrib); - } else if (opts & kPath) { - data->Set(path_symbol, v8::String::New("/"), attrib); + if (opts & kPath) { + if (uri.path.start) { + data->Set(path_symbol, v8::String::New(uri.path.start, uri.path.len), attrib); + } else { + data->Set(path_symbol, v8::String::New("/"), attrib); + } } delete parser; @@ -217,10 +227,12 @@ static v8::Handle parse(const v8::Arguments& args){ return scope.Close(data); } + extern "C" void init (v8::Handle target){ - v8::HandleScope scope; NODE_SET_METHOD(target, "parse", parse); + + // Old properties NODE_DEFINE_CONSTANT(target, kProtocol); NODE_DEFINE_CONSTANT(target, kAuth); NODE_DEFINE_CONSTANT(target, kHost); @@ -230,6 +242,21 @@ extern "C" void init (v8::Handle target){ NODE_DEFINE_CONSTANT(target, kPath); NODE_DEFINE_CONSTANT(target, kAll); - NODE_DEFINE_CONSTANT(target, eNgxParser); - NODE_DEFINE_CONSTANT(target, eRfcParser); + v8::Handle uri = v8::Object::New(); + uri->Set(v8::String::New("PROTOCOL"), v8::Integer::New(kProtocol)); + uri->Set(v8::String::New("AUTH"), v8::Integer::New(kAuth)); + uri->Set(v8::String::New("HOST"), v8::Integer::New(kHost)); + uri->Set(v8::String::New("PORT"), v8::Integer::New(kPort)); + uri->Set(v8::String::New("QUERY"), v8::Integer::New(kQuery)); + uri->Set(v8::String::New("FRAGMENT"), v8::Integer::New(kFragment)); + uri->Set(v8::String::New("ALL"), v8::Integer::New(kAll)); + target->Set(v8::String::New("Uri"), uri); + + v8::Handle engines = v8::Object::New(); + engines->Set(v8::String::New("URIPARSER"), v8::Integer::New(eUriParser)); + engines->Set(v8::String::New("NGINX"), v8::Integer::New(eNgxParser)); + target->Set(v8::String::New("Engines"), engines); + } + +NODE_MODULE(uriparser, init) diff --git a/tests/parseSpec.js b/tests/parseSpec.js index a7e2270..7948b27 100644 --- a/tests/parseSpec.js +++ b/tests/parseSpec.js @@ -176,9 +176,8 @@ describe('uriparser - parse', function () { expect(url.queryArraySuffix).toEqual({a: '%5B%5D'}); }); - it('http://www.dreamlab.pl/test/test1/a[]=1&a[]=2', function () { - var url = uriparser.parse('http://www.dreamlab.pl/test/test1/?a[]=1&a[]=2', null, uriparser.eNgxParser); + var url = uriparser.parse('http://www.dreamlab.pl/test/test1/?a[]=1&a[]=2', null, uriparser.Engines.NGINX); expect(Object.keys(url).length).toEqual(5); expect(url.protocol).toEqual('http:'); @@ -188,8 +187,30 @@ describe('uriparser - parse', function () { expect(url.queryArraySuffix).toEqual({a: '[]'}); }); + it('http://www.dreamlab.pl/test/test1/a[name]=1&a[name]=2', function () { + var url = uriparser.parse('http://www.dreamlab.pl/test/test1/?a[name]=1&a[name]=2', null, uriparser.Engines.NGINX); + + expect(Object.keys(url).length).toEqual(4); + expect(url.protocol).toEqual('http:'); + expect(url.host).toEqual('www.dreamlab.pl'); + expect(url.path).toEqual('/test/test1/'); + expect(url.query).toEqual({'a[name]': ['1', '2']}); + }); + + it('http://user:pw@www.dreamlab.pl/test/test1/a[name]=1&a[name]=2#fragment', function () { + var url = uriparser.parse('http://user:pw@www.dreamlab.pl/test/test1/?a[name]=1&a[name]=2#fragment', null, uriparser.Engines.NGINX); + + expect(Object.keys(url).length).toEqual(6); + expect(url.protocol).toEqual('http:'); + expect(url.host).toEqual('www.dreamlab.pl'); + expect(url.path).toEqual('/test/test1/'); + expect(url.query).toEqual({'a[name]': ['1', '2']}); + expect(url.auth).toEqual({'user': 'user', 'password': 'pw'}); + expect(url.fragment).toEqual('fragment'); + }); + it('http://www.dreamlab.pl/test/test1/?b=3&a=1&a=2', function () { - var url = uriparser.parse('http://www.dreamlab.pl/test/test1/?b=3&a=1&a=2', null, uriparser.eNgxParser); + var url = uriparser.parse('http://www.dreamlab.pl/test/test1/?b=3&a=1&a=2', null, uriparser.Engines.NGINX); expect(Object.keys(url).length).toEqual(4); expect(url.protocol).toEqual('http:'); @@ -199,7 +220,7 @@ describe('uriparser - parse', function () { }); it('http://dreamlab.pl:/', function () { - var url = uriparser.parse('http://www.dreamlab.pl:/', null, uriparser.eNgxParser); + var url = uriparser.parse('http://www.dreamlab.pl:/', null, uriparser.Engines.NGINX); expect(Object.keys(url).length).toEqual(4); expect(url.protocol).toEqual('http:'); @@ -207,8 +228,14 @@ describe('uriparser - parse', function () { expect(url.port).toEqual(''); }); + it('http://dreamlab.pl:/ - only protocol', function () { + var url = uriparser.parse('http://www.dreamlab.pl:/', uriparser.Uri.PROTOCOL, uriparser.Engines.NGINX); + expect(Object.keys(url).length).toEqual(1); + expect(url.protocol).toEqual('http:'); + }); + it('http://dreamlab.pl:', function () { - var url = uriparser.parse('http://www.dreamlab.pl:', null, uriparser.eNgxParser); + var url = uriparser.parse('http://www.dreamlab.pl:', null, uriparser.Engines.NGINX); expect(Object.keys(url).length).toEqual(4); expect(url.protocol).toEqual('http:'); @@ -217,11 +244,11 @@ describe('uriparser - parse', function () { }); it('http:////', function () { - var url = uriparser.parse('http:////', null, uriparser.eNgxParser); + var url = uriparser.parse('http:////', null, uriparser.Engines.NGINX); - expect(Object.keys(url).length).toEqual(2); + expect(Object.keys(url).length).toEqual(3); expect(url.protocol).toEqual('http:'); expect(url.path).toEqual('//'); + expect(url.host).toEqual(''); }); - }); diff --git a/wscript b/wscript index 6ad5a09..463f31b 100644 --- a/wscript +++ b/wscript @@ -7,7 +7,7 @@ bldir = "build" version = "1.0" def set_options(opt): - opt.add_option('-b', '--build-uri-parser', action='store_false', default=True, dest='buildUri', help='build with bundled uriparser'); + opt.add_option('-b', '--build-uri-parser', action='store_false', default=True, dest='buildUri', help='build with bundled deps'); opt.tool_options("compiler_cxx") def configure(conf): @@ -24,13 +24,14 @@ def do_clean(): def build(bld): if Options.options.buildUri == True and do_clean() == False: bld.exec_command("mkdir -p uriparser; cd ../deps/uriparser && ./autogen.sh && ./configure --with-pic --disable-test --disable-doc --disable-shared --prefix=%s && make clean install" % (bld.bdir + "/uriparser")) - bld.exec_command("cd ../deps/ngx_url_parser && make static-lib") + bld.exec_command("cd -") + bld.exec_command("mkdir -p ngx_url_parser; cd ../deps/ngx_url_parser && ./autogen.sh && ./configure --with-pic --disable-shared --prefix=%s && make clean install" %(bld.bdir + "/ngx_url_parser")) obj = bld.new_task_gen("cxx", "shlib", "node_addon") obj.target = "uriparser" obj.source = "src/node-uriparser.cc" obj.lib = ["uriparser", "ngx_url_parser"] - obj.includes = [bld.bdir + "/uriparser/include/uriparser", "deps/ngx_url_parser/"] - obj.libpath = [bld.bdir + "/uriparser/lib", '../deps/ngx_url_parser/lib'] + obj.includes = [bld.bdir + "/uriparser/include/uriparser", bld.bdir + "/ngx_url_parser/include/ngx_url_parser", "node_modules/nan/"] + obj.libpath = [bld.bdir + "/uriparser/lib", bld.bdir + '/ngx_url_parser/lib'] obj.cxxflags = ["-g"] obj.cflags = ["-g"] From d14605d9149a7cc4a8a3482da7478124b2d30cc5 Mon Sep 17 00:00:00 2001 From: Marcin Kaciuba Date: Tue, 12 Jan 2016 14:16:35 +0100 Subject: [PATCH 11/22] rename file --- src/node-uriparser.cc | 1 + src/parser.hpp | 206 ---------------------------------------- src/parsers.hpp | 215 ++++++++++++++++++++++++++++++++++++++++++ wscript | 3 +- 4 files changed, 217 insertions(+), 208 deletions(-) delete mode 100644 src/parser.hpp create mode 100644 src/parsers.hpp diff --git a/src/node-uriparser.cc b/src/node-uriparser.cc index 47be96a..bb117e6 100644 --- a/src/node-uriparser.cc +++ b/src/node-uriparser.cc @@ -229,6 +229,7 @@ static v8::Handle parse(const v8::Arguments& args){ extern "C" void init (v8::Handle target){ + v8::HandleScope scope; NODE_SET_METHOD(target, "parse", parse); diff --git a/src/parser.hpp b/src/parser.hpp deleted file mode 100644 index 507dbf4..0000000 --- a/src/parser.hpp +++ /dev/null @@ -1,206 +0,0 @@ -extern "C" { - #include -} - -#include -#include - -// base structure for url properties -typedef struct { - char * schema; - char * host; - char * path; - char * query; - char * fragment; - char * port; - char * auth; -} Url; - - -class Parser { - public: - Parser(const char * str): m_str(str) { - url.schema = NULL; - url.host = NULL; - url.path = NULL; - url.query = NULL; - url.fragment = NULL; - url.port = NULL; - url.auth = NULL; - } - - virtual ~Parser() { - } - - enum Status { - ERROR = -1, - OK, - }; - - Status status; - Url url; - protected: - const char * m_str; -}; - -class NgxParser: public Parser { - public: - NgxParser(const char * str): Parser(str), ngx_url() { - if (ngx_url_parser(&ngx_url, str) == NGX_URL_OK) { - status = Parser::OK; - } else { - status = Parser::ERROR; - return; - } - - url.schema = ngx_url.schema; - url.host = ngx_url.host; - url.path = ngx_url.path; - url.query = ngx_url.query; - url.fragment = ngx_url.fragment; - url.port = ngx_url.port; - url.auth = ngx_url.auth; - } - - virtual ~NgxParser() { - ngx_url_free(&ngx_url); - } - - protected: - ngx_http_url ngx_url; -}; - -class RfcParser: public Parser { - public: - RfcParser(const char *str): Parser(str) { - UriParserStateA state; - UriUriA uri; - - state.uri = &uri; - if (uriParseUriA(&state, str) == URI_SUCCESS) { - status = Parser::OK; - } else { - status = Parser::ERROR; - return; - } - - if (uri.scheme.first) { - copyFromMeta(&url.schema, uri.scheme); - } - - if (uri.userInfo.first) { - copyFromMeta(&url.auth, uri.userInfo); - } - - if (uri.hostText.first) { - copyFromMeta(&url.host, uri.hostText); - } - - if (uri.portText.first) { - copyFromMeta(&url.port, uri.portText); - } - - if (uri.query.first) { - copyFromMeta(&url.query, uri.query); - } - - if (uri.fragment.first) { - copyFromMeta(&url.fragment, uri.fragment); - } - - if (uri.pathHead && uri.pathHead->text.first) { - int len = 0; - - UriPathSegmentA *pathHead = uri.pathHead; - do { - if (pathHead->text.first == pathHead->text.afterLast) { - len++; - } else { - //len +1 because we need to add slash - len += pathHead->text.afterLast - pathHead->text.first + 1; - } - pathHead = pathHead->next; - } while (pathHead); - - char *path, *p, *tmp; - path = p = tmp = new char[len + 1]; - path[len] = '\0'; - - pathHead = uri.pathHead; - do { - // adding slash no matter what - *path = '/'; - path++; - // copying text only in case when path segment is not empty - if (pathHead->text.first != pathHead->text.afterLast) { - int localLen = pathHead->text.afterLast - pathHead->text.first; - memcpy(path, pathHead->text.first, localLen); - path += localLen; - } - pathHead = pathHead->next; - } while (pathHead); - - // path is always prefixed with / in case of relative url we move pointer further - if (!uri.absolutePath && !uri.hostText.first) { - p++; - } - - int pathLen = std::strlen(p); - url.path = new char[pathLen]; - std::strcpy(url.path, p); - delete[] tmp; - - } else { - url.path = new char[2]; - url.path[0] = '/'; - url.path[1] = '\0'; - } - - uriFreeUriMembersA(&uri); - } - - virtual ~RfcParser() { - if (url.schema != NULL) { - delete[] url.schema; - url.schema = NULL; - } - - if (url.host != NULL) { - delete[] url.host; - url.host = NULL; - } - - if (url.path != NULL) { - delete url.path; - url.path = NULL; - } - - if (url.query != NULL) { - delete[] url.query; - url.query= NULL; - } - - if (url.fragment != NULL) { - delete[] url.fragment; - url.fragment = NULL; - } - - if (url.port != NULL) { - delete[] url.port; - url.port = NULL; - } - - if (url.auth != NULL) { - delete[] url.auth; - url.auth = NULL; - } - } - - private: - void copyFromMeta(char ** dest, UriTextRangeStructA &src) { - uint32_t len = src.afterLast - src.first + 1; - *dest = new char[len]; - std::memcpy(*dest, src.first, len - 1); - (*dest)[len - 1] = '\0'; - } -}; diff --git a/src/parsers.hpp b/src/parsers.hpp new file mode 100644 index 0000000..01764a5 --- /dev/null +++ b/src/parsers.hpp @@ -0,0 +1,215 @@ +/* + * Copyright (C) DreamLab Onet.pl Sp. z o. o. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +extern "C" { + #include +} +#include + +// base structure for url properties +typedef struct { + const char * start; + size_t len; +} Element; + +typedef struct { + Element scheme; + Element host; + Element path; + Element query; + Element fragment; + Element port; + Element auth; +} Url; + + +class Parser { + public: + Parser(const char * str): m_str(str) { + url.scheme.start = NULL; + url.host.start = NULL; + url.path.start = NULL; + url.query.start = NULL; + url.fragment.start = NULL; + url.port.start = NULL; + url.auth.start = NULL; + } + + virtual ~Parser() { + } + + enum Status { + ERROR = -1, + OK, + }; + + Status status; + Url url; + protected: + const char * m_str; +}; + +class NgxParser: public Parser { + public: + NgxParser(const char * str): Parser(str), url_meta() { + if (ngx_url_parser_meta(&url_meta, str) == NGX_URL_OK) { + status = Parser::OK; + } else { + status = Parser::ERROR; + return; + } + + url.scheme.start = url_meta.scheme_start; + url.scheme.len = url_meta.scheme_end - url_meta.scheme_start; + url.host.start = url_meta.host_start; + url.host.len = url_meta.host_end - url_meta.host_start; + url.path.start = url_meta.uri_start; + url.path.len = url_meta.uri_end - url_meta.uri_start; + url.query.start = url_meta.args_start; + url.query.len = url_meta.args_end - url_meta.args_start; + url.fragment.start = url_meta.fragment_start; + url.fragment.len = url_meta.fragment_end - url_meta.fragment_start; + url.port.start = url_meta.port_start; + url.port.len = url_meta.port_end - url_meta.port_end; + url.auth.start = url_meta.auth_start; + url.auth.len = url_meta.auth_end - url_meta.auth_start; + } + + virtual ~NgxParser() { + } + + protected: + ngx_http_url_meta url_meta; +}; + +class UriParser: public Parser { + public: + UriParser(const char *str): Parser(str), m_uri(), m_state() { + + m_state.uri = &m_uri; + if (uriParseUriA(&m_state, str) == URI_SUCCESS) { + status = Parser::OK; + } else { + status = Parser::ERROR; + return; + } + if (m_uri.scheme.first) { + url.scheme.start = m_uri.scheme.first; + url.scheme.len = calculateLen(m_uri.scheme); + } + + if (m_uri.userInfo.first) { + url.auth.start = m_uri.userInfo.first; + url.auth.len = calculateLen(m_uri.userInfo); + } + + if (m_uri.hostText.first) { + url.host.start = m_uri.hostText.first; + url.host.len = calculateLen(m_uri.hostText); + } + + if (m_uri.portText.first) { + url.port.start = m_uri.portText.first; + url.port.len = calculateLen(m_uri.portText); + } + + if (m_uri.query.first) { + url.query.start = m_uri.query.first; + url.query.len = calculateLen(m_uri.query); + } + + if (m_uri.fragment.first) { + url.fragment.start = m_uri.fragment.first; + url.fragment.len = calculateLen(m_uri.fragment); + } + + if (m_uri.pathHead && m_uri.pathHead->text.first) { + int len = 0; + + UriPathSegmentA *pathHead = m_uri.pathHead; + do { + if (pathHead->text.first == pathHead->text.afterLast) { + len++; + } else { + //len +1 because we need to add slash + len += pathHead->text.afterLast - pathHead->text.first + 1; + } + pathHead = pathHead->next; + } while (pathHead); + + char *path, *p, *tmp; + path = p = tmp = new char[len + 1]; + path[len] = '\0'; + + pathHead = m_uri.pathHead; + do { + // adding slash no matter what + *path = '/'; + path++; + // copying text only in case when path segment is not empty + if (pathHead->text.first != pathHead->text.afterLast) { + int localLen = pathHead->text.afterLast - pathHead->text.first; + memcpy(path, pathHead->text.first, localLen); + path += localLen; + } + pathHead = pathHead->next; + } while (pathHead); + + // path is always prefixed with / in case of relative url we move pointer further + if (!m_uri.absolutePath && !m_uri.hostText.first) { + p++; + } + + int pathLen = std::strlen(p); + char * pathPtr = new char[pathLen + 1]; + std::strcpy(pathPtr, p); + url.path.start = pathPtr; + url.path.len = pathLen; + delete[] tmp; + + } else { + char * pathPtr = new char[2]; + pathPtr[0] = '/'; + pathPtr[1] = '\0'; + url.path.start = pathPtr; + url.path.len = 1; + } + + } + + virtual ~UriParser() { + uriFreeUriMembersA(&m_uri); + + if (url.path.start) { + delete[] url.path.start; + url.path.start = NULL; + } + } + + private: + UriUriA m_uri; + UriParserStateA m_state; + + inline size_t calculateLen(UriTextRangeStructA &src) { + return src.afterLast - src.first; + } +}; diff --git a/wscript b/wscript index 463f31b..810b4a3 100644 --- a/wscript +++ b/wscript @@ -23,9 +23,8 @@ def do_clean(): def build(bld): if Options.options.buildUri == True and do_clean() == False: - bld.exec_command("mkdir -p uriparser; cd ../deps/uriparser && ./autogen.sh && ./configure --with-pic --disable-test --disable-doc --disable-shared --prefix=%s && make clean install" % (bld.bdir + "/uriparser")) - bld.exec_command("cd -") bld.exec_command("mkdir -p ngx_url_parser; cd ../deps/ngx_url_parser && ./autogen.sh && ./configure --with-pic --disable-shared --prefix=%s && make clean install" %(bld.bdir + "/ngx_url_parser")) + bld.exec_command("mkdir -p uriparser; cd ../deps/uriparser && ./autogen.sh && ./configure --with-pic --disable-test --disable-doc --disable-shared --prefix=%s && make clean install" % (bld.bdir + "/uriparser")) obj = bld.new_task_gen("cxx", "shlib", "node_addon") obj.target = "uriparser" From 1430e83b3c0c08e0809444280463831311a2770d Mon Sep 17 00:00:00 2001 From: Marcin Kaciuba Date: Tue, 12 Jan 2016 17:09:06 +0100 Subject: [PATCH 12/22] Update ngx_url_parser, changed default parser --- deps/ngx_url_parser | 2 +- src/node-uriparser.cc | 8 ++++---- tests/exceptionSpec.js | 5 ----- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/deps/ngx_url_parser b/deps/ngx_url_parser index 2d22184..e0d2e42 160000 --- a/deps/ngx_url_parser +++ b/deps/ngx_url_parser @@ -1 +1 @@ -Subproject commit 2d221846f989273542b3d1e432f17e84f14f15f2 +Subproject commit e0d2e42fb8afb7007a608f89c97e54c7824c7a61 diff --git a/src/node-uriparser.cc b/src/node-uriparser.cc index bb117e6..4e2a7c6 100644 --- a/src/node-uriparser.cc +++ b/src/node-uriparser.cc @@ -63,7 +63,7 @@ static v8::Persistent password_symbol = NODE_PSYMBOL("password"); static v8::Handle parse(const v8::Arguments& args){ v8::HandleScope scope; parseOptions opts = kAll; - Engines engine = eUriParser; + Engines engine = eNgxParser; if (args.Length() == 0 || !args[0]->IsString()) { return v8::ThrowException(v8::Exception::TypeError(v8::String::New("First argument has to be string"))); @@ -89,10 +89,10 @@ static v8::Handle parse(const v8::Arguments& args){ Url uri; Parser *parser; - if (engine == eNgxParser) { - parser = new NgxParser(*url); - } else { + if (engine == eUriParser) { parser = new UriParser(*url); + } else { + parser = new NgxParser(*url); } if (parser->status != Parser::OK) { diff --git a/tests/exceptionSpec.js b/tests/exceptionSpec.js index 2f84b48..080b654 100644 --- a/tests/exceptionSpec.js +++ b/tests/exceptionSpec.js @@ -35,9 +35,4 @@ describe("uriparser - exceptions", function () { }).toThrow(); }); - it("wrong url given", function () { - expect(function () { - uriparser.parse("http://www.dreamlab.pl/a[]=1"); - }).toThrow(); - }); }); From 695650c18b91fc28dd64d246f8b232a181a2e35d Mon Sep 17 00:00:00 2001 From: Marcin Kaciuba Date: Wed, 13 Jan 2016 17:02:44 +0100 Subject: [PATCH 13/22] Fixed memory leak, added more tests --- deps/ngx_url_parser | 2 +- src/node-uriparser.cc | 1 + src/parsers.hpp | 2 +- tests/exceptionSpec.js | 5 ++ tests/parseSpec.js | 190 ++++++++++++++++++++++++++--------------- 5 files changed, 130 insertions(+), 70 deletions(-) diff --git a/deps/ngx_url_parser b/deps/ngx_url_parser index e0d2e42..6f6d0ce 160000 --- a/deps/ngx_url_parser +++ b/deps/ngx_url_parser @@ -1 +1 @@ -Subproject commit e0d2e42fb8afb7007a608f89c97e54c7824c7a61 +Subproject commit 6f6d0ced994a303f7a67f23b7830569d4463905c diff --git a/src/node-uriparser.cc b/src/node-uriparser.cc index 4e2a7c6..ac7b82b 100644 --- a/src/node-uriparser.cc +++ b/src/node-uriparser.cc @@ -111,6 +111,7 @@ static v8::Handle parse(const v8::Arguments& args){ char * auth = new char[uri.auth.len + 1]; std::strncpy(auth, uri.auth.start, uri.auth.len); + auth[uri.auth.len] = '\0'; authUser = strtok_r(auth, delim, &authPtr); authPassword = strtok_r(NULL, delim, &authPtr); diff --git a/src/parsers.hpp b/src/parsers.hpp index 01764a5..0c56e77 100644 --- a/src/parsers.hpp +++ b/src/parsers.hpp @@ -89,7 +89,7 @@ class NgxParser: public Parser { url.fragment.start = url_meta.fragment_start; url.fragment.len = url_meta.fragment_end - url_meta.fragment_start; url.port.start = url_meta.port_start; - url.port.len = url_meta.port_end - url_meta.port_end; + url.port.len = url_meta.port_end - url_meta.port_start; url.auth.start = url_meta.auth_start; url.auth.len = url_meta.auth_end - url_meta.auth_start; } diff --git a/tests/exceptionSpec.js b/tests/exceptionSpec.js index 080b654..c2812fd 100644 --- a/tests/exceptionSpec.js +++ b/tests/exceptionSpec.js @@ -35,4 +35,9 @@ describe("uriparser - exceptions", function () { }).toThrow(); }); + it("incorrect url - no auth", function () { + expect(function () { + uriparser.parse("http://:www.dreamlab.pl"); + }).toThrow(); + }); }); diff --git a/tests/parseSpec.js b/tests/parseSpec.js index 7948b27..d3a673d 100644 --- a/tests/parseSpec.js +++ b/tests/parseSpec.js @@ -26,25 +26,25 @@ describe('uriparser - parse', function () { var url = uriparser.parse('http://dreamlab.pl'); expect(Object.keys(url).length).toEqual(3); - expect(url.protocol).toEqual('http:'); - expect(url.host).toEqual('dreamlab.pl'); - expect(url.path).toEqual('/'); + expect(url.protocol).toBe('http:'); + expect(url.host).toBe('dreamlab.pl'); + expect(url.path).toBe('/'); }); it('http://dreamlab.pl/', function () { var url = uriparser.parse('http://dreamlab.pl/'); expect(Object.keys(url).length).toEqual(3); - expect(url.protocol).toEqual('http:'); - expect(url.host).toEqual('dreamlab.pl'); - expect(url.path).toEqual('/'); + expect(url.protocol).toBe('http:'); + expect(url.host).toBe('dreamlab.pl'); + expect(url.path).toBe('/'); }); it('1.txt?test1=okok', function () { var url = uriparser.parse('1.txt?test1=okok'); expect(Object.keys(url).length).toEqual(2); - expect(url.path).toEqual('1.txt'); + expect(url.path).toBe('1.txt'); expect(url.query).toEqual({'test1': 'okok'}); }); @@ -52,7 +52,7 @@ describe('uriparser - parse', function () { var url = uriparser.parse('/1.txt?test1=okok'); expect(Object.keys(url).length).toEqual(2); - expect(url.path).toEqual('/1.txt'); + expect(url.path).toBe('/1.txt'); expect(url.query).toEqual({'test1': 'okok'}); }); @@ -60,9 +60,9 @@ describe('uriparser - parse', function () { var url = uriparser.parse('http://dreamlab.pl/X?X'); expect(Object.keys(url).length).toEqual(4); - expect(url.protocol).toEqual('http:'); - expect(url.host).toEqual('dreamlab.pl'); - expect(url.path).toEqual('/X'); + expect(url.protocol).toBe('http:'); + expect(url.host).toBe('dreamlab.pl'); + expect(url.path).toBe('/X'); expect(url.query).toEqual({'X': ""}); }); @@ -70,99 +70,99 @@ describe('uriparser - parse', function () { var url = uriparser.parse('http://dreamlab.pl/X'); expect(Object.keys(url).length).toEqual(3); - expect(url.protocol).toEqual('http:'); - expect(url.host).toEqual('dreamlab.pl'); - expect(url.path).toEqual('/X'); + expect(url.protocol).toBe('http:'); + expect(url.host).toBe('dreamlab.pl'); + expect(url.path).toBe('/X'); }); it('http://dreamlab.pl/hejka/', function () { var url = uriparser.parse('http://dreamlab.pl/hejka/'); expect(Object.keys(url).length).toEqual(3); - expect(url.protocol).toEqual('http:'); - expect(url.host).toEqual('dreamlab.pl'); - expect(url.path).toEqual('/hejka/'); + expect(url.protocol).toBe('http:'); + expect(url.host).toBe('dreamlab.pl'); + expect(url.path).toBe('/hejka/'); }); it('http://dreamlab.pl/hejka/?hejka=123', function () { var url = uriparser.parse('http://dreamlab.pl/hejka/?hejka=123'); expect(Object.keys(url).length).toEqual(4); - expect(url.protocol).toEqual('http:'); - expect(url.host).toEqual('dreamlab.pl'); - expect(url.path).toEqual('/hejka/'); + expect(url.protocol).toBe('http:'); + expect(url.host).toBe('dreamlab.pl'); + expect(url.path).toBe('/hejka/'); expect(url.query).toEqual({'hejka': "123"}) }); it('http://:@www.dreamlab.pl/?', function () { var url = uriparser.parse('http://:@www.dreamlab.pl/?'); expect(Object.keys(url).length).toEqual(3); - expect(url.protocol).toEqual('http:'); - expect(url.host).toEqual('www.dreamlab.pl'); - expect(url.path).toEqual('/'); + expect(url.protocol).toBe('http:'); + expect(url.host).toBe('www.dreamlab.pl'); + expect(url.path).toBe('/'); }); it('http://user:@www.dreamlab.pl/?', function () { var url = uriparser.parse('http://user:@www.dreamlab.pl/?'); expect(Object.keys(url).length).toEqual(3); - expect(url.protocol).toEqual('http:'); - expect(url.host).toEqual('www.dreamlab.pl'); - expect(url.path).toEqual('/'); + expect(url.protocol).toBe('http:'); + expect(url.host).toBe('www.dreamlab.pl'); + expect(url.path).toBe('/'); }); it('http://:pw@www.dreamlab.pl/?', function () { var url = uriparser.parse('http://:pw@www.dreamlab.pl/?'); expect(Object.keys(url).length).toEqual(3); - expect(url.protocol).toEqual('http:'); - expect(url.host).toEqual('www.dreamlab.pl'); - expect(url.path).toEqual('/'); + expect(url.protocol).toBe('http:'); + expect(url.host).toBe('www.dreamlab.pl'); + expect(url.path).toBe('/'); }); it('http://user:pw@www.dreamlab.pl/?', function () { var url = uriparser.parse('http://user:pw@www.dreamlab.pl/?'); expect(Object.keys(url).length).toEqual(4); - expect(url.protocol).toEqual('http:'); + expect(url.protocol).toBe('http:'); expect(url.auth).toEqual({'user': "user", "password": "pw"}); - expect(url.host).toEqual('www.dreamlab.pl'); - expect(url.path).toEqual('/'); + expect(url.host).toBe('www.dreamlab.pl'); + expect(url.path).toBe('/'); }); it('http://www.dreamlab.pl/?=&=', function () { var url = uriparser.parse('http://www.dreamlab.pl/?=&='); expect(Object.keys(url).length).toEqual(3); - expect(url.protocol).toEqual('http:'); - expect(url.host).toEqual('www.dreamlab.pl'); - expect(url.path).toEqual('/'); + expect(url.protocol).toBe('http:'); + expect(url.host).toBe('www.dreamlab.pl'); + expect(url.path).toBe('/'); }); it('http://www.dreamlab.pl//test/123', function () { var url = uriparser.parse('http://www.dreamlab.pl//test/123'); expect(Object.keys(url).length).toEqual(3); - expect(url.protocol).toEqual('http:'); - expect(url.host).toEqual('www.dreamlab.pl'); - expect(url.path).toEqual('//test/123'); + expect(url.protocol).toBe('http:'); + expect(url.host).toBe('www.dreamlab.pl'); + expect(url.path).toBe('//test/123'); }); it('http://www.dreamlab.pl/test//123', function () { var url = uriparser.parse('http://www.dreamlab.pl/test//123'); expect(Object.keys(url).length).toEqual(3); - expect(url.protocol).toEqual('http:'); - expect(url.host).toEqual('www.dreamlab.pl'); - expect(url.path).toEqual('/test//123'); + expect(url.protocol).toBe('http:'); + expect(url.host).toBe('www.dreamlab.pl'); + expect(url.path).toBe('/test//123'); }); it('http://www.dreamlab.pl/test/?a=1&b=1&a=2&c=3', function () { var url = uriparser.parse('http://www.dreamlab.pl/test/?a=1&b=4&a=2&c=3'); expect(Object.keys(url).length).toEqual(4); - expect(url.protocol).toEqual('http:'); - expect(url.host).toEqual('www.dreamlab.pl'); + expect(url.protocol).toBe('http:'); + expect(url.host).toBe('www.dreamlab.pl'); expect(url.query).toEqual({a: ['1', '2'], b: '4', c: '3'}); }); @@ -170,8 +170,8 @@ describe('uriparser - parse', function () { var url = uriparser.parse('http://www.dreamlab.pl/test/?b=1&c=3&a%5B%5D=1&a%5B%5D=2'); expect(Object.keys(url).length).toEqual(5); - expect(url.protocol).toEqual('http:'); - expect(url.host).toEqual('www.dreamlab.pl'); + expect(url.protocol).toBe('http:'); + expect(url.host).toBe('www.dreamlab.pl'); expect(url.query).toEqual({b: '1', c: '3', a: ['1', '2']}); expect(url.queryArraySuffix).toEqual({a: '%5B%5D'}); }); @@ -180,9 +180,9 @@ describe('uriparser - parse', function () { var url = uriparser.parse('http://www.dreamlab.pl/test/test1/?a[]=1&a[]=2', null, uriparser.Engines.NGINX); expect(Object.keys(url).length).toEqual(5); - expect(url.protocol).toEqual('http:'); - expect(url.host).toEqual('www.dreamlab.pl'); - expect(url.path).toEqual('/test/test1/'); + expect(url.protocol).toBe('http:'); + expect(url.host).toBe('www.dreamlab.pl'); + expect(url.path).toBe('/test/test1/'); expect(url.query).toEqual({a: ['1', '2']}); expect(url.queryArraySuffix).toEqual({a: '[]'}); }); @@ -191,9 +191,9 @@ describe('uriparser - parse', function () { var url = uriparser.parse('http://www.dreamlab.pl/test/test1/?a[name]=1&a[name]=2', null, uriparser.Engines.NGINX); expect(Object.keys(url).length).toEqual(4); - expect(url.protocol).toEqual('http:'); - expect(url.host).toEqual('www.dreamlab.pl'); - expect(url.path).toEqual('/test/test1/'); + expect(url.protocol).toBe('http:'); + expect(url.host).toBe('www.dreamlab.pl'); + expect(url.path).toBe('/test/test1/'); expect(url.query).toEqual({'a[name]': ['1', '2']}); }); @@ -201,21 +201,21 @@ describe('uriparser - parse', function () { var url = uriparser.parse('http://user:pw@www.dreamlab.pl/test/test1/?a[name]=1&a[name]=2#fragment', null, uriparser.Engines.NGINX); expect(Object.keys(url).length).toEqual(6); - expect(url.protocol).toEqual('http:'); - expect(url.host).toEqual('www.dreamlab.pl'); - expect(url.path).toEqual('/test/test1/'); + expect(url.protocol).toBe('http:'); + expect(url.host).toBe('www.dreamlab.pl'); + expect(url.path).toBe('/test/test1/'); expect(url.query).toEqual({'a[name]': ['1', '2']}); expect(url.auth).toEqual({'user': 'user', 'password': 'pw'}); - expect(url.fragment).toEqual('fragment'); + expect(url.fragment).toBe('fragment'); }); it('http://www.dreamlab.pl/test/test1/?b=3&a=1&a=2', function () { var url = uriparser.parse('http://www.dreamlab.pl/test/test1/?b=3&a=1&a=2', null, uriparser.Engines.NGINX); expect(Object.keys(url).length).toEqual(4); - expect(url.protocol).toEqual('http:'); - expect(url.host).toEqual('www.dreamlab.pl'); - expect(url.path).toEqual('/test/test1/'); + expect(url.protocol).toBe('http:'); + expect(url.host).toBe('www.dreamlab.pl'); + expect(url.path).toBe('/test/test1/'); expect(url.query).toEqual({b:'3', a: ['1', '2']}); }); @@ -223,32 +223,86 @@ describe('uriparser - parse', function () { var url = uriparser.parse('http://www.dreamlab.pl:/', null, uriparser.Engines.NGINX); expect(Object.keys(url).length).toEqual(4); - expect(url.protocol).toEqual('http:'); - expect(url.host).toEqual('www.dreamlab.pl'); - expect(url.port).toEqual(''); + expect(url.protocol).toBe('http:'); + expect(url.host).toBe('www.dreamlab.pl'); + expect(url.port).toBe(''); }); it('http://dreamlab.pl:/ - only protocol', function () { var url = uriparser.parse('http://www.dreamlab.pl:/', uriparser.Uri.PROTOCOL, uriparser.Engines.NGINX); expect(Object.keys(url).length).toEqual(1); - expect(url.protocol).toEqual('http:'); + expect(url.protocol).toBe('http:'); }); it('http://dreamlab.pl:', function () { var url = uriparser.parse('http://www.dreamlab.pl:', null, uriparser.Engines.NGINX); expect(Object.keys(url).length).toEqual(4); - expect(url.protocol).toEqual('http:'); - expect(url.host).toEqual('www.dreamlab.pl'); - expect(url.port).toEqual(''); + expect(url.protocol).toBe('http:'); + expect(url.host).toBe('www.dreamlab.pl'); + expect(url.port).toBe(''); + }); + + it('http://dreamlab.pl:80/path/index.html?arg1=5', function () { + var url = uriparser.parse('http://www.dreamlab.pl:80/path/index.html?arg1=5', null, uriparser.Engines.NGINX); + + expect(Object.keys(url).length).toEqual(5); + expect(url.protocol).toBe('http:'); + expect(url.host).toBe('www.dreamlab.pl'); + expect(url.port).toBe('80'); + expect(url.path).toBe('/path/index.html'); + expect(url.query).toEqual({arg1: '5'}); }); it('http:////', function () { var url = uriparser.parse('http:////', null, uriparser.Engines.NGINX); expect(Object.keys(url).length).toEqual(3); - expect(url.protocol).toEqual('http:'); - expect(url.path).toEqual('//'); - expect(url.host).toEqual(''); + expect(url.protocol).toBe('http:'); + expect(url.path).toBe('//'); + expect(url.host).toBe(''); }); + + it('somestring', function () { + var url = uriparser.parse('somestring', null, uriparser.Engines.NGINX); + + expect(Object.keys(url).length).toEqual(1); + expect(url.path).toBe('somestring'); + }); + + it('#fragmen/t', function () { + var url = uriparser.parse('#fragmen/t', null, uriparser.Engines.NGINX); + + expect(Object.keys(url).length).toEqual(2); + expect(url.fragment).toBe('fragmen/t'); + }); + + it('?query', function () { + var url = uriparser.parse('?query', null, uriparser.Engines.NGINX); + + expect(Object.keys(url).length).toEqual(2); + expect(url.query).toEqual({'query': ''}); + }); + + it('https://user_usr:password@www.dreamlab.pl:81/path/index.html?arg1=1&arg2=2', function () { + var url = uriparser.parse('https://user_usr:password@www.dreamlab.pl:81/path/index.html?arg1=1&arg2=2', null, uriparser.Engines.NGINX); + + expect(Object.keys(url).length).toEqual(6); + expect(url.protocol).toBe('https:'); + expect(url.host).toBe('www.dreamlab.pl'); + expect(url.port).toBe('81'); + expect(url.path).toBe('/path/index.html'); + expect(url.auth).toEqual({user: 'user_usr', password: 'password'}); + expect(url.query).toEqual({arg1: '1', arg2: '2'}); + }); + + it('https://zs.usernanme_cms.test.api.pl/', function () { + var url = uriparser.parse('https://zs.usernanme_cms.test.api.pl/', null, uriparser.Engines.NGINX); + + expect(Object.keys(url).length).toEqual(3); + expect(url.protocol).toBe('https:'); + expect(url.host).toBe('zs.usernanme_cms.test.api.pl'); + expect(url.path).toBe('/'); + }); + }); From 07d3ed86cb4699c83daa5c01c361e0d69fc1e248 Mon Sep 17 00:00:00 2001 From: Marcin Kaciuba Date: Mon, 8 Feb 2016 19:09:29 +0100 Subject: [PATCH 14/22] Handle semicolon in qs --- src/node-uriparser.cc | 17 ++++++++++++++--- tests/parseSpec.js | 19 +++++++++++++++++++ 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/node-uriparser.cc b/src/node-uriparser.cc index ac7b82b..ca5c43e 100644 --- a/src/node-uriparser.cc +++ b/src/node-uriparser.cc @@ -142,12 +142,23 @@ static v8::Handle parse(const v8::Arguments& args){ std::strncpy(query, uri.query.start, uri.query.len); query[uri.query.len] = '\0'; - const char *amp = "&", *sum = "="; + const char *amp = "&", *sum = "=", *semicolon = ";", *delimeter = amp; char *queryParamPairPtr, *queryParam, *queryParamKey, *queryParamValue, *queryParamPtr; bool empty = true; v8::Local qsSuffix = v8::Object::New(); - queryParam = strtok_r(query, amp, &queryParamPairPtr); + // find qs delimeter & or ; + for (size_t i = 0; i < uri.query.len; ++i) { + if (query[i] == *amp) { + delimeter = amp; + break; + } else if (query[i] == *semicolon) { + delimeter = semicolon; + break; + } + } + + queryParam = strtok_r(query, delimeter, &queryParamPairPtr); v8::Local queryData = v8::Object::New(); bool arrayBrackets = false; @@ -179,7 +190,7 @@ static v8::Handle parse(const v8::Arguments& args){ } paramsMap[queryParamKey].push_back(queryParamValue ? queryParamValue : ""); } - queryParam = strtok_r(NULL, amp, &queryParamPairPtr); + queryParam = strtok_r(NULL, delimeter, &queryParamPairPtr); } for (std::vector::iterator it=paramsOrder.begin(); it!=paramsOrder.end(); ++it) { diff --git a/tests/parseSpec.js b/tests/parseSpec.js index d3a673d..97245b3 100644 --- a/tests/parseSpec.js +++ b/tests/parseSpec.js @@ -305,4 +305,23 @@ describe('uriparser - parse', function () { expect(url.path).toBe('/'); }); + it('http://www.dreamlab.pl/test/test1/?a=3;b=1;a=2', function () { + var url = uriparser.parse('http://www.dreamlab.pl/test/test1/?a=3;b=1;a=2', null, uriparser.Engines.NGINX); + + expect(Object.keys(url).length).toEqual(4); + expect(url.protocol).toBe('http:'); + expect(url.host).toBe('www.dreamlab.pl'); + expect(url.path).toBe('/test/test1/'); + expect(url.query).toEqual({ a: ['3', '2'], b: '1'}); + }); + + it('http://www.dreamlab.pl/test/test1/?a', function () { + var url = uriparser.parse('http://www.dreamlab.pl/test/test1/?a', null, uriparser.Engines.NGINX); + + expect(Object.keys(url).length).toEqual(4); + expect(url.protocol).toBe('http:'); + expect(url.host).toBe('www.dreamlab.pl'); + expect(url.path).toBe('/test/test1/'); + expect(url.query).toEqual({ a: ''}); + }); }); From 22f055bece509f43d7c6545519a1c0d9f329d255 Mon Sep 17 00:00:00 2001 From: Marcin Kaciuba Date: Fri, 12 Feb 2016 16:45:10 +0100 Subject: [PATCH 15/22] Added parsing of semicolon in query string, and return it as property of object --- package.json | 7 +++-- src/node-uriparser.cc | 3 +++ tests/parseSpec.js | 59 ++++++++++++++++++++++++++++--------------- 3 files changed, 47 insertions(+), 22 deletions(-) diff --git a/package.json b/package.json index e42a464..1a61a50 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,12 @@ { "name": "uriparser", - "version": "1.2.12", + "version": "1.2.13", "description": "Fastest uriparser, written in C", "keywords": ["uriparser", "uri", "parser", "url"], - "author": "Jakub Lekstan ", + "contributors": [ + "Jakub Lekstan ", + "Marcin Kaciuba " + ], "dependencies": {}, "main": "./lib/bindings.js", "repository": { diff --git a/src/node-uriparser.cc b/src/node-uriparser.cc index ca5c43e..9c0ec55 100644 --- a/src/node-uriparser.cc +++ b/src/node-uriparser.cc @@ -55,6 +55,7 @@ static v8::Persistent host_symbol = NODE_PSYMBOL("host"); static v8::Persistent port_symbol = NODE_PSYMBOL("port"); static v8::Persistent query_symbol = NODE_PSYMBOL("query"); static v8::Persistent query_arr_suffix = NODE_PSYMBOL("queryArraySuffix"); +static v8::Persistent query_delimeter = NODE_PSYMBOL("queryDelimeter"); static v8::Persistent fragment_symbol = NODE_PSYMBOL("fragment"); static v8::Persistent path_symbol = NODE_PSYMBOL("path"); static v8::Persistent user_symbol = NODE_PSYMBOL("user"); @@ -158,6 +159,8 @@ static v8::Handle parse(const v8::Arguments& args){ } } + data->Set(query_delimeter, v8::String::New(delimeter), attrib); + queryParam = strtok_r(query, delimeter, &queryParamPairPtr); v8::Local queryData = v8::Object::New(); diff --git a/tests/parseSpec.js b/tests/parseSpec.js index 97245b3..deb0c01 100644 --- a/tests/parseSpec.js +++ b/tests/parseSpec.js @@ -43,27 +43,30 @@ describe('uriparser - parse', function () { it('1.txt?test1=okok', function () { var url = uriparser.parse('1.txt?test1=okok'); - expect(Object.keys(url).length).toEqual(2); + expect(Object.keys(url).length).toEqual(3); expect(url.path).toBe('1.txt'); expect(url.query).toEqual({'test1': 'okok'}); + expect(url.queryDelimeter).toBe('&'); }); it('/1.txt?test1=okok', function () { var url = uriparser.parse('/1.txt?test1=okok'); - expect(Object.keys(url).length).toEqual(2); + expect(Object.keys(url).length).toEqual(3); expect(url.path).toBe('/1.txt'); expect(url.query).toEqual({'test1': 'okok'}); + expect(url.queryDelimeter).toBe('&'); }); it('http://dreamlab.pl/X?X', function () { var url = uriparser.parse('http://dreamlab.pl/X?X'); - expect(Object.keys(url).length).toEqual(4); + expect(Object.keys(url).length).toEqual(5); expect(url.protocol).toBe('http:'); expect(url.host).toBe('dreamlab.pl'); expect(url.path).toBe('/X'); expect(url.query).toEqual({'X': ""}); + expect(url.queryDelimeter).toBe('&'); }); it('http://dreamlab.pl/X', function () { @@ -87,34 +90,37 @@ describe('uriparser - parse', function () { it('http://dreamlab.pl/hejka/?hejka=123', function () { var url = uriparser.parse('http://dreamlab.pl/hejka/?hejka=123'); - expect(Object.keys(url).length).toEqual(4); + expect(Object.keys(url).length).toEqual(5); expect(url.protocol).toBe('http:'); expect(url.host).toBe('dreamlab.pl'); expect(url.path).toBe('/hejka/'); expect(url.query).toEqual({'hejka': "123"}) + expect(url.queryDelimeter).toBe('&'); }); it('http://:@www.dreamlab.pl/?', function () { var url = uriparser.parse('http://:@www.dreamlab.pl/?'); - expect(Object.keys(url).length).toEqual(3); + expect(Object.keys(url).length).toEqual(4); expect(url.protocol).toBe('http:'); expect(url.host).toBe('www.dreamlab.pl'); expect(url.path).toBe('/'); + expect(url.queryDelimeter).toBe('&'); }); it('http://user:@www.dreamlab.pl/?', function () { var url = uriparser.parse('http://user:@www.dreamlab.pl/?'); - expect(Object.keys(url).length).toEqual(3); + expect(Object.keys(url).length).toEqual(4); expect(url.protocol).toBe('http:'); expect(url.host).toBe('www.dreamlab.pl'); expect(url.path).toBe('/'); + expect(url.queryDelimeter).toBe('&'); }); it('http://:pw@www.dreamlab.pl/?', function () { var url = uriparser.parse('http://:pw@www.dreamlab.pl/?'); - expect(Object.keys(url).length).toEqual(3); + expect(Object.keys(url).length).toEqual(4); expect(url.protocol).toBe('http:'); expect(url.host).toBe('www.dreamlab.pl'); expect(url.path).toBe('/'); @@ -123,20 +129,22 @@ describe('uriparser - parse', function () { it('http://user:pw@www.dreamlab.pl/?', function () { var url = uriparser.parse('http://user:pw@www.dreamlab.pl/?'); - expect(Object.keys(url).length).toEqual(4); + expect(Object.keys(url).length).toEqual(5); expect(url.protocol).toBe('http:'); expect(url.auth).toEqual({'user': "user", "password": "pw"}); expect(url.host).toBe('www.dreamlab.pl'); expect(url.path).toBe('/'); + expect(url.queryDelimeter).toBe('&'); }); it('http://www.dreamlab.pl/?=&=', function () { var url = uriparser.parse('http://www.dreamlab.pl/?=&='); - expect(Object.keys(url).length).toEqual(3); + expect(Object.keys(url).length).toEqual(4); expect(url.protocol).toBe('http:'); expect(url.host).toBe('www.dreamlab.pl'); expect(url.path).toBe('/'); + expect(url.queryDelimeter).toBe('&'); }); it('http://www.dreamlab.pl//test/123', function () { @@ -160,63 +168,69 @@ describe('uriparser - parse', function () { it('http://www.dreamlab.pl/test/?a=1&b=1&a=2&c=3', function () { var url = uriparser.parse('http://www.dreamlab.pl/test/?a=1&b=4&a=2&c=3'); - expect(Object.keys(url).length).toEqual(4); + expect(Object.keys(url).length).toEqual(5); expect(url.protocol).toBe('http:'); expect(url.host).toBe('www.dreamlab.pl'); expect(url.query).toEqual({a: ['1', '2'], b: '4', c: '3'}); + expect(url.queryDelimeter).toBe('&'); }); it('http://www.dreamlab.pl/test/?b=1&c=3&a%5B%5D=1&a%5B%5D=1', function () { var url = uriparser.parse('http://www.dreamlab.pl/test/?b=1&c=3&a%5B%5D=1&a%5B%5D=2'); - expect(Object.keys(url).length).toEqual(5); + expect(Object.keys(url).length).toEqual(6); expect(url.protocol).toBe('http:'); expect(url.host).toBe('www.dreamlab.pl'); expect(url.query).toEqual({b: '1', c: '3', a: ['1', '2']}); expect(url.queryArraySuffix).toEqual({a: '%5B%5D'}); + expect(url.queryDelimeter).toBe('&'); }); it('http://www.dreamlab.pl/test/test1/a[]=1&a[]=2', function () { var url = uriparser.parse('http://www.dreamlab.pl/test/test1/?a[]=1&a[]=2', null, uriparser.Engines.NGINX); - expect(Object.keys(url).length).toEqual(5); + expect(Object.keys(url).length).toEqual(6); expect(url.protocol).toBe('http:'); expect(url.host).toBe('www.dreamlab.pl'); expect(url.path).toBe('/test/test1/'); expect(url.query).toEqual({a: ['1', '2']}); expect(url.queryArraySuffix).toEqual({a: '[]'}); + expect(url.queryDelimeter).toBe('&'); }); it('http://www.dreamlab.pl/test/test1/a[name]=1&a[name]=2', function () { var url = uriparser.parse('http://www.dreamlab.pl/test/test1/?a[name]=1&a[name]=2', null, uriparser.Engines.NGINX); - expect(Object.keys(url).length).toEqual(4); + expect(Object.keys(url).length).toEqual(5); expect(url.protocol).toBe('http:'); expect(url.host).toBe('www.dreamlab.pl'); expect(url.path).toBe('/test/test1/'); expect(url.query).toEqual({'a[name]': ['1', '2']}); + expect(url.queryDelimeter).toBe('&'); }); it('http://user:pw@www.dreamlab.pl/test/test1/a[name]=1&a[name]=2#fragment', function () { var url = uriparser.parse('http://user:pw@www.dreamlab.pl/test/test1/?a[name]=1&a[name]=2#fragment', null, uriparser.Engines.NGINX); - expect(Object.keys(url).length).toEqual(6); + expect(Object.keys(url).length).toEqual(7); expect(url.protocol).toBe('http:'); expect(url.host).toBe('www.dreamlab.pl'); expect(url.path).toBe('/test/test1/'); expect(url.query).toEqual({'a[name]': ['1', '2']}); expect(url.auth).toEqual({'user': 'user', 'password': 'pw'}); expect(url.fragment).toBe('fragment'); + expect(url.queryDelimeter).toBe('&'); }); it('http://www.dreamlab.pl/test/test1/?b=3&a=1&a=2', function () { var url = uriparser.parse('http://www.dreamlab.pl/test/test1/?b=3&a=1&a=2', null, uriparser.Engines.NGINX); - expect(Object.keys(url).length).toEqual(4); + expect(Object.keys(url).length).toEqual(5); expect(url.protocol).toBe('http:'); expect(url.host).toBe('www.dreamlab.pl'); expect(url.path).toBe('/test/test1/'); expect(url.query).toEqual({b:'3', a: ['1', '2']}); + expect(url.queryDelimeter).toBe('&'); }); it('http://dreamlab.pl:/', function () { @@ -246,12 +260,13 @@ describe('uriparser - parse', function () { it('http://dreamlab.pl:80/path/index.html?arg1=5', function () { var url = uriparser.parse('http://www.dreamlab.pl:80/path/index.html?arg1=5', null, uriparser.Engines.NGINX); - expect(Object.keys(url).length).toEqual(5); + expect(Object.keys(url).length).toEqual(6); expect(url.protocol).toBe('http:'); expect(url.host).toBe('www.dreamlab.pl'); expect(url.port).toBe('80'); expect(url.path).toBe('/path/index.html'); expect(url.query).toEqual({arg1: '5'}); + expect(url.queryDelimeter).toBe('&'); }); it('http:////', function () { @@ -280,20 +295,22 @@ describe('uriparser - parse', function () { it('?query', function () { var url = uriparser.parse('?query', null, uriparser.Engines.NGINX); - expect(Object.keys(url).length).toEqual(2); + expect(Object.keys(url).length).toEqual(3); expect(url.query).toEqual({'query': ''}); + expect(url.queryDelimeter).toBe('&'); }); it('https://user_usr:password@www.dreamlab.pl:81/path/index.html?arg1=1&arg2=2', function () { var url = uriparser.parse('https://user_usr:password@www.dreamlab.pl:81/path/index.html?arg1=1&arg2=2', null, uriparser.Engines.NGINX); - expect(Object.keys(url).length).toEqual(6); + expect(Object.keys(url).length).toEqual(7); expect(url.protocol).toBe('https:'); expect(url.host).toBe('www.dreamlab.pl'); expect(url.port).toBe('81'); expect(url.path).toBe('/path/index.html'); expect(url.auth).toEqual({user: 'user_usr', password: 'password'}); expect(url.query).toEqual({arg1: '1', arg2: '2'}); + expect(url.queryDelimeter).toBe('&'); }); it('https://zs.usernanme_cms.test.api.pl/', function () { @@ -308,20 +325,22 @@ describe('uriparser - parse', function () { it('http://www.dreamlab.pl/test/test1/?a=3;b=1;a=2', function () { var url = uriparser.parse('http://www.dreamlab.pl/test/test1/?a=3;b=1;a=2', null, uriparser.Engines.NGINX); - expect(Object.keys(url).length).toEqual(4); + expect(Object.keys(url).length).toEqual(5); expect(url.protocol).toBe('http:'); expect(url.host).toBe('www.dreamlab.pl'); expect(url.path).toBe('/test/test1/'); expect(url.query).toEqual({ a: ['3', '2'], b: '1'}); + expect(url.queryDelimeter).toBe(';'); }); it('http://www.dreamlab.pl/test/test1/?a', function () { var url = uriparser.parse('http://www.dreamlab.pl/test/test1/?a', null, uriparser.Engines.NGINX); - expect(Object.keys(url).length).toEqual(4); + expect(Object.keys(url).length).toEqual(5); expect(url.protocol).toBe('http:'); expect(url.host).toBe('www.dreamlab.pl'); expect(url.path).toBe('/test/test1/'); expect(url.query).toEqual({ a: ''}); + expect(url.queryDelimeter).toBe('&'); }); }); From de13548f38a59ffcc118a1e0e0a193518b392d92 Mon Sep 17 00:00:00 2001 From: Marcin Kaciuba Date: Tue, 8 Mar 2016 12:13:23 +0100 Subject: [PATCH 16/22] update ngx_url_parser --- deps/ngx_url_parser | 2 +- tests/parseSpec.js | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/deps/ngx_url_parser b/deps/ngx_url_parser index 6f6d0ce..9e7c66b 160000 --- a/deps/ngx_url_parser +++ b/deps/ngx_url_parser @@ -1 +1 @@ -Subproject commit 6f6d0ced994a303f7a67f23b7830569d4463905c +Subproject commit 9e7c66b266c720403a9a486b5f524838599b87fa diff --git a/tests/parseSpec.js b/tests/parseSpec.js index deb0c01..60a55ca 100644 --- a/tests/parseSpec.js +++ b/tests/parseSpec.js @@ -343,4 +343,14 @@ describe('uriparser - parse', function () { expect(url.query).toEqual({ a: ''}); expect(url.queryDelimeter).toBe('&'); }); + + it('//www.dreamlab.pl/test/test1/?a', function () { + var url = uriparser.parse('//www.dreamlab.pl/test/test1/?a', null, uriparser.Engines.NGINX); + + expect(Object.keys(url).length).toEqual(4); + expect(url.host).toBe('www.dreamlab.pl'); + expect(url.path).toBe('/test/test1/'); + expect(url.query).toEqual({ a: ''}); + expect(url.queryDelimeter).toBe('&'); + }); }); From 47c8b6fe97aaf8546e233b709e99285cd4f11c37 Mon Sep 17 00:00:00 2001 From: Marcin Kaciuba Date: Wed, 9 Mar 2016 16:07:21 +0100 Subject: [PATCH 17/22] rename variable --- src/node-uriparser.cc | 14 +++++++------- tests/parseSpec.js | 40 ++++++++++++++++++++-------------------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/node-uriparser.cc b/src/node-uriparser.cc index 9c0ec55..b18e27e 100644 --- a/src/node-uriparser.cc +++ b/src/node-uriparser.cc @@ -55,7 +55,7 @@ static v8::Persistent host_symbol = NODE_PSYMBOL("host"); static v8::Persistent port_symbol = NODE_PSYMBOL("port"); static v8::Persistent query_symbol = NODE_PSYMBOL("query"); static v8::Persistent query_arr_suffix = NODE_PSYMBOL("queryArraySuffix"); -static v8::Persistent query_delimeter = NODE_PSYMBOL("queryDelimeter"); +static v8::Persistent query_separator = NODE_PSYMBOL("querySeparator"); static v8::Persistent fragment_symbol = NODE_PSYMBOL("fragment"); static v8::Persistent path_symbol = NODE_PSYMBOL("path"); static v8::Persistent user_symbol = NODE_PSYMBOL("user"); @@ -143,7 +143,7 @@ static v8::Handle parse(const v8::Arguments& args){ std::strncpy(query, uri.query.start, uri.query.len); query[uri.query.len] = '\0'; - const char *amp = "&", *sum = "=", *semicolon = ";", *delimeter = amp; + const char *amp = "&", *sum = "=", *semicolon = ";", *separator = amp; char *queryParamPairPtr, *queryParam, *queryParamKey, *queryParamValue, *queryParamPtr; bool empty = true; v8::Local qsSuffix = v8::Object::New(); @@ -151,17 +151,17 @@ static v8::Handle parse(const v8::Arguments& args){ // find qs delimeter & or ; for (size_t i = 0; i < uri.query.len; ++i) { if (query[i] == *amp) { - delimeter = amp; + separator = amp; break; } else if (query[i] == *semicolon) { - delimeter = semicolon; + separator = semicolon; break; } } - data->Set(query_delimeter, v8::String::New(delimeter), attrib); + data->Set(query_separator, v8::String::New(separator), attrib); - queryParam = strtok_r(query, delimeter, &queryParamPairPtr); + queryParam = strtok_r(query, separator, &queryParamPairPtr); v8::Local queryData = v8::Object::New(); bool arrayBrackets = false; @@ -193,7 +193,7 @@ static v8::Handle parse(const v8::Arguments& args){ } paramsMap[queryParamKey].push_back(queryParamValue ? queryParamValue : ""); } - queryParam = strtok_r(NULL, delimeter, &queryParamPairPtr); + queryParam = strtok_r(NULL, separator, &queryParamPairPtr); } for (std::vector::iterator it=paramsOrder.begin(); it!=paramsOrder.end(); ++it) { diff --git a/tests/parseSpec.js b/tests/parseSpec.js index 60a55ca..31b0c95 100644 --- a/tests/parseSpec.js +++ b/tests/parseSpec.js @@ -46,7 +46,7 @@ describe('uriparser - parse', function () { expect(Object.keys(url).length).toEqual(3); expect(url.path).toBe('1.txt'); expect(url.query).toEqual({'test1': 'okok'}); - expect(url.queryDelimeter).toBe('&'); + expect(url.querySeparator).toBe('&'); }); it('/1.txt?test1=okok', function () { @@ -55,7 +55,7 @@ describe('uriparser - parse', function () { expect(Object.keys(url).length).toEqual(3); expect(url.path).toBe('/1.txt'); expect(url.query).toEqual({'test1': 'okok'}); - expect(url.queryDelimeter).toBe('&'); + expect(url.querySeparator).toBe('&'); }); it('http://dreamlab.pl/X?X', function () { @@ -66,7 +66,7 @@ describe('uriparser - parse', function () { expect(url.host).toBe('dreamlab.pl'); expect(url.path).toBe('/X'); expect(url.query).toEqual({'X': ""}); - expect(url.queryDelimeter).toBe('&'); + expect(url.querySeparator).toBe('&'); }); it('http://dreamlab.pl/X', function () { @@ -95,7 +95,7 @@ describe('uriparser - parse', function () { expect(url.host).toBe('dreamlab.pl'); expect(url.path).toBe('/hejka/'); expect(url.query).toEqual({'hejka': "123"}) - expect(url.queryDelimeter).toBe('&'); + expect(url.querySeparator).toBe('&'); }); it('http://:@www.dreamlab.pl/?', function () { var url = uriparser.parse('http://:@www.dreamlab.pl/?'); @@ -104,7 +104,7 @@ describe('uriparser - parse', function () { expect(url.protocol).toBe('http:'); expect(url.host).toBe('www.dreamlab.pl'); expect(url.path).toBe('/'); - expect(url.queryDelimeter).toBe('&'); + expect(url.querySeparator).toBe('&'); }); it('http://user:@www.dreamlab.pl/?', function () { @@ -114,7 +114,7 @@ describe('uriparser - parse', function () { expect(url.protocol).toBe('http:'); expect(url.host).toBe('www.dreamlab.pl'); expect(url.path).toBe('/'); - expect(url.queryDelimeter).toBe('&'); + expect(url.querySeparator).toBe('&'); }); it('http://:pw@www.dreamlab.pl/?', function () { @@ -134,7 +134,7 @@ describe('uriparser - parse', function () { expect(url.auth).toEqual({'user': "user", "password": "pw"}); expect(url.host).toBe('www.dreamlab.pl'); expect(url.path).toBe('/'); - expect(url.queryDelimeter).toBe('&'); + expect(url.querySeparator).toBe('&'); }); it('http://www.dreamlab.pl/?=&=', function () { @@ -144,7 +144,7 @@ describe('uriparser - parse', function () { expect(url.protocol).toBe('http:'); expect(url.host).toBe('www.dreamlab.pl'); expect(url.path).toBe('/'); - expect(url.queryDelimeter).toBe('&'); + expect(url.querySeparator).toBe('&'); }); it('http://www.dreamlab.pl//test/123', function () { @@ -172,7 +172,7 @@ describe('uriparser - parse', function () { expect(url.protocol).toBe('http:'); expect(url.host).toBe('www.dreamlab.pl'); expect(url.query).toEqual({a: ['1', '2'], b: '4', c: '3'}); - expect(url.queryDelimeter).toBe('&'); + expect(url.querySeparator).toBe('&'); }); it('http://www.dreamlab.pl/test/?b=1&c=3&a%5B%5D=1&a%5B%5D=1', function () { @@ -183,7 +183,7 @@ describe('uriparser - parse', function () { expect(url.host).toBe('www.dreamlab.pl'); expect(url.query).toEqual({b: '1', c: '3', a: ['1', '2']}); expect(url.queryArraySuffix).toEqual({a: '%5B%5D'}); - expect(url.queryDelimeter).toBe('&'); + expect(url.querySeparator).toBe('&'); }); it('http://www.dreamlab.pl/test/test1/a[]=1&a[]=2', function () { @@ -195,7 +195,7 @@ describe('uriparser - parse', function () { expect(url.path).toBe('/test/test1/'); expect(url.query).toEqual({a: ['1', '2']}); expect(url.queryArraySuffix).toEqual({a: '[]'}); - expect(url.queryDelimeter).toBe('&'); + expect(url.querySeparator).toBe('&'); }); it('http://www.dreamlab.pl/test/test1/a[name]=1&a[name]=2', function () { @@ -206,7 +206,7 @@ describe('uriparser - parse', function () { expect(url.host).toBe('www.dreamlab.pl'); expect(url.path).toBe('/test/test1/'); expect(url.query).toEqual({'a[name]': ['1', '2']}); - expect(url.queryDelimeter).toBe('&'); + expect(url.querySeparator).toBe('&'); }); it('http://user:pw@www.dreamlab.pl/test/test1/a[name]=1&a[name]=2#fragment', function () { @@ -219,7 +219,7 @@ describe('uriparser - parse', function () { expect(url.query).toEqual({'a[name]': ['1', '2']}); expect(url.auth).toEqual({'user': 'user', 'password': 'pw'}); expect(url.fragment).toBe('fragment'); - expect(url.queryDelimeter).toBe('&'); + expect(url.querySeparator).toBe('&'); }); it('http://www.dreamlab.pl/test/test1/?b=3&a=1&a=2', function () { @@ -230,7 +230,7 @@ describe('uriparser - parse', function () { expect(url.host).toBe('www.dreamlab.pl'); expect(url.path).toBe('/test/test1/'); expect(url.query).toEqual({b:'3', a: ['1', '2']}); - expect(url.queryDelimeter).toBe('&'); + expect(url.querySeparator).toBe('&'); }); it('http://dreamlab.pl:/', function () { @@ -266,7 +266,7 @@ describe('uriparser - parse', function () { expect(url.port).toBe('80'); expect(url.path).toBe('/path/index.html'); expect(url.query).toEqual({arg1: '5'}); - expect(url.queryDelimeter).toBe('&'); + expect(url.querySeparator).toBe('&'); }); it('http:////', function () { @@ -297,7 +297,7 @@ describe('uriparser - parse', function () { expect(Object.keys(url).length).toEqual(3); expect(url.query).toEqual({'query': ''}); - expect(url.queryDelimeter).toBe('&'); + expect(url.querySeparator).toBe('&'); }); it('https://user_usr:password@www.dreamlab.pl:81/path/index.html?arg1=1&arg2=2', function () { @@ -310,7 +310,7 @@ describe('uriparser - parse', function () { expect(url.path).toBe('/path/index.html'); expect(url.auth).toEqual({user: 'user_usr', password: 'password'}); expect(url.query).toEqual({arg1: '1', arg2: '2'}); - expect(url.queryDelimeter).toBe('&'); + expect(url.querySeparator).toBe('&'); }); it('https://zs.usernanme_cms.test.api.pl/', function () { @@ -330,7 +330,7 @@ describe('uriparser - parse', function () { expect(url.host).toBe('www.dreamlab.pl'); expect(url.path).toBe('/test/test1/'); expect(url.query).toEqual({ a: ['3', '2'], b: '1'}); - expect(url.queryDelimeter).toBe(';'); + expect(url.querySeparator).toBe(';'); }); it('http://www.dreamlab.pl/test/test1/?a', function () { @@ -341,7 +341,7 @@ describe('uriparser - parse', function () { expect(url.host).toBe('www.dreamlab.pl'); expect(url.path).toBe('/test/test1/'); expect(url.query).toEqual({ a: ''}); - expect(url.queryDelimeter).toBe('&'); + expect(url.querySeparator).toBe('&'); }); it('//www.dreamlab.pl/test/test1/?a', function () { @@ -351,6 +351,6 @@ describe('uriparser - parse', function () { expect(url.host).toBe('www.dreamlab.pl'); expect(url.path).toBe('/test/test1/'); expect(url.query).toEqual({ a: ''}); - expect(url.queryDelimeter).toBe('&'); + expect(url.querySeparator).toBe('&'); }); }); From 56f1be61a41e20083a9d09c6815ad7425221542f Mon Sep 17 00:00:00 2001 From: Marcin Kaciuba Date: Wed, 26 Jul 2017 10:09:16 +0200 Subject: [PATCH 18/22] fixed parsing csr url; optimization --- .gitmodules | 3 - deps/ngx_url_parser | 2 +- deps/uriparser | 1 - package.json | 2 +- src/node-uriparser.cc | 68 ++++++++--------- src/parsers.hpp | 114 ---------------------------- tests/parseSpec.js | 172 ++++++++++++++++++++++++++++++++---------- wscript | 11 ++- 8 files changed, 169 insertions(+), 204 deletions(-) delete mode 160000 deps/uriparser diff --git a/.gitmodules b/.gitmodules index 94e50e5..14a014f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ -[submodule "deps/uriparser"] - path = deps/uriparser - url = git://git.code.sf.net/p/uriparser/git [submodule "deps/ngx_url_parser"] path = deps/ngx_url_parser url = https://github.com/DreamLab/ngx_url_parser diff --git a/deps/ngx_url_parser b/deps/ngx_url_parser index 9e7c66b..9d2bd75 160000 --- a/deps/ngx_url_parser +++ b/deps/ngx_url_parser @@ -1 +1 @@ -Subproject commit 9e7c66b266c720403a9a486b5f524838599b87fa +Subproject commit 9d2bd753ba7aa2d4510e79ad429d0e4ecb139905 diff --git a/deps/uriparser b/deps/uriparser deleted file mode 160000 index c87f53f..0000000 --- a/deps/uriparser +++ /dev/null @@ -1 +0,0 @@ -Subproject commit c87f53f727ed138739e0fd1b9345015e5b70bb3b diff --git a/package.json b/package.json index 1a61a50..ae9bef2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "uriparser", - "version": "1.2.13", + "version": "1.2.14", "description": "Fastest uriparser, written in C", "keywords": ["uriparser", "uri", "parser", "url"], "contributors": [ diff --git a/src/node-uriparser.cc b/src/node-uriparser.cc index b18e27e..937bb7a 100644 --- a/src/node-uriparser.cc +++ b/src/node-uriparser.cc @@ -44,10 +44,6 @@ enum parseOptions { kAll = kProtocol | kAuth | kHost | kPort | kQuery | kFragment | kPath }; -enum Engines { - eUriParser = 1, - eNgxParser -}; static v8::Persistent protocol_symbol = NODE_PSYMBOL("protocol"); static v8::Persistent auth_symbol = NODE_PSYMBOL("auth"); @@ -59,12 +55,12 @@ static v8::Persistent query_separator = NODE_PSYMBOL("querySeparator static v8::Persistent fragment_symbol = NODE_PSYMBOL("fragment"); static v8::Persistent path_symbol = NODE_PSYMBOL("path"); static v8::Persistent user_symbol = NODE_PSYMBOL("user"); +static v8::Persistent search_symbol = NODE_PSYMBOL("search"); static v8::Persistent password_symbol = NODE_PSYMBOL("password"); static v8::Handle parse(const v8::Arguments& args){ v8::HandleScope scope; parseOptions opts = kAll; - Engines engine = eNgxParser; if (args.Length() == 0 || !args[0]->IsString()) { return v8::ThrowException(v8::Exception::TypeError(v8::String::New("First argument has to be string"))); @@ -80,26 +76,16 @@ static v8::Handle parse(const v8::Arguments& args){ return v8::ThrowException(v8::Exception::TypeError(v8::String::New("String mustn't be empty"))); } - if (args[2]->IsNumber()) { - engine = static_cast(args[2]->Int32Value()); - } - v8::PropertyAttribute attrib = (v8::PropertyAttribute) (v8::ReadOnly | v8::DontDelete); v8::Local data = v8::Object::New(); Url uri; - Parser *parser; - - if (engine == eUriParser) { - parser = new UriParser(*url); - } else { - parser = new NgxParser(*url); - } + NgxParser parser(*url); - if (parser->status != Parser::OK) { + if (parser.status != Parser::OK) { return v8::ThrowException(v8::Exception::Error(v8::String::New("Unable to parse given url"))); } - uri = parser->url; + uri = parser.url; if (uri.scheme.start && (opts & kProtocol)) { // +1 becasue we need ":" in scheme/protocol @@ -137,16 +123,19 @@ static v8::Handle parse(const v8::Arguments& args){ } if (uri.query.start && (opts & kQuery)) { - std::map > paramsMap; - std::vector paramsOrder; - char *query = new char[uri.query.len + 1]; - std::strncpy(query, uri.query.start, uri.query.len); - query[uri.query.len] = '\0'; + std::map > paramsMap; + std::vector paramsOrder; + paramsOrder.reserve(uri.query.len / 2); + char *query = new char[uri.query.len + 2]; + std::strncpy(query, uri.query.start - 1, uri.query.len + 1); + query[uri.query.len + 1] = '\0'; const char *amp = "&", *sum = "=", *semicolon = ";", *separator = amp; char *queryParamPairPtr, *queryParam, *queryParamKey, *queryParamValue, *queryParamPtr; bool empty = true; v8::Local qsSuffix = v8::Object::New(); + data->Set(search_symbol, v8::String::New(query), attrib); + query++; // find qs delimeter & or ; for (size_t i = 0; i < uri.query.len; ++i) { @@ -167,8 +156,9 @@ static v8::Handle parse(const v8::Arguments& args){ bool arrayBrackets = false; while (queryParam) { if (*queryParam != *sum) { - size_t len; empty = false; + uint16_t len, queryLen; + queryLen = strlen(queryParam); queryParamKey = strtok_r(queryParam, sum, &queryParamPtr); len = strlen(queryParamKey); if (len > (sizeof(ENCODED_BRACKETS) - 1) && @@ -187,30 +177,39 @@ static v8::Handle parse(const v8::Arguments& args){ qsSuffix->Set(v8::String::New(queryParamKey), v8::String::New(BRACKETS)); } - queryParamValue = strtok_r(NULL, sum, &queryParamPtr); + queryParamValue = strtok_r(NULL, separator, &queryParamPtr); if (paramsMap.find(queryParamKey) == paramsMap.end()) { paramsOrder.push_back(queryParamKey); } - paramsMap[queryParamKey].push_back(queryParamValue ? queryParamValue : ""); + if (queryLen - len > 0) { + paramsMap[queryParamKey].push_back(queryParamValue ? queryParamValue: ""); + } else { + paramsMap[queryParamKey].push_back(NULL); + } } queryParam = strtok_r(NULL, separator, &queryParamPairPtr); } - for (std::vector::iterator it=paramsOrder.begin(); it!=paramsOrder.end(); ++it) { - v8::Local key = v8::String::New(it->c_str()); - std::list vals = paramsMap[*it]; + for (std::vector::iterator it=paramsOrder.begin(); it!=paramsOrder.end(); ++it) { + v8::Local key = v8::String::New(*it); + std::vector &vals = paramsMap[*it]; int arrSize = vals.size(); if (arrSize > 1 || qsSuffix->Has(key)) { v8::Local arrVal = v8::Array::New(arrSize); int i = 0; - for (std::list::iterator it2 = vals.begin(); it2 != vals.end(); ++it2) { + for (std::vector::iterator it2 = vals.begin(); it2 != vals.end(); ++it2) { arrVal->Set(i, v8::String::New(*it2)); i++; } queryData->Set(key, arrVal); } else { - queryData->Set(key, v8::String::New(vals.front())); + const char * tmp = vals.front(); + if (tmp) { + queryData->Set(key, v8::String::New(vals.front())); + } else { + queryData->Set(key, v8::Null()); + } } } @@ -222,6 +221,7 @@ static v8::Handle parse(const v8::Arguments& args){ } } + query--; delete[] query; } @@ -237,7 +237,6 @@ static v8::Handle parse(const v8::Arguments& args){ } } - delete parser; return scope.Close(data); } @@ -268,11 +267,6 @@ extern "C" void init (v8::Handle target){ uri->Set(v8::String::New("ALL"), v8::Integer::New(kAll)); target->Set(v8::String::New("Uri"), uri); - v8::Handle engines = v8::Object::New(); - engines->Set(v8::String::New("URIPARSER"), v8::Integer::New(eUriParser)); - engines->Set(v8::String::New("NGINX"), v8::Integer::New(eNgxParser)); - target->Set(v8::String::New("Engines"), engines); - } NODE_MODULE(uriparser, init) diff --git a/src/parsers.hpp b/src/parsers.hpp index 0c56e77..2f0538f 100644 --- a/src/parsers.hpp +++ b/src/parsers.hpp @@ -23,7 +23,6 @@ extern "C" { #include } -#include // base structure for url properties typedef struct { @@ -100,116 +99,3 @@ class NgxParser: public Parser { protected: ngx_http_url_meta url_meta; }; - -class UriParser: public Parser { - public: - UriParser(const char *str): Parser(str), m_uri(), m_state() { - - m_state.uri = &m_uri; - if (uriParseUriA(&m_state, str) == URI_SUCCESS) { - status = Parser::OK; - } else { - status = Parser::ERROR; - return; - } - if (m_uri.scheme.first) { - url.scheme.start = m_uri.scheme.first; - url.scheme.len = calculateLen(m_uri.scheme); - } - - if (m_uri.userInfo.first) { - url.auth.start = m_uri.userInfo.first; - url.auth.len = calculateLen(m_uri.userInfo); - } - - if (m_uri.hostText.first) { - url.host.start = m_uri.hostText.first; - url.host.len = calculateLen(m_uri.hostText); - } - - if (m_uri.portText.first) { - url.port.start = m_uri.portText.first; - url.port.len = calculateLen(m_uri.portText); - } - - if (m_uri.query.first) { - url.query.start = m_uri.query.first; - url.query.len = calculateLen(m_uri.query); - } - - if (m_uri.fragment.first) { - url.fragment.start = m_uri.fragment.first; - url.fragment.len = calculateLen(m_uri.fragment); - } - - if (m_uri.pathHead && m_uri.pathHead->text.first) { - int len = 0; - - UriPathSegmentA *pathHead = m_uri.pathHead; - do { - if (pathHead->text.first == pathHead->text.afterLast) { - len++; - } else { - //len +1 because we need to add slash - len += pathHead->text.afterLast - pathHead->text.first + 1; - } - pathHead = pathHead->next; - } while (pathHead); - - char *path, *p, *tmp; - path = p = tmp = new char[len + 1]; - path[len] = '\0'; - - pathHead = m_uri.pathHead; - do { - // adding slash no matter what - *path = '/'; - path++; - // copying text only in case when path segment is not empty - if (pathHead->text.first != pathHead->text.afterLast) { - int localLen = pathHead->text.afterLast - pathHead->text.first; - memcpy(path, pathHead->text.first, localLen); - path += localLen; - } - pathHead = pathHead->next; - } while (pathHead); - - // path is always prefixed with / in case of relative url we move pointer further - if (!m_uri.absolutePath && !m_uri.hostText.first) { - p++; - } - - int pathLen = std::strlen(p); - char * pathPtr = new char[pathLen + 1]; - std::strcpy(pathPtr, p); - url.path.start = pathPtr; - url.path.len = pathLen; - delete[] tmp; - - } else { - char * pathPtr = new char[2]; - pathPtr[0] = '/'; - pathPtr[1] = '\0'; - url.path.start = pathPtr; - url.path.len = 1; - } - - } - - virtual ~UriParser() { - uriFreeUriMembersA(&m_uri); - - if (url.path.start) { - delete[] url.path.start; - url.path.start = NULL; - } - } - - private: - UriUriA m_uri; - UriParserStateA m_state; - - inline size_t calculateLen(UriTextRangeStructA &src) { - return src.afterLast - src.first; - } -}; diff --git a/tests/parseSpec.js b/tests/parseSpec.js index 31b0c95..1d9c248 100644 --- a/tests/parseSpec.js +++ b/tests/parseSpec.js @@ -43,30 +43,33 @@ describe('uriparser - parse', function () { it('1.txt?test1=okok', function () { var url = uriparser.parse('1.txt?test1=okok'); - expect(Object.keys(url).length).toEqual(3); + expect(Object.keys(url).length).toEqual(4); expect(url.path).toBe('1.txt'); expect(url.query).toEqual({'test1': 'okok'}); expect(url.querySeparator).toBe('&'); + expect(url.search).toBe('?test1=okok'); }); it('/1.txt?test1=okok', function () { var url = uriparser.parse('/1.txt?test1=okok'); - expect(Object.keys(url).length).toEqual(3); + expect(Object.keys(url).length).toEqual(4); expect(url.path).toBe('/1.txt'); expect(url.query).toEqual({'test1': 'okok'}); expect(url.querySeparator).toBe('&'); + expect(url.search).toBe('?test1=okok'); }); it('http://dreamlab.pl/X?X', function () { var url = uriparser.parse('http://dreamlab.pl/X?X'); - expect(Object.keys(url).length).toEqual(5); + expect(Object.keys(url).length).toEqual(6); expect(url.protocol).toBe('http:'); expect(url.host).toBe('dreamlab.pl'); expect(url.path).toBe('/X'); - expect(url.query).toEqual({'X': ""}); + expect(url.query).toEqual({'X': null}); expect(url.querySeparator).toBe('&'); + expect(url.search).toBe('?X'); }); it('http://dreamlab.pl/X', function () { @@ -90,61 +93,67 @@ describe('uriparser - parse', function () { it('http://dreamlab.pl/hejka/?hejka=123', function () { var url = uriparser.parse('http://dreamlab.pl/hejka/?hejka=123'); - expect(Object.keys(url).length).toEqual(5); + expect(Object.keys(url).length).toEqual(6); expect(url.protocol).toBe('http:'); expect(url.host).toBe('dreamlab.pl'); expect(url.path).toBe('/hejka/'); expect(url.query).toEqual({'hejka': "123"}) expect(url.querySeparator).toBe('&'); + expect(url.search).toBe('?hejka=123'); }); it('http://:@www.dreamlab.pl/?', function () { var url = uriparser.parse('http://:@www.dreamlab.pl/?'); - expect(Object.keys(url).length).toEqual(4); + expect(Object.keys(url).length).toEqual(5); expect(url.protocol).toBe('http:'); expect(url.host).toBe('www.dreamlab.pl'); expect(url.path).toBe('/'); expect(url.querySeparator).toBe('&'); + expect(url.search).toBe('?'); }); it('http://user:@www.dreamlab.pl/?', function () { var url = uriparser.parse('http://user:@www.dreamlab.pl/?'); - expect(Object.keys(url).length).toEqual(4); + expect(Object.keys(url).length).toEqual(5); expect(url.protocol).toBe('http:'); expect(url.host).toBe('www.dreamlab.pl'); expect(url.path).toBe('/'); expect(url.querySeparator).toBe('&'); + expect(url.search).toBe('?'); }); it('http://:pw@www.dreamlab.pl/?', function () { var url = uriparser.parse('http://:pw@www.dreamlab.pl/?'); - expect(Object.keys(url).length).toEqual(4); + expect(Object.keys(url).length).toEqual(5); expect(url.protocol).toBe('http:'); expect(url.host).toBe('www.dreamlab.pl'); expect(url.path).toBe('/'); + expect(url.search).toBe('?'); }); it('http://user:pw@www.dreamlab.pl/?', function () { var url = uriparser.parse('http://user:pw@www.dreamlab.pl/?'); - expect(Object.keys(url).length).toEqual(5); + expect(Object.keys(url).length).toEqual(6); expect(url.protocol).toBe('http:'); expect(url.auth).toEqual({'user': "user", "password": "pw"}); expect(url.host).toBe('www.dreamlab.pl'); expect(url.path).toBe('/'); expect(url.querySeparator).toBe('&'); + expect(url.search).toBe('?'); }); it('http://www.dreamlab.pl/?=&=', function () { var url = uriparser.parse('http://www.dreamlab.pl/?=&='); - expect(Object.keys(url).length).toEqual(4); + expect(Object.keys(url).length).toEqual(5); expect(url.protocol).toBe('http:'); expect(url.host).toBe('www.dreamlab.pl'); expect(url.path).toBe('/'); expect(url.querySeparator).toBe('&'); + expect(url.search).toBe('?=&='); }); it('http://www.dreamlab.pl//test/123', function () { @@ -168,51 +177,55 @@ describe('uriparser - parse', function () { it('http://www.dreamlab.pl/test/?a=1&b=1&a=2&c=3', function () { var url = uriparser.parse('http://www.dreamlab.pl/test/?a=1&b=4&a=2&c=3'); - expect(Object.keys(url).length).toEqual(5); + expect(Object.keys(url).length).toEqual(6); expect(url.protocol).toBe('http:'); expect(url.host).toBe('www.dreamlab.pl'); expect(url.query).toEqual({a: ['1', '2'], b: '4', c: '3'}); expect(url.querySeparator).toBe('&'); + expect(url.search).toBe('?a=1&b=4&a=2&c=3'); }); it('http://www.dreamlab.pl/test/?b=1&c=3&a%5B%5D=1&a%5B%5D=1', function () { var url = uriparser.parse('http://www.dreamlab.pl/test/?b=1&c=3&a%5B%5D=1&a%5B%5D=2'); - expect(Object.keys(url).length).toEqual(6); + expect(Object.keys(url).length).toEqual(7); expect(url.protocol).toBe('http:'); expect(url.host).toBe('www.dreamlab.pl'); expect(url.query).toEqual({b: '1', c: '3', a: ['1', '2']}); expect(url.queryArraySuffix).toEqual({a: '%5B%5D'}); expect(url.querySeparator).toBe('&'); + expect(url.search).toBe('?b=1&c=3&a%5B%5D=1&a%5B%5D=2'); }); it('http://www.dreamlab.pl/test/test1/a[]=1&a[]=2', function () { - var url = uriparser.parse('http://www.dreamlab.pl/test/test1/?a[]=1&a[]=2', null, uriparser.Engines.NGINX); + var url = uriparser.parse('http://www.dreamlab.pl/test/test1/?a[]=1&a[]=2'); - expect(Object.keys(url).length).toEqual(6); + expect(Object.keys(url).length).toEqual(7); expect(url.protocol).toBe('http:'); expect(url.host).toBe('www.dreamlab.pl'); expect(url.path).toBe('/test/test1/'); expect(url.query).toEqual({a: ['1', '2']}); expect(url.queryArraySuffix).toEqual({a: '[]'}); expect(url.querySeparator).toBe('&'); + expect(url.search).toBe('?a[]=1&a[]=2'); }); it('http://www.dreamlab.pl/test/test1/a[name]=1&a[name]=2', function () { - var url = uriparser.parse('http://www.dreamlab.pl/test/test1/?a[name]=1&a[name]=2', null, uriparser.Engines.NGINX); + var url = uriparser.parse('http://www.dreamlab.pl/test/test1/?a[name]=1&a[name]=2'); - expect(Object.keys(url).length).toEqual(5); + expect(Object.keys(url).length).toEqual(6); expect(url.protocol).toBe('http:'); expect(url.host).toBe('www.dreamlab.pl'); expect(url.path).toBe('/test/test1/'); expect(url.query).toEqual({'a[name]': ['1', '2']}); expect(url.querySeparator).toBe('&'); + expect(url.search).toBe('?a[name]=1&a[name]=2'); }); it('http://user:pw@www.dreamlab.pl/test/test1/a[name]=1&a[name]=2#fragment', function () { - var url = uriparser.parse('http://user:pw@www.dreamlab.pl/test/test1/?a[name]=1&a[name]=2#fragment', null, uriparser.Engines.NGINX); + var url = uriparser.parse('http://user:pw@www.dreamlab.pl/test/test1/?a[name]=1&a[name]=2#fragment'); - expect(Object.keys(url).length).toEqual(7); + expect(Object.keys(url).length).toEqual(8); expect(url.protocol).toBe('http:'); expect(url.host).toBe('www.dreamlab.pl'); expect(url.path).toBe('/test/test1/'); @@ -220,21 +233,23 @@ describe('uriparser - parse', function () { expect(url.auth).toEqual({'user': 'user', 'password': 'pw'}); expect(url.fragment).toBe('fragment'); expect(url.querySeparator).toBe('&'); + expect(url.search).toBe('?a[name]=1&a[name]=2'); }); it('http://www.dreamlab.pl/test/test1/?b=3&a=1&a=2', function () { - var url = uriparser.parse('http://www.dreamlab.pl/test/test1/?b=3&a=1&a=2', null, uriparser.Engines.NGINX); + var url = uriparser.parse('http://www.dreamlab.pl/test/test1/?b=3&a=1&a=2'); - expect(Object.keys(url).length).toEqual(5); + expect(Object.keys(url).length).toEqual(6); expect(url.protocol).toBe('http:'); expect(url.host).toBe('www.dreamlab.pl'); expect(url.path).toBe('/test/test1/'); expect(url.query).toEqual({b:'3', a: ['1', '2']}); expect(url.querySeparator).toBe('&'); + expect(url.search).toBe('?b=3&a=1&a=2'); }); it('http://dreamlab.pl:/', function () { - var url = uriparser.parse('http://www.dreamlab.pl:/', null, uriparser.Engines.NGINX); + var url = uriparser.parse('http://www.dreamlab.pl:/'); expect(Object.keys(url).length).toEqual(4); expect(url.protocol).toBe('http:'); @@ -243,13 +258,13 @@ describe('uriparser - parse', function () { }); it('http://dreamlab.pl:/ - only protocol', function () { - var url = uriparser.parse('http://www.dreamlab.pl:/', uriparser.Uri.PROTOCOL, uriparser.Engines.NGINX); + var url = uriparser.parse('http://www.dreamlab.pl:/', uriparser.Uri.PROTOCOL); expect(Object.keys(url).length).toEqual(1); expect(url.protocol).toBe('http:'); }); it('http://dreamlab.pl:', function () { - var url = uriparser.parse('http://www.dreamlab.pl:', null, uriparser.Engines.NGINX); + var url = uriparser.parse('http://www.dreamlab.pl:'); expect(Object.keys(url).length).toEqual(4); expect(url.protocol).toBe('http:'); @@ -258,19 +273,20 @@ describe('uriparser - parse', function () { }); it('http://dreamlab.pl:80/path/index.html?arg1=5', function () { - var url = uriparser.parse('http://www.dreamlab.pl:80/path/index.html?arg1=5', null, uriparser.Engines.NGINX); + var url = uriparser.parse('http://www.dreamlab.pl:80/path/index.html?arg1=5'); - expect(Object.keys(url).length).toEqual(6); + expect(Object.keys(url).length).toEqual(7); expect(url.protocol).toBe('http:'); expect(url.host).toBe('www.dreamlab.pl'); expect(url.port).toBe('80'); expect(url.path).toBe('/path/index.html'); expect(url.query).toEqual({arg1: '5'}); expect(url.querySeparator).toBe('&'); + expect(url.search).toBe('?arg1=5'); }); it('http:////', function () { - var url = uriparser.parse('http:////', null, uriparser.Engines.NGINX); + var url = uriparser.parse('http:////'); expect(Object.keys(url).length).toEqual(3); expect(url.protocol).toBe('http:'); @@ -279,31 +295,32 @@ describe('uriparser - parse', function () { }); it('somestring', function () { - var url = uriparser.parse('somestring', null, uriparser.Engines.NGINX); + var url = uriparser.parse('somestring'); expect(Object.keys(url).length).toEqual(1); expect(url.path).toBe('somestring'); }); it('#fragmen/t', function () { - var url = uriparser.parse('#fragmen/t', null, uriparser.Engines.NGINX); + var url = uriparser.parse('#fragmen/t'); expect(Object.keys(url).length).toEqual(2); expect(url.fragment).toBe('fragmen/t'); }); it('?query', function () { - var url = uriparser.parse('?query', null, uriparser.Engines.NGINX); + var url = uriparser.parse('?query'); - expect(Object.keys(url).length).toEqual(3); - expect(url.query).toEqual({'query': ''}); + expect(Object.keys(url).length).toEqual(4); + expect(url.query).toEqual({'query': null}); + expect(url.search).toBe('?query'); expect(url.querySeparator).toBe('&'); }); it('https://user_usr:password@www.dreamlab.pl:81/path/index.html?arg1=1&arg2=2', function () { - var url = uriparser.parse('https://user_usr:password@www.dreamlab.pl:81/path/index.html?arg1=1&arg2=2', null, uriparser.Engines.NGINX); + var url = uriparser.parse('https://user_usr:password@www.dreamlab.pl:81/path/index.html?arg1=1&arg2=2'); - expect(Object.keys(url).length).toEqual(7); + expect(Object.keys(url).length).toEqual(8); expect(url.protocol).toBe('https:'); expect(url.host).toBe('www.dreamlab.pl'); expect(url.port).toBe('81'); @@ -311,10 +328,11 @@ describe('uriparser - parse', function () { expect(url.auth).toEqual({user: 'user_usr', password: 'password'}); expect(url.query).toEqual({arg1: '1', arg2: '2'}); expect(url.querySeparator).toBe('&'); + expect(url.search).toBe('?arg1=1&arg2=2'); }); it('https://zs.usernanme_cms.test.api.pl/', function () { - var url = uriparser.parse('https://zs.usernanme_cms.test.api.pl/', null, uriparser.Engines.NGINX); + var url = uriparser.parse('https://zs.usernanme_cms.test.api.pl/'); expect(Object.keys(url).length).toEqual(3); expect(url.protocol).toBe('https:'); @@ -323,34 +341,106 @@ describe('uriparser - parse', function () { }); it('http://www.dreamlab.pl/test/test1/?a=3;b=1;a=2', function () { - var url = uriparser.parse('http://www.dreamlab.pl/test/test1/?a=3;b=1;a=2', null, uriparser.Engines.NGINX); + var url = uriparser.parse('http://www.dreamlab.pl/test/test1/?a=3;b=1;a=2'); - expect(Object.keys(url).length).toEqual(5); + expect(Object.keys(url).length).toEqual(6); expect(url.protocol).toBe('http:'); expect(url.host).toBe('www.dreamlab.pl'); expect(url.path).toBe('/test/test1/'); expect(url.query).toEqual({ a: ['3', '2'], b: '1'}); expect(url.querySeparator).toBe(';'); + expect(url.search).toBe('?a=3;b=1;a=2'); }); - it('http://www.dreamlab.pl/test/test1/?a', function () { - var url = uriparser.parse('http://www.dreamlab.pl/test/test1/?a', null, uriparser.Engines.NGINX); + it('http://www.dreamlab.pl/test/test1/?a=3;b;a=2', function () { + var url = uriparser.parse('http://www.dreamlab.pl/test/test1/?a=3;b;a=2'); - expect(Object.keys(url).length).toEqual(5); + expect(Object.keys(url).length).toEqual(6); + expect(url.protocol).toBe('http:'); + expect(url.host).toBe('www.dreamlab.pl'); + expect(url.path).toBe('/test/test1/'); + expect(url.query).toEqual({ a: ['3', '2'], b: null}); + expect(url.querySeparator).toBe(';'); + expect(url.search).toBe('?a=3;b;a=2'); + }); + + it('http://www.dreamlab.pl/test/test1/?a=', function () { + var url = uriparser.parse('http://www.dreamlab.pl/test/test1/?a='); + + expect(Object.keys(url).length).toEqual(6); expect(url.protocol).toBe('http:'); expect(url.host).toBe('www.dreamlab.pl'); expect(url.path).toBe('/test/test1/'); expect(url.query).toEqual({ a: ''}); expect(url.querySeparator).toBe('&'); + expect(url.search).toBe('?a='); + }); + + it('http://www.dreamlab.pl/test/test1/?a', function () { + var url = uriparser.parse('http://www.dreamlab.pl/test/test1/?a'); + + expect(Object.keys(url).length).toEqual(6); + expect(url.protocol).toBe('http:'); + expect(url.host).toBe('www.dreamlab.pl'); + expect(url.path).toBe('/test/test1/'); + expect(url.query).toEqual({ a: null}); + expect(url.querySeparator).toBe('&'); + expect(url.search).toBe('?a'); }); it('//www.dreamlab.pl/test/test1/?a', function () { - var url = uriparser.parse('//www.dreamlab.pl/test/test1/?a', null, uriparser.Engines.NGINX); + var url = uriparser.parse('//www.dreamlab.pl/test/test1/?a'); - expect(Object.keys(url).length).toEqual(4); + expect(Object.keys(url).length).toEqual(5); expect(url.host).toBe('www.dreamlab.pl'); expect(url.path).toBe('/test/test1/'); + expect(url.query).toEqual({ a: null}); + expect(url.querySeparator).toBe('&'); + expect(url.search).toBe('?a'); + }); + + it('/?a', function () { + var url = uriparser.parse('/?a'); + + expect(Object.keys(url).length).toEqual(4); + expect(url.path).toBe('/'); + expect(url.query).toEqual({ a: null}); + expect(url.querySeparator).toBe('&'); + expect(url.search).toBe('?a'); + }); + + it('/?a=', function () { + var url = uriparser.parse('/?a='); + + expect(Object.keys(url).length).toEqual(4); + expect(url.path).toBe('/'); expect(url.query).toEqual({ a: ''}); expect(url.querySeparator).toBe('&'); + expect(url.search).toBe('?a='); + }); + + it('/.!@$%^&*()_-feed', function () { + var url = uriparser.parse('/.!@$%^&*()_-feed'); + + expect(Object.keys(url).length).toEqual(1); + expect(url.path).toBe('/.!@$%^&*()_-feed'); + }); + + it('.!@$%^&*()_-feed', function () { + var url = uriparser.parse('.!@$%^&*()_-feed'); + + expect(Object.keys(url).length).toEqual(1); + expect(url.path).toBe('.!@$%^&*()_-feed'); + }); + + it('/adclick?a=1&d2dest=https://ad.doubleclick.net/ddm/trackclk/N100601.127443ONET.PL/B11524173.200789083;dc_trk_aid=400712373;dc_trk_cid=83040526;dc_lat=;dc_rdid=;tag_for_child_directed_treatment=', function () { + var url = uriparser.parse('/adclick?a=1&d2dest=https://ad.doubleclick.net/ddm/trackclk/N100601.127443ONET.PL/B11524173.200789083;dc_trk_aid=400712373;dc_trk_cid=83040526;dc_lat=;dc_rdid=;tag_for_child_directed_treatment='); + + expect(Object.keys(url).length).toEqual(4); + expect(url.path).toBe('/adclick'); + expect(url.search).toBe('?a=1&d2dest=https://ad.doubleclick.net/ddm/trackclk/N100601.127443ONET.PL/B11524173.200789083;dc_trk_aid=400712373;dc_trk_cid=83040526;dc_lat=;dc_rdid=;tag_for_child_directed_treatment='); + expect(url.query).toEqual({ a : '1', + d2dest : 'https://ad.doubleclick.net/ddm/trackclk/N100601.127443ONET.PL/B11524173.200789083;dc_trk_aid=400712373;dc_trk_cid=83040526;dc_lat=;dc_rdid=;tag_for_child_directed_treatment=' + }); }); }); diff --git a/wscript b/wscript index 810b4a3..4771afa 100644 --- a/wscript +++ b/wscript @@ -24,13 +24,12 @@ def do_clean(): def build(bld): if Options.options.buildUri == True and do_clean() == False: bld.exec_command("mkdir -p ngx_url_parser; cd ../deps/ngx_url_parser && ./autogen.sh && ./configure --with-pic --disable-shared --prefix=%s && make clean install" %(bld.bdir + "/ngx_url_parser")) - bld.exec_command("mkdir -p uriparser; cd ../deps/uriparser && ./autogen.sh && ./configure --with-pic --disable-test --disable-doc --disable-shared --prefix=%s && make clean install" % (bld.bdir + "/uriparser")) obj = bld.new_task_gen("cxx", "shlib", "node_addon") obj.target = "uriparser" obj.source = "src/node-uriparser.cc" - obj.lib = ["uriparser", "ngx_url_parser"] - obj.includes = [bld.bdir + "/uriparser/include/uriparser", bld.bdir + "/ngx_url_parser/include/ngx_url_parser", "node_modules/nan/"] - obj.libpath = [bld.bdir + "/uriparser/lib", bld.bdir + '/ngx_url_parser/lib'] - obj.cxxflags = ["-g"] - obj.cflags = ["-g"] + obj.lib = [ "ngx_url_parser"] + obj.includes = [bld.bdir + "/ngx_url_parser/include/ngx_url_parser"] + obj.libpath = [bld.bdir + '/ngx_url_parser/lib'] + obj.cxxflags = ["-O3"] + obj.cflags = ["-O3"] From d570c9c70e6d7648ffe5faaa6fb81cf7b29e73fa Mon Sep 17 00:00:00 2001 From: Marcin Kaciuba Date: Wed, 26 Jul 2017 11:45:38 +0200 Subject: [PATCH 19/22] change package versioon --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ae9bef2..32c6b83 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "uriparser", - "version": "1.2.14", + "version": "1.3.0", "description": "Fastest uriparser, written in C", "keywords": ["uriparser", "uri", "parser", "url"], "contributors": [ From b35502d699a38f99a27dc5a50cf6c2353efda092 Mon Sep 17 00:00:00 2001 From: Marcin Kaciuba Date: Wed, 26 Jul 2017 13:43:41 +0200 Subject: [PATCH 20/22] change version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 32c6b83..ae9bef2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "uriparser", - "version": "1.3.0", + "version": "1.2.14", "description": "Fastest uriparser, written in C", "keywords": ["uriparser", "uri", "parser", "url"], "contributors": [ From 18c4347ae80413d2d708e9069cabe15f1c3110bb Mon Sep 17 00:00:00 2001 From: Marcin Kaciuba Date: Wed, 26 Jul 2017 13:47:56 +0200 Subject: [PATCH 21/22] change version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ae9bef2..7f03876 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "uriparser", - "version": "1.2.14", + "version": "1.2.15", "description": "Fastest uriparser, written in C", "keywords": ["uriparser", "uri", "parser", "url"], "contributors": [ From 843a4951bb4844afe8be67d32bf56c2453f34d9c Mon Sep 17 00:00:00 2001 From: Marcin Kaciuba Date: Thu, 27 Jul 2017 10:14:05 +0200 Subject: [PATCH 22/22] fixed segfault when parsing url with arguments without value --- package.json | 2 +- src/node-uriparser.cc | 6 +++++- tests/parseSpec.js | 19 +++++++++++++++++++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 7f03876..d486f24 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "uriparser", - "version": "1.2.15", + "version": "1.2.16", "description": "Fastest uriparser, written in C", "keywords": ["uriparser", "uri", "parser", "url"], "contributors": [ diff --git a/src/node-uriparser.cc b/src/node-uriparser.cc index 937bb7a..a5ffd03 100644 --- a/src/node-uriparser.cc +++ b/src/node-uriparser.cc @@ -199,7 +199,11 @@ static v8::Handle parse(const v8::Arguments& args){ int i = 0; for (std::vector::iterator it2 = vals.begin(); it2 != vals.end(); ++it2) { - arrVal->Set(i, v8::String::New(*it2)); + if (*it2 != NULL) { + arrVal->Set(i, v8::String::New(*it2)); + } else { + arrVal->Set(i, v8::Null()); + } i++; } queryData->Set(key, arrVal); diff --git a/tests/parseSpec.js b/tests/parseSpec.js index 1d9c248..760a53d 100644 --- a/tests/parseSpec.js +++ b/tests/parseSpec.js @@ -443,4 +443,23 @@ describe('uriparser - parse', function () { d2dest : 'https://ad.doubleclick.net/ddm/trackclk/N100601.127443ONET.PL/B11524173.200789083;dc_trk_aid=400712373;dc_trk_cid=83040526;dc_lat=;dc_rdid=;tag_for_child_directed_treatment=' }); }); + + it('http://dreamlab.pl/?attach_external_tab&180508352&4&0&0&0&0&iexplore', function () { + + var url = uriparser.parse('http://dreamlab.pl/?attach_external_tab&180508352&4&0&0&0&0&iexplore'); + + expect(Object.keys(url).length).toEqual(6); + expect(url.protocol).toBe('http:'); + expect(url.host).toBe('dreamlab.pl'); + expect(url.search).toBe('?attach_external_tab&180508352&4&0&0&0&0&iexplore'); + expect(url.query).toEqual({ + '0': [ null, null, null, null ], + '4': null, + '180508352': null, + attach_external_tab: null, + iexplore: null + }); + expect(url.path).toBe('/'); + }); + });