2012-06-04 16:48:31 +02:00
|
|
|
/*
|
2014-03-30 12:09:21 +02:00
|
|
|
* nghttp2 - HTTP/2 C Library
|
2012-06-04 16:48:31 +02:00
|
|
|
*
|
|
|
|
* 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_client_handler.h"
|
|
|
|
|
2012-08-21 17:14:02 +02:00
|
|
|
#include <unistd.h>
|
2012-07-15 14:15:28 +02:00
|
|
|
#include <cerrno>
|
|
|
|
|
2012-06-04 16:48:31 +02:00
|
|
|
#include "shrpx_upstream.h"
|
2013-07-26 12:38:54 +02:00
|
|
|
#include "shrpx_http2_upstream.h"
|
2012-06-04 16:48:31 +02:00
|
|
|
#include "shrpx_https_upstream.h"
|
|
|
|
#include "shrpx_config.h"
|
2012-11-18 13:23:13 +01:00
|
|
|
#include "shrpx_http_downstream_connection.h"
|
2013-11-04 09:53:57 +01:00
|
|
|
#include "shrpx_http2_downstream_connection.h"
|
2014-01-01 16:53:07 +01:00
|
|
|
#include "shrpx_ssl.h"
|
2014-06-26 15:55:22 +02:00
|
|
|
#include "shrpx_worker.h"
|
2014-10-13 14:09:00 +02:00
|
|
|
#include "shrpx_downstream_connection_pool.h"
|
2014-11-18 16:56:44 +01:00
|
|
|
#include "shrpx_downstream.h"
|
2013-07-26 13:12:55 +02:00
|
|
|
#ifdef HAVE_SPDYLAY
|
|
|
|
#include "shrpx_spdy_upstream.h"
|
|
|
|
#endif // HAVE_SPDYLAY
|
2013-09-23 17:02:02 +02:00
|
|
|
#include "util.h"
|
2015-02-05 15:21:53 +01:00
|
|
|
#include "template.h"
|
2013-09-23 17:02:02 +02:00
|
|
|
|
|
|
|
using namespace nghttp2;
|
2013-07-26 13:12:55 +02:00
|
|
|
|
2012-06-04 16:48:31 +02:00
|
|
|
namespace shrpx {
|
|
|
|
|
|
|
|
namespace {
|
2014-12-27 18:59:06 +01:00
|
|
|
void timeoutcb(struct ev_loop *loop, ev_timer *w, int revents) {
|
2015-02-04 13:15:58 +01:00
|
|
|
auto conn = static_cast<Connection *>(w->data);
|
|
|
|
auto handler = static_cast<ClientHandler *>(conn->data);
|
2014-12-27 18:59:06 +01:00
|
|
|
|
|
|
|
if (LOG_ENABLED(INFO)) {
|
|
|
|
CLOG(INFO, handler) << "Time out";
|
2012-06-04 16:48:31 +02:00
|
|
|
}
|
2014-12-27 18:59:06 +01:00
|
|
|
|
|
|
|
delete handler;
|
2012-06-04 16:48:31 +02:00
|
|
|
}
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
namespace {
|
2014-12-27 18:59:06 +01:00
|
|
|
void shutdowncb(struct ev_loop *loop, ev_timer *w, int revents) {
|
|
|
|
auto handler = static_cast<ClientHandler *>(w->data);
|
|
|
|
|
|
|
|
if (LOG_ENABLED(INFO)) {
|
|
|
|
CLOG(INFO, handler) << "Close connection due to TLS renegotiation";
|
2014-09-18 16:03:36 +02:00
|
|
|
}
|
2014-06-10 17:07:51 +02:00
|
|
|
|
2014-12-27 18:59:06 +01:00
|
|
|
delete handler;
|
|
|
|
}
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
void readcb(struct ev_loop *loop, ev_io *w, int revents) {
|
2015-02-04 13:15:58 +01:00
|
|
|
auto conn = static_cast<Connection *>(w->data);
|
|
|
|
auto handler = static_cast<ClientHandler *>(conn->data);
|
2014-11-05 16:56:07 +01:00
|
|
|
|
2014-12-27 18:59:06 +01:00
|
|
|
if (handler->do_read() != 0) {
|
|
|
|
delete handler;
|
2012-11-21 19:13:30 +01:00
|
|
|
return;
|
|
|
|
}
|
2015-03-28 17:47:22 +01:00
|
|
|
if (handler->do_write() != 0) {
|
|
|
|
delete handler;
|
|
|
|
return;
|
2015-02-10 16:44:30 +01:00
|
|
|
}
|
2014-12-27 18:59:06 +01:00
|
|
|
}
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
void writecb(struct ev_loop *loop, ev_io *w, int revents) {
|
2015-02-04 13:15:58 +01:00
|
|
|
auto conn = static_cast<Connection *>(w->data);
|
|
|
|
auto handler = static_cast<ClientHandler *>(conn->data);
|
2014-12-27 18:59:06 +01:00
|
|
|
|
|
|
|
if (handler->do_write() != 0) {
|
2012-06-04 16:48:31 +02:00
|
|
|
delete handler;
|
2014-01-19 15:32:07 +01:00
|
|
|
return;
|
|
|
|
}
|
2014-12-27 18:59:06 +01:00
|
|
|
}
|
|
|
|
} // namespace
|
2014-09-18 16:03:36 +02:00
|
|
|
|
2014-12-27 18:59:06 +01:00
|
|
|
int ClientHandler::read_clear() {
|
2015-02-04 13:15:58 +01:00
|
|
|
ev_timer_again(conn_.loop, &conn_.rt);
|
2014-12-27 18:59:06 +01:00
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
if (rb_.rleft() && on_read() != 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
2015-02-13 14:41:50 +01:00
|
|
|
if (rb_.rleft() == 0) {
|
|
|
|
rb_.reset();
|
|
|
|
} else if (rb_.wleft() == 0) {
|
|
|
|
conn_.rlimit.stopw();
|
2015-01-06 14:48:17 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2015-01-29 14:47:37 +01:00
|
|
|
|
2015-02-04 13:15:58 +01:00
|
|
|
auto nread = conn_.read_clear(rb_.last, rb_.wleft());
|
2014-12-27 18:59:06 +01:00
|
|
|
|
2015-02-04 13:15:58 +01:00
|
|
|
if (nread == 0) {
|
|
|
|
return 0;
|
2014-12-27 18:59:06 +01:00
|
|
|
}
|
|
|
|
|
2015-02-04 13:15:58 +01:00
|
|
|
if (nread < 0) {
|
2014-12-27 18:59:06 +01:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
rb_.write(nread);
|
2014-01-19 15:32:07 +01:00
|
|
|
}
|
2014-12-27 18:59:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int ClientHandler::write_clear() {
|
2015-02-04 13:15:58 +01:00
|
|
|
ev_timer_again(conn_.loop, &conn_.rt);
|
2014-12-27 18:59:06 +01:00
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
if (wb_.rleft() > 0) {
|
2015-02-04 13:15:58 +01:00
|
|
|
auto nwrite = conn_.write_clear(wb_.pos, wb_.rleft());
|
2015-01-29 14:47:37 +01:00
|
|
|
if (nwrite == 0) {
|
2014-12-27 18:59:06 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2015-02-04 13:15:58 +01:00
|
|
|
if (nwrite < 0) {
|
2014-12-27 18:59:06 +01:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
wb_.drain(nwrite);
|
|
|
|
continue;
|
|
|
|
}
|
2015-01-02 05:54:41 +01:00
|
|
|
wb_.reset();
|
2014-12-27 18:59:06 +01:00
|
|
|
if (on_write() != 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (wb_.rleft() == 0) {
|
|
|
|
break;
|
|
|
|
}
|
2012-06-04 16:48:31 +02:00
|
|
|
}
|
2014-12-27 18:59:06 +01:00
|
|
|
|
2015-02-04 13:15:58 +01:00
|
|
|
conn_.wlimit.stopw();
|
|
|
|
ev_timer_stop(conn_.loop, &conn_.wt);
|
2014-12-27 18:59:06 +01:00
|
|
|
|
|
|
|
return 0;
|
2012-06-04 16:48:31 +02:00
|
|
|
}
|
|
|
|
|
2014-12-27 18:59:06 +01:00
|
|
|
int ClientHandler::tls_handshake() {
|
2015-02-04 13:15:58 +01:00
|
|
|
ev_timer_again(conn_.loop, &conn_.rt);
|
2014-12-27 18:59:06 +01:00
|
|
|
|
2015-01-08 16:07:28 +01:00
|
|
|
ERR_clear_error();
|
|
|
|
|
2015-02-04 13:15:58 +01:00
|
|
|
auto rv = conn_.tls_handshake();
|
2014-12-27 18:59:06 +01:00
|
|
|
|
2015-02-04 13:15:58 +01:00
|
|
|
if (rv == SHRPX_ERR_INPROGRESS) {
|
|
|
|
return 0;
|
2014-12-27 18:59:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (rv < 0) {
|
2015-02-04 13:15:58 +01:00
|
|
|
return -1;
|
2012-06-04 16:48:31 +02:00
|
|
|
}
|
2014-12-27 18:59:06 +01:00
|
|
|
|
|
|
|
if (LOG_ENABLED(INFO)) {
|
|
|
|
CLOG(INFO, this) << "SSL/TLS handshake completed";
|
|
|
|
}
|
2015-02-04 13:15:58 +01:00
|
|
|
|
2014-12-27 18:59:06 +01:00
|
|
|
if (validate_next_proto() != 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
read_ = &ClientHandler::read_tls;
|
|
|
|
write_ = &ClientHandler::write_tls;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ClientHandler::read_tls() {
|
2015-02-04 13:15:58 +01:00
|
|
|
ev_timer_again(conn_.loop, &conn_.rt);
|
2014-12-27 18:59:06 +01:00
|
|
|
|
2015-01-08 16:07:28 +01:00
|
|
|
ERR_clear_error();
|
|
|
|
|
2014-12-27 18:59:06 +01:00
|
|
|
for (;;) {
|
2015-01-06 14:48:17 +01:00
|
|
|
// we should process buffered data first before we read EOF.
|
2014-12-27 18:59:06 +01:00
|
|
|
if (rb_.rleft() && on_read() != 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
2015-02-13 14:41:50 +01:00
|
|
|
if (rb_.rleft() == 0) {
|
|
|
|
rb_.reset();
|
|
|
|
} else if (rb_.wleft() == 0) {
|
|
|
|
conn_.rlimit.stopw();
|
2015-01-06 14:48:17 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2015-01-29 14:47:37 +01:00
|
|
|
|
2015-02-04 13:15:58 +01:00
|
|
|
auto nread = conn_.read_tls(rb_.last, rb_.wleft());
|
2014-12-27 18:59:06 +01:00
|
|
|
|
2015-02-04 13:15:58 +01:00
|
|
|
if (nread == 0) {
|
|
|
|
return 0;
|
2012-06-04 16:48:31 +02:00
|
|
|
}
|
2014-12-27 18:59:06 +01:00
|
|
|
|
2015-02-04 13:15:58 +01:00
|
|
|
if (nread < 0) {
|
|
|
|
return -1;
|
2014-12-27 18:59:06 +01:00
|
|
|
}
|
|
|
|
|
2015-02-04 13:15:58 +01:00
|
|
|
rb_.write(nread);
|
2012-06-04 16:48:31 +02:00
|
|
|
}
|
2014-12-27 18:59:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int ClientHandler::write_tls() {
|
2015-02-04 13:15:58 +01:00
|
|
|
ev_timer_again(conn_.loop, &conn_.rt);
|
2014-12-27 18:59:06 +01:00
|
|
|
|
2015-01-08 16:07:28 +01:00
|
|
|
ERR_clear_error();
|
|
|
|
|
2014-12-27 18:59:06 +01:00
|
|
|
for (;;) {
|
|
|
|
if (wb_.rleft() > 0) {
|
2015-02-04 13:15:58 +01:00
|
|
|
auto nwrite = conn_.write_tls(wb_.pos, wb_.rleft());
|
2014-12-27 18:59:06 +01:00
|
|
|
|
2015-02-04 13:15:58 +01:00
|
|
|
if (nwrite == 0) {
|
|
|
|
return 0;
|
2014-01-01 16:53:07 +01:00
|
|
|
}
|
2015-01-08 15:03:56 +01:00
|
|
|
|
2015-02-04 13:15:58 +01:00
|
|
|
if (nwrite < 0) {
|
2014-12-27 18:59:06 +01:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2015-02-04 13:15:58 +01:00
|
|
|
wb_.drain(nwrite);
|
2014-12-27 18:59:06 +01:00
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
2015-01-02 05:54:41 +01:00
|
|
|
wb_.reset();
|
2014-12-27 18:59:06 +01:00
|
|
|
if (on_write() != 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (wb_.rleft() == 0) {
|
|
|
|
break;
|
2012-06-04 16:48:31 +02:00
|
|
|
}
|
|
|
|
}
|
2014-12-27 18:59:06 +01:00
|
|
|
|
2015-02-04 13:15:58 +01:00
|
|
|
conn_.wlimit.stopw();
|
|
|
|
ev_timer_stop(conn_.loop, &conn_.wt);
|
2014-12-27 18:59:06 +01:00
|
|
|
|
|
|
|
return 0;
|
2012-06-04 16:48:31 +02:00
|
|
|
}
|
|
|
|
|
2014-12-27 18:59:06 +01:00
|
|
|
int ClientHandler::upstream_noop() { return 0; }
|
|
|
|
|
|
|
|
int ClientHandler::upstream_read() {
|
|
|
|
assert(upstream_);
|
|
|
|
if (upstream_->on_read() != 0) {
|
|
|
|
return -1;
|
2013-07-26 14:35:14 +02:00
|
|
|
}
|
2014-12-27 18:59:06 +01:00
|
|
|
return 0;
|
2013-07-26 14:35:14 +02:00
|
|
|
}
|
|
|
|
|
2014-12-27 18:59:06 +01:00
|
|
|
int ClientHandler::upstream_write() {
|
|
|
|
assert(upstream_);
|
|
|
|
if (upstream_->on_write() != 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (get_should_close_after_write() && wb_.rleft() == 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ClientHandler::upstream_http2_connhd_read() {
|
2015-01-29 14:47:37 +01:00
|
|
|
auto nread = std::min(left_connhd_len_, rb_.rleft());
|
2015-04-05 15:35:40 +02:00
|
|
|
if (memcmp(NGHTTP2_CLIENT_MAGIC + NGHTTP2_CLIENT_MAGIC_LEN - left_connhd_len_,
|
2015-01-29 14:47:37 +01:00
|
|
|
rb_.pos, nread) != 0) {
|
|
|
|
// There is no downgrade path here. Just drop the connection.
|
|
|
|
if (LOG_ENABLED(INFO)) {
|
|
|
|
CLOG(INFO, this) << "invalid client connection header";
|
2014-12-27 18:59:06 +01:00
|
|
|
}
|
|
|
|
|
2015-01-29 14:47:37 +01:00
|
|
|
return -1;
|
|
|
|
}
|
2014-12-27 18:59:06 +01:00
|
|
|
|
2015-01-29 14:47:37 +01:00
|
|
|
left_connhd_len_ -= nread;
|
|
|
|
rb_.drain(nread);
|
2015-02-13 14:41:50 +01:00
|
|
|
conn_.rlimit.startw();
|
2015-01-29 14:47:37 +01:00
|
|
|
|
|
|
|
if (left_connhd_len_ == 0) {
|
|
|
|
on_read_ = &ClientHandler::upstream_read;
|
|
|
|
// Run on_read to process data left in buffer since they are not
|
|
|
|
// notified further
|
|
|
|
if (on_read() != 0) {
|
|
|
|
return -1;
|
2014-12-27 18:59:06 +01:00
|
|
|
}
|
2015-01-29 14:47:37 +01:00
|
|
|
return 0;
|
2013-08-03 11:51:01 +02:00
|
|
|
}
|
2014-12-27 18:59:06 +01:00
|
|
|
|
|
|
|
return 0;
|
2013-08-03 11:51:01 +02:00
|
|
|
}
|
|
|
|
|
2014-12-27 18:59:06 +01:00
|
|
|
int ClientHandler::upstream_http1_connhd_read() {
|
2015-01-29 14:47:37 +01:00
|
|
|
auto nread = std::min(left_connhd_len_, rb_.rleft());
|
2015-04-05 15:35:40 +02:00
|
|
|
if (memcmp(NGHTTP2_CLIENT_MAGIC + NGHTTP2_CLIENT_MAGIC_LEN - left_connhd_len_,
|
2015-01-29 14:47:37 +01:00
|
|
|
rb_.pos, nread) != 0) {
|
|
|
|
if (LOG_ENABLED(INFO)) {
|
|
|
|
CLOG(INFO, this) << "This is HTTP/1.1 connection, "
|
|
|
|
<< "but may be upgraded to HTTP/2 later.";
|
|
|
|
}
|
2014-12-27 18:59:06 +01:00
|
|
|
|
2015-01-29 14:47:37 +01:00
|
|
|
// Reset header length for later HTTP/2 upgrade
|
2015-04-05 15:35:40 +02:00
|
|
|
left_connhd_len_ = NGHTTP2_CLIENT_MAGIC_LEN;
|
2015-01-29 14:47:37 +01:00
|
|
|
on_read_ = &ClientHandler::upstream_read;
|
|
|
|
on_write_ = &ClientHandler::upstream_write;
|
2014-12-27 18:59:06 +01:00
|
|
|
|
2015-01-29 14:47:37 +01:00
|
|
|
if (on_read() != 0) {
|
|
|
|
return -1;
|
2014-12-27 18:59:06 +01:00
|
|
|
}
|
|
|
|
|
2015-01-29 14:47:37 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2014-12-27 18:59:06 +01:00
|
|
|
|
2015-01-29 14:47:37 +01:00
|
|
|
left_connhd_len_ -= nread;
|
|
|
|
rb_.drain(nread);
|
2015-02-13 14:41:50 +01:00
|
|
|
conn_.rlimit.startw();
|
2014-12-27 18:59:06 +01:00
|
|
|
|
2015-01-29 14:47:37 +01:00
|
|
|
if (left_connhd_len_ == 0) {
|
|
|
|
if (LOG_ENABLED(INFO)) {
|
|
|
|
CLOG(INFO, this) << "direct HTTP/2 connection";
|
|
|
|
}
|
2014-12-27 18:59:06 +01:00
|
|
|
|
2015-01-29 14:47:37 +01:00
|
|
|
direct_http2_upgrade();
|
|
|
|
on_read_ = &ClientHandler::upstream_read;
|
|
|
|
on_write_ = &ClientHandler::upstream_write;
|
2014-12-27 18:59:06 +01:00
|
|
|
|
2015-01-29 14:47:37 +01:00
|
|
|
// Run on_read to process data left in buffer since they are not
|
|
|
|
// notified further
|
|
|
|
if (on_read() != 0) {
|
|
|
|
return -1;
|
2014-12-27 18:59:06 +01:00
|
|
|
}
|
2015-01-29 14:47:37 +01:00
|
|
|
|
|
|
|
return 0;
|
2014-12-27 18:59:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-02-11 11:18:41 +01:00
|
|
|
ClientHandler::ClientHandler(Worker *worker, int fd, SSL *ssl,
|
|
|
|
const char *ipaddr, const char *port)
|
|
|
|
: conn_(worker->get_loop(), fd, ssl, get_config()->upstream_write_timeout,
|
2015-02-04 13:15:58 +01:00
|
|
|
get_config()->upstream_read_timeout, get_config()->write_rate,
|
|
|
|
get_config()->write_burst, get_config()->read_rate,
|
|
|
|
get_config()->read_burst, writecb, readcb, timeoutcb, this),
|
2015-02-11 11:18:41 +01:00
|
|
|
ipaddr_(ipaddr), port_(port), worker_(worker),
|
2015-03-11 13:14:55 +01:00
|
|
|
http2session_(worker_->next_http2_session()),
|
2015-04-05 15:35:40 +02:00
|
|
|
left_connhd_len_(NGHTTP2_CLIENT_MAGIC_LEN),
|
2015-02-04 13:15:58 +01:00
|
|
|
should_close_after_write_(false) {
|
2014-03-09 06:53:28 +01:00
|
|
|
|
2015-02-11 11:18:41 +01:00
|
|
|
++worker_->get_worker_stat()->num_connections;
|
2014-06-26 15:55:22 +02:00
|
|
|
|
2014-12-27 18:59:06 +01:00
|
|
|
ev_timer_init(&reneg_shutdown_timer_, shutdowncb, 0., 0.);
|
|
|
|
|
|
|
|
reneg_shutdown_timer_.data = this;
|
|
|
|
|
2015-02-04 13:15:58 +01:00
|
|
|
conn_.rlimit.startw();
|
|
|
|
ev_timer_again(conn_.loop, &conn_.rt);
|
2014-03-09 06:53:28 +01:00
|
|
|
|
2015-02-04 13:15:58 +01:00
|
|
|
if (conn_.tls.ssl) {
|
|
|
|
SSL_set_app_data(conn_.tls.ssl, &conn_);
|
2014-12-27 18:59:06 +01:00
|
|
|
read_ = write_ = &ClientHandler::tls_handshake;
|
|
|
|
on_read_ = &ClientHandler::upstream_noop;
|
|
|
|
on_write_ = &ClientHandler::upstream_write;
|
2012-11-18 13:23:13 +01:00
|
|
|
} else {
|
2013-08-03 11:51:01 +02:00
|
|
|
// For non-TLS version, first create HttpsUpstream. It may be
|
2014-03-30 12:09:21 +02:00
|
|
|
// upgraded to HTTP/2 through HTTP Upgrade or direct HTTP/2
|
2013-08-03 11:51:01 +02:00
|
|
|
// connection.
|
2015-02-05 15:21:53 +01:00
|
|
|
upstream_ = make_unique<HttpsUpstream>(this);
|
2014-11-24 07:22:10 +01:00
|
|
|
alpn_ = "http/1.1";
|
2014-12-27 18:59:06 +01:00
|
|
|
read_ = &ClientHandler::read_clear;
|
|
|
|
write_ = &ClientHandler::write_clear;
|
|
|
|
on_read_ = &ClientHandler::upstream_http1_connhd_read;
|
|
|
|
on_write_ = &ClientHandler::upstream_noop;
|
2012-11-18 13:23:13 +01:00
|
|
|
}
|
2012-06-04 16:48:31 +02:00
|
|
|
}
|
|
|
|
|
2014-11-27 15:39:04 +01:00
|
|
|
ClientHandler::~ClientHandler() {
|
|
|
|
if (LOG_ENABLED(INFO)) {
|
2012-12-09 11:15:14 +01:00
|
|
|
CLOG(INFO, this) << "Deleting";
|
2012-06-04 16:48:31 +02:00
|
|
|
}
|
2014-06-10 17:07:51 +02:00
|
|
|
|
2014-11-27 15:39:04 +01:00
|
|
|
if (upstream_) {
|
2014-11-18 17:59:09 +01:00
|
|
|
upstream_->on_handler_delete();
|
|
|
|
}
|
|
|
|
|
2015-02-11 11:18:41 +01:00
|
|
|
auto worker_stat = worker_->get_worker_stat();
|
|
|
|
--worker_stat->num_connections;
|
2014-06-26 15:55:22 +02:00
|
|
|
|
2015-02-04 13:15:58 +01:00
|
|
|
ev_timer_stop(conn_.loop, &reneg_shutdown_timer_);
|
2014-12-27 18:59:06 +01:00
|
|
|
|
2014-08-12 15:22:02 +02:00
|
|
|
// TODO If backend is http/2, and it is in CONNECTED state, signal
|
|
|
|
// it and make it loopbreak when output is zero.
|
2015-02-25 14:53:23 +01:00
|
|
|
if (worker_->get_graceful_shutdown() && worker_stat->num_connections == 0) {
|
2015-02-04 13:15:58 +01:00
|
|
|
ev_break(conn_.loop);
|
2014-06-10 18:16:49 +02:00
|
|
|
}
|
|
|
|
|
2014-11-27 15:39:04 +01:00
|
|
|
if (LOG_ENABLED(INFO)) {
|
2012-12-09 11:15:14 +01:00
|
|
|
CLOG(INFO, this) << "Deleted";
|
2012-06-04 16:48:31 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-27 15:39:04 +01:00
|
|
|
Upstream *ClientHandler::get_upstream() { return upstream_.get(); }
|
2012-06-04 16:48:31 +02:00
|
|
|
|
2014-12-27 18:59:06 +01:00
|
|
|
struct ev_loop *ClientHandler::get_loop() const {
|
2015-02-04 13:15:58 +01:00
|
|
|
return conn_.loop;
|
2012-06-04 16:48:31 +02:00
|
|
|
}
|
|
|
|
|
2014-12-27 18:59:06 +01:00
|
|
|
void ClientHandler::reset_upstream_read_timeout(ev_tstamp t) {
|
2015-02-04 13:15:58 +01:00
|
|
|
conn_.rt.repeat = t;
|
|
|
|
if (ev_is_active(&conn_.rt)) {
|
|
|
|
ev_timer_again(conn_.loop, &conn_.rt);
|
2014-12-27 18:59:06 +01:00
|
|
|
}
|
2012-06-04 16:48:31 +02:00
|
|
|
}
|
|
|
|
|
2014-12-27 18:59:06 +01:00
|
|
|
void ClientHandler::reset_upstream_write_timeout(ev_tstamp t) {
|
2015-02-04 13:15:58 +01:00
|
|
|
conn_.wt.repeat = t;
|
|
|
|
if (ev_is_active(&conn_.wt)) {
|
|
|
|
ev_timer_again(conn_.loop, &conn_.wt);
|
2014-12-27 18:59:06 +01:00
|
|
|
}
|
2012-06-04 16:48:31 +02:00
|
|
|
}
|
|
|
|
|
2014-11-27 15:39:04 +01:00
|
|
|
int ClientHandler::validate_next_proto() {
|
2013-07-26 12:33:25 +02:00
|
|
|
const unsigned char *next_proto = nullptr;
|
2012-06-04 16:48:31 +02:00
|
|
|
unsigned int next_proto_len;
|
2014-06-10 17:07:51 +02:00
|
|
|
int rv;
|
|
|
|
|
2013-07-26 14:35:14 +02:00
|
|
|
// First set callback for catch all cases
|
2014-12-27 18:59:06 +01:00
|
|
|
on_read_ = &ClientHandler::upstream_read;
|
|
|
|
|
2015-02-04 13:15:58 +01:00
|
|
|
SSL_get0_next_proto_negotiated(conn_.tls.ssl, &next_proto, &next_proto_len);
|
2014-11-27 15:39:04 +01:00
|
|
|
for (int i = 0; i < 2; ++i) {
|
|
|
|
if (next_proto) {
|
|
|
|
if (LOG_ENABLED(INFO)) {
|
|
|
|
std::string proto(next_proto, next_proto + next_proto_len);
|
2014-01-01 15:54:28 +01:00
|
|
|
CLOG(INFO, this) << "The negotiated next protocol: " << proto;
|
2013-07-26 13:12:55 +02:00
|
|
|
}
|
2014-11-27 15:39:04 +01:00
|
|
|
if (!ssl::in_proto_list(get_config()->npn_list, next_proto,
|
|
|
|
next_proto_len)) {
|
2014-01-01 16:53:07 +01:00
|
|
|
break;
|
|
|
|
}
|
2014-12-15 14:51:34 +01:00
|
|
|
if (util::check_h2_is_selected(next_proto, next_proto_len) ||
|
|
|
|
(next_proto_len == sizeof("h2-16") - 1 &&
|
|
|
|
memcmp("h2-16", next_proto, next_proto_len) == 0)) {
|
2014-04-26 15:51:39 +02:00
|
|
|
|
2014-12-27 18:59:06 +01:00
|
|
|
on_read_ = &ClientHandler::upstream_http2_connhd_read;
|
2014-06-10 17:07:51 +02:00
|
|
|
|
2015-02-05 15:21:53 +01:00
|
|
|
auto http2_upstream = make_unique<Http2Upstream>(this);
|
2014-06-10 17:07:51 +02:00
|
|
|
|
2015-02-04 13:15:58 +01:00
|
|
|
if (!ssl::check_http2_requirement(conn_.tls.ssl)) {
|
2014-06-10 17:07:51 +02:00
|
|
|
rv = http2_upstream->terminate_session(NGHTTP2_INADEQUATE_SECURITY);
|
|
|
|
|
2014-11-27 15:39:04 +01:00
|
|
|
if (rv != 0) {
|
2014-06-10 17:07:51 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2014-04-26 15:51:39 +02:00
|
|
|
}
|
|
|
|
|
2014-06-10 17:07:51 +02:00
|
|
|
upstream_ = std::move(http2_upstream);
|
2014-11-24 07:22:10 +01:00
|
|
|
alpn_.assign(next_proto, next_proto + next_proto_len);
|
2014-06-10 17:07:51 +02:00
|
|
|
|
2014-06-19 15:40:24 +02:00
|
|
|
// At this point, input buffer is already filled with some
|
|
|
|
// bytes. The read callback is not called until new data
|
|
|
|
// come. So consume input buffer here.
|
2014-12-27 18:59:06 +01:00
|
|
|
if (on_read() != 0) {
|
2014-10-30 13:47:38 +01:00
|
|
|
return -1;
|
|
|
|
}
|
2014-06-19 15:40:24 +02:00
|
|
|
|
2014-01-01 15:54:28 +01:00
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
#ifdef HAVE_SPDYLAY
|
|
|
|
uint16_t version = spdylay_npn_get_version(next_proto, next_proto_len);
|
2014-11-27 15:39:04 +01:00
|
|
|
if (version) {
|
2015-02-05 15:21:53 +01:00
|
|
|
upstream_ = make_unique<SpdyUpstream>(version, this);
|
2014-06-19 15:40:24 +02:00
|
|
|
|
2014-11-27 15:39:04 +01:00
|
|
|
switch (version) {
|
2014-11-24 07:22:10 +01:00
|
|
|
case SPDYLAY_PROTO_SPDY2:
|
|
|
|
alpn_ = "spdy/2";
|
|
|
|
break;
|
|
|
|
case SPDYLAY_PROTO_SPDY3:
|
|
|
|
alpn_ = "spdy/3";
|
|
|
|
break;
|
|
|
|
case SPDYLAY_PROTO_SPDY3_1:
|
|
|
|
alpn_ = "spdy/3.1";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
alpn_ = "spdy/unknown";
|
|
|
|
}
|
|
|
|
|
2014-06-19 15:40:24 +02:00
|
|
|
// At this point, input buffer is already filled with some
|
|
|
|
// bytes. The read callback is not called until new data
|
|
|
|
// come. So consume input buffer here.
|
2014-12-27 18:59:06 +01:00
|
|
|
if (on_read() != 0) {
|
2014-06-19 15:40:24 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-01-01 15:54:28 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2013-07-26 13:12:55 +02:00
|
|
|
#endif // HAVE_SPDYLAY
|
2014-11-27 15:39:04 +01:00
|
|
|
if (next_proto_len == 8 && memcmp("http/1.1", next_proto, 8) == 0) {
|
2015-02-05 15:21:53 +01:00
|
|
|
upstream_ = make_unique<HttpsUpstream>(this);
|
2014-11-24 07:22:10 +01:00
|
|
|
alpn_ = "http/1.1";
|
2014-06-19 15:40:24 +02:00
|
|
|
|
|
|
|
// At this point, input buffer is already filled with some
|
|
|
|
// bytes. The read callback is not called until new data
|
|
|
|
// come. So consume input buffer here.
|
2014-12-27 18:59:06 +01:00
|
|
|
if (on_read() != 0) {
|
2014-06-19 15:40:24 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-01-01 16:53:07 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2014-01-01 15:54:28 +01:00
|
|
|
}
|
|
|
|
break;
|
2012-06-04 16:48:31 +02:00
|
|
|
}
|
2014-01-01 15:54:28 +01:00
|
|
|
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
2015-02-06 13:14:04 +01:00
|
|
|
SSL_get0_alpn_selected(conn_.tls.ssl, &next_proto, &next_proto_len);
|
2014-11-27 15:39:04 +01:00
|
|
|
#else // OPENSSL_VERSION_NUMBER < 0x10002000L
|
2014-01-01 15:54:28 +01:00
|
|
|
break;
|
|
|
|
#endif // OPENSSL_VERSION_NUMBER < 0x10002000L
|
|
|
|
}
|
2014-11-27 15:39:04 +01:00
|
|
|
if (!next_proto) {
|
|
|
|
if (LOG_ENABLED(INFO)) {
|
2014-01-01 16:53:07 +01:00
|
|
|
CLOG(INFO, this) << "No protocol negotiated. Fallback to HTTP/1.1";
|
2012-06-04 16:48:31 +02:00
|
|
|
}
|
2015-02-05 15:21:53 +01:00
|
|
|
upstream_ = make_unique<HttpsUpstream>(this);
|
2014-11-24 07:22:10 +01:00
|
|
|
alpn_ = "http/1.1";
|
2014-06-19 15:40:24 +02:00
|
|
|
|
|
|
|
// At this point, input buffer is already filled with some bytes.
|
|
|
|
// The read callback is not called until new data come. So consume
|
|
|
|
// input buffer here.
|
2014-12-27 18:59:06 +01:00
|
|
|
if (on_read() != 0) {
|
2014-06-19 15:40:24 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-01-01 16:53:07 +01:00
|
|
|
return 0;
|
2012-06-04 16:48:31 +02:00
|
|
|
}
|
2014-11-27 15:39:04 +01:00
|
|
|
if (LOG_ENABLED(INFO)) {
|
2014-01-01 16:53:07 +01:00
|
|
|
CLOG(INFO, this) << "The negotiated protocol is not supported";
|
2012-06-05 18:26:04 +02:00
|
|
|
}
|
2014-01-01 16:53:07 +01:00
|
|
|
return -1;
|
2012-06-04 16:48:31 +02:00
|
|
|
}
|
|
|
|
|
2014-12-27 18:59:06 +01:00
|
|
|
int ClientHandler::do_read() { return read_(*this); }
|
|
|
|
int ClientHandler::do_write() { return write_(*this); }
|
2014-10-30 13:47:38 +01:00
|
|
|
|
2014-12-27 18:59:06 +01:00
|
|
|
int ClientHandler::on_read() { return on_read_(*this); }
|
|
|
|
int ClientHandler::on_write() { return on_write_(*this); }
|
2014-10-30 13:47:38 +01:00
|
|
|
|
2014-11-27 15:39:04 +01:00
|
|
|
const std::string &ClientHandler::get_ipaddr() const { return ipaddr_; }
|
2012-06-04 16:48:31 +02:00
|
|
|
|
2014-11-27 15:39:04 +01:00
|
|
|
bool ClientHandler::get_should_close_after_write() const {
|
2012-06-04 16:48:31 +02:00
|
|
|
return should_close_after_write_;
|
|
|
|
}
|
|
|
|
|
2014-11-27 15:39:04 +01:00
|
|
|
void ClientHandler::set_should_close_after_write(bool f) {
|
2012-06-04 16:48:31 +02:00
|
|
|
should_close_after_write_ = f;
|
|
|
|
}
|
|
|
|
|
2014-11-27 15:39:04 +01:00
|
|
|
void ClientHandler::pool_downstream_connection(
|
|
|
|
std::unique_ptr<DownstreamConnection> dconn) {
|
2015-03-10 15:11:22 +01:00
|
|
|
if (!dconn->poolable()) {
|
|
|
|
return;
|
|
|
|
}
|
2014-11-27 15:39:04 +01:00
|
|
|
if (LOG_ENABLED(INFO)) {
|
2014-08-18 17:16:51 +02:00
|
|
|
CLOG(INFO, this) << "Pooling downstream connection DCONN:" << dconn.get();
|
2012-06-09 16:14:00 +02:00
|
|
|
}
|
2014-10-13 14:09:00 +02:00
|
|
|
dconn->set_client_handler(nullptr);
|
2015-02-11 11:18:41 +01:00
|
|
|
auto dconn_pool = worker_->get_dconn_pool();
|
|
|
|
dconn_pool->add_downstream_connection(std::move(dconn));
|
2012-06-09 16:14:00 +02:00
|
|
|
}
|
|
|
|
|
2014-11-27 15:39:04 +01:00
|
|
|
void ClientHandler::remove_downstream_connection(DownstreamConnection *dconn) {
|
|
|
|
if (LOG_ENABLED(INFO)) {
|
2012-12-09 11:15:14 +01:00
|
|
|
CLOG(INFO, this) << "Removing downstream connection DCONN:" << dconn
|
|
|
|
<< " from pool";
|
2012-06-09 16:14:00 +02:00
|
|
|
}
|
2015-02-11 11:18:41 +01:00
|
|
|
auto dconn_pool = worker_->get_dconn_pool();
|
|
|
|
dconn_pool->remove_downstream_connection(dconn);
|
2012-06-09 16:14:00 +02:00
|
|
|
}
|
|
|
|
|
2014-08-18 17:16:51 +02:00
|
|
|
std::unique_ptr<DownstreamConnection>
|
2014-11-27 15:39:04 +01:00
|
|
|
ClientHandler::get_downstream_connection() {
|
2015-02-11 11:18:41 +01:00
|
|
|
auto dconn_pool = worker_->get_dconn_pool();
|
|
|
|
auto dconn = dconn_pool->pop_downstream_connection();
|
2014-10-13 14:09:00 +02:00
|
|
|
|
2014-11-27 15:39:04 +01:00
|
|
|
if (!dconn) {
|
|
|
|
if (LOG_ENABLED(INFO)) {
|
2012-12-09 11:15:14 +01:00
|
|
|
CLOG(INFO, this) << "Downstream connection pool is empty."
|
|
|
|
<< " Create new one";
|
2012-06-09 16:14:00 +02:00
|
|
|
}
|
2014-10-13 14:09:00 +02:00
|
|
|
|
2015-02-11 11:18:41 +01:00
|
|
|
auto dconn_pool = worker_->get_dconn_pool();
|
|
|
|
|
2015-03-11 13:14:55 +01:00
|
|
|
if (http2session_) {
|
|
|
|
dconn = make_unique<Http2DownstreamConnection>(dconn_pool, http2session_);
|
2015-02-05 15:21:53 +01:00
|
|
|
} else {
|
2015-02-11 11:18:41 +01:00
|
|
|
dconn = make_unique<HttpDownstreamConnection>(dconn_pool, conn_.loop);
|
2012-11-18 13:23:13 +01:00
|
|
|
}
|
2014-10-13 14:09:00 +02:00
|
|
|
dconn->set_client_handler(this);
|
|
|
|
return dconn;
|
2012-06-09 16:14:00 +02:00
|
|
|
}
|
2014-08-18 17:16:51 +02:00
|
|
|
|
2014-10-13 14:09:00 +02:00
|
|
|
dconn->set_client_handler(this);
|
|
|
|
|
2014-11-27 15:39:04 +01:00
|
|
|
if (LOG_ENABLED(INFO)) {
|
2014-08-18 17:16:51 +02:00
|
|
|
CLOG(INFO, this) << "Reuse downstream connection DCONN:" << dconn.get()
|
|
|
|
<< " from pool";
|
|
|
|
}
|
|
|
|
|
|
|
|
return dconn;
|
2012-06-09 16:14:00 +02:00
|
|
|
}
|
|
|
|
|
2015-02-04 13:15:58 +01:00
|
|
|
SSL *ClientHandler::get_ssl() const { return conn_.tls.ssl; }
|
2012-07-14 16:24:03 +02:00
|
|
|
|
2015-03-10 15:11:22 +01:00
|
|
|
ConnectBlocker *ClientHandler::get_connect_blocker() const {
|
|
|
|
return worker_->get_connect_blocker();
|
2014-08-19 16:36:04 +02:00
|
|
|
}
|
|
|
|
|
2014-11-27 15:39:04 +01:00
|
|
|
void ClientHandler::direct_http2_upgrade() {
|
2015-02-05 15:21:53 +01:00
|
|
|
upstream_ = make_unique<Http2Upstream>(this);
|
2014-11-24 07:22:10 +01:00
|
|
|
// TODO We don't know exact h2 draft version in direct upgrade. We
|
|
|
|
// just use library default for now.
|
|
|
|
alpn_ = NGHTTP2_CLEARTEXT_PROTO_VERSION_ID;
|
2014-12-27 18:59:06 +01:00
|
|
|
on_read_ = &ClientHandler::upstream_read;
|
2013-08-03 11:51:01 +02:00
|
|
|
}
|
|
|
|
|
2014-11-27 15:39:04 +01:00
|
|
|
int ClientHandler::perform_http2_upgrade(HttpsUpstream *http) {
|
2015-02-05 15:21:53 +01:00
|
|
|
auto upstream = make_unique<Http2Upstream>(this);
|
2014-11-27 15:39:04 +01:00
|
|
|
if (upstream->upgrade_upstream(http) != 0) {
|
2013-08-03 11:51:01 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2013-09-26 14:39:19 +02:00
|
|
|
// http pointer is now owned by upstream.
|
|
|
|
upstream_.release();
|
2013-09-23 17:02:02 +02:00
|
|
|
upstream_ = std::move(upstream);
|
2014-11-24 07:22:10 +01:00
|
|
|
// TODO We might get other version id in HTTP2-settings, if we
|
|
|
|
// support aliasing for h2, but we just use library default for now.
|
|
|
|
alpn_ = NGHTTP2_CLEARTEXT_PROTO_VERSION_ID;
|
2014-12-27 18:59:06 +01:00
|
|
|
on_read_ = &ClientHandler::upstream_http2_connhd_read;
|
|
|
|
|
2013-08-03 11:51:01 +02:00
|
|
|
static char res[] = "HTTP/1.1 101 Switching Protocols\r\n"
|
2014-11-27 15:39:04 +01:00
|
|
|
"Connection: Upgrade\r\n"
|
|
|
|
"Upgrade: " NGHTTP2_CLEARTEXT_PROTO_VERSION_ID "\r\n"
|
|
|
|
"\r\n";
|
2014-12-27 18:59:06 +01:00
|
|
|
wb_.write(res, sizeof(res) - 1);
|
2015-03-01 02:11:45 +01:00
|
|
|
signal_write();
|
2013-08-03 11:51:01 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-02-04 13:15:58 +01:00
|
|
|
bool ClientHandler::get_http2_upgrade_allowed() const { return !conn_.tls.ssl; }
|
2013-08-03 11:51:01 +02:00
|
|
|
|
2014-11-27 15:39:04 +01:00
|
|
|
std::string ClientHandler::get_upstream_scheme() const {
|
2015-02-04 13:15:58 +01:00
|
|
|
if (conn_.tls.ssl) {
|
2013-12-21 09:49:31 +01:00
|
|
|
return "https";
|
|
|
|
} else {
|
|
|
|
return "http";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-04 13:15:58 +01:00
|
|
|
void ClientHandler::start_immediate_shutdown() {
|
|
|
|
ev_timer_start(conn_.loop, &reneg_shutdown_timer_);
|
2014-11-05 16:56:07 +01:00
|
|
|
}
|
|
|
|
|
2014-11-27 15:39:04 +01:00
|
|
|
void ClientHandler::write_accesslog(Downstream *downstream) {
|
2014-11-18 16:56:44 +01:00
|
|
|
LogSpec lgsp = {
|
2014-11-27 15:39:04 +01:00
|
|
|
downstream, ipaddr_.c_str(), downstream->get_request_method().c_str(),
|
|
|
|
|
|
|
|
downstream->get_request_path().empty()
|
|
|
|
? downstream->get_request_http2_authority().c_str()
|
|
|
|
: downstream->get_request_path().c_str(),
|
|
|
|
|
|
|
|
alpn_.c_str(),
|
|
|
|
|
2015-01-06 15:10:11 +01:00
|
|
|
std::chrono::system_clock::now(), // time_now
|
|
|
|
downstream->get_request_start_time(), // request_start_time
|
|
|
|
std::chrono::high_resolution_clock::now(), // request_end_time
|
2014-11-27 15:39:04 +01:00
|
|
|
|
|
|
|
downstream->get_request_major(), downstream->get_request_minor(),
|
|
|
|
downstream->get_response_http_status(),
|
|
|
|
downstream->get_response_sent_bodylen(), port_.c_str(),
|
|
|
|
get_config()->port, get_config()->pid,
|
2014-11-18 16:56:44 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
upstream_accesslog(get_config()->accesslog_format, &lgsp);
|
|
|
|
}
|
|
|
|
|
2014-11-27 15:39:04 +01:00
|
|
|
void ClientHandler::write_accesslog(int major, int minor, unsigned int status,
|
|
|
|
int64_t body_bytes_sent) {
|
2015-01-06 15:10:11 +01:00
|
|
|
auto time_now = std::chrono::system_clock::now();
|
|
|
|
auto highres_now = std::chrono::high_resolution_clock::now();
|
|
|
|
|
2014-11-18 16:56:44 +01:00
|
|
|
LogSpec lgsp = {
|
2015-01-06 15:10:11 +01:00
|
|
|
nullptr, ipaddr_.c_str(),
|
2014-11-27 15:39:04 +01:00
|
|
|
"-", // method
|
|
|
|
"-", // path,
|
2015-01-06 15:10:11 +01:00
|
|
|
alpn_.c_str(), time_now,
|
|
|
|
highres_now, // request_start_time TODO is
|
|
|
|
// there a better value?
|
|
|
|
highres_now, // request_end_time
|
|
|
|
major, minor, // major, minor
|
|
|
|
status, body_bytes_sent, port_.c_str(),
|
|
|
|
get_config()->port, get_config()->pid,
|
2014-11-18 16:56:44 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
upstream_accesslog(get_config()->accesslog_format, &lgsp);
|
|
|
|
}
|
|
|
|
|
2015-01-08 13:28:52 +01:00
|
|
|
ClientHandler::WriteBuf *ClientHandler::get_wb() { return &wb_; }
|
2014-12-27 18:59:06 +01:00
|
|
|
|
2015-01-08 13:28:52 +01:00
|
|
|
ClientHandler::ReadBuf *ClientHandler::get_rb() { return &rb_; }
|
2014-12-27 18:59:06 +01:00
|
|
|
|
2015-02-04 13:15:58 +01:00
|
|
|
void ClientHandler::signal_write() { conn_.wlimit.startw(); }
|
2014-12-27 18:59:06 +01:00
|
|
|
|
2015-02-04 13:15:58 +01:00
|
|
|
RateLimit *ClientHandler::get_rlimit() { return &conn_.rlimit; }
|
|
|
|
RateLimit *ClientHandler::get_wlimit() { return &conn_.wlimit; }
|
2014-12-27 18:59:06 +01:00
|
|
|
|
2015-02-10 16:44:30 +01:00
|
|
|
ev_io *ClientHandler::get_wev() { return &conn_.wev; }
|
|
|
|
|
2015-02-11 11:18:41 +01:00
|
|
|
Worker *ClientHandler::get_worker() const { return worker_; }
|
|
|
|
|
2012-06-04 16:48:31 +02:00
|
|
|
} // namespace shrpx
|