1
0
Fork 0
mirror of https://github.com/warmcat/libwebsockets.git synced 2025-03-09 00:00:04 +01:00

http: redo redirects to follow close flow

Until now although we can follow redirects, and they can promote the
protocol from h1->h2, we couldn't handle h2 wsi reuse since there are many
states in the wsi affected by being h2.

This wipes the related states in lws_wsi_reset() and follows the generic
wsi close flow before deviating into the redirect really close to the end,
ensuring we cleaned out evidence of our previous life properly.

h2->h2 redirects work properly after this.

The max number of redirects is increased from 3 -> 4 since this was seen in
the wild with www and then geographic-based redirects.
This commit is contained in:
Andy Green 2021-06-17 10:07:04 +01:00
parent 2f9bb7a30a
commit 272dba8307
16 changed files with 466 additions and 339 deletions

View file

@ -60,7 +60,7 @@ lws_http_client_connect_via_info2(struct lws *wsi)
for (n = 0; n < (int)LWS_ARRAY_SIZE(hnames); n++)
if (hnames[n] && stash->cis[n] &&
lws_hdr_simple_create(wsi, hnames[n], stash->cis[n]))
goto bail1;
goto bail;
#if defined(LWS_WITH_SOCKS5)
if (!wsi->a.vhost->socks_proxy_port)
@ -70,15 +70,58 @@ lws_http_client_connect_via_info2(struct lws *wsi)
no_ah:
return lws_client_connect_2_dnsreq(wsi);
bail1:
bail:
#if defined(LWS_WITH_SOCKS5)
if (!wsi->a.vhost->socks_proxy_port)
lws_free_set_NULL(wsi->stash);
#endif
lws_free_set_NULL(wsi->stash);
return NULL;
}
int
lws_client_stash_create(struct lws *wsi, const char **cisin)
{
size_t size;
char *pc;
int n;
size = sizeof(*wsi->stash);
/*
* Let's overallocate the stash object with space for all the args
* in one hit.
*/
for (n = 0; n < CIS_COUNT; n++)
if (cisin[n])
size += strlen(cisin[n]) + 1;
if (wsi->stash)
lws_free_set_NULL(wsi->stash);
wsi->stash = lws_malloc(size, "client stash");
if (!wsi->stash)
return 1;
/* all the pointers default to NULL, but no need to zero the args */
memset(wsi->stash, 0, sizeof(*wsi->stash));
pc = (char *)&wsi->stash[1];
for (n = 0; n < CIS_COUNT; n++)
if (cisin[n]) {
size_t mm;
wsi->stash->cis[n] = pc;
mm = strlen(cisin[n]) + 1;
memcpy(pc, cisin[n], mm);
pc += mm;
}
return 0;
}
struct lws *
lws_client_connect_via_info(const struct lws_client_connect_info *i)
{
@ -86,10 +129,8 @@ lws_client_connect_via_info(const struct lws_client_connect_info *i)
struct lws *wsi, *safe = NULL;
const struct lws_protocols *p;
const char *cisin[CIS_COUNT];
struct lws_vhost *vh, *v;
size_t size;
int n, tsi;
char *pc;
struct lws_vhost *vh;
int tsi;
if (i->context->requested_stop_internal_loops)
return NULL;
@ -118,11 +159,10 @@ lws_client_connect_via_info(const struct lws_client_connect_info *i)
wsi = __lws_wsi_create_with_role(i->context, tsi, NULL);
lws_context_unlock(i->context);
if (wsi == NULL)
goto bail;
return NULL;
vh = i->vhost;
if (!vh) {
#if defined(LWS_WITH_TLS_JIT_TRUST)
if (lws_tls_jit_trust_vhost_bind(i->context, i->address, &vh))
#endif
@ -199,23 +239,11 @@ lws_client_connect_via_info(const struct lws_client_connect_info *i)
if (i->ssl_connection & LCCSCF_WAKE_SUSPEND__VALIDITY)
wsi->conn_validity_wakesuspend = 1;
if (!i->vhost) {
v = i->context->vhost_list;
if (!v) { /* coverity */
lwsl_err("%s: no vhost\n", __func__);
goto bail;
}
if (!strcmp(v->name, "system"))
v = v->vhost_next;
} else
v = i->vhost;
lws_vhost_bind_wsi(v, wsi);
lws_vhost_bind_wsi(vh, wsi);
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
/* additionally inerit from vhost we bound to */
lws_fi_inherit_copy(&wsi->fic, &v->fic, "wsi", i->fi_wsi_name);
lws_fi_inherit_copy(&wsi->fic, &vh->fic, "wsi", i->fi_wsi_name);
#endif
if (!wsi->a.vhost) {
@ -324,23 +352,13 @@ lws_client_connect_via_info(const struct lws_client_connect_info *i)
cisin[CIS_IFACE] = i->iface;
cisin[CIS_ALPN] = i->alpn;
size = sizeof(*wsi->stash);
if (lws_client_stash_create(wsi, cisin))
goto bail;
/*
* Let's overallocate the stash object with space for all the args
* in one hit.
*/
for (n = 0; n < CIS_COUNT; n++)
if (cisin[n])
size += strlen(cisin[n]) + 1;
wsi->stash = lws_malloc(size, "client stash");
if (!wsi->stash) {
lwsl_err("%s: OOM\n", __func__);
goto bail1;
}
/* all the pointers default to NULL, but no need to zero the args */
memset(wsi->stash, 0, sizeof(*wsi->stash));
#if defined(LWS_WITH_TLS)
if (i->alpn)
lws_strncpy(wsi->alpn, i->alpn, sizeof(wsi->alpn));
#endif
wsi->a.opaque_user_data = wsi->stash->opaque_user_data =
i->opaque_user_data;
@ -382,17 +400,6 @@ lws_client_connect_via_info(const struct lws_client_connect_info *i)
lws_metrics_tag_wsi_add(wsi, "vh", wsi->a.vhost->name);
pc = (char *)&wsi->stash[1];
for (n = 0; n < CIS_COUNT; n++)
if (cisin[n]) {
size_t mm;
wsi->stash->cis[n] = pc;
mm = strlen(cisin[n]) + 1;
memcpy(pc, cisin[n], mm);
pc += mm;
}
/*
* at this point user callbacks like
* LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER will be interested to
@ -519,10 +526,8 @@ bail3:
return NULL;
#endif
bail1:
lws_free_set_NULL(wsi->stash);
bail:
lws_free_set_NULL(wsi->stash);
lws_fi_destroy(&wsi->fic);
lws_free(wsi);
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)

View file

@ -144,6 +144,26 @@ lws_client_connect_2_dnsreq(struct lws *wsi)
return wsi;
}
/*
* clients who will create their own fresh connection keep a copy of
* the hostname they originally connected to, in case other connections
* want to use it too
*/
if (!wsi->cli_hostname_copy) {
if (wsi->stash && wsi->stash->cis[CIS_HOST])
wsi->cli_hostname_copy =
lws_strdup(wsi->stash->cis[CIS_HOST]);
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
else {
char *pa = lws_hdr_simple_ptr(wsi,
_WSI_TOKEN_CLIENT_PEER_ADDRESS);
if (pa)
wsi->cli_hostname_copy = lws_strdup(pa);
}
#endif
}
/*
* The first job is figure out if we want to pipeline on or just join
* an existing "active connection" to the same place
@ -213,26 +233,6 @@ lws_client_connect_2_dnsreq(struct lws *wsi)
solo:
/*
* clients who will create their own fresh connection keep a copy of
* the hostname they originally connected to, in case other connections
* want to use it too
*/
if (!wsi->cli_hostname_copy) {
if (wsi->stash && wsi->stash->cis[CIS_HOST])
wsi->cli_hostname_copy =
lws_strdup(wsi->stash->cis[CIS_HOST]);
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
else {
char *pa = lws_hdr_simple_ptr(wsi,
_WSI_TOKEN_CLIENT_PEER_ADDRESS);
if (pa)
wsi->cli_hostname_copy = lws_strdup(pa);
}
#endif
}
/*
* If we made our own connection, and we're doing a method that can
* take a pipeline, we are an "active client connection".

View file

@ -475,7 +475,7 @@ ads_known:
errno_copy = 999;
#endif
lwsl_debug("%s: connect: errno: %d\n", __func__, errno_copy);
lwsl_debug("%s: connect: fd %d errno: %d\n", __func__, wsi->desc.sockfd, errno_copy);
if (errno_copy &&
errno_copy != LWS_EALREADY &&

View file

@ -1,7 +1,7 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
* Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
@ -95,7 +95,8 @@ lws_client_connect_4_established(struct lws *wsi, struct lws *wsi_piggyback,
goto failed;
wsi->c_port = (uint16_t)wsi->a.vhost->http.http_proxy_port;
n = (int)send(wsi->desc.sockfd, (char *)pt->serv_buf, (unsigned int)plen,
n = (int)send(wsi->desc.sockfd, (char *)pt->serv_buf,
(unsigned int)plen,
MSG_NOSIGNAL);
if (n < 0) {
lwsl_debug("ERROR writing to proxy socket\n");
@ -161,14 +162,18 @@ send_hs:
__func__, wsi->lc.gutag, lwsi_state(wsi_piggyback));
} else {
lwsl_info("%s: %s: %s %s client created own conn "
"(raw %d) vh %sm st 0x%x\n",
__func__, wsi->lc.gutag, wsi->role_ops->name,
wsi->a.protocol->name, rawish, wsi->a.vhost->name,
lwsi_state(wsi));
"(raw %d) vh %sm st 0x%x\n", __func__, wsi->lc.gutag,
wsi->role_ops->name, wsi->a.protocol->name, rawish,
wsi->a.vhost->name, lwsi_state(wsi));
/* we are making our own connection */
if (!rawish) {
if (!rawish
#if defined(LWS_WITH_TLS)
// && (!(wsi->tls.use_ssl & LCCSCF_USE_SSL) || wsi->tls.ssl)
#endif
) {
if (lwsi_state(wsi) != LRS_H1C_ISSUE_HANDSHAKE2)
lwsi_set_state(wsi, LRS_H1C_ISSUE_HANDSHAKE);
} else {
@ -183,20 +188,24 @@ send_hs:
(wsi->tls.use_ssl & LCCSCF_USE_SSL)) {
int result;
//lwsi_set_state(wsi, LRS_WAITING_SSL);
/*
* We can retry this... just cook the SSL BIO
* the first time
*/
result = lws_client_create_tls(wsi, &cce, 1);
lwsl_debug("%s: create_tls said %d\n",
__func__, result);
switch (result) {
case CCTLS_RETURN_DONE:
break;
case CCTLS_RETURN_RETRY:
lwsl_debug("%s: create_tls RETRY\n",
__func__);
return wsi;
default:
lwsl_debug("%s: create_tls FAIL\n",
__func__);
goto failed;
}
@ -207,9 +216,10 @@ send_hs:
* LRS_H2_WAITING_TO_SEND_HEADERS already.
*/
lwsl_notice("%s: %s: "
"tls established st 0x%x\n",
__func__, wsi->lc.gutag, lwsi_state(wsi));
lwsl_notice("%s: %s: tls established st 0x%x, "
"client_h2_alpn %d\n", __func__,
wsi->lc.gutag, lwsi_state(wsi),
wsi->client_h2_alpn);
if (lwsi_state(wsi) !=
LRS_H2_WAITING_TO_SEND_HEADERS)
@ -217,7 +227,13 @@ send_hs:
LRS_H1C_ISSUE_HANDSHAKE2);
lws_set_timeout(wsi,
PENDING_TIMEOUT_AWAITING_CLIENT_HS_SEND,
(int)wsi->a.context->timeout_secs);
(int)wsi->a.context->timeout_secs);
#if 0
/* ensure pollin enabled */
if (lws_change_pollfd(wsi, 0, LWS_POLLIN))
lwsl_notice("%s: unable to set POLLIN\n",
__func__);
#endif
goto provoke_service;
}
@ -230,7 +246,8 @@ send_hs:
if (m) {
n = user_callback_handle_rxflow(
wsi->a.protocol->callback, wsi,
(enum lws_callback_reasons)m, wsi->user_space, NULL, 0);
(enum lws_callback_reasons)m,
wsi->user_space, NULL, 0);
if (n < 0) {
lwsl_info("RAW_PROXY_CLI_ADOPT err\n");
goto failed;
@ -240,7 +257,7 @@ send_hs:
/* service.c pollout processing wants this */
wsi->hdr_parsing_completed = 1;
#if defined(LWS_ROLE_MQTT)
if (!strcmp(meth, "MQTT")) {
if (meth && !strcmp(meth, "MQTT")) {
#if defined(LWS_WITH_TLS)
if (wsi->tls.use_ssl & LCCSCF_USE_SSL) {
lwsi_set_state(wsi, LRS_WAITING_SSL);
@ -320,7 +337,7 @@ provoke_service:
failed:
lws_inform_client_conn_fail(wsi, (void *)cce, strlen(cce));
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "client_connect2");
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "client_connect4");
return NULL;
}

View file

@ -123,6 +123,8 @@ __lws_reset_wsi(struct lws *wsi)
#if defined(LWS_WITH_CLIENT)
lws_dll2_remove(&wsi->dll2_cli_txn_queue);
lws_dll2_remove(&wsi->dll_cli_active_conns);
if (wsi->cli_hostname_copy)
lws_free_set_NULL(wsi->cli_hostname_copy);
#endif
#if defined(LWS_WITH_SYS_ASYNC_DNS)
@ -143,7 +145,7 @@ __lws_reset_wsi(struct lws *wsi)
__lws_same_vh_protocol_remove(wsi);
#if defined(LWS_WITH_CLIENT)
lws_free_set_NULL(wsi->stash);
//lws_free_set_NULL(wsi->stash);
lws_free_set_NULL(wsi->cli_hostname_copy);
#endif
@ -166,6 +168,34 @@ __lws_reset_wsi(struct lws *wsi)
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
__lws_header_table_detach(wsi, 0);
#endif
#if defined(LWS_ROLE_H2)
/*
* Let's try to clean out the h2-ness of the wsi
*/
memset(&wsi->h2, 0, sizeof(wsi->h2));
wsi->hdr_parsing_completed = wsi->mux_substream =
wsi->upgraded_to_http2 = wsi->mux_stream_immortal =
wsi->h2_acked_settings = wsi->seen_nonpseudoheader =
wsi->socket_is_permanently_unusable = wsi->favoured_pollin =
wsi->already_did_cce = wsi->told_user_closed =
wsi->waiting_to_send_close_frame = wsi->close_needs_ack =
wsi->parent_pending_cb_on_writable = wsi->seen_zero_length_recv =
wsi->close_when_buffered_out_drained = wsi->could_have_pending = 0;
#endif
#if defined(LWS_WITH_CLIENT)
wsi->do_ws = wsi->chunked = wsi->client_rx_avail =
wsi->client_http_body_pending = wsi->transaction_from_pipeline_queue =
wsi->keepalive_active = wsi->keepalive_rejected =
wsi->redirected_to_get = wsi->client_pipeline = wsi->client_h2_alpn =
wsi->client_mux_substream = wsi->client_mux_migrated =
wsi->tls_session_reused = wsi->perf_done = 0;
wsi->immortal_substream_count = 0;
#endif
}
/* req cx lock */
@ -194,17 +224,23 @@ __lws_free_wsi(struct lws *wsi)
}
#endif
vh = wsi->a.vhost;
__lws_reset_wsi(wsi);
__lws_wsi_remove_from_sul(wsi);
vh = wsi->a.vhost;
if (vh)
/* this may destroy vh */
__lws_vhost_unbind_wsi(wsi); /* req cx + vh lock */
#if defined(LWS_WITH_CLIENT)
if (wsi->stash)
lws_free_set_NULL(wsi->stash);
#endif
if (wsi->a.context->event_loop_ops->destroy_wsi)
wsi->a.context->event_loop_ops->destroy_wsi(wsi);
if (vh)
__lws_vhost_unbind_wsi(wsi); /* req cx + vh lock */
lwsl_debug("%s: %s, tsi fds count %d\n", __func__,
lws_wsi_tag(wsi),
wsi->a.context->pt[(int)wsi->tsi].fds_count);
@ -339,6 +375,7 @@ __lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason,
#if defined(LWS_WITH_CLIENT)
lws_free_set_NULL(wsi->cli_hostname_copy);
wsi->client_mux_substream_was = wsi->client_mux_substream;
lws_addrinfo_clean(wsi);
#endif
@ -407,7 +444,8 @@ __lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason,
#endif
#if defined(LWS_WITH_CLIENT)
lws_free_set_NULL(wsi->stash);
if (!wsi->close_is_redirect)
lws_free_set_NULL(wsi->stash);
#endif
if (wsi->role_ops == &role_ops_raw_skt) {
@ -565,7 +603,8 @@ just_kill_connection:
#endif
lwsi_state(wsi) == LRS_WAITING_DNS ||
lwsi_state(wsi) == LRS_WAITING_CONNECT) &&
!wsi->already_did_cce && wsi->a.protocol) {
!wsi->already_did_cce && wsi->a.protocol &&
!wsi->close_is_redirect) {
static const char _reason[] = "closed before established";
lwsl_debug("%s: closing in unestablished state 0x%x\n",
@ -624,6 +663,9 @@ just_kill_connection:
#if !defined(_WIN32_WCE) && !defined(LWS_PLAT_FREERTOS)
/* libuv: no event available to guarantee completion */
if (!wsi->socket_is_permanently_unusable &&
#if defined(LWS_WITH_CLIENT)
!wsi->close_is_redirect &&
#endif
lws_socket_is_valid(wsi->desc.sockfd) &&
lwsi_state(wsi) != LRS_SHUTDOWN &&
(context->event_loop_ops->flags & LELOF_ISPOLL)) {
@ -696,7 +738,7 @@ just_kill_connection:
/*
* He's a guy who go started with dns, but failed or is
* caught with a shutdown before he got the result. We have
* to issue him a close cb
* to issclient_mux_substream_wasue him a close cb
*/
ccb = 1;
@ -712,12 +754,17 @@ just_kill_connection:
ccb = 0;
#if defined(LWS_WITH_CLIENT)
if (!ccb && (lwsi_state_PRE_CLOSE(wsi) & LWSIFS_NOT_EST) &&
if (!wsi->close_is_redirect && !ccb &&
(lwsi_state_PRE_CLOSE(wsi) & LWSIFS_NOT_EST) &&
lwsi_role_client(wsi)) {
lws_inform_client_conn_fail(wsi, "Closed before conn", 18);
}
#endif
if (ccb) {
if (ccb
#if defined(LWS_WITH_CLIENT)
&& !wsi->close_is_redirect
#endif
) {
if (!wsi->a.protocol && wsi->a.vhost && wsi->a.vhost->protocols)
pro = &wsi->a.vhost->protocols[0];
@ -831,10 +878,80 @@ __lws_close_free_wsi_final(struct lws *wsi)
#endif
sanity_assert_no_sockfd_traces(wsi->a.context, wsi->desc.sockfd);
wsi->desc.sockfd = LWS_SOCK_INVALID;
}
wsi->desc.sockfd = LWS_SOCK_INVALID;
#if defined(LWS_WITH_CLIENT)
if (wsi->close_is_redirect) {
wsi->close_is_redirect = 0;
lwsl_info("%s: picking up redirection %s\n", __func__,
wsi->lc.gutag);
lws_role_transition(wsi, LWSIFR_CLIENT, LRS_UNCONNECTED,
&role_ops_h1);
#if defined(LWS_WITH_HTTP2)
if (wsi->client_mux_substream_was)
wsi->h2.END_STREAM = wsi->h2.END_HEADERS = 0;
#endif
#if defined(LWS_ROLE_H2) || defined(LWS_ROLE_MQTT)
if (wsi->mux.parent_wsi) {
lws_wsi_mux_sibling_disconnect(wsi);
wsi->mux.parent_wsi = NULL;
}
#endif
#if defined(LWS_WITH_TLS)
memset(&wsi->tls, 0, sizeof(wsi->tls));
#endif
// wsi->a.protocol = NULL;
if (wsi->a.protocol)
lws_bind_protocol(wsi, wsi->a.protocol, "client_reset");
wsi->pending_timeout = NO_PENDING_TIMEOUT;
wsi->hdr_parsing_completed = 0;
#if defined(LWS_WITH_TLS)
if (wsi->stash->cis[CIS_ALPN])
lws_strncpy(wsi->alpn, wsi->stash->cis[CIS_ALPN],
sizeof(wsi->alpn));
#endif
if (lws_header_table_attach(wsi, 0)) {
lwsl_err("%s: failed to get ah\n", __func__);
return;
}
// }
//_lws_header_table_reset(wsi->http.ah);
#if defined(LWS_WITH_TLS)
wsi->tls.use_ssl = wsi->flags & LCCSCF_USE_SSL;
#endif
#if defined(LWS_WITH_TLS_JIT_TRUST)
if (wsi->stash && wsi->stash->cis[CIS_ADDRESS]) {
struct lws_vhost *vh = NULL;
lws_tls_jit_trust_vhost_bind(wsi->a.context,
wsi->stash->cis[CIS_ADDRESS],
&vh);
if (vh) {
if (!vh->count_bound_wsi && vh->grace_after_unref) {
lwsl_info("%s: %s: in use\n", __func__, vh->lc.gutag);
lws_sul_cancel(&vh->sul_unref);
}
vh->count_bound_wsi++;
wsi->a.vhost = vh;
}
}
#endif
return;
}
#endif
/* outermost destroy notification for wsi (user_space still intact) */
if (wsi->a.vhost)
wsi->a.vhost->protocols[0].callback(wsi, LWS_CALLBACK_WSI_DESTROY,

View file

@ -540,7 +540,7 @@ struct lws_vhost {
#endif
#if defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY)
int8_t ss_refcount;
int8_t ss_refcount;
/**< refcount of number of ss connections with streamtypes using this
* trust store */
#endif
@ -742,6 +742,7 @@ struct lws {
#if defined(LWS_WITH_TLS)
struct lws_lws_tls tls;
char alpn[24];
#endif
lws_sock_file_fd_type desc; /* .filefd / .sockfd */
@ -759,6 +760,8 @@ struct lws {
#endif
unsigned int cache_secs;
short bugcatcher;
unsigned int hdr_parsing_completed:1;
unsigned int mux_substream:1;
unsigned int upgraded_to_http2:1;
@ -837,6 +840,8 @@ struct lws {
* this activity, and will report the failure */
unsigned int tls_session_reused:1;
unsigned int perf_done:1;
unsigned int close_is_redirect:1;
unsigned int client_mux_substream_was:1;
#endif
#ifdef _WIN32
@ -1351,6 +1356,9 @@ __lws_same_vh_protocol_remove(struct lws *wsi);
void
lws_same_vh_protocol_insert(struct lws *wsi, int n);
int
lws_client_stash_create(struct lws *wsi, const char **cisin);
void
lws_seq_destroy_all_on_pt(struct lws_context_per_thread *pt);

View file

@ -557,6 +557,7 @@ lws_create_vhost(struct lws_context *context,
#endif
struct lws_protocols *lwsp;
int m, f = !info->pvo, fx = 0, abs_pcol_count = 0, sec_pcol_count = 0;
const char *name = "default";
char buf[96];
char *p;
#if defined(LWS_WITH_SYS_ASYNC_DNS)
@ -564,10 +565,13 @@ lws_create_vhost(struct lws_context *context,
#endif
int n;
if (info->vhost_name)
name = info->vhost_name;
if (lws_fi(&info->fic, "vh_create_oom"))
vh = NULL;
else
vh = lws_zalloc(sizeof(*vh)
vh = lws_zalloc(sizeof(*vh) + strlen(name) + 1
#if defined(LWS_WITH_EVENT_LIBS)
+ context->event_loop_ops->evlib_size_vh
#endif
@ -577,7 +581,12 @@ lws_create_vhost(struct lws_context *context,
#if defined(LWS_WITH_EVENT_LIBS)
vh->evlib_vh = (void *)&vh[1];
vh->name = (const char *)vh->evlib_vh +
context->event_loop_ops->evlib_size_vh;
#else
vh->name = (const char *)&vh[1];
#endif
memcpy((char *)vh->name, name, strlen(name) + 1);
#if LWS_MAX_SMP > 1
lws_mutex_refcount_init(&vh->mr);
@ -587,10 +596,6 @@ lws_create_vhost(struct lws_context *context,
pcols = &protocols_dummy[0];
vh->context = context;
if (!info->vhost_name)
vh->name = "default";
else
vh->name = info->vhost_name;
{
char *end = buf + sizeof(buf) - 1;
p = buf;

View file

@ -43,10 +43,12 @@ void lwsi_set_role(struct lws *wsi, lws_wsi_state_t role)
void lwsi_set_state(struct lws *wsi, lws_wsi_state_t lrs)
{
wsi->wsistate = (wsi->wsistate & (unsigned int)(~LRS_MASK)) | lrs;
lws_wsi_state_t old = wsi->wsistate;
lwsl_debug("lwsi_set_state(%s, 0x%lx)\n", lws_wsi_tag(wsi),
(unsigned long)wsi->wsistate);
wsi->wsistate = (old & (unsigned int)(~LRS_MASK)) | lrs;
lwsl_debug("lwsi_set_state(%s): 0x%lx -> 0x%lx)\n", lws_wsi_tag(wsi),
(unsigned long)old, (unsigned long)wsi->wsistate);
}
#endif
@ -56,6 +58,7 @@ lws_vhost_bind_wsi(struct lws_vhost *vh, struct lws *wsi)
{
if (wsi->a.vhost == vh)
return;
lws_context_lock(vh->context, __func__); /* ---------- context { */
wsi->a.vhost = vh;
@ -68,6 +71,7 @@ lws_vhost_bind_wsi(struct lws_vhost *vh, struct lws *wsi)
vh->count_bound_wsi++;
lws_context_unlock(vh->context); /* } context ---------- */
lwsl_debug("%s: vh %s: wsi %s/%s, count_bound_wsi %d\n", __func__,
vh->name, wsi->role_ops ? wsi->role_ops->name : "none",
wsi->a.protocol ? wsi->a.protocol->name : "none",

View file

@ -395,12 +395,17 @@ lws_h2_issue_preface(struct lws *wsi)
return 1;
}
if (h2n->sent_preface)
return 1;
lwsl_debug("%s: %s: fd %d\n", __func__, lws_wsi_tag(wsi), (int)wsi->desc.sockfd);
if (lws_issue_raw(wsi, (uint8_t *)preface, strlen(preface)) !=
(int)strlen(preface))
return 1;
h2n->sent_preface = 1;
lws_role_transition(wsi, LWSIFR_CLIENT, LRS_H2_WAITING_TO_SEND_HEADERS,
&role_ops_h2);
@ -1534,6 +1539,11 @@ lws_h2_parse_end_of_frame(struct lws *wsi)
h2n->swsi->txc.manual_initial_tx_credit =
wsi->txc.manual_initial_tx_credit;
#if defined(LWS_WITH_TLS)
lws_strncpy(h2n->swsi->alpn, wsi->alpn,
sizeof(wsi->alpn));
#endif
wsi->user_space = NULL;
if (h2n->swsi->http.ah)
@ -1631,8 +1641,17 @@ lws_h2_parse_end_of_frame(struct lws *wsi)
#if defined(LWS_WITH_CLIENT)
if (h2n->swsi->client_mux_substream &&
lws_client_interpret_server_handshake(h2n->swsi)) {
lwsl_info("%s: cli int serv hs closed it\n", __func__);
break;
/*
* This is more complicated than it looks, one exit from
* interpret_server_handshake() is to do a close that
* turns into a redirect.
*
* In that case, the wsi survives having being reset
* and detached from any h2 identity. We need to get
* our parents out from touching it any more
*/
lwsl_info("%s: cli int serv hs closed, or redir\n", __func__);
return 2;
}
#endif
@ -2032,7 +2051,7 @@ lws_h2_parser(struct lws *wsi, unsigned char *in, lws_filepos_t _inlen,
h2n->count++;
if (h2n->type == LWS_H2_FRAME_TYPE_COUNT) { /* IGNORING FRAME */
lwsl_debug("%s: consuming for ignored %u %u\n", __func__, (unsigned int)h2n->count, (unsigned int)h2n->length);
//lwsl_debug("%s: consuming for ignored %u %u\n", __func__, (unsigned int)h2n->count, (unsigned int)h2n->length);
goto frame_end;
}
@ -2372,7 +2391,7 @@ do_windows:
break;
case LWS_H2_FRAME_TYPE_COUNT: /* IGNORING FRAME */
lwsl_debug("%s: consuming for ignored %u %u\n", __func__, (unsigned int)h2n->count, (unsigned int)h2n->length);
//lwsl_debug("%s: consuming for ignored %u %u\n", __func__, (unsigned int)h2n->count, (unsigned int)h2n->length);
h2n->count++;
break;
@ -2396,7 +2415,13 @@ frame_end:
/*
* end of frame just happened
*/
if (lws_h2_parse_end_of_frame(wsi))
n = lws_h2_parse_end_of_frame(wsi);
if (n == 2) {
*inused = (lws_filepos_t)lws_ptr_diff_size_t(in, oldin);
return 2;
}
if (n)
goto fail;
break;
@ -2442,7 +2467,7 @@ try_frame_start:
default:
if (h2n->type == LWS_H2_FRAME_TYPE_COUNT) { /* IGNORING FRAME */
lwsl_debug("%s: consuming for ignored %u %u\n", __func__, (unsigned int)h2n->count, (unsigned int)h2n->length);
//lwsl_debug("%s: consuming for ignored %u %u\n", __func__, (unsigned int)h2n->count, (unsigned int)h2n->length);
h2n->count++;
}
break;
@ -2480,6 +2505,7 @@ lws_h2_client_handshake(struct lws *wsi)
char *meth = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_METHOD),
*uri = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_URI), *simp;
struct lws *nwsi = lws_get_network_wsi(wsi);
const char *path = "/";
int n, m;
/*
* The identifier of a newly established stream MUST be numerically
@ -2517,6 +2543,8 @@ lws_h2_client_handshake(struct lws *wsi)
if (!meth)
meth = "GET";
/* h2 pseudoheaders must be in a bunch at the start */
if (lws_add_http_header_by_token(wsi,
WSI_TOKEN_HTTP_COLON_METHOD,
(unsigned char *)meth,
@ -2529,31 +2557,49 @@ lws_h2_client_handshake(struct lws *wsi)
&p, end))
goto fail_length;
n = lws_hdr_total_length(wsi, _WSI_TOKEN_CLIENT_URI);
if (n)
path = uri;
else
if (wsi->stash && wsi->stash->cis[CIS_PATH]) {
path = wsi->stash->cis[CIS_PATH];
n = (int)strlen(path);
} else
n = 1;
if (n > 1 && path[0] == '/' && path[1] == '/') {
path++;
n--;
}
if (n && lws_add_http_header_by_token(wsi,
WSI_TOKEN_HTTP_COLON_PATH,
(unsigned char *)uri, n, &p, end))
goto fail_length;
n = lws_hdr_total_length(wsi, _WSI_TOKEN_CLIENT_ORIGIN);
simp = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN);
if (n && simp && lws_add_http_header_by_token(wsi,
WSI_TOKEN_HTTP_COLON_AUTHORITY,
(unsigned char *)simp, n, &p, end))
(unsigned char *)path, n, &p, end))
goto fail_length;
n = lws_hdr_total_length(wsi, _WSI_TOKEN_CLIENT_HOST);
simp = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_HOST);
if (!n && wsi->stash && wsi->stash->cis[CIS_ADDRESS]) {
n = (int)strlen(wsi->stash->cis[CIS_ADDRESS]);
simp = wsi->stash->cis[CIS_ADDRESS];
}
if (!wsi->client_h2_alpn && n && simp &&
// n = lws_hdr_total_length(wsi, _WSI_TOKEN_CLIENT_ORIGIN);
// simp = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN);
#if 0
if (n && simp && lws_add_http_header_by_token(wsi,
WSI_TOKEN_HTTP_COLON_AUTHORITY,
(unsigned char *)simp, n, &p, end))
goto fail_length;
#endif
if (/*!wsi->client_h2_alpn && */n && simp &&
lws_add_http_header_by_token(wsi, WSI_TOKEN_HOST,
(unsigned char *)simp, n, &p, end))
goto fail_length;
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_USER_AGENT,
(unsigned char *)"lwsss", 5,
&p, end))
goto fail_length;
if (wsi->flags & LCCSCF_HTTP_MULTIPART_MIME) {
p1 = lws_http_multipart_headers(wsi, p);

View file

@ -113,8 +113,20 @@ rops_handle_POLLIN_h2(struct lws_context_per_thread *pt, struct lws *wsi,
}
#endif
lwsl_info("%s: wsistate 0x%x, pollout %d\n", __func__,
(unsigned int)wsi->wsistate, pollfd->revents & LWS_POLLOUT);
lwsl_info("%s: %s wsistate 0x%x, events %d, revents %d, pollout %d\n", __func__,
wsi->lc.gutag, (unsigned int)wsi->wsistate,
pollfd->events, pollfd->revents,
pollfd->revents & LWS_POLLOUT);
/* !!! */
if (wsi->wsistate == 0x10000013) {
wsi->bugcatcher++;
if (wsi->bugcatcher == 250) {
lwsl_err("%s: BUGCATCHER\n", __func__);
return LWS_HPI_RET_PLEASE_CLOSE_ME;
}
} else
wsi->bugcatcher = 0;
/*
* something went wrong with parsing the handshake, and
@ -170,7 +182,9 @@ rops_handle_POLLIN_h2(struct lws_context_per_thread *pt, struct lws *wsi,
if (wsi->mux_substream || wsi->upgraded_to_http2) {
wsi1 = lws_get_network_wsi(wsi);
if (wsi1 && lws_has_buffered_out(wsi1))
if (wsi1 && lws_has_buffered_out(wsi1)) {
lwsl_info("%s: has buffered out\n", __func__);
/*
* We cannot deal with any kind of new RX
* because we are dealing with a partial send
@ -178,6 +192,7 @@ rops_handle_POLLIN_h2(struct lws_context_per_thread *pt, struct lws *wsi,
* expect to be able to send)
*/
return LWS_HPI_RET_HANDLED;
}
}
read:
@ -205,8 +220,11 @@ read:
!(pollfd->revents & pollfd->events & LWS_POLLIN))
return LWS_HPI_RET_HANDLED;
/* We have something to read... */
if (!(lwsi_role_client(wsi) &&
(lwsi_state(wsi) != LRS_ESTABLISHED &&
// lwsi_state(wsi) != LRS_H1C_ISSUE_HANDSHAKE2 &&
lwsi_state(wsi) != LRS_H2_WAITING_TO_SEND_HEADERS))) {
ebuf.token = pt->serv_buf;
@ -228,7 +246,8 @@ read:
// lwsl_notice("%s: Actual RX %d\n", __func__, ebuf.len);
// if (ebuf.len > 0)
// lwsl_hexdump_notice(ebuf.token, ebuf.len);
}
} else
lwsl_info("%s: skipped read\n", __func__);
if (ebuf.len < 0)
return LWS_HPI_RET_PLEASE_CLOSE_ME;
@ -484,9 +503,9 @@ rops_write_role_protocol_h2(struct lws *wsi, unsigned char *buf, size_t len,
}
if (base == LWS_WRITE_HTTP_FINAL || ((*wp) & LWS_WRITE_H2_STREAM_END)) {
lwsl_info("%s: %s: setting END_STREAM\n", __func__,
lws_wsi_tag(wsi));
flags |= LWS_H2_FLAG_END_STREAM;
lwsl_info("%s: %s: setting END_STREAM, 0x%x\n", __func__,
lws_wsi_tag(wsi), flags);
wsi->h2.send_END_STREAM = 1;
}

View file

@ -272,6 +272,7 @@ struct lws_h2_netconn {
unsigned int is_first_header_char:1;
unsigned int zero_huff_padding:1;
unsigned int last_action_dyntable_resize:1;
unsigned int sent_preface:1;
uint32_t hdr_idx;
uint32_t hpack_len;

View file

@ -217,7 +217,9 @@ start_ws_handshake:
#endif
#if defined (LWS_WITH_HTTP2)
if (wsi->client_h2_alpn && lwsi_state(wsi) != LRS_H1C_ISSUE_HANDSHAKE2) {
if (wsi->client_h2_alpn //&&
//lwsi_state(wsi) != LRS_H1C_ISSUE_HANDSHAKE2
) {
/*
* We connected to the server and set up tls and
* negotiated "h2" or connected as clear text
@ -227,16 +229,18 @@ start_ws_handshake:
* now, not an h1 client connection.
*/
#if defined(LWS_WITH_TLS)
if (wsi->tls.use_ssl & LCCSCF_USE_SSL)
lws_tls_server_conn_alpn(wsi);
#endif
lwsl_info("%s: doing h2 hello path\n", __func__);
/* send the H2 preface to legitimize the connection */
if (lws_h2_issue_preface(wsi)) {
cce = "error sending h2 preface";
goto bail3;
}
/*
* send the H2 preface to legitimize the connection
*
* transitions us to LRS_H2_WAITING_TO_SEND_HEADERS
*/
if (wsi->client_h2_alpn)
if (lws_h2_issue_preface(wsi)) {
cce = "error sending h2 preface";
goto bail3;
}
// lwsi_set_state(wsi, LRS_H1C_ISSUE_HANDSHAKE2);
lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_CLIENT_HS_SEND,
@ -800,7 +804,18 @@ lws_client_interpret_server_handshake(struct lws *wsi)
/* wsi has closed */
return 1;
}
return 0;
/*
* We are redirecting, let's close in order to extricate
* ourselves from the current wsi usage, eg, h2 mux cleanly.
*
* We will notice close_is_redirect and switch to redirect
* flow late in the close action.
*/
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "redir");
return -1;
}
/* if h1 KA is allowed, enable the queued pipeline guys */
@ -1094,7 +1109,7 @@ char *
lws_generate_client_handshake(struct lws *wsi, char *pkt)
{
const char *meth, *pp = lws_hdr_simple_ptr(wsi,
_WSI_TOKEN_CLIENT_SENT_PROTOCOLS);
_WSI_TOKEN_CLIENT_SENT_PROTOCOLS), *path;
char *p = pkt, *p1, *end = p + wsi->a.context->pt_serv_buf_size;
meth = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_METHOD);
@ -1147,9 +1162,17 @@ lws_generate_client_handshake(struct lws *wsi, char *pkt)
* Sec-WebSocket-Version: 4
*/
path = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_URI);
if (!path) {
if (wsi->stash && wsi->stash->cis[CIS_PATH] &&
wsi->stash->cis[CIS_PATH][0])
path = wsi->stash->cis[CIS_PATH];
else
path = "/";
}
p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
"%s %s HTTP/1.1\x0d\x0a", meth,
lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_URI));
"%s %s HTTP/1.1\x0d\x0a", meth, path);
p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
"Pragma: no-cache\x0d\x0a"
@ -1168,7 +1191,9 @@ lws_generate_client_handshake(struct lws *wsi, char *pkt)
_WSI_TOKEN_CLIENT_ORIGIN));
else
p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
"Origin: http://%s\x0d\x0a",
"Origin: %s://%s\x0d\x0a",
wsi->flags & LCCSCF_USE_SSL ?
"https" : "http",
lws_hdr_simple_ptr(wsi,
_WSI_TOKEN_CLIENT_ORIGIN));
}
@ -1523,8 +1548,7 @@ static uint8_t hnames2[] = {
_WSI_TOKEN_CLIENT_ORIGIN,
_WSI_TOKEN_CLIENT_SENT_PROTOCOLS,
_WSI_TOKEN_CLIENT_METHOD,
_WSI_TOKEN_CLIENT_IFACE,
_WSI_TOKEN_CLIENT_ALPN
_WSI_TOKEN_CLIENT_IFACE
};
/**
@ -1545,9 +1569,9 @@ lws_client_reset(struct lws **pwsi, int ssl, const char *address, int port,
#if defined(LWS_ROLE_WS)
struct _lws_websocket_related *ws;
#endif
char *stash, *p;
const char *cisin[CIS_COUNT];
struct lws *wsi;
size_t size = 0;
size_t o;
int n;
if (!pwsi)
@ -1559,7 +1583,7 @@ lws_client_reset(struct lws **pwsi, int ssl, const char *address, int port,
lwsl_debug("%s: %s: redir %d: %s\n", __func__, lws_wsi_tag(wsi),
wsi->redirects, address);
if (wsi->redirects == 3) {
if (wsi->redirects == 4) {
lwsl_err("%s: Too many redirects\n", __func__);
return NULL;
}
@ -1570,52 +1594,24 @@ lws_client_reset(struct lws **pwsi, int ssl, const char *address, int port,
* but leave our wsi extant and still bound to whatever vhost it was
*/
o = path[0] == '/' && path[1] == '/';
memset((char *)cisin, 0, sizeof(cisin));
cisin[CIS_ADDRESS] = address;
cisin[CIS_PATH] = path + o;
cisin[CIS_HOST] = host;
for (n = 0; n < (int)LWS_ARRAY_SIZE(hnames2); n++)
size += (unsigned int)lws_hdr_total_length(wsi, hnames2[n]) + 1u;
cisin[n + 3] = lws_hdr_simple_ptr(wsi, hnames2[n]);
if (size < (size_t)lws_hdr_total_length(wsi, _WSI_TOKEN_CLIENT_URI) + 1)
size = (unsigned int)lws_hdr_total_length(wsi, _WSI_TOKEN_CLIENT_URI) + 1u;
#if defined(LWS_WITH_TLS)
cisin[CIS_ALPN] = wsi->alpn;
#endif
/*
* The incoming address and host can be from inside the existing ah
* we are going to detach and reattch
*/
size += strlen(path) + 1 + strlen(address) + 1 + strlen(host) + 1 + 1;
p = stash = lws_malloc(size, __func__);
if (!stash)
if (lws_client_stash_create(wsi, cisin))
return NULL;
/*
* _WSI_TOKEN_CLIENT_ORIGIN,
* _WSI_TOKEN_CLIENT_SENT_PROTOCOLS,
* _WSI_TOKEN_CLIENT_METHOD,
* _WSI_TOKEN_CLIENT_IFACE,
* _WSI_TOKEN_CLIENT_ALPN
* address
* host
* path
*/
for (n = 0; n < (int)LWS_ARRAY_SIZE(hnames2); n++)
if (lws_hdr_total_length(wsi, hnames2[n]) &&
lws_hdr_simple_ptr(wsi, hnames2[n])) {
memcpy(p, lws_hdr_simple_ptr(wsi, hnames2[n]), (size_t)(
lws_hdr_total_length(wsi, hnames2[n]) + 1));
p += (size_t)(lws_hdr_total_length(wsi, hnames2[n]) + 1);
} else
*p++ = '\0';
memcpy(p, address, strlen(address) + (size_t)1);
address = p;
p += strlen(address) + 1;
memcpy(p, host, strlen(host) + (size_t)1);
host = p;
p += strlen(host) + 1;
memcpy(p, path, strlen(path) + (size_t)1);
path = p;
if (!port) {
lwsl_info("%s: forcing port 443\n", __func__);
@ -1623,8 +1619,16 @@ lws_client_reset(struct lws **pwsi, int ssl, const char *address, int port,
ssl = 1;
}
lwsl_info("redirect ads='%s', port=%d, path='%s', ssl = %d, pifds %d\n",
address, port, path, ssl, wsi->position_in_fds_table);
wsi->c_port = (uint16_t)port;
wsi->flags = (wsi->flags & (~LCCSCF_USE_SSL)) |
(ssl ? LCCSCF_USE_SSL : 0);
lwsl_notice("%s: REDIRECT %s:%d, path='%s', ssl = %d, alpn='%s'\n",
__func__, address, port, path, ssl, cisin[CIS_ALPN]);
if (!cisin[CIS_ALPN][0])
assert(0);
lws_pt_lock(pt, __func__);
__remove_wsi_socket_from_fds(wsi);
@ -1636,6 +1640,14 @@ lws_client_reset(struct lws **pwsi, int ssl, const char *address, int port,
wsi->ws = NULL;
}
#endif
/*
* After this point we can't trust the incoming strings like address,
* path any more, since they may have been pointing into the old ah.
*
* We must use the copies in the wsi->stash instead if we want them.
*/
__lws_reset_wsi(wsi); /* detaches ah here */
#if defined(LWS_ROLE_WS)
if (weak)
@ -1643,102 +1655,11 @@ lws_client_reset(struct lws **pwsi, int ssl, const char *address, int port,
#endif
wsi->client_pipeline = 1;
/* close the connection by hand */
#if defined(LWS_WITH_TLS)
lws_ssl_close(wsi);
#endif
if (wsi->role_ops &&
lws_rops_fidx(wsi->role_ops, LWS_ROPS_close_kill_connection))
lws_rops_func_fidx(wsi->role_ops, LWS_ROPS_close_kill_connection).
close_kill_connection(wsi, 1);
if (wsi->a.context->event_loop_ops->close_handle_manually)
wsi->a.context->event_loop_ops->close_handle_manually(wsi);
else
if (wsi->desc.sockfd != LWS_SOCK_INVALID)
compatible_close(wsi->desc.sockfd);
#if defined(LWS_WITH_TLS)
if (!ssl)
wsi->tls.use_ssl &= (unsigned int)~LCCSCF_USE_SSL;
else
wsi->tls.use_ssl |= LCCSCF_USE_SSL;
#else
if (ssl) {
lwsl_err("%s: not configured for ssl\n", __func__);
goto bail;
}
#endif
if (wsi->a.protocol && wsi->role_ops && wsi->protocol_bind_balance) {
wsi->a.protocol->callback(wsi,
wsi->role_ops->protocol_unbind_cb[
!!lwsi_role_server(wsi)],
wsi->user_space, (void *)__func__, 0);
wsi->protocol_bind_balance = 0;
}
wsi->desc.sockfd = LWS_SOCK_INVALID;
lws_role_transition(wsi, LWSIFR_CLIENT, LRS_UNCONNECTED, &role_ops_h1);
// wsi->a.protocol = NULL;
if (wsi->a.protocol)
lws_bind_protocol(wsi, wsi->a.protocol, "client_reset");
wsi->pending_timeout = NO_PENDING_TIMEOUT;
wsi->c_port = (uint16_t)port;
wsi->hdr_parsing_completed = 0;
if (lws_header_table_attach(wsi, 0)) {
lwsl_err("%s: failed to get ah\n", __func__);
goto bail;
}
//_lws_header_table_reset(wsi->http.ah);
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS, address))
goto bail;
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_HOST, host))
goto bail;
/*
* _WSI_TOKEN_CLIENT_ORIGIN,
* _WSI_TOKEN_CLIENT_SENT_PROTOCOLS,
* _WSI_TOKEN_CLIENT_METHOD,
* _WSI_TOKEN_CLIENT_IFACE,
* _WSI_TOKEN_CLIENT_ALPN
* address
* host
* path
* Will complete at close flow
*/
p = stash;
for (n = 0; n < (int)LWS_ARRAY_SIZE(hnames2); n++) {
if (lws_hdr_simple_create(wsi, hnames2[n], p))
goto bail;
p += lws_hdr_total_length(wsi, hnames2[n]) + 1;
}
stash[0] = '/';
memmove(&stash[1], path, size - 1 < strlen(path) + 1 ?
size - 1 : strlen(path) + (size_t)1);
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_URI, stash))
goto bail;
lws_free_set_NULL(stash);
#if defined(LWS_WITH_HTTP2)
if (wsi->client_mux_substream)
wsi->h2.END_STREAM = wsi->h2.END_HEADERS = 0;
#endif
*pwsi = lws_client_connect_2_dnsreq(wsi);
wsi->close_is_redirect = 1;
return *pwsi;
bail:
lws_free_set_NULL(stash);
return NULL;
}

