3 * Copyright 2000-2006, OpenLDAP Foundation, All Rights Reserved.
4 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
15 #define PCT_ENCFLAG_NONE 0x0000U
16 #define PCT_ENCFLAG_COMMA 0x0001U
17 #define PCT_ENCFLAG_SLASH 0x0002U
19 #define LDAP_DEFAULT_PORT 389
20 #define LDAPS_DEFAULT_PORT 636
22 LDAPUrl::LDAPUrl(const std::string &url)
24 DEBUG(LDAP_DEBUG_CONSTRUCT, "LDAPUrl::LDAPUrl()" << endl);
25 DEBUG(LDAP_DEBUG_CONSTRUCT | LDAP_DEBUG_PARAMETER,
26 " url:" << url << endl);
40 DEBUG(LDAP_DEBUG_DESTROY, "LDAPUrl::~LDAPUrl()" << endl);
44 int LDAPUrl::getPort() const
49 void LDAPUrl::setPort(int port)
55 int LDAPUrl::getScope() const
60 void LDAPUrl::setScope( const std::string &scope )
62 if (scope == "base" || scope == "" ) {
64 } else if (scope == "one" ) {
66 } else if (scope == "sub" ) {
69 throw LDAPUrlException(LDAPUrlException::INVALID_SCOPE,
70 "Scope was:" + scope);
75 const string& LDAPUrl::getURLString() const
78 this->components2Url();
84 void LDAPUrl::setURLString( const std::string &url )
93 const string& LDAPUrl::getHost() const
98 void LDAPUrl::setHost( const std::string &host )
104 const string& LDAPUrl::getDN() const
108 void LDAPUrl::setDN( const std::string &dn )
114 const string& LDAPUrl::getFilter() const
118 void LDAPUrl::setFilter( const std::string &filter )
124 const StringList& LDAPUrl::getAttrs() const
128 void LDAPUrl::setAttrs( const StringList &attrs )
134 const StringList& LDAPUrl::getExtensions() const
139 void LDAPUrl::setExtensions( const StringList &ext )
145 const std::string& LDAPUrl::getScheme() const
150 void LDAPUrl::setScheme( const std::string &scheme )
152 if (scheme == "ldap" || scheme == "ldaps" ||
153 scheme == "ldapi" || scheme == "cldap" )
158 throw LDAPUrlException(LDAPUrlException::INVALID_SCHEME,
159 "Unknown URL scheme: \"" + scheme + "\"");
163 void LDAPUrl::parseUrl()
165 DEBUG(LDAP_DEBUG_TRACE, "LDAPUrl::parseUrl()" << std::endl);
167 std::string::size_type pos = m_urlString.find(':');
168 std::string::size_type startpos = pos;
169 if (pos == std::string::npos) {
170 throw LDAPUrlException(LDAPUrlException::INVALID_URL,
171 "No colon found in URL");
173 std::string scheme = m_urlString.substr(0, pos);
174 DEBUG(LDAP_DEBUG_TRACE, " scheme is <" << scheme << ">" << std::endl);
176 if ( scheme == "ldap" ) {
178 } else if ( scheme == "ldaps" ) {
180 } else if ( scheme == "ldapi" ) {
182 } else if ( scheme == "cldap" ) {
185 throw LDAPUrlException(LDAPUrlException::INVALID_SCHEME,
186 "Unknown URL Scheme: \"" + scheme + "\"");
189 if ( m_urlString[pos+1] != '/' || m_urlString[pos+2] != '/' ) {
190 throw LDAPUrlException(LDAPUrlException::INVALID_URL);
194 if ( m_urlString[startpos] == '/' ) {
195 // no hostname and port
198 std::string::size_type hostend;
199 std::string::size_type portstart;
200 pos = m_urlString.find('/', startpos);
203 if ( m_urlString[startpos] == '[' ) {
206 hostend = m_urlString.find(']', startpos);
207 if ( hostend == std::string::npos ){
208 throw LDAPUrlException(LDAPUrlException::INVALID_URL);
210 portstart = hostend + 1;
212 hostend = m_urlString.find(':', startpos);
213 if ( hostend == std::string::npos || portstart > pos ) {
218 std::string host = m_urlString.substr(startpos, hostend - startpos);
219 DEBUG(LDAP_DEBUG_TRACE, " host: <" << host << ">" << std::endl);
220 percentDecode(host, m_Host);
222 if (portstart >= m_urlString.length() || portstart >= pos ) {
223 if ( m_Scheme == "ldap" || m_Scheme == "cldap" ) {
224 m_Port = LDAP_DEFAULT_PORT;
225 } else if ( m_Scheme == "ldaps" ) {
226 m_Port = LDAPS_DEFAULT_PORT;
229 std::string port = m_urlString.substr(portstart+1,
230 (pos == std::string::npos ? pos : pos-portstart-1) );
231 if ( port.length() > 0 ) {
232 std::istringstream i(port);
235 throw LDAPUrlException(LDAPUrlException::INVALID_PORT);
238 DEBUG(LDAP_DEBUG_TRACE, " Port: <" << m_Port << ">"
243 int parserMode = base;
244 while ( pos != std::string::npos ) {
245 pos = m_urlString.find('?', startpos);
246 std::string actComponent = m_urlString.substr(startpos,
248 DEBUG(LDAP_DEBUG_TRACE, " ParserMode:" << parserMode << std::endl);
249 DEBUG(LDAP_DEBUG_TRACE, " ActComponent: <" << actComponent << ">"
251 std::string s_scope = "";
252 std::string s_ext = "";
255 percentDecode(actComponent, m_DN);
256 DEBUG(LDAP_DEBUG_TRACE, " BaseDN:" << m_DN << std::endl);
259 DEBUG(LDAP_DEBUG_TRACE, " reading Attributes" << std::endl);
260 if (actComponent.length() != 0 ) {
261 string2list(actComponent,m_Attrs, true);
265 percentDecode(actComponent, s_scope);
266 if (s_scope == "base" || s_scope == "" ) {
268 } else if (s_scope == "one" ) {
270 } else if (s_scope == "sub" ) {
273 throw LDAPUrlException(LDAPUrlException::INVALID_SCOPE);
275 DEBUG(LDAP_DEBUG_TRACE, " Scope: <" << s_scope << ">"
279 percentDecode(actComponent, m_Filter);
280 DEBUG(LDAP_DEBUG_TRACE, " filter: <" << m_Filter << ">"
284 DEBUG(LDAP_DEBUG_TRACE, " reading Extensions" << std::endl);
285 string2list(actComponent, m_Extensions, true);
288 DEBUG(LDAP_DEBUG_TRACE, " unknown state" << std::endl);
296 void LDAPUrl::percentDecode(const std::string& src, std::string &out)
298 DEBUG(LDAP_DEBUG_TRACE, "LDAPUrl::percentDecode()" << std::endl);
299 std::string::size_type pos = 0;
300 std::string::size_type startpos = 0;
301 pos = src.find('%', startpos);
302 while ( pos != std::string::npos ) {
303 out += src.substr(startpos, pos - startpos);
304 std::string istr(src.substr(pos+1, 2));
305 std::istringstream i(istr);
306 i.setf(std::ios::hex, std::ios::basefield);
307 i.unsetf(std::ios::showbase);
311 throw LDAPUrlException(LDAPUrlException::URL_DECODING_ERROR,
312 "Invalid percent encoding");
317 pos = src.find('%', startpos);
319 out += src.substr(startpos, pos - startpos);
322 void LDAPUrl::string2list(const std::string &src, StringList& sl,
325 std::string::size_type comma_startpos = 0;
326 std::string::size_type comma_pos = 0;
328 while ( comma_pos != std::string::npos ) {
329 comma_pos = src.find(',', comma_startpos);
330 actItem = src.substr(comma_startpos, comma_pos - comma_startpos);
333 this->percentDecode(actItem,decoded);
337 comma_startpos = comma_pos + 1;
342 void LDAPUrl::components2Url() const
344 std::ostringstream url;
345 std::string encoded = "";
347 url << m_Scheme << "://";
349 if ( m_Host.find( ':', 0 ) != std::string::npos ) {
350 url << "[" << this->percentEncode(m_Host, encoded) << "]";
352 url << this->percentEncode(m_Host, encoded, PCT_ENCFLAG_SLASH);
356 url << ":" << m_Port;
362 this->percentEncode( m_DN, encoded );
366 if ( ! m_Attrs.empty() ){
369 for ( StringList::const_iterator i = m_Attrs.begin();
370 i != m_Attrs.end(); i++)
372 this->percentEncode( *i, encoded );
383 if ( m_Scope == 1 ) {
386 } else if ( m_Scope == 2 ) {
392 if (m_Filter != "" ){
393 this->percentEncode( m_Filter, encoded );
394 url << qm << "?" << encoded;
400 if ( ! m_Extensions.empty() ){
403 for ( StringList::const_iterator i = m_Extensions.begin();
404 i != m_Extensions.end(); i++)
406 this->percentEncode( *i, encoded, 1);
415 m_urlString=url.str();
419 std::string& LDAPUrl::percentEncode( const std::string &src,
423 std::ostringstream o;
424 o.setf(std::ios::hex, std::ios::basefield);
425 o.setf(std::ios::uppercase);
426 o.unsetf(std::ios::showbase);
428 for ( std::string::const_iterator i = src.begin(); i != src.end(); i++ ){
435 if ( flags & PCT_ENCFLAG_COMMA ) {
443 if ( flags & PCT_ENCFLAG_SLASH ) {
471 if ( std::isalnum(*i) ) {
479 o << "%" << std::setw(2) << std::setfill('0') << (int)(unsigned char)*i ;
488 const code2string_s LDAPUrlException::code2string[] = {
489 { INVALID_SCHEME, "Invalid URL Scheme" },
490 { INVALID_PORT, "Invalid Port in Url" },
491 { INVALID_SCOPE, "Invalid Search Scope in Url" },
492 { INVALID_URL, "Invalid LDAP Url" },
493 { URL_DECODING_ERROR, "Url-decoding Error" },
497 LDAPUrlException::LDAPUrlException( int code, const std::string &msg) :
498 m_code(code), m_addMsg(msg) {}
500 int LDAPUrlException::getCode() const
505 const std::string LDAPUrlException::getAdditionalInfo() const
510 const std::string LDAPUrlException::getErrorMessage() const
512 for ( int i = 0; code2string[i].string != 0; i++ ) {
513 if ( code2string[i].code == m_code ) {
514 return std::string(code2string[i].string);