shrpx_https_upstream.cc 20.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
/*
 * Spdylay - SPDY Library
 *
 * Copyright (c) 2012 Tatsuhiro Tsujikawa
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#include "shrpx_https_upstream.h"

#include <cassert>
#include <set>

#include "shrpx_client_handler.h"
#include "shrpx_downstream.h"
32
#include "shrpx_downstream_connection.h"
33
#include "shrpx_spdy_downstream_connection.h"
34 35 36 37 38 39 40 41 42
#include "shrpx_http.h"
#include "shrpx_config.h"
#include "shrpx_error.h"
#include "util.h"

using namespace spdylay;

namespace shrpx {

43
namespace {
44
const size_t SHRPX_HTTPS_UPSTREAM_OUTPUT_UPPER_THRES = 64*1024;
45
const size_t SHRPX_HTTPS_MAX_HEADER_LENGTH = 64*1024;
46 47
} // namespace

48 49
HttpsUpstream::HttpsUpstream(ClientHandler *handler)
  : handler_(handler),
50
    htp_(new http_parser()),
51
    current_header_length_(0),
52
    downstream_(0),
53
    ioctrl_(handler->get_bev())
54
{
55 56
  http_parser_init(htp_, HTTP_REQUEST);
  htp_->data = this;
57 58 59 60
}

HttpsUpstream::~HttpsUpstream()
{
61
  delete htp_;
62
  delete downstream_;
63 64
}

65 66 67 68 69
void HttpsUpstream::reset_current_header_length()
{
  current_header_length_ = 0;
}

70
namespace {
71
int htp_msg_begin(http_parser *htp)
72 73
{
  HttpsUpstream *upstream;
74
  upstream = reinterpret_cast<HttpsUpstream*>(htp->data);
Tatsuhiro Tsujikawa's avatar
Tatsuhiro Tsujikawa committed
75 76 77
  if(ENABLE_LOG) {
    LOG(INFO) << "Upstream https request start " << upstream;
  }
78
  upstream->reset_current_header_length();
79
  Downstream *downstream = new Downstream(upstream, 0, 0);
80
  upstream->attach_downstream(downstream);
81 82 83 84 85
  return 0;
}
} // namespace

namespace {
86
int htp_uricb(http_parser *htp, const char *data, size_t len)
87 88
{
  HttpsUpstream *upstream;
89
  upstream = reinterpret_cast<HttpsUpstream*>(htp->data);
90
  Downstream *downstream = upstream->get_downstream();
91
  downstream->append_request_path(data, len);
92 93 94 95 96
  return 0;
}
} // namespace

namespace {
97
int htp_hdr_keycb(http_parser *htp, const char *data, size_t len)
98 99
{
  HttpsUpstream *upstream;
100
  upstream = reinterpret_cast<HttpsUpstream*>(htp->data);
101
  Downstream *downstream = upstream->get_downstream();
102 103 104 105
  if(downstream->get_request_header_key_prev()) {
    downstream->append_last_request_header_key(data, len);
  } else {
    downstream->add_request_header(std::string(data, len), "");
106 107 108 109 110 111
  }
  return 0;
}
} // namespace

namespace {
112
int htp_hdr_valcb(http_parser *htp, const char *data, size_t len)
113 114
{
  HttpsUpstream *upstream;
115
  upstream = reinterpret_cast<HttpsUpstream*>(htp->data);
116
  Downstream *downstream = upstream->get_downstream();
117 118 119 120 121
  if(downstream->get_request_header_key_prev()) {
    downstream->set_last_request_header_value(std::string(data, len));
  } else {
    downstream->append_last_request_header_value(data, len);
  }
122 123 124 125 126
  return 0;
}
} // namespace

namespace {
127
int htp_hdrs_completecb(http_parser *htp)
128
{
129
  int rv;
130
  HttpsUpstream *upstream;
131
  upstream = reinterpret_cast<HttpsUpstream*>(htp->data);
Tatsuhiro Tsujikawa's avatar
Tatsuhiro Tsujikawa committed
132 133 134
  if(ENABLE_LOG) {
    LOG(INFO) << "Upstream https request headers complete " << upstream;
  }
135
  Downstream *downstream = upstream->get_downstream();
136

137 138 139
  downstream->set_request_method(http_method_str((enum http_method)htp->method));
  downstream->set_request_major(htp->http_major);
  downstream->set_request_minor(htp->http_minor);
140

141
  downstream->set_request_connection_close(!http_should_keep_alive(htp));
Tatsuhiro Tsujikawa's avatar
Tatsuhiro Tsujikawa committed
142

143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
  if(get_config()->client_proxy &&
     downstream->get_request_method() != "CONNECT") {
    // Make sure that request path is an absolute URI.
    http_parser_url u;
    const char *url = downstream->get_request_path().c_str();
    memset(&u, 0, sizeof(u));
    rv = http_parser_parse_url(url,
                               downstream->get_request_path().size(),
                               0, &u);
    if(rv != 0 || !(u.field_set & (1 << UF_SCHEMA))) {
      // Expect to respond with 400 bad request
      return -1;
    }
  }

158 159
  DownstreamConnection *dconn;
  dconn = upstream->get_client_handler()->get_downstream_connection();
160

161 162
  if(downstream->get_expect_100_continue()) {
    static const char reply_100[] = "HTTP/1.1 100 Continue\r\n\r\n";
163 164 165 166 167
    if(bufferevent_write(upstream->get_client_handler()->get_bev(),
                         reply_100, sizeof(reply_100)-1) != 0) {
      LOG(FATAL) << "bufferevent_write() faild";
      return -1;
    }
168 169
  }

170
  rv =  dconn->attach_downstream(downstream);
171 172 173 174
  if(rv != 0) {
    downstream->set_request_state(Downstream::CONNECT_FAIL);
    downstream->set_downstream_connection(0);
    delete dconn;
175
    return -1;
176
  } else {
177 178 179 180
    rv = downstream->push_request_headers();
    if(rv != 0) {
      return -1;
    }
181 182
    downstream->set_request_state(Downstream::HEADER_COMPLETE);
    return 0;
183
  }
184 185 186 187
}
} // namespace

namespace {
188
int htp_bodycb(http_parser *htp, const char *data, size_t len)
189
{
190
  int rv;
191
  HttpsUpstream *upstream;
192
  upstream = reinterpret_cast<HttpsUpstream*>(htp->data);
193
  Downstream *downstream = upstream->get_downstream();
194 195 196 197 198
  rv = downstream->push_upload_data_chunk
    (reinterpret_cast<const uint8_t*>(data), len);
  if(rv != 0) {
    return -1;
  }
199 200 201 202 203
  return 0;
}
} // namespace

namespace {
204
int htp_msg_completecb(http_parser *htp)
205
{
206
  int rv;
207
  if(ENABLE_LOG) {
208
    LOG(INFO) << "Upstream https request complete";
209 210
  }
  HttpsUpstream *upstream;
211
  upstream = reinterpret_cast<HttpsUpstream*>(htp->data);
212
  Downstream *downstream = upstream->get_downstream();
213
  downstream->set_request_state(Downstream::MSG_COMPLETE);
214 215 216 217
  rv = downstream->end_upload_data();
  if(rv != 0) {
    return -1;
  }
218
  // Stop further processing to complete this request
219 220
  http_parser_pause(htp, 1);
  return 0;
221 222 223 224
}
} // namespace

namespace {
225 226 227 228 229 230 231 232
http_parser_settings htp_hooks = {
  htp_msg_begin, /*http_cb      on_message_begin;*/
  htp_uricb, /*http_data_cb on_url;*/
  htp_hdr_keycb, /*http_data_cb on_header_field;*/
  htp_hdr_valcb, /*http_data_cb on_header_value;*/
  htp_hdrs_completecb, /*http_cb      on_headers_complete;*/
  htp_bodycb, /*http_data_cb on_body;*/
  htp_msg_completecb /*http_cb      on_message_complete;*/