View file

@ -74,7 +74,7 @@ lws_ssl_client_connect2(struct lws *wsi, char *errbuf, size_t len)
lwsi_set_state(wsi, LRS_WAITING_SSL);
/* fallthru */
case LWS_SSL_CAPABLE_MORE_SERVICE:
return 0;
return 0; /* retry */
}
}
@ -89,7 +89,7 @@ lws_ssl_client_connect2(struct lws *wsi, char *errbuf, size_t len)
(lws_now_usecs() - wsi->conmon_datum);
#endif
return 1;
return 1; /* connected */
}
@ -176,7 +176,6 @@ int lws_context_init_client_ssl(const struct lws_context_creation_info *info,
int
lws_client_create_tls(struct lws *wsi, const char **pcce, int do_c1)
{
/* we can retry this... just cook the SSL BIO the first time */
if (wsi->tls.use_ssl & LCCSCF_USE_SSL) {
@ -198,7 +197,7 @@ lws_client_create_tls(struct lws *wsi, const char **pcce, int do_c1)
}
if (!do_c1)
return 0;
return CCTLS_RETURN_DONE;
lws_metrics_caliper_report(wsi->cal_conn, METRES_GO);
lws_metrics_caliper_bind(wsi->cal_conn, wsi->a.context->mt_conn_tls);
@ -211,39 +210,18 @@ lws_client_create_tls(struct lws *wsi, const char **pcce, int do_c1)
lwsl_debug("%s: lws_ssl_client_connect1: %d\n", __func__, n);
if (!n)
return CCTLS_RETURN_RETRY; /* caller should return 0 */
if (n < 0) {
*pcce = (const char *)wsi->a.context->pt[(int)wsi->tsi].serv_buf;
lws_metrics_caliper_report(wsi->cal_conn, METRES_NOGO);
return CCTLS_RETURN_ERROR;
}
/* ...connect1 already handled caliper if SSL_accept done */
lws_tls_server_conn_alpn(wsi);
} else
wsi->tls.ssl = NULL;
#if 0
#if defined (LWS_WITH_HTTP2)
if (wsi->client_h2_alpn) {
/*
* We connected to the server and set up tls, and
* negotiated "h2".
*
* So this is it, we are an h2 nwsi client connection
* now, not an h1 client connection.
*/
#if defined(LWS_WITH_TLS)
lws_tls_server_conn_alpn(wsi);
#endif
/* send the H2 preface to legitimize the connection */
if (lws_h2_issue_preface(wsi)) {
*pcce = "error sending h2 preface";
return CCTLS_RETURN_ERROR;
}
lwsi_set_state(wsi, LRS_H1C_ISSUE_HANDSHAKE2);
}
#endif
#endif
return CCTLS_RETURN_DONE; /* OK */
}

