|
6 | 6 | // (See accompanying file LICENSE_1_0.txt or copy at
|
7 | 7 | // http://www.boost.org/LICENSE_1_0.txt)
|
8 | 8 |
|
| 9 | +#include <algorithm> |
| 10 | +#include <bitset> |
9 | 11 | #include <boost/network/traits/string.hpp>
|
10 | 12 | #include <boost/network/protocol/http/message/header/name.hpp>
|
11 | 13 | #include <boost/network/protocol/http/message/header/value.hpp>
|
|
15 | 17 | #include <boost/concept/requires.hpp>
|
16 | 18 | #include <boost/optional.hpp>
|
17 | 19 | #include <boost/range/algorithm/copy.hpp>
|
| 20 | +#include <boost/algorithm/string/compare.hpp> |
18 | 21 |
|
19 | 22 | namespace boost { namespace network { namespace http {
|
20 | 23 |
|
@@ -92,48 +95,86 @@ namespace boost { namespace network { namespace http {
|
92 | 95 | *oi = consts::dot_char();
|
93 | 96 | boost::copy(version_minor_str, oi);
|
94 | 97 | boost::copy(crlf, oi);
|
95 |
| - boost::copy(host, oi); |
96 |
| - *oi = consts::colon_char(); |
97 |
| - *oi = consts::space_char(); |
98 |
| - boost::copy(request.host(), oi); |
99 |
| - boost::optional<boost::uint16_t> port_ = port(request); |
100 |
| - if (port_) { |
101 |
| - string_type port_str = boost::lexical_cast<string_type>(*port_); |
102 |
| - *oi = consts::colon_char(); |
103 |
| - boost::copy(port_str, oi); |
104 |
| - } |
105 |
| - boost::copy(crlf, oi); |
106 |
| - boost::copy(accept, oi); |
107 |
| - *oi = consts::colon_char(); |
108 |
| - *oi = consts::space_char(); |
109 |
| - boost::copy(accept_mime, oi); |
110 |
| - boost::copy(crlf, oi); |
111 |
| - if (version_major == 1u && version_minor == 1u) { |
112 |
| - boost::copy(accept_encoding, oi); |
113 |
| - *oi = consts::colon_char(); |
114 |
| - *oi = consts::space_char(); |
115 |
| - boost::copy(default_accept_encoding, oi); |
116 |
| - boost::copy(crlf, oi); |
117 |
| - } |
| 98 | + |
| 99 | + // We need to determine whether we've seen any of the following headers |
| 100 | + // before setting the defaults. We use a bitset to keep track of the |
| 101 | + // defaulted headers. |
| 102 | + enum { ACCEPT, ACCEPT_ENCODING, HOST, MAX }; |
| 103 | + std::bitset<MAX> found_headers; |
| 104 | + static char const* defaulted_headers[][2] = { |
| 105 | + {consts::accept(), |
| 106 | + consts::accept() + std::strlen(consts::accept())}, |
| 107 | + {consts::accept_encoding(), |
| 108 | + consts::accept_encoding() + std::strlen(consts::accept_encoding())}, |
| 109 | + {consts::host(), consts::host() + std::strlen(consts::host())} |
| 110 | + }; |
| 111 | + |
118 | 112 | typedef typename headers_range<Request>::type headers_range;
|
119 | 113 | typedef typename range_value<headers_range>::type headers_value;
|
120 |
| - BOOST_FOREACH(const headers_value &header, headers(request)) |
121 |
| - { |
122 |
| - string_type header_name = name(header), |
123 |
| - header_value = value(header); |
124 |
| - boost::copy(header_name, oi); |
125 |
| - *oi = consts::colon_char(); |
126 |
| - *oi = consts::space_char(); |
127 |
| - boost::copy(header_value, oi); |
128 |
| - boost::copy(crlf, oi); |
| 114 | + BOOST_FOREACH(const headers_value & header, headers(request)) { |
| 115 | + string_type header_name = name(header), header_value = value(header); |
| 116 | + // Here we check that we have not seen an override to the defaulted |
| 117 | + // headers. |
| 118 | + for (int header_index = 0; header_index < MAX; ++header_index) |
| 119 | + if (std::distance(header_name.begin(), header_name.end()) == |
| 120 | + std::distance(defaulted_headers[header_index][0], |
| 121 | + defaulted_headers[header_index][1]) && |
| 122 | + std::equal(header_name.begin(), |
| 123 | + header_name.end(), |
| 124 | + defaulted_headers[header_index][0], |
| 125 | + algorithm::is_iequal())) |
| 126 | + found_headers.set(header_index, true); |
| 127 | + |
| 128 | + // We ignore empty headers. |
| 129 | + if (header_value.empty()) continue; |
| 130 | + boost::copy(header_name, oi); |
| 131 | + *oi = consts::colon_char(); |
| 132 | + *oi = consts::space_char(); |
| 133 | + boost::copy(header_value, oi); |
| 134 | + boost::copy(crlf, oi); |
| 135 | + |
| 136 | + } |
| 137 | + |
| 138 | + if (!found_headers[HOST]) { |
| 139 | + boost::copy(host, oi); |
| 140 | + *oi = consts::colon_char(); |
| 141 | + *oi = consts::space_char(); |
| 142 | + boost::copy(request.host(), oi); |
| 143 | + boost::optional<boost::uint16_t> port_ = port(request); |
| 144 | + if (port_) { |
| 145 | + string_type port_str = boost::lexical_cast<string_type>(*port_); |
| 146 | + *oi = consts::colon_char(); |
| 147 | + boost::copy(port_str, oi); |
| 148 | + } |
| 149 | + boost::copy(crlf, oi); |
| 150 | + } |
| 151 | + |
| 152 | + if (!found_headers[ACCEPT]) { |
| 153 | + boost::copy(accept, oi); |
| 154 | + *oi = consts::colon_char(); |
| 155 | + *oi = consts::space_char(); |
| 156 | + boost::copy(accept_mime, oi); |
| 157 | + boost::copy(crlf, oi); |
| 158 | + } |
| 159 | + |
| 160 | + if (version_major == 1u && |
| 161 | + version_minor == 1u && |
| 162 | + !found_headers[ACCEPT_ENCODING]) { |
| 163 | + boost::copy(accept_encoding, oi); |
| 164 | + *oi = consts::colon_char(); |
| 165 | + *oi = consts::space_char(); |
| 166 | + boost::copy(default_accept_encoding, oi); |
| 167 | + boost::copy(crlf, oi); |
129 | 168 | }
|
| 169 | + |
130 | 170 | if (!connection_keepalive<Tag>::value) {
|
131 |
| - boost::copy(connection, oi); |
132 |
| - *oi = consts::colon_char(); |
133 |
| - *oi = consts::space_char(); |
| 171 | + boost::copy(connection, oi); |
| 172 | + *oi = consts::colon_char(); |
| 173 | + *oi = consts::space_char(); |
134 | 174 | boost::copy(close, oi);
|
135 | 175 | boost::copy(crlf, oi);
|
136 | 176 | }
|
| 177 | + |
137 | 178 | boost::copy(crlf, oi);
|
138 | 179 | typename body_range<Request>::type body_data = body(request).range();
|
139 | 180 | return boost::copy(body_data, oi);
|
|
0 commit comments