• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mbits-os / quick_dra / 22077168793

16 Feb 2026 08:51PM UTC coverage: 97.995% (+11.0%) from 87.008%
22077168793

push

github

mzdun
chore: tweak Clang targets

4447 of 4538 relevant lines covered (97.99%)

1922.16 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.3
/libs/libforms/src/io/http.cpp
1
// Copyright (c) 2026 midnightBITS
2
// This code is licensed under MIT license (see LICENSE for details)
3

4
#define NOMINMAX
5

6
#include <curl/curl.h>
7
#include <fmt/format.h>
8
#include <memory>
9
#include <quick_dra/base/str.hpp>
10
#include <quick_dra/io/http.hpp>
11
#include <quick_dra/version.hpp>
12
#include <span>
13
#include <stdexcept>
14

15
namespace quick_dra {
16
        namespace {
17
                struct curl_global_initer {
18
                        curl_global_initer() {
34✔
19
                                if (::curl_global_init(CURL_GLOBAL_DEFAULT) != 0) {
34✔
20
                                        // GCOV_EXCL_START
21
                                        throw std::runtime_error(
22
                                            "CURL global initialization failed");
23
                                        // GCOV_EXCL_STOP
24
                                }
25
                        }
100✔
26
                        ~curl_global_initer() { ::curl_global_cleanup(); }
34✔
27
                };
28

29
                struct curl_cleanup {
30
                        void operator()(CURL* p) const { ::curl_easy_cleanup(p); }
34✔
31
                };
32

33
                using curl_ptr = std::unique_ptr<CURL, curl_cleanup>;
34

35
                curl_ptr curl_easy_init() {
34✔
36
                        static const curl_global_initer init{};
100✔
37
                        return curl_ptr{::curl_easy_init()};
100✔
38
                }
67✔
39

40
                CURLcode curl_easy_setopt(curl_ptr const& curl,
198✔
41
                                          CURLoption option,
42
                                          auto arg) {
1✔
43
                        return ::curl_easy_setopt(curl.get(), option, arg);
595✔
44
                }
397✔
45

46
                CURLcode curl_easy_perform(curl_ptr const& curl) {
34✔
47
                        return ::curl_easy_perform(curl.get());
100✔
48
                }
67✔
49

50
                auto ua_version() noexcept {
34✔
51
                        if constexpr (version::major < 1) {
66✔
52
                                return version::string;
100✔
53
                        } else {
66✔
54
                                return version::string_short;
55
                        }
56
                }
67✔
57
        }  // namespace
58

59
        http_response http_get(std::string const& url) try {
34✔
60
                http_response response{};
99✔
61

66✔
62
                auto curl = curl_easy_init();
100✔
63
                if (!curl) return response;
34✔
64

66✔
65
                auto const ua = fmt::format("{}/{}", version::program, ua_version());
45✔
66

66✔
67
                curl_easy_setopt(curl, CURLOPT_USERAGENT, ua.c_str());
100✔
68
                curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
100✔
69
                curl_write_callback write_cb = [](char* contents, std::size_t size,
133✔
70
                                                  std::size_t nmemb,
66✔
71
                                                  void* userp) -> std::size_t {
1✔
72
                        auto& resp = *static_cast<http_response*>(userp);
100✔
73
                        auto realsize = size * nmemb;
100✔
74
                        auto bytes = reinterpret_cast<std::byte*>(contents);
100✔
75
                        resp.content.insert(resp.content.end(), bytes, bytes + realsize);
100✔
76
                        return realsize;
100✔
77
                };
67✔
78
                curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
100✔
79
                curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb);
100✔
80
                curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
100✔
81
                curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
100✔
82
                if (curl_easy_perform(curl) != CURLE_OK) {
34✔
83
                        // GCOV_EXCL_START
84
                        [[unlikely]];
85
                        return response.cleaned();
86
                        // GCOV_EXCL_STOP
87
                }
88

66✔
89
                long code;
11✔
90
                if (curl_easy_getinfo(curl.get(), CURLINFO_RESPONSE_CODE, &code) !=
34✔
91
                    CURLE_OK) {
66✔
92
                        // GCOV_EXCL_START
93
                        [[unlikely]];
94
                        return response.cleaned();
95
                        // GCOV_EXCL_STOP
96
                }
97
                response.status = static_cast<unsigned>(std::max(code, 0l));
34✔
98

66✔
99
                curl_header* header{};
100✔
100
                if (curl_easy_header(curl.get(), "Content-Type", 0, CURLH_HEADER, -1,
33✔
101
                                     &header) != CURLHE_OK) {
100✔
102
                        // GCOV_EXCL_START
103
                        [[unlikely]];
104
                        return response.cleaned();
105
                        // GCOV_EXCL_STOP
106
                }
107
                auto const view = std::string_view{header->value};
34✔
108
                auto const split_view = split_sv(view, ';'_sep);
100✔
109

66✔
110
                auto const type_subtype = split_sv(split_view[0], '/'_sep, 1);
100✔
111
                if (type_subtype.size() == 2) {
34✔
112
                        response.content_type.type = strip_sv(type_subtype[0]);
100✔
113
                        response.content_type.subtype = strip_sv(type_subtype[1]);
100✔
114
                }
66✔
115

66✔
116
                auto const params = std::span{split_view}.subspan(1);
100✔
117
                for (auto const& param_view : params) {
67✔
118
                        auto const name_value = split_sv(param_view, '='_sep, 1);
100✔
119
                        if (name_value.size() != 2) {
34✔
120
                                continue;
×
121
                        }
122
                        if (strip_sv(name_value[0]) != "charset"sv) {
34✔
123
                                continue;
×
124
                        }
125
                        response.charset = strip_sv(name_value[1]);
34✔
126
                }
100✔
127

66✔
128
                return response;
100✔
129
        } catch (std::exception& error) {  // GCOV_EXCL_START
130
                // the line below is broken, because when it is reported as excluded,
131
                // the <words>, <colon>, <space>, <keyword>, <colon> makes msbuild to
132
                // assume this is an error reporting on behalf of tool, which
133
                // otherwise returns 0 and the step in the build process ends with
134
                // an imagined -1 result
135
                fmt::print(stderr,
136
                           "Quick-DRA: "
137
                           "error"
138
                           ": {}\n"
139
                           "           while downloading {}\n",
140
                           error.what(), url);
141
                return http_response{};
142
        }  // GCOV_EXCL_STOP
143
}  // namespace quick_dra
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc