12c593315Sopenharmony_ci/*
22c593315Sopenharmony_ci * nghttp2 - HTTP/2 C Library
32c593315Sopenharmony_ci *
42c593315Sopenharmony_ci * Copyright (c) 2016 Tatsuhiro Tsujikawa
52c593315Sopenharmony_ci *
62c593315Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining
72c593315Sopenharmony_ci * a copy of this software and associated documentation files (the
82c593315Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
92c593315Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
102c593315Sopenharmony_ci * distribute, sublicense, and/or sell copies of the Software, and to
112c593315Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
122c593315Sopenharmony_ci * the following conditions:
132c593315Sopenharmony_ci *
142c593315Sopenharmony_ci * The above copyright notice and this permission notice shall be
152c593315Sopenharmony_ci * included in all copies or substantial portions of the Software.
162c593315Sopenharmony_ci *
172c593315Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
182c593315Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
192c593315Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
202c593315Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
212c593315Sopenharmony_ci * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
222c593315Sopenharmony_ci * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
232c593315Sopenharmony_ci * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
242c593315Sopenharmony_ci */
252c593315Sopenharmony_ci#include "shrpx_api_downstream_connection.h"
262c593315Sopenharmony_ci
272c593315Sopenharmony_ci#include <sys/mman.h>
282c593315Sopenharmony_ci#include <fcntl.h>
292c593315Sopenharmony_ci#include <unistd.h>
302c593315Sopenharmony_ci#include <cstdlib>
312c593315Sopenharmony_ci
322c593315Sopenharmony_ci#include "shrpx_client_handler.h"
332c593315Sopenharmony_ci#include "shrpx_upstream.h"
342c593315Sopenharmony_ci#include "shrpx_downstream.h"
352c593315Sopenharmony_ci#include "shrpx_worker.h"
362c593315Sopenharmony_ci#include "shrpx_connection_handler.h"
372c593315Sopenharmony_ci#include "shrpx_log.h"
382c593315Sopenharmony_ci
392c593315Sopenharmony_cinamespace shrpx {
402c593315Sopenharmony_ci
412c593315Sopenharmony_cinamespace {
422c593315Sopenharmony_ci// List of API endpoints
432c593315Sopenharmony_ciconst std::array<APIEndpoint, 2> &apis() {
442c593315Sopenharmony_ci  static const auto apis = new std::array<APIEndpoint, 2>{
452c593315Sopenharmony_ci      APIEndpoint{
462c593315Sopenharmony_ci          StringRef::from_lit("/api/v1beta1/backendconfig"),
472c593315Sopenharmony_ci          true,
482c593315Sopenharmony_ci          (1 << API_METHOD_POST) | (1 << API_METHOD_PUT),
492c593315Sopenharmony_ci          &APIDownstreamConnection::handle_backendconfig,
502c593315Sopenharmony_ci      },
512c593315Sopenharmony_ci      APIEndpoint{
522c593315Sopenharmony_ci          StringRef::from_lit("/api/v1beta1/configrevision"),
532c593315Sopenharmony_ci          true,
542c593315Sopenharmony_ci          (1 << API_METHOD_GET),
552c593315Sopenharmony_ci          &APIDownstreamConnection::handle_configrevision,
562c593315Sopenharmony_ci      },
572c593315Sopenharmony_ci  };
582c593315Sopenharmony_ci
592c593315Sopenharmony_ci  return *apis;
602c593315Sopenharmony_ci}
612c593315Sopenharmony_ci} // namespace
622c593315Sopenharmony_ci
632c593315Sopenharmony_cinamespace {
642c593315Sopenharmony_ci// The method string.  This must be same order of APIMethod.
652c593315Sopenharmony_ciconstexpr StringRef API_METHOD_STRING[] = {
662c593315Sopenharmony_ci    StringRef::from_lit("GET"),
672c593315Sopenharmony_ci    StringRef::from_lit("POST"),
682c593315Sopenharmony_ci    StringRef::from_lit("PUT"),
692c593315Sopenharmony_ci};
702c593315Sopenharmony_ci} // namespace
712c593315Sopenharmony_ci
722c593315Sopenharmony_ciAPIDownstreamConnection::APIDownstreamConnection(Worker *worker)
732c593315Sopenharmony_ci    : worker_(worker), api_(nullptr), fd_(-1), shutdown_read_(false) {}
742c593315Sopenharmony_ci
752c593315Sopenharmony_ciAPIDownstreamConnection::~APIDownstreamConnection() {
762c593315Sopenharmony_ci  if (fd_ != -1) {
772c593315Sopenharmony_ci    close(fd_);
782c593315Sopenharmony_ci  }
792c593315Sopenharmony_ci}
802c593315Sopenharmony_ci
812c593315Sopenharmony_ciint APIDownstreamConnection::attach_downstream(Downstream *downstream) {
822c593315Sopenharmony_ci  if (LOG_ENABLED(INFO)) {
832c593315Sopenharmony_ci    DCLOG(INFO, this) << "Attaching to DOWNSTREAM:" << downstream;
842c593315Sopenharmony_ci  }
852c593315Sopenharmony_ci
862c593315Sopenharmony_ci  downstream_ = downstream;
872c593315Sopenharmony_ci
882c593315Sopenharmony_ci  return 0;
892c593315Sopenharmony_ci}
902c593315Sopenharmony_ci
912c593315Sopenharmony_civoid APIDownstreamConnection::detach_downstream(Downstream *downstream) {
922c593315Sopenharmony_ci  if (LOG_ENABLED(INFO)) {
932c593315Sopenharmony_ci    DCLOG(INFO, this) << "Detaching from DOWNSTREAM:" << downstream;
942c593315Sopenharmony_ci  }
952c593315Sopenharmony_ci  downstream_ = nullptr;
962c593315Sopenharmony_ci}
972c593315Sopenharmony_ci
982c593315Sopenharmony_ciint APIDownstreamConnection::send_reply(unsigned int http_status,
992c593315Sopenharmony_ci                                        APIStatusCode api_status,
1002c593315Sopenharmony_ci                                        const StringRef &data) {
1012c593315Sopenharmony_ci  shutdown_read_ = true;
1022c593315Sopenharmony_ci
1032c593315Sopenharmony_ci  auto upstream = downstream_->get_upstream();
1042c593315Sopenharmony_ci
1052c593315Sopenharmony_ci  auto &resp = downstream_->response();
1062c593315Sopenharmony_ci
1072c593315Sopenharmony_ci  resp.http_status = http_status;
1082c593315Sopenharmony_ci
1092c593315Sopenharmony_ci  auto &balloc = downstream_->get_block_allocator();
1102c593315Sopenharmony_ci
1112c593315Sopenharmony_ci  StringRef api_status_str;
1122c593315Sopenharmony_ci
1132c593315Sopenharmony_ci  switch (api_status) {
1142c593315Sopenharmony_ci  case APIStatusCode::SUCCESS:
1152c593315Sopenharmony_ci    api_status_str = StringRef::from_lit("Success");
1162c593315Sopenharmony_ci    break;
1172c593315Sopenharmony_ci  case APIStatusCode::FAILURE:
1182c593315Sopenharmony_ci    api_status_str = StringRef::from_lit("Failure");
1192c593315Sopenharmony_ci    break;
1202c593315Sopenharmony_ci  default:
1212c593315Sopenharmony_ci    assert(0);
1222c593315Sopenharmony_ci  }
1232c593315Sopenharmony_ci
1242c593315Sopenharmony_ci  constexpr auto M1 = StringRef::from_lit("{\"status\":\"");
1252c593315Sopenharmony_ci  constexpr auto M2 = StringRef::from_lit("\",\"code\":");
1262c593315Sopenharmony_ci  constexpr auto M3 = StringRef::from_lit("}");
1272c593315Sopenharmony_ci
1282c593315Sopenharmony_ci  // 3 is the number of digits in http_status, assuming it is 3 digits
1292c593315Sopenharmony_ci  // number.
1302c593315Sopenharmony_ci  auto buflen = M1.size() + M2.size() + M3.size() + data.size() +
1312c593315Sopenharmony_ci                api_status_str.size() + 3;
1322c593315Sopenharmony_ci
1332c593315Sopenharmony_ci  auto buf = make_byte_ref(balloc, buflen);
1342c593315Sopenharmony_ci  auto p = buf.base;
1352c593315Sopenharmony_ci
1362c593315Sopenharmony_ci  p = std::copy(std::begin(M1), std::end(M1), p);
1372c593315Sopenharmony_ci  p = std::copy(std::begin(api_status_str), std::end(api_status_str), p);
1382c593315Sopenharmony_ci  p = std::copy(std::begin(M2), std::end(M2), p);
1392c593315Sopenharmony_ci  p = util::utos(p, http_status);
1402c593315Sopenharmony_ci  p = std::copy(std::begin(data), std::end(data), p);
1412c593315Sopenharmony_ci  p = std::copy(std::begin(M3), std::end(M3), p);
1422c593315Sopenharmony_ci
1432c593315Sopenharmony_ci  buf.len = p - buf.base;
1442c593315Sopenharmony_ci
1452c593315Sopenharmony_ci  auto content_length = util::make_string_ref_uint(balloc, buf.len);
1462c593315Sopenharmony_ci
1472c593315Sopenharmony_ci  resp.fs.add_header_token(StringRef::from_lit("content-length"),
1482c593315Sopenharmony_ci                           content_length, false, http2::HD_CONTENT_LENGTH);
1492c593315Sopenharmony_ci
1502c593315Sopenharmony_ci  switch (http_status) {
1512c593315Sopenharmony_ci  case 400:
1522c593315Sopenharmony_ci  case 405:
1532c593315Sopenharmony_ci  case 413:
1542c593315Sopenharmony_ci    resp.fs.add_header_token(StringRef::from_lit("connection"),
1552c593315Sopenharmony_ci                             StringRef::from_lit("close"), false,
1562c593315Sopenharmony_ci                             http2::HD_CONNECTION);
1572c593315Sopenharmony_ci    break;
1582c593315Sopenharmony_ci  }
1592c593315Sopenharmony_ci
1602c593315Sopenharmony_ci  if (upstream->send_reply(downstream_, buf.base, buf.len) != 0) {
1612c593315Sopenharmony_ci    return -1;
1622c593315Sopenharmony_ci  }
1632c593315Sopenharmony_ci
1642c593315Sopenharmony_ci  return 0;
1652c593315Sopenharmony_ci}
1662c593315Sopenharmony_ci
1672c593315Sopenharmony_cinamespace {
1682c593315Sopenharmony_ciconst APIEndpoint *lookup_api(const StringRef &path) {
1692c593315Sopenharmony_ci  switch (path.size()) {
1702c593315Sopenharmony_ci  case 26:
1712c593315Sopenharmony_ci    switch (path[25]) {
1722c593315Sopenharmony_ci    case 'g':
1732c593315Sopenharmony_ci      if (util::streq_l("/api/v1beta1/backendconfi", std::begin(path), 25)) {
1742c593315Sopenharmony_ci        return &apis()[0];
1752c593315Sopenharmony_ci      }
1762c593315Sopenharmony_ci      break;
1772c593315Sopenharmony_ci    }
1782c593315Sopenharmony_ci    break;
1792c593315Sopenharmony_ci  case 27:
1802c593315Sopenharmony_ci    switch (path[26]) {
1812c593315Sopenharmony_ci    case 'n':
1822c593315Sopenharmony_ci      if (util::streq_l("/api/v1beta1/configrevisio", std::begin(path), 26)) {
1832c593315Sopenharmony_ci        return &apis()[1];
1842c593315Sopenharmony_ci      }
1852c593315Sopenharmony_ci      break;
1862c593315Sopenharmony_ci    }
1872c593315Sopenharmony_ci    break;
1882c593315Sopenharmony_ci  }
1892c593315Sopenharmony_ci  return nullptr;
1902c593315Sopenharmony_ci}
1912c593315Sopenharmony_ci} // namespace
1922c593315Sopenharmony_ci
1932c593315Sopenharmony_ciint APIDownstreamConnection::push_request_headers() {
1942c593315Sopenharmony_ci  auto &req = downstream_->request();
1952c593315Sopenharmony_ci
1962c593315Sopenharmony_ci  auto path =
1972c593315Sopenharmony_ci      StringRef{std::begin(req.path),
1982c593315Sopenharmony_ci                std::find(std::begin(req.path), std::end(req.path), '?')};
1992c593315Sopenharmony_ci
2002c593315Sopenharmony_ci  api_ = lookup_api(path);
2012c593315Sopenharmony_ci
2022c593315Sopenharmony_ci  if (!api_) {
2032c593315Sopenharmony_ci    send_reply(404, APIStatusCode::FAILURE);
2042c593315Sopenharmony_ci
2052c593315Sopenharmony_ci    return 0;
2062c593315Sopenharmony_ci  }
2072c593315Sopenharmony_ci
2082c593315Sopenharmony_ci  switch (req.method) {
2092c593315Sopenharmony_ci  case HTTP_GET:
2102c593315Sopenharmony_ci    if (!(api_->allowed_methods & (1 << API_METHOD_GET))) {
2112c593315Sopenharmony_ci      error_method_not_allowed();
2122c593315Sopenharmony_ci      return 0;
2132c593315Sopenharmony_ci    }
2142c593315Sopenharmony_ci    break;
2152c593315Sopenharmony_ci  case HTTP_POST:
2162c593315Sopenharmony_ci    if (!(api_->allowed_methods & (1 << API_METHOD_POST))) {
2172c593315Sopenharmony_ci      error_method_not_allowed();
2182c593315Sopenharmony_ci      return 0;
2192c593315Sopenharmony_ci    }
2202c593315Sopenharmony_ci    break;
2212c593315Sopenharmony_ci  case HTTP_PUT:
2222c593315Sopenharmony_ci    if (!(api_->allowed_methods & (1 << API_METHOD_PUT))) {
2232c593315Sopenharmony_ci      error_method_not_allowed();
2242c593315Sopenharmony_ci      return 0;
2252c593315Sopenharmony_ci    }
2262c593315Sopenharmony_ci    break;
2272c593315Sopenharmony_ci  default:
2282c593315Sopenharmony_ci    error_method_not_allowed();
2292c593315Sopenharmony_ci    return 0;
2302c593315Sopenharmony_ci  }
2312c593315Sopenharmony_ci
2322c593315Sopenharmony_ci  // This works with req.fs.content_length == -1
2332c593315Sopenharmony_ci  if (req.fs.content_length >
2342c593315Sopenharmony_ci      static_cast<int64_t>(get_config()->api.max_request_body)) {
2352c593315Sopenharmony_ci    send_reply(413, APIStatusCode::FAILURE);
2362c593315Sopenharmony_ci
2372c593315Sopenharmony_ci    return 0;
2382c593315Sopenharmony_ci  }
2392c593315Sopenharmony_ci
2402c593315Sopenharmony_ci  switch (req.method) {
2412c593315Sopenharmony_ci  case HTTP_POST:
2422c593315Sopenharmony_ci  case HTTP_PUT: {
2432c593315Sopenharmony_ci    char tempname[] = "/tmp/nghttpx-api.XXXXXX";
2442c593315Sopenharmony_ci#ifdef HAVE_MKOSTEMP
2452c593315Sopenharmony_ci    fd_ = mkostemp(tempname, O_CLOEXEC);
2462c593315Sopenharmony_ci#else  // !HAVE_MKOSTEMP
2472c593315Sopenharmony_ci    fd_ = mkstemp(tempname);
2482c593315Sopenharmony_ci#endif // !HAVE_MKOSTEMP
2492c593315Sopenharmony_ci    if (fd_ == -1) {
2502c593315Sopenharmony_ci      send_reply(500, APIStatusCode::FAILURE);
2512c593315Sopenharmony_ci
2522c593315Sopenharmony_ci      return 0;
2532c593315Sopenharmony_ci    }
2542c593315Sopenharmony_ci#ifndef HAVE_MKOSTEMP
2552c593315Sopenharmony_ci    util::make_socket_closeonexec(fd_);
2562c593315Sopenharmony_ci#endif // HAVE_MKOSTEMP
2572c593315Sopenharmony_ci    unlink(tempname);
2582c593315Sopenharmony_ci    break;
2592c593315Sopenharmony_ci  }
2602c593315Sopenharmony_ci  }
2612c593315Sopenharmony_ci
2622c593315Sopenharmony_ci  downstream_->set_request_header_sent(true);
2632c593315Sopenharmony_ci  auto src = downstream_->get_blocked_request_buf();
2642c593315Sopenharmony_ci  auto dest = downstream_->get_request_buf();
2652c593315Sopenharmony_ci  src->remove(*dest);
2662c593315Sopenharmony_ci
2672c593315Sopenharmony_ci  return 0;
2682c593315Sopenharmony_ci}
2692c593315Sopenharmony_ci
2702c593315Sopenharmony_ciint APIDownstreamConnection::error_method_not_allowed() {
2712c593315Sopenharmony_ci  auto &resp = downstream_->response();
2722c593315Sopenharmony_ci
2732c593315Sopenharmony_ci  size_t len = 0;
2742c593315Sopenharmony_ci  for (uint8_t i = 0; i < API_METHOD_MAX; ++i) {
2752c593315Sopenharmony_ci    if (api_->allowed_methods & (1 << i)) {
2762c593315Sopenharmony_ci      // The length of method + ", "
2772c593315Sopenharmony_ci      len += API_METHOD_STRING[i].size() + 2;
2782c593315Sopenharmony_ci    }
2792c593315Sopenharmony_ci  }
2802c593315Sopenharmony_ci
2812c593315Sopenharmony_ci  assert(len > 0);
2822c593315Sopenharmony_ci
2832c593315Sopenharmony_ci  auto &balloc = downstream_->get_block_allocator();
2842c593315Sopenharmony_ci
2852c593315Sopenharmony_ci  auto iov = make_byte_ref(balloc, len + 1);
2862c593315Sopenharmony_ci  auto p = iov.base;
2872c593315Sopenharmony_ci  for (uint8_t i = 0; i < API_METHOD_MAX; ++i) {
2882c593315Sopenharmony_ci    if (api_->allowed_methods & (1 << i)) {
2892c593315Sopenharmony_ci      auto &s = API_METHOD_STRING[i];
2902c593315Sopenharmony_ci      p = std::copy(std::begin(s), std::end(s), p);
2912c593315Sopenharmony_ci      p = std::copy_n(", ", 2, p);
2922c593315Sopenharmony_ci    }
2932c593315Sopenharmony_ci  }
2942c593315Sopenharmony_ci
2952c593315Sopenharmony_ci  p -= 2;
2962c593315Sopenharmony_ci  *p = '\0';
2972c593315Sopenharmony_ci
2982c593315Sopenharmony_ci  resp.fs.add_header_token(StringRef::from_lit("allow"), StringRef{iov.base, p},
2992c593315Sopenharmony_ci                           false, -1);
3002c593315Sopenharmony_ci  return send_reply(405, APIStatusCode::FAILURE);
3012c593315Sopenharmony_ci}
3022c593315Sopenharmony_ci
3032c593315Sopenharmony_ciint APIDownstreamConnection::push_upload_data_chunk(const uint8_t *data,
3042c593315Sopenharmony_ci                                                    size_t datalen) {
3052c593315Sopenharmony_ci  if (shutdown_read_ || !api_->require_body) {
3062c593315Sopenharmony_ci    return 0;
3072c593315Sopenharmony_ci  }
3082c593315Sopenharmony_ci
3092c593315Sopenharmony_ci  auto &req = downstream_->request();
3102c593315Sopenharmony_ci  auto &apiconf = get_config()->api;
3112c593315Sopenharmony_ci
3122c593315Sopenharmony_ci  if (static_cast<size_t>(req.recv_body_length) > apiconf.max_request_body) {
3132c593315Sopenharmony_ci    send_reply(413, APIStatusCode::FAILURE);
3142c593315Sopenharmony_ci
3152c593315Sopenharmony_ci    return 0;
3162c593315Sopenharmony_ci  }
3172c593315Sopenharmony_ci
3182c593315Sopenharmony_ci  ssize_t nwrite;
3192c593315Sopenharmony_ci  while ((nwrite = write(fd_, data, datalen)) == -1 && errno == EINTR)
3202c593315Sopenharmony_ci    ;
3212c593315Sopenharmony_ci  if (nwrite == -1) {
3222c593315Sopenharmony_ci    auto error = errno;
3232c593315Sopenharmony_ci    LOG(ERROR) << "Could not write API request body: errno=" << error;
3242c593315Sopenharmony_ci    send_reply(500, APIStatusCode::FAILURE);
3252c593315Sopenharmony_ci
3262c593315Sopenharmony_ci    return 0;
3272c593315Sopenharmony_ci  }
3282c593315Sopenharmony_ci
3292c593315Sopenharmony_ci  // We don't have to call Upstream::resume_read() here, because
3302c593315Sopenharmony_ci  // request buffer is effectively unlimited.  Actually, we cannot
3312c593315Sopenharmony_ci  // call it here since it could recursively call this function again.
3322c593315Sopenharmony_ci
3332c593315Sopenharmony_ci  return 0;
3342c593315Sopenharmony_ci}
3352c593315Sopenharmony_ci
3362c593315Sopenharmony_ciint APIDownstreamConnection::end_upload_data() {
3372c593315Sopenharmony_ci  if (shutdown_read_) {
3382c593315Sopenharmony_ci    return 0;
3392c593315Sopenharmony_ci  }
3402c593315Sopenharmony_ci
3412c593315Sopenharmony_ci  return api_->handler(*this);
3422c593315Sopenharmony_ci}
3432c593315Sopenharmony_ci
3442c593315Sopenharmony_ciint APIDownstreamConnection::handle_backendconfig() {
3452c593315Sopenharmony_ci  auto &req = downstream_->request();
3462c593315Sopenharmony_ci
3472c593315Sopenharmony_ci  if (req.recv_body_length == 0) {
3482c593315Sopenharmony_ci    send_reply(200, APIStatusCode::SUCCESS);
3492c593315Sopenharmony_ci
3502c593315Sopenharmony_ci    return 0;
3512c593315Sopenharmony_ci  }
3522c593315Sopenharmony_ci
3532c593315Sopenharmony_ci  auto rp = mmap(nullptr, req.recv_body_length, PROT_READ, MAP_SHARED, fd_, 0);
3542c593315Sopenharmony_ci  if (rp == reinterpret_cast<void *>(-1)) {
3552c593315Sopenharmony_ci    send_reply(500, APIStatusCode::FAILURE);
3562c593315Sopenharmony_ci    return 0;
3572c593315Sopenharmony_ci  }
3582c593315Sopenharmony_ci
3592c593315Sopenharmony_ci  auto unmapper = defer(munmap, rp, req.recv_body_length);
3602c593315Sopenharmony_ci
3612c593315Sopenharmony_ci  Config new_config{};
3622c593315Sopenharmony_ci  new_config.conn.downstream = std::make_shared<DownstreamConfig>();
3632c593315Sopenharmony_ci  const auto &downstreamconf = new_config.conn.downstream;
3642c593315Sopenharmony_ci
3652c593315Sopenharmony_ci  auto config = get_config();
3662c593315Sopenharmony_ci  auto &src = config->conn.downstream;
3672c593315Sopenharmony_ci
3682c593315Sopenharmony_ci  downstreamconf->timeout = src->timeout;
3692c593315Sopenharmony_ci  downstreamconf->connections_per_host = src->connections_per_host;
3702c593315Sopenharmony_ci  downstreamconf->connections_per_frontend = src->connections_per_frontend;
3712c593315Sopenharmony_ci  downstreamconf->request_buffer_size = src->request_buffer_size;
3722c593315Sopenharmony_ci  downstreamconf->response_buffer_size = src->response_buffer_size;
3732c593315Sopenharmony_ci  downstreamconf->family = src->family;
3742c593315Sopenharmony_ci
3752c593315Sopenharmony_ci  std::set<StringRef> include_set;
3762c593315Sopenharmony_ci  std::map<StringRef, size_t> pattern_addr_indexer;
3772c593315Sopenharmony_ci
3782c593315Sopenharmony_ci  for (auto first = reinterpret_cast<const uint8_t *>(rp),
3792c593315Sopenharmony_ci            last = first + req.recv_body_length;
3802c593315Sopenharmony_ci       first != last;) {
3812c593315Sopenharmony_ci    auto eol = std::find(first, last, '\n');
3822c593315Sopenharmony_ci    if (eol == last) {
3832c593315Sopenharmony_ci      break;
3842c593315Sopenharmony_ci    }
3852c593315Sopenharmony_ci
3862c593315Sopenharmony_ci    if (first == eol || *first == '#') {
3872c593315Sopenharmony_ci      first = ++eol;
3882c593315Sopenharmony_ci      continue;
3892c593315Sopenharmony_ci    }
3902c593315Sopenharmony_ci
3912c593315Sopenharmony_ci    auto eq = std::find(first, eol, '=');
3922c593315Sopenharmony_ci    if (eq == eol) {
3932c593315Sopenharmony_ci      send_reply(400, APIStatusCode::FAILURE);
3942c593315Sopenharmony_ci      return 0;
3952c593315Sopenharmony_ci    }
3962c593315Sopenharmony_ci
3972c593315Sopenharmony_ci    auto opt = StringRef{first, eq};
3982c593315Sopenharmony_ci    auto optval = StringRef{eq + 1, eol};
3992c593315Sopenharmony_ci
4002c593315Sopenharmony_ci    auto optid = option_lookup_token(opt.c_str(), opt.size());
4012c593315Sopenharmony_ci
4022c593315Sopenharmony_ci    switch (optid) {
4032c593315Sopenharmony_ci    case SHRPX_OPTID_BACKEND:
4042c593315Sopenharmony_ci      break;
4052c593315Sopenharmony_ci    default:
4062c593315Sopenharmony_ci      first = ++eol;
4072c593315Sopenharmony_ci      continue;
4082c593315Sopenharmony_ci    }
4092c593315Sopenharmony_ci
4102c593315Sopenharmony_ci    if (parse_config(&new_config, optid, opt, optval, include_set,
4112c593315Sopenharmony_ci                     pattern_addr_indexer) != 0) {
4122c593315Sopenharmony_ci      send_reply(400, APIStatusCode::FAILURE);
4132c593315Sopenharmony_ci      return 0;
4142c593315Sopenharmony_ci    }
4152c593315Sopenharmony_ci
4162c593315Sopenharmony_ci    first = ++eol;
4172c593315Sopenharmony_ci  }
4182c593315Sopenharmony_ci
4192c593315Sopenharmony_ci  auto &tlsconf = config->tls;
4202c593315Sopenharmony_ci  if (configure_downstream_group(&new_config, config->http2_proxy, true,
4212c593315Sopenharmony_ci                                 tlsconf) != 0) {
4222c593315Sopenharmony_ci    send_reply(400, APIStatusCode::FAILURE);
4232c593315Sopenharmony_ci    return 0;
4242c593315Sopenharmony_ci  }
4252c593315Sopenharmony_ci
4262c593315Sopenharmony_ci  auto conn_handler = worker_->get_connection_handler();
4272c593315Sopenharmony_ci
4282c593315Sopenharmony_ci  conn_handler->send_replace_downstream(downstreamconf);
4292c593315Sopenharmony_ci
4302c593315Sopenharmony_ci  send_reply(200, APIStatusCode::SUCCESS);
4312c593315Sopenharmony_ci
4322c593315Sopenharmony_ci  return 0;
4332c593315Sopenharmony_ci}
4342c593315Sopenharmony_ci
4352c593315Sopenharmony_ciint APIDownstreamConnection::handle_configrevision() {
4362c593315Sopenharmony_ci  auto config = get_config();
4372c593315Sopenharmony_ci  auto &balloc = downstream_->get_block_allocator();
4382c593315Sopenharmony_ci
4392c593315Sopenharmony_ci  // Construct the following string:
4402c593315Sopenharmony_ci  //   ,
4412c593315Sopenharmony_ci  //   "data":{
4422c593315Sopenharmony_ci  //     "configRevision": N
4432c593315Sopenharmony_ci  //   }
4442c593315Sopenharmony_ci  auto data = concat_string_ref(
4452c593315Sopenharmony_ci      balloc, StringRef::from_lit(R"(,"data":{"configRevision":)"),
4462c593315Sopenharmony_ci      util::make_string_ref_uint(balloc, config->config_revision),
4472c593315Sopenharmony_ci      StringRef::from_lit("}"));
4482c593315Sopenharmony_ci
4492c593315Sopenharmony_ci  send_reply(200, APIStatusCode::SUCCESS, data);
4502c593315Sopenharmony_ci
4512c593315Sopenharmony_ci  return 0;
4522c593315Sopenharmony_ci}
4532c593315Sopenharmony_ci
4542c593315Sopenharmony_civoid APIDownstreamConnection::pause_read(IOCtrlReason reason) {}
4552c593315Sopenharmony_ci
4562c593315Sopenharmony_ciint APIDownstreamConnection::resume_read(IOCtrlReason reason, size_t consumed) {
4572c593315Sopenharmony_ci  return 0;
4582c593315Sopenharmony_ci}
4592c593315Sopenharmony_ci
4602c593315Sopenharmony_civoid APIDownstreamConnection::force_resume_read() {}
4612c593315Sopenharmony_ci
4622c593315Sopenharmony_ciint APIDownstreamConnection::on_read() { return 0; }
4632c593315Sopenharmony_ci
4642c593315Sopenharmony_ciint APIDownstreamConnection::on_write() { return 0; }
4652c593315Sopenharmony_ci
4662c593315Sopenharmony_civoid APIDownstreamConnection::on_upstream_change(Upstream *upstream) {}
4672c593315Sopenharmony_ci
4682c593315Sopenharmony_cibool APIDownstreamConnection::poolable() const { return false; }
4692c593315Sopenharmony_ci
4702c593315Sopenharmony_ciconst std::shared_ptr<DownstreamAddrGroup> &
4712c593315Sopenharmony_ciAPIDownstreamConnection::get_downstream_addr_group() const {
4722c593315Sopenharmony_ci  static std::shared_ptr<DownstreamAddrGroup> s;
4732c593315Sopenharmony_ci  return s;
4742c593315Sopenharmony_ci}
4752c593315Sopenharmony_ci
4762c593315Sopenharmony_ciDownstreamAddr *APIDownstreamConnection::get_addr() const { return nullptr; }
4772c593315Sopenharmony_ci
4782c593315Sopenharmony_ci} // namespace shrpx
479