View file

@ -116,8 +116,12 @@ lws_tls_server_conn_alpn(struct lws *wsi)
char cstr[10];
unsigned len;
if (!wsi->tls.ssl)
lwsl_info("%s\n", __func__);
if (!wsi->tls.ssl) {
lwsl_err("%s: non-ssl\n", __func__);
return 0;
}
SSL_get0_alpn_selected(wsi->tls.ssl, &name, &len);
if (!len) {
@ -131,10 +135,12 @@ lws_tls_server_conn_alpn(struct lws *wsi)
memcpy(cstr, name, len);
cstr[len] = '\0';
lwsl_info("negotiated '%s' using ALPN\n", cstr);
lwsl_info("%s: negotiated '%s' using ALPN\n", __func__, cstr);
wsi->tls.use_ssl |= LCCSCF_USE_SSL;
return lws_role_call_alpn_negotiated(wsi, (const char *)cstr);
#else
lwsl_err("%s: openssl too old\n", __func__);
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
return 0;

View file

@ -119,17 +119,17 @@ endif()
add_test(NAME http-client-multi-h1 COMMAND lws-minimal-http-client-multi
--h1 -l --port ${PORT_HCM_SRV} -d1151)
add_test(NAME http-client-multi-pipe COMMAND lws-minimal-http-client-multi
-p -l --port ${PORT_HCM_SRV})
-p -l --port ${PORT_HCM_SRV} -d1151)
add_test(NAME http-client-multi-h1-pipe COMMAND lws-minimal-http-client-multi
--h1 -p -l --port ${PORT_HCM_SRV})
--h1 -p -l --port ${PORT_HCM_SRV} -d1151)
add_test(NAME http-client-multi-stag COMMAND lws-minimal-http-client-multi
-s -l --port ${PORT_HCM_SRV})
-s -l --port ${PORT_HCM_SRV} -d1151)
add_test(NAME http-client-multi-stag-h1 COMMAND lws-minimal-http-client-multi
--h1 -s -l --port ${PORT_HCM_SRV})
--h1 -s -l --port ${PORT_HCM_SRV} -d1151)
add_test(NAME http-client-multi-stag-pipe COMMAND lws-minimal-http-client-multi
-p -s -l --port ${PORT_HCM_SRV})
-p -s -l --port ${PORT_HCM_SRV} -d1151)
add_test(NAME http-client-multi-stag-h1-pipe COMMAND lws-minimal-http-client-multi
--h1 -p -s -l --port ${PORT_HCM_SRV})
--h1 -p -s -l --port ${PORT_HCM_SRV} -d1151)
# confirm that the pipelined mode really is doing it in one connection
add_test(NAME http-client-multi-restrict-pipe COMMAND lws-minimal-http-client-multi -d1151 --limit 1 -p -l --port ${PORT_HCM_SRV})
@ -137,9 +137,9 @@ endif()
add_test(NAME http-client-multi-restrict-stag-pipe COMMAND lws-minimal-http-client-multi -d1151 --limit 1 -p -s -l --port ${PORT_HCM_SRV})
add_test(NAME http-client-multi-restrict-stag-h1-pipe COMMAND lws-minimal-http-client-multi -d1151 --limit 1 --h1 -p -s -l --port ${PORT_HCM_SRV})
# confirm that we do fail with a one connection limit and no pipelining
add_test(NAME http-client-multi-restrict-nopipe-fail COMMAND lws-minimal-http-client-multi --limit 1 -l --port ${PORT_HCM_SRV})
add_test(NAME http-client-multi-restrict-nopipe-fail COMMAND lws-minimal-http-client-multi --limit 1 -l --port ${PORT_HCM_SRV} -d1151)
set_property(TEST http-client-multi-restrict-nopipe-fail PROPERTY WILL_FAIL TRUE)
add_test(NAME http-client-multi-restrict-h1-nopipe-fail COMMAND lws-minimal-http-client-multi --limit 1 --h1 -l --port ${PORT_HCM_SRV})
add_test(NAME http-client-multi-restrict-h1-nopipe-fail COMMAND lws-minimal-http-client-multi --limit 1 --h1 -l --port ${PORT_HCM_SRV} -d1151)
set_property(TEST http-client-multi-restrict-h1-nopipe-fail PROPERTY WILL_FAIL TRUE)
set_tests_properties(http-client-multi-restrict-pipe
@ -163,21 +163,21 @@ endif()
# POSTs against local http-server-form-post
add_test(NAME http-client-multi-post COMMAND lws-minimal-http-client-multi
--post -l --port 1${PORT_HCM_SRV})
--post -l --port 1${PORT_HCM_SRV} -d1151)
add_test(NAME http-client-multi-post-h1 COMMAND lws-minimal-http-client-multi
--post --h1 -l --port 1${PORT_HCM_SRV})
--post --h1 -l --port 1${PORT_HCM_SRV} -d1151)
add_test(NAME http-client-multi-post-pipe COMMAND lws-minimal-http-client-multi
--post -p -l --port 1${PORT_HCM_SRV})
--post -p -l --port 1${PORT_HCM_SRV} -d1151)
add_test(NAME http-client-multi-post-h1-pipe COMMAND lws-minimal-http-client-multi
--post --h1 -p -l --port 1${PORT_HCM_SRV})
--post --h1 -p -l --port 1${PORT_HCM_SRV} -d1151)
add_test(NAME http-client-multi-post-stag COMMAND lws-minimal-http-client-multi
--post -s -l -d1151 --port 1${PORT_HCM_SRV})
--post -s -l -d1151 --port 1${PORT_HCM_SRV} -d1151)
add_test(NAME http-client-multi-post-stag-h1 COMMAND lws-minimal-http-client-multi
--post --h1 -d1151 -s -l --port 1${PORT_HCM_SRV})
--post --h1 -d1151 -s -l --port 1${PORT_HCM_SRV} -d1151)
add_test(NAME http-client-multi-post-stag-pipe COMMAND lws-minimal-http-client-multi
--post -p -s -l --port 1${PORT_HCM_SRV})
--post -p -s -l --port 1${PORT_HCM_SRV} -d1151)
add_test(NAME http-client-multi-post-stag-h1-pipe COMMAND lws-minimal-http-client-multi
--post --h1 -p -s -l --port 1${PORT_HCM_SRV})
--post --h1 -p -s -l --port 1${PORT_HCM_SRV} -d1151)
set_tests_properties(http-client-multi-post
http-client-multi-post-h1
http-client-multi-post-pipe

View file

@ -259,7 +259,7 @@ system_notify_cb(lws_state_manager_t *mgr, lws_state_notify_link_t *link,
LCCSCF_ACCEPT_TLS_DOWNGRADE_REDIRECTS |
LCCSCF_H2_QUIRK_NGHTTP2_END_STREAM;
i.alpn = "h2";
i.alpn = "h2,http/1.1";
if (lws_cmdline_option(a->argc, a->argv, "--h1"))
i.alpn = "http/1.1";