summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>2010-09-11 09:11:57 +0000
committerTatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>2010-09-11 09:11:57 +0000
commitec3bd81486d6f9b266753984f0da31f8d39fd951 (patch)
tree1c9d8870d478781deb0c6ade762c8d15645c1d10 /src
parentcb796432eca9d0ebf7b782c04a1cdc13e555793b (diff)
2010-09-11 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
Moved URI parser code to uri.h, uri.cc to provide fast URI parser without Request object initialization. * src/Makefile.am * src/Request.cc * src/uri.cc * src/uri.h * test/Makefile.am * test/RequestTest.cc * test/UriTest.cc
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am3
-rw-r--r--src/Makefile.in28
-rw-r--r--src/Request.cc167
-rw-r--r--src/uri.cc207
-rw-r--r--src/uri.h71
5 files changed, 310 insertions, 166 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 813c96a1..f9a9818e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -211,7 +211,8 @@ SRCS = Socket.h\
SinkStreamFilter.cc SinkStreamFilter.h\
GZipDecodingStreamFilter.cc GZipDecodingStreamFilter.h\
ChunkedDecodingStreamFilter.cc ChunkedDecodingStreamFilter.h\
- NullSinkStreamFilter.cc NullSinkStreamFilter.h
+ NullSinkStreamFilter.cc NullSinkStreamFilter.h\
+ uri.cc uri.h
if ENABLE_XML_RPC
SRCS += XmlRpcRequestParserController.cc XmlRpcRequestParserController.h\
diff --git a/src/Makefile.in b/src/Makefile.in
index af897bba..a354543f 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -446,7 +446,7 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \
StreamFilter.h SinkStreamFilter.cc SinkStreamFilter.h \
GZipDecodingStreamFilter.cc GZipDecodingStreamFilter.h \
ChunkedDecodingStreamFilter.cc ChunkedDecodingStreamFilter.h \
- NullSinkStreamFilter.cc NullSinkStreamFilter.h \
+ NullSinkStreamFilter.cc NullSinkStreamFilter.h uri.cc uri.h \
XmlRpcRequestParserController.cc \
XmlRpcRequestParserController.h \
XmlRpcRequestParserStateMachine.cc \
@@ -890,7 +890,7 @@ am__objects_32 = SocketCore.$(OBJEXT) Command.$(OBJEXT) \
StreamFilter.$(OBJEXT) SinkStreamFilter.$(OBJEXT) \
GZipDecodingStreamFilter.$(OBJEXT) \
ChunkedDecodingStreamFilter.$(OBJEXT) \
- NullSinkStreamFilter.$(OBJEXT) $(am__objects_1) \
+ NullSinkStreamFilter.$(OBJEXT) uri.$(OBJEXT) $(am__objects_1) \
$(am__objects_2) $(am__objects_3) $(am__objects_4) \
$(am__objects_5) $(am__objects_6) $(am__objects_7) \
$(am__objects_8) $(am__objects_9) $(am__objects_10) \
@@ -1238,17 +1238,18 @@ SRCS = Socket.h SocketCore.cc SocketCore.h BinaryStream.h Command.cc \
StreamFilter.h SinkStreamFilter.cc SinkStreamFilter.h \
GZipDecodingStreamFilter.cc GZipDecodingStreamFilter.h \
ChunkedDecodingStreamFilter.cc ChunkedDecodingStreamFilter.h \
- NullSinkStreamFilter.cc NullSinkStreamFilter.h $(am__append_1) \
- $(am__append_2) $(am__append_3) $(am__append_4) \
- $(am__append_5) $(am__append_6) $(am__append_7) \
- $(am__append_8) $(am__append_9) $(am__append_10) \
- $(am__append_11) $(am__append_12) $(am__append_13) \
- $(am__append_14) $(am__append_15) $(am__append_16) \
- $(am__append_17) $(am__append_18) $(am__append_19) \
- $(am__append_20) $(am__append_21) $(am__append_22) \
- $(am__append_23) $(am__append_24) $(am__append_25) \
- $(am__append_26) $(am__append_27) $(am__append_28) \
- $(am__append_29) $(am__append_30) $(am__append_31)
+ NullSinkStreamFilter.cc NullSinkStreamFilter.h uri.cc uri.h \
+ $(am__append_1) $(am__append_2) $(am__append_3) \
+ $(am__append_4) $(am__append_5) $(am__append_6) \
+ $(am__append_7) $(am__append_8) $(am__append_9) \
+ $(am__append_10) $(am__append_11) $(am__append_12) \
+ $(am__append_13) $(am__append_14) $(am__append_15) \
+ $(am__append_16) $(am__append_17) $(am__append_18) \
+ $(am__append_19) $(am__append_20) $(am__append_21) \
+ $(am__append_22) $(am__append_23) $(am__append_24) \
+ $(am__append_25) $(am__append_26) $(am__append_27) \
+ $(am__append_28) $(am__append_29) $(am__append_30) \
+ $(am__append_31)
noinst_LIBRARIES = libaria2c.a
libaria2c_a_SOURCES = $(SRCS)
aria2c_LDADD = libaria2c.a @LIBINTL@ @ALLOCA@ @LIBGNUTLS_LIBS@\
@@ -1682,6 +1683,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/prefs.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strptime.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/timegm.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/uri.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/version_usage.Po@am__quote@
diff --git a/src/Request.cc b/src/Request.cc
index 1eb7c4e7..1e7e3d3b 100644
--- a/src/Request.cc
+++ b/src/Request.cc
@@ -41,6 +41,7 @@
#include "StringFormat.h"
#include "A2STR.h"
#include "a2functional.h"
+#include "uri.h"
namespace aria2 {
@@ -147,161 +148,23 @@ bool Request::redirectUri(const std::string& uri) {
}
bool Request::parseUri(const std::string& srcUri) {
- const std::string uri = percentEncode(removeFragment(srcUri));
- currentUri_ = uri;
- host_ = A2STR::NIL;
- port_ = 0;
- dir_ = A2STR::NIL;
- file_ = A2STR::NIL;
- query_ = A2STR::NIL;
- username_ = A2STR::NIL;
- password_ = A2STR::NIL;
- hasPassword_ = false;
- ipv6LiteralAddress_ = false;
-
- // http://user:password@aria2.sourceforge.net:80/dir/file?query
- // | || || | | |
- // | || hostLast| | | |
- // | || portFirst| | |
- // authorityFirst || authorityLast | |
- // || | | |
- // userInfoLast | | |
- // | | | |
- // hostPortFirst | | |
- // | | |
- // dirFirst dirLast|
- // |
- // queryFirst
-
- // find query part
- std::string::const_iterator queryFirst = uri.begin();
- for(; queryFirst != uri.end(); ++queryFirst) {
- if(*queryFirst == '?') break;
- }
- query_ = std::string(queryFirst, uri.end());
- // find protocol
- std::string::size_type protocolOffset = uri.find("://");
- if(protocolOffset == std::string::npos) return false;
- protocol_ = std::string(uri.begin(), uri.begin()+protocolOffset);
- uint16_t defPort;
- if((defPort = FeatureConfig::getInstance()->getDefaultPort(protocol_)) == 0) {
- return false;
- }
- // find authority
- std::string::const_iterator authorityFirst = uri.begin()+protocolOffset+3;
- std::string::const_iterator authorityLast = authorityFirst;
- for(; authorityLast != queryFirst; ++authorityLast) {
- if(*authorityLast == '/') break;
- }
- if(authorityFirst == authorityLast) {
- // No authority found
- return false;
- }
- // find userinfo(username and password) in authority if they exist
- std::string::const_iterator userInfoLast = authorityLast;
- std::string::const_iterator hostPortFirst = authorityFirst;
- for(; userInfoLast != authorityFirst-1; --userInfoLast) {
- if(*userInfoLast == '@') {
- hostPortFirst = userInfoLast;
- ++hostPortFirst;
- std::string::const_iterator userLast = authorityFirst;
- for(; userLast != userInfoLast; ++userLast) {
- if(*userLast == ':') {
- password_ = util::percentDecode(std::string(userLast+1,userInfoLast));
- hasPassword_ = true;
- break;
- }
- }
- username_ = util::percentDecode(std::string(authorityFirst, userLast));
- break;
- }
- }
- std::string::const_iterator hostLast = hostPortFirst;
- std::string::const_iterator portFirst = authorityLast;
- if(*hostPortFirst == '[') {
- // Detected IPv6 literal address in square brackets
- for(; hostLast != authorityLast; ++hostLast) {
- if(*hostLast == ']') {
- ++hostLast;
- if(hostLast == authorityLast) {
- ipv6LiteralAddress_ = true;
- } else {
- if(*hostLast == ':') {
- portFirst = hostLast;
- ++portFirst;
- ipv6LiteralAddress_ = true;
- }
- }
- break;
- }
- }
- if(!ipv6LiteralAddress_) {
- return false;
- }
+ currentUri_ = percentEncode(removeFragment(srcUri));
+ uri::UriStruct us;
+ if(uri::parse(us, currentUri_)) {
+ protocol_.swap(us.protocol);
+ host_.swap(us.host);
+ port_ = us.port;
+ dir_.swap(us.dir);
+ file_.swap(us.file);
+ query_.swap(us.query);
+ username_.swap(us.username);
+ password_.swap(us.password);
+ hasPassword_ = us.hasPassword;
+ ipv6LiteralAddress_ = us.ipv6LiteralAddress;
+ return true;
} else {
- for(; hostLast != authorityLast; ++hostLast) {
- if(*hostLast == ':') {
- portFirst = hostLast;
- ++portFirst;
- break;
- }
- }
- }
- if(hostPortFirst == hostLast) {
- // No host
return false;
}
- if(portFirst == authorityLast) {
- // If port is not specified, then we set it to default port of
- // its protocol..
- port_ = defPort;
- } else {
- uint32_t tempPort;
- if(util::parseUIntNoThrow(tempPort, std::string(portFirst, authorityLast))){
- if(65535 < tempPort) {
- return false;
- }
- port_ = tempPort;
- } else {
- return false;
- }
- }
- if(ipv6LiteralAddress_) {
- host_ = std::string(hostPortFirst+1, hostLast-1);
- } else {
- host_ = std::string(hostPortFirst, hostLast);
- }
- // find directory and file part
- std::string::const_iterator dirLast = authorityLast;
- for(std::string::const_iterator i = authorityLast;
- i != queryFirst; ++i) {
- if(*i == '/') {
- dirLast = i;
- }
- }
- if(dirLast != queryFirst) {
- file_ = std::string(dirLast+1, queryFirst);
- }
- // Erase duplicated slashes.
- std::string::const_iterator dirFirst = authorityLast;
- for(; dirFirst != dirLast; ++dirFirst) {
- if(*dirFirst != '/') {
- --dirFirst;
- break;
- }
- }
- for(; dirLast != dirFirst; --dirLast) {
- if(*dirLast != '/') {
- ++dirLast;
- break;
- }
- }
- if(dirFirst == dirLast) {
- dir_ = A2STR::SLASH_C;
- } else {
- dir_ = std::string(dirFirst, dirLast);
- }
- return true;
}
void Request::resetRedirectCount()
diff --git a/src/uri.cc b/src/uri.cc
new file mode 100644
index 00000000..cee5589a
--- /dev/null
+++ b/src/uri.cc
@@ -0,0 +1,207 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2010 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#include "uri.h"
+#include "A2STR.h"
+#include "FeatureConfig.h"
+#include "util.h"
+
+namespace aria2 {
+
+namespace uri {
+
+bool parse(UriStruct& result, const std::string& uri)
+{
+ // http://user:password@aria2.sourceforge.net:80/dir/file?query#fragment
+ // | || || | | | |
+ // | || hostLast| | | | |
+ // | || portFirst| | | |
+ // authorityFirst || authorityLast | | |
+ // || | | | |
+ // userInfoLast | | | |
+ // | | | | |
+ // hostPortFirst | | | |
+ // | | | |
+ // dirFirst dirLast| |
+ // | |
+ // queryFirst fragmentFirst
+
+ // find fragment part
+ std::string::const_iterator fragmentFirst = uri.begin();
+ for(; fragmentFirst != uri.end(); ++fragmentFirst) {
+ if(*fragmentFirst == '#') break;
+ }
+ // find query part
+ std::string::const_iterator queryFirst = uri.begin();
+ for(; queryFirst != fragmentFirst; ++queryFirst) {
+ if(*queryFirst == '?') break;
+ }
+ result.query = std::string(queryFirst, fragmentFirst);
+ // find protocol
+ std::string::size_type protocolOffset = uri.find("://");
+ if(protocolOffset == std::string::npos) return false;
+ result.protocol = std::string(uri.begin(), uri.begin()+protocolOffset);
+ uint16_t defPort;
+ if((defPort = FeatureConfig::getInstance()->
+ getDefaultPort(result.protocol)) == 0) {
+ return false;
+ }
+ // find authority
+ std::string::const_iterator authorityFirst = uri.begin()+protocolOffset+3;
+ std::string::const_iterator authorityLast = authorityFirst;
+ for(; authorityLast != queryFirst; ++authorityLast) {
+ if(*authorityLast == '/') break;
+ }
+ if(authorityFirst == authorityLast) {
+ // No authority found
+ return false;
+ }
+ // find userinfo(username and password) in authority if they exist
+ result.username = A2STR::NIL;
+ result.password = A2STR::NIL;
+ result.hasPassword = false;
+ std::string::const_iterator userInfoLast = authorityLast;
+ std::string::const_iterator hostPortFirst = authorityFirst;
+ for(; userInfoLast != authorityFirst-1; --userInfoLast) {
+ if(*userInfoLast == '@') {
+ hostPortFirst = userInfoLast;
+ ++hostPortFirst;
+ std::string::const_iterator userLast = authorityFirst;
+ for(; userLast != userInfoLast; ++userLast) {
+ if(*userLast == ':') {
+ result.password =
+ util::percentDecode(std::string(userLast+1,userInfoLast));
+ result.hasPassword = true;
+ break;
+ }
+ }
+ result.username =
+ util::percentDecode(std::string(authorityFirst, userLast));
+ break;
+ }
+ }
+ std::string::const_iterator hostLast = hostPortFirst;
+ std::string::const_iterator portFirst = authorityLast;
+ result.ipv6LiteralAddress = false;
+ if(*hostPortFirst == '[') {
+ // Detected IPv6 literal address in square brackets
+ for(; hostLast != authorityLast; ++hostLast) {
+ if(*hostLast == ']') {
+ ++hostLast;
+ if(hostLast == authorityLast) {
+ result.ipv6LiteralAddress = true;
+ } else {
+ if(*hostLast == ':') {
+ portFirst = hostLast;
+ ++portFirst;
+ result.ipv6LiteralAddress = true;
+ }
+ }
+ break;
+ }
+ }
+ if(!result.ipv6LiteralAddress) {
+ return false;
+ }
+ } else {
+ for(; hostLast != authorityLast; ++hostLast) {
+ if(*hostLast == ':') {
+ portFirst = hostLast;
+ ++portFirst;
+ break;
+ }
+ }
+ }
+ if(hostPortFirst == hostLast) {
+ // No host
+ return false;
+ }
+ if(portFirst == authorityLast) {
+ // If port is not specified, then we set it to default port of
+ // its protocol..
+ result.port = defPort;
+ } else {
+ uint32_t tempPort;
+ if(util::parseUIntNoThrow(tempPort, std::string(portFirst, authorityLast))){
+ if(65535 < tempPort) {
+ return false;
+ }
+ result.port = tempPort;
+ } else {
+ return false;
+ }
+ }
+ if(result.ipv6LiteralAddress) {
+ result.host = std::string(hostPortFirst+1, hostLast-1);
+ } else {
+ result.host = std::string(hostPortFirst, hostLast);
+ }
+ // find directory and file part
+ std::string::const_iterator dirLast = authorityLast;
+ for(std::string::const_iterator i = authorityLast;
+ i != queryFirst; ++i) {
+ if(*i == '/') {
+ dirLast = i;
+ }
+ }
+ if(dirLast == queryFirst) {
+ result.file = A2STR::NIL;
+ } else {
+ result.file = std::string(dirLast+1, queryFirst);
+ }
+ // Erase duplicated slashes.
+ std::string::const_iterator dirFirst = authorityLast;
+ for(; dirFirst != dirLast; ++dirFirst) {
+ if(*dirFirst != '/') {
+ --dirFirst;
+ break;
+ }
+ }
+ for(; dirLast != dirFirst; --dirLast) {
+ if(*dirLast != '/') {
+ ++dirLast;
+ break;
+ }
+ }
+ if(dirFirst == dirLast) {
+ result.dir = A2STR::SLASH_C;
+ } else {
+ result.dir = std::string(dirFirst, dirLast);
+ }
+ return true;
+}
+
+} // namespace uri
+
+} // namespace aria2
diff --git a/src/uri.h b/src/uri.h
new file mode 100644
index 00000000..97ed7ac6
--- /dev/null
+++ b/src/uri.h
@@ -0,0 +1,71 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2010 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef D_URI_H
+#define D_URI_H
+
+#include "common.h"
+
+#include <string>
+#include "A2STR.h"
+
+namespace aria2 {
+
+namespace uri {
+
+struct UriStruct {
+ std::string protocol;
+ std::string host;
+ uint16_t port;
+ std::string dir;
+ std::string file;
+ std::string query;
+ std::string username;
+ std::string password;
+ bool hasPassword;
+ bool ipv6LiteralAddress;
+
+ UriStruct():port(0), hasPassword(false), ipv6LiteralAddress(false) {}
+};
+
+// Splits URI uri into components and stores them into result. On
+// success returns true. Otherwise returns false and result is
+// undefined.
+bool parse(UriStruct& result, const std::string& uri);
+
+} // namespace uri
+
+} // namespace aria2
+
+#endif // D_URI_H