2 * nghttp2 - HTTP/2 C Library
4 * Copyright (c) 2012 Tatsuhiro Tsujikawa
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 #include "shrpx_http_downstream_connection.h"
27 #include "shrpx_client_handler.h"
28 #include "shrpx_upstream.h"
29 #include "shrpx_downstream.h"
30 #include "shrpx_config.h"
31 #include "shrpx_error.h"
32 #include "shrpx_http.h"
33 #include "shrpx_worker_config.h"
34 #include "shrpx_connect_blocker.h"
35 #include "shrpx_downstream_connection_pool.h"
36 #include "shrpx_worker.h"
40 using namespace nghttp2;
45 void timeoutcb(struct ev_loop *loop, ev_timer *w, int revents) {
46 auto conn = static_cast<Connection *>(w->data);
47 auto dconn = static_cast<HttpDownstreamConnection *>(conn->data);
49 if (LOG_ENABLED(INFO)) {
50 DCLOG(INFO, dconn) << "Time out";
53 auto downstream = dconn->get_downstream();
54 auto upstream = downstream->get_upstream();
55 auto handler = upstream->get_client_handler();
57 // Do this so that dconn is not pooled
58 downstream->set_response_connection_close(true);
60 if (upstream->downstream_error(dconn, Downstream::EVENT_TIMEOUT) != 0) {
67 void readcb(struct ev_loop *loop, ev_io *w, int revents) {
68 auto conn = static_cast<Connection *>(w->data);
69 auto dconn = static_cast<HttpDownstreamConnection *>(conn->data);
70 auto downstream = dconn->get_downstream();
71 auto upstream = downstream->get_upstream();
72 auto handler = upstream->get_client_handler();
74 if (upstream->downstream_read(dconn) != 0) {
81 void writecb(struct ev_loop *loop, ev_io *w, int revents) {
82 auto conn = static_cast<Connection *>(w->data);
83 auto dconn = static_cast<HttpDownstreamConnection *>(conn->data);
84 auto downstream = dconn->get_downstream();
85 auto upstream = downstream->get_upstream();
86 auto handler = upstream->get_client_handler();
88 if (upstream->downstream_write(dconn) != 0) {
95 void connectcb(struct ev_loop *loop, ev_io *w, int revents) {
96 auto conn = static_cast<Connection *>(w->data);
97 auto dconn = static_cast<HttpDownstreamConnection *>(conn->data);
98 auto downstream = dconn->get_downstream();
99 auto upstream = downstream->get_upstream();
100 auto handler = upstream->get_client_handler();
101 if (dconn->on_connect() != 0) {
102 if (upstream->on_downstream_abort_request(downstream, 503) != 0) {
107 writecb(loop, w, revents);
111 HttpDownstreamConnection::HttpDownstreamConnection(
112 DownstreamConnectionPool *dconn_pool, struct ev_loop *loop)
113 : DownstreamConnection(dconn_pool),
114 conn_(loop, -1, nullptr, get_config()->downstream_write_timeout,
115 get_config()->downstream_read_timeout, 0, 0, 0, 0, connectcb,
116 readcb, timeoutcb, this),
117 ioctrl_(&conn_.rlimit), response_htp_{0}, addr_idx_(0) {}
119 HttpDownstreamConnection::~HttpDownstreamConnection() {
120 // Downstream and DownstreamConnection may be deleted
123 downstream_->release_downstream_connection();
127 int HttpDownstreamConnection::attach_downstream(Downstream *downstream) {
128 if (LOG_ENABLED(INFO)) {
129 DCLOG(INFO, this) << "Attaching to DOWNSTREAM:" << downstream;
132 if (conn_.fd == -1) {
133 auto connect_blocker = client_handler_->get_http1_connect_blocker();
135 if (connect_blocker->blocked()) {
136 if (LOG_ENABLED(INFO)) {
138 << "Downstream connection was blocked by connect_blocker";
143 auto worker_stat = client_handler_->get_worker_stat();
144 auto end = worker_stat->next_downstream;
146 auto i = worker_stat->next_downstream;
147 ++worker_stat->next_downstream;
148 worker_stat->next_downstream %= get_config()->downstream_addrs.size();
150 conn_.fd = util::create_nonblock_socket(
151 get_config()->downstream_addrs[i].addr.storage.ss_family);
153 if (conn_.fd == -1) {
155 DCLOG(WARN, this) << "socket() failed; errno=" << error;
157 connect_blocker->on_failure();
159 return SHRPX_ERR_NETWORK;
163 rv = connect(conn_.fd, const_cast<sockaddr *>(
164 &get_config()->downstream_addrs[i].addr.sa),
165 get_config()->downstream_addrs[i].addrlen);
166 if (rv != 0 && errno != EINPROGRESS) {
168 DCLOG(WARN, this) << "connect() failed; errno=" << error;
170 connect_blocker->on_failure();
174 if (end == worker_stat->next_downstream) {
175 return SHRPX_ERR_NETWORK;
178 // Try again with the next downstream server
182 if (LOG_ENABLED(INFO)) {
183 DCLOG(INFO, this) << "Connecting to downstream server";
188 ev_io_set(&conn_.wev, conn_.fd, EV_WRITE);
189 ev_io_set(&conn_.rev, conn_.fd, EV_READ);
191 conn_.wlimit.startw();
197 downstream_ = downstream;
199 http_parser_init(&response_htp_, HTTP_RESPONSE);
200 response_htp_.data = downstream_;
202 ev_set_cb(&conn_.rev, readcb);
204 conn_.rt.repeat = get_config()->downstream_read_timeout;
205 ev_timer_again(conn_.loop, &conn_.rt);
206 // TODO we should have timeout for connection establishment
207 ev_timer_again(conn_.loop, &conn_.wt);
212 int HttpDownstreamConnection::push_request_headers() {
213 const char *authority = nullptr, *host = nullptr;
214 if (!get_config()->no_host_rewrite && !get_config()->http2_proxy &&
215 !get_config()->client_proxy) {
216 if (!downstream_->get_request_http2_authority().empty()) {
217 authority = get_config()->downstream_addrs[addr_idx_].hostport.get();
219 if (downstream_->get_request_header(http2::HD_HOST)) {
220 host = get_config()->downstream_addrs[addr_idx_].hostport.get();
223 if (!downstream_->get_request_http2_authority().empty()) {
224 authority = downstream_->get_request_http2_authority().c_str();
226 auto h = downstream_->get_request_header(http2::HD_HOST);
228 host = h->value.c_str();
232 if (!authority && !host) {
233 // upstream is HTTP/1.0. We use backend server's host
235 host = get_config()->downstream_addrs[addr_idx_].hostport.get();
239 downstream_->set_request_downstream_host(authority);
241 downstream_->set_request_downstream_host(host);
244 downstream_->assemble_request_cookie();
246 // Assume that method and request path do not contain \r\n.
247 std::string hdrs = downstream_->get_request_method();
249 if (downstream_->get_request_method() == "CONNECT") {
253 hdrs += downstream_->get_request_path();
255 } else if (get_config()->http2_proxy &&
256 !downstream_->get_request_http2_scheme().empty() && authority &&
257 (downstream_->get_request_path().c_str()[0] == '/' ||
258 downstream_->get_request_path() == "*")) {
259 // Construct absolute-form request target because we are going to
260 // send a request to a HTTP/1 proxy.
261 hdrs += downstream_->get_request_http2_scheme();
265 // Server-wide OPTIONS takes following form in proxy request:
267 // OPTIONS http://example.org HTTP/1.1
269 // Notice that no slash after authority. See
270 // http://tools.ietf.org/html/rfc7230#section-5.3.4
271 if (downstream_->get_request_path() != "*") {
272 hdrs += downstream_->get_request_path();
275 // No proxy case. get_request_path() may be absolute-form but we
277 hdrs += downstream_->get_request_path();
279 hdrs += " HTTP/1.1\r\nHost: ";
287 http2::build_http1_headers_from_headers(hdrs,
288 downstream_->get_request_headers());
290 if (!downstream_->get_assembled_request_cookie().empty()) {
292 hdrs += downstream_->get_assembled_request_cookie();
296 if (downstream_->get_request_method() != "CONNECT" &&
297 downstream_->get_request_http2_expect_body() &&
298 !downstream_->get_request_header(http2::HD_CONTENT_LENGTH)) {
300 downstream_->set_chunked_request(true);
301 hdrs += "Transfer-Encoding: chunked\r\n";
304 if (downstream_->get_request_connection_close()) {
305 hdrs += "Connection: close\r\n";
307 auto xff = downstream_->get_request_header(http2::HD_X_FORWARDED_FOR);
308 if (get_config()->add_x_forwarded_for) {
309 hdrs += "X-Forwarded-For: ";
310 if (xff && !get_config()->strip_incoming_x_forwarded_for) {
311 hdrs += (*xff).value;
314 hdrs += client_handler_->get_ipaddr();
316 } else if (xff && !get_config()->strip_incoming_x_forwarded_for) {
317 hdrs += "X-Forwarded-For: ";
318 hdrs += (*xff).value;
321 if (!get_config()->http2_proxy && !get_config()->client_proxy &&
322 downstream_->get_request_method() != "CONNECT") {
323 hdrs += "X-Forwarded-Proto: ";
324 if (!downstream_->get_request_http2_scheme().empty()) {
325 hdrs += downstream_->get_request_http2_scheme();
327 } else if (client_handler_->get_ssl()) {
333 auto expect = downstream_->get_request_header(http2::HD_EXPECT);
334 if (expect && !util::strifind((*expect).value.c_str(), "100-continue")) {
336 hdrs += (*expect).value;
339 auto via = downstream_->get_request_header(http2::HD_VIA);
340 if (get_config()->no_via) {
343 hdrs += (*via).value;
349 hdrs += (*via).value;
352 hdrs += http::create_via_header_value(downstream_->get_request_major(),
353 downstream_->get_request_minor());
358 if (LOG_ENABLED(INFO)) {
361 if (worker_config->errorlog_tty) {
362 nhdrs = http::colorizeHeaders(hdrs.c_str());
363 hdrp = nhdrs.c_str();
367 DCLOG(INFO, this) << "HTTP request headers. stream_id="
368 << downstream_->get_stream_id() << "\n" << hdrp;
370 auto output = downstream_->get_request_buf();
371 output->append(hdrs.c_str(), hdrs.size());
378 int HttpDownstreamConnection::push_upload_data_chunk(const uint8_t *data,
380 auto chunked = downstream_->get_chunked_request();
381 auto output = downstream_->get_request_buf();
384 auto chunk_size_hex = util::utox(datalen);
385 output->append(chunk_size_hex.c_str(), chunk_size_hex.size());
386 output->append("\r\n");
389 output->append(data, datalen);
392 output->append("\r\n");
400 int HttpDownstreamConnection::end_upload_data() {
401 if (!downstream_->get_chunked_request()) {
405 auto output = downstream_->get_request_buf();
406 output->append("0\r\n\r\n");
414 void idle_readcb(struct ev_loop *loop, ev_io *w, int revents) {
415 auto conn = static_cast<Connection *>(w->data);
416 auto dconn = static_cast<HttpDownstreamConnection *>(conn->data);
417 if (LOG_ENABLED(INFO)) {
418 DCLOG(INFO, dconn) << "Idle connection EOF";
420 auto dconn_pool = dconn->get_dconn_pool();
421 dconn_pool->remove_downstream_connection(dconn);
427 void idle_timeoutcb(struct ev_loop *loop, ev_timer *w, int revents) {
428 auto conn = static_cast<Connection *>(w->data);
429 auto dconn = static_cast<HttpDownstreamConnection *>(conn->data);
430 if (LOG_ENABLED(INFO)) {
431 DCLOG(INFO, dconn) << "Idle connection timeout";
433 auto dconn_pool = dconn->get_dconn_pool();
434 dconn_pool->remove_downstream_connection(dconn);
439 void HttpDownstreamConnection::detach_downstream(Downstream *downstream) {
440 if (LOG_ENABLED(INFO)) {
441 DCLOG(INFO, this) << "Detaching from DOWNSTREAM:" << downstream;
443 downstream_ = nullptr;
444 ioctrl_.force_resume_read();
446 conn_.rlimit.startw();
447 conn_.wlimit.stopw();
449 ev_set_cb(&conn_.rev, idle_readcb);
451 ev_timer_stop(conn_.loop, &conn_.wt);
453 conn_.rt.repeat = get_config()->downstream_idle_read_timeout;
454 ev_set_cb(&conn_.rt, idle_timeoutcb);
455 ev_timer_again(conn_.loop, &conn_.rt);
458 void HttpDownstreamConnection::pause_read(IOCtrlReason reason) {
459 ioctrl_.pause_read(reason);
462 int HttpDownstreamConnection::resume_read(IOCtrlReason reason,
464 if (!downstream_->response_buf_full()) {
465 ioctrl_.resume_read(reason);
471 void HttpDownstreamConnection::force_resume_read() {
472 ioctrl_.force_resume_read();
476 int htp_msg_begincb(http_parser *htp) {
477 auto downstream = static_cast<Downstream *>(htp->data);
479 if (downstream->get_response_state() != Downstream::INITIAL) {
488 int htp_hdrs_completecb(http_parser *htp) {
489 auto downstream = static_cast<Downstream *>(htp->data);
490 auto upstream = downstream->get_upstream();
493 downstream->set_response_http_status(htp->status_code);
494 downstream->set_response_major(htp->http_major);
495 downstream->set_response_minor(htp->http_minor);
497 if (downstream->index_response_headers() != 0) {
498 downstream->set_response_state(Downstream::MSG_BAD_HEADER);
502 if (downstream->get_non_final_response()) {
503 // For non-final response code, we just call
504 // on_downstream_header_complete() without changing response
506 rv = upstream->on_downstream_header_complete(downstream);
515 downstream->set_response_connection_close(!http_should_keep_alive(htp));
516 downstream->set_response_state(Downstream::HEADER_COMPLETE);
517 downstream->inspect_http1_response();
518 downstream->check_upgrade_fulfilled();
519 if (downstream->get_upgraded()) {
520 downstream->set_response_connection_close(true);
522 if (upstream->on_downstream_header_complete(downstream) != 0) {
526 if (downstream->get_upgraded()) {
527 // Upgrade complete, read until EOF in both ends
528 if (upstream->resume_read(SHRPX_MSG_BLOCK, downstream, 0) != 0) {
531 downstream->set_request_state(Downstream::HEADER_COMPLETE);
532 if (LOG_ENABLED(INFO)) {
533 LOG(INFO) << "HTTP upgrade success. stream_id="
534 << downstream->get_stream_id();
538 unsigned int status = downstream->get_response_http_status();
539 // Ignore the response body. HEAD response may contain
540 // Content-Length or Transfer-Encoding: chunked. Some server send
541 // 304 status code with nonzero Content-Length, but without response
543 // http://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-20#section-3.3
545 // TODO It seems that the cases other than HEAD are handled by
546 // http-parser. Need test.
547 return downstream->get_request_method() == "HEAD" ||
548 (100 <= status && status <= 199) || status == 204 ||
556 int htp_hdr_keycb(http_parser *htp, const char *data, size_t len) {
557 auto downstream = static_cast<Downstream *>(htp->data);
558 if (downstream->get_response_state() != Downstream::INITIAL) {
562 if (downstream->get_response_header_key_prev()) {
563 downstream->append_last_response_header_key(data, len);
565 downstream->add_response_header(std::string(data, len), "");
567 if (downstream->get_response_headers_sum() > Downstream::MAX_HEADERS_SUM) {
568 if (LOG_ENABLED(INFO)) {
569 DLOG(INFO, downstream) << "Too large header block size="
570 << downstream->get_response_headers_sum();
579 int htp_hdr_valcb(http_parser *htp, const char *data, size_t len) {
580 auto downstream = static_cast<Downstream *>(htp->data);
581 if (downstream->get_response_state() != Downstream::INITIAL) {
585 if (downstream->get_response_header_key_prev()) {
586 downstream->set_last_response_header_value(std::string(data, len));
588 downstream->append_last_response_header_value(data, len);
590 if (downstream->get_response_headers_sum() > Downstream::MAX_HEADERS_SUM) {
591 if (LOG_ENABLED(INFO)) {
592 DLOG(INFO, downstream) << "Too large header block size="
593 << downstream->get_response_headers_sum();
602 int htp_bodycb(http_parser *htp, const char *data, size_t len) {
603 auto downstream = static_cast<Downstream *>(htp->data);
605 downstream->add_response_bodylen(len);
607 return downstream->get_upstream()->on_downstream_body(
608 downstream, reinterpret_cast<const uint8_t *>(data), len, true);
613 int htp_msg_completecb(http_parser *htp) {
614 auto downstream = static_cast<Downstream *>(htp->data);
616 if (downstream->get_non_final_response()) {
617 downstream->reset_response();
622 downstream->set_response_state(Downstream::MSG_COMPLETE);
623 // Block reading another response message from (broken?)
624 // server. This callback is not called if the connection is
626 downstream->pause_read(SHRPX_MSG_BLOCK);
627 return downstream->get_upstream()->on_downstream_body_complete(downstream);
632 http_parser_settings htp_hooks = {
633 htp_msg_begincb, // http_cb on_message_begin;
634 nullptr, // http_data_cb on_url;
635 nullptr, // http_data_cb on_status;
636 htp_hdr_keycb, // http_data_cb on_header_field;
637 htp_hdr_valcb, // http_data_cb on_header_value;
638 htp_hdrs_completecb, // http_cb on_headers_complete;
639 htp_bodycb, // http_data_cb on_body;
640 htp_msg_completecb // http_cb on_message_complete;
644 int HttpDownstreamConnection::on_read() {
645 ev_timer_again(conn_.loop, &conn_.rt);
646 std::array<uint8_t, 8192> buf;
649 if (downstream_->get_upgraded()) {
650 // For upgraded connection, just pass data to the upstream.
652 auto nread = conn_.read_clear(buf.data(), buf.size());
662 rv = downstream_->get_upstream()->on_downstream_body(
663 downstream_, buf.data(), nread, true);
668 if (downstream_->response_buf_full()) {
669 downstream_->pause_read(SHRPX_NO_BUFFER);
676 auto nread = conn_.read_clear(buf.data(), buf.size());
687 http_parser_execute(&response_htp_, &htp_hooks,
688 reinterpret_cast<char *>(buf.data()), nread);
690 if (nproc != static_cast<size_t>(nread)) {
691 if (LOG_ENABLED(INFO)) {
692 DCLOG(INFO, this) << "nproc != nread";
697 auto htperr = HTTP_PARSER_ERRNO(&response_htp_);
699 if (htperr != HPE_OK) {
700 if (LOG_ENABLED(INFO)) {
701 DCLOG(INFO, this) << "HTTP parser failure: "
702 << "(" << http_errno_name(htperr) << ") "
703 << http_errno_description(htperr);
709 if (downstream_->response_buf_full()) {
710 downstream_->pause_read(SHRPX_NO_BUFFER);
716 int HttpDownstreamConnection::on_write() {
717 ev_timer_again(conn_.loop, &conn_.rt);
719 auto upstream = downstream_->get_upstream();
720 auto input = downstream_->get_request_buf();
722 std::array<struct iovec, MAX_WR_IOVCNT> iov;
724 while (input->rleft() > 0) {
725 auto iovcnt = input->riovec(iov.data(), iov.size());
727 auto nwrite = conn_.writev_clear(iov.data(), iovcnt);
737 input->drain(nwrite);
740 conn_.wlimit.stopw();
741 ev_timer_stop(conn_.loop, &conn_.wt);
743 if (input->rleft() == 0) {
744 upstream->resume_read(SHRPX_NO_BUFFER, downstream_,
745 downstream_->get_request_datalen());
751 int HttpDownstreamConnection::on_connect() {
752 auto connect_blocker = client_handler_->get_http1_connect_blocker();
754 if (!util::check_socket_connected(conn_.fd)) {
755 conn_.wlimit.stopw();
757 if (LOG_ENABLED(INFO)) {
758 DLOG(INFO, this) << "downstream connect failed";
760 connect_blocker->on_failure();
764 connect_blocker->on_success();
766 conn_.rlimit.startw();
767 ev_set_cb(&conn_.wev, writecb);
772 void HttpDownstreamConnection::on_upstream_change(Upstream *upstream) {}
774 void HttpDownstreamConnection::signal_write() { conn_.wlimit.startw(); }