Line data Source code
1 : // 2 : // Copyright (c) 2021 Vinnie Falco (vinnie.falco@gmail.com) 3 : // 4 : // Distributed under the Boost Software License, Version 1.0. (See accompanying 5 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 : // 7 : // Official repository: https://github.com/cppalliance/http_proto 8 : // 9 : 10 : #include <boost/http_proto/message_base.hpp> 11 : #include <boost/http_proto/rfc/list_rule.hpp> 12 : #include <boost/http_proto/rfc/token_rule.hpp> 13 : #include <boost/http_proto/detail/except.hpp> 14 : #include "detail/number_string.hpp" 15 : #include <boost/url/grammar/parse.hpp> 16 : #include <boost/url/grammar/ci_string.hpp> 17 : 18 : namespace boost { 19 : namespace http_proto { 20 : 21 : void 22 0 : message_base:: 23 : set_payload_size( 24 : std::uint64_t n) 25 : { 26 : //if(! is_head_response()) 27 : if(true) 28 : { 29 : // comes first for exception safety 30 0 : set_content_length(n); 31 : 32 0 : set_chunked(false); 33 : } 34 : else 35 : { 36 : // VFALCO ? 37 : } 38 0 : } 39 : 40 : void 41 0 : message_base:: 42 : set_content_length( 43 : std::uint64_t n) 44 : { 45 0 : set(field::content_length, 46 0 : detail::number_string(n)); 47 0 : } 48 : 49 : void 50 0 : message_base:: 51 : set_chunked(bool value) 52 : { 53 0 : if(value) 54 : { 55 : // set chunked 56 0 : if(! h_.md.transfer_encoding.is_chunked ) 57 : { 58 0 : append( 59 : field::transfer_encoding, 60 0 : "chunked"); 61 0 : return; 62 : } 63 : } 64 : else 65 : { 66 : // clear chunked 67 : // VFALCO ? 68 : } 69 : } 70 : 71 : void 72 12 : message_base:: 73 : set_keep_alive(bool value) 74 : { 75 12 : if(ph_->md.connection.ec.failed()) 76 : { 77 : // throw? return false? 78 5 : return; 79 : } 80 : 81 12 : if(ph_->md.connection.count == 0) 82 : { 83 : // no Connection field 84 5 : switch(ph_->version) 85 : { 86 3 : default: 87 : case version::http_1_1: 88 3 : if(! value) 89 2 : set(field::connection, "close"); 90 3 : break; 91 : 92 2 : case version::http_1_0: 93 2 : if(value) 94 1 : set(field::connection, "keep-alive"); 95 2 : break; 96 : } 97 5 : return; 98 : } 99 : 100 : // VFALCO TODO iterate in reverse order, 101 : // and cache the last iterator to use 102 : // for appending 103 : 104 : // one or more Connection fields 105 7 : auto it = begin(); 106 : auto const erase_token = 107 14 : [&](core::string_view token) 108 : { 109 14 : while(it != end()) 110 : { 111 8 : if(it->id != field::connection) 112 : { 113 0 : ++it; 114 4 : continue; 115 : } 116 : auto rv = grammar::parse( 117 8 : it->value, 118 16 : list_rule(token_rule, 1)); 119 8 : BOOST_ASSERT(! rv.has_error()); 120 8 : BOOST_ASSERT(! rv->empty()); 121 8 : auto itv = rv->begin(); 122 8 : if(urls::grammar::ci_is_equal( 123 8 : *itv, token)) 124 : { 125 4 : if(rv->size() == 1) 126 : { 127 : // only one token 128 3 : it = erase(it); 129 : } 130 : else 131 : { 132 : // first token matches 133 1 : ++itv; 134 1 : set(it, 135 1 : it->value.substr( 136 1 : (*itv).data() - 137 3 : it->value.data())); 138 1 : ++it; 139 : } 140 4 : continue; 141 : } 142 : // search remaining tokens 143 8 : std::string s = *itv++; 144 7 : while(itv != rv->end()) 145 : { 146 3 : if(! urls::grammar::ci_is_equal( 147 3 : *itv, token)) 148 1 : s += ", " + std::string(*itv); 149 3 : ++itv; 150 : } 151 4 : set(it, s); 152 4 : ++it; 153 : } 154 6 : }; 155 7 : if(value) 156 : { 157 6 : if(ph_->md.connection.close) 158 5 : erase_token("close"); 159 : } 160 : else 161 : { 162 1 : if(ph_->md.connection.keep_alive) 163 1 : erase_token("keep-alive"); 164 : } 165 7 : switch(ph_->version) 166 : { 167 5 : default: 168 : case version::http_1_1: 169 5 : if(! value) 170 : { 171 : // add one "close" token if needed 172 0 : if(! ph_->md.connection.close) 173 0 : append(field::connection, "close"); 174 : } 175 5 : break; 176 : 177 2 : case version::http_1_0: 178 2 : if(value) 179 : { 180 : // add one "keep-alive" token if needed 181 1 : if(! ph_->md.connection.keep_alive) 182 0 : append(field::connection, "keep-alive"); 183 : } 184 2 : break; 185 : } 186 : } 187 : 188 : //------------------------------------------------ 189 : 190 : char* 191 25 : message_base:: 192 : set_prefix_impl( 193 : std::size_t n) 194 : { 195 25 : if( n > h_.prefix || 196 4 : h_.buf == nullptr) 197 : { 198 : // allocate or grow 199 23 : if( n > h_.prefix && 200 : static_cast<std::size_t>( 201 21 : n - h_.prefix) > 202 21 : static_cast<std::size_t>( 203 21 : max_offset - h_.size)) 204 1 : detail::throw_length_error(); 205 : 206 22 : auto n0 = detail::header::bytes_needed( 207 22 : n + h_.size - h_.prefix, 208 22 : h_.count); 209 22 : auto buf = new char[n0]; 210 22 : if(h_.buf != nullptr) 211 : { 212 3 : std::memcpy( 213 3 : buf + n, 214 3 : h_.buf + h_.prefix, 215 3 : h_.size - h_.prefix); 216 : detail::header::table ft( 217 3 : h_.buf + h_.cap); 218 3 : h_.copy_table(buf + n0); 219 3 : delete[] h_.buf; 220 : } 221 : else 222 : { 223 19 : std::memcpy( 224 19 : buf + n, 225 19 : h_.cbuf + h_.prefix, 226 19 : h_.size - h_.prefix); 227 : } 228 22 : h_.buf = buf; 229 22 : h_.cbuf = buf; 230 22 : h_.size = static_cast< 231 22 : offset_type>(h_.size + 232 22 : n - h_.prefix); 233 22 : h_.prefix = static_cast< 234 : offset_type>(n); 235 22 : h_.cap = n0; 236 22 : return h_.buf; 237 : } 238 : 239 : // shrink 240 2 : std::memmove( 241 2 : h_.buf + n, 242 2 : h_.buf + h_.prefix, 243 2 : h_.size - h_.prefix); 244 2 : h_.size = static_cast< 245 2 : offset_type>(h_.size - 246 2 : h_.prefix + n); 247 2 : h_.prefix = static_cast< 248 : offset_type>(n); 249 2 : return h_.buf; 250 : } 251 : 252 : } // http_proto 253 : } // boost