1/* 2 * nghttp2 - HTTP/2 C Library 3 * 4 * Copyright (c) 2012 Tatsuhiro Tsujikawa 5 * 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: 13 * 14 * The above copyright notice and this permission notice shall be 15 * included in all copies or substantial portions of the Software. 16 * 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. 24 */ 25#include "shrpx_https_upstream.h" 26 27#include <cassert> 28#include <set> 29#include <sstream> 30 31#include "shrpx_client_handler.h" 32#include "shrpx_downstream.h" 33#include "shrpx_downstream_connection.h" 34#include "shrpx_http.h" 35#include "shrpx_config.h" 36#include "shrpx_error.h" 37#include "shrpx_log_config.h" 38#include "shrpx_worker.h" 39#include "shrpx_http2_session.h" 40#include "shrpx_log.h" 41#ifdef HAVE_MRUBY 42# include "shrpx_mruby.h" 43#endif // HAVE_MRUBY 44#include "http2.h" 45#include "util.h" 46#include "template.h" 47#include "base64.h" 48#include "url-parser/url_parser.h" 49 50using namespace nghttp2; 51 52namespace shrpx { 53 54namespace { 55int htp_msg_begin(llhttp_t *htp); 56int htp_uricb(llhttp_t *htp, const char *data, size_t len); 57int htp_hdr_keycb(llhttp_t *htp, const char *data, size_t len); 58int htp_hdr_valcb(llhttp_t *htp, const char *data, size_t len); 59int htp_hdrs_completecb(llhttp_t *htp); 60int htp_bodycb(llhttp_t *htp, const char *data, size_t len); 61int htp_msg_completecb(llhttp_t *htp); 62} // namespace 63 64namespace { 65constexpr llhttp_settings_t htp_hooks = { 66 htp_msg_begin, // llhttp_cb on_message_begin; 67 htp_uricb, // llhttp_data_cb on_url; 68 nullptr, // llhttp_data_cb on_status; 69 nullptr, // llhttp_data_cb on_method; 70 nullptr, // llhttp_data_cb on_version; 71 htp_hdr_keycb, // llhttp_data_cb on_header_field; 72 htp_hdr_valcb, // llhttp_data_cb on_header_value; 73 nullptr, // llhttp_data_cb on_chunk_extension_name; 74 nullptr, // llhttp_data_cb on_chunk_extension_value; 75 htp_hdrs_completecb, // llhttp_cb on_headers_complete; 76 htp_bodycb, // llhttp_data_cb on_body; 77 htp_msg_completecb, // llhttp_cb on_message_complete; 78 nullptr, // llhttp_cb on_url_complete; 79 nullptr, // llhttp_cb on_status_complete; 80 nullptr, // llhttp_cb on_method_complete; 81 nullptr, // llhttp_cb on_version_complete; 82 nullptr, // llhttp_cb on_header_field_complete; 83 nullptr, // llhttp_cb on_header_value_complete; 84 nullptr, // llhttp_cb on_chunk_extension_name_complete; 85 nullptr, // llhttp_cb on_chunk_extension_value_complete; 86 nullptr, // llhttp_cb on_chunk_header; 87 nullptr, // llhttp_cb on_chunk_complete; 88 nullptr, // llhttp_cb on_reset; 89}; 90} // namespace 91 92HttpsUpstream::HttpsUpstream(ClientHandler *handler) 93 : handler_(handler), 94 current_header_length_(0), 95 ioctrl_(handler->get_rlimit()), 96 num_requests_(0) { 97 llhttp_init(&htp_, HTTP_REQUEST, &htp_hooks); 98 htp_.data = this; 99} 100 101HttpsUpstream::~HttpsUpstream() {} 102 103void HttpsUpstream::reset_current_header_length() { 104 current_header_length_ = 0; 105} 106 107void HttpsUpstream::on_start_request() { 108 if (LOG_ENABLED(INFO)) { 109 ULOG(INFO, this) << "HTTP request started"; 110 } 111 reset_current_header_length(); 112 113 auto downstream = 114 std::make_unique<Downstream>(this, handler_->get_mcpool(), 0); 115 116 attach_downstream(std::move(downstream)); 117 118 auto conn = handler_->get_connection(); 119 auto &upstreamconf = get_config()->conn.upstream; 120 121 conn->rt.repeat = upstreamconf.timeout.read; 122 123 handler_->repeat_read_timer(); 124 125 ++num_requests_; 126} 127 128namespace { 129int htp_msg_begin(llhttp_t *htp) { 130 auto upstream = static_cast<HttpsUpstream *>(htp->data); 131 upstream->on_start_request(); 132 return 0; 133} 134} // namespace 135 136namespace { 137int htp_uricb(llhttp_t *htp, const char *data, size_t len) { 138 auto upstream = static_cast<HttpsUpstream *>(htp->data); 139 auto downstream = upstream->get_downstream(); 140 auto &req = downstream->request(); 141 142 auto &balloc = downstream->get_block_allocator(); 143 144 // We happen to have the same value for method token. 145 req.method = htp->method; 146 147 if (req.fs.buffer_size() + len > 148 get_config()->http.request_header_field_buffer) { 149 if (LOG_ENABLED(INFO)) { 150 ULOG(INFO, upstream) << "Too large URI size=" 151 << req.fs.buffer_size() + len; 152 } 153 assert(downstream->get_request_state() == DownstreamState::INITIAL); 154 downstream->set_request_state( 155 DownstreamState::HTTP1_REQUEST_HEADER_TOO_LARGE); 156 llhttp_set_error_reason(htp, "too long request URI"); 157 return HPE_USER; 158 } 159 160 req.fs.add_extra_buffer_size(len); 161 162 if (req.method == HTTP_CONNECT) { 163 req.authority = 164 concat_string_ref(balloc, req.authority, StringRef{data, len}); 165 } else { 166 req.path = concat_string_ref(balloc, req.path, StringRef{data, len}); 167 } 168 169 return 0; 170} 171} // namespace 172 173namespace { 174int htp_hdr_keycb(llhttp_t *htp, const char *data, size_t len) { 175 auto upstream = static_cast<HttpsUpstream *>(htp->data); 176 auto downstream = upstream->get_downstream(); 177 auto &req = downstream->request(); 178 auto &httpconf = get_config()->http; 179 180 if (req.fs.buffer_size() + len > httpconf.request_header_field_buffer) { 181 if (LOG_ENABLED(INFO)) { 182 ULOG(INFO, upstream) << "Too large header block size=" 183 << req.fs.buffer_size() + len; 184 } 185 if (downstream->get_request_state() == DownstreamState::INITIAL) { 186 downstream->set_request_state( 187 DownstreamState::HTTP1_REQUEST_HEADER_TOO_LARGE); 188 } 189 llhttp_set_error_reason(htp, "too large header"); 190 return HPE_USER; 191 } 192 if (downstream->get_request_state() == DownstreamState::INITIAL) { 193 if (req.fs.header_key_prev()) { 194 req.fs.append_last_header_key(data, len); 195 } else { 196 if (req.fs.num_fields() >= httpconf.max_request_header_fields) { 197 if (LOG_ENABLED(INFO)) { 198 ULOG(INFO, upstream) 199 << "Too many header field num=" << req.fs.num_fields() + 1; 200 } 201 downstream->set_request_state( 202 DownstreamState::HTTP1_REQUEST_HEADER_TOO_LARGE); 203 llhttp_set_error_reason(htp, "too many headers"); 204 return HPE_USER; 205 } 206 req.fs.alloc_add_header_name(StringRef{data, len}); 207 } 208 } else { 209 // trailer part 210 if (req.fs.trailer_key_prev()) { 211 req.fs.append_last_trailer_key(data, len); 212 } else { 213 if (req.fs.num_fields() >= httpconf.max_request_header_fields) { 214 if (LOG_ENABLED(INFO)) { 215 ULOG(INFO, upstream) 216 << "Too many header field num=" << req.fs.num_fields() + 1; 217 } 218 llhttp_set_error_reason(htp, "too many headers"); 219 return HPE_USER; 220 } 221 req.fs.alloc_add_trailer_name(StringRef{data, len}); 222 } 223 } 224 return 0; 225} 226} // namespace 227 228namespace { 229int htp_hdr_valcb(llhttp_t *htp, const char *data, size_t len) { 230 auto upstream = static_cast<HttpsUpstream *>(htp->data); 231 auto downstream = upstream->get_downstream(); 232 auto &req = downstream->request(); 233 234 if (req.fs.buffer_size() + len > 235 get_config()->http.request_header_field_buffer) { 236 if (LOG_ENABLED(INFO)) { 237 ULOG(INFO, upstream) << "Too large header block size=" 238 << req.fs.buffer_size() + len; 239 } 240 if (downstream->get_request_state() == DownstreamState::INITIAL) { 241 downstream->set_request_state( 242 DownstreamState::HTTP1_REQUEST_HEADER_TOO_LARGE); 243 } 244 llhttp_set_error_reason(htp, "too large header"); 245 return HPE_USER; 246 } 247 if (downstream->get_request_state() == DownstreamState::INITIAL) { 248 req.fs.append_last_header_value(data, len); 249 } else { 250 req.fs.append_last_trailer_value(data, len); 251 } 252 return 0; 253} 254} // namespace 255 256namespace { 257void rewrite_request_host_path_from_uri(BlockAllocator &balloc, Request &req, 258 const StringRef &uri, 259 http_parser_url &u) { 260 assert(u.field_set & (1 << UF_HOST)); 261 262 // As per https://tools.ietf.org/html/rfc7230#section-5.4, we 263 // rewrite host header field with authority component. 264 auto authority = util::get_uri_field(uri.c_str(), u, UF_HOST); 265 // TODO properly check IPv6 numeric address 266 auto ipv6 = std::find(std::begin(authority), std::end(authority), ':') != 267 std::end(authority); 268 auto authoritylen = authority.size(); 269 if (ipv6) { 270 authoritylen += 2; 271 } 272 if (u.field_set & (1 << UF_PORT)) { 273 authoritylen += 1 + str_size("65535"); 274 } 275 if (authoritylen > authority.size()) { 276 auto iovec = make_byte_ref(balloc, authoritylen + 1); 277 auto p = iovec.base; 278 if (ipv6) { 279 *p++ = '['; 280 } 281 p = std::copy(std::begin(authority), std::end(authority), p); 282 if (ipv6) { 283 *p++ = ']'; 284 } 285 286 if (u.field_set & (1 << UF_PORT)) { 287 *p++ = ':'; 288 p = util::utos(p, u.port); 289 } 290 *p = '\0'; 291 292 req.authority = StringRef{iovec.base, p}; 293 } else { 294 req.authority = authority; 295 } 296 297 req.scheme = util::get_uri_field(uri.c_str(), u, UF_SCHEMA); 298 299 StringRef path; 300 if (u.field_set & (1 << UF_PATH)) { 301 path = util::get_uri_field(uri.c_str(), u, UF_PATH); 302 } else if (req.method == HTTP_OPTIONS) { 303 // Server-wide OPTIONS takes following form in proxy request: 304 // 305 // OPTIONS http://example.org HTTP/1.1 306 // 307 // Notice that no slash after authority. See 308 // http://tools.ietf.org/html/rfc7230#section-5.3.4 309 req.path = StringRef::from_lit(""); 310 // we ignore query component here 311 return; 312 } else { 313 path = StringRef::from_lit("/"); 314 } 315 316 if (u.field_set & (1 << UF_QUERY)) { 317 auto &fdata = u.field_data[UF_QUERY]; 318 319 if (u.field_set & (1 << UF_PATH)) { 320 auto q = util::get_uri_field(uri.c_str(), u, UF_QUERY); 321 path = StringRef{std::begin(path), std::end(q)}; 322 } else { 323 path = concat_string_ref(balloc, path, StringRef::from_lit("?"), 324 StringRef{&uri[fdata.off], fdata.len}); 325 } 326 } 327 328 req.path = http2::rewrite_clean_path(balloc, path); 329} 330} // namespace 331 332namespace { 333int htp_hdrs_completecb(llhttp_t *htp) { 334 int rv; 335 auto upstream = static_cast<HttpsUpstream *>(htp->data); 336 if (LOG_ENABLED(INFO)) { 337 ULOG(INFO, upstream) << "HTTP request headers completed"; 338 } 339 340 auto handler = upstream->get_client_handler(); 341 342 auto downstream = upstream->get_downstream(); 343 auto &req = downstream->request(); 344 auto &balloc = downstream->get_block_allocator(); 345 346 for (auto &kv : req.fs.headers()) { 347 kv.value = util::rstrip(balloc, kv.value); 348 349 if (kv.token == http2::HD_TRANSFER_ENCODING && 350 !http2::check_transfer_encoding(kv.value)) { 351 return -1; 352 } 353 } 354 355 auto lgconf = log_config(); 356 lgconf->update_tstamp(std::chrono::system_clock::now()); 357 req.tstamp = lgconf->tstamp; 358 359 req.http_major = htp->http_major; 360 req.http_minor = htp->http_minor; 361 362 req.connection_close = !llhttp_should_keep_alive(htp); 363 364 handler->stop_read_timer(); 365 366 auto method = req.method; 367 368 if (LOG_ENABLED(INFO)) { 369 std::stringstream ss; 370 ss << http2::to_method_string(method) << " " 371 << (method == HTTP_CONNECT ? req.authority : req.path) << " " 372 << "HTTP/" << req.http_major << "." << req.http_minor << "\n"; 373 374 for (const auto &kv : req.fs.headers()) { 375 if (kv.name == "authorization") { 376 ss << TTY_HTTP_HD << kv.name << TTY_RST << ": <redacted>\n"; 377 continue; 378 } 379 ss << TTY_HTTP_HD << kv.name << TTY_RST << ": " << kv.value << "\n"; 380 } 381 382 ULOG(INFO, upstream) << "HTTP request headers\n" << ss.str(); 383 } 384 385 // set content-length if method is not CONNECT, and no 386 // transfer-encoding is given. If transfer-encoding is given, leave 387 // req.fs.content_length to -1. 388 if (method != HTTP_CONNECT && !req.fs.header(http2::HD_TRANSFER_ENCODING)) { 389 // llhttp sets 0 to htp->content_length if there is no 390 // content-length header field. If we don't have both 391 // transfer-encoding and content-length header field, we assume 392 // that there is no request body. 393 req.fs.content_length = htp->content_length; 394 } 395 396 auto host = req.fs.header(http2::HD_HOST); 397 398 if (req.http_major > 1 || req.http_minor > 1) { 399 req.http_major = 1; 400 req.http_minor = 1; 401 return -1; 402 } 403 404 if (req.http_major == 1 && req.http_minor == 1 && !host) { 405 return -1; 406 } 407 408 if (host) { 409 const auto &value = host->value; 410 // Not allow at least '"' or '\' in host. They are illegal in 411 // authority component, also they cause headaches when we put them 412 // in quoted-string. 413 if (std::find_if(std::begin(value), std::end(value), [](char c) { 414 return c == '"' || c == '\\'; 415 }) != std::end(value)) { 416 return -1; 417 } 418 } 419 420 downstream->inspect_http1_request(); 421 422 if (htp->flags & F_CHUNKED) { 423 downstream->set_chunked_request(true); 424 } 425 426 auto transfer_encoding = req.fs.header(http2::HD_TRANSFER_ENCODING); 427 if (transfer_encoding && 428 http2::legacy_http1(req.http_major, req.http_minor)) { 429 return -1; 430 } 431 432 auto faddr = handler->get_upstream_addr(); 433 auto config = get_config(); 434 435 if (method != HTTP_CONNECT) { 436 http_parser_url u{}; 437 rv = http_parser_parse_url(req.path.c_str(), req.path.size(), 0, &u); 438 if (rv != 0) { 439 // Expect to respond with 400 bad request 440 return -1; 441 } 442 // checking UF_HOST could be redundant, but just in case ... 443 if (!(u.field_set & (1 << UF_SCHEMA)) || !(u.field_set & (1 << UF_HOST))) { 444 req.no_authority = true; 445 446 if (method == HTTP_OPTIONS && req.path == StringRef::from_lit("*")) { 447 req.path = StringRef{}; 448 } else { 449 req.path = http2::rewrite_clean_path(balloc, req.path); 450 } 451 452 if (host) { 453 req.authority = host->value; 454 } 455 456 if (handler->get_ssl()) { 457 req.scheme = StringRef::from_lit("https"); 458 } else { 459 req.scheme = StringRef::from_lit("http"); 460 } 461 } else { 462 rewrite_request_host_path_from_uri(balloc, req, req.path, u); 463 } 464 } 465 466 downstream->set_request_state(DownstreamState::HEADER_COMPLETE); 467 468 auto &resp = downstream->response(); 469 470 if (config->http.require_http_scheme && 471 !http::check_http_scheme(req.scheme, handler->get_ssl() != nullptr)) { 472 resp.http_status = 400; 473 return -1; 474 } 475 476#ifdef HAVE_MRUBY 477 auto worker = handler->get_worker(); 478 auto mruby_ctx = worker->get_mruby_context(); 479 480 if (mruby_ctx->run_on_request_proc(downstream) != 0) { 481 resp.http_status = 500; 482 return -1; 483 } 484#endif // HAVE_MRUBY 485 486 // mruby hook may change method value 487 488 if (req.no_authority && config->http2_proxy && 489 faddr->alt_mode == UpstreamAltMode::NONE) { 490 // Request URI should be absolute-form for client proxy mode 491 return -1; 492 } 493 494 if (downstream->get_response_state() == DownstreamState::MSG_COMPLETE) { 495 return 0; 496 } 497 498#ifdef HAVE_MRUBY 499 DownstreamConnection *dconn_ptr; 500#endif // HAVE_MRUBY 501 502 for (;;) { 503 auto dconn = handler->get_downstream_connection(rv, downstream); 504 505 if (!dconn) { 506 if (rv == SHRPX_ERR_TLS_REQUIRED) { 507 upstream->redirect_to_https(downstream); 508 } 509 downstream->set_request_state(DownstreamState::CONNECT_FAIL); 510 return -1; 511 } 512 513#ifdef HAVE_MRUBY 514 dconn_ptr = dconn.get(); 515#endif // HAVE_MRUBY 516 if (downstream->attach_downstream_connection(std::move(dconn)) == 0) { 517 break; 518 } 519 } 520 521#ifdef HAVE_MRUBY 522 const auto &group = dconn_ptr->get_downstream_addr_group(); 523 if (group) { 524 const auto &dmruby_ctx = group->shared_addr->mruby_ctx; 525 526 if (dmruby_ctx->run_on_request_proc(downstream) != 0) { 527 resp.http_status = 500; 528 return -1; 529 } 530 531 if (downstream->get_response_state() == DownstreamState::MSG_COMPLETE) { 532 return 0; 533 } 534 } 535#endif // HAVE_MRUBY 536 537 rv = downstream->push_request_headers(); 538 539 if (rv != 0) { 540 return -1; 541 } 542 543 if (faddr->alt_mode != UpstreamAltMode::NONE) { 544 // Normally, we forward expect: 100-continue to backend server, 545 // and let them decide whether responds with 100 Continue or not. 546 // For alternative mode, we have no backend, so just send 100 547 // Continue here to make the client happy. 548 if (downstream->get_expect_100_continue()) { 549 auto output = downstream->get_response_buf(); 550 constexpr auto res = StringRef::from_lit("HTTP/1.1 100 Continue\r\n\r\n"); 551 output->append(res); 552 handler->signal_write(); 553 } 554 } 555 556 return 0; 557} 558} // namespace 559 560namespace { 561int htp_bodycb(llhttp_t *htp, const char *data, size_t len) { 562 int rv; 563 auto upstream = static_cast<HttpsUpstream *>(htp->data); 564 auto downstream = upstream->get_downstream(); 565 rv = downstream->push_upload_data_chunk( 566 reinterpret_cast<const uint8_t *>(data), len); 567 if (rv != 0) { 568 // Ignore error if response has been completed. We will end up in 569 // htp_msg_completecb, and request will end gracefully. 570 if (downstream->get_response_state() == DownstreamState::MSG_COMPLETE) { 571 return 0; 572 } 573 574 llhttp_set_error_reason(htp, "could not process request body"); 575 return HPE_USER; 576 } 577 return 0; 578} 579} // namespace 580 581namespace { 582int htp_msg_completecb(llhttp_t *htp) { 583 int rv; 584 auto upstream = static_cast<HttpsUpstream *>(htp->data); 585 if (LOG_ENABLED(INFO)) { 586 ULOG(INFO, upstream) << "HTTP request completed"; 587 } 588 auto handler = upstream->get_client_handler(); 589 auto downstream = upstream->get_downstream(); 590 auto &req = downstream->request(); 591 auto &balloc = downstream->get_block_allocator(); 592 593 for (auto &kv : req.fs.trailers()) { 594 kv.value = util::rstrip(balloc, kv.value); 595 } 596 597 downstream->set_request_state(DownstreamState::MSG_COMPLETE); 598 rv = downstream->end_upload_data(); 599 if (rv != 0) { 600 if (downstream->get_response_state() == DownstreamState::MSG_COMPLETE) { 601 // Here both response and request were completed. One of the 602 // reason why end_upload_data() failed is when we sent response 603 // in request phase hook. We only delete and proceed to the 604 // next request handling (if we don't close the connection). We 605 // first pause parser here just as we normally do, and call 606 // signal_write() to run on_write(). 607 return HPE_PAUSED; 608 } 609 return -1; 610 } 611 612 if (handler->get_http2_upgrade_allowed() && 613 downstream->get_http2_upgrade_request() && 614 handler->perform_http2_upgrade(upstream) != 0) { 615 if (LOG_ENABLED(INFO)) { 616 ULOG(INFO, upstream) << "HTTP Upgrade to HTTP/2 failed"; 617 } 618 } 619 620 // Stop further processing to complete this request 621 return HPE_PAUSED; 622} 623} // namespace 624 625// on_read() does not consume all available data in input buffer if 626// one http request is fully received. 627int HttpsUpstream::on_read() { 628 auto rb = handler_->get_rb(); 629 auto rlimit = handler_->get_rlimit(); 630 auto downstream = get_downstream(); 631 632 if (rb->rleft() == 0 || handler_->get_should_close_after_write()) { 633 return 0; 634 } 635 636 // downstream can be nullptr here, because it is initialized in the 637 // callback chain called by llhttp_execute() 638 if (downstream && downstream->get_upgraded()) { 639 640 auto rv = downstream->push_upload_data_chunk(rb->pos(), rb->rleft()); 641 642 if (rv != 0) { 643 return -1; 644 } 645 646 rb->reset(); 647 rlimit->startw(); 648 649 if (downstream->request_buf_full()) { 650 if (LOG_ENABLED(INFO)) { 651 ULOG(INFO, this) << "Downstream request buf is full"; 652 } 653 pause_read(SHRPX_NO_BUFFER); 654 655 return 0; 656 } 657 658 return 0; 659 } 660 661 if (downstream) { 662 // To avoid reading next pipelined request 663 switch (downstream->get_request_state()) { 664 case DownstreamState::INITIAL: 665 case DownstreamState::HEADER_COMPLETE: 666 break; 667 default: 668 return 0; 669 } 670 } 671 672 // llhttp_execute() does nothing once it entered error state. 673 auto htperr = llhttp_execute(&htp_, reinterpret_cast<const char *>(rb->pos()), 674 rb->rleft()); 675 676 if (htperr == HPE_PAUSED_UPGRADE && 677 rb->pos() == 678 reinterpret_cast<const uint8_t *>(llhttp_get_error_pos(&htp_))) { 679 llhttp_resume_after_upgrade(&htp_); 680 681 htperr = llhttp_execute(&htp_, reinterpret_cast<const char *>(rb->pos()), 682 rb->rleft()); 683 } 684 685 auto nread = 686 htperr == HPE_OK 687 ? rb->rleft() 688 : reinterpret_cast<const uint8_t *>(llhttp_get_error_pos(&htp_)) - 689 rb->pos(); 690 rb->drain(nread); 691 rlimit->startw(); 692 693 // Well, actually header length + some body bytes 694 current_header_length_ += nread; 695 696 // Get downstream again because it may be initialized in http parser 697 // execution 698 downstream = get_downstream(); 699 700 if (htperr == HPE_PAUSED) { 701 // We may pause parser in htp_msg_completecb when both side are 702 // completed. Signal write, so that we can run on_write(). 703 if (downstream && 704 downstream->get_request_state() == DownstreamState::MSG_COMPLETE && 705 downstream->get_response_state() == DownstreamState::MSG_COMPLETE) { 706 handler_->signal_write(); 707 } 708 return 0; 709 } 710 711 if (htperr != HPE_OK) { 712 if (LOG_ENABLED(INFO)) { 713 ULOG(INFO, this) << "HTTP parse failure: " 714 << "(" << llhttp_errno_name(htperr) << ") " 715 << llhttp_get_error_reason(&htp_); 716 } 717 718 if (downstream && 719 downstream->get_response_state() != DownstreamState::INITIAL) { 720 handler_->set_should_close_after_write(true); 721 handler_->signal_write(); 722 return 0; 723 } 724 725 unsigned int status_code; 726 727 if (htperr == HPE_INVALID_METHOD) { 728 status_code = 501; 729 } else if (downstream) { 730 status_code = downstream->response().http_status; 731 if (status_code == 0) { 732 if (downstream->get_request_state() == DownstreamState::CONNECT_FAIL) { 733 status_code = 502; 734 } else if (downstream->get_request_state() == 735 DownstreamState::HTTP1_REQUEST_HEADER_TOO_LARGE) { 736 status_code = 431; 737 } else { 738 status_code = 400; 739 } 740 } 741 } else { 742 status_code = 400; 743 } 744 745 error_reply(status_code); 746 747 handler_->signal_write(); 748 749 return 0; 750 } 751 752 // downstream can be NULL here. 753 if (downstream && downstream->request_buf_full()) { 754 if (LOG_ENABLED(INFO)) { 755 ULOG(INFO, this) << "Downstream request buffer is full"; 756 } 757 758 pause_read(SHRPX_NO_BUFFER); 759 760 return 0; 761 } 762 763 return 0; 764} 765 766int HttpsUpstream::on_write() { 767 auto downstream = get_downstream(); 768 if (!downstream) { 769 return 0; 770 } 771 772 auto output = downstream->get_response_buf(); 773 const auto &resp = downstream->response(); 774 775 if (output->rleft() > 0) { 776 return 0; 777 } 778 779 // We need to postpone detachment until all data are sent so that 780 // we can notify nghttp2 library all data consumed. 781 if (downstream->get_response_state() == DownstreamState::MSG_COMPLETE) { 782 if (downstream->can_detach_downstream_connection()) { 783 // Keep-alive 784 downstream->detach_downstream_connection(); 785 } else { 786 // Connection close 787 downstream->pop_downstream_connection(); 788 // dconn was deleted 789 } 790 // We need this if response ends before request. 791 if (downstream->get_request_state() == DownstreamState::MSG_COMPLETE) { 792 delete_downstream(); 793 794 if (handler_->get_should_close_after_write()) { 795 return 0; 796 } 797 798 auto conn = handler_->get_connection(); 799 auto &upstreamconf = get_config()->conn.upstream; 800 801 conn->rt.repeat = upstreamconf.timeout.idle_read; 802 803 handler_->repeat_read_timer(); 804 805 return resume_read(SHRPX_NO_BUFFER, nullptr, 0); 806 } else { 807 // If the request is not complete, close the connection. 808 delete_downstream(); 809 810 handler_->set_should_close_after_write(true); 811 812 return 0; 813 } 814 } 815 816 return downstream->resume_read(SHRPX_NO_BUFFER, resp.unconsumed_body_length); 817} 818 819int HttpsUpstream::on_event() { return 0; } 820 821ClientHandler *HttpsUpstream::get_client_handler() const { return handler_; } 822 823void HttpsUpstream::pause_read(IOCtrlReason reason) { 824 ioctrl_.pause_read(reason); 825} 826 827int HttpsUpstream::resume_read(IOCtrlReason reason, Downstream *downstream, 828 size_t consumed) { 829 // downstream could be nullptr 830 if (downstream && downstream->request_buf_full()) { 831 return 0; 832 } 833 if (ioctrl_.resume_read(reason)) { 834 // Process remaining data in input buffer here because these bytes 835 // are not notified by readcb until new data arrive. 836 llhttp_resume(&htp_); 837 838 auto conn = handler_->get_connection(); 839 ev_feed_event(conn->loop, &conn->rev, EV_READ); 840 return 0; 841 } 842 843 return 0; 844} 845 846int HttpsUpstream::downstream_read(DownstreamConnection *dconn) { 847 auto downstream = dconn->get_downstream(); 848 int rv; 849 850 rv = downstream->on_read(); 851 852 if (rv == SHRPX_ERR_EOF) { 853 if (downstream->get_request_header_sent()) { 854 return downstream_eof(dconn); 855 } 856 return SHRPX_ERR_RETRY; 857 } 858 859 if (rv == SHRPX_ERR_DCONN_CANCELED) { 860 downstream->pop_downstream_connection(); 861 goto end; 862 } 863 864 if (rv < 0) { 865 return downstream_error(dconn, Downstream::EVENT_ERROR); 866 } 867 868 if (downstream->get_response_state() == DownstreamState::MSG_RESET) { 869 return -1; 870 } 871 872 if (downstream->get_response_state() == DownstreamState::MSG_BAD_HEADER) { 873 error_reply(502); 874 downstream->pop_downstream_connection(); 875 goto end; 876 } 877 878 if (downstream->can_detach_downstream_connection()) { 879 // Keep-alive 880 downstream->detach_downstream_connection(); 881 } 882 883end: 884 handler_->signal_write(); 885 886 return 0; 887} 888 889int HttpsUpstream::downstream_write(DownstreamConnection *dconn) { 890 int rv; 891 rv = dconn->on_write(); 892 if (rv == SHRPX_ERR_NETWORK) { 893 return downstream_error(dconn, Downstream::EVENT_ERROR); 894 } 895 896 if (rv != 0) { 897 return rv; 898 } 899 900 return 0; 901} 902 903int HttpsUpstream::downstream_eof(DownstreamConnection *dconn) { 904 auto downstream = dconn->get_downstream(); 905 906 if (LOG_ENABLED(INFO)) { 907 DCLOG(INFO, dconn) << "EOF"; 908 } 909 910 if (downstream->get_response_state() == DownstreamState::MSG_COMPLETE) { 911 goto end; 912 } 913 914 if (downstream->get_response_state() == DownstreamState::HEADER_COMPLETE) { 915 // Server may indicate the end of the request by EOF 916 if (LOG_ENABLED(INFO)) { 917 DCLOG(INFO, dconn) << "The end of the response body was indicated by " 918 << "EOF"; 919 } 920 on_downstream_body_complete(downstream); 921 downstream->set_response_state(DownstreamState::MSG_COMPLETE); 922 downstream->pop_downstream_connection(); 923 goto end; 924 } 925 926 if (downstream->get_response_state() == DownstreamState::INITIAL) { 927 // we did not send any response headers, so we can reply error 928 // message. 929 if (LOG_ENABLED(INFO)) { 930 DCLOG(INFO, dconn) << "Return error reply"; 931 } 932 error_reply(502); 933 downstream->pop_downstream_connection(); 934 goto end; 935 } 936 937 // Otherwise, we don't know how to recover from this situation. Just 938 // drop connection. 939 return -1; 940end: 941 handler_->signal_write(); 942 943 return 0; 944} 945 946int HttpsUpstream::downstream_error(DownstreamConnection *dconn, int events) { 947 auto downstream = dconn->get_downstream(); 948 if (LOG_ENABLED(INFO)) { 949 if (events & Downstream::EVENT_ERROR) { 950 DCLOG(INFO, dconn) << "Network error/general error"; 951 } else { 952 DCLOG(INFO, dconn) << "Timeout"; 953 } 954 } 955 if (downstream->get_response_state() != DownstreamState::INITIAL) { 956 return -1; 957 } 958 959 unsigned int status; 960 if (events & Downstream::EVENT_TIMEOUT) { 961 if (downstream->get_request_header_sent()) { 962 status = 504; 963 } else { 964 status = 408; 965 } 966 } else { 967 status = 502; 968 } 969 error_reply(status); 970 971 downstream->pop_downstream_connection(); 972 973 handler_->signal_write(); 974 return 0; 975} 976 977int HttpsUpstream::send_reply(Downstream *downstream, const uint8_t *body, 978 size_t bodylen) { 979 const auto &req = downstream->request(); 980 auto &resp = downstream->response(); 981 auto &balloc = downstream->get_block_allocator(); 982 auto config = get_config(); 983 auto &httpconf = config->http; 984 985 auto connection_close = false; 986 987 auto worker = handler_->get_worker(); 988 989 if (httpconf.max_requests <= num_requests_ || 990 worker->get_graceful_shutdown()) { 991 resp.fs.add_header_token(StringRef::from_lit("connection"), 992 StringRef::from_lit("close"), false, 993 http2::HD_CONNECTION); 994 connection_close = true; 995 } else if (req.http_major <= 0 || 996 (req.http_major == 1 && req.http_minor == 0)) { 997 connection_close = true; 998 } else { 999 auto c = resp.fs.header(http2::HD_CONNECTION); 1000 if (c && util::strieq_l("close", c->value)) { 1001 connection_close = true; 1002 } 1003 } 1004 1005 if (connection_close) { 1006 resp.connection_close = true; 1007 handler_->set_should_close_after_write(true); 1008 } 1009 1010 auto output = downstream->get_response_buf(); 1011 1012 output->append("HTTP/1.1 "); 1013 output->append(http2::stringify_status(balloc, resp.http_status)); 1014 output->append(' '); 1015 output->append(http2::get_reason_phrase(resp.http_status)); 1016 output->append("\r\n"); 1017 1018 for (auto &kv : resp.fs.headers()) { 1019 if (kv.name.empty() || kv.name[0] == ':') { 1020 continue; 1021 } 1022 http2::capitalize(output, kv.name); 1023 output->append(": "); 1024 output->append(kv.value); 1025 output->append("\r\n"); 1026 } 1027 1028 if (!resp.fs.header(http2::HD_SERVER)) { 1029 output->append("Server: "); 1030 output->append(config->http.server_name); 1031 output->append("\r\n"); 1032 } 1033 1034 for (auto &p : httpconf.add_response_headers) { 1035 output->append(p.name); 1036 output->append(": "); 1037 output->append(p.value); 1038 output->append("\r\n"); 1039 } 1040 1041 output->append("\r\n"); 1042 1043 output->append(body, bodylen); 1044 1045 downstream->response_sent_body_length += bodylen; 1046 downstream->set_response_state(DownstreamState::MSG_COMPLETE); 1047 1048 return 0; 1049} 1050 1051void HttpsUpstream::error_reply(unsigned int status_code) { 1052 auto downstream = get_downstream(); 1053 1054 if (!downstream) { 1055 attach_downstream( 1056 std::make_unique<Downstream>(this, handler_->get_mcpool(), 1)); 1057 downstream = get_downstream(); 1058 } 1059 1060 auto &resp = downstream->response(); 1061 auto &balloc = downstream->get_block_allocator(); 1062 1063 auto html = http::create_error_html(balloc, status_code); 1064 1065 resp.http_status = status_code; 1066 // we are going to close connection for both frontend and backend in 1067 // error condition. This is safest option. 1068 resp.connection_close = true; 1069 handler_->set_should_close_after_write(true); 1070 1071 auto output = downstream->get_response_buf(); 1072 1073 output->append("HTTP/1.1 "); 1074 output->append(http2::stringify_status(balloc, status_code)); 1075 output->append(' '); 1076 output->append(http2::get_reason_phrase(status_code)); 1077 output->append("\r\nServer: "); 1078 output->append(get_config()->http.server_name); 1079 output->append("\r\nContent-Length: "); 1080 std::array<uint8_t, NGHTTP2_MAX_UINT64_DIGITS> intbuf; 1081 output->append(StringRef{std::begin(intbuf), 1082 util::utos(std::begin(intbuf), html.size())}); 1083 output->append("\r\nDate: "); 1084 auto lgconf = log_config(); 1085 lgconf->update_tstamp(std::chrono::system_clock::now()); 1086 output->append(lgconf->tstamp->time_http); 1087 output->append("\r\nContent-Type: text/html; " 1088 "charset=UTF-8\r\nConnection: close\r\n\r\n"); 1089 output->append(html); 1090 1091 downstream->response_sent_body_length += html.size(); 1092 downstream->set_response_state(DownstreamState::MSG_COMPLETE); 1093} 1094 1095void HttpsUpstream::attach_downstream(std::unique_ptr<Downstream> downstream) { 1096 assert(!downstream_); 1097 downstream_ = std::move(downstream); 1098} 1099 1100void HttpsUpstream::delete_downstream() { 1101 if (downstream_ && downstream_->accesslog_ready()) { 1102 handler_->write_accesslog(downstream_.get()); 1103 } 1104 1105 downstream_.reset(); 1106} 1107 1108Downstream *HttpsUpstream::get_downstream() const { return downstream_.get(); } 1109 1110std::unique_ptr<Downstream> HttpsUpstream::pop_downstream() { 1111 return std::unique_ptr<Downstream>(downstream_.release()); 1112} 1113 1114int HttpsUpstream::on_downstream_header_complete(Downstream *downstream) { 1115 if (LOG_ENABLED(INFO)) { 1116 if (downstream->get_non_final_response()) { 1117 DLOG(INFO, downstream) << "HTTP non-final response header"; 1118 } else { 1119 DLOG(INFO, downstream) << "HTTP response header completed"; 1120 } 1121 } 1122 1123 const auto &req = downstream->request(); 1124 auto &resp = downstream->response(); 1125 auto &balloc = downstream->get_block_allocator(); 1126 auto dconn = downstream->get_downstream_connection(); 1127 // dconn might be nullptr if this is non-final response from mruby. 1128 1129 if (downstream->get_non_final_response() && 1130 !downstream->supports_non_final_response()) { 1131 resp.fs.clear_headers(); 1132 return 0; 1133 } 1134 1135#ifdef HAVE_MRUBY 1136 if (!downstream->get_non_final_response()) { 1137 assert(dconn); 1138 const auto &group = dconn->get_downstream_addr_group(); 1139 if (group) { 1140 const auto &dmruby_ctx = group->shared_addr->mruby_ctx; 1141 1142 if (dmruby_ctx->run_on_response_proc(downstream) != 0) { 1143 error_reply(500); 1144 return -1; 1145 } 1146 1147 if (downstream->get_response_state() == DownstreamState::MSG_COMPLETE) { 1148 return -1; 1149 } 1150 } 1151 1152 auto worker = handler_->get_worker(); 1153 auto mruby_ctx = worker->get_mruby_context(); 1154 1155 if (mruby_ctx->run_on_response_proc(downstream) != 0) { 1156 error_reply(500); 1157 return -1; 1158 } 1159 1160 if (downstream->get_response_state() == DownstreamState::MSG_COMPLETE) { 1161 return -1; 1162 } 1163 } 1164#endif // HAVE_MRUBY 1165 1166 auto connect_method = req.method == HTTP_CONNECT; 1167 1168 auto buf = downstream->get_response_buf(); 1169 buf->append("HTTP/"); 1170 buf->append('0' + req.http_major); 1171 buf->append('.'); 1172 buf->append('0' + req.http_minor); 1173 buf->append(' '); 1174 if (req.connect_proto != ConnectProto::NONE && downstream->get_upgraded()) { 1175 buf->append(http2::stringify_status(balloc, 101)); 1176 buf->append(' '); 1177 buf->append(http2::get_reason_phrase(101)); 1178 } else { 1179 buf->append(http2::stringify_status(balloc, resp.http_status)); 1180 buf->append(' '); 1181 buf->append(http2::get_reason_phrase(resp.http_status)); 1182 } 1183 buf->append("\r\n"); 1184 1185 auto config = get_config(); 1186 auto &httpconf = config->http; 1187 1188 if (!config->http2_proxy && !httpconf.no_location_rewrite) { 1189 downstream->rewrite_location_response_header( 1190 get_client_handler()->get_upstream_scheme()); 1191 } 1192 1193 if (downstream->get_non_final_response()) { 1194 http2::build_http1_headers_from_headers(buf, resp.fs.headers(), 1195 http2::HDOP_STRIP_ALL); 1196 1197 buf->append("\r\n"); 1198 1199 if (LOG_ENABLED(INFO)) { 1200 log_response_headers(buf); 1201 } 1202 1203 resp.fs.clear_headers(); 1204 1205 return 0; 1206 } 1207 1208 auto build_flags = (http2::HDOP_STRIP_ALL & ~http2::HDOP_STRIP_VIA) | 1209 (!http2::legacy_http1(req.http_major, req.http_minor) 1210 ? 0 1211 : http2::HDOP_STRIP_TRANSFER_ENCODING); 1212 1213 http2::build_http1_headers_from_headers(buf, resp.fs.headers(), build_flags); 1214 1215 auto worker = handler_->get_worker(); 1216 1217 // after graceful shutdown commenced, add connection: close header 1218 // field. 1219 if (httpconf.max_requests <= num_requests_ || 1220 worker->get_graceful_shutdown()) { 1221 resp.connection_close = true; 1222 } 1223 1224 // We check downstream->get_response_connection_close() in case when 1225 // the Content-Length is not available. 1226 if (!req.connection_close && !resp.connection_close) { 1227 if (req.http_major <= 0 || req.http_minor <= 0) { 1228 // We add this header for HTTP/1.0 or HTTP/0.9 clients 1229 buf->append("Connection: Keep-Alive\r\n"); 1230 } 1231 } else if (!downstream->get_upgraded()) { 1232 buf->append("Connection: close\r\n"); 1233 } 1234 1235 if (!connect_method && downstream->get_upgraded()) { 1236 if (req.connect_proto == ConnectProto::WEBSOCKET && 1237 resp.http_status / 100 == 2) { 1238 buf->append("Upgrade: websocket\r\nConnection: Upgrade\r\n"); 1239 auto key = req.fs.header(http2::HD_SEC_WEBSOCKET_KEY); 1240 if (!key || key->value.size() != base64::encode_length(16)) { 1241 return -1; 1242 } 1243 std::array<uint8_t, base64::encode_length(20)> out; 1244 auto accept = http2::make_websocket_accept_token(out.data(), key->value); 1245 if (accept.empty()) { 1246 return -1; 1247 } 1248 buf->append("Sec-WebSocket-Accept: "); 1249 buf->append(accept); 1250 buf->append("\r\n"); 1251 } else { 1252 auto connection = resp.fs.header(http2::HD_CONNECTION); 1253 if (connection) { 1254 buf->append("Connection: "); 1255 buf->append((*connection).value); 1256 buf->append("\r\n"); 1257 } 1258 1259 auto upgrade = resp.fs.header(http2::HD_UPGRADE); 1260 if (upgrade) { 1261 buf->append("Upgrade: "); 1262 buf->append((*upgrade).value); 1263 buf->append("\r\n"); 1264 } 1265 } 1266 } 1267 1268 if (!resp.fs.header(http2::HD_ALT_SVC)) { 1269 // We won't change or alter alt-svc from backend for now 1270 if (!httpconf.altsvcs.empty()) { 1271 buf->append("Alt-Svc: "); 1272 buf->append(httpconf.altsvc_header_value); 1273 buf->append("\r\n"); 1274 } 1275 } 1276 1277 if (!config->http2_proxy && !httpconf.no_server_rewrite) { 1278 buf->append("Server: "); 1279 buf->append(httpconf.server_name); 1280 buf->append("\r\n"); 1281 } else { 1282 auto server = resp.fs.header(http2::HD_SERVER); 1283 if (server) { 1284 buf->append("Server: "); 1285 buf->append((*server).value); 1286 buf->append("\r\n"); 1287 } 1288 } 1289 1290 if (req.method != HTTP_CONNECT || !downstream->get_upgraded()) { 1291 auto affinity_cookie = downstream->get_affinity_cookie_to_send(); 1292 if (affinity_cookie) { 1293 auto &group = dconn->get_downstream_addr_group(); 1294 auto &shared_addr = group->shared_addr; 1295 auto &cookieconf = shared_addr->affinity.cookie; 1296 auto secure = 1297 http::require_cookie_secure_attribute(cookieconf.secure, req.scheme); 1298 auto cookie_str = http::create_affinity_cookie( 1299 balloc, cookieconf.name, affinity_cookie, cookieconf.path, secure); 1300 buf->append("Set-Cookie: "); 1301 buf->append(cookie_str); 1302 buf->append("\r\n"); 1303 } 1304 } 1305 1306 auto via = resp.fs.header(http2::HD_VIA); 1307 if (httpconf.no_via) { 1308 if (via) { 1309 buf->append("Via: "); 1310 buf->append((*via).value); 1311 buf->append("\r\n"); 1312 } 1313 } else { 1314 buf->append("Via: "); 1315 if (via) { 1316 buf->append((*via).value); 1317 buf->append(", "); 1318 } 1319 std::array<char, 16> viabuf; 1320 auto end = http::create_via_header_value(viabuf.data(), resp.http_major, 1321 resp.http_minor); 1322 buf->append(viabuf.data(), end - std::begin(viabuf)); 1323 buf->append("\r\n"); 1324 } 1325 1326 for (auto &p : httpconf.add_response_headers) { 1327 buf->append(p.name); 1328 buf->append(": "); 1329 buf->append(p.value); 1330 buf->append("\r\n"); 1331 } 1332 1333 buf->append("\r\n"); 1334 1335 if (LOG_ENABLED(INFO)) { 1336 log_response_headers(buf); 1337 } 1338 1339 return 0; 1340} 1341 1342int HttpsUpstream::on_downstream_body(Downstream *downstream, 1343 const uint8_t *data, size_t len, 1344 bool flush) { 1345 if (len == 0) { 1346 return 0; 1347 } 1348 auto output = downstream->get_response_buf(); 1349 if (downstream->get_chunked_response()) { 1350 output->append(util::utox(len)); 1351 output->append("\r\n"); 1352 } 1353 output->append(data, len); 1354 1355 downstream->response_sent_body_length += len; 1356 1357 if (downstream->get_chunked_response()) { 1358 output->append("\r\n"); 1359 } 1360 return 0; 1361} 1362 1363int HttpsUpstream::on_downstream_body_complete(Downstream *downstream) { 1364 const auto &req = downstream->request(); 1365 auto &resp = downstream->response(); 1366 1367 if (downstream->get_chunked_response()) { 1368 auto output = downstream->get_response_buf(); 1369 const auto &trailers = resp.fs.trailers(); 1370 if (trailers.empty()) { 1371 output->append("0\r\n\r\n"); 1372 } else { 1373 output->append("0\r\n"); 1374 http2::build_http1_headers_from_headers(output, trailers, 1375 http2::HDOP_STRIP_ALL); 1376 output->append("\r\n"); 1377 } 1378 } 1379 if (LOG_ENABLED(INFO)) { 1380 DLOG(INFO, downstream) << "HTTP response completed"; 1381 } 1382 1383 if (!downstream->validate_response_recv_body_length()) { 1384 resp.connection_close = true; 1385 } 1386 1387 if (req.connection_close || resp.connection_close || 1388 // To avoid to stall upload body 1389 downstream->get_request_state() != DownstreamState::MSG_COMPLETE) { 1390 auto handler = get_client_handler(); 1391 handler->set_should_close_after_write(true); 1392 } 1393 return 0; 1394} 1395 1396int HttpsUpstream::on_downstream_abort_request(Downstream *downstream, 1397 unsigned int status_code) { 1398 error_reply(status_code); 1399 handler_->signal_write(); 1400 return 0; 1401} 1402 1403int HttpsUpstream::on_downstream_abort_request_with_https_redirect( 1404 Downstream *downstream) { 1405 redirect_to_https(downstream); 1406 handler_->signal_write(); 1407 return 0; 1408} 1409 1410int HttpsUpstream::redirect_to_https(Downstream *downstream) { 1411 auto &req = downstream->request(); 1412 if (req.method == HTTP_CONNECT || req.scheme != "http" || 1413 req.authority.empty()) { 1414 error_reply(400); 1415 return 0; 1416 } 1417 1418 auto authority = util::extract_host(req.authority); 1419 if (authority.empty()) { 1420 error_reply(400); 1421 return 0; 1422 } 1423 1424 auto &balloc = downstream->get_block_allocator(); 1425 auto config = get_config(); 1426 auto &httpconf = config->http; 1427 1428 StringRef loc; 1429 if (httpconf.redirect_https_port == StringRef::from_lit("443")) { 1430 loc = concat_string_ref(balloc, StringRef::from_lit("https://"), authority, 1431 req.path); 1432 } else { 1433 loc = concat_string_ref(balloc, StringRef::from_lit("https://"), authority, 1434 StringRef::from_lit(":"), 1435 httpconf.redirect_https_port, req.path); 1436 } 1437 1438 auto &resp = downstream->response(); 1439 resp.http_status = 308; 1440 resp.fs.add_header_token(StringRef::from_lit("location"), loc, false, 1441 http2::HD_LOCATION); 1442 resp.fs.add_header_token(StringRef::from_lit("connection"), 1443 StringRef::from_lit("close"), false, 1444 http2::HD_CONNECTION); 1445 1446 return send_reply(downstream, nullptr, 0); 1447} 1448 1449void HttpsUpstream::log_response_headers(DefaultMemchunks *buf) const { 1450 std::string nhdrs; 1451 for (auto chunk = buf->head; chunk; chunk = chunk->next) { 1452 nhdrs.append(chunk->pos, chunk->last); 1453 } 1454 if (log_config()->errorlog_tty) { 1455 nhdrs = http::colorizeHeaders(nhdrs.c_str()); 1456 } 1457 ULOG(INFO, this) << "HTTP response headers\n" << nhdrs; 1458} 1459 1460void HttpsUpstream::on_handler_delete() { 1461 if (downstream_ && downstream_->accesslog_ready()) { 1462 handler_->write_accesslog(downstream_.get()); 1463 } 1464} 1465 1466int HttpsUpstream::on_downstream_reset(Downstream *downstream, bool no_retry) { 1467 int rv; 1468 std::unique_ptr<DownstreamConnection> dconn; 1469 1470 assert(downstream == downstream_.get()); 1471 1472 downstream_->pop_downstream_connection(); 1473 1474 if (!downstream_->request_submission_ready()) { 1475 switch (downstream_->get_response_state()) { 1476 case DownstreamState::MSG_COMPLETE: 1477 // We have got all response body already. Send it off. 1478 return 0; 1479 case DownstreamState::INITIAL: 1480 if (on_downstream_abort_request(downstream_.get(), 502) != 0) { 1481 return -1; 1482 } 1483 return 0; 1484 default: 1485 break; 1486 } 1487 // Return error so that caller can delete handler 1488 return -1; 1489 } 1490 1491 downstream_->add_retry(); 1492 1493 rv = 0; 1494 1495 if (no_retry || downstream_->no_more_retry()) { 1496 goto fail; 1497 } 1498 1499 for (;;) { 1500 auto dconn = handler_->get_downstream_connection(rv, downstream_.get()); 1501 if (!dconn) { 1502 goto fail; 1503 } 1504 1505 rv = downstream_->attach_downstream_connection(std::move(dconn)); 1506 if (rv == 0) { 1507 break; 1508 } 1509 } 1510 1511 rv = downstream_->push_request_headers(); 1512 if (rv != 0) { 1513 goto fail; 1514 } 1515 1516 return 0; 1517 1518fail: 1519 if (rv == SHRPX_ERR_TLS_REQUIRED) { 1520 rv = on_downstream_abort_request_with_https_redirect(downstream); 1521 } else { 1522 rv = on_downstream_abort_request(downstream_.get(), 502); 1523 } 1524 if (rv != 0) { 1525 return -1; 1526 } 1527 downstream_->pop_downstream_connection(); 1528 1529 return 0; 1530} 1531 1532int HttpsUpstream::initiate_push(Downstream *downstream, const StringRef &uri) { 1533 return 0; 1534} 1535 1536int HttpsUpstream::response_riovec(struct iovec *iov, int iovcnt) const { 1537 if (!downstream_) { 1538 return 0; 1539 } 1540 1541 auto buf = downstream_->get_response_buf(); 1542 1543 return buf->riovec(iov, iovcnt); 1544} 1545 1546void HttpsUpstream::response_drain(size_t n) { 1547 if (!downstream_) { 1548 return; 1549 } 1550 1551 auto buf = downstream_->get_response_buf(); 1552 1553 buf->drain(n); 1554} 1555 1556bool HttpsUpstream::response_empty() const { 1557 if (!downstream_) { 1558 return true; 1559 } 1560 1561 auto buf = downstream_->get_response_buf(); 1562 1563 return buf->rleft() == 0; 1564} 1565 1566Downstream * 1567HttpsUpstream::on_downstream_push_promise(Downstream *downstream, 1568 int32_t promised_stream_id) { 1569 return nullptr; 1570} 1571 1572int HttpsUpstream::on_downstream_push_promise_complete( 1573 Downstream *downstream, Downstream *promised_downstream) { 1574 return -1; 1575} 1576 1577bool HttpsUpstream::push_enabled() const { return false; } 1578 1579void HttpsUpstream::cancel_premature_downstream( 1580 Downstream *promised_downstream) {} 1581 1582} // namespace shrpx 1583