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