diff --git a/README.md b/README.md index ad7b1c10..ab5a12d7 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,25 @@ RestClient::Response r = RestClient::put("http://url.com/put", "application/json RestClient::Response r = RestClient::patch("http://url.com/patch", "application/json", "{\"foo\": \"bla\"}") RestClient::Response r = RestClient::del("http://url.com/delete") RestClient::Response r = RestClient::head("http://url.com") + +// Post Form Upload +/* Filling information about the form in a RestClient::PostFormInfo object */ +RestClient::PostFormInfo uploadInfo; +/* "submitted" is the name of the "file" input and "TestPostForm.txt" +is the location of the file to submit. + +*/ +uploadInfo.addFormFile("submitted", "TestPostForm.txt"); +/* In some rare cases, some fields related to the form can be filled with +addFormContent(), the 1st argument is the name of the input element and +the 2nd argument is the value assigned to it. + + +*/ +uploadInfo.addFormContent("filename", "myfile.cpp"); +uploadInfo.addFormContent("submit", "send"); +/* Performing a post form upload with the information provided above */ +RestClient::Response res = RestClient::postForm("http://posttestserver.com/post.php?dir=restclientcpptests", uploadInfo); RestClient::Response r = RestClient::options("http://url.com") ``` diff --git a/include/restclient-cpp/connection.h b/include/restclient-cpp/connection.h index df3423fb..7f512739 100644 --- a/include/restclient-cpp/connection.h +++ b/include/restclient-cpp/connection.h @@ -188,6 +188,8 @@ class Connection { RestClient::Response get(const std::string& uri); RestClient::Response post(const std::string& uri, const std::string& data); + RestClient::Response postForm(const std::string& uri, + const PostFormInfo& data); RestClient::Response put(const std::string& uri, const std::string& data); RestClient::Response patch(const std::string& uri, diff --git a/include/restclient-cpp/helpers.h b/include/restclient-cpp/helpers.h index 9078a267..035dbc85 100644 --- a/include/restclient-cpp/helpers.h +++ b/include/restclient-cpp/helpers.h @@ -9,6 +9,8 @@ #ifndef INCLUDE_RESTCLIENT_CPP_HELPERS_H_ #define INCLUDE_RESTCLIENT_CPP_HELPERS_H_ +#include + #include #include #include diff --git a/include/restclient-cpp/restclient.h b/include/restclient-cpp/restclient.h index a5542b2d..15297bc9 100644 --- a/include/restclient-cpp/restclient.h +++ b/include/restclient-cpp/restclient.h @@ -13,6 +13,7 @@ #include #include +#include "restclient-cpp/helpers.h" #include "restclient-cpp/version.h" /** @@ -40,6 +41,26 @@ typedef struct { HeaderFields headers; } Response; +/** @class PostFormInfo + * @brief This class represents the form information to send on + * POST Form requests + */ +class PostFormInfo { + struct curl_httppost* formPtr; + struct curl_httppost* lastFormPtr; + public: + PostFormInfo(); + ~PostFormInfo(); + /* Fill in the file upload field */ + void addFormFile(const std::string& fieldName, + const std::string& fieldValue); + /* Fill in the filename or the submit field */ + void addFormContent(const std::string& fieldName, + const std::string& fieldValue); + /* Get Form pointer */ + struct curl_httppost* GetFormPtr() const { return formPtr; } +}; + // init and disable functions int init(); void disable(); @@ -53,6 +74,8 @@ Response get(const std::string& url); Response post(const std::string& url, const std::string& content_type, const std::string& data); +Response postForm(const std::string& url, + const PostFormInfo& data); Response put(const std::string& url, const std::string& content_type, const std::string& data); diff --git a/source/connection.cc b/source/connection.cc index bcdd53ca..195d6b1f 100644 --- a/source/connection.cc +++ b/source/connection.cc @@ -470,6 +470,26 @@ RestClient::Connection::post(const std::string& url, return this->performCurlRequest(url); } +/** + * @brief HTTP POST Form method + * + * @param url to query + * @param data form info + * + * @return response struct + */ +RestClient::Response +RestClient::Connection::postForm(const std::string& url, + const PostFormInfo& data) { + /** Now specify we want to POST data */ + curl_easy_setopt(this->curlHandle, CURLOPT_POST, 1L); + /* stating that Expect: 100-continue is not wanted */ + AppendHeader("Expect", ""); + /** set post form */ + curl_easy_setopt(this->curlHandle, CURLOPT_HTTPPOST, data.GetFormPtr()); + + return this->performCurlRequest(url); +} /** * @brief HTTP PUT method * diff --git a/source/helpers.cc b/source/helpers.cc index aa51bf58..eb62cac5 100644 --- a/source/helpers.cc +++ b/source/helpers.cc @@ -36,6 +36,7 @@ size_t RestClient::Helpers::write_callback(void *data, size_t size, * @param size of data * @param nmemb memblock * @param userdata pointer to user data object to save headr data + * * @return size * nmemb; */ size_t RestClient::Helpers::header_callback(void *data, size_t size, diff --git a/source/restclient.cc b/source/restclient.cc index ed0fe861..e0d6bca7 100644 --- a/source/restclient.cc +++ b/source/restclient.cc @@ -87,6 +87,23 @@ RestClient::Response RestClient::post(const std::string& url, #endif } +/** + * @brief HTTP POST Form method + * + * @param url to query + * @param data post form information + * + * @return response struct + */ +RestClient::Response RestClient::postForm(const std::string& url, + const PostFormInfo& data) { + RestClient::Response ret; + RestClient::Connection *conn = new RestClient::Connection(""); + ret = conn->postForm(url, data); + delete conn; + return ret; +} + /** * @brief HTTP PUT method * @@ -187,3 +204,51 @@ RestClient::Response RestClient::options(const std::string& url) { delete conn; return ret; } + +/** + * @brief PostFormInfo constructor + */ +RestClient::PostFormInfo::PostFormInfo() + : formPtr(NULL), lastFormPtr(NULL) { +} + +/** + * @brief PostFormInfo destructor + */ +RestClient::PostFormInfo::~PostFormInfo() { + // cleanup the formpost chain + if (this->formPtr) { + curl_formfree(this->formPtr); + this->formPtr = NULL; + this->lastFormPtr = NULL; + } +} + +/** + * @brief set the name and the value of the HTML "file" form's input + * + * @param fieldName name of the "file" input + * @param fieldValue path to the file to upload + */ +void RestClient::PostFormInfo::addFormFile( + const std::string& fieldName, const std::string& fieldValue) { + curl_formadd(&this->formPtr, &this->lastFormPtr, + CURLFORM_COPYNAME, fieldName.c_str(), + CURLFORM_FILE, fieldValue.c_str(), + CURLFORM_END); +} + +/** + * @brief set the name and the value of an HTML form's input + * (other than "file" like "text", "hidden" or "submit") + * + * @param fieldName name of the input element + * @param fieldValue value to be assigned to the input element + */ +void RestClient::PostFormInfo::addFormContent( + const std::string& fieldName, const std::string& fieldValue) { + curl_formadd(&this->formPtr, &this->lastFormPtr, + CURLFORM_COPYNAME, fieldName.c_str(), + CURLFORM_COPYCONTENTS, fieldValue.c_str(), + CURLFORM_END); +} diff --git a/test/test_restclient.cc b/test/test_restclient.cc index e25cad6e..45cc013c 100644 --- a/test/test_restclient.cc +++ b/test/test_restclient.cc @@ -1,7 +1,10 @@ #include "restclient-cpp/restclient.h" #include #include +#include +#include #include +#include class RestClientTest : public ::testing::Test { @@ -118,6 +121,37 @@ TEST_F(RestClientTest, TestRestClientPOSTBody) EXPECT_EQ("restclient-cpp/" RESTCLIENT_VERSION, root["headers"].get("User-Agent", "no url set").asString()); } +TEST_F(RestClientTest, TestRestClientPostForm) +{ + // generating a file name with a timestamp + std::ostringstream fileName; + time_t rawtime; + tm * timeinfo; + time(&rawtime); + timeinfo = localtime( &rawtime ); + + fileName << "TestPostForm_" << (timeinfo->tm_year)+1900 << "_" << timeinfo->tm_mon+1 + << "_" << timeinfo->tm_mday << "-" << timeinfo->tm_hour + << "_"<< timeinfo->tm_min << "_" << timeinfo->tm_sec << ".txt"; + + // creating a dummy file to upload via a post form request + std::ofstream ofDummyFile(fileName.str().c_str()); + ASSERT_TRUE(static_cast(ofDummyFile)); + ofDummyFile << "Dummy file for the unit test 'TestRestClientPostForm' of the restclient-cpp Project."; + ASSERT_TRUE(static_cast(ofDummyFile)); + ofDummyFile.close(); + + // uploading the dummy file + RestClient::PostFormInfo UploadInfo; + UploadInfo.addFormFile("submitted", fileName.str()); + UploadInfo.addFormContent("filename", fileName.str()); + RestClient::Response res = RestClient::postForm("http://posttestserver.com/post.php?dir=restclientcpptests", UploadInfo); + EXPECT_EQ(200, res.code); + + // remove dummy file + remove(fileName.str().c_str()); +} + // check for failure TEST_F(RestClientTest, TestRestClientPOSTFailureCode) {