nghttpx: Avoid last buffer copy when HTTP/1.1 is used
This commit is contained in:
parent
a5b0ad04d3
commit
fe79b6d118
|
@ -164,6 +164,47 @@ int ClientHandler::write_clear() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ClientHandler::writev_clear() {
|
||||||
|
ev_timer_again(conn_.loop, &conn_.rt);
|
||||||
|
|
||||||
|
auto buf = upstream_->get_response_buf();
|
||||||
|
if (!buf) {
|
||||||
|
conn_.wlimit.stopw();
|
||||||
|
ev_timer_stop(conn_.loop, &conn_.wt);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
if (buf->rleft() > 0) {
|
||||||
|
std::array<iovec, 2> iov;
|
||||||
|
auto iovcnt = buf->riovec(iov.data(), iov.size());
|
||||||
|
auto nwrite = conn_.writev_clear(iov.data(), iovcnt);
|
||||||
|
if (nwrite == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (nwrite < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
buf->drain(nwrite);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (on_write() != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
// buf may be destroyed inside on_write()
|
||||||
|
buf = upstream_->get_response_buf();
|
||||||
|
if (!buf || buf->rleft() == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
conn_.wlimit.stopw();
|
||||||
|
ev_timer_stop(conn_.loop, &conn_.wt);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int ClientHandler::tls_handshake() {
|
int ClientHandler::tls_handshake() {
|
||||||
ev_timer_again(conn_.loop, &conn_.rt);
|
ev_timer_again(conn_.loop, &conn_.rt);
|
||||||
|
|
||||||
|
@ -188,7 +229,12 @@ int ClientHandler::tls_handshake() {
|
||||||
}
|
}
|
||||||
|
|
||||||
read_ = &ClientHandler::read_tls;
|
read_ = &ClientHandler::read_tls;
|
||||||
write_ = &ClientHandler::write_tls;
|
|
||||||
|
if (alpn_ == "http/1.1") {
|
||||||
|
write_ = &ClientHandler::writev_tls;
|
||||||
|
} else {
|
||||||
|
write_ = &ClientHandler::write_tls;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -261,6 +307,57 @@ int ClientHandler::write_tls() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ClientHandler::writev_tls() {
|
||||||
|
ev_timer_again(conn_.loop, &conn_.rt);
|
||||||
|
|
||||||
|
auto buf = upstream_->get_response_buf();
|
||||||
|
if (!buf) {
|
||||||
|
conn_.wlimit.stopw();
|
||||||
|
ev_timer_stop(conn_.loop, &conn_.wt);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ERR_clear_error();
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
if (buf->rleft() > 0) {
|
||||||
|
iovec iov;
|
||||||
|
auto iovcnt = buf->riovec(&iov, 1);
|
||||||
|
if (iovcnt == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto nwrite = conn_.write_tls(iov.iov_base, iov.iov_len);
|
||||||
|
|
||||||
|
if (nwrite == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nwrite < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf->drain(nwrite);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (on_write() != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
buf = upstream_->get_response_buf();
|
||||||
|
if (!buf || buf->rleft() == 0) {
|
||||||
|
conn_.start_tls_write_idle();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
conn_.wlimit.stopw();
|
||||||
|
ev_timer_stop(conn_.loop, &conn_.wt);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int ClientHandler::upstream_noop() { return 0; }
|
int ClientHandler::upstream_noop() { return 0; }
|
||||||
|
|
||||||
int ClientHandler::upstream_read() {
|
int ClientHandler::upstream_read() {
|
||||||
|
@ -277,7 +374,9 @@ int ClientHandler::upstream_write() {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (get_should_close_after_write() && wb_.rleft() == 0) {
|
if (get_should_close_after_write() && wb_.rleft() == 0 &&
|
||||||
|
(!upstream_->get_response_buf() ||
|
||||||
|
upstream_->get_response_buf()->rleft() == 0)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -407,7 +506,7 @@ void ClientHandler::setup_upstream_io_callback() {
|
||||||
upstream_ = make_unique<HttpsUpstream>(this);
|
upstream_ = make_unique<HttpsUpstream>(this);
|
||||||
alpn_ = "http/1.1";
|
alpn_ = "http/1.1";
|
||||||
read_ = &ClientHandler::read_clear;
|
read_ = &ClientHandler::read_clear;
|
||||||
write_ = &ClientHandler::write_clear;
|
write_ = &ClientHandler::writev_clear;
|
||||||
on_read_ = &ClientHandler::upstream_http1_connhd_read;
|
on_read_ = &ClientHandler::upstream_http1_connhd_read;
|
||||||
on_write_ = &ClientHandler::upstream_noop;
|
on_write_ = &ClientHandler::upstream_noop;
|
||||||
}
|
}
|
||||||
|
@ -709,6 +808,7 @@ void ClientHandler::direct_http2_upgrade() {
|
||||||
upstream_ = make_unique<Http2Upstream>(this);
|
upstream_ = make_unique<Http2Upstream>(this);
|
||||||
alpn_ = NGHTTP2_CLEARTEXT_PROTO_VERSION_ID;
|
alpn_ = NGHTTP2_CLEARTEXT_PROTO_VERSION_ID;
|
||||||
on_read_ = &ClientHandler::upstream_read;
|
on_read_ = &ClientHandler::upstream_read;
|
||||||
|
write_ = &ClientHandler::write_clear;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ClientHandler::perform_http2_upgrade(HttpsUpstream *http) {
|
int ClientHandler::perform_http2_upgrade(HttpsUpstream *http) {
|
||||||
|
@ -723,6 +823,7 @@ int ClientHandler::perform_http2_upgrade(HttpsUpstream *http) {
|
||||||
// support aliasing for h2, but we just use library default for now.
|
// support aliasing for h2, but we just use library default for now.
|
||||||
alpn_ = NGHTTP2_CLEARTEXT_PROTO_VERSION_ID;
|
alpn_ = NGHTTP2_CLEARTEXT_PROTO_VERSION_ID;
|
||||||
on_read_ = &ClientHandler::upstream_http2_connhd_read;
|
on_read_ = &ClientHandler::upstream_http2_connhd_read;
|
||||||
|
write_ = &ClientHandler::write_clear;
|
||||||
|
|
||||||
static char res[] = "HTTP/1.1 101 Switching Protocols\r\n"
|
static char res[] = "HTTP/1.1 101 Switching Protocols\r\n"
|
||||||
"Connection: Upgrade\r\n"
|
"Connection: Upgrade\r\n"
|
||||||
|
|
|
@ -60,11 +60,13 @@ public:
|
||||||
// Performs clear text I/O
|
// Performs clear text I/O
|
||||||
int read_clear();
|
int read_clear();
|
||||||
int write_clear();
|
int write_clear();
|
||||||
|
int writev_clear();
|
||||||
// Performs TLS handshake
|
// Performs TLS handshake
|
||||||
int tls_handshake();
|
int tls_handshake();
|
||||||
// Performs TLS I/O
|
// Performs TLS I/O
|
||||||
int read_tls();
|
int read_tls();
|
||||||
int write_tls();
|
int write_tls();
|
||||||
|
int writev_tls();
|
||||||
|
|
||||||
int upstream_noop();
|
int upstream_noop();
|
||||||
int upstream_read();
|
int upstream_read();
|
||||||
|
|
|
@ -571,10 +571,6 @@ int HttpsUpstream::on_write() {
|
||||||
if (!downstream) {
|
if (!downstream) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
auto wb = handler_->get_wb();
|
|
||||||
if (wb->wleft() == 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto dconn = downstream->get_downstream_connection();
|
auto dconn = downstream->get_downstream_connection();
|
||||||
auto output = downstream->get_response_buf();
|
auto output = downstream->get_response_buf();
|
||||||
|
@ -591,10 +587,7 @@ int HttpsUpstream::on_write() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto n = output->remove(wb->last, wb->wleft());
|
if (output->rleft() > 0) {
|
||||||
wb->write(n);
|
|
||||||
|
|
||||||
if (wb->rleft() > 0) {
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1167,4 +1160,12 @@ int HttpsUpstream::initiate_push(Downstream *downstream, const char *uri,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DefaultMemchunks *HttpsUpstream::get_response_buf() const {
|
||||||
|
if (!downstream_) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return downstream_->get_response_buf();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace shrpx
|
} // namespace shrpx
|
||||||
|
|
|
@ -78,6 +78,7 @@ public:
|
||||||
size_t bodylen);
|
size_t bodylen);
|
||||||
virtual int initiate_push(Downstream *downstream, const char *uri,
|
virtual int initiate_push(Downstream *downstream, const char *uri,
|
||||||
size_t len);
|
size_t len);
|
||||||
|
virtual DefaultMemchunks *get_response_buf() const;
|
||||||
|
|
||||||
void reset_current_header_length();
|
void reset_current_header_length();
|
||||||
void log_response_headers(DefaultMemchunks *buf) const;
|
void log_response_headers(DefaultMemchunks *buf) const;
|
||||||
|
|
|
@ -27,6 +27,9 @@
|
||||||
|
|
||||||
#include "shrpx.h"
|
#include "shrpx.h"
|
||||||
#include "shrpx_io_control.h"
|
#include "shrpx_io_control.h"
|
||||||
|
#include "memchunk.h"
|
||||||
|
|
||||||
|
using namespace nghttp2;
|
||||||
|
|
||||||
namespace shrpx {
|
namespace shrpx {
|
||||||
|
|
||||||
|
@ -67,6 +70,10 @@ public:
|
||||||
|
|
||||||
virtual int initiate_push(Downstream *downstream, const char *uri,
|
virtual int initiate_push(Downstream *downstream, const char *uri,
|
||||||
size_t len) = 0;
|
size_t len) = 0;
|
||||||
|
|
||||||
|
// Returns response buffer of Downstream directly. This exists for
|
||||||
|
// optimization purpose for cleartext HttpsUpstream.
|
||||||
|
virtual DefaultMemchunks *get_response_buf() const { return nullptr; }
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace shrpx
|
} // namespace shrpx
|
||||||
|
|
Loading…
Reference in New Issue