Skip to content

Commit 051c56d

Browse files
committed
RAII wrapper for underlying libcurl elements
1 parent 308852d commit 051c56d

File tree

1 file changed

+75
-42
lines changed

1 file changed

+75
-42
lines changed

simple_http.hpp

+75-42
Original file line numberDiff line numberDiff line change
@@ -531,52 +531,21 @@ struct Client final {
531531
const CurlHeaderCallback &curl_header_callback,
532532
const CurlSetupCallback &curl_setup_callback,
533533
const Predicate<HttpStatusCode> &successPredicate) {
534-
std::string body_buffer;
535-
std::string header_buffer;
536-
long rawStatusCode = 0;
537-
538-
CURL *curl = curl_easy_init();
539-
if (curl) {
540-
struct curl_slist *chunk = nullptr;
541-
542-
curl_easy_setopt(curl, CURLOPT_URL, url.value().c_str());
543-
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
544-
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &body_buffer);
545-
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, curl_header_callback(chunk));
546-
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, write_callback);
547-
curl_easy_setopt(curl, CURLOPT_HEADERDATA, &header_buffer);
548-
curl_easy_setopt(curl, CURLOPT_VERBOSE, debug_);
549-
curl_setup_callback(curl);
550-
551-
if (url.protocol().value() == "https") {
552-
verify_
553-
? curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L)
554-
: curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
555-
}
534+
CurlWrapper curlWrapper{successPredicate, error_callback_};
556535

557-
CURLcode res = curl_easy_perform(curl);
558-
if (res != CURLE_OK) {
559-
error_callback_(curl_easy_strerror(res));
560-
curl_easy_cleanup(curl);
561-
curl_slist_free_all(chunk);
562-
return std::nullopt;
563-
}
536+
curlWrapper.execute_header_callback(curl_header_callback);
537+
curlWrapper.add_option(CURLOPT_URL, url.value().c_str());
538+
curlWrapper.add_option(CURLOPT_VERBOSE, debug_);
564539

565-
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &rawStatusCode);
566-
curl_easy_cleanup(curl);
567-
curl_slist_free_all(chunk);
540+
if (url.protocol().value() == "https") {
541+
verify_
542+
? curlWrapper.add_option(CURLOPT_SSL_VERIFYPEER, 1L)
543+
: curlWrapper.add_option(CURLOPT_SSL_VERIFYPEER, 0L);
568544
}
569545

570-
HttpStatusCode status{rawStatusCode};
571-
if (successPredicate(status)) {
572-
return std::optional<HttpResponse>({
573-
status,
574-
HttpResponseHeaders{header_buffer},
575-
HttpResponseBody{body_buffer}
576-
});
577-
} else {
578-
return std::nullopt;
579-
}
546+
curlWrapper.execute_setup_callback(curl_setup_callback);
547+
548+
return curlWrapper.execute();
580549
}
581550

582551
private:
@@ -600,5 +569,69 @@ struct Client final {
600569
return chunk;
601570
};
602571
}
572+
573+
struct CurlWrapper final {
574+
CurlWrapper(const Predicate<HttpStatusCode> &success_predicate, ErrorCallback error_callback)
575+
: curl_(curl_easy_init())
576+
, slist_(nullptr)
577+
, success_predicate_(success_predicate)
578+
, error_callback_(std::move(error_callback))
579+
{ }
580+
581+
~CurlWrapper() {
582+
curl_easy_cleanup(curl_);
583+
curl_slist_free_all(slist_);
584+
}
585+
586+
template<class A>
587+
void add_option(const CURLoption option, A value) {
588+
curl_easy_setopt(curl_, option, value);
589+
}
590+
591+
void execute_header_callback(const CurlHeaderCallback &header_callback) {
592+
slist_ = header_callback(slist_);
593+
}
594+
595+
void execute_setup_callback(const CurlSetupCallback &setup_callback) {
596+
setup_callback(curl_);
597+
}
598+
599+
[[nodiscard]]
600+
std::optional<HttpResponse> execute() {
601+
std::string body_buffer;
602+
std::string header_buffer;
603+
604+
curl_easy_setopt(curl_, CURLOPT_WRITEFUNCTION, write_callback);
605+
curl_easy_setopt(curl_, CURLOPT_WRITEDATA, &body_buffer);
606+
curl_easy_setopt(curl_, CURLOPT_HTTPHEADER, slist_);
607+
curl_easy_setopt(curl_, CURLOPT_HEADERDATA, &header_buffer);
608+
609+
CURLcode res = curl_easy_perform(curl_);
610+
if (res != CURLE_OK) {
611+
error_callback_(curl_easy_strerror(res));
612+
return std::nullopt;
613+
}
614+
615+
long status_code = 0;
616+
curl_easy_getinfo(curl_, CURLINFO_RESPONSE_CODE, &status_code);
617+
618+
HttpStatusCode status{status_code};
619+
if (success_predicate_(status)) {
620+
return std::optional<HttpResponse>({
621+
status,
622+
HttpResponseHeaders{header_buffer},
623+
HttpResponseBody{body_buffer}
624+
});
625+
} else {
626+
return std::nullopt;
627+
}
628+
}
629+
630+
private:
631+
CURL *curl_;
632+
curl_slist *slist_;
633+
Predicate<HttpStatusCode> success_predicate_;
634+
ErrorCallback error_callback_;
635+
};
603636
};
604637
} // namespace SimpleHttp

0 commit comments

Comments
 (0)