233 234 235
};
} // namespace

236

237 238 239 240 241 242
// on_read() does not consume all available data in input buffer if
// one http request is fully received.
int HttpsUpstream::on_read()
{
  bufferevent *bev = handler_->get_bev();
  evbuffer *input = bufferevent_get_input(bev);
Tatsuhiro Tsujikawa's avatar
Tatsuhiro Tsujikawa committed
243

244
  unsigned char *mem = evbuffer_pullup(input, -1);
Tatsuhiro Tsujikawa's avatar
Tatsuhiro Tsujikawa committed
245

246 247 248 249 250 251 252
  if(evbuffer_get_length(input) == 0) {
    return 0;
  }

  size_t nread = http_parser_execute(htp_, &htp_hooks,
                                     reinterpret_cast<const char*>(mem),
                                     evbuffer_get_length(input));
253
  evbuffer_drain(input, nread);
254 255
  // Well, actually header length + some body bytes
  current_header_length_ += nread;
256
  Downstream *downstream = get_downstream();
257

258 259
  http_errno htperr = HTTP_PARSER_ERRNO(htp_);
  if(htperr == HPE_PAUSED) {
260
    if(downstream->get_request_state() == Downstream::CONNECT_FAIL) {
261
      get_client_handler()->set_should_close_after_write(true);
262 263
      // Following paues_read is needed to avoid reading next data.
      pause_read(SHRPX_MSG_BLOCK);
264 265 266
      if(error_reply(503) != 0) {
        return -1;
      }
267 268 269 270
      // Downstream gets deleted after response body is read.
    } else {
      assert(downstream->get_request_state() == Downstream::MSG_COMPLETE);
      if(downstream->get_downstream_connection() == 0) {
271
        // Error response has already be sent
272
        assert(downstream->get_response_state() == Downstream::MSG_COMPLETE);
273
        delete_downstream();
274 275 276 277
      } else {
        pause_read(SHRPX_MSG_BLOCK);
      }
    }
278
  } else if(htperr == HPE_OK) {
279
    // downstream can be NULL here.
280 281 282 283 284 285
    if(downstream) {
      if(downstream->get_request_state() == Downstream::INITIAL &&
         current_header_length_ > SHRPX_HTTPS_MAX_HEADER_LENGTH) {
        LOG(WARNING) << "Request Header too long:" << current_header_length_
                     << " bytes";
        get_client_handler()->set_should_close_after_write(true);
286
        pause_read(SHRPX_MSG_BLOCK);
287 288 289
        if(error_reply(400) != 0) {
          return -1;
        }
290 291 292 293 294 295
      } else if(downstream->get_output_buffer_full()) {
        if(ENABLE_LOG) {
          LOG(INFO) << "Downstream output buffer is full";
        }
        pause_read(SHRPX_NO_BUFFER);
      }
296
    }
297
  } else {
298
    if(ENABLE_LOG) {
299
      LOG(INFO) << "Upstream http parse failure: "
300 301
                << "(" << http_errno_name(htperr) << ") "
                << http_errno_description(htperr);
302
    }
303
    get_client_handler()->set_should_close_after_write(true);
304
    pause_read(SHRPX_MSG_BLOCK);
305 306 307
    if(error_reply(400) != 0) {
      return -1;
    }
308 309 310 311
  }
  return 0;
}

