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