|
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 | namespaceboost {namespacenetwork {namespacehttp {
|
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 | +staticcharconst* 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 | typedeftypename headers_range<Request>::type headers_range;
|
119 | 113 | typedeftypename 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 | returnboost::copy(body_data, oi);
|
|