312 313
int HttpsUpstream::on_write()
{
314
  int rv = 0;
315
  Downstream *downstream = get_downstream();
316 317
  if(downstream) {
    downstream->resume_read(SHRPX_NO_BUFFER);
318
    rv = downstream->on_upstream_write();
319
  }
320
  return rv;
321 322
}

323 324 325 326 327 328 329 330 331 332
int HttpsUpstream::on_event()
{
  return 0;
}

ClientHandler* HttpsUpstream::get_client_handler() const
{
  return handler_;
}

333 334 335 336 337
void HttpsUpstream::pause_read(IOCtrlReason reason)
{
  ioctrl_.pause_read(reason);
}

338
int HttpsUpstream::resume_read(IOCtrlReason reason)
339
{
340 341 342
  if(ioctrl_.resume_read(reason)) {
    // Process remaining data in input buffer here because these bytes
    // are not notified by readcb until new data arrive.
343
    http_parser_pause(htp_, 0);
344 345 346
    return on_read();
  } else {
    return 0;
347
  }
348 349 350 351 352
}

namespace {
void https_downstream_readcb(bufferevent *bev, void *ptr)
{
353 354
  DownstreamConnection *dconn = reinterpret_cast<DownstreamConnection*>(ptr);
  Downstream *downstream = dconn->get_downstream();
355 356
  HttpsUpstream *upstream;
  upstream = static_cast<HttpsUpstream*>(downstream->get_upstream());
357
  int rv;
358 359 360 361
  rv = downstream->on_read();
  if(downstream->get_response_state() == Downstream::MSG_RESET) {
    delete upstream->get_client_handler();
  } else if(rv == 0) {
362
    if(downstream->get_response_state() == Downstream::MSG_COMPLETE) {
363
      if(downstream->get_response_connection_close()) {
364 365 366 367 368 369 370 371 372
        // Connection close
        downstream->set_downstream_connection(0);
        delete dconn;
        dconn = 0;
      } else {
        // Keep-alive
        dconn->detach_downstream(downstream);
      }
      if(downstream->get_request_state() == Downstream::MSG_COMPLETE) {
Tatsuhiro Tsujikawa's avatar
Tatsuhiro Tsujikawa committed
373 374 375 376 377 378 379 380 381
        ClientHandler *handler = upstream->get_client_handler();
        if(handler->get_should_close_after_write() &&
           handler->get_pending_write_length() == 0) {
          // If all upstream response body has already written out to
          // the peer, we cannot use writecb for ClientHandler. In
          // this case, we just delete handler here.
          delete handler;
          return;
        } else {
382
          upstream->delete_downstream();
Tatsuhiro Tsujikawa's avatar
Tatsuhiro Tsujikawa committed
383 384 385
          // Process next HTTP request
          upstream->resume_read(SHRPX_MSG_BLOCK);
        }
386
      }
387 388 389 390 391 392 393
    } else {
      ClientHandler *handler = upstream->get_client_handler();
      bufferevent *bev = handler->get_bev();
      size_t outputlen = evbuffer_get_length(bufferevent_get_output(bev));
      if(outputlen > SHRPX_HTTPS_UPSTREAM_OUTPUT_UPPER_THRES) {
        downstream->pause_read(SHRPX_NO_BUFFER);
      }
394 395 396
    }
  } else {
    if(downstream->get_response_state() == Downstream::HEADER_COMPLETE) {
397 398
      // We already sent HTTP response headers to upstream
      // client. Just close the upstream connection.
399 400
      delete upstream->get_client_handler();
    } else {
401 402
      // We did not sent any HTTP response, so sent error
      // response. Cannot reuse downstream connection in this case.
403 404 405 406
      if(upstream->error_reply(502) != 0) {
        delete upstream->get_client_handler();
        return;
      }
407
      if(downstream->get_request_state() == Downstream::MSG_COMPLETE) {
408
        upstream->delete_downstream();
409 410 411
        // Process next HTTP request
        upstream->resume_read(SHRPX_MSG_BLOCK);
      }
412 413 414 415 416 417 418 419
    }
  }
}
} // namespace

