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

Generated on Tue Sep 25 19:23:11 2007 for libzypp by  doxygen 1.5.3