nghttpx: Accept s or ms as unit for <T> argument

This commit is contained in:
Tatsuhiro Tsujikawa 2015-01-28 00:36:44 +09:00
parent 402ebb277f
commit 6a39de0ae5
7 changed files with 155 additions and 70 deletions

View File

@ -134,6 +134,8 @@ int main(int argc, char *argv[]) {
!CU_add_test(pSuite, "util_parse_uint_with_unit",
shrpx::test_util_parse_uint_with_unit) ||
!CU_add_test(pSuite, "util_parse_uint", shrpx::test_util_parse_uint) ||
!CU_add_test(pSuite, "util_parse_time_with_unit",
shrpx::test_util_parse_time_with_unit) ||
!CU_add_test(pSuite, "gzip_inflate", test_nghttp2_gzip_inflate) ||
!CU_add_test(pSuite, "ringbuf_write", nghttp2::test_ringbuf_write) ||
!CU_add_test(pSuite, "ringbuf_iovec", nghttp2::test_ringbuf_iovec) ||

View File

@ -902,46 +902,55 @@ Performance:
--num-accept=<N>
The number of connections acceptor can accept at once.
Default: )" << get_config()->num_accept << R"(
--accept-delay=<MSEC>
Acceptors get idle in <MSEC> milliseconds after they
--accept-delay=<T>
Acceptors get idle in <T> amount of time after they
accepted at most N connections, where N is defined in
--num-accept option.
Default: )" << static_cast<int>(get_config()->accept_delay * 1000)
Default: )" << util::duration_str(get_config()->accept_delay)
<< R"(
Timeout:
--frontend-http2-read-timeout=<SEC>
--frontend-http2-read-timeout=<T>
Specify read timeout for HTTP/2 and SPDY frontend
connection.
Default: )" << get_config()->http2_upstream_read_timeout << R"(
--frontend-read-timeout=<SEC>
Default: )"
<< util::duration_str(get_config()->http2_upstream_read_timeout) << R"(
--frontend-read-timeout=<T>
Specify read timeout for HTTP/1.1 frontend connection.
Default: )" << get_config()->upstream_read_timeout << R"(
--frontend-write-timeout=<SEC>
Default: )"
<< util::duration_str(get_config()->upstream_read_timeout) << R"(
--frontend-write-timeout=<T>
Specify write timeout for all frontend connections.
Default: )" << get_config()->upstream_write_timeout << R"(
--stream-read-timeout=<SEC>
Default: )"
<< util::duration_str(get_config()->upstream_write_timeout) << R"(
--stream-read-timeout=<T>
Specify read timeout for HTTP/2 and SPDY streams. 0
means no timeout.
Default: )" << get_config()->stream_read_timeout << R"(
--stream-write-timeout=<SEC>
Default: )"
<< util::duration_str(get_config()->stream_read_timeout) << R"(
--stream-write-timeout=<T>
Specify write timeout for HTTP/2 and SPDY streams. 0
means no timeout.
Default: )" << get_config()->stream_write_timeout << R"(
--backend-read-timeout=<SEC>
Default: )"
<< util::duration_str(get_config()->stream_write_timeout) << R"(
--backend-read-timeout=<T>
Specify read timeout for backend connection.
Default: )" << get_config()->downstream_read_timeout << R"(
--backend-write-timeout=<SEC>
Default: )"
<< util::duration_str(get_config()->downstream_read_timeout) << R"(
--backend-write-timeout=<T>
Specify write timeout for backend connection.
Default: )" << get_config()->downstream_write_timeout << R"(
--backend-keep-alive-timeout=<SEC>
Default: )"
<< util::duration_str(get_config()->downstream_write_timeout) << R"(
--backend-keep-alive-timeout=<T>
Specify keep-alive timeout for backend connection.
Default: )" << get_config()->downstream_idle_read_timeout << R"(
--listener-disable-timeout=<SEC>
Default: )"
<< util::duration_str(get_config()->downstream_idle_read_timeout) << R"(
--listener-disable-timeout=<T>
After accepting connection failed, connection listener
is disabled for a given time in seconds. Specifying 0
is disabled for a given amount of time. Specifying 0
disables this feature.
Default: )" << get_config()->listener_disable_timeout << R"(
Default: )"
<< util::duration_str(get_config()->listener_disable_timeout) << R"(
SSL/TLS:
--ciphers=<SUITE>
@ -1203,7 +1212,11 @@ Misc:
-h, --help Print this help and exit.
The <SIZE> argument is an integer and an optional unit (e.g., 10K is
10 * 1024). Units are K, M and G (powers of 1024).)" << std::endl;
10 * 1024). Units are K, M and G (powers of 1024).
The <T> argument is an integer and an optional unit (e.g., 1s is 1
second and 500ms is 500 milliseconds). Units are s or ms. If a
unit is omitted, a second is used as unit.)" << std::endl;
}
} // namespace

View File

