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

randombit / botan / 26141725099

19 May 2026 08:32PM UTC coverage: 89.343% (+0.009%) from 89.334%
26141725099

push

github

web-flow
Merge pull request #5609 from randombit/jack/improve-http

Improve the HTTP 1.0 client used for OCSP/CRL

109341 of 122383 relevant lines covered (89.34%)

11264402.07 hits per line

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

81.56
/src/cli/utils.cpp
1
/*
2
* (C) 2009,2010,2014,2015 Jack Lloyd
3
* (C) 2017 René Korthaus, Rohde & Schwarz Cybersecurity
4
*
5
* Botan is released under the Simplified BSD License (see license.txt)
6
*/
7

8
#include "cli.h"
9

10
#include <botan/version.h>
11
#include <botan/internal/target_info.h>
12
#include <iomanip>
13
#include <sstream>
14

15
#if defined(BOTAN_HAS_CPUID)
16
   #include <botan/internal/cpuid.h>
17
#endif
18

19
#if defined(BOTAN_HAS_HTTP_UTIL)
20
   #include <botan/uri.h>
21
   #include <botan/internal/http_util.h>
22
#endif
23

24
#if defined(BOTAN_HAS_UUID)
25
   #include <botan/uuid.h>
26
#endif
27

28
#if defined(BOTAN_HAS_OS_UTILS)
29
   #include <botan/internal/os_utils.h>
30
#endif
31

