nghttpx: Add custom error pages

This commit is contained in:
Tatsuhiro Tsujikawa 2016-03-19 23:41:21 +09:00
parent db1ee3aa88
commit d7051f5207
14 changed files with 196 additions and 99 deletions

View File

@ -127,7 +127,8 @@ OPTIONS = [
"backend-http2-max-concurrent-streams", "backend-http2-max-concurrent-streams",
"backend-connections-per-frontend", "backend-connections-per-frontend",
"backend-tls", "backend-tls",
"backend-connections-per-host" "backend-connections-per-host",
"error-page",
] ]
LOGVARS = [ LOGVARS = [

View File

@ -1899,11 +1899,15 @@ void acceptcb(struct ev_loop *loop, ev_io *w, int revents) {
namespace { namespace {
FileEntry make_status_body(int status, uint16_t port) { FileEntry make_status_body(int status, uint16_t port) {
BlockAllocator balloc(1024, 1024);
auto status_string = http2::get_status_string(balloc, status);
std::string body; std::string body;
body = "<html><head><title>"; body = "<html><head><title>";
body += http2::get_status_string(status); body += status_string;
body += "</title></head><body><h1>"; body += "</title></head><body><h1>";
body += http2::get_status_string(status); body += status_string;
body += "</h1><hr><address>"; body += "</h1><hr><address>";
body += NGHTTPD_SERVER; body += NGHTTPD_SERVER;
body += " at port "; body += " at port ";

View File

@ -33,9 +33,10 @@ namespace server {
namespace { namespace {
std::string create_html(int status_code) { std::string create_html(int status_code) {
BlockAllocator balloc(1024, 1024);
std::string res; std::string res;
res.reserve(512); res.reserve(512);
auto status = ::nghttp2::http2::get_status_string(status_code); auto status = ::nghttp2::http2::get_status_string(balloc, status_code);
res += R"(<!DOCTYPE html><html lang="en"><title>)"; res += R"(<!DOCTYPE html><html lang="en"><title>)";
res += status; res += status;
res += "</title><body><h1>"; res += "</title><body><h1>";

View File

@ -30,111 +30,111 @@ namespace nghttp2 {
namespace http2 { namespace http2 {
std::string get_status_string(unsigned int status_code) { StringRef get_status_string(BlockAllocator &balloc, unsigned int status_code) {
switch (status_code) { switch (status_code) {
case 100: case 100:
return "100 Continue"; return StringRef::from_lit("100 Continue");
case 101: case 101:
return "101 Switching Protocols"; return StringRef::from_lit("101 Switching Protocols");
case 200: case 200:
return "200 OK"; return StringRef::from_lit("200 OK");
case 201: case 201:
return "201 Created"; return StringRef::from_lit("201 Created");
case 202: case 202:
return "202 Accepted"; return StringRef::from_lit("202 Accepted");
case 203: case 203:
return "203 Non-Authoritative Information"; return StringRef::from_lit("203 Non-Authoritative Information");
case 204: case 204:
return "204 No Content"; return StringRef::from_lit("204 No Content");
case 205: case 205:
return "205 Reset Content"; return StringRef::from_lit("205 Reset Content");
case 206: case 206:
return "206 Partial Content"; return StringRef::from_lit("206 Partial Content");
case 300: case 300:
return "300 Multiple Choices"; return StringRef::from_lit("300 Multiple Choices");
case 301: case 301:
return "301 Moved Permanently"; return StringRef::from_lit("301 Moved Permanently");
case 302: case 302:
return "302 Found"; return StringRef::from_lit("302 Found");
case 303: case 303:
return "303 See Other"; return StringRef::from_lit("303 See Other");
case 304: case 304:
return "304 Not Modified"; return StringRef::from_lit("304 Not Modified");
case 305: case 305:
return "305 Use Proxy"; return StringRef::from_lit("305 Use Proxy");
// case 306: return "306 (Unused)"; // case 306: return StringRef::from_lit("306 (Unused)");
case 307: case 307:
return "307 Temporary Redirect"; return StringRef::from_lit("307 Temporary Redirect");
case 308: case 308:
return "308 Permanent Redirect"; return StringRef::from_lit("308 Permanent Redirect");
case 400: case 400:
return "400 Bad Request"; return StringRef::from_lit("400 Bad Request");
case 401: case 401:
return "401 Unauthorized"; return StringRef::from_lit("401 Unauthorized");
case 402: case 402:
return "402 Payment Required"; return StringRef::from_lit("402 Payment Required");
case 403: case 403:
return "403 Forbidden"; return StringRef::from_lit("403 Forbidden");
case 404: case 404:
return "404 Not Found"; return StringRef::from_lit("404 Not Found");
case 405: case 405:
return "405 Method Not Allowed"; return StringRef::from_lit("405 Method Not Allowed");
case 406: case 406:
return "406 Not Acceptable"; return StringRef::from_lit("406 Not Acceptable");
case 407: case 407:
return "407 Proxy Authentication Required"; return StringRef::from_lit("407 Proxy Authentication Required");
case 408: case 408:
return "408 Request Timeout"; return StringRef::from_lit("408 Request Timeout");
case 409: case 409:
return "409 Conflict"; return StringRef::from_lit("409 Conflict");
case 410: case 410:
return "410 Gone"; return StringRef::from_lit("410 Gone");
case 411: case 411:
return "411 Length Required"; return StringRef::from_lit("411 Length Required");
case 412: case 412:
return "412 Precondition Failed"; return StringRef::from_lit("412 Precondition Failed");
case 413: case 413:
return "413 Payload Too Large"; return StringRef::from_lit("413 Payload Too Large");
case 414: case 414:
return "414 URI Too Long"; return StringRef::from_lit("414 URI Too Long");
case 415: case 415:
return "415 Unsupported Media Type"; return StringRef::from_lit("415 Unsupported Media Type");
case 416: case 416:
return "416 Requested Range Not Satisfiable"; return StringRef::from_lit("416 Requested Range Not Satisfiable");
case 417: case 417:
return "417 Expectation Failed"; return StringRef::from_lit("417 Expectation Failed");
case 421: case 421:
return "421 Misdirected Request"; return StringRef::from_lit("421 Misdirected Request");
case 426: case 426:
return "426 Upgrade Required"; return StringRef::from_lit("426 Upgrade Required");
case 428: case 428:
return "428 Precondition Required"; return StringRef::from_lit("428 Precondition Required");
case 429: case 429:
return "429 Too Many Requests"; return StringRef::from_lit("429 Too Many Requests");
case 431: case 431:
return "431 Request Header Fields Too Large"; return StringRef::from_lit("431 Request Header Fields Too Large");
case 451: case 451:
return "451 Unavailable For Legal Reasons"; return StringRef::from_lit("451 Unavailable For Legal Reasons");
case 500: case 500:
return "500 Internal Server Error"; return StringRef::from_lit("500 Internal Server Error");
case 501: case 501:
return "501 Not Implemented"; return StringRef::from_lit("501 Not Implemented");
case 502: case 502:
return "502 Bad Gateway"; return StringRef::from_lit("502 Bad Gateway");
case 503: case 503:
return "503 Service Unavailable"; return StringRef::from_lit("503 Service Unavailable");
case 504: case 504:
return "504 Gateway Timeout"; return StringRef::from_lit("504 Gateway Timeout");
case 505: case 505:
return "505 HTTP Version Not Supported"; return StringRef::from_lit("505 HTTP Version Not Supported");
case 511: case 511:
return "511 Network Authentication Required"; return StringRef::from_lit("511 Network Authentication Required");
default: default:
return util::utos(status_code); return util::make_string_ref_uint(balloc, status_code);
} }
} }
StringRef stringify_status(unsigned int status_code) { StringRef stringify_status(BlockAllocator &balloc, unsigned int status_code) {
switch (status_code) { switch (status_code) {
case 100: case 100:
return StringRef::from_lit("100"); return StringRef::from_lit("100");
@ -234,7 +234,7 @@ StringRef stringify_status(unsigned int status_code) {
case 511: case 511:
return StringRef::from_lit("511"); return StringRef::from_lit("511");
default: default:
return StringRef{}; return util::make_string_ref_uint(balloc, status_code);
} }
} }

View File

@ -94,11 +94,12 @@ using HeaderRefs = std::vector<HeaderRef>;
namespace http2 { namespace http2 {
std::string get_status_string(unsigned int status_code); // Returns string version of |status code| followed by reason
// string. (e.g., "404 Not Found").
StringRef get_status_string(BlockAllocator &balloc, unsigned int status_code);
// Returns string version of |status_code|. This function can handle // Returns string version of |status_code|. (e.g., "404")
// only predefined status code. Otherwise, returns nullptr. StringRef stringify_status(BlockAllocator &balloc, unsigned int status_code);
StringRef stringify_status(unsigned int status_code);
void capitalize(DefaultMemchunks *buf, const StringRef &s); void capitalize(DefaultMemchunks *buf, const StringRef &s);

View File

@ -1843,6 +1843,12 @@ HTTP:
towards this number. towards this number.
Default: )" << get_config()->http.max_response_header_fields Default: )" << get_config()->http.max_response_header_fields
<< R"( << R"(
--error-page=<CODE>=<PATH>
Set file path to custom error page served when nghttpx
originally generates HTTP error status code <CODE>.
<CODE> must be greater than or equal to 400, and at most
599. If error status code comes from backend server,
the custom error pages are not used.
Debug: Debug:
--frontend-http2-dump-request-header=<PATH> --frontend-http2-dump-request-header=<PATH>
@ -2464,6 +2470,7 @@ int main(int argc, char **argv) {
119}, 119},
{SHRPX_OPT_BACKEND_TLS, no_argument, &flag, 120}, {SHRPX_OPT_BACKEND_TLS, no_argument, &flag, 120},
{SHRPX_OPT_BACKEND_CONNECTIONS_PER_HOST, required_argument, &flag, 121}, {SHRPX_OPT_BACKEND_CONNECTIONS_PER_HOST, required_argument, &flag, 121},
{SHRPX_OPT_ERROR_PAGE, required_argument, &flag, 122},
{nullptr, 0, nullptr, 0}}; {nullptr, 0, nullptr, 0}};
int option_index = 0; int option_index = 0;
@ -2982,6 +2989,10 @@ int main(int argc, char **argv) {
// --backend-connections-per-host // --backend-connections-per-host
cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_CONNECTIONS_PER_HOST, optarg); cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_CONNECTIONS_PER_HOST, optarg);
break; break;
case 122:
// --error-page
cmdcfgs.emplace_back(SHRPX_OPT_ERROR_PAGE, optarg);
break;
default: default:
break; break;
} }

View File

@ -704,6 +704,57 @@ int parse_forwarded_node_type(const std::string &optarg) {
} }
} // namespace } // namespace
namespace {
int parse_error_page(std::vector<ErrorPage> &error_pages, const char *opt,
const char *optarg) {
auto arg = StringRef{optarg};
auto eq = std::find(std::begin(arg), std::end(arg), '=');
if (eq == std::end(arg) || eq + 1 == std::end(arg)) {
LOG(ERROR) << opt << ": bad value: '" << arg << "'";
return -1;
}
auto codestr = StringRef{std::begin(arg), eq};
auto code = util::parse_uint(codestr);
if (code == -1 || code < 400 || code > 599) {
LOG(ERROR) << opt << ": bad code: '" << codestr << "'";
return -1;
}
auto path = StringRef{eq + 1, std::end(arg)};
std::vector<uint8_t> content;
auto fd = open(path.c_str(), O_RDONLY);
if (fd == -1) {
auto error = errno;
LOG(ERROR) << opt << ": " << optarg << ": " << strerror(error);
return -1;
}
auto fd_closer = defer(close, fd);
std::array<uint8_t, 4096> buf;
for (;;) {
auto n = read(fd, buf.data(), buf.size());
if (n == -1) {
auto error = errno;
LOG(ERROR) << opt << ": " << optarg << ": " << strerror(error);
return -1;
}
if (n == 0) {
break;
}
content.insert(std::end(content), std::begin(buf), std::begin(buf) + n);
}
error_pages.push_back(
ErrorPage{std::move(content), static_cast<unsigned int>(code)});
return 0;
}
} // namespace
// generated by gennghttpxfun.py // generated by gennghttpxfun.py
enum { enum {
SHRPX_OPTID_ACCEPT_PROXY_PROTOCOL, SHRPX_OPTID_ACCEPT_PROXY_PROTOCOL,
@ -748,6 +799,7 @@ enum {
SHRPX_OPTID_CONF, SHRPX_OPTID_CONF,
SHRPX_OPTID_DAEMON, SHRPX_OPTID_DAEMON,
SHRPX_OPTID_DH_PARAM_FILE, SHRPX_OPTID_DH_PARAM_FILE,
SHRPX_OPTID_ERROR_PAGE,
SHRPX_OPTID_ERRORLOG_FILE, SHRPX_OPTID_ERRORLOG_FILE,
SHRPX_OPTID_ERRORLOG_SYSLOG, SHRPX_OPTID_ERRORLOG_SYSLOG,
SHRPX_OPTID_FASTOPEN, SHRPX_OPTID_FASTOPEN,
@ -963,6 +1015,9 @@ int option_lookup_token(const char *name, size_t namelen) {
case 10: case 10:
switch (name[9]) { switch (name[9]) {
case 'e': case 'e':
if (util::strieq_l("error-pag", name, 9)) {
return SHRPX_OPTID_ERROR_PAGE;
}
if (util::strieq_l("mruby-fil", name, 9)) { if (util::strieq_l("mruby-fil", name, 9)) {
return SHRPX_OPTID_MRUBY_FILE; return SHRPX_OPTID_MRUBY_FILE;
} }
@ -2437,6 +2492,8 @@ int parse_config(const char *opt, const char *optarg,
case SHRPX_OPTID_BACKEND_HTTP2_MAX_CONCURRENT_STREAMS: case SHRPX_OPTID_BACKEND_HTTP2_MAX_CONCURRENT_STREAMS:
return parse_uint(&mod_config()->http2.downstream.max_concurrent_streams, return parse_uint(&mod_config()->http2.downstream.max_concurrent_streams,
opt, optarg); opt, optarg);
case SHRPX_OPTID_ERROR_PAGE:
return parse_error_page(mod_config()->http.error_pages, opt, optarg);
case SHRPX_OPTID_CONF: case SHRPX_OPTID_CONF:
LOG(WARN) << "conf: ignored"; LOG(WARN) << "conf: ignored";

View File

@ -237,6 +237,7 @@ constexpr char SHRPX_OPT_BACKEND_CONNECTIONS_PER_FRONTEND[] =
constexpr char SHRPX_OPT_BACKEND_TLS[] = "backend-tls"; constexpr char SHRPX_OPT_BACKEND_TLS[] = "backend-tls";
constexpr char SHRPX_OPT_BACKEND_CONNECTIONS_PER_HOST[] = constexpr char SHRPX_OPT_BACKEND_CONNECTIONS_PER_HOST[] =
"backend-connections-per-host"; "backend-connections-per-host";
constexpr char SHRPX_OPT_ERROR_PAGE[] = "error-page";
constexpr size_t SHRPX_OBFUSCATED_NODE_LENGTH = 8; constexpr size_t SHRPX_OBFUSCATED_NODE_LENGTH = 8;
@ -438,6 +439,13 @@ struct TLSConfig {
bool no_http2_cipher_black_list; bool no_http2_cipher_black_list;
}; };
// custom error page
struct ErrorPage {
// not NULL-terminated
std::vector<uint8_t> content;
unsigned int http_status;
};
struct HttpConfig { struct HttpConfig {
struct { struct {
// obfuscated value used in "by" parameter of Forwarded header // obfuscated value used in "by" parameter of Forwarded header
@ -459,6 +467,7 @@ struct HttpConfig {
bool strip_incoming; bool strip_incoming;
} xff; } xff;
std::vector<AltSvc> altsvcs; std::vector<AltSvc> altsvcs;
std::vector<ErrorPage> error_pages;
Headers add_request_headers; Headers add_request_headers;
Headers add_response_headers; Headers add_response_headers;
StringRef server_name; StringRef server_name;

View File

@ -35,19 +35,33 @@ namespace shrpx {
namespace http { namespace http {
std::string create_error_html(unsigned int status_code) { StringRef create_error_html(BlockAllocator &balloc, unsigned int http_status) {
std::string res; auto &httpconf = get_config()->http;
res.reserve(512);
auto status = http2::get_status_string(status_code); const auto &error_pages = httpconf.error_pages;
res += R"(<!DOCTYPE html><html lang="en"><title>)"; for (const auto &page : error_pages) {
res += status; if (page.http_status == http_status) {
res += "</title><body><h1>"; return StringRef{std::begin(page.content), std::end(page.content)};
res += status; }
res += "</h1><footer>"; }
const auto &server_name = get_config()->http.server_name;
res.append(server_name.c_str(), server_name.size()); auto status_string = http2::get_status_string(balloc, http_status);
res += "</footer></body></html>"; const auto &server_name = httpconf.server_name;
return res;
size_t len = 256 + server_name.size() + status_string.size() * 2;
auto iov = make_byte_ref(balloc, len + 1);
auto p = iov.base;
p = util::copy_lit(p, R"(<!DOCTYPE html><html lang="en"><title>)");
p = std::copy(std::begin(status_string), std::end(status_string), p);
p = util::copy_lit(p, "</title><body><h1>");
p = std::copy(std::begin(status_string), std::end(status_string), p);
p = util::copy_lit(p, "</h1><footer>");
p = std::copy(std::begin(server_name), std::end(server_name), p);
p = util::copy_lit(p, "</footer></body></html>");
*p = '\0';
return StringRef{iov.base, p};
} }
StringRef create_forwarded(BlockAllocator &balloc, int params, StringRef create_forwarded(BlockAllocator &balloc, int params,

View File

@ -38,7 +38,7 @@ namespace shrpx {
namespace http { namespace http {
std::string create_error_html(unsigned int status_code); StringRef create_error_html(BlockAllocator &balloc, unsigned int status_code);
template <typename OutputIt> template <typename OutputIt>
OutputIt create_via_header_value(OutputIt dst, int major, int minor) { OutputIt create_via_header_value(OutputIt dst, int major, int minor) {

View File

@ -1241,10 +1241,7 @@ int Http2Upstream::send_reply(Downstream *downstream, const uint8_t *body,
// 2 for :status and server // 2 for :status and server
nva.reserve(2 + headers.size() + httpconf.add_response_headers.size()); nva.reserve(2 + headers.size() + httpconf.add_response_headers.size());
auto response_status = http2::stringify_status(resp.http_status); auto response_status = http2::stringify_status(balloc, resp.http_status);
if (response_status.empty()) {
response_status = util::make_string_ref_uint(balloc, resp.http_status);
}
nva.push_back(http2::make_nv_ls_nocopy(":status", response_status)); nva.push_back(http2::make_nv_ls_nocopy(":status", response_status));
@ -1297,7 +1294,7 @@ int Http2Upstream::error_reply(Downstream *downstream,
auto &balloc = downstream->get_block_allocator(); auto &balloc = downstream->get_block_allocator();
auto html = http::create_error_html(status_code); auto html = http::create_error_html(balloc, status_code);
resp.http_status = status_code; resp.http_status = status_code;
auto body = downstream->get_response_buf(); auto body = downstream->get_response_buf();
body->append(html); body->append(html);
@ -1310,11 +1307,7 @@ int Http2Upstream::error_reply(Downstream *downstream,
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 response_status = http2::stringify_status(status_code); auto response_status = http2::stringify_status(balloc, status_code);
if (response_status.empty()) {
response_status = util::make_string_ref_uint(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, StringRef{lgconf->time_http_str});
@ -1405,10 +1398,7 @@ int Http2Upstream::on_downstream_header_complete(Downstream *downstream) {
nva.reserve(resp.fs.headers().size() + 4 + nva.reserve(resp.fs.headers().size() + 4 +
httpconf.add_response_headers.size()); httpconf.add_response_headers.size());
auto response_status = http2::stringify_status(resp.http_status); auto response_status = http2::stringify_status(balloc, resp.http_status);
if (response_status.empty()) {
response_status = util::make_string_ref_uint(balloc, resp.http_status);
}
nva.push_back(http2::make_nv_ls_nocopy(":status", response_status)); nva.push_back(http2::make_nv_ls_nocopy(":status", response_status));

View File

@ -810,6 +810,7 @@ int HttpsUpstream::send_reply(Downstream *downstream, const uint8_t *body,
size_t bodylen) { size_t bodylen) {
const auto &req = downstream->request(); const auto &req = downstream->request();
auto &resp = downstream->response(); auto &resp = downstream->response();
auto &balloc = downstream->get_block_allocator();
auto connection_close = false; auto connection_close = false;
if (req.http_major <= 0 || (req.http_major == 1 && req.http_minor == 0)) { if (req.http_major <= 0 || (req.http_major == 1 && req.http_minor == 0)) {
@ -829,7 +830,7 @@ int HttpsUpstream::send_reply(Downstream *downstream, const uint8_t *body,
auto output = downstream->get_response_buf(); auto output = downstream->get_response_buf();
output->append("HTTP/1.1 "); output->append("HTTP/1.1 ");
output->append(http2::get_status_string(resp.http_status)); output->append(http2::get_status_string(balloc, resp.http_status));
output->append("\r\n"); output->append("\r\n");
for (auto &kv : resp.fs.headers()) { for (auto &kv : resp.fs.headers()) {
@ -868,7 +869,6 @@ int HttpsUpstream::send_reply(Downstream *downstream, const uint8_t *body,
} }
void HttpsUpstream::error_reply(unsigned int status_code) { void HttpsUpstream::error_reply(unsigned int status_code) {
auto html = http::create_error_html(status_code);
auto downstream = get_downstream(); auto downstream = get_downstream();
if (!downstream) { if (!downstream) {
@ -877,6 +877,9 @@ void HttpsUpstream::error_reply(unsigned int status_code) {
} }
auto &resp = downstream->response(); auto &resp = downstream->response();
auto &balloc = downstream->get_block_allocator();
auto html = http::create_error_html(balloc, status_code);
resp.http_status = status_code; resp.http_status = status_code;
// we are going to close connection for both frontend and backend in // we are going to close connection for both frontend and backend in
@ -887,7 +890,7 @@ void HttpsUpstream::error_reply(unsigned int status_code) {
auto output = downstream->get_response_buf(); auto output = downstream->get_response_buf();
output->append("HTTP/1.1 "); output->append("HTTP/1.1 ");
auto status_str = http2::get_status_string(status_code); auto status_str = http2::get_status_string(balloc, status_code);
output->append(status_str); output->append(status_str);
output->append("\r\nServer: "); output->append("\r\nServer: ");
output->append(get_config()->http.server_name); output->append(get_config()->http.server_name);
@ -948,6 +951,7 @@ int HttpsUpstream::on_downstream_header_complete(Downstream *downstream) {
const auto &req = downstream->request(); const auto &req = downstream->request();
auto &resp = downstream->response(); auto &resp = downstream->response();
auto &balloc = downstream->get_block_allocator();
#ifdef HAVE_MRUBY #ifdef HAVE_MRUBY
if (!downstream->get_non_final_response()) { if (!downstream->get_non_final_response()) {
@ -974,7 +978,7 @@ int HttpsUpstream::on_downstream_header_complete(Downstream *downstream) {
buf->append("."); buf->append(".");
buf->append(util::utos(req.http_minor)); buf->append(util::utos(req.http_minor));
buf->append(" "); buf->append(" ");
buf->append(http2::get_status_string(resp.http_status)); buf->append(http2::get_status_string(balloc, resp.http_status));
buf->append("\r\n"); buf->append("\r\n");
auto &httpconf = get_config()->http; auto &httpconf = get_config()->http;

View File

@ -856,8 +856,9 @@ int SpdyUpstream::send_reply(Downstream *downstream, const uint8_t *body,
} }
const auto &resp = downstream->response(); const auto &resp = downstream->response();
auto &balloc = downstream->get_block_allocator();
auto status_string = http2::get_status_string(resp.http_status); auto status_string = http2::get_status_string(balloc, resp.http_status);
const auto &headers = resp.fs.headers(); const auto &headers = resp.fs.headers();
@ -921,8 +922,9 @@ int SpdyUpstream::error_reply(Downstream *downstream,
unsigned int status_code) { unsigned int status_code) {
int rv; int rv;
auto &resp = downstream->response(); auto &resp = downstream->response();
auto &balloc = downstream->get_block_allocator();
auto html = http::create_error_html(status_code); auto html = http::create_error_html(balloc, status_code);
resp.http_status = status_code; resp.http_status = status_code;
auto body = downstream->get_response_buf(); auto body = downstream->get_response_buf();
body->append(html); body->append(html);
@ -935,8 +937,9 @@ int SpdyUpstream::error_reply(Downstream *downstream,
auto lgconf = log_config(); auto lgconf = log_config();
lgconf->update_tstamp(std::chrono::system_clock::now()); lgconf->update_tstamp(std::chrono::system_clock::now());
std::string content_length = util::utos(html.size()); auto content_length = util::make_string_ref_uint(balloc, html.size());
std::string status_string = http2::get_status_string(status_code); auto status_string = http2::get_status_string(balloc, status_code);
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",
@ -995,6 +998,7 @@ int SpdyUpstream::on_downstream_header_complete(Downstream *downstream) {
} }
const auto &req = downstream->request(); const auto &req = downstream->request();
auto &balloc = downstream->get_block_allocator();
#ifdef HAVE_MRUBY #ifdef HAVE_MRUBY
auto worker = handler_->get_worker(); auto worker = handler_->get_worker();
@ -1030,7 +1034,7 @@ int SpdyUpstream::on_downstream_header_complete(Downstream *downstream) {
size_t hdidx = 0; size_t hdidx = 0;
std::string via_value; std::string via_value;
auto status_string = http2::get_status_string(resp.http_status); auto status_string = http2::get_status_string(balloc, resp.http_status);
nv[hdidx++] = ":status"; nv[hdidx++] = ":status";
nv[hdidx++] = status_string.c_str(); nv[hdidx++] = status_string.c_str();
nv[hdidx++] = ":version"; nv[hdidx++] = ":version";

View File

@ -419,7 +419,8 @@ public:
: base(reinterpret_cast<const char *>(s)), len(n) {} : base(reinterpret_cast<const char *>(s)), len(n) {}
template <typename InputIt> template <typename InputIt>
StringRef(InputIt first, InputIt last) StringRef(InputIt first, InputIt last)
: base(&*first), len(std::distance(first, last)) {} : base(reinterpret_cast<const char *>(&*first)),
len(std::distance(first, last)) {}
template <typename InputIt> template <typename InputIt>
StringRef(InputIt *first, InputIt *last) StringRef(InputIt *first, InputIt *last)
: base(reinterpret_cast<const char *>(first)), : base(reinterpret_cast<const char *>(first)),