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

Generated on Thu Apr 24 02:25:04 2008 for zypp by  doxygen 1.4.6