tizen 2.4 release
[external/nghttp2.git] / src / shrpx_http2_downstream_connection.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_downstream_connection.h"
26
27 #include <unistd.h>
28
29 #include "http-parser/http_parser.h"
30
31 #include "shrpx_client_handler.h"
32 #include "shrpx_upstream.h"
33 #include "shrpx_downstream.h"
34 #include "shrpx_config.h"
35 #include "shrpx_error.h"
36 #include "shrpx_http.h"
37 #include "shrpx_http2_session.h"
38 #include "shrpx_worker_config.h"
39 #include "http2.h"
40 #include "util.h"
41
42 using namespace nghttp2;
43
44 namespace shrpx {
45
46 Http2DownstreamConnection::Http2DownstreamConnection(
47     DownstreamConnectionPool *dconn_pool, Http2Session *http2session)
48     : DownstreamConnection(dconn_pool), http2session_(http2session),
49       sd_(nullptr) {}
50
51 Http2DownstreamConnection::~Http2DownstreamConnection() {
52   if (LOG_ENABLED(INFO)) {
53     DCLOG(INFO, this) << "Deleting";
54   }
55   if (downstream_) {
56     downstream_->disable_downstream_rtimer();
57     downstream_->disable_downstream_wtimer();
58
59     uint32_t error_code;
60     if (downstream_->get_request_state() == Downstream::STREAM_CLOSED &&
61         downstream_->get_upgraded()) {
62       // For upgraded connection, send NO_ERROR.  Should we consider
63       // request states other than Downstream::STREAM_CLOSED ?
64       error_code = NGHTTP2_NO_ERROR;
65     } else {
66       error_code = NGHTTP2_INTERNAL_ERROR;
67     }
68
69     if (downstream_->get_downstream_stream_id() != -1) {
70       if (LOG_ENABLED(INFO)) {
71         DCLOG(INFO, this) << "Submit RST_STREAM for DOWNSTREAM:" << downstream_
72                           << ", stream_id="
73                           << downstream_->get_downstream_stream_id()
74                           << ", error_code=" << error_code;
75       }
76
77       submit_rst_stream(downstream_, error_code);
78
79       http2session_->consume(downstream_->get_downstream_stream_id(),
80                              downstream_->get_response_datalen());
81
82       downstream_->reset_response_datalen();
83
84       http2session_->signal_write();
85     }
86   }
87   http2session_->remove_downstream_connection(this);
88   // Downstream and DownstreamConnection may be deleted
89   // asynchronously.
90   if (downstream_) {
91     downstream_->release_downstream_connection();
92   }
93   if (LOG_ENABLED(INFO)) {
94     DCLOG(INFO, this) << "Deleted";
95   }
96 }
97
98 int Http2DownstreamConnection::attach_downstream(Downstream *downstream) {
99   if (LOG_ENABLED(INFO)) {
100     DCLOG(INFO, this) << "Attaching to DOWNSTREAM:" << downstream;
101   }
102   http2session_->add_downstream_connection(this);
103   if (http2session_->get_state() == Http2Session::DISCONNECTED) {
104     http2session_->signal_write();
105   }
106
107   downstream_ = downstream;
108   downstream_->reset_downstream_rtimer();
109
110   return 0;
111 }
112
113 void Http2DownstreamConnection::detach_downstream(Downstream *downstream) {
114   if (LOG_ENABLED(INFO)) {
115     DCLOG(INFO, this) << "Detaching from DOWNSTREAM:" << downstream;
116   }
117   if (submit_rst_stream(downstream) == 0) {
118     http2session_->signal_write();
119   }
120
121   if (downstream_->get_downstream_stream_id() != -1) {
122     http2session_->consume(downstream_->get_downstream_stream_id(),
123                            downstream_->get_response_datalen());
124
125     downstream_->reset_response_datalen();
126
127     http2session_->signal_write();
128   }
129
130   downstream->disable_downstream_rtimer();
131   downstream->disable_downstream_wtimer();
132   downstream_ = nullptr;
133 }
134
135 int Http2DownstreamConnection::submit_rst_stream(Downstream *downstream,
136                                                  uint32_t error_code) {
137   int rv = -1;
138   if (http2session_->get_state() == Http2Session::CONNECTED &&
139       downstream->get_downstream_stream_id() != -1) {
140     switch (downstream->get_response_state()) {
141     case Downstream::MSG_RESET:
142     case Downstream::MSG_BAD_HEADER:
143     case Downstream::MSG_COMPLETE:
144       break;
145     default:
146       if (LOG_ENABLED(INFO)) {
147         DCLOG(INFO, this) << "Submit RST_STREAM for DOWNSTREAM:" << downstream
148                           << ", stream_id="
149                           << downstream->get_downstream_stream_id();
150       }
151       rv = http2session_->submit_rst_stream(
152           downstream->get_downstream_stream_id(), error_code);
153     }
154   }
155   return rv;
156 }
157
158 namespace {
159 ssize_t http2_data_read_callback(nghttp2_session *session, int32_t stream_id,
160                                  uint8_t *buf, size_t length,
161                                  uint32_t *data_flags,
162                                  nghttp2_data_source *source, void *user_data) {
163   auto sd = static_cast<StreamData *>(
164       nghttp2_session_get_stream_user_data(session, stream_id));
165   if (!sd || !sd->dconn) {
166     return NGHTTP2_ERR_DEFERRED;
167   }
168   auto dconn = static_cast<Http2DownstreamConnection *>(source->ptr);
169   auto downstream = dconn->get_downstream();
170   if (!downstream) {
171     // In this case, RST_STREAM should have been issued. But depending
172     // on the priority, DATA frame may come first.
173     return NGHTTP2_ERR_DEFERRED;
174   }
175   auto input = downstream->get_request_buf();
176   auto nread = input->remove(buf, length);
177   auto input_empty = input->rleft() == 0;
178
179   if (nread > 0) {
180     // This is important because it will handle flow control
181     // stuff.
182     if (downstream->get_upstream()->resume_read(SHRPX_NO_BUFFER, downstream,
183                                                 nread) != 0) {
184       // In this case, downstream may be deleted.
185       return NGHTTP2_ERR_CALLBACK_FAILURE;
186     }
187
188     // Check dconn is still alive because Upstream::resume_read()
189     // may delete downstream which will delete dconn.
190     if (sd->dconn == nullptr) {
191       return NGHTTP2_ERR_DEFERRED;
192     }
193   }
194
195   if (input_empty &&
196       downstream->get_request_state() == Downstream::MSG_COMPLETE &&
197       // If connection is upgraded, don't set EOF flag, since HTTP/1
198       // will set MSG_COMPLETE to request state after upgrade response
199       // header is seen.
200       (!downstream->get_upgrade_request() ||
201        (downstream->get_response_state() == Downstream::HEADER_COMPLETE &&
202         !downstream->get_upgraded()))) {
203
204     *data_flags |= NGHTTP2_DATA_FLAG_EOF;
205   }
206
207   if (!input_empty) {
208     downstream->reset_downstream_wtimer();
209   } else {
210     downstream->disable_downstream_wtimer();
211   }
212
213   if (nread == 0 && (*data_flags & NGHTTP2_DATA_FLAG_EOF) == 0) {
214     downstream->disable_downstream_wtimer();
215
216     return NGHTTP2_ERR_DEFERRED;
217   }
218
219   return nread;
220 }
221 } // namespace
222
223 int Http2DownstreamConnection::push_request_headers() {
224   int rv;
225   if (!http2session_->can_push_request()) {
226     // The HTTP2 session to the backend has not been established or
227     // connection is now being checked.  This function will be called
228     // again just after it is established.
229     http2session_->start_checking_connection();
230     return 0;
231   }
232   if (!downstream_) {
233     return 0;
234   }
235
236   const char *authority = nullptr, *host = nullptr;
237   if (!get_config()->no_host_rewrite && !get_config()->http2_proxy &&
238       !get_config()->client_proxy) {
239     // HTTP/2 backend does not support multiple address, so we always
240     // use index = 0.
241     if (!downstream_->get_request_http2_authority().empty()) {
242       authority = get_config()->downstream_addrs[0].hostport.get();
243     }
244     if (downstream_->get_request_header(http2::HD_HOST)) {
245       host = get_config()->downstream_addrs[0].hostport.get();
246     }
247   } else {
248     if (!downstream_->get_request_http2_authority().empty()) {
249       authority = downstream_->get_request_http2_authority().c_str();
250     }
251     auto h = downstream_->get_request_header(http2::HD_HOST);
252     if (h) {
253       host = h->value.c_str();
254     }
255   }
256
257   if (!authority && !host) {
258     // upstream is HTTP/1.0.  We use backend server's host
259     // nonetheless.
260     host = get_config()->downstream_addrs[0].hostport.get();
261   }
262
263   if (authority) {
264     downstream_->set_request_downstream_host(authority);
265   } else {
266     downstream_->set_request_downstream_host(host);
267   }
268
269   size_t nheader = downstream_->get_request_headers().size();
270
271   Headers cookies;
272   if (!get_config()->http2_no_cookie_crumbling) {
273     cookies = downstream_->crumble_request_cookie();
274   }
275
276   // 8 means:
277   // 1. :method
278   // 2. :scheme
279   // 3. :path
280   // 4. :authority (at least either :authority or host exists)
281   // 5. host
282   // 6. via (optional)
283   // 7. x-forwarded-for (optional)
284   // 8. x-forwarded-proto (optional)
285   auto nva = std::vector<nghttp2_nv>();
286   nva.reserve(nheader + 8 + cookies.size());
287
288   std::string via_value;
289   std::string xff_value;
290   std::string scheme, uri_authority, path, query;
291
292   // To reconstruct HTTP/1 status line and headers, proxy should
293   // preserve host header field. See draft-09 section 8.1.3.1.
294   if (downstream_->get_request_method() == "CONNECT") {
295     // The upstream may be HTTP/2 or HTTP/1
296     if (authority) {
297       nva.push_back(http2::make_nv_lc(":authority", authority));
298     } else {
299       nva.push_back(
300           http2::make_nv_ls(":authority", downstream_->get_request_path()));
301     }
302   } else if (!downstream_->get_request_http2_scheme().empty()) {
303     // Here the upstream is HTTP/2
304     nva.push_back(
305         http2::make_nv_ls(":scheme", downstream_->get_request_http2_scheme()));
306     nva.push_back(http2::make_nv_ls(":path", downstream_->get_request_path()));
307     if (authority) {
308       nva.push_back(http2::make_nv_lc(":authority", authority));
309     }
310   } else {
311     // The upstream is HTTP/1
312     http_parser_url u;
313     const char *url = downstream_->get_request_path().c_str();
314     memset(&u, 0, sizeof(u));
315     rv = http_parser_parse_url(url, downstream_->get_request_path().size(), 0,
316                                &u);
317     if (rv == 0) {
318       http2::copy_url_component(scheme, &u, UF_SCHEMA, url);
319       http2::copy_url_component(uri_authority, &u, UF_HOST, url);
320       http2::copy_url_component(path, &u, UF_PATH, url);
321       http2::copy_url_component(query, &u, UF_QUERY, url);
322       if (path.empty()) {
323         if (!uri_authority.empty() &&
324             downstream_->get_request_method() == "OPTIONS") {
325           path = "*";
326         } else {
327           path = "/";
328         }
329       }
330       if (!query.empty()) {
331         path += "?";
332         path += query;
333       }
334     }
335     if (scheme.empty()) {
336       if (client_handler_->get_ssl()) {
337         nva.push_back(http2::make_nv_ll(":scheme", "https"));
338       } else {
339         nva.push_back(http2::make_nv_ll(":scheme", "http"));
340       }
341     } else {
342       nva.push_back(http2::make_nv_ls(":scheme", scheme));
343     }
344     if (path.empty()) {
345       nva.push_back(
346           http2::make_nv_ls(":path", downstream_->get_request_path()));
347     } else {
348       nva.push_back(http2::make_nv_ls(":path", path));
349     }
350
351     if (!get_config()->no_host_rewrite && !get_config()->http2_proxy &&
352         !get_config()->client_proxy) {
353       if (authority) {
354         nva.push_back(http2::make_nv_lc(":authority", authority));
355       }
356     } else if (!uri_authority.empty()) {
357       // TODO properly check IPv6 numeric address
358       if (uri_authority.find(":") != std::string::npos) {
359         uri_authority = "[" + uri_authority;
360         uri_authority += "]";
361       }
362       if (u.field_set & (1 << UF_PORT)) {
363         uri_authority += ":";
364         uri_authority += util::utos(u.port);
365       }
366       nva.push_back(http2::make_nv_ls(":authority", uri_authority));
367     }
368   }
369
370   nva.push_back(
371       http2::make_nv_ls(":method", downstream_->get_request_method()));
372
373   if (host) {
374     nva.push_back(http2::make_nv_lc("host", host));
375   }
376
377   http2::copy_headers_to_nva(nva, downstream_->get_request_headers());
378
379   bool chunked_encoding = false;
380   auto transfer_encoding =
381       downstream_->get_request_header(http2::HD_TRANSFER_ENCODING);
382   if (transfer_encoding &&
383       util::strieq((*transfer_encoding).value.c_str(), "chunked")) {
384     chunked_encoding = true;
385   }
386
387   for (auto &nv : cookies) {
388     nva.push_back(http2::make_nv(nv.name, nv.value, nv.no_index));
389   }
390
391   auto xff = downstream_->get_request_header(http2::HD_X_FORWARDED_FOR);
392   if (get_config()->add_x_forwarded_for) {
393     if (xff && !get_config()->strip_incoming_x_forwarded_for) {
394       xff_value = (*xff).value;
395       xff_value += ", ";
396     }
397     xff_value +=
398         downstream_->get_upstream()->get_client_handler()->get_ipaddr();
399     nva.push_back(http2::make_nv_ls("x-forwarded-for", xff_value));
400   } else if (xff && !get_config()->strip_incoming_x_forwarded_for) {
401     nva.push_back(http2::make_nv_ls("x-forwarded-for", (*xff).value));
402   }
403
404   if (!get_config()->http2_proxy && !get_config()->client_proxy &&
405       downstream_->get_request_method() != "CONNECT") {
406     // We use same protocol with :scheme header field
407     if (scheme.empty()) {
408       if (client_handler_->get_ssl()) {
409         nva.push_back(http2::make_nv_ll("x-forwarded-proto", "https"));
410       } else {
411         nva.push_back(http2::make_nv_ll("x-forwarded-proto", "http"));
412       }
413     } else {
414       nva.push_back(http2::make_nv_ls("x-forwarded-proto", scheme));
415     }
416   }
417
418   auto via = downstream_->get_request_header(http2::HD_VIA);
419   if (get_config()->no_via) {
420     if (via) {
421       nva.push_back(http2::make_nv_ls("via", (*via).value));
422     }
423   } else {
424     if (via) {
425       via_value = (*via).value;
426       via_value += ", ";
427     }
428     via_value += http::create_via_header_value(
429         downstream_->get_request_major(), downstream_->get_request_minor());
430     nva.push_back(http2::make_nv_ls("via", via_value));
431   }
432
433   if (LOG_ENABLED(INFO)) {
434     std::stringstream ss;
435     for (auto &nv : nva) {
436       ss << TTY_HTTP_HD;
437       ss.write(reinterpret_cast<const char *>(nv.name), nv.namelen);
438       ss << TTY_RST << ": ";
439       ss.write(reinterpret_cast<const char *>(nv.value), nv.valuelen);
440       ss << "\n";
441     }
442     DCLOG(INFO, this) << "HTTP request headers\n" << ss.str();
443   }
444
445   auto content_length =
446       downstream_->get_request_header(http2::HD_CONTENT_LENGTH);
447   // TODO check content-length: 0 case
448
449   if (downstream_->get_request_method() == "CONNECT" || chunked_encoding ||
450       content_length || downstream_->get_request_http2_expect_body()) {
451     // Request-body is expected.
452     nghttp2_data_provider data_prd;
453     data_prd.source.ptr = this;
454     data_prd.read_callback = http2_data_read_callback;
455     rv = http2session_->submit_request(this, downstream_->get_priority(),
456                                        nva.data(), nva.size(), &data_prd);
457   } else {
458     rv = http2session_->submit_request(this, downstream_->get_priority(),
459                                        nva.data(), nva.size(), nullptr);
460   }
461   if (rv != 0) {
462     DCLOG(FATAL, this) << "nghttp2_submit_request() failed";
463     return -1;
464   }
465
466   downstream_->reset_downstream_wtimer();
467
468   http2session_->signal_write();
469   return 0;
470 }
471
472 int Http2DownstreamConnection::push_upload_data_chunk(const uint8_t *data,
473                                                       size_t datalen) {
474   int rv;
475   auto output = downstream_->get_request_buf();
476   output->append(data, datalen);
477   if (downstream_->get_downstream_stream_id() != -1) {
478     rv = http2session_->resume_data(this);
479     if (rv != 0) {
480       return -1;
481     }
482
483     downstream_->ensure_downstream_wtimer();
484
485     http2session_->signal_write();
486   }
487   return 0;
488 }
489
490 int Http2DownstreamConnection::end_upload_data() {
491   int rv;
492   if (downstream_->get_downstream_stream_id() != -1) {
493     rv = http2session_->resume_data(this);
494     if (rv != 0) {
495       return -1;
496     }
497
498     downstream_->ensure_downstream_wtimer();
499
500     http2session_->signal_write();
501   }
502   return 0;
503 }
504
505 int Http2DownstreamConnection::resume_read(IOCtrlReason reason,
506                                            size_t consumed) {
507   int rv;
508
509   if (http2session_->get_state() != Http2Session::CONNECTED ||
510       !http2session_->get_flow_control()) {
511     return 0;
512   }
513
514   if (!downstream_ || downstream_->get_downstream_stream_id() == -1) {
515     return 0;
516   }
517
518   if (consumed > 0) {
519     assert(downstream_->get_response_datalen() >= consumed);
520
521     rv = http2session_->consume(downstream_->get_downstream_stream_id(),
522                                 consumed);
523
524     if (rv != 0) {
525       return -1;
526     }
527
528     downstream_->dec_response_datalen(consumed);
529
530     http2session_->signal_write();
531   }
532
533   return 0;
534 }
535
536 int Http2DownstreamConnection::on_read() { return 0; }
537
538 int Http2DownstreamConnection::on_write() { return 0; }
539
540 void Http2DownstreamConnection::attach_stream_data(StreamData *sd) {
541   // It is possible sd->dconn is not NULL. sd is detached when
542   // on_stream_close_callback. Before that, after MSG_COMPLETE is set
543   // to Downstream::set_response_state(), upstream's readcb is called
544   // and execution path eventually could reach here. Since the
545   // response was already handled, we just detach sd.
546   detach_stream_data();
547   sd_ = sd;
548   sd_->dconn = this;
549 }
550
551 StreamData *Http2DownstreamConnection::detach_stream_data() {
552   if (sd_) {
553     auto sd = sd_;
554     sd_ = nullptr;
555     sd->dconn = nullptr;
556     return sd;
557   }
558   return nullptr;
559 }
560
561 int Http2DownstreamConnection::on_priority_change(int32_t pri) {
562   int rv;
563   if (downstream_->get_priority() == pri) {
564     return 0;
565   }
566   downstream_->set_priority(pri);
567   if (http2session_->get_state() != Http2Session::CONNECTED) {
568     return 0;
569   }
570   rv = http2session_->submit_priority(this, pri);
571   if (rv != 0) {
572     DLOG(FATAL, this) << "nghttp2_submit_priority() failed";
573     return -1;
574   }
575   http2session_->signal_write();
576   return 0;
577 }
578
579 int Http2DownstreamConnection::on_timeout() {
580   if (!downstream_) {
581     return 0;
582   }
583
584   return submit_rst_stream(downstream_, NGHTTP2_NO_ERROR);
585 }
586
587 } // namespace shrpx