mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-09 00:00:04 +01:00
h2: unify immortal stream tracking across SSE and ws substreams
It was already correct but add helpers to isolate and deduplicate processing adding and closing a generically immortal stream. Change the default 31s h2 network connection timeout to be settable by .keepalive_timeout if nonzero. Add a public api allowing a client h2 stream to transition to half-closed LOCAL (by sending a 0-byte DATA with END_STREAM) and mark itself as immortal to create a read-only long-poll stream if the server allows it. Add a vhost server option flag LWS_SERVER_OPTION_VH_H2_HALF_CLOSED_LONG_POLL which allows the vhost to treat half-closed remotes as immortal long poll streams.
This commit is contained in:
parent
4e8497b28a
commit
ba754c4cb2
18 changed files with 599 additions and 60 deletions
55
READMEs/README.h2-long-poll.md
Normal file
55
READMEs/README.h2-long-poll.md
Normal file
|
@ -0,0 +1,55 @@
|
|||
# h2 long poll in lws
|
||||
|
||||
lws server and client can support "immortal" streams that are
|
||||
not subject to normal timeouts under a special condition. These
|
||||
are read-only (to the client).
|
||||
|
||||
Network connections that contain at least one immortal stream
|
||||
are themselves not subject to timeouts until the last immortal
|
||||
stream they are carrying closes.
|
||||
|
||||
Because of this, it's recommended there is some other way of
|
||||
confirming that the client is still active.
|
||||
|
||||
## Setting up lws server for h2 long poll
|
||||
|
||||
Vhosts that wish to allow clients to serve these immortal
|
||||
streams need to set the info.options flag `LWS_SERVER_OPTION_VH_H2_HALF_CLOSED_LONG_POLL`
|
||||
at vhost creation time. The JSON config equivalent is to set
|
||||
|
||||
```
|
||||
"h2-half-closed-long-poll": "1"
|
||||
```
|
||||
|
||||
on the vhost. That's all that is needed.
|
||||
|
||||
Streams continue to act normally for timeout with the exception
|
||||
client streams are allowed to signal they are half-closing by
|
||||
sending a zero-length DATA frame with END_STREAM set. These
|
||||
streams are allowed to exist outside of any timeout and data
|
||||
can be sent on them at will in the server -> client direction.
|
||||
|
||||
## Setting client streams for long poll
|
||||
|
||||
An API is provided to allow established h2 client streams to
|
||||
transition to immortal mode and send the END_STREAM to the server
|
||||
to indicate it.
|
||||
|
||||
```
|
||||
int
|
||||
lws_h2_client_stream_long_poll_rxonly(struct lws *wsi);
|
||||
```
|
||||
|
||||
## Example applications
|
||||
|
||||
You can confirm the long poll flow simply using example applications.
|
||||
Build and run `http-server/minimal-http-server-h2-long-poll` in one
|
||||
terminal.
|
||||
|
||||
In another, build the usual `http-client/minimal-http-client` example
|
||||
and run it with the flags `-l --long-poll`
|
||||
|
||||
The client will connect to the server and transition to the immortal mode.
|
||||
The server sends a timestamp every minute to the client, and that will
|
||||
stay up without timeouts.
|
||||
|
|
@ -212,6 +212,12 @@
|
|||
/**< (VH) Indicates the connections using this vhost should ignore
|
||||
* h2 WINDOW_UPDATE from broken peers and fix them up */
|
||||
|
||||
#define LWS_SERVER_OPTION_VH_H2_HALF_CLOSED_LONG_POLL (1ll << 32)
|
||||
/**< (VH) Tell the vhost to treat half-closed remote clients as
|
||||
* entered into an immortal (ie, not subject to normal timeouts) long
|
||||
* poll mode.
|
||||
*/
|
||||
|
||||
/****** add new things just above ---^ ******/
|
||||
|
||||
|
||||
|
@ -398,8 +404,9 @@ struct lws_context_creation_info {
|
|||
/**< VHOST: pointer to optional linked list of per-vhost
|
||||
* options made accessible to protocols */
|
||||
int keepalive_timeout;
|
||||
/**< VHOST: (default = 0 = 5s) seconds to allow remote
|
||||
* client to hold on to an idle HTTP/1.1 connection */
|
||||
/**< VHOST: (default = 0 = 5s, 31s for http/2) seconds to allow remote
|
||||
* client to hold on to an idle HTTP/1.1 connection. Timeout lifetime
|
||||
* applied to idle h2 network connections */
|
||||
const char *log_filepath;
|
||||
/**< VHOST: filepath to append logs to... this is opened before
|
||||
* any dropping of initial privileges */
|
||||
|
|
|
@ -745,6 +745,24 @@ lws_http_headers_detach(struct lws *wsi);
|
|||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_http_mark_sse(struct lws *wsi);
|
||||
|
||||
/**
|
||||
* lws_h2_client_stream_long_poll_rxonly() - h2 stream to immortal read-only
|
||||
*
|
||||
* \param wsi: h2 stream client wsi
|
||||
*
|
||||
* Send END_STREAM-flagged zero-length DATA frame to set client stream wsi into
|
||||
* half-closed (local) and remote into half-closed (remote). Set the client
|
||||
* stream wsi to be immortal (not subject to timeouts).
|
||||
*
|
||||
* Used if the remote server supports immortal long poll to put the stream into
|
||||
* a read-only state where it can wait as long as needed for rx.
|
||||
*
|
||||
* Returns 0 if the process (which happens asynchronously) started or non-zero
|
||||
* if it wasn't an h2 stream.
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_h2_client_stream_long_poll_rxonly(struct lws *wsi);
|
||||
|
||||
/**
|
||||
* lws_http_compression_apply() - apply an http compression transform
|
||||
*
|
||||
|
|
|
@ -254,6 +254,11 @@ __lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason,
|
|||
lws_addrinfo_clean(wsi);
|
||||
#endif
|
||||
|
||||
#if defined(LWS_WITH_HTTP2)
|
||||
if (wsi->h2_stream_immortal)
|
||||
lws_http_close_immortal(wsi);
|
||||
#endif
|
||||
|
||||
/* if we have children, close them first */
|
||||
if (wsi->child_list) {
|
||||
wsi2 = wsi->child_list;
|
||||
|
|
|
@ -676,8 +676,9 @@ struct lws {
|
|||
unsigned int hdr_parsing_completed:1;
|
||||
unsigned int http2_substream:1;
|
||||
unsigned int upgraded_to_http2:1;
|
||||
unsigned int h2_stream_carries_ws:1;
|
||||
unsigned int h2_stream_carries_sse:1;
|
||||
unsigned int h2_stream_immortal:1;
|
||||
unsigned int h2_stream_carries_ws:1; /* immortal set as well */
|
||||
unsigned int h2_stream_carries_sse:1; /* immortal set as well */
|
||||
unsigned int seen_nonpseudoheader:1;
|
||||
unsigned int listener:1;
|
||||
unsigned int user_space_externally_allocated:1;
|
||||
|
@ -1086,20 +1087,25 @@ lws_prepare_access_log_info(struct lws *wsi, char *uri_ptr, int len, int meth);
|
|||
#define lws_access_log(_a)
|
||||
#endif
|
||||
|
||||
LWS_EXTERN int
|
||||
void
|
||||
lws_http_mark_immortal(struct lws *wsi);
|
||||
void
|
||||
lws_http_close_immortal(struct lws *wsi);
|
||||
|
||||
int
|
||||
lws_cgi_kill_terminated(struct lws_context_per_thread *pt);
|
||||
|
||||
LWS_EXTERN void
|
||||
void
|
||||
lws_cgi_remove_and_kill(struct lws *wsi);
|
||||
|
||||
LWS_EXTERN void
|
||||
void
|
||||
lws_plat_delete_socket_from_fds(struct lws_context *context,
|
||||
struct lws *wsi, int m);
|
||||
LWS_EXTERN void
|
||||
void
|
||||
lws_plat_insert_socket_into_fds(struct lws_context *context,
|
||||
struct lws *wsi);
|
||||
|
||||
LWS_EXTERN int
|
||||
int
|
||||
lws_plat_change_pollfd(struct lws_context *context, struct lws *wsi,
|
||||
struct lws_pollfd *pfd);
|
||||
|
||||
|
|
|
@ -158,6 +158,8 @@ lws_set_timeout(struct lws *wsi, enum pending_timeout reason, int secs)
|
|||
if (secs == LWS_TO_KILL_ASYNC)
|
||||
secs = 0;
|
||||
|
||||
assert(!wsi->h2_stream_immortal);
|
||||
|
||||
lws_pt_lock(pt, __func__);
|
||||
__lws_set_timeout(wsi, reason, secs);
|
||||
lws_pt_unlock(pt);
|
||||
|
|
|
@ -830,20 +830,69 @@ lws_bind_protocol(struct lws *wsi, const struct lws_protocols *p,
|
|||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
lws_http_close_immortal(struct lws *wsi)
|
||||
{
|
||||
struct lws *nwsi;
|
||||
|
||||
if (!wsi->http2_substream)
|
||||
return;
|
||||
|
||||
assert(wsi->h2_stream_immortal);
|
||||
wsi->h2_stream_immortal = 0;
|
||||
|
||||
nwsi = lws_get_network_wsi(wsi);
|
||||
lwsl_debug("%s: %p %p %d\n", __func__, wsi, nwsi,
|
||||
nwsi->immortal_substream_count);
|
||||
assert(nwsi->immortal_substream_count);
|
||||
nwsi->immortal_substream_count--;
|
||||
if (!nwsi->immortal_substream_count)
|
||||
/*
|
||||
* since we closed the only immortal stream on this nwsi, we
|
||||
* need to reapply a normal timeout regime to the nwsi
|
||||
*/
|
||||
lws_set_timeout(nwsi, PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE,
|
||||
wsi->vhost->keepalive_timeout ?
|
||||
wsi->vhost->keepalive_timeout : 31);
|
||||
}
|
||||
|
||||
void
|
||||
lws_http_mark_immortal(struct lws *wsi)
|
||||
{
|
||||
struct lws *nwsi;
|
||||
|
||||
lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
|
||||
|
||||
if (!wsi->http2_substream
|
||||
#if defined(LWS_WITH_CLIENT)
|
||||
&& !wsi->client_h2_substream
|
||||
#endif
|
||||
) {
|
||||
lwsl_err("%s: not h2 substream\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
nwsi = lws_get_network_wsi(wsi);
|
||||
|
||||
lwsl_debug("%s: %p %p %d\n", __func__, wsi, nwsi,
|
||||
nwsi->immortal_substream_count);
|
||||
|
||||
wsi->h2_stream_immortal = 1;
|
||||
assert(nwsi->immortal_substream_count < 255); /* largest count */
|
||||
nwsi->immortal_substream_count++;
|
||||
if (nwsi->immortal_substream_count == 1)
|
||||
lws_set_timeout(nwsi, NO_PENDING_TIMEOUT, 0);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lws_http_mark_sse(struct lws *wsi)
|
||||
{
|
||||
lws_http_headers_detach(wsi);
|
||||
lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
|
||||
|
||||
if (wsi->http2_substream) {
|
||||
struct lws *nwsi = lws_get_network_wsi(wsi);
|
||||
lws_http_mark_immortal(wsi);
|
||||
|
||||
if (wsi->http2_substream)
|
||||
wsi->h2_stream_carries_sse = 1;
|
||||
nwsi->immortal_substream_count++;
|
||||
if (nwsi->immortal_substream_count == 1)
|
||||
lws_set_timeout(nwsi, NO_PENDING_TIMEOUT, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -845,11 +845,9 @@ lws_h2_parse_frame_header(struct lws *wsi)
|
|||
/* let the network wsi live a bit longer if subs are active */
|
||||
|
||||
if (!wsi->immortal_substream_count)
|
||||
#if defined(LWS_AMAZON_RTOS) || defined(LWS_AMAZON_LINUX)
|
||||
lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE, wsi->vhost->keepalive_timeout);
|
||||
#else
|
||||
lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE, 31);
|
||||
#endif
|
||||
lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE,
|
||||
wsi->vhost->keepalive_timeout ?
|
||||
wsi->vhost->keepalive_timeout : 31);
|
||||
|
||||
if (h2n->sid)
|
||||
h2n->swsi = lws_h2_wsi_from_id(wsi, h2n->sid);
|
||||
|
@ -1164,12 +1162,24 @@ lws_h2_parse_frame_header(struct lws *wsi)
|
|||
assert(w->h2.sibling_list != w);
|
||||
} lws_end_foreach_ll(w, h2.sibling_list);
|
||||
|
||||
if (lws_check_opt(h2n->swsi->vhost->options,
|
||||
LWS_SERVER_OPTION_VH_H2_HALF_CLOSED_LONG_POLL)) {
|
||||
|
||||
/* END_STREAM means after servicing this, close the stream */
|
||||
h2n->swsi->h2.END_STREAM =
|
||||
/*
|
||||
* We don't directly timeout streams that enter the
|
||||
* half-closed remote state, allowing immortal long
|
||||
* poll
|
||||
*/
|
||||
lws_http_mark_immortal(h2n->swsi);
|
||||
lwsl_info("%s: %p: h2 stream entering long poll\n",
|
||||
__func__, h2n->swsi);
|
||||
|
||||
} else {
|
||||
h2n->swsi->h2.END_STREAM =
|
||||
!!(h2n->flags & LWS_H2_FLAG_END_STREAM);
|
||||
lwsl_info("%s: hdr END_STREAM = %d\n",__func__,
|
||||
lwsl_debug("%s: hdr END_STREAM = %d\n",__func__,
|
||||
h2n->swsi->h2.END_STREAM);
|
||||
}
|
||||
|
||||
h2n->cont_exp = !(h2n->flags & LWS_H2_FLAG_END_HEADERS);
|
||||
h2n->cont_exp_sid = h2n->sid;
|
||||
|
@ -1863,12 +1873,9 @@ lws_h2_parser(struct lws *wsi, unsigned char *in, lws_filepos_t inlen,
|
|||
*/
|
||||
if (!wsi->immortal_substream_count)
|
||||
lws_set_timeout(wsi,
|
||||
PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE,
|
||||
#if defined(LWS_AMAZON_RTOS) || defined(LWS_AMAZON_LINUX)
|
||||
wsi->vhost->keepalive_timeout);
|
||||
#else
|
||||
31);
|
||||
#endif
|
||||
PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE,
|
||||
wsi->vhost->keepalive_timeout ?
|
||||
wsi->vhost->keepalive_timeout : 31);
|
||||
|
||||
if (!h2n->swsi)
|
||||
break;
|
||||
|
@ -2411,3 +2418,21 @@ lws_read_h2(struct lws *wsi, unsigned char *buf, lws_filepos_t len)
|
|||
return lws_ptr_diff(buf, oldbuf);
|
||||
}
|
||||
|
||||
int
|
||||
lws_h2_client_stream_long_poll_rxonly(struct lws *wsi)
|
||||
{
|
||||
|
||||
if (!wsi->http2_substream)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* Elect to send an empty DATA with END_STREAM, to force the stream
|
||||
* into HALF_CLOSED LOCAL
|
||||
*/
|
||||
wsi->h2.long_poll = 1;
|
||||
wsi->h2.send_END_STREAM = 1;
|
||||
|
||||
lws_callback_on_writable(wsi);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -386,20 +386,22 @@ rops_write_role_protocol_h2(struct lws *wsi, unsigned char *buf, size_t len,
|
|||
|
||||
/* if not in a state to send stuff, then just send nothing */
|
||||
|
||||
if (!lwsi_role_ws(wsi) &&
|
||||
if (!lwsi_role_ws(wsi) && !wsi->h2_stream_immortal &&
|
||||
base != LWS_WRITE_HTTP &&
|
||||
base != LWS_WRITE_HTTP_FINAL &&
|
||||
base != LWS_WRITE_HTTP_HEADERS_CONTINUATION &&
|
||||
base != LWS_WRITE_HTTP_HEADERS &&
|
||||
((lwsi_state(wsi) != LRS_RETURNED_CLOSE &&
|
||||
lwsi_state(wsi) != LRS_WAITING_TO_SEND_CLOSE &&
|
||||
lwsi_state(wsi) != LRS_ESTABLISHED &&
|
||||
lwsi_state(wsi) != LRS_AWAITING_CLOSE_ACK)
|
||||
#if defined(LWS_ROLE_WS)
|
||||
|| base != LWS_WRITE_CLOSE
|
||||
#endif
|
||||
)) {
|
||||
//assert(0);
|
||||
lwsl_notice("binning wsistate 0x%x %d\n", wsi->wsistate, *wp);
|
||||
lwsl_notice("%s: binning wsistate 0x%x %d\n", __func__,
|
||||
wsi->wsistate, *wp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -486,7 +488,6 @@ static int
|
|||
rops_check_upgrades_h2(struct lws *wsi)
|
||||
{
|
||||
#if defined(LWS_ROLE_WS)
|
||||
struct lws *nwsi;
|
||||
char *p;
|
||||
|
||||
/*
|
||||
|
@ -504,21 +505,16 @@ rops_check_upgrades_h2(struct lws *wsi)
|
|||
if (!p || strcmp(p, "websocket"))
|
||||
return LWS_UPG_RET_CONTINUE;
|
||||
|
||||
nwsi = lws_get_network_wsi(wsi);
|
||||
|
||||
#if defined(LWS_WITH_SERVER_STATUS)
|
||||
wsi->vhost->conn_stats.ws_upg++;
|
||||
#endif
|
||||
lwsl_info("Upgrade h2 to ws\n");
|
||||
lws_http_mark_immortal(wsi);
|
||||
wsi->h2_stream_carries_ws = 1;
|
||||
nwsi->immortal_substream_count++;
|
||||
|
||||
if (lws_process_ws_upgrade(wsi))
|
||||
return LWS_UPG_RET_BAIL;
|
||||
|
||||
if (nwsi->immortal_substream_count == 1)
|
||||
lws_set_timeout(nwsi, NO_PENDING_TIMEOUT, 0);
|
||||
|
||||
lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
|
||||
lwsl_info("Upgraded h2 to ws OK\n");
|
||||
|
||||
return LWS_UPG_RET_DONE;
|
||||
|
@ -717,16 +713,6 @@ rops_close_kill_connection_h2(struct lws *wsi, enum lws_close_status reason)
|
|||
lws_free_set_NULL(wsi->h2.pending_status_body);
|
||||
}
|
||||
|
||||
if (wsi->h2_stream_carries_ws || wsi->h2_stream_carries_sse) {
|
||||
struct lws *nwsi = lws_get_network_wsi(wsi);
|
||||
|
||||
nwsi->immortal_substream_count--;
|
||||
/* if no ws, then put a timeout on the parent wsi */
|
||||
if (!nwsi->immortal_substream_count)
|
||||
__lws_set_timeout(nwsi,
|
||||
PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE, 31);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1148,6 +1134,30 @@ rops_perform_user_POLLOUT_h2(struct lws *wsi)
|
|||
goto next_child;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* set client wsi to immortal long-poll mode; send END_STREAM
|
||||
* flag on headers to indicate to a server, that allows
|
||||
* it, that you want them to leave the stream in a long poll
|
||||
* ro immortal state. We have to send headers so the client
|
||||
* understands the http connection is ongoing.
|
||||
*/
|
||||
|
||||
if (w->h2.send_END_STREAM && w->h2.long_poll) {
|
||||
uint8_t buf[LWS_PRE + 1];
|
||||
enum lws_write_protocol wp = 0;
|
||||
|
||||
if (!rops_write_role_protocol_h2(w, buf + LWS_PRE, 0,
|
||||
&wp)) {
|
||||
lwsl_info("%s: wsi %p: entering ro long poll\n",
|
||||
__func__, w);
|
||||
lws_http_mark_immortal(w);
|
||||
} else
|
||||
lwsl_err("%s: wsi %p: failed to set long poll\n",
|
||||
__func__, w);
|
||||
goto next_child;
|
||||
}
|
||||
|
||||
if (lws_callback_as_writeable(w)) {
|
||||
lwsl_info("Closing POLLOUT child (end stream %d)\n",
|
||||
w->h2.send_END_STREAM);
|
||||
|
|
|
@ -328,12 +328,13 @@ struct _lws_h2_related {
|
|||
int my_priority;
|
||||
uint32_t dependent_on;
|
||||
|
||||
unsigned int END_STREAM:1;
|
||||
unsigned int END_HEADERS:1;
|
||||
unsigned int send_END_STREAM:1;
|
||||
unsigned int GOING_AWAY;
|
||||
unsigned int requested_POLLOUT:1;
|
||||
unsigned int skint:1;
|
||||
uint16_t END_STREAM:1;
|
||||
uint16_t END_HEADERS:1;
|
||||
uint16_t send_END_STREAM:1;
|
||||
uint16_t long_poll:1;
|
||||
uint16_t GOING_AWAY;
|
||||
uint16_t requested_POLLOUT:1;
|
||||
uint16_t skint:1;
|
||||
|
||||
uint16_t round_robin_POLLOUT;
|
||||
uint16_t count_POLLOUT_children;
|
||||
|
|
|
@ -132,6 +132,7 @@ static const char * const paths_vhosts[] = {
|
|||
"vhosts[].allow-http-on-https",
|
||||
|
||||
"vhosts[].disable-no-protocol-ws-upgrades",
|
||||
"vhosts[].h2-half-closed-long-poll",
|
||||
};
|
||||
|
||||
enum lejp_vhost_paths {
|
||||
|
@ -199,6 +200,7 @@ enum lejp_vhost_paths {
|
|||
LEJPVP_FLAG_ALLOW_HTTP_ON_HTTPS,
|
||||
|
||||
LEJPVP_FLAG_DISABLE_NO_PROTOCOL_WS_UPGRADES,
|
||||
LEJPVP_FLAG_H2_HALF_CLOSED_LONG_POLL,
|
||||
};
|
||||
|
||||
#define MAX_PLUGIN_DIRS 10
|
||||
|
@ -864,6 +866,11 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
|
|||
a->reject_ws_with_no_protocol = 1;
|
||||
return 0;
|
||||
|
||||
case LEJPVP_FLAG_H2_HALF_CLOSED_LONG_POLL:
|
||||
set_reset_flag(&a->info->options, ctx->buf,
|
||||
LWS_SERVER_OPTION_VH_H2_HALF_CLOSED_LONG_POLL);
|
||||
return 0;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1340,8 +1340,9 @@ lws_http_action(struct lws *wsi)
|
|||
* if there is content supposed to be coming,
|
||||
* put a timeout on it having arrived
|
||||
*/
|
||||
lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_CONTENT,
|
||||
wsi->context->timeout_secs);
|
||||
if (!wsi->h2_stream_immortal)
|
||||
lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_CONTENT,
|
||||
wsi->context->timeout_secs);
|
||||
#ifdef LWS_WITH_TLS
|
||||
if (wsi->tls.redirect_to_https) {
|
||||
/*
|
||||
|
|
|
@ -17,6 +17,9 @@
|
|||
#include <signal.h>
|
||||
|
||||
static int interrupted, bad = 1, status;
|
||||
#if defined(LWS_WITH_HTTP2)
|
||||
static int long_poll;
|
||||
#endif
|
||||
static struct lws *client_wsi;
|
||||
|
||||
static int
|
||||
|
@ -35,11 +38,22 @@ callback_http(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
|
||||
status = lws_http_client_http_response(wsi);
|
||||
lwsl_user("Connected with server response: %d\n", status);
|
||||
#if defined(LWS_WITH_HTTP2)
|
||||
if (long_poll) {
|
||||
lwsl_user("%s: Client entering long poll mode\n", __func__);
|
||||
lws_h2_client_stream_long_poll_rxonly(wsi);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
/* chunks of chunked content, with header removed */
|
||||
case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ:
|
||||
lwsl_user("RECEIVE_CLIENT_HTTP_READ: read %d\n", (int)len);
|
||||
#if defined(LWS_WITH_HTTP2)
|
||||
if (long_poll)
|
||||
lwsl_notice("long poll rx: '%.*s'\n",
|
||||
(int)len, (const char *)in);
|
||||
#endif
|
||||
#if 0 /* enable to dump the html */
|
||||
{
|
||||
const char *p = in;
|
||||
|
@ -155,8 +169,16 @@ int main(int argc, const char **argv)
|
|||
|
||||
memset(&i, 0, sizeof i); /* otherwise uninitialized garbage */
|
||||
i.context = context;
|
||||
if (!lws_cmdline_option(argc, argv, "-n"))
|
||||
if (!lws_cmdline_option(argc, argv, "-n")) {
|
||||
i.ssl_connection = LCCSCF_USE_SSL;
|
||||
#if defined(LWS_WITH_HTTP2)
|
||||
/* requires h2 */
|
||||
if (lws_cmdline_option(argc, argv, "--long-poll")) {
|
||||
lwsl_user("%s: long poll mode\n", __func__);
|
||||
long_poll = 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (lws_cmdline_option(argc, argv, "-l")) {
|
||||
i.port = 7681;
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
cmake_minimum_required(VERSION 2.8)
|
||||
include(CheckCSourceCompiles)
|
||||
|
||||
set(SAMP lws-minimal-http-server-h2-long-poll)
|
||||
set(SRCS minimal-http-server.c)
|
||||
|
||||
# If we are being built as part of lws, confirm current build config supports
|
||||
# reqconfig, else skip building ourselves.
|
||||
#
|
||||
# If we are being built externally, confirm installed lws was configured to
|
||||
# support reqconfig, else error out with a helpful message about the problem.
|
||||
#
|
||||
MACRO(require_lws_config reqconfig _val result)
|
||||
|
||||
if (DEFINED ${reqconfig})
|
||||
if (${reqconfig})
|
||||
set (rq 1)
|
||||
else()
|
||||
set (rq 0)
|
||||
endif()
|
||||
else()
|
||||
set(rq 0)
|
||||
endif()
|
||||
|
||||
if (${_val} EQUAL ${rq})
|
||||
set(SAME 1)
|
||||
else()
|
||||
set(SAME 0)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
|
||||
if (${_val})
|
||||
message("${SAMP}: skipping as lws being built without ${reqconfig}")
|
||||
else()
|
||||
message("${SAMP}: skipping as lws built with ${reqconfig}")
|
||||
endif()
|
||||
set(${result} 0)
|
||||
else()
|
||||
if (LWS_WITH_MINIMAL_EXAMPLES)
|
||||
set(MET ${SAME})
|
||||
else()
|
||||
CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
|
||||
if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
|
||||
set(HAS_${reqconfig} 0)
|
||||
else()
|
||||
set(HAS_${reqconfig} 1)
|
||||
endif()
|
||||
if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
|
||||
set(MET 1)
|
||||
else()
|
||||
set(MET 0)
|
||||
endif()
|
||||
endif()
|
||||
if (NOT MET)
|
||||
if (${_val})
|
||||
message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
|
||||
else()
|
||||
message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
endif()
|
||||
ENDMACRO()
|
||||
|
||||
|
||||
set(requirements 1)
|
||||
require_lws_config(LWS_ROLE_H1 1 requirements)
|
||||
require_lws_config(LWS_WITH_SERVER 1 requirements)
|
||||
require_lws_config(LWS_WITH_HTTP2 1 requirements)
|
||||
|
||||
if (requirements)
|
||||
add_executable(${SAMP} ${SRCS})
|
||||
|
||||
if (websockets_shared)
|
||||
target_link_libraries(${SAMP} websockets_shared)
|
||||
add_dependencies(${SAMP} websockets_shared)
|
||||
else()
|
||||
target_link_libraries(${SAMP} websockets)
|
||||
endif()
|
||||
endif()
|
|
@ -0,0 +1,18 @@
|
|||
# lws minimal http server
|
||||
|
||||
## build
|
||||
|
||||
```
|
||||
$ cmake . && make
|
||||
```
|
||||
|
||||
## usage
|
||||
|
||||
```
|
||||
$ ./lws-minimal-http-server
|
||||
[2018/03/04 09:30:02:7986] USER: LWS minimal http server | visit http://localhost:7681
|
||||
[2018/03/04 09:30:02:7986] NOTICE: Creating Vhost 'default' port 7681, 1 protocols, IPv6 on
|
||||
```
|
||||
|
||||
Visit http://localhost:7681
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
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
|
||||
e2Hl/7M0c/lbZ4FvXgARlex2rkgS0Ka06HE=
|
||||
-----END CERTIFICATE-----
|
|
@ -0,0 +1,52 @@
|
|||
-----BEGIN PRIVATE KEY-----
|
||||
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
|
||||
fBrpEY1IATtPq1taBZZogRqI3rOkkPk=
|
||||
-----END PRIVATE KEY-----
|
|
@ -0,0 +1,147 @@
|
|||
/*
|
||||
* lws-minimal-http-server-h2-long-poll
|
||||
*
|
||||
* Written in 2010-2019 by Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This file is made available under the Creative Commons CC0 1.0
|
||||
* Universal Public Domain Dedication.
|
||||
*
|
||||
* This demonstrates an h2 server that supports "long poll"
|
||||
* immortal client connections. For simplicity it doesn't serve
|
||||
* any regular files, you can add a mount to do it if you want.
|
||||
*
|
||||
* The protocol keeps the long poll h2 stream open, and sends
|
||||
* the time on the stream once per minute. Normally idle h2
|
||||
* connections are closed by default within 30s, so this demonstrates
|
||||
* the stream and network connection are operating as "immortal"
|
||||
* on both sides.
|
||||
*
|
||||
* See http-client/minimal-http-client-h2-long-poll for the
|
||||
* client example that connects and transitions the stream to the
|
||||
* immortal long poll mode.
|
||||
*/
|
||||
|
||||
#include <libwebsockets.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
|
||||
static int interrupted;
|
||||
|
||||
struct pss {
|
||||
struct lws *wsi;
|
||||
lws_sorted_usec_list_t sul;
|
||||
char pending;
|
||||
};
|
||||
|
||||
static void
|
||||
sul_cb(lws_sorted_usec_list_t *sul)
|
||||
{
|
||||
struct pss *pss = (struct pss *)lws_container_of(sul, struct pss, sul);
|
||||
|
||||
pss->pending = 1;
|
||||
lws_callback_on_writable(pss->wsi);
|
||||
/* interval 1min... longer than any normal timeout */
|
||||
lws_sul_schedule(lws_get_context(pss->wsi), 0, &pss->sul, sul_cb,
|
||||
60 * LWS_US_PER_SEC);
|
||||
}
|
||||
|
||||
static int
|
||||
callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
|
||||
void *in, size_t len)
|
||||
{
|
||||
struct pss * pss = (struct pss *)user;
|
||||
uint8_t buf[LWS_PRE + LWS_RECOMMENDED_MIN_HEADER_SPACE],
|
||||
*start = &buf[LWS_PRE], *p = start,
|
||||
*end = p + sizeof(buf) - LWS_PRE;
|
||||
int m, n;
|
||||
|
||||
switch (reason) {
|
||||
case LWS_CALLBACK_HTTP:
|
||||
lwsl_user("%s: connect\n", __func__);
|
||||
pss->wsi = wsi;
|
||||
|
||||
if (lws_add_http_common_headers(wsi, HTTP_STATUS_OK,
|
||||
"text/html",
|
||||
LWS_ILLEGAL_HTTP_CONTENT_LEN, /* no content len */
|
||||
&p, end))
|
||||
return 1;
|
||||
if (lws_finalize_write_http_header(wsi, start, &p, end))
|
||||
return 1;
|
||||
|
||||
sul_cb(&pss->sul);
|
||||
return 0;
|
||||
|
||||
case LWS_CALLBACK_CLOSED_HTTP:
|
||||
if (!pss)
|
||||
break;
|
||||
lws_sul_schedule(lws_get_context(wsi), 0, &pss->sul, sul_cb,
|
||||
LWS_SET_TIMER_USEC_CANCEL);
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_HTTP_WRITEABLE:
|
||||
if (!pss->pending)
|
||||
break;
|
||||
n = lws_snprintf((char *)p, sizeof(buf) - LWS_PRE, "%llu",
|
||||
(unsigned long long)lws_now_usecs());
|
||||
m = lws_write(wsi, p, n, LWS_WRITE_HTTP);
|
||||
if (m < n) {
|
||||
lwsl_err("ERROR %d writing to socket\n", n);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return lws_callback_http_dummy(wsi, reason, user, in, len);
|
||||
}
|
||||
|
||||
static struct lws_protocols protocols[] = {
|
||||
{ "http", callback_http, sizeof(struct pss), 0 },
|
||||
{ NULL, NULL, 0, 0 } /* terminator */
|
||||
};
|
||||
|
||||
|
||||
void sigint_handler(int sig)
|
||||
{
|
||||
interrupted = 1;
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
struct lws_context_creation_info info;
|
||||
struct lws_context *context;
|
||||
const char *p;
|
||||
int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
|
||||
|
||||
signal(SIGINT, sigint_handler);
|
||||
|
||||
if ((p = lws_cmdline_option(argc, argv, "-d")))
|
||||
logs = atoi(p);
|
||||
|
||||
lws_set_log_level(logs, NULL);
|
||||
lwsl_user("LWS minimal http server h2 long poll\n");
|
||||
|
||||
memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
|
||||
info.port = 7681;
|
||||
info.ssl_cert_filepath = "localhost-100y.cert";
|
||||
info.ssl_private_key_filepath = "localhost-100y.key";
|
||||
info.protocols = protocols;
|
||||
info.options =
|
||||
LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT |
|
||||
LWS_SERVER_OPTION_VH_H2_HALF_CLOSED_LONG_POLL |
|
||||
LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE;
|
||||
|
||||
context = lws_create_context(&info);
|
||||
if (!context) {
|
||||
lwsl_err("lws init failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
while (n >= 0 && !interrupted)
|
||||
n = lws_service(context, 0);
|
||||
|
||||
lws_context_destroy(context);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Reference in a new issue