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