namespace {
void https_downstream_writecb(bufferevent *bev, void *ptr)
{
420 421 422
  if(evbuffer_get_length(bufferevent_get_output(bev)) > 0) {
    return;
  }
423 424 425 426 427
  DownstreamConnection *dconn = reinterpret_cast<DownstreamConnection*>(ptr);
  Downstream *downstream = dconn->get_downstream();
  HttpsUpstream *upstream;
  upstream = static_cast<HttpsUpstream*>(downstream->get_upstream());
  upstream->resume_read(SHRPX_NO_BUFFER);
428 429 430 431 432 433
}
} // namespace

namespace {
void https_downstream_eventcb(bufferevent *bev, short events, void *ptr)
{
434 435
  DownstreamConnection *dconn = reinterpret_cast<DownstreamConnection*>(ptr);
  Downstream *downstream = dconn->get_downstream();
436 437 438 439
  HttpsUpstream *upstream;
  upstream = static_cast<HttpsUpstream*>(downstream->get_upstream());
  if(events & BEV_EVENT_CONNECTED) {
    if(ENABLE_LOG) {
440 441
      LOG(INFO) << "Downstream connection established. downstream "
                << downstream;
442
    }
443
  } else if(events & BEV_EVENT_EOF) {
444
    if(ENABLE_LOG) {
445
      LOG(INFO) << "Downstream EOF. stream_id="
446 447
                << downstream->get_stream_id();
    }
Tatsuhiro Tsujikawa's avatar
Tatsuhiro Tsujikawa committed
448 449 450
    if(downstream->get_response_state() == Downstream::HEADER_COMPLETE) {
      // Server may indicate the end of the request by EOF
      if(ENABLE_LOG) {
Tatsuhiro Tsujikawa's avatar
Tatsuhiro Tsujikawa committed
451
        LOG(INFO) << "Downstream body was ended by EOF";
452
      }
Tatsuhiro Tsujikawa's avatar
Tatsuhiro Tsujikawa committed
453
      upstream->on_downstream_body_complete(downstream);
Tatsuhiro Tsujikawa's avatar
Tatsuhiro Tsujikawa committed
454 455 456 457 458 459 460 461 462 463 464
      downstream->set_response_state(Downstream::MSG_COMPLETE);

      ClientHandler *handler = upstream->get_client_handler();
      if(handler->get_should_close_after_write() &&
         handler->get_pending_write_length() == 0) {
        // If all upstream response body has already written out to
        // the peer, we cannot use writecb for ClientHandler. In this
        // case, we just delete handler here.
        delete handler;
        return;
      }
Tatsuhiro Tsujikawa's avatar
Tatsuhiro Tsujikawa committed
465 466 467 468 469 470 471
    } else if(downstream->get_response_state() == Downstream::MSG_COMPLETE) {
      // Nothing to do
    } else {
      // error
      if(ENABLE_LOG) {
        LOG(INFO) << "Treated as downstream error";
      }
472 473 474 475
      if(upstream->error_reply(502) != 0) {
        delete upstream->get_client_handler();
        return;
      }
476
    }
477
    if(downstream->get_request_state() == Downstream::MSG_COMPLETE) {
478
      upstream->delete_downstream();
479 480
      upstream->resume_read(SHRPX_MSG_BLOCK);
    }
481 482
  } else if(events & (BEV_EVENT_ERROR | BEV_EVENT_TIMEOUT)) {
    if(ENABLE_LOG) {
483
      LOG(INFO) << "Downstream error/timeout. " << downstream;
484 485 486 487 488 489 490 491
    }
    if(downstream->get_response_state() == Downstream::INITIAL) {
      int status;
      if(events & BEV_EVENT_TIMEOUT) {
        status = 504;
      } else {
        status = 502;
      }
492 493 494 495
      if(upstream->error_reply(status) != 0) {
        delete upstream->get_client_handler();
        return;
      }
496
    }
497
    if(downstream->get_request_state() == Downstream::MSG_COMPLETE) {
498
      upstream->delete_downstream();
499 500
      upstream->resume_read(SHRPX_MSG_BLOCK);
    }
501 502 503 504
  }
}
} // namespace

