ReCodEx - Task Broker
ReCodEx is complex programmer testing solution, primary targeted to technical universities. It's highly customizable and based on modern technologies.
curl.cpp
1 #include "curl.h"
2 
3 // Tweak for older libcurls
4 #ifndef CURL_HTTP_VERSION_2_0
5 #define CURL_HTTP_VERSION_2_0 CURL_HTTP_VERSION_1_1
6 #endif
7 
8 
9 std::string helpers::get_http_query(const curl_params &params)
10 {
11  std::string result;
12 
13  for (auto &par : params) {
14  if (result.length() > 0) {
15  result += "&";
16  }
17 
18  result += par.first + "=" + par.second;
19  }
20 
21  return result;
22 }
23 
32 static size_t string_write_wrapper(void *ptr, size_t size, size_t nmemb, std::string *str)
33 {
34  size_t length = size * nmemb;
35 
36  std::copy((char *) ptr, (char *) ptr + length, std::back_inserter(*str));
37 
38  return length;
39 }
40 
41 std::string helpers::curl_get(const std::string &url,
42  const long port,
43  const curl_params &params,
44  const std::string &username,
45  const std::string &passwd)
46 {
47  std::string result;
48  std::string query = get_http_query(params);
49  std::string url_query = url + "?" + query;
50  CURL *curl;
51  CURLcode res;
52 
53  // get curl handle
54  curl = curl_easy_init();
55  if (curl) {
56  // destination address
57  curl_easy_setopt(curl, CURLOPT_URL, url_query.c_str());
58 
59  // set port
60  curl_easy_setopt(curl, CURLOPT_PORT, port);
61 
62  // set writer wrapper and result string
63  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, string_write_wrapper);
64  curl_easy_setopt(curl, CURLOPT_WRITEDATA, &result);
65 
66  // Follow redirects
67  curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
68  // Ennable support for HTTP2
69  curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
70  // We have trusted HTTPS certificate, so set validation on
71  curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
72  curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L);
73  // Causes error on HTTP responses >= 400
74  curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);
75 
76  if (username.length() != 0 || passwd.length() != 0) {
77  curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
78  curl_easy_setopt(curl, CURLOPT_USERPWD, (username + ":" + passwd).c_str());
79  }
80 
81  // Enable verbose for easier tracing
82  // curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
83 
84  // perform action itself
85  res = curl_easy_perform(curl);
86 
87  // Always cleanup
88  curl_easy_cleanup(curl);
89 
90  // Check for errors
91  if (res != CURLE_OK) {
92  long response_code;
93  curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
94  auto error_message = "GET request failed to " + url_query + ". Error: (" + std::to_string(response_code) +
95  ") " + curl_easy_strerror(res);
96  throw curl_exception(error_message);
97  }
98  }
99 
100  return result;
101 }
102 
103 std::string helpers::curl_post(const std::string &url,
104  const long port,
105  const curl_params &params,
106  const std::string &username,
107  const std::string &passwd)
108 {
109  std::string result;
110  std::string query = get_http_query(params);
111  std::string url_query = url + "?" + query;
112  CURL *curl;
113  CURLcode res;
114 
115  // get curl handle
116  curl = curl_easy_init();
117  if (curl) {
118  // destination address
119  curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
120 
121  // set port
122  curl_easy_setopt(curl, CURLOPT_PORT, port);
123 
124  /* Now specify the POST data */
125  curl_easy_setopt(curl, CURLOPT_POSTFIELDS, query.c_str());
126 
127  // set writer wrapper and result string
128  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, string_write_wrapper);
129  curl_easy_setopt(curl, CURLOPT_WRITEDATA, &result);
130 
131  // Follow redirects
132  curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
133  // Ennable support for HTTP2
134  curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
135  // We have trusted HTTPS certificate, so set validation on
136  curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
137  curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L);
138  // Causes error on HTTP responses >= 400
139  curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);
140 
141  if (username.length() != 0 || passwd.length() != 0) {
142  curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
143  curl_easy_setopt(curl, CURLOPT_USERPWD, (username + ":" + passwd).c_str());
144  }
145 
146  // Enable verbose for easier tracing
147  // curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
148 
149  // perform action itself
150  res = curl_easy_perform(curl);
151 
152  // Always cleanup
153  curl_easy_cleanup(curl);
154 
155  // Check for errors
156  if (res != CURLE_OK) {
157  long response_code;
158  curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
159  auto error_message = "POST request failed to " + url_query + ". Error: (" + std::to_string(response_code) +
160  ") " + curl_easy_strerror(res);
161  throw curl_exception(error_message);
162  }
163  }
164 
165  return result;
166 }