shrpx: Send pending response data before RST_STREAM in tunnel connection
This commit is contained in:
parent
98d18e647f
commit
d830e099a6
|
@ -378,6 +378,20 @@ void https_downstream_readcb(bufferevent *bev, void *ptr)
|
||||||
delete upstream->get_client_handler();
|
delete upstream->get_client_handler();
|
||||||
} else if(rv == 0) {
|
} else if(rv == 0) {
|
||||||
if(downstream->get_response_state() == Downstream::MSG_COMPLETE) {
|
if(downstream->get_response_state() == Downstream::MSG_COMPLETE) {
|
||||||
|
if(get_config()->client_mode && downstream->tunnel_established()) {
|
||||||
|
// For tunneled connection, if there is no pending data,
|
||||||
|
// delete handler because on_write will not be called.
|
||||||
|
ClientHandler *handler = upstream->get_client_handler();
|
||||||
|
if(handler->get_pending_write_length() == 0) {
|
||||||
|
delete handler;
|
||||||
|
} else {
|
||||||
|
if(LOG_ENABLED(INFO)) {
|
||||||
|
DLOG(INFO, downstream) << "Tunneled connection has pending data";
|
||||||
|
}
|
||||||
|
handler->set_should_close_after_write(true);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
if(downstream->get_response_connection_close()) {
|
if(downstream->get_response_connection_close()) {
|
||||||
// Connection close
|
// Connection close
|
||||||
downstream->set_downstream_connection(0);
|
downstream->set_downstream_connection(0);
|
||||||
|
|
|
@ -697,9 +697,22 @@ void on_ctrl_recv_callback
|
||||||
if(downstream &&
|
if(downstream &&
|
||||||
downstream->get_downstream_stream_id() ==
|
downstream->get_downstream_stream_id() ==
|
||||||
frame->rst_stream.stream_id) {
|
frame->rst_stream.stream_id) {
|
||||||
|
if(downstream->tunnel_established() &&
|
||||||
|
downstream->get_response_state() == Downstream::HEADER_COMPLETE) {
|
||||||
|
// For tunneled connection, we has to submit RST_STREAM to
|
||||||
|
// upstream *after* whole response body is sent. We just set
|
||||||
|
// MSG_COMPLETE here. Upstream will take care of that.
|
||||||
|
if(LOG_ENABLED(INFO)) {
|
||||||
|
SSLOG(INFO, spdy) << "RST_STREAM against tunneled stream "
|
||||||
|
<< "stream_id="
|
||||||
|
<< frame->rst_stream.stream_id;
|
||||||
|
}
|
||||||
|
downstream->set_response_state(Downstream::MSG_COMPLETE);
|
||||||
|
} else {
|
||||||
// If we got RST_STREAM, just flag MSG_RESET to indicate
|
// If we got RST_STREAM, just flag MSG_RESET to indicate
|
||||||
// upstream connection must be terminated.
|
// upstream connection must be terminated.
|
||||||
downstream->set_response_state(Downstream::MSG_RESET);
|
downstream->set_response_state(Downstream::MSG_RESET);
|
||||||
|
}
|
||||||
call_downstream_readcb(spdy, downstream);
|
call_downstream_readcb(spdy, downstream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -543,11 +543,12 @@ void spdy_downstream_eventcb(bufferevent *bev, short events, void *ptr)
|
||||||
ULOG(INFO, upstream) << "Downstream body was ended by EOF";
|
ULOG(INFO, upstream) << "Downstream body was ended by EOF";
|
||||||
}
|
}
|
||||||
downstream->set_response_state(Downstream::MSG_COMPLETE);
|
downstream->set_response_state(Downstream::MSG_COMPLETE);
|
||||||
if(downstream->tunnel_established()) {
|
|
||||||
upstream->rst_stream(downstream, SPDYLAY_INTERNAL_ERROR);
|
// For tunneled connection, MSG_COMPLETE signals
|
||||||
} else {
|
// spdy_data_read_callback to send RST_STREAM after pending
|
||||||
|
// response body is sent. This is needed to ensure that
|
||||||
|
// RST_STREAM is sent after all pending data are sent.
|
||||||
upstream->on_downstream_body_complete(downstream);
|
upstream->on_downstream_body_complete(downstream);
|
||||||
}
|
|
||||||
} else if(downstream->get_response_state() == Downstream::MSG_COMPLETE) {
|
} else if(downstream->get_response_state() == Downstream::MSG_COMPLETE) {
|
||||||
// For SSL tunneling?
|
// For SSL tunneling?
|
||||||
upstream->rst_stream(downstream, SPDYLAY_INTERNAL_ERROR);
|
upstream->rst_stream(downstream, SPDYLAY_INTERNAL_ERROR);
|
||||||
|
@ -661,11 +662,20 @@ ssize_t spdy_data_read_callback(spdylay_session *session,
|
||||||
evbuffer *body = downstream->get_response_body_buf();
|
evbuffer *body = downstream->get_response_body_buf();
|
||||||
assert(body);
|
assert(body);
|
||||||
int nread = evbuffer_remove(body, buf, length);
|
int nread = evbuffer_remove(body, buf, length);
|
||||||
// For tunneling, DATA stream is endless
|
if(nread == 0 &&
|
||||||
if(!downstream->tunnel_established() &&
|
|
||||||
nread == 0 &&
|
|
||||||
downstream->get_response_state() == Downstream::MSG_COMPLETE) {
|
downstream->get_response_state() == Downstream::MSG_COMPLETE) {
|
||||||
|
if(!downstream->tunnel_established()) {
|
||||||
*eof = 1;
|
*eof = 1;
|
||||||
|
} else {
|
||||||
|
// For tunneling, issue RST_STREAM to finish the stream.
|
||||||
|
SpdyUpstream *upstream;
|
||||||
|
upstream = reinterpret_cast<SpdyUpstream*>(downstream->get_upstream());
|
||||||
|
if(LOG_ENABLED(INFO)) {
|
||||||
|
ULOG(INFO, upstream) << "RST_STREAM to tunneled stream stream_id="
|
||||||
|
<< stream_id;
|
||||||
|
}
|
||||||
|
upstream->rst_stream(downstream, SPDYLAY_CANCEL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if(nread == 0 && *eof != 1) {
|
if(nread == 0 && *eof != 1) {
|
||||||
return SPDYLAY_ERR_DEFERRED;
|
return SPDYLAY_ERR_DEFERRED;
|
||||||
|
|
Loading…
Reference in New Issue