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 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>{
|
||||
{http2::make_nv_ls_nocopy(":status", response_status),
|
||||
|
|
|
@ -933,8 +933,7 @@ void HttpsUpstream::error_reply(unsigned int status_code) {
|
|||
output->append("\r\nDate: ");
|
||||
auto lgconf = log_config();
|
||||
lgconf->update_tstamp(std::chrono::system_clock::now());
|
||||
auto &date = lgconf->time_http_str;
|
||||
output->append(date);
|
||||
output->append(lgconf->time_http);
|
||||
output->append("\r\nContent-Type: text/html; "
|
||||
"charset=UTF-8\r\nConnection: close\r\n\r\n");
|
||||
output->append(html);
|
||||
|
|
|
@ -138,7 +138,7 @@ Log::~Log() {
|
|||
auto tty = lgconf->errorlog_tty;
|
||||
|
||||
lgconf->update_tstamp(std::chrono::system_clock::now());
|
||||
auto &time_local = lgconf->time_local_str;
|
||||
auto &time_local = lgconf->time_local;
|
||||
|
||||
if (severity_ == NOTICE) {
|
||||
rv =
|
||||
|
@ -255,8 +255,8 @@ void upstream_accesslog(const std::vector<LogFragment> &lfv,
|
|||
auto avail = sizeof(buf) - 2;
|
||||
|
||||
lgconf->update_tstamp(lgsp.time_now);
|
||||
auto &time_local = lgconf->time_local_str;
|
||||
auto &time_iso8601 = lgconf->time_iso8601_str;
|
||||
auto &time_local = lgconf->time_local;
|
||||
auto &time_iso8601 = lgconf->time_iso8601;
|
||||
|
||||
for (auto &lf : lfv) {
|
||||
switch (lf.type) {
|
||||
|
|
|
@ -62,9 +62,9 @@ void LogConfig::update_tstamp(
|
|||
|
||||
time_str_updated_ = now;
|
||||
|
||||
time_local_str = util::format_common_log(now);
|
||||
time_iso8601_str = util::format_iso8601(now);
|
||||
time_http_str = util::format_http_date(now);
|
||||
time_local = util::format_common_log(time_local_buf.data(), now);
|
||||
time_iso8601 = util::format_iso8601(time_iso8601_buf.data(), now);
|
||||
time_http = util::format_http_date(time_http_buf.data(), now);
|
||||
}
|
||||
|
||||
} // namespace shrpx
|
||||
|
|
|
@ -29,13 +29,20 @@
|
|||
|
||||
#include <chrono>
|
||||
|
||||
#include "template.h"
|
||||
|
||||
using namespace nghttp2;
|
||||
|
||||
namespace shrpx {
|
||||
|
||||
struct LogConfig {
|
||||
std::chrono::system_clock::time_point time_str_updated_;
|
||||
std::string time_local_str;
|
||||
std::string time_iso8601_str;
|
||||
std::string time_http_str;
|
||||
std::array<char, sizeof("03/Jul/2014:00:19:38 +0900")> time_local_buf;
|
||||
std::array<char, sizeof("2014-11-15T12:58:24.741+09:00")> time_iso8601_buf;
|
||||
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 errorlog_fd;
|
||||
// true if errorlog_fd is referring to a terminal.
|
||||
|
|
|
@ -230,9 +230,8 @@ mrb_value response_return(mrb_state *mrb, mrb_value self) {
|
|||
if (!date) {
|
||||
auto lgconf = log_config();
|
||||
lgconf->update_tstamp(std::chrono::system_clock::now());
|
||||
resp.fs.add_header_token(
|
||||
StringRef::from_lit("date"),
|
||||
make_string_ref(balloc, StringRef{lgconf->time_http_str}), false,
|
||||
resp.fs.add_header_token(StringRef::from_lit("date"),
|
||||
make_string_ref(balloc, lgconf->time_http), false,
|
||||
http2::HD_DATE);
|
||||
}
|
||||
|
||||
|
|
|
@ -1003,8 +1003,8 @@ int SpdyUpstream::error_reply(Downstream *downstream,
|
|||
const char *nv[] = {":status", status_string.c_str(), ":version", "http/1.1",
|
||||
"content-type", "text/html; charset=UTF-8", "server",
|
||||
get_config()->http.server_name.c_str(), "content-length",
|
||||
content_length.c_str(), "date",
|
||||
lgconf->time_http_str.c_str(), nullptr};
|
||||
content_length.c_str(), "date", lgconf->time_http.c_str(),
|
||||
nullptr};
|
||||
|
||||
rv = spdylay_submit_response(session_, downstream->get_stream_id(), nv,
|
||||
&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
|
||||
|
||||
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;
|
||||
std::string res;
|
||||
|
||||
if (gmtime_r(&t, &tms) == nullptr) {
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Sat, 27 Sep 2014 06:31:15 GMT */
|
||||
res.resize(29);
|
||||
|
||||
auto p = std::begin(res);
|
||||
auto p = res;
|
||||
|
||||
auto s = DAY_OF_WEEK[tms.tm_wday];
|
||||
p = std::copy_n(s, 3, p);
|
||||
|
@ -242,22 +245,24 @@ std::string http_date(time_t t) {
|
|||
s = " GMT";
|
||||
p = std::copy_n(s, 4, p);
|
||||
|
||||
return res;
|
||||
return p;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (localtime_r(&t, &tms) == nullptr) {
|
||||
return "";
|
||||
return res;
|
||||
}
|
||||
|
||||
// Format data like this:
|
||||
// 03/Jul/2014:00:19:38 +0900
|
||||
std::string res;
|
||||
res.resize(26);
|
||||
|
||||
auto p = std::begin(res);
|
||||
auto p = res;
|
||||
|
||||
p = cpydig(p, tms.tm_mday, 2);
|
||||
*p++ = '/';
|
||||
|
@ -288,24 +293,27 @@ std::string common_log_date(time_t t) {
|
|||
p = cpydig(p, gmtoff / 3600, 2);
|
||||
p = cpydig(p, (gmtoff % 3600) / 60, 2);
|
||||
|
||||
return res;
|
||||
return p;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
tm tms;
|
||||
if (localtime_r(&sec, &tms) == nullptr) {
|
||||
return "";
|
||||
return res;
|
||||
}
|
||||
|
||||
// Format data like this:
|
||||
// 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);
|
||||
auto p = res;
|
||||
|
||||
p = cpydig(p, tms.tm_year + 1900, 4);
|
||||
*p++ = '-';
|
||||
|
@ -340,9 +348,7 @@ std::string iso8601_date(int64_t ms) {
|
|||
p = cpydig(p, (gmtoff % 3600) / 60, 2);
|
||||
}
|
||||
|
||||
res.resize(p - std::begin(res));
|
||||
|
||||
return res;
|
||||
return p;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// 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);
|
||||
// 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.,
|
||||
// 03/Jul/2014:00:19:38 +0900)
|
||||
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.,
|
||||
// 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);
|
||||
// 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);
|
||||
|
||||
|
@ -536,29 +550,55 @@ std::vector<std::string> parse_config_str_list(const StringRef &s,
|
|||
// treated as a part of substring.
|
||||
std::vector<StringRef> split_str(const StringRef &s, char delim);
|
||||
|
||||
// Returns given time |tp| in Common Log format (e.g.,
|
||||
// 03/Jul/2014:00:19:38 +0900)
|
||||
// Expected type of |tp| is std::chrono::timepoint
|
||||
template <typename T> std::string format_common_log(const T &tp) {
|
||||
// Writes given time |tp| in Common Log format (e.g.,
|
||||
// 03/Jul/2014:00:19:38 +0900) in buffer pointed by |out|. The buffer
|
||||
// must be at least 27 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_common_log(char *out, const T &tp) {
|
||||
auto t =
|
||||
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.,
|
||||
// 2014-11-15T12:58:24.741Z)
|
||||
// Expected type of |tp| is std::chrono::timepoint
|
||||
// 2014-11-15T12:58:24.741Z or 2014-11-15T12:58:24.741+09:00).
|
||||
// Expected type of |tp| is std::chrono::time_point
|
||||
template <typename T> std::string format_iso8601(const T &tp) {
|
||||
auto t = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
tp.time_since_epoch());
|
||||
return iso8601_date(t.count());
|
||||
}
|
||||
|
||||
// Returns given time |tp| in HTTP date format.
|
||||
template <typename T> std::string format_http_date(const T &tp) {
|
||||
// Writes given time |tp| in ISO 8601 format (e.g.,
|
||||
// 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 =
|
||||
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
|
||||
|
|
|
@ -194,6 +194,16 @@ void test_util_utox(void) {
|
|||
void test_util_http_date(void) {
|
||||
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));
|
||||
|
||||
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) {
|
||||
|
@ -446,6 +456,21 @@ void test_util_localtime_date(void) {
|
|||
CU_ASSERT_STRING_EQUAL("2001-10-02T00:34:56.123+12:00",
|
||||
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) {
|
||||
setenv("TZ", tz, 1);
|
||||
} else {
|
||||
|
|
Loading…
Reference in New Issue