XRootD
XrdClHttpParseTimeout.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* Copyright (C) 2025, Pelican Project, Morgridge Institute for Research */
3 /* */
4 /* This file is part of the XrdClHttp client plugin for XRootD. */
5 /* */
6 /* XRootD is free software: you can redistribute it and/or modify it under */
7 /* the terms of the GNU Lesser General Public License as published by the */
8 /* Free Software Foundation, either version 3 of the License, or (at your */
9 /* option) any later version. */
10 /* */
11 /* XRootD is distributed in the hope that it will be useful, but WITHOUT */
12 /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
13 /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
14 /* License for more details. */
15 /* */
16 /* The copyright holder's institutional names and contributor's names may not */
17 /* be used to endorse or promote products derived from this software without */
18 /* specific prior written permission of the institution or contributor. */
19 /******************************************************************************/
20 
21 #include "XrdClHttpParseTimeout.hh"
22 
23 #include <stdexcept>
24 #include <cstring>
25 
26 bool XrdClHttp::ParseTimeout(const std::string &duration, struct timespec &result, std::string &errmsg) {
27 
28  if (duration.empty()) {
29  errmsg = "cannot parse empty string as a time duration";
30  return false;
31  }
32  if (duration == "0") {
33  result = {0, 0};
34  return true;
35  }
36  struct timespec ts = {0, 0};
37  auto strValue = duration;
38  while (!strValue.empty()) {
39  std::size_t pos;
40  double value;
41  try {
42  value = std::stod(strValue, &pos);
43  } catch (std::invalid_argument const &exc) {
44  errmsg = "Invalid number provided as timeout: " + strValue;
45  return false;
46  } catch (std::out_of_range const &exc) {
47  errmsg = "Provided timeout out of representable range: " + std::string(exc.what());
48  return false;
49  }
50  if (value < 0) {
51  errmsg = "Provided timeout was negative";
52  return false;
53  }
54  strValue = strValue.substr(pos);
55  char unit[3] = {'\0', '\0', '\0'};
56  if (!strValue.empty()) {
57  unit[0] = strValue[0];
58  if (unit[0] >= '0' && unit[0] <= '9') {unit[0] = '\0';}
59  }
60  if (strValue.size() > 1) {
61  unit[1] = strValue[1];
62  if (unit[1] >= '0' && unit[1] <= '9') {unit[1] = '\0';}
63  }
64  if (!strncmp(unit, "ns", 2)) {
65  ts.tv_nsec += value;
66  } else if (!strncmp(unit, "us", 2)) {
67  auto value_s = (static_cast<long long>(value)) / 1'000'000;
68  ts.tv_sec += value_s;
69  value -= value_s * 1'000'000;
70  ts.tv_nsec += value * 1'000'000;
71  } else if (!strncmp(unit, "ms", 2)) {
72  auto value_s = (static_cast<long long>(value)) / 1'000;
73  ts.tv_sec += value_s;
74  value -= value_s * 1'000;
75  ts.tv_nsec += value * 1'000'000;
76  } else if (!strncmp(unit, "s", 1)) {
77  auto value_s = (static_cast<long long>(value));
78  ts.tv_sec += value_s;
79  value -= value_s;
80  ts.tv_nsec += value * 1'000'000'000;
81  } else if (!strncmp(unit, "m", 1)) {
82  value *= 60;
83  auto value_s = (static_cast<long long>(value));
84  ts.tv_sec += value_s;
85  value -= value_s;
86  ts.tv_nsec += value * 1'000'000'000;
87  } else if (!strncmp(unit, "h", 1)) {
88  value *= 3600;
89  auto value_s = (static_cast<long long>(value));
90  ts.tv_sec += value_s;
91  value -= value_s;
92  ts.tv_nsec += value * 1'000'000'000;
93  } else if (strlen(unit) > 0) {
94  errmsg = "Unknown unit in duration: " + std::string(unit);
95  return false;
96  } else {
97  errmsg = "Unit missing from duration: " + duration;
98  return false;
99  }
100  if (ts.tv_nsec > 1'000'000'000) {
101  ts.tv_sec += ts.tv_nsec / 1'000'000'000;
102  ts.tv_nsec = ts.tv_nsec % 1'000'000'000;
103  }
104  strValue = strValue.substr(strlen(unit));
105  }
106  result.tv_nsec = ts.tv_nsec;
107  result.tv_sec = ts.tv_sec;
108  return true;
109 }
110 
111 std::string XrdClHttp::MarshalDuration(const struct timespec &duration)
112 {
113  if (duration.tv_sec == 0 && duration.tv_nsec == 0) {return "0s";}
114 
115  std::string result = duration.tv_sec != 0 ? std::to_string(duration.tv_sec) + "s" : "";
116  if (duration.tv_nsec) {
117  result += std::to_string(duration.tv_nsec / 1'000'000) + "ms";
118  }
119  return result;
120 }
static std::string ts()
timestamp output for logging messages
Definition: XrdCephOss.cc:53
bool ParseTimeout(const std::string &duration, struct timespec &, std::string &errmsg)
std::string MarshalDuration(const struct timespec &timeout)