commit
2d8059a9a5
|
@ -152,6 +152,8 @@ LOGVARS = [
|
||||||
"ssl_protocol",
|
"ssl_protocol",
|
||||||
"ssl_session_id",
|
"ssl_session_id",
|
||||||
"ssl_session_reused",
|
"ssl_session_reused",
|
||||||
|
"backend_host",
|
||||||
|
"backend_port",
|
||||||
]
|
]
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
@ -668,6 +668,10 @@ typedef enum {
|
||||||
/**
|
/**
|
||||||
* @macro
|
* @macro
|
||||||
*
|
*
|
||||||
|
* .. warning::
|
||||||
|
*
|
||||||
|
* Deprecated. The initial max concurrent streams is 0xffffffffu.
|
||||||
|
*
|
||||||
* Default maximum number of incoming concurrent streams. Use
|
* Default maximum number of incoming concurrent streams. Use
|
||||||
* `nghttp2_submit_settings()` with
|
* `nghttp2_submit_settings()` with
|
||||||
* :enum:`NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS` to change the
|
* :enum:`NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS` to change the
|
||||||
|
|
|
@ -532,7 +532,7 @@ static void hd_map_insert(nghttp2_hd_map *map, nghttp2_hd_entry *ent) {
|
||||||
|
|
||||||
static nghttp2_hd_entry *hd_map_find(nghttp2_hd_map *map, int *exact_match,
|
static nghttp2_hd_entry *hd_map_find(nghttp2_hd_map *map, int *exact_match,
|
||||||
const nghttp2_nv *nv, int32_t token,
|
const nghttp2_nv *nv, int32_t token,
|
||||||
uint32_t hash) {
|
uint32_t hash, int name_only) {
|
||||||
nghttp2_hd_entry *p;
|
nghttp2_hd_entry *p;
|
||||||
nghttp2_hd_entry *res = NULL;
|
nghttp2_hd_entry *res = NULL;
|
||||||
|
|
||||||
|
@ -545,6 +545,9 @@ static nghttp2_hd_entry *hd_map_find(nghttp2_hd_map *map, int *exact_match,
|
||||||
}
|
}
|
||||||
if (!res) {
|
if (!res) {
|
||||||
res = p;
|
res = p;
|
||||||
|
if (name_only) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (value_eq(&p->nv, nv)) {
|
if (value_eq(&p->nv, nv)) {
|
||||||
res = p;
|
res = p;
|
||||||
|
@ -1148,16 +1151,16 @@ static int add_hd_table_incremental(nghttp2_hd_context *context,
|
||||||
typedef struct {
|
typedef struct {
|
||||||
ssize_t index;
|
ssize_t index;
|
||||||
/* Nonzero if both name and value are matched. */
|
/* Nonzero if both name and value are matched. */
|
||||||
uint8_t name_value_match;
|
int name_value_match;
|
||||||
} search_result;
|
} search_result;
|
||||||
|
|
||||||
static search_result search_static_table(const nghttp2_nv *nv, int32_t token,
|
static search_result search_static_table(const nghttp2_nv *nv, int32_t token,
|
||||||
int indexing_mode) {
|
int name_only) {
|
||||||
search_result res = {token, 0};
|
search_result res = {token, 0};
|
||||||
int i;
|
int i;
|
||||||
nghttp2_hd_static_entry *ent;
|
nghttp2_hd_static_entry *ent;
|
||||||
|
|
||||||
if (indexing_mode == NGHTTP2_HD_NEVER_INDEXING) {
|
if (name_only) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1182,30 +1185,22 @@ static search_result search_hd_table(nghttp2_hd_context *context,
|
||||||
search_result res = {-1, 0};
|
search_result res = {-1, 0};
|
||||||
nghttp2_hd_entry *ent;
|
nghttp2_hd_entry *ent;
|
||||||
int exact_match;
|
int exact_match;
|
||||||
|
int name_only = indexing_mode == NGHTTP2_HD_NEVER_INDEXING;
|
||||||
if (token >= 0 && token <= NGHTTP2_TOKEN_WWW_AUTHENTICATE) {
|
|
||||||
res = search_static_table(nv, token, indexing_mode);
|
|
||||||
if (res.name_value_match) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
exact_match = 0;
|
exact_match = 0;
|
||||||
ent = hd_map_find(map, &exact_match, nv, token, hash);
|
ent = hd_map_find(map, &exact_match, nv, token, hash, name_only);
|
||||||
if (ent == NULL) {
|
|
||||||
return res;
|
if (!exact_match && token >= 0 && token <= NGHTTP2_TOKEN_WWW_AUTHENTICATE) {
|
||||||
|
return search_static_table(nv, token, name_only);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res.index != -1 && !exact_match) {
|
if (ent == NULL) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
res.index =
|
res.index =
|
||||||
(ssize_t)(context->next_seq - 1 - ent->seq + NGHTTP2_STATIC_TABLE_LENGTH);
|
(ssize_t)(context->next_seq - 1 - ent->seq + NGHTTP2_STATIC_TABLE_LENGTH);
|
||||||
|
res.name_value_match = exact_match;
|
||||||
if (exact_match) {
|
|
||||||
res.name_value_match = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
|
@ -365,7 +365,7 @@ static void session_inbound_frame_reset(nghttp2_session *session) {
|
||||||
static void init_settings(nghttp2_settings_storage *settings) {
|
static void init_settings(nghttp2_settings_storage *settings) {
|
||||||
settings->header_table_size = NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE;
|
settings->header_table_size = NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE;
|
||||||
settings->enable_push = 1;
|
settings->enable_push = 1;
|
||||||
settings->max_concurrent_streams = NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS;
|
settings->max_concurrent_streams = NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS;
|
||||||
settings->initial_window_size = NGHTTP2_INITIAL_WINDOW_SIZE;
|
settings->initial_window_size = NGHTTP2_INITIAL_WINDOW_SIZE;
|
||||||
settings->max_frame_size = NGHTTP2_MAX_FRAME_SIZE_MIN;
|
settings->max_frame_size = NGHTTP2_MAX_FRAME_SIZE_MIN;
|
||||||
settings->max_header_list_size = UINT32_MAX;
|
settings->max_header_list_size = UINT32_MAX;
|
||||||
|
@ -435,7 +435,7 @@ static int session_new(nghttp2_session **session_ptr,
|
||||||
(*session_ptr)->remote_last_stream_id = (1u << 31) - 1;
|
(*session_ptr)->remote_last_stream_id = (1u << 31) - 1;
|
||||||
|
|
||||||
(*session_ptr)->pending_local_max_concurrent_stream =
|
(*session_ptr)->pending_local_max_concurrent_stream =
|
||||||
NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS;
|
NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS;
|
||||||
(*session_ptr)->pending_enable_push = 1;
|
(*session_ptr)->pending_enable_push = 1;
|
||||||
|
|
||||||
if (server) {
|
if (server) {
|
||||||
|
@ -772,7 +772,7 @@ int nghttp2_session_reprioritize_stream(
|
||||||
stream->stream_id));
|
stream->stream_id));
|
||||||
|
|
||||||
nghttp2_stream_dep_remove_subtree(dep_stream);
|
nghttp2_stream_dep_remove_subtree(dep_stream);
|
||||||
rv = nghttp2_stream_dep_add_subtree(&session->root, dep_stream);
|
rv = nghttp2_stream_dep_add_subtree(stream->dep_prev, dep_stream);
|
||||||
if (rv != 0) {
|
if (rv != 0) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -1185,13 +1185,11 @@ int nghttp2_session_close_stream(nghttp2_session *session, int32_t stream_id,
|
||||||
combined with the current active incoming streams to make
|
combined with the current active incoming streams to make
|
||||||
dependency tree work better. */
|
dependency tree work better. */
|
||||||
nghttp2_session_keep_closed_stream(session, stream);
|
nghttp2_session_keep_closed_stream(session, stream);
|
||||||
|
|
||||||
rv = nghttp2_session_adjust_closed_stream(session);
|
|
||||||
} else {
|
} else {
|
||||||
rv = nghttp2_session_destroy_stream(session, stream);
|
rv = nghttp2_session_destroy_stream(session, stream);
|
||||||
}
|
if (rv != 0) {
|
||||||
if (rv != 0) {
|
return rv;
|
||||||
return rv;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1285,8 +1283,12 @@ int nghttp2_session_adjust_closed_stream(nghttp2_session *session) {
|
||||||
size_t num_stream_max;
|
size_t num_stream_max;
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
num_stream_max = nghttp2_min(session->local_settings.max_concurrent_streams,
|
if (session->local_settings.max_concurrent_streams ==
|
||||||
session->pending_local_max_concurrent_stream);
|
NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS) {
|
||||||
|
num_stream_max = session->pending_local_max_concurrent_stream;
|
||||||
|
} else {
|
||||||
|
num_stream_max = session->local_settings.max_concurrent_streams;
|
||||||
|
}
|
||||||
|
|
||||||
DEBUGF(fprintf(stderr, "stream: adjusting kept closed streams "
|
DEBUGF(fprintf(stderr, "stream: adjusting kept closed streams "
|
||||||
"num_closed_streams=%zu, num_incoming_streams=%zu, "
|
"num_closed_streams=%zu, num_incoming_streams=%zu, "
|
||||||
|
@ -3777,13 +3779,6 @@ int nghttp2_session_on_request_headers_received(nghttp2_session *session,
|
||||||
assert(session->server);
|
assert(session->server);
|
||||||
|
|
||||||
if (!session_is_new_peer_stream_id(session, frame->hd.stream_id)) {
|
if (!session_is_new_peer_stream_id(session, frame->hd.stream_id)) {
|
||||||
/* The spec says if an endpoint receives a HEADERS with invalid
|
|
||||||
stream ID, it MUST issue connection error with error code
|
|
||||||
PROTOCOL_ERROR. But we could get trailer HEADERS after we have
|
|
||||||
sent RST_STREAM to this stream and peer have not received it.
|
|
||||||
Then connection error is too harsh. It means that we only use
|
|
||||||
connection error if stream ID refers idle stream. Therwise we
|
|
||||||
just ignore HEADERS for now. */
|
|
||||||
if (frame->hd.stream_id == 0 ||
|
if (frame->hd.stream_id == 0 ||
|
||||||
nghttp2_session_is_my_stream_id(session, frame->hd.stream_id)) {
|
nghttp2_session_is_my_stream_id(session, frame->hd.stream_id)) {
|
||||||
return session_inflate_handle_invalid_connection(
|
return session_inflate_handle_invalid_connection(
|
||||||
|
@ -3791,8 +3786,67 @@ int nghttp2_session_on_request_headers_received(nghttp2_session *session,
|
||||||
"request HEADERS: invalid stream_id");
|
"request HEADERS: invalid stream_id");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* RFC 7540 says if an endpoint receives a HEADERS with invalid
|
||||||
|
* stream ID (e.g, numerically smaller than previous), it MUST
|
||||||
|
* issue connection error with error code PROTOCOL_ERROR. It is a
|
||||||
|
* bit hard to detect this, since we cannot remember all streams
|
||||||
|
* we observed so far.
|
||||||
|
*
|
||||||
|
* You might imagine this is really easy. But no. HTTP/2 is
|
||||||
|
* asynchronous protocol, and usually client and server do not
|
||||||
|
* share the complete picture of open/closed stream status. For
|
||||||
|
* example, after server sends RST_STREAM for a stream, client may
|
||||||
|
* send trailer HEADERS for that stream. If naive server detects
|
||||||
|
* that, and issued connection error, then it is a bug of server
|
||||||
|
* implementation since client is not wrong if it did not get
|
||||||
|
* RST_STREAM when it issued trailer HEADERS.
|
||||||
|
*
|
||||||
|
* For server session, we remember closed streams as long as the
|
||||||
|
* sum of closed streams and opened streams are under current max
|
||||||
|
* concurrent streams. We can use these closed streams to detect
|
||||||
|
* the error in some cases.
|
||||||
|
*
|
||||||
|
* If the stream cannot be found in either closed or opened
|
||||||
|
* streams, it is considered to be closed, or it has not exist
|
||||||
|
* (e.g., peer skipped sending the stream). Actually, it is
|
||||||
|
* impossible to detect which is which, since that information was
|
||||||
|
* lost forever. For these cases, we send back GOAWAY with
|
||||||
|
* PROTOCOL_ERROR.
|
||||||
|
*
|
||||||
|
* If the stream is found, and we know that it is in half closed
|
||||||
|
* (remote), or closed by peer's explicit action (e.g., received
|
||||||
|
* RST_STREAM from peer, or peer sends HEADERS/DATA frame with
|
||||||
|
* END_STREAM), getting new frame on that stream is clearly error.
|
||||||
|
* In this case, we send GOAWAY with error code STREAM_CLOSED.
|
||||||
|
*
|
||||||
|
* There is one corner case here. Server can change the max
|
||||||
|
* concurrent streams. The initial value of max concurrent
|
||||||
|
* streams is unlimited (NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS,
|
||||||
|
* which is UINT32_MAX). When sending out SETTINGS with
|
||||||
|
* MAX_CONCURRENT_STREAMS, we save its value as pending max
|
||||||
|
* concurrent streams, and use it as a cap to remember closed
|
||||||
|
* stream to save memory. This means that we might not sure that
|
||||||
|
* stream surely closed or has not exist when it is not found in
|
||||||
|
* closed or opened stream. To workaround this issue, we ignore
|
||||||
|
* incoming frame if the current max concurrent streams is
|
||||||
|
* NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS, and pending max
|
||||||
|
* concurrent streams is less than that.
|
||||||
|
*/
|
||||||
stream = nghttp2_session_get_stream_raw(session, frame->hd.stream_id);
|
stream = nghttp2_session_get_stream_raw(session, frame->hd.stream_id);
|
||||||
if (stream && (stream->shut_flags & NGHTTP2_SHUT_RD)) {
|
|
||||||
|
if (!stream) {
|
||||||
|
if (session->local_settings.max_concurrent_streams ==
|
||||||
|
NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS &&
|
||||||
|
session->pending_local_max_concurrent_stream <
|
||||||
|
NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS) {
|
||||||
|
return NGHTTP2_ERR_IGN_HEADER_BLOCK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return session_inflate_handle_invalid_connection(
|
||||||
|
session, frame, NGHTTP2_ERR_PROTO, "HEADERS: stream does not exist");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stream->shut_flags & NGHTTP2_SHUT_RD) {
|
||||||
return session_inflate_handle_invalid_connection(
|
return session_inflate_handle_invalid_connection(
|
||||||
session, frame, NGHTTP2_ERR_STREAM_CLOSED, "HEADERS: stream closed");
|
session, frame, NGHTTP2_ERR_STREAM_CLOSED, "HEADERS: stream closed");
|
||||||
}
|
}
|
||||||
|
@ -5066,7 +5120,25 @@ static int session_on_data_received_fail_fast(nghttp2_session *session) {
|
||||||
stream = nghttp2_session_get_stream(session, stream_id);
|
stream = nghttp2_session_get_stream(session, stream_id);
|
||||||
if (!stream) {
|
if (!stream) {
|
||||||
stream = nghttp2_session_get_stream_raw(session, stream_id);
|
stream = nghttp2_session_get_stream_raw(session, stream_id);
|
||||||
if (stream && (stream->shut_flags & NGHTTP2_SHUT_RD)) {
|
|
||||||
|
if (!stream) {
|
||||||
|
if (session->server) {
|
||||||
|
if (session->local_settings.max_concurrent_streams ==
|
||||||
|
NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS &&
|
||||||
|
session->pending_local_max_concurrent_stream <
|
||||||
|
NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS) {
|
||||||
|
return NGHTTP2_ERR_IGN_PAYLOAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
failure_reason = "DATA: stream does not exist";
|
||||||
|
error_code = NGHTTP2_PROTOCOL_ERROR;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NGHTTP2_ERR_IGN_PAYLOAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stream->shut_flags & NGHTTP2_SHUT_RD) {
|
||||||
failure_reason = "DATA: stream closed";
|
failure_reason = "DATA: stream closed";
|
||||||
error_code = NGHTTP2_STREAM_CLOSED;
|
error_code = NGHTTP2_STREAM_CLOSED;
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
|
@ -97,6 +97,9 @@ typedef struct {
|
||||||
these frames in this number, it is considered suspicious. */
|
these frames in this number, it is considered suspicious. */
|
||||||
#define NGHTTP2_MAX_OBQ_FLOOD_ITEM 10000
|
#define NGHTTP2_MAX_OBQ_FLOOD_ITEM 10000
|
||||||
|
|
||||||
|
/* The default value of maximum number of concurrent streams. */
|
||||||
|
#define NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS 0xffffffffu
|
||||||
|
|
||||||
/* Internal state when receiving incoming frame */
|
/* Internal state when receiving incoming frame */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
/* Receiving frame header */
|
/* Receiving frame header */
|
||||||
|
|
|
@ -2082,6 +2082,10 @@ Logging:
|
||||||
* $ssl_session_id: session ID for SSL/TLS connection.
|
* $ssl_session_id: session ID for SSL/TLS connection.
|
||||||
* $ssl_session_reused: "r" if SSL/TLS session was
|
* $ssl_session_reused: "r" if SSL/TLS session was
|
||||||
reused. Otherwise, "."
|
reused. Otherwise, "."
|
||||||
|
* $backend_host: backend host used to fulfill the
|
||||||
|
request. "-" if backend host is not available.
|
||||||
|
* $backend_port: backend port used to fulfill the
|
||||||
|
request. "-" if backend host is not available.
|
||||||
|
|
||||||
The variable can be enclosed by "{" and "}" for
|
The variable can be enclosed by "{" and "}" for
|
||||||
disambiguation (e.g., ${remote_addr}).
|
disambiguation (e.g., ${remote_addr}).
|
||||||
|
|
|
@ -301,9 +301,10 @@ void APIDownstreamConnection::on_upstream_change(Upstream *uptream) {}
|
||||||
|
|
||||||
bool APIDownstreamConnection::poolable() const { return false; }
|
bool APIDownstreamConnection::poolable() const { return false; }
|
||||||
|
|
||||||
DownstreamAddrGroup *
|
const std::shared_ptr<DownstreamAddrGroup> &
|
||||||
APIDownstreamConnection::get_downstream_addr_group() const {
|
APIDownstreamConnection::get_downstream_addr_group() const {
|
||||||
return nullptr;
|
static std::shared_ptr<DownstreamAddrGroup> s;
|
||||||
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
DownstreamAddr *APIDownstreamConnection::get_addr() const { return nullptr; }
|
DownstreamAddr *APIDownstreamConnection::get_addr() const { return nullptr; }
|
||||||
|
|
|
@ -54,7 +54,8 @@ public:
|
||||||
// true if this object is poolable.
|
// true if this object is poolable.
|
||||||
virtual bool poolable() const;
|
virtual bool poolable() const;
|
||||||
|
|
||||||
virtual DownstreamAddrGroup *get_downstream_addr_group() const;
|
virtual const std::shared_ptr<DownstreamAddrGroup> &
|
||||||
|
get_downstream_addr_group() const;
|
||||||
virtual DownstreamAddr *get_addr() const;
|
virtual DownstreamAddr *get_addr() const;
|
||||||
|
|
||||||
int send_reply(unsigned int http_status, int api_status);
|
int send_reply(unsigned int http_status, int api_status);
|
||||||
|
|
|
@ -643,7 +643,7 @@ void ClientHandler::pool_downstream_connection(
|
||||||
|
|
||||||
dconn->set_client_handler(nullptr);
|
dconn->set_client_handler(nullptr);
|
||||||
|
|
||||||
auto group = dconn->get_downstream_addr_group();
|
auto &group = dconn->get_downstream_addr_group();
|
||||||
|
|
||||||
if (LOG_ENABLED(INFO)) {
|
if (LOG_ENABLED(INFO)) {
|
||||||
CLOG(INFO, this) << "Pooling downstream connection DCONN:" << dconn.get()
|
CLOG(INFO, this) << "Pooling downstream connection DCONN:" << dconn.get()
|
||||||
|
@ -1143,7 +1143,8 @@ void ClientHandler::write_accesslog(Downstream *downstream) {
|
||||||
upstream_accesslog(
|
upstream_accesslog(
|
||||||
get_config()->logging.access.format,
|
get_config()->logging.access.format,
|
||||||
LogSpec{
|
LogSpec{
|
||||||
downstream, StringRef{ipaddr_}, http2::to_method_string(req.method),
|
downstream, downstream->get_addr(), StringRef{ipaddr_},
|
||||||
|
http2::to_method_string(req.method),
|
||||||
|
|
||||||
req.method == HTTP_CONNECT
|
req.method == HTTP_CONNECT
|
||||||
? StringRef(req.authority)
|
? StringRef(req.authority)
|
||||||
|
@ -1176,7 +1177,7 @@ void ClientHandler::write_accesslog(int major, int minor, unsigned int status,
|
||||||
|
|
||||||
upstream_accesslog(get_config()->logging.access.format,
|
upstream_accesslog(get_config()->logging.access.format,
|
||||||
LogSpec{
|
LogSpec{
|
||||||
nullptr, StringRef(ipaddr_),
|
nullptr, nullptr, StringRef(ipaddr_),
|
||||||
StringRef::from_lit("-"), // method
|
StringRef::from_lit("-"), // method
|
||||||
StringRef::from_lit("-"), // path,
|
StringRef::from_lit("-"), // path,
|
||||||
StringRef(alpn_), nghttp2::ssl::get_tls_session_info(
|
StringRef(alpn_), nghttp2::ssl::get_tls_session_info(
|
||||||
|
|
|
@ -434,6 +434,14 @@ LogFragmentType log_var_lookup_token(const char *name, size_t namelen) {
|
||||||
return SHRPX_LOGF_SSL_PROTOCOL;
|
return SHRPX_LOGF_SSL_PROTOCOL;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 't':
|
||||||
|
if (util::strieq_l("backend_hos", name, 11)) {
|
||||||
|
return SHRPX_LOGF_BACKEND_HOST;
|
||||||
|
}
|
||||||
|
if (util::strieq_l("backend_por", name, 11)) {
|
||||||
|
return SHRPX_LOGF_BACKEND_PORT;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 14:
|
case 14:
|
||||||
|
|
|
@ -124,6 +124,7 @@ Downstream::Downstream(Upstream *upstream, MemchunkPool *mcpool,
|
||||||
response_buf_(mcpool),
|
response_buf_(mcpool),
|
||||||
upstream_(upstream),
|
upstream_(upstream),
|
||||||
blocked_link_(nullptr),
|
blocked_link_(nullptr),
|
||||||
|
addr_(nullptr),
|
||||||
num_retry_(0),
|
num_retry_(0),
|
||||||
stream_id_(stream_id),
|
stream_id_(stream_id),
|
||||||
assoc_stream_id_(-1),
|
assoc_stream_id_(-1),
|
||||||
|
@ -943,4 +944,13 @@ void Downstream::add_rcbuf(nghttp2_rcbuf *rcbuf) {
|
||||||
rcbufs_.push_back(rcbuf);
|
rcbufs_.push_back(rcbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Downstream::set_downstream_addr_group(
|
||||||
|
const std::shared_ptr<DownstreamAddrGroup> &group) {
|
||||||
|
group_ = group;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Downstream::set_addr(const DownstreamAddr *addr) { addr_ = addr; }
|
||||||
|
|
||||||
|
const DownstreamAddr *Downstream::get_addr() const { return addr_; }
|
||||||
|
|
||||||
} // namespace shrpx
|
} // namespace shrpx
|
||||||
|
|
|
@ -49,6 +49,8 @@ namespace shrpx {
|
||||||
class Upstream;
|
class Upstream;
|
||||||
class DownstreamConnection;
|
class DownstreamConnection;
|
||||||
struct BlockedLink;
|
struct BlockedLink;
|
||||||
|
struct DownstreamAddrGroup;
|
||||||
|
struct DownstreamAddr;
|
||||||
|
|
||||||
class FieldStore {
|
class FieldStore {
|
||||||
public:
|
public:
|
||||||
|
@ -382,6 +384,12 @@ public:
|
||||||
|
|
||||||
void add_rcbuf(nghttp2_rcbuf *rcbuf);
|
void add_rcbuf(nghttp2_rcbuf *rcbuf);
|
||||||
|
|
||||||
|
void
|
||||||
|
set_downstream_addr_group(const std::shared_ptr<DownstreamAddrGroup> &group);
|
||||||
|
void set_addr(const DownstreamAddr *addr);
|
||||||
|
|
||||||
|
const DownstreamAddr *get_addr() const;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
EVENT_ERROR = 0x1,
|
EVENT_ERROR = 0x1,
|
||||||
EVENT_TIMEOUT = 0x2,
|
EVENT_TIMEOUT = 0x2,
|
||||||
|
@ -429,6 +437,10 @@ private:
|
||||||
|
|
||||||
// only used by HTTP/2 or SPDY upstream
|
// only used by HTTP/2 or SPDY upstream
|
||||||
BlockedLink *blocked_link_;
|
BlockedLink *blocked_link_;
|
||||||
|
// The backend address used to fulfill this request. These are for
|
||||||
|
// logging purpose.
|
||||||
|
std::shared_ptr<DownstreamAddrGroup> group_;
|
||||||
|
const DownstreamAddr *addr_;
|
||||||
// How many times we tried in backend connection
|
// How many times we tried in backend connection
|
||||||
size_t num_retry_;
|
size_t num_retry_;
|
||||||
// The stream ID in frontend connection
|
// The stream ID in frontend connection
|
||||||
|
|
|
@ -61,7 +61,8 @@ public:
|
||||||
// true if this object is poolable.
|
// true if this object is poolable.
|
||||||
virtual bool poolable() const = 0;
|
virtual bool poolable() const = 0;
|
||||||
|
|
||||||
virtual DownstreamAddrGroup *get_downstream_addr_group() const = 0;
|
virtual const std::shared_ptr<DownstreamAddrGroup> &
|
||||||
|
get_downstream_addr_group() const = 0;
|
||||||
virtual DownstreamAddr *get_addr() const = 0;
|
virtual DownstreamAddr *get_addr() const = 0;
|
||||||
|
|
||||||
void set_client_handler(ClientHandler *client_handler);
|
void set_client_handler(ClientHandler *client_handler);
|
||||||
|
|
|
@ -95,9 +95,10 @@ void HealthMonitorDownstreamConnection::on_upstream_change(Upstream *uptream) {}
|
||||||
|
|
||||||
bool HealthMonitorDownstreamConnection::poolable() const { return false; }
|
bool HealthMonitorDownstreamConnection::poolable() const { return false; }
|
||||||
|
|
||||||
DownstreamAddrGroup *
|
const std::shared_ptr<DownstreamAddrGroup> &
|
||||||
HealthMonitorDownstreamConnection::get_downstream_addr_group() const {
|
HealthMonitorDownstreamConnection::get_downstream_addr_group() const {
|
||||||
return nullptr;
|
static std::shared_ptr<DownstreamAddrGroup> s;
|
||||||
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
DownstreamAddr *HealthMonitorDownstreamConnection::get_addr() const {
|
DownstreamAddr *HealthMonitorDownstreamConnection::get_addr() const {
|
||||||
|
|
|
@ -54,7 +54,8 @@ public:
|
||||||
// true if this object is poolable.
|
// true if this object is poolable.
|
||||||
virtual bool poolable() const;
|
virtual bool poolable() const;
|
||||||
|
|
||||||
virtual DownstreamAddrGroup *get_downstream_addr_group() const;
|
virtual const std::shared_ptr<DownstreamAddrGroup> &
|
||||||
|
get_downstream_addr_group() const;
|
||||||
virtual DownstreamAddr *get_addr() const;
|
virtual DownstreamAddr *get_addr() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -538,7 +538,7 @@ int Http2DownstreamConnection::on_timeout() {
|
||||||
return submit_rst_stream(downstream_, NGHTTP2_NO_ERROR);
|
return submit_rst_stream(downstream_, NGHTTP2_NO_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
DownstreamAddrGroup *
|
const std::shared_ptr<DownstreamAddrGroup> &
|
||||||
Http2DownstreamConnection::get_downstream_addr_group() const {
|
Http2DownstreamConnection::get_downstream_addr_group() const {
|
||||||
return http2session_->get_downstream_addr_group();
|
return http2session_->get_downstream_addr_group();
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,7 +64,8 @@ public:
|
||||||
// migrate to another Http2Session object.
|
// migrate to another Http2Session object.
|
||||||
virtual bool poolable() const { return false; }
|
virtual bool poolable() const { return false; }
|
||||||
|
|
||||||
virtual DownstreamAddrGroup *get_downstream_addr_group() const;
|
virtual const std::shared_ptr<DownstreamAddrGroup> &
|
||||||
|
get_downstream_addr_group() const;
|
||||||
virtual DownstreamAddr *get_addr() const;
|
virtual DownstreamAddr *get_addr() const;
|
||||||
|
|
||||||
int send();
|
int send();
|
||||||
|
|
|
@ -976,6 +976,10 @@ int on_response_headers(Http2Session *http2session, Downstream *downstream,
|
||||||
resp.http_major = 2;
|
resp.http_major = 2;
|
||||||
resp.http_minor = 0;
|
resp.http_minor = 0;
|
||||||
|
|
||||||
|
downstream->set_downstream_addr_group(
|
||||||
|
http2session->get_downstream_addr_group());
|
||||||
|
downstream->set_addr(http2session->get_addr());
|
||||||
|
|
||||||
if (LOG_ENABLED(INFO)) {
|
if (LOG_ENABLED(INFO)) {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
for (auto &nv : nva) {
|
for (auto &nv : nva) {
|
||||||
|
@ -2126,8 +2130,9 @@ bool Http2Session::max_concurrency_reached(size_t extra) const {
|
||||||
session_, NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS);
|
session_, NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS);
|
||||||
}
|
}
|
||||||
|
|
||||||
DownstreamAddrGroup *Http2Session::get_downstream_addr_group() const {
|
const std::shared_ptr<DownstreamAddrGroup> &
|
||||||
return group_.get();
|
Http2Session::get_downstream_addr_group() const {
|
||||||
|
return group_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Http2Session::add_to_avail_freelist() {
|
void Http2Session::add_to_avail_freelist() {
|
||||||
|
|
|
@ -162,7 +162,7 @@ public:
|
||||||
|
|
||||||
DownstreamAddr *get_addr() const;
|
DownstreamAddr *get_addr() const;
|
||||||
|
|
||||||
DownstreamAddrGroup *get_downstream_addr_group() const;
|
const std::shared_ptr<DownstreamAddrGroup> &get_downstream_addr_group() const;
|
||||||
|
|
||||||
int handle_downstream_push_promise(Downstream *downstream,
|
int handle_downstream_push_promise(Downstream *downstream,
|
||||||
int32_t promised_stream_id);
|
int32_t promised_stream_id);
|
||||||
|
|
|
@ -565,7 +565,7 @@ int HttpDownstreamConnection::end_upload_data() {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
void remove_from_pool(HttpDownstreamConnection *dconn) {
|
void remove_from_pool(HttpDownstreamConnection *dconn) {
|
||||||
auto group = dconn->get_downstream_addr_group();
|
auto &group = dconn->get_downstream_addr_group();
|
||||||
auto &shared_addr = group->shared_addr;
|
auto &shared_addr = group->shared_addr;
|
||||||
|
|
||||||
if (shared_addr->affinity == AFFINITY_NONE) {
|
if (shared_addr->affinity == AFFINITY_NONE) {
|
||||||
|
@ -677,6 +677,11 @@ int htp_hdrs_completecb(http_parser *htp) {
|
||||||
resp.http_minor = 1;
|
resp.http_minor = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto dconn = downstream->get_downstream_connection();
|
||||||
|
|
||||||
|
downstream->set_downstream_addr_group(dconn->get_downstream_addr_group());
|
||||||
|
downstream->set_addr(dconn->get_addr());
|
||||||
|
|
||||||
if (resp.fs.parse_content_length() != 0) {
|
if (resp.fs.parse_content_length() != 0) {
|
||||||
downstream->set_response_state(Downstream::MSG_BAD_HEADER);
|
downstream->set_response_state(Downstream::MSG_BAD_HEADER);
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -1192,9 +1197,9 @@ int HttpDownstreamConnection::actual_signal_write() {
|
||||||
|
|
||||||
int HttpDownstreamConnection::noop() { return 0; }
|
int HttpDownstreamConnection::noop() { return 0; }
|
||||||
|
|
||||||
DownstreamAddrGroup *
|
const std::shared_ptr<DownstreamAddrGroup> &
|
||||||
HttpDownstreamConnection::get_downstream_addr_group() const {
|
HttpDownstreamConnection::get_downstream_addr_group() const {
|
||||||
return group_.get();
|
return group_;
|
||||||
}
|
}
|
||||||
|
|
||||||
DownstreamAddr *HttpDownstreamConnection::get_addr() const { return addr_; }
|
DownstreamAddr *HttpDownstreamConnection::get_addr() const { return addr_; }
|
||||||
|
|
|
@ -64,7 +64,8 @@ public:
|
||||||
|
|
||||||
virtual bool poolable() const;
|
virtual bool poolable() const;
|
||||||
|
|
||||||
virtual DownstreamAddrGroup *get_downstream_addr_group() const;
|
virtual const std::shared_ptr<DownstreamAddrGroup> &
|
||||||
|
get_downstream_addr_group() const;
|
||||||
virtual DownstreamAddr *get_addr() const;
|
virtual DownstreamAddr *get_addr() const;
|
||||||
|
|
||||||
int read_clear();
|
int read_clear();
|
||||||
|
@ -88,7 +89,7 @@ private:
|
||||||
Worker *worker_;
|
Worker *worker_;
|
||||||
// nullptr if TLS is not used.
|
// nullptr if TLS is not used.
|
||||||
SSL_CTX *ssl_ctx_;
|
SSL_CTX *ssl_ctx_;
|
||||||
const std::shared_ptr<DownstreamAddrGroup> &group_;
|
std::shared_ptr<DownstreamAddrGroup> group_;
|
||||||
// Address of remote endpoint
|
// Address of remote endpoint
|
||||||
DownstreamAddr *addr_;
|
DownstreamAddr *addr_;
|
||||||
IOControl ioctrl_;
|
IOControl ioctrl_;
|
||||||
|
|
|
@ -45,6 +45,7 @@
|
||||||
|
|
||||||
#include "shrpx_config.h"
|
#include "shrpx_config.h"
|
||||||
#include "shrpx_downstream.h"
|
#include "shrpx_downstream.h"
|
||||||
|
#include "shrpx_worker.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "template.h"
|
#include "template.h"
|
||||||
|
|
||||||
|
@ -367,6 +368,21 @@ void upstream_accesslog(const std::vector<LogFragment> &lfv,
|
||||||
std::tie(p, avail) =
|
std::tie(p, avail) =
|
||||||
copy_l(lgsp.tls_info->session_reused ? "r" : ".", avail, p);
|
copy_l(lgsp.tls_info->session_reused ? "r" : ".", avail, p);
|
||||||
break;
|
break;
|
||||||
|
case SHRPX_LOGF_BACKEND_HOST:
|
||||||
|
if (!lgsp.downstream_addr) {
|
||||||
|
std::tie(p, avail) = copy_l("-", avail, p);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
std::tie(p, avail) = copy(lgsp.downstream_addr->host, avail, p);
|
||||||
|
break;
|
||||||
|
case SHRPX_LOGF_BACKEND_PORT:
|
||||||
|
if (!lgsp.downstream_addr) {
|
||||||
|
std::tie(p, avail) = copy_l("-", avail, p);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
std::tie(p, avail) =
|
||||||
|
copy(util::utos(lgsp.downstream_addr->port), avail, p);
|
||||||
|
break;
|
||||||
case SHRPX_LOGF_NONE:
|
case SHRPX_LOGF_NONE:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -85,6 +85,7 @@ using namespace nghttp2;
|
||||||
namespace shrpx {
|
namespace shrpx {
|
||||||
|
|
||||||
class Downstream;
|
class Downstream;
|
||||||
|
struct DownstreamAddr;
|
||||||
|
|
||||||
enum SeverityLevel { INFO, NOTICE, WARN, ERROR, FATAL };
|
enum SeverityLevel { INFO, NOTICE, WARN, ERROR, FATAL };
|
||||||
|
|
||||||
|
@ -131,6 +132,8 @@ enum LogFragmentType {
|
||||||
SHRPX_LOGF_SSL_PROTOCOL,
|
SHRPX_LOGF_SSL_PROTOCOL,
|
||||||
SHRPX_LOGF_SSL_SESSION_ID,
|
SHRPX_LOGF_SSL_SESSION_ID,
|
||||||
SHRPX_LOGF_SSL_SESSION_REUSED,
|
SHRPX_LOGF_SSL_SESSION_REUSED,
|
||||||
|
SHRPX_LOGF_BACKEND_HOST,
|
||||||
|
SHRPX_LOGF_BACKEND_PORT,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LogFragment {
|
struct LogFragment {
|
||||||
|
@ -142,6 +145,7 @@ struct LogFragment {
|
||||||
|
|
||||||
struct LogSpec {
|
struct LogSpec {
|
||||||
Downstream *downstream;
|
Downstream *downstream;
|
||||||
|
const DownstreamAddr *downstream_addr;
|
||||||
StringRef remote_addr;
|
StringRef remote_addr;
|
||||||
StringRef method;
|
StringRef method;
|
||||||
StringRef path;
|
StringRef path;
|
||||||
|
|
|
@ -308,6 +308,8 @@ int main(int argc _U_, char *argv[] _U_) {
|
||||||
test_nghttp2_session_set_local_window_size) ||
|
test_nghttp2_session_set_local_window_size) ||
|
||||||
!CU_add_test(pSuite, "session_cancel_from_before_frame_send",
|
!CU_add_test(pSuite, "session_cancel_from_before_frame_send",
|
||||||
test_nghttp2_session_cancel_from_before_frame_send) ||
|
test_nghttp2_session_cancel_from_before_frame_send) ||
|
||||||
|
!CU_add_test(pSuite, "session_removed_closed_stream",
|
||||||
|
test_nghttp2_session_removed_closed_stream) ||
|
||||||
!CU_add_test(pSuite, "http_mandatory_headers",
|
!CU_add_test(pSuite, "http_mandatory_headers",
|
||||||
test_nghttp2_http_mandatory_headers) ||
|
test_nghttp2_http_mandatory_headers) ||
|
||||||
!CU_add_test(pSuite, "http_content_length",
|
!CU_add_test(pSuite, "http_content_length",
|
||||||
|
|
|
@ -2366,7 +2366,7 @@ void test_nghttp2_session_on_request_headers_received(void) {
|
||||||
|
|
||||||
nghttp2_frame_headers_free(&frame.headers, mem);
|
nghttp2_frame_headers_free(&frame.headers, mem);
|
||||||
session->local_settings.max_concurrent_streams =
|
session->local_settings.max_concurrent_streams =
|
||||||
NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS;
|
NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS;
|
||||||
|
|
||||||
/* Stream ID less than or equal to the previouly received request
|
/* Stream ID less than or equal to the previouly received request
|
||||||
HEADERS is just ignored due to race condition */
|
HEADERS is just ignored due to race condition */
|
||||||
|
@ -4003,22 +4003,23 @@ void test_nghttp2_session_upgrade2(void) {
|
||||||
void test_nghttp2_session_reprioritize_stream(void) {
|
void test_nghttp2_session_reprioritize_stream(void) {
|
||||||
nghttp2_session *session;
|
nghttp2_session *session;
|
||||||
nghttp2_session_callbacks callbacks;
|
nghttp2_session_callbacks callbacks;
|
||||||
my_user_data ud;
|
|
||||||
nghttp2_stream *stream;
|
nghttp2_stream *stream;
|
||||||
nghttp2_stream *dep_stream;
|
nghttp2_stream *dep_stream;
|
||||||
nghttp2_priority_spec pri_spec;
|
nghttp2_priority_spec pri_spec;
|
||||||
|
int rv;
|
||||||
|
|
||||||
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
|
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
|
||||||
callbacks.send_callback = block_count_send_callback;
|
callbacks.send_callback = block_count_send_callback;
|
||||||
|
|
||||||
nghttp2_session_server_new(&session, &callbacks, &ud);
|
nghttp2_session_server_new(&session, &callbacks, NULL);
|
||||||
|
|
||||||
stream = open_recv_stream(session, 1);
|
stream = open_recv_stream(session, 1);
|
||||||
|
|
||||||
nghttp2_priority_spec_init(&pri_spec, 0, 10, 0);
|
nghttp2_priority_spec_init(&pri_spec, 0, 10, 0);
|
||||||
|
|
||||||
nghttp2_session_reprioritize_stream(session, stream, &pri_spec);
|
rv = nghttp2_session_reprioritize_stream(session, stream, &pri_spec);
|
||||||
|
|
||||||
|
CU_ASSERT(0 == rv);
|
||||||
CU_ASSERT(10 == stream->weight);
|
CU_ASSERT(10 == stream->weight);
|
||||||
CU_ASSERT(&session->root == stream->dep_prev);
|
CU_ASSERT(&session->root == stream->dep_prev);
|
||||||
|
|
||||||
|
@ -4026,8 +4027,9 @@ void test_nghttp2_session_reprioritize_stream(void) {
|
||||||
|
|
||||||
nghttp2_priority_spec_init(&pri_spec, 3, 99, 0);
|
nghttp2_priority_spec_init(&pri_spec, 3, 99, 0);
|
||||||
|
|
||||||
nghttp2_session_reprioritize_stream(session, stream, &pri_spec);
|
rv = nghttp2_session_reprioritize_stream(session, stream, &pri_spec);
|
||||||
|
|
||||||
|
CU_ASSERT(0 == rv);
|
||||||
CU_ASSERT(99 == stream->weight);
|
CU_ASSERT(99 == stream->weight);
|
||||||
CU_ASSERT(3 == stream->dep_prev->stream_id);
|
CU_ASSERT(3 == stream->dep_prev->stream_id);
|
||||||
|
|
||||||
|
@ -4040,16 +4042,18 @@ void test_nghttp2_session_reprioritize_stream(void) {
|
||||||
/* Change weight */
|
/* Change weight */
|
||||||
pri_spec.weight = 128;
|
pri_spec.weight = 128;
|
||||||
|
|
||||||
nghttp2_session_reprioritize_stream(session, stream, &pri_spec);
|
rv = nghttp2_session_reprioritize_stream(session, stream, &pri_spec);
|
||||||
|
|
||||||
|
CU_ASSERT(0 == rv);
|
||||||
CU_ASSERT(128 == stream->weight);
|
CU_ASSERT(128 == stream->weight);
|
||||||
CU_ASSERT(dep_stream == stream->dep_prev);
|
CU_ASSERT(dep_stream == stream->dep_prev);
|
||||||
|
|
||||||
/* Change weight again to test short-path case */
|
/* Change weight again to test short-path case */
|
||||||
pri_spec.weight = 100;
|
pri_spec.weight = 100;
|
||||||
|
|
||||||
nghttp2_session_reprioritize_stream(session, stream, &pri_spec);
|
rv = nghttp2_session_reprioritize_stream(session, stream, &pri_spec);
|
||||||
|
|
||||||
|
CU_ASSERT(0 == rv);
|
||||||
CU_ASSERT(100 == stream->weight);
|
CU_ASSERT(100 == stream->weight);
|
||||||
CU_ASSERT(dep_stream == stream->dep_prev);
|
CU_ASSERT(dep_stream == stream->dep_prev);
|
||||||
CU_ASSERT(100 == dep_stream->sum_dep_weight);
|
CU_ASSERT(100 == dep_stream->sum_dep_weight);
|
||||||
|
@ -4058,8 +4062,9 @@ void test_nghttp2_session_reprioritize_stream(void) {
|
||||||
root. Then stream 3 depends on it. */
|
root. Then stream 3 depends on it. */
|
||||||
nghttp2_priority_spec_init(&pri_spec, 1, 1, 0);
|
nghttp2_priority_spec_init(&pri_spec, 1, 1, 0);
|
||||||
|
|
||||||
nghttp2_session_reprioritize_stream(session, dep_stream, &pri_spec);
|
rv = nghttp2_session_reprioritize_stream(session, dep_stream, &pri_spec);
|
||||||
|
|
||||||
|
CU_ASSERT(0 == rv);
|
||||||
CU_ASSERT(1 == dep_stream->weight);
|
CU_ASSERT(1 == dep_stream->weight);
|
||||||
CU_ASSERT(stream == dep_stream->dep_prev);
|
CU_ASSERT(stream == dep_stream->dep_prev);
|
||||||
|
|
||||||
|
@ -4069,11 +4074,76 @@ void test_nghttp2_session_reprioritize_stream(void) {
|
||||||
|
|
||||||
nghttp2_priority_spec_init(&pri_spec, 5, 5, 0);
|
nghttp2_priority_spec_init(&pri_spec, 5, 5, 0);
|
||||||
|
|
||||||
nghttp2_session_reprioritize_stream(session, stream, &pri_spec);
|
rv = nghttp2_session_reprioritize_stream(session, stream, &pri_spec);
|
||||||
|
|
||||||
|
CU_ASSERT(0 == rv);
|
||||||
CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == stream->weight);
|
CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == stream->weight);
|
||||||
|
|
||||||
nghttp2_session_del(session);
|
nghttp2_session_del(session);
|
||||||
|
|
||||||
|
nghttp2_session_server_new(&session, &callbacks, NULL);
|
||||||
|
|
||||||
|
/* circular dependency; in case of stream which is not a direct
|
||||||
|
descendant of root. Use exclusive dependency. */
|
||||||
|
stream = open_recv_stream(session, 1);
|
||||||
|
stream = open_recv_stream_with_dep(session, 3, stream);
|
||||||
|
stream = open_recv_stream_with_dep(session, 5, stream);
|
||||||
|
stream = open_recv_stream_with_dep(session, 7, stream);
|
||||||
|
open_recv_stream_with_dep(session, 9, stream);
|
||||||
|
|
||||||
|
nghttp2_priority_spec_init(&pri_spec, 7, 1, 1);
|
||||||
|
|
||||||
|
stream = nghttp2_session_get_stream(session, 3);
|
||||||
|
rv = nghttp2_session_reprioritize_stream(session, stream, &pri_spec);
|
||||||
|
|
||||||
|
CU_ASSERT(0 == rv);
|
||||||
|
CU_ASSERT(7 == stream->dep_prev->stream_id);
|
||||||
|
|
||||||
|
stream = nghttp2_session_get_stream(session, 7);
|
||||||
|
|
||||||
|
CU_ASSERT(1 == stream->dep_prev->stream_id);
|
||||||
|
|
||||||
|
stream = nghttp2_session_get_stream(session, 9);
|
||||||
|
|
||||||
|
CU_ASSERT(3 == stream->dep_prev->stream_id);
|
||||||
|
|
||||||
|
stream = nghttp2_session_get_stream(session, 5);
|
||||||
|
|
||||||
|
CU_ASSERT(3 == stream->dep_prev->stream_id);
|
||||||
|
|
||||||
|
nghttp2_session_del(session);
|
||||||
|
|
||||||
|
nghttp2_session_server_new(&session, &callbacks, NULL);
|
||||||
|
|
||||||
|
/* circular dependency; in case of stream which is not a direct
|
||||||
|
descendant of root. Without exclusive dependency. */
|
||||||
|
stream = open_recv_stream(session, 1);
|
||||||
|
stream = open_recv_stream_with_dep(session, 3, stream);
|
||||||
|
stream = open_recv_stream_with_dep(session, 5, stream);
|
||||||
|
stream = open_recv_stream_with_dep(session, 7, stream);
|
||||||
|
open_recv_stream_with_dep(session, 9, stream);
|
||||||
|
|
||||||
|
nghttp2_priority_spec_init(&pri_spec, 7, 1, 0);
|
||||||
|
|
||||||
|
stream = nghttp2_session_get_stream(session, 3);
|
||||||
|
rv = nghttp2_session_reprioritize_stream(session, stream, &pri_spec);
|
||||||
|
|
||||||
|
CU_ASSERT(0 == rv);
|
||||||
|
CU_ASSERT(7 == stream->dep_prev->stream_id);
|
||||||
|
|
||||||
|
stream = nghttp2_session_get_stream(session, 7);
|
||||||
|
|
||||||
|
CU_ASSERT(1 == stream->dep_prev->stream_id);
|
||||||
|
|
||||||
|
stream = nghttp2_session_get_stream(session, 9);
|
||||||
|
|
||||||
|
CU_ASSERT(7 == stream->dep_prev->stream_id);
|
||||||
|
|
||||||
|
stream = nghttp2_session_get_stream(session, 5);
|
||||||
|
|
||||||
|
CU_ASSERT(3 == stream->dep_prev->stream_id);
|
||||||
|
|
||||||
|
nghttp2_session_del(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_nghttp2_session_reprioritize_stream_with_idle_stream_dep(void) {
|
void test_nghttp2_session_reprioritize_stream_with_idle_stream_dep(void) {
|
||||||
|
@ -4972,7 +5042,7 @@ void test_nghttp2_submit_settings(void) {
|
||||||
nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, iv, 7));
|
nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, iv, 7));
|
||||||
|
|
||||||
/* Make sure that local settings are not changed */
|
/* Make sure that local settings are not changed */
|
||||||
CU_ASSERT(NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS ==
|
CU_ASSERT(NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS ==
|
||||||
session->local_settings.max_concurrent_streams);
|
session->local_settings.max_concurrent_streams);
|
||||||
CU_ASSERT(NGHTTP2_INITIAL_WINDOW_SIZE ==
|
CU_ASSERT(NGHTTP2_INITIAL_WINDOW_SIZE ==
|
||||||
session->local_settings.initial_window_size);
|
session->local_settings.initial_window_size);
|
||||||
|
@ -9645,6 +9715,186 @@ void test_nghttp2_session_cancel_from_before_frame_send(void) {
|
||||||
nghttp2_session_del(session);
|
nghttp2_session_del(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
prepare_session_removed_closed_stream(nghttp2_session *session,
|
||||||
|
nghttp2_hd_deflater *deflater) {
|
||||||
|
int rv;
|
||||||
|
nghttp2_settings_entry iv;
|
||||||
|
nghttp2_bufs bufs;
|
||||||
|
nghttp2_mem *mem;
|
||||||
|
ssize_t nread;
|
||||||
|
int i;
|
||||||
|
nghttp2_stream *stream;
|
||||||
|
nghttp2_frame_hd hd;
|
||||||
|
|
||||||
|
mem = nghttp2_mem_default();
|
||||||
|
|
||||||
|
frame_pack_bufs_init(&bufs);
|
||||||
|
|
||||||
|
iv.settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
|
||||||
|
iv.value = 2;
|
||||||
|
|
||||||
|
rv = nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, &iv, 1);
|
||||||
|
|
||||||
|
CU_ASSERT(0 == rv);
|
||||||
|
|
||||||
|
rv = nghttp2_session_send(session);
|
||||||
|
|
||||||
|
CU_ASSERT(0 == rv);
|
||||||
|
|
||||||
|
for (i = 1; i <= 3; i += 2) {
|
||||||
|
rv = pack_headers(&bufs, deflater, i,
|
||||||
|
NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_END_STREAM, reqnv,
|
||||||
|
ARRLEN(reqnv), mem);
|
||||||
|
|
||||||
|
CU_ASSERT(0 == rv);
|
||||||
|
|
||||||
|
nread = nghttp2_session_mem_recv(session, bufs.head->buf.pos,
|
||||||
|
nghttp2_bufs_len(&bufs));
|
||||||
|
|
||||||
|
CU_ASSERT((ssize_t)nghttp2_bufs_len(&bufs) == nread);
|
||||||
|
|
||||||
|
nghttp2_bufs_reset(&bufs);
|
||||||
|
}
|
||||||
|
|
||||||
|
nghttp2_session_close_stream(session, 3, NGHTTP2_NO_ERROR);
|
||||||
|
|
||||||
|
rv = pack_headers(&bufs, deflater, 5,
|
||||||
|
NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_END_STREAM, reqnv,
|
||||||
|
ARRLEN(reqnv), mem);
|
||||||
|
|
||||||
|
CU_ASSERT(0 == rv);
|
||||||
|
|
||||||
|
/* Receiving stream 5 will erase stream 3 from closed stream list */
|
||||||
|
nread = nghttp2_session_mem_recv(session, bufs.head->buf.pos,
|
||||||
|
nghttp2_bufs_len(&bufs));
|
||||||
|
|
||||||
|
CU_ASSERT((ssize_t)nghttp2_bufs_len(&bufs) == nread);
|
||||||
|
|
||||||
|
stream = nghttp2_session_get_stream_raw(session, 3);
|
||||||
|
|
||||||
|
CU_ASSERT(NULL == stream);
|
||||||
|
|
||||||
|
/* Since the current max concurrent streams is
|
||||||
|
NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS, receiving frame on stream
|
||||||
|
3 is ignored. */
|
||||||
|
nghttp2_bufs_reset(&bufs);
|
||||||
|
rv = pack_headers(&bufs, deflater, 3,
|
||||||
|
NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_END_STREAM,
|
||||||
|
trailernv, ARRLEN(trailernv), mem);
|
||||||
|
|
||||||
|
CU_ASSERT(0 == rv);
|
||||||
|
|
||||||
|
nread = nghttp2_session_mem_recv(session, bufs.head->buf.pos,
|
||||||
|
nghttp2_bufs_len(&bufs));
|
||||||
|
|
||||||
|
CU_ASSERT((ssize_t)nghttp2_bufs_len(&bufs) == nread);
|
||||||
|
CU_ASSERT(NULL == nghttp2_session_get_next_ob_item(session));
|
||||||
|
|
||||||
|
nghttp2_frame_hd_init(&hd, 0, NGHTTP2_DATA, NGHTTP2_FLAG_NONE, 3);
|
||||||
|
nghttp2_bufs_reset(&bufs);
|
||||||
|
nghttp2_frame_pack_frame_hd(bufs.head->buf.last, &hd);
|
||||||
|
bufs.head->buf.last += NGHTTP2_FRAME_HDLEN;
|
||||||
|
|
||||||
|
nread = nghttp2_session_mem_recv(session, bufs.head->buf.pos,
|
||||||
|
nghttp2_bufs_len(&bufs));
|
||||||
|
|
||||||
|
CU_ASSERT((ssize_t)nghttp2_bufs_len(&bufs) == nread);
|
||||||
|
CU_ASSERT(NULL == nghttp2_session_get_next_ob_item(session));
|
||||||
|
|
||||||
|
/* Now server receives SETTINGS ACK */
|
||||||
|
nghttp2_frame_hd_init(&hd, 0, NGHTTP2_SETTINGS, NGHTTP2_FLAG_ACK, 0);
|
||||||
|
nghttp2_bufs_reset(&bufs);
|
||||||
|
nghttp2_frame_pack_frame_hd(bufs.head->buf.last, &hd);
|
||||||
|
bufs.head->buf.last += NGHTTP2_FRAME_HDLEN;
|
||||||
|
|
||||||
|
nread = nghttp2_session_mem_recv(session, bufs.head->buf.pos,
|
||||||
|
nghttp2_bufs_len(&bufs));
|
||||||
|
|
||||||
|
CU_ASSERT((ssize_t)nghttp2_bufs_len(&bufs) == nread);
|
||||||
|
|
||||||
|
nghttp2_bufs_free(&bufs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_nghttp2_session_removed_closed_stream(void) {
|
||||||
|
nghttp2_session *session;
|
||||||
|
nghttp2_session_callbacks callbacks;
|
||||||
|
int rv;
|
||||||
|
nghttp2_hd_deflater deflater;
|
||||||
|
nghttp2_bufs bufs;
|
||||||
|
nghttp2_mem *mem;
|
||||||
|
ssize_t nread;
|
||||||
|
nghttp2_frame_hd hd;
|
||||||
|
nghttp2_outbound_item *item;
|
||||||
|
|
||||||
|
mem = nghttp2_mem_default();
|
||||||
|
|
||||||
|
frame_pack_bufs_init(&bufs);
|
||||||
|
|
||||||
|
memset(&callbacks, 0, sizeof(callbacks));
|
||||||
|
|
||||||
|
callbacks.send_callback = null_send_callback;
|
||||||
|
|
||||||
|
nghttp2_session_server_new(&session, &callbacks, NULL);
|
||||||
|
|
||||||
|
/* Now local max concurrent streams is still unlimited, pending max
|
||||||
|
concurrent streams is now 2. */
|
||||||
|
|
||||||
|
nghttp2_hd_deflate_init(&deflater, mem);
|
||||||
|
|
||||||
|
prepare_session_removed_closed_stream(session, &deflater);
|
||||||
|
|
||||||
|
/* Now current max concurrent streams is 2, so receiving frame on
|
||||||
|
stream 3 is treated as connection error */
|
||||||
|
nghttp2_bufs_reset(&bufs);
|
||||||
|
rv = pack_headers(&bufs, &deflater, 3,
|
||||||
|
NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_END_STREAM,
|
||||||
|
trailernv, ARRLEN(trailernv), mem);
|
||||||
|
|
||||||
|
CU_ASSERT(0 == rv);
|
||||||
|
|
||||||
|
nread = nghttp2_session_mem_recv(session, bufs.head->buf.pos,
|
||||||
|
nghttp2_bufs_len(&bufs));
|
||||||
|
|
||||||
|
CU_ASSERT((ssize_t)nghttp2_bufs_len(&bufs) == nread);
|
||||||
|
|
||||||
|
item = nghttp2_session_get_next_ob_item(session);
|
||||||
|
|
||||||
|
CU_ASSERT(NULL != item);
|
||||||
|
CU_ASSERT(NGHTTP2_GOAWAY == item->frame.hd.type);
|
||||||
|
CU_ASSERT(NGHTTP2_PROTOCOL_ERROR == item->frame.goaway.error_code);
|
||||||
|
|
||||||
|
nghttp2_hd_deflate_free(&deflater);
|
||||||
|
nghttp2_session_del(session);
|
||||||
|
|
||||||
|
nghttp2_session_server_new(&session, &callbacks, NULL);
|
||||||
|
nghttp2_hd_deflate_init(&deflater, mem);
|
||||||
|
/* Same setup, and then receive DATA instead of HEADERS */
|
||||||
|
|
||||||
|
prepare_session_removed_closed_stream(session, &deflater);
|
||||||
|
|
||||||
|
nghttp2_frame_hd_init(&hd, 0, NGHTTP2_DATA, NGHTTP2_FLAG_NONE, 3);
|
||||||
|
nghttp2_bufs_reset(&bufs);
|
||||||
|
nghttp2_frame_pack_frame_hd(bufs.head->buf.last, &hd);
|
||||||
|
bufs.head->buf.last += NGHTTP2_FRAME_HDLEN;
|
||||||
|
|
||||||
|
nread = nghttp2_session_mem_recv(session, bufs.head->buf.pos,
|
||||||
|
nghttp2_bufs_len(&bufs));
|
||||||
|
|
||||||
|
CU_ASSERT((ssize_t)nghttp2_bufs_len(&bufs) == nread);
|
||||||
|
|
||||||
|
item = nghttp2_session_get_next_ob_item(session);
|
||||||
|
|
||||||
|
CU_ASSERT(NULL != item);
|
||||||
|
CU_ASSERT(NGHTTP2_GOAWAY == item->frame.hd.type);
|
||||||
|
CU_ASSERT(NGHTTP2_PROTOCOL_ERROR == item->frame.goaway.error_code);
|
||||||
|
|
||||||
|
nghttp2_hd_deflate_free(&deflater);
|
||||||
|
nghttp2_session_del(session);
|
||||||
|
|
||||||
|
nghttp2_bufs_free(&bufs);
|
||||||
|
}
|
||||||
|
|
||||||
static void check_nghttp2_http_recv_headers_fail(
|
static void check_nghttp2_http_recv_headers_fail(
|
||||||
nghttp2_session *session, nghttp2_hd_deflater *deflater, int32_t stream_id,
|
nghttp2_session *session, nghttp2_hd_deflater *deflater, int32_t stream_id,
|
||||||
int stream_state, const nghttp2_nv *nva, size_t nvlen) {
|
int stream_state, const nghttp2_nv *nva, size_t nvlen) {
|
||||||
|
|
|
@ -152,6 +152,7 @@ void test_nghttp2_session_repeated_priority_change(void);
|
||||||
void test_nghttp2_session_repeated_priority_submission(void);
|
void test_nghttp2_session_repeated_priority_submission(void);
|
||||||
void test_nghttp2_session_set_local_window_size(void);
|
void test_nghttp2_session_set_local_window_size(void);
|
||||||
void test_nghttp2_session_cancel_from_before_frame_send(void);
|
void test_nghttp2_session_cancel_from_before_frame_send(void);
|
||||||
|
void test_nghttp2_session_removed_closed_stream(void);
|
||||||
void test_nghttp2_http_mandatory_headers(void);
|
void test_nghttp2_http_mandatory_headers(void);
|
||||||
void test_nghttp2_http_content_length(void);
|
void test_nghttp2_http_content_length(void);
|
||||||
void test_nghttp2_http_content_length_mismatch(void);
|
void test_nghttp2_http_content_length_mismatch(void);
|
||||||
|
|
Loading…
Reference in New Issue