std::size_t read_until(SyncReadStream& s, boost::asio::basic_streambuf<Allocator>& b, const boost::regex& expr, boost::system::error_code& ec) { std::size_t search_position = 0; for (;;) { // Determine the range of the data to be searched. typedef typename boost::asio::basic_streambuf< Allocator>::const_buffers_type const_buffers_type; typedef boost::asio::buffers_iterator<const_buffers_type> iterator; const_buffers_type buffers = b.data(); iterator begin = iterator::begin(buffers); iterator start_pos = begin + search_position; iterator end = iterator::end(buffers); // Look for a match. boost::match_results<iterator, typename std::vector<boost::sub_match<iterator> >::allocator_type> match_results; if (regex_search(start_pos, end, match_results, expr, boost::match_default | boost::match_partial)) { if (match_results[0].matched) { // Full match. We're done. ec = boost::system::error_code(); return match_results[0].second - begin; } else { // Partial match. Next search needs to start from beginning of match. search_position = match_results[0].first - begin; } } else { // No match. Next search can start with the new data. search_position = end - begin; } // Check if buffer is full. if (b.size() == b.max_size()) { ec = error::not_found; return 0; } // Need more data. std::size_t bytes_to_read = read_size_helper(b, 65536); b.commit(s.read_some(b.prepare(bytes_to_read), ec)); if (ec) return 0; } }
std::size_t read_until(SyncReadStream& s, boost::asio::basic_streambuf<Allocator>& b, const std::string& delim, boost::system::error_code& ec) { std::size_t search_position = 0; for (;;) { // Determine the range of the data to be searched. typedef typename boost::asio::basic_streambuf< Allocator>::const_buffers_type const_buffers_type; typedef boost::asio::buffers_iterator<const_buffers_type> iterator; const_buffers_type buffers = b.data(); iterator begin = iterator::begin(buffers); iterator start_pos = begin + search_position; iterator end = iterator::end(buffers); // Look for a match. std::pair<iterator, bool> result = detail::partial_search( start_pos, end, delim.begin(), delim.end()); if (result.first != end) { if (result.second) { // Full match. We're done. ec = boost::system::error_code(); return result.first - begin + delim.length(); } else { // Partial match. Next search needs to start from beginning of match. search_position = result.first - begin; } } else { // No match. Next search can start with the new data. search_position = end - begin; } // Check if buffer is full. if (b.size() == b.max_size()) { ec = error::not_found; return 0; } // Need more data. std::size_t bytes_to_read = read_size_helper(b, 65536); b.commit(s.read_some(b.prepare(bytes_to_read), ec)); if (ec) return 0; } }
std::size_t read_until(SyncReadStream& s, asio::basic_streambuf<Allocator>& b, MatchCondition match_condition, asio::error_code& ec, typename enable_if<is_match_condition<MatchCondition>::value>::type*) { std::size_t search_position = 0; for (;;) { // Determine the range of the data to be searched. typedef typename asio::basic_streambuf< Allocator>::const_buffers_type const_buffers_type; typedef asio::buffers_iterator<const_buffers_type> iterator; const_buffers_type buffers = b.data(); iterator begin = iterator::begin(buffers); iterator start_pos = begin + search_position; iterator end = iterator::end(buffers); // Look for a match. std::pair<iterator, bool> result = match_condition(start_pos, end); if (result.second) { // Full match. We're done. ec = asio::error_code(); return result.first - begin; } else if (result.first != end) { // Partial match. Next search needs to start from beginning of match. search_position = result.first - begin; } else { // No match. Next search can start with the new data. search_position = end - begin; } // Check if buffer is full. if (b.size() == b.max_size()) { ec = error::not_found; return 0; } // Need more data. std::size_t bytes_to_read = read_size_helper(b, 65536); b.commit(s.read_some(b.prepare(bytes_to_read), ec)); if (ec) return 0; } }
std::size_t read_buffer_sequence(SyncReadStream& s, const MutableBufferSequence& buffers, const MutableBufferIterator&, CompletionCondition completion_condition, boost::system::error_code& ec) { ec = boost::system::error_code(); boost::asio::detail::consuming_buffers<mutable_buffer, MutableBufferSequence, MutableBufferIterator> tmp(buffers); while (!tmp.empty()) { if (std::size_t max_size = detail::adapt_completion_condition_result( completion_condition(ec, tmp.total_consumed()))) tmp.consume(s.read_some(tmp.prepare(max_size), ec)); else break; } return tmp.total_consumed();; }
std::size_t read_until(SyncReadStream& s, boost::asio::basic_streambuf<Allocator>& b, char delim, boost::system::error_code& ec) { std::size_t search_position = 0; for (;;) { // Determine the range of the data to be searched. typedef typename boost::asio::basic_streambuf< Allocator>::const_buffers_type const_buffers_type; typedef boost::asio::buffers_iterator<const_buffers_type> iterator; const_buffers_type buffers = b.data(); iterator begin = iterator::begin(buffers); iterator start_pos = begin + search_position; iterator end = iterator::end(buffers); // Look for a match. iterator iter = std::find(start_pos, end, delim); if (iter != end) { // Found a match. We're done. ec = boost::system::error_code(); return iter - begin + 1; } else { // No match. Next search can start with the new data. search_position = end - begin; } // Check if buffer is full. if (b.size() == b.max_size()) { ec = error::not_found; return 0; } // Need more data. std::size_t bytes_to_read = read_size_helper(b, 65536); b.commit(s.read_some(b.prepare(bytes_to_read), ec)); if (ec) return 0; } }
std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, CompletionCondition completion_condition, asio::error_code& ec) { ec = asio::error_code(); asio::detail::consuming_buffers< mutable_buffer, MutableBufferSequence> tmp(buffers); std::size_t total_transferred = 0; tmp.prepare(detail::adapt_completion_condition_result( completion_condition(ec, total_transferred))); while (tmp.begin() != tmp.end()) { std::size_t bytes_transferred = s.read_some(tmp, ec); tmp.consume(bytes_transferred); total_transferred += bytes_transferred; tmp.prepare(detail::adapt_completion_condition_result( completion_condition(ec, total_transferred))); } return total_transferred; }
std::size_t read(SyncReadStream& s, asio::basic_streambuf<Allocator>& b, CompletionCondition completion_condition, asio::error_code& ec) { ec = asio::error_code(); std::size_t total_transferred = 0; std::size_t max_size = detail::adapt_completion_condition_result( completion_condition(ec, total_transferred)); std::size_t bytes_available = read_size_helper(b, max_size); while (bytes_available > 0) { std::size_t bytes_transferred = s.read_some(b.prepare(bytes_available), ec); b.commit(bytes_transferred); total_transferred += bytes_transferred; max_size = detail::adapt_completion_condition_result( completion_condition(ec, total_transferred)); bytes_available = read_size_helper(b, max_size); } return total_transferred; }
void send_cgi_response( SyncReadStream& input, SyncWriteStream& output, error_code& ec) { static_assert(is_sync_read_stream<SyncReadStream>::value, "SyncReadStream requirements not met"); static_assert(is_sync_write_stream<SyncWriteStream>::value, "SyncWriteStream requirements not met"); using boost::asio::buffer_cast; using boost::asio::buffer_size; // Set up the response. We use the buffer_body type, // allowing serialization to use manually provided buffers. response<buffer_body> res; res.result(status::ok); res.version = 11; res.set(field::server, "Beast"); res.set(field::transfer_encoding, "chunked"); // No data yet, but we set more = true to indicate // that it might be coming later. Otherwise the // serializer::is_done would return true right after // sending the header. res.body.data = nullptr; res.body.more = true; // Create the serializer. response_serializer<buffer_body, fields> sr{res}; // Send the header immediately. write_header(output, sr, ec); if(ec) return; // Alternate between reading from the child process // and sending all the process output until there // is no more output. do { // Read a buffer from the child process char buffer[2048]; auto bytes_transferred = input.read_some( boost::asio::buffer(buffer, sizeof(buffer)), ec); if(ec == boost::asio::error::eof) { ec = {}; // `nullptr` indicates there is no buffer res.body.data = nullptr; // `false` means no more data is coming res.body.more = false; } else { if(ec) return; // Point to our buffer with the bytes that // we received, and indicate that there may // be some more data coming res.body.data = buffer; res.body.size = bytes_transferred; res.body.more = true; } // Write everything in the body buffer write(output, sr, ec); // This error is returned by body_buffer during // serialization when it is done sending the data // provided and needs another buffer. if(ec == error::need_buffer) { ec = {}; continue; } if(ec) return; } while(! sr.is_done()); }