Newer
Older
-DLWS_WITH_LIBEVENT=1
at cmake configure-time. The user application may use one of the
context init options flags
LWS_SERVER_OPTION_LIBEV
LWS_SERVER_OPTION_LIBUV
LWS_SERVER_OPTION_LIBEVENT
to indicate it will use one of the event libraries at runtime.
libev has some problems, its headers conflict with libevent, they both define
critical constants like EV_READ to different values. Attempts
to discuss clearing that up with libevent and libev did not get anywhere useful.
In addition building anything with libev using gcc spews warnings, the
maintainer is aware of this for many years, and blames gcc. We worked
around this by disabling -Werror on the parts of lws that use libev.
For these reasons and the response I got trying to raise these issues with
them, if you have a choice about event loop, I would gently encourage you
to avoid libev. Where lws uses an event loop itself, eg in lwsws, we use
libuv.
@section extopts Extension option control from user code
User code may set per-connection extension options now, using a new api
This should be called from the ESTABLISHED callback like this
```
lws_set_extension_option(wsi, "permessage-deflate",
"rx_buf_size", "12"); /* 1 << 12 */
```
If the extension is not active (missing or not negotiated for the
connection, or extensions are disabled on the library) the call is
just returns -1. Otherwise the connection's extension has its
named option changed.
The extension may decide to alter or disallow the change, in the
example above permessage-deflate restricts the size of his rx
output buffer also considering the protocol's rx_buf_size member.
@section httpsclient Client connections as HTTP[S] rather than WS[S]
You may open a generic http client connection using the same
struct lws_client_connect_info used to create client ws[s]
connections.
To stay in http[s], set the optional info member "method" to
point to the string "GET" instead of the default NULL.
After the server headers are processed, when payload from the
server is available the callback LWS_CALLBACK_RECEIVE_CLIENT_HTTP
will be made.
You can choose whether to process the data immediately, or
queue a callback when an outgoing socket is writeable to provide
flow control, and process the data in the writable callback.
Either way you use the api `lws_http_client_read()` to access the
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
case LWS_CALLBACK_RECEIVE_CLIENT_HTTP:
{
char buffer[1024 + LWS_PRE];
char *px = buffer + LWS_PRE;
int lenx = sizeof(buffer) - LWS_PRE;
lwsl_notice("LWS_CALLBACK_RECEIVE_CLIENT_HTTP\n");
/*
* Often you need to flow control this by something
* else being writable. In that case call the api
* to get a callback when writable here, and do the
* pending client read in the writeable callback of
* the output.
*/
if (lws_http_client_read(wsi, &px, &lenx) < 0)
return -1;
while (lenx--)
putchar(*px++);
}
break;
Notice that if you will use SSL client connections on a vhost, you must
prepare the client SSL context for the vhost after creating the vhost, since
this is not normally done if the vhost was set up to listen / serve. Call
the api lws_init_vhost_client_ssl() to also allow client SSL on the vhost.
@section clipipe Pipelining Client Requests to same host
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
If you are opening more client requests to the same host and port, you
can give the flag LCCSCF_PIPELINE on `info.ssl_connection` to indicate
you wish to pipeline them.
Without the flag, the client connections will occur concurrently using a
socket and tls wrapper if requested for each connection individually.
That is fast, but resource-intensive.
With the flag, lws will queue subsequent client connections on the first
connection to the same host and port. When it has confirmed from the
first connection that pipelining / keep-alive is supported by the server,
it lets the queued client pipeline connections send their headers ahead
of time to create a pipeline of requests on the server side.
In this way only one tcp connection and tls wrapper is required to transfer
all the transactions sequentially. It takes a little longer but it
can make a significant difference to resources on both sides.
If lws learns from the first response header that keepalive is not possible,
then it marks itself with that information and detaches any queued clients
to make their own individual connections as a fallback.
Lws can also intelligently combine multiple ongoing client connections to
the same host and port into a single http/2 connection with multiple
streams if the server supports it.
Unlike http/1 pipelining, with http/2 the client connections all occur
simultaneously using h2 stream multiplexing inside the one tcp + tls
connection.
You can turn off the h2 client support either by not building lws with
`-DLWS_WITH_HTTP2=1` or giving the `LCCSCF_NOT_H2` flag in the client
connection info struct `ssl_connection` member.
If you set LWS_SERVER_OPTION_EXPLICIT_VHOSTS options flag when you create
your context, it won't create a default vhost using the info struct
members for compatibility. Instead you can call lws_create_vhost()
afterwards to attach one or more vhosts manually.
```
LWS_VISIBLE struct lws_vhost *
lws_create_vhost(struct lws_context *context,
struct lws_context_creation_info *info);
```
lws_create_vhost() uses the same info struct as lws_create_context(),
it ignores members related to context and uses the ones meaningful
for vhost (marked with VH in libwebsockets.h).
```
struct lws_context_creation_info {
int port; /* VH */
const char *iface; /* VH */
const struct lws_protocols *protocols; /* VH */
const struct lws_extension *extensions; /* VH */
...
```
When you attach the vhost, if the vhost's port already has a listen socket
then both vhosts share it and use SNI (is SSL in use) or the Host: header
from the client to select the right one. Or if no other vhost already
listening the a new listen socket is created.
There are some new members but mainly it's stuff you used to set at
context creation time.
@section sni How lws matches hostname or SNI to a vhost
LWS first strips any trailing :port number.
Then it tries to find an exact name match for a vhost listening on the correct
port, ie, if SNI or the Host: header provided abc.com:1234, it will match on a
vhost named abc.com that is listening on port 1234.
If there is no exact match, lws will consider wildcard matches, for example
if cats.abc.com:1234 is provided by the client by SNI or Host: header, it will
accept a vhost "abc.com" listening on port 1234. If there was a better, exact,
match, it will have been chosen in preference to this.
Connections with SSL will still have the client go on to check the
certificate allows wildcards and error out if not.
The last argument to lws_create_vhost() lets you associate a linked
list of lws_http_mount structures with that vhost's URL 'namespace', in
a similar way that unix lets you mount filesystems into areas of your /
filesystem how you like and deal with the contents transparently.
```
struct lws_http_mount {
struct lws_http_mount *mount_next;
const char *mountpoint; /* mountpoint in http pathspace, eg, "/" */
const char *origin; /* path to be mounted, eg, "/var/www/warmcat.com" */
const char *def; /* default target, eg, "index.html" */
struct lws_protocol_vhost_options *cgienv;
int cgi_timeout;
int cache_max_age;
unsigned int cache_reusable:1;
unsigned int cache_revalidate:1;
unsigned int cache_intermediaries:1;
unsigned char origin_protocol;
unsigned char mountpoint_len;
};
```
The last mount structure should have a NULL mount_next, otherwise it should
point to the 'next' mount structure in your list.
Both the mount structures and the strings must persist until the context is
destroyed, since they are not copied but used in place.
`.origin_protocol` should be one of
```
enum {
LWSMPRO_HTTP,
LWSMPRO_HTTPS,
LWSMPRO_FILE,
LWSMPRO_CGI,
LWSMPRO_REDIR_HTTP,
LWSMPRO_REDIR_HTTPS,
LWSMPRO_CALLBACK,
};
- LWSMPRO_FILE is used for mapping url namespace to a filesystem directory and
- LWSMPRO_CGI associates the url namespace with the given CGI executable, which
runs when the URL is accessed and the output provided to the client.
- LWSMPRO_REDIR_HTTP and LWSMPRO_REDIR_HTTPS auto-redirect clients to the given
- LWSMPRO_CALLBACK causes the http connection to attach to the callback
associated with the named protocol (which may be a plugin).
@section mountcallback Operation of LWSMPRO_CALLBACK mounts
The feature provided by CALLBACK type mounts is binding a part of the URL
namespace to a named protocol callback handler.
This allows protocol plugins to handle areas of the URL namespace. For example
in test-server-v2.0.c, the URL area "/formtest" is associated with the plugin
providing "protocol-post-demo" like this
```
static const struct lws_http_mount mount_post = {
NULL, /* linked-list pointer to next*/
"/formtest", /* mountpoint in URL namespace on this vhost */
"protocol-post-demo", /* handler */
NULL, /* default filename if none given */
NULL,
0,
0,
0,
0,
0,
LWSMPRO_CALLBACK, /* origin points to a callback */
9, /* strlen("/formtest"), ie length of the mountpoint */
};
```
Client access to /formtest[anything] will be passed to the callback registered
with the named protocol, which in this case is provided by a protocol plugin.
Access by all methods, eg, GET and POST are handled by the callback.
protocol-post-demo deals with accepting and responding to the html form that
is in the test server HTML.
When a connection accesses a URL related to a CALLBACK type mount, the
connection protocol is changed until the next access on the connection to a
URL outside the same CALLBACK mount area. User space on the connection is
arranged to be the size of the new protocol user space allocation as given in
the protocol struct.
This allocation is only deleted / replaced when the connection accesses a
URL region with a different protocol (or the default protocols[0] if no
CALLBACK area matches it).
This "binding connection to a protocol" lifecycle in managed by
`LWS_CALLBACK_HTTP_BIND_PROTOCOL` and `LWS_CALLBACK_HTTP_DROP_PROTOCOL`.
Because of HTTP/1.1 connection pipelining, one connection may perform
many transactions, each of which may map to different URLs and need
binding to different protocols. So these messages are used to
create the binding of the wsi to your protocol including any
allocations, and to destroy the binding, at which point you should
destroy any related allocations.
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
@section BINDTODEV SO_BIND_TO_DEVICE
The .bind_iface flag in the context / vhost creation struct lets you
declare that you want all traffic for listen and transport on that
vhost to be strictly bound to the network interface named in .iface.
This Linux-only feature requires SO_BIND_TO_DEVICE, which in turn
requires CAP_NET_RAW capability... root has this capability.
However this feature needs to apply the binding also to accepted
sockets during normal operation, which implies the server must run
the whole time as root.
You can avoid this by using the Linux capabilities feature to have
the unprivileged user inherit just the CAP_NET_RAW capability.
You can confirm this with the test server
```
$ sudo /usr/local/bin/libwebsockets-test-server -u agreen -i eno1 -k
```
The part that ensures the capability is inherited by the unprivileged
user is
```
#if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP)
info.caps[0] = CAP_NET_RAW;
info.count_caps = 1;
#endif
```
@section dim Dimming webpage when connection lost
The lws test plugins' html provides useful feedback on the webpage about if it
is still connected to the server, by greying out the page if not. You can
also add this to your own html easily
- include lws-common.js from your HEAD section
- dim the page during initialization, in a script section on your page
lws_gray_out(true,{'zindex':'499'});
- in your ws onOpen(), remove the dimming
lws_gray_out(false);
- in your ws onClose(), reapply the dimming
lws_gray_out(true,{'zindex':'499'});
@section errstyle Styling http error pages
In the code, http errors should be handled by `lws_return_http_status()`.
There are basically two ways... the vhost can be told to redirect to an "error
page" URL in response to specifically a 404... this is controlled by the
context / vhost info struct (`struct lws_context_creation_info`) member
`.error_document_404`... if non-null the client is redirected to this string.
If it wasn't redirected, then the response code html is synthesized containing
the user-selected text message and attempts to pull in `/error.css` for styling.
If this file exists, it can be used to style the error page. See
https://libwebsockets.org/git/badrepo for an example of what can be done (
and https://libwebsockets.org/error.css for the corresponding css).