@ -503,14 +503,14 @@ std::vector<LogFragment> parse_log_format(const char *optarg) {
}
namespace {
int parse_timeval(ev_tstamp *dest, const char *opt, const char *optarg) {
time_t sec;
if (parse_uint(&sec, opt, optarg) != 0) {
int parse_duration(ev_tstamp *dest, const char *opt, const char *optarg) {
auto t = util::parse_time_with_unit(optarg);
if (t == std::numeric_limits<double>::infinity()) {
LOG(ERROR) << opt << ": bad value: '" << optarg << "'";
return -1;
}
*dest = sec;
*dest = t;
return 0;
}
@ -604,32 +604,32 @@ int parse_config(const char *opt, const char *optarg) {
}
if (util::strieq(opt, SHRPX_OPT_FRONTEND_HTTP2_READ_TIMEOUT)) {
return parse_timeval(&mod_config()->http2_upstream_read_timeout, opt,
optarg);
return parse_duration(&mod_config()->http2_upstream_read_timeout, opt,
optarg);
}
if (util::strieq(opt, SHRPX_OPT_FRONTEND_READ_TIMEOUT)) {
return parse_timeval(&mod_config()->upstream_read_timeout, opt, optarg);
return parse_duration(&mod_config()->upstream_read_timeout, opt, optarg);
}
if (util::strieq(opt, SHRPX_OPT_FRONTEND_WRITE_TIMEOUT)) {
return parse_timeval(&mod_config()->upstream_write_timeout, opt, optarg);
return parse_duration(&mod_config()->upstream_write_timeout, opt, optarg);
}
if (util::strieq(opt, SHRPX_OPT_BACKEND_READ_TIMEOUT)) {
return parse_timeval(&mod_config()->downstream_read_timeout, opt, optarg);
return parse_duration(&mod_config()->downstream_read_timeout, opt, optarg);
}
if (util::strieq(opt, SHRPX_OPT_BACKEND_WRITE_TIMEOUT)) {
return parse_timeval(&mod_config()->downstream_write_timeout, opt, optarg);
return parse_duration(&mod_config()->downstream_write_timeout, opt, optarg);
}
if (util::strieq(opt, SHRPX_OPT_STREAM_READ_TIMEOUT)) {
return parse_timeval(&mod_config()->stream_read_timeout, opt, optarg);
return parse_duration(&mod_config()->stream_read_timeout, opt, optarg);
}
if (util::strieq(opt, SHRPX_OPT_STREAM_WRITE_TIMEOUT)) {
return parse_timeval(&mod_config()->stream_write_timeout, opt, optarg);
return parse_duration(&mod_config()->stream_write_timeout, opt, optarg);
}
if (util::strieq(opt, SHRPX_OPT_ACCESSLOG_FILE)) {
@ -663,8 +663,8 @@ int parse_config(const char *opt, const char *optarg) {
}
if (util::strieq(opt, SHRPX_OPT_BACKEND_KEEP_ALIVE_TIMEOUT)) {
return parse_timeval(&mod_config()->downstream_idle_read_timeout, opt,
optarg);
return parse_duration(&mod_config()->downstream_idle_read_timeout, opt,
optarg);
}
if (util::strieq(opt, SHRPX_OPT_FRONTEND_HTTP2_WINDOW_BITS) ||
@ -1104,7 +1104,7 @@ int parse_config(const char *opt, const char *optarg) {
}
if (util::strieq(opt, SHRPX_OPT_LISTENER_DISABLE_TIMEOUT)) {
return parse_timeval(&mod_config()->listener_disable_timeout, opt, optarg);
return parse_duration(&mod_config()->listener_disable_timeout, opt, optarg);
}
if (util::strieq(opt, SHRPX_OPT_TLS_TICKET_KEY_FILE)) {
@ -1170,14 +1170,7 @@ int parse_config(const char *opt, const char *optarg) {
}
if (util::strieq(opt, SHRPX_OPT_ACCEPT_DELAY)) {
size_t n;
if (parse_uint(&n, opt, optarg) != 0) {
return -1;
}
mod_config()->accept_delay = n / 1000.;
return 0;
return parse_duration(&mod_config()->accept_delay, opt, optarg);
}
if (util::strieq(opt, "conf")) {

View File

@ -899,32 +899,48 @@ bool ipv6_numeric_addr(const char *host) {
return inet_pton(AF_INET6, host, dst) == 1;
}
int64_t parse_uint_with_unit(const char *s) {
namespace {
std::pair<int64_t, size_t> parse_uint_digits(const void *ss, size_t len) {
const uint8_t *s = static_cast<const uint8_t *>(ss);
int64_t n = 0;
size_t i;
auto len = strlen(s);
if (len == 0) {
return -1;
return {-1, 0};
}
constexpr int64_t max = std::numeric_limits<int64_t>::max();
for (i = 0; i < len; ++i) {
if ('0' <= s[i] && s[i] <= '9') {
if (n > max / 10) {
return -1;
return {-1, 0};
}
n *= 10;
if (n > max - (s[i] - '0')) {
return -1;
return {-1, 0};
}
n += s[i] - '0';
continue;
}
break;
}
if (i == 0) {
return {-1, 0};
}
return {n, i};
}
} // namespace
int64_t parse_uint_with_unit(const char *s) {
int64_t n;
size_t i;
auto len = strlen(s);
std::tie(n, i) = parse_uint_digits(s, len);
if (n == -1) {
return -1;
}
if (i == len) {
return n;
}
if (i == 0 || i + 1 != len) {
if (i + 1 != len) {
return -1;
}
int mul = 1;
@ -944,6 +960,7 @@ int64_t parse_uint_with_unit(const char *s) {
default:
return -1;
}
constexpr int64_t max = std::numeric_limits<int64_t>::max();
if (n > max / mul) {
return -1;
}
@ -959,28 +976,53 @@ int64_t parse_uint(const std::string &s) {
}
int64_t parse_uint(const uint8_t *s, size_t len) {
if (len == 0) {
return -1;
}
constexpr int64_t max = std::numeric_limits<int64_t>::max();
int64_t n = 0;
for (size_t i = 0; i < len; ++i) {
if ('0' <= s[i] && s[i] <= '9') {
if (n > max / 10) {
return -1;
}
n *= 10;
if (n > max - (s[i] - '0')) {
return -1;
}
n += s[i] - '0';
continue;
}
int64_t n;
size_t i;
std::tie(n, i) = parse_uint_digits(s, len);
if (n == -1 || i != len) {
return -1;
}
return n;
}
double parse_time_with_unit(const char *s) {
int64_t n;
size_t i;
auto len = strlen(s);
std::tie(n, i) = parse_uint_digits(s, len);
if (n == -1) {
goto fail;
}
if (i == len) {
return static_cast<double>(n);
}
switch (s[i]) {
case 'S':
case 's':
if (i + 1 != len) {
goto fail;
}
return static_cast<double>(n);
break;
case 'M':
case 'm':
if (i + 2 != len || (s[i + 1] != 's' && s[i + 1] != 'S')) {
goto fail;
}
return static_cast<double>(n) / 1000.;
}
fail:
return std::numeric_limits<double>::infinity();
}
std::string duration_str(double t) {
auto frac = static_cast<int64_t>(t * 1000) % 1000;
if (frac > 0) {
return utos(static_cast<int64_t>(t * 1000)) + "ms";
}
return utos(static_cast<int64_t>(t)) + "s";
}
} // namespace util
} // namespace nghttp2

View File

@ -508,6 +508,20 @@ int64_t parse_uint(const char *s);
int64_t parse_uint(const uint8_t *s, size_t len);
int64_t parse_uint(const std::string &s);
// Parses NULL terminated string |s| as unsigned integer and returns
// the parsed integer casted to double. If |s| ends with "s", the
// parsed value's unit is a second. If |s| ends with "ms", the unit
// is millisecond. If none of them are given, the unit is second.
// This function returns std::numeric_limits<double>::infinity() if
// error occurs.
double parse_time_with_unit(const char *s);
// Returns string representation of time duration |t|. If t has
// fractional part (at least more than or equal to 1e-3), |t| is
// multiplied by 1000 and the unit "ms" is appended. Otherwise, |t|
// is left as is and "s" is appended.
std::string duration_str(double t);
} // namespace util
} // namespace nghttp2

View File

@ -223,4 +223,24 @@ void test_util_parse_uint(void) {
CU_ASSERT(-1 == util::parse_uint(""));
}
void test_util_parse_time_with_unit(void) {
CU_ASSERT(0. == util::parse_time_with_unit("0"));
CU_ASSERT(123. == util::parse_time_with_unit("123"));
CU_ASSERT(123. == util::parse_time_with_unit("123s"));
CU_ASSERT(0.500 == util::parse_time_with_unit("500ms"));
CU_ASSERT(123. == util::parse_time_with_unit("123S"));
CU_ASSERT(0.500 == util::parse_time_with_unit("500MS"));
auto err = std::numeric_limits<double>::infinity();
// check overflow case
CU_ASSERT(err == util::parse_time_with_unit("9223372036854775808"));
// bad characters
CU_ASSERT(err == util::parse_time_with_unit("0u"));
CU_ASSERT(err == util::parse_time_with_unit("0xs"));
CU_ASSERT(err == util::parse_time_with_unit("0mt"));
CU_ASSERT(err == util::parse_time_with_unit("0mss"));
CU_ASSERT(err == util::parse_time_with_unit("s"));
CU_ASSERT(err == util::parse_time_with_unit("ms"));
}
} // namespace shrpx

View File

@ -40,6 +40,7 @@ void test_util_ipv6_numeric_addr(void);
void test_util_utos_with_unit(void);
void test_util_parse_uint_with_unit(void);
void test_util_parse_uint(void);
void test_util_parse_time_with_unit(void);
} // namespace shrpx