tizen 2.4 release
[external/nghttp2.git] / src / shrpx_https_upstream.cc
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_worker_config.h"
38 #include "http2.h"
39 #include "util.h"
40 #include "template.h"
41
42 using namespace nghttp2;
43
44 namespace shrpx {
45
46 HttpsUpstream::HttpsUpstream(ClientHandler *handler)
47     : handler_(handler), current_header_length_(0),
48       ioctrl_(handler->get_rlimit()) {
49   http_parser_init(&htp_, HTTP_REQUEST);
50   htp_.data = this;
51 }
52
53 HttpsUpstream::~HttpsUpstream() {}
54
55 void HttpsUpstream::reset_current_header_length() {
56   current_header_length_ = 0;
57 }
58
59 namespace {
60 int htp_msg_begin(http_parser *htp) {
61   auto upstream = static_cast<HttpsUpstream *>(htp->data);
62   if (LOG_ENABLED(INFO)) {
63     ULOG(INFO, upstream) << "HTTP request started";
64   }
65   upstream->reset_current_header_length();
66   // TODO specify 0 as priority for now
67   upstream->attach_downstream(make_unique<Downstream>(upstream, 0, 0));
68   return 0;
69 }
70 } // namespace
71
72 namespace {
73 int htp_uricb(http_parser *htp, const char *data, size_t len) {
74   auto upstream = static_cast<HttpsUpstream *>(htp->data);
75   auto downstream = upstream->get_downstream();
76   downstream->append_request_path(data, len);
77   return 0;
78 }
79 } // namespace
80
81 namespace {
82 int htp_hdr_keycb(http_parser *htp, const char *data, size_t len) {
83   auto upstream = static_cast<HttpsUpstream *>(htp->data);
84   auto downstream = upstream->get_downstream();
85   if (downstream->get_request_state() != Downstream::INITIAL) {
86     // ignore trailers
87     return 0;
88   }
89   if (downstream->get_request_header_key_prev()) {
90     downstream->append_last_request_header_key(data, len);
91   } else {
92     downstream->add_request_header(std::string(data, len), "");
93   }
94   if (downstream->get_request_headers_sum() > Downstream::MAX_HEADERS_SUM) {
95     if (LOG_ENABLED(INFO)) {
96       ULOG(INFO, upstream) << "Too large header block size="
97                            << downstream->get_request_headers_sum();
98     }
99     return -1;
100   }
101   return 0;
102 }
103 } // namespace
104
105 namespace {
106 int htp_hdr_valcb(http_parser *htp, const char *data, size_t len) {
107   auto upstream = static_cast<HttpsUpstream *>(htp->data);
108   auto downstream = upstream->get_downstream();
109   if (downstream->get_request_state() != Downstream::INITIAL) {
110     // ignore trailers
111     return 0;
112   }
113   if (downstream->get_request_header_key_prev()) {
114     downstream->set_last_request_header_value(std::string(data, len));
115   } else {
116     downstream->append_last_request_header_value(data, len);
117   }
118   if (downstream->get_request_headers_sum() > Downstream::MAX_HEADERS_SUM) {
119     if (LOG_ENABLED(INFO)) {
120       ULOG(INFO, upstream) << "Too large header block size="
121                            << downstream->get_request_headers_sum();
122     }
123     return -1;
124   }
125   return 0;
126 }
127 } // namespace
128
129 namespace {
130 int htp_hdrs_completecb(http_parser *htp) {
131   int rv;
132   auto upstream = static_cast<HttpsUpstream *>(htp->data);
133   if (LOG_ENABLED(INFO)) {
134     ULOG(INFO, upstream) << "HTTP request headers completed";
135   }
136   auto downstream = upstream->get_downstream();
137
138   downstream->set_request_method(
139       http_method_str((enum http_method)htp->method));
140   downstream->set_request_major(htp->http_major);
141   downstream->set_request_minor(htp->http_minor);
142
143   downstream->set_request_connection_close(!http_should_keep_alive(htp));
144
145   if (LOG_ENABLED(INFO)) {
146     std::stringstream ss;
147     ss << downstream->get_request_method() << " "
148        << downstream->get_request_path() << " "
149        << "HTTP/" << downstream->get_request_major() << "."
150        << downstream->get_request_minor() << "\n";
151     const auto &headers = downstream->get_request_headers();
152     for (size_t i = 0; i < headers.size(); ++i) {
153       ss << TTY_HTTP_HD << headers[i].name << TTY_RST << ": "
154          << headers[i].value << "\n";
155     }
156     ULOG(INFO, upstream) << "HTTP request headers\n" << ss.str();
157   }
158
159   if (downstream->index_request_headers() != 0) {
160     return -1;
161   }
162
163   if (downstream->get_request_major() == 1 &&
164       downstream->get_request_minor() == 1 &&
165       !downstream->get_request_header(http2::HD_HOST)) {
166     return -1;
167   }
168
169   downstream->inspect_http1_request();
170
171   if (get_config()->client_proxy &&
172       downstream->get_request_method() != "CONNECT") {
173     // Make sure that request path is an absolute URI.
174     http_parser_url u;
175     auto url = downstream->get_request_path().c_str();
176     memset(&u, 0, sizeof(u));
177     rv = http_parser_parse_url(url, downstream->get_request_path().size(), 0,
178                                &u);
179     if (rv != 0 || !(u.field_set & (1 << UF_SCHEMA))) {
180       // Expect to respond with 400 bad request
181       return -1;
182     }
183   }
184
185   rv = downstream->attach_downstream_connection(
186       upstream->get_client_handler()->get_downstream_connection());
187
188   if (rv != 0) {
189     downstream->set_request_state(Downstream::CONNECT_FAIL);
190
191     return -1;
192   }
193
194   rv = downstream->push_request_headers();
195
196   if (rv != 0) {
197     return -1;
198   }
199
200   downstream->set_request_state(Downstream::HEADER_COMPLETE);
201
202   return 0;
203 }
204 } // namespace
205
206 namespace {
207 int htp_bodycb(http_parser *htp, const char *data, size_t len) {
208   int rv;
209   auto upstream = static_cast<HttpsUpstream *>(htp->data);
210   auto downstream = upstream->get_downstream();
211   rv = downstream->push_upload_data_chunk(
212       reinterpret_cast<const uint8_t *>(data), len);
213   if (rv != 0) {
214     return -1;
215   }
216   return 0;
217 }
218 } // namespace
219
220 namespace {
221 int htp_msg_completecb(http_parser *htp) {
222   int rv;
223   auto upstream = static_cast<HttpsUpstream *>(htp->data);
224   if (LOG_ENABLED(INFO)) {
225     ULOG(INFO, upstream) << "HTTP request completed";
226   }
227   auto downstream = upstream->get_downstream();
228   downstream->set_request_state(Downstream::MSG_COMPLETE);
229   rv = downstream->end_upload_data();
230   if (rv != 0) {
231     return -1;
232   }
233   // Stop further processing to complete this request
234   http_parser_pause(htp, 1);
235   return 0;
236 }
237 } // namespace
238
239 namespace {
240 http_parser_settings htp_hooks = {
241     htp_msg_begin,       // http_cb      on_message_begin;
242     htp_uricb,           // http_data_cb on_url;
243     nullptr,             // http_data_cb on_status;
244     htp_hdr_keycb,       // http_data_cb on_header_field;
245     htp_hdr_valcb,       // http_data_cb on_header_value;
246     htp_hdrs_completecb, // http_cb      on_headers_complete;
247     htp_bodycb,          // http_data_cb on_body;
248     htp_msg_completecb   // http_cb      on_message_complete;
249 };
250 } // namespace
251
252 // on_read() does not consume all available data in input buffer if
253 // one http request is fully received.
254 int HttpsUpstream::on_read() {
255   auto rb = handler_->get_rb();
256   auto downstream = get_downstream();
257
258   if (rb->rleft() == 0) {
259     return 0;
260   }
261
262   // downstream can be nullptr here, because it is initialized in the
263   // callback chain called by http_parser_execute()
264   if (downstream && downstream->get_upgraded()) {
265
266     auto rv = downstream->push_upload_data_chunk(rb->pos, rb->rleft());
267
268     if (rv != 0) {
269       return -1;
270     }
271
272     rb->reset();
273
274     if (downstream->request_buf_full()) {
275       if (LOG_ENABLED(INFO)) {
276         ULOG(INFO, this) << "Downstream request buf is full";
277       }
278       pause_read(SHRPX_NO_BUFFER);
279
280       return 0;
281     }
282
283     return 0;
284   }
285
286   auto nread = http_parser_execute(
287       &htp_, &htp_hooks, reinterpret_cast<const char *>(rb->pos), rb->rleft());
288
289   rb->drain(nread);
290
291   // Well, actually header length + some body bytes
292   current_header_length_ += nread;
293
294   // Get downstream again because it may be initialized in http parser
295   // execution
296   downstream = get_downstream();
297
298   auto handler = get_client_handler();
299   auto htperr = HTTP_PARSER_ERRNO(&htp_);
300
301   if (htperr == HPE_PAUSED) {
302
303     assert(downstream);
304
305     if (downstream->get_request_state() == Downstream::CONNECT_FAIL) {
306       // Following paues_read is needed to avoid reading next data.
307       pause_read(SHRPX_MSG_BLOCK);
308       error_reply(503);
309       handler_->signal_write();
310       // Downstream gets deleted after response body is read.
311       return 0;
312     }
313
314     assert(downstream->get_request_state() == Downstream::MSG_COMPLETE);
315
316     if (downstream->get_downstream_connection() == nullptr) {
317       // Error response has already be sent
318       assert(downstream->get_response_state() == Downstream::MSG_COMPLETE);
319       delete_downstream();
320
321       return 0;
322     }
323
324     if (handler->get_http2_upgrade_allowed() &&
325         downstream->get_http2_upgrade_request()) {
326
327       if (handler->perform_http2_upgrade(this) != 0) {
328         return -1;
329       }
330
331       handler_->signal_write();
332
333       return 0;
334     }
335
336     pause_read(SHRPX_MSG_BLOCK);
337
338     return 0;
339   }
340
341   if (htperr != HPE_OK) {
342     if (LOG_ENABLED(INFO)) {
343       ULOG(INFO, this) << "HTTP parse failure: "
344                        << "(" << http_errno_name(htperr) << ") "
345                        << http_errno_description(htperr);
346     }
347
348     pause_read(SHRPX_MSG_BLOCK);
349
350     unsigned int status_code;
351
352     if (downstream &&
353         downstream->get_request_state() == Downstream::CONNECT_FAIL) {
354       status_code = 503;
355     } else {
356       status_code = 400;
357     }
358
359     error_reply(status_code);
360
361     handler_->signal_write();
362
363     return 0;
364   }
365
366   // downstream can be NULL here.
367   if (downstream && downstream->request_buf_full()) {
368     if (LOG_ENABLED(INFO)) {
369       ULOG(INFO, this) << "Downstream request buffer is full";
370     }
371
372     pause_read(SHRPX_NO_BUFFER);
373
374     return 0;
375   }
376
377   return 0;
378 }
379
380 int HttpsUpstream::on_write() {
381   auto downstream = get_downstream();
382   if (!downstream) {
383     return 0;
384   }
385   auto wb = handler_->get_wb();
386   if (wb->wleft() == 0) {
387     return 0;
388   }
389
390   auto dconn = downstream->get_downstream_connection();
391   auto output = downstream->get_response_buf();
392
393   if (output->rleft() == 0 && dconn &&
394       downstream->get_response_state() != Downstream::MSG_COMPLETE) {
395     if (downstream->resume_read(SHRPX_NO_BUFFER,
396                                 downstream->get_response_datalen()) != 0) {
397       return -1;
398     }
399
400     if (downstream_read(dconn) != 0) {
401       return -1;
402     }
403   }
404
405   auto n = output->remove(wb->last, wb->wleft());
406   wb->write(n);
407
408   if (wb->rleft() > 0) {
409     return 0;
410   }
411
412   // We need to postpone detachment until all data are sent so that
413   // we can notify nghttp2 library all data consumed.
414   if (downstream->get_response_state() == Downstream::MSG_COMPLETE) {
415     if (downstream->get_response_connection_close()) {
416       // Connection close
417       downstream->pop_downstream_connection();
418       // dconn was deleted
419     } else {
420       // Keep-alive
421       downstream->detach_downstream_connection();
422     }
423     // We need this if response ends before request.
424     if (downstream->get_request_state() == Downstream::MSG_COMPLETE) {
425       delete_downstream();
426       return resume_read(SHRPX_MSG_BLOCK, nullptr, 0);
427     }
428   }
429
430   return downstream->resume_read(SHRPX_NO_BUFFER,
431                                  downstream->get_response_datalen());
432 }
433
434 int HttpsUpstream::on_event() { return 0; }
435
436 ClientHandler *HttpsUpstream::get_client_handler() const { return handler_; }
437
438 void HttpsUpstream::pause_read(IOCtrlReason reason) {
439   ioctrl_.pause_read(reason);
440 }
441
442 int HttpsUpstream::resume_read(IOCtrlReason reason, Downstream *downstream,
443                                size_t consumed) {
444   // downstream could be nullptr if reason is SHRPX_MSG_BLOCK.
445   if (downstream && downstream->request_buf_full()) {
446     return 0;
447   }
448   if (ioctrl_.resume_read(reason)) {
449     // Process remaining data in input buffer here because these bytes
450     // are not notified by readcb until new data arrive.
451     http_parser_pause(&htp_, 0);
452     return on_read();
453   }
454
455   return 0;
456 }
457
458 int HttpsUpstream::downstream_read(DownstreamConnection *dconn) {
459   auto downstream = dconn->get_downstream();
460   int rv;
461
462   rv = downstream->on_read();
463
464   if (downstream->get_response_state() == Downstream::MSG_RESET) {
465     return -1;
466   }
467
468   if (downstream->get_response_state() == Downstream::MSG_BAD_HEADER) {
469     error_reply(502);
470     downstream->pop_downstream_connection();
471     goto end;
472   }
473
474   // Detach downstream connection early so that it could be reused
475   // without hitting server's request timeout.
476   if (downstream->get_response_state() == Downstream::MSG_COMPLETE &&
477       !downstream->get_response_connection_close()) {
478     // Keep-alive
479     downstream->detach_downstream_connection();
480   }
481
482   if (rv == SHRPX_ERR_EOF) {
483     return downstream_eof(dconn);
484   }
485
486   if (rv < 0) {
487     return downstream_error(dconn, Downstream::EVENT_ERROR);
488   }
489
490 end:
491   handler_->signal_write();
492
493   return 0;
494 }
495
496 int HttpsUpstream::downstream_write(DownstreamConnection *dconn) {
497   int rv;
498   rv = dconn->on_write();
499   if (rv == SHRPX_ERR_NETWORK) {
500     return downstream_error(dconn, Downstream::EVENT_ERROR);
501   }
502
503   if (rv != 0) {
504     return -1;
505   }
506
507   return 0;
508 }
509
510 int HttpsUpstream::downstream_eof(DownstreamConnection *dconn) {
511   auto downstream = dconn->get_downstream();
512
513   if (LOG_ENABLED(INFO)) {
514     DCLOG(INFO, dconn) << "EOF";
515   }
516
517   if (downstream->get_response_state() == Downstream::MSG_COMPLETE) {
518     goto end;
519   }
520
521   if (downstream->get_response_state() == Downstream::HEADER_COMPLETE) {
522     // Server may indicate the end of the request by EOF
523     if (LOG_ENABLED(INFO)) {
524       DCLOG(INFO, dconn) << "The end of the response body was indicated by "
525                          << "EOF";
526     }
527     on_downstream_body_complete(downstream);
528     downstream->set_response_state(Downstream::MSG_COMPLETE);
529     downstream->pop_downstream_connection();
530     goto end;
531   }
532
533   if (downstream->get_response_state() == Downstream::INITIAL) {
534     // we did not send any response headers, so we can reply error
535     // message.
536     if (LOG_ENABLED(INFO)) {
537       DCLOG(INFO, dconn) << "Return error reply";
538     }
539     error_reply(502);
540     downstream->pop_downstream_connection();
541     goto end;
542   }
543
544   // Otherwise, we don't know how to recover from this situation. Just
545   // drop connection.
546   return -1;
547 end:
548   handler_->signal_write();
549
550   return 0;
551 }
552
553 int HttpsUpstream::downstream_error(DownstreamConnection *dconn, int events) {
554   auto downstream = dconn->get_downstream();
555   if (LOG_ENABLED(INFO)) {
556     if (events & Downstream::EVENT_ERROR) {
557       DCLOG(INFO, dconn) << "Network error/general error";
558     } else {
559       DCLOG(INFO, dconn) << "Timeout";
560     }
561   }
562   if (downstream->get_response_state() != Downstream::INITIAL) {
563     return -1;
564   }
565
566   unsigned int status;
567   if (events & Downstream::EVENT_TIMEOUT) {
568     status = 504;
569   } else {
570     status = 502;
571   }
572   error_reply(status);
573
574   downstream->pop_downstream_connection();
575
576   handler_->signal_write();
577   return 0;
578 }
579
580 void HttpsUpstream::error_reply(unsigned int status_code) {
581   auto html = http::create_error_html(status_code);
582   auto downstream = get_downstream();
583
584   if (!downstream) {
585     attach_downstream(make_unique<Downstream>(this, 1, 1));
586     downstream = get_downstream();
587   }
588
589   downstream->set_response_http_status(status_code);
590   // we are going to close connection for both frontend and backend in
591   // error condition.  This is safest option.
592   downstream->set_response_connection_close(true);
593   handler_->set_should_close_after_write(true);
594
595   auto output = downstream->get_response_buf();
596
597   output->append("HTTP/1.1 ");
598   auto status_str = http2::get_status_string(status_code);
599   output->append(status_str.c_str(), status_str.size());
600   output->append("\r\nServer: ");
601   output->append(get_config()->server_name, strlen(get_config()->server_name));
602   output->append("\r\nContent-Length: ");
603   auto cl = util::utos(html.size());
604   output->append(cl.c_str(), cl.size());
605   output->append("\r\nContent-Type: text/html; "
606                  "charset=UTF-8\r\nConnection: close\r\n\r\n");
607   output->append(html.c_str(), html.size());
608
609   downstream->add_response_sent_bodylen(html.size());
610   downstream->set_response_state(Downstream::MSG_COMPLETE);
611 }
612
613 void HttpsUpstream::attach_downstream(std::unique_ptr<Downstream> downstream) {
614   assert(!downstream_);
615   downstream_ = std::move(downstream);
616 }
617
618 void HttpsUpstream::delete_downstream() {
619   if (downstream_ && downstream_->accesslog_ready()) {
620     handler_->write_accesslog(downstream_.get());
621   }
622
623   downstream_.reset();
624 }
625
626 Downstream *HttpsUpstream::get_downstream() const { return downstream_.get(); }
627
628 std::unique_ptr<Downstream> HttpsUpstream::pop_downstream() {
629   return std::unique_ptr<Downstream>(downstream_.release());
630 }
631
632 int HttpsUpstream::on_downstream_header_complete(Downstream *downstream) {
633   if (LOG_ENABLED(INFO)) {
634     if (downstream->get_non_final_response()) {
635       DLOG(INFO, downstream) << "HTTP non-final response header";
636     } else {
637       DLOG(INFO, downstream) << "HTTP response header completed";
638     }
639   }
640
641   std::string hdrs = "HTTP/";
642   hdrs += util::utos(downstream->get_request_major());
643   hdrs += ".";
644   hdrs += util::utos(downstream->get_request_minor());
645   hdrs += " ";
646   hdrs += http2::get_status_string(downstream->get_response_http_status());
647   hdrs += "\r\n";
648
649   if (!get_config()->http2_proxy && !get_config()->client_proxy &&
650       !get_config()->no_location_rewrite) {
651     downstream->rewrite_location_response_header(
652         get_client_handler()->get_upstream_scheme());
653   }
654
655   http2::build_http1_headers_from_headers(hdrs,
656                                           downstream->get_response_headers());
657
658   auto output = downstream->get_response_buf();
659
660   if (downstream->get_non_final_response()) {
661     hdrs += "\r\n";
662
663     if (LOG_ENABLED(INFO)) {
664       log_response_headers(hdrs);
665     }
666
667     output->append(hdrs.c_str(), hdrs.size());
668
669     downstream->clear_response_headers();
670
671     return 0;
672   }
673
674   // after graceful shutdown commenced, add connection: close header
675   // field.
676   if (worker_config->graceful_shutdown) {
677     downstream->set_response_connection_close(true);
678   }
679
680   // We check downstream->get_response_connection_close() in case when
681   // the Content-Length is not available.
682   if (!downstream->get_request_connection_close() &&
683       !downstream->get_response_connection_close()) {
684     if (downstream->get_request_major() <= 0 ||
685         downstream->get_request_minor() <= 0) {
686       // We add this header for HTTP/1.0 or HTTP/0.9 clients
687       hdrs += "Connection: Keep-Alive\r\n";
688     }
689   } else if (!downstream->get_upgraded() ||
690              downstream->get_request_method() != "CONNECT") {
691     hdrs += "Connection: close\r\n";
692   }
693
694   if (!downstream->get_response_header(http2::HD_ALT_SVC)) {
695     // We won't change or alter alt-svc from backend for now
696     if (!get_config()->altsvcs.empty()) {
697       hdrs += "Alt-Svc: ";
698
699       for (auto &altsvc : get_config()->altsvcs) {
700         hdrs += util::percent_encode_token(altsvc.protocol_id);
701         hdrs += "=\"";
702         hdrs += util::quote_string(std::string(altsvc.host, altsvc.host_len));
703         hdrs += ":";
704         hdrs += util::utos(altsvc.port);
705         hdrs += "\", ";
706       }
707
708       hdrs[hdrs.size() - 2] = '\r';
709       hdrs[hdrs.size() - 1] = '\n';
710     }
711   }
712
713   if (!get_config()->http2_proxy && !get_config()->client_proxy) {
714     hdrs += "Server: ";
715     hdrs += get_config()->server_name;
716     hdrs += "\r\n";
717   } else {
718     auto server = downstream->get_response_header(http2::HD_SERVER);
719     if (server) {
720       hdrs += "Server: ";
721       hdrs += (*server).value;
722       hdrs += "\r\n";
723     }
724   }
725
726   auto via = downstream->get_response_header(http2::HD_VIA);
727   if (get_config()->no_via) {
728     if (via) {
729       hdrs += "Via: ";
730       hdrs += (*via).value;
731       hdrs += "\r\n";
732     }
733   } else {
734     hdrs += "Via: ";
735     if (via) {
736       hdrs += (*via).value;
737       hdrs += ", ";
738     }
739     hdrs += http::create_via_header_value(downstream->get_response_major(),
740                                           downstream->get_response_minor());
741     hdrs += "\r\n";
742   }
743
744   for (auto &p : get_config()->add_response_headers) {
745     hdrs += p.first;
746     hdrs += ": ";
747     hdrs += p.second;
748     hdrs += "\r\n";
749   }
750
751   hdrs += "\r\n";
752
753   if (LOG_ENABLED(INFO)) {
754     log_response_headers(hdrs);
755   }
756
757   output->append(hdrs.c_str(), hdrs.size());
758
759   return 0;
760 }
761
762 int HttpsUpstream::on_downstream_body(Downstream *downstream,
763                                       const uint8_t *data, size_t len,
764                                       bool flush) {
765   if (len == 0) {
766     return 0;
767   }
768   auto output = downstream->get_response_buf();
769   if (downstream->get_chunked_response()) {
770     auto chunk_size_hex = util::utox(len);
771     chunk_size_hex += "\r\n";
772
773     output->append(chunk_size_hex.c_str(), chunk_size_hex.size());
774   }
775   output->append(data, len);
776
777   downstream->add_response_sent_bodylen(len);
778
779   if (downstream->get_chunked_response()) {
780     output->append("\r\n");
781   }
782   return 0;
783 }
784
785 int HttpsUpstream::on_downstream_body_complete(Downstream *downstream) {
786   if (downstream->get_chunked_response()) {
787     auto output = downstream->get_response_buf();
788     output->append("0\r\n\r\n");
789   }
790   if (LOG_ENABLED(INFO)) {
791     DLOG(INFO, downstream) << "HTTP response completed";
792   }
793
794   if (!downstream->validate_response_bodylen()) {
795     downstream->set_response_connection_close(true);
796   }
797
798   if (downstream->get_request_connection_close() ||
799       downstream->get_response_connection_close()) {
800     auto handler = get_client_handler();
801     handler->set_should_close_after_write(true);
802   }
803   return 0;
804 }
805
806 int HttpsUpstream::on_downstream_abort_request(Downstream *downstream,
807                                                unsigned int status_code) {
808   error_reply(status_code);
809   handler_->signal_write();
810   return 0;
811 }
812
813 void HttpsUpstream::log_response_headers(const std::string &hdrs) const {
814   const char *hdrp;
815   std::string nhdrs;
816   if (worker_config->errorlog_tty) {
817     nhdrs = http::colorizeHeaders(hdrs.c_str());
818     hdrp = nhdrs.c_str();
819   } else {
820     hdrp = hdrs.c_str();
821   }
822   ULOG(INFO, this) << "HTTP response headers\n" << hdrp;
823 }
824
825 void HttpsUpstream::on_handler_delete() {
826   if (downstream_ && downstream_->accesslog_ready()) {
827     handler_->write_accesslog(downstream_.get());
828   }
829 }
830
831 int HttpsUpstream::on_downstream_reset(bool no_retry) {
832   int rv;
833
834   if ((downstream_->get_request_state() != Downstream::HEADER_COMPLETE &&
835        downstream_->get_request_state() != Downstream::MSG_COMPLETE) ||
836       downstream_->get_response_state() != Downstream::INITIAL) {
837     // Return error so that caller can delete handler
838     return -1;
839   }
840
841   downstream_->pop_downstream_connection();
842
843   downstream_->add_retry();
844
845   if (no_retry || downstream_->no_more_retry()) {
846     if (on_downstream_abort_request(downstream_.get(), 503) != 0) {
847       return -1;
848     }
849     return 0;
850   }
851
852   rv = downstream_->attach_downstream_connection(
853       handler_->get_downstream_connection());
854   if (rv != 0) {
855     return -1;
856   }
857   return 0;
858 }
859
860 MemchunkPool *HttpsUpstream::get_mcpool() { return &mcpool_; }
861
862 } // namespace shrpx