Skip to content

Commit a1ac23a

Browse files
committed
Merge pull request #1179 from simue/fix/reset-session-content
Add Session::RemoveContent()
1 parent a10c980 commit a1ac23a

File tree

6 files changed

+79
-3
lines changed

6 files changed

+79
-3
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ if(${CMAKE_PROJECT_NAME} STREQUAL ${PROJECT_NAME})
1010
set_property(GLOBAL PROPERTY PREDEFINED_TARGETS_FOLDER "CMake")
1111
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin)
1212
set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/lib)
13+
set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # generate compile_commands.json to be used by other tools (e.g. vs code)
1314
else()
1415
# Check required c++ standard of parent project
1516
if(CMAKE_CXX_STANDARD)

cpr/session.cpp

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,26 @@ void Session::SetLimitRate(const LimitRate& limit_rate) {
262262
curl_easy_setopt(curl_->handle, CURLOPT_MAX_SEND_SPEED_LARGE, limit_rate.uprate);
263263
}
264264

265+
const Content& Session::GetContent() const {
266+
return content_;
267+
}
268+
269+
void Session::RemoveContent() {
270+
// inverse function to prepareBodyPayloadOrMultipart()
271+
if (std::holds_alternative<cpr::Payload>(content_) || std::holds_alternative<cpr::Body>(content_)) {
272+
// set default values, so curl does not send a body in subsequent requests
273+
curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDSIZE_LARGE, -1);
274+
curl_easy_setopt(curl_->handle, CURLOPT_COPYPOSTFIELDS, nullptr);
275+
} else if (std::holds_alternative<cpr::Multipart>(content_)) {
276+
if (curl_->multipart) {
277+
// remove multipart data
278+
curl_mime_free(curl_->multipart);
279+
curl_->multipart = nullptr;
280+
}
281+
}
282+
content_ = std::monostate{};
283+
}
284+
265285
void Session::SetReadCallback(const ReadCallback& read) {
266286
cbs_->readcb_ = read;
267287
curl_easy_setopt(curl_->handle, CURLOPT_INFILESIZE_LARGE, read.size);
@@ -917,7 +937,7 @@ const std::optional<Response> Session::intercept() {
917937
}
918938

919939
void Session::prepareBodyPayloadOrMultipart() const {
920-
// Either a body, multipart or a payload is allowed.
940+
// Either a body, multipart or a payload is allowed. Inverse function to RemoveContent()
921941

922942
if (std::holds_alternative<cpr::Payload>(content_)) {
923943
const std::string payload = std::get<cpr::Payload>(content_).GetContent(*curl_);

include/cpr/session.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
namespace cpr {
4747

4848
using AsyncResponse = AsyncWrapper<Response>;
49+
using Content = std::variant<std::monostate, cpr::Payload, cpr::Body, cpr::Multipart>;
4950

5051
class Interceptor;
5152
class MultiPerform;
@@ -112,6 +113,17 @@ class Session : public std::enable_shared_from_this<Session> {
112113
void SetAcceptEncoding(AcceptEncoding&& accept_encoding);
113114
void SetLimitRate(const LimitRate& limit_rate);
114115

116+
/**
117+
* Returns a reference to the content sent in previous request.
118+
**/
119+
[[nodiscard]] const Content& GetContent() const;
120+
121+
/**
122+
* Removes the content sent in previous request from internal state, so it will not be sent with the next request.
123+
* Call this before doing a request that is specified not to send a body, e.g. GET.
124+
**/
125+
void RemoveContent();
126+
115127
// For cancellable requests
116128
void SetCancellationParam(std::shared_ptr<std::atomic_bool> param);
117129

@@ -237,7 +249,7 @@ class Session : public std::enable_shared_from_this<Session> {
237249

238250

239251
bool chunkedTransferEncoding_{false};
240-
std::variant<std::monostate, cpr::Payload, cpr::Body, cpr::Multipart> content_{std::monostate{}};
252+
Content content_{std::monostate{}};
241253
std::shared_ptr<CurlHolder> curl_;
242254
Url url_;
243255
Parameters parameters_;

test/httpServer.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,18 @@ void HttpServer::OnRequestBasicJson(mg_connection* conn, mg_http_message* /*msg*
272272
}
273273

274274
void HttpServer::OnRequestHeaderReflect(mg_connection* conn, mg_http_message* msg) {
275+
if (std::string_view{msg->method.ptr, msg->method.len} == "GET") {
276+
if (msg->body.len > 0) {
277+
std::string errorMessage{"Bad Request: GET shouldn't contain a body."};
278+
SendError(conn, 400, errorMessage);
279+
return;
280+
} else if (msg->chunk.len > 0) {
281+
std::string errorMessage{"Bad Request: GET shouldn't contain a body."};
282+
SendError(conn, 400, errorMessage);
283+
return;
284+
}
285+
}
286+
275287
std::string response = "Header reflect " + std::string{msg->method.ptr, msg->method.len};
276288
std::string headers;
277289
bool hasContentTypeHeader = false;
@@ -852,6 +864,7 @@ void HttpServer::OnRequestGetDownloadFileLength(mg_connection* conn, mg_http_mes
852864

853865
void HttpServer::OnRequest(mg_connection* conn, mg_http_message* msg) {
854866
std::string uri = std::string(msg->uri.ptr, msg->uri.len);
867+
855868
if (uri == "/") {
856869
OnRequestRoot(conn, msg);
857870
} else if (uri == "/hello.html") {

test/prepare_tests.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ TEST(PrepareTests, MultipleDeleteHeadPutGetPostTest) {
6868
Session session;
6969
for (size_t i = 0; i < 3; ++i) {
7070
{
71+
session.RemoveContent();
7172
session.SetUrl(url);
7273
session.PrepareDelete();
7374
CURLcode curl_result = curl_easy_perform(session.GetCurlHolder()->handle);
@@ -91,6 +92,7 @@ TEST(PrepareTests, MultipleDeleteHeadPutGetPostTest) {
9192
EXPECT_EQ(ErrorCode::OK, response.error.code);
9293
}
9394
{
95+
session.RemoveContent();
9496
session.SetUrl(url);
9597
session.PrepareGet();
9698
CURLcode curl_result = curl_easy_perform(session.GetCurlHolder()->handle);
@@ -118,6 +120,7 @@ TEST(PrepareTests, MultipleDeleteHeadPutGetPostTest) {
118120
EXPECT_EQ(ErrorCode::OK, response.error.code);
119121
}
120122
{
123+
session.RemoveContent();
121124
session.SetUrl(url);
122125
session.PrepareHead();
123126
CURLcode curl_result = curl_easy_perform(session.GetCurlHolder()->handle);

test/session_tests.cpp

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
#include <algorithm>
2+
#include <chrono>
23
#include <cstdint>
34
#include <cstdlib>
45
#include <gtest/gtest.h>
56

6-
#include <chrono>
77
#include <stdexcept>
88
#include <string>
99

@@ -1005,9 +1005,34 @@ TEST(DifferentMethodTests, MultipleDeleteHeadPutGetPostTest) {
10051005
Url url{server->GetBaseUrl() + "/header_reflect.html"};
10061006
Url urlPost{server->GetBaseUrl() + "/post_reflect.html"};
10071007
Url urlPut{server->GetBaseUrl() + "/put.html"};
1008+
Url urlMultipartPost{server->GetBaseUrl() + "/post_file_upload.html"};
10081009
Session session;
10091010
for (size_t i = 0; i < 10; ++i) {
10101011
{
1012+
session.RemoveContent();
1013+
session.SetUrl(url);
1014+
Response response = session.Get();
1015+
std::string expected_text{"Header reflect GET"};
1016+
EXPECT_EQ(expected_text, response.text);
1017+
EXPECT_EQ(url, response.url);
1018+
EXPECT_EQ(200, response.status_code);
1019+
EXPECT_EQ(ErrorCode::OK, response.error.code);
1020+
}
1021+
{
1022+
session.RemoveContent();
1023+
session.SetUrl(urlMultipartPost);
1024+
std::string fileContentsBinary{"this is a binary payload"};
1025+
std::string fileExtension = ".myfile";
1026+
session.SetMultipart(cpr::Multipart{{"files", cpr::Buffer{fileContentsBinary.begin(), fileContentsBinary.end(), "myfile.jpg"}}, {"file_types", "[\"" + fileExtension + "\"]"}});
1027+
Response response = session.Post();
1028+
std::string expected_text{"{\n \"files\": \"myfile.jpg=this is a binary payload\",\n \"file_types\": \"[\".myfile\"]\"\n}"};
1029+
EXPECT_EQ(expected_text, response.text);
1030+
EXPECT_EQ(urlMultipartPost, response.url);
1031+
EXPECT_EQ(201, response.status_code);
1032+
EXPECT_EQ(ErrorCode::OK, response.error.code);
1033+
}
1034+
{
1035+
session.RemoveContent();
10111036
session.SetUrl(url);
10121037
Response response = session.Delete();
10131038
std::string expected_text{"Header reflect DELETE"};
@@ -1027,6 +1052,7 @@ TEST(DifferentMethodTests, MultipleDeleteHeadPutGetPostTest) {
10271052
EXPECT_EQ(ErrorCode::OK, response.error.code);
10281053
}
10291054
{
1055+
session.RemoveContent();
10301056
session.SetUrl(url);
10311057
Response response = session.Get();
10321058
std::string expected_text{"Header reflect GET"};
@@ -1050,6 +1076,7 @@ TEST(DifferentMethodTests, MultipleDeleteHeadPutGetPostTest) {
10501076
EXPECT_EQ(ErrorCode::OK, response.error.code);
10511077
}
10521078
{
1079+
session.RemoveContent();
10531080
session.SetUrl(url);
10541081
Response response = session.Head();
10551082
std::string expected_text{"Header reflect HEAD"};

0 commit comments

Comments
 (0)