1[/ 2 / Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot 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 8[section:line_based Line-Based Operations] 9 10Many commonly-used internet protocols are line-based, which means that they 11have protocol elements that are delimited by the character sequence `"\r\n"`. 12Examples include HTTP, SMTP and FTP. To more easily permit the implementation 13of line-based protocols, as well as other protocols that use delimiters, Boost.Asio 14includes the functions `read_until()` and `async_read_until()`. 15 16The following example illustrates the use of `async_read_until()` in an HTTP 17server, to receive the first line of an HTTP request from a client: 18 19 class http_connection 20 { 21 ... 22 23 void start() 24 { 25 boost::asio::async_read_until(socket_, data_, "\r\n", 26 boost::bind(&http_connection::handle_request_line, this, _1)); 27 } 28 29 void handle_request_line(boost::system::error_code ec) 30 { 31 if (!ec) 32 { 33 std::string method, uri, version; 34 char sp1, sp2, cr, lf; 35 std::istream is(&data_); 36 is.unsetf(std::ios_base::skipws); 37 is >> method >> sp1 >> uri >> sp2 >> version >> cr >> lf; 38 ... 39 } 40 } 41 42 ... 43 44 boost::asio::ip::tcp::socket socket_; 45 boost::asio::streambuf data_; 46 }; 47 48The `streambuf` data member serves as a place to store the data that has been 49read from the socket before it is searched for the delimiter. It is important 50to remember that there may be additional data ['after] the delimiter. This 51surplus data should be left in the `streambuf` so that it may be inspected by a 52subsequent call to `read_until()` or `async_read_until()`. 53 54The delimiters may be specified as a single `char`, a `std::string` or a 55`boost::regex`. The `read_until()` and `async_read_until()` functions also 56include overloads that accept a user-defined function object called a match 57condition. For example, to read data into a streambuf until whitespace is 58encountered: 59 60 typedef boost::asio::buffers_iterator< 61 boost::asio::streambuf::const_buffers_type> iterator; 62 63 std::pair<iterator, bool> 64 match_whitespace(iterator begin, iterator end) 65 { 66 iterator i = begin; 67 while (i != end) 68 if (std::isspace(*i++)) 69 return std::make_pair(i, true); 70 return std::make_pair(i, false); 71 } 72 ... 73 boost::asio::streambuf b; 74 boost::asio::read_until(s, b, match_whitespace); 75 76To read data into a streambuf until a matching character is found: 77 78 class match_char 79 { 80 public: 81 explicit match_char(char c) : c_(c) {} 82 83 template <typename Iterator> 84 std::pair<Iterator, bool> operator()( 85 Iterator begin, Iterator end) const 86 { 87 Iterator i = begin; 88 while (i != end) 89 if (c_ == *i++) 90 return std::make_pair(i, true); 91 return std::make_pair(i, false); 92 } 93 94 private: 95 char c_; 96 }; 97 98 namespace boost { namespace asio { 99 template <> struct is_match_condition<match_char> 100 : public boost::true_type {}; 101 } } // namespace boost::asio 102 ... 103 boost::asio::streambuf b; 104 boost::asio::read_until(s, b, match_char('a')); 105 106The `is_match_condition<>` type trait automatically evaluates to true for 107functions, and for function objects with a nested `result_type` typedef. For 108other types the trait must be explicitly specialised, as shown above. 109 110[heading See Also] 111 112[link boost_asio.reference.async_read_until async_read_until()], 113[link boost_asio.reference.is_match_condition is_match_condition], 114[link boost_asio.reference.read_until read_until()], 115[link boost_asio.reference.streambuf streambuf], 116[link boost_asio.examples.cpp03_examples.http_client HTTP client example]. 117 118[endsect] 119