mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-30 13:37:55 +00:00
[#3490] Moved the HTTPS variant
This commit is contained in:
committed by
Razvan Becheriu
parent
d84761ca87
commit
9fc12fbe0f
@@ -19,6 +19,7 @@
|
||||
#include <http/response_creator_factory.h>
|
||||
#include <http/response_json.h>
|
||||
#include <http/tests/response_test.h>
|
||||
#include <http/testutils/test_http_client.h>
|
||||
#include <http/url.h>
|
||||
#include <util/multi_threading_mgr.h>
|
||||
|
||||
@@ -386,247 +387,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/// @brief Entity which can connect to the HTTP server endpoint.
|
||||
class TestHttpsClient : public boost::noncopyable {
|
||||
public:
|
||||
|
||||
/// @brief Constructor.
|
||||
///
|
||||
/// This constructor creates new socket instance. It doesn't connect. Call
|
||||
/// connect() to connect to the server.
|
||||
///
|
||||
/// @param io_service IO service to be stopped on error.
|
||||
/// @param tls_context TLS context.
|
||||
TestHttpsClient(const IOServicePtr& io_service, TlsContextPtr tls_context)
|
||||
: io_service_(io_service), stream_(io_service_->getInternalIOService(),
|
||||
tls_context->getContext()), buf_(), response_() {
|
||||
}
|
||||
|
||||
/// @brief Destructor.
|
||||
///
|
||||
/// Closes the underlying socket if it is open.
|
||||
~TestHttpsClient() {
|
||||
close();
|
||||
}
|
||||
|
||||
/// @brief Send HTTP request specified in textual format.
|
||||
///
|
||||
/// @param request HTTP request in the textual format.
|
||||
void startRequest(const std::string& request) {
|
||||
tcp::endpoint endpoint(address::from_string(SERVER_ADDRESS),
|
||||
SERVER_PORT);
|
||||
stream_.lowest_layer().async_connect(endpoint,
|
||||
[this, request](const boost::system::error_code& ec) {
|
||||
if (ec) {
|
||||
// One would expect that async_connect wouldn't return
|
||||
// EINPROGRESS error code, but simply wait for the connection
|
||||
// to get established before the handler is invoked. It turns out,
|
||||
// however, that on some OSes the connect handler may receive this
|
||||
// error code which doesn't necessarily indicate a problem.
|
||||
// Making an attempt to write and read from this socket will
|
||||
// typically succeed. So, we ignore this error.
|
||||
if (ec.value() != boost::asio::error::in_progress) {
|
||||
ADD_FAILURE() << "error occurred while connecting: "
|
||||
<< ec.message();
|
||||
io_service_->stop();
|
||||
return;
|
||||
}
|
||||
}
|
||||
stream_.async_handshake(roleToImpl(TlsRole::CLIENT),
|
||||
[this, request](const boost::system::error_code& ec) {
|
||||
if (ec) {
|
||||
ADD_FAILURE() << "error occurred during handshake: "
|
||||
<< ec.message();
|
||||
io_service_->stop();
|
||||
return;
|
||||
}
|
||||
sendRequest(request);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/// @brief Send HTTP request.
|
||||
///
|
||||
/// @param request HTTP request in the textual format.
|
||||
void sendRequest(const std::string& request) {
|
||||
sendPartialRequest(request);
|
||||
}
|
||||
|
||||
/// @brief Send part of the HTTP request.
|
||||
///
|
||||
/// @param request part of the HTTP request to be sent.
|
||||
void sendPartialRequest(std::string request) {
|
||||
boost::asio::async_write(stream_,
|
||||
boost::asio::buffer(request.data(), request.size()),
|
||||
[this, request](const boost::system::error_code& ec,
|
||||
std::size_t bytes_transferred) mutable {
|
||||
if (ec) {
|
||||
if (ec.value() == boost::asio::error::operation_aborted) {
|
||||
return;
|
||||
|
||||
} else if ((ec.value() == boost::asio::error::try_again) ||
|
||||
(ec.value() == boost::asio::error::would_block)) {
|
||||
// If we should try again make sure there is no garbage in the
|
||||
// bytes_transferred.
|
||||
bytes_transferred = 0;
|
||||
|
||||
} else {
|
||||
ADD_FAILURE() << "error occurred while connecting: "
|
||||
<< ec.message();
|
||||
io_service_->stop();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the part of the request which has been sent.
|
||||
if (bytes_transferred > 0 && (request.size() <= bytes_transferred)) {
|
||||
request.erase(0, bytes_transferred);
|
||||
}
|
||||
|
||||
// Continue sending request data if there are still some data to be
|
||||
// sent.
|
||||
if (!request.empty()) {
|
||||
sendPartialRequest(request);
|
||||
|
||||
} else {
|
||||
// Request has been sent. Start receiving response.
|
||||
response_.clear();
|
||||
receivePartialResponse();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// @brief Receive response from the server.
|
||||
void receivePartialResponse() {
|
||||
stream_.async_read_some(boost::asio::buffer(buf_.data(), buf_.size()),
|
||||
[this](const boost::system::error_code& ec,
|
||||
std::size_t bytes_transferred) {
|
||||
if (ec) {
|
||||
// IO service stopped so simply return.
|
||||
if (ec.value() == boost::asio::error::operation_aborted) {
|
||||
return;
|
||||
|
||||
} else if ((ec.value() == boost::asio::error::try_again) ||
|
||||
(ec.value() == boost::asio::error::would_block)) {
|
||||
// If we should try again, make sure that there is no garbage
|
||||
// in the bytes_transferred.
|
||||
bytes_transferred = 0;
|
||||
|
||||
} else {
|
||||
// Error occurred, bail...
|
||||
ADD_FAILURE() << "error occurred while receiving HTTP"
|
||||
" response from the server: " << ec.message();
|
||||
io_service_->stop();
|
||||
}
|
||||
}
|
||||
|
||||
if (bytes_transferred > 0) {
|
||||
response_.insert(response_.end(), buf_.data(),
|
||||
buf_.data() + bytes_transferred);
|
||||
}
|
||||
|
||||
// Two consecutive new lines end the part of the response we're
|
||||
// expecting.
|
||||
if (response_.find("\r\n\r\n", 0) != std::string::npos) {
|
||||
io_service_->stop();
|
||||
|
||||
} else {
|
||||
receivePartialResponse();
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
/// @brief Checks if the TCP connection is still open.
|
||||
///
|
||||
/// Tests the TCP connection by trying to read from the socket.
|
||||
/// Unfortunately expected failure depends on a race between the read
|
||||
/// and the other side close so to check if the connection is closed
|
||||
/// please use @c isConnectionClosed instead.
|
||||
///
|
||||
/// @return true if the TCP connection is open.
|
||||
bool isConnectionAlive() {
|
||||
// Remember the current non blocking setting.
|
||||
const bool non_blocking_orig = stream_.lowest_layer().non_blocking();
|
||||
// Set the socket to non blocking mode. We're going to test if the socket
|
||||
// returns would_block status on the attempt to read from it.
|
||||
stream_.lowest_layer().non_blocking(true);
|
||||
|
||||
// We need to provide a buffer for a call to read.
|
||||
char data[2];
|
||||
boost::system::error_code ec;
|
||||
boost::asio::read(stream_, boost::asio::buffer(data, sizeof(data)), ec);
|
||||
|
||||
// Revert the original non_blocking flag on the socket.
|
||||
stream_.lowest_layer().non_blocking(non_blocking_orig);
|
||||
|
||||
// If the connection is alive we'd typically get would_block status code.
|
||||
// If there are any data that haven't been read we may also get success
|
||||
// status. We're guessing that try_again may also be returned by some
|
||||
// implementations in some situations. Any other error code indicates a
|
||||
// problem with the connection so we assume that the connection has been
|
||||
// closed.
|
||||
return (!ec || (ec.value() == boost::asio::error::try_again) ||
|
||||
(ec.value() == boost::asio::error::would_block));
|
||||
}
|
||||
|
||||
/// @brief Checks if the TCP connection is already closed.
|
||||
///
|
||||
/// Tests the TCP connection by trying to read from the socket.
|
||||
/// The read can block so this must be used to check if a connection
|
||||
/// is alive so to check if the connection is alive please always
|
||||
/// use @c isConnectionAlive.
|
||||
///
|
||||
/// @return true if the TCP connection is closed.
|
||||
bool isConnectionClosed() {
|
||||
// Remember the current non blocking setting.
|
||||
const bool non_blocking_orig = stream_.lowest_layer().non_blocking();
|
||||
// Set the socket to blocking mode. We're going to test if the socket
|
||||
// returns eof status on the attempt to read from it.
|
||||
stream_.lowest_layer().non_blocking(false);
|
||||
|
||||
// We need to provide a buffer for a call to read.
|
||||
char data[2];
|
||||
boost::system::error_code ec;
|
||||
boost::asio::read(stream_, boost::asio::buffer(data, sizeof(data)), ec);
|
||||
|
||||
// Revert the original non_blocking flag on the socket.
|
||||
stream_.lowest_layer().non_blocking(non_blocking_orig);
|
||||
|
||||
// If the connection is closed we'd typically get eof or
|
||||
// stream_truncated status code.
|
||||
return ((ec.value() == boost::asio::error::eof) ||
|
||||
(ec.value() == STREAM_TRUNCATED));
|
||||
}
|
||||
|
||||
/// @brief Close connection.
|
||||
void close() {
|
||||
stream_.lowest_layer().close();
|
||||
}
|
||||
|
||||
std::string getResponse() const {
|
||||
return (response_);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/// @brief Holds pointer to the IO service.
|
||||
isc::asiolink::IOServicePtr io_service_;
|
||||
|
||||
/// @brief A socket used for the connection.
|
||||
TlsStreamImpl stream_;
|
||||
|
||||
/// @brief Buffer into which response is written.
|
||||
std::array<char, 8192> buf_;
|
||||
|
||||
/// @brief Response in the textual format.
|
||||
std::string response_;
|
||||
};
|
||||
|
||||
/// @brief Pointer to the TestHttpsClient.
|
||||
typedef boost::shared_ptr<TestHttpsClient> TestHttpsClientPtr;
|
||||
|
||||
/// @brief Test fixture class for @ref HttpListener.
|
||||
class HttpsListenerTest : public ::testing::Test {
|
||||
public:
|
||||
|
@@ -19,8 +19,68 @@
|
||||
using namespace boost::asio::ip;
|
||||
using namespace isc::asiolink;
|
||||
|
||||
/// @brief Common base for test HTTP/HTTPS clients.
|
||||
class BaseTestHttpClient : public boost::noncopyable {
|
||||
public:
|
||||
|
||||
/// @brief Destructor.
|
||||
virtual ~BaseTestHttpClient() = default;
|
||||
|
||||
/// @brief Send HTTP request specified in textual format.
|
||||
///
|
||||
/// @param request HTTP request in the textual format.
|
||||
virtual void startRequest(const std::string& request) = 0;
|
||||
|
||||
/// @brief Send HTTP request.
|
||||
///
|
||||
/// @param request HTTP request in the textual format.
|
||||
virtual void sendRequest(const std::string& request) = 0;
|
||||
|
||||
/// @brief Send part of the HTTP request.
|
||||
///
|
||||
/// @param request part of the HTTP request to be sent.
|
||||
virtual void sendPartialRequest(std::string request) = 0;
|
||||
|
||||
/// @brief Receive response from the server.
|
||||
virtual void receivePartialResponse() = 0;
|
||||
|
||||
/// @brief Checks if the TCP connection is still open.
|
||||
///
|
||||
/// Tests the TCP connection by trying to read from the socket.
|
||||
/// Unfortunately expected failure depends on a race between the read
|
||||
/// and the other side close so to check if the connection is closed
|
||||
/// please use @c isConnectionClosed instead.
|
||||
///
|
||||
/// @return true if the TCP connection is open.
|
||||
virtual bool isConnectionAlive() = 0;
|
||||
|
||||
/// @brief Checks if the TCP connection is already closed.
|
||||
///
|
||||
/// Tests the TCP connection by trying to read from the socket.
|
||||
/// The read can block so this must be used to check if a connection
|
||||
/// is alive so to check if the connection is alive please always
|
||||
/// use @c isConnectionAlive.
|
||||
///
|
||||
/// @return true if the TCP connection is closed.
|
||||
virtual bool isConnectionClosed() = 0;
|
||||
|
||||
/// @brief Close connection.
|
||||
virtual void close() = 0;
|
||||
|
||||
/// @brief Returns the HTTP response string.
|
||||
///
|
||||
/// @return string containing the response.
|
||||
virtual std::string getResponse() const = 0;
|
||||
|
||||
/// @brief Returns true if the receive completed without error.
|
||||
///
|
||||
/// @return True if the receive completed successfully, false
|
||||
/// otherwise.
|
||||
virtual bool receiveDone() const = 0;
|
||||
};
|
||||
|
||||
/// @brief Entity which can connect to the HTTP server endpoint.
|
||||
class TestHttpClient : public boost::noncopyable {
|
||||
class TestHttpClient : public BaseTestHttpClient {
|
||||
public:
|
||||
|
||||
/// @brief Constructor.
|
||||
@@ -42,14 +102,14 @@ public:
|
||||
/// @brief Destructor.
|
||||
///
|
||||
/// Closes the underlying socket if it is open.
|
||||
~TestHttpClient() {
|
||||
virtual ~TestHttpClient() {
|
||||
close();
|
||||
}
|
||||
|
||||
/// @brief Send HTTP request specified in textual format.
|
||||
///
|
||||
/// @param request HTTP request in the textual format.
|
||||
void startRequest(const std::string& request) {
|
||||
virtual void startRequest(const std::string& request) {
|
||||
tcp::endpoint endpoint(address::from_string(server_address_), server_port_);
|
||||
socket_.async_connect(endpoint,
|
||||
[this, request](const boost::system::error_code& ec) {
|
||||
@@ -76,14 +136,14 @@ public:
|
||||
/// @brief Send HTTP request.
|
||||
///
|
||||
/// @param request HTTP request in the textual format.
|
||||
void sendRequest(const std::string& request) {
|
||||
virtual void sendRequest(const std::string& request) {
|
||||
sendPartialRequest(request);
|
||||
}
|
||||
|
||||
/// @brief Send part of the HTTP request.
|
||||
///
|
||||
/// @param request part of the HTTP request to be sent.
|
||||
void sendPartialRequest(std::string request) {
|
||||
virtual void sendPartialRequest(std::string request) {
|
||||
socket_.async_send(boost::asio::buffer(request.data(), request.size()),
|
||||
[this, request](const boost::system::error_code& ec,
|
||||
std::size_t bytes_transferred) mutable {
|
||||
@@ -124,7 +184,7 @@ public:
|
||||
}
|
||||
|
||||
/// @brief Receive response from the server.
|
||||
void receivePartialResponse() {
|
||||
virtual void receivePartialResponse() {
|
||||
socket_.async_read_some(boost::asio::buffer(buf_.data(), buf_.size()),
|
||||
[this](const boost::system::error_code& ec,
|
||||
std::size_t bytes_transferred) {
|
||||
@@ -171,7 +231,7 @@ public:
|
||||
/// please use @c isConnectionClosed instead.
|
||||
///
|
||||
/// @return true if the TCP connection is open.
|
||||
bool isConnectionAlive() {
|
||||
virtual bool isConnectionAlive() {
|
||||
// Remember the current non blocking setting.
|
||||
const bool non_blocking_orig = socket_.non_blocking();
|
||||
// Set the socket to non blocking mode. We're going to test if the socket
|
||||
@@ -204,7 +264,7 @@ public:
|
||||
/// use @c isConnectionAlive.
|
||||
///
|
||||
/// @return true if the TCP connection is closed.
|
||||
bool isConnectionClosed() {
|
||||
virtual bool isConnectionClosed() {
|
||||
// Remember the current non blocking setting.
|
||||
const bool non_blocking_orig = socket_.non_blocking();
|
||||
// Set the socket to blocking mode. We're going to test if the socket
|
||||
@@ -224,14 +284,14 @@ public:
|
||||
}
|
||||
|
||||
/// @brief Close connection.
|
||||
void close() {
|
||||
virtual void close() {
|
||||
socket_.close();
|
||||
}
|
||||
|
||||
/// @brief Returns the HTTP response string.
|
||||
///
|
||||
/// @return string containing the response.
|
||||
std::string getResponse() const {
|
||||
virtual std::string getResponse() const {
|
||||
return (response_);
|
||||
}
|
||||
|
||||
@@ -239,7 +299,7 @@ public:
|
||||
///
|
||||
/// @return True if the receive completed successfully, false
|
||||
/// otherwise.
|
||||
bool receiveDone() {
|
||||
virtual bool receiveDone() const {
|
||||
return (receive_done_);
|
||||
}
|
||||
|
||||
@@ -270,4 +330,268 @@ private:
|
||||
/// @brief Pointer to the TestHttpClient.
|
||||
typedef boost::shared_ptr<TestHttpClient> TestHttpClientPtr;
|
||||
|
||||
/// @brief Entity which can connect to the HTTPS server endpoint.
|
||||
class TestHttpsClient : public boost::noncopyable {
|
||||
public:
|
||||
|
||||
/// @brief Constructor.
|
||||
///
|
||||
/// This constructor creates new socket instance. It doesn't connect. Call
|
||||
/// connect() to connect to the server.
|
||||
///
|
||||
/// @param io_service IO service to be stopped on error.
|
||||
/// @param tls_context TLS context.
|
||||
/// @param server_address string containing the IP address of the server.
|
||||
/// @param port port number of the server.
|
||||
TestHttpsClient(const IOServicePtr& io_service, TlsContextPtr tls_context,
|
||||
const std::string& server_address = "127.0.0.1",
|
||||
uint16_t port = 18123)
|
||||
: io_service_(io_service), stream_(io_service_->getInternalIOService(),
|
||||
tls_context->getContext()), buf_(), response_(),
|
||||
server_address_(server_address), server_port_(port),
|
||||
receive_done_(false) {
|
||||
}
|
||||
|
||||
/// @brief Destructor.
|
||||
///
|
||||
/// Closes the underlying socket if it is open.
|
||||
virtual ~TestHttpsClient() {
|
||||
close();
|
||||
}
|
||||
|
||||
/// @brief Send HTTP request specified in textual format.
|
||||
///
|
||||
/// @param request HTTP request in the textual format.
|
||||
virtual void startRequest(const std::string& request) {
|
||||
tcp::endpoint endpoint(address::from_string(server_address_),
|
||||
server_port_);
|
||||
stream_.lowest_layer().async_connect(endpoint,
|
||||
[this, request](const boost::system::error_code& ec) {
|
||||
receive_done_ = false;
|
||||
if (ec) {
|
||||
// One would expect that async_connect wouldn't return
|
||||
// EINPROGRESS error code, but simply wait for the connection
|
||||
// to get established before the handler is invoked. It turns out,
|
||||
// however, that on some OSes the connect handler may receive this
|
||||
// error code which doesn't necessarily indicate a problem.
|
||||
// Making an attempt to write and read from this socket will
|
||||
// typically succeed. So, we ignore this error.
|
||||
if (ec.value() != boost::asio::error::in_progress) {
|
||||
ADD_FAILURE() << "error occurred while connecting: "
|
||||
<< ec.message();
|
||||
io_service_->stop();
|
||||
return;
|
||||
}
|
||||
}
|
||||
stream_.async_handshake(roleToImpl(TlsRole::CLIENT),
|
||||
[this, request](const boost::system::error_code& ec) {
|
||||
if (ec) {
|
||||
ADD_FAILURE() << "error occurred during handshake: "
|
||||
<< ec.message();
|
||||
io_service_->stop();
|
||||
return;
|
||||
}
|
||||
sendRequest(request);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/// @brief Send HTTP request.
|
||||
///
|
||||
/// @param request HTTP request in the textual format.
|
||||
virtual void sendRequest(const std::string& request) {
|
||||
sendPartialRequest(request);
|
||||
}
|
||||
|
||||
/// @brief Send part of the HTTP request.
|
||||
///
|
||||
/// @param request part of the HTTP request to be sent.
|
||||
virtual void sendPartialRequest(std::string request) {
|
||||
boost::asio::async_write(stream_,
|
||||
boost::asio::buffer(request.data(), request.size()),
|
||||
[this, request](const boost::system::error_code& ec,
|
||||
std::size_t bytes_transferred) mutable {
|
||||
if (ec) {
|
||||
if (ec.value() == boost::asio::error::operation_aborted) {
|
||||
return;
|
||||
|
||||
} else if ((ec.value() == boost::asio::error::try_again) ||
|
||||
(ec.value() == boost::asio::error::would_block)) {
|
||||
// If we should try again make sure there is no garbage in the
|
||||
// bytes_transferred.
|
||||
bytes_transferred = 0;
|
||||
|
||||
} else {
|
||||
ADD_FAILURE() << "error occurred while connecting: "
|
||||
<< ec.message();
|
||||
io_service_->stop();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the part of the request which has been sent.
|
||||
if (bytes_transferred > 0 && (request.size() <= bytes_transferred)) {
|
||||
request.erase(0, bytes_transferred);
|
||||
}
|
||||
|
||||
// Continue sending request data if there are still some data to be
|
||||
// sent.
|
||||
if (!request.empty()) {
|
||||
sendPartialRequest(request);
|
||||
|
||||
} else {
|
||||
// Request has been sent. Start receiving response.
|
||||
response_.clear();
|
||||
receivePartialResponse();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// @brief Receive response from the server.
|
||||
virtual void receivePartialResponse() {
|
||||
stream_.async_read_some(boost::asio::buffer(buf_.data(), buf_.size()),
|
||||
[this](const boost::system::error_code& ec,
|
||||
std::size_t bytes_transferred) {
|
||||
if (ec) {
|
||||
// IO service stopped so simply return.
|
||||
if (ec.value() == boost::asio::error::operation_aborted) {
|
||||
return;
|
||||
|
||||
} else if ((ec.value() == boost::asio::error::try_again) ||
|
||||
(ec.value() == boost::asio::error::would_block)) {
|
||||
// If we should try again, make sure that there is no garbage
|
||||
// in the bytes_transferred.
|
||||
bytes_transferred = 0;
|
||||
|
||||
} else {
|
||||
// Error occurred, bail...
|
||||
ADD_FAILURE() << "error occurred while receiving HTTP"
|
||||
" response from the server: " << ec.message();
|
||||
io_service_->stop();
|
||||
}
|
||||
}
|
||||
|
||||
if (bytes_transferred > 0) {
|
||||
response_.insert(response_.end(), buf_.data(),
|
||||
buf_.data() + bytes_transferred);
|
||||
}
|
||||
|
||||
// Two consecutive new lines end the part of the response we're
|
||||
// expecting.
|
||||
if (response_.find("\r\n\r\n", 0) != std::string::npos) {
|
||||
receive_done_ = true;
|
||||
io_service_->stop();
|
||||
} else {
|
||||
receivePartialResponse();
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
/// @brief Checks if the TCP connection is still open.
|
||||
///
|
||||
/// Tests the TCP connection by trying to read from the socket.
|
||||
/// Unfortunately expected failure depends on a race between the read
|
||||
/// and the other side close so to check if the connection is closed
|
||||
/// please use @c isConnectionClosed instead.
|
||||
///
|
||||
/// @return true if the TCP connection is open.
|
||||
virtual bool isConnectionAlive() {
|
||||
// Remember the current non blocking setting.
|
||||
const bool non_blocking_orig = stream_.lowest_layer().non_blocking();
|
||||
// Set the socket to non blocking mode. We're going to test if the socket
|
||||
// returns would_block status on the attempt to read from it.
|
||||
stream_.lowest_layer().non_blocking(true);
|
||||
|
||||
// We need to provide a buffer for a call to read.
|
||||
char data[2];
|
||||
boost::system::error_code ec;
|
||||
boost::asio::read(stream_, boost::asio::buffer(data, sizeof(data)), ec);
|
||||
|
||||
// Revert the original non_blocking flag on the socket.
|
||||
stream_.lowest_layer().non_blocking(non_blocking_orig);
|
||||
|
||||
// If the connection is alive we'd typically get would_block status code.
|
||||
// If there are any data that haven't been read we may also get success
|
||||
// status. We're guessing that try_again may also be returned by some
|
||||
// implementations in some situations. Any other error code indicates a
|
||||
// problem with the connection so we assume that the connection has been
|
||||
// closed.
|
||||
return (!ec || (ec.value() == boost::asio::error::try_again) ||
|
||||
(ec.value() == boost::asio::error::would_block));
|
||||
}
|
||||
|
||||
/// @brief Checks if the TCP connection is already closed.
|
||||
///
|
||||
/// Tests the TCP connection by trying to read from the socket.
|
||||
/// The read can block so this must be used to check if a connection
|
||||
/// is alive so to check if the connection is alive please always
|
||||
/// use @c isConnectionAlive.
|
||||
///
|
||||
/// @return true if the TCP connection is closed.
|
||||
virtual bool isConnectionClosed() {
|
||||
// Remember the current non blocking setting.
|
||||
const bool non_blocking_orig = stream_.lowest_layer().non_blocking();
|
||||
// Set the socket to blocking mode. We're going to test if the socket
|
||||
// returns eof status on the attempt to read from it.
|
||||
stream_.lowest_layer().non_blocking(false);
|
||||
|
||||
// We need to provide a buffer for a call to read.
|
||||
char data[2];
|
||||
boost::system::error_code ec;
|
||||
boost::asio::read(stream_, boost::asio::buffer(data, sizeof(data)), ec);
|
||||
|
||||
// Revert the original non_blocking flag on the socket.
|
||||
stream_.lowest_layer().non_blocking(non_blocking_orig);
|
||||
|
||||
// If the connection is closed we'd typically get eof or
|
||||
// stream_truncated status code.
|
||||
return ((ec.value() == boost::asio::error::eof) ||
|
||||
(ec.value() == STREAM_TRUNCATED));
|
||||
}
|
||||
|
||||
/// @brief Close connection.
|
||||
virtual void close() {
|
||||
stream_.lowest_layer().close();
|
||||
}
|
||||
|
||||
virtual std::string getResponse() const {
|
||||
return (response_);
|
||||
}
|
||||
|
||||
/// @brief Returns true if the receive completed without error.
|
||||
///
|
||||
/// @return True if the receive completed successfully, false
|
||||
/// otherwise.
|
||||
virtual bool receiveDone() const {
|
||||
return (receive_done_);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/// @brief Holds pointer to the IO service.
|
||||
isc::asiolink::IOServicePtr io_service_;
|
||||
|
||||
/// @brief A socket used for the connection.
|
||||
TlsStreamImpl stream_;
|
||||
|
||||
/// @brief Buffer into which response is written.
|
||||
std::array<char, 8192> buf_;
|
||||
|
||||
/// @brief Response in the textual format.
|
||||
std::string response_;
|
||||
|
||||
/// @brief IP address of the server.
|
||||
std::string server_address_;
|
||||
|
||||
/// @brief IP port of the server.
|
||||
uint16_t server_port_;
|
||||
|
||||
/// @brief Set to true when the receive has completed successfully.
|
||||
bool receive_done_;
|
||||
};
|
||||
|
||||
/// @brief Pointer to the TestHttpsClient.
|
||||
typedef boost::shared_ptr<TestHttpsClient> TestHttpsClientPtr;
|
||||
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user