diff options
| author | Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com> | 2010-09-11 09:11:57 +0000 |
|---|---|---|
| committer | Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com> | 2010-09-11 09:11:57 +0000 |
| commit | ec3bd81486d6f9b266753984f0da31f8d39fd951 (patch) | |
| tree | 1c9d8870d478781deb0c6ade762c8d15645c1d10 /src | |
| parent | cb796432eca9d0ebf7b782c04a1cdc13e555793b (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.am | 3 | ||||
| -rw-r--r-- | src/Makefile.in | 28 | ||||
| -rw-r--r-- | src/Request.cc | 167 | ||||
| -rw-r--r-- | src/uri.cc | 207 | ||||
| -rw-r--r-- | src/uri.h | 71 |
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 |
