LCOV - code coverage report
Current view: top level - core/data - SPDataUrlencoded.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 121 144 84.0 %
Date: 2024-05-12 00:16:13 Functions: 14 14 100.0 %

          Line data    Source code
       1             : /**
       2             : Copyright (c) 2016-2019 Roman Katuntsev <sbkarr@stappler.org>
       3             : Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
       4             : 
       5             : Permission is hereby granted, free of charge, to any person obtaining a copy
       6             : of this software and associated documentation files (the "Software"), to deal
       7             : in the Software without restriction, including without limitation the rights
       8             : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       9             : copies of the Software, and to permit persons to whom the Software is
      10             : furnished to do so, subject to the following conditions:
      11             : 
      12             : The above copyright notice and this permission notice shall be included in
      13             : all copies or substantial portions of the Software.
      14             : 
      15             : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      16             : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      17             : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      18             : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      19             : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      20             : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      21             : THE SOFTWARE.
      22             : **/
      23             : 
      24             : #include "SPString.h"
      25             : #include "SPValid.h"
      26             : #include "SPData.h"
      27             : 
      28             : namespace STAPPLER_VERSIONIZED stappler::data {
      29             : 
      30             : using NextToken = chars::Chars<char, '=', '&', ';', '[', ']', '+', '%'>;
      31             : using NextKey = chars::Chars<char, '&', ';', '+'>;
      32             : 
      33             : template <typename Interface>
      34             : class UrlencodeParser {
      35             : public:
      36             :         using Reader = StringView;
      37             : 
      38             :         enum class Literal {
      39             :                 None,
      40             :                 String,
      41             :                 Percent,
      42             :                 Open,
      43             :                 Close,
      44             :                 Delim,
      45             :         };
      46             : 
      47             :         enum class VarState {
      48             :                 Key,
      49             :                 SubKey,
      50             :                 SubKeyEnd,
      51             :                 Value,
      52             :                 End,
      53             :         };
      54             : 
      55        3325 :         UrlencodeParser(ValueTemplate<Interface> &target, size_t length = maxOf<size_t>(), size_t maxVarSize = maxOf<size_t>())
      56        3325 :         : target(&target), length(length), maxVarSize(maxVarSize) { }
      57             : 
      58             :         size_t read(const uint8_t * s, size_t count);
      59             : 
      60             :         ValueTemplate<Interface> *flushString(StringView &r, ValueTemplate<Interface> *, VarState state);
      61             : 
      62             :         ValueTemplate<Interface> & data() { return *target; }
      63             :         const ValueTemplate<Interface> & data() const { return *target; }
      64             : 
      65             : protected:
      66             :         void bufferize(Reader &r);
      67             :         void bufferize(char c);
      68             :         void flush(Reader &r);
      69             : 
      70             :         ValueTemplate<Interface> *target;
      71             :         size_t length = maxOf<size_t>();
      72             :         size_t maxVarSize = maxOf<size_t>();
      73             : 
      74             :         bool skip = false;
      75             :         VarState state = VarState::Key;
      76             :         Literal literal = Literal::None;
      77             : 
      78             :         BufferTemplate<Interface> buf;
      79             :         ValueTemplate<Interface> *current = nullptr;
      80             : };
      81             : 
      82             : template <typename Interface>
      83         400 : void UrlencodeParser<Interface>::bufferize(Reader &r) {
      84         400 :         if (!skip) {
      85         400 :                 if (buf.size() + r.size() > maxVarSize) {
      86           0 :                         buf.clear();
      87           0 :                         skip = true;
      88             :                 } else {
      89         400 :                         buf.put(r.data(), r.size());
      90             :                 }
      91             :         }
      92         400 : }
      93             : 
      94             : template <typename Interface>
      95         200 : void UrlencodeParser<Interface>::bufferize(char c) {
      96         200 :         if (!skip) {
      97         200 :                 if (buf.size() + 1 > maxVarSize) {
      98           0 :                         buf.clear();
      99           0 :                         skip = true;
     100             :                 } else {
     101         200 :                         buf.putc(c);
     102         200 :                         return;
     103             :                 }
     104             :         }
     105           0 :         buf.putc(c);
     106             : }
     107             : 
     108             : template <typename Interface>
     109        6125 : void UrlencodeParser<Interface>::flush(Reader &r) {
     110        6125 :         if (!skip) {
     111        6125 :                 if (r.size() < maxVarSize) {
     112        6125 :                         current = flushString(r, current, state);
     113             :                 } else {
     114           0 :                         skip = true;
     115             :                 }
     116        6125 :                 buf.clear();
     117             :         }
     118        6125 : }
     119             : 
     120             : template <typename Interface>
     121        3325 : size_t UrlencodeParser<Interface>::read(const uint8_t * s, size_t count) {
     122        3325 :         if (count >= length) {
     123        3325 :                 count = length;
     124        3325 :                 length = 0;
     125             :         }
     126        3325 :         Reader r((const char *)s, count);
     127             : 
     128        9650 :         while (!r.empty()) {
     129        6325 :                 Reader str;
     130        6325 :                 if (state == VarState::Value) {
     131        1275 :                         str = r.readUntil<NextKey>();
     132             :                 } else {
     133        5050 :                         str = r.readUntil<NextToken>();
     134             :                 }
     135             : 
     136        6325 :                 if (buf.empty() && (!r.empty() || length == 0) && !r.is('+') && !r.is('%')) {
     137        5925 :                         flush(str);
     138             :                 } else {
     139         400 :                         bufferize(str);
     140         400 :                         if (!r.empty() && !r.is('+') && !r.is('%')) {
     141         200 :                                 Reader tmp = buf.get();
     142         200 :                                 flush(tmp);
     143             :                         }
     144             :                 }
     145             : 
     146        6325 :                 char c = r[0];
     147        6325 :                 if (c == '+') {
     148           0 :                         bufferize(' ');
     149           0 :                         ++ r;
     150             :                 } else {
     151        6325 :                         ++ r;
     152        6325 :                         if (c == '%') {
     153         200 :                                 if (r.is("5B")) {
     154           0 :                                         c = '[';
     155           0 :                                         r += 2;
     156         200 :                                 } else if (r.is("5D")) {
     157           0 :                                         c = ']';
     158           0 :                                         r += 2;
     159             :                                 } else {
     160         200 :                                         bufferize('%');
     161         200 :                                         c = 0;
     162             :                                 }
     163             :                         }
     164             : 
     165        6325 :                         if (c != 0) {
     166        5475 :                                 switch (state) {
     167        3950 :                                 case VarState::Key:
     168        3950 :                                         switch (c) {
     169         350 :                                         case '[':                       state = VarState::SubKey; break;
     170        3600 :                                         case '=':                       state = VarState::Value; break;
     171           0 :                                         case '&': case ';': state = VarState::Key; break;
     172           0 :                                         default:                        state = VarState::End; break;
     173             :                                         }
     174        3950 :                                         break;
     175         450 :                                 case VarState::SubKey:
     176         450 :                                         switch (c) {
     177         450 :                                         case ']':                       state = VarState::SubKeyEnd; break;
     178           0 :                                         default:                        state = VarState::End; break;
     179             :                                         }
     180         450 :                                         break;
     181         450 :                                 case VarState::SubKeyEnd:
     182         450 :                                         switch (c) {
     183         100 :                                         case '[':                       state = VarState::SubKey; break;
     184         350 :                                         case '=':                       state = VarState::Value; break;
     185           0 :                                         case '&': case ';': state = VarState::Key; break;
     186           0 :                                         default:                        state = VarState::End; break;
     187             :                                         }
     188         450 :                                         break;
     189         625 :                                 case VarState::Value:
     190         625 :                                         switch (c) {
     191         625 :                                         case '&': case ';': state = VarState::Key; skip = false; break;
     192           0 :                                         default:                        state = VarState::End; break;
     193             :                                         }
     194         625 :                                         break;
     195           0 :                                 default:
     196           0 :                                         break;
     197             :                                 }
     198             :                         }
     199             :                 }
     200        6325 :                 if (skip) {
     201           0 :                         break;
     202             :                 }
     203             :         }
     204             : 
     205        3325 :         if (!buf.empty()) {
     206           0 :                 auto tmp = buf.get();
     207           0 :                 flush(tmp);
     208             :         }
     209             : 
     210        3325 :         return count;
     211             : }
     212             : 
     213             : template <typename Interface>
     214        6125 : auto UrlencodeParser<Interface>::flushString(StringView &r, ValueTemplate<Interface> *cur, VarState varState)
     215             :                 -> ValueTemplate<Interface> * {
     216        6125 :         auto str = string::urldecode<Interface>(r);
     217             : 
     218        6125 :         switch (varState) {
     219        3950 :         case VarState::Key:
     220        3950 :                 if (!str.empty()) {
     221        3950 :                         if (target->hasValue(str)) {
     222         200 :                                 cur = &target->getValue(str);
     223             :                         } else {
     224        3750 :                                 cur = &target->setValue(ValueTemplate<Interface>(true), str);
     225             :                         }
     226             :                 }
     227        3950 :                 break;
     228         450 :         case VarState::SubKey:
     229         450 :                 if (cur) {
     230         450 :                         if (!str.empty() && valid::validateNumber(str)) {
     231         150 :                                 auto num = StringView(str).readInteger().get();
     232         150 :                                 if (cur->isArray()) {
     233         100 :                                         if (num < int64_t(cur->size())) {
     234          50 :                                                 cur = &cur->getValue(num);
     235         150 :                                                 return cur;
     236          50 :                                         } else if (num == int64_t(cur->size())) {
     237          50 :                                                 cur = &cur->addValue(ValueTemplate<Interface>(true));
     238          50 :                                                 return cur;
     239             :                                         }
     240          50 :                                 } else if (!cur->isDictionary() && num == 0) {
     241          50 :                                         cur->setArray(typename ValueTemplate<Interface>::ArrayType());
     242          50 :                                         cur = &cur->addValue(ValueTemplate<Interface>(true));
     243          50 :                                         return cur;
     244             :                                 }
     245             :                         }
     246         300 :                         if (str.empty()) {
     247         200 :                                 if (!cur->isArray()) {
     248         100 :                                         cur->setArray(typename ValueTemplate<Interface>::ArrayType());
     249             :                                 }
     250         200 :                                 cur = &cur->addValue(ValueTemplate<Interface>(true));
     251             :                         } else {
     252         100 :                                 if (!cur->isDictionary()) {
     253          50 :                                         cur->setDict(typename ValueTemplate<Interface>::DictionaryType());
     254             :                                 }
     255         100 :                                 if (cur->hasValue(str)) {
     256          50 :                                         cur = &cur->getValue(str);
     257             :                                 } else {
     258          50 :                                         cur = &cur->setValue(ValueTemplate<Interface>(true), str);
     259             :                                 }
     260             :                         }
     261             :                 }
     262         300 :                 break;
     263        1275 :         case VarState::Value:
     264             :         case VarState::End:
     265        1275 :                 if (cur) {
     266        1275 :                         if (!str.empty()) {
     267        1275 :                                 cur->setString(str);
     268             :                         }
     269        1275 :                         cur = nullptr;
     270             :                 }
     271        1275 :                 break;
     272         450 :         default:
     273         450 :                 break;
     274             :         }
     275             : 
     276        5975 :         return cur;
     277        6125 : }
     278             : 
     279             : template <>
     280        3300 : auto readUrlencoded<memory::PoolInterface>(StringView r, size_t maxVarSize) -> ValueTemplate<memory::PoolInterface> {
     281        3300 :         ValueTemplate<memory::PoolInterface> ret;
     282        3300 :         UrlencodeParser<memory::PoolInterface> parser(ret, r.size(), maxVarSize);
     283        3300 :         parser.read((const uint8_t *)r.data(), r.size());
     284        6600 :         return ret;
     285        3300 : }
     286             : 
     287             : template <>
     288          25 : auto readUrlencoded<memory::StandartInterface>(StringView r, size_t maxVarSize) -> ValueTemplate<memory::StandartInterface> {
     289          25 :         ValueTemplate<memory::StandartInterface> ret;
     290          25 :         UrlencodeParser<memory::StandartInterface> parser(ret, r.size(), maxVarSize);
     291          25 :         parser.read((const uint8_t *)r.data(), r.size());
     292          50 :         return ret;
     293          25 : }
     294             : 
     295             : 
     296             : }

Generated by: LCOV version 1.14