95.78% Lines (159/166) 100.00% Functions (10/10)
TLA Baseline Branch
Line Hits Code Line Hits Code
1   // 1   //
2   // Copyright (c) 2021 Vinnie Falco (vinnie.falco@gmail.com) 2   // Copyright (c) 2021 Vinnie Falco (vinnie.falco@gmail.com)
3   // 3   //
4   // Distributed under the Boost Software License, Version 1.0. (See accompanying 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) 5   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6   // 6   //
7   // Official repository: https://github.com/cppalliance/http 7   // Official repository: https://github.com/cppalliance/http
8   // 8   //
9   9  
10   #include "src/rfc/detail/rules.hpp" 10   #include "src/rfc/detail/rules.hpp"
11   11  
12   #include <boost/http/error.hpp> 12   #include <boost/http/error.hpp>
13   #include <boost/http/detail/config.hpp> 13   #include <boost/http/detail/config.hpp>
14   #include <boost/http/rfc/token_rule.hpp> 14   #include <boost/http/rfc/token_rule.hpp>
15   15  
16   #include <boost/core/detail/string_view.hpp> 16   #include <boost/core/detail/string_view.hpp>
17   #include <boost/url/grammar/delim_rule.hpp> 17   #include <boost/url/grammar/delim_rule.hpp>
18   #include <boost/url/grammar/digit_chars.hpp> 18   #include <boost/url/grammar/digit_chars.hpp>
19   #include <boost/url/grammar/error.hpp> 19   #include <boost/url/grammar/error.hpp>
20   #include <boost/url/grammar/hexdig_chars.hpp> 20   #include <boost/url/grammar/hexdig_chars.hpp>
21   #include <boost/url/grammar/lut_chars.hpp> 21   #include <boost/url/grammar/lut_chars.hpp>
22   #include <boost/url/grammar/parse.hpp> 22   #include <boost/url/grammar/parse.hpp>
23   #include <boost/url/grammar/tuple_rule.hpp> 23   #include <boost/url/grammar/tuple_rule.hpp>
24   24  
25   #include "src/rfc/detail/rules.hpp" 25   #include "src/rfc/detail/rules.hpp"
26   26  
27   namespace boost { 27   namespace boost {
28   namespace http { 28   namespace http {
29   namespace detail { 29   namespace detail {
30   30  
31   auto 31   auto
HITCBC 32   28303 crlf_rule_t:: 32   28320 crlf_rule_t::
33   parse( 33   parse(
34   char const*& it, 34   char const*& it,
35   char const* end) const noexcept -> 35   char const* end) const noexcept ->
36   system::result<value_type> 36   system::result<value_type>
37   { 37   {
HITCBC 38   28303 if(it == end) 38   28320 if(it == end)
HITCBC 39   6145 return grammar::error::need_more; 39   6145 return grammar::error::need_more;
HITCBC 40   22158 if(*it != '\r') 40   22175 if(*it != '\r')
HITCBC 41   29 return grammar::error::mismatch; 41   29 return grammar::error::mismatch;
HITCBC 42   22129 ++it; 42   22146 ++it;
HITCBC 43   22129 if(it == end) 43   22146 if(it == end)
HITCBC 44   887 return grammar::error::need_more; 44   887 return grammar::error::need_more;
HITCBC 45   21242 if(*it != '\n') 45   21259 if(*it != '\n')
HITCBC 46   51 return grammar::error::mismatch; 46   51 return grammar::error::mismatch;
HITCBC 47   21191 ++it; 47   21208 ++it;
HITCBC 48   21191 return {}; 48   21208 return {};
49   } 49   }
50   50  
51   //------------------------------------------------ 51   //------------------------------------------------
52   52  
53   auto 53   auto
HITCBC 54   26891 version_rule_t:: 54   26900 version_rule_t::
55   parse( 55   parse(
56   char const*& it, 56   char const*& it,
57   char const* end) const noexcept -> 57   char const* end) const noexcept ->
58   system::result<value_type> 58   system::result<value_type>
59   { 59   {
HITCBC 60   26891 value_type v = 0; 60   26900 value_type v = 0;
HITCBC 61   26891 if(it == end) 61   26900 if(it == end)
62   { 62   {
63   // expected "HTTP/" 63   // expected "HTTP/"
HITCBC 64   1511 BOOST_HTTP_RETURN_EC( 64   1511 BOOST_HTTP_RETURN_EC(
65   grammar::error::need_more); 65   grammar::error::need_more);
66   } 66   }
HITCBC 67   25380 if(end - it >= 5) 67   25389 if(end - it >= 5)
68   { 68   {
HITCBC 69   21074 if(std::memcmp( 69   21083 if(std::memcmp(
70   it, "HTTP/", 5) != 0) 70   it, "HTTP/", 5) != 0)
71   { 71   {
MISUBC 72   BOOST_HTTP_RETURN_EC( 72   BOOST_HTTP_RETURN_EC(
73   grammar::error::mismatch); 73   grammar::error::mismatch);
74   } 74   }
HITCBC 75   21074 it += 5; 75   21083 it += 5;
76   } 76   }
HITCBC 77   25380 if(it == end) 77   25389 if(it == end)
78   { 78   {
79   // expected DIGIT 79   // expected DIGIT
HITCBC 80   991 BOOST_HTTP_RETURN_EC( 80   991 BOOST_HTTP_RETURN_EC(
81   grammar::error::need_more); 81   grammar::error::need_more);
82   } 82   }
HITCBC 83   24389 if(! grammar::digit_chars(*it)) 83   24398 if(! grammar::digit_chars(*it))
84   { 84   {
85   // expected DIGIT 85   // expected DIGIT
HITCBC 86   4306 BOOST_HTTP_RETURN_EC( 86   4306 BOOST_HTTP_RETURN_EC(
87   grammar::error::need_more); 87   grammar::error::need_more);
88   } 88   }
HITCBC 89   20083 v = 10 * (*it++ - '0'); 89   20092 v = 10 * (*it++ - '0');
HITCBC 90   20083 if(it == end) 90   20092 if(it == end)
91   { 91   {
92   // expected "." 92   // expected "."
HITCBC 93   1119 BOOST_HTTP_RETURN_EC( 93   1119 BOOST_HTTP_RETURN_EC(
94   grammar::error::need_more); 94   grammar::error::need_more);
95   } 95   }
HITCBC 96   18964 if(*it != '.') 96   18973 if(*it != '.')
97   { 97   {
98   // expected "." 98   // expected "."
MISUBC 99   BOOST_HTTP_RETURN_EC( 99   BOOST_HTTP_RETURN_EC(
100   grammar::error::need_more); 100   grammar::error::need_more);
101   } 101   }
HITCBC 102   18964 ++it; 102   18973 ++it;
HITCBC 103   18964 if(it == end) 103   18973 if(it == end)
104   { 104   {
105   // expected DIGIT 105   // expected DIGIT
HITCBC 106   959 BOOST_HTTP_RETURN_EC( 106   959 BOOST_HTTP_RETURN_EC(
107   grammar::error::need_more); 107   grammar::error::need_more);
108   } 108   }
HITCBC 109   18005 if(! grammar::digit_chars(*it)) 109   18014 if(! grammar::digit_chars(*it))
110   { 110   {
111   // expected DIGIT 111   // expected DIGIT
MISUBC 112   BOOST_HTTP_RETURN_EC( 112   BOOST_HTTP_RETURN_EC(
113   grammar::error::need_more); 113   grammar::error::need_more);
114   } 114   }
HITCBC 115   18005 v += *it++ - '0'; 115   18014 v += *it++ - '0';
HITCBC 116   18005 return v; 116   18014 return v;
117   } 117   }
118   118  
119   //------------------------------------------------ 119   //------------------------------------------------
120   120  
121   auto 121   auto
HITCBC 122   7455 status_code_rule_t:: 122   7464 status_code_rule_t::
123   parse( 123   parse(
124   char const*& it, 124   char const*& it,
125   char const* end) const noexcept -> 125   char const* end) const noexcept ->
126   system::result<value_type> 126   system::result<value_type>
127   { 127   {
128   auto const dig = 128   auto const dig =
HITCBC 129   17353 [](char c) -> int 129   17380 [](char c) -> int
130   { 130   {
HITCBC 131   17353 unsigned char uc(c - '0'); 131   17380 unsigned char uc(c - '0');
HITCBC 132   17353 if(uc > 9) 132   17380 if(uc > 9)
MISUBC 133   return -1; 133   return -1;
HITCBC 134   17353 return uc; 134   17380 return uc;
135   }; 135   };
136   136  
HITCBC 137   7455 if(it == end) 137   7464 if(it == end)
138   { 138   {
139   // end 139   // end
HITCBC 140   846 BOOST_HTTP_RETURN_EC( 140   846 BOOST_HTTP_RETURN_EC(
141   grammar::error::need_more); 141   grammar::error::need_more);
142   } 142   }
HITCBC 143   6609 auto it0 = it; 143   6618 auto it0 = it;
HITCBC 144   6609 int v = dig(*it); 144   6618 int v = dig(*it);
HITCBC 145   6609 if(v == -1) 145   6618 if(v == -1)
146   { 146   {
147   // expected DIGIT 147   // expected DIGIT
MISUBC 148   BOOST_HTTP_RETURN_EC( 148   BOOST_HTTP_RETURN_EC(
149   grammar::error::mismatch); 149   grammar::error::mismatch);
150   } 150   }
HITCBC 151   6609 value_type t; 151   6618 value_type t;
HITCBC 152   6609 t.v = 100 * v; 152   6618 t.v = 100 * v;
HITCBC 153   6609 ++it; 153   6618 ++it;
HITCBC 154   6609 if(it == end) 154   6618 if(it == end)
155   { 155   {
156   // end 156   // end
HITCBC 157   830 BOOST_HTTP_RETURN_EC( 157   830 BOOST_HTTP_RETURN_EC(
158   grammar::error::need_more); 158   grammar::error::need_more);
159   } 159   }
HITCBC 160   5779 v = dig(*it); 160   5788 v = dig(*it);
HITCBC 161   5779 if(v == -1) 161   5788 if(v == -1)
162   { 162   {
163   // expected DIGIT 163   // expected DIGIT
MISUBC 164   BOOST_HTTP_RETURN_EC( 164   BOOST_HTTP_RETURN_EC(
165   grammar::error::mismatch); 165   grammar::error::mismatch);
166   } 166   }
HITCBC 167   5779 t.v = t.v + (10 * v); 167   5788 t.v = t.v + (10 * v);
HITCBC 168   5779 ++it; 168   5788 ++it;
HITCBC 169   5779 if(it == end) 169   5788 if(it == end)
170   { 170   {
171   // end 171   // end
HITCBC 172   814 BOOST_HTTP_RETURN_EC( 172   814 BOOST_HTTP_RETURN_EC(
173   grammar::error::need_more); 173   grammar::error::need_more);
174   } 174   }
HITCBC 175   4965 v = dig(*it); 175   4974 v = dig(*it);
HITCBC 176   4965 if(v == -1) 176   4974 if(v == -1)
177   { 177   {
178   // expected DIGIT 178   // expected DIGIT
MISUBC 179   BOOST_HTTP_RETURN_EC( 179   BOOST_HTTP_RETURN_EC(
180   grammar::error::need_more); 180   grammar::error::need_more);
181   } 181   }
HITCBC 182   4965 t.v = t.v + v; 182   4974 t.v = t.v + v;
HITCBC 183   4965 ++it; 183   4974 ++it;
184   184  
HITCBC 185   4965 t.s = core::string_view(it0, it - it0); 185   4974 t.s = core::string_view(it0, it - it0);
HITCBC 186   4965 t.st = int_to_status(t.v); 186   4974 t.st = int_to_status(t.v);
HITCBC 187   4965 return t; 187   4974 return t;
188   } 188   }
189   189  
190   //------------------------------------------------ 190   //------------------------------------------------
191   191  
192   auto 192   auto
HITCBC 193   4167 reason_phrase_rule_t:: 193   4176 reason_phrase_rule_t::
194   parse( 194   parse(
195   char const*& it, 195   char const*& it,
196   char const* end) const noexcept -> 196   char const* end) const noexcept ->
197   system::result<value_type> 197   system::result<value_type>
198   { 198   {
HITCBC 199   4167 auto begin = it; 199   4176 auto begin = it;
HITCBC 200   4167 it = grammar::find_if_not(it, end, ws_vchars); 200   4176 it = grammar::find_if_not(it, end, ws_vchars);
HITCBC 201   4167 return core::string_view(begin, it); 201   4176 return core::string_view(begin, it);
202   } 202   }
203   203  
204   //------------------------------------------------ 204   //------------------------------------------------
205   205  
206   auto 206   auto
HITCBC 207   25305 field_name_rule_t:: 207   25313 field_name_rule_t::
208   parse( 208   parse(
209   char const*& it, 209   char const*& it,
210   char const* end) const noexcept -> 210   char const* end) const noexcept ->
211   system::result<value_type> 211   system::result<value_type>
212   { 212   {
HITCBC 213   25305 if( it == end ) 213   25313 if( it == end )
HITCBC 214   1 BOOST_HTTP_RETURN_EC( 214   1 BOOST_HTTP_RETURN_EC(
215   grammar::error::need_more); 215   grammar::error::need_more);
216   216  
HITCBC 217   25304 value_type v; 217   25312 value_type v;
218   218  
HITCBC 219   25304 auto begin = it; 219   25312 auto begin = it;
HITCBC 220   25304 auto rv = grammar::parse( 220   25312 auto rv = grammar::parse(
221   it, end, token_rule); 221   it, end, token_rule);
HITCBC 222   25304 if( rv.has_error() || (it != end) ) 222   25312 if( rv.has_error() || (it != end) )
223   { 223   {
HITCBC 224   15679 if( it != begin ) 224   15687 if( it != begin )
225   { 225   {
HITCBC 226   15613 v = core::string_view(begin, it - begin); 226   15621 v = core::string_view(begin, it - begin);
HITCBC 227   15613 return v; 227   15621 return v;
228   } 228   }
HITCBC 229   66 return error::bad_field_name; 229   66 return error::bad_field_name;
230   } 230   }
231   231  
HITCBC 232   9625 v = core::string_view(begin, end - begin); 232   9625 v = core::string_view(begin, end - begin);
HITCBC 233   9625 return v; 233   9625 return v;
234   } 234   }
235   235  
236   auto 236   auto
HITCBC 237   15882 field_value_rule_t:: 237   15890 field_value_rule_t::
238   parse( 238   parse(
239   char const*& it, 239   char const*& it,
240   char const* end) const noexcept -> 240   char const* end) const noexcept ->
241   system::result<value_type> 241   system::result<value_type>
242   { 242   {
HITCBC 243   15882 value_type v; 243   15890 value_type v;
HITCBC 244   15882 if( it == end ) 244   15890 if( it == end )
245   { 245   {
HITCBC 246   651 v.value = core::string_view(it, 0); 246   651 v.value = core::string_view(it, 0);
HITCBC 247   651 return v; 247   651 return v;
248   } 248   }
249   249  
250   // field-line = field-name ":" OWS field-value OWS 250   // field-line = field-name ":" OWS field-value OWS
251   // field-value = *field-content 251   // field-value = *field-content
252   // field-content = field-vchar 252   // field-content = field-vchar
253   // [ 1*( SP / HTAB / field-vchar ) field-vchar ] 253   // [ 1*( SP / HTAB / field-vchar ) field-vchar ]
254   // field-vchar = VCHAR / obs-text 254   // field-vchar = VCHAR / obs-text
255   // obs-text = %x80-FF 255   // obs-text = %x80-FF
256   // VCHAR = %x21-7E 256   // VCHAR = %x21-7E
257   // ; visible (printing) characters 257   // ; visible (printing) characters
258   258  
HITCBC 259   66256 auto is_field_vchar = [](unsigned char ch) 259   66277 auto is_field_vchar = [](unsigned char ch)
260   { 260   {
HITCBC 261   66256 return (ch >= 0x21 && ch <= 0x7e) || ch >= 0x80; 261   66277 return (ch >= 0x21 && ch <= 0x7e) || ch >= 0x80;
262   }; 262   };
263   263  
HITCBC 264   15231 char const* s0 = nullptr; 264   15239 char const* s0 = nullptr;
HITCBC 265   15231 char const* s1 = nullptr; 265   15239 char const* s1 = nullptr;
266   266  
HITCBC 267   15231 bool has_crlf = false; 267   15239 bool has_crlf = false;
HITCBC 268   15231 bool has_obs_fold = false; 268   15239 bool has_obs_fold = false;
269   269  
HITCBC 270   99326 while( it < end ) 270   99363 while( it < end )
271   { 271   {
HITCBC 272   95944 auto ch = *it; 272   95981 auto ch = *it;
HITCBC 273   95944 if( ws(ch) ) 273   95981 if( ws(ch) )
274   { 274   {
HITCBC 275   17143 ++it; 275   17151 ++it;
HITCBC 276   17143 continue; 276   17151 continue;
277   } 277   }
278   278  
HITCBC 279   78801 if( ch == '\r' ) 279   78830 if( ch == '\r' )
280   { 280   {
281   // too short to know if we have a potential obs-fold 281   // too short to know if we have a potential obs-fold
282   // occurrence 282   // occurrence
HITCBC 283   12545 if( end - it < 2 ) 283   12553 if( end - it < 2 )
HITCBC 284   558 BOOST_HTTP_RETURN_EC( 284   558 BOOST_HTTP_RETURN_EC(
285   grammar::error::need_more); 285   grammar::error::need_more);
286   286  
HITCBC 287   11987 if( it[1] != '\n' ) 287   11995 if( it[1] != '\n' )
HITCBC 288   53 goto done; 288   53 goto done;
289   289  
HITCBC 290   11934 if( end - it < 3 ) 290   11942 if( end - it < 3 )
HITCBC 291   514 BOOST_HTTP_RETURN_EC( 291   514 BOOST_HTTP_RETURN_EC(
292   grammar::error::need_more); 292   grammar::error::need_more);
293   293  
HITCBC 294   11420 if(! ws(it[2]) ) 294   11428 if(! ws(it[2]) )
295   { 295   {
HITCBC 296   10690 has_crlf = true; 296   10698 has_crlf = true;
HITCBC 297   10690 goto done; 297   10698 goto done;
298   } 298   }
299   299  
HITCBC 300   730 has_obs_fold = true; 300   730 has_obs_fold = true;
HITCBC 301   730 it = it + 3; 301   730 it = it + 3;
HITCBC 302   730 continue; 302   730 continue;
HITCBC 303   730 } 303   730 }
304   304  
HITCBC 305   66256 if(! is_field_vchar(ch) ) 305   66277 if(! is_field_vchar(ch) )
306   { 306   {
HITCBC 307   34 goto done; 307   34 goto done;
308   } 308   }
309   309  
HITCBC 310   66222 if(! s0 ) 310   66243 if(! s0 )
HITCBC 311   14168 s0 = it; 311   14176 s0 = it;
312   312  
HITCBC 313   66222 ++it; 313   66243 ++it;
HITCBC 314   66222 s1 = it; 314   66243 s1 = it;
315   } 315   }
316   316  
HITCBC 317   3382 done: 317   3382 done:
318   // later routines wind up doing pointer 318   // later routines wind up doing pointer
319   // subtraction using the .data() member 319   // subtraction using the .data() member
320   // of the value so we need a valid 0-len range 320   // of the value so we need a valid 0-len range
HITCBC 321   14159 if(! s0 ) 321   14167 if(! s0 )
322   { 322   {
HITCBC 323   899 s0 = it; 323   899 s0 = it;
HITCBC 324   899 s1 = s0; 324   899 s1 = s0;
325   } 325   }
326   326  
HITCBC 327   14159 v.value = core::string_view(s0, s1 - s0); 327   14167 v.value = core::string_view(s0, s1 - s0);
HITCBC 328   14159 v.has_crlf = has_crlf; 328   14167 v.has_crlf = has_crlf;
HITCBC 329   14159 v.has_obs_fold = has_obs_fold; 329   14167 v.has_obs_fold = has_obs_fold;
HITCBC 330   14159 return v; 330   14167 return v;
331   } 331   }
332   332  
333   auto 333   auto
HITCBC 334   36543 field_rule_t:: 334   36560 field_rule_t::
335   parse( 335   parse(
336   char const*& it, 336   char const*& it,
337   char const* end) const noexcept -> 337   char const* end) const noexcept ->
338   system::result<value_type> 338   system::result<value_type>
339   { 339   {
HITCBC 340   36543 if(it == end) 340   36560 if(it == end)
341   { 341   {
HITCBC 342   907 BOOST_HTTP_RETURN_EC( 342   907 BOOST_HTTP_RETURN_EC(
343   grammar::error::need_more); 343   grammar::error::need_more);
344   } 344   }
345   // check for leading CRLF 345   // check for leading CRLF
HITCBC 346   35636 if(it[0] == '\r') 346   35653 if(it[0] == '\r')
347   { 347   {
HITCBC 348   10572 ++it; 348   10581 ++it;
HITCBC 349   10572 if(it == end) 349   10581 if(it == end)
350   { 350   {
HITCBC 351   459 BOOST_HTTP_RETURN_EC( 351   459 BOOST_HTTP_RETURN_EC(
352   grammar::error::need_more); 352   grammar::error::need_more);
353   } 353   }
HITCBC 354   10113 if(*it != '\n') 354   10122 if(*it != '\n')
355   { 355   {
HITCBC 356   21 BOOST_HTTP_RETURN_EC( 356   21 BOOST_HTTP_RETURN_EC(
357   grammar::error::mismatch); 357   grammar::error::mismatch);
358   } 358   }
359   // end of fields 359   // end of fields
HITCBC 360   10092 ++it; 360   10101 ++it;
HITCBC 361   10092 BOOST_HTTP_RETURN_EC( 361   10101 BOOST_HTTP_RETURN_EC(
362   grammar::error::end_of_range); 362   grammar::error::end_of_range);
363   } 363   }
364   364  
HITCBC 365   25064 value_type v; 365   25072 value_type v;
366   auto rv = grammar::parse( 366   auto rv = grammar::parse(
HITCBC 367   25064 it, end, grammar::tuple_rule( 367   25072 it, end, grammar::tuple_rule(
368   field_name_rule, 368   field_name_rule,
HITCBC 369   25064 grammar::delim_rule(':'), 369   25072 grammar::delim_rule(':'),
370   field_value_rule, 370   field_value_rule,
HITCBC 371   25064 crlf_rule)); 371   25072 crlf_rule));
372   372  
HITCBC 373   25064 if( rv.has_error() ) 373   25072 if( rv.has_error() )
HITCBC 374   14390 return rv.error(); 374   14390 return rv.error();
375   375  
HITCBC 376   10674 auto val = rv.value(); 376   10682 auto val = rv.value();
HITCBC 377   10674 v.name = std::get<0>(val); 377   10682 v.name = std::get<0>(val);
HITCBC 378   10674 v.value = std::get<2>(val).value; 378   10682 v.value = std::get<2>(val).value;
HITCBC 379   10674 v.has_obs_fold = std::get<2>(val).has_obs_fold; 379   10682 v.has_obs_fold = std::get<2>(val).has_obs_fold;
380   380  
HITCBC 381   10674 return v; 381   10682 return v;
382   } 382   }
383   383  
384   //------------------------------------------------ 384   //------------------------------------------------
385   385  
386   void 386   void
HITCBC 387   244 remove_obs_fold( 387   244 remove_obs_fold(
388   char* it, 388   char* it,
389   char const* const end) noexcept 389   char const* const end) noexcept
390   { 390   {
HITCBC 391   2262 while(it != end) 391   2262 while(it != end)
392   { 392   {
HITCBC 393   2236 if(*it != '\r') 393   2236 if(*it != '\r')
394   { 394   {
HITCBC 395   1637 ++it; 395   1637 ++it;
HITCBC 396   1637 continue; 396   1637 continue;
397   } 397   }
HITCBC 398   599 if(end - it < 3) 398   599 if(end - it < 3)
HITCBC 399   218 break; 399   218 break;
HITCBC 400   381 BOOST_ASSERT(it[1] == '\n'); 400   381 BOOST_ASSERT(it[1] == '\n');
HITCBC 401   762 if( it[1] == '\n' && 401   762 if( it[1] == '\n' &&
HITCBC 402   381 ws(it[2])) 402   381 ws(it[2]))
403   { 403   {
HITCBC 404   378 it[0] = ' '; 404   378 it[0] = ' ';
HITCBC 405   378 it[1] = ' '; 405   378 it[1] = ' ';
HITCBC 406   378 it += 3; 406   378 it += 3;
407   } 407   }
408   else 408   else
409   { 409   {
HITCBC 410   3 ++it; 410   3 ++it;
411   } 411   }
412   } 412   }
HITCBC 413   244 } 413   244 }
414   414  
415   } // detail 415   } // detail
416   } // http 416   } // http
417   } // boost 417   } // boost