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_log_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),
120 HttpDownstreamConnection::~HttpDownstreamConnection() {
121 // Downstream and DownstreamConnection may be deleted
124 downstream_->release_downstream_connection();
128 int HttpDownstreamConnection::attach_downstream(Downstream *downstream) {
129 if (LOG_ENABLED(INFO)) {
130 DCLOG(INFO, this) << "Attaching to DOWNSTREAM:" << downstream;
133 if (conn_.fd == -1) {
134 auto connect_blocker = client_handler_->get_connect_blocker();
136 if (connect_blocker->blocked()) {
137 if (LOG_ENABLED(INFO)) {
139 << "Downstream connection was blocked by connect_blocker";
144 auto worker = client_handler_->get_worker();
145 auto worker_stat = worker->get_worker_stat();
146 auto end = worker_stat->next_downstream;
148 auto i = worker_stat->next_downstream;
149 ++worker_stat->next_downstream;
150 worker_stat->next_downstream %= get_config()->downstream_addrs.size();
152 conn_.fd = util::create_nonblock_socket(
153 get_config()->downstream_addrs[i].addr.storage.ss_family);
155 if (conn_.fd == -1) {
157 DCLOG(WARN, this) << "socket() failed; errno=" << error;
159 connect_blocker->on_failure();
161 return SHRPX_ERR_NETWORK;
165 rv = connect(conn_.fd, &get_config()->downstream_addrs[i].addr.sa,
166 get_config()->downstream_addrs[i].addrlen);
167 if (rv != 0 && errno != EINPROGRESS) {
169 DCLOG(WARN, this) << "connect() failed; errno=" << error;
171 connect_blocker->on_failure();
175 if (end == worker_stat->next_downstream) {
176 return SHRPX_ERR_NETWORK;
179 // Try again with the next downstream server
183 if (LOG_ENABLED(INFO)) {
184 DCLOG(INFO, this) << "Connecting to downstream server";
189 ev_io_set(&conn_.wev, conn_.fd, EV_WRITE);
190 ev_io_set(&conn_.rev, conn_.fd, EV_READ);
192 conn_.wlimit.startw();
198 downstream_ = downstream;
200 http_parser_init(&response_htp_, HTTP_RESPONSE);
201 response_htp_.data = downstream_;
203 ev_set_cb(&conn_.rev, readcb);
205 conn_.rt.repeat = get_config()->downstream_read_timeout;
206 ev_timer_again(conn_.loop, &conn_.rt);
207 // TODO we should have timeout for connection establishment
208 ev_timer_again(conn_.loop, &conn_.wt);
213 int HttpDownstreamConnection::push_request_headers() {
214 const char *authority = nullptr, *host = nullptr;
215 auto downstream_hostport =
216 get_config()->downstream_addrs[addr_idx_].hostport.get();
218 if (!get_config()->no_host_rewrite && !get_config()->http2_proxy &&
219 !get_config()->client_proxy &&
220 downstream_->get_request_method() != "CONNECT") {
221 if (!downstream_->get_request_http2_authority().empty()) {
222 authority = downstream_hostport;
224 if (downstream_->get_request_header(http2::HD_HOST)) {
225 host = downstream_hostport;
228 if (!downstream_->get_request_http2_authority().empty()) {
229 authority = downstream_->get_request_http2_authority().c_str();
231 auto h = downstream_->get_request_header(http2::HD_HOST);
233 host = h->value.c_str();
237 if (!authority && !host) {
238 // upstream is HTTP/1.0. We use backend server's host
240 host = downstream_hostport;
244 downstream_->set_request_downstream_host(authority);
246 downstream_->set_request_downstream_host(host);
249 downstream_->assemble_request_cookie();
251 // Assume that method and request path do not contain \r\n.
252 std::string hdrs = downstream_->get_request_method();
254 if (downstream_->get_request_method() == "CONNECT") {
258 hdrs += downstream_->get_request_path();
260 } else if (get_config()->http2_proxy || get_config()->client_proxy) {
261 // Construct absolute-form request target because we are going to
262 // send a request to a HTTP/1 proxy.
263 if (downstream_->get_request_http2_scheme().empty()) {
264 // this comes from HTTP/1 upstream, use http scheme. We don't
265 // support https forward link yet.
268 hdrs += downstream_->get_request_http2_scheme();
277 // Server-wide OPTIONS takes following form in proxy request:
279 // OPTIONS http://example.org HTTP/1.1
281 // Notice that no slash after authority. See
282 // http://tools.ietf.org/html/rfc7230#section-5.3.4
283 if (downstream_->get_request_path() != "*") {
284 hdrs += downstream_->get_request_path();
288 hdrs += downstream_->get_request_path();
290 hdrs += " HTTP/1.1\r\nHost: ";
298 http2::build_http1_headers_from_headers(hdrs,
299 downstream_->get_request_headers());
301 if (!downstream_->get_assembled_request_cookie().empty()) {
303 hdrs += downstream_->get_assembled_request_cookie();
307 if (downstream_->get_request_method() != "CONNECT" &&
308 downstream_->get_request_http2_expect_body() &&
309 !downstream_->get_request_header(http2::HD_CONTENT_LENGTH)) {
311 downstream_->set_chunked_request(true);
312 hdrs += "Transfer-Encoding: chunked\r\n";
315 if (downstream_->get_request_connection_close()) {
316 hdrs += "Connection: close\r\n";
318 auto xff = downstream_->get_request_header(http2::HD_X_FORWARDED_FOR);
319 if (get_config()->add_x_forwarded_for) {
320 hdrs += "X-Forwarded-For: ";
321 if (xff && !get_config()->strip_incoming_x_forwarded_for) {
322 hdrs += (*xff).value;
325 hdrs += client_handler_->get_ipaddr();
327 } else if (xff && !get_config()->strip_incoming_x_forwarded_for) {
328 hdrs += "X-Forwarded-For: ";
329 hdrs += (*xff).value;
332 if (!get_config()->http2_proxy && !get_config()->client_proxy &&
333 downstream_->get_request_method() != "CONNECT") {
334 hdrs += "X-Forwarded-Proto: ";
335 if (!downstream_->get_request_http2_scheme().empty()) {
336 hdrs += downstream_->get_request_http2_scheme();
338 } else if (client_handler_->get_ssl()) {
344 auto expect = downstream_->get_request_header(http2::HD_EXPECT);
345 if (expect && !util::strifind((*expect).value.c_str(), "100-continue")) {
347 hdrs += (*expect).value;
350 auto via = downstream_->get_request_header(http2::HD_VIA);
351 if (get_config()->no_via) {
354 hdrs += (*via).value;
360 hdrs += (*via).value;
363 hdrs += http::create_via_header_value(downstream_->get_request_major(),
364 downstream_->get_request_minor());
369 if (LOG_ENABLED(INFO)) {
372 if (log_config()->errorlog_tty) {
373 nhdrs = http::colorizeHeaders(hdrs.c_str());
374 hdrp = nhdrs.c_str();
378 DCLOG(INFO, this) << "HTTP request headers. stream_id="
379 << downstream_->get_stream_id() << "\n" << hdrp;
381 auto output = downstream_->get_request_buf();
382 output->append(hdrs.c_str(), hdrs.size());
389 int HttpDownstreamConnection::push_upload_data_chunk(const uint8_t *data,
391 auto chunked = downstream_->get_chunked_request();
392 auto output = downstream_->get_request_buf();
395 auto chunk_size_hex = util::utox(datalen);
396 output->append(chunk_size_hex.c_str(), chunk_size_hex.size());
397 output->append("\r\n");
400 output->append(data, datalen);
403 output->append("\r\n");
411 int HttpDownstreamConnection::end_upload_data() {
412 if (!downstream_->get_chunked_request()) {
416 auto output = downstream_->get_request_buf();
417 auto &trailers = downstream_->get_request_trailers();
418 if (trailers.empty()) {
419 output->append("0\r\n\r\n");
421 output->append("0\r\n");
422 std::string trailer_part;
423 http2::build_http1_headers_from_headers(trailer_part, trailers);
424 output->append(trailer_part.c_str(), trailer_part.size());
425 output->append("\r\n");
434 void idle_readcb(struct ev_loop *loop, ev_io *w, int revents) {
435 auto conn = static_cast<Connection *>(w->data);
436 auto dconn = static_cast<HttpDownstreamConnection *>(conn->data);
437 if (LOG_ENABLED(INFO)) {
438 DCLOG(INFO, dconn) << "Idle connection EOF";
440 auto dconn_pool = dconn->get_dconn_pool();
441 dconn_pool->remove_downstream_connection(dconn);
447 void idle_timeoutcb(struct ev_loop *loop, ev_timer *w, int revents) {
448 auto conn = static_cast<Connection *>(w->data);
449 auto dconn = static_cast<HttpDownstreamConnection *>(conn->data);
450 if (LOG_ENABLED(INFO)) {
451 DCLOG(INFO, dconn) << "Idle connection timeout";
453 auto dconn_pool = dconn->get_dconn_pool();
454 dconn_pool->remove_downstream_connection(dconn);
459 void HttpDownstreamConnection::detach_downstream(Downstream *downstream) {
460 if (LOG_ENABLED(INFO)) {
461 DCLOG(INFO, this) << "Detaching from DOWNSTREAM:" << downstream;
463 downstream_ = nullptr;
464 ioctrl_.force_resume_read();
466 conn_.rlimit.startw();
467 conn_.wlimit.stopw();
469 ev_set_cb(&conn_.rev, idle_readcb);
471 ev_timer_stop(conn_.loop, &conn_.wt);
473 conn_.rt.repeat = get_config()->downstream_idle_read_timeout;
474 ev_set_cb(&conn_.rt, idle_timeoutcb);
475 ev_timer_again(conn_.loop, &conn_.rt);
478 void HttpDownstreamConnection::pause_read(IOCtrlReason reason) {
479 ioctrl_.pause_read(reason);
482 int HttpDownstreamConnection::resume_read(IOCtrlReason reason,
484 if (!downstream_->response_buf_full()) {
485 ioctrl_.resume_read(reason);
491 void HttpDownstreamConnection::force_resume_read() {
492 ioctrl_.force_resume_read();
496 int htp_msg_begincb(http_parser *htp) {
497 auto downstream = static_cast<Downstream *>(htp->data);
499 if (downstream->get_response_state() != Downstream::INITIAL) {
508 int htp_hdrs_completecb(http_parser *htp) {
509 auto downstream = static_cast<Downstream *>(htp->data);
510 auto upstream = downstream->get_upstream();
513 downstream->set_response_http_status(htp->status_code);
514 downstream->set_response_major(htp->http_major);
515 downstream->set_response_minor(htp->http_minor);
517 if (downstream->index_response_headers() != 0) {
518 downstream->set_response_state(Downstream::MSG_BAD_HEADER);
522 if (downstream->get_non_final_response()) {
523 // Reset content-length because we reuse same Downstream for the
525 downstream->set_response_content_length(-1);
526 // For non-final response code, we just call
527 // on_downstream_header_complete() without changing response
529 rv = upstream->on_downstream_header_complete(downstream);
538 downstream->set_response_connection_close(!http_should_keep_alive(htp));
539 downstream->set_response_state(Downstream::HEADER_COMPLETE);
540 downstream->inspect_http1_response();
541 downstream->check_upgrade_fulfilled();
542 if (downstream->get_upgraded()) {
543 // content-length must be ignored for upgraded connection.
544 downstream->set_response_content_length(-1);
545 downstream->set_response_connection_close(true);
546 // transfer-encoding not applied to upgraded connection
547 downstream->set_chunked_response(false);
549 if (upstream->on_downstream_header_complete(downstream) != 0) {
553 if (downstream->get_upgraded()) {
554 // Upgrade complete, read until EOF in both ends
555 if (upstream->resume_read(SHRPX_NO_BUFFER, downstream, 0) != 0) {
558 downstream->set_request_state(Downstream::HEADER_COMPLETE);
559 if (LOG_ENABLED(INFO)) {
560 LOG(INFO) << "HTTP upgrade success. stream_id="
561 << downstream->get_stream_id();
565 unsigned int status = downstream->get_response_http_status();
566 // Ignore the response body. HEAD response may contain
567 // Content-Length or Transfer-Encoding: chunked. Some server send
568 // 304 status code with nonzero Content-Length, but without response
570 // https://tools.ietf.org/html/rfc7230#section-3.3
572 // TODO It seems that the cases other than HEAD are handled by
573 // http-parser. Need test.
574 return downstream->get_request_method() == "HEAD" ||
575 (100 <= status && status <= 199) || status == 204 ||
583 int htp_hdr_keycb(http_parser *htp, const char *data, size_t len) {
584 auto downstream = static_cast<Downstream *>(htp->data);
586 if (downstream->get_response_headers_sum() + len >
587 get_config()->header_field_buffer) {
588 if (LOG_ENABLED(INFO)) {
589 DLOG(INFO, downstream) << "Too large header block size="
590 << downstream->get_response_headers_sum() + len;
595 if (downstream->get_response_state() == Downstream::INITIAL) {
596 if (downstream->get_response_header_key_prev()) {
597 downstream->append_last_response_header_key(data, len);
599 if (downstream->get_response_headers().size() >=
600 get_config()->max_header_fields) {
601 if (LOG_ENABLED(INFO)) {
602 DLOG(INFO, downstream)
603 << "Too many header field num="
604 << downstream->get_response_headers().size() + 1;
608 downstream->add_response_header(std::string(data, len), "");
612 if (downstream->get_response_trailer_key_prev()) {
613 downstream->append_last_response_trailer_key(data, len);
615 if (downstream->get_response_headers().size() >=
616 get_config()->max_header_fields) {
617 if (LOG_ENABLED(INFO)) {
618 DLOG(INFO, downstream)
619 << "Too many header field num="
620 << downstream->get_response_headers().size() + 1;
624 downstream->add_response_trailer(std::string(data, len), "");
632 int htp_hdr_valcb(http_parser *htp, const char *data, size_t len) {
633 auto downstream = static_cast<Downstream *>(htp->data);
634 if (downstream->get_response_headers_sum() + len >
635 get_config()->header_field_buffer) {
636 if (LOG_ENABLED(INFO)) {
637 DLOG(INFO, downstream) << "Too large header block size="
638 << downstream->get_response_headers_sum() + len;
642 if (downstream->get_response_state() == Downstream::INITIAL) {
643 if (downstream->get_response_header_key_prev()) {
644 downstream->set_last_response_header_value(data, len);
646 downstream->append_last_response_header_value(data, len);
649 if (downstream->get_response_trailer_key_prev()) {
650 downstream->set_last_response_trailer_value(data, len);
652 downstream->append_last_response_trailer_value(data, len);
660 int htp_bodycb(http_parser *htp, const char *data, size_t len) {
661 auto downstream = static_cast<Downstream *>(htp->data);
663 downstream->add_response_bodylen(len);
665 return downstream->get_upstream()->on_downstream_body(
666 downstream, reinterpret_cast<const uint8_t *>(data), len, true);
671 int htp_msg_completecb(http_parser *htp) {
672 auto downstream = static_cast<Downstream *>(htp->data);
674 if (downstream->get_non_final_response()) {
675 downstream->reset_response();
680 downstream->set_response_state(Downstream::MSG_COMPLETE);
681 // Block reading another response message from (broken?)
682 // server. This callback is not called if the connection is
684 downstream->pause_read(SHRPX_MSG_BLOCK);
685 return downstream->get_upstream()->on_downstream_body_complete(downstream);
690 http_parser_settings htp_hooks = {
691 htp_msg_begincb, // http_cb on_message_begin;
692 nullptr, // http_data_cb on_url;
693 nullptr, // http_data_cb on_status;
694 htp_hdr_keycb, // http_data_cb on_header_field;
695 htp_hdr_valcb, // http_data_cb on_header_value;
696 htp_hdrs_completecb, // http_cb on_headers_complete;
697 htp_bodycb, // http_data_cb on_body;
698 htp_msg_completecb // http_cb on_message_complete;
702 int HttpDownstreamConnection::on_read() {
707 ev_timer_again(conn_.loop, &conn_.rt);
708 std::array<uint8_t, 8192> buf;
711 if (downstream_->get_upgraded()) {
712 // For upgraded connection, just pass data to the upstream.
714 auto nread = conn_.read_clear(buf.data(), buf.size());
724 rv = downstream_->get_upstream()->on_downstream_body(
725 downstream_, buf.data(), nread, true);
730 if (downstream_->response_buf_full()) {
731 downstream_->pause_read(SHRPX_NO_BUFFER);
738 auto nread = conn_.read_clear(buf.data(), buf.size());
749 http_parser_execute(&response_htp_, &htp_hooks,
750 reinterpret_cast<char *>(buf.data()), nread);
752 auto htperr = HTTP_PARSER_ERRNO(&response_htp_);
754 if (htperr != HPE_OK) {
755 if (LOG_ENABLED(INFO)) {
756 DCLOG(INFO, this) << "HTTP parser failure: "
757 << "(" << http_errno_name(htperr) << ") "
758 << http_errno_description(htperr);
764 if (nproc != static_cast<size_t>(nread)) {
765 if (LOG_ENABLED(INFO)) {
766 DCLOG(INFO, this) << "nproc != nread";
771 if (downstream_->response_buf_full()) {
772 downstream_->pause_read(SHRPX_NO_BUFFER);
778 int HttpDownstreamConnection::on_write() {
783 ev_timer_again(conn_.loop, &conn_.rt);
785 auto upstream = downstream_->get_upstream();
786 auto input = downstream_->get_request_buf();
788 std::array<struct iovec, MAX_WR_IOVCNT> iov;
790 while (input->rleft() > 0) {
791 auto iovcnt = input->riovec(iov.data(), iov.size());
793 auto nwrite = conn_.writev_clear(iov.data(), iovcnt);
803 input->drain(nwrite);
806 conn_.wlimit.stopw();
807 ev_timer_stop(conn_.loop, &conn_.wt);
809 if (input->rleft() == 0) {
810 upstream->resume_read(SHRPX_NO_BUFFER, downstream_,
811 downstream_->get_request_datalen());
817 int HttpDownstreamConnection::on_connect() {
818 auto connect_blocker = client_handler_->get_connect_blocker();
820 if (!util::check_socket_connected(conn_.fd)) {
821 conn_.wlimit.stopw();
823 if (LOG_ENABLED(INFO)) {
824 DLOG(INFO, this) << "downstream connect failed";
832 connect_blocker->on_success();
834 conn_.rlimit.startw();
835 ev_set_cb(&conn_.wev, writecb);
840 void HttpDownstreamConnection::on_upstream_change(Upstream *upstream) {}
842 void HttpDownstreamConnection::signal_write() { conn_.wlimit.startw(); }