Skip to content

Commit

Permalink
Add method SetAcceptEncoding for customized Accept-Encoding header (#683
Browse files Browse the repository at this point in the history
)
  • Loading branch information
leviliangtw committed Jun 2, 2022
1 parent 2157a31 commit be9ece6
Show file tree
Hide file tree
Showing 10 changed files with 168 additions and 3 deletions.
1 change: 1 addition & 0 deletions cpr/CMakeLists.txt
@@ -1,6 +1,7 @@
cmake_minimum_required(VERSION 3.15)

add_library(cpr
accept_encoding.cpp
async.cpp
auth.cpp
bearer.cpp
Expand Down
25 changes: 25 additions & 0 deletions cpr/accept_encoding.cpp
@@ -0,0 +1,25 @@
#include "cpr/accept_encoding.h"

#include <algorithm>
#include <iterator>
#include <numeric>

namespace cpr {

AcceptEncoding::AcceptEncoding(const std::initializer_list<AcceptEncodingMethods>& methods) {
methods_.clear();
std::transform(methods.begin(), methods.end(), std::back_inserter(methods_), [&](cpr::AcceptEncodingMethods method) { return cpr::AcceptEncodingMethodsStringMap.at(method); });
}

AcceptEncoding::AcceptEncoding(const std::initializer_list<std::string>& string_methods) : methods_{string_methods} {}

bool AcceptEncoding::empty() const noexcept {
return methods_.empty();
}

const std::string AcceptEncoding::getString() const {
std::string methodsString = std::accumulate(std::next(methods_.begin()), methods_.end(), methods_[0], [](std::string a, std::string b) { return std::move(a) + ", " + std::move(b); });
return methodsString;
}

} // namespace cpr
24 changes: 22 additions & 2 deletions cpr/session.cpp
Expand Up @@ -76,6 +76,8 @@ class Session::Impl {
void SetRange(const Range& range);
void SetMultiRange(const MultiRange& multi_range);
void SetReserveSize(const ReserveSize& reserve_size);
void SetAcceptEncoding(AcceptEncoding&& accept_encoding);
void SetAcceptEncoding(const AcceptEncoding& accept_encoding);

cpr_off_t GetDownloadFileLength();
void ResponseStringReserve(size_t size);
Expand Down Expand Up @@ -115,6 +117,7 @@ class Session::Impl {
Proxies proxies_;
ProxyAuthentication proxyAuth_;
Header header_;
AcceptEncoding acceptEncoding_;
/**
* Will be set by the read callback.
* Ensures that the "Transfer-Encoding" is set to "chunked", if not overriden in header_.
Expand Down Expand Up @@ -600,6 +603,14 @@ void Session::Impl::SetReserveSize(const ReserveSize& reserve_size) {
ResponseStringReserve(reserve_size.size);
}

void Session::Impl::SetAcceptEncoding(const AcceptEncoding& accept_encoding) {
acceptEncoding_ = accept_encoding;
}

void Session::Impl::SetAcceptEncoding(AcceptEncoding&& accept_encoding) {
acceptEncoding_ = std::move(accept_encoding);
}

void Session::Impl::PrepareDelete() {
curl_easy_setopt(curl_->handle, CURLOPT_HTTPGET, 0L);
curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L);
Expand Down Expand Up @@ -830,8 +841,13 @@ void Session::Impl::prepareCommon() {

#if LIBCURL_VERSION_MAJOR >= 7
#if LIBCURL_VERSION_MINOR >= 21
/* enable all supported built-in compressions */
curl_easy_setopt(curl_->handle, CURLOPT_ACCEPT_ENCODING, "");
if (acceptEncoding_.empty()) {
/* enable all supported built-in compressions */
curl_easy_setopt(curl_->handle, CURLOPT_ACCEPT_ENCODING, "");
}
else {
curl_easy_setopt(curl_->handle, CURLOPT_ACCEPT_ENCODING, acceptEncoding_.getString().c_str());
}
#endif
#endif

Expand Down Expand Up @@ -934,6 +950,8 @@ void Session::SetHttpVersion(const HttpVersion& version) { pimpl_->SetHttpVersio
void Session::SetRange(const Range& range) { pimpl_->SetRange(range); }
void Session::SetMultiRange(const MultiRange& multi_range) { pimpl_->SetMultiRange(multi_range); }
void Session::SetReserveSize(const ReserveSize& reserve_size) { pimpl_->SetReserveSize(reserve_size); }
void Session::SetAcceptEncoding(const AcceptEncoding& accept_encoding) { pimpl_->SetAcceptEncoding(accept_encoding); }
void Session::SetAcceptEncoding(AcceptEncoding&& accept_encoding) { pimpl_->SetAcceptEncoding(std::move(accept_encoding)); }
void Session::SetOption(const ReadCallback& read) { pimpl_->SetReadCallback(read); }
void Session::SetOption(const HeaderCallback& header) { pimpl_->SetHeaderCallback(header); }
void Session::SetOption(const WriteCallback& write) { pimpl_->SetWriteCallback(write); }
Expand Down Expand Up @@ -977,6 +995,8 @@ void Session::SetOption(const HttpVersion& version) { pimpl_->SetHttpVersion(ver
void Session::SetOption(const Range& range) { pimpl_->SetRange(range); }
void Session::SetOption(const MultiRange& multi_range) { pimpl_->SetMultiRange(multi_range); }
void Session::SetOption(const ReserveSize& reserve_size) { pimpl_->SetReserveSize(reserve_size.size); }
void Session::SetOption(const AcceptEncoding& accept_encoding) { pimpl_->SetAcceptEncoding(accept_encoding); }
void Session::SetOption(AcceptEncoding&& accept_encoding) { pimpl_->SetAcceptEncoding(std::move(accept_encoding)); }

cpr_off_t Session::GetDownloadFileLength() { return pimpl_->GetDownloadFileLength(); }
void Session::ResponseStringReserve(size_t size) { pimpl_->ResponseStringReserve(size); }
Expand Down
1 change: 1 addition & 0 deletions include/CMakeLists.txt
Expand Up @@ -7,6 +7,7 @@ target_include_directories(cpr PUBLIC

target_sources(cpr PRIVATE
# Header files (useful in IDEs)
cpr/accept_encoding.h
cpr/api.h
cpr/async.h
cpr/auth.h
Expand Down
36 changes: 36 additions & 0 deletions include/cpr/accept_encoding.h
@@ -0,0 +1,36 @@
#ifndef CPR_ACCEPT_ENCODING_H
#define CPR_ACCEPT_ENCODING_H

#include <curl/curlver.h>
#include <initializer_list>
#include <map>
#include <string>
#include <vector>

namespace cpr {

enum class AcceptEncodingMethods {
identity,
deflate,
zlib,
gzip,
};

static const std::map<AcceptEncodingMethods, std::string> AcceptEncodingMethodsStringMap{{AcceptEncodingMethods::identity, "identity"}, {AcceptEncodingMethods::deflate, "deflate"}, {AcceptEncodingMethods::zlib, "zlib"}, {AcceptEncodingMethods::gzip, "gzip"}};

class AcceptEncoding {
public:
AcceptEncoding() = default;
AcceptEncoding(const std::initializer_list<AcceptEncodingMethods>& methods);
AcceptEncoding(const std::initializer_list<std::string>& methods);

bool empty() const noexcept;
const std::string getString() const;

private:
std::vector<std::string> methods_;
};

} // namespace cpr

#endif
5 changes: 5 additions & 0 deletions include/cpr/session.h
Expand Up @@ -13,6 +13,7 @@
#include "cpr/cookies.h"
#include "cpr/cprtypes.h"
#include "cpr/curlholder.h"
#include "cpr/accept_encoding.h"
#include "cpr/http_version.h"
#include "cpr/interface.h"
#include "cpr/limit_rate.h"
Expand Down Expand Up @@ -87,6 +88,8 @@ class Session {
void SetRange(const Range& range);
void SetMultiRange(const MultiRange& multi_range);
void SetReserveSize(const ReserveSize& reserve_size);
void SetAcceptEncoding(const AcceptEncoding& accept_encoding);
void SetAcceptEncoding(AcceptEncoding&& accept_encoding);

// Used in templated functions
void SetOption(const Url& url);
Expand Down Expand Up @@ -132,6 +135,8 @@ class Session {
void SetOption(const Range& range);
void SetOption(const MultiRange& multi_range);
void SetOption(const ReserveSize& reserve_size);
void SetOption(const AcceptEncoding& accept_encoding);
void SetOption(AcceptEncoding&& accept_encoding);

cpr_off_t GetDownloadFileLength();
/**
Expand Down
2 changes: 1 addition & 1 deletion test/abstractServer.cpp
Expand Up @@ -105,7 +105,7 @@ std::string AbstractServer::Base64Decode(const std::string& in) {
break;
}
// NOLINTNEXTLINE (cppcoreguidelines-avoid-magic-numbers)
val = (val << 6) + T[c];
val = (static_cast<uint>(val) << static_cast<uint>(6)) + T[c];
// NOLINTNEXTLINE (cppcoreguidelines-avoid-magic-numbers)
valb += 6;
if (valb >= 0) {
Expand Down
18 changes: 18 additions & 0 deletions test/httpServer.cpp
Expand Up @@ -756,6 +756,22 @@ void HttpServer::OnRequestDownloadGzip(mg_connection* conn, http_message* msg) {
}
}

void HttpServer::OnRequestCheckAcceptEncoding(mg_connection* conn, http_message* msg) {
std::string response;
for (size_t i = 0; i < sizeof(msg->header_names) / sizeof(mg_str); i++) {
if (!msg->header_names[i].p) {
continue;
}
std::string name = std::string(msg->header_names[i].p, msg->header_names[i].len);
if (std::string{"Accept-Encoding"} == name) {
response = std::string(msg->header_values[i].p, msg->header_values[i].len);
}
}
std::string headers = "Content-Type: text/html";
mg_send_head(conn, 200, response.length(), headers.c_str());
mg_send(conn, response.c_str(), response.length());
}

void HttpServer::OnRequest(mg_connection* conn, http_message* msg) {
std::string uri = std::string(msg->uri.p, msg->uri.len);
if (uri == "/") {
Expand Down Expand Up @@ -822,6 +838,8 @@ void HttpServer::OnRequest(mg_connection* conn, http_message* msg) {
OnRequestDownloadGzip(conn, msg);
} else if (uri == "/local_port.html") {
OnRequestLocalPort(conn, msg);
} else if (uri == "/check_accept_encoding.html") {
OnRequestCheckAcceptEncoding(conn, msg);
} else {
OnRequestNotFound(conn, msg);
}
Expand Down
1 change: 1 addition & 0 deletions test/httpServer.hpp
Expand Up @@ -52,6 +52,7 @@ class HttpServer : public AbstractServer {
static void OnRequestPatchNotAllowed(mg_connection* conn, http_message* msg);
static void OnRequestDownloadGzip(mg_connection* conn, http_message* msg);
static void OnRequestLocalPort(mg_connection* conn, http_message* msg);
static void OnRequestCheckAcceptEncoding(mg_connection* conn, http_message* msg);

protected:
mg_connection* initServer(mg_mgr* mgr, MG_CB(mg_event_handler_t event_handler, void* user_data)) override;
Expand Down
58 changes: 58 additions & 0 deletions test/session_tests.cpp
Expand Up @@ -1004,6 +1004,64 @@ TEST(BasicTests, ReserveResponseString) {
EXPECT_EQ(ErrorCode::OK, response.error.code);
}

TEST(BasicTests, AcceptEncodingTestWithMethodsStringMap) {
Url url{server->GetBaseUrl() + "/check_accept_encoding.html"};
Session session;
session.SetUrl(url);
session.SetAcceptEncoding({{AcceptEncodingMethods::deflate, AcceptEncodingMethods::gzip, AcceptEncodingMethods::zlib}});
Response response = session.Get();
std::string expected_text{"deflate, gzip, zlib"};
EXPECT_EQ(expected_text, response.text);
EXPECT_EQ(url, response.url);
EXPECT_EQ(std::string{"text/html"}, response.header["content-type"]);
EXPECT_EQ(200, response.status_code);
EXPECT_EQ(ErrorCode::OK, response.error.code);
}

TEST(BasicTests, AcceptEncodingTestWithMethodsStringMapLValue) {
Url url{server->GetBaseUrl() + "/check_accept_encoding.html"};
Session session;
session.SetUrl(url);
AcceptEncoding accept_encoding{{AcceptEncodingMethods::deflate, AcceptEncodingMethods::gzip, AcceptEncodingMethods::zlib}};
session.SetAcceptEncoding(accept_encoding);
Response response = session.Get();
std::string expected_text{"deflate, gzip, zlib"};
EXPECT_EQ(expected_text, response.text);
EXPECT_EQ(url, response.url);
EXPECT_EQ(std::string{"text/html"}, response.header["content-type"]);
EXPECT_EQ(200, response.status_code);
EXPECT_EQ(ErrorCode::OK, response.error.code);
}

TEST(BasicTests, AcceptEncodingTestWithCostomizedString) {
Url url{server->GetBaseUrl() + "/check_accept_encoding.html"};
Session session;
session.SetUrl(url);
session.SetAcceptEncoding({{"deflate", "gzip", "zlib"}});
Response response = session.Get();
std::string expected_text{"deflate, gzip, zlib"};
EXPECT_EQ(expected_text, response.text);
EXPECT_EQ(url, response.url);
EXPECT_EQ(std::string{"text/html"}, response.header["content-type"]);
EXPECT_EQ(200, response.status_code);
EXPECT_EQ(ErrorCode::OK, response.error.code);
}

TEST(BasicTests, AcceptEncodingTestWithCostomizedStringLValue) {
Url url{server->GetBaseUrl() + "/check_accept_encoding.html"};
Session session;
session.SetUrl(url);
AcceptEncoding accept_encoding{{"deflate", "gzip", "zlib"}};
session.SetAcceptEncoding(accept_encoding);
Response response = session.Get();
std::string expected_text{"deflate, gzip, zlib"};
EXPECT_EQ(expected_text, response.text);
EXPECT_EQ(url, response.url);
EXPECT_EQ(std::string{"text/html"}, response.header["content-type"]);
EXPECT_EQ(200, response.status_code);
EXPECT_EQ(ErrorCode::OK, response.error.code);
}

int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
::testing::AddGlobalTestEnvironment(server);
Expand Down

0 comments on commit be9ece6

Please sign in to comment.