UrlBase.cc

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00012 #include <zypp/url/UrlBase.h>
00013 #include <zypp/base/String.h>
00014 #include <zypp/base/Gettext.h>
00015  
00016 #include <stdexcept>
00017 #include <climits>
00018 #include <errno.h>
00019 #include <sys/types.h>
00020 #include <sys/socket.h>
00021 #include <arpa/inet.h>
00022 
00023 
00024 // ---------------------------------------------------------------
00025 /*
00026 ** authority = //[user [:password] @ ] host [:port]
00027 **
00028 ** host      = hostname | IPv4 | "[" IPv6-IP "]" | "[v...]"
00029 */
00030 #define RX_SPLIT_AUTHORITY \
00031         "^(([^:@]*)([:]([^@]*))?@)?(\\[[^]]+\\]|[^:]+)?([:](.*))?"
00032 
00033 #define RX_VALID_SCHEME    "^[a-zA-Z][a-zA-Z0-9\\.+-]*$"
00034 
00035 #define RX_VALID_PORT      "^[0-9]{1,5}$"
00036 
00037 #define RX_VALID_HOSTNAME  "^[[:alnum:]]+([\\.-][[:alnum:]]+)*$"
00038 
00039 #define RX_VALID_HOSTIPV4  \
00040         "^([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})$"
00041 
00042 #define RX_VALID_HOSTIPV6  \
00043         "^\\[[:a-fA-F0-9]+(:[0-9]{1,3}(\\.[0-9]{1,3}){3})?\\]$"
00044 
00045 
00047 namespace zypp
00048 { 
00049 
00051   namespace url
00052   { 
00053 
00054 
00055     // ---------------------------------------------------------------
00056     /*
00057     ** URL asString() view option constants:
00058     */
00059     const ViewOption  ViewOption::WITH_SCHEME       = 0x0001;
00060     const ViewOption  ViewOption::WITH_USERNAME     = 0x0002;
00061     const ViewOption  ViewOption::WITH_PASSWORD     = 0x0004;
00062     const ViewOption  ViewOption::WITH_HOST         = 0x0008;
00063     const ViewOption  ViewOption::WITH_PORT         = 0x0010;
00064     const ViewOption  ViewOption::WITH_PATH_NAME    = 0x0020;
00065     const ViewOption  ViewOption::WITH_PATH_PARAMS  = 0x0040;
00066     const ViewOption  ViewOption::WITH_QUERY_STR    = 0x0080;
00067     const ViewOption  ViewOption::WITH_FRAGMENT     = 0x0100;
00068     const ViewOption  ViewOption::EMPTY_AUTHORITY   = 0x0200;
00069     const ViewOption  ViewOption::EMPTY_PATH_NAME   = 0x0400;
00070     const ViewOption  ViewOption::EMPTY_PATH_PARAMS = 0x0800;
00071     const ViewOption  ViewOption::EMPTY_QUERY_STR   = 0x1000;
00072     const ViewOption  ViewOption::EMPTY_FRAGMENT    = 0x2000;
00073     const ViewOption  ViewOption::DEFAULTS          = 0x07bb;
00074     /*
00075     const ViewOption  ViewOption::DEFAULTS          =
00076                       ViewOption::WITH_SCHEME       +
00077                       ViewOption::WITH_USERNAME     +
00078                       ViewOption::WITH_HOST         +
00079                       ViewOption::WITH_PORT         +
00080                       ViewOption::WITH_PATH_NAME    +
00081                       ViewOption::WITH_QUERY_STR    +
00082                       ViewOption::WITH_FRAGMENT     +
00083                       ViewOption::EMPTY_AUTHORITY   +
00084                       ViewOption::EMPTY_PATH_NAME;
00085     */
00086 
00087     // ---------------------------------------------------------------
00088     ViewOption::ViewOption()
00089       : opt(0x07bb)
00090     {}
00091 
00092     // ---------------------------------------------------------------
00093     ViewOption::ViewOption(int option)
00094       : opt(option)
00095     {}
00096 
00097 
00098     // ---------------------------------------------------------------
00099     /*
00100     ** Behaviour configuration variables.
00101     */
00102     typedef std::map< std::string, std::string > UrlConfig;
00103 
00104 
00105     // ---------------------------------------------------------------
00109     class UrlBaseData
00110     {
00111     public:
00112       UrlBaseData()
00113       {}
00114 
00115       UrlBaseData(const UrlConfig &conf)
00116         : config(conf)
00117       {}
00118 
00119       UrlConfig       config;
00120       ViewOptions     vopts;
00121 
00122       std::string     scheme;
00123       std::string     user;
00124       std::string     pass;
00125       std::string     host;
00126       std::string     port;
00127       std::string     pathname;
00128       std::string     pathparams;
00129       std::string     querystr;
00130       std::string     fragment;
00131     };
00132 
00133 
00134     // ---------------------------------------------------------------
00135     /*
00136     ** Anonymous/internal utility namespace:
00137     */
00138     namespace // anonymous
00139     {
00140 
00141                         // -------------------------------------------------------------
00142       inline void
00143       checkUrlData(const std::string &data,
00144                    const std::string &name,
00145                    const std::string &regx,
00146                    bool               show=true)
00147       {
00148         if( regx.empty() || regx == "^$")
00149         {
00150           ZYPP_THROW(UrlNotAllowedException(
00151             str::form(_("Url scheme does not allow a %s"), name.c_str())
00152           ));
00153         }
00154         else
00155         {
00156           bool valid = false;
00157           try
00158           {
00159             str::regex rex(regx);
00160             valid = str::regex_match(data, rex);
00161           }
00162           catch( ... )
00163           {}
00164 
00165           if( !valid)
00166           {
00167             if( show)
00168             {
00169               ZYPP_THROW(UrlBadComponentException(
00170                 str::form(_("Invalid %s component '%s'"),
00171                           name.c_str(), data.c_str())
00172               ));
00173             }
00174             else
00175             {
00176               ZYPP_THROW(UrlBadComponentException(
00177                 str::form(_("Invalid %s component"), name.c_str())
00178               ));
00179             }
00180           }
00181         }
00182       }
00183 
00184     } // namespace
00185 
00186 
00187     // ---------------------------------------------------------------
00188     UrlBase::~UrlBase()
00189     {
00190       delete m_data;
00191       m_data = NULL;
00192     }
00193 
00194 
00195     // ---------------------------------------------------------------
00196     UrlBase::UrlBase()
00197       : m_data( new UrlBaseData())
00198     {
00199       configure();
00200     }
00201 
00202 
00203     // ---------------------------------------------------------------
00204     UrlBase::UrlBase(const UrlBase &url)
00205       : m_data( new UrlBaseData( *(url.m_data)))
00206     {
00207     }
00208 
00209 
00210     // ---------------------------------------------------------------
00211     UrlBase::UrlBase(const std::string &scheme,
00212                      const std::string &authority,
00213                      const std::string &pathdata,
00214                      const std::string &querystr,
00215                      const std::string &fragment)
00216       : m_data( new UrlBaseData())
00217     {
00218       configure();
00219       init(scheme, authority, pathdata, querystr, fragment);
00220     }
00221 
00222 
00223     // ---------------------------------------------------------------
00224     void
00225     UrlBase::init(const std::string &scheme,
00226                   const std::string &authority,
00227                   const std::string &pathdata,
00228                   const std::string &querystr,
00229                   const std::string &fragment)
00230     {
00231       setScheme(scheme);
00232       setAuthority(authority);
00233       setPathData(pathdata);
00234       setQueryString(querystr);
00235       setFragment(fragment, zypp::url::E_ENCODED);
00236     }
00237 
00238 
00239     // ---------------------------------------------------------------
00240     void
00241     UrlBase::configure()
00242     {
00243       config("sep_pathparams",  ";");
00244       config("psep_pathparam",  ",");
00245       config("vsep_pathparam",  "=");
00246 
00247       config("psep_querystr",   "&");
00248       config("vsep_querystr",   "=");
00249 
00250       config("safe_username",   "~!$&'()*+=,;");
00251       config("safe_password",   "~!$&'()*+=,:;");
00252       config("safe_hostname",   "[:]");
00253       config("safe_pathname",   "~!$&'()*+=,:@/");
00254       config("safe_pathparams", "~!$&'()*+=,:;@/");
00255       config("safe_querystr",   "~!$&'()*+=,:;@/?");
00256       config("safe_fragment",   "~!$&'()*+=,:;@/?");
00257 
00258       // y=yes (allowed)
00259       // n=no  (disallowed, exception if !empty)
00260       config("with_authority",  "y");
00261       config("with_port",       "y");
00262 
00263       // y=yes (required but don't throw if empty)
00264       // n=no  (not required, ignore if empty)
00265       // m=mandatory (exception if empty)
00266       config("require_host",    "n");
00267       config("require_pathname","n");
00268 
00269       // y=yes (encode 2. slash even if authority present)
00270       // n=no  (don't encode 2. slash if authority present)
00271       config("path_encode_slash2", "n");
00272 
00273       config("rx_username",     "^([a-zA-Z0-9!$&'\\(\\)*+=,;~\\._-]|%[a-fA-F0-9]{2})+$");
00274       config("rx_password",     "^([a-zA-Z0-9!$&'\\(\\)*+=,:;~\\._-]|%[a-fA-F0-9]{2})+$");
00275 
00276       config("rx_pathname",     "^([a-zA-Z0-9!$&'\\(\\)*+=,:@/~\\._-]|%[a-fA-F0-9]{2})+$");
00277       config("rx_pathparams",   "^([a-zA-Z0-9!$&'\\(\\)*+=,:;@/~\\._-]|%[a-fA-F0-9]{2})+$");
00278 
00279       config("rx_querystr",     "^([a-zA-Z0-9!$&'\\(\\)*+=,:;@/?~\\._-]|%[a-fA-F0-9]{2})+$");
00280       config("rx_fragment",     "^([a-zA-Z0-9!$&'\\(\\)*+=,:;@/?~\\._-]|%[a-fA-F0-9]{2})+$");
00281     }
00282 
00283 
00284     // ---------------------------------------------------------------
00285     void
00286     UrlBase::config(const std::string &opt, const std::string &val)
00287     {
00288       m_data->config[opt] = val;
00289     }
00290 
00291 
00292     // ---------------------------------------------------------------
00293     std::string
00294     UrlBase::config(const std::string &opt) const
00295     {
00296       UrlConfig::const_iterator v( m_data->config.find(opt));
00297       if( v != m_data->config.end())
00298         return v->second;
00299       else
00300         return std::string();
00301     }
00302 
00303 
00304     // ---------------------------------------------------------------
00305     ViewOptions
00306     UrlBase::getViewOptions() const
00307     {
00308       return m_data->vopts;
00309     }
00310 
00311 
00312     // ---------------------------------------------------------------
00313     void
00314     UrlBase::setViewOptions(const ViewOptions &vopts)
00315     {
00316         m_data->vopts = vopts;
00317     }
00318 
00319 
00320     // ---------------------------------------------------------------
00321     void
00322     UrlBase::clear()
00323     {
00324       zypp::url::UrlConfig   config(m_data->config);
00325       zypp::url::ViewOptions vopts(m_data->vopts);
00326       *m_data = UrlBaseData();
00327       m_data->config = config;
00328       m_data->vopts  = vopts;
00329     }
00330 
00331 
00332     // ---------------------------------------------------------------
00333     UrlBase *
00334     UrlBase::clone() const
00335     {
00336       return new UrlBase(*this);
00337     }
00338 
00339 
00340     // ---------------------------------------------------------------
00341     zypp::url::UrlSchemes
00342     UrlBase::getKnownSchemes() const
00343     {
00344       return UrlSchemes();
00345     }
00346 
00347 
00348     // ---------------------------------------------------------------
00349     bool
00350     UrlBase::isKnownScheme(const std::string &scheme) const
00351     {
00352       std::string                lscheme( str::toLower(scheme));
00353       UrlSchemes                 schemes( getKnownSchemes());
00354       UrlSchemes::const_iterator s;
00355 
00356       for(s=schemes.begin(); s!=schemes.end(); ++s)
00357       {
00358         if( lscheme == str::toLower(*s))
00359           return true;
00360       }
00361       return false;
00362     }
00363 
00364 
00365     // ---------------------------------------------------------------
00366     bool
00367     UrlBase::isValidScheme(const std::string &scheme) const
00368     {
00369       bool valid = false;
00370       try
00371       {
00372         str::regex rex(RX_VALID_SCHEME);
00373         valid = str::regex_match(scheme, rex);
00374       }
00375       catch( ... )
00376       {}
00377 
00378       if(valid)
00379       {
00380         std::string    lscheme( str::toLower(scheme));
00381         UrlSchemes     schemes( getKnownSchemes());
00382 
00383         if( schemes.empty())
00384           return true;
00385 
00386         UrlSchemes::const_iterator s;
00387         for(s=schemes.begin(); s!=schemes.end(); ++s)
00388         {
00389           if( lscheme == str::toLower(*s))
00390             return true;
00391         }
00392       }
00393       return false;
00394     }
00395 
00396 
00397     // ---------------------------------------------------------------
00398     bool
00399     UrlBase::isValid() const
00400     {
00401       /*
00402       ** scheme is the only mandatory component
00403       ** for all url's and is already verified,
00404       ** (except for empty Url instances), so
00405       ** Url with empty scheme is never valid.
00406       */
00407       if( getScheme().empty())
00408         return false;
00409 
00410       std::string host( getHost(zypp::url::E_ENCODED));
00411       if( host.empty() && config("require_host")     != "n")
00412         return false;
00413 
00414       std::string path( getPathName(zypp::url::E_ENCODED));
00415       if( path.empty() && config("require_pathname") != "n")
00416         return false;
00417 
00418       /*
00419       ** path has to begin with "/" if authority avaliable
00420       ** if host is set after the pathname, we can't throw
00421       */
00422       if( !host.empty() && !path.empty() && path.at(0) != '/')
00423         return false;
00424 
00425       return true;
00426     }
00427 
00428 
00429     // ---------------------------------------------------------------
00430     std::string
00431     UrlBase::asString() const
00432     {
00433       return asString(getViewOptions());
00434     }
00435 
00436 
00437     // ---------------------------------------------------------------
00438     std::string
00439     UrlBase::asString(const zypp::url::ViewOptions &opts) const
00440     {
00441       std::string   url;
00442       UrlBaseData   tmp;
00443 
00444       if( opts.has(ViewOptions::WITH_SCHEME))
00445       {
00446         tmp.scheme = getScheme();
00447         if( !tmp.scheme.empty())
00448         {
00449           url += tmp.scheme + ":";
00450 
00451           if( opts.has(ViewOptions::WITH_HOST))
00452           {
00453             tmp.host = getHost(zypp::url::E_ENCODED);
00454             if( !tmp.host.empty())
00455             {
00456               url += "//";
00457 
00458               if( opts.has(ViewOptions::WITH_USERNAME))
00459               {
00460                 tmp.user = getUsername(zypp::url::E_ENCODED);
00461                 if( !tmp.user.empty())
00462                 {
00463                   url += tmp.user;
00464 
00465                   if( opts.has(ViewOptions::WITH_PASSWORD))
00466                   {
00467                     tmp.pass = getPassword(zypp::url::E_ENCODED);
00468                     if( !tmp.pass.empty())
00469                     {
00470                       url += ":" + tmp.pass;
00471                     }
00472                   }
00473                   url += "@";
00474                 }
00475               }
00476 
00477               url += tmp.host;
00478 
00479               if( opts.has(ViewOptions::WITH_PORT))
00480               {
00481                 tmp.port = getPort();
00482                 if( !tmp.port.empty())
00483                 {
00484                   url += ":" + tmp.port;
00485                 }
00486               }
00487             }
00488             else if( opts.has(ViewOptions::EMPTY_AUTHORITY))
00489             {
00490               url += "//";
00491             }
00492           }
00493           else if( opts.has(ViewOptions::EMPTY_AUTHORITY))
00494           {
00495             url += "//";
00496           }
00497         }
00498       }
00499 
00500       if( opts.has(ViewOptions::WITH_PATH_NAME))
00501       {
00502         tmp.pathname = getPathName(zypp::url::E_ENCODED);
00503         if( !tmp.pathname.empty())
00504         {
00505           if(url.find("/") != std::string::npos)
00506           {
00507             // Url contains authority (that may be empty),
00508             // we may need a rewrite of the encoded path.
00509             tmp.pathname = cleanupPathName(tmp.pathname, true);
00510             if(tmp.pathname.at(0) != '/')
00511             {
00512               url += "/";
00513             }
00514           }
00515           url += tmp.pathname;
00516 
00517           if( opts.has(ViewOptions::WITH_PATH_PARAMS))
00518           {
00519             tmp.pathparams = getPathParams();
00520             if( !tmp.pathparams.empty())
00521             {
00522               url += ";" + tmp.pathparams;
00523             }
00524             else if( opts.has(ViewOptions::EMPTY_PATH_PARAMS))
00525             {
00526               url += ";";
00527             }
00528           }
00529         }
00530         else if( opts.has(ViewOptions::EMPTY_PATH_NAME)
00531                  && url.find("/") != std::string::npos)
00532         {
00533           url += "/";
00534           if( opts.has(ViewOptions::EMPTY_PATH_PARAMS))
00535           {
00536             url += ";";
00537           }
00538         }
00539       }
00540 
00541       if( opts.has(ViewOptions::WITH_QUERY_STR))
00542       {
00543         tmp.querystr = getQueryString();
00544         if( !tmp.querystr.empty())
00545         {
00546           url += "?" + tmp.querystr;
00547         }
00548         else if( opts.has(ViewOptions::EMPTY_QUERY_STR))
00549         {
00550           url += "?";
00551         }
00552       }
00553 
00554       if( opts.has(ViewOptions::WITH_FRAGMENT))
00555       {
00556         tmp.fragment = getFragment(zypp::url::E_ENCODED);
00557         if( !tmp.fragment.empty())
00558         {
00559           url += "#" + tmp.fragment;
00560         }
00561         else if( opts.has(ViewOptions::EMPTY_FRAGMENT))
00562         {
00563           url += "#";
00564         }
00565       }
00566 
00567       return url;
00568     }
00569 
00570 
00571     // ---------------------------------------------------------------
00572     std::string
00573     UrlBase::getScheme() const
00574     {
00575       return m_data->scheme;
00576     }
00577 
00578 
00579     // ---------------------------------------------------------------
00580     std::string
00581     UrlBase::getAuthority() const
00582     {
00583       std::string str;
00584       if( !getHost(zypp::url::E_ENCODED).empty())
00585       {
00586         if( !getUsername(zypp::url::E_ENCODED).empty())
00587         {
00588           str = getUsername(zypp::url::E_ENCODED);
00589           if( !getPassword(zypp::url::E_ENCODED).empty())
00590           {
00591             str += ":" + getPassword(zypp::url::E_ENCODED);
00592           }
00593           str += "@";
00594         }
00595 
00596         str += getHost(zypp::url::E_ENCODED);
00597         if( !getPort().empty())
00598         {
00599           str += ":" + getPort();
00600         }
00601       }
00602       return str;
00603     }
00604 
00605 
00606     // ---------------------------------------------------------------
00607     std::string
00608     UrlBase::getPathData() const
00609     {
00610       return getPathName(zypp::url::E_ENCODED) +
00611              config("sep_pathparams") +
00612              getPathParams();
00613     }
00614 
00615 
00616     // ---------------------------------------------------------------
00617     std::string
00618     UrlBase::getQueryString() const
00619     {
00620       return m_data->querystr;
00621     }
00622 
00623 
00624     // ---------------------------------------------------------------
00625     std::string
00626     UrlBase::getFragment(EEncoding eflag) const
00627     {
00628       if(eflag == zypp::url::E_DECODED)
00629         return zypp::url::decode(m_data->fragment);
00630       else
00631         return m_data->fragment;
00632     }
00633 
00634 
00635     // ---------------------------------------------------------------
00636     std::string
00637     UrlBase::getUsername(EEncoding eflag) const
00638     {
00639       if(eflag == zypp::url::E_DECODED)
00640         return zypp::url::decode(m_data->user);
00641       else
00642         return m_data->user;
00643     }
00644 
00645 
00646     // ---------------------------------------------------------------
00647     std::string
00648     UrlBase::getPassword(EEncoding eflag) const
00649     {
00650       if(eflag == zypp::url::E_DECODED)
00651         return zypp::url::decode(m_data->pass);
00652       else
00653         return m_data->pass;
00654     }
00655 
00656 
00657     // ---------------------------------------------------------------
00658     std::string
00659     UrlBase::getHost(EEncoding eflag) const
00660     {
00661       if(eflag == zypp::url::E_DECODED)
00662         return zypp::url::decode(m_data->host);
00663       else
00664         return m_data->host;
00665     }
00666 
00667 
00668     // ---------------------------------------------------------------
00669     std::string
00670     UrlBase::getPort() const
00671     {
00672       return m_data->port;
00673     }
00674 
00675 
00676     // ---------------------------------------------------------------
00677     std::string
00678     UrlBase::getPathName(EEncoding eflag) const
00679     {
00680       if(eflag == zypp::url::E_DECODED)
00681         return zypp::url::decode(m_data->pathname);
00682       else
00683         return cleanupPathName(m_data->pathname);
00684     }
00685 
00686 
00687     // ---------------------------------------------------------------
00688     std::string
00689     UrlBase::getPathParams() const
00690     {
00691       return m_data->pathparams;
00692     }
00693 
00694 
00695     // ---------------------------------------------------------------
00696     zypp::url::ParamVec
00697     UrlBase::getPathParamsVec() const
00698     {
00699       zypp::url::ParamVec pvec;
00700       if( config("psep_pathparam").empty())
00701       {
00702         pvec.push_back(getPathParams());
00703       }
00704       else
00705       {
00706         zypp::url::split(
00707           pvec,
00708           getPathParams(),
00709           config("psep_pathparam")
00710         );
00711       }
00712       return pvec;
00713     }
00714 
00715 
00716     // ---------------------------------------------------------------
00717     zypp::url::ParamMap
00718     UrlBase::getPathParamsMap(EEncoding eflag) const
00719     {
00720       if( config("psep_pathparam").empty() ||
00721           config("vsep_pathparam").empty())
00722       {
00723         ZYPP_THROW(UrlNotSupportedException(
00724           _("Path parameter parsing not supported for this URL")
00725         ));
00726       }
00727       zypp::url::ParamMap pmap;
00728       zypp::url::split(
00729         pmap,
00730         getPathParams(),
00731         config("psep_pathparam"),
00732         config("vsep_pathparam"),
00733         eflag
00734       );
00735       return pmap;
00736     }
00737 
00738 
00739     // ---------------------------------------------------------------
00740     std::string
00741     UrlBase::getPathParam(const std::string &param, EEncoding eflag) const
00742     {
00743       zypp::url::ParamMap pmap( getPathParamsMap( eflag));
00744       zypp::url::ParamMap::const_iterator i( pmap.find(param));
00745 
00746       return i != pmap.end() ? i->second : std::string();
00747     }
00748 
00749 
00750     // ---------------------------------------------------------------
00751     zypp::url::ParamVec
00752     UrlBase::getQueryStringVec() const
00753     {
00754       zypp::url::ParamVec pvec;
00755       if( config("psep_querystr").empty())
00756       {
00757         pvec.push_back(getQueryString());
00758       }
00759       else
00760       {
00761         zypp::url::split(
00762           pvec,
00763           getQueryString(),
00764           config("psep_querystr")
00765         );
00766       }
00767       return pvec;
00768     }
00769 
00770 
00771     // ---------------------------------------------------------------
00772     zypp::url::ParamMap
00773     UrlBase::getQueryStringMap(EEncoding eflag) const
00774     {
00775       if( config("psep_querystr").empty() ||
00776           config("vsep_querystr").empty())
00777       {
00778         ZYPP_THROW(UrlNotSupportedException(
00779           _("Query string parsing not supported for this URL")
00780         ));
00781       }
00782       zypp::url::ParamMap pmap;
00783       zypp::url::split(
00784         pmap,
00785         getQueryString(),
00786         config("psep_querystr"),
00787         config("vsep_querystr"),
00788         eflag
00789       );
00790       return pmap;
00791     }
00792 
00793 
00794     // ---------------------------------------------------------------
00795     std::string
00796     UrlBase::getQueryParam(const std::string &param, EEncoding eflag) const
00797     {
00798       zypp::url::ParamMap pmap( getQueryStringMap( eflag));
00799       zypp::url::ParamMap::const_iterator i( pmap.find(param));
00800 
00801       return i != pmap.end() ? i->second : std::string();
00802     }
00803 
00804 
00805     // ---------------------------------------------------------------
00806     void
00807     UrlBase::setScheme(const std::string &scheme)
00808     {
00809       if( isValidScheme(scheme))
00810       {
00811         m_data->scheme = str::toLower(scheme);
00812       }
00813       else
00814       if( scheme.empty())
00815       {
00816         ZYPP_THROW(UrlBadComponentException(
00817           _("Url scheme is a required component")
00818         ));
00819       }
00820       else
00821       {
00822         ZYPP_THROW(UrlBadComponentException(
00823           str::form(_("Invalid Url scheme '%s'"), scheme.c_str())
00824         ));
00825       }
00826     }
00827 
00828 
00829     // ---------------------------------------------------------------
00830     void
00831     UrlBase::setAuthority(const std::string &authority)
00832     {
00833       str::smatch out;
00834       bool        ret = false;
00835 
00836       try
00837       {
00838         str::regex  rex(RX_SPLIT_AUTHORITY);
00839         ret = str::regex_match(authority, out, rex);
00840       }
00841       catch( ... )
00842       {}
00843 
00844       if( ret && out.size() == 8)
00845       {
00846         setUsername(out[2].str(), zypp::url::E_ENCODED);
00847         setPassword(out[4].str(), zypp::url::E_ENCODED);
00848         setHost(out[5].str());
00849         setPort(out[7].str());
00850       }
00851       else
00852       {
00853         ZYPP_THROW(UrlParsingException(
00854           _("Unable to parse Url authority")
00855         ));
00856       }
00857     }
00858 
00859     // ---------------------------------------------------------------
00860     void
00861     UrlBase::setPathData(const std::string &pathdata)
00862     {
00863       size_t      pos = std::string::npos;
00864       std::string sep(config("sep_pathparams"));
00865 
00866       if( !sep.empty())
00867         pos = pathdata.find(sep);
00868 
00869       if( pos != std::string::npos)
00870       {
00871         setPathName(pathdata.substr(0, pos),
00872                     zypp::url::E_ENCODED);
00873         setPathParams(pathdata.substr(pos + 1));
00874       }
00875       else
00876       {
00877         setPathName(pathdata,
00878                     zypp::url::E_ENCODED);
00879         setPathParams("");
00880       }
00881     }
00882 
00883 
00884     // ---------------------------------------------------------------
00885     void
00886     UrlBase::setQueryString(const std::string &querystr)
00887     {
00888       if( querystr.empty())
00889       {
00890         m_data->querystr = querystr;
00891       }
00892       else
00893       {
00894         checkUrlData(querystr, "query string", config("rx_querystr"));
00895 
00896         m_data->querystr = querystr;
00897       }
00898     }
00899 
00900 
00901     // ---------------------------------------------------------------
00902     void
00903     UrlBase::setFragment(const std::string &fragment,
00904                          EEncoding         eflag)
00905     {
00906       if( fragment.empty())
00907       {
00908         m_data->fragment = fragment;
00909       }
00910       else
00911       {
00912         if(eflag == zypp::url::E_ENCODED)
00913         {
00914           checkUrlData(fragment, "fragment", config("rx_fragment"));
00915 
00916           m_data->fragment = fragment;
00917         }
00918         else
00919         {
00920           m_data->fragment = zypp::url::encode(
00921             fragment, config("safe_fragment")
00922           );
00923         }
00924       }
00925     }
00926 
00927 
00928     // ---------------------------------------------------------------
00929     void
00930     UrlBase::setUsername(const std::string &user,
00931                          EEncoding         eflag)
00932     {
00933       if( user.empty())
00934       {
00935         m_data->user = user;
00936       }
00937       else
00938       {
00939         if( config("with_authority") != "y")
00940         {
00941           ZYPP_THROW(UrlNotAllowedException(
00942             _("Url scheme does not allow a username")
00943           ));
00944         }
00945 
00946         if(eflag == zypp::url::E_ENCODED)
00947         {
00948           checkUrlData(user, "username", config("rx_username"));
00949 
00950           m_data->user = user;
00951         }
00952         else
00953         {
00954           m_data->user = zypp::url::encode(
00955             user, config("safe_username")
00956           );
00957         }
00958       }
00959     }
00960 
00961 
00962     // ---------------------------------------------------------------
00963     void
00964     UrlBase::setPassword(const std::string &pass,
00965                          EEncoding         eflag)
00966     {
00967       if( pass.empty())
00968       {
00969         m_data->pass = pass;
00970       }
00971       else
00972       {
00973         if( config("with_authority") != "y")
00974         {
00975           ZYPP_THROW(UrlNotAllowedException(
00976             _("Url scheme does not allow a password")
00977           ));
00978         }
00979 
00980         if(eflag == zypp::url::E_ENCODED)
00981         {
00982           checkUrlData(pass, "password", config("rx_password"), false);
00983 
00984           m_data->pass = pass;
00985         }
00986         else
00987         {
00988           m_data->pass = zypp::url::encode(
00989             pass, config("safe_password")
00990           );
00991         }
00992       }
00993     }
00994 
00995 
00996     // ---------------------------------------------------------------
00997     void
00998     UrlBase::setHost(const std::string &host)
00999     {
01000       if( host.empty())
01001       {
01002         if(config("require_host") == "m")
01003         {
01004           ZYPP_THROW(UrlNotAllowedException(
01005             _("Url scheme requires a host component")
01006           ));
01007         }
01008         m_data->host = host;
01009       }
01010       else
01011       {
01012         if( config("with_authority") != "y")
01013         {
01014           ZYPP_THROW(UrlNotAllowedException(
01015             _("Url scheme does not allow a host component")
01016           ));
01017         }
01018 
01019         if( isValidHost(host))
01020         {
01021           std::string temp;
01022 
01023           // always decode in case isValidHost()
01024           // is reimplemented and supports also
01025           // the [v ... ] notation.
01026           if( host.at(0) == '[')
01027           {
01028             temp = str::toUpper(zypp::url::decode(host));
01029           }
01030           else
01031           {
01032             temp = str::toLower(zypp::url::decode(host));
01033           }
01034 
01035           m_data->host = zypp::url::encode(
01036             temp, config("safe_hostname")
01037           );
01038         }
01039         else
01040         {
01041           ZYPP_THROW(UrlBadComponentException(
01042             str::form(_("Invalid host component '%s'"), host.c_str())
01043           ));
01044         }
01045       }
01046     }
01047 
01048 
01049     // ---------------------------------------------------------------
01050     void
01051     UrlBase::setPort(const std::string &port)
01052     {
01053       if( port.empty())
01054       {
01055         m_data->port = port;
01056       }
01057       else
01058       {
01059         if( config("with_authority") != "y" ||
01060             config("with_port")      != "y")
01061         {
01062           ZYPP_THROW(UrlNotAllowedException(
01063             _("Url scheme does not allow a port")
01064           ));
01065         }
01066 
01067         if( isValidPort(port))
01068         {
01069           m_data->port = port;
01070         }
01071         else
01072         {
01073           ZYPP_THROW(UrlBadComponentException(
01074             str::form(_("Invalid port component '%s'"), port.c_str())
01075           ));
01076         }
01077       }
01078     }
01079 
01080 
01081     // ---------------------------------------------------------------
01082     void
01083     UrlBase::setPathName(const std::string &path,
01084                          EEncoding         eflag)
01085     {
01086       if( path.empty())
01087       {
01088         if(config("require_pathname") == "m")
01089         {
01090           ZYPP_THROW(UrlNotAllowedException(
01091             _("Url scheme requires path name")
01092           ));
01093         }
01094         m_data->pathname = path;
01095       }
01096       else
01097       {
01098         if(eflag == zypp::url::E_ENCODED)
01099         {
01100           checkUrlData(path, "path name", config("rx_pathname"));
01101 
01102           if( !getHost(zypp::url::E_ENCODED).empty())
01103           {
01104             // has to begin with a "/". For consistency with
01105             // setPathName while the host is empty, we allow
01106             // it in encoded ("%2f") form - cleanupPathName()
01107             // will fix / decode the first slash if needed.
01108             if(!(path.at(0) == '/' || (path.size() >= 3 &&
01109                  str::toLower(path.substr(0, 3)) == "%2f")))
01110             {
01111               ZYPP_THROW(UrlNotAllowedException(
01112                 _("Relative path not allowed if authority exists")
01113               ));
01114             }
01115           }
01116 
01117           m_data->pathname = cleanupPathName(path);
01118         }
01119         else //     zypp::url::E_DECODED
01120         {
01121           if( !getHost(zypp::url::E_ENCODED).empty())
01122           {
01123             if(path.at(0) != '/')
01124             {
01125               ZYPP_THROW(UrlNotAllowedException(
01126                 _("Relative path not allowed if authority exists")
01127               ));
01128             }
01129           }
01130 
01131           m_data->pathname = cleanupPathName(
01132             zypp::url::encode(
01133               path, config("safe_pathname")
01134             )
01135           );
01136         }
01137       }
01138     }
01139 
01140 
01141     // ---------------------------------------------------------------
01142     void
01143     UrlBase::setPathParams(const std::string &params)
01144     {
01145       if( params.empty())
01146       {
01147         m_data->pathparams = params;
01148       }
01149       else
01150       {
01151         checkUrlData(params, "path parameters", config("rx_pathparams"));
01152 
01153         m_data->pathparams = params;
01154       }
01155     }
01156 
01157 
01158     // ---------------------------------------------------------------
01159     void
01160     UrlBase::setPathParamsVec(const zypp::url::ParamVec &pvec)
01161     {
01162       setPathParams(
01163         zypp::url::join(
01164           pvec,
01165           config("psep_pathparam")
01166         )
01167       );
01168     }
01169 
01170 
01171     // ---------------------------------------------------------------
01172     void
01173     UrlBase::setPathParamsMap(const zypp::url::ParamMap &pmap)
01174     {
01175       if( config("psep_pathparam").empty() ||
01176           config("vsep_pathparam").empty())
01177       {
01178         ZYPP_THROW(UrlNotSupportedException(
01179           _("Path Parameter parsing not supported for this URL")
01180         ));
01181       }
01182       setPathParams(
01183         zypp::url::join(
01184           pmap,
01185           config("psep_pathparam"),
01186           config("vsep_pathparam"),
01187           config("safe_pathparams")
01188         )
01189       );
01190     }
01191 
01192 
01193     // ---------------------------------------------------------------
01194     void
01195     UrlBase::setPathParam(const std::string &param, const std::string &value)
01196     {
01197           zypp::url::ParamMap pmap( getPathParamsMap(zypp::url::E_DECODED));
01198           pmap[param] = value;
01199           setPathParamsMap(pmap);
01200     }
01201 
01202 
01203     // ---------------------------------------------------------------
01204     void
01205     UrlBase::setQueryStringVec(const zypp::url::ParamVec &pvec)
01206     {
01207       setQueryString(
01208         zypp::url::join(
01209           pvec,
01210           config("psep_querystr")
01211         )
01212       );
01213     }
01214 
01215 
01216     // ---------------------------------------------------------------
01217     void
01218     UrlBase::setQueryStringMap(const zypp::url::ParamMap &pmap)
01219     {
01220       if( config("psep_querystr").empty() ||
01221           config("vsep_querystr").empty())
01222       {
01223         ZYPP_THROW(UrlNotSupportedException(
01224           _("Query string parsing not supported for this URL")
01225         ));
01226       }
01227       setQueryString(
01228         zypp::url::join(
01229           pmap,
01230           config("psep_querystr"),
01231           config("vsep_querystr"),
01232           config("safe_querystr")
01233         )
01234       );
01235     }
01236 
01237     // ---------------------------------------------------------------
01238     void
01239     UrlBase::setQueryParam(const std::string &param, const std::string &value)
01240     {
01241           zypp::url::ParamMap pmap( getQueryStringMap(zypp::url::E_DECODED));
01242           pmap[param] = value;
01243           setQueryStringMap(pmap);
01244     }
01245 
01246 
01247     // ---------------------------------------------------------------
01248     std::string
01249     UrlBase::cleanupPathName(const std::string &path) const
01250     {
01251       bool authority = !getHost(zypp::url::E_ENCODED).empty();
01252       return cleanupPathName(path, authority);
01253     }
01254 
01255     // ---------------------------------------------------------------
01256     std::string
01257     UrlBase::cleanupPathName(const std::string &path, bool authority) const
01258     {
01259       std::string copy( path);
01260 
01261       // decode the first slash if it is encoded ...
01262       if(copy.size() >= 3 && copy.at(0) != '/' &&
01263          str::toLower(copy.substr(0, 3)) == "%2f")
01264       {
01265         copy.replace(0, 3, "/");
01266       }
01267 
01268       // if path begins with a double slash ("//"); encode the second
01269       // slash [minimal and IMO sufficient] before the first path
01270       // segment, to fulfill the path-absolute rule of RFC 3986
01271       // disallowing a "//" if no authority is present.
01272       if( authority)
01273       {
01274         //
01275         // rewrite of "//" to "/%2f" not required, use config
01276         //
01277         if(config("path_encode_slash2") == "y")
01278         {
01279           // rewrite "//" ==> "/%2f"
01280           if(copy.size() >= 2 && copy.at(0) == '/' && copy.at(1) == '/')
01281           {
01282             copy.replace(1, 1, "%2F");
01283           }
01284         }
01285         else
01286         {
01287           // rewrite "/%2f" ==> "//"
01288           if(copy.size() >= 4 && copy.at(0) == '/' &&
01289              str::toLower(copy.substr(1, 4)) == "%2f")
01290           {
01291             copy.replace(1, 4, "/");
01292           }
01293         }
01294       }
01295       else
01296       {
01297         // rewrite of "//" to "/%2f" is required (no authority)
01298         if(copy.size() >= 2 && copy.at(0) == '/' && copy.at(1) == '/')
01299         {
01300           copy.replace(1, 1, "%2F");
01301         }
01302       }
01303       return copy;
01304     }
01305 
01306 
01307     // ---------------------------------------------------------------
01308     bool
01309     UrlBase::isValidHost(const std::string &host) const
01310     {
01311       try
01312       {
01313         str::regex regx(RX_VALID_HOSTIPV6);
01314         if( str::regex_match(host, regx))
01315         {
01316           struct in6_addr ip;
01317           std::string temp( host.substr(1, host.size()-2));
01318           
01319           return inet_pton(AF_INET6, temp.c_str(), &ip) > 0;
01320         }
01321         else
01322         {
01323           // matches also IPv4 dotted-decimal adresses...
01324           std::string temp( zypp::url::decode(host));
01325           str::regex  regx(RX_VALID_HOSTNAME);
01326           return str::regex_match(temp, regx);
01327         }
01328       }
01329       catch( ... )
01330       {}
01331 
01332       return false;
01333     }
01334 
01335 
01336     // ---------------------------------------------------------------
01337     bool
01338     UrlBase::isValidPort(const std::string &port) const
01339     {
01340       try
01341       {
01342         str::regex regx(RX_VALID_PORT);
01343         if( str::regex_match(port, regx))
01344         {
01345           long pnum = str::strtonum<long>(port);
01346           return ( pnum >= 1 && pnum <= USHRT_MAX);
01347         }
01348       }
01349       catch( ... )
01350       {}
01351 
01352       return false;
01353     }
01354 
01355 
01357   } // namespace url
01359 
01361 } // namespace zypp
01363 /*
01364 ** vim: set ts=2 sts=2 sw=2 ai et:
01365 */

Generated on Tue Nov 28 16:49:34 2006 for zypp by  doxygen 1.5.0