12c593315Sopenharmony_ci/*
22c593315Sopenharmony_ci * nghttp2 - HTTP/2 C Library
32c593315Sopenharmony_ci *
42c593315Sopenharmony_ci * Copyright (c) 2012 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_client_handler.h"
262c593315Sopenharmony_ci
272c593315Sopenharmony_ci#ifdef HAVE_UNISTD_H
282c593315Sopenharmony_ci#  include <unistd.h>
292c593315Sopenharmony_ci#endif // HAVE_UNISTD_H
302c593315Sopenharmony_ci#ifdef HAVE_SYS_SOCKET_H
312c593315Sopenharmony_ci#  include <sys/socket.h>
322c593315Sopenharmony_ci#endif // HAVE_SYS_SOCKET_H
332c593315Sopenharmony_ci#ifdef HAVE_NETDB_H
342c593315Sopenharmony_ci#  include <netdb.h>
352c593315Sopenharmony_ci#endif // HAVE_NETDB_H
362c593315Sopenharmony_ci
372c593315Sopenharmony_ci#include <cerrno>
382c593315Sopenharmony_ci
392c593315Sopenharmony_ci#include "shrpx_upstream.h"
402c593315Sopenharmony_ci#include "shrpx_http2_upstream.h"
412c593315Sopenharmony_ci#include "shrpx_https_upstream.h"
422c593315Sopenharmony_ci#include "shrpx_config.h"
432c593315Sopenharmony_ci#include "shrpx_http_downstream_connection.h"
442c593315Sopenharmony_ci#include "shrpx_http2_downstream_connection.h"
452c593315Sopenharmony_ci#include "shrpx_tls.h"
462c593315Sopenharmony_ci#include "shrpx_worker.h"
472c593315Sopenharmony_ci#include "shrpx_downstream_connection_pool.h"
482c593315Sopenharmony_ci#include "shrpx_downstream.h"
492c593315Sopenharmony_ci#include "shrpx_http2_session.h"
502c593315Sopenharmony_ci#include "shrpx_connect_blocker.h"
512c593315Sopenharmony_ci#include "shrpx_api_downstream_connection.h"
522c593315Sopenharmony_ci#include "shrpx_health_monitor_downstream_connection.h"
532c593315Sopenharmony_ci#include "shrpx_null_downstream_connection.h"
542c593315Sopenharmony_ci#ifdef ENABLE_HTTP3
552c593315Sopenharmony_ci#  include "shrpx_http3_upstream.h"
562c593315Sopenharmony_ci#endif // ENABLE_HTTP3
572c593315Sopenharmony_ci#include "shrpx_log.h"
582c593315Sopenharmony_ci#include "util.h"
592c593315Sopenharmony_ci#include "template.h"
602c593315Sopenharmony_ci#include "tls.h"
612c593315Sopenharmony_ci
622c593315Sopenharmony_ciusing namespace nghttp2;
632c593315Sopenharmony_ci
642c593315Sopenharmony_cinamespace shrpx {
652c593315Sopenharmony_ci
662c593315Sopenharmony_cinamespace {
672c593315Sopenharmony_civoid timeoutcb(struct ev_loop *loop, ev_timer *w, int revents) {
682c593315Sopenharmony_ci  auto conn = static_cast<Connection *>(w->data);
692c593315Sopenharmony_ci  auto handler = static_cast<ClientHandler *>(conn->data);
702c593315Sopenharmony_ci
712c593315Sopenharmony_ci  if (LOG_ENABLED(INFO)) {
722c593315Sopenharmony_ci    CLOG(INFO, handler) << "Time out";
732c593315Sopenharmony_ci  }
742c593315Sopenharmony_ci
752c593315Sopenharmony_ci  delete handler;
762c593315Sopenharmony_ci}
772c593315Sopenharmony_ci} // namespace
782c593315Sopenharmony_ci
792c593315Sopenharmony_cinamespace {
802c593315Sopenharmony_civoid shutdowncb(struct ev_loop *loop, ev_timer *w, int revents) {
812c593315Sopenharmony_ci  auto handler = static_cast<ClientHandler *>(w->data);
822c593315Sopenharmony_ci
832c593315Sopenharmony_ci  if (LOG_ENABLED(INFO)) {
842c593315Sopenharmony_ci    CLOG(INFO, handler) << "Close connection due to TLS renegotiation";
852c593315Sopenharmony_ci  }
862c593315Sopenharmony_ci
872c593315Sopenharmony_ci  delete handler;
882c593315Sopenharmony_ci}
892c593315Sopenharmony_ci} // namespace
902c593315Sopenharmony_ci
912c593315Sopenharmony_cinamespace {
922c593315Sopenharmony_civoid readcb(struct ev_loop *loop, ev_io *w, int revents) {
932c593315Sopenharmony_ci  auto conn = static_cast<Connection *>(w->data);
942c593315Sopenharmony_ci  auto handler = static_cast<ClientHandler *>(conn->data);
952c593315Sopenharmony_ci
962c593315Sopenharmony_ci  if (handler->do_read() != 0) {
972c593315Sopenharmony_ci    delete handler;
982c593315Sopenharmony_ci    return;
992c593315Sopenharmony_ci  }
1002c593315Sopenharmony_ci}
1012c593315Sopenharmony_ci} // namespace
1022c593315Sopenharmony_ci
1032c593315Sopenharmony_cinamespace {
1042c593315Sopenharmony_civoid writecb(struct ev_loop *loop, ev_io *w, int revents) {
1052c593315Sopenharmony_ci  auto conn = static_cast<Connection *>(w->data);
1062c593315Sopenharmony_ci  auto handler = static_cast<ClientHandler *>(conn->data);
1072c593315Sopenharmony_ci
1082c593315Sopenharmony_ci  if (handler->do_write() != 0) {
1092c593315Sopenharmony_ci    delete handler;
1102c593315Sopenharmony_ci    return;
1112c593315Sopenharmony_ci  }
1122c593315Sopenharmony_ci}
1132c593315Sopenharmony_ci} // namespace
1142c593315Sopenharmony_ci
1152c593315Sopenharmony_ciint ClientHandler::noop() { return 0; }
1162c593315Sopenharmony_ci
1172c593315Sopenharmony_ciint ClientHandler::read_clear() {
1182c593315Sopenharmony_ci  auto should_break = false;
1192c593315Sopenharmony_ci  rb_.ensure_chunk();
1202c593315Sopenharmony_ci  for (;;) {
1212c593315Sopenharmony_ci    if (rb_.rleft() && on_read() != 0) {
1222c593315Sopenharmony_ci      return -1;
1232c593315Sopenharmony_ci    }
1242c593315Sopenharmony_ci    if (rb_.rleft() == 0) {
1252c593315Sopenharmony_ci      rb_.reset();
1262c593315Sopenharmony_ci    } else if (rb_.wleft() == 0) {
1272c593315Sopenharmony_ci      conn_.rlimit.stopw();
1282c593315Sopenharmony_ci      return 0;
1292c593315Sopenharmony_ci    }
1302c593315Sopenharmony_ci
1312c593315Sopenharmony_ci    if (!ev_is_active(&conn_.rev) || should_break) {
1322c593315Sopenharmony_ci      return 0;
1332c593315Sopenharmony_ci    }
1342c593315Sopenharmony_ci
1352c593315Sopenharmony_ci    auto nread = conn_.read_clear(rb_.last(), rb_.wleft());
1362c593315Sopenharmony_ci
1372c593315Sopenharmony_ci    if (nread == 0) {
1382c593315Sopenharmony_ci      if (rb_.rleft() == 0) {
1392c593315Sopenharmony_ci        rb_.release_chunk();
1402c593315Sopenharmony_ci      }
1412c593315Sopenharmony_ci      return 0;
1422c593315Sopenharmony_ci    }
1432c593315Sopenharmony_ci
1442c593315Sopenharmony_ci    if (nread < 0) {
1452c593315Sopenharmony_ci      return -1;
1462c593315Sopenharmony_ci    }
1472c593315Sopenharmony_ci
1482c593315Sopenharmony_ci    rb_.write(nread);
1492c593315Sopenharmony_ci    should_break = true;
1502c593315Sopenharmony_ci  }
1512c593315Sopenharmony_ci}
1522c593315Sopenharmony_ci
1532c593315Sopenharmony_ciint ClientHandler::write_clear() {
1542c593315Sopenharmony_ci  std::array<iovec, 2> iov;
1552c593315Sopenharmony_ci
1562c593315Sopenharmony_ci  for (;;) {
1572c593315Sopenharmony_ci    if (on_write() != 0) {
1582c593315Sopenharmony_ci      return -1;
1592c593315Sopenharmony_ci    }
1602c593315Sopenharmony_ci
1612c593315Sopenharmony_ci    auto iovcnt = upstream_->response_riovec(iov.data(), iov.size());
1622c593315Sopenharmony_ci    if (iovcnt == 0) {
1632c593315Sopenharmony_ci      break;
1642c593315Sopenharmony_ci    }
1652c593315Sopenharmony_ci
1662c593315Sopenharmony_ci    auto nwrite = conn_.writev_clear(iov.data(), iovcnt);
1672c593315Sopenharmony_ci    if (nwrite < 0) {
1682c593315Sopenharmony_ci      return -1;
1692c593315Sopenharmony_ci    }
1702c593315Sopenharmony_ci
1712c593315Sopenharmony_ci    if (nwrite == 0) {
1722c593315Sopenharmony_ci      return 0;
1732c593315Sopenharmony_ci    }
1742c593315Sopenharmony_ci
1752c593315Sopenharmony_ci    upstream_->response_drain(nwrite);
1762c593315Sopenharmony_ci  }
1772c593315Sopenharmony_ci
1782c593315Sopenharmony_ci  conn_.wlimit.stopw();
1792c593315Sopenharmony_ci  ev_timer_stop(conn_.loop, &conn_.wt);
1802c593315Sopenharmony_ci
1812c593315Sopenharmony_ci  return 0;
1822c593315Sopenharmony_ci}
1832c593315Sopenharmony_ci
1842c593315Sopenharmony_ciint ClientHandler::proxy_protocol_peek_clear() {
1852c593315Sopenharmony_ci  rb_.ensure_chunk();
1862c593315Sopenharmony_ci
1872c593315Sopenharmony_ci  assert(rb_.rleft() == 0);
1882c593315Sopenharmony_ci
1892c593315Sopenharmony_ci  auto nread = conn_.peek_clear(rb_.last(), rb_.wleft());
1902c593315Sopenharmony_ci  if (nread < 0) {
1912c593315Sopenharmony_ci    return -1;
1922c593315Sopenharmony_ci  }
1932c593315Sopenharmony_ci  if (nread == 0) {
1942c593315Sopenharmony_ci    return 0;
1952c593315Sopenharmony_ci  }
1962c593315Sopenharmony_ci
1972c593315Sopenharmony_ci  if (LOG_ENABLED(INFO)) {
1982c593315Sopenharmony_ci    CLOG(INFO, this) << "PROXY-protocol: Peek " << nread
1992c593315Sopenharmony_ci                     << " bytes from socket";
2002c593315Sopenharmony_ci  }
2012c593315Sopenharmony_ci
2022c593315Sopenharmony_ci  rb_.write(nread);
2032c593315Sopenharmony_ci
2042c593315Sopenharmony_ci  if (on_read() != 0) {
2052c593315Sopenharmony_ci    return -1;
2062c593315Sopenharmony_ci  }
2072c593315Sopenharmony_ci
2082c593315Sopenharmony_ci  rb_.reset();
2092c593315Sopenharmony_ci
2102c593315Sopenharmony_ci  return 0;
2112c593315Sopenharmony_ci}
2122c593315Sopenharmony_ci
2132c593315Sopenharmony_ciint ClientHandler::tls_handshake() {
2142c593315Sopenharmony_ci  ev_timer_again(conn_.loop, &conn_.rt);
2152c593315Sopenharmony_ci
2162c593315Sopenharmony_ci  ERR_clear_error();
2172c593315Sopenharmony_ci
2182c593315Sopenharmony_ci  auto rv = conn_.tls_handshake();
2192c593315Sopenharmony_ci
2202c593315Sopenharmony_ci  if (rv == SHRPX_ERR_INPROGRESS) {
2212c593315Sopenharmony_ci    return 0;
2222c593315Sopenharmony_ci  }
2232c593315Sopenharmony_ci
2242c593315Sopenharmony_ci  if (rv < 0) {
2252c593315Sopenharmony_ci    return -1;
2262c593315Sopenharmony_ci  }
2272c593315Sopenharmony_ci
2282c593315Sopenharmony_ci  if (LOG_ENABLED(INFO)) {
2292c593315Sopenharmony_ci    CLOG(INFO, this) << "SSL/TLS handshake completed";
2302c593315Sopenharmony_ci  }
2312c593315Sopenharmony_ci
2322c593315Sopenharmony_ci  if (validate_next_proto() != 0) {
2332c593315Sopenharmony_ci    return -1;
2342c593315Sopenharmony_ci  }
2352c593315Sopenharmony_ci
2362c593315Sopenharmony_ci  read_ = &ClientHandler::read_tls;
2372c593315Sopenharmony_ci  write_ = &ClientHandler::write_tls;
2382c593315Sopenharmony_ci
2392c593315Sopenharmony_ci  return 0;
2402c593315Sopenharmony_ci}
2412c593315Sopenharmony_ci
2422c593315Sopenharmony_ciint ClientHandler::read_tls() {
2432c593315Sopenharmony_ci  auto should_break = false;
2442c593315Sopenharmony_ci
2452c593315Sopenharmony_ci  ERR_clear_error();
2462c593315Sopenharmony_ci
2472c593315Sopenharmony_ci  rb_.ensure_chunk();
2482c593315Sopenharmony_ci
2492c593315Sopenharmony_ci  for (;;) {
2502c593315Sopenharmony_ci    // we should process buffered data first before we read EOF.
2512c593315Sopenharmony_ci    if (rb_.rleft() && on_read() != 0) {
2522c593315Sopenharmony_ci      return -1;
2532c593315Sopenharmony_ci    }
2542c593315Sopenharmony_ci    if (rb_.rleft() == 0) {
2552c593315Sopenharmony_ci      rb_.reset();
2562c593315Sopenharmony_ci    } else if (rb_.wleft() == 0) {
2572c593315Sopenharmony_ci      conn_.rlimit.stopw();
2582c593315Sopenharmony_ci      return 0;
2592c593315Sopenharmony_ci    }
2602c593315Sopenharmony_ci
2612c593315Sopenharmony_ci    if (!ev_is_active(&conn_.rev) || should_break) {
2622c593315Sopenharmony_ci      return 0;
2632c593315Sopenharmony_ci    }
2642c593315Sopenharmony_ci
2652c593315Sopenharmony_ci    auto nread = conn_.read_tls(rb_.last(), rb_.wleft());
2662c593315Sopenharmony_ci
2672c593315Sopenharmony_ci    if (nread == 0) {
2682c593315Sopenharmony_ci      if (rb_.rleft() == 0) {
2692c593315Sopenharmony_ci        rb_.release_chunk();
2702c593315Sopenharmony_ci      }
2712c593315Sopenharmony_ci      return 0;
2722c593315Sopenharmony_ci    }
2732c593315Sopenharmony_ci
2742c593315Sopenharmony_ci    if (nread < 0) {
2752c593315Sopenharmony_ci      return -1;
2762c593315Sopenharmony_ci    }
2772c593315Sopenharmony_ci
2782c593315Sopenharmony_ci    rb_.write(nread);
2792c593315Sopenharmony_ci    should_break = true;
2802c593315Sopenharmony_ci  }
2812c593315Sopenharmony_ci}
2822c593315Sopenharmony_ci
2832c593315Sopenharmony_ciint ClientHandler::write_tls() {
2842c593315Sopenharmony_ci  struct iovec iov;
2852c593315Sopenharmony_ci
2862c593315Sopenharmony_ci  ERR_clear_error();
2872c593315Sopenharmony_ci
2882c593315Sopenharmony_ci  if (on_write() != 0) {
2892c593315Sopenharmony_ci    return -1;
2902c593315Sopenharmony_ci  }
2912c593315Sopenharmony_ci
2922c593315Sopenharmony_ci  auto iovcnt = upstream_->response_riovec(&iov, 1);
2932c593315Sopenharmony_ci  if (iovcnt == 0) {
2942c593315Sopenharmony_ci    conn_.start_tls_write_idle();
2952c593315Sopenharmony_ci
2962c593315Sopenharmony_ci    conn_.wlimit.stopw();
2972c593315Sopenharmony_ci    ev_timer_stop(conn_.loop, &conn_.wt);
2982c593315Sopenharmony_ci
2992c593315Sopenharmony_ci    return 0;
3002c593315Sopenharmony_ci  }
3012c593315Sopenharmony_ci
3022c593315Sopenharmony_ci  for (;;) {
3032c593315Sopenharmony_ci    auto nwrite = conn_.write_tls(iov.iov_base, iov.iov_len);
3042c593315Sopenharmony_ci    if (nwrite < 0) {
3052c593315Sopenharmony_ci      return -1;
3062c593315Sopenharmony_ci    }
3072c593315Sopenharmony_ci
3082c593315Sopenharmony_ci    if (nwrite == 0) {
3092c593315Sopenharmony_ci      return 0;
3102c593315Sopenharmony_ci    }
3112c593315Sopenharmony_ci
3122c593315Sopenharmony_ci    upstream_->response_drain(nwrite);
3132c593315Sopenharmony_ci
3142c593315Sopenharmony_ci    iovcnt = upstream_->response_riovec(&iov, 1);
3152c593315Sopenharmony_ci    if (iovcnt == 0) {
3162c593315Sopenharmony_ci      return 0;
3172c593315Sopenharmony_ci    }
3182c593315Sopenharmony_ci  }
3192c593315Sopenharmony_ci}
3202c593315Sopenharmony_ci
3212c593315Sopenharmony_ci#ifdef ENABLE_HTTP3
3222c593315Sopenharmony_ciint ClientHandler::read_quic(const UpstreamAddr *faddr,
3232c593315Sopenharmony_ci                             const Address &remote_addr,
3242c593315Sopenharmony_ci                             const Address &local_addr,
3252c593315Sopenharmony_ci                             const ngtcp2_pkt_info &pi, const uint8_t *data,
3262c593315Sopenharmony_ci                             size_t datalen) {
3272c593315Sopenharmony_ci  auto upstream = static_cast<Http3Upstream *>(upstream_.get());
3282c593315Sopenharmony_ci
3292c593315Sopenharmony_ci  return upstream->on_read(faddr, remote_addr, local_addr, pi, data, datalen);
3302c593315Sopenharmony_ci}
3312c593315Sopenharmony_ci
3322c593315Sopenharmony_ciint ClientHandler::write_quic() { return upstream_->on_write(); }
3332c593315Sopenharmony_ci#endif // ENABLE_HTTP3
3342c593315Sopenharmony_ci
3352c593315Sopenharmony_ciint ClientHandler::upstream_noop() { return 0; }
3362c593315Sopenharmony_ci
3372c593315Sopenharmony_ciint ClientHandler::upstream_read() {
3382c593315Sopenharmony_ci  assert(upstream_);
3392c593315Sopenharmony_ci  if (upstream_->on_read() != 0) {
3402c593315Sopenharmony_ci    return -1;
3412c593315Sopenharmony_ci  }
3422c593315Sopenharmony_ci  return 0;
3432c593315Sopenharmony_ci}
3442c593315Sopenharmony_ci
3452c593315Sopenharmony_ciint ClientHandler::upstream_write() {
3462c593315Sopenharmony_ci  assert(upstream_);
3472c593315Sopenharmony_ci  if (upstream_->on_write() != 0) {
3482c593315Sopenharmony_ci    return -1;
3492c593315Sopenharmony_ci  }
3502c593315Sopenharmony_ci
3512c593315Sopenharmony_ci  if (get_should_close_after_write() && upstream_->response_empty()) {
3522c593315Sopenharmony_ci    return -1;
3532c593315Sopenharmony_ci  }
3542c593315Sopenharmony_ci
3552c593315Sopenharmony_ci  return 0;
3562c593315Sopenharmony_ci}
3572c593315Sopenharmony_ci
3582c593315Sopenharmony_ciint ClientHandler::upstream_http2_connhd_read() {
3592c593315Sopenharmony_ci  auto nread = std::min(left_connhd_len_, rb_.rleft());
3602c593315Sopenharmony_ci  if (memcmp(&NGHTTP2_CLIENT_MAGIC[NGHTTP2_CLIENT_MAGIC_LEN - left_connhd_len_],
3612c593315Sopenharmony_ci             rb_.pos(), nread) != 0) {
3622c593315Sopenharmony_ci    // There is no downgrade path here. Just drop the connection.
3632c593315Sopenharmony_ci    if (LOG_ENABLED(INFO)) {
3642c593315Sopenharmony_ci      CLOG(INFO, this) << "invalid client connection header";
3652c593315Sopenharmony_ci    }
3662c593315Sopenharmony_ci
3672c593315Sopenharmony_ci    return -1;
3682c593315Sopenharmony_ci  }
3692c593315Sopenharmony_ci
3702c593315Sopenharmony_ci  left_connhd_len_ -= nread;
3712c593315Sopenharmony_ci  rb_.drain(nread);
3722c593315Sopenharmony_ci  conn_.rlimit.startw();
3732c593315Sopenharmony_ci
3742c593315Sopenharmony_ci  if (left_connhd_len_ == 0) {
3752c593315Sopenharmony_ci    on_read_ = &ClientHandler::upstream_read;
3762c593315Sopenharmony_ci    // Run on_read to process data left in buffer since they are not
3772c593315Sopenharmony_ci    // notified further
3782c593315Sopenharmony_ci    if (on_read() != 0) {
3792c593315Sopenharmony_ci      return -1;
3802c593315Sopenharmony_ci    }
3812c593315Sopenharmony_ci    return 0;
3822c593315Sopenharmony_ci  }
3832c593315Sopenharmony_ci
3842c593315Sopenharmony_ci  return 0;
3852c593315Sopenharmony_ci}
3862c593315Sopenharmony_ci
3872c593315Sopenharmony_ciint ClientHandler::upstream_http1_connhd_read() {
3882c593315Sopenharmony_ci  auto nread = std::min(left_connhd_len_, rb_.rleft());
3892c593315Sopenharmony_ci  if (memcmp(&NGHTTP2_CLIENT_MAGIC[NGHTTP2_CLIENT_MAGIC_LEN - left_connhd_len_],
3902c593315Sopenharmony_ci             rb_.pos(), nread) != 0) {
3912c593315Sopenharmony_ci    if (LOG_ENABLED(INFO)) {
3922c593315Sopenharmony_ci      CLOG(INFO, this) << "This is HTTP/1.1 connection, "
3932c593315Sopenharmony_ci                       << "but may be upgraded to HTTP/2 later.";
3942c593315Sopenharmony_ci    }
3952c593315Sopenharmony_ci
3962c593315Sopenharmony_ci    // Reset header length for later HTTP/2 upgrade
3972c593315Sopenharmony_ci    left_connhd_len_ = NGHTTP2_CLIENT_MAGIC_LEN;
3982c593315Sopenharmony_ci    on_read_ = &ClientHandler::upstream_read;
3992c593315Sopenharmony_ci    on_write_ = &ClientHandler::upstream_write;
4002c593315Sopenharmony_ci
4012c593315Sopenharmony_ci    if (on_read() != 0) {
4022c593315Sopenharmony_ci      return -1;
4032c593315Sopenharmony_ci    }
4042c593315Sopenharmony_ci
4052c593315Sopenharmony_ci    return 0;
4062c593315Sopenharmony_ci  }
4072c593315Sopenharmony_ci
4082c593315Sopenharmony_ci  left_connhd_len_ -= nread;
4092c593315Sopenharmony_ci  rb_.drain(nread);
4102c593315Sopenharmony_ci  conn_.rlimit.startw();
4112c593315Sopenharmony_ci
4122c593315Sopenharmony_ci  if (left_connhd_len_ == 0) {
4132c593315Sopenharmony_ci    if (LOG_ENABLED(INFO)) {
4142c593315Sopenharmony_ci      CLOG(INFO, this) << "direct HTTP/2 connection";
4152c593315Sopenharmony_ci    }
4162c593315Sopenharmony_ci
4172c593315Sopenharmony_ci    direct_http2_upgrade();
4182c593315Sopenharmony_ci    on_read_ = &ClientHandler::upstream_read;
4192c593315Sopenharmony_ci    on_write_ = &ClientHandler::upstream_write;
4202c593315Sopenharmony_ci
4212c593315Sopenharmony_ci    // Run on_read to process data left in buffer since they are not
4222c593315Sopenharmony_ci    // notified further
4232c593315Sopenharmony_ci    if (on_read() != 0) {
4242c593315Sopenharmony_ci      return -1;
4252c593315Sopenharmony_ci    }
4262c593315Sopenharmony_ci
4272c593315Sopenharmony_ci    return 0;
4282c593315Sopenharmony_ci  }
4292c593315Sopenharmony_ci
4302c593315Sopenharmony_ci  return 0;
4312c593315Sopenharmony_ci}
4322c593315Sopenharmony_ci
4332c593315Sopenharmony_ciClientHandler::ClientHandler(Worker *worker, int fd, SSL *ssl,
4342c593315Sopenharmony_ci                             const StringRef &ipaddr, const StringRef &port,
4352c593315Sopenharmony_ci                             int family, const UpstreamAddr *faddr)
4362c593315Sopenharmony_ci    : // We use balloc_ for TLS session ID (64), ipaddr (IPv6) (39),
4372c593315Sopenharmony_ci      // port (5), forwarded-for (IPv6) (41), alpn (5), proxyproto
4382c593315Sopenharmony_ci      // ipaddr (15), proxyproto port (5), sni (32, estimated).  we
4392c593315Sopenharmony_ci      // need terminal NULL byte for each.  We also require 8 bytes
4402c593315Sopenharmony_ci      // header for each allocation.  We align at 16 bytes boundary,
4412c593315Sopenharmony_ci      // so the required space is 64 + 48 + 16 + 48 + 16 + 16 + 16 +
4422c593315Sopenharmony_ci      // 32 + 8 + 8 * 8 = 328.
4432c593315Sopenharmony_ci      balloc_(512, 512),
4442c593315Sopenharmony_ci      rb_(worker->get_mcpool()),
4452c593315Sopenharmony_ci      conn_(worker->get_loop(), fd, ssl, worker->get_mcpool(),
4462c593315Sopenharmony_ci            get_config()->conn.upstream.timeout.write,
4472c593315Sopenharmony_ci            get_config()->conn.upstream.timeout.read,
4482c593315Sopenharmony_ci            get_config()->conn.upstream.ratelimit.write,
4492c593315Sopenharmony_ci            get_config()->conn.upstream.ratelimit.read, writecb, readcb,
4502c593315Sopenharmony_ci            timeoutcb, this, get_config()->tls.dyn_rec.warmup_threshold,
4512c593315Sopenharmony_ci            get_config()->tls.dyn_rec.idle_timeout,
4522c593315Sopenharmony_ci            faddr->quic ? Proto::HTTP3 : Proto::NONE),
4532c593315Sopenharmony_ci      ipaddr_(make_string_ref(balloc_, ipaddr)),
4542c593315Sopenharmony_ci      port_(make_string_ref(balloc_, port)),
4552c593315Sopenharmony_ci      faddr_(faddr),
4562c593315Sopenharmony_ci      worker_(worker),
4572c593315Sopenharmony_ci      left_connhd_len_(NGHTTP2_CLIENT_MAGIC_LEN),
4582c593315Sopenharmony_ci      affinity_hash_(0),
4592c593315Sopenharmony_ci      should_close_after_write_(false),
4602c593315Sopenharmony_ci      affinity_hash_computed_(false) {
4612c593315Sopenharmony_ci
4622c593315Sopenharmony_ci  ++worker_->get_worker_stat()->num_connections;
4632c593315Sopenharmony_ci
4642c593315Sopenharmony_ci  ev_timer_init(&reneg_shutdown_timer_, shutdowncb, 0., 0.);
4652c593315Sopenharmony_ci
4662c593315Sopenharmony_ci  reneg_shutdown_timer_.data = this;
4672c593315Sopenharmony_ci
4682c593315Sopenharmony_ci  if (!faddr->quic) {
4692c593315Sopenharmony_ci    conn_.rlimit.startw();
4702c593315Sopenharmony_ci  }
4712c593315Sopenharmony_ci  ev_timer_again(conn_.loop, &conn_.rt);
4722c593315Sopenharmony_ci
4732c593315Sopenharmony_ci  auto config = get_config();
4742c593315Sopenharmony_ci
4752c593315Sopenharmony_ci  if (!faddr->quic) {
4762c593315Sopenharmony_ci    if (faddr_->accept_proxy_protocol ||
4772c593315Sopenharmony_ci        config->conn.upstream.accept_proxy_protocol) {
4782c593315Sopenharmony_ci      read_ = &ClientHandler::proxy_protocol_peek_clear;
4792c593315Sopenharmony_ci      write_ = &ClientHandler::noop;
4802c593315Sopenharmony_ci      on_read_ = &ClientHandler::proxy_protocol_read;
4812c593315Sopenharmony_ci      on_write_ = &ClientHandler::upstream_noop;
4822c593315Sopenharmony_ci    } else {
4832c593315Sopenharmony_ci      setup_upstream_io_callback();
4842c593315Sopenharmony_ci    }
4852c593315Sopenharmony_ci  }
4862c593315Sopenharmony_ci
4872c593315Sopenharmony_ci  auto &fwdconf = config->http.forwarded;
4882c593315Sopenharmony_ci
4892c593315Sopenharmony_ci  if (fwdconf.params & FORWARDED_FOR) {
4902c593315Sopenharmony_ci    if (fwdconf.for_node_type == ForwardedNode::OBFUSCATED) {
4912c593315Sopenharmony_ci      // 1 for '_'
4922c593315Sopenharmony_ci      auto len = SHRPX_OBFUSCATED_NODE_LENGTH + 1;
4932c593315Sopenharmony_ci      // 1 for terminating NUL.
4942c593315Sopenharmony_ci      auto buf = make_byte_ref(balloc_, len + 1);
4952c593315Sopenharmony_ci      auto p = buf.base;
4962c593315Sopenharmony_ci      *p++ = '_';
4972c593315Sopenharmony_ci      p = util::random_alpha_digit(p, p + SHRPX_OBFUSCATED_NODE_LENGTH,
4982c593315Sopenharmony_ci                                   worker_->get_randgen());
4992c593315Sopenharmony_ci      *p = '\0';
5002c593315Sopenharmony_ci
5012c593315Sopenharmony_ci      forwarded_for_ = StringRef{buf.base, p};
5022c593315Sopenharmony_ci    } else {
5032c593315Sopenharmony_ci      init_forwarded_for(family, ipaddr_);
5042c593315Sopenharmony_ci    }
5052c593315Sopenharmony_ci  }
5062c593315Sopenharmony_ci}
5072c593315Sopenharmony_ci
5082c593315Sopenharmony_civoid ClientHandler::init_forwarded_for(int family, const StringRef &ipaddr) {
5092c593315Sopenharmony_ci  if (family == AF_INET6) {
5102c593315Sopenharmony_ci    // 2 for '[' and ']'
5112c593315Sopenharmony_ci    auto len = 2 + ipaddr.size();
5122c593315Sopenharmony_ci    // 1 for terminating NUL.
5132c593315Sopenharmony_ci    auto buf = make_byte_ref(balloc_, len + 1);
5142c593315Sopenharmony_ci    auto p = buf.base;
5152c593315Sopenharmony_ci    *p++ = '[';
5162c593315Sopenharmony_ci    p = std::copy(std::begin(ipaddr), std::end(ipaddr), p);
5172c593315Sopenharmony_ci    *p++ = ']';
5182c593315Sopenharmony_ci    *p = '\0';
5192c593315Sopenharmony_ci
5202c593315Sopenharmony_ci    forwarded_for_ = StringRef{buf.base, p};
5212c593315Sopenharmony_ci  } else {
5222c593315Sopenharmony_ci    // family == AF_INET or family == AF_UNIX
5232c593315Sopenharmony_ci    forwarded_for_ = ipaddr;
5242c593315Sopenharmony_ci  }
5252c593315Sopenharmony_ci}
5262c593315Sopenharmony_ci
5272c593315Sopenharmony_civoid ClientHandler::setup_upstream_io_callback() {
5282c593315Sopenharmony_ci  if (conn_.tls.ssl) {
5292c593315Sopenharmony_ci    conn_.prepare_server_handshake();
5302c593315Sopenharmony_ci    read_ = write_ = &ClientHandler::tls_handshake;
5312c593315Sopenharmony_ci    on_read_ = &ClientHandler::upstream_noop;
5322c593315Sopenharmony_ci    on_write_ = &ClientHandler::upstream_write;
5332c593315Sopenharmony_ci  } else {
5342c593315Sopenharmony_ci    // For non-TLS version, first create HttpsUpstream. It may be
5352c593315Sopenharmony_ci    // upgraded to HTTP/2 through HTTP Upgrade or direct HTTP/2
5362c593315Sopenharmony_ci    // connection.
5372c593315Sopenharmony_ci    upstream_ = std::make_unique<HttpsUpstream>(this);
5382c593315Sopenharmony_ci    alpn_ = StringRef::from_lit("http/1.1");
5392c593315Sopenharmony_ci    read_ = &ClientHandler::read_clear;
5402c593315Sopenharmony_ci    write_ = &ClientHandler::write_clear;
5412c593315Sopenharmony_ci    on_read_ = &ClientHandler::upstream_http1_connhd_read;
5422c593315Sopenharmony_ci    on_write_ = &ClientHandler::upstream_noop;
5432c593315Sopenharmony_ci  }
5442c593315Sopenharmony_ci}
5452c593315Sopenharmony_ci
5462c593315Sopenharmony_ci#ifdef ENABLE_HTTP3
5472c593315Sopenharmony_civoid ClientHandler::setup_http3_upstream(
5482c593315Sopenharmony_ci    std::unique_ptr<Http3Upstream> &&upstream) {
5492c593315Sopenharmony_ci  upstream_ = std::move(upstream);
5502c593315Sopenharmony_ci  write_ = &ClientHandler::write_quic;
5512c593315Sopenharmony_ci
5522c593315Sopenharmony_ci  auto config = get_config();
5532c593315Sopenharmony_ci
5542c593315Sopenharmony_ci  reset_upstream_read_timeout(config->conn.upstream.timeout.http3_read);
5552c593315Sopenharmony_ci}
5562c593315Sopenharmony_ci#endif // ENABLE_HTTP3
5572c593315Sopenharmony_ci
5582c593315Sopenharmony_ciClientHandler::~ClientHandler() {
5592c593315Sopenharmony_ci  if (LOG_ENABLED(INFO)) {
5602c593315Sopenharmony_ci    CLOG(INFO, this) << "Deleting";
5612c593315Sopenharmony_ci  }
5622c593315Sopenharmony_ci
5632c593315Sopenharmony_ci  if (upstream_) {
5642c593315Sopenharmony_ci    upstream_->on_handler_delete();
5652c593315Sopenharmony_ci  }
5662c593315Sopenharmony_ci
5672c593315Sopenharmony_ci  auto worker_stat = worker_->get_worker_stat();
5682c593315Sopenharmony_ci  --worker_stat->num_connections;
5692c593315Sopenharmony_ci
5702c593315Sopenharmony_ci  if (worker_stat->num_connections == 0) {
5712c593315Sopenharmony_ci    worker_->schedule_clear_mcpool();
5722c593315Sopenharmony_ci  }
5732c593315Sopenharmony_ci
5742c593315Sopenharmony_ci  ev_timer_stop(conn_.loop, &reneg_shutdown_timer_);
5752c593315Sopenharmony_ci
5762c593315Sopenharmony_ci  // TODO If backend is http/2, and it is in CONNECTED state, signal
5772c593315Sopenharmony_ci  // it and make it loopbreak when output is zero.
5782c593315Sopenharmony_ci  if (worker_->get_graceful_shutdown() && worker_stat->num_connections == 0 &&
5792c593315Sopenharmony_ci      worker_stat->num_close_waits == 0) {
5802c593315Sopenharmony_ci    ev_break(conn_.loop);
5812c593315Sopenharmony_ci  }
5822c593315Sopenharmony_ci
5832c593315Sopenharmony_ci  if (LOG_ENABLED(INFO)) {
5842c593315Sopenharmony_ci    CLOG(INFO, this) << "Deleted";
5852c593315Sopenharmony_ci  }
5862c593315Sopenharmony_ci}
5872c593315Sopenharmony_ci
5882c593315Sopenharmony_ciUpstream *ClientHandler::get_upstream() { return upstream_.get(); }
5892c593315Sopenharmony_ci
5902c593315Sopenharmony_cistruct ev_loop *ClientHandler::get_loop() const {
5912c593315Sopenharmony_ci  return conn_.loop;
5922c593315Sopenharmony_ci}
5932c593315Sopenharmony_ci
5942c593315Sopenharmony_civoid ClientHandler::reset_upstream_read_timeout(ev_tstamp t) {
5952c593315Sopenharmony_ci  conn_.rt.repeat = t;
5962c593315Sopenharmony_ci  if (ev_is_active(&conn_.rt)) {
5972c593315Sopenharmony_ci    ev_timer_again(conn_.loop, &conn_.rt);
5982c593315Sopenharmony_ci  }
5992c593315Sopenharmony_ci}
6002c593315Sopenharmony_ci
6012c593315Sopenharmony_civoid ClientHandler::reset_upstream_write_timeout(ev_tstamp t) {
6022c593315Sopenharmony_ci  conn_.wt.repeat = t;
6032c593315Sopenharmony_ci  if (ev_is_active(&conn_.wt)) {
6042c593315Sopenharmony_ci    ev_timer_again(conn_.loop, &conn_.wt);
6052c593315Sopenharmony_ci  }
6062c593315Sopenharmony_ci}
6072c593315Sopenharmony_ci
6082c593315Sopenharmony_civoid ClientHandler::repeat_read_timer() {
6092c593315Sopenharmony_ci  ev_timer_again(conn_.loop, &conn_.rt);
6102c593315Sopenharmony_ci}
6112c593315Sopenharmony_ci
6122c593315Sopenharmony_civoid ClientHandler::stop_read_timer() { ev_timer_stop(conn_.loop, &conn_.rt); }
6132c593315Sopenharmony_ci
6142c593315Sopenharmony_ciint ClientHandler::validate_next_proto() {
6152c593315Sopenharmony_ci  const unsigned char *next_proto = nullptr;
6162c593315Sopenharmony_ci  unsigned int next_proto_len = 0;
6172c593315Sopenharmony_ci
6182c593315Sopenharmony_ci  // First set callback for catch all cases
6192c593315Sopenharmony_ci  on_read_ = &ClientHandler::upstream_read;
6202c593315Sopenharmony_ci
6212c593315Sopenharmony_ci#ifndef OPENSSL_NO_NEXTPROTONEG
6222c593315Sopenharmony_ci  SSL_get0_next_proto_negotiated(conn_.tls.ssl, &next_proto, &next_proto_len);
6232c593315Sopenharmony_ci#endif // !OPENSSL_NO_NEXTPROTONEG
6242c593315Sopenharmony_ci#if OPENSSL_VERSION_NUMBER >= 0x10002000L
6252c593315Sopenharmony_ci  if (next_proto == nullptr) {
6262c593315Sopenharmony_ci    SSL_get0_alpn_selected(conn_.tls.ssl, &next_proto, &next_proto_len);
6272c593315Sopenharmony_ci  }
6282c593315Sopenharmony_ci#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
6292c593315Sopenharmony_ci
6302c593315Sopenharmony_ci  StringRef proto;
6312c593315Sopenharmony_ci
6322c593315Sopenharmony_ci  if (next_proto) {
6332c593315Sopenharmony_ci    proto = StringRef{next_proto, next_proto_len};
6342c593315Sopenharmony_ci
6352c593315Sopenharmony_ci    if (LOG_ENABLED(INFO)) {
6362c593315Sopenharmony_ci      CLOG(INFO, this) << "The negotiated next protocol: " << proto;
6372c593315Sopenharmony_ci    }
6382c593315Sopenharmony_ci  } else {
6392c593315Sopenharmony_ci    if (LOG_ENABLED(INFO)) {
6402c593315Sopenharmony_ci      CLOG(INFO, this) << "No protocol negotiated. Fallback to HTTP/1.1";
6412c593315Sopenharmony_ci    }
6422c593315Sopenharmony_ci
6432c593315Sopenharmony_ci    proto = StringRef::from_lit("http/1.1");
6442c593315Sopenharmony_ci  }
6452c593315Sopenharmony_ci
6462c593315Sopenharmony_ci  if (!tls::in_proto_list(get_config()->tls.npn_list, proto)) {
6472c593315Sopenharmony_ci    if (LOG_ENABLED(INFO)) {
6482c593315Sopenharmony_ci      CLOG(INFO, this) << "The negotiated protocol is not supported: " << proto;
6492c593315Sopenharmony_ci    }
6502c593315Sopenharmony_ci    return -1;
6512c593315Sopenharmony_ci  }
6522c593315Sopenharmony_ci
6532c593315Sopenharmony_ci  if (util::check_h2_is_selected(proto)) {
6542c593315Sopenharmony_ci    on_read_ = &ClientHandler::upstream_http2_connhd_read;
6552c593315Sopenharmony_ci
6562c593315Sopenharmony_ci    auto http2_upstream = std::make_unique<Http2Upstream>(this);
6572c593315Sopenharmony_ci
6582c593315Sopenharmony_ci    upstream_ = std::move(http2_upstream);
6592c593315Sopenharmony_ci    alpn_ = make_string_ref(balloc_, proto);
6602c593315Sopenharmony_ci
6612c593315Sopenharmony_ci    // At this point, input buffer is already filled with some bytes.
6622c593315Sopenharmony_ci    // The read callback is not called until new data come. So consume
6632c593315Sopenharmony_ci    // input buffer here.
6642c593315Sopenharmony_ci    if (on_read() != 0) {
6652c593315Sopenharmony_ci      return -1;
6662c593315Sopenharmony_ci    }
6672c593315Sopenharmony_ci
6682c593315Sopenharmony_ci    return 0;
6692c593315Sopenharmony_ci  }
6702c593315Sopenharmony_ci
6712c593315Sopenharmony_ci  if (proto == StringRef::from_lit("http/1.1")) {
6722c593315Sopenharmony_ci    upstream_ = std::make_unique<HttpsUpstream>(this);
6732c593315Sopenharmony_ci    alpn_ = StringRef::from_lit("http/1.1");
6742c593315Sopenharmony_ci
6752c593315Sopenharmony_ci    // At this point, input buffer is already filled with some bytes.
6762c593315Sopenharmony_ci    // The read callback is not called until new data come. So consume
6772c593315Sopenharmony_ci    // input buffer here.
6782c593315Sopenharmony_ci    if (on_read() != 0) {
6792c593315Sopenharmony_ci      return -1;
6802c593315Sopenharmony_ci    }
6812c593315Sopenharmony_ci
6822c593315Sopenharmony_ci    return 0;
6832c593315Sopenharmony_ci  }
6842c593315Sopenharmony_ci  if (LOG_ENABLED(INFO)) {
6852c593315Sopenharmony_ci    CLOG(INFO, this) << "The negotiated protocol is not supported";
6862c593315Sopenharmony_ci  }
6872c593315Sopenharmony_ci  return -1;
6882c593315Sopenharmony_ci}
6892c593315Sopenharmony_ci
6902c593315Sopenharmony_ciint ClientHandler::do_read() { return read_(*this); }
6912c593315Sopenharmony_ciint ClientHandler::do_write() { return write_(*this); }
6922c593315Sopenharmony_ci
6932c593315Sopenharmony_ciint ClientHandler::on_read() {
6942c593315Sopenharmony_ci  if (rb_.chunk_avail()) {
6952c593315Sopenharmony_ci    auto rv = on_read_(*this);
6962c593315Sopenharmony_ci    if (rv != 0) {
6972c593315Sopenharmony_ci      return rv;
6982c593315Sopenharmony_ci    }
6992c593315Sopenharmony_ci  }
7002c593315Sopenharmony_ci  conn_.handle_tls_pending_read();
7012c593315Sopenharmony_ci  return 0;
7022c593315Sopenharmony_ci}
7032c593315Sopenharmony_ciint ClientHandler::on_write() { return on_write_(*this); }
7042c593315Sopenharmony_ci
7052c593315Sopenharmony_ciconst StringRef &ClientHandler::get_ipaddr() const { return ipaddr_; }
7062c593315Sopenharmony_ci
7072c593315Sopenharmony_cibool ClientHandler::get_should_close_after_write() const {
7082c593315Sopenharmony_ci  return should_close_after_write_;
7092c593315Sopenharmony_ci}
7102c593315Sopenharmony_ci
7112c593315Sopenharmony_civoid ClientHandler::set_should_close_after_write(bool f) {
7122c593315Sopenharmony_ci  should_close_after_write_ = f;
7132c593315Sopenharmony_ci}
7142c593315Sopenharmony_ci
7152c593315Sopenharmony_civoid ClientHandler::pool_downstream_connection(
7162c593315Sopenharmony_ci    std::unique_ptr<DownstreamConnection> dconn) {
7172c593315Sopenharmony_ci  if (!dconn->poolable()) {
7182c593315Sopenharmony_ci    return;
7192c593315Sopenharmony_ci  }
7202c593315Sopenharmony_ci
7212c593315Sopenharmony_ci  dconn->set_client_handler(nullptr);
7222c593315Sopenharmony_ci
7232c593315Sopenharmony_ci  auto &group = dconn->get_downstream_addr_group();
7242c593315Sopenharmony_ci
7252c593315Sopenharmony_ci  if (LOG_ENABLED(INFO)) {
7262c593315Sopenharmony_ci    CLOG(INFO, this) << "Pooling downstream connection DCONN:" << dconn.get()
7272c593315Sopenharmony_ci                     << " in group " << group;
7282c593315Sopenharmony_ci  }
7292c593315Sopenharmony_ci
7302c593315Sopenharmony_ci  auto addr = dconn->get_addr();
7312c593315Sopenharmony_ci  auto &dconn_pool = addr->dconn_pool;
7322c593315Sopenharmony_ci  dconn_pool->add_downstream_connection(std::move(dconn));
7332c593315Sopenharmony_ci}
7342c593315Sopenharmony_ci
7352c593315Sopenharmony_cinamespace {
7362c593315Sopenharmony_ci// Computes 32bits hash for session affinity for IP address |ip|.
7372c593315Sopenharmony_ciuint32_t compute_affinity_from_ip(const StringRef &ip) {
7382c593315Sopenharmony_ci  int rv;
7392c593315Sopenharmony_ci  std::array<uint8_t, 32> buf;
7402c593315Sopenharmony_ci
7412c593315Sopenharmony_ci  rv = util::sha256(buf.data(), ip);
7422c593315Sopenharmony_ci  if (rv != 0) {
7432c593315Sopenharmony_ci    // Not sure when sha256 failed.  Just fall back to another
7442c593315Sopenharmony_ci    // function.
7452c593315Sopenharmony_ci    return util::hash32(ip);
7462c593315Sopenharmony_ci  }
7472c593315Sopenharmony_ci
7482c593315Sopenharmony_ci  return (static_cast<uint32_t>(buf[0]) << 24) |
7492c593315Sopenharmony_ci         (static_cast<uint32_t>(buf[1]) << 16) |
7502c593315Sopenharmony_ci         (static_cast<uint32_t>(buf[2]) << 8) | static_cast<uint32_t>(buf[3]);
7512c593315Sopenharmony_ci}
7522c593315Sopenharmony_ci} // namespace
7532c593315Sopenharmony_ci
7542c593315Sopenharmony_ciHttp2Session *ClientHandler::get_http2_session(
7552c593315Sopenharmony_ci    const std::shared_ptr<DownstreamAddrGroup> &group, DownstreamAddr *addr) {
7562c593315Sopenharmony_ci  auto &shared_addr = group->shared_addr;
7572c593315Sopenharmony_ci
7582c593315Sopenharmony_ci  if (LOG_ENABLED(INFO)) {
7592c593315Sopenharmony_ci    CLOG(INFO, this) << "Selected DownstreamAddr=" << addr
7602c593315Sopenharmony_ci                     << ", index=" << (addr - shared_addr->addrs.data());
7612c593315Sopenharmony_ci  }
7622c593315Sopenharmony_ci
7632c593315Sopenharmony_ci  for (auto session = addr->http2_extra_freelist.head; session;) {
7642c593315Sopenharmony_ci    auto next = session->dlnext;
7652c593315Sopenharmony_ci
7662c593315Sopenharmony_ci    if (session->max_concurrency_reached(0)) {
7672c593315Sopenharmony_ci      if (LOG_ENABLED(INFO)) {
7682c593315Sopenharmony_ci        CLOG(INFO, this)
7692c593315Sopenharmony_ci            << "Maximum streams have been reached for Http2Session(" << session
7702c593315Sopenharmony_ci            << ").  Skip it";
7712c593315Sopenharmony_ci      }
7722c593315Sopenharmony_ci
7732c593315Sopenharmony_ci      session->remove_from_freelist();
7742c593315Sopenharmony_ci      session = next;
7752c593315Sopenharmony_ci
7762c593315Sopenharmony_ci      continue;
7772c593315Sopenharmony_ci    }
7782c593315Sopenharmony_ci
7792c593315Sopenharmony_ci    if (LOG_ENABLED(INFO)) {
7802c593315Sopenharmony_ci      CLOG(INFO, this) << "Use Http2Session " << session
7812c593315Sopenharmony_ci                       << " from http2_extra_freelist";
7822c593315Sopenharmony_ci    }
7832c593315Sopenharmony_ci
7842c593315Sopenharmony_ci    if (session->max_concurrency_reached(1)) {
7852c593315Sopenharmony_ci      if (LOG_ENABLED(INFO)) {
7862c593315Sopenharmony_ci        CLOG(INFO, this) << "Maximum streams are reached for Http2Session("
7872c593315Sopenharmony_ci                         << session << ").";
7882c593315Sopenharmony_ci      }
7892c593315Sopenharmony_ci
7902c593315Sopenharmony_ci      session->remove_from_freelist();
7912c593315Sopenharmony_ci    }
7922c593315Sopenharmony_ci    return session;
7932c593315Sopenharmony_ci  }
7942c593315Sopenharmony_ci
7952c593315Sopenharmony_ci  auto session = new Http2Session(conn_.loop, worker_->get_cl_ssl_ctx(),
7962c593315Sopenharmony_ci                                  worker_, group, addr);
7972c593315Sopenharmony_ci
7982c593315Sopenharmony_ci  if (LOG_ENABLED(INFO)) {
7992c593315Sopenharmony_ci    CLOG(INFO, this) << "Create new Http2Session " << session;
8002c593315Sopenharmony_ci  }
8012c593315Sopenharmony_ci
8022c593315Sopenharmony_ci  session->add_to_extra_freelist();
8032c593315Sopenharmony_ci
8042c593315Sopenharmony_ci  return session;
8052c593315Sopenharmony_ci}
8062c593315Sopenharmony_ci
8072c593315Sopenharmony_ciuint32_t ClientHandler::get_affinity_cookie(Downstream *downstream,
8082c593315Sopenharmony_ci                                            const StringRef &cookie_name) {
8092c593315Sopenharmony_ci  auto h = downstream->find_affinity_cookie(cookie_name);
8102c593315Sopenharmony_ci  if (h) {
8112c593315Sopenharmony_ci    return h;
8122c593315Sopenharmony_ci  }
8132c593315Sopenharmony_ci
8142c593315Sopenharmony_ci  auto d = std::uniform_int_distribution<uint32_t>(1);
8152c593315Sopenharmony_ci  auto rh = d(worker_->get_randgen());
8162c593315Sopenharmony_ci  h = util::hash32(StringRef{reinterpret_cast<uint8_t *>(&rh),
8172c593315Sopenharmony_ci                             reinterpret_cast<uint8_t *>(&rh) + sizeof(rh)});
8182c593315Sopenharmony_ci
8192c593315Sopenharmony_ci  downstream->renew_affinity_cookie(h);
8202c593315Sopenharmony_ci
8212c593315Sopenharmony_ci  return h;
8222c593315Sopenharmony_ci}
8232c593315Sopenharmony_ci
8242c593315Sopenharmony_cinamespace {
8252c593315Sopenharmony_civoid reschedule_addr(
8262c593315Sopenharmony_ci    std::priority_queue<DownstreamAddrEntry, std::vector<DownstreamAddrEntry>,
8272c593315Sopenharmony_ci                        DownstreamAddrEntryGreater> &pq,
8282c593315Sopenharmony_ci    DownstreamAddr *addr) {
8292c593315Sopenharmony_ci  auto penalty = MAX_DOWNSTREAM_ADDR_WEIGHT + addr->pending_penalty;
8302c593315Sopenharmony_ci  addr->cycle += penalty / addr->weight;
8312c593315Sopenharmony_ci  addr->pending_penalty = penalty % addr->weight;
8322c593315Sopenharmony_ci
8332c593315Sopenharmony_ci  pq.push(DownstreamAddrEntry{addr, addr->seq, addr->cycle});
8342c593315Sopenharmony_ci  addr->queued = true;
8352c593315Sopenharmony_ci}
8362c593315Sopenharmony_ci} // namespace
8372c593315Sopenharmony_ci
8382c593315Sopenharmony_cinamespace {
8392c593315Sopenharmony_civoid reschedule_wg(
8402c593315Sopenharmony_ci    std::priority_queue<WeightGroupEntry, std::vector<WeightGroupEntry>,
8412c593315Sopenharmony_ci                        WeightGroupEntryGreater> &pq,
8422c593315Sopenharmony_ci    WeightGroup *wg) {
8432c593315Sopenharmony_ci  auto penalty = MAX_DOWNSTREAM_ADDR_WEIGHT + wg->pending_penalty;
8442c593315Sopenharmony_ci  wg->cycle += penalty / wg->weight;
8452c593315Sopenharmony_ci  wg->pending_penalty = penalty % wg->weight;
8462c593315Sopenharmony_ci
8472c593315Sopenharmony_ci  pq.push(WeightGroupEntry{wg, wg->seq, wg->cycle});
8482c593315Sopenharmony_ci  wg->queued = true;
8492c593315Sopenharmony_ci}
8502c593315Sopenharmony_ci} // namespace
8512c593315Sopenharmony_ci
8522c593315Sopenharmony_ciDownstreamAddr *ClientHandler::get_downstream_addr(int &err,
8532c593315Sopenharmony_ci                                                   DownstreamAddrGroup *group,
8542c593315Sopenharmony_ci                                                   Downstream *downstream) {
8552c593315Sopenharmony_ci  err = 0;
8562c593315Sopenharmony_ci
8572c593315Sopenharmony_ci  switch (faddr_->alt_mode) {
8582c593315Sopenharmony_ci  case UpstreamAltMode::API:
8592c593315Sopenharmony_ci  case UpstreamAltMode::HEALTHMON:
8602c593315Sopenharmony_ci    assert(0);
8612c593315Sopenharmony_ci  default:
8622c593315Sopenharmony_ci    break;
8632c593315Sopenharmony_ci  }
8642c593315Sopenharmony_ci
8652c593315Sopenharmony_ci  auto &shared_addr = group->shared_addr;
8662c593315Sopenharmony_ci
8672c593315Sopenharmony_ci  if (shared_addr->affinity.type != SessionAffinity::NONE) {
8682c593315Sopenharmony_ci    uint32_t hash;
8692c593315Sopenharmony_ci    switch (shared_addr->affinity.type) {
8702c593315Sopenharmony_ci    case SessionAffinity::IP:
8712c593315Sopenharmony_ci      if (!affinity_hash_computed_) {
8722c593315Sopenharmony_ci        affinity_hash_ = compute_affinity_from_ip(ipaddr_);
8732c593315Sopenharmony_ci        affinity_hash_computed_ = true;
8742c593315Sopenharmony_ci      }
8752c593315Sopenharmony_ci      hash = affinity_hash_;
8762c593315Sopenharmony_ci      break;
8772c593315Sopenharmony_ci    case SessionAffinity::COOKIE:
8782c593315Sopenharmony_ci      if (shared_addr->affinity.cookie.stickiness ==
8792c593315Sopenharmony_ci          SessionAffinityCookieStickiness::STRICT) {
8802c593315Sopenharmony_ci        return get_downstream_addr_strict_affinity(err, shared_addr,
8812c593315Sopenharmony_ci                                                   downstream);
8822c593315Sopenharmony_ci      }
8832c593315Sopenharmony_ci
8842c593315Sopenharmony_ci      hash = get_affinity_cookie(downstream, shared_addr->affinity.cookie.name);
8852c593315Sopenharmony_ci      break;
8862c593315Sopenharmony_ci    default:
8872c593315Sopenharmony_ci      assert(0);
8882c593315Sopenharmony_ci    }
8892c593315Sopenharmony_ci
8902c593315Sopenharmony_ci    const auto &affinity_hash = shared_addr->affinity_hash;
8912c593315Sopenharmony_ci
8922c593315Sopenharmony_ci    auto it = std::lower_bound(
8932c593315Sopenharmony_ci        std::begin(affinity_hash), std::end(affinity_hash), hash,
8942c593315Sopenharmony_ci        [](const AffinityHash &lhs, uint32_t rhs) { return lhs.hash < rhs; });
8952c593315Sopenharmony_ci
8962c593315Sopenharmony_ci    if (it == std::end(affinity_hash)) {
8972c593315Sopenharmony_ci      it = std::begin(affinity_hash);
8982c593315Sopenharmony_ci    }
8992c593315Sopenharmony_ci
9002c593315Sopenharmony_ci    auto aff_idx =
9012c593315Sopenharmony_ci        static_cast<size_t>(std::distance(std::begin(affinity_hash), it));
9022c593315Sopenharmony_ci    auto idx = (*it).idx;
9032c593315Sopenharmony_ci    auto addr = &shared_addr->addrs[idx];
9042c593315Sopenharmony_ci
9052c593315Sopenharmony_ci    if (addr->connect_blocker->blocked()) {
9062c593315Sopenharmony_ci      size_t i;
9072c593315Sopenharmony_ci      for (i = aff_idx + 1; i != aff_idx; ++i) {
9082c593315Sopenharmony_ci        if (i == shared_addr->affinity_hash.size()) {
9092c593315Sopenharmony_ci          i = 0;
9102c593315Sopenharmony_ci        }
9112c593315Sopenharmony_ci        addr = &shared_addr->addrs[shared_addr->affinity_hash[i].idx];
9122c593315Sopenharmony_ci        if (addr->connect_blocker->blocked()) {
9132c593315Sopenharmony_ci          continue;
9142c593315Sopenharmony_ci        }
9152c593315Sopenharmony_ci        break;
9162c593315Sopenharmony_ci      }
9172c593315Sopenharmony_ci      if (i == aff_idx) {
9182c593315Sopenharmony_ci        err = -1;
9192c593315Sopenharmony_ci        return nullptr;
9202c593315Sopenharmony_ci      }
9212c593315Sopenharmony_ci    }
9222c593315Sopenharmony_ci
9232c593315Sopenharmony_ci    return addr;
9242c593315Sopenharmony_ci  }
9252c593315Sopenharmony_ci
9262c593315Sopenharmony_ci  auto &wgpq = shared_addr->pq;
9272c593315Sopenharmony_ci
9282c593315Sopenharmony_ci  for (;;) {
9292c593315Sopenharmony_ci    if (wgpq.empty()) {
9302c593315Sopenharmony_ci      CLOG(INFO, this) << "No working downstream address found";
9312c593315Sopenharmony_ci      err = -1;
9322c593315Sopenharmony_ci      return nullptr;
9332c593315Sopenharmony_ci    }
9342c593315Sopenharmony_ci
9352c593315Sopenharmony_ci    auto wg = wgpq.top().wg;
9362c593315Sopenharmony_ci    wgpq.pop();
9372c593315Sopenharmony_ci    wg->queued = false;
9382c593315Sopenharmony_ci
9392c593315Sopenharmony_ci    for (;;) {
9402c593315Sopenharmony_ci      if (wg->pq.empty()) {
9412c593315Sopenharmony_ci        break;
9422c593315Sopenharmony_ci      }
9432c593315Sopenharmony_ci
9442c593315Sopenharmony_ci      auto addr = wg->pq.top().addr;
9452c593315Sopenharmony_ci      wg->pq.pop();
9462c593315Sopenharmony_ci      addr->queued = false;
9472c593315Sopenharmony_ci
9482c593315Sopenharmony_ci      if (addr->connect_blocker->blocked()) {
9492c593315Sopenharmony_ci        continue;
9502c593315Sopenharmony_ci      }
9512c593315Sopenharmony_ci
9522c593315Sopenharmony_ci      reschedule_addr(wg->pq, addr);
9532c593315Sopenharmony_ci      reschedule_wg(wgpq, wg);
9542c593315Sopenharmony_ci
9552c593315Sopenharmony_ci      return addr;
9562c593315Sopenharmony_ci    }
9572c593315Sopenharmony_ci  }
9582c593315Sopenharmony_ci}
9592c593315Sopenharmony_ci
9602c593315Sopenharmony_ciDownstreamAddr *ClientHandler::get_downstream_addr_strict_affinity(
9612c593315Sopenharmony_ci    int &err, const std::shared_ptr<SharedDownstreamAddr> &shared_addr,
9622c593315Sopenharmony_ci    Downstream *downstream) {
9632c593315Sopenharmony_ci  const auto &affinity_hash = shared_addr->affinity_hash;
9642c593315Sopenharmony_ci
9652c593315Sopenharmony_ci  auto h = downstream->find_affinity_cookie(shared_addr->affinity.cookie.name);
9662c593315Sopenharmony_ci  if (h) {
9672c593315Sopenharmony_ci    auto it = shared_addr->affinity_hash_map.find(h);
9682c593315Sopenharmony_ci    if (it != std::end(shared_addr->affinity_hash_map)) {
9692c593315Sopenharmony_ci      auto addr = &shared_addr->addrs[(*it).second];
9702c593315Sopenharmony_ci      if (!addr->connect_blocker->blocked()) {
9712c593315Sopenharmony_ci        return addr;
9722c593315Sopenharmony_ci      }
9732c593315Sopenharmony_ci    }
9742c593315Sopenharmony_ci  } else {
9752c593315Sopenharmony_ci    auto d = std::uniform_int_distribution<uint32_t>(1);
9762c593315Sopenharmony_ci    auto rh = d(worker_->get_randgen());
9772c593315Sopenharmony_ci    h = util::hash32(StringRef{reinterpret_cast<uint8_t *>(&rh),
9782c593315Sopenharmony_ci                               reinterpret_cast<uint8_t *>(&rh) + sizeof(rh)});
9792c593315Sopenharmony_ci  }
9802c593315Sopenharmony_ci
9812c593315Sopenharmony_ci  // Client is not bound to a particular backend, or the bound backend
9822c593315Sopenharmony_ci  // is not found, or is blocked.  Find new backend using h.  Using
9832c593315Sopenharmony_ci  // existing h allows us to find new server in a deterministic way.
9842c593315Sopenharmony_ci  // It is preferable because multiple concurrent requests with the
9852c593315Sopenharmony_ci  // stale cookie might be in-flight.
9862c593315Sopenharmony_ci  auto it = std::lower_bound(
9872c593315Sopenharmony_ci      std::begin(affinity_hash), std::end(affinity_hash), h,
9882c593315Sopenharmony_ci      [](const AffinityHash &lhs, uint32_t rhs) { return lhs.hash < rhs; });
9892c593315Sopenharmony_ci
9902c593315Sopenharmony_ci  if (it == std::end(affinity_hash)) {
9912c593315Sopenharmony_ci    it = std::begin(affinity_hash);
9922c593315Sopenharmony_ci  }
9932c593315Sopenharmony_ci
9942c593315Sopenharmony_ci  auto aff_idx =
9952c593315Sopenharmony_ci      static_cast<size_t>(std::distance(std::begin(affinity_hash), it));
9962c593315Sopenharmony_ci  auto idx = (*it).idx;
9972c593315Sopenharmony_ci  auto addr = &shared_addr->addrs[idx];
9982c593315Sopenharmony_ci
9992c593315Sopenharmony_ci  if (addr->connect_blocker->blocked()) {
10002c593315Sopenharmony_ci    size_t i;
10012c593315Sopenharmony_ci    for (i = aff_idx + 1; i != aff_idx; ++i) {
10022c593315Sopenharmony_ci      if (i == shared_addr->affinity_hash.size()) {
10032c593315Sopenharmony_ci        i = 0;
10042c593315Sopenharmony_ci      }
10052c593315Sopenharmony_ci      addr = &shared_addr->addrs[shared_addr->affinity_hash[i].idx];
10062c593315Sopenharmony_ci      if (addr->connect_blocker->blocked()) {
10072c593315Sopenharmony_ci        continue;
10082c593315Sopenharmony_ci      }
10092c593315Sopenharmony_ci      break;
10102c593315Sopenharmony_ci    }
10112c593315Sopenharmony_ci    if (i == aff_idx) {
10122c593315Sopenharmony_ci      err = -1;
10132c593315Sopenharmony_ci      return nullptr;
10142c593315Sopenharmony_ci    }
10152c593315Sopenharmony_ci  }
10162c593315Sopenharmony_ci
10172c593315Sopenharmony_ci  downstream->renew_affinity_cookie(addr->affinity_hash);
10182c593315Sopenharmony_ci
10192c593315Sopenharmony_ci  return addr;
10202c593315Sopenharmony_ci}
10212c593315Sopenharmony_ci
10222c593315Sopenharmony_cistd::unique_ptr<DownstreamConnection>
10232c593315Sopenharmony_ciClientHandler::get_downstream_connection(int &err, Downstream *downstream) {
10242c593315Sopenharmony_ci  size_t group_idx;
10252c593315Sopenharmony_ci  auto &downstreamconf = *worker_->get_downstream_config();
10262c593315Sopenharmony_ci  auto &routerconf = downstreamconf.router;
10272c593315Sopenharmony_ci
10282c593315Sopenharmony_ci  auto catch_all = downstreamconf.addr_group_catch_all;
10292c593315Sopenharmony_ci  auto &groups = worker_->get_downstream_addr_groups();
10302c593315Sopenharmony_ci
10312c593315Sopenharmony_ci  auto &req = downstream->request();
10322c593315Sopenharmony_ci
10332c593315Sopenharmony_ci  err = 0;
10342c593315Sopenharmony_ci
10352c593315Sopenharmony_ci  switch (faddr_->alt_mode) {
10362c593315Sopenharmony_ci  case UpstreamAltMode::API: {
10372c593315Sopenharmony_ci    auto dconn = std::make_unique<APIDownstreamConnection>(worker_);
10382c593315Sopenharmony_ci    dconn->set_client_handler(this);
10392c593315Sopenharmony_ci    return dconn;
10402c593315Sopenharmony_ci  }
10412c593315Sopenharmony_ci  case UpstreamAltMode::HEALTHMON: {
10422c593315Sopenharmony_ci    auto dconn = std::make_unique<HealthMonitorDownstreamConnection>();
10432c593315Sopenharmony_ci    dconn->set_client_handler(this);
10442c593315Sopenharmony_ci    return dconn;
10452c593315Sopenharmony_ci  }
10462c593315Sopenharmony_ci  default:
10472c593315Sopenharmony_ci    break;
10482c593315Sopenharmony_ci  }
10492c593315Sopenharmony_ci
10502c593315Sopenharmony_ci  auto &balloc = downstream->get_block_allocator();
10512c593315Sopenharmony_ci
10522c593315Sopenharmony_ci  StringRef authority, path;
10532c593315Sopenharmony_ci
10542c593315Sopenharmony_ci  if (req.forwarded_once) {
10552c593315Sopenharmony_ci    if (groups.size() != 1) {
10562c593315Sopenharmony_ci      authority = req.orig_authority;
10572c593315Sopenharmony_ci      path = req.orig_path;
10582c593315Sopenharmony_ci    }
10592c593315Sopenharmony_ci  } else {
10602c593315Sopenharmony_ci    if (faddr_->sni_fwd) {
10612c593315Sopenharmony_ci      authority = sni_;
10622c593315Sopenharmony_ci    } else if (!req.authority.empty()) {
10632c593315Sopenharmony_ci      authority = req.authority;
10642c593315Sopenharmony_ci    } else {
10652c593315Sopenharmony_ci      auto h = req.fs.header(http2::HD_HOST);
10662c593315Sopenharmony_ci      if (h) {
10672c593315Sopenharmony_ci        authority = h->value;
10682c593315Sopenharmony_ci      }
10692c593315Sopenharmony_ci    }
10702c593315Sopenharmony_ci
10712c593315Sopenharmony_ci    // CONNECT method does not have path.  But we requires path in
10722c593315Sopenharmony_ci    // host-path mapping.  As workaround, we assume that path is
10732c593315Sopenharmony_ci    // "/".
10742c593315Sopenharmony_ci    if (!req.regular_connect_method()) {
10752c593315Sopenharmony_ci      path = req.path;
10762c593315Sopenharmony_ci    }
10772c593315Sopenharmony_ci
10782c593315Sopenharmony_ci    // Cache the authority and path used for the first-time backend
10792c593315Sopenharmony_ci    // selection because per-pattern mruby script can change them.
10802c593315Sopenharmony_ci    req.orig_authority = authority;
10812c593315Sopenharmony_ci    req.orig_path = path;
10822c593315Sopenharmony_ci    req.forwarded_once = true;
10832c593315Sopenharmony_ci  }
10842c593315Sopenharmony_ci
10852c593315Sopenharmony_ci  // Fast path.  If we have one group, it must be catch-all group.
10862c593315Sopenharmony_ci  if (groups.size() == 1) {
10872c593315Sopenharmony_ci    group_idx = 0;
10882c593315Sopenharmony_ci  } else {
10892c593315Sopenharmony_ci    group_idx = match_downstream_addr_group(routerconf, authority, path, groups,
10902c593315Sopenharmony_ci                                            catch_all, balloc);
10912c593315Sopenharmony_ci  }
10922c593315Sopenharmony_ci
10932c593315Sopenharmony_ci  if (LOG_ENABLED(INFO)) {
10942c593315Sopenharmony_ci    CLOG(INFO, this) << "Downstream address group_idx: " << group_idx;
10952c593315Sopenharmony_ci  }
10962c593315Sopenharmony_ci
10972c593315Sopenharmony_ci  if (groups[group_idx]->shared_addr->redirect_if_not_tls && !conn_.tls.ssl) {
10982c593315Sopenharmony_ci    if (LOG_ENABLED(INFO)) {
10992c593315Sopenharmony_ci      CLOG(INFO, this) << "Downstream address group " << group_idx
11002c593315Sopenharmony_ci                       << " requires frontend TLS connection.";
11012c593315Sopenharmony_ci    }
11022c593315Sopenharmony_ci    err = SHRPX_ERR_TLS_REQUIRED;
11032c593315Sopenharmony_ci    return nullptr;
11042c593315Sopenharmony_ci  }
11052c593315Sopenharmony_ci
11062c593315Sopenharmony_ci  auto &group = groups[group_idx];
11072c593315Sopenharmony_ci
11082c593315Sopenharmony_ci  if (group->shared_addr->dnf) {
11092c593315Sopenharmony_ci    auto dconn = std::make_unique<NullDownstreamConnection>(group);
11102c593315Sopenharmony_ci    dconn->set_client_handler(this);
11112c593315Sopenharmony_ci    return dconn;
11122c593315Sopenharmony_ci  }
11132c593315Sopenharmony_ci
11142c593315Sopenharmony_ci  auto addr = get_downstream_addr(err, group.get(), downstream);
11152c593315Sopenharmony_ci  if (addr == nullptr) {
11162c593315Sopenharmony_ci    return nullptr;
11172c593315Sopenharmony_ci  }
11182c593315Sopenharmony_ci
11192c593315Sopenharmony_ci  if (addr->proto == Proto::HTTP1) {
11202c593315Sopenharmony_ci    auto dconn = addr->dconn_pool->pop_downstream_connection();
11212c593315Sopenharmony_ci    if (dconn) {
11222c593315Sopenharmony_ci      dconn->set_client_handler(this);
11232c593315Sopenharmony_ci      return dconn;
11242c593315Sopenharmony_ci    }
11252c593315Sopenharmony_ci
11262c593315Sopenharmony_ci    if (worker_->get_connect_blocker()->blocked()) {
11272c593315Sopenharmony_ci      if (LOG_ENABLED(INFO)) {
11282c593315Sopenharmony_ci        DCLOG(INFO, this)
11292c593315Sopenharmony_ci            << "Worker wide backend connection was blocked temporarily";
11302c593315Sopenharmony_ci      }
11312c593315Sopenharmony_ci      return nullptr;
11322c593315Sopenharmony_ci    }
11332c593315Sopenharmony_ci
11342c593315Sopenharmony_ci    if (LOG_ENABLED(INFO)) {
11352c593315Sopenharmony_ci      CLOG(INFO, this) << "Downstream connection pool is empty."
11362c593315Sopenharmony_ci                       << " Create new one";
11372c593315Sopenharmony_ci    }
11382c593315Sopenharmony_ci
11392c593315Sopenharmony_ci    dconn = std::make_unique<HttpDownstreamConnection>(group, addr, conn_.loop,
11402c593315Sopenharmony_ci                                                       worker_);
11412c593315Sopenharmony_ci    dconn->set_client_handler(this);
11422c593315Sopenharmony_ci    return dconn;
11432c593315Sopenharmony_ci  }
11442c593315Sopenharmony_ci
11452c593315Sopenharmony_ci  if (LOG_ENABLED(INFO)) {
11462c593315Sopenharmony_ci    CLOG(INFO, this) << "Downstream connection pool is empty."
11472c593315Sopenharmony_ci                     << " Create new one";
11482c593315Sopenharmony_ci  }
11492c593315Sopenharmony_ci
11502c593315Sopenharmony_ci  auto http2session = get_http2_session(group, addr);
11512c593315Sopenharmony_ci  auto dconn = std::make_unique<Http2DownstreamConnection>(http2session);
11522c593315Sopenharmony_ci  dconn->set_client_handler(this);
11532c593315Sopenharmony_ci  return dconn;
11542c593315Sopenharmony_ci}
11552c593315Sopenharmony_ci
11562c593315Sopenharmony_ciMemchunkPool *ClientHandler::get_mcpool() { return worker_->get_mcpool(); }
11572c593315Sopenharmony_ci
11582c593315Sopenharmony_ciSSL *ClientHandler::get_ssl() const { return conn_.tls.ssl; }
11592c593315Sopenharmony_ci
11602c593315Sopenharmony_civoid ClientHandler::direct_http2_upgrade() {
11612c593315Sopenharmony_ci  upstream_ = std::make_unique<Http2Upstream>(this);
11622c593315Sopenharmony_ci  alpn_ = StringRef::from_lit(NGHTTP2_CLEARTEXT_PROTO_VERSION_ID);
11632c593315Sopenharmony_ci  on_read_ = &ClientHandler::upstream_read;
11642c593315Sopenharmony_ci  write_ = &ClientHandler::write_clear;
11652c593315Sopenharmony_ci}
11662c593315Sopenharmony_ci
11672c593315Sopenharmony_ciint ClientHandler::perform_http2_upgrade(HttpsUpstream *http) {
11682c593315Sopenharmony_ci  auto upstream = std::make_unique<Http2Upstream>(this);
11692c593315Sopenharmony_ci
11702c593315Sopenharmony_ci  auto output = upstream->get_response_buf();
11712c593315Sopenharmony_ci
11722c593315Sopenharmony_ci  // We might have written non-final header in response_buf, in this
11732c593315Sopenharmony_ci  // case, response_state is still INITIAL.  If this non-final header
11742c593315Sopenharmony_ci  // and upgrade header fit in output buffer, do upgrade.  Otherwise,
11752c593315Sopenharmony_ci  // to avoid to send this non-final header as response body in HTTP/2
11762c593315Sopenharmony_ci  // upstream, fail upgrade.
11772c593315Sopenharmony_ci  auto downstream = http->get_downstream();
11782c593315Sopenharmony_ci  auto input = downstream->get_response_buf();
11792c593315Sopenharmony_ci
11802c593315Sopenharmony_ci  if (upstream->upgrade_upstream(http) != 0) {
11812c593315Sopenharmony_ci    return -1;
11822c593315Sopenharmony_ci  }
11832c593315Sopenharmony_ci  // http pointer is now owned by upstream.
11842c593315Sopenharmony_ci  upstream_.release();
11852c593315Sopenharmony_ci  // TODO We might get other version id in HTTP2-settings, if we
11862c593315Sopenharmony_ci  // support aliasing for h2, but we just use library default for now.
11872c593315Sopenharmony_ci  alpn_ = StringRef::from_lit(NGHTTP2_CLEARTEXT_PROTO_VERSION_ID);
11882c593315Sopenharmony_ci  on_read_ = &ClientHandler::upstream_http2_connhd_read;
11892c593315Sopenharmony_ci  write_ = &ClientHandler::write_clear;
11902c593315Sopenharmony_ci
11912c593315Sopenharmony_ci  input->remove(*output, input->rleft());
11922c593315Sopenharmony_ci
11932c593315Sopenharmony_ci  constexpr auto res =
11942c593315Sopenharmony_ci      StringRef::from_lit("HTTP/1.1 101 Switching Protocols\r\n"
11952c593315Sopenharmony_ci                          "Connection: Upgrade\r\n"
11962c593315Sopenharmony_ci                          "Upgrade: " NGHTTP2_CLEARTEXT_PROTO_VERSION_ID "\r\n"
11972c593315Sopenharmony_ci                          "\r\n");
11982c593315Sopenharmony_ci
11992c593315Sopenharmony_ci  output->append(res);
12002c593315Sopenharmony_ci  upstream_ = std::move(upstream);
12012c593315Sopenharmony_ci
12022c593315Sopenharmony_ci  signal_write();
12032c593315Sopenharmony_ci  return 0;
12042c593315Sopenharmony_ci}
12052c593315Sopenharmony_ci
12062c593315Sopenharmony_cibool ClientHandler::get_http2_upgrade_allowed() const { return !conn_.tls.ssl; }
12072c593315Sopenharmony_ci
12082c593315Sopenharmony_ciStringRef ClientHandler::get_upstream_scheme() const {
12092c593315Sopenharmony_ci  if (conn_.tls.ssl) {
12102c593315Sopenharmony_ci    return StringRef::from_lit("https");
12112c593315Sopenharmony_ci  } else {
12122c593315Sopenharmony_ci    return StringRef::from_lit("http");
12132c593315Sopenharmony_ci  }
12142c593315Sopenharmony_ci}
12152c593315Sopenharmony_ci
12162c593315Sopenharmony_civoid ClientHandler::start_immediate_shutdown() {
12172c593315Sopenharmony_ci  ev_timer_start(conn_.loop, &reneg_shutdown_timer_);
12182c593315Sopenharmony_ci}
12192c593315Sopenharmony_ci
12202c593315Sopenharmony_civoid ClientHandler::write_accesslog(Downstream *downstream) {
12212c593315Sopenharmony_ci  auto &req = downstream->request();
12222c593315Sopenharmony_ci
12232c593315Sopenharmony_ci  auto config = get_config();
12242c593315Sopenharmony_ci
12252c593315Sopenharmony_ci  if (!req.tstamp) {
12262c593315Sopenharmony_ci    auto lgconf = log_config();
12272c593315Sopenharmony_ci    lgconf->update_tstamp(std::chrono::system_clock::now());
12282c593315Sopenharmony_ci    req.tstamp = lgconf->tstamp;
12292c593315Sopenharmony_ci  }
12302c593315Sopenharmony_ci
12312c593315Sopenharmony_ci  upstream_accesslog(
12322c593315Sopenharmony_ci      config->logging.access.format,
12332c593315Sopenharmony_ci      LogSpec{
12342c593315Sopenharmony_ci          downstream,
12352c593315Sopenharmony_ci          ipaddr_,
12362c593315Sopenharmony_ci          alpn_,
12372c593315Sopenharmony_ci          sni_,
12382c593315Sopenharmony_ci          conn_.tls.ssl,
12392c593315Sopenharmony_ci          std::chrono::high_resolution_clock::now(), // request_end_time
12402c593315Sopenharmony_ci          port_,
12412c593315Sopenharmony_ci          faddr_->port,
12422c593315Sopenharmony_ci          config->pid,
12432c593315Sopenharmony_ci      });
12442c593315Sopenharmony_ci}
12452c593315Sopenharmony_ci
12462c593315Sopenharmony_ciClientHandler::ReadBuf *ClientHandler::get_rb() { return &rb_; }
12472c593315Sopenharmony_ci
12482c593315Sopenharmony_civoid ClientHandler::signal_write() { conn_.wlimit.startw(); }
12492c593315Sopenharmony_ci
12502c593315Sopenharmony_ciRateLimit *ClientHandler::get_rlimit() { return &conn_.rlimit; }
12512c593315Sopenharmony_ciRateLimit *ClientHandler::get_wlimit() { return &conn_.wlimit; }
12522c593315Sopenharmony_ci
12532c593315Sopenharmony_ciev_io *ClientHandler::get_wev() { return &conn_.wev; }
12542c593315Sopenharmony_ci
12552c593315Sopenharmony_ciWorker *ClientHandler::get_worker() const { return worker_; }
12562c593315Sopenharmony_ci
12572c593315Sopenharmony_cinamespace {
12582c593315Sopenharmony_cissize_t parse_proxy_line_port(const uint8_t *first, const uint8_t *last) {
12592c593315Sopenharmony_ci  auto p = first;
12602c593315Sopenharmony_ci  int32_t port = 0;
12612c593315Sopenharmony_ci
12622c593315Sopenharmony_ci  if (p == last) {
12632c593315Sopenharmony_ci    return -1;
12642c593315Sopenharmony_ci  }
12652c593315Sopenharmony_ci
12662c593315Sopenharmony_ci  if (*p == '0') {
12672c593315Sopenharmony_ci    if (p + 1 != last && util::is_digit(*(p + 1))) {
12682c593315Sopenharmony_ci      return -1;
12692c593315Sopenharmony_ci    }
12702c593315Sopenharmony_ci    return 1;
12712c593315Sopenharmony_ci  }
12722c593315Sopenharmony_ci
12732c593315Sopenharmony_ci  for (; p != last && util::is_digit(*p); ++p) {
12742c593315Sopenharmony_ci    port *= 10;
12752c593315Sopenharmony_ci    port += *p - '0';
12762c593315Sopenharmony_ci
12772c593315Sopenharmony_ci    if (port > 65535) {
12782c593315Sopenharmony_ci      return -1;
12792c593315Sopenharmony_ci    }
12802c593315Sopenharmony_ci  }
12812c593315Sopenharmony_ci
12822c593315Sopenharmony_ci  return p - first;
12832c593315Sopenharmony_ci}
12842c593315Sopenharmony_ci} // namespace
12852c593315Sopenharmony_ci
12862c593315Sopenharmony_ciint ClientHandler::on_proxy_protocol_finish() {
12872c593315Sopenharmony_ci  auto len = rb_.pos() - rb_.begin();
12882c593315Sopenharmony_ci
12892c593315Sopenharmony_ci  assert(len);
12902c593315Sopenharmony_ci
12912c593315Sopenharmony_ci  if (LOG_ENABLED(INFO)) {
12922c593315Sopenharmony_ci    CLOG(INFO, this) << "PROXY-protocol: Draining " << len
12932c593315Sopenharmony_ci                     << " bytes from socket";
12942c593315Sopenharmony_ci  }
12952c593315Sopenharmony_ci
12962c593315Sopenharmony_ci  rb_.reset();
12972c593315Sopenharmony_ci
12982c593315Sopenharmony_ci  if (conn_.read_nolim_clear(rb_.pos(), len) < 0) {
12992c593315Sopenharmony_ci    return -1;
13002c593315Sopenharmony_ci  }
13012c593315Sopenharmony_ci
13022c593315Sopenharmony_ci  rb_.reset();
13032c593315Sopenharmony_ci
13042c593315Sopenharmony_ci  setup_upstream_io_callback();
13052c593315Sopenharmony_ci
13062c593315Sopenharmony_ci  return 0;
13072c593315Sopenharmony_ci}
13082c593315Sopenharmony_ci
13092c593315Sopenharmony_cinamespace {
13102c593315Sopenharmony_ci// PROXY-protocol v2 header signature
13112c593315Sopenharmony_ciconstexpr uint8_t PROXY_PROTO_V2_SIG[] =
13122c593315Sopenharmony_ci    "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A";
13132c593315Sopenharmony_ci
13142c593315Sopenharmony_ci// PROXY-protocol v2 header length
13152c593315Sopenharmony_ciconstexpr size_t PROXY_PROTO_V2_HDLEN =
13162c593315Sopenharmony_ci    str_size(PROXY_PROTO_V2_SIG) + /* ver_cmd(1) + fam(1) + len(2) = */ 4;
13172c593315Sopenharmony_ci} // namespace
13182c593315Sopenharmony_ci
13192c593315Sopenharmony_ci// http://www.haproxy.org/download/1.5/doc/proxy-protocol.txt
13202c593315Sopenharmony_ciint ClientHandler::proxy_protocol_read() {
13212c593315Sopenharmony_ci  if (LOG_ENABLED(INFO)) {
13222c593315Sopenharmony_ci    CLOG(INFO, this) << "PROXY-protocol: Started";
13232c593315Sopenharmony_ci  }
13242c593315Sopenharmony_ci
13252c593315Sopenharmony_ci  auto first = rb_.pos();
13262c593315Sopenharmony_ci
13272c593315Sopenharmony_ci  if (rb_.rleft() >= PROXY_PROTO_V2_HDLEN &&
13282c593315Sopenharmony_ci      (*(first + str_size(PROXY_PROTO_V2_SIG)) & 0xf0) == 0x20) {
13292c593315Sopenharmony_ci    if (LOG_ENABLED(INFO)) {
13302c593315Sopenharmony_ci      CLOG(INFO, this) << "PROXY-protocol: Detected v2 header signature";
13312c593315Sopenharmony_ci    }
13322c593315Sopenharmony_ci    return proxy_protocol_v2_read();
13332c593315Sopenharmony_ci  }
13342c593315Sopenharmony_ci
13352c593315Sopenharmony_ci  // NULL character really destroys functions which expects NULL
13362c593315Sopenharmony_ci  // terminated string.  We won't expect it in PROXY protocol line, so
13372c593315Sopenharmony_ci  // find it here.
13382c593315Sopenharmony_ci  auto chrs = std::array<char, 2>{'\n', '\0'};
13392c593315Sopenharmony_ci
13402c593315Sopenharmony_ci  constexpr size_t MAX_PROXY_LINELEN = 107;
13412c593315Sopenharmony_ci
13422c593315Sopenharmony_ci  auto bufend = rb_.pos() + std::min(MAX_PROXY_LINELEN, rb_.rleft());
13432c593315Sopenharmony_ci
13442c593315Sopenharmony_ci  auto end =
13452c593315Sopenharmony_ci      std::find_first_of(rb_.pos(), bufend, std::begin(chrs), std::end(chrs));
13462c593315Sopenharmony_ci
13472c593315Sopenharmony_ci  if (end == bufend || *end == '\0' || end == rb_.pos() || *(end - 1) != '\r') {
13482c593315Sopenharmony_ci    if (LOG_ENABLED(INFO)) {
13492c593315Sopenharmony_ci      CLOG(INFO, this) << "PROXY-protocol-v1: No ending CR LF sequence found";
13502c593315Sopenharmony_ci    }
13512c593315Sopenharmony_ci    return -1;
13522c593315Sopenharmony_ci  }
13532c593315Sopenharmony_ci
13542c593315Sopenharmony_ci  --end;
13552c593315Sopenharmony_ci
13562c593315Sopenharmony_ci  constexpr auto HEADER = StringRef::from_lit("PROXY ");
13572c593315Sopenharmony_ci
13582c593315Sopenharmony_ci  if (static_cast<size_t>(end - rb_.pos()) < HEADER.size()) {
13592c593315Sopenharmony_ci    if (LOG_ENABLED(INFO)) {
13602c593315Sopenharmony_ci      CLOG(INFO, this) << "PROXY-protocol-v1: PROXY version 1 ID not found";
13612c593315Sopenharmony_ci    }
13622c593315Sopenharmony_ci    return -1;
13632c593315Sopenharmony_ci  }
13642c593315Sopenharmony_ci
13652c593315Sopenharmony_ci  if (!util::streq(HEADER, StringRef{rb_.pos(), HEADER.size()})) {
13662c593315Sopenharmony_ci    if (LOG_ENABLED(INFO)) {
13672c593315Sopenharmony_ci      CLOG(INFO, this) << "PROXY-protocol-v1: Bad PROXY protocol version 1 ID";
13682c593315Sopenharmony_ci    }
13692c593315Sopenharmony_ci    return -1;
13702c593315Sopenharmony_ci  }
13712c593315Sopenharmony_ci
13722c593315Sopenharmony_ci  rb_.drain(HEADER.size());
13732c593315Sopenharmony_ci
13742c593315Sopenharmony_ci  int family;
13752c593315Sopenharmony_ci
13762c593315Sopenharmony_ci  if (rb_.pos()[0] == 'T') {
13772c593315Sopenharmony_ci    if (end - rb_.pos() < 5) {
13782c593315Sopenharmony_ci      if (LOG_ENABLED(INFO)) {
13792c593315Sopenharmony_ci        CLOG(INFO, this) << "PROXY-protocol-v1: INET protocol family not found";
13802c593315Sopenharmony_ci      }
13812c593315Sopenharmony_ci      return -1;
13822c593315Sopenharmony_ci    }
13832c593315Sopenharmony_ci
13842c593315Sopenharmony_ci    if (rb_.pos()[1] != 'C' || rb_.pos()[2] != 'P') {
13852c593315Sopenharmony_ci      if (LOG_ENABLED(INFO)) {
13862c593315Sopenharmony_ci        CLOG(INFO, this) << "PROXY-protocol-v1: Unknown INET protocol family";
13872c593315Sopenharmony_ci      }
13882c593315Sopenharmony_ci      return -1;
13892c593315Sopenharmony_ci    }
13902c593315Sopenharmony_ci
13912c593315Sopenharmony_ci    switch (rb_.pos()[3]) {
13922c593315Sopenharmony_ci    case '4':
13932c593315Sopenharmony_ci      family = AF_INET;
13942c593315Sopenharmony_ci      break;
13952c593315Sopenharmony_ci    case '6':
13962c593315Sopenharmony_ci      family = AF_INET6;
13972c593315Sopenharmony_ci      break;
13982c593315Sopenharmony_ci    default:
13992c593315Sopenharmony_ci      if (LOG_ENABLED(INFO)) {
14002c593315Sopenharmony_ci        CLOG(INFO, this) << "PROXY-protocol-v1: Unknown INET protocol family";
14012c593315Sopenharmony_ci      }
14022c593315Sopenharmony_ci      return -1;
14032c593315Sopenharmony_ci    }
14042c593315Sopenharmony_ci
14052c593315Sopenharmony_ci    rb_.drain(5);
14062c593315Sopenharmony_ci  } else {
14072c593315Sopenharmony_ci    if (end - rb_.pos() < 7) {
14082c593315Sopenharmony_ci      if (LOG_ENABLED(INFO)) {
14092c593315Sopenharmony_ci        CLOG(INFO, this) << "PROXY-protocol-v1: INET protocol family not found";
14102c593315Sopenharmony_ci      }
14112c593315Sopenharmony_ci      return -1;
14122c593315Sopenharmony_ci    }
14132c593315Sopenharmony_ci    if (!util::streq_l("UNKNOWN", rb_.pos(), 7)) {
14142c593315Sopenharmony_ci      if (LOG_ENABLED(INFO)) {
14152c593315Sopenharmony_ci        CLOG(INFO, this) << "PROXY-protocol-v1: Unknown INET protocol family";
14162c593315Sopenharmony_ci      }
14172c593315Sopenharmony_ci      return -1;
14182c593315Sopenharmony_ci    }
14192c593315Sopenharmony_ci
14202c593315Sopenharmony_ci    rb_.drain(end + 2 - rb_.pos());
14212c593315Sopenharmony_ci
14222c593315Sopenharmony_ci    return on_proxy_protocol_finish();
14232c593315Sopenharmony_ci  }
14242c593315Sopenharmony_ci
14252c593315Sopenharmony_ci  // source address
14262c593315Sopenharmony_ci  auto token_end = std::find(rb_.pos(), end, ' ');
14272c593315Sopenharmony_ci  if (token_end == end) {
14282c593315Sopenharmony_ci    if (LOG_ENABLED(INFO)) {
14292c593315Sopenharmony_ci      CLOG(INFO, this) << "PROXY-protocol-v1: Source address not found";
14302c593315Sopenharmony_ci    }
14312c593315Sopenharmony_ci    return -1;
14322c593315Sopenharmony_ci  }
14332c593315Sopenharmony_ci
14342c593315Sopenharmony_ci  *token_end = '\0';
14352c593315Sopenharmony_ci  if (!util::numeric_host(reinterpret_cast<const char *>(rb_.pos()), family)) {
14362c593315Sopenharmony_ci    if (LOG_ENABLED(INFO)) {
14372c593315Sopenharmony_ci      CLOG(INFO, this) << "PROXY-protocol-v1: Invalid source address";
14382c593315Sopenharmony_ci    }
14392c593315Sopenharmony_ci    return -1;
14402c593315Sopenharmony_ci  }
14412c593315Sopenharmony_ci
14422c593315Sopenharmony_ci  auto src_addr = rb_.pos();
14432c593315Sopenharmony_ci  auto src_addrlen = token_end - rb_.pos();
14442c593315Sopenharmony_ci
14452c593315Sopenharmony_ci  rb_.drain(token_end - rb_.pos() + 1);
14462c593315Sopenharmony_ci
14472c593315Sopenharmony_ci  // destination address
14482c593315Sopenharmony_ci  token_end = std::find(rb_.pos(), end, ' ');
14492c593315Sopenharmony_ci  if (token_end == end) {
14502c593315Sopenharmony_ci    if (LOG_ENABLED(INFO)) {
14512c593315Sopenharmony_ci      CLOG(INFO, this) << "PROXY-protocol-v1: Destination address not found";
14522c593315Sopenharmony_ci    }
14532c593315Sopenharmony_ci    return -1;
14542c593315Sopenharmony_ci  }
14552c593315Sopenharmony_ci
14562c593315Sopenharmony_ci  *token_end = '\0';
14572c593315Sopenharmony_ci  if (!util::numeric_host(reinterpret_cast<const char *>(rb_.pos()), family)) {
14582c593315Sopenharmony_ci    if (LOG_ENABLED(INFO)) {
14592c593315Sopenharmony_ci      CLOG(INFO, this) << "PROXY-protocol-v1: Invalid destination address";
14602c593315Sopenharmony_ci    }
14612c593315Sopenharmony_ci    return -1;
14622c593315Sopenharmony_ci  }
14632c593315Sopenharmony_ci
14642c593315Sopenharmony_ci  // Currently we don't use destination address
14652c593315Sopenharmony_ci
14662c593315Sopenharmony_ci  rb_.drain(token_end - rb_.pos() + 1);
14672c593315Sopenharmony_ci
14682c593315Sopenharmony_ci  // source port
14692c593315Sopenharmony_ci  auto n = parse_proxy_line_port(rb_.pos(), end);
14702c593315Sopenharmony_ci  if (n <= 0 || *(rb_.pos() + n) != ' ') {
14712c593315Sopenharmony_ci    if (LOG_ENABLED(INFO)) {
14722c593315Sopenharmony_ci      CLOG(INFO, this) << "PROXY-protocol-v1: Invalid source port";
14732c593315Sopenharmony_ci    }
14742c593315Sopenharmony_ci    return -1;
14752c593315Sopenharmony_ci  }
14762c593315Sopenharmony_ci
14772c593315Sopenharmony_ci  rb_.pos()[n] = '\0';
14782c593315Sopenharmony_ci  auto src_port = rb_.pos();
14792c593315Sopenharmony_ci  auto src_portlen = n;
14802c593315Sopenharmony_ci
14812c593315Sopenharmony_ci  rb_.drain(n + 1);
14822c593315Sopenharmony_ci
14832c593315Sopenharmony_ci  // destination  port
14842c593315Sopenharmony_ci  n = parse_proxy_line_port(rb_.pos(), end);
14852c593315Sopenharmony_ci  if (n <= 0 || rb_.pos() + n != end) {
14862c593315Sopenharmony_ci    if (LOG_ENABLED(INFO)) {
14872c593315Sopenharmony_ci      CLOG(INFO, this) << "PROXY-protocol-v1: Invalid destination port";
14882c593315Sopenharmony_ci    }
14892c593315Sopenharmony_ci    return -1;
14902c593315Sopenharmony_ci  }
14912c593315Sopenharmony_ci
14922c593315Sopenharmony_ci  // Currently we don't use destination port
14932c593315Sopenharmony_ci
14942c593315Sopenharmony_ci  rb_.drain(end + 2 - rb_.pos());
14952c593315Sopenharmony_ci
14962c593315Sopenharmony_ci  ipaddr_ =
14972c593315Sopenharmony_ci      make_string_ref(balloc_, StringRef{src_addr, src_addr + src_addrlen});
14982c593315Sopenharmony_ci  port_ = make_string_ref(balloc_, StringRef{src_port, src_port + src_portlen});
14992c593315Sopenharmony_ci
15002c593315Sopenharmony_ci  if (LOG_ENABLED(INFO)) {
15012c593315Sopenharmony_ci    CLOG(INFO, this) << "PROXY-protocol-v1: Finished, " << (rb_.pos() - first)
15022c593315Sopenharmony_ci                     << " bytes read";
15032c593315Sopenharmony_ci  }
15042c593315Sopenharmony_ci
15052c593315Sopenharmony_ci  auto config = get_config();
15062c593315Sopenharmony_ci  auto &fwdconf = config->http.forwarded;
15072c593315Sopenharmony_ci
15082c593315Sopenharmony_ci  if ((fwdconf.params & FORWARDED_FOR) &&
15092c593315Sopenharmony_ci      fwdconf.for_node_type == ForwardedNode::IP) {
15102c593315Sopenharmony_ci    init_forwarded_for(family, ipaddr_);
15112c593315Sopenharmony_ci  }
15122c593315Sopenharmony_ci
15132c593315Sopenharmony_ci  return on_proxy_protocol_finish();
15142c593315Sopenharmony_ci}
15152c593315Sopenharmony_ci
15162c593315Sopenharmony_ciint ClientHandler::proxy_protocol_v2_read() {
15172c593315Sopenharmony_ci  // Assume that first str_size(PROXY_PROTO_V2_SIG) octets match v2
15182c593315Sopenharmony_ci  // protocol signature and followed by the bytes which indicates v2.
15192c593315Sopenharmony_ci  assert(rb_.rleft() >= PROXY_PROTO_V2_HDLEN);
15202c593315Sopenharmony_ci
15212c593315Sopenharmony_ci  auto p = rb_.pos() + str_size(PROXY_PROTO_V2_SIG);
15222c593315Sopenharmony_ci
15232c593315Sopenharmony_ci  assert(((*p) & 0xf0) == 0x20);
15242c593315Sopenharmony_ci
15252c593315Sopenharmony_ci  enum { LOCAL, PROXY } cmd;
15262c593315Sopenharmony_ci
15272c593315Sopenharmony_ci  auto cmd_bits = (*p++) & 0xf;
15282c593315Sopenharmony_ci  switch (cmd_bits) {
15292c593315Sopenharmony_ci  case 0x0:
15302c593315Sopenharmony_ci    cmd = LOCAL;
15312c593315Sopenharmony_ci    break;
15322c593315Sopenharmony_ci  case 0x01:
15332c593315Sopenharmony_ci    cmd = PROXY;
15342c593315Sopenharmony_ci    break;
15352c593315Sopenharmony_ci  default:
15362c593315Sopenharmony_ci    if (LOG_ENABLED(INFO)) {
15372c593315Sopenharmony_ci      CLOG(INFO, this) << "PROXY-protocol-v2: Unknown command " << log::hex
15382c593315Sopenharmony_ci                       << cmd_bits;
15392c593315Sopenharmony_ci    }
15402c593315Sopenharmony_ci    return -1;
15412c593315Sopenharmony_ci  }
15422c593315Sopenharmony_ci
15432c593315Sopenharmony_ci  auto fam = *p++;
15442c593315Sopenharmony_ci  uint16_t len;
15452c593315Sopenharmony_ci  memcpy(&len, p, sizeof(len));
15462c593315Sopenharmony_ci  len = ntohs(len);
15472c593315Sopenharmony_ci
15482c593315Sopenharmony_ci  p += sizeof(len);
15492c593315Sopenharmony_ci
15502c593315Sopenharmony_ci  if (LOG_ENABLED(INFO)) {
15512c593315Sopenharmony_ci    CLOG(INFO, this) << "PROXY-protocol-v2: Detected family=" << log::hex << fam
15522c593315Sopenharmony_ci                     << ", len=" << log::dec << len;
15532c593315Sopenharmony_ci  }
15542c593315Sopenharmony_ci
15552c593315Sopenharmony_ci  if (rb_.last() - p < len) {
15562c593315Sopenharmony_ci    if (LOG_ENABLED(INFO)) {
15572c593315Sopenharmony_ci      CLOG(INFO, this)
15582c593315Sopenharmony_ci          << "PROXY-protocol-v2: Prematurely truncated header block; require "
15592c593315Sopenharmony_ci          << len << " bytes, " << rb_.last() - p << " bytes left";
15602c593315Sopenharmony_ci    }
15612c593315Sopenharmony_ci    return -1;
15622c593315Sopenharmony_ci  }
15632c593315Sopenharmony_ci
15642c593315Sopenharmony_ci  int family;
15652c593315Sopenharmony_ci  std::array<char, std::max(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)> src_addr,
15662c593315Sopenharmony_ci      dst_addr;
15672c593315Sopenharmony_ci  size_t addrlen;
15682c593315Sopenharmony_ci
15692c593315Sopenharmony_ci  switch (fam) {
15702c593315Sopenharmony_ci  case 0x11:
15712c593315Sopenharmony_ci  case 0x12:
15722c593315Sopenharmony_ci    if (len < 12) {
15732c593315Sopenharmony_ci      if (LOG_ENABLED(INFO)) {
15742c593315Sopenharmony_ci        CLOG(INFO, this) << "PROXY-protocol-v2: Too short AF_INET addresses";
15752c593315Sopenharmony_ci      }
15762c593315Sopenharmony_ci      return -1;
15772c593315Sopenharmony_ci    }
15782c593315Sopenharmony_ci    family = AF_INET;
15792c593315Sopenharmony_ci    addrlen = 4;
15802c593315Sopenharmony_ci    break;
15812c593315Sopenharmony_ci  case 0x21:
15822c593315Sopenharmony_ci  case 0x22:
15832c593315Sopenharmony_ci    if (len < 36) {
15842c593315Sopenharmony_ci      if (LOG_ENABLED(INFO)) {
15852c593315Sopenharmony_ci        CLOG(INFO, this) << "PROXY-protocol-v2: Too short AF_INET6 addresses";
15862c593315Sopenharmony_ci      }
15872c593315Sopenharmony_ci      return -1;
15882c593315Sopenharmony_ci    }
15892c593315Sopenharmony_ci    family = AF_INET6;
15902c593315Sopenharmony_ci    addrlen = 16;
15912c593315Sopenharmony_ci    break;
15922c593315Sopenharmony_ci  case 0x31:
15932c593315Sopenharmony_ci  case 0x32:
15942c593315Sopenharmony_ci    if (len < 216) {
15952c593315Sopenharmony_ci      if (LOG_ENABLED(INFO)) {
15962c593315Sopenharmony_ci        CLOG(INFO, this) << "PROXY-protocol-v2: Too short AF_UNIX addresses";
15972c593315Sopenharmony_ci      }
15982c593315Sopenharmony_ci      return -1;
15992c593315Sopenharmony_ci    }
16002c593315Sopenharmony_ci    // fall through
16012c593315Sopenharmony_ci  case 0x00: {
16022c593315Sopenharmony_ci    // UNSPEC and UNIX are just ignored.
16032c593315Sopenharmony_ci    if (LOG_ENABLED(INFO)) {
16042c593315Sopenharmony_ci      CLOG(INFO, this) << "PROXY-protocol-v2: Ignore combination of address "
16052c593315Sopenharmony_ci                          "family and protocol "
16062c593315Sopenharmony_ci                       << log::hex << fam;
16072c593315Sopenharmony_ci    }
16082c593315Sopenharmony_ci    rb_.drain(PROXY_PROTO_V2_HDLEN + len);
16092c593315Sopenharmony_ci    return on_proxy_protocol_finish();
16102c593315Sopenharmony_ci  }
16112c593315Sopenharmony_ci  default:
16122c593315Sopenharmony_ci    if (LOG_ENABLED(INFO)) {
16132c593315Sopenharmony_ci      CLOG(INFO, this) << "PROXY-protocol-v2: Unknown combination of address "
16142c593315Sopenharmony_ci                          "family and protocol "
16152c593315Sopenharmony_ci                       << log::hex << fam;
16162c593315Sopenharmony_ci    }
16172c593315Sopenharmony_ci    return -1;
16182c593315Sopenharmony_ci  }
16192c593315Sopenharmony_ci
16202c593315Sopenharmony_ci  if (cmd != PROXY) {
16212c593315Sopenharmony_ci    if (LOG_ENABLED(INFO)) {
16222c593315Sopenharmony_ci      CLOG(INFO, this) << "PROXY-protocol-v2: Ignore non-PROXY command";
16232c593315Sopenharmony_ci    }
16242c593315Sopenharmony_ci    rb_.drain(PROXY_PROTO_V2_HDLEN + len);
16252c593315Sopenharmony_ci    return on_proxy_protocol_finish();
16262c593315Sopenharmony_ci  }
16272c593315Sopenharmony_ci
16282c593315Sopenharmony_ci  if (inet_ntop(family, p, src_addr.data(), src_addr.size()) == nullptr) {
16292c593315Sopenharmony_ci    if (LOG_ENABLED(INFO)) {
16302c593315Sopenharmony_ci      CLOG(INFO, this) << "PROXY-protocol-v2: Unable to parse source address";
16312c593315Sopenharmony_ci    }
16322c593315Sopenharmony_ci    return -1;
16332c593315Sopenharmony_ci  }
16342c593315Sopenharmony_ci
16352c593315Sopenharmony_ci  p += addrlen;
16362c593315Sopenharmony_ci
16372c593315Sopenharmony_ci  if (inet_ntop(family, p, dst_addr.data(), dst_addr.size()) == nullptr) {
16382c593315Sopenharmony_ci    if (LOG_ENABLED(INFO)) {
16392c593315Sopenharmony_ci      CLOG(INFO, this)
16402c593315Sopenharmony_ci          << "PROXY-protocol-v2: Unable to parse destination address";
16412c593315Sopenharmony_ci    }
16422c593315Sopenharmony_ci    return -1;
16432c593315Sopenharmony_ci  }
16442c593315Sopenharmony_ci
16452c593315Sopenharmony_ci  p += addrlen;
16462c593315Sopenharmony_ci
16472c593315Sopenharmony_ci  uint16_t src_port;
16482c593315Sopenharmony_ci
16492c593315Sopenharmony_ci  memcpy(&src_port, p, sizeof(src_port));
16502c593315Sopenharmony_ci  src_port = ntohs(src_port);
16512c593315Sopenharmony_ci
16522c593315Sopenharmony_ci  // We don't use destination port.
16532c593315Sopenharmony_ci  p += 4;
16542c593315Sopenharmony_ci
16552c593315Sopenharmony_ci  ipaddr_ = make_string_ref(balloc_, StringRef{src_addr.data()});
16562c593315Sopenharmony_ci  port_ = util::make_string_ref_uint(balloc_, src_port);
16572c593315Sopenharmony_ci
16582c593315Sopenharmony_ci  if (LOG_ENABLED(INFO)) {
16592c593315Sopenharmony_ci    CLOG(INFO, this) << "PROXY-protocol-v2: Finished reading proxy addresses, "
16602c593315Sopenharmony_ci                     << p - rb_.pos() << " bytes read, "
16612c593315Sopenharmony_ci                     << PROXY_PROTO_V2_HDLEN + len - (p - rb_.pos())
16622c593315Sopenharmony_ci                     << " bytes left";
16632c593315Sopenharmony_ci  }
16642c593315Sopenharmony_ci
16652c593315Sopenharmony_ci  auto config = get_config();
16662c593315Sopenharmony_ci  auto &fwdconf = config->http.forwarded;
16672c593315Sopenharmony_ci
16682c593315Sopenharmony_ci  if ((fwdconf.params & FORWARDED_FOR) &&
16692c593315Sopenharmony_ci      fwdconf.for_node_type == ForwardedNode::IP) {
16702c593315Sopenharmony_ci    init_forwarded_for(family, ipaddr_);
16712c593315Sopenharmony_ci  }
16722c593315Sopenharmony_ci
16732c593315Sopenharmony_ci  rb_.drain(PROXY_PROTO_V2_HDLEN + len);
16742c593315Sopenharmony_ci  return on_proxy_protocol_finish();
16752c593315Sopenharmony_ci}
16762c593315Sopenharmony_ci
16772c593315Sopenharmony_ciStringRef ClientHandler::get_forwarded_by() const {
16782c593315Sopenharmony_ci  auto &fwdconf = get_config()->http.forwarded;
16792c593315Sopenharmony_ci
16802c593315Sopenharmony_ci  if (fwdconf.by_node_type == ForwardedNode::OBFUSCATED) {
16812c593315Sopenharmony_ci    return fwdconf.by_obfuscated;
16822c593315Sopenharmony_ci  }
16832c593315Sopenharmony_ci
16842c593315Sopenharmony_ci  return faddr_->hostport;
16852c593315Sopenharmony_ci}
16862c593315Sopenharmony_ci
16872c593315Sopenharmony_ciStringRef ClientHandler::get_forwarded_for() const { return forwarded_for_; }
16882c593315Sopenharmony_ci
16892c593315Sopenharmony_ciconst UpstreamAddr *ClientHandler::get_upstream_addr() const { return faddr_; }
16902c593315Sopenharmony_ci
16912c593315Sopenharmony_ciConnection *ClientHandler::get_connection() { return &conn_; };
16922c593315Sopenharmony_ci
16932c593315Sopenharmony_civoid ClientHandler::set_tls_sni(const StringRef &sni) {
16942c593315Sopenharmony_ci  sni_ = make_string_ref(balloc_, sni);
16952c593315Sopenharmony_ci}
16962c593315Sopenharmony_ci
16972c593315Sopenharmony_ciStringRef ClientHandler::get_tls_sni() const { return sni_; }
16982c593315Sopenharmony_ci
16992c593315Sopenharmony_ciStringRef ClientHandler::get_alpn() const { return alpn_; }
17002c593315Sopenharmony_ci
17012c593315Sopenharmony_ciBlockAllocator &ClientHandler::get_block_allocator() { return balloc_; }
17022c593315Sopenharmony_ci
17032c593315Sopenharmony_civoid ClientHandler::set_alpn_from_conn() {
17042c593315Sopenharmony_ci  const unsigned char *alpn;
17052c593315Sopenharmony_ci  unsigned int alpnlen;
17062c593315Sopenharmony_ci
17072c593315Sopenharmony_ci  SSL_get0_alpn_selected(conn_.tls.ssl, &alpn, &alpnlen);
17082c593315Sopenharmony_ci
17092c593315Sopenharmony_ci  alpn_ = make_string_ref(balloc_, StringRef{alpn, alpnlen});
17102c593315Sopenharmony_ci}
17112c593315Sopenharmony_ci
17122c593315Sopenharmony_ci} // namespace shrpx
1713