Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 61 additions & 45 deletions shared/curlException.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,58 +18,74 @@

namespace Curl
{
/**
* @brief Custom exception for Curl wrapper.
*
*/
class CurlException : public std::exception
{
public:
/**
* @brief Returns HTTP response code ID.
*
* @return long HTTP response code ID.
*/
long responseCode() const noexcept
{
return m_responseCode;
}

/**
* @brief Custom exception for Curl wrapper.
* @brief Returns HTTP response body.
*
* @return const std::string& HTTP response body.
*/
class CurlException : public std::exception
const std::string& responseBody() const noexcept
{
public:
/**
* @brief Returns HTTP response code ID.
*
* @return long HTTP response code ID.
*/
long responseCode() const noexcept
{
return m_responseCode;
}
return m_responseBody;
}

/**
* @brief Return error message.
*
* @return const char* Error message.
*/
const char* what() const noexcept override
{
return m_error.what();
}
/**
* @brief Return error message.
*
* @return const char* Error message.
*/
const char* what() const noexcept override
{
return m_error.what();
}

/**
* @brief Construct a new Curl Exception object
*
* @param errorMessage Error message to show.
* @param responseCode HTTP response code ID.
*/
CurlException(const std::string& errorMessage, const long responseCode)
: m_error {errorMessage}
, m_responseCode {responseCode}
{}
/**
* @brief Construct a new Curl Exception object
*
* @param errorMessage Error message to show.
* @param responseCode HTTP response code ID.
* @param responseBody HTTP response body (optional).
*/
CurlException(const std::string& errorMessage, const long responseCode, std::string responseBody = "")
: m_error {errorMessage}
, m_responseCode {responseCode}
, m_responseBody {std::move(responseBody)}
{
}

/**
* @brief Construct a new Curl Exception object
*
* @param curlException Pair object with an error message and a response code ID.
*/
explicit CurlException(const std::pair<const std::string&, const long>& curlException)
: m_error {curlException.first}
, m_responseCode {curlException.second}
{}
/**
* @brief Construct a new Curl Exception object
*
* @param curlException Pair object with an error message and a response code ID.
*/
explicit CurlException(const std::pair<const std::string&, const long>& curlException)
: m_error {curlException.first}
, m_responseCode {curlException.second}
, m_responseBody {}
{
}

private:
std::runtime_error m_error;
const long m_responseCode;
};
}
private:
std::runtime_error m_error;
const long m_responseCode;
const std::string m_responseBody;
};
} // namespace Curl

#endif // _CURL_EXCEPTION_HPP
8 changes: 5 additions & 3 deletions src/curlSingleHandler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
#include <memory>
#include <stdexcept>

constexpr auto NOT_USED {-1};

using deleterCurlHandler = CustomDeleter<decltype(&curl_easy_cleanup), curl_easy_cleanup>;

//! cURLSingleHandler class
Expand Down Expand Up @@ -50,7 +52,7 @@ class cURLSingleHandler final : public ICURLHandler
{
const auto resPerform {curl_easy_perform(m_curlHandler.get())};

long responseCode;
long responseCode = NOT_USED;
const auto resGetInfo {curl_easy_getinfo(m_curlHandler.get(), CURLINFO_RESPONSE_CODE, &responseCode)};

curl_easy_reset(m_curlHandler.get());
Expand All @@ -61,11 +63,11 @@ class cURLSingleHandler final : public ICURLHandler
{
if (resGetInfo != CURLE_OK)
{
throw std::runtime_error("cURLSingleHandler::execute() failed: Couldn't get HTTP response code");
throw Curl::CurlException("cURLSingleHandler::execute() failed", NOT_USED);
}
throw Curl::CurlException(curl_easy_strerror(resPerform), responseCode);
}
throw std::runtime_error(curl_easy_strerror(resPerform));
throw Curl::CurlException(curl_easy_strerror(resPerform), NOT_USED);
}
}
};
Expand Down
18 changes: 16 additions & 2 deletions src/curlWrapper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,12 @@ class cURLWrapper final : public IRequestImplementator

this->setOptionPtr(OPT_WRITEDATA, &m_response);

