[core] handle Connection: Upgrade
This commit is contained in:
parent
5e0a58be53
commit
5e4a94b0c6
|
@ -26,8 +26,11 @@ typedef enum {
|
|||
|
||||
/** write remaining bytes from raw_out, mainvr finished (or not started) */
|
||||
LI_CON_STATE_WRITE,
|
||||
|
||||
/** connection was upgraded */
|
||||
LI_CON_STATE_UPGRADED
|
||||
} liConnectionState;
|
||||
#define LI_CON_STATE_LAST LI_CON_STATE_WRITE
|
||||
#define LI_CON_STATE_LAST LI_CON_STATE_UPGRADED
|
||||
/* update mod_status too */
|
||||
|
||||
typedef struct liConnectionSocketCallbacks liConnectionSocketCallbacks;
|
||||
|
|
|
@ -23,6 +23,12 @@ struct liHttpHeaders {
|
|||
GQueue entries;
|
||||
};
|
||||
|
||||
typedef struct liHttpHeaderTokenizer liHttpHeaderTokenizer;
|
||||
struct liHttpHeaderTokenizer {
|
||||
GList *cur;
|
||||
guint pos;
|
||||
};
|
||||
|
||||
/* strings always get copied, so you should free key and value yourself */
|
||||
|
||||
LI_API liHttpHeaders* li_http_headers_new(void);
|
||||
|
@ -59,4 +65,9 @@ INLINE gboolean li_http_header_key_is(liHttpHeader *h, const gchar *key, size_t
|
|||
return (h->keylen == keylen && 0 == g_ascii_strncasecmp(key, h->data->str, keylen));
|
||||
}
|
||||
|
||||
/* very simple tokenizer. splits at ' ' and ',', unquotes \\ escapes and "..." tokens */
|
||||
LI_API void li_http_header_tokenizer_start(liHttpHeaderTokenizer *tokenizer, liHttpHeaders *headers, const gchar *key, size_t keylen);
|
||||
LI_API gboolean li_http_header_tokenizer_next(liHttpHeaderTokenizer *tokenizer, GString *token);
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -15,6 +15,6 @@ LI_API void li_response_init(liResponse *resp);
|
|||
LI_API void li_response_reset(liResponse *resp);
|
||||
LI_API void li_response_clear(liResponse *resp);
|
||||
|
||||
LI_API void li_response_send_headers(liVRequest *vr, liChunkQueue *raw_out, liChunkQueue *response_body);
|
||||
LI_API void li_response_send_headers(liVRequest *vr, liChunkQueue *raw_out, liChunkQueue *response_body, gboolean upgraded);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -36,10 +36,12 @@ typedef enum {
|
|||
|
||||
typedef void (*liVRequestHandlerCB)(liVRequest *vr);
|
||||
typedef liThrottleState* (*liVRequestThrottleCB)(liVRequest *vr);
|
||||
typedef void (*liVRequestConnectionUpgradeCB)(liVRequest *vr, liStream *backend_drain, liStream *backend_source);
|
||||
|
||||
struct liConCallbacks {
|
||||
liVRequestHandlerCB handle_response_error; /* this is _not_ for 500 - internal error */
|
||||
liVRequestThrottleCB throttle_out, throttle_in;
|
||||
liVRequestConnectionUpgradeCB connection_upgrade;
|
||||
};
|
||||
|
||||
/* this data "belongs" to a vrequest, but is updated by the connection code */
|
||||
|
@ -167,6 +169,9 @@ LI_API void li_vrequest_indirect_connect(liVRequest *vr, liStream *backend_drain
|
|||
/* received all response headers/status code - call once from your indirect handler */
|
||||
LI_API void li_vrequest_indirect_headers_ready(liVRequest *vr);
|
||||
|
||||
/* call instead of headers_ready */
|
||||
LI_API void li_vrequest_connection_upgrade(liVRequest *vr, liStream *backend_drain, liStream *backend_source);
|
||||
|
||||
/* Signals an internal error; handles the error in the _next_ loop */
|
||||
LI_API void li_vrequest_error(liVRequest *vr);
|
||||
|
||||
|
|
|
@ -129,7 +129,6 @@ static liThrottleState* simple_tcp_throttle_in(liConnection *con) {
|
|||
return data->sock_stream->throttle_in;
|
||||
}
|
||||
|
||||
|
||||
static const liConnectionSocketCallbacks simple_tcp_cbs = {
|
||||
simple_tcp_finished,
|
||||
simple_tcp_throttle_out,
|
||||
|
@ -220,6 +219,12 @@ static void _connection_http_in_cb(liStream *stream, liStreamEvent event) {
|
|||
|
||||
if (0 == raw_in->length) return; /* no (new) data */
|
||||
|
||||
if (LI_CON_STATE_UPGRADED == con->state) {
|
||||
li_chunkqueue_steal_all(in, raw_in);
|
||||
li_stream_notify(stream);
|
||||
return;
|
||||
}
|
||||
|
||||
if (con->state == LI_CON_STATE_KEEP_ALIVE) {
|
||||
/* stop keep alive timeout watchers */
|
||||
if (con->keep_alive_data.link) {
|
||||
|
@ -407,7 +412,7 @@ static void _connection_http_out_cb(liStream *stream, liStreamEvent event) {
|
|||
VR_DEBUG(vr, "%s", "write response headers");
|
||||
}
|
||||
con->response_headers_sent = TRUE;
|
||||
li_response_send_headers(vr, raw_out, out);
|
||||
li_response_send_headers(vr, raw_out, out, FALSE);
|
||||
}
|
||||
|
||||
if (!con->out_has_all_data && !raw_out->is_closed && NULL != out) {
|
||||
|
@ -573,10 +578,45 @@ static liThrottleState* mainvr_throttle_in(liVRequest *vr) {
|
|||
return con->con_sock.callbacks->throttle_in(con);
|
||||
}
|
||||
|
||||
static void mainvr_connection_upgrade(liVRequest *vr, liStream *backend_drain, liStream *backend_source) {
|
||||
liConnection* con = li_connection_from_vrequest(vr);
|
||||
assert(NULL != con);
|
||||
|
||||
if (con->response_headers_sent || NULL != con->out.source) {
|
||||
li_connection_error(con);
|
||||
return;
|
||||
}
|
||||
if (CORE_OPTION(LI_CORE_OPTION_DEBUG_REQUEST_HANDLING).boolean) {
|
||||
VR_DEBUG(vr, "%s", "connection upgrade: write response headers");
|
||||
}
|
||||
con->response_headers_sent = TRUE;
|
||||
con->info.keep_alive = FALSE;
|
||||
li_response_send_headers(vr, con->out.out, NULL, TRUE);
|
||||
con->state = LI_CON_STATE_UPGRADED;
|
||||
vr->response.transfer_encoding = 0;
|
||||
|
||||
li_stream_disconnect_dest(&con->in);
|
||||
con->in.out->is_closed = FALSE;
|
||||
|
||||
li_stream_connect(&con->in, backend_drain);
|
||||
li_stream_connect(backend_source, &con->out);
|
||||
|
||||
li_vrequest_reset(con->mainvr, TRUE);
|
||||
|
||||
if (NULL != con->in.source) {
|
||||
li_chunkqueue_steal_all(con->out.out, backend_drain->out);
|
||||
}
|
||||
con->info.out_queue_length = con->out.out->length;
|
||||
|
||||
li_stream_notify(&con->out);
|
||||
li_stream_notify(&con->in);
|
||||
}
|
||||
|
||||
static const liConCallbacks con_callbacks = {
|
||||
mainvr_handle_response_error,
|
||||
mainvr_throttle_out,
|
||||
mainvr_throttle_in
|
||||
mainvr_throttle_in,
|
||||
mainvr_connection_upgrade
|
||||
};
|
||||
|
||||
liConnection* li_connection_new(liWorker *wrk) {
|
||||
|
@ -815,6 +855,8 @@ gchar *li_connection_state_str(liConnectionState state) {
|
|||
return "handle main vrequest";
|
||||
case LI_CON_STATE_WRITE:
|
||||
return "write";
|
||||
case LI_CON_STATE_UPGRADED:
|
||||
return "upgraded";
|
||||
}
|
||||
|
||||
return "undefined";
|
||||
|
|
|
@ -7,6 +7,45 @@ static void _http_header_free(gpointer p) {
|
|||
g_slice_free(liHttpHeader, h);
|
||||
}
|
||||
|
||||
/* remove folding */
|
||||
static void _http_header_sanitize(liHttpHeader *h) {
|
||||
guint i, j, len = h->data->len;
|
||||
gboolean folding = FALSE;
|
||||
char *str = h->data->str;
|
||||
for (i = h->keylen + 2; i < len; ++i) {
|
||||
switch (str[i]) {
|
||||
case '\r':
|
||||
case '\n':
|
||||
goto cleanup;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
cleanup:
|
||||
for (j = i; i < len; ++i) {
|
||||
switch (str[i]) {
|
||||
case '\r':
|
||||
case '\n':
|
||||
folding = TRUE;
|
||||
break;
|
||||
case ' ':
|
||||
case '\t':
|
||||
if (!folding) str[j++] = str[i];
|
||||
break;
|
||||
default:
|
||||
if (folding) {
|
||||
str[j++] = ' ';
|
||||
folding = FALSE;
|
||||
}
|
||||
str[j++] = str[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
g_string_truncate(h->data, j);
|
||||
}
|
||||
|
||||
static liHttpHeader* _http_header_new(const gchar *key, size_t keylen, const gchar *val, size_t valuelen) {
|
||||
liHttpHeader *h = g_slice_new0(liHttpHeader);
|
||||
gchar *s;
|
||||
|
@ -19,6 +58,7 @@ static liHttpHeader* _http_header_new(const gchar *key, size_t keylen, const gch
|
|||
memcpy(s, ": ", 2);
|
||||
s += 2;
|
||||
memcpy(s, val, valuelen);
|
||||
_http_header_sanitize(h);
|
||||
return h;
|
||||
}
|
||||
|
||||
|
@ -173,3 +213,81 @@ void li_http_header_get_all(GString *dest, liHttpHeaders *headers, const gchar *
|
|||
g_string_append_len(dest, &h->data->str[h->keylen+2], h->data->len - (h->keylen + 2));
|
||||
}
|
||||
}
|
||||
|
||||
void li_http_header_tokenizer_start(liHttpHeaderTokenizer *tokenizer, liHttpHeaders *headers, const gchar *key, size_t keylen) {
|
||||
if (NULL != (tokenizer->cur = li_http_header_find_first(headers, key, keylen))) {
|
||||
liHttpHeader *h = (liHttpHeader*) tokenizer->cur->data;
|
||||
tokenizer->pos = h->keylen + 2;
|
||||
} else {
|
||||
tokenizer->pos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
gboolean li_http_header_tokenizer_next(liHttpHeaderTokenizer *tokenizer, GString *token) {
|
||||
liHttpHeader *h;
|
||||
guint len;
|
||||
guint pos = tokenizer->pos;
|
||||
gchar *str;
|
||||
|
||||
g_string_truncate(token, 0);
|
||||
|
||||
if (NULL == tokenizer->cur) return FALSE;
|
||||
h = (liHttpHeader*) tokenizer->cur->data;
|
||||
len = h->data->len;
|
||||
str = h->data->str;
|
||||
|
||||
for (;;++pos) {
|
||||
while (pos >= len) {
|
||||
if (token->len > 0) {
|
||||
tokenizer->pos = pos;
|
||||
return TRUE;
|
||||
}
|
||||
if (NULL != (tokenizer->cur = li_http_header_find_next(tokenizer->cur, LI_HEADER_KEY_LEN(h)))) {
|
||||
h = (liHttpHeader*) tokenizer->cur->data;
|
||||
pos = tokenizer->pos = h->keylen + 2;
|
||||
len = h->data->len;
|
||||
str = h->data->str;
|
||||
} else {
|
||||
tokenizer->pos = 0;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
switch (str[pos]) {
|
||||
case '"':
|
||||
++pos;
|
||||
if (token->len > 0) return FALSE; /* either the complete token is quoted or nothing */
|
||||
goto quoted;
|
||||
case ' ':
|
||||
case ',':
|
||||
if (token->len == 0) continue;
|
||||
tokenizer->pos = pos+1;
|
||||
return TRUE;
|
||||
case '\\':
|
||||
++pos;
|
||||
if (pos >= len) return FALSE; /* no character after backslash */
|
||||
/* fall through, append whatever comes */
|
||||
default:
|
||||
g_string_append_c(token, str[pos]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
quoted:
|
||||
for (; pos < len; ++pos) {
|
||||
switch (str[pos]) {
|
||||
case '"':
|
||||
++pos;
|
||||
tokenizer->pos = pos;
|
||||
return TRUE;
|
||||
case '\\':
|
||||
++pos;
|
||||
if (pos >= len) return FALSE; /* no character after backslash */
|
||||
/* fall through, append whatever comes */
|
||||
default:
|
||||
g_string_append_c(token, str[pos]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return FALSE; /* no terminating quote found */
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ void li_response_clear(liResponse *resp) {
|
|||
|
||||
static void li_response_send_error_page(liVRequest *vr, liChunkQueue *response_body);
|
||||
|
||||
void li_response_send_headers(liVRequest *vr, liChunkQueue *raw_out, liChunkQueue *response_body) {
|
||||
void li_response_send_headers(liVRequest *vr, liChunkQueue *raw_out, liChunkQueue *response_body, gboolean upgraded) {
|
||||
GString *head;
|
||||
gboolean have_real_body, response_complete;
|
||||
liChunkQueue *tmp_cq = NULL;
|
||||
|
@ -53,8 +53,8 @@ void li_response_send_headers(liVRequest *vr, liChunkQueue *raw_out, liChunkQueu
|
|||
vr->response.http_status == 205 ||
|
||||
vr->response.http_status == 304) {
|
||||
/* They never have a content-body/length */
|
||||
li_chunkqueue_skip_all(response_body);
|
||||
raw_out->is_closed = TRUE;
|
||||
if (NULL != response_body) li_chunkqueue_skip_all(response_body);
|
||||
if (!upgraded) raw_out->is_closed = TRUE;
|
||||
} else if (response_complete) {
|
||||
if (vr->request.http_method != LI_HTTP_METHOD_HEAD || response_body->length > 0) {
|
||||
/* do not send content-length: 0 if backend already skipped content generation for HEAD */
|
||||
|
@ -74,8 +74,8 @@ void li_response_send_headers(liVRequest *vr, liChunkQueue *raw_out, liChunkQueu
|
|||
|
||||
if (vr->request.http_method == LI_HTTP_METHOD_HEAD) {
|
||||
/* content-length is set, but no body */
|
||||
li_chunkqueue_skip_all(response_body);
|
||||
raw_out->is_closed = TRUE;
|
||||
if (NULL != response_body) li_chunkqueue_skip_all(response_body);
|
||||
if (!upgraded) raw_out->is_closed = TRUE;
|
||||
}
|
||||
|
||||
/* Status line */
|
||||
|
@ -97,7 +97,9 @@ void li_response_send_headers(liVRequest *vr, liChunkQueue *raw_out, liChunkQueu
|
|||
}
|
||||
|
||||
/* connection header, if needed. connection entries in the list are ignored below, send them directly */
|
||||
if (vr->request.http_version == LI_HTTP_VERSION_1_1) {
|
||||
if (upgraded) {
|
||||
g_string_append_len(head, CONST_STR_LEN("Connection: Upgrade\r\n"));
|
||||
} else if (vr->request.http_version == LI_HTTP_VERSION_1_1) {
|
||||
if (!vr->coninfo->keep_alive)
|
||||
g_string_append_len(head, CONST_STR_LEN("Connection: close\r\n"));
|
||||
} else {
|
||||
|
|
|
@ -11,9 +11,8 @@ struct liStreamHttpResponse {
|
|||
liFilterChunkedDecodeState chunked_decode_state;
|
||||
};
|
||||
|
||||
static gboolean check_response_header(liStreamHttpResponse* shr) {
|
||||
static void check_response_header(liStreamHttpResponse* shr) {
|
||||
liResponse *resp = &shr->vr->response;
|
||||
liHttpHeader *hh;
|
||||
GList *l;
|
||||
|
||||
shr->transfer_encoding_chunked = FALSE;
|
||||
|
@ -22,7 +21,7 @@ static gboolean check_response_header(liStreamHttpResponse* shr) {
|
|||
l = li_http_header_find_first(resp->headers, CONST_STR_LEN("transfer-encoding"));
|
||||
if (l) {
|
||||
for ( ; l ; l = li_http_header_find_next(l, CONST_STR_LEN("transfer-encoding")) ) {
|
||||
hh = (liHttpHeader*) l->data;
|
||||
liHttpHeader *hh = (liHttpHeader*) l->data;
|
||||
if (0 == g_ascii_strcasecmp( LI_HEADER_VALUE(hh), "identity" )) {
|
||||
/* ignore */
|
||||
continue;
|
||||
|
@ -30,13 +29,13 @@ static gboolean check_response_header(liStreamHttpResponse* shr) {
|
|||
if (shr->transfer_encoding_chunked) {
|
||||
VR_ERROR(shr->vr, "%s", "Response is chunked encoded twice");
|
||||
li_vrequest_error(shr->vr);
|
||||
return FALSE;
|
||||
return;
|
||||
}
|
||||
shr->transfer_encoding_chunked = TRUE;
|
||||
} else {
|
||||
VR_ERROR(shr->vr, "Response has unsupported Transfer-Encoding: %s", LI_HEADER_VALUE(hh));
|
||||
li_vrequest_error(shr->vr);
|
||||
return FALSE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
li_http_header_remove(resp->headers, CONST_STR_LEN("transfer-encoding"));
|
||||
|
@ -46,10 +45,49 @@ static gboolean check_response_header(liStreamHttpResponse* shr) {
|
|||
}
|
||||
}
|
||||
|
||||
/* Upgrade: */
|
||||
l = li_http_header_find_first(resp->headers, CONST_STR_LEN("upgrade"));
|
||||
if (l) {
|
||||
gboolean have_connection_upgrade = FALSE;
|
||||
liHttpHeaderTokenizer header_tokenizer;
|
||||
GString *token;
|
||||
if (101 != resp->http_status) {
|
||||
VR_ERROR(shr->vr, "Upgrade but status is %i instead of 101 'Switching Protocols'", resp->http_status);
|
||||
li_vrequest_error(shr->vr);
|
||||
return;
|
||||
}
|
||||
if (shr->transfer_encoding_chunked) {
|
||||
VR_ERROR(shr->vr, "%s", "Upgrade with Transfer-Encoding: chunked");
|
||||
li_vrequest_error(shr->vr);
|
||||
return;
|
||||
}
|
||||
/* requires Connection: Upgrade header */
|
||||
token = g_string_sized_new(15);
|
||||
li_http_header_tokenizer_start(&header_tokenizer, resp->headers, CONST_STR_LEN("Connection"));
|
||||
while (li_http_header_tokenizer_next(&header_tokenizer, token)) {
|
||||
VR_ERROR(shr->vr, "Parsing header '%s'", ((liHttpHeader*)header_tokenizer.cur->data)->data->str);
|
||||
VR_ERROR(shr->vr, "Connection token '%s'", token->str);
|
||||
if (0 == g_ascii_strcasecmp(token->str, "Upgrade")) {
|
||||
have_connection_upgrade = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
g_string_free(token, TRUE); token = NULL;
|
||||
if (!have_connection_upgrade) {
|
||||
VR_ERROR(shr->vr, "%s", "Upgrade without Connection: Upgrade Transfer");
|
||||
li_vrequest_error(shr->vr);
|
||||
return;
|
||||
}
|
||||
shr->response_headers_finished = TRUE;
|
||||
shr->vr->backend_drain->out->is_closed = FALSE;
|
||||
li_vrequest_connection_upgrade(shr->vr, shr->vr->backend_drain, &shr->stream);
|
||||
return;
|
||||
}
|
||||
|
||||
shr->response_headers_finished = TRUE;
|
||||
li_vrequest_indirect_headers_ready(shr->vr);
|
||||
|
||||
return TRUE;
|
||||
return;
|
||||
}
|
||||
|
||||
static void stream_http_response_data(liStreamHttpResponse* shr) {
|
||||
|
@ -58,7 +96,8 @@ static void stream_http_response_data(liStreamHttpResponse* shr) {
|
|||
if (!shr->response_headers_finished) {
|
||||
switch (li_http_response_parse(shr->vr, &shr->parse_response_ctx)) {
|
||||
case LI_HANDLER_GO_ON:
|
||||
if (!check_response_header(shr)) return;
|
||||
check_response_header(shr);
|
||||
if (NULL == shr->stream.source) return;
|
||||
break;
|
||||
case LI_HANDLER_ERROR:
|
||||
VR_ERROR(shr->vr, "%s", "Parsing response header failed");
|
||||
|
|
|
@ -288,10 +288,16 @@ static liThrottleState* subvr_handle_throttle_in(liVRequest *vr) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void subvr_connection_upgrade(liVRequest *vr, liStream *backend_drain, liStream *backend_source) {
|
||||
UNUSED(backend_drain); UNUSED(backend_source);
|
||||
subvr_handle_response_error(vr);
|
||||
}
|
||||
|
||||
static const liConCallbacks subrequest_callbacks = {
|
||||
subvr_handle_response_error,
|
||||
subvr_handle_throttle_out,
|
||||
subvr_handle_throttle_in
|
||||
subvr_handle_throttle_in,
|
||||
subvr_connection_upgrade
|
||||
};
|
||||
|
||||
static liSubrequest* subrequest_new(liVRequest *vr) {
|
||||
|
|
|
@ -399,7 +399,23 @@ void li_vrequest_indirect_headers_ready(liVRequest* vr) {
|
|||
li_vrequest_joblist_append(vr);
|
||||
}
|
||||
|
||||
void li_vrequest_connection_upgrade(liVRequest *vr, liStream *backend_drain, liStream *backend_source) {
|
||||
assert(LI_VRS_HANDLE_RESPONSE_HEADERS > vr->state);
|
||||
|
||||
/* abort config handling. no filter, no more headers, ... */
|
||||
vr->state = LI_VRS_WRITE_CONTENT;
|
||||
li_action_stack_reset(vr, &vr->action_stack);
|
||||
|
||||
if (CORE_OPTION(LI_CORE_OPTION_DEBUG_REQUEST_HANDLING).boolean) {
|
||||
VR_DEBUG(vr, "%s", "connection uprade");
|
||||
}
|
||||
|
||||
/* we don't want these to be disconnected by a li_vrequest_reset */
|
||||
li_stream_safe_release(&vr->backend_drain);
|
||||
li_stream_safe_release(&vr->backend_source);
|
||||
|
||||
vr->coninfo->callbacks->connection_upgrade(vr, backend_drain, backend_source);
|
||||
}
|
||||
|
||||
gboolean li_vrequest_is_handled(liVRequest *vr) {
|
||||
return vr->state >= LI_VRS_READ_CONTENT;
|
||||
|
|
|
@ -568,7 +568,9 @@ static void fastcgi_stream_out(liStream *stream, liStreamEvent event) {
|
|||
li_stream_notify(stream);
|
||||
break;
|
||||
case LI_STREAM_CONNECTED_SOURCE:
|
||||
assert(!ctx->stdin_closed);
|
||||
/* support Connection: Upgrade by reopening stdin. not standard compliant,
|
||||
* but the backend asked for it :) */
|
||||
ctx->stdin_closed = FALSE;
|
||||
break;
|
||||
case LI_STREAM_DISCONNECTED_SOURCE:
|
||||
if (!ctx->stdin_closed) {
|
||||
|
|
|
@ -57,6 +57,8 @@ static void proxy_send_headers(liVRequest *vr, liChunkQueue *out) {
|
|||
liHttpHeader *header;
|
||||
GList *iter;
|
||||
gchar *enc_path;
|
||||
liHttpHeaderTokenizer header_tokenizer;
|
||||
GString *tmp_str = vr->wrk->tmp_str;
|
||||
|
||||
g_string_append_len(head, GSTR_LEN(vr->request.http_method_str));
|
||||
g_string_append_len(head, CONST_STR_LEN(" "));
|
||||
|
@ -81,11 +83,19 @@ static void proxy_send_headers(liVRequest *vr, liChunkQueue *out) {
|
|||
break;
|
||||
}
|
||||
|
||||
li_http_header_tokenizer_start(&header_tokenizer, vr->request.headers, CONST_STR_LEN("Connection"));
|
||||
while (li_http_header_tokenizer_next(&header_tokenizer, tmp_str)) {
|
||||
if (0 == g_ascii_strcasecmp(tmp_str->str, "Upgrade")) {
|
||||
g_string_append_len(head, CONST_STR_LEN("Connection: Upgrade\r\n"));
|
||||
}
|
||||
}
|
||||
|
||||
for (iter = g_queue_peek_head_link(&vr->request.headers->entries); iter; iter = g_list_next(iter)) {
|
||||
header = (liHttpHeader*) iter->data;
|
||||
if (li_http_header_key_is(header, CONST_STR_LEN("Connection"))) continue;
|
||||
if (li_http_header_key_is(header, CONST_STR_LEN("Proxy-Connection"))) continue;
|
||||
if (li_http_header_key_is(header, CONST_STR_LEN("X-Forwarded-Proto"))) continue;
|
||||
if (li_http_header_key_is(header, CONST_STR_LEN("X-Forwarded-For"))) continue;
|
||||
g_string_append_len(head, GSTR_LEN(header->data));
|
||||
g_string_append_len(head, CONST_STR_LEN("\r\n"));
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ static liHandlerResult status_info_runtime(liVRequest *vr, liPlugin *p);
|
|||
static gint str_comp(gconstpointer a, gconstpointer b);
|
||||
|
||||
/* auto format constants */
|
||||
static gchar liConnectionState_short[LI_CON_STATE_LAST+2] = "_cKqrhw";
|
||||
static gchar liConnectionState_short[LI_CON_STATE_LAST+2] = "_cKqrhwu";
|
||||
|
||||
/* html snippet constants */
|
||||
static const gchar html_header[] =
|
||||
|
@ -176,10 +176,11 @@ static const gchar html_connections_sum[] =
|
|||
" <tr>\n"
|
||||
" <th style=\"width: 100px;\">inactive</th>\n"
|
||||
" <th style=\"width: 100px;\">request start</th>\n"
|
||||
" <th style=\"width: 150px;\">read request header</th>\n"
|
||||
" <th style=\"width: 150px;\">handle request</th>\n"
|
||||
" <th style=\"width: 150px;\">write response</th>\n"
|
||||
" <th style=\"width: 150px;\">keep-alive</th>\n"
|
||||
" <th style=\"width: 100px;\">read header</th>\n"
|
||||
" <th style=\"width: 100px;\">handle request</th>\n"
|
||||
" <th style=\"width: 100px;\">write response</th>\n"
|
||||
" <th style=\"width: 100px;\">keep-alive</th>\n"
|
||||
" <th style=\"width: 100px;\">upgraded</th>\n"
|
||||
" </tr>\n"
|
||||
" <tr>\n"
|
||||
" <td>%u</td>\n"
|
||||
|
@ -188,6 +189,7 @@ static const gchar html_connections_sum[] =
|
|||
" <td>%u</td>\n"
|
||||
" <td>%u</td>\n"
|
||||
" <td>%u</td>\n"
|
||||
" <td>%u</td>\n"
|
||||
" </tr>\n"
|
||||
" </table>\n";
|
||||
static const gchar html_status_codes[] =
|
||||
|
@ -737,9 +739,11 @@ static GString *status_info_full(liVRequest *vr, liPlugin *p, gboolean short_inf
|
|||
|
||||
/* connection counts */
|
||||
g_string_append_len(html, CONST_STR_LEN("<div class=\"title\"><strong>Connections</strong> (states, sum)</div>\n"));
|
||||
g_string_append_printf(html, html_connections_sum, connection_count[0] + connection_count[1],
|
||||
connection_count[3], connection_count[4], connection_count[5], connection_count[6],
|
||||
connection_count[2]
|
||||
g_string_append_printf(html, html_connections_sum,
|
||||
connection_count[LI_CON_STATE_DEAD] + connection_count[LI_CON_STATE_CLOSE],
|
||||
connection_count[LI_CON_STATE_REQUEST_START], connection_count[LI_CON_STATE_READ_REQUEST_HEADER],
|
||||
connection_count[LI_CON_STATE_HANDLE_MAINVR], connection_count[LI_CON_STATE_WRITE],
|
||||
connection_count[LI_CON_STATE_KEEP_ALIVE], connection_count[LI_CON_STATE_UPGRADED]
|
||||
);
|
||||
|
||||
/* response status codes */
|
||||
|
@ -874,6 +878,8 @@ static GString *status_info_plain(liVRequest *vr, guint uptime, liStatistics *to
|
|||
li_string_append_int(html, connection_count[LI_CON_STATE_WRITE]);
|
||||
g_string_append_len(html, CONST_STR_LEN("\nconnection_state_keep_alive: "));
|
||||
li_string_append_int(html, connection_count[LI_CON_STATE_KEEP_ALIVE]);
|
||||
g_string_append_len(html, CONST_STR_LEN("\nconnection_state_upgraded: "));
|
||||
li_string_append_int(html, connection_count[LI_CON_STATE_UPGRADED]);
|
||||
/* status cpdes */
|
||||
g_string_append_len(html, CONST_STR_LEN("\n\n# Status Codes (since start)\nstatus_1xx: "));
|
||||
li_string_append_int(html, mod_status_response_codes[0]);
|
||||
|
@ -906,7 +912,7 @@ static GString *status_info_auto(liVRequest *vr, guint uptime, liStatistics *tot
|
|||
li_string_append_int(html, (gint64)uptime);
|
||||
/* connection states */
|
||||
g_string_append_len(html, CONST_STR_LEN("\nBusyServers: "));
|
||||
li_string_append_int(html, connection_count[3]+connection_count[4]+connection_count[5]+connection_count[6]);
|
||||
li_string_append_int(html, connection_count[3]+connection_count[4]+connection_count[5]+connection_count[6]+connection_count[7]);
|
||||
g_string_append_len(html, CONST_STR_LEN("\nIdleServers: "));
|
||||
li_string_append_int(html, connection_count[0]+connection_count[1]+connection_count[2]);
|
||||
/* average since start */
|
||||
|
|
Loading…
Reference in New Issue