ndmspc v1.2.0-0.1.rc5
Loading...
Searching...
No Matches
NHttpRequest.cxx
1#include <fstream>
2#include <iostream>
3#include <sstream>
4#include <vector>
5#include <TString.h>
6#include <TBase64.h>
7#include <curl/curl.h>
8#include "NLogger.h"
9#include "NHttpRequest.h"
10
11namespace Ndmspc {
13{
14 curl_global_init(CURL_GLOBAL_DEFAULT);
15 curl = curl_easy_init();
16 if (!curl) {
17 throw std::runtime_error("Error: curl_easy_init() failed");
18 }
19}
20
22{
23 if (curl) {
24 curl_easy_cleanup(curl);
25 }
26 if (headers) {
27 curl_slist_free_all(headers);
28 }
29 curl_global_cleanup();
30}
31
32std::string Ndmspc::NHttpRequest::get(const std::string & url, const std::string & cert_path,
33 const std::string & key_path, const std::string & key_password_file,
34 bool insecure)
35{
36 std::ostringstream response_stream;
37 CURLcode res = request("GET", url, "", response_stream, cert_path, key_path, key_password_file, insecure);
38 if (res != CURLE_OK) {
40 }
41 return response_stream.str();
42}
43
44std::string Ndmspc::NHttpRequest::post(const std::string & url, const std::string & post_data,
45 const std::string & cert_path, const std::string & key_path,
46 const std::string & key_password_file, bool insecure)
47{
48 std::ostringstream response_stream;
49 CURLcode res = request("POST", url, post_data, response_stream, cert_path, key_path, key_password_file, insecure);
50 if (res != CURLE_OK) {
52 }
53 return response_stream.str();
54}
55
56int Ndmspc::NHttpRequest::head(const std::string & url, const std::string & cert_path, const std::string & key_path,
57 const std::string & key_password_file, bool insecure)
58{
59 std::ostringstream response_stream;
60 CURLcode res = request("HEAD", url, "", response_stream, cert_path, key_path, key_password_file, insecure);
61 if (res != CURLE_OK) {
63 }
64 // Find HTTP in header to get the response code
65 int http_code = -1;
66 for (const auto & header : received_headers) {
67 if (header.find("HTTP/") != std::string::npos) {
68 sscanf(header.c_str(), "HTTP/%*s %d", &http_code);
69 break;
70 }
71 }
72
73 return http_code;
74}
75
76CURLcode Ndmspc::NHttpRequest::request(const std::string & method, const std::string & url, const std::string & data,
77 std::ostringstream & response_stream, const std::string & cert_path,
78 const std::string & key_path, const std::string & key_password_file,
79 bool insecure)
80{
81 CURLcode res = CURLE_OK;
82
83 curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
84
85 received_headers.clear();
86 // Set method (GET or POST)
87 if (method == "POST") {
88 curl_easy_setopt(curl, CURLOPT_POST, 1L);
89 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str());
90 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
91 curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_stream);
92 // Set Content-Type header to application/json
93 headers = curl_slist_append(headers, "Content-Type: application/json");
94 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
95 }
96 else if (method == "HEAD") {
97 // curl_easy_setopt(curl, CURLOPT_HTTPHEADER, 1L);
98 curl_easy_setopt(curl, CURLOPT_NOBODY, 1L); // Set the header callback function
99 curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, HeaderCallback);
100 // Pass our vector address to the callback function via userdata
101 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
102 curl_easy_setopt(curl, CURLOPT_HEADERDATA, &received_headers);
103 curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
104 curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10L); // 10 seconds
105 }
106 else if (method == "GET") {
107 curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L);
108 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
109 curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_stream);
110 // Set Content-Type header to application/json
111 headers = curl_slist_append(headers, "Content-Type: application/json");
112 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
113 }
114 else {
115 return CURLE_UNSUPPORTED_PROTOCOL; // Unsupported method
116 }
117
118 // SSL certificate and key
119 if (!cert_path.empty() && !key_path.empty()) {
120 curl_easy_setopt(curl, CURLOPT_SSLCERT, cert_path.c_str());
121 curl_easy_setopt(curl, CURLOPT_SSLKEY, key_path.c_str());
122
123 // Set the key password file
124 if (!key_password_file.empty()) {
125 curl_easy_setopt(curl, CURLOPT_SSLKEYPASSWD, NULL);
126 curl_easy_setopt(curl, CURLOPT_KEYPASSWD, NULL);
127 curl_easy_setopt(curl, CURLOPT_SSLKEYPASSWD, "");
128 curl_easy_setopt(curl, CURLOPT_KEYPASSWD, "");
129
130 std::ifstream passwordFile(key_password_file);
131 std::string encodedPassword;
132 if (passwordFile.is_open()) {
133 std::getline(passwordFile, encodedPassword);
134 passwordFile.close();
135
136 TString encoded(encodedPassword); // Use TString
137 TString decoded = TBase64::Decode(encoded); // Decode with TBase64
138 std::string password = decoded.Data(); // Convert TString back to std::string
139
140 // Remove carriage return if it exists, to avoid authentication failure.
141 if (!password.empty() && password.back() == '\r') {
142 password.pop_back();
143 }
144
145 curl_easy_setopt(curl, CURLOPT_SSLKEYPASSWD, password.c_str());
146 curl_easy_setopt(curl, CURLOPT_KEYPASSWD, password.c_str());
147 }
148 else {
149 std::cerr << "Error: Could not open password file: " << key_password_file << std::endl;
150 return CURLE_FILE_COULDNT_READ_FILE;
151 }
152 }
153 }
154
155 // Insecure option
156 if (insecure) {
157 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
158 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
159 }
160 else {
161 // Add the CA cert path here for secure connection
162 // curl_easy_setopt(curl, CURLOPT_CAINFO, "/path/to/ca/cert.pem");
163 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
164 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L);
165 }
166
167 res = curl_easy_perform(curl);
168 if (res != CURLE_OK) {
169 return res; // Return the error code
170 }
171
172 // // process received headers for HEAD request
173 // for (const auto & header : received_headers) {
174 // NLogInfo("Header: %s", header.c_str());
175 // }
176
177 return res;
178}
179
180size_t Ndmspc::NHttpRequest::WriteCallback(void * contents, size_t size, size_t nmemb, void * userp)
181{
182 (static_cast<std::ostringstream *>(userp))->write(static_cast<char *>(contents), size * nmemb);
183 return size * nmemb;
184}
185
186size_t Ndmspc::NHttpRequest::HeaderCallback(char * buffer, size_t size, size_t nitems, void * userdata)
187{
188 size_t len = size * nitems;
189 std::string header(buffer, len);
190
191 // Remove trailing newlines and carriage returns
192 if (!header.empty() && header.back() == '\n') {
193 header.pop_back();
194 }
195 if (!header.empty() && header.back() == '\r') {
196 header.pop_back();
197 }
198
199 // Cast userdata back to the vector we passed
200 std::vector<std::string> * headers = static_cast<std::vector<std::string> *>(userdata);
201 if (headers) {
202 headers->push_back(header);
203 }
204
205 return len; // Must return the number of bytes processed
206}
207
209{
210 throw std::runtime_error(std::string("curl error: ") + curl_easy_strerror(res));
211}
212} // namespace Ndmspc
std::string post(const std::string &url, const std::string &post_data, const std::string &cert_path="", const std::string &key_path="", const std::string &key_password_file="", bool insecure=false)
Performs an HTTP POST request.
virtual ~NHttpRequest()
Destroys the NHttpRequest instance.
std::string get(const std::string &url, const std::string &cert_path="", const std::string &key_path="", const std::string &key_password_file="", bool insecure=false)
Performs an HTTP GET request.
static size_t HeaderCallback(char *buffer, size_t size, size_t nitems, void *userdata)
Callback for handling response headers.
int head(const std::string &url, const std::string &cert_path="", const std::string &key_path="", const std::string &key_password_file="", bool insecure=false)
Performs an HTTP HEAD request.
std::vector< std::string > received_headers
Received response headers.
static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp)
Callback for writing response data.
struct curl_slist * headers
List of custom headers.
NHttpRequest()
Constructs a new NHttpRequest instance.
CURL * curl
libcurl handle
CURLcode request(const std::string &method, const std::string &url, const std::string &data, std::ostringstream &response, const std::string &cert_path, const std::string &key_path, const std::string &key_password_file, bool insecure)
Internal method to perform an HTTP request.
void throw_curl_error(CURLcode res) const
Throws an exception if a CURL error occurs.
Global callback function for libwebsockets client events.