32
namespace Botan_CLI {
33

34
namespace {
35

36
class Print_Help final : public Command {
37
   public:
38
      Print_Help() : Command("help") {}
4✔
39

40
      std::string help_text() const override {
1✔
41
         std::map<std::string, std::vector<std::unique_ptr<Command>>> grouped_commands;
1✔
42

43
         auto reg_commands = Command::registered_cmds();
1✔
44
         for(const auto& cmd_name : reg_commands) {
74✔
45
            auto cmd = Command::get_cmd(cmd_name);
73✔
46
            if(cmd) {
73✔
47
               grouped_commands[cmd->group()].push_back(std::move(cmd));
73✔
48
            }
49
         }
73✔
50

51
         const std::map<std::string, std::string> groups_description{{"codec", "Encoders/Decoders"},
1✔
52
                                                                     {"compression", "Compression"},
53
                                                                     {
54
                                                                        "crypto",
55
                                                                        "Encryption",
56
                                                                     },
57
                                                                     {"fec", "Forward Error Correction"},
58
                                                                     {"hash", "Hash Functions"},
59
                                                                     {"hmac", "HMAC"},
60
                                                                     {"info", "Informational"},
61
                                                                     {"misc", "Miscellaneous"},
62
                                                                     {"numtheory", "Number Theory"},
63
                                                                     {"passhash", "Password Hashing"},
64
                                                                     {"psk", "PSK Database"},
65
                                                                     {"pubkey", "Public Key Cryptography"},
66
                                                                     {"testing", "Testing"},
67
                                                                     {"tls", "TLS"},
68
                                                                     {"tss", "Secret Sharing"},
69
                                                                     {"x509", "X.509"}};
17✔
70

71
         std::ostringstream oss;
1✔
72

73
         oss << "Usage: botan <cmd> <cmd-options>\n";
1✔
74
         oss << "All commands support --verbose --help --output= --error-output= --rng-type= --drbg-seed=\n\n";
1✔
75
         oss << "Available commands:\n\n";
1✔
76

77
         for(const auto& commands : grouped_commands) {
19✔
78
            const std::string group = commands.first;
18✔
79
            if(group.empty()) {
18✔
80
               // ???
81
               continue;
1✔
82
            }
83

84
            auto descr = groups_description.find(group);
17✔
85
            if(descr != groups_description.end()) {
17✔
86
               oss << descr->second;
16✔
87
            } else {
88
               oss << group;
1✔
89
            }
90
            oss << ":\n";
17✔
91
            for(const auto& cmd : commands.second) {
89✔
92
               oss << "   " << std::setw(16) << std::left << cmd->cmd_name() << "   " << cmd->description() << "\n";
288✔
93
            }
94
            oss << "\n";
17✔
95
         }
18✔
96

97
         return oss.str();
1✔
98
      }
2✔
99

100
      std::string group() const override { return ""; }
1✔
101

102
      std::string description() const override { return "Prints a help string"; }
×
103

104
      void go() override {
1✔
105
         this->set_return_code(1);
1✔
106
         output() << help_text();
2✔
107
      }
1✔
108
};
109

110
BOTAN_REGISTER_COMMAND("help", Print_Help);
2✔
111

112
class Has_Command final : public Command {
113
   public:
114
      Has_Command() : Command("has_command cmd") {}
22✔
115

116
      std::string group() const override { return "info"; }
1✔
117

118
      std::string description() const override { return "Test if a command is available"; }
1✔
119

120
      void go() override {
10✔
121
         const std::string cmd = get_arg("cmd");
10✔
122

123
         bool exists = false;
10✔
124
         for(const auto& registered_cmd : Command::registered_cmds()) {
531✔
125
            if(cmd == registered_cmd) {
531✔
126
               exists = true;
127
               break;
128
            }
129
         }
10✔
130

131
         if(verbose()) {
10✔
132
            output() << "Command '" << cmd << "' is " << (exists ? "" : "not ") << "available\n";
×
133
         }
134

135
         if(!exists) {
10✔
136
            this->set_return_code(1);
×
137
         }
138
      }
10✔
139
};
140

141
BOTAN_REGISTER_COMMAND("has_command", Has_Command);
11✔
142

143
class Config_Info final : public Command {
144
   public:
145
      Config_Info() : Command("config info_type") {}
10✔
146

147
      std::string help_text() const override {
×
148
         return "Usage: config info_type\n"
×
149
                "   prefix: Print install prefix\n"
150
                "   cflags: Print include params\n"
151
                "   ldflags: Print linker params\n"
152
                "   libs: Print libraries\n";
×
153
      }
154

155
      std::string group() const override { return "info"; }
1✔
156

157
      std::string description() const override { return "Print the used prefix, cflags, ldflags or libs"; }
1✔
158

159
      void go() override {
4✔
160
         const std::string arg = get_arg("info_type");
4✔
161

162
         if(arg == "prefix") {
4✔
163
            output() << BOTAN_INSTALL_PREFIX << "\n";
1✔
164
         } else if(arg == "cflags") {
3✔
165
            output() << "-I" << BOTAN_INSTALL_PREFIX << "/" << BOTAN_INSTALL_HEADER_DIR << "\n";
1✔
166
         } else if(arg == "ldflags") {
2✔
167
            if(*BOTAN_LINK_FLAGS != 0) {
1✔
168
               output() << BOTAN_LINK_FLAGS << ' ';
1✔
169
            }
170
            output() << "-L" << BOTAN_INSTALL_LIB_DIR << "\n";
1✔
171
         } else if(arg == "libs") {
1✔
172
            output() << "-lbotan-" << Botan::version_major() << " " << BOTAN_LIB_LINK << "\n";
1✔
173
         } else {
174
            throw CLI_Usage_Error("Unknown option to botan config " + arg);
×
175
         }
176
      }
4✔
177
};
178

179
BOTAN_REGISTER_COMMAND("config", Config_Info);
5✔
180

181
class Version_Info final : public Command {
182
   public:
183
      Version_Info() : Command("version --full") {}
6✔
184

185
      std::string group() const override { return "info"; }
1✔
186

187
      std::string description() const override { return "Print version info"; }
1✔
188

189
      void go() override {
2✔
190
         if(flag_set("full")) {
2✔
191
            output() << Botan::version_string() << "\n";
3✔
192
         } else {
193
            output() << Botan::short_version_string() << "\n";
3✔
194
         }
195
      }
2✔
196
};
197

198
BOTAN_REGISTER_COMMAND("version", Version_Info);
3✔
199

200
#if defined(BOTAN_HAS_CPUID)
201

202
class Print_Cpuid final : public Command {
203
   public:
204
      Print_Cpuid() : Command("cpuid") {}
32✔
205

206
      std::string group() const override { return "info"; }
1✔
207

208
      std::string description() const override {
1✔
209
         return "List available processor flags (aes_ni, SIMD extensions, ...)";
1✔
210
      }
211

212
      void go() override { output() << "CPUID flags: " << Botan::CPUID::to_string() << "\n"; }
45✔
213
};
214

215
BOTAN_REGISTER_COMMAND("cpuid", Print_Cpuid);
16✔
216

217
#endif
218

219
#if defined(BOTAN_HAS_OS_UTILS)
220

221
class Cycle_Counter final : public Command {
222
   public:
223
      Cycle_Counter() : Command("cpu_clock --test-duration=500") {}
4✔
224

225
      std::string group() const override { return "info"; }
1✔
226

227
      std::string description() const override { return "Estimate the speed of the CPU cycle counter"; }
1✔
228

229
      void go() override {
1✔
230
         if(Botan::OS::get_cpu_cycle_counter() == 0) {
1✔
231
            output() << "No CPU cycle counter on this machine\n";
×
232
            return;
×
233
         }
234

235
         const uint64_t test_duration_ns = get_arg_sz("test-duration") * 1000000;
1✔
236

237
         if(test_duration_ns == 0) {
1✔
238
            output() << "Invalid test duration\n";
×
239
            return;
×
240
         }
241

242
         const uint64_t cc_start = Botan::OS::get_cpu_cycle_counter();
1✔
243
         const uint64_t ns_start = Botan::OS::get_system_timestamp_ns();
1✔
244

245
         uint64_t cc_end = 0;
1✔
246
         uint64_t ns_end = ns_start;
1✔
247

248
         while((ns_end - ns_start) < test_duration_ns) {
10,042,478✔
249
            ns_end = Botan::OS::get_system_timestamp_ns();
10,042,476✔
250
            cc_end = Botan::OS::get_cpu_cycle_counter();
10,042,476✔
251
         }
252

253
         if(cc_end <= cc_start) {
1✔
254
            output() << "Cycle counter seems to have wrapped, try again\n";
×
255
            return;
×
256
         }
257

258
         if(ns_end <= ns_start) {
1✔
259
            output() << "System clock seems to have wrapped (?!?)\n";
×
260
            return;
×
261
         }
262

263
         const uint64_t ns_duration = ns_end - ns_start;
1✔
264
         const uint64_t cc_duration = cc_end - cc_start;
1✔
265

266
         const double ratio = static_cast<double>(cc_duration) / ns_duration;
1✔
267

268
         if(ratio >= 1.0) {
1✔
269
            // GHz
270
            output() << "Estimated CPU clock " << std::setprecision(2) << ratio << " GHz\n";
1✔
271
         } else {
272
            // MHz
273
            output() << "Estimated CPU clock " << static_cast<size_t>(ratio * 1000) << " MHz\n";
×
274
         }
275
      }
276
};
277

278
BOTAN_REGISTER_COMMAND("cpu_clock", Cycle_Counter);
2✔
279

280
#endif
281

282
#if defined(BOTAN_HAS_UUID)
283

284
class Print_UUID final : public Command {
285
   public:
286
      Print_UUID() : Command("uuid") {}
6✔
287

288
      std::string group() const override { return "misc"; }
1✔
289

290
      std::string description() const override { return "Print a random UUID"; }
1✔
291

292
      void go() override {
2✔
293
         const Botan::UUID uuid(rng());
2✔
294
         output() << uuid.to_string() << "\n";
6✔
295
      }
2✔
296
};
297

298
BOTAN_REGISTER_COMMAND("uuid", Print_UUID);
3✔
299

300
#endif
301

302
#if defined(BOTAN_HAS_HTTP_UTIL)
303

304
class HTTP_Get final : public Command {
305
   public:
306
      HTTP_Get() : Command("http_get --redirects=1 --timeout=3000 url") {}
2✔
307

308
      std::string group() const override { return "misc"; }
1✔
309

310
      std::string description() const override { return "Retrieve resource from the passed http/https url"; }
1✔
311

312
      void go() override {
×
313
         const std::string url = get_arg("url");
×
314
         const std::chrono::milliseconds timeout(get_arg_sz("timeout"));
×
315
         const size_t redirects = get_arg_sz("redirects");
×
316

317
         auto uri = Botan::URI::parse(url);
×
318
         if(!uri) {
×
319
            throw CLI_Usage_Error("Could not parse URL '" + url + "'");
×
320
         }
321

322
         const auto limits = Botan::HTTP::RequestLimits().set_max_redirects(redirects).set_timeout(timeout);
×
323
         output() << Botan::HTTP::GET_sync(*uri, limits) << "\n";
×
324
      }
×
325
};
326

327
BOTAN_REGISTER_COMMAND("http_get", HTTP_Get);
1✔
328

329
#endif  // http_util
330

331
}  // namespace
332

333
}  // namespace Botan_CLI
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