LDMX Software
URLStreamer.cxx
1#include "Conditions/URLStreamer.h"
2
3#include <curl/curl.h>
4
5#include <fstream>
6#include <sstream>
7#include <string>
8
9#include "Framework/Exception/Exception.h"
10
11namespace conditions {
12
13static unsigned int http_requests = 0;
14static unsigned int http_failures = 0;
15
16void urlstatistics(unsigned int& requests, unsigned int& failures) {
17 requests = http_requests;
18 failures = http_failures;
19}
20
24static 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;
30}
31
32std::unique_ptr<std::istream> urlstream(const std::string& url) {
33 if (url.find("file://") == 0 || (url.length() > 0 && url[0] == '/')) {
34 std::string fname = url;
35 if (fname.find("file://") == 0) fname = url.substr(7);
36 auto fs = std::make_unique<std::ifstream>(fname);
37 if (!fs->good()) {
38 EXCEPTION_RAISE("ConditionsException",
39 "Unable to open CSV file '" + fname + "'");
40 }
41 return fs;
42 }
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 + "'");
51 }
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++;
80 EXCEPTION_RAISE("ConditionsException",
81 "HTTP error " + std::to_string(http_code) +
82 " retrieving URL '" + url + "'");
83 }
84
85 auto ss = std::make_unique<std::stringstream>(std::move(response_body));
86 return ss;
87 }
88 EXCEPTION_RAISE("ConditionsException", "Unable to handle URL '" + url + "'");
89 return std::unique_ptr<std::istream>(nullptr);
90}
91
92} // namespace conditions