tizen 2.4 release
[external/nghttp2.git] / src / shrpx_http2_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_http2_upstream.h"
26
27 #include <netinet/tcp.h>
28 #include <assert.h>
29 #include <cerrno>
30 #include <sstream>
31
32 #include "shrpx_client_handler.h"
33 #include "shrpx_https_upstream.h"
34 #include "shrpx_downstream.h"
35 #include "shrpx_downstream_connection.h"
36 #include "shrpx_config.h"
37 #include "shrpx_http.h"
38 #include "shrpx_worker_config.h"
39 #include "http2.h"
40 #include "util.h"
41 #include "base64.h"
42 #include "app_helper.h"
43 #include "template.h"
44
45 using namespace nghttp2;
46
47 namespace shrpx {
48
49 namespace {
50 int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
51                              uint32_t error_code, void *user_data) {
52   auto upstream = static_cast<Http2Upstream *>(user_data);
53   if (LOG_ENABLED(INFO)) {
54     ULOG(INFO, upstream) << "Stream stream_id=" << stream_id
55                          << " is being closed";
56   }
57
58   auto downstream = upstream->find_downstream(stream_id);
59
60   if (!downstream) {
61     return 0;
62   }
63
64   upstream->consume(stream_id, downstream->get_request_datalen());
65
66   downstream->reset_request_datalen();
67
68   if (downstream->get_request_state() == Downstream::CONNECT_FAIL) {
69     upstream->remove_downstream(downstream);
70     // downstream was deleted
71
72     return 0;
73   }
74
75   downstream->set_request_state(Downstream::STREAM_CLOSED);
76
77   if (downstream->get_response_state() == Downstream::MSG_COMPLETE) {
78     // At this point, downstream response was read
79     if (!downstream->get_upgraded() &&
80         !downstream->get_response_connection_close()) {
81       // Keep-alive
82       downstream->detach_downstream_connection();
83     }
84
85     upstream->remove_downstream(downstream);
86     // downstream was deleted
87
88     return 0;
89   }
90
91   // At this point, downstream read may be paused.
92
93   // If shrpx_downstream::push_request_headers() failed, the
94   // error is handled here.
95   upstream->remove_downstream(downstream);
96   // downstream was deleted
97
98   // How to test this case? Request sufficient large download
99   // and make client send RST_STREAM after it gets first DATA
100   // frame chunk.
101
102   return 0;
103 }
104 } // namespace
105
106 int Http2Upstream::upgrade_upstream(HttpsUpstream *http) {
107   int rv;
108
109   auto http2_settings = http->get_downstream()->get_http2_settings();
110   util::to_base64(http2_settings);
111
112   auto settings_payload =
113       base64::decode(std::begin(http2_settings), std::end(http2_settings));
114
115   rv = nghttp2_session_upgrade(
116       session_, reinterpret_cast<const uint8_t *>(settings_payload.c_str()),
117       settings_payload.size(), nullptr);
118   if (rv != 0) {
119     ULOG(WARN, this) << "nghttp2_session_upgrade() returned error: "
120                      << nghttp2_strerror(rv);
121     return -1;
122   }
123   pre_upstream_.reset(http);
124   auto downstream = http->pop_downstream();
125   downstream->reset_upstream(this);
126   downstream->set_stream_id(1);
127   downstream->reset_upstream_rtimer();
128   downstream->set_stream_id(1);
129   downstream->set_priority(0);
130
131   downstream_queue_.add_active(std::move(downstream));
132
133   if (LOG_ENABLED(INFO)) {
134     ULOG(INFO, this) << "Connection upgraded to HTTP/2";
135   }
136
137   return 0;
138 }
139
140 void Http2Upstream::start_settings_timer() {
141   ev_timer_start(handler_->get_loop(), &settings_timer_);
142 }
143
144 void Http2Upstream::stop_settings_timer() {
145   ev_timer_stop(handler_->get_loop(), &settings_timer_);
146 }
147
148 namespace {
149 int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
150                        const uint8_t *name, size_t namelen,
151                        const uint8_t *value, size_t valuelen, uint8_t flags,
152                        void *user_data) {
153   if (get_config()->upstream_frame_debug) {
154     verbose_on_header_callback(session, frame, name, namelen, value, valuelen,
155                                flags, user_data);
156   }
157   if (frame->hd.type != NGHTTP2_HEADERS ||
158       frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
159     return 0;
160   }
161   auto upstream = static_cast<Http2Upstream *>(user_data);
162   auto downstream = upstream->find_downstream(frame->hd.stream_id);
163   if (!downstream) {
164     return 0;
165   }
166
167   if (downstream->get_request_headers_sum() > Downstream::MAX_HEADERS_SUM) {
168     if (downstream->get_response_state() == Downstream::MSG_COMPLETE) {
169       return 0;
170     }
171
172     if (LOG_ENABLED(INFO)) {
173       ULOG(INFO, upstream) << "Too large header block size="
174                            << downstream->get_request_headers_sum();
175     }
176
177     if (upstream->error_reply(downstream, 431) != 0) {
178       return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
179     }
180
181     return 0;
182   }
183   if (!http2::check_nv(name, namelen, value, valuelen)) {
184     upstream->rst_stream(downstream, NGHTTP2_PROTOCOL_ERROR);
185     return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
186   }
187
188   auto token = http2::lookup_token(name, namelen);
189
190   if (name[0] == ':') {
191     if (!downstream->request_pseudo_header_allowed(token)) {
192       upstream->rst_stream(downstream, NGHTTP2_PROTOCOL_ERROR);
193       return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
194     }
195   }
196
197   if (!http2::http2_header_allowed(token)) {
198     upstream->rst_stream(downstream, NGHTTP2_PROTOCOL_ERROR);
199     return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
200   }
201
202   switch (token) {
203   case http2::HD_CONTENT_LENGTH: {
204     auto len = util::parse_uint(value, valuelen);
205     if (len == -1) {
206       if (upstream->error_reply(downstream, 400) != 0) {
207         return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
208       }
209       return 0;
210     }
211     if (downstream->get_request_content_length() != -1) {
212       if (upstream->error_reply(downstream, 400) != 0) {
213         return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
214       }
215       return 0;
216     }
217     downstream->set_request_content_length(len);
218     break;
219   }
220   case http2::HD_TE:
221     if (!util::strieq("trailers", value, valuelen)) {
222       upstream->rst_stream(downstream, NGHTTP2_PROTOCOL_ERROR);
223       return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
224     }
225     break;
226   }
227
228   downstream->add_request_header(name, namelen, value, valuelen,
229                                  flags & NGHTTP2_NV_FLAG_NO_INDEX, token);
230   return 0;
231 }
232 } // namespace
233
234 namespace {
235 int on_begin_headers_callback(nghttp2_session *session,
236                               const nghttp2_frame *frame, void *user_data) {
237   auto upstream = static_cast<Http2Upstream *>(user_data);
238
239   if (frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
240     return 0;
241   }
242   if (LOG_ENABLED(INFO)) {
243     ULOG(INFO, upstream) << "Received upstream request HEADERS stream_id="
244                          << frame->hd.stream_id;
245   }
246
247   // TODO Use priority 0 for now
248   auto downstream = make_unique<Downstream>(upstream, frame->hd.stream_id, 0);
249
250   downstream->reset_upstream_rtimer();
251
252   // Although, we deprecated minor version from HTTP/2, we supply
253   // minor version 0 to use via header field in a conventional way.
254   downstream->set_request_major(2);
255   downstream->set_request_minor(0);
256
257   upstream->add_pending_downstream(std::move(downstream));
258
259   return 0;
260 }
261 } // namespace
262
263 namespace {
264 int on_request_headers(Http2Upstream *upstream, Downstream *downstream,
265                        nghttp2_session *session, const nghttp2_frame *frame) {
266   if (downstream->get_response_state() == Downstream::MSG_COMPLETE) {
267     return 0;
268   }
269
270   auto &nva = downstream->get_request_headers();
271
272   if (LOG_ENABLED(INFO)) {
273     std::stringstream ss;
274     for (auto &nv : nva) {
275       ss << TTY_HTTP_HD << nv.name << TTY_RST << ": " << nv.value << "\n";
276     }
277     ULOG(INFO, upstream) << "HTTP request headers. stream_id="
278                          << downstream->get_stream_id() << "\n" << ss.str();
279   }
280
281   if (get_config()->http2_upstream_dump_request_header) {
282     http2::dump_nv(get_config()->http2_upstream_dump_request_header, nva);
283   }
284
285   auto host = downstream->get_request_header(http2::HD_HOST);
286   auto authority = downstream->get_request_header(http2::HD__AUTHORITY);
287   auto path = downstream->get_request_header(http2::HD__PATH);
288   auto method = downstream->get_request_header(http2::HD__METHOD);
289   auto scheme = downstream->get_request_header(http2::HD__SCHEME);
290
291   bool is_connect = method && "CONNECT" == method->value;
292   bool having_host = http2::non_empty_value(host);
293   bool having_authority = http2::non_empty_value(authority);
294
295   if (is_connect) {
296     // Here we strictly require :authority header field.
297     if (scheme || path || !having_authority) {
298
299       upstream->rst_stream(downstream, NGHTTP2_PROTOCOL_ERROR);
300
301       return 0;
302     }
303   } else {
304     // For proxy, :authority is required. Otherwise, we can accept
305     // :authority or host for methods.
306     if (!http2::non_empty_value(method) || !http2::non_empty_value(scheme) ||
307         (get_config()->http2_proxy && !having_authority) ||
308         (!get_config()->http2_proxy && !having_authority && !having_host) ||
309         !http2::non_empty_value(path)) {
310
311       upstream->rst_stream(downstream, NGHTTP2_PROTOCOL_ERROR);
312
313       return 0;
314     }
315   }
316
317   downstream->set_request_method(http2::value_to_str(method));
318   downstream->set_request_http2_scheme(http2::value_to_str(scheme));
319   downstream->set_request_http2_authority(http2::value_to_str(authority));
320   downstream->set_request_path(http2::value_to_str(path));
321
322   if (!(frame->hd.flags & NGHTTP2_FLAG_END_STREAM)) {
323     downstream->set_request_http2_expect_body(true);
324   }
325
326   downstream->inspect_http2_request();
327
328   downstream->set_request_state(Downstream::HEADER_COMPLETE);
329   if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
330     if (!downstream->validate_request_bodylen()) {
331       upstream->rst_stream(downstream, NGHTTP2_PROTOCOL_ERROR);
332       return 0;
333     }
334
335     downstream->disable_upstream_rtimer();
336
337     downstream->set_request_state(Downstream::MSG_COMPLETE);
338   }
339
340   upstream->start_downstream(downstream);
341
342   return 0;
343 }
344 } // namespace
345
346 void Http2Upstream::start_downstream(Downstream *downstream) {
347   auto next_downstream =
348       downstream_queue_.pop_pending(downstream->get_stream_id());
349   assert(next_downstream);
350
351   if (downstream_queue_.can_activate(
352           downstream->get_request_http2_authority())) {
353     initiate_downstream(std::move(next_downstream));
354     return;
355   }
356
357   downstream_queue_.add_blocked(std::move(next_downstream));
358 }
359
360 void
361 Http2Upstream::initiate_downstream(std::unique_ptr<Downstream> downstream) {
362   int rv;
363
364   rv = downstream->attach_downstream_connection(
365       handler_->get_downstream_connection());
366   if (rv != 0) {
367     // downstream connection fails, send error page
368     if (error_reply(downstream.get(), 503) != 0) {
369       rst_stream(downstream.get(), NGHTTP2_INTERNAL_ERROR);
370     }
371
372     downstream->set_request_state(Downstream::CONNECT_FAIL);
373
374     downstream_queue_.add_failure(std::move(downstream));
375
376     return;
377   }
378   rv = downstream->push_request_headers();
379   if (rv != 0) {
380
381     if (error_reply(downstream.get(), 503) != 0) {
382       rst_stream(downstream.get(), NGHTTP2_INTERNAL_ERROR);
383     }
384
385     downstream_queue_.add_failure(std::move(downstream));
386
387     return;
388   }
389
390   downstream_queue_.add_active(std::move(downstream));
391
392   return;
393 }
394
395 namespace {
396 int on_frame_recv_callback(nghttp2_session *session, const nghttp2_frame *frame,
397                            void *user_data) {
398   int rv;
399   if (get_config()->upstream_frame_debug) {
400     verbose_on_frame_recv_callback(session, frame, user_data);
401   }
402   auto upstream = static_cast<Http2Upstream *>(user_data);
403
404   switch (frame->hd.type) {
405   case NGHTTP2_DATA: {
406     auto downstream = upstream->find_downstream(frame->hd.stream_id);
407     if (!downstream) {
408       return 0;
409     }
410
411     if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
412       downstream->disable_upstream_rtimer();
413
414       if (!downstream->validate_request_bodylen()) {
415         upstream->rst_stream(downstream, NGHTTP2_PROTOCOL_ERROR);
416         return 0;
417       }
418
419       downstream->end_upload_data();
420       downstream->set_request_state(Downstream::MSG_COMPLETE);
421     }
422
423     break;
424   }
425   case NGHTTP2_HEADERS: {
426     auto downstream = upstream->find_downstream(frame->hd.stream_id);
427     if (!downstream) {
428       return 0;
429     }
430
431     if (frame->headers.cat == NGHTTP2_HCAT_REQUEST) {
432       downstream->reset_upstream_rtimer();
433
434       return on_request_headers(upstream, downstream, session, frame);
435     }
436
437     if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
438       if (!downstream->validate_request_bodylen()) {
439         upstream->rst_stream(downstream, NGHTTP2_PROTOCOL_ERROR);
440         return 0;
441       }
442
443       downstream->disable_upstream_rtimer();
444
445       downstream->end_upload_data();
446       downstream->set_request_state(Downstream::MSG_COMPLETE);
447     } else {
448       rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
449                                      frame->hd.stream_id,
450                                      NGHTTP2_PROTOCOL_ERROR);
451       if (rv != 0) {
452         return NGHTTP2_ERR_CALLBACK_FAILURE;
453       }
454     }
455
456     break;
457   }
458   case NGHTTP2_PRIORITY: {
459     // TODO comment out for now
460     // rv = downstream->change_priority(frame->priority.pri);
461     // if(rv != 0) {
462     //   return NGHTTP2_ERR_CALLBACK_FAILURE;
463     // }
464     break;
465   }
466   case NGHTTP2_SETTINGS:
467     if ((frame->hd.flags & NGHTTP2_FLAG_ACK) == 0) {
468       break;
469     }
470     upstream->stop_settings_timer();
471     break;
472   case NGHTTP2_GOAWAY:
473     if (LOG_ENABLED(INFO)) {
474       auto debug_data = util::ascii_dump(frame->goaway.opaque_data,
475                                          frame->goaway.opaque_data_len);
476
477       ULOG(INFO, upstream) << "GOAWAY received: last-stream-id="
478                            << frame->goaway.last_stream_id
479                            << ", error_code=" << frame->goaway.error_code
480                            << ", debug_data=" << debug_data;
481     }
482     break;
483   default:
484     break;
485   }
486   return 0;
487 }
488 } // namespace
489
490 namespace {
491 int on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags,
492                                 int32_t stream_id, const uint8_t *data,
493                                 size_t len, void *user_data) {
494   auto upstream = static_cast<Http2Upstream *>(user_data);
495   auto downstream = upstream->find_downstream(stream_id);
496
497   if (!downstream || !downstream->get_downstream_connection()) {
498     if (upstream->consume(stream_id, len) != 0) {
499       return NGHTTP2_ERR_CALLBACK_FAILURE;
500     }
501
502     return 0;
503   }
504
505   downstream->reset_upstream_rtimer();
506
507   if (downstream->push_upload_data_chunk(data, len) != 0) {
508     upstream->rst_stream(downstream, NGHTTP2_INTERNAL_ERROR);
509
510     if (upstream->consume(stream_id, len) != 0) {
511       return NGHTTP2_ERR_CALLBACK_FAILURE;
512     }
513
514     return 0;
515   }
516
517   return 0;
518 }
519 } // namespace
520
521 namespace {
522 int on_frame_send_callback(nghttp2_session *session, const nghttp2_frame *frame,
523                            void *user_data) {
524   if (get_config()->upstream_frame_debug) {
525     verbose_on_frame_send_callback(session, frame, user_data);
526   }
527   auto upstream = static_cast<Http2Upstream *>(user_data);
528
529   switch (frame->hd.type) {
530   case NGHTTP2_SETTINGS:
531     if ((frame->hd.flags & NGHTTP2_FLAG_ACK) == 0) {
532       upstream->start_settings_timer();
533     }
534     break;
535   case NGHTTP2_PUSH_PROMISE: {
536     auto downstream = make_unique<Downstream>(
537         upstream, frame->push_promise.promised_stream_id, 0);
538
539     downstream->disable_upstream_rtimer();
540
541     downstream->set_request_major(2);
542     downstream->set_request_minor(0);
543
544     for (size_t i = 0; i < frame->push_promise.nvlen; ++i) {
545       auto &nv = frame->push_promise.nva[i];
546       auto token = http2::lookup_token(nv.name, nv.namelen);
547       switch (token) {
548       case http2::HD__METHOD:
549         downstream->set_request_method({nv.value, nv.value + nv.valuelen});
550         break;
551       case http2::HD__SCHEME:
552         downstream->set_request_http2_scheme(
553             {nv.value, nv.value + nv.valuelen});
554         break;
555       case http2::HD__AUTHORITY:
556         downstream->set_request_http2_authority(
557             {nv.value, nv.value + nv.valuelen});
558         break;
559       case http2::HD__PATH:
560         downstream->set_request_path({nv.value, nv.value + nv.valuelen});
561         break;
562       }
563       downstream->add_request_header(nv.name, nv.namelen, nv.value, nv.valuelen,
564                                      nv.flags & NGHTTP2_NV_FLAG_NO_INDEX,
565                                      token);
566     }
567
568     downstream->inspect_http2_request();
569
570     downstream->set_request_state(Downstream::MSG_COMPLETE);
571
572     // a bit weird but start_downstream() expects that given
573     // downstream is in pending queue.
574     auto ptr = downstream.get();
575     upstream->add_pending_downstream(std::move(downstream));
576     upstream->start_downstream(ptr);
577
578     break;
579   }
580   case NGHTTP2_GOAWAY:
581     if (LOG_ENABLED(INFO)) {
582       auto debug_data = util::ascii_dump(frame->goaway.opaque_data,
583                                          frame->goaway.opaque_data_len);
584
585       ULOG(INFO, upstream) << "Sending GOAWAY: last-stream-id="
586                            << frame->goaway.last_stream_id
587                            << ", error_code=" << frame->goaway.error_code
588                            << ", debug_data=" << debug_data;
589     }
590     break;
591   }
592   return 0;
593 }
594 } // namespace
595
596 namespace {
597 int on_frame_not_send_callback(nghttp2_session *session,
598                                const nghttp2_frame *frame, int lib_error_code,
599                                void *user_data) {
600   auto upstream = static_cast<Http2Upstream *>(user_data);
601   if (LOG_ENABLED(INFO)) {
602     ULOG(INFO, upstream) << "Failed to send control frame type="
603                          << static_cast<uint32_t>(frame->hd.type)
604                          << ", lib_error_code=" << lib_error_code << ":"
605                          << nghttp2_strerror(lib_error_code);
606   }
607   if (frame->hd.type == NGHTTP2_HEADERS &&
608       frame->headers.cat == NGHTTP2_HCAT_RESPONSE &&
609       lib_error_code != NGHTTP2_ERR_STREAM_CLOSED &&
610       lib_error_code != NGHTTP2_ERR_STREAM_CLOSING) {
611     // To avoid stream hanging around, issue RST_STREAM.
612     auto downstream = upstream->find_downstream(frame->hd.stream_id);
613     if (downstream) {
614       upstream->rst_stream(downstream, NGHTTP2_INTERNAL_ERROR);
615     }
616   }
617   return 0;
618 }
619 } // namespace
620
621 namespace {
622 uint32_t infer_upstream_rst_stream_error_code(uint32_t downstream_error_code) {
623   // NGHTTP2_REFUSED_STREAM is important because it tells upstream
624   // client to retry.
625   switch (downstream_error_code) {
626   case NGHTTP2_NO_ERROR:
627   case NGHTTP2_REFUSED_STREAM:
628     return downstream_error_code;
629   default:
630     return NGHTTP2_INTERNAL_ERROR;
631   }
632 }
633 } // namespace
634
635 namespace {
636 void settings_timeout_cb(struct ev_loop *loop, ev_timer *w, int revents) {
637   auto upstream = static_cast<Http2Upstream *>(w->data);
638   auto handler = upstream->get_client_handler();
639   ULOG(INFO, upstream) << "SETTINGS timeout";
640   if (upstream->terminate_session(NGHTTP2_SETTINGS_TIMEOUT) != 0) {
641     delete handler;
642     return;
643   }
644   handler->signal_write();
645 }
646 } // namespace
647
648 namespace {
649 void shutdown_timeout_cb(struct ev_loop *loop, ev_timer *w, int revents) {
650   auto upstream = static_cast<Http2Upstream *>(w->data);
651   auto handler = upstream->get_client_handler();
652   upstream->submit_goaway();
653   handler->signal_write();
654 }
655 } // namespace
656
657 namespace {
658 void prepare_cb(struct ev_loop *loop, ev_prepare *w, int revents) {
659   auto upstream = static_cast<Http2Upstream *>(w->data);
660   upstream->check_shutdown();
661 }
662 } // namespace
663
664 void Http2Upstream::submit_goaway() {
665   auto last_stream_id = nghttp2_session_get_last_proc_stream_id(session_);
666   nghttp2_submit_goaway(session_, NGHTTP2_FLAG_NONE, last_stream_id,
667                         NGHTTP2_NO_ERROR, nullptr, 0);
668 }
669
670 void Http2Upstream::check_shutdown() {
671   int rv;
672   if (shutdown_handled_) {
673     return;
674   }
675   if (worker_config->graceful_shutdown) {
676     shutdown_handled_ = true;
677     rv = nghttp2_submit_shutdown_notice(session_);
678     if (rv != 0) {
679       ULOG(FATAL, this) << "nghttp2_submit_shutdown_notice() failed: "
680                         << nghttp2_strerror(rv);
681       return;
682     }
683     handler_->signal_write();
684     ev_timer_start(handler_->get_loop(), &shutdown_timer_);
685   }
686 }
687
688 Http2Upstream::Http2Upstream(ClientHandler *handler)
689     : downstream_queue_(
690           get_config()->http2_proxy
691               ? get_config()->downstream_connections_per_host
692               : get_config()->downstream_proto == PROTO_HTTP
693                     ? get_config()->downstream_connections_per_frontend
694                     : 0,
695           !get_config()->http2_proxy),
696       handler_(handler), session_(nullptr), data_pending_(nullptr),
697       data_pendinglen_(0), shutdown_handled_(false) {
698
699   int rv;
700
701   nghttp2_session_callbacks *callbacks;
702   rv = nghttp2_session_callbacks_new(&callbacks);
703
704   assert(rv == 0);
705
706   auto callbacks_deleter = defer(nghttp2_session_callbacks_del, callbacks);
707
708   nghttp2_session_callbacks_set_on_stream_close_callback(
709       callbacks, on_stream_close_callback);
710
711   nghttp2_session_callbacks_set_on_frame_recv_callback(callbacks,
712                                                        on_frame_recv_callback);
713
714   nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
715       callbacks, on_data_chunk_recv_callback);
716
717   nghttp2_session_callbacks_set_on_frame_send_callback(callbacks,
718                                                        on_frame_send_callback);
719
720   nghttp2_session_callbacks_set_on_frame_not_send_callback(
721       callbacks, on_frame_not_send_callback);
722
723   nghttp2_session_callbacks_set_on_header_callback(callbacks,
724                                                    on_header_callback);
725
726   nghttp2_session_callbacks_set_on_begin_headers_callback(
727       callbacks, on_begin_headers_callback);
728
729   if (get_config()->padding) {
730     nghttp2_session_callbacks_set_select_padding_callback(
731         callbacks, http::select_padding_callback);
732   }
733
734   rv = nghttp2_session_server_new2(&session_, callbacks, this,
735                                    get_config()->http2_option);
736
737   assert(rv == 0);
738
739   flow_control_ = true;
740
741   // TODO Maybe call from outside?
742   std::array<nghttp2_settings_entry, 2> entry;
743   entry[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
744   entry[0].value = get_config()->http2_max_concurrent_streams;
745
746   entry[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
747   entry[1].value = (1 << get_config()->http2_upstream_window_bits) - 1;
748
749   rv = nghttp2_submit_settings(session_, NGHTTP2_FLAG_NONE, entry.data(),
750                                entry.size());
751   if (rv != 0) {
752     ULOG(ERROR, this) << "nghttp2_submit_settings() returned error: "
753                       << nghttp2_strerror(rv);
754   }
755
756   if (get_config()->http2_upstream_connection_window_bits > 16) {
757     int32_t delta = (1 << get_config()->http2_upstream_connection_window_bits) -
758                     1 - NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE;
759     rv = nghttp2_submit_window_update(session_, NGHTTP2_FLAG_NONE, 0, delta);
760
761     if (rv != 0) {
762       ULOG(ERROR, this) << "nghttp2_submit_window_update() returned error: "
763                         << nghttp2_strerror(rv);
764     }
765   }
766
767   if (!get_config()->altsvcs.empty()) {
768     // Set max_age to 24hrs, which is default for alt-svc header
769     // field.
770     for (auto &altsvc : get_config()->altsvcs) {
771       rv = nghttp2_submit_altsvc(
772           session_, NGHTTP2_FLAG_NONE, 0, 86400, altsvc.port,
773           reinterpret_cast<const uint8_t *>(altsvc.protocol_id),
774           altsvc.protocol_id_len,
775           reinterpret_cast<const uint8_t *>(altsvc.host), altsvc.host_len,
776           reinterpret_cast<const uint8_t *>(altsvc.origin), altsvc.origin_len);
777
778       if (rv != 0) {
779         ULOG(ERROR, this) << "nghttp2_submit_altsvc() returned error: "
780                           << nghttp2_strerror(rv);
781       }
782     }
783   }
784
785   // We wait for SETTINGS ACK at least 10 seconds.
786   ev_timer_init(&settings_timer_, settings_timeout_cb, 10., 0.);
787
788   settings_timer_.data = this;
789
790   // timer for 2nd GOAWAY.  HTTP/2 spec recommend 1 RTT.  We wait for
791   // 2 seconds.
792   ev_timer_init(&shutdown_timer_, shutdown_timeout_cb, 2., 0);
793   shutdown_timer_.data = this;
794
795   ev_prepare_init(&prep_, prepare_cb);
796   prep_.data = this;
797   ev_prepare_start(handler_->get_loop(), &prep_);
798
799   handler_->reset_upstream_read_timeout(
800       get_config()->http2_upstream_read_timeout);
801
802   handler_->signal_write();
803 }
804
805 Http2Upstream::~Http2Upstream() {
806   nghttp2_session_del(session_);
807   ev_prepare_stop(handler_->get_loop(), &prep_);
808   ev_timer_stop(handler_->get_loop(), &shutdown_timer_);
809   ev_timer_stop(handler_->get_loop(), &settings_timer_);
810 }
811
812 int Http2Upstream::on_read() {
813   ssize_t rv = 0;
814   auto rb = handler_->get_rb();
815
816   if (rb->rleft()) {
817     rv = nghttp2_session_mem_recv(session_, rb->pos, rb->rleft());
818     if (rv < 0) {
819       if (rv != NGHTTP2_ERR_BAD_PREFACE) {
820         ULOG(ERROR, this) << "nghttp2_session_recv() returned error: "
821                           << nghttp2_strerror(rv);
822       }
823       return -1;
824     }
825
826     // nghttp2_session_mem_recv should consume all input bytes on
827     // success.
828     assert(static_cast<size_t>(rv) == rb->rleft());
829     rb->reset();
830   }
831
832   auto wb = handler_->get_wb();
833   if (nghttp2_session_want_read(session_) == 0 &&
834       nghttp2_session_want_write(session_) == 0 && wb->rleft() == 0) {
835     if (LOG_ENABLED(INFO)) {
836       ULOG(INFO, this) << "No more read/write for this HTTP2 session";
837     }
838     return -1;
839   }
840
841   handler_->signal_write();
842   return 0;
843 }
844
845 // After this function call, downstream may be deleted.
846 int Http2Upstream::on_write() {
847   auto wb = handler_->get_wb();
848
849   if (data_pending_) {
850     auto n = std::min(wb->wleft(), data_pendinglen_);
851     wb->write(data_pending_, n);
852     if (n < data_pendinglen_) {
853       data_pending_ += n;
854       data_pendinglen_ -= n;
855       return 0;
856     }
857
858     data_pending_ = nullptr;
859     data_pendinglen_ = 0;
860   }
861
862   for (;;) {
863     const uint8_t *data;
864     auto datalen = nghttp2_session_mem_send(session_, &data);
865
866     if (datalen < 0) {
867       ULOG(ERROR, this) << "nghttp2_session_mem_send() returned error: "
868                         << nghttp2_strerror(datalen);
869       return -1;
870     }
871     if (datalen == 0) {
872       break;
873     }
874     auto n = wb->write(data, datalen);
875     if (n < static_cast<decltype(n)>(datalen)) {
876       data_pending_ = data + n;
877       data_pendinglen_ = datalen - n;
878       return 0;
879     }
880   }
881
882   if (nghttp2_session_want_read(session_) == 0 &&
883       nghttp2_session_want_write(session_) == 0 && wb->rleft() == 0) {
884     if (LOG_ENABLED(INFO)) {
885       ULOG(INFO, this) << "No more read/write for this HTTP2 session";
886     }
887     return -1;
888   }
889
890   return 0;
891 }
892
893 ClientHandler *Http2Upstream::get_client_handler() const { return handler_; }
894
895 int Http2Upstream::downstream_read(DownstreamConnection *dconn) {
896   auto downstream = dconn->get_downstream();
897
898   if (downstream->get_request_state() == Downstream::STREAM_CLOSED) {
899     // If upstream HTTP2 stream was closed, we just close downstream,
900     // because there is no consumer now. Downstream connection is also
901     // closed in this case.
902     remove_downstream(downstream);
903     // downstream was deleted
904
905     return 0;
906   }
907
908   if (downstream->get_response_state() == Downstream::MSG_RESET) {
909     // The downstream stream was reset (canceled). In this case,
910     // RST_STREAM to the upstream and delete downstream connection
911     // here. Deleting downstream will be taken place at
912     // on_stream_close_callback.
913     rst_stream(downstream,
914                infer_upstream_rst_stream_error_code(
915                    downstream->get_response_rst_stream_error_code()));
916     downstream->pop_downstream_connection();
917     // dconn was deleted
918     dconn = nullptr;
919   } else if (downstream->get_response_state() == Downstream::MSG_BAD_HEADER) {
920     if (error_reply(downstream, 502) != 0) {
921       return -1;
922     }
923     downstream->pop_downstream_connection();
924     // dconn was deleted
925     dconn = nullptr;
926   } else {
927     auto rv = downstream->on_read();
928     if (rv == SHRPX_ERR_EOF) {
929       return downstream_eof(dconn);
930     }
931     if (rv != 0) {
932       if (rv != SHRPX_ERR_NETWORK) {
933         if (LOG_ENABLED(INFO)) {
934           DCLOG(INFO, dconn) << "HTTP parser failure";
935         }
936       }
937       return downstream_error(dconn, Downstream::EVENT_ERROR);
938     }
939     // Detach downstream connection early so that it could be reused
940     // without hitting server's request timeout.
941     if (downstream->get_response_state() == Downstream::MSG_COMPLETE &&
942         !downstream->get_response_connection_close()) {
943       // Keep-alive
944       downstream->detach_downstream_connection();
945     }
946   }
947
948   handler_->signal_write();
949
950   // At this point, downstream may be deleted.
951
952   return 0;
953 }
954
955 int Http2Upstream::downstream_write(DownstreamConnection *dconn) {
956   int rv;
957   rv = dconn->on_write();
958   if (rv == SHRPX_ERR_NETWORK) {
959     return downstream_error(dconn, Downstream::EVENT_ERROR);
960   }
961   if (rv != 0) {
962     return -1;
963   }
964   return 0;
965 }
966
967 int Http2Upstream::downstream_eof(DownstreamConnection *dconn) {
968   auto downstream = dconn->get_downstream();
969
970   if (LOG_ENABLED(INFO)) {
971     DCLOG(INFO, dconn) << "EOF. stream_id=" << downstream->get_stream_id();
972   }
973   if (downstream->get_request_state() == Downstream::STREAM_CLOSED) {
974     // If stream was closed already, we don't need to send reply at
975     // the first place. We can delete downstream.
976     remove_downstream(downstream);
977     // downstream was deleted
978
979     return 0;
980   }
981
982   // Delete downstream connection. If we don't delete it here, it will
983   // be pooled in on_stream_close_callback.
984   downstream->pop_downstream_connection();
985   // dconn was deleted
986   dconn = nullptr;
987   // downstream wil be deleted in on_stream_close_callback.
988   if (downstream->get_response_state() == Downstream::HEADER_COMPLETE) {
989     // Server may indicate the end of the request by EOF
990     if (LOG_ENABLED(INFO)) {
991       ULOG(INFO, this) << "Downstream body was ended by EOF";
992     }
993     downstream->set_response_state(Downstream::MSG_COMPLETE);
994
995     // For tunneled connection, MSG_COMPLETE signals
996     // downstream_data_read_callback to send RST_STREAM after pending
997     // response body is sent. This is needed to ensure that RST_STREAM
998     // is sent after all pending data are sent.
999     on_downstream_body_complete(downstream);
1000   } else if (downstream->get_response_state() != Downstream::MSG_COMPLETE) {
1001     // If stream was not closed, then we set MSG_COMPLETE and let
1002     // on_stream_close_callback delete downstream.
1003     if (error_reply(downstream, 502) != 0) {
1004       return -1;
1005     }
1006   }
1007   handler_->signal_write();
1008   // At this point, downstream may be deleted.
1009   return 0;
1010 }
1011
1012 int Http2Upstream::downstream_error(DownstreamConnection *dconn, int events) {
1013   auto downstream = dconn->get_downstream();
1014
1015   if (LOG_ENABLED(INFO)) {
1016     if (events & Downstream::EVENT_ERROR) {
1017       DCLOG(INFO, dconn) << "Downstream network/general error";
1018     } else {
1019       DCLOG(INFO, dconn) << "Timeout";
1020     }
1021     if (downstream->get_upgraded()) {
1022       DCLOG(INFO, dconn) << "Note: this is tunnel connection";
1023     }
1024   }
1025
1026   if (downstream->get_request_state() == Downstream::STREAM_CLOSED) {
1027     remove_downstream(downstream);
1028     // downstream was deleted
1029
1030     return 0;
1031   }
1032
1033   // Delete downstream connection. If we don't delete it here, it will
1034   // be pooled in on_stream_close_callback.
1035   downstream->pop_downstream_connection();
1036   // dconn was deleted
1037   dconn = nullptr;
1038
1039   if (downstream->get_response_state() == Downstream::MSG_COMPLETE) {
1040     // For SSL tunneling, we issue RST_STREAM. For other types of
1041     // stream, we don't have to do anything since response was
1042     // complete.
1043     if (downstream->get_upgraded()) {
1044       rst_stream(downstream, NGHTTP2_NO_ERROR);
1045     }
1046   } else {
1047     if (downstream->get_response_state() == Downstream::HEADER_COMPLETE) {
1048       if (downstream->get_upgraded()) {
1049         on_downstream_body_complete(downstream);
1050       } else {
1051         rst_stream(downstream, NGHTTP2_INTERNAL_ERROR);
1052       }
1053     } else {
1054       unsigned int status;
1055       if (events & Downstream::EVENT_TIMEOUT) {
1056         status = 504;
1057       } else {
1058         status = 502;
1059       }
1060       if (error_reply(downstream, status) != 0) {
1061         return -1;
1062       }
1063     }
1064     downstream->set_response_state(Downstream::MSG_COMPLETE);
1065   }
1066   handler_->signal_write();
1067   // At this point, downstream may be deleted.
1068   return 0;
1069 }
1070
1071 int Http2Upstream::rst_stream(Downstream *downstream, uint32_t error_code) {
1072   if (LOG_ENABLED(INFO)) {
1073     ULOG(INFO, this) << "RST_STREAM stream_id=" << downstream->get_stream_id()
1074                      << " with error_code=" << error_code;
1075   }
1076   int rv;
1077   rv = nghttp2_submit_rst_stream(session_, NGHTTP2_FLAG_NONE,
1078                                  downstream->get_stream_id(), error_code);
1079   if (rv < NGHTTP2_ERR_FATAL) {
1080     ULOG(FATAL, this) << "nghttp2_submit_rst_stream() failed: "
1081                       << nghttp2_strerror(rv);
1082     DIE();
1083   }
1084   return 0;
1085 }
1086
1087 int Http2Upstream::terminate_session(uint32_t error_code) {
1088   int rv;
1089   rv = nghttp2_session_terminate_session(session_, error_code);
1090   if (rv != 0) {
1091     return -1;
1092   }
1093   return 0;
1094 }
1095
1096 namespace {
1097 ssize_t downstream_data_read_callback(nghttp2_session *session,
1098                                       int32_t stream_id, uint8_t *buf,
1099                                       size_t length, uint32_t *data_flags,
1100                                       nghttp2_data_source *source,
1101                                       void *user_data) {
1102   auto downstream = static_cast<Downstream *>(source->ptr);
1103   auto upstream = static_cast<Http2Upstream *>(downstream->get_upstream());
1104   auto body = downstream->get_response_buf();
1105   assert(body);
1106
1107   auto dconn = downstream->get_downstream_connection();
1108
1109   if (body->rleft() == 0 && dconn &&
1110       downstream->get_response_state() != Downstream::MSG_COMPLETE) {
1111     // Try to read more if buffer is empty.  This will help small
1112     // buffer and make priority handling a bit better.
1113     if (upstream->downstream_read(dconn) != 0) {
1114       return NGHTTP2_ERR_CALLBACK_FAILURE;
1115     }
1116   }
1117
1118   auto nread = body->remove(buf, length);
1119   auto body_empty = body->rleft() == 0;
1120
1121   if (body_empty &&
1122       downstream->get_response_state() == Downstream::MSG_COMPLETE) {
1123
1124     *data_flags |= NGHTTP2_DATA_FLAG_EOF;
1125
1126     if (!downstream->get_upgraded()) {
1127
1128       if (nghttp2_session_get_stream_remote_close(session, stream_id) == 0) {
1129         upstream->rst_stream(downstream, NGHTTP2_NO_ERROR);
1130       }
1131     } else {
1132       // For tunneling, issue RST_STREAM to finish the stream.
1133       if (LOG_ENABLED(INFO)) {
1134         ULOG(INFO, upstream)
1135             << "RST_STREAM to tunneled stream stream_id=" << stream_id;
1136       }
1137       upstream->rst_stream(downstream, NGHTTP2_NO_ERROR);
1138     }
1139   }
1140
1141   if (body_empty) {
1142     downstream->disable_upstream_wtimer();
1143   } else {
1144     downstream->reset_upstream_wtimer();
1145   }
1146
1147   if (nread > 0 && downstream->resume_read(SHRPX_NO_BUFFER, nread) != 0) {
1148     return NGHTTP2_ERR_CALLBACK_FAILURE;
1149   }
1150
1151   if (nread == 0 && ((*data_flags) & NGHTTP2_DATA_FLAG_EOF) == 0) {
1152     return NGHTTP2_ERR_DEFERRED;
1153   }
1154
1155   if (nread > 0) {
1156     downstream->add_response_sent_bodylen(nread);
1157   }
1158
1159   return nread;
1160 }
1161 } // namespace
1162
1163 int Http2Upstream::error_reply(Downstream *downstream,
1164                                unsigned int status_code) {
1165   int rv;
1166   auto html = http::create_error_html(status_code);
1167   downstream->set_response_http_status(status_code);
1168   auto body = downstream->get_response_buf();
1169   body->append(html.c_str(), html.size());
1170   downstream->set_response_state(Downstream::MSG_COMPLETE);
1171
1172   nghttp2_data_provider data_prd;
1173   data_prd.source.ptr = downstream;
1174   data_prd.read_callback = downstream_data_read_callback;
1175
1176   auto content_length = util::utos(html.size());
1177   auto status_code_str = util::utos(status_code);
1178   auto nva =
1179       make_array(http2::make_nv_ls(":status", status_code_str),
1180                  http2::make_nv_ll("content-type", "text/html; charset=UTF-8"),
1181                  http2::make_nv_lc("server", get_config()->server_name),
1182                  http2::make_nv_ls("content-length", content_length));
1183
1184   rv = nghttp2_submit_response(session_, downstream->get_stream_id(),
1185                                nva.data(), nva.size(), &data_prd);
1186   if (rv < NGHTTP2_ERR_FATAL) {
1187     ULOG(FATAL, this) << "nghttp2_submit_response() failed: "
1188                       << nghttp2_strerror(rv);
1189     return -1;
1190   }
1191
1192   return 0;
1193 }
1194
1195 void
1196 Http2Upstream::add_pending_downstream(std::unique_ptr<Downstream> downstream) {
1197   downstream_queue_.add_pending(std::move(downstream));
1198 }
1199
1200 void Http2Upstream::remove_downstream(Downstream *downstream) {
1201   if (downstream->accesslog_ready()) {
1202     handler_->write_accesslog(downstream);
1203   }
1204
1205   auto next_downstream =
1206       downstream_queue_.remove_and_pop_blocked(downstream->get_stream_id());
1207
1208   if (next_downstream) {
1209     initiate_downstream(std::move(next_downstream));
1210   }
1211 }
1212
1213 Downstream *Http2Upstream::find_downstream(int32_t stream_id) {
1214   return downstream_queue_.find(stream_id);
1215 }
1216
1217 nghttp2_session *Http2Upstream::get_http2_session() { return session_; }
1218
1219 // WARNING: Never call directly or indirectly nghttp2_session_send or
1220 // nghttp2_session_recv. These calls may delete downstream.
1221 int Http2Upstream::on_downstream_header_complete(Downstream *downstream) {
1222   int rv;
1223
1224   if (LOG_ENABLED(INFO)) {
1225     if (downstream->get_non_final_response()) {
1226       DLOG(INFO, downstream) << "HTTP non-final response header";
1227     } else {
1228       DLOG(INFO, downstream) << "HTTP response header completed";
1229     }
1230   }
1231
1232   if (!get_config()->http2_proxy && !get_config()->client_proxy &&
1233       !get_config()->no_location_rewrite) {
1234     downstream->rewrite_location_response_header(
1235         downstream->get_request_http2_scheme());
1236   }
1237
1238   size_t nheader = downstream->get_response_headers().size();
1239   auto nva = std::vector<nghttp2_nv>();
1240   // 3 means :status and possible server and via header field.
1241   nva.reserve(nheader + 3 + get_config()->add_response_headers.size());
1242   std::string via_value;
1243   auto response_status = util::utos(downstream->get_response_http_status());
1244   nva.push_back(http2::make_nv_ls(":status", response_status));
1245
1246   http2::copy_headers_to_nva(nva, downstream->get_response_headers());
1247
1248   if (downstream->get_non_final_response()) {
1249     if (LOG_ENABLED(INFO)) {
1250       log_response_headers(downstream, nva);
1251     }
1252
1253     rv = nghttp2_submit_headers(session_, NGHTTP2_FLAG_NONE,
1254                                 downstream->get_stream_id(), nullptr,
1255                                 nva.data(), nva.size(), nullptr);
1256
1257     downstream->clear_response_headers();
1258
1259     if (rv != 0) {
1260       ULOG(FATAL, this) << "nghttp2_submit_headers() failed";
1261       return -1;
1262     }
1263
1264     return 0;
1265   }
1266
1267   if (!get_config()->http2_proxy && !get_config()->client_proxy) {
1268     nva.push_back(http2::make_nv_lc("server", get_config()->server_name));
1269   } else {
1270     auto server = downstream->get_response_header(http2::HD_SERVER);
1271     if (server) {
1272       nva.push_back(http2::make_nv_ls("server", (*server).value));
1273     }
1274   }
1275
1276   auto via = downstream->get_response_header(http2::HD_VIA);
1277   if (get_config()->no_via) {
1278     if (via) {
1279       nva.push_back(http2::make_nv_ls("via", (*via).value));
1280     }
1281   } else {
1282     if (via) {
1283       via_value = (*via).value;
1284       via_value += ", ";
1285     }
1286     via_value += http::create_via_header_value(
1287         downstream->get_response_major(), downstream->get_response_minor());
1288     nva.push_back(http2::make_nv_ls("via", via_value));
1289   }
1290
1291   for (auto &p : get_config()->add_response_headers) {
1292     nva.push_back(http2::make_nv(p.first, p.second));
1293   }
1294
1295   if (LOG_ENABLED(INFO)) {
1296     log_response_headers(downstream, nva);
1297   }
1298
1299   if (get_config()->http2_upstream_dump_response_header) {
1300     http2::dump_nv(get_config()->http2_upstream_dump_response_header,
1301                    nva.data(), nva.size());
1302   }
1303
1304   nghttp2_data_provider data_prd;
1305   data_prd.source.ptr = downstream;
1306   data_prd.read_callback = downstream_data_read_callback;
1307
1308   nghttp2_data_provider *data_prdptr;
1309
1310   if (downstream->expect_response_body()) {
1311     data_prdptr = &data_prd;
1312   } else {
1313     data_prdptr = nullptr;
1314   }
1315
1316   rv = nghttp2_submit_response(session_, downstream->get_stream_id(),
1317                                nva.data(), nva.size(), data_prdptr);
1318   if (rv != 0) {
1319     ULOG(FATAL, this) << "nghttp2_submit_response() failed";
1320     return -1;
1321   }
1322
1323   // We need some conditions that must be fulfilled to initiate server
1324   // push.
1325   //
1326   // * Server push is disabled for http2 proxy, since incoming headers
1327   //   are mixed origins.  We don't know how to reliably determine the
1328   //   authority yet.
1329   //
1330   // * If downstream is http/2, it is likely that PUSH_PROMISE is
1331   //   coming from there, so we don't initiate PUSH_RPOMISE here.
1332   //
1333   // * We need 200 response code for associated resource.  This is too
1334   //   restrictive, we will review this later.
1335   //
1336   // * We requires GET or POST for associated resource.  Probably we
1337   //   don't want to push for HEAD request.  Not sure other methods
1338   //   are also eligible for push.
1339   if (!get_config()->no_server_push &&
1340       get_config()->downstream_proto == PROTO_HTTP &&
1341       !get_config()->http2_proxy && (downstream->get_stream_id() % 2) &&
1342       downstream->get_response_header(http2::HD_LINK) &&
1343       downstream->get_response_http_status() == 200 &&
1344       (downstream->get_request_method() == "GET" ||
1345        downstream->get_request_method() == "POST")) {
1346
1347     if (prepare_push_promise(downstream) != 0) {
1348       return -1;
1349     }
1350   }
1351
1352   return 0;
1353 }
1354
1355 // WARNING: Never call directly or indirectly nghttp2_session_send or
1356 // nghttp2_session_recv. These calls may delete downstream.
1357 int Http2Upstream::on_downstream_body(Downstream *downstream,
1358                                       const uint8_t *data, size_t len,
1359                                       bool flush) {
1360   auto body = downstream->get_response_buf();
1361   body->append(data, len);
1362
1363   if (flush) {
1364     nghttp2_session_resume_data(session_, downstream->get_stream_id());
1365
1366     downstream->ensure_upstream_wtimer();
1367   }
1368
1369   return 0;
1370 }
1371
1372 // WARNING: Never call directly or indirectly nghttp2_session_send or
1373 // nghttp2_session_recv. These calls may delete downstream.
1374 int Http2Upstream::on_downstream_body_complete(Downstream *downstream) {
1375   if (LOG_ENABLED(INFO)) {
1376     DLOG(INFO, downstream) << "HTTP response completed";
1377   }
1378
1379   if (!downstream->validate_response_bodylen()) {
1380     rst_stream(downstream, NGHTTP2_PROTOCOL_ERROR);
1381     downstream->set_response_connection_close(true);
1382     return 0;
1383   }
1384
1385   nghttp2_session_resume_data(session_, downstream->get_stream_id());
1386   downstream->ensure_upstream_wtimer();
1387
1388   return 0;
1389 }
1390
1391 bool Http2Upstream::get_flow_control() const { return flow_control_; }
1392
1393 void Http2Upstream::pause_read(IOCtrlReason reason) {}
1394
1395 int Http2Upstream::resume_read(IOCtrlReason reason, Downstream *downstream,
1396                                size_t consumed) {
1397   if (get_flow_control()) {
1398     assert(downstream->get_request_datalen() >= consumed);
1399
1400     if (consume(downstream->get_stream_id(), consumed) != 0) {
1401       return -1;
1402     }
1403
1404     downstream->dec_request_datalen(consumed);
1405   }
1406
1407   handler_->signal_write();
1408   return 0;
1409 }
1410
1411 int Http2Upstream::on_downstream_abort_request(Downstream *downstream,
1412                                                unsigned int status_code) {
1413   int rv;
1414
1415   rv = error_reply(downstream, status_code);
1416
1417   if (rv != 0) {
1418     return -1;
1419   }
1420
1421   handler_->signal_write();
1422   return 0;
1423 }
1424
1425 int Http2Upstream::consume(int32_t stream_id, size_t len) {
1426   int rv;
1427
1428   rv = nghttp2_session_consume(session_, stream_id, len);
1429
1430   if (rv != 0) {
1431     ULOG(WARN, this) << "nghttp2_session_consume() returned error: "
1432                      << nghttp2_strerror(rv);
1433     return -1;
1434   }
1435
1436   return 0;
1437 }
1438
1439 void
1440 Http2Upstream::log_response_headers(Downstream *downstream,
1441                                     const std::vector<nghttp2_nv> &nva) const {
1442   std::stringstream ss;
1443   for (auto &nv : nva) {
1444     ss << TTY_HTTP_HD;
1445     ss.write(reinterpret_cast<const char *>(nv.name), nv.namelen);
1446     ss << TTY_RST << ": ";
1447     ss.write(reinterpret_cast<const char *>(nv.value), nv.valuelen);
1448     ss << "\n";
1449   }
1450   ULOG(INFO, this) << "HTTP response headers. stream_id="
1451                    << downstream->get_stream_id() << "\n" << ss.str();
1452 }
1453
1454 int Http2Upstream::on_timeout(Downstream *downstream) {
1455   if (LOG_ENABLED(INFO)) {
1456     ULOG(INFO, this) << "Stream timeout stream_id="
1457                      << downstream->get_stream_id();
1458   }
1459
1460   rst_stream(downstream, NGHTTP2_NO_ERROR);
1461
1462   return 0;
1463 }
1464
1465 void Http2Upstream::on_handler_delete() {
1466   for (auto &ent : downstream_queue_.get_active_downstreams()) {
1467     if (ent.second->accesslog_ready()) {
1468       handler_->write_accesslog(ent.second.get());
1469     }
1470   }
1471 }
1472
1473 int Http2Upstream::on_downstream_reset(bool no_retry) {
1474   int rv;
1475
1476   for (auto &ent : downstream_queue_.get_active_downstreams()) {
1477     auto downstream = ent.second.get();
1478     if ((downstream->get_request_state() != Downstream::HEADER_COMPLETE &&
1479          downstream->get_request_state() != Downstream::MSG_COMPLETE) ||
1480         downstream->get_response_state() != Downstream::INITIAL) {
1481       rst_stream(downstream, NGHTTP2_INTERNAL_ERROR);
1482       downstream->pop_downstream_connection();
1483       continue;
1484     }
1485
1486     downstream->pop_downstream_connection();
1487
1488     downstream->add_retry();
1489
1490     if (no_retry || downstream->no_more_retry()) {
1491       if (on_downstream_abort_request(downstream, 503) != 0) {
1492         return -1;
1493       }
1494       continue;
1495     }
1496
1497     // downstream connection is clean; we can retry with new
1498     // downstream connection.
1499
1500     rv = downstream->attach_downstream_connection(
1501         handler_->get_downstream_connection());
1502     if (rv != 0) {
1503       rst_stream(downstream, NGHTTP2_INTERNAL_ERROR);
1504       downstream->pop_downstream_connection();
1505       continue;
1506     }
1507   }
1508
1509   handler_->signal_write();
1510
1511   return 0;
1512 }
1513
1514 MemchunkPool *Http2Upstream::get_mcpool() { return &mcpool_; }
1515
1516 int Http2Upstream::prepare_push_promise(Downstream *downstream) {
1517   int rv;
1518   http_parser_url u;
1519   memset(&u, 0, sizeof(u));
1520   rv = http_parser_parse_url(downstream->get_request_path().c_str(),
1521                              downstream->get_request_path().size(), 0, &u);
1522   if (rv != 0) {
1523     return 0;
1524   }
1525   const char *base;
1526   size_t baselen;
1527   if (u.field_set & (1 << UF_PATH)) {
1528     auto &f = u.field_data[UF_PATH];
1529     base = downstream->get_request_path().c_str() + f.off;
1530     baselen = f.len;
1531   } else {
1532     base = "/";
1533     baselen = 1;
1534   }
1535   for (auto &kv : downstream->get_response_headers()) {
1536     if (kv.token != http2::HD_LINK) {
1537       continue;
1538     }
1539     for (auto &link :
1540          http2::parse_link_header(kv.value.c_str(), kv.value.size())) {
1541       auto link_url = link.uri.first;
1542       auto link_urllen = link.uri.second - link.uri.first;
1543
1544       const char *rel;
1545       size_t rellen;
1546       const char *relq = nullptr;
1547       size_t relqlen = 0;
1548
1549       http_parser_url v;
1550       memset(&v, 0, sizeof(v));
1551       rv = http_parser_parse_url(link_url, link_urllen, 0, &v);
1552       if (rv != 0) {
1553         assert(link_urllen);
1554         if (link_url[0] == '/') {
1555           continue;
1556         }
1557         // treat link_url as relative URI.
1558         auto end = std::find(link_url, link_url + link_urllen, '#');
1559         auto q = std::find(link_url, end, '?');
1560         rel = link_url;
1561         rellen = q - link_url;
1562         if (q != end) {
1563           relq = q + 1;
1564           relqlen = end - relq;
1565         }
1566       } else {
1567         if (v.field_set & (1 << UF_HOST)) {
1568           continue;
1569         }
1570         if (v.field_set & (1 << UF_PATH)) {
1571           auto &f = v.field_data[UF_PATH];
1572           rel = link_url + f.off;
1573           rellen = f.len;
1574         } else {
1575           rel = "/";
1576           rellen = 1;
1577         }
1578
1579         if (v.field_set & (1 << UF_QUERY)) {
1580           auto &f = v.field_data[UF_QUERY];
1581           relq = link_url + f.off;
1582           relqlen = f.len;
1583         }
1584       }
1585       auto path = http2::path_join(base, baselen, nullptr, 0, rel, rellen, relq,
1586                                    relqlen);
1587       rv = submit_push_promise(path, downstream);
1588       if (rv != 0) {
1589         return -1;
1590       }
1591     }
1592   }
1593   return 0;
1594 }
1595
1596 int Http2Upstream::submit_push_promise(const std::string &path,
1597                                        Downstream *downstream) {
1598   int rv;
1599   std::vector<nghttp2_nv> nva;
1600   nva.reserve(downstream->get_request_headers().size());
1601   for (auto &kv : downstream->get_request_headers()) {
1602     switch (kv.token) {
1603     // TODO generate referer
1604     case http2::HD__AUTHORITY:
1605     case http2::HD__SCHEME:
1606     case http2::HD_ACCEPT_ENCODING:
1607     case http2::HD_ACCEPT_LANGUAGE:
1608     case http2::HD_CACHE_CONTROL:
1609     case http2::HD_HOST:
1610     case http2::HD_USER_AGENT:
1611       nva.push_back(http2::make_nv(kv.name, kv.value, kv.no_index));
1612       break;
1613     case http2::HD__METHOD:
1614       // juse use "GET" for now
1615       nva.push_back(http2::make_nv_lc(":method", "GET"));
1616       continue;
1617     case http2::HD__PATH:
1618       nva.push_back(http2::make_nv_ls(":path", path));
1619       continue;
1620     }
1621   }
1622
1623   rv = nghttp2_submit_push_promise(session_, NGHTTP2_FLAG_NONE,
1624                                    downstream->get_stream_id(), nva.data(),
1625                                    nva.size(), nullptr);
1626
1627   if (rv < 0) {
1628     if (LOG_ENABLED(INFO)) {
1629       ULOG(INFO, this) << "nghttp2_submit_push_promise() failed: "
1630                        << nghttp2_strerror(rv);
1631     }
1632     if (nghttp2_is_fatal(rv)) {
1633       return -1;
1634     }
1635     return 0;
1636   }
1637
1638   if (LOG_ENABLED(INFO)) {
1639     std::stringstream ss;
1640     for (auto &nv : nva) {
1641       ss << TTY_HTTP_HD << nv.name << TTY_RST << ": " << nv.value << "\n";
1642     }
1643     ULOG(INFO, this) << "HTTP push request headers. promised_stream_id=" << rv
1644                      << "\n" << ss.str();
1645   }
1646
1647   return 0;
1648 }
1649
1650 } // namespace shrpx