Skip to content

Commit 5b96edd

Browse files
committed
Added a method to perform a post form upload.
Fixed code indentation to comply with Cpplint. Added web proxy tunneling support. this adds support for using proxies corresponding to the CURLOPT_PROXY and CURLOPT_HTTPPROXYTUNNEL config options in libcurl. closes mrtazz#68 default to 10s timeout in unit tests this makes the conn object in unit tests default to a 10s timeout in order to fail fast if something is up with the connection or configured hosts.
1 parent 934aff7 commit 5b96edd

File tree

9 files changed

+165
-0
lines changed

9 files changed

+165
-0
lines changed

README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,25 @@ RestClient::Response r = RestClient::post("http://url.com/post", "text/json", "{
2828
RestClient::Response r = RestClient::put("http://url.com/put", "text/json", "{\"foo\": \"bla\"}")
2929
RestClient::Response r = RestClient::del("http://url.com/delete")
3030
RestClient::Response r = RestClient::head("http://url.com")
31+
32+
// Post Form Upload
33+
/* Filling information about the form in a Helpers::PostFormInfo object */
34+
Helpers::PostFormInfo uploadInfo;
35+
/* "submitted" is the name of the "file" input and "TestPostForm.txt"
36+
is the location of the file to submit.
37+
<input type="file" name="submitted">
38+
*/
39+
uploadInfo.addFormFile("submitted", "TestPostForm.txt");
40+
/* In some rare cases, some fields related to the form can be filled with
41+
addFormContent(), the 1st argument is the name of the input element and
42+
the 2nd argument is the value assigned to it.
43+
<input type="text" name="filename" value=""/>
44+
<input type="submit" name="submit" value="send">
45+
*/
46+
uploadInfo.addFormContent("filename", "myfile.cpp");
47+
uploadInfo.addFormContent("submit", "send");
48+
/* Performing a post form upload with the information provided above */
49+
RestClient::Response res = RestClient::postForm("http://posttestserver.com/post.php?dir=restclientcpptests", uploadInfo);
3150
```
3251

3352
The response is of type [RestClient::Response][restclient_response] and has

include/restclient-cpp/connection.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,8 @@ class Connection {
180180
RestClient::Response get(const std::string& uri);
181181
RestClient::Response post(const std::string& uri,
182182
const std::string& data);
183+
RestClient::Response postForm(const std::string& uri,
184+
const Helpers::PostFormInfo& data);
183185
RestClient::Response put(const std::string& uri,
184186
const std::string& data);
185187
RestClient::Response del(const std::string& uri);

include/restclient-cpp/helpers.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
#ifndef INCLUDE_RESTCLIENT_CPP_HELPERS_H_
1010
#define INCLUDE_RESTCLIENT_CPP_HELPERS_H_
1111

12+
#include <curl/curl.h>
13+
1214
#include <string>
1315
#include <algorithm>
1416
#include <functional>
@@ -25,6 +27,24 @@ namespace RestClient {
2527
*/
2628
namespace Helpers {
2729

30+
/** @struct PostFormInfo
31+
* @brief This struct represents the form information to send on
32+
* POST Form requests
33+
*/
34+
struct PostFormInfo {
35+
PostFormInfo();
36+
~PostFormInfo();
37+
/* Fill in the file upload field */
38+
void addFormFile(const std::string& fieldName,
39+
const std::string& fieldValue);
40+
/* Fill in the filename or the submit field */
41+
void addFormContent(const std::string& fieldName,
42+
const std::string& fieldValue);
43+
44+
struct curl_httppost* formPtr;
45+
struct curl_httppost* lastFormPtr;
46+
};
47+
2848
/** @struct UploadObject
2949
* @brief This structure represents the payload to upload on POST
3050
* requests

include/restclient-cpp/restclient.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <map>
1515
#include <cstdlib>
1616

17+
#include "restclient-cpp/helpers.h"
1718
#include "restclient-cpp/version.h"
1819

1920
/**
@@ -54,6 +55,8 @@ Response get(const std::string& url);
5455
Response post(const std::string& url,
5556
const std::string& content_type,
5657
const std::string& data);
58+
Response postForm(const std::string& url,
59+
const RestClient::Helpers::PostFormInfo& data);
5760
Response put(const std::string& url,
5861
const std::string& content_type,
5962
const std::string& data);

source/connection.cc

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,26 @@ RestClient::Connection::post(const std::string& url,
448448

449449
return this->performCurlRequest(url);
450450
}
451+
/**
452+
* @brief HTTP POST Form method
453+
*
454+
* @param url to query
455+
* @param data form info
456+
*
457+
* @return response struct
458+
*/
459+
RestClient::Response
460+
RestClient::Connection::postForm(const std::string& url,
461+
const Helpers::PostFormInfo& data) {
462+
/** Now specify we want to POST data */
463+
curl_easy_setopt(this->curlHandle, CURLOPT_POST, 1L);
464+
/* stating that Expect: 100-continue is not wanted */
465+
AppendHeader("Expect", "");
466+
/** set post form */
467+
curl_easy_setopt(this->curlHandle, CURLOPT_HTTPPOST, data.formPtr);
468+
469+
return this->performCurlRequest(url);
470+
}
451471
/**
452472
* @brief HTTP PUT method
453473
*

source/helpers.cc

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ size_t RestClient::Helpers::write_callback(void *data, size_t size,
3636
* @param size of data
3737
* @param nmemb memblock
3838
* @param userdata pointer to user data object to save headr data
39+
*
3940
* @return size * nmemb;
4041
*/
4142
size_t RestClient::Helpers::header_callback(void *data, size_t size,
@@ -88,3 +89,51 @@ size_t RestClient::Helpers::read_callback(void *data, size_t size,
8889
/** return copied size */
8990
return copy_size;
9091
}
92+
93+
/**
94+
* @brief PostFormInfo constructor
95+
*/
96+
RestClient::Helpers::PostFormInfo::PostFormInfo()
97+
: formPtr(NULL), lastFormPtr(NULL) {
98+
}
99+
100+
/**
101+
* @brief PostFormInfo destructor
102+
*/
103+
RestClient::Helpers::PostFormInfo::~PostFormInfo() {
104+
// cleanup the formpost chain
105+
if (this->formPtr) {
106+
curl_formfree(this->formPtr);
107+
this->formPtr = NULL;
108+
this->lastFormPtr = NULL;
109+
}
110+
}
111+
112+
/**
113+
* @brief set the name and the value of the HTML "file" form's input
114+
*
115+
* @param fieldName name of the "file" input
116+
* @param fieldValue path to the file to upload
117+
*/
118+
void RestClient::Helpers::PostFormInfo::addFormFile(
119+
const std::string& fieldName, const std::string& fieldValue) {
120+
curl_formadd(&this->formPtr, &this->lastFormPtr,
121+
CURLFORM_COPYNAME, fieldName.c_str(),
122+
CURLFORM_FILE, fieldValue.c_str(),
123+
CURLFORM_END);
124+
}
125+
126+
/**
127+
* @brief set the name and the value of an HTML form's input
128+
* (other than "file" like "text", "hidden" or "submit")
129+
*
130+
* @param fieldName name of the input element
131+
* @param fieldValue value to be assigned to the input element
132+
*/
133+
void RestClient::Helpers::PostFormInfo::addFormContent(
134+
const std::string& fieldName, const std::string& fieldValue) {
135+
curl_formadd(&this->formPtr, &this->lastFormPtr,
136+
CURLFORM_COPYNAME, fieldName.c_str(),
137+
CURLFORM_COPYCONTENTS, fieldValue.c_str(),
138+
CURLFORM_END);
139+
}

source/restclient.cc

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,23 @@ RestClient::Response RestClient::post(const std::string& url,
7373
return ret;
7474
}
7575

76+
/**
77+
* @brief HTTP POST Form method
78+
*
79+
* @param url to query
80+
* @param data post form information
81+
*
82+
* @return response struct
83+
*/
84+
RestClient::Response RestClient::postForm(const std::string& url,
85+
const RestClient::Helpers::PostFormInfo& data) {
86+
RestClient::Response ret;
87+
RestClient::Connection *conn = new RestClient::Connection("");
88+
ret = conn->postForm(url, data);
89+
delete conn;
90+
return ret;
91+
}
92+
7693
/**
7794
* @brief HTTP PUT method
7895
*

test/test_connection.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ class ConnectionTest : public ::testing::Test
2222
virtual void SetUp()
2323
{
2424
conn = new RestClient::Connection("https://httpbin.org");
25+
conn->SetTimeout(10);
2526
}
2627

2728
virtual void TearDown()

test/test_restclient.cc

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
#include "restclient-cpp/restclient.h"
2+
#include "restclient-cpp/helpers.h"
23
#include <gtest/gtest.h>
34
#include <json/json.h>
5+
#include <cstdio>
6+
#include <fstream>
47
#include <string>
8+
#include <sstream>
59

610
class RestClientTest : public ::testing::Test
711
{
@@ -107,6 +111,36 @@ TEST_F(RestClientTest, TestRestClientPostBody)
107111
EXPECT_EQ("http://httpbin.org/post", root.get("url", "no url set").asString());
108112
EXPECT_EQ("restclient-cpp/" RESTCLIENT_VERSION, root["headers"].get("User-Agent", "no url set").asString());
109113
}
114+
TEST_F(RestClientTest, TestRestClientPostForm)
115+
{
116+
// generating a file name with a timestamp
117+
std::ostringstream fileName;
118+
time_t rawtime;
119+
tm * timeinfo;
120+
time(&rawtime);
121+
timeinfo = localtime( &rawtime );
122+
123+
fileName << "TestPostForm_" << (timeinfo->tm_year)+1900 << "_" << timeinfo->tm_mon+1
124+
<< "_" << timeinfo->tm_mday << "-" << timeinfo->tm_hour
125+
<< "_"<< timeinfo->tm_min << "_" << timeinfo->tm_sec << ".txt";
126+
127+
// creating a dummy file to upload via a post form request
128+
std::ofstream ofDummyFile(fileName.str().c_str());
129+
ASSERT_TRUE(static_cast<bool>(ofDummyFile));
130+
ofDummyFile << "Dummy file for the unit test 'TestRestClientPostForm' of the restclient-cpp Project.";
131+
ASSERT_TRUE(static_cast<bool>(ofDummyFile));
132+
ofDummyFile.close();
133+
134+
// uploading the dummy file
135+
RestClient::Helpers::PostFormInfo UploadInfo;
136+
UploadInfo.addFormFile("submitted", fileName.str());
137+
UploadInfo.addFormContent("filename", fileName.str());
138+
RestClient::Response res = RestClient::postForm("http://posttestserver.com/post.php?dir=restclientcpptests", UploadInfo);
139+
EXPECT_EQ(200, res.code);
140+
141+
// remove dummy file
142+
remove(fileName.str().c_str());
143+
}
110144
// check for failure
111145
TEST_F(RestClientTest, TestRestClientPOSTFailureCode)
112146
{

0 commit comments

Comments
 (0)