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