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

Generated on Thu Jul 6 00:07:29 2006 for zypp by  doxygen 1.4.6