LCOV - code coverage report
Current view: top level - edhttp - string_part.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 74 74 100.0 %
Date: 2022-07-09 10:44:38 Functions: 11 11 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Copyright (c) 2011-2022  Made to Order Software Corp.  All Rights Reserved
       2             : //
       3             : // https://snapwebsites.org/project/edhttp
       4             : // contact@m2osw.com
       5             : //
       6             : // This program is free software: you can redistribute it and/or modify
       7             : // it under the terms of the GNU General Public License as published by
       8             : // the Free Software Foundation, either version 3 of the License, or
       9             : // (at your option) any later version.
      10             : //
      11             : // This program is distributed in the hope that it will be useful,
      12             : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             : // GNU General Public License for more details.
      15             : //
      16             : // You should have received a copy of the GNU General Public License
      17             : // along with this program.  If not, see <https://www.gnu.org/licenses/>.
      18             : 
      19             : 
      20             : // self
      21             : //
      22             : #include    "edhttp/string_part.h"
      23             : 
      24             : #include    "edhttp/exception.h"
      25             : 
      26             : 
      27             : // advgetopt
      28             : //
      29             : #include    <advgetopt/validator_double.h>
      30             : 
      31             : 
      32             : // snaplogger
      33             : //
      34             : #include    <snaplogger/message.h>
      35             : 
      36             : 
      37             : // snapdev
      38             : //
      39             : #include    <snapdev/trim_string.h>
      40             : 
      41             : 
      42             : // last include
      43             : //
      44             : #include    <snapdev/poison.h>
      45             : 
      46             : 
      47             : 
      48             : namespace edhttp
      49             : {
      50             : 
      51             : 
      52             : 
      53             : /** \brief Create a named string_part.
      54             :  *
      55             :  * This function is used to create a valid string_part object.
      56             :  *
      57             :  * \param[in] name  The name of the string_part object.
      58             :  *
      59             :  * \sa get_name()
      60             :  */
      61          87 : string_part::string_part(std::string const & name)
      62         174 :     : f_name(name)
      63             : {
      64          87 : }
      65             : 
      66             : 
      67             : /** \brief Retrieve the string_part name.
      68             :  *
      69             :  * The name of a string_part object cannot be changed once it was created.
      70             :  *
      71             :  * You may retrieve the name with this function, though.
      72             :  *
      73             :  * \bug
      74             :  * It is currently possible to create a string_part object without a name
      75             :  * so the class works with QVector.
      76             :  *
      77             :  * \return The name as passed in when create the string_part object.
      78             :  */
      79         178 : std::string const & string_part::get_name() const
      80             : {
      81         178 :     return f_name;
      82             : }
      83             : 
      84             : 
      85             : /** \brief Retrieve the value of this part.
      86             :  *
      87             :  * By default, a part is not expected to include a value, but there
      88             :  * are many strings in HTTP headers that accept a syntax where parameters
      89             :  * can be given a value. For example, in the Cache-Control field, we
      90             :  * can have a "max-age=123" parameter. This function returns the "123".
      91             :  * The name ("max-age") is returned by the get_name() function.
      92             :  *
      93             :  * In a weighted HTTP string such as a string of language definitions,
      94             :  * the named value has no value. It is expected to represent a flag
      95             :  * which is set (i.e. do not interpret a part with an empty string
      96             :  * as "false").
      97             :  *
      98             :  * \return The value of this part of the string.
      99             :  */
     100           6 : std::string const & string_part::get_value() const
     101             : {
     102           6 :     return f_value;
     103             : }
     104             : 
     105             : 
     106             : /** \brief This function is used to setup the value of a part.
     107             :  *
     108             :  * This function defines the value of a part. By default a part is just
     109             :  * defined and its value is the empty string (it is still viewed as being
     110             :  * "true", but without anything more than that.)
     111             :  *
     112             :  * The function is called by the parser when it finds a part name followed
     113             :  * by an equal sign.
     114             :  *
     115             :  * \param[in] value  The new value of this part.
     116             :  */
     117           8 : void string_part::set_value(std::string const & value)
     118             : {
     119           8 :     f_value = value;
     120           8 : }
     121             : 
     122             : 
     123             : /** \brief Retrieve the level of this string_part object.
     124             :  *
     125             :  * This function retrieves the level of the string_part object. It is a floating
     126             :  * point value.
     127             :  *
     128             :  * The level is taken from the "q" parameter. For example, in:
     129             :  *
     130             :  * \code
     131             :  *      fr; q=0.3
     132             :  * \endcode
     133             :  *
     134             :  * the level is viewed as 0.3.
     135             :  *
     136             :  * \return The string_part object level.
     137             :  */
     138          86 : string_part::level_t string_part::get_level() const
     139             : {
     140          86 :     return f_level;
     141             : }
     142             : 
     143             : 
     144             : /** \brief Change the level of this part.
     145             :  *
     146             :  * This function saves the new \p level parameter in this string_part object.
     147             :  * Items without a level (q=<value>) parameter are assigned the special
     148             :  * value DEFAULT_LEVEL, which is 1.0.
     149             :  *
     150             :  * \bug
     151             :  * The function does not limit the level. It is expected to be defined
     152             :  * between 0.0 and 1.0, though.
     153             :  *
     154             :  * \param[in] level  The new string_part level.
     155             :  */
     156          40 : void string_part::set_level(string_part::level_t const level)
     157             : {
     158          40 :     f_level = level;
     159          40 : }
     160             : 
     161             : 
     162             : /** \brief Retrieve the value of a parameter.
     163             :  *
     164             :  * This function returns the value of a parameter given its name.
     165             :  *
     166             :  * If the parameter is not exist defined, then the function returns
     167             :  * an empty string. A parameter may exist and be set to the empty
     168             :  * string. There is no way to know at this point.
     169             :  *
     170             :  * \param[in] name  The name of the parameter to retrieve.
     171             :  *
     172             :  * \return The value of the parameter or "" if undefined.
     173             :  */
     174          65 : std::string string_part::get_parameter(std::string const & name) const
     175             : {
     176          65 :     auto const it(f_param.find(name));
     177          65 :     if(it == f_param.end())
     178             :     {
     179          54 :         return std::string();
     180             :     }
     181          11 :     return it->second;
     182             : }
     183             : 
     184             : 
     185             : /** \brief Add a parameter.
     186             :  *
     187             :  * This function is used to add a parameter to the string_part object.
     188             :  *
     189             :  * A parameter has a name and a value.
     190             :  *
     191             :  * \param[in] name  The name of the parameter to add.
     192             :  * \param[in] value  The value of the parameter.
     193             :  */
     194          54 : void string_part::add_parameter(std::string const & name, std::string const & value)
     195             : {
     196          54 :     f_param[name] = value;
     197          54 : }
     198             : 
     199             : 
     200             : /** \brief Convert one part back into a weighted HTTP string.
     201             :  *
     202             :  * This function builds one part of a weighted HTTP string. The string
     203             :  * will look something like:
     204             :  *
     205             :  * \code
     206             :  *      es; q=0.8
     207             :  * \endcode
     208             :  *
     209             :  * \return The part converted to one string.
     210             :  */
     211          91 : std::string string_part::to_string() const
     212             : {
     213          91 :     std::string result(f_name);
     214          91 :     if(!f_value.empty())
     215             :     {
     216           8 :         result += '=';
     217             : 
     218           8 :         char q(value_require_quotes(f_value));
     219           6 :         if(q == '?')
     220             :         {
     221           2 :             q = '"';
     222             :         }
     223           6 :         if(q == '\0')
     224             :         {
     225           4 :             result += f_value;
     226             :         }
     227             :         else
     228             :         {
     229           2 :             result += q;
     230           2 :             result += f_value;
     231           2 :             result += q;
     232             :         }
     233             :     }
     234             : 
     235         143 :     for(auto const & it : f_param)
     236             :     {
     237         108 :         std::string p(it.first);
     238          54 :         if(!it.second.empty())
     239             :         {
     240          54 :             p += '=';
     241             : 
     242          54 :             char q(value_require_quotes(it.second));
     243          54 :             if(q == '?')
     244             :             {
     245           2 :                 q = '"';
     246             :             }
     247          54 :             if(q == '\0')
     248             :             {
     249          50 :                 p += it.second;
     250             :             }
     251             :             else
     252             :             {
     253           4 :                 p += q;
     254           4 :                 p += it.second;
     255           4 :                 p += q;
     256             :             }
     257             :         }
     258          54 :         result += "; ";
     259          54 :         result += p;
     260             :     }
     261             : 
     262          89 :     return result;
     263             : }
     264             : 
     265             : 
     266             : /** \brief Operator used to sort elements.
     267             :  *
     268             :  * This operator overload is used by the different sort algorithms
     269             :  * that we can apply against this type. In most cases, it is a
     270             :  * std::stable_sort(),
     271             :  *
     272             :  * The function compares the level of the two string_part objects involved.
     273             :  *
     274             :  * Note that we sort from the largest to the smallest level. In other
     275             :  * words, if this string_part has level 1.0 and \p rhs has level 0.5, the
     276             :  * function returns true (i.e. 1.0 > 0.5).
     277             :  *
     278             :  * \param[in] rhs  The right hand side string_part object to compare against.
     279             :  *
     280             :  * \return true if this string_part is considered smaller than \p rhs.
     281             :  */
     282          23 : bool string_part::operator < (string_part const & rhs) const
     283             : {
     284          23 :     return f_level > rhs.f_level;
     285             : }
     286             : 
     287             : 
     288             : /** \brief Determine whether a string needs quoting.
     289             :  *
     290             :  * This function checks the characters in a string a decides whether it needs
     291             :  * quoting. Note that it works on the safe side and will request quotes in
     292             :  * more cases than required.
     293             :  *
     294             :  * The function returns one of:
     295             :  *
     296             :  * * `'\0'` -- no quoting is required
     297             :  * * `'?'` -- a character requires quoting, the type of quote is left to you.
     298             :  * * `'"'` -- the string includes `'\\''` so we need to use `'"'` to quote
     299             :  * * `'\\''` -- the string includes `'"'` so we need to use `'\\''` to quote
     300             :  *
     301             :  * \param[in] value  The string to be checked. In general a part value.
     302             :  *
     303             :  * \return The quote to use or '?' or '\0'.
     304             :  */
     305          62 : char string_part::value_require_quotes(std::string const & value)
     306             : {
     307          62 :     char quote('\0');
     308         311 :     for(auto const v : value)
     309             :     {
     310         251 :         if((v < 'a' || v > 'z')
     311         154 :         && (v < 'A' || v > 'Z')
     312         152 :         && (v < '0' || v > '9')
     313          58 :         && v != '.'
     314          23 :         && v != '-'
     315          23 :         && v != '+'
     316          23 :         && v != '*'
     317          23 :         && v != '_')
     318             :         {
     319          23 :             if(v == '"')
     320             :             {
     321           4 :                 if(quote != '\0' && quote != '\'' && quote != '?')
     322             :                 {
     323           1 :                     throw unquotable_string("string [" + value + "] includes single and double quotes.");
     324             :                 }
     325           3 :                 quote = '\'';
     326             :             }
     327          19 :             else if(v == '\'')
     328             :             {
     329           3 :                 if(quote != '\0' && quote != '"' && quote != '?')
     330             :                 {
     331           1 :                     throw unquotable_string("string [" + value + "] includes single and double quotes.");
     332             :                 }
     333           2 :                 quote = '"';
     334             :             }
     335          16 :             else if(quote == '\0')
     336             :             {
     337           5 :                 quote = '?';
     338             :             }
     339             :         }
     340             :     }
     341             : 
     342          60 :     return quote;
     343             : }
     344             : 
     345             : 
     346             : 
     347             : } // namespace edhttp
     348             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.13