505
int HttpsUpstream::error_reply(int status_code)
506 507 508 509 510 511
{
  std::string html = http::create_error_html(status_code);
  std::stringstream ss;
  ss << "HTTP/1.1 " << http::get_status_string(status_code) << "\r\n"
     << "Server: " << get_config()->server_name << "\r\n"
     << "Content-Length: " << html.size() << "\r\n"
512 513 514 515 516
     << "Content-Type: " << "text/html; charset=UTF-8\r\n";
  if(get_client_handler()->get_should_close_after_write()) {
    ss << "Connection: close\r\n";
  }
  ss << "\r\n";
517 518
  std::string header = ss.str();
  evbuffer *output = bufferevent_get_output(handler_->get_bev());
519 520 521 522 523
  if(evbuffer_add(output, header.c_str(), header.size()) != 0 ||
     evbuffer_add(output, html.c_str(), html.size()) != 0) {
    LOG(FATAL) << "evbuffer_add() failed";
    return -1;
  }
524
  Downstream *downstream = get_downstream();
525 526 527
  if(downstream) {
    downstream->set_response_state(Downstream::MSG_COMPLETE);
  }
528
  return 0;
529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545
}

bufferevent_data_cb HttpsUpstream::get_downstream_readcb()
{
  return https_downstream_readcb;
}

bufferevent_data_cb HttpsUpstream::get_downstream_writecb()
{
  return https_downstream_writecb;
}

bufferevent_event_cb HttpsUpstream::get_downstream_eventcb()
{
  return https_downstream_eventcb;
}

546
void HttpsUpstream::attach_downstream(Downstream *downstream)
547
{
548 549
  assert(!downstream_);
  downstream_ = downstream;
550 551
}

552
void HttpsUpstream::delete_downstream()
553
{
554 555
  delete downstream_;
  downstream_ = 0;
556 557
}

558
Downstream* HttpsUpstream::get_downstream() const
559
{
560
  return downstream_;
561 562 563 564 565
}

