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