nghttpx: Use pre-allocated buffer for timestamp string
This commit is contained in:
parent
00a8c378d4
commit
1a37044d3c
|
@ -1488,7 +1488,7 @@ int Http2Upstream::error_reply(Downstream *downstream,
|
||||||
|
|
||||||
auto response_status = http2::stringify_status(balloc, status_code);
|
auto response_status = http2::stringify_status(balloc, status_code);
|
||||||
auto content_length = util::make_string_ref_uint(balloc, html.size());
|
auto content_length = util::make_string_ref_uint(balloc, html.size());
|
||||||
auto date = make_string_ref(balloc, StringRef{lgconf->time_http_str});
|
auto date = make_string_ref(balloc, lgconf->time_http);
|
||||||
|
|
||||||
auto nva = std::array<nghttp2_nv, 5>{
|
auto nva = std::array<nghttp2_nv, 5>{
|
||||||
{http2::make_nv_ls_nocopy(":status", response_status),
|
{http2::make_nv_ls_nocopy(":status", response_status),
|
||||||
|
|
|
@ -933,8 +933,7 @@ void HttpsUpstream::error_reply(unsigned int status_code) {
|
||||||
output->append("\r\nDate: ");
|
output->append("\r\nDate: ");
|
||||||
auto lgconf = log_config();
|
auto lgconf = log_config();
|
||||||
lgconf->update_tstamp(std::chrono::system_clock::now());
|
lgconf->update_tstamp(std::chrono::system_clock::now());
|
||||||
auto &date = lgconf->time_http_str;
|
output->append(lgconf->time_http);
|
||||||
output->append(date);
|
|
||||||
output->append("\r\nContent-Type: text/html; "
|
output->append("\r\nContent-Type: text/html; "
|
||||||
"charset=UTF-8\r\nConnection: close\r\n\r\n");
|
"charset=UTF-8\r\nConnection: close\r\n\r\n");
|
||||||
output->append(html);
|
output->append(html);
|
||||||
|
|
|
@ -138,7 +138,7 @@ Log::~Log() {
|
||||||
auto tty = lgconf->errorlog_tty;
|
auto tty = lgconf->errorlog_tty;
|
||||||
|
|
||||||
lgconf->update_tstamp(std::chrono::system_clock::now());
|
lgconf->update_tstamp(std::chrono::system_clock::now());
|
||||||
auto &time_local = lgconf->time_local_str;
|
auto &time_local = lgconf->time_local;
|
||||||
|
|
||||||
if (severity_ == NOTICE) {
|
if (severity_ == NOTICE) {
|
||||||
rv =
|
rv =
|
||||||
|
@ -255,8 +255,8 @@ void upstream_accesslog(const std::vector<LogFragment> &lfv,
|
||||||
auto avail = sizeof(buf) - 2;
|
auto avail = sizeof(buf) - 2;
|
||||||
|
|
||||||
lgconf->update_tstamp(lgsp.time_now);
|
lgconf->update_tstamp(lgsp.time_now);
|
||||||
auto &time_local = lgconf->time_local_str;
|
auto &time_local = lgconf->time_local;
|
||||||
auto &time_iso8601 = lgconf->time_iso8601_str;
|
auto &time_iso8601 = lgconf->time_iso8601;
|
||||||
|
|
||||||
for (auto &lf : lfv) {
|
for (auto &lf : lfv) {
|
||||||
switch (lf.type) {
|
switch (lf.type) {
|
||||||
|
|
|
@ -62,9 +62,9 @@ void LogConfig::update_tstamp(
|
||||||
|
|
||||||
time_str_updated_ = now;
|
time_str_updated_ = now;
|
||||||
|
|
||||||
time_local_str = util::format_common_log(now);
|
time_local = util::format_common_log(time_local_buf.data(), now);
|
||||||
time_iso8601_str = util::format_iso8601(now);
|
time_iso8601 = util::format_iso8601(time_iso8601_buf.data(), now);
|
||||||
time_http_str = util::format_http_date(now);
|
time_http = util::format_http_date(time_http_buf.data(), now);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace shrpx
|
} // namespace shrpx
|
||||||
|
|
|
@ -29,13 +29,20 @@
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
|
#include "template.h"
|
||||||
|
|
||||||
|
using namespace nghttp2;
|
||||||
|
|
||||||
namespace shrpx {
|
namespace shrpx {
|
||||||
|
|
||||||
struct LogConfig {
|
struct LogConfig {
|
||||||
std::chrono::system_clock::time_point time_str_updated_;
|
std::chrono::system_clock::time_point time_str_updated_;
|
||||||
std::string time_local_str;
|
std::array<char, sizeof("03/Jul/2014:00:19:38 +0900")> time_local_buf;
|
||||||
std::string time_iso8601_str;
|
std::array<char, sizeof("2014-11-15T12:58:24.741+09:00")> time_iso8601_buf;
|
||||||
std::string time_http_str;
|
std::array<char, sizeof("Mon, 10 Oct 2016 10:25:58 GMT")> time_http_buf;
|
||||||
|
StringRef time_local;
|
||||||
|
StringRef time_iso8601;
|
||||||
|
StringRef time_http;
|
||||||
int accesslog_fd;
|
int accesslog_fd;
|
||||||
int errorlog_fd;
|
int errorlog_fd;
|
||||||
// true if errorlog_fd is referring to a terminal.
|
// true if errorlog_fd is referring to a terminal.
|
||||||
|
|
|
@ -230,10 +230,9 @@ mrb_value response_return(mrb_state *mrb, mrb_value self) {
|
||||||
if (!date) {
|
if (!date) {
|
||||||
auto lgconf = log_config();
|
auto lgconf = log_config();
|
||||||
lgconf->update_tstamp(std::chrono::system_clock::now());
|
lgconf->update_tstamp(std::chrono::system_clock::now());
|
||||||
resp.fs.add_header_token(
|
resp.fs.add_header_token(StringRef::from_lit("date"),
|
||||||
StringRef::from_lit("date"),
|
make_string_ref(balloc, lgconf->time_http), false,
|
||||||
make_string_ref(balloc, StringRef{lgconf->time_http_str}), false,
|
http2::HD_DATE);
|
||||||
http2::HD_DATE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto upstream = downstream->get_upstream();
|
auto upstream = downstream->get_upstream();
|
||||||
|
|
|
@ -1003,8 +1003,8 @@ int SpdyUpstream::error_reply(Downstream *downstream,
|
||||||
const char *nv[] = {":status", status_string.c_str(), ":version", "http/1.1",
|
const char *nv[] = {":status", status_string.c_str(), ":version", "http/1.1",
|
||||||
"content-type", "text/html; charset=UTF-8", "server",
|
"content-type", "text/html; charset=UTF-8", "server",
|
||||||
get_config()->http.server_name.c_str(), "content-length",
|
get_config()->http.server_name.c_str(), "content-length",
|
||||||
content_length.c_str(), "date",
|
content_length.c_str(), "date", lgconf->time_http.c_str(),
|
||||||
lgconf->time_http_str.c_str(), nullptr};
|
nullptr};
|
||||||
|
|
||||||
rv = spdylay_submit_response(session_, downstream->get_stream_id(), nv,
|
rv = spdylay_submit_response(session_, downstream->get_stream_id(), nv,
|
||||||
&data_prd);
|
&data_prd);
|
||||||
|
|
56
src/util.cc
56
src/util.cc
|
@ -211,17 +211,20 @@ const char *DAY_OF_WEEK[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
std::string http_date(time_t t) {
|
std::string http_date(time_t t) {
|
||||||
|
/* Sat, 27 Sep 2014 06:31:15 GMT */
|
||||||
|
std::string res(29, 0);
|
||||||
|
http_date(&res[0], t);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *http_date(char *res, time_t t) {
|
||||||
struct tm tms;
|
struct tm tms;
|
||||||
std::string res;
|
|
||||||
|
|
||||||
if (gmtime_r(&t, &tms) == nullptr) {
|
if (gmtime_r(&t, &tms) == nullptr) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sat, 27 Sep 2014 06:31:15 GMT */
|
auto p = res;
|
||||||
res.resize(29);
|
|
||||||
|
|
||||||
auto p = std::begin(res);
|
|
||||||
|
|
||||||
auto s = DAY_OF_WEEK[tms.tm_wday];
|
auto s = DAY_OF_WEEK[tms.tm_wday];
|
||||||
p = std::copy_n(s, 3, p);
|
p = std::copy_n(s, 3, p);
|
||||||
|
@ -242,22 +245,24 @@ std::string http_date(time_t t) {
|
||||||
s = " GMT";
|
s = " GMT";
|
||||||
p = std::copy_n(s, 4, p);
|
p = std::copy_n(s, 4, p);
|
||||||
|
|
||||||
return res;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string common_log_date(time_t t) {
|
std::string common_log_date(time_t t) {
|
||||||
|
// 03/Jul/2014:00:19:38 +0900
|
||||||
|
std::string res(26, 0);
|
||||||
|
common_log_date(&res[0], t);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *common_log_date(char *res, time_t t) {
|
||||||
struct tm tms;
|
struct tm tms;
|
||||||
|
|
||||||
if (localtime_r(&t, &tms) == nullptr) {
|
if (localtime_r(&t, &tms) == nullptr) {
|
||||||
return "";
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format data like this:
|
auto p = res;
|
||||||
// 03/Jul/2014:00:19:38 +0900
|
|
||||||
std::string res;
|
|
||||||
res.resize(26);
|
|
||||||
|
|
||||||
auto p = std::begin(res);
|
|
||||||
|
|
||||||
p = cpydig(p, tms.tm_mday, 2);
|
p = cpydig(p, tms.tm_mday, 2);
|
||||||
*p++ = '/';
|
*p++ = '/';
|
||||||
|
@ -288,24 +293,27 @@ std::string common_log_date(time_t t) {
|
||||||
p = cpydig(p, gmtoff / 3600, 2);
|
p = cpydig(p, gmtoff / 3600, 2);
|
||||||
p = cpydig(p, (gmtoff % 3600) / 60, 2);
|
p = cpydig(p, (gmtoff % 3600) / 60, 2);
|
||||||
|
|
||||||
return res;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string iso8601_date(int64_t ms) {
|
std::string iso8601_date(int64_t ms) {
|
||||||
|
// 2014-11-15T12:58:24.741Z
|
||||||
|
// 2014-11-15T12:58:24.741+09:00
|
||||||
|
std::string res(29, 0);
|
||||||
|
auto p = iso8601_date(&res[0], ms);
|
||||||
|
res.resize(p - &res[0]);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *iso8601_date(char *res, int64_t ms) {
|
||||||
time_t sec = ms / 1000;
|
time_t sec = ms / 1000;
|
||||||
|
|
||||||
tm tms;
|
tm tms;
|
||||||
if (localtime_r(&sec, &tms) == nullptr) {
|
if (localtime_r(&sec, &tms) == nullptr) {
|
||||||
return "";
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format data like this:
|
auto p = res;
|
||||||
// 2014-11-15T12:58:24.741Z
|
|
||||||
// 2014-11-15T12:58:24.741+09:00
|
|
||||||
std::string res;
|
|
||||||
res.resize(29);
|
|
||||||
|
|
||||||
auto p = std::begin(res);
|
|
||||||
|
|
||||||
p = cpydig(p, tms.tm_year + 1900, 4);
|
p = cpydig(p, tms.tm_year + 1900, 4);
|
||||||
*p++ = '-';
|
*p++ = '-';
|
||||||
|
@ -340,9 +348,7 @@ std::string iso8601_date(int64_t ms) {
|
||||||
p = cpydig(p, (gmtoff % 3600) / 60, 2);
|
p = cpydig(p, (gmtoff % 3600) / 60, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
res.resize(p - std::begin(res));
|
return p;
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
time_t parse_http_date(const StringRef &s) {
|
time_t parse_http_date(const StringRef &s) {
|
||||||
|
|
62
src/util.h
62
src/util.h
|
@ -147,15 +147,29 @@ template <size_t N> std::string format_hex(const std::array<uint8_t, N> &s) {
|
||||||
|
|
||||||
StringRef format_hex(BlockAllocator &balloc, const StringRef &s);
|
StringRef format_hex(BlockAllocator &balloc, const StringRef &s);
|
||||||
|
|
||||||
|
// Returns given time |t| from epoch in HTTP Date format (e.g., Mon,
|
||||||
|
// 10 Oct 2016 10:25:58 GMT).
|
||||||
std::string http_date(time_t t);
|
std::string http_date(time_t t);
|
||||||
|
// Writes given time |t| from epoch in HTTP Date format into the
|
||||||
|
// buffer pointed by |res|. The buffer must be at least 29 bytes
|
||||||
|
// long. This function returns the one beyond the last position.
|
||||||
|
char *http_date(char *res, time_t t);
|
||||||
|
|
||||||
// Returns given time |t| from epoch in Common Log format (e.g.,
|
// Returns given time |t| from epoch in Common Log format (e.g.,
|
||||||
// 03/Jul/2014:00:19:38 +0900)
|
// 03/Jul/2014:00:19:38 +0900)
|
||||||
std::string common_log_date(time_t t);
|
std::string common_log_date(time_t t);
|
||||||
|
// Writes given time |t| from epoch in Common Log format into the
|
||||||
|
// buffer pointed by |res|. The buffer must be at least 26 bytes
|
||||||
|
// long. This function returns the one beyond the last position.
|
||||||
|
char *common_log_date(char *res, time_t t);
|
||||||
|
|
||||||
// Returns given millisecond |ms| from epoch in ISO 8601 format (e.g.,
|
// Returns given millisecond |ms| from epoch in ISO 8601 format (e.g.,
|
||||||
// 2014-11-15T12:58:24.741Z)
|
// 2014-11-15T12:58:24.741Z or 2014-11-15T12:58:24.741+09:00)
|
||||||
std::string iso8601_date(int64_t ms);
|
std::string iso8601_date(int64_t ms);
|
||||||
|
// Writes given time |t| from epoch in ISO 8601 format into the buffer
|
||||||
|
// pointed by |res|. The buffer must be at least 29 bytes long. This
|
||||||
|
// function returns the one beyond the last position.
|
||||||
|
char *iso8601_date(char *res, int64_t ms);
|
||||||
|
|
||||||
time_t parse_http_date(const StringRef &s);
|
time_t parse_http_date(const StringRef &s);
|
||||||
|
|
||||||
|
@ -536,29 +550,55 @@ std::vector<std::string> parse_config_str_list(const StringRef &s,
|
||||||
// treated as a part of substring.
|
// treated as a part of substring.
|
||||||
std::vector<StringRef> split_str(const StringRef &s, char delim);
|
std::vector<StringRef> split_str(const StringRef &s, char delim);
|
||||||
|
|
||||||
// Returns given time |tp| in Common Log format (e.g.,
|
// Writes given time |tp| in Common Log format (e.g.,
|
||||||
// 03/Jul/2014:00:19:38 +0900)
|
// 03/Jul/2014:00:19:38 +0900) in buffer pointed by |out|. The buffer
|
||||||
// Expected type of |tp| is std::chrono::timepoint
|
// must be at least 27 bytes, including terminal NULL byte. Expected
|
||||||
template <typename T> std::string format_common_log(const T &tp) {
|
// type of |tp| is std::chrono::time_point. This function returns
|
||||||
|
// StringRef wrapping the buffer pointed by |out|, and this string is
|
||||||
|
// terminated by NULL.
|
||||||
|
template <typename T> StringRef format_common_log(char *out, const T &tp) {
|
||||||
auto t =
|
auto t =
|
||||||
std::chrono::duration_cast<std::chrono::seconds>(tp.time_since_epoch());
|
std::chrono::duration_cast<std::chrono::seconds>(tp.time_since_epoch());
|
||||||
return common_log_date(t.count());
|
auto p = common_log_date(out, t.count());
|
||||||
|
*p = '\0';
|
||||||
|
return StringRef{out, p};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns given time |tp| in ISO 8601 format (e.g.,
|
// Returns given time |tp| in ISO 8601 format (e.g.,
|
||||||
// 2014-11-15T12:58:24.741Z)
|
// 2014-11-15T12:58:24.741Z or 2014-11-15T12:58:24.741+09:00).
|
||||||
// Expected type of |tp| is std::chrono::timepoint
|
// Expected type of |tp| is std::chrono::time_point
|
||||||
template <typename T> std::string format_iso8601(const T &tp) {
|
template <typename T> std::string format_iso8601(const T &tp) {
|
||||||
auto t = std::chrono::duration_cast<std::chrono::milliseconds>(
|
auto t = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||||
tp.time_since_epoch());
|
tp.time_since_epoch());
|
||||||
return iso8601_date(t.count());
|
return iso8601_date(t.count());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns given time |tp| in HTTP date format.
|
// Writes given time |tp| in ISO 8601 format (e.g.,
|
||||||
template <typename T> std::string format_http_date(const T &tp) {
|
// 2014-11-15T12:58:24.741Z or 2014-11-15T12:58:24.741+09:00) in
|
||||||
|
// buffer pointed by |out|. The buffer must be at least 30 bytes,
|
||||||
|
// including terminal NULL byte. Expected type of |tp| is
|
||||||
|
// std::chrono::time_point. This function returns StringRef wrapping
|
||||||
|
// the buffer pointed by |out|, and this string is terminated by NULL.
|
||||||
|
template <typename T> StringRef format_iso8601(char *out, const T &tp) {
|
||||||
|
auto t = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||||
|
tp.time_since_epoch());
|
||||||
|
auto p = iso8601_date(out, t.count());
|
||||||
|
*p = '\0';
|
||||||
|
return StringRef{out, p};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Writes given time |tp| in HTTP Date format (e.g., Mon, 10 Oct 2016
|
||||||
|
// 10:25:58 GMT) in buffer pointed by |out|. The buffer must be at
|
||||||
|
// least 30 bytes, including terminal NULL byte. Expected type of
|
||||||
|
// |tp| is std::chrono::time_point. This function returns StringRef
|
||||||
|
// wrapping the buffer pointed by |out|, and this string is terminated
|
||||||
|
// by NULL.
|
||||||
|
template <typename T> StringRef format_http_date(char *out, const T &tp) {
|
||||||
auto t =
|
auto t =
|
||||||
std::chrono::duration_cast<std::chrono::seconds>(tp.time_since_epoch());
|
std::chrono::duration_cast<std::chrono::seconds>(tp.time_since_epoch());
|
||||||
return http_date(t.count());
|
auto p = http_date(out, t.count());
|
||||||
|
*p = '\0';
|
||||||
|
return StringRef{out, p};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the system precision of the template parameter |Clock| as
|
// Return the system precision of the template parameter |Clock| as
|
||||||
|
|
|
@ -194,6 +194,16 @@ void test_util_utox(void) {
|
||||||
void test_util_http_date(void) {
|
void test_util_http_date(void) {
|
||||||
CU_ASSERT("Thu, 01 Jan 1970 00:00:00 GMT" == util::http_date(0));
|
CU_ASSERT("Thu, 01 Jan 1970 00:00:00 GMT" == util::http_date(0));
|
||||||
CU_ASSERT("Wed, 29 Feb 2012 09:15:16 GMT" == util::http_date(1330506916));
|
CU_ASSERT("Wed, 29 Feb 2012 09:15:16 GMT" == util::http_date(1330506916));
|
||||||
|
|
||||||
|
std::array<char, 30> http_buf;
|
||||||
|
|
||||||
|
CU_ASSERT("Thu, 01 Jan 1970 00:00:00 GMT" ==
|
||||||
|
util::format_http_date(http_buf.data(),
|
||||||
|
std::chrono::system_clock::time_point()));
|
||||||
|
CU_ASSERT("Wed, 29 Feb 2012 09:15:16 GMT" ==
|
||||||
|
util::format_http_date(http_buf.data(),
|
||||||
|
std::chrono::system_clock::time_point(
|
||||||
|
std::chrono::seconds(1330506916))));
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_util_select_h2(void) {
|
void test_util_select_h2(void) {
|
||||||
|
@ -446,6 +456,21 @@ void test_util_localtime_date(void) {
|
||||||
CU_ASSERT_STRING_EQUAL("2001-10-02T00:34:56.123+12:00",
|
CU_ASSERT_STRING_EQUAL("2001-10-02T00:34:56.123+12:00",
|
||||||
util::iso8601_date(1001939696000LL + 123).c_str());
|
util::iso8601_date(1001939696000LL + 123).c_str());
|
||||||
|
|
||||||
|
std::array<char, 27> common_buf;
|
||||||
|
|
||||||
|
CU_ASSERT("02/Oct/2001:00:34:56 +1200" ==
|
||||||
|
util::format_common_log(common_buf.data(),
|
||||||
|
std::chrono::system_clock::time_point(
|
||||||
|
std::chrono::seconds(1001939696))));
|
||||||
|
|
||||||
|
std::array<char, 30> iso8601_buf;
|
||||||
|
|
||||||
|
CU_ASSERT(
|
||||||
|
"2001-10-02T00:34:56.123+12:00" ==
|
||||||
|
util::format_iso8601(iso8601_buf.data(),
|
||||||
|
std::chrono::system_clock::time_point(
|
||||||
|
std::chrono::milliseconds(1001939696123LL))));
|
||||||
|
|
||||||
if (tz) {
|
if (tz) {
|
||||||
setenv("TZ", tz, 1);
|
setenv("TZ", tz, 1);
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in New Issue