nghttpx: Use JSON for API resposne body

This commit is contained in:
Tatsuhiro Tsujikawa 2016-06-04 18:18:07 +09:00
parent 27fa9c3c12
commit aad2a24a22
2 changed files with 52 additions and 19 deletions

View File

@ -54,8 +54,15 @@ void APIDownstreamConnection::detach_downstream(Downstream *downstream) {
downstream_ = nullptr; downstream_ = nullptr;
} }
// API status, which is independent from HTTP status code. But
// generally, 2xx code for API_SUCCESS, and otherwise API_FAILURE.
enum {
API_SUCCESS,
API_FAILURE,
};
int APIDownstreamConnection::send_reply(unsigned int http_status, int APIDownstreamConnection::send_reply(unsigned int http_status,
const StringRef &body) { int api_status) {
abandoned_ = true; abandoned_ = true;
auto upstream = downstream_->get_upstream(); auto upstream = downstream_->get_upstream();
@ -66,7 +73,39 @@ int APIDownstreamConnection::send_reply(unsigned int http_status,
auto &balloc = downstream_->get_block_allocator(); auto &balloc = downstream_->get_block_allocator();
auto content_length = util::make_string_ref_uint(balloc, body.size()); StringRef api_status_str;
switch (api_status) {
case API_SUCCESS:
api_status_str = StringRef::from_lit("Success");
break;
case API_FAILURE:
api_status_str = StringRef::from_lit("Failure");
break;
default:
assert(0);
}
constexpr auto M1 = StringRef::from_lit("{\"status\":\"");
constexpr auto M2 = StringRef::from_lit("\",\"code\":");
constexpr auto M3 = StringRef::from_lit("}");
// 3 is the number of digits in http_status, assuming it is 3 digits
// number.
auto buflen = M1.size() + M2.size() + M3.size() + api_status_str.size() + 3;
auto buf = make_byte_ref(balloc, buflen);
auto p = buf.base;
p = std::copy(std::begin(M1), std::end(M1), p);
p = std::copy(std::begin(api_status_str), std::end(api_status_str), p);
p = std::copy(std::begin(M2), std::end(M2), p);
p = util::utos(p, http_status);
p = std::copy(std::begin(M3), std::end(M3), p);
buf.len = p - buf.base;
auto content_length = util::make_string_ref_uint(balloc, buf.len);
resp.fs.add_header_token(StringRef::from_lit("content-length"), resp.fs.add_header_token(StringRef::from_lit("content-length"),
content_length, false, http2::HD_CONTENT_LENGTH); content_length, false, http2::HD_CONTENT_LENGTH);
@ -81,7 +120,7 @@ int APIDownstreamConnection::send_reply(unsigned int http_status,
break; break;
} }
if (upstream->send_reply(downstream_, body.byte(), body.size()) != 0) { if (upstream->send_reply(downstream_, buf.base, buf.len) != 0) {
return -1; return -1;
} }
@ -93,7 +132,7 @@ int APIDownstreamConnection::push_request_headers() {
auto &resp = downstream_->response(); auto &resp = downstream_->response();
if (req.path != StringRef::from_lit("/api/v1alpha1/backend/replace")) { if (req.path != StringRef::from_lit("/api/v1alpha1/backend/replace")) {
send_reply(404, StringRef::from_lit("404 Not Found")); send_reply(404, API_FAILURE);
return 0; return 0;
} }
@ -101,8 +140,7 @@ int APIDownstreamConnection::push_request_headers() {
if (req.method != HTTP_POST && req.method != HTTP_PUT) { if (req.method != HTTP_POST && req.method != HTTP_PUT) {
resp.fs.add_header_token(StringRef::from_lit("allow"), resp.fs.add_header_token(StringRef::from_lit("allow"),
StringRef::from_lit("POST, PUT"), false, -1); StringRef::from_lit("POST, PUT"), false, -1);
send_reply( send_reply(405, API_FAILURE);
405, http2::get_status_string(downstream_->get_block_allocator(), 405));
return 0; return 0;
} }
@ -110,8 +148,7 @@ int APIDownstreamConnection::push_request_headers() {
// This works with req.fs.content_length == -1 // This works with req.fs.content_length == -1
if (req.fs.content_length > if (req.fs.content_length >
static_cast<int64_t>(get_config()->api.max_request_body)) { static_cast<int64_t>(get_config()->api.max_request_body)) {
send_reply( send_reply(413, API_FAILURE);
413, http2::get_status_string(downstream_->get_block_allocator(), 413));
return 0; return 0;
} }
@ -130,8 +167,7 @@ int APIDownstreamConnection::push_upload_data_chunk(const uint8_t *data,
auto &apiconf = get_config()->api; auto &apiconf = get_config()->api;
if (output->rleft() + datalen > apiconf.max_request_body) { if (output->rleft() + datalen > apiconf.max_request_body) {
send_reply( send_reply(413, API_FAILURE);
413, http2::get_status_string(downstream_->get_block_allocator(), 413));
return 0; return 0;
} }
@ -155,11 +191,8 @@ int APIDownstreamConnection::end_upload_data() {
struct iovec iov; struct iovec iov;
auto iovcnt = output->riovec(&iov, 2); auto iovcnt = output->riovec(&iov, 2);
constexpr auto body = StringRef::from_lit("200 OK");
constexpr auto error_body = StringRef::from_lit("400 Bad Request");
if (iovcnt == 0) { if (iovcnt == 0) {
send_reply(200, body); send_reply(200, API_SUCCESS);
return 0; return 0;
} }
@ -207,7 +240,7 @@ int APIDownstreamConnection::end_upload_data() {
auto eq = std::find(first, eol, '='); auto eq = std::find(first, eol, '=');
if (eq == eol) { if (eq == eol) {
send_reply(400, error_body); send_reply(400, API_FAILURE);
return 0; return 0;
} }
@ -225,7 +258,7 @@ int APIDownstreamConnection::end_upload_data() {
} }
if (parse_config(&config, optid, opt, optval, include_set) != 0) { if (parse_config(&config, optid, opt, optval, include_set) != 0) {
send_reply(400, error_body); send_reply(400, API_FAILURE);
return 0; return 0;
} }
@ -235,7 +268,7 @@ int APIDownstreamConnection::end_upload_data() {
auto &tlsconf = get_config()->tls; auto &tlsconf = get_config()->tls;
if (configure_downstream_group(&config, get_config()->http2_proxy, true, if (configure_downstream_group(&config, get_config()->http2_proxy, true,
tlsconf) != 0) { tlsconf) != 0) {
send_reply(400, error_body); send_reply(400, API_FAILURE);
return 0; return 0;
} }
@ -243,7 +276,7 @@ int APIDownstreamConnection::end_upload_data() {
conn_handler->send_replace_downstream(downstreamconf); conn_handler->send_replace_downstream(downstreamconf);
send_reply(200, body); send_reply(200, API_SUCCESS);
return 0; return 0;
} }

View File

@ -56,7 +56,7 @@ public:
virtual DownstreamAddrGroup *get_downstream_addr_group() const; virtual DownstreamAddrGroup *get_downstream_addr_group() const;
int send_reply(unsigned int http_status, const StringRef &body); int send_reply(unsigned int http_status, int api_status);
private: private:
Worker *worker_; Worker *worker_;