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