int HttpsUpstream::on_downstream_header_complete(Downstream *downstream)
{
  if(ENABLE_LOG) {
566
    LOG(INFO) << "Downstream on_downstream_header_complete";
567
  }
568
  std::string via_value;
Tatsuhiro Tsujikawa's avatar
Tatsuhiro Tsujikawa committed
569 570
  char temp[16];
  snprintf(temp, sizeof(temp), "HTTP/%d.%d ",
571 572
           downstream->get_request_major(),
           downstream->get_request_minor());
Tatsuhiro Tsujikawa's avatar
Tatsuhiro Tsujikawa committed
573
  std::string hdrs = temp;
574 575 576 577 578 579 580 581
  hdrs += http::get_status_string(downstream->get_response_http_status());
  hdrs += "\r\n";
  for(Headers::const_iterator i = downstream->get_response_headers().begin();
      i != downstream->get_response_headers().end(); ++i) {
    if(util::strieq((*i).first.c_str(), "keep-alive") || // HTTP/1.0?
       util::strieq((*i).first.c_str(), "connection") ||
       util:: strieq((*i).first.c_str(), "proxy-connection")) {
      // These are ignored
582 583
    } else if(util::strieq((*i).first.c_str(), "via")) {
      via_value = (*i).second;
584
    } else {
585
      hdrs += (*i).first;
586
      http::capitalize(hdrs, hdrs.size()-(*i).first.size());
587 588
      hdrs += ": ";
      hdrs += (*i).second;
589 590 591
      hdrs += "\r\n";
    }
  }
Tatsuhiro Tsujikawa's avatar
Tatsuhiro Tsujikawa committed
592

593 594 595 596 597 598 599
  // We check downstream->get_response_connection_close() in case when
  // the Content-Length is not available.
  if(!downstream->get_request_connection_close() &&
     !downstream->get_response_connection_close()) {
    if(downstream->get_request_major() <= 0 ||
       downstream->get_request_minor() <= 0) {
      // We add this header for HTTP/1.0 or HTTP/0.9 clients
Tatsuhiro Tsujikawa's avatar
Tatsuhiro Tsujikawa committed
600 601 602
      hdrs += "Connection: Keep-Alive\r\n";
    }
  } else {
603
    hdrs += "Connection: close\r\n";
604
  }
Tatsuhiro Tsujikawa's avatar
Tatsuhiro Tsujikawa committed
605

606 607 608 609 610 611 612 613
  hdrs += "Via: ";
  hdrs += via_value;
  if(!via_value.empty()) {
    hdrs += ", ";
  }
  hdrs += http::create_via_header_value
    (downstream->get_response_major(), downstream->get_response_minor());
  hdrs += "\r\n";
614 615
  hdrs += "\r\n";
  if(ENABLE_LOG) {
616
    LOG(INFO) << "Upstream https response headers\n" << hdrs;
617 618
  }
  evbuffer *output = bufferevent_get_output(handler_->get_bev());
619 620 621 622
  if(evbuffer_add(output, hdrs.c_str(), hdrs.size()) != 0) {
    LOG(FATAL) << "evbuffer_add() failed";
    return -1;
  }
623 624 625 626 627 628 629 630 631 632 633 634
  return 0;
}

int HttpsUpstream::on_downstream_body(Downstream *downstream,
                                      const uint8_t *data, size_t len)
{
  int rv;
  evbuffer *output = bufferevent_get_output(handler_->get_bev());
  if(downstream->get_chunked_response()) {
    char chunk_size_hex[16];
    rv = snprintf(chunk_size_hex, sizeof(chunk_size_hex), "%X\r\n",
                  static_cast<unsigned int>(len));
635 636 637 638
    if(evbuffer_add(output, chunk_size_hex, rv) != 0) {
      LOG(FATAL) << "evbuffer_add() failed";
      return -1;
    }
639 640
  }
  evbuffer_add(output, data, len);
641 642 643
  if(downstream->get_chunked_response()) {
    evbuffer_add(output, "\r\n", 2);
  }
644 645 646 647 648 649 650
  return 0;
}

int HttpsUpstream::on_downstream_body_complete(Downstream *downstream)
{
  if(downstream->get_chunked_response()) {
    evbuffer *output = bufferevent_get_output(handler_->get_bev());
651 652 653 654
    if(evbuffer_add(output, "0\r\n\r\n", 5) != 0) {
      LOG(FATAL) << "evbuffer_add() failed";
      return -1;
    }
655 656
  }
  if(ENABLE_LOG) {
657
    LOG(INFO) << "Downstream on_downstream_body_complete";
658
  }
659 660
  if(downstream->get_request_connection_close() ||
     downstream->get_response_connection_close()) {
Tatsuhiro Tsujikawa's avatar
Tatsuhiro Tsujikawa committed
661
    ClientHandler *handler = get_client_handler();
662 663 664 665 666 667
    handler->set_should_close_after_write(true);
  }
  return 0;
}

} // namespace shrpx