Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:29:29

0001 //
0002 // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
0003 //
0004 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0005 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0006 //
0007 // Official repository: https://github.com/boostorg/beast
0008 //
0009 
0010 #ifndef BOOST_BEAST_HTTP_IMPL_CHUNK_ENCODE_HPP
0011 #define BOOST_BEAST_HTTP_IMPL_CHUNK_ENCODE_HPP
0012 
0013 #include <boost/beast/core/buffer_traits.hpp>
0014 #include <boost/beast/core/detail/varint.hpp>
0015 #include <boost/beast/http/error.hpp>
0016 #include <boost/beast/http/detail/rfc7230.hpp>
0017 #include <algorithm>
0018 
0019 namespace boost {
0020 namespace beast {
0021 namespace http {
0022 
0023 inline
0024 chunk_header::
0025 chunk_header(std::size_t size)
0026     : view_(
0027         size,
0028         net::const_buffer{nullptr, 0},
0029         chunk_crlf{})
0030 {
0031     BOOST_ASSERT(size > 0);
0032 }
0033 
0034 inline
0035 chunk_header::
0036 chunk_header(
0037     std::size_t size,
0038     string_view extensions)
0039     : view_(
0040         size,
0041         net::const_buffer{
0042             extensions.data(), extensions.size()},
0043         chunk_crlf{})
0044 {
0045     BOOST_ASSERT(size > 0);
0046 }
0047 
0048 template<class ChunkExtensions, class>
0049 chunk_header::
0050 chunk_header(
0051     std::size_t size,
0052     ChunkExtensions&& extensions)
0053     : exts_(std::make_shared<detail::chunk_extensions_impl<
0054         typename std::decay<ChunkExtensions>::type>>(
0055             std::forward<ChunkExtensions>(extensions)))
0056     , view_(
0057         size,
0058         exts_->str(),
0059         chunk_crlf{})
0060 {
0061     static_assert(
0062         detail::is_chunk_extensions<ChunkExtensions>::value,
0063         "ChunkExtensions requirements not met");
0064     BOOST_ASSERT(size > 0);
0065 }
0066 
0067 template<class ChunkExtensions, class Allocator, class>
0068 chunk_header::
0069 chunk_header(
0070     std::size_t size,
0071     ChunkExtensions&& extensions,
0072     Allocator const& allocator)
0073     : exts_(std::allocate_shared<detail::chunk_extensions_impl<
0074         typename std::decay<ChunkExtensions>::type>>(allocator,
0075             std::forward<ChunkExtensions>(extensions)))
0076     , view_(
0077         size,
0078         exts_->str(),
0079         chunk_crlf{})
0080 {
0081     static_assert(
0082         detail::is_chunk_extensions<ChunkExtensions>::value,
0083         "ChunkExtensions requirements not met");
0084     BOOST_ASSERT(size > 0);
0085 }
0086 
0087 //------------------------------------------------------------------------------
0088 
0089 template<class ConstBufferSequence>
0090 chunk_body<ConstBufferSequence>::
0091 chunk_body(ConstBufferSequence const& buffers)
0092     : view_(
0093         buffer_bytes(buffers),
0094         net::const_buffer{nullptr, 0},
0095         chunk_crlf{},
0096         buffers,
0097         chunk_crlf{})
0098 {
0099 }
0100 
0101 template<class ConstBufferSequence>
0102 chunk_body<ConstBufferSequence>::
0103 chunk_body(
0104     ConstBufferSequence const& buffers,
0105     string_view extensions)
0106     : view_(
0107         buffer_bytes(buffers),
0108         net::const_buffer{
0109             extensions.data(), extensions.size()},
0110         chunk_crlf{},
0111         buffers,
0112         chunk_crlf{})
0113 {
0114 }
0115 
0116 template<class ConstBufferSequence>
0117 template<class ChunkExtensions, class>
0118 chunk_body<ConstBufferSequence>::
0119 chunk_body(
0120     ConstBufferSequence const& buffers,
0121     ChunkExtensions&& extensions)
0122     : exts_(std::make_shared<detail::chunk_extensions_impl<
0123         typename std::decay<ChunkExtensions>::type>>(
0124             std::forward<ChunkExtensions>(extensions)))
0125     , view_(
0126         buffer_bytes(buffers),
0127         exts_->str(),
0128         chunk_crlf{},
0129         buffers,
0130         chunk_crlf{})
0131 {
0132 }
0133 
0134 template<class ConstBufferSequence>
0135 template<class ChunkExtensions, class Allocator, class>
0136 chunk_body<ConstBufferSequence>::
0137 chunk_body(
0138     ConstBufferSequence const& buffers,
0139     ChunkExtensions&& extensions,
0140     Allocator const& allocator)
0141     : exts_(std::allocate_shared<detail::chunk_extensions_impl<
0142         typename std::decay<ChunkExtensions>::type>>(allocator,
0143             std::forward<ChunkExtensions>(extensions)))
0144     , view_(
0145         buffer_bytes(buffers),
0146         exts_->str(),
0147         chunk_crlf{},
0148         buffers,
0149         chunk_crlf{})
0150 {
0151 }
0152 
0153 //------------------------------------------------------------------------------
0154 
0155 template<class Trailer>
0156 template<class Allocator>
0157 auto
0158 chunk_last<Trailer>::
0159 prepare(Trailer const& trailer, Allocator const& allocator) ->
0160     buffers_type
0161 {
0162     auto sp = std::allocate_shared<typename
0163         Trailer::writer>(allocator, trailer);
0164     sp_ = sp;
0165     return sp->get();
0166 }
0167 
0168 template<class Trailer>
0169 auto
0170 chunk_last<Trailer>::
0171 prepare(Trailer const& trailer, std::true_type) ->
0172     buffers_type
0173 {
0174     auto sp = std::make_shared<
0175         typename Trailer::writer>(trailer);
0176     sp_ = sp;
0177     return sp->get();
0178 }
0179 
0180 template<class Trailer>
0181 auto
0182 chunk_last<Trailer>::
0183 prepare(Trailer const& trailer, std::false_type) ->
0184     buffers_type
0185 {
0186     return trailer;
0187 }
0188 
0189 template<class Trailer>
0190 chunk_last<Trailer>::
0191 chunk_last()
0192     : view_(
0193         detail::chunk_size0{},
0194         Trailer{})
0195 {
0196 }
0197 
0198 template<class Trailer>
0199 chunk_last<Trailer>::
0200 chunk_last(Trailer const& trailer)
0201     : view_(
0202         detail::chunk_size0{},
0203         prepare(trailer, is_fields<Trailer>{}))
0204 {
0205 }
0206 
0207 template<class Trailer>
0208 template<class DeducedTrailer, class Allocator, class>
0209 chunk_last<Trailer>::
0210 chunk_last(
0211     DeducedTrailer const& trailer, Allocator const& allocator)
0212     : view_(
0213         detail::chunk_size0{},
0214         prepare(trailer, allocator))
0215 {
0216 }
0217 
0218 //------------------------------------------------------------------------------
0219 
0220 template<class Allocator>
0221 class basic_chunk_extensions<Allocator>::const_iterator
0222 {
0223     friend class basic_chunk_extensions;
0224 
0225     using iter_type = char const*;
0226 
0227     iter_type it_;
0228     typename basic_chunk_extensions::value_type value_;
0229 
0230     explicit
0231     const_iterator(iter_type it)
0232         : it_(it)
0233     {
0234     }
0235 
0236     void
0237     increment();
0238 
0239 public:
0240     using value_type = typename
0241         basic_chunk_extensions::value_type;
0242     using pointer = value_type const*;
0243     using reference = value_type const&;
0244     using difference_type = std::ptrdiff_t;
0245     using iterator_category =
0246         std::forward_iterator_tag;
0247 
0248     const_iterator() = default;
0249     const_iterator(const_iterator&& other) = default;
0250     const_iterator(const_iterator const& other) = default;
0251     const_iterator& operator=(const_iterator&& other) = default;
0252     const_iterator& operator=(const_iterator const& other) = default;
0253 
0254     bool
0255     operator==(const_iterator const& other) const
0256     {
0257         return it_ == other.it_;
0258     }
0259 
0260     bool
0261     operator!=(const_iterator const& other) const
0262     {
0263         return !(*this == other);
0264     }
0265 
0266     reference
0267     operator*();
0268 
0269     pointer
0270     operator->()
0271     {
0272         return &(**this);
0273     }
0274 
0275     const_iterator&
0276     operator++()
0277     {
0278         increment();
0279         return *this;
0280     }
0281 
0282     const_iterator
0283     operator++(int)
0284     {
0285         auto temp = *this;
0286         increment();
0287         return temp;
0288     }
0289 };
0290 
0291 template<class Allocator>
0292 void
0293 basic_chunk_extensions<Allocator>::
0294 const_iterator::
0295 increment()
0296 {
0297     using beast::detail::varint_read;
0298     auto n = varint_read(it_);
0299     it_ += n;
0300     n = varint_read(it_);
0301     it_ += n;
0302 }
0303 
0304 template<class Allocator>
0305 auto
0306 basic_chunk_extensions<Allocator>::
0307 const_iterator::
0308 operator*() ->
0309     reference
0310 {
0311     using beast::detail::varint_read;
0312     auto it = it_;
0313     auto n = varint_read(it);
0314     value_.first = string_view{it, n};
0315     it += n;
0316     n = varint_read(it);
0317     value_.second = string_view{it, n};
0318     return value_;
0319 }
0320 
0321 //------------------------------------------------------------------------------
0322 
0323 template<class Allocator>
0324 template<class FwdIt>
0325 FwdIt
0326 basic_chunk_extensions<Allocator>::
0327 do_parse(FwdIt it, FwdIt last, error_code& ec)
0328 {
0329 /*
0330     chunk-ext       = *( BWS  ";" BWS chunk-ext-name [ BWS  "=" BWS chunk-ext-val ] )
0331     BWS             = *( SP / HTAB ) ; "Bad White Space"
0332     chunk-ext-name  = token
0333     chunk-ext-val   = token / quoted-string
0334     token           = 1*tchar
0335     quoted-string   = DQUOTE *( qdtext / quoted-pair ) DQUOTE
0336     qdtext          = HTAB / SP / "!" / %x23-5B ; '#'-'[' / %x5D-7E ; ']'-'~' / obs-text
0337     quoted-pair     = "\" ( HTAB / SP / VCHAR / obs-text )
0338     obs-text        = %x80-FF
0339 
0340     https://www.rfc-editor.org/errata_search.php?rfc=7230&eid=4667
0341 */
0342     using beast::detail::varint_size;
0343     using beast::detail::varint_write;
0344     using CharT = char;
0345     using Traits = std::char_traits<CharT>;
0346     range_.reserve(static_cast<std::size_t>(
0347         std::distance(it, last) * 1.2));
0348     range_.resize(0);
0349     auto const emit_string =
0350         [this](FwdIt from, FwdIt to)
0351         {
0352             auto const len =
0353                 std::distance(from, to);
0354             auto const offset = range_.size();
0355             range_.resize(
0356                 offset +
0357                 varint_size(len) +
0358                 len);
0359             auto dest = &range_[offset];
0360             varint_write(dest, len);
0361             Traits::copy(dest, from, len);
0362         };
0363     auto const emit_string_plus_empty =
0364         [this](FwdIt from, FwdIt to)
0365         {
0366             auto const len =
0367                 std::distance(from, to);
0368             auto const offset = range_.size();
0369             range_.resize(
0370                 offset +
0371                 varint_size(len) +
0372                 len +
0373                 varint_size(0));
0374             auto dest = &range_[offset];
0375             varint_write(dest, len);
0376             Traits::copy(dest, from, len);
0377             dest += len;
0378             varint_write(dest, 0);
0379         };
0380     auto const emit_empty_string =
0381         [this]
0382         {
0383             auto const offset = range_.size();
0384             range_.resize(offset + varint_size(0));
0385             auto dest = &range_[offset];
0386             varint_write(dest, 0);
0387         };
0388 loop:
0389     if(it == last)
0390     {
0391         ec = {};
0392         return it;
0393     }
0394     // BWS
0395     if(*it == ' ' || *it == '\t')
0396     {
0397         for(;;)
0398         {
0399             ++it;
0400             if(it == last)
0401             {
0402                 BOOST_BEAST_ASSIGN_EC(ec, error::bad_chunk_extension);
0403                 return it;
0404             }
0405             if(*it != ' ' && *it != '\t')
0406                 break;
0407         }
0408     }
0409     // ';'
0410     if(*it != ';')
0411     {
0412         BOOST_BEAST_ASSIGN_EC(ec, error::bad_chunk_extension);
0413         return it;
0414     }
0415 semi:
0416     ++it; // skip ';'
0417     // BWS
0418     for(;;)
0419     {
0420         if(it == last)
0421         {
0422             BOOST_BEAST_ASSIGN_EC(ec, error::bad_chunk_extension);
0423             return it;
0424         }
0425         if(*it != ' ' && *it != '\t')
0426             break;
0427         ++it;
0428     }
0429     // chunk-ext-name
0430     {
0431         if(! detail::is_token_char(*it))
0432         {
0433             BOOST_BEAST_ASSIGN_EC(ec, error::bad_chunk_extension);
0434             return it;
0435         }
0436         auto const first = it;
0437         for(;;)
0438         {
0439             ++it;
0440             if(it == last)
0441             {
0442                 emit_string_plus_empty(first, it);
0443                 return it;
0444             }
0445             if(! detail::is_token_char(*it))
0446                 break;
0447         }
0448         emit_string(first, it);
0449     }
0450     // BWS [ ";" / "=" ]
0451     for(;;)
0452     {
0453         if(*it != ' ' && *it != '\t')
0454             break;
0455         ++it;
0456         if(it == last)
0457         {
0458             BOOST_BEAST_ASSIGN_EC(ec, error::bad_chunk_extension);
0459             return it;
0460         }
0461     }
0462     if(*it == ';')
0463     {
0464         emit_empty_string();
0465         goto semi;
0466     }
0467     if(*it != '=')
0468     {
0469         BOOST_BEAST_ASSIGN_EC(ec, error::bad_chunk_extension);
0470         return it;
0471     }
0472     ++it; // skip '='
0473     // BWS
0474     for(;;)
0475     {
0476         if(it == last)
0477         {
0478             BOOST_BEAST_ASSIGN_EC(ec, error::bad_chunk_extension);
0479             return it;
0480         }
0481         if(*it != ' ' && *it != '\t')
0482             break;
0483         ++it;
0484     }
0485     // chunk-ext-val
0486     if(*it != '"')
0487     {
0488         // token
0489         if(! detail::is_token_char(*it))
0490         {
0491             BOOST_BEAST_ASSIGN_EC(ec, error::bad_chunk_extension);
0492             return it;
0493         }
0494         auto const first = it;
0495         for(;;)
0496         {
0497             ++it;
0498             if(it == last)
0499                 break;
0500             if(! detail::is_token_char(*it))
0501                 break;
0502         }
0503         emit_string(first, it);
0504         if(it == last)
0505             return it;
0506     }
0507     else
0508     {
0509         // quoted-string
0510         auto const first = ++it; // skip DQUOTE
0511         // first pass, count chars
0512         std::size_t len = 0;
0513         for(;;)
0514         {
0515             if(it == last)
0516             {
0517                 BOOST_BEAST_ASSIGN_EC(ec, error::bad_chunk_extension);
0518                 return it;
0519             }
0520             if(*it == '"')
0521                 break;
0522             if(*it == '\\')
0523             {
0524                 ++it;
0525                 if(it == last)
0526                 {
0527                     BOOST_BEAST_ASSIGN_EC(ec, error::bad_chunk_extension);
0528                     return it;
0529                 }
0530             }
0531             ++len;
0532             ++it;
0533         }
0534         // now build the string
0535         auto const offset = range_.size();
0536         range_.resize(
0537             offset +
0538             varint_size(len) +
0539             len);
0540         auto dest = &range_[offset];
0541         varint_write(dest, len);
0542         it = first;
0543         for(;;)
0544         {
0545             BOOST_ASSERT(it != last);
0546             if(*it == '"')
0547                 break;
0548             if(*it == '\\')
0549             {
0550                 ++it;
0551                 BOOST_ASSERT(it != last);
0552             }
0553             Traits::assign(*dest++, *it++);
0554         }
0555         ++it; // skip DQUOTE
0556     }
0557     goto loop;
0558 }
0559 
0560 template<class Allocator>
0561 void
0562 basic_chunk_extensions<Allocator>::
0563 do_insert(string_view name, string_view value)
0564 {
0565 /*
0566     chunk-ext       = *( ";" chunk-ext-name [ "=" chunk-ext-val ] )
0567     chunk-ext-name  = token
0568     chunk-ext-val   = token / quoted-string
0569     token           = 1*tchar
0570     quoted-string   = DQUOTE *( qdtext / quoted-pair ) DQUOTE
0571     qdtext          = HTAB / SP / "!" / %x23-5B ; '#'-'[' / %x5D-7E ; ']'-'~' / obs-text
0572     quoted-pair     = "\" ( HTAB / SP / VCHAR / obs-text )
0573     obs-text        = %x80-FF
0574 */
0575     if(value.empty())
0576     {
0577         s_.reserve(1 + name.size());
0578         s_.push_back(';');
0579         s_.append(name.data(), name.size());
0580         return;
0581     }
0582 
0583     bool is_token = true;
0584     for(auto const c : value)
0585     {
0586         if(! detail::is_token_char(c))
0587         {
0588             is_token = false;
0589             break;
0590         }
0591     }
0592     if(is_token)
0593     {
0594         // token
0595         s_.reserve(1 + name.size() + 1 + value.size());
0596         s_.push_back(';');
0597         s_.append(name.data(), name.size());
0598         s_.push_back('=');
0599         s_.append(value.data(), value.size());
0600     }
0601     else
0602     {
0603         // quoted-string
0604         s_.reserve(
0605             1 + name.size() + 1 +
0606             1 + value.size() + 20 + 1);
0607         s_.push_back(';');
0608         s_.append(name.data(), name.size());
0609         s_.append("=\"", 2);
0610         for(auto const c : value)
0611         {
0612             if(c == '\\')
0613                 s_.append(R"(\\)", 2);
0614             else if(c == '\"')
0615                 s_.append(R"(\")", 2);
0616             else
0617                 s_.push_back(c);
0618         }
0619         s_.push_back('"');
0620     }
0621 }
0622 
0623 template<class Allocator>
0624 void
0625 basic_chunk_extensions<Allocator>::
0626 parse(string_view s, error_code& ec)
0627 {
0628     do_parse(s.data(), s.data() + s.size(), ec);
0629     if(! ec)
0630     {
0631         s_.clear();
0632         for(auto const& v : *this)
0633             do_insert(v.first, v.second);
0634     }
0635 }
0636 
0637 template<class Allocator>
0638 void
0639 basic_chunk_extensions<Allocator>::
0640 insert(string_view name)
0641 {
0642     do_insert(name, {});
0643 
0644     using beast::detail::varint_size;
0645     using beast::detail::varint_write;
0646     auto const offset = range_.size();
0647     range_.resize(
0648         offset +
0649         varint_size(name.size()) +
0650         name.size() +
0651         varint_size(0));
0652     auto dest = &range_[offset];
0653     varint_write(dest, name.size());
0654     std::memcpy(dest, name.data(), name.size());
0655     dest += name.size();
0656     varint_write(dest, 0);
0657 }
0658 
0659 template<class Allocator>
0660 void
0661 basic_chunk_extensions<Allocator>::
0662 insert(string_view name, string_view value)
0663 {
0664     do_insert(name, value);
0665 
0666     using beast::detail::varint_size;
0667     using beast::detail::varint_write;
0668     auto const offset = range_.size();
0669     range_.resize(
0670         offset +
0671         varint_size(name.size()) +
0672         name.size() +
0673         varint_size(value.size()) +
0674         value.size());
0675     auto dest = &range_[offset];
0676     varint_write(dest, name.size());
0677     std::memcpy(dest, name.data(), name.size());
0678     dest += name.size();
0679     varint_write(dest, value.size());
0680     std::memcpy(dest, value.data(), value.size());
0681 }
0682 
0683 template<class Allocator>
0684 auto
0685 basic_chunk_extensions<Allocator>::
0686 begin() const ->
0687     const_iterator
0688 {
0689     return const_iterator{range_.data()};
0690 }
0691 
0692 template<class Allocator>
0693 auto
0694 basic_chunk_extensions<Allocator>::
0695 end() const ->
0696     const_iterator
0697 {
0698     return const_iterator{
0699         range_.data() + range_.size()};
0700 }
0701 
0702 } // http
0703 } // beast
0704 } // boost
0705 
0706 #endif