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
637 auto rv = downstream->push_upload_data_chunk(rb->pos(), rb->rleft());
638
639 if (rv != 0) {
640 return -1;
641 }
642
643 rb->reset();
644 rlimit->startw();
645
646 if (downstream->request_buf_full()) {
647 if (LOG_ENABLED(INFO)) {
648 ULOG(INFO, this) << "Downstream request buf is full";
649 }
650 pause_read(SHRPX_NO_BUFFER);
651
652 return 0;
653 }
654
655 return 0;
656 }
657
658 if (downstream) {
659 // To avoid reading next pipelined request
660 switch (downstream->get_request_state()) {
661 case DownstreamState::INITIAL:
662 case DownstreamState::HEADER_COMPLETE:
663 break;
664 default:
665 return 0;
666 }
667 }
668
669 // llhttp_execute() does nothing once it entered error state.
670 auto htperr = llhttp_execute(&htp_, reinterpret_cast<const char *>(rb->pos()),
671 rb->rleft());
672
673 if (htperr == HPE_PAUSED_UPGRADE &&
674 rb->pos() ==
675 reinterpret_cast<const uint8_t *>(llhttp_get_error_pos(&htp_))) {
676 llhttp_resume_after_upgrade(&htp_);
677
678 htperr = llhttp_execute(&htp_, reinterpret_cast<const char *>(rb->pos()),
679 rb->rleft());
680 }
681
682 auto nread =
683 htperr == HPE_OK
684 ? rb->rleft()
685 : reinterpret_cast<const uint8_t *>(llhttp_get_error_pos(&htp_)) -
686 rb->pos();
687 rb->drain(nread);
688 rlimit->startw();
689
690 // Well, actually header length + some body bytes
691 current_header_length_ += nread;
692
693 // Get downstream again because it may be initialized in http parser
694 // execution
695 downstream = get_downstream();
696
697 if (htperr == HPE_PAUSED) {
698 // We may pause parser in htp_msg_completecb when both side are
699 // completed. Signal write, so that we can run on_write().
700 if (downstream &&
701 downstream->get_request_state() == DownstreamState::MSG_COMPLETE &&
702 downstream->get_response_state() == DownstreamState::MSG_COMPLETE) {
703 handler_->signal_write();
704 }
705 return 0;
706 }
707
708 if (htperr != HPE_OK) {
709 if (LOG_ENABLED(INFO)) {
710 ULOG(INFO, this) << "HTTP parse failure: "
711 << "(" << llhttp_errno_name(htperr) << ") "
712 << llhttp_get_error_reason(&htp_);
713 }
714
715 if (downstream &&
716 downstream->get_response_state() != DownstreamState::INITIAL) {
717 handler_->set_should_close_after_write(true);
718 handler_->signal_write();
719 return 0;
720 }
721
722 unsigned int status_code;
723
724 if (htperr == HPE_INVALID_METHOD) {
725 status_code = 501;
726 } else if (downstream) {
727 status_code = downstream->response().http_status;
728 if (status_code == 0) {
729 if (downstream->get_request_state() == DownstreamState::CONNECT_FAIL) {
730 status_code = 502;
731 } else if (downstream->get_request_state() ==
732 DownstreamState::HTTP1_REQUEST_HEADER_TOO_LARGE) {
733 status_code = 431;
734 } else {
735 status_code = 400;
736 }
737 }
738 } else {
739 status_code = 400;
740 }
741
742 error_reply(status_code);
743
744 handler_->signal_write();
745
746 return 0;
747 }
748
749 // downstream can be NULL here.
750 if (downstream && downstream->request_buf_full()) {
751 if (LOG_ENABLED(INFO)) {
752 ULOG(INFO, this) << "Downstream request buffer is full";
753 }
754
755 pause_read(SHRPX_NO_BUFFER);
756
757 return 0;
758 }
759
760 return 0;
761 }
762
on_write()763 int HttpsUpstream::on_write() {
764 auto downstream = get_downstream();
765 if (!downstream) {
766 return 0;
767 }
768
769 auto output = downstream->get_response_buf();
770 const auto &resp = downstream->response();
771
772 if (output->rleft() > 0) {
773 return 0;
774 }
775
776 // We need to postpone detachment until all data are sent so that
777 // we can notify nghttp2 library all data consumed.
778 if (downstream->get_response_state() == DownstreamState::MSG_COMPLETE) {
779 if (downstream->can_detach_downstream_connection()) {
780 // Keep-alive
781 downstream->detach_downstream_connection();
782 } else {
783 // Connection close
784 downstream->pop_downstream_connection();
785 // dconn was deleted
786 }
787 // We need this if response ends before request.
788 if (downstream->get_request_state() == DownstreamState::MSG_COMPLETE) {
789 delete_downstream();
790
791 if (handler_->get_should_close_after_write()) {
792 return 0;
793 }
794
795 auto &upstreamconf = get_config()->conn.upstream;
796
797 handler_->reset_upstream_read_timeout(upstreamconf.timeout.idle);
798
799 return resume_read(SHRPX_NO_BUFFER, nullptr, 0);
800 } else {
801 // If the request is not complete, close the connection.
802 delete_downstream();
803
804 handler_->set_should_close_after_write(true);
805
806 return 0;
807 }
808 }
809
810 return downstream->resume_read(SHRPX_NO_BUFFER, resp.unconsumed_body_length);
811 }
812
on_event()813 int HttpsUpstream::on_event() { return 0; }
814
get_client_handler() const815 ClientHandler *HttpsUpstream::get_client_handler() const { return handler_; }
816
pause_read(IOCtrlReason reason)817 void HttpsUpstream::pause_read(IOCtrlReason reason) {
818 ioctrl_.pause_read(reason);
819 }
820
resume_read(IOCtrlReason reason,Downstream * downstream,size_t consumed)821 int HttpsUpstream::resume_read(IOCtrlReason reason, Downstream *downstream,
822 size_t consumed) {
823 // downstream could be nullptr
824 if (downstream && downstream->request_buf_full()) {
825 return 0;
826 }
827 if (ioctrl_.resume_read(reason)) {
828 // Process remaining data in input buffer here because these bytes
829 // are not notified by readcb until new data arrive.
830 llhttp_resume(&htp_);
831
832 auto conn = handler_->get_connection();
833 ev_feed_event(conn->loop, &conn->rev, EV_READ);
834 return 0;
835 }
836
837 return 0;
838 }
839
downstream_read(DownstreamConnection * dconn)840 int HttpsUpstream::downstream_read(DownstreamConnection *dconn) {
841 auto downstream = dconn->get_downstream();
842 int rv;
843
844 rv = downstream->on_read();
845
846 if (rv == SHRPX_ERR_EOF) {
847 if (downstream->get_request_header_sent()) {
848 return downstream_eof(dconn);
849 }
850 return SHRPX_ERR_RETRY;
851 }
852
853 if (rv == SHRPX_ERR_DCONN_CANCELED) {
854 downstream->pop_downstream_connection();
855 goto end;
856 }
857
858 if (rv < 0) {
859 return downstream_error(dconn, Downstream::EVENT_ERROR);
860 }
861
862 if (downstream->get_response_state() == DownstreamState::MSG_RESET) {
863 return -1;
864 }
865
866 if (downstream->get_response_state() == DownstreamState::MSG_BAD_HEADER) {
867 error_reply(502);
868 downstream->pop_downstream_connection();
869 goto end;
870 }
871
872 if (downstream->can_detach_downstream_connection()) {
873 // Keep-alive
874 downstream->detach_downstream_connection();
875 }
876
877 end:
878 handler_->signal_write();
879
880 return 0;
881 }
882
downstream_write(DownstreamConnection * dconn)883 int HttpsUpstream::downstream_write(DownstreamConnection *dconn) {
884 int rv;
885 rv = dconn->on_write();
886 if (rv == SHRPX_ERR_NETWORK) {
887 return downstream_error(dconn, Downstream::EVENT_ERROR);
888 }
889
890 if (rv != 0) {
891 return rv;
892 }
893
894 return 0;
895 }
896
downstream_eof(DownstreamConnection * dconn)897 int HttpsUpstream::downstream_eof(DownstreamConnection *dconn) {
898 auto downstream = dconn->get_downstream();
899
900 if (LOG_ENABLED(INFO)) {
901 DCLOG(INFO, dconn) << "EOF";
902 }
903
904 if (downstream->get_response_state() == DownstreamState::MSG_COMPLETE) {
905 goto end;
906 }
907
908 if (downstream->get_response_state() == DownstreamState::HEADER_COMPLETE) {
909 // Server may indicate the end of the request by EOF
910 if (LOG_ENABLED(INFO)) {
911 DCLOG(INFO, dconn) << "The end of the response body was indicated by "
912 << "EOF";
913 }
914 on_downstream_body_complete(downstream);
915 downstream->set_response_state(DownstreamState::MSG_COMPLETE);
916 downstream->pop_downstream_connection();
917 goto end;
918 }
919
920 if (downstream->get_response_state() == DownstreamState::INITIAL) {
921 // we did not send any response headers, so we can reply error
922 // message.
923 if (LOG_ENABLED(INFO)) {
924 DCLOG(INFO, dconn) << "Return error reply";
925 }
926 error_reply(502);
927 downstream->pop_downstream_connection();
928 goto end;
929 }
930
931 // Otherwise, we don't know how to recover from this situation. Just
932 // drop connection.
933 return -1;
934 end:
935 handler_->signal_write();
936
937 return 0;
938 }
939
downstream_error(DownstreamConnection * dconn,int events)940 int HttpsUpstream::downstream_error(DownstreamConnection *dconn, int events) {
941 auto downstream = dconn->get_downstream();
942 if (LOG_ENABLED(INFO)) {
943 if (events & Downstream::EVENT_ERROR) {
944 DCLOG(INFO, dconn) << "Network error/general error";
945 } else {
946 DCLOG(INFO, dconn) << "Timeout";
947 }
948 }
949 if (downstream->get_response_state() != DownstreamState::INITIAL) {
950 return -1;
951 }
952
953 unsigned int status;
954 if (events & Downstream::EVENT_TIMEOUT) {
955 if (downstream->get_request_header_sent()) {
956 status = 504;
957 } else {
958 status = 408;
959 }
960 } else {
961 status = 502;
962 }
963 error_reply(status);
964
965 downstream->pop_downstream_connection();
966
967 handler_->signal_write();
968 return 0;
969 }
970
send_reply(Downstream * downstream,const uint8_t * body,size_t bodylen)971 int HttpsUpstream::send_reply(Downstream *downstream, const uint8_t *body,
972 size_t bodylen) {
973 const auto &req = downstream->request();
974 auto &resp = downstream->response();
975 auto &balloc = downstream->get_block_allocator();
976 auto config = get_config();
977 auto &httpconf = config->http;
978
979 auto connection_close = false;
980
981 auto worker = handler_->get_worker();
982
983 if (httpconf.max_requests <= num_requests_ ||
984 worker->get_graceful_shutdown()) {
985 resp.fs.add_header_token("connection"_sr, "close"_sr, false,
986 http2::HD_CONNECTION);
987 connection_close = true;
988 } else if (req.http_major <= 0 ||
989 (req.http_major == 1 && req.http_minor == 0)) {
990 connection_close = true;
991 } else {
992 auto c = resp.fs.header(http2::HD_CONNECTION);
993 if (c && util::strieq("close"_sr, c->value)) {
994 connection_close = true;
995 }
996 }
997
998 if (connection_close) {
999 resp.connection_close = true;
1000 handler_->set_should_close_after_write(true);
1001 }
1002
1003 auto output = downstream->get_response_buf();
1004
1005 output->append("HTTP/1.1 ");
1006 output->append(http2::stringify_status(balloc, resp.http_status));
1007 output->append(' ');
1008 output->append(http2::get_reason_phrase(resp.http_status));
1009 output->append("\r\n");
1010
1011 for (auto &kv : resp.fs.headers()) {
1012 if (kv.name.empty() || kv.name[0] == ':') {
1013 continue;
1014 }
1015 http2::capitalize(output, kv.name);
1016 output->append(": ");
1017 output->append(kv.value);
1018 output->append("\r\n");
1019 }
1020
1021 if (!resp.fs.header(http2::HD_SERVER)) {
1022 output->append("Server: ");
1023 output->append(config->http.server_name);
1024 output->append("\r\n");
1025 }
1026
1027 for (auto &p : httpconf.add_response_headers) {
1028 output->append(p.name);
1029 output->append(": ");
1030 output->append(p.value);
1031 output->append("\r\n");
1032 }
1033
1034 output->append("\r\n");
1035
1036 if (req.method != HTTP_HEAD) {
1037 output->append(body, bodylen);
1038
1039 downstream->response_sent_body_length += bodylen;
1040 }
1041
1042 downstream->set_response_state(DownstreamState::MSG_COMPLETE);
1043
1044 return 0;
1045 }
1046
error_reply(unsigned int status_code)1047 void HttpsUpstream::error_reply(unsigned int status_code) {
1048 auto downstream = get_downstream();
1049
1050 if (!downstream) {
1051 attach_downstream(
1052 std::make_unique<Downstream>(this, handler_->get_mcpool(), 1));
1053 downstream = get_downstream();
1054 }
1055
1056 auto &resp = downstream->response();
1057 auto &balloc = downstream->get_block_allocator();
1058
1059 auto html = http::create_error_html(balloc, status_code);
1060
1061 resp.http_status = status_code;
1062 // we are going to close connection for both frontend and backend in
1063 // error condition. This is safest option.
1064 resp.connection_close = true;
1065 handler_->set_should_close_after_write(true);
1066
1067 auto output = downstream->get_response_buf();
1068
1069 output->append("HTTP/1.1 ");
1070 output->append(http2::stringify_status(balloc, status_code));
1071 output->append(' ');
1072 output->append(http2::get_reason_phrase(status_code));
1073 output->append("\r\nServer: ");
1074 output->append(get_config()->http.server_name);
1075 output->append("\r\nContent-Length: ");
1076 std::array<char, NGHTTP2_MAX_UINT64_DIGITS> intbuf;
1077 output->append(StringRef{std::begin(intbuf),
1078 util::utos(std::begin(intbuf), html.size())});
1079 output->append("\r\nDate: ");
1080 auto lgconf = log_config();
1081 lgconf->update_tstamp(std::chrono::system_clock::now());
1082 output->append(lgconf->tstamp->time_http);
1083 output->append("\r\nContent-Type: text/html; "
1084 "charset=UTF-8\r\nConnection: close\r\n\r\n");
1085
1086 const auto &req = downstream->request();
1087
1088 if (req.method != HTTP_HEAD) {
1089 output->append(html);
1090
1091 downstream->response_sent_body_length += html.size();
1092 }
1093
1094 downstream->set_response_state(DownstreamState::MSG_COMPLETE);
1095 }
1096
attach_downstream(std::unique_ptr<Downstream> downstream)1097 void HttpsUpstream::attach_downstream(std::unique_ptr<Downstream> downstream) {
1098 assert(!downstream_);
1099 downstream_ = std::move(downstream);
1100 }
1101
delete_downstream()1102 void HttpsUpstream::delete_downstream() {
1103 if (downstream_ && downstream_->accesslog_ready()) {
1104 handler_->write_accesslog(downstream_.get());
1105 }
1106
1107 downstream_.reset();
1108 }
1109
get_downstream() const1110 Downstream *HttpsUpstream::get_downstream() const { return downstream_.get(); }
1111
pop_downstream()1112 std::unique_ptr<Downstream> HttpsUpstream::pop_downstream() {
1113 return std::unique_ptr<Downstream>(downstream_.release());
1114 }
1115
on_downstream_header_complete(Downstream * downstream)1116 int HttpsUpstream::on_downstream_header_complete(Downstream *downstream) {
1117 if (LOG_ENABLED(INFO)) {
1118 if (downstream->get_non_final_response()) {
1119 DLOG(INFO, downstream) << "HTTP non-final response header";
1120 } else {
1121 DLOG(INFO, downstream) << "HTTP response header completed";
1122 }
1123 }
1124
1125 const auto &req = downstream->request();
1126 auto &resp = downstream->response();
1127 auto &balloc = downstream->get_block_allocator();
1128 auto dconn = downstream->get_downstream_connection();
1129 // dconn might be nullptr if this is non-final response from mruby.
1130
1131 if (downstream->get_non_final_response() &&
1132 !downstream->supports_non_final_response()) {
1133 resp.fs.clear_headers();
1134 return 0;
1135 }
1136
1137 #ifdef HAVE_MRUBY
1138 if (!downstream->get_non_final_response()) {
1139 assert(dconn);
1140 const auto &group = dconn->get_downstream_addr_group();
1141 if (group) {
1142 const auto &dmruby_ctx = group->shared_addr->mruby_ctx;
1143
1144 if (dmruby_ctx->run_on_response_proc(downstream) != 0) {
1145 error_reply(500);
1146 return -1;
1147 }
1148
1149 if (downstream->get_response_state() == DownstreamState::MSG_COMPLETE) {
1150 return -1;
1151 }
1152 }
1153
1154 auto worker = handler_->get_worker();
1155 auto mruby_ctx = worker->get_mruby_context();
1156
1157 if (mruby_ctx->run_on_response_proc(downstream) != 0) {
1158 error_reply(500);
1159 return -1;
1160 }
1161
1162 if (downstream->get_response_state() == DownstreamState::MSG_COMPLETE) {
1163 return -1;
1164 }
1165 }
1166 #endif // HAVE_MRUBY
1167
1168 auto connect_method = req.method == HTTP_CONNECT;
1169
1170 auto buf = downstream->get_response_buf();
1171 buf->append("HTTP/");
1172 buf->append('0' + req.http_major);
1173 buf->append('.');
1174 buf->append('0' + req.http_minor);
1175 buf->append(' ');
1176 if (req.connect_proto != ConnectProto::NONE && downstream->get_upgraded()) {
1177 buf->append(http2::stringify_status(balloc, 101));
1178 buf->append(' ');
1179 buf->append(http2::get_reason_phrase(101));
1180 } else {
1181 buf->append(http2::stringify_status(balloc, resp.http_status));
1182 buf->append(' ');
1183 buf->append(http2::get_reason_phrase(resp.http_status));
1184 }
1185 buf->append("\r\n");
1186
1187 auto config = get_config();
1188 auto &httpconf = config->http;
1189
1190 if (!config->http2_proxy && !httpconf.no_location_rewrite) {
1191 downstream->rewrite_location_response_header(
1192 get_client_handler()->get_upstream_scheme());
1193 }
1194
1195 if (downstream->get_non_final_response()) {
1196 http2::build_http1_headers_from_headers(buf, resp.fs.headers(),
1197 http2::HDOP_STRIP_ALL);
1198
1199 buf->append("\r\n");
1200
1201 if (LOG_ENABLED(INFO)) {
1202 log_response_headers(buf);
1203 }
1204
1205 resp.fs.clear_headers();
1206
1207 return 0;
1208 }
1209
1210 auto build_flags = (http2::HDOP_STRIP_ALL & ~http2::HDOP_STRIP_VIA) |
1211 (!http2::legacy_http1(req.http_major, req.http_minor)
1212 ? 0
1213 : http2::HDOP_STRIP_TRANSFER_ENCODING);
1214
1215 http2::build_http1_headers_from_headers(buf, resp.fs.headers(), build_flags);
1216
1217 auto worker = handler_->get_worker();
1218
1219 // after graceful shutdown commenced, add connection: close header
1220 // field.
1221 if (httpconf.max_requests <= num_requests_ ||
1222 worker->get_graceful_shutdown()) {
1223 resp.connection_close = true;
1224 }
1225
1226 // We check downstream->get_response_connection_close() in case when
1227 // the Content-Length is not available.
1228 if (!req.connection_close && !resp.connection_close) {
1229 if (req.http_major <= 0 || req.http_minor <= 0) {
1230 // We add this header for HTTP/1.0 or HTTP/0.9 clients
1231 buf->append("Connection: Keep-Alive\r\n");
1232 }
1233 } else if (!downstream->get_upgraded()) {
1234 buf->append("Connection: close\r\n");
1235 }
1236
1237 if (!connect_method && downstream->get_upgraded()) {
1238 if (req.connect_proto == ConnectProto::WEBSOCKET &&
1239 resp.http_status / 100 == 2) {
1240 buf->append("Upgrade: websocket\r\nConnection: Upgrade\r\n");
1241 auto key = req.fs.header(http2::HD_SEC_WEBSOCKET_KEY);
1242 if (!key || key->value.size() != base64::encode_length(16)) {
1243 return -1;
1244 }
1245 std::array<uint8_t, base64::encode_length(20)> out;
1246 auto accept = http2::make_websocket_accept_token(out.data(), key->value);
1247 if (accept.empty()) {
1248 return -1;
1249 }
1250 buf->append("Sec-WebSocket-Accept: ");
1251 buf->append(accept);
1252 buf->append("\r\n");
1253 } else {
1254 auto connection = resp.fs.header(http2::HD_CONNECTION);
1255 if (connection) {
1256 buf->append("Connection: ");
1257 buf->append((*connection).value);
1258 buf->append("\r\n");
1259 }
1260
1261 auto upgrade = resp.fs.header(http2::HD_UPGRADE);
1262 if (upgrade) {
1263 buf->append("Upgrade: ");
1264 buf->append((*upgrade).value);
1265 buf->append("\r\n");
1266 }
1267 }
1268 }
1269
1270 if (!resp.fs.header(http2::HD_ALT_SVC)) {
1271 // We won't change or alter alt-svc from backend for now
1272 if (!httpconf.altsvcs.empty()) {
1273 buf->append("Alt-Svc: ");
1274 buf->append(httpconf.altsvc_header_value);
1275 buf->append("\r\n");
1276 }
1277 }
1278
1279 if (!config->http2_proxy && !httpconf.no_server_rewrite) {
1280 buf->append("Server: ");
1281 buf->append(httpconf.server_name);
1282 buf->append("\r\n");
1283 } else {
1284 auto server = resp.fs.header(http2::HD_SERVER);
1285 if (server) {
1286 buf->append("Server: ");
1287 buf->append((*server).value);
1288 buf->append("\r\n");
1289 }
1290 }
1291
1292 if (req.method != HTTP_CONNECT || !downstream->get_upgraded()) {
1293 auto affinity_cookie = downstream->get_affinity_cookie_to_send();
1294 if (affinity_cookie) {
1295 auto &group = dconn->get_downstream_addr_group();
1296 auto &shared_addr = group->shared_addr;
1297 auto &cookieconf = shared_addr->affinity.cookie;
1298 auto secure =
1299 http::require_cookie_secure_attribute(cookieconf.secure, req.scheme);
1300 auto cookie_str = http::create_affinity_cookie(
1301 balloc, cookieconf.name, affinity_cookie, cookieconf.path, secure);
1302 buf->append("Set-Cookie: ");
1303 buf->append(cookie_str);
1304 buf->append("\r\n");
1305 }
1306 }
1307
1308 auto via = resp.fs.header(http2::HD_VIA);
1309 if (httpconf.no_via) {
1310 if (via) {
1311 buf->append("Via: ");
1312 buf->append((*via).value);
1313 buf->append("\r\n");
1314 }
1315 } else {
1316 buf->append("Via: ");
1317 if (via) {
1318 buf->append((*via).value);
1319 buf->append(", ");
1320 }
1321 std::array<char, 16> viabuf;
1322 auto end = http::create_via_header_value(viabuf.data(), resp.http_major,
1323 resp.http_minor);
1324 buf->append(viabuf.data(), end - std::begin(viabuf));
1325 buf->append("\r\n");
1326 }
1327
1328 for (auto &p : httpconf.add_response_headers) {
1329 buf->append(p.name);
1330 buf->append(": ");
1331 buf->append(p.value);
1332 buf->append("\r\n");
1333 }
1334
1335 buf->append("\r\n");
1336
1337 if (LOG_ENABLED(INFO)) {
1338 log_response_headers(buf);
1339 }
1340
1341 return 0;
1342 }
1343
on_downstream_body(Downstream * downstream,const uint8_t * data,size_t len,bool flush)1344 int HttpsUpstream::on_downstream_body(Downstream *downstream,
1345 const uint8_t *data, size_t len,
1346 bool flush) {
1347 if (len == 0) {
1348 return 0;
1349 }
1350 auto output = downstream->get_response_buf();
1351 if (downstream->get_chunked_response()) {
1352 output->append(util::utox(len));
1353 output->append("\r\n");
1354 }
1355 output->append(data, len);
1356
1357 downstream->response_sent_body_length += len;
1358
1359 if (downstream->get_chunked_response()) {
1360 output->append("\r\n");
1361 }
1362 return 0;
1363 }
1364
on_downstream_body_complete(Downstream * downstream)1365 int HttpsUpstream::on_downstream_body_complete(Downstream *downstream) {
1366 const auto &req = downstream->request();
1367 auto &resp = downstream->response();
1368
1369 if (downstream->get_chunked_response()) {
1370 auto output = downstream->get_response_buf();
1371 const auto &trailers = resp.fs.trailers();
1372 if (trailers.empty()) {
1373 output->append("0\r\n\r\n");
1374 } else {
1375 output->append("0\r\n");
1376 http2::build_http1_headers_from_headers(output, trailers,
1377 http2::HDOP_STRIP_ALL);
1378 output->append("\r\n");
1379 }
1380 }
1381 if (LOG_ENABLED(INFO)) {
1382 DLOG(INFO, downstream) << "HTTP response completed";
1383 }
1384
1385 if (!downstream->validate_response_recv_body_length()) {
1386 resp.connection_close = true;
1387 }
1388
1389 if (req.connection_close || resp.connection_close ||
1390 // To avoid to stall upload body
1391 downstream->get_request_state() != DownstreamState::MSG_COMPLETE) {
1392 auto handler = get_client_handler();
1393 handler->set_should_close_after_write(true);
1394 }
1395 return 0;
1396 }
1397
on_downstream_abort_request(Downstream * downstream,unsigned int status_code)1398 int HttpsUpstream::on_downstream_abort_request(Downstream *downstream,
1399 unsigned int status_code) {
1400 error_reply(status_code);
1401 handler_->signal_write();
1402 return 0;
1403 }
1404
on_downstream_abort_request_with_https_redirect(Downstream * downstream)1405 int HttpsUpstream::on_downstream_abort_request_with_https_redirect(
1406 Downstream *downstream) {
1407 redirect_to_https(downstream);
1408 handler_->signal_write();
1409 return 0;
1410 }
1411
redirect_to_https(Downstream * downstream)1412 int HttpsUpstream::redirect_to_https(Downstream *downstream) {
1413 auto &req = downstream->request();
1414 if (req.method == HTTP_CONNECT || req.scheme != "http"_sr ||
1415 req.authority.empty()) {
1416 error_reply(400);
1417 return 0;
1418 }
1419
1420 auto authority = util::extract_host(req.authority);
1421 if (authority.empty()) {
1422 error_reply(400);
1423 return 0;
1424 }
1425
1426 auto &balloc = downstream->get_block_allocator();
1427 auto config = get_config();
1428 auto &httpconf = config->http;
1429
1430 StringRef loc;
1431 if (httpconf.redirect_https_port == "443"_sr) {
1432 loc = concat_string_ref(balloc, "https://"_sr, authority, req.path);
1433 } else {
1434 loc = concat_string_ref(balloc, "https://"_sr, authority, ":"_sr,
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("location"_sr, loc, false, http2::HD_LOCATION);
1441 resp.fs.add_header_token("connection"_sr, "close"_sr, false,
1442 http2::HD_CONNECTION);
1443
1444 return send_reply(downstream, nullptr, 0);
1445 }
1446
log_response_headers(DefaultMemchunks * buf) const1447 void HttpsUpstream::log_response_headers(DefaultMemchunks *buf) const {
1448 std::string nhdrs;
1449 for (auto chunk = buf->head; chunk; chunk = chunk->next) {
1450 nhdrs.append(chunk->pos, chunk->last);
1451 }
1452 if (log_config()->errorlog_tty) {
1453 nhdrs = http::colorizeHeaders(nhdrs.c_str());
1454 }
1455 ULOG(INFO, this) << "HTTP response headers\n" << nhdrs;
1456 }
1457
on_handler_delete()1458 void HttpsUpstream::on_handler_delete() {
1459 if (downstream_ && downstream_->accesslog_ready()) {
1460 handler_->write_accesslog(downstream_.get());
1461 }
1462 }
1463
on_downstream_reset(Downstream * downstream,bool no_retry)1464 int HttpsUpstream::on_downstream_reset(Downstream *downstream, bool no_retry) {
1465 int rv;
1466 std::unique_ptr<DownstreamConnection> dconn;
1467
1468 assert(downstream == downstream_.get());
1469
1470 downstream_->pop_downstream_connection();
1471
1472 if (!downstream_->request_submission_ready()) {
1473 switch (downstream_->get_response_state()) {
1474 case DownstreamState::MSG_COMPLETE:
1475 // We have got all response body already. Send it off.
1476 return 0;
1477 case DownstreamState::INITIAL:
1478 if (on_downstream_abort_request(downstream_.get(), 502) != 0) {
1479 return -1;
1480 }
1481 return 0;
1482 default:
1483 break;
1484 }
1485 // Return error so that caller can delete handler
1486 return -1;
1487 }
1488
1489 downstream_->add_retry();
1490
1491 rv = 0;
1492
1493 if (no_retry || downstream_->no_more_retry()) {
1494 goto fail;
1495 }
1496
1497 for (;;) {
1498 auto dconn = handler_->get_downstream_connection(rv, downstream_.get());
1499 if (!dconn) {
1500 goto fail;
1501 }
1502
1503 rv = downstream_->attach_downstream_connection(std::move(dconn));
1504 if (rv == 0) {
1505 break;
1506 }
1507 }
1508
1509 rv = downstream_->push_request_headers();
1510 if (rv != 0) {
1511 goto fail;
1512 }
1513
1514 return 0;
1515
1516 fail:
1517 if (rv == SHRPX_ERR_TLS_REQUIRED) {
1518 rv = on_downstream_abort_request_with_https_redirect(downstream);
1519 } else {
1520 rv = on_downstream_abort_request(downstream_.get(), 502);
1521 }
1522 if (rv != 0) {
1523 return -1;
1524 }
1525 downstream_->pop_downstream_connection();
1526
1527 return 0;
1528 }
1529
initiate_push(Downstream * downstream,const StringRef & uri)1530 int HttpsUpstream::initiate_push(Downstream *downstream, const StringRef &uri) {
1531 return 0;
1532 }
1533
response_riovec(struct iovec * iov,int iovcnt) const1534 int HttpsUpstream::response_riovec(struct iovec *iov, int iovcnt) const {
1535 if (!downstream_) {
1536 return 0;
1537 }
1538
1539 auto buf = downstream_->get_response_buf();
1540
1541 return buf->riovec(iov, iovcnt);
1542 }
1543
response_drain(size_t n)1544 void HttpsUpstream::response_drain(size_t n) {
1545 if (!downstream_) {
1546 return;
1547 }
1548
1549 auto buf = downstream_->get_response_buf();
1550
1551 buf->drain(n);
1552 }
1553
response_empty() const1554 bool HttpsUpstream::response_empty() const {
1555 if (!downstream_) {
1556 return true;
1557 }
1558
1559 auto buf = downstream_->get_response_buf();
1560
1561 return buf->rleft() == 0;
1562 }
1563
1564 Downstream *
on_downstream_push_promise(Downstream * downstream,int32_t promised_stream_id)1565 HttpsUpstream::on_downstream_push_promise(Downstream *downstream,
1566 int32_t promised_stream_id) {
1567 return nullptr;
1568 }
1569
on_downstream_push_promise_complete(Downstream * downstream,Downstream * promised_downstream)1570 int HttpsUpstream::on_downstream_push_promise_complete(
1571 Downstream *downstream, Downstream *promised_downstream) {
1572 return -1;
1573 }
1574
push_enabled() const1575 bool HttpsUpstream::push_enabled() const { return false; }
1576
cancel_premature_downstream(Downstream * promised_downstream)1577 void HttpsUpstream::cancel_premature_downstream(
1578 Downstream *promised_downstream) {}
1579
1580 } // namespace shrpx
1581