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   28324 crlf_rule_t:: 32   28890 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   28324 if(it == end) 38   28890 if(it == end)
HITCBC 39   6145 return grammar::error::need_more; 39   6535 return grammar::error::need_more;
HITCBC 40   22179 if(*it != '\r') 40   22355 if(*it != '\r')
HITCBC 41   29 return grammar::error::mismatch; 41   29 return grammar::error::mismatch;
HITCBC 42   22150 ++it; 42   22326 ++it;
HITCBC 43   22150 if(it == end) 43   22326 if(it == end)
HITCBC 44   887 return grammar::error::need_more; 44   961 return grammar::error::need_more;
HITCBC 45   21263 if(*it != '\n') 45   21365 if(*it != '\n')
HITCBC 46   51 return grammar::error::mismatch; 46   51 return grammar::error::mismatch;
HITCBC 47   21212 ++it; 47   21314 ++it;
HITCBC 48   21212 return {}; 48   21314 return {};
49   } 49   }
50   50  
51   //------------------------------------------------ 51   //------------------------------------------------
52   52  
53   auto 53   auto
HITCBC 54   26902 version_rule_t:: 54   28506 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   26902 value_type v = 0; 60   28506 value_type v = 0;
HITCBC 61   26902 if(it == end) 61   28506 if(it == end)
62   { 62   {
63   // expected "HTTP/" 63   // expected "HTTP/"
HITCBC 64   1511 BOOST_HTTP_RETURN_EC( 64   1619 BOOST_HTTP_RETURN_EC(
65   grammar::error::need_more); 65   grammar::error::need_more);
66   } 66   }
HITCBC 67   25391 if(end - it >= 5) 67   26887 if(end - it >= 5)
68   { 68   {
HITCBC 69   21085 if(std::memcmp( 69   22177 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   21085 it += 5; 75   22177 it += 5;
76   } 76   }
HITCBC 77   25391 if(it == end) 77   26887 if(it == end)
78   { 78   {
79   // expected DIGIT 79   // expected DIGIT
HITCBC 80   991 BOOST_HTTP_RETURN_EC( 80   1087 BOOST_HTTP_RETURN_EC(
81   grammar::error::need_more); 81   grammar::error::need_more);
82   } 82   }
HITCBC 83   24400 if(! grammar::digit_chars(*it)) 83   25800 if(! grammar::digit_chars(*it))
84   { 84   {
85   // expected DIGIT 85   // expected DIGIT
HITCBC 86   4306 BOOST_HTTP_RETURN_EC( 86   4710 BOOST_HTTP_RETURN_EC(
87   grammar::error::need_more); 87   grammar::error::need_more);
88   } 88   }
HITCBC 89   20094 v = 10 * (*it++ - '0'); 89   21090 v = 10 * (*it++ - '0');
HITCBC 90   20094 if(it == end) 90   21090 if(it == end)
91   { 91   {
92   // expected "." 92   // expected "."
HITCBC 93   1119 BOOST_HTTP_RETURN_EC( 93   1213 BOOST_HTTP_RETURN_EC(
94   grammar::error::need_more); 94   grammar::error::need_more);
95   } 95   }
HITCBC 96   18975 if(*it != '.') 96   19877 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   18975 ++it; 102   19877 ++it;
HITCBC 103   18975 if(it == end) 103   19877 if(it == end)
104   { 104   {
105   // expected DIGIT 105   // expected DIGIT
HITCBC 106   959 BOOST_HTTP_RETURN_EC( 106   1051 BOOST_HTTP_RETURN_EC(
107   grammar::error::need_more); 107   grammar::error::need_more);
108   } 108   }
HITCBC 109   18016 if(! grammar::digit_chars(*it)) 109   18826 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   18016 v += *it++ - '0'; 115   18826 v += *it++ - '0';
HITCBC 116   18016 return v; 116   18826 return v;
117   } 117   }
118   118  
119   //------------------------------------------------ 119   //------------------------------------------------
120   120  
121   auto 121   auto
HITCBC 122   7464 status_code_rule_t:: 122   8184 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   17380 [](char c) -> int 129   19020 [](char c) -> int
130   { 130   {
HITCBC 131   17380 unsigned char uc(c - '0'); 131   19020 unsigned char uc(c - '0');
HITCBC 132   17380 if(uc > 9) 132   19020 if(uc > 9)
MISUBC 133   return -1; 133   return -1;
HITCBC 134   17380 return uc; 134   19020 return uc;
135   }; 135   };
136   136  
HITCBC 137   7464 if(it == end) 137   8184 if(it == end)
138   { 138   {
139   // end 139   // end
HITCBC 140   846 BOOST_HTTP_RETURN_EC( 140   934 BOOST_HTTP_RETURN_EC(
141   grammar::error::need_more); 141   grammar::error::need_more);
142   } 142   }
HITCBC 143   6618 auto it0 = it; 143   7250 auto it0 = it;
HITCBC 144   6618 int v = dig(*it); 144   7250 int v = dig(*it);
HITCBC 145   6618 if(v == -1) 145   7250 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   6618 value_type t; 151   7250 value_type t;
HITCBC 152   6618 t.v = 100 * v; 152   7250 t.v = 100 * v;
HITCBC 153   6618 ++it; 153   7250 ++it;
HITCBC 154   6618 if(it == end) 154   7250 if(it == end)
155   { 155   {
156   // end 156   // end
HITCBC 157   830 BOOST_HTTP_RETURN_EC( 157   916 BOOST_HTTP_RETURN_EC(
158   grammar::error::need_more); 158   grammar::error::need_more);
159   } 159   }
HITCBC 160   5788 v = dig(*it); 160   6334 v = dig(*it);
HITCBC 161   5788 if(v == -1) 161   6334 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   5788 t.v = t.v + (10 * v); 167   6334 t.v = t.v + (10 * v);
HITCBC 168   5788 ++it; 168   6334 ++it;
HITCBC 169   5788 if(it == end) 169   6334 if(it == end)
170   { 170   {
171   // end 171   // end
HITCBC 172   814 BOOST_HTTP_RETURN_EC( 172   898 BOOST_HTTP_RETURN_EC(
173   grammar::error::need_more); 173   grammar::error::need_more);
174   } 174   }
HITCBC 175   4974 v = dig(*it); 175   5436 v = dig(*it);
HITCBC 176   4974 if(v == -1) 176   5436 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   4974 t.v = t.v + v; 182   5436 t.v = t.v + v;
HITCBC 183   4974 ++it; 183   5436 ++it;
184   184  
HITCBC 185   4974 t.s = core::string_view(it0, it - it0); 185   5436 t.s = core::string_view(it0, it - it0);
HITCBC 186   4974 t.st = int_to_status(t.v); 186   5436 t.st = int_to_status(t.v);
HITCBC 187   4974 return t; 187   5436 return t;
188   } 188   }
189   189  
190   //------------------------------------------------ 190   //------------------------------------------------
191   191  
192   auto 192   auto
HITCBC 193   4176 reason_phrase_rule_t:: 193   4556 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   4176 auto begin = it; 199   4556 auto begin = it;
HITCBC 200   4176 it = grammar::find_if_not(it, end, ws_vchars); 200   4556 it = grammar::find_if_not(it, end, ws_vchars);
HITCBC 201   4176 return core::string_view(begin, it); 201   4556 return core::string_view(begin, it);
202   } 202   }
203   203  
204   //------------------------------------------------ 204   //------------------------------------------------
205   205  
206   auto 206   auto
HITCBC 207   25315 field_name_rule_t:: 207   26365 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   25315 if( it == end ) 213   26365 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   25314 value_type v; 217   26364 value_type v;
218   218  
HITCBC 219   25314 auto begin = it; 219   26364 auto begin = it;
HITCBC 220   25314 auto rv = grammar::parse( 220   26364 auto rv = grammar::parse(
221   it, end, token_rule); 221   it, end, token_rule);
HITCBC 222   25314 if( rv.has_error() || (it != end) ) 222   26364 if( rv.has_error() || (it != end) )
223   { 223   {
HITCBC 224   15689 if( it != begin ) 224   15941 if( it != begin )
225   { 225   {
HITCBC 226   15623 v = core::string_view(begin, it - begin); 226   15875 v = core::string_view(begin, it - begin);
HITCBC 227   15623 return v; 227   15875 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   10423 v = core::string_view(begin, end - begin);
HITCBC 233   9625 return v; 233   10423 return v;
234   } 234   }
235   235  
236   auto 236   auto
HITCBC 237   15892 field_value_rule_t:: 237   16144 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   15892 value_type v; 243   16144 value_type v;
HITCBC 244   15892 if( it == end ) 244   16144 if( it == end )
245   { 245   {
HITCBC 246   651 v.value = core::string_view(it, 0); 246   693 v.value = core::string_view(it, 0);
HITCBC 247   651 return v; 247   693 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   66283 auto is_field_vchar = [](unsigned char ch) 259   66585 auto is_field_vchar = [](unsigned char ch)
260   { 260   {
HITCBC 261   66283 return (ch >= 0x21 && ch <= 0x7e) || ch >= 0x80; 261   66585 return (ch >= 0x21 && ch <= 0x7e) || ch >= 0x80;
262   }; 262   };
263   263  
HITCBC 264   15241 char const* s0 = nullptr; 264   15451 char const* s0 = nullptr;
HITCBC 265   15241 char const* s1 = nullptr; 265   15451 char const* s1 = nullptr;
266   266  
HITCBC 267   15241 bool has_crlf = false; 267   15451 bool has_crlf = false;
HITCBC 268   15241 bool has_obs_fold = false; 268   15451 bool has_obs_fold = false;
269   269  
HITCBC 270   99373 while( it < end ) 270   100095 while( it < end )
271   { 271   {
HITCBC 272   95991 auto ch = *it; 272   96599 auto ch = *it;
HITCBC 273   95991 if( ws(ch) ) 273   96599 if( ws(ch) )
274   { 274   {
HITCBC 275   17153 ++it; 275   17363 ++it;
HITCBC 276   17153 continue; 276   17363 continue;
277   } 277   }
278   278  
HITCBC 279   78838 if( ch == '\r' ) 279   79236 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   12555 if( end - it < 2 ) 283   12651 if( end - it < 2 )
HITCBC 284   558 BOOST_HTTP_RETURN_EC( 284   592 BOOST_HTTP_RETURN_EC(
285   grammar::error::need_more); 285   grammar::error::need_more);
286   286  
HITCBC 287   11997 if( it[1] != '\n' ) 287   12059 if( it[1] != '\n' )
HITCBC 288   53 goto done; 288   53 goto done;
289   289  
HITCBC 290   11944 if( end - it < 3 ) 290   12006 if( end - it < 3 )
HITCBC 291   514 BOOST_HTTP_RETURN_EC( 291   546 BOOST_HTTP_RETURN_EC(
292   grammar::error::need_more); 292   grammar::error::need_more);
293   293  
HITCBC 294   11430 if(! ws(it[2]) ) 294   11460 if(! ws(it[2]) )
295   { 295   {
HITCBC 296   10700 has_crlf = true; 296   10730 has_crlf = true;
HITCBC 297   10700 goto done; 297   10730 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   66283 if(! is_field_vchar(ch) ) 305   66585 if(! is_field_vchar(ch) )
306   { 306   {
HITCBC 307   34 goto done; 307   34 goto done;
308   } 308   }
309   309  
HITCBC 310   66249 if(! s0 ) 310   66551 if(! s0 )
HITCBC 311   14178 s0 = it; 311   14348 s0 = it;
312   312  
HITCBC 313   66249 ++it; 313   66551 ++it;
HITCBC 314   66249 s1 = it; 314   66551 s1 = it;
315   } 315   }
316   316  
HITCBC 317   3382 done: 317   3496 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   14169 if(! s0 ) 321   14313 if(! s0 )
322   { 322   {
HITCBC 323   899 s0 = it; 323   939 s0 = it;
HITCBC 324   899 s1 = s0; 324   939 s1 = s0;
325   } 325   }
326   326  
HITCBC 327   14169 v.value = core::string_view(s0, s1 - s0); 327   14313 v.value = core::string_view(s0, s1 - s0);
HITCBC 328   14169 v.has_crlf = has_crlf; 328   14313 v.has_crlf = has_crlf;
HITCBC 329   14169 v.has_obs_fold = has_obs_fold; 329   14313 v.has_obs_fold = has_obs_fold;
HITCBC 330   14169 return v; 330   14313 return v;
331   } 331   }
332   332  
333   auto 333   auto
HITCBC 334   36564 field_rule_t:: 334   37744 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   36564 if(it == end) 340   37744 if(it == end)
341   { 341   {
HITCBC 342   907 BOOST_HTTP_RETURN_EC( 342   979 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   35657 if(it[0] == '\r') 346   36765 if(it[0] == '\r')
347   { 347   {
HITCBC 348   10583 ++it; 348   10641 ++it;
HITCBC 349   10583 if(it == end) 349   10641 if(it == end)
350   { 350   {
HITCBC 351   459 BOOST_HTTP_RETURN_EC( 351   489 BOOST_HTTP_RETURN_EC(
352   grammar::error::need_more); 352   grammar::error::need_more);
353   } 353   }
HITCBC 354   10124 if(*it != '\n') 354   10152 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   10103 ++it; 360   10131 ++it;
HITCBC 361   10103 BOOST_HTTP_RETURN_EC( 361   10131 BOOST_HTTP_RETURN_EC(
362   grammar::error::end_of_range); 362   grammar::error::end_of_range);
363   } 363   }
364   364  
HITCBC 365   25074 value_type v; 365   26124 value_type v;
366   auto rv = grammar::parse( 366   auto rv = grammar::parse(
HITCBC 367   25074 it, end, grammar::tuple_rule( 367   26124 it, end, grammar::tuple_rule(
368   field_name_rule, 368   field_name_rule,
HITCBC 369   25074 grammar::delim_rule(':'), 369   26124 grammar::delim_rule(':'),
370   field_value_rule, 370   field_value_rule,
HITCBC 371   25074 crlf_rule)); 371   26124 crlf_rule));
372   372  
HITCBC 373   25074 if( rv.has_error() ) 373   26124 if( rv.has_error() )
HITCBC 374   14390 return rv.error(); 374   15410 return rv.error();
375   375  
HITCBC 376   10684 auto val = rv.value(); 376   10714 auto val = rv.value();
HITCBC 377   10684 v.name = std::get<0>(val); 377   10714 v.name = std::get<0>(val);
HITCBC 378   10684 v.value = std::get<2>(val).value; 378   10714 v.value = std::get<2>(val).value;
HITCBC 379   10684 v.has_obs_fold = std::get<2>(val).has_obs_fold; 379   10714 v.has_obs_fold = std::get<2>(val).has_obs_fold;
380   380  
HITCBC 381   10684 return v; 381   10714 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