this->setOptionLong(OPT_FAILONERROR, 1l);
// this->setOptionLong(OPT_FAILONERROR, 1l);

// Note: OPT_FAILONERROR is intentionally NOT set. This option would cause cURL
// to fail automatically on HTTP response codes >= 400, preventing us from
// capturing the response body. We want to allow callers to handle HTTP errors
// with full access to the server's response.

this->setOptionLong(OPT_FOLLOW_REDIRECT, 1l);

Expand Down Expand Up @@ -216,7 +221,16 @@ class cURLWrapper final : public IRequestImplementator
throw std::runtime_error("cURLWrapper::execute() failed: Couldn't set HTTP headers");
}

m_curlHandler->execute();
try
{
m_curlHandler->execute();
}
catch (Curl::CurlException& ex)
{
// Note: m_returnValue contains the response body, even for errors. Could be empty if
// the server didn't send any body.
throw Curl::CurlException(ex.what(), ex.responseCode(), m_response.m_returnValue);
}
}
};

Expand Down
14 changes: 7 additions & 7 deletions test/component/component_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ TEST_F(ComponentTestInterface, DownloadFileError)
},
.outputFile = TEST_FILE_1});

EXPECT_TRUE(m_callbackComplete);
EXPECT_FALSE(m_callbackComplete); //We are not longer considering 4xx as errors that throws an exception
checkEmptyFile(TEST_FILE_1);
}

Expand Down Expand Up @@ -269,7 +269,7 @@ TEST_F(ComponentTestInterface, DownloadFileErrorUsingTheSingleHandler)
.outputFile = TEST_FILE_1},
ConfigurationParameters {.handlerType = CurlHandlerTypeEnum::SINGLE});

EXPECT_TRUE(m_callbackComplete);
EXPECT_FALSE(m_callbackComplete); //We are not longer considering 4xx as errors that throws an exception
checkEmptyFile(TEST_FILE_1);
}

Expand Down Expand Up @@ -383,7 +383,7 @@ TEST_F(ComponentTestInterface, DownloadFileErrorUsingTheMultiHandler)
.outputFile = TEST_FILE_1},
ConfigurationParameters {.handlerType = CurlHandlerTypeEnum::MULTI, .shouldRun = m_shouldRun});

EXPECT_TRUE(m_callbackComplete);
EXPECT_FALSE(m_callbackComplete); //We are not longer considering 4xx as errors that throws an exception
checkEmptyFile(TEST_FILE_1);
}

Expand Down Expand Up @@ -624,7 +624,7 @@ TEST_F(ComponentTestInternalParameters, GetError)
EXPECT_EQ(std::string(ex.what()), "HTTP response code said error");
m_callbackComplete = true;
}
EXPECT_TRUE(m_callbackComplete);
EXPECT_FALSE(m_callbackComplete); //We are not longer considering 4xx as errors that throws an exception
}

/**
Expand All @@ -645,7 +645,7 @@ TEST_F(ComponentTestInternalParameters, PostError)
EXPECT_EQ(std::string(ex.what()), "HTTP response code said error");
m_callbackComplete = true;
}
EXPECT_TRUE(m_callbackComplete);
EXPECT_FALSE(m_callbackComplete); //We are not longer considering 4xx as errors that throws an exception
}

/**
Expand All @@ -666,7 +666,7 @@ TEST_F(ComponentTestInternalParameters, PutError)
EXPECT_EQ(std::string(ex.what()), "HTTP response code said error");
m_callbackComplete = true;
}
EXPECT_TRUE(m_callbackComplete);
EXPECT_FALSE(m_callbackComplete); //We are not longer considering 4xx as errors that throws an exception
}

/**
Expand All @@ -686,7 +686,7 @@ TEST_F(ComponentTestInternalParameters, DeleteError)
EXPECT_EQ(std::string(ex.what()), "HTTP response code said error");
m_callbackComplete = true;
}
EXPECT_TRUE(m_callbackComplete);
EXPECT_FALSE(m_callbackComplete); //We are not longer considering 4xx as errors that throws an exception
}

/**
Expand Down