Skip to content

Commit cb01142

Browse files
authored
Move Conditions to use libcurl (#1973)
* Move Conditions to use libcurl * Bump container verison to v5.2.3
1 parent 3268d71 commit cb01142

3 files changed

Lines changed: 65 additions & 48 deletions

File tree

Conditions/CMakeLists.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ project(Conditions DESCRIPTION "Module that contains Conditions providers and ob
55
LANGUAGES CXX
66
)
77

8+
find_package(CURL REQUIRED)
9+
810
setup_library(module Conditions
9-
dependencies Framework::Framework DetDescr::DetDescr
11+
dependencies Framework::Framework DetDescr::DetDescr CURL::libcurl
1012
)
1113

1214
setup_test(dependencies Conditions::Conditions)

Conditions/src/Conditions/URLStreamer.cxx

Lines changed: 61 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,89 @@
11
#include "Conditions/URLStreamer.h"
22

3-
#include <string.h>
4-
#include <sys/wait.h>
5-
#include <unistd.h>
3+
#include <curl/curl.h>
64

75
#include <fstream>
8-
#include <iostream>
96
#include <sstream>
107
#include <string>
118

129
#include "Framework/Exception/Exception.h"
1310

1411
namespace conditions {
1512

16-
static unsigned int http_requests_ = 0;
17-
static unsigned int http_failures_ = 0;
13+
static unsigned int http_requests = 0;
14+
static unsigned int http_failures = 0;
1815

19-
void urlstatistics(unsigned int& http_requests, unsigned int& http_failures) {
20-
http_requests = http_requests_;
21-
http_failures = http_failures_;
16+
void urlstatistics(unsigned int& requests, unsigned int& failures) {
17+
requests = http_requests;
18+
failures = http_failures;
19+
}
20+
21+
/**
22+
* Callback for libcurl to write received data into a std::string buffer.
23+
*/
24+
static size_t writeCallback(char* ptr, size_t size, size_t nmemb,
25+
void* userdata) {
26+
auto* buffer = static_cast<std::string*>(userdata);
27+
size_t total = size * nmemb;
28+
buffer->append(ptr, total);
29+
return total;
2230
}
2331

2432
std::unique_ptr<std::istream> urlstream(const std::string& url) {
2533
if (url.find("file://") == 0 || (url.length() > 0 && url[0] == '/')) {
2634
std::string fname = url;
27-
if (fname.find("file://") == 0)
28-
fname = url.substr(url.find("file://") + strlen("file://"));
29-
std::ifstream* fs = new std::ifstream(fname);
35+
if (fname.find("file://") == 0) fname = url.substr(7);
36+
auto fs = std::make_unique<std::ifstream>(fname);
3037
if (!fs->good()) {
31-
delete fs;
3238
EXCEPTION_RAISE("ConditionsException",
3339
"Unable to open CSV file '" + fname + "'");
3440
}
35-
return std::unique_ptr<std::istream>(fs);
41+
return fs;
3642
}
37-
if ((url.find("http://") != std::string::npos) ||
38-
(url.find("https://") != std::string::npos)) {
39-
http_requests_++;
40-
// this implementation uses wget to handle the SSL processes
41-
static int istream = 0;
42-
char fname[250];
43-
snprintf(fname, 250, "/tmp/httpstream_%d_%d.csv ", getpid(), istream++);
44-
pid_t apid = fork();
45-
if (apid == 0) { // child
46-
execl("/usr/bin/wget", "wget", "-q", "--no-check-certificate", "-O",
47-
fname, "-o", "/tmp/wget.log", url.c_str(), (char*)0);
48-
} else {
49-
int wstatus;
50-
waitpid(apid, &wstatus, 0);
51-
// std::cout << "EXITED: " << WIFEXITED(wstatus) << " STATUS: " <<
52-
// WEXITSTATUS(wstatus) << std::endl;
53-
if (WIFEXITED(wstatus) != 1 || WEXITSTATUS(wstatus) != 0) {
54-
http_failures_++;
55-
EXCEPTION_RAISE("ConditionsException",
56-
"Wget error " + std::to_string(WEXITSTATUS(wstatus)) +
57-
" retreiving URL '" + url + "'");
58-
}
43+
if ((url.find("http://") == 0) || (url.find("https://") == 0)) {
44+
http_requests++;
45+
46+
CURL* curl = curl_easy_init();
47+
if (!curl) {
48+
http_failures++;
49+
EXCEPTION_RAISE("ConditionsException",
50+
"Failed to initialize libcurl for URL '" + url + "'");
5951
}
60-
std::ifstream ib(fname);
61-
if (ib.bad()) {
62-
http_failures_++;
52+
53+
std::string response_body;
54+
55+
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
56+
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeCallback);
57+
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_body);
58+
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
59+
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
60+
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L);
61+
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 30L);
62+
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 300L);
63+
64+
CURLcode res = curl_easy_perform(curl);
65+
66+
if (res != CURLE_OK) {
67+
curl_easy_cleanup(curl);
68+
http_failures++;
69+
EXCEPTION_RAISE("ConditionsException",
70+
"Curl error (" + std::string(curl_easy_strerror(res)) +
71+
") retrieving URL '" + url + "'");
72+
}
73+
74+
long http_code = 0;
75+
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
76+
curl_easy_cleanup(curl);
77+
78+
if (http_code != 200) {
79+
http_failures++;
6380
EXCEPTION_RAISE("ConditionsException",
64-
"Bad/empty file retreiving URL '" + url + "'");
81+
"HTTP error " + std::to_string(http_code) +
82+
" retrieving URL '" + url + "'");
6583
}
66-
std::stringstream* ss = new std::stringstream();
67-
(*ss) << ib.rdbuf();
68-
// std::cout << "CONTENTS: \n" << ss->str();
69-
ib.close(); // needed for some implementations
70-
std::remove(fname);
71-
return std::unique_ptr<std::istream>(ss);
84+
85+
auto ss = std::make_unique<std::stringstream>(std::move(response_body));
86+
return ss;
7287
}
7388
EXCEPTION_RAISE("ConditionsException", "Unable to handle URL '" + url + "'");
7489
return std::unique_ptr<std::istream>(nullptr);

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# for the development image, look at the LDMX-Software/dev-build-context repo
44
###############################################################################
55

6-
FROM ldmx/dev:v5.2.2
6+
FROM ldmx/dev:v5.2.3
77

88
# install ldmx-sw into the container at /usr/local
99
COPY . /code

0 commit comments

Comments
 (0)