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