LCOV - code coverage report
Current view: top level - lunchbox - uri.cpp (source / functions) Hit Total Coverage
Test: lcov2.info Lines: 76 90 84.4 %
Date: 2014-08-05 Functions: 20 29 69.0 %

          Line data    Source code
       1             : 
       2             : /* Copyright (c) 2013-2014, ahmet.bilgili@epfl.ch
       3             :  *
       4             :  * This file is part of Lunchbox <https://github.com/Eyescale/Lunchbox>
       5             :  *
       6             :  * This library is free software; you can redistribute it and/or modify it under
       7             :  * the terms of the GNU Lesser General Public License version 2.1 as published
       8             :  * by the Free Software Foundation.
       9             :  *
      10             :  * This library is distributed in the hope that it will be useful, but WITHOUT
      11             :  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
      12             :  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
      13             :  * details.
      14             :  *
      15             :  * You should have received a copy of the GNU Lesser General Public License
      16             :  * along with this library; if not, write to the Free Software Foundation, Inc.,
      17             :  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      18             :  */
      19             : 
      20             : #include <lunchbox/uri.h>
      21             : 
      22             : #include <boost/regex.hpp>
      23             : #include <boost/algorithm/string_regex.hpp>
      24             : #include <boost/lexical_cast.hpp>
      25             : #include <sstream>
      26             : #include <exception>
      27             : 
      28             : namespace lunchbox
      29             : {
      30             : namespace detail
      31             : {
      32             : 
      33          10 : struct URIData
      34             : {
      35          10 :     URIData() : port( 0 ) {}
      36             : 
      37             :     std::string scheme;
      38             :     std::string userinfo;
      39             :     std::string host;
      40             :     uint16_t port;
      41             :     std::string path;
      42             :     std::string query;
      43             :     std::string fragment;
      44             :     lunchbox::URI::KVMap queryMap;
      45             : };
      46             : 
      47             : class uri_parse : public std::exception
      48             : {
      49             : public:
      50           1 :     uri_parse( const std::string& uri )
      51           1 :     {
      52           1 :         _error << "Error parsing URI string: " << uri << std::endl;
      53           1 :     }
      54             : 
      55             :     uri_parse( const uri_parse& excep )
      56             :     {
      57             :         _error << excep._error;
      58             :     }
      59             : 
      60           1 :     virtual ~uri_parse() throw() {}
      61             : 
      62           0 :     virtual const char* what() const throw() { return _error.str().c_str(); }
      63             : 
      64             : private:
      65             :     std::stringstream _error;
      66             : };
      67             : 
      68           9 : class URI
      69             : {
      70             : public:
      71          10 :     URI( const std::string& uri )
      72          11 :        : _uri( uri )
      73             :     {
      74          10 :         if( uri.empty( ))
      75          11 :             return;
      76             : 
      77           8 :         boost::match_results< std::string::const_iterator > results;
      78             :         boost::regex expr(
      79             :             "^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?",
      80          16 :             boost::regex::perl | boost::regex::icase );
      81             : 
      82           8 :         if( !boost::regex_search( uri, results, expr ) )
      83           0 :             throw uri_parse( _uri );
      84             : 
      85           8 :         const std::string& schema = std::string( results[2].first,
      86          24 :                                                  results[2].second );
      87           8 :         if( schema.empty() )
      88           1 :             throw uri_parse( _uri );
      89             : 
      90           7 :         _uriData.scheme = schema;
      91           7 :         const std::string& userHost = std::string( results[4].first,
      92          21 :                                                    results[4].second );
      93           7 :         if( !userHost.empty() )
      94             :         {
      95           3 :             std::vector< std::string > splitUserHost;
      96           6 :             std::string hostPort;
      97             :             boost::algorithm::split( splitUserHost, userHost,
      98           3 :                                      boost::is_any_of( "@"));
      99           3 :             if( splitUserHost.size() == 2 ) // for ex: user:pass@hello.com:port
     100             :             {
     101           1 :                 _uriData.userinfo = splitUserHost[ 0 ];
     102           1 :                 hostPort = splitUserHost[ 1 ];
     103             :             }
     104             :             else
     105           2 :                 hostPort = splitUserHost[ 0 ];
     106             : 
     107           6 :             std::vector< std::string > splitHostPort;
     108             :             boost::algorithm::split( splitHostPort, hostPort,
     109           3 :                                      boost::is_any_of( ":" ));
     110           3 :             _uriData.host = splitHostPort[ 0 ];
     111             : 
     112           3 :             if( splitUserHost.size() == 2 ) // for ex: user:pass@hello.com:port
     113             :                 _uriData.port = boost::lexical_cast< uint16_t >(
     114           4 :                     splitHostPort[ 1 ] );
     115             :         }
     116             : 
     117           7 :         _uriData.path = std::string( results[5].first, results[5].second );
     118           7 :         _uriData.query = std::string( results[7].first, results[7].second );
     119           7 :         _uriData.fragment = std::string( results[9].first, results[9].second );
     120             : 
     121             :         // parse query data into key-value pairs
     122          14 :         std::string query = _uriData.query;
     123          16 :         while( !query.empty( ))
     124             :         {
     125           2 :             const size_t nextPair = query.find( ',' );
     126           2 :             if( nextPair == 0 )
     127             :             {
     128           0 :                 query = query.substr( 1 );
     129           0 :                 continue;
     130             :             }
     131             : 
     132           2 :             const std::string pair = query.substr( 0, nextPair );
     133           2 :             if( nextPair == std::string::npos )
     134           1 :                 query.clear();
     135             :             else
     136           1 :                 query = query.substr( nextPair + 1 );
     137             : 
     138           2 :             const size_t eq = pair.find( '=' );
     139           2 :             if( eq == std::string::npos || eq == 0 )
     140           0 :                 continue;
     141           2 :             _uriData.queryMap[ pair.substr( 0, eq ) ] = pair.substr( eq + 1 );
     142          10 :         }
     143             :     }
     144             : 
     145          44 :     const URIData& getData() const { return _uriData; }
     146             :     const std::string& getURI() const { return _uri; }
     147             : 
     148             : private:
     149             :      std::string _uri;
     150             :      URIData _uriData;
     151             : };
     152             : 
     153             : }
     154             : 
     155          10 : URI::URI( const std::string &uri )
     156          11 :    : _impl( new detail::URI( uri ) )
     157             : {
     158           9 : }
     159             : 
     160           0 : URI::URI( const URI& from )
     161           0 :     : _impl( new detail::URI( *from._impl ))
     162             : {
     163           0 : }
     164           9 : lunchbox::URI::~URI()
     165             : {
     166           9 :     delete _impl;
     167           9 : }
     168             : 
     169           0 : URI& URI::operator = ( const URI& rhs )
     170             : {
     171           0 :     if( this != &rhs )
     172           0 :         *_impl = *rhs._impl;
     173           0 :     return *this;
     174             : }
     175             : 
     176          13 : const std::string &URI::getScheme() const
     177             : {
     178          13 :     return _impl->getData().scheme;
     179             : }
     180             : 
     181           2 : const std::string &URI::getHost() const
     182             : {
     183           2 :     return _impl->getData().host;
     184             : }
     185             : 
     186           3 : uint16_t URI::getPort() const
     187             : {
     188           3 :     return _impl->getData().port;
     189             : }
     190             : 
     191           3 : const std::string &URI::getUserinfo() const
     192             : {
     193           3 :     return _impl->getData().userinfo;
     194             : }
     195             : 
     196          10 : const std::string& URI::getPath() const
     197             : {
     198          10 :     return _impl->getData().path;
     199             : }
     200             : 
     201           2 : const std::string& URI::getQuery() const
     202             : {
     203           2 :     return _impl->getData().query;
     204             : }
     205             : 
     206           3 : const std::string &URI::getFragment() const
     207             : {
     208           3 :     return _impl->getData().fragment;
     209             : }
     210             : 
     211           0 : URI::ConstKVIter URI::queryBegin() const
     212             : {
     213           0 :     return _impl->getData().queryMap.begin();
     214             : }
     215             : 
     216           3 : URI::ConstKVIter URI::queryEnd() const
     217             : {
     218           3 :     return _impl->getData().queryMap.end();
     219             : }
     220             : 
     221           5 : URI::ConstKVIter URI::findQuery( const std::string& key ) const
     222             : {
     223           5 :     return _impl->getData().queryMap.find( key );
     224             : }
     225             : 
     226          87 : }

Generated by: LCOV version 1.10