Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Session::RemoveContent() #1179

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ if(${CMAKE_PROJECT_NAME} STREQUAL ${PROJECT_NAME})
set_property(GLOBAL PROPERTY PREDEFINED_TARGETS_FOLDER "CMake")
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin)
set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # generate compile_commands.json to be used by other tools (e.g. vs code)
else()
# Check required c++ standard of parent project
if(CMAKE_CXX_STANDARD)
Expand Down
2 changes: 1 addition & 1 deletion cpr/curlholder.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#include "cpr/curlholder.h"
#include "cpr/secure_string.h"
#include <cassert>
#include <curl/curl.h>
#include <curl/easy.h>
#include <string_view>
#include "cpr/secure_string.h"

namespace cpr {
CurlHolder::CurlHolder() {
Expand Down
22 changes: 21 additions & 1 deletion cpr/session.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,26 @@ void Session::SetLimitRate(const LimitRate& limit_rate) {
curl_easy_setopt(curl_->handle, CURLOPT_MAX_SEND_SPEED_LARGE, limit_rate.uprate);
}

const Content& Session::GetContent() const {
return content_;
}

void Session::RemoveContent() {
// inverse function to prepareBodyPayloadOrMultipart()
if (std::holds_alternative<cpr::Payload>(content_) || std::holds_alternative<cpr::Body>(content_)) {
// set default values, so curl does not send a body in subsequent requests
curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDSIZE_LARGE, -1);
curl_easy_setopt(curl_->handle, CURLOPT_COPYPOSTFIELDS, nullptr);
} else if (std::holds_alternative<cpr::Multipart>(content_)) {
if (curl_->multipart) {
// remove multipart data
curl_mime_free(curl_->multipart);
curl_->multipart = nullptr;
}
}
content_ = std::monostate{};
}

void Session::SetReadCallback(const ReadCallback& read) {
cbs_->readcb_ = read;
curl_easy_setopt(curl_->handle, CURLOPT_INFILESIZE_LARGE, read.size);
Expand Down Expand Up @@ -930,7 +950,7 @@ const std::optional<Response> Session::intercept() {
}

void Session::prepareBodyPayloadOrMultipart() const {
// Either a body, multipart or a payload is allowed.
// Either a body, multipart or a payload is allowed. Inverse function to RemoveContent()

if (std::holds_alternative<cpr::Payload>(content_)) {
const std::string payload = std::get<cpr::Payload>(content_).GetContent(*curl_);
Expand Down
14 changes: 13 additions & 1 deletion include/cpr/session.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
namespace cpr {

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

class Interceptor;
class MultiPerform;
Expand Down Expand Up @@ -112,6 +113,17 @@ class Session : public std::enable_shared_from_this<Session> {
void SetAcceptEncoding(AcceptEncoding&& accept_encoding);
void SetLimitRate(const LimitRate& limit_rate);

/**
* Returns a reference to the content sent in previous request.
**/
[[nodiscard]] const Content& GetContent() const;
simue marked this conversation as resolved.
Show resolved Hide resolved

/**
* Removes the content sent in previous request from internal state, so it will not be sent with the next request.
* Call this before doing a request that is specified not to send a body, e.g. GET.
**/
void RemoveContent();

// For cancellable requests
void SetCancellationParam(std::shared_ptr<std::atomic_bool> param);

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


bool chunkedTransferEncoding_{false};
std::variant<std::monostate, cpr::Payload, cpr::Body, cpr::Multipart> content_{std::monostate{}};
Content content_{std::monostate{}};
std::shared_ptr<CurlHolder> curl_;
Url url_;
Parameters parameters_;
Expand Down
13 changes: 13 additions & 0 deletions test/httpServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,18 @@ void HttpServer::OnRequestBasicJson(mg_connection* conn, mg_http_message* /*msg*
}

void HttpServer::OnRequestHeaderReflect(mg_connection* conn, mg_http_message* msg) {
if (std::string_view{msg->method.ptr, msg->method.len} == "GET") {
if (msg->body.len > 0) {
std::string errorMessage{"Bad Request: GET shouldn't contain a body."};
SendError(conn, 400, errorMessage);
return;
} else if (msg->chunk.len > 0) {
std::string errorMessage{"Bad Request: GET shouldn't contain a body."};
SendError(conn, 400, errorMessage);
return;
}
}

std::string response = "Header reflect " + std::string{msg->method.ptr, msg->method.len};
std::string headers;
bool hasContentTypeHeader = false;
Expand Down Expand Up @@ -852,6 +864,7 @@ void HttpServer::OnRequestGetDownloadFileLength(mg_connection* conn, mg_http_mes

void HttpServer::OnRequest(mg_connection* conn, mg_http_message* msg) {
std::string uri = std::string(msg->uri.ptr, msg->uri.len);

if (uri == "/") {
OnRequestRoot(conn, msg);
} else if (uri == "/hello.html") {
Expand Down
3 changes: 3 additions & 0 deletions test/prepare_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ TEST(PrepareTests, MultipleDeleteHeadPutGetPostTest) {
Session session;
for (size_t i = 0; i < 3; ++i) {
{
session.RemoveContent();
session.SetUrl(url);
session.PrepareDelete();
CURLcode curl_result = curl_easy_perform(session.GetCurlHolder()->handle);
Expand All @@ -91,6 +92,7 @@ TEST(PrepareTests, MultipleDeleteHeadPutGetPostTest) {
EXPECT_EQ(ErrorCode::OK, response.error.code);
}
{
session.RemoveContent();
session.SetUrl(url);
session.PrepareGet();
CURLcode curl_result = curl_easy_perform(session.GetCurlHolder()->handle);
Expand Down Expand Up @@ -118,6 +120,7 @@ TEST(PrepareTests, MultipleDeleteHeadPutGetPostTest) {
EXPECT_EQ(ErrorCode::OK, response.error.code);
}
{
session.RemoveContent();
session.SetUrl(url);
session.PrepareHead();
CURLcode curl_result = curl_easy_perform(session.GetCurlHolder()->handle);
Expand Down
29 changes: 28 additions & 1 deletion test/session_tests.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#include <algorithm>
#include <chrono>
#include <cstdint>
#include <cstdlib>
#include <gtest/gtest.h>

#include <chrono>
#include <stdexcept>
#include <string>

Expand Down Expand Up @@ -1005,9 +1005,34 @@ TEST(DifferentMethodTests, MultipleDeleteHeadPutGetPostTest) {
Url url{server->GetBaseUrl() + "/header_reflect.html"};
Url urlPost{server->GetBaseUrl() + "/post_reflect.html"};
Url urlPut{server->GetBaseUrl() + "/put.html"};
Url urlMultipartPost{server->GetBaseUrl() + "/post_file_upload.html"};
Session session;
for (size_t i = 0; i < 10; ++i) {
{
session.RemoveContent();
session.SetUrl(url);
Response response = session.Get();
std::string expected_text{"Header reflect GET"};
EXPECT_EQ(expected_text, response.text);
EXPECT_EQ(url, response.url);
EXPECT_EQ(200, response.status_code);
EXPECT_EQ(ErrorCode::OK, response.error.code);
}
{
session.RemoveContent();
session.SetUrl(urlMultipartPost);
std::string fileContentsBinary{"this is a binary payload"};
std::string fileExtension = ".myfile";
session.SetMultipart(cpr::Multipart{{"files", cpr::Buffer{fileContentsBinary.begin(), fileContentsBinary.end(), "myfile.jpg"}}, {"file_types", "[\"" + fileExtension + "\"]"}});
Response response = session.Post();
std::string expected_text{"{\n \"files\": \"myfile.jpg=this is a binary payload\",\n \"file_types\": \"[\".myfile\"]\"\n}"};
EXPECT_EQ(expected_text, response.text);
EXPECT_EQ(urlMultipartPost, response.url);
EXPECT_EQ(201, response.status_code);
EXPECT_EQ(ErrorCode::OK, response.error.code);
}
{
session.RemoveContent();
session.SetUrl(url);
Response response = session.Delete();
std::string expected_text{"Header reflect DELETE"};
Expand All @@ -1027,6 +1052,7 @@ TEST(DifferentMethodTests, MultipleDeleteHeadPutGetPostTest) {
EXPECT_EQ(ErrorCode::OK, response.error.code);
}
{
session.RemoveContent();
session.SetUrl(url);
Response response = session.Get();
std::string expected_text{"Header reflect GET"};
Expand All @@ -1050,6 +1076,7 @@ TEST(DifferentMethodTests, MultipleDeleteHeadPutGetPostTest) {
EXPECT_EQ(ErrorCode::OK, response.error.code);
}
{
session.RemoveContent();
session.SetUrl(url);
Response response = session.Head();
std::string expected_text{"Header reflect HEAD"};
Expand Down
Loading