You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@activemq.apache.org by ta...@apache.org on 2008/12/16 19:56:43 UTC
svn commit: r727119 - in /activemq/activemq-cpp/trunk/src/main/decaf/net:
URI.cpp URI.h
Author: tabish
Date: Tue Dec 16 10:56:43 2008
New Revision: 727119
URL: http://svn.apache.org/viewvc?rev=727119&view=rev
Log:
Partially working URI class
Modified:
activemq/activemq-cpp/trunk/src/main/decaf/net/URI.cpp
activemq/activemq-cpp/trunk/src/main/decaf/net/URI.h
Modified: activemq/activemq-cpp/trunk/src/main/decaf/net/URI.cpp
URL: http://svn.apache.org/viewvc/activemq/activemq-cpp/trunk/src/main/decaf/net/URI.cpp?rev=727119&r1=727118&r2=727119&view=diff
==============================================================================
--- activemq/activemq-cpp/trunk/src/main/decaf/net/URI.cpp (original)
+++ activemq/activemq-cpp/trunk/src/main/decaf/net/URI.cpp Tue Dec 16 10:56:43 2008
@@ -18,10 +18,17 @@
#include "URI.h"
#include <apr_strings.h>
+#include <apr_lib.h>
#include <decaf/lang/Integer.h>
+#include <decaf/internal/net/URIHelper.h>
+#include <decaf/internal/net/URIEncoderDecoder.h>
+
+using namespace std;
using namespace decaf;
using namespace decaf::net;
+using namespace decaf::internal;
+using namespace decaf::internal::net;
using namespace decaf::lang;
using namespace decaf::lang::exceptions;
@@ -33,10 +40,14 @@
const std::string URI::allLegal = unreserved + reserved;
////////////////////////////////////////////////////////////////////////////////
+URI::URI() {
+}
+
+////////////////////////////////////////////////////////////////////////////////
URI::URI( const std::string& uri ) throw ( URISyntaxException) {
- this->uriString = NULL;
- this->parseURI( uri );
+ this->uriString = uri;
+ this->parseURI( uri, false );
}
////////////////////////////////////////////////////////////////////////////////
@@ -63,7 +74,7 @@
}
// Now hand of to the main parse function.
- this->parseURI( uri );
+ this->parseURI( uri, false );
}
////////////////////////////////////////////////////////////////////////////////
@@ -72,12 +83,10 @@
const std::string& path, const std::string& query,
const std::string& fragment ) throw ( URISyntaxException ) {
- this->uriString = NULL;
-
if( scheme == "" && userInfo == "" && host == "" &&
path == "" && query == "" && fragment == "" ) {
- this->uri.path = "";
+ this->uri.setPath( "" );
return;
}
@@ -141,7 +150,7 @@
uri.append( quoteComponent( fragment, allLegal ) );
}
- this->parseURI( uri );
+ this->parseURI( uri, true );
}
////////////////////////////////////////////////////////////////////////////////
@@ -149,8 +158,6 @@
const std::string& path, const std::string& fragment )
throw ( URISyntaxException ) {
- this->uriString = NULL;
-
URI::URI( scheme, "", host, -1, path, "", fragment );
}
@@ -159,8 +166,6 @@
const std::string& path, const std::string& query,
const std::string& fragment ) throw ( URISyntaxException ) {
- this->uriString = NULL;
-
if( scheme != "" && path.length() > 0 && path.at(0) != '/' ) {
throw URISyntaxException(
__FILE__, __LINE__, path,
@@ -193,57 +198,228 @@
uri.append( quoteComponent( fragment, allLegal ) );
}
- this->parseURI( uri );
+ this->parseURI( uri, false );
}
////////////////////////////////////////////////////////////////////////////////
-void URI::parseURI( const std::string& uri ) throw ( URISyntaxException ) {
-
- // Use APR to perform the main parse.
- apr_status_t result = apr_uri_parse( pool.getAprPool(),
- uri.c_str(), &this->uri );
+void URI::parseURI( const std::string& uri, bool forceServer ) throw ( URISyntaxException ) {
- if( result != APR_SUCCESS ) {
- throw URISyntaxException(
- __FILE__, __LINE__, uri,
- "URI::praseURI - URI String %s invalid." );
+ try{
+ this->uri = URIHelper().parseURI( uri, forceServer );
}
-
- std::cout << "\n";
- std::cout << "Original URI String: " << uri << std::endl;
- std::cout << "\n";
- std::cout << "Scheme: "
- << ( this->uri.scheme ? this->uri.scheme : "" ) << std::endl;
- std::cout << "Host: "
- << ( this->uri.hostinfo ? this->uri.hostinfo : "" ) << std::endl;
- std::cout << "User: "
- << ( this->uri.user ? this->uri.user : "" ) << std::endl;
- std::cout << "Passwrod: "
- << ( this->uri.password ? this->uri.password : "" ) << std::endl;
- std::cout << "Host Name: "
- << ( this->uri.hostname ? this->uri.hostname : "" ) << std::endl;
- std::cout << "Port Str: "
- << ( this->uri.port_str ? this->uri.port_str : "" ) << std::endl;
- std::cout << "Path: "
- << ( this->uri.path ? this->uri.path : "" ) << std::endl;
- std::cout << "Query: "
- << ( this->uri.query ? this->uri.query : "" ) << std::endl;
- std::cout << "Fragment: "
- << ( this->uri.fragment ? this->uri.fragment : "" ) << std::endl;
- std::cout << "Port: " << this->uri.port << std::endl;
- std::cout << "Is Initialized: " << this->uri.is_initialized << std::endl;
- std::cout << "DNS Looked Up: " << this->uri.dns_looked_up << std::endl;
- std::cout << "DNS Resolved: " << this->uri.dns_resolved << std::endl;
+ DECAF_CATCH_RETHROW( URISyntaxException )
+ DECAF_CATCHALL_THROW( URISyntaxException )
}
////////////////////////////////////////////////////////////////////////////////
-int URI::compareTo( DECAF_UNUSED const URI& value ) const {
+int URI::compareTo( const URI& uri ) const {
+
+ int ret = 0;
+
+ // compare schemes
+ if( this->uri.getScheme() == "" && uri.getScheme() != "" ) {
+ return -1;
+ } else if( this->uri.getScheme() != "" && uri.getScheme() == "" ) {
+ return 1;
+ } else if( this->uri.getScheme() != "" && uri.getScheme() != "" ) {
+ ret = apr_strnatcasecmp( this->uri.getScheme().c_str(), uri.getScheme().c_str() );
+ if( ret != 0 ) {
+ return ret;
+ }
+ }
+
+ // compare opacities
+ if( !this->uri.isOpaque() && uri.isOpaque() ) {
+ return -1;
+ } else if( this->uri.isOpaque() && !uri.isOpaque() ) {
+ return 1;
+ } else if( this->uri.isOpaque() && uri.isOpaque() ) {
+ ret = apr_strnatcmp( this->getSchemeSpecificPart().c_str(),
+ uri.getSchemeSpecificPart().c_str() );
+ if( ret != 0 ) {
+ return ret;
+ }
+ } else {
+
+ // otherwise both must be hierarchical
+
+ // compare authorities
+ if( this->uri.getAuthority() != "" && uri.getAuthority() == "" ) {
+ return 1;
+ } else if( this->uri.getAuthority() == "" && uri.getAuthority() != "" ) {
+ return -1;
+ } else if( this->uri.getAuthority() != "" && uri.getAuthority() != "" ) {
+
+ if( this->uri.getHost() != "" && uri.getHost() != "" ) {
+
+ // both are server based, so compare userinfo, host, port
+ if( this->getUserInfo() != "" && uri.getUserInfo() == "" ) {
+ return 1;
+ } else if( this->getUserInfo() == "" && uri.getUserInfo() != "" ) {
+ return -1;
+ } else if( this->getUserInfo() != "" && uri.getUserInfo() != "" ) {
+ ret = apr_strnatcmp( this->getUserInfo().c_str(),
+ uri.getUserInfo().c_str() );
+ if( ret != 0 ) {
+ return ret;
+ }
+ }
+
+ // userinfo's are the same, compare hostname
+ ret = apr_strnatcmp( this->uri.getHost().c_str(), uri.getHost().c_str() );
+ if( ret != 0 ) {
+ return ret;
+ }
+
+ // compare port
+ if( this->getPort() != uri.getPort() ) {
+ return getPort() - uri.getPort();
+ }
+
+ } else {
+
+ // one or both are registry based, compare the whole authority
+ ret = apr_strnatcmp( this->uri.getAuthority().c_str(),
+ uri.getAuthority().c_str() );
+ if( ret != 0 ) {
+ return ret;
+ }
+ }
+ }
+
+ // authorities are the same
+ // compare paths
+ ret = apr_strnatcmp( this->getPath().c_str(), uri.getPath().c_str() );
+ if( ret != 0 ) {
+ return ret;
+ }
+
+ // compare queries
+ if( this->getQuery() != "" && uri.getQuery() == "" ) {
+ return 1;
+ } else if( this->getQuery() == "" && uri.getQuery() != "" ) {
+ return -1;
+ } else if( this->getQuery() != "" && uri.getQuery() != "" ) {
+ ret = apr_strnatcmp( this->getQuery().c_str(), uri.getQuery().c_str() );
+ if( ret != 0 ) {
+ return ret;
+ }
+ }
+ }
+
+ // everything else is identical, so compare fragments
+ if( this->getFragment() != "" && uri.getFragment() == "" ) {
+ return 1;
+ } else if( this->getFragment() == "" && uri.getFragment() != "" ) {
+ return -1;
+ } else if( this->getFragment() != "" && uri.getFragment() != "" ) {
+ ret = apr_strnatcmp( this->getFragment().c_str(), uri.getFragment().c_str() );
+ if( ret != 0 ) {
+ return ret;
+ }
+ }
+
+ // identical
return 0;
}
////////////////////////////////////////////////////////////////////////////////
-bool URI::equals( const URI& value ) const {
- return compareTo( value ) == 0 ? true : false;
+bool URI::equals( const URI& uri ) const {
+
+ if( ( uri.getFragment() == "" && this->getFragment() != "" ) ||
+ ( uri.getFragment() != "" && this->getFragment() == "" ) ) {
+
+ return false;
+
+ } else if( uri.getFragment() != "" && this->getFragment() != "" ) {
+
+ if( !equalsHexCaseInsensitive( uri.getFragment(), this->getFragment() ) ) {
+ return false;
+ }
+ }
+
+ if( ( uri.getScheme() == "" && this->getScheme() != "" ) ||
+ ( uri.getScheme() != "" && this->getScheme() == "" ) ) {
+
+ return false;
+
+ } else if( uri.getScheme() != "" && this->getScheme() != "" ) {
+
+ if( apr_strnatcasecmp( uri.getScheme().c_str(), this->getScheme().c_str() ) != 0 ) {
+ return false;
+ }
+ }
+
+ if( uri.isOpaque() && this->isOpaque() ) {
+
+ return equalsHexCaseInsensitive(
+ uri.getSchemeSpecificPart(), this->getSchemeSpecificPart() );
+
+ } else if( !uri.isOpaque() && !this->isOpaque() ) {
+
+ if( !equalsHexCaseInsensitive( this->getPath(), uri.getPath() ) ) {
+ return false;
+ }
+
+ if( ( uri.getQuery() != "" && this->getQuery() == "" ) ||
+ ( uri.getQuery() == "" && this->getQuery() != "" ) ) {
+
+ return false;
+
+ } else if( uri.getQuery() != "" && this->getQuery() != "" ) {
+
+ if( !equalsHexCaseInsensitive( uri.getQuery(), this->getQuery() ) ) {
+ return false;
+ }
+ }
+
+ if( ( uri.getAuthority() != "" && this->getAuthority() == "" ) ||
+ ( uri.getAuthority() == "" && this->getAuthority() != "" ) ) {
+
+ return false;
+
+ } else if( uri.getAuthority() != "" && this->getAuthority() != "" ) {
+
+ if( ( uri.getHost() != "" && this->getHost() == "" ) ||
+ ( uri.getHost() == "" && this->getHost() != "" ) ) {
+
+ return false;
+
+ } else if( uri.getHost() == "" && this->getHost() == "" ) {
+
+ // both are registry based, so compare the whole authority
+ return equalsHexCaseInsensitive( uri.getAuthority(), this->getAuthority() );
+
+ } else { // uri.host != "" && host != "", so server-based
+
+ if( apr_strnatcasecmp( uri.getHost().c_str(), this->getHost().c_str() ) != 0 ) {
+ return false;
+ }
+
+ if( this->getPort() != uri.getPort() ) {
+ return false;
+ }
+
+ if( ( uri.getUserInfo() != "" && this->getUserInfo() == "" ) ||
+ ( uri.getUserInfo() == "" && this->getUserInfo() != "" ) ) {
+
+ return false;
+
+ } else if( uri.getUserInfo() != "" && this->getUserInfo() != "" ) {
+ return equalsHexCaseInsensitive( this->getUserInfo(), uri.getUserInfo() );
+ } else {
+ return true;
+ }
+ }
+ } else {
+ // no authority
+ return true;
+ }
+
+ } else {
+ // one is opaque, the other hierarchical
+ return false;
+ }
}
////////////////////////////////////////////////////////////////////////////////
@@ -268,19 +444,528 @@
}
////////////////////////////////////////////////////////////////////////////////
-std::string URI::quoteComponent( DECAF_UNUSED const std::string& component,
- DECAF_UNUSED const std::string& legalset ) {
-// try {
+std::string URI::quoteComponent( const std::string& component,
+ const std::string& legalset ) {
+
+ try {
+
/*
* Use a different encoder than URLEncoder since: 1. chars like "/",
* "#", "@" etc needs to be preserved instead of being encoded, 2.
* UTF-8 char set needs to be used for encoding instead of default
* platform one
*/
-// return URIEncoderDecoder.quoteIllegal(component, legalset);
-// } catch( UnsupportedEncodingException e ) {
-// throw RuntimeException( e );
-// }
-
- return "";
+ return URIEncoderDecoder::quoteIllegal(component, legalset);
+ }
+ DECAF_CATCH_RETHROW( decaf::lang::Exception )
+ DECAF_CATCHALL_THROW( decaf::lang::Exception )
+}
+
+////////////////////////////////////////////////////////////////////////////////
+std::string URI::encodeOthers( const std::string& src ) const {
+
+ try {
+ /*
+ * Use a different encoder than URLEncoder since: 1. chars like "/",
+ * "#", "@" etc needs to be preserved instead of being encoded, 2.
+ * UTF-8 char set needs to be used for encoding instead of default
+ * platform one 3. Only other chars need to be converted
+ */
+ return URIEncoderDecoder::encodeOthers( src );
+ }
+ DECAF_CATCH_RETHROW( decaf::lang::Exception )
+ DECAF_CATCHALL_THROW( decaf::lang::Exception )
+}
+
+////////////////////////////////////////////////////////////////////////////////
+std::string URI::decode( const std::string& src ) const {
+
+ if( src == "" ) {
+ return src;
+ }
+
+ try {
+ return URIEncoderDecoder::decode( src );
+ }
+ DECAF_CATCH_RETHROW( decaf::lang::Exception )
+ DECAF_CATCHALL_THROW( decaf::lang::Exception )
+}
+
+////////////////////////////////////////////////////////////////////////////////
+bool URI::equalsHexCaseInsensitive( const std::string& first, const std::string& second ) const {
+
+ if( first.find( '%' ) != second.find( '%' ) ) {
+ return apr_strnatcmp( first.c_str(), second.c_str() ) == 0;
+ }
+
+ unsigned int index = 0;
+ unsigned int previndex = 0;
+
+ while( ( index = first.find( '%', previndex ) ) != string::npos &&
+ second.find( '%', previndex ) == index ) {
+
+ bool match = first.substr( previndex, index - previndex ) ==
+ second.substr( previndex, index - previndex );
+
+ if( !match ) {
+ return false;
+ }
+
+ match = apr_strnatcasecmp( first.substr( index + 1, 3 ).c_str(),
+ second.substr( index + 1, 3 ).c_str() ) == 0;
+
+ if( !match ) {
+ return false;
+ }
+
+ index += 3;
+ previndex = index;
+ }
+
+ return first.substr( previndex ) == second.substr( previndex );
+}
+
+////////////////////////////////////////////////////////////////////////////////
+std::string URI::convertHexToLowerCase( const std::string& s ) const {
+
+ string result = "";
+
+ if( s.find('%') == string::npos ) {
+ return s;
+ }
+
+ unsigned int index = 0;
+ unsigned int previndex = 0;
+
+ while( ( index = s.find( '%', previndex ) ) != string::npos ) {
+ result.append( s.substr( previndex, ( index - previndex ) + 1 ) );
+
+ string temp = s.substr( index + 1, 3 );
+
+ for( size_t i = 0; i < temp.length(); ++i ) {
+ result.append( 1, (char)apr_tolower( temp.at(i) ) );
+ }
+
+ index += 3;
+ previndex = index;
+ }
+
+ return result;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+std::string URI::normalize( const std::string& path ) const {
+
+ // count the number of '/'s, to determine number of segments
+ unsigned int index = -1;
+ unsigned int pathlen = path.length();
+ unsigned int size = 0;
+
+ if( pathlen > 0 && path.at(0) != '/' ) {
+ size++;
+ }
+
+ while( ( index = path.find( '/', index + 1 ) ) != string::npos ) {
+ if( index + 1 < pathlen && path.at( index + 1 ) != '/' ) {
+ size++;
+ }
+ }
+
+ std::vector<string> seglist;
+ std::vector<bool> include;
+
+ // break the path into segments and store in the list
+ unsigned int current = 0;
+ unsigned int index2 = 0;
+
+ index = ( pathlen > 0 && path.at(0) == '/' ) ? 1 : 0;
+ while( ( index2 = path.find( '/', index + 1 ) ) != string::npos ) {
+ seglist[current++] = path.substr( index, index2 - index );
+ index = index2 + 1;
+ }
+
+ // if current==size, then the last character was a slash
+ // and there are no more segments
+ if( current < size ) {
+ seglist[current] = path.substr( index );
+ }
+
+ // determine which segments get included in the normalized path
+ for( unsigned int i = 0; i < size; i++ ) {
+
+ include[i] = true;
+
+ if( seglist[i] == ".." ) {
+
+ int remove = i - 1;
+
+ // search back to find a segment to remove, if possible
+ while( remove > -1 && !include[remove] ) {
+ remove--;
+ }
+
+ // if we find a segment to remove, remove it and the ".."
+ // segment
+ if( remove > -1 && !( seglist[remove] == "..") ) {
+ include[remove] = false;
+ include[i] = false;
+ }
+
+ } else if( seglist[i] == "." ) {
+ include[i] = false;
+ }
+ }
+
+ // put the path back together
+ string newpath;
+ if( path.at(0) == '/' ) {
+ newpath.append( "/" );
+ }
+
+ for( unsigned int i = 0; i < seglist.size(); i++ ) {
+ if( include[i] ) {
+ newpath.append( seglist[i] );
+ newpath.append( "/" );
+ }
+ }
+
+ // if we used at least one segment and the path previously ended with
+ // a slash and the last segment is still used, then delete the extra
+ // trailing '/'
+ if( !path.at( path.length() ) == '/' && seglist.size() > 0 &&
+ include[seglist.size() - 1] ) {
+
+ newpath.erase( newpath.length() - 1, 1 );
+ }
+
+ string result = newpath;
+
+ // check for a ':' in the first segment if one exists,
+ // prepend "./" to normalize
+ index = result.find(':');
+ index2 = result.find('/');
+
+ if( index != string::npos && ( index < index2 || index2 == string::npos ) ) {
+ newpath.insert( 0, "./" );
+ result = newpath;
+ }
+
+ return result;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+URI URI::normalize() const {
+
+ if( isOpaque() ) {
+ return *this;
+ }
+
+ string normalizedPath = normalize( this->uri.getPath() );
+
+ // if the path is already normalized, return this
+ if( this->uri.getPath() == normalizedPath ) {
+ return *this;
+ }
+
+ // get an exact copy of the URI re-calculate the scheme specific part
+ // since the path of the normalized URI is different from this URI.
+ URI result = *this;
+ result.uri.setPath( normalizedPath );
+ result.setSchemeSpecificPart();
+
+ return result;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+void URI::setSchemeSpecificPart() {
+
+ // ssp = [//authority][path][?query]
+ string ssp;
+
+ if( this->uri.getAuthority() != "" ) {
+ ssp.append( string("//") + this->uri.getAuthority() );
+ }
+
+ if( this->uri.getPath() != "" ) {
+ ssp.append( this->uri.getPath() );
+ }
+
+ if( this->uri.getQuery() != "" ) {
+ ssp.append( "?" + this->uri.getQuery() );
+ }
+
+ this->uri.setSchemeSpecificPart( ssp );
+
+ // reset string, so that it can be re-calculated correctly when asked.
+ this->uriString = "";
+}
+
+////////////////////////////////////////////////////////////////////////////////
+URI URI::parseServerAuthority() const throw( URISyntaxException ) {
+
+ URI newURI = *this;
+
+ if( newURI.uri.isServerAuthority() ) {
+ newURI.uri = URIHelper().parseAuthority( true, this->uri.getAuthority() );
+ }
+
+ return newURI;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+URI URI::relativize( const URI& relative ) const {
+
+ if( relative.isOpaque() || this->isOpaque() ) {
+ return relative;
+ }
+
+ if( this->uri.getScheme() == "" ? relative.uri.getScheme() != "" :
+ this->uri.getScheme() != relative.uri.getScheme() ) {
+
+ return relative;
+ }
+
+ if( this->uri.getAuthority() == "" ? relative.uri.getAuthority() != "" :
+ this->uri.getAuthority() != relative.uri.getAuthority() ) {
+
+ return relative;
+ }
+
+ // normalize both paths
+ string thisPath = normalize( this->uri.getPath() );
+ string relativePath = normalize( relative.uri.getPath() );
+
+ /*
+ * if the paths aren't equal, then we need to determine if this URI's
+ * path is a parent path (begins with) the relative URI's path
+ */
+ if( thisPath != relativePath ) {
+
+ // if this URI's path doesn't end in a '/', add one
+ if( thisPath.at( thisPath.length() ) != '/' ) {
+ thisPath = thisPath + '/';
+ }
+
+ /*
+ * if the relative URI's path doesn't start with this URI's path,
+ * then just return the relative URI; the URIs have nothing in
+ * common
+ */
+ if( relativePath.find( thisPath ) != 0 ) {
+ return relative;
+ }
+ }
+
+ URI result;
+ result.uri.setFragment( relative.uri.getFragment() );
+ result.uri.setQuery( relative.uri.getQuery() );
+ // the result URI is the remainder of the relative URI's path
+ result.uri.setPath( relativePath.substr( thisPath.length() ) );
+
+ return result;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+URI URI::resolve( const URI& relative ) const {
+
+ if( relative.isAbsolute() || this->isOpaque() ) {
+ return relative;
+ }
+
+ URI result;
+ if( relative.uri.getPath() == "" && relative.uri.getScheme() == "" &&
+ relative.uri.getAuthority() == "" && relative.uri.getQuery() == "" &&
+ relative.uri.getFragment() != "" ) {
+
+ // if the relative URI only consists of fragment,
+ // the resolved URI is very similar to this URI,
+ // except that it has the fragment from the relative URI.
+ result = *this;
+ result.uri.setFragment( relative.uri.getFragment() );
+ // no need to re-calculate the scheme specific part,
+ // since fragment is not part of scheme specific part.
+ return result;
+ }
+
+ if( relative.uri.getAuthority() != "" ) {
+
+ // if the relative URI has authority,
+ // the resolved URI is almost the same as the relative URI,
+ // except that it has the scheme of this URI.
+ result = *this;
+ result.uri.setScheme( this->uri.getScheme() );
+ result.uri.setAbsolute( this->uri.isAbsolute() );
+
+ } else {
+
+ // since relative URI has no authority,
+ // the resolved URI is very similar to this URI,
+ // except that it has the query and fragment of the relative URI,
+ // and the path is different.
+ result = *this;
+ result.uri.setFragment( relative.uri.getFragment() );
+ result.uri.setQuery( relative.uri.getQuery() );
+
+ if( relative.uri.getPath().at(0) == '/' ) {
+ result.uri.setPath( relative.uri.getPath() );
+ } else {
+ // resolve a relative reference
+ int endindex = this->uri.getPath().find_last_of('/') + 1;
+ result.uri.setPath( normalize(
+ this->uri.getPath().substr( 0, endindex ) + relative.uri.getPath() ) );
+ }
+
+ // re-calculate the scheme specific part since
+ // query and path of the resolved URI is different from this URI.
+ result.setSchemeSpecificPart();
+ }
+
+ return result;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+URI URI::resolve( const std::string& relative ) const
+ throw ( lang::exceptions::IllegalArgumentException ) {
+
+ return resolve( create( relative ) );
+}
+
+////////////////////////////////////////////////////////////////////////////////
+string URI::toString() const {
+
+ if( this->uriString == "" ) {
+
+ string result = "";
+
+ if( this->uri.getScheme() != "" ) {
+ result.append( this->uri.getScheme() );
+ result.append( ":" );
+ }
+
+ if( this->isOpaque() ) {
+ result.append( this->uri.getSchemeSpecificPart() );
+ } else {
+
+ if( this->uri.getAuthority() != "" ) {
+ result.append( "//" );
+ result.append( this->uri.getAuthority() );
+ }
+
+ if( this->uri.getPath() != "" ) {
+ result.append( this->uri.getPath() );
+ }
+
+ if( this->uri.getQuery() != "" ) {
+ result.append( "?" );
+ result.append( this->uri.getQuery() );
+ }
+ }
+
+ if( this->uri.getFragment() != "" ) {
+ result.append( "#" );
+ result.append( this->uri.getFragment() );
+ }
+
+ this->uriString = result;
+ }
+
+ return this->uriString;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+URL URI::toURL() const
+ throw ( MalformedURLException, lang::exceptions::IllegalArgumentException ) {
+
+ if( !this->isAbsolute() ) {
+ throw IllegalArgumentException(
+ __FILE__, __LINE__,
+ "URI is not absolute, cannot convert to an URL." );
+ }
+
+ return URL( this->toString() );
+}
+
+////////////////////////////////////////////////////////////////////////////////
+std::string URI::getAuthority() const {
+ return this->decode( this->uri.getAuthority() );
+}
+
+////////////////////////////////////////////////////////////////////////////////
+std::string URI::getFragment() const {
+ return this->decode( this->uri.getFragment() );
+}
+
+////////////////////////////////////////////////////////////////////////////////
+std::string URI::getHost() const {
+ return this->uri.getHost();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+std::string URI::getPath() const {
+ return this->decode( this->uri.getPath() );
+}
+
+////////////////////////////////////////////////////////////////////////////////
+int URI::getPort() const {
+ return this->uri.getPort();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+std::string URI::getQuery() const {
+ return this->decode( this->uri.getQuery() );
+}
+
+////////////////////////////////////////////////////////////////////////////////
+std::string URI::getRawAuthority() const {
+ return this->uri.getAuthority();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+std::string URI::getRawFragment() const {
+ return this->uri.getFragment();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+std::string URI::getRawPath() const {
+ return this->uri.getPath();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+std::string URI::getRawQuery() const {
+ return this->uri.getQuery();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+std::string URI::getRawSchemeSpecificPart() const {
+ return this->uri.getSchemeSpecificPart();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+std::string URI::getRawUserInfo() const {
+ return this->uri.getUserInfo();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+std::string URI::getScheme() const {
+ return this->uri.getScheme();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+std::string URI::getSchemeSpecificPart() const {
+ return this->decode( this->uri.getSchemeSpecificPart() );
+}
+
+////////////////////////////////////////////////////////////////////////////////
+std::string URI::getUserInfo() const {
+ return this->decode( this->uri.getUserInfo() );
+}
+
+////////////////////////////////////////////////////////////////////////////////
+bool URI::isAbsolute() const {
+ return this->uri.isAbsolute();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+bool URI::isOpaque() const {
+ return this->uri.isOpaque();
}
Modified: activemq/activemq-cpp/trunk/src/main/decaf/net/URI.h
URL: http://svn.apache.org/viewvc/activemq/activemq-cpp/trunk/src/main/decaf/net/URI.h?rev=727119&r1=727118&r2=727119&view=diff
==============================================================================
--- activemq/activemq-cpp/trunk/src/main/decaf/net/URI.h (original)
+++ activemq/activemq-cpp/trunk/src/main/decaf/net/URI.h Tue Dec 16 10:56:43 2008
@@ -24,9 +24,8 @@
#include <decaf/net/URISyntaxException.h>
#include <decaf/net/MalformedURLException.h>
#include <decaf/net/URL.h>
+#include <decaf/internal/net/URIType.h>
#include <string>
-#include <apr_uri.h>
-#include <decaf/internal/AprPool.h>
namespace decaf{
namespace net{
@@ -37,12 +36,11 @@
class DECAF_API URI : public lang::Comparable<URI> {
private:
- // Apr Data for parsing the uri.
- apr_uri_t uri;
- internal::AprPool pool;
+ // The structure that holds the parsed URI data.
+ decaf::internal::net::URIType uri;
// The original string entered from URI( string ), empty if not set.
- const char* uriString;
+ mutable std::string uriString;
static const std::string unreserved;
static const std::string punct;
@@ -66,7 +64,7 @@
*/
URI( const std::string& scheme,
const std::string& ssp,
- const std::string& fragment) throw ( URISyntaxException );
+ const std::string& fragment ) throw ( URISyntaxException );
/**
* Constructs a URI from the given components.
@@ -329,7 +327,7 @@
* @returns The resulting URI
* @throws IllegalArgumentException - If the given string violates RFC 2396
*/
- URI resolve( const std::string& str )
+ URI resolve( const std::string& str ) const
throw ( lang::exceptions::IllegalArgumentException );
/**
@@ -368,7 +366,7 @@
* @param uri - The URI to be resolved against this URI
* @returns The resulting URI
*/
- URI resolve( const URI& uri );
+ URI resolve( const URI& uri ) const;
/**
* Returns the content of this URI as a string.
@@ -410,6 +408,13 @@
static URI create( const std::string uri )
throw ( lang::exceptions::IllegalArgumentException );
+ protected:
+
+ /**
+ * Default Constructor
+ */
+ URI();
+
private:
/**
@@ -417,9 +422,10 @@
* URISyntaxException if things fail.
*
* @param uri - the URI to parse
+ * @param forceServer - should a server authority be enforced.
* @throws URISyntaxException if an error occurs.
*/
- void parseURI( const std::string& uri ) throw ( URISyntaxException );
+ void parseURI( const std::string& uri, bool forceServer ) throw ( URISyntaxException );
/*
* Quote illegal chars for each component, but not the others
@@ -431,6 +437,56 @@
std::string quoteComponent( const std::string& component,
const std::string& legalset );
+ /*
+ * Encode unicode chars that are not part of US-ASCII char set into the
+ * escaped form
+ *
+ * i.e. The Euro currency symbol is encoded as "%E2%82%AC".
+ *
+ * @param component java.lang.String the component to be converted @param
+ * legalset java.lang.String the legal character set allowed in the
+ * component s @return java.lang.String the converted string
+ */
+ std::string encodeOthers( const std::string& src ) const;
+
+ /**
+ * Decode an encoded URI String.
+ *
+ * @param src - the encoded string
+ * @return the unencoded string version of src.
+ */
+ std::string decode( const std::string& src ) const;
+
+ /**
+ * Compare the Two Hexadecimal encoded strings and return if they are equal.
+ *
+ * @param first - First String to compare.
+ * @param second - The second string to compare.
+ */
+ bool equalsHexCaseInsensitive( const std::string& first,
+ const std::string& second ) const;
+
+ /*
+ * Takes a string that may contain hex sequences like %F1 or %2b and
+ * converts the hex values following the '%' to lowercase.
+ *
+ * @param s - String to convert the hex in.
+ */
+ std::string convertHexToLowerCase( const std::string& s ) const;
+
+ /*
+ * Normalize path, and return the resulting string.
+ *
+ * @param path - the path value to normalize.
+ */
+ std::string normalize( const std::string& path ) const;
+
+ /**
+ * Helper method used to re-calculate the scheme specific part of the
+ * resolved or normalized URIs
+ */
+ void setSchemeSpecificPart();
+
};
}}