2018-04-11 13:39:42 +08:00
|
|
|
/*
|
|
|
|
* libwebsockets - small server side websockets and web server implementation
|
|
|
|
*
|
2019-08-14 10:44:14 +01:00
|
|
|
* Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
|
2018-04-11 13:39:42 +08:00
|
|
|
*
|
2019-08-14 10:44:14 +01:00
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
* of this software and associated documentation files (the "Software"), to
|
|
|
|
* deal in the Software without restriction, including without limitation the
|
|
|
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
|
|
* sell copies of the Software, and to permit persons to whom the Software is
|
|
|
|
* furnished to do so, subject to the following conditions:
|
2018-04-11 13:39:42 +08:00
|
|
|
*
|
2019-08-14 10:44:14 +01:00
|
|
|
* The above copyright notice and this permission notice shall be included in
|
|
|
|
* all copies or substantial portions of the Software.
|
2018-04-11 13:39:42 +08:00
|
|
|
*
|
2019-08-14 10:44:14 +01:00
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
|
|
* IN THE SOFTWARE.
|
2018-04-11 13:39:42 +08:00
|
|
|
*/
|
|
|
|
|
2019-08-15 10:49:52 +01:00
|
|
|
#include <private-lib-core.h>
|
2018-04-11 13:39:42 +08:00
|
|
|
|
|
|
|
#ifndef min
|
|
|
|
#define min(a, b) ((a) < (b) ? (a) : (b))
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We have to take care about parsing because the headers may be split
|
|
|
|
* into multiple fragments. They may contain unknown headers with arbitrary
|
|
|
|
* argument lengths. So, we parse using a single-character at a time state
|
|
|
|
* machine that is completely independent of packet size.
|
|
|
|
*
|
|
|
|
* Returns <0 for error or length of chars consumed from buf (up to len)
|
|
|
|
*/
|
|
|
|
|
|
|
|
int
|
|
|
|
lws_read_h1(struct lws *wsi, unsigned char *buf, lws_filepos_t len)
|
|
|
|
{
|
|
|
|
unsigned char *last_char, *oldbuf = buf;
|
|
|
|
lws_filepos_t body_chunk_len;
|
|
|
|
size_t n;
|
|
|
|
|
2018-09-02 14:35:37 +08:00
|
|
|
lwsl_debug("%s: h1 path: wsi state 0x%x\n", __func__, lwsi_state(wsi));
|
2018-04-11 13:39:42 +08:00
|
|
|
|
|
|
|
switch (lwsi_state(wsi)) {
|
|
|
|
|
|
|
|
case LRS_ISSUING_FILE:
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case LRS_ESTABLISHED:
|
|
|
|
|
|
|
|
if (lwsi_role_ws(wsi))
|
|
|
|
goto ws_mode;
|
|
|
|
|
|
|
|
if (lwsi_role_client(wsi))
|
|
|
|
break;
|
|
|
|
|
|
|
|
wsi->hdr_parsing_completed = 0;
|
|
|
|
|
|
|
|
/* fallthru */
|
|
|
|
|
|
|
|
case LRS_HEADERS:
|
2018-04-27 15:20:56 +08:00
|
|
|
if (!wsi->http.ah) {
|
2018-04-11 13:39:42 +08:00
|
|
|
lwsl_err("%s: LRS_HEADERS: NULL ah\n", __func__);
|
|
|
|
assert(0);
|
|
|
|
}
|
|
|
|
lwsl_parser("issuing %d bytes to parser\n", (int)len);
|
2019-08-18 05:04:15 +01:00
|
|
|
#if defined(LWS_ROLE_WS) && defined(LWS_WITH_CLIENT)
|
2018-04-25 08:42:18 +08:00
|
|
|
if (lws_ws_handshake_client(wsi, &buf, (size_t)len))
|
2018-04-11 13:39:42 +08:00
|
|
|
goto bail;
|
2018-04-20 10:33:23 +08:00
|
|
|
#endif
|
2018-04-11 13:39:42 +08:00
|
|
|
last_char = buf;
|
|
|
|
if (lws_handshake_server(wsi, &buf, (size_t)len))
|
|
|
|
/* Handshake indicates this session is done. */
|
|
|
|
goto bail;
|
|
|
|
|
|
|
|
/* we might have transitioned to RAW */
|
2020-02-28 15:50:15 +00:00
|
|
|
if (wsi->role_ops == &role_ops_raw_skt
|
|
|
|
#if defined(LWS_ROLE_RAW_FILE)
|
|
|
|
||
|
|
|
|
wsi->role_ops == &role_ops_raw_file
|
|
|
|
#endif
|
|
|
|
)
|
2018-04-11 13:39:42 +08:00
|
|
|
/* we gave the read buffer to RAW handler already */
|
|
|
|
goto read_ok;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* It's possible that we've exhausted our data already, or
|
|
|
|
* rx flow control has stopped us dealing with this early,
|
|
|
|
* but lws_handshake_server doesn't update len for us.
|
|
|
|
* Figure out how much was read, so that we can proceed
|
|
|
|
* appropriately:
|
|
|
|
*/
|
2020-12-12 06:21:40 +00:00
|
|
|
len -= (unsigned int)lws_ptr_diff(buf, last_char);
|
2018-04-11 13:39:42 +08:00
|
|
|
|
|
|
|
if (!wsi->hdr_parsing_completed)
|
|
|
|
/* More header content on the way */
|
|
|
|
goto read_ok;
|
|
|
|
|
|
|
|
switch (lwsi_state(wsi)) {
|
|
|
|
case LRS_ESTABLISHED:
|
|
|
|
case LRS_HEADERS:
|
|
|
|
goto read_ok;
|
|
|
|
case LRS_ISSUING_FILE:
|
|
|
|
goto read_ok;
|
2019-07-05 06:07:03 +01:00
|
|
|
case LRS_DISCARD_BODY:
|
2018-04-11 13:39:42 +08:00
|
|
|
case LRS_BODY:
|
|
|
|
wsi->http.rx_content_remain =
|
|
|
|
wsi->http.rx_content_length;
|
|
|
|
if (wsi->http.rx_content_remain)
|
|
|
|
goto http_postbody;
|
|
|
|
|
|
|
|
/* there is no POST content */
|
|
|
|
goto postbody_completion;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2019-07-05 06:07:03 +01:00
|
|
|
case LRS_DISCARD_BODY:
|
2018-04-11 13:39:42 +08:00
|
|
|
case LRS_BODY:
|
|
|
|
http_postbody:
|
2020-12-20 08:39:49 +00:00
|
|
|
lwsl_info("%s: http post body: cl set %d, remain %d, len %d\n", __func__,
|
|
|
|
(int)wsi->http.content_length_given,
|
|
|
|
(int)wsi->http.rx_content_remain, (int)len);
|
2018-05-24 12:19:53 +08:00
|
|
|
|
2020-12-20 08:39:49 +00:00
|
|
|
if (wsi->http.content_length_given && !wsi->http.rx_content_remain)
|
2018-05-24 12:19:53 +08:00
|
|
|
goto postbody_completion;
|
|
|
|
|
2020-12-20 08:39:49 +00:00
|
|
|
while (len && (!wsi->http.content_length_given || wsi->http.rx_content_remain)) {
|
2018-04-11 13:39:42 +08:00
|
|
|
/* Copy as much as possible, up to the limit of:
|
|
|
|
* what we have in the read buffer (len)
|
|
|
|
* remaining portion of the POST body (content_remain)
|
|
|
|
*/
|
2020-12-20 08:39:49 +00:00
|
|
|
if (wsi->http.content_length_given)
|
|
|
|
body_chunk_len = min(wsi->http.rx_content_remain, len);
|
|
|
|
else
|
|
|
|
body_chunk_len = len;
|
2018-04-11 13:39:42 +08:00
|
|
|
wsi->http.rx_content_remain -= body_chunk_len;
|
2019-07-16 10:03:05 -07:00
|
|
|
// len -= body_chunk_len;
|
2018-04-11 13:39:42 +08:00
|
|
|
#ifdef LWS_WITH_CGI
|
2018-04-27 19:16:50 +08:00
|
|
|
if (wsi->http.cgi) {
|
2018-04-11 13:39:42 +08:00
|
|
|
struct lws_cgi_args args;
|
|
|
|
|
|
|
|
args.ch = LWS_STDIN;
|
2020-02-12 10:12:39 +00:00
|
|
|
args.stdwsi = &wsi->http.cgi->lsp->stdwsi[0];
|
2018-04-11 13:39:42 +08:00
|
|
|
args.data = buf;
|
2020-12-12 06:21:40 +00:00
|
|
|
args.len = (int)(unsigned int)body_chunk_len;
|
2018-04-11 13:39:42 +08:00
|
|
|
|
|
|
|
/* returns how much used */
|
2020-12-12 06:21:40 +00:00
|
|
|
n = (unsigned int)user_callback_handle_rxflow(
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
wsi->a.protocol->callback,
|
2018-04-11 13:39:42 +08:00
|
|
|
wsi, LWS_CALLBACK_CGI_STDIN_DATA,
|
|
|
|
wsi->user_space,
|
|
|
|
(void *)&args, 0);
|
|
|
|
if ((int)n < 0)
|
|
|
|
goto bail;
|
|
|
|
} else {
|
|
|
|
#endif
|
2019-07-05 06:07:03 +01:00
|
|
|
if (lwsi_state(wsi) != LRS_DISCARD_BODY) {
|
2020-12-20 08:39:49 +00:00
|
|
|
lwsl_info("%s: HTTP_BODY %d\n", __func__, (int)body_chunk_len);
|
|
|
|
n = (unsigned int)wsi->a.protocol->callback(wsi,
|
|
|
|
LWS_CALLBACK_HTTP_BODY, wsi->user_space,
|
|
|
|
buf, (size_t)body_chunk_len);
|
|
|
|
if (n)
|
|
|
|
goto bail;
|
2019-07-05 06:07:03 +01:00
|
|
|
}
|
2018-04-11 13:39:42 +08:00
|
|
|
n = (size_t)body_chunk_len;
|
|
|
|
#ifdef LWS_WITH_CGI
|
|
|
|
}
|
|
|
|
#endif
|
2020-12-20 08:39:49 +00:00
|
|
|
lwsl_info("%s: advancing buf by %d\n", __func__, (int)n);
|
2018-04-11 13:39:42 +08:00
|
|
|
buf += n;
|
|
|
|
|
2020-12-20 08:39:49 +00:00
|
|
|
#if defined(LWS_ROLE_H2)
|
|
|
|
if (lwsi_role_h2(wsi) && !wsi->http.content_length_given) {
|
|
|
|
struct lws *w = lws_get_network_wsi(wsi);
|
|
|
|
|
2020-12-19 09:13:24 +00:00
|
|
|
if (w)
|
|
|
|
lwsl_info("%s: h2: nwsi h2 flags %d\n", __func__,
|
2020-12-20 08:39:49 +00:00
|
|
|
w->h2.h2n ? w->h2.h2n->flags: -1);
|
|
|
|
|
|
|
|
if (w && w->h2.h2n && !(w->h2.h2n->flags & 1)) {
|
|
|
|
lwsl_info("%s: h2, no cl, not END_STREAM, continuing\n", __func__);
|
|
|
|
lws_set_timeout(wsi,
|
|
|
|
PENDING_TIMEOUT_HTTP_CONTENT,
|
|
|
|
(int)wsi->a.context->timeout_secs);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
goto postbody_completion;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2018-04-11 13:39:42 +08:00
|
|
|
if (wsi->http.rx_content_remain) {
|
2018-11-23 08:47:56 +08:00
|
|
|
lws_set_timeout(wsi,
|
|
|
|
PENDING_TIMEOUT_HTTP_CONTENT,
|
2020-12-12 06:21:40 +00:00
|
|
|
(int)wsi->a.context->timeout_secs);
|
2018-04-11 13:39:42 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* he sent all the content in time */
|
|
|
|
postbody_completion:
|
|
|
|
#ifdef LWS_WITH_CGI
|
|
|
|
/*
|
|
|
|
* If we're running a cgi, we can't let him off the
|
|
|
|
* hook just because he sent his POST data
|
|
|
|
*/
|
2018-04-27 19:16:50 +08:00
|
|
|
if (wsi->http.cgi)
|
2018-04-11 13:39:42 +08:00
|
|
|
lws_set_timeout(wsi, PENDING_TIMEOUT_CGI,
|
2020-12-12 06:21:40 +00:00
|
|
|
(int)wsi->a.context->timeout_secs);
|
2018-04-11 13:39:42 +08:00
|
|
|
else
|
|
|
|
#endif
|
|
|
|
lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
|
|
|
|
#ifdef LWS_WITH_CGI
|
2018-04-27 19:16:50 +08:00
|
|
|
if (!wsi->http.cgi)
|
2018-04-11 13:39:42 +08:00
|
|
|
#endif
|
|
|
|
{
|
2019-08-18 05:04:15 +01:00
|
|
|
#if defined(LWS_WITH_SERVER)
|
2019-07-05 06:07:03 +01:00
|
|
|
if (lwsi_state(wsi) == LRS_DISCARD_BODY) {
|
|
|
|
/*
|
|
|
|
* repeat the transaction completed
|
|
|
|
* that got us into this state, having
|
|
|
|
* consumed the pending body now
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (lws_http_transaction_completed(wsi))
|
2020-10-06 13:55:39 +01:00
|
|
|
goto bail;
|
2019-07-05 06:07:03 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_info("HTTP_BODY_COMPLETION: %s (%s)\n",
|
|
|
|
lws_wsi_tag(wsi), wsi->a.protocol->name);
|
2019-04-05 09:08:55 +08:00
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
n = (unsigned int)wsi->a.protocol->callback(wsi,
|
2018-04-11 13:39:42 +08:00
|
|
|
LWS_CALLBACK_HTTP_BODY_COMPLETION,
|
|
|
|
wsi->user_space, NULL, 0);
|
2020-12-20 08:39:49 +00:00
|
|
|
if (n) {
|
|
|
|
lwsl_info("%s: bailing after BODY_COMPLETION\n", __func__);
|
2018-04-11 13:39:42 +08:00
|
|
|
goto bail;
|
2020-12-20 08:39:49 +00:00
|
|
|
}
|
2018-04-11 13:39:42 +08:00
|
|
|
|
2019-12-23 11:31:57 +00:00
|
|
|
if (wsi->mux_substream)
|
2018-04-11 13:39:42 +08:00
|
|
|
lwsi_set_state(wsi, LRS_ESTABLISHED);
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2018-05-11 10:25:28 +08:00
|
|
|
case LRS_RETURNED_CLOSE:
|
2018-04-11 13:39:42 +08:00
|
|
|
case LRS_AWAITING_CLOSE_ACK:
|
|
|
|
case LRS_WAITING_TO_SEND_CLOSE:
|
|
|
|
case LRS_SHUTDOWN:
|
|
|
|
|
|
|
|
ws_mode:
|
2019-08-18 05:04:15 +01:00
|
|
|
#if defined(LWS_WITH_CLIENT) && defined(LWS_ROLE_WS)
|
2018-04-20 10:33:23 +08:00
|
|
|
// lwsl_notice("%s: ws_mode\n", __func__);
|
2018-04-25 08:42:18 +08:00
|
|
|
if (lws_ws_handshake_client(wsi, &buf, (size_t)len))
|
2018-04-11 13:39:42 +08:00
|
|
|
goto bail;
|
2018-04-20 10:33:23 +08:00
|
|
|
#endif
|
2018-04-11 13:39:42 +08:00
|
|
|
#if defined(LWS_ROLE_WS)
|
|
|
|
if (lwsi_role_ws(wsi) && lwsi_role_server(wsi) &&
|
|
|
|
/*
|
|
|
|
* for h2 we are on the swsi
|
|
|
|
*/
|
2018-04-20 10:33:23 +08:00
|
|
|
lws_parse_ws(wsi, &buf, (size_t)len) < 0) {
|
|
|
|
lwsl_info("%s: lws_parse_ws bailed\n", __func__);
|
2018-04-11 13:39:42 +08:00
|
|
|
goto bail;
|
|
|
|
}
|
|
|
|
#endif
|
2018-04-25 08:42:18 +08:00
|
|
|
// lwsl_notice("%s: ws_mode: buf moved on by %d\n", __func__,
|
|
|
|
// lws_ptr_diff(buf, oldbuf));
|
2018-04-11 13:39:42 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case LRS_DEFERRING_ACTION:
|
2018-09-02 14:35:37 +08:00
|
|
|
lwsl_notice("%s: LRS_DEFERRING_ACTION\n", __func__);
|
2018-04-11 13:39:42 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case LRS_SSL_ACK_PENDING:
|
|
|
|
break;
|
|
|
|
|
2020-03-26 18:07:48 +00:00
|
|
|
case LRS_FLUSHING_BEFORE_CLOSE:
|
|
|
|
break;
|
|
|
|
|
2018-04-11 13:39:42 +08:00
|
|
|
case LRS_DEAD_SOCKET:
|
|
|
|
lwsl_err("%s: Unhandled state LRS_DEAD_SOCKET\n", __func__);
|
2018-04-26 15:27:02 +08:00
|
|
|
goto bail;
|
|
|
|
// assert(0);
|
2018-04-11 13:39:42 +08:00
|
|
|
/* fallthru */
|
|
|
|
|
|
|
|
default:
|
|
|
|
lwsl_err("%s: Unhandled state %d\n", __func__, lwsi_state(wsi));
|
|
|
|
assert(0);
|
|
|
|
goto bail;
|
|
|
|
}
|
|
|
|
|
|
|
|
read_ok:
|
|
|
|
/* Nothing more to do for now */
|
|
|
|
// lwsl_info("%s: %p: read_ok, used %ld (len %d, state %d)\n", __func__,
|
|
|
|
// wsi, (long)(buf - oldbuf), (int)len, wsi->state);
|
|
|
|
|
|
|
|
return lws_ptr_diff(buf, oldbuf);
|
|
|
|
|
|
|
|
bail:
|
|
|
|
/*
|
2018-04-25 08:42:18 +08:00
|
|
|
* h2 / h2-ws calls us recursively in
|
|
|
|
*
|
|
|
|
* lws_read_h1()->
|
|
|
|
* lws_h2_parser()->
|
|
|
|
* lws_read_h1()
|
|
|
|
*
|
|
|
|
* pattern, having stripped the h2 framing in the middle.
|
2018-04-11 13:39:42 +08:00
|
|
|
*
|
|
|
|
* When taking down the whole connection, make sure that only the
|
|
|
|
* outer lws_read() does the wsi close.
|
|
|
|
*/
|
|
|
|
if (!wsi->outer_will_close)
|
2018-04-25 08:42:18 +08:00
|
|
|
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS,
|
|
|
|
"lws_read_h1 bail");
|
2018-04-11 13:39:42 +08:00
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
2019-08-18 05:04:15 +01:00
|
|
|
#if defined(LWS_WITH_SERVER)
|
2018-04-20 10:33:23 +08:00
|
|
|
static int
|
2018-04-11 13:39:42 +08:00
|
|
|
lws_h1_server_socket_service(struct lws *wsi, struct lws_pollfd *pollfd)
|
|
|
|
{
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
|
2018-04-17 15:35:15 +08:00
|
|
|
struct lws_tokens ebuf;
|
|
|
|
int n, buffered;
|
2018-04-11 13:39:42 +08:00
|
|
|
|
|
|
|
if (lwsi_state(wsi) == LRS_DEFERRING_ACTION)
|
|
|
|
goto try_pollout;
|
|
|
|
|
|
|
|
/* any incoming data ready? */
|
|
|
|
|
|
|
|
if (!(pollfd->revents & pollfd->events & LWS_POLLIN))
|
|
|
|
goto try_pollout;
|
|
|
|
|
|
|
|
/*
|
2018-04-17 15:35:15 +08:00
|
|
|
* If we previously just did POLLIN when IN and OUT were signaled
|
|
|
|
* (because POLLIN processing may have used up the POLLOUT), don't let
|
|
|
|
* that happen twice in a row... next time we see the situation favour
|
|
|
|
* POLLOUT
|
2018-04-11 13:39:42 +08:00
|
|
|
*/
|
2018-04-17 15:35:15 +08:00
|
|
|
|
2018-04-11 13:39:42 +08:00
|
|
|
if (wsi->favoured_pollin &&
|
|
|
|
(pollfd->revents & pollfd->events & LWS_POLLOUT)) {
|
|
|
|
// lwsl_notice("favouring pollout\n");
|
|
|
|
wsi->favoured_pollin = 0;
|
|
|
|
goto try_pollout;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We haven't processed that the tunnel is set up yet, so
|
|
|
|
* defer reading
|
|
|
|
*/
|
2018-04-17 15:35:15 +08:00
|
|
|
|
2018-04-11 13:39:42 +08:00
|
|
|
if (lwsi_state(wsi) == LRS_SSL_ACK_PENDING)
|
|
|
|
return LWS_HPI_RET_HANDLED;
|
|
|
|
|
|
|
|
/* these states imply we MUST have an ah attached */
|
|
|
|
|
|
|
|
if ((lwsi_state(wsi) == LRS_ESTABLISHED ||
|
|
|
|
lwsi_state(wsi) == LRS_ISSUING_FILE ||
|
2018-04-17 15:35:15 +08:00
|
|
|
lwsi_state(wsi) == LRS_HEADERS ||
|
2019-07-05 06:07:03 +01:00
|
|
|
lwsi_state(wsi) == LRS_DISCARD_BODY ||
|
2018-04-17 15:35:15 +08:00
|
|
|
lwsi_state(wsi) == LRS_BODY)) {
|
2018-05-04 12:05:56 +08:00
|
|
|
|
|
|
|
if (!wsi->http.ah && lws_header_table_attach(wsi, 0)) {
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_info("%s: %s: ah not available\n", __func__,
|
|
|
|
lws_wsi_tag(wsi));
|
2018-04-17 15:35:15 +08:00
|
|
|
goto try_pollout;
|
2018-04-11 13:39:42 +08:00
|
|
|
}
|
|
|
|
|
2018-04-30 19:17:32 +08:00
|
|
|
/*
|
|
|
|
* We got here because there was specifically POLLIN...
|
|
|
|
* regardless of our buflist state, we need to get it,
|
|
|
|
* and either use it, or append to the buflist and use
|
|
|
|
* buflist head material.
|
2018-05-04 12:05:56 +08:00
|
|
|
*
|
|
|
|
* We will not notice a connection close until the buflist is
|
|
|
|
* exhausted and we tried to do a read of some kind.
|
2018-04-30 19:17:32 +08:00
|
|
|
*/
|
|
|
|
|
2020-01-20 10:02:56 +00:00
|
|
|
ebuf.token = NULL;
|
|
|
|
ebuf.len = 0;
|
|
|
|
buffered = lws_buflist_aware_read(pt, wsi, &ebuf, 0, __func__);
|
2018-04-17 15:35:15 +08:00
|
|
|
switch (ebuf.len) {
|
|
|
|
case 0:
|
2018-04-30 19:17:32 +08:00
|
|
|
lwsl_info("%s: read 0 len a\n", __func__);
|
2018-04-17 15:35:15 +08:00
|
|
|
wsi->seen_zero_length_recv = 1;
|
2019-07-13 12:06:33 -07:00
|
|
|
if (lws_change_pollfd(wsi, LWS_POLLIN, 0))
|
|
|
|
goto fail;
|
2018-05-04 12:05:56 +08:00
|
|
|
#if !defined(LWS_WITHOUT_EXTENSIONS)
|
|
|
|
/*
|
|
|
|
* autobahn requires us to win the race between close
|
|
|
|
* and draining the extensions
|
|
|
|
*/
|
|
|
|
if (wsi->ws &&
|
2018-11-23 08:47:56 +08:00
|
|
|
(wsi->ws->rx_draining_ext ||
|
|
|
|
wsi->ws->tx_draining_ext))
|
2018-05-04 12:05:56 +08:00
|
|
|
goto try_pollout;
|
|
|
|
#endif
|
|
|
|
/*
|
|
|
|
* normally, we respond to close with logically closing
|
|
|
|
* our side immediately
|
|
|
|
*/
|
|
|
|
goto fail;
|
2018-04-11 13:39:42 +08:00
|
|
|
|
2018-04-17 15:35:15 +08:00
|
|
|
case LWS_SSL_CAPABLE_ERROR:
|
|
|
|
goto fail;
|
|
|
|
case LWS_SSL_CAPABLE_MORE_SERVICE:
|
|
|
|
goto try_pollout;
|
2018-04-11 13:39:42 +08:00
|
|
|
}
|
|
|
|
|
2018-04-17 15:35:15 +08:00
|
|
|
/* just ignore incoming if waiting for close */
|
|
|
|
if (lwsi_state(wsi) == LRS_FLUSHING_BEFORE_CLOSE) {
|
|
|
|
lwsl_notice("%s: just ignoring\n", __func__);
|
|
|
|
goto try_pollout;
|
2018-04-11 13:39:42 +08:00
|
|
|
}
|
|
|
|
|
2018-04-17 15:35:15 +08:00
|
|
|
if (lwsi_state(wsi) == LRS_ISSUING_FILE) {
|
|
|
|
// lwsl_notice("stashing: wsi %p: bd %d\n", wsi, buffered);
|
2019-08-27 06:06:13 +01:00
|
|
|
if (lws_buflist_aware_finished_consuming(wsi, &ebuf, 0,
|
|
|
|
buffered, __func__))
|
2018-04-17 15:35:15 +08:00
|
|
|
return LWS_HPI_RET_PLEASE_CLOSE_ME;
|
|
|
|
|
2018-04-11 13:39:42 +08:00
|
|
|
goto try_pollout;
|
2018-04-17 15:35:15 +08:00
|
|
|
}
|
2018-04-11 13:39:42 +08:00
|
|
|
|
|
|
|
/*
|
2018-04-17 15:35:15 +08:00
|
|
|
* Otherwise give it to whoever wants it according to the
|
|
|
|
* connection state
|
2018-04-11 13:39:42 +08:00
|
|
|
*/
|
|
|
|
#if defined(LWS_ROLE_H2)
|
|
|
|
if (lwsi_role_h2(wsi) && lwsi_state(wsi) != LRS_BODY)
|
2020-12-12 06:21:40 +00:00
|
|
|
n = lws_read_h2(wsi, ebuf.token, (unsigned int)ebuf.len);
|
2018-04-11 13:39:42 +08:00
|
|
|
else
|
|
|
|
#endif
|
2020-12-12 06:21:40 +00:00
|
|
|
n = lws_read_h1(wsi, ebuf.token, (unsigned int)ebuf.len);
|
2018-04-11 13:39:42 +08:00
|
|
|
if (n < 0) /* we closed wsi */
|
2018-04-17 15:35:15 +08:00
|
|
|
return LWS_HPI_RET_WSI_ALREADY_DIED;
|
2018-04-11 13:39:42 +08:00
|
|
|
|
2019-09-12 05:41:19 +01:00
|
|
|
// lwsl_notice("%s: consumed %d\n", __func__, n);
|
2018-04-11 13:39:42 +08:00
|
|
|
|
2019-08-27 06:06:13 +01:00
|
|
|
if (lws_buflist_aware_finished_consuming(wsi, &ebuf, n,
|
|
|
|
buffered, __func__))
|
2018-04-17 15:35:15 +08:00
|
|
|
return LWS_HPI_RET_PLEASE_CLOSE_ME;
|
2018-04-11 13:39:42 +08:00
|
|
|
|
|
|
|
/*
|
2018-04-17 15:35:15 +08:00
|
|
|
* during the parsing our role changed to something non-http,
|
|
|
|
* so the ah has no further meaning
|
2018-04-11 13:39:42 +08:00
|
|
|
*/
|
|
|
|
|
2018-04-27 15:20:56 +08:00
|
|
|
if (wsi->http.ah &&
|
2018-04-17 15:35:15 +08:00
|
|
|
!lwsi_role_h1(wsi) &&
|
|
|
|
!lwsi_role_h2(wsi) &&
|
|
|
|
!lwsi_role_cgi(wsi))
|
|
|
|
lws_header_table_detach(wsi, 0);
|
2018-04-11 13:39:42 +08:00
|
|
|
|
|
|
|
/*
|
2018-04-17 15:35:15 +08:00
|
|
|
* He may have used up the writability above, if we will defer
|
|
|
|
* POLLOUT processing in favour of POLLIN, note it
|
2018-04-11 13:39:42 +08:00
|
|
|
*/
|
2018-04-17 15:35:15 +08:00
|
|
|
|
2018-04-11 13:39:42 +08:00
|
|
|
if (pollfd->revents & LWS_POLLOUT)
|
|
|
|
wsi->favoured_pollin = 1;
|
2018-04-17 15:35:15 +08:00
|
|
|
|
2018-04-11 13:39:42 +08:00
|
|
|
return LWS_HPI_RET_HANDLED;
|
|
|
|
}
|
2018-04-17 15:35:15 +08:00
|
|
|
|
2018-04-11 13:39:42 +08:00
|
|
|
/*
|
2018-04-17 15:35:15 +08:00
|
|
|
* He may have used up the writability above, if we will defer POLLOUT
|
2018-04-11 13:39:42 +08:00
|
|
|
* processing in favour of POLLIN, note it
|
|
|
|
*/
|
2018-04-17 15:35:15 +08:00
|
|
|
|
2018-04-11 13:39:42 +08:00
|
|
|
if (pollfd->revents & LWS_POLLOUT)
|
|
|
|
wsi->favoured_pollin = 1;
|
|
|
|
|
|
|
|
try_pollout:
|
|
|
|
|
|
|
|
/* this handles POLLOUT for http serving fragments */
|
|
|
|
|
|
|
|
if (!(pollfd->revents & LWS_POLLOUT))
|
|
|
|
return LWS_HPI_RET_HANDLED;
|
|
|
|
|
|
|
|
/* one shot */
|
|
|
|
if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) {
|
|
|
|
lwsl_notice("%s a\n", __func__);
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* clear back-to-back write detection */
|
|
|
|
wsi->could_have_pending = 0;
|
|
|
|
|
|
|
|
if (lwsi_state(wsi) == LRS_DEFERRING_ACTION) {
|
2018-04-17 15:35:15 +08:00
|
|
|
lwsl_debug("%s: LRS_DEFERRING_ACTION now writable\n", __func__);
|
2018-04-11 13:39:42 +08:00
|
|
|
|
|
|
|
lwsi_set_state(wsi, LRS_ESTABLISHED);
|
|
|
|
if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) {
|
|
|
|
lwsl_info("failed at set pollfd\n");
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!wsi->hdr_parsing_completed)
|
|
|
|
return LWS_HPI_RET_HANDLED;
|
|
|
|
|
|
|
|
if (lwsi_state(wsi) != LRS_ISSUING_FILE) {
|
|
|
|
|
2018-08-20 12:02:26 +08:00
|
|
|
if (lws_has_buffered_out(wsi)) {
|
2018-06-16 10:38:17 +08:00
|
|
|
//lwsl_notice("%s: completing partial\n", __func__);
|
2018-08-20 12:02:26 +08:00
|
|
|
if (lws_issue_raw(wsi, NULL, 0) < 0) {
|
2018-06-16 10:38:17 +08:00
|
|
|
lwsl_info("%s signalling to close\n", __func__);
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
return LWS_HPI_RET_HANDLED;
|
|
|
|
}
|
|
|
|
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
n = user_callback_handle_rxflow(wsi->a.protocol->callback, wsi,
|
2018-04-17 15:35:15 +08:00
|
|
|
LWS_CALLBACK_HTTP_WRITEABLE,
|
|
|
|
wsi->user_space, NULL, 0);
|
2018-04-11 13:39:42 +08:00
|
|
|
if (n < 0) {
|
|
|
|
lwsl_info("writeable_fail\n");
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
return LWS_HPI_RET_HANDLED;
|
|
|
|
}
|
|
|
|
|
2019-08-18 10:35:43 +01:00
|
|
|
#if defined(LWS_WITH_FILE_OPS)
|
|
|
|
|
2018-04-11 13:39:42 +08:00
|
|
|
/* >0 == completion, <0 == error
|
|
|
|
*
|
|
|
|
* We'll get a LWS_CALLBACK_HTTP_FILE_COMPLETION callback when
|
|
|
|
* it's done. That's the case even if we just completed the
|
|
|
|
* send, so wait for that.
|
|
|
|
*/
|
|
|
|
n = lws_serve_http_file_fragment(wsi);
|
|
|
|
if (n < 0)
|
|
|
|
goto fail;
|
2019-08-18 10:35:43 +01:00
|
|
|
#endif
|
2018-04-11 13:39:42 +08:00
|
|
|
|
|
|
|
return LWS_HPI_RET_HANDLED;
|
|
|
|
|
|
|
|
|
|
|
|
fail:
|
2018-05-04 12:05:56 +08:00
|
|
|
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS,
|
|
|
|
"server socket svc fail");
|
2018-04-11 13:39:42 +08:00
|
|
|
|
2018-04-17 15:35:15 +08:00
|
|
|
return LWS_HPI_RET_WSI_ALREADY_DIED;
|
2018-04-11 13:39:42 +08:00
|
|
|
}
|
2018-04-20 10:33:23 +08:00
|
|
|
#endif
|
2018-04-11 13:39:42 +08:00
|
|
|
|
|
|
|
static int
|
|
|
|
rops_handle_POLLIN_h1(struct lws_context_per_thread *pt, struct lws *wsi,
|
|
|
|
struct lws_pollfd *pollfd)
|
|
|
|
{
|
2019-08-09 10:12:09 +01:00
|
|
|
if (lwsi_state(wsi) == LRS_IDLING) {
|
|
|
|
uint8_t buf[1];
|
|
|
|
int rlen;
|
2018-04-11 13:39:42 +08:00
|
|
|
|
2019-08-09 10:12:09 +01:00
|
|
|
/*
|
|
|
|
* h1 staggered spins here in IDLING if we don't close it.
|
|
|
|
* It shows POLLIN but the tls connection returns ERROR if
|
|
|
|
* you try to read it.
|
|
|
|
*/
|
|
|
|
|
|
|
|
// lwsl_notice("%s: %p: wsistate 0x%x %s, revents 0x%x\n",
|
|
|
|
// __func__, wsi, wsi->wsistate, wsi->role_ops->name,
|
|
|
|
// pollfd->revents);
|
|
|
|
|
|
|
|
rlen = lws_ssl_capable_read(wsi, buf, sizeof(buf));
|
|
|
|
if (rlen == LWS_SSL_CAPABLE_ERROR)
|
|
|
|
return LWS_HPI_RET_PLEASE_CLOSE_ME;
|
|
|
|
}
|
2018-04-11 13:39:42 +08:00
|
|
|
|
|
|
|
#ifdef LWS_WITH_CGI
|
2018-04-27 19:16:50 +08:00
|
|
|
if (wsi->http.cgi && (pollfd->revents & LWS_POLLOUT)) {
|
2018-04-11 13:39:42 +08:00
|
|
|
if (lws_handle_POLLOUT_event(wsi, pollfd))
|
2018-04-17 15:35:15 +08:00
|
|
|
return LWS_HPI_RET_PLEASE_CLOSE_ME;
|
2018-04-11 13:39:42 +08:00
|
|
|
|
|
|
|
return LWS_HPI_RET_HANDLED;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2018-09-02 14:35:37 +08:00
|
|
|
/* Priority 2: pre- compression transform */
|
|
|
|
|
|
|
|
#if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
|
|
|
|
if (wsi->http.comp_ctx.buflist_comp ||
|
|
|
|
wsi->http.comp_ctx.may_have_more) {
|
|
|
|
enum lws_write_protocol wp = LWS_WRITE_HTTP;
|
|
|
|
|
|
|
|
lwsl_info("%s: completing comp partial (buflist_comp %p, may %d)\n",
|
|
|
|
__func__, wsi->http.comp_ctx.buflist_comp,
|
|
|
|
wsi->http.comp_ctx.may_have_more
|
|
|
|
);
|
|
|
|
|
roles: compress role ops structs
role ops are usually only sparsely filled, there are currently 20
function pointers but several roles only fill in two. No single
role has more than 14 of the ops. On a 32/64 bit build this part
of the ops struct takes a fixed 80 / 160 bytes then.
First reduce the type of the callback reason part from uint16_t to
uint8_t, this saves 12 bytes unconditionally.
Change to a separate function pointer array with a nybble index
array, it costs 10 bytes for the index and a pointer to the
separate array, for 32-bit the cost is
2 + (4 x ops_used)
and for 64-bit
6 + (8 x ops_used)
for 2 x ops_used it means 32-bit: 10 vs 80 / 64-bit: 22 vs 160
For a typical system with h1 (9), h2 (14), listen (2), netlink (2),
pipe (1), raw_skt (3), ws (12), == 43 ops_used out of 140, it means
the .rodata for this reduced from 32-bit: 560 -> 174 (386 byte
saving) and 64-bit: 1120 -> 350 (770 byte saving)
This doesn't account for the changed function ops calling code, two
ways were tried, a preprocessor macro and explicit functions
For an x86_64 gcc 10 build with most options, release mode,
.text + .rodata
before patch: 553282
accessor macro: 552714 (568 byte saving)
accessor functions: 553674 (392 bytes worse than without patch)
therefore we went with the macros
2020-10-19 13:55:21 +01:00
|
|
|
if (lws_rops_fidx(wsi->role_ops, LWS_ROPS_write_role_protocol) &&
|
|
|
|
lws_rops_func_fidx(wsi->role_ops, LWS_ROPS_write_role_protocol).
|
|
|
|
write_role_protocol(wsi, NULL, 0, &wp) < 0) {
|
2018-09-02 14:35:37 +08:00
|
|
|
lwsl_info("%s signalling to close\n", __func__);
|
|
|
|
return LWS_HPI_RET_PLEASE_CLOSE_ME;
|
|
|
|
}
|
|
|
|
lws_callback_on_writable(wsi);
|
|
|
|
|
|
|
|
if (!wsi->http.comp_ctx.buflist_comp &&
|
|
|
|
!wsi->http.comp_ctx.may_have_more &&
|
|
|
|
wsi->http.deferred_transaction_completed) {
|
|
|
|
wsi->http.deferred_transaction_completed = 0;
|
|
|
|
if (lws_http_transaction_completed(wsi))
|
|
|
|
return LWS_HPI_RET_PLEASE_CLOSE_ME;
|
|
|
|
}
|
|
|
|
|
|
|
|
return LWS_HPI_RET_HANDLED;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2018-04-11 13:39:42 +08:00
|
|
|
if (lws_is_flowcontrolled(wsi))
|
|
|
|
/* We cannot deal with any kind of new RX because we are
|
|
|
|
* RX-flowcontrolled.
|
|
|
|
*/
|
|
|
|
return LWS_HPI_RET_HANDLED;
|
|
|
|
|
2019-08-18 05:04:15 +01:00
|
|
|
#if defined(LWS_WITH_SERVER)
|
2018-04-11 13:39:42 +08:00
|
|
|
if (!lwsi_role_client(wsi)) {
|
|
|
|
int n;
|
|
|
|
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_debug("%s: %s: wsistate 0x%x\n", __func__, lws_wsi_tag(wsi),
|
|
|
|
(unsigned int)wsi->wsistate);
|
2021-05-23 14:45:37 +01:00
|
|
|
|
|
|
|
if (pollfd->revents & LWS_POLLHUP &&
|
|
|
|
!lws_buflist_total_len(&wsi->buflist))
|
|
|
|
return LWS_HPI_RET_PLEASE_CLOSE_ME;
|
|
|
|
|
2018-04-11 13:39:42 +08:00
|
|
|
n = lws_h1_server_socket_service(wsi, pollfd);
|
|
|
|
if (n != LWS_HPI_RET_HANDLED)
|
|
|
|
return n;
|
|
|
|
if (lwsi_state(wsi) != LRS_SSL_INIT)
|
2018-11-23 08:47:56 +08:00
|
|
|
if (lws_server_socket_service_ssl(wsi,
|
2020-04-19 08:43:01 +01:00
|
|
|
LWS_SOCK_INVALID,
|
|
|
|
!!(pollfd->revents & LWS_POLLIN)))
|
2018-04-17 15:35:15 +08:00
|
|
|
return LWS_HPI_RET_PLEASE_CLOSE_ME;
|
2018-04-11 13:39:42 +08:00
|
|
|
|
|
|
|
return LWS_HPI_RET_HANDLED;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2019-08-18 05:04:15 +01:00
|
|
|
#if defined(LWS_WITH_CLIENT)
|
2018-04-11 13:39:42 +08:00
|
|
|
if ((pollfd->revents & LWS_POLLIN) &&
|
|
|
|
wsi->hdr_parsing_completed && !wsi->told_user_closed) {
|
|
|
|
|
|
|
|
/*
|
|
|
|
* In SSL mode we get POLLIN notification about
|
|
|
|
* encrypted data in.
|
|
|
|
*
|
|
|
|
* But that is not necessarily related to decrypted
|
|
|
|
* data out becoming available; in may need to perform
|
|
|
|
* other in or out before that happens.
|
|
|
|
*
|
|
|
|
* simply mark ourselves as having readable data
|
|
|
|
* and turn off our POLLIN
|
|
|
|
*/
|
|
|
|
wsi->client_rx_avail = 1;
|
2019-07-13 12:06:33 -07:00
|
|
|
if (lws_change_pollfd(wsi, LWS_POLLIN, 0))
|
|
|
|
return LWS_HPI_RET_PLEASE_CLOSE_ME;
|
2018-04-11 13:39:42 +08:00
|
|
|
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
//lwsl_notice("calling back %s\n", wsi->a.protocol->name);
|
2018-04-11 13:39:42 +08:00
|
|
|
|
|
|
|
/* let user code know, he'll usually ask for writeable
|
|
|
|
* callback and drain / re-enable it there
|
|
|
|
*/
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
if (user_callback_handle_rxflow(wsi->a.protocol->callback, wsi,
|
2018-11-23 08:47:56 +08:00
|
|
|
LWS_CALLBACK_RECEIVE_CLIENT_HTTP,
|
|
|
|
wsi->user_space, NULL, 0)) {
|
2018-04-11 13:39:42 +08:00
|
|
|
lwsl_info("RECEIVE_CLIENT_HTTP closed it\n");
|
2018-04-17 15:35:15 +08:00
|
|
|
return LWS_HPI_RET_PLEASE_CLOSE_ME;
|
2018-04-11 13:39:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return LWS_HPI_RET_HANDLED;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// if (lwsi_state(wsi) == LRS_ESTABLISHED)
|
|
|
|
// return LWS_HPI_RET_HANDLED;
|
|
|
|
|
2019-08-18 05:04:15 +01:00
|
|
|
#if defined(LWS_WITH_CLIENT)
|
2018-04-11 13:39:42 +08:00
|
|
|
if ((pollfd->revents & LWS_POLLOUT) &&
|
|
|
|
lws_handle_POLLOUT_event(wsi, pollfd)) {
|
|
|
|
lwsl_debug("POLLOUT event closed it\n");
|
2018-04-17 15:35:15 +08:00
|
|
|
return LWS_HPI_RET_PLEASE_CLOSE_ME;
|
2018-04-11 13:39:42 +08:00
|
|
|
}
|
|
|
|
|
2020-09-19 13:27:33 +01:00
|
|
|
if (lws_http_client_socket_service(wsi, pollfd))
|
2018-04-17 15:35:15 +08:00
|
|
|
return LWS_HPI_RET_WSI_ALREADY_DIED;
|
2018-04-11 13:39:42 +08:00
|
|
|
#endif
|
|
|
|
|
2021-01-29 14:48:35 +00:00
|
|
|
if (lwsi_state(wsi) == LRS_WAITING_CONNECT &&
|
|
|
|
(pollfd->revents & LWS_POLLHUP))
|
|
|
|
return LWS_HPI_RET_PLEASE_CLOSE_ME;
|
|
|
|
|
2018-04-11 13:39:42 +08:00
|
|
|
return LWS_HPI_RET_HANDLED;
|
|
|
|
}
|
|
|
|
|
2018-11-29 08:29:48 +08:00
|
|
|
static int
|
|
|
|
rops_handle_POLLOUT_h1(struct lws *wsi)
|
2018-04-11 13:39:42 +08:00
|
|
|
{
|
2019-03-22 06:22:40 +08:00
|
|
|
|
2021-08-13 21:16:24 +01:00
|
|
|
|
|
|
|
if (lwsi_state(wsi) == LRS_ISSUE_HTTP_BODY ||
|
|
|
|
lwsi_state(wsi) == LRS_WAITING_SERVER_REPLY) {
|
2019-03-22 06:22:40 +08:00
|
|
|
#if defined(LWS_WITH_HTTP_PROXY)
|
|
|
|
if (wsi->http.proxy_clientside) {
|
2019-04-05 21:13:59 +08:00
|
|
|
unsigned char *buf, prebuf[LWS_PRE + 1024];
|
2019-03-22 06:22:40 +08:00
|
|
|
size_t len = lws_buflist_next_segment_len(
|
|
|
|
&wsi->parent->http.buflist_post_body, &buf);
|
|
|
|
int n;
|
|
|
|
|
2019-07-01 05:53:08 +01:00
|
|
|
if (len > sizeof(prebuf) - LWS_PRE)
|
|
|
|
len = sizeof(prebuf) - LWS_PRE;
|
2019-04-05 21:13:59 +08:00
|
|
|
|
2019-07-01 05:53:08 +01:00
|
|
|
if (len) {
|
2019-04-05 21:13:59 +08:00
|
|
|
memcpy(prebuf + LWS_PRE, buf, len);
|
2019-03-22 06:22:40 +08:00
|
|
|
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_debug("%s: %s: proxying body %d %d %d %d %d\n",
|
|
|
|
__func__, lws_wsi_tag(wsi), (int)len,
|
2019-04-05 21:13:59 +08:00
|
|
|
(int)wsi->http.tx_content_length,
|
|
|
|
(int)wsi->http.tx_content_remain,
|
|
|
|
(int)wsi->http.rx_content_length,
|
|
|
|
(int)wsi->http.rx_content_remain
|
|
|
|
);
|
|
|
|
|
|
|
|
n = lws_write(wsi, prebuf + LWS_PRE, len, LWS_WRITE_HTTP);
|
|
|
|
if (n < 0) {
|
|
|
|
lwsl_err("%s: PROXY_BODY: write %d failed\n",
|
|
|
|
__func__, (int)len);
|
|
|
|
return LWS_HP_RET_BAIL_DIE;
|
|
|
|
}
|
|
|
|
|
|
|
|
lws_buflist_use_segment(&wsi->parent->http.buflist_post_body, len);
|
2021-08-13 21:16:24 +01:00
|
|
|
|
2019-04-05 21:13:59 +08:00
|
|
|
}
|
2019-03-22 06:22:40 +08:00
|
|
|
|
2021-08-13 21:16:24 +01:00
|
|
|
if (wsi->parent->http.buflist_post_body) {
|
2019-03-22 06:22:40 +08:00
|
|
|
lws_callback_on_writable(wsi);
|
2021-08-13 21:16:24 +01:00
|
|
|
return LWS_HP_RET_DROP_POLLOUT;
|
|
|
|
}
|
|
|
|
|
2021-08-28 07:38:25 +01:00
|
|
|
lwsl_err("%s: nothing to send\n", __func__);
|
2019-03-22 06:22:40 +08:00
|
|
|
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
|
2021-08-13 21:16:24 +01:00
|
|
|
/* prepare ourselves to do the parsing */
|
|
|
|
wsi->http.ah->parser_state = WSI_TOKEN_NAME_PART;
|
|
|
|
wsi->http.ah->lextable_pos = 0;
|
2019-03-22 06:22:40 +08:00
|
|
|
#if defined(LWS_WITH_CUSTOM_HEADERS)
|
2021-08-13 21:16:24 +01:00
|
|
|
wsi->http.ah->unk_pos = 0;
|
2019-03-22 06:22:40 +08:00
|
|
|
#endif
|
|
|
|
#endif
|
2021-08-13 21:16:24 +01:00
|
|
|
lwsi_set_state(wsi, LRS_WAITING_SERVER_REPLY);
|
|
|
|
lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_SERVER_RESPONSE,
|
|
|
|
(int)wsi->a.context->timeout_secs);
|
|
|
|
|
|
|
|
return LWS_HP_RET_DROP_POLLOUT;
|
2019-03-22 06:22:40 +08:00
|
|
|
}
|
|
|
|
#endif
|
2018-04-11 13:39:42 +08:00
|
|
|
return LWS_HP_RET_USER_SERVICE;
|
2019-03-22 06:22:40 +08:00
|
|
|
}
|
2018-04-11 13:39:42 +08:00
|
|
|
|
|
|
|
if (lwsi_role_client(wsi))
|
|
|
|
return LWS_HP_RET_USER_SERVICE;
|
|
|
|
|
|
|
|
return LWS_HP_RET_BAIL_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
rops_write_role_protocol_h1(struct lws *wsi, unsigned char *buf, size_t len,
|
|
|
|
enum lws_write_protocol *wp)
|
|
|
|
{
|
http: compression methods
Add generic http compression layer eanbled at cmake with LWS_WITH_HTTP_STREAM_COMPRESSION.
This is wholly a feature of the HTTP role (used by h1 and h2 roles) and doesn't exist
outside that context.
Currently provides 'deflate' and 'br' compression methods for server side only.
'br' requires also -DLWS_WITH_HTTP_BROTLI=1 at cmake and the brotli libraries (available in
your distro already) and dev package.
Other compression methods can be added nicely using an ops struct.
The built-in file serving stuff will use this is the client says he can handle it, and the
mimetype of the file either starts with "text/" (html and css etc) or is the mimetype of
Javascript.
zlib allocates quite a bit while in use, it seems to be around 256KiB per stream. So this
is only useful on relatively strong servers with lots of memory. However for some usecases
where you are serving a lot of css and js assets, it's a nice help.
The patch performs special treatment for http/1.1 pipelining, since the compression is
performed on the fly the compressed content-length is not known until the end. So for h1
only, chunked transfer-encoding is automatically added so pipelining can continue of the
connection.
For h2 the chunking is neither supported nor required, so it "just works".
User code can also request to add a compression transform before the reply headers were
sent using the new api
LWS_VISIBLE int
lws_http_compression_apply(struct lws *wsi, const char *name,
unsigned char **p, unsigned char *end, char decomp);
... this allows transparent compression of dynamically generated HTTP. The requested
compression (eg, "deflate") is only applied if the client headers indicated it was
supported, otherwise it's a NOP.
Name may be NULL in which case the first compression method in the internal table at
stream.c that is mentioned as acceptable by the client will be used.
NOTE: the compression translation, same as h2 support, relies on the user code using
LWS_WRITE_HTTP and then LWS_WRITE_HTTP_FINAL on the last part written. The internal
lws fileserving code already does this.
2018-09-02 14:43:05 +08:00
|
|
|
size_t olen = len;
|
|
|
|
int n;
|
2018-04-11 13:39:42 +08:00
|
|
|
|
http: compression methods
Add generic http compression layer eanbled at cmake with LWS_WITH_HTTP_STREAM_COMPRESSION.
This is wholly a feature of the HTTP role (used by h1 and h2 roles) and doesn't exist
outside that context.
Currently provides 'deflate' and 'br' compression methods for server side only.
'br' requires also -DLWS_WITH_HTTP_BROTLI=1 at cmake and the brotli libraries (available in
your distro already) and dev package.
Other compression methods can be added nicely using an ops struct.
The built-in file serving stuff will use this is the client says he can handle it, and the
mimetype of the file either starts with "text/" (html and css etc) or is the mimetype of
Javascript.
zlib allocates quite a bit while in use, it seems to be around 256KiB per stream. So this
is only useful on relatively strong servers with lots of memory. However for some usecases
where you are serving a lot of css and js assets, it's a nice help.
The patch performs special treatment for http/1.1 pipelining, since the compression is
performed on the fly the compressed content-length is not known until the end. So for h1
only, chunked transfer-encoding is automatically added so pipelining can continue of the
connection.
For h2 the chunking is neither supported nor required, so it "just works".
User code can also request to add a compression transform before the reply headers were
sent using the new api
LWS_VISIBLE int
lws_http_compression_apply(struct lws *wsi, const char *name,
unsigned char **p, unsigned char *end, char decomp);
... this allows transparent compression of dynamically generated HTTP. The requested
compression (eg, "deflate") is only applied if the client headers indicated it was
supported, otherwise it's a NOP.
Name may be NULL in which case the first compression method in the internal table at
stream.c that is mentioned as acceptable by the client will be used.
NOTE: the compression translation, same as h2 support, relies on the user code using
LWS_WRITE_HTTP and then LWS_WRITE_HTTP_FINAL on the last part written. The internal
lws fileserving code already does this.
2018-09-02 14:43:05 +08:00
|
|
|
#if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
|
|
|
|
if (wsi->http.lcs && (((*wp) & 0x1f) == LWS_WRITE_HTTP_FINAL ||
|
|
|
|
((*wp) & 0x1f) == LWS_WRITE_HTTP)) {
|
2020-01-02 08:32:23 +00:00
|
|
|
unsigned char mtubuf[1500 + LWS_PRE +
|
http: compression methods
Add generic http compression layer eanbled at cmake with LWS_WITH_HTTP_STREAM_COMPRESSION.
This is wholly a feature of the HTTP role (used by h1 and h2 roles) and doesn't exist
outside that context.
Currently provides 'deflate' and 'br' compression methods for server side only.
'br' requires also -DLWS_WITH_HTTP_BROTLI=1 at cmake and the brotli libraries (available in
your distro already) and dev package.
Other compression methods can be added nicely using an ops struct.
The built-in file serving stuff will use this is the client says he can handle it, and the
mimetype of the file either starts with "text/" (html and css etc) or is the mimetype of
Javascript.
zlib allocates quite a bit while in use, it seems to be around 256KiB per stream. So this
is only useful on relatively strong servers with lots of memory. However for some usecases
where you are serving a lot of css and js assets, it's a nice help.
The patch performs special treatment for http/1.1 pipelining, since the compression is
performed on the fly the compressed content-length is not known until the end. So for h1
only, chunked transfer-encoding is automatically added so pipelining can continue of the
connection.
For h2 the chunking is neither supported nor required, so it "just works".
User code can also request to add a compression transform before the reply headers were
sent using the new api
LWS_VISIBLE int
lws_http_compression_apply(struct lws *wsi, const char *name,
unsigned char **p, unsigned char *end, char decomp);
... this allows transparent compression of dynamically generated HTTP. The requested
compression (eg, "deflate") is only applied if the client headers indicated it was
supported, otherwise it's a NOP.
Name may be NULL in which case the first compression method in the internal table at
stream.c that is mentioned as acceptable by the client will be used.
NOTE: the compression translation, same as h2 support, relies on the user code using
LWS_WRITE_HTTP and then LWS_WRITE_HTTP_FINAL on the last part written. The internal
lws fileserving code already does this.
2018-09-02 14:43:05 +08:00
|
|
|
LWS_HTTP_CHUNK_HDR_MAX_SIZE +
|
|
|
|
LWS_HTTP_CHUNK_TRL_MAX_SIZE],
|
|
|
|
*out = mtubuf + LWS_PRE +
|
|
|
|
LWS_HTTP_CHUNK_HDR_MAX_SIZE;
|
|
|
|
size_t o = sizeof(mtubuf) - LWS_PRE -
|
|
|
|
LWS_HTTP_CHUNK_HDR_MAX_SIZE -
|
|
|
|
LWS_HTTP_CHUNK_TRL_MAX_SIZE;
|
|
|
|
|
|
|
|
n = lws_http_compression_transform(wsi, buf, len, wp, &out, &o);
|
|
|
|
if (n)
|
|
|
|
return n;
|
|
|
|
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_info("%s: %s: transformed %d bytes to %d "
|
|
|
|
"(wp 0x%x, more %d)\n", __func__,
|
|
|
|
lws_wsi_tag(wsi), (int)len,
|
http: compression methods
Add generic http compression layer eanbled at cmake with LWS_WITH_HTTP_STREAM_COMPRESSION.
This is wholly a feature of the HTTP role (used by h1 and h2 roles) and doesn't exist
outside that context.
Currently provides 'deflate' and 'br' compression methods for server side only.
'br' requires also -DLWS_WITH_HTTP_BROTLI=1 at cmake and the brotli libraries (available in
your distro already) and dev package.
Other compression methods can be added nicely using an ops struct.
The built-in file serving stuff will use this is the client says he can handle it, and the
mimetype of the file either starts with "text/" (html and css etc) or is the mimetype of
Javascript.
zlib allocates quite a bit while in use, it seems to be around 256KiB per stream. So this
is only useful on relatively strong servers with lots of memory. However for some usecases
where you are serving a lot of css and js assets, it's a nice help.
The patch performs special treatment for http/1.1 pipelining, since the compression is
performed on the fly the compressed content-length is not known until the end. So for h1
only, chunked transfer-encoding is automatically added so pipelining can continue of the
connection.
For h2 the chunking is neither supported nor required, so it "just works".
User code can also request to add a compression transform before the reply headers were
sent using the new api
LWS_VISIBLE int
lws_http_compression_apply(struct lws *wsi, const char *name,
unsigned char **p, unsigned char *end, char decomp);
... this allows transparent compression of dynamically generated HTTP. The requested
compression (eg, "deflate") is only applied if the client headers indicated it was
supported, otherwise it's a NOP.
Name may be NULL in which case the first compression method in the internal table at
stream.c that is mentioned as acceptable by the client will be used.
NOTE: the compression translation, same as h2 support, relies on the user code using
LWS_WRITE_HTTP and then LWS_WRITE_HTTP_FINAL on the last part written. The internal
lws fileserving code already does this.
2018-09-02 14:43:05 +08:00
|
|
|
(int)o, (int)*wp, wsi->http.comp_ctx.may_have_more);
|
|
|
|
|
|
|
|
if (!o)
|
2020-12-12 06:21:40 +00:00
|
|
|
return (int)olen;
|
http: compression methods
Add generic http compression layer eanbled at cmake with LWS_WITH_HTTP_STREAM_COMPRESSION.
This is wholly a feature of the HTTP role (used by h1 and h2 roles) and doesn't exist
outside that context.
Currently provides 'deflate' and 'br' compression methods for server side only.
'br' requires also -DLWS_WITH_HTTP_BROTLI=1 at cmake and the brotli libraries (available in
your distro already) and dev package.
Other compression methods can be added nicely using an ops struct.
The built-in file serving stuff will use this is the client says he can handle it, and the
mimetype of the file either starts with "text/" (html and css etc) or is the mimetype of
Javascript.
zlib allocates quite a bit while in use, it seems to be around 256KiB per stream. So this
is only useful on relatively strong servers with lots of memory. However for some usecases
where you are serving a lot of css and js assets, it's a nice help.
The patch performs special treatment for http/1.1 pipelining, since the compression is
performed on the fly the compressed content-length is not known until the end. So for h1
only, chunked transfer-encoding is automatically added so pipelining can continue of the
connection.
For h2 the chunking is neither supported nor required, so it "just works".
User code can also request to add a compression transform before the reply headers were
sent using the new api
LWS_VISIBLE int
lws_http_compression_apply(struct lws *wsi, const char *name,
unsigned char **p, unsigned char *end, char decomp);
... this allows transparent compression of dynamically generated HTTP. The requested
compression (eg, "deflate") is only applied if the client headers indicated it was
supported, otherwise it's a NOP.
Name may be NULL in which case the first compression method in the internal table at
stream.c that is mentioned as acceptable by the client will be used.
NOTE: the compression translation, same as h2 support, relies on the user code using
LWS_WRITE_HTTP and then LWS_WRITE_HTTP_FINAL on the last part written. The internal
lws fileserving code already does this.
2018-09-02 14:43:05 +08:00
|
|
|
|
|
|
|
if (wsi->http.comp_ctx.chunking) {
|
2018-10-10 13:54:43 +08:00
|
|
|
char c[LWS_HTTP_CHUNK_HDR_MAX_SIZE + 2];
|
http: compression methods
Add generic http compression layer eanbled at cmake with LWS_WITH_HTTP_STREAM_COMPRESSION.
This is wholly a feature of the HTTP role (used by h1 and h2 roles) and doesn't exist
outside that context.
Currently provides 'deflate' and 'br' compression methods for server side only.
'br' requires also -DLWS_WITH_HTTP_BROTLI=1 at cmake and the brotli libraries (available in
your distro already) and dev package.
Other compression methods can be added nicely using an ops struct.
The built-in file serving stuff will use this is the client says he can handle it, and the
mimetype of the file either starts with "text/" (html and css etc) or is the mimetype of
Javascript.
zlib allocates quite a bit while in use, it seems to be around 256KiB per stream. So this
is only useful on relatively strong servers with lots of memory. However for some usecases
where you are serving a lot of css and js assets, it's a nice help.
The patch performs special treatment for http/1.1 pipelining, since the compression is
performed on the fly the compressed content-length is not known until the end. So for h1
only, chunked transfer-encoding is automatically added so pipelining can continue of the
connection.
For h2 the chunking is neither supported nor required, so it "just works".
User code can also request to add a compression transform before the reply headers were
sent using the new api
LWS_VISIBLE int
lws_http_compression_apply(struct lws *wsi, const char *name,
unsigned char **p, unsigned char *end, char decomp);
... this allows transparent compression of dynamically generated HTTP. The requested
compression (eg, "deflate") is only applied if the client headers indicated it was
supported, otherwise it's a NOP.
Name may be NULL in which case the first compression method in the internal table at
stream.c that is mentioned as acceptable by the client will be used.
NOTE: the compression translation, same as h2 support, relies on the user code using
LWS_WRITE_HTTP and then LWS_WRITE_HTTP_FINAL on the last part written. The internal
lws fileserving code already does this.
2018-09-02 14:43:05 +08:00
|
|
|
/*
|
|
|
|
* this only needs dealing with on http/1.1 to allow
|
|
|
|
* pipelining
|
|
|
|
*/
|
|
|
|
n = lws_snprintf(c, sizeof(c), "%X\x0d\x0a", (int)o);
|
2018-09-02 14:35:37 +08:00
|
|
|
lwsl_info("%s: chunk (%d) %s", __func__, (int)o, c);
|
http: compression methods
Add generic http compression layer eanbled at cmake with LWS_WITH_HTTP_STREAM_COMPRESSION.
This is wholly a feature of the HTTP role (used by h1 and h2 roles) and doesn't exist
outside that context.
Currently provides 'deflate' and 'br' compression methods for server side only.
'br' requires also -DLWS_WITH_HTTP_BROTLI=1 at cmake and the brotli libraries (available in
your distro already) and dev package.
Other compression methods can be added nicely using an ops struct.
The built-in file serving stuff will use this is the client says he can handle it, and the
mimetype of the file either starts with "text/" (html and css etc) or is the mimetype of
Javascript.
zlib allocates quite a bit while in use, it seems to be around 256KiB per stream. So this
is only useful on relatively strong servers with lots of memory. However for some usecases
where you are serving a lot of css and js assets, it's a nice help.
The patch performs special treatment for http/1.1 pipelining, since the compression is
performed on the fly the compressed content-length is not known until the end. So for h1
only, chunked transfer-encoding is automatically added so pipelining can continue of the
connection.
For h2 the chunking is neither supported nor required, so it "just works".
User code can also request to add a compression transform before the reply headers were
sent using the new api
LWS_VISIBLE int
lws_http_compression_apply(struct lws *wsi, const char *name,
unsigned char **p, unsigned char *end, char decomp);
... this allows transparent compression of dynamically generated HTTP. The requested
compression (eg, "deflate") is only applied if the client headers indicated it was
supported, otherwise it's a NOP.
Name may be NULL in which case the first compression method in the internal table at
stream.c that is mentioned as acceptable by the client will be used.
NOTE: the compression translation, same as h2 support, relies on the user code using
LWS_WRITE_HTTP and then LWS_WRITE_HTTP_FINAL on the last part written. The internal
lws fileserving code already does this.
2018-09-02 14:43:05 +08:00
|
|
|
out -= n;
|
2020-12-12 06:21:40 +00:00
|
|
|
o += (unsigned int)n;
|
|
|
|
memcpy(out, c, (unsigned int)n);
|
http: compression methods
Add generic http compression layer eanbled at cmake with LWS_WITH_HTTP_STREAM_COMPRESSION.
This is wholly a feature of the HTTP role (used by h1 and h2 roles) and doesn't exist
outside that context.
Currently provides 'deflate' and 'br' compression methods for server side only.
'br' requires also -DLWS_WITH_HTTP_BROTLI=1 at cmake and the brotli libraries (available in
your distro already) and dev package.
Other compression methods can be added nicely using an ops struct.
The built-in file serving stuff will use this is the client says he can handle it, and the
mimetype of the file either starts with "text/" (html and css etc) or is the mimetype of
Javascript.
zlib allocates quite a bit while in use, it seems to be around 256KiB per stream. So this
is only useful on relatively strong servers with lots of memory. However for some usecases
where you are serving a lot of css and js assets, it's a nice help.
The patch performs special treatment for http/1.1 pipelining, since the compression is
performed on the fly the compressed content-length is not known until the end. So for h1
only, chunked transfer-encoding is automatically added so pipelining can continue of the
connection.
For h2 the chunking is neither supported nor required, so it "just works".
User code can also request to add a compression transform before the reply headers were
sent using the new api
LWS_VISIBLE int
lws_http_compression_apply(struct lws *wsi, const char *name,
unsigned char **p, unsigned char *end, char decomp);
... this allows transparent compression of dynamically generated HTTP. The requested
compression (eg, "deflate") is only applied if the client headers indicated it was
supported, otherwise it's a NOP.
Name may be NULL in which case the first compression method in the internal table at
stream.c that is mentioned as acceptable by the client will be used.
NOTE: the compression translation, same as h2 support, relies on the user code using
LWS_WRITE_HTTP and then LWS_WRITE_HTTP_FINAL on the last part written. The internal
lws fileserving code already does this.
2018-09-02 14:43:05 +08:00
|
|
|
out[o++] = '\x0d';
|
|
|
|
out[o++] = '\x0a';
|
|
|
|
|
|
|
|
if (((*wp) & 0x1f) == LWS_WRITE_HTTP_FINAL) {
|
2018-09-02 14:35:37 +08:00
|
|
|
lwsl_info("%s: final chunk\n", __func__);
|
http: compression methods
Add generic http compression layer eanbled at cmake with LWS_WITH_HTTP_STREAM_COMPRESSION.
This is wholly a feature of the HTTP role (used by h1 and h2 roles) and doesn't exist
outside that context.
Currently provides 'deflate' and 'br' compression methods for server side only.
'br' requires also -DLWS_WITH_HTTP_BROTLI=1 at cmake and the brotli libraries (available in
your distro already) and dev package.
Other compression methods can be added nicely using an ops struct.
The built-in file serving stuff will use this is the client says he can handle it, and the
mimetype of the file either starts with "text/" (html and css etc) or is the mimetype of
Javascript.
zlib allocates quite a bit while in use, it seems to be around 256KiB per stream. So this
is only useful on relatively strong servers with lots of memory. However for some usecases
where you are serving a lot of css and js assets, it's a nice help.
The patch performs special treatment for http/1.1 pipelining, since the compression is
performed on the fly the compressed content-length is not known until the end. So for h1
only, chunked transfer-encoding is automatically added so pipelining can continue of the
connection.
For h2 the chunking is neither supported nor required, so it "just works".
User code can also request to add a compression transform before the reply headers were
sent using the new api
LWS_VISIBLE int
lws_http_compression_apply(struct lws *wsi, const char *name,
unsigned char **p, unsigned char *end, char decomp);
... this allows transparent compression of dynamically generated HTTP. The requested
compression (eg, "deflate") is only applied if the client headers indicated it was
supported, otherwise it's a NOP.
Name may be NULL in which case the first compression method in the internal table at
stream.c that is mentioned as acceptable by the client will be used.
NOTE: the compression translation, same as h2 support, relies on the user code using
LWS_WRITE_HTTP and then LWS_WRITE_HTTP_FINAL on the last part written. The internal
lws fileserving code already does this.
2018-09-02 14:43:05 +08:00
|
|
|
out[o++] = '0';
|
|
|
|
out[o++] = '\x0d';
|
|
|
|
out[o++] = '\x0a';
|
|
|
|
out[o++] = '\x0d';
|
|
|
|
out[o++] = '\x0a';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
buf = out;
|
|
|
|
len = o;
|
2018-04-11 13:39:42 +08:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
http: compression methods
Add generic http compression layer eanbled at cmake with LWS_WITH_HTTP_STREAM_COMPRESSION.
This is wholly a feature of the HTTP role (used by h1 and h2 roles) and doesn't exist
outside that context.
Currently provides 'deflate' and 'br' compression methods for server side only.
'br' requires also -DLWS_WITH_HTTP_BROTLI=1 at cmake and the brotli libraries (available in
your distro already) and dev package.
Other compression methods can be added nicely using an ops struct.
The built-in file serving stuff will use this is the client says he can handle it, and the
mimetype of the file either starts with "text/" (html and css etc) or is the mimetype of
Javascript.
zlib allocates quite a bit while in use, it seems to be around 256KiB per stream. So this
is only useful on relatively strong servers with lots of memory. However for some usecases
where you are serving a lot of css and js assets, it's a nice help.
The patch performs special treatment for http/1.1 pipelining, since the compression is
performed on the fly the compressed content-length is not known until the end. So for h1
only, chunked transfer-encoding is automatically added so pipelining can continue of the
connection.
For h2 the chunking is neither supported nor required, so it "just works".
User code can also request to add a compression transform before the reply headers were
sent using the new api
LWS_VISIBLE int
lws_http_compression_apply(struct lws *wsi, const char *name,
unsigned char **p, unsigned char *end, char decomp);
... this allows transparent compression of dynamically generated HTTP. The requested
compression (eg, "deflate") is only applied if the client headers indicated it was
supported, otherwise it's a NOP.
Name may be NULL in which case the first compression method in the internal table at
stream.c that is mentioned as acceptable by the client will be used.
NOTE: the compression translation, same as h2 support, relies on the user code using
LWS_WRITE_HTTP and then LWS_WRITE_HTTP_FINAL on the last part written. The internal
lws fileserving code already does this.
2018-09-02 14:43:05 +08:00
|
|
|
n = lws_issue_raw(wsi, (unsigned char *)buf, len);
|
|
|
|
if (n < 0)
|
|
|
|
return n;
|
|
|
|
|
|
|
|
/* hide there may have been compression */
|
|
|
|
|
2018-08-23 11:29:45 +08:00
|
|
|
return (int)olen;
|
2018-04-11 13:39:42 +08:00
|
|
|
}
|
|
|
|
|
2018-04-12 15:56:38 +08:00
|
|
|
static int
|
|
|
|
rops_alpn_negotiated_h1(struct lws *wsi, const char *alpn)
|
|
|
|
{
|
|
|
|
lwsl_debug("%s: client %d\n", __func__, lwsi_role_client(wsi));
|
2019-08-18 05:04:15 +01:00
|
|
|
#if defined(LWS_WITH_CLIENT)
|
2018-04-12 15:56:38 +08:00
|
|
|
if (lwsi_role_client(wsi)) {
|
|
|
|
/*
|
|
|
|
* If alpn asserts it is http/1.1, server support for KA is
|
|
|
|
* mandatory.
|
|
|
|
*
|
|
|
|
* Knowing this lets us proceed with sending pipelined headers
|
|
|
|
* before we received the first response headers.
|
|
|
|
*/
|
|
|
|
wsi->keepalive_active = 1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-05-02 08:46:16 +08:00
|
|
|
static int
|
|
|
|
rops_destroy_role_h1(struct lws *wsi)
|
|
|
|
{
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
|
2018-05-02 08:46:16 +08:00
|
|
|
struct allocated_headers *ah;
|
|
|
|
|
|
|
|
/* we may not have an ah, but may be on the waiting list... */
|
|
|
|
lwsl_info("%s: ah det due to close\n", __func__);
|
|
|
|
__lws_header_table_detach(wsi, 0);
|
|
|
|
|
|
|
|
ah = pt->http.ah_list;
|
|
|
|
|
|
|
|
while (ah) {
|
|
|
|
if (ah->in_use && ah->wsi == wsi) {
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_err("%s: ah leak: wsi %s\n", __func__,
|
|
|
|
lws_wsi_tag(wsi));
|
2018-05-02 08:46:16 +08:00
|
|
|
ah->in_use = 0;
|
|
|
|
ah->wsi = NULL;
|
|
|
|
pt->http.ah_count_in_use--;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ah = ah->next;
|
|
|
|
}
|
|
|
|
|
http: compression methods
Add generic http compression layer eanbled at cmake with LWS_WITH_HTTP_STREAM_COMPRESSION.
This is wholly a feature of the HTTP role (used by h1 and h2 roles) and doesn't exist
outside that context.
Currently provides 'deflate' and 'br' compression methods for server side only.
'br' requires also -DLWS_WITH_HTTP_BROTLI=1 at cmake and the brotli libraries (available in
your distro already) and dev package.
Other compression methods can be added nicely using an ops struct.
The built-in file serving stuff will use this is the client says he can handle it, and the
mimetype of the file either starts with "text/" (html and css etc) or is the mimetype of
Javascript.
zlib allocates quite a bit while in use, it seems to be around 256KiB per stream. So this
is only useful on relatively strong servers with lots of memory. However for some usecases
where you are serving a lot of css and js assets, it's a nice help.
The patch performs special treatment for http/1.1 pipelining, since the compression is
performed on the fly the compressed content-length is not known until the end. So for h1
only, chunked transfer-encoding is automatically added so pipelining can continue of the
connection.
For h2 the chunking is neither supported nor required, so it "just works".
User code can also request to add a compression transform before the reply headers were
sent using the new api
LWS_VISIBLE int
lws_http_compression_apply(struct lws *wsi, const char *name,
unsigned char **p, unsigned char *end, char decomp);
... this allows transparent compression of dynamically generated HTTP. The requested
compression (eg, "deflate") is only applied if the client headers indicated it was
supported, otherwise it's a NOP.
Name may be NULL in which case the first compression method in the internal table at
stream.c that is mentioned as acceptable by the client will be used.
NOTE: the compression translation, same as h2 support, relies on the user code using
LWS_WRITE_HTTP and then LWS_WRITE_HTTP_FINAL on the last part written. The internal
lws fileserving code already does this.
2018-09-02 14:43:05 +08:00
|
|
|
#if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
|
|
|
|
lws_http_compression_destroy(wsi);
|
|
|
|
#endif
|
|
|
|
|
2018-06-02 05:57:26 +08:00
|
|
|
#ifdef LWS_ROLE_WS
|
|
|
|
lws_free_set_NULL(wsi->ws);
|
|
|
|
#endif
|
2018-05-02 08:46:16 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-08-18 05:04:15 +01:00
|
|
|
#if defined(LWS_WITH_SERVER)
|
2018-05-10 16:13:26 +08:00
|
|
|
|
|
|
|
static int
|
|
|
|
rops_adoption_bind_h1(struct lws *wsi, int type, const char *vh_prot_name)
|
|
|
|
{
|
|
|
|
if (!(type & LWS_ADOPT_HTTP))
|
|
|
|
return 0; /* no match */
|
|
|
|
|
2018-11-29 08:29:48 +08:00
|
|
|
if (type & _LWS_ADOPT_FINISH && !lwsi_role_http(wsi))
|
|
|
|
return 0;
|
2018-05-10 16:13:26 +08:00
|
|
|
|
|
|
|
if (type & _LWS_ADOPT_FINISH) {
|
|
|
|
if (!lws_header_table_attach(wsi, 0))
|
|
|
|
lwsl_debug("Attached ah immediately\n");
|
|
|
|
else
|
|
|
|
lwsl_info("%s: waiting for ah\n", __func__);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2020-07-28 09:21:45 +01:00
|
|
|
#if defined(LWS_WITH_SERVER) && defined(LWS_WITH_SECURE_STREAMS)
|
|
|
|
if (wsi->a.vhost->ss_handle &&
|
|
|
|
wsi->a.vhost->ss_handle->policy->protocol == LWSSSP_RAW) {
|
|
|
|
lws_role_transition(wsi, LWSIFR_SERVER, (type & LWS_ADOPT_ALLOW_SSL) ?
|
|
|
|
LRS_SSL_INIT : LRS_ESTABLISHED, &role_ops_raw_skt);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2020-05-07 15:21:48 -07:00
|
|
|
/* If Non-TLS and HTTP2 prior knowledge is enabled, skip to clear text HTTP2 */
|
|
|
|
|
|
|
|
#if defined(LWS_WITH_HTTP2)
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
if ((!(type & LWS_ADOPT_ALLOW_SSL)) && (wsi->a.vhost->options & LWS_SERVER_OPTION_H2_PRIOR_KNOWLEDGE)) {
|
2020-05-07 15:21:48 -07:00
|
|
|
lwsl_info("http/2 prior knowledge\n");
|
2021-01-06 15:08:22 +00:00
|
|
|
lws_metrics_tag_wsi_add(wsi, "upg", "h2_prior");
|
2020-05-07 15:21:48 -07:00
|
|
|
lws_role_call_alpn_negotiated(wsi, "h2");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
lws_role_transition(wsi, LWSIFR_SERVER, (type & LWS_ADOPT_ALLOW_SSL) ?
|
|
|
|
LRS_SSL_INIT : LRS_HEADERS, &role_ops_h1);
|
2018-05-10 16:13:26 +08:00
|
|
|
|
2019-02-22 14:27:21 +08:00
|
|
|
/*
|
2020-05-07 15:21:48 -07:00
|
|
|
* Otherwise, we have to bind to h1 as a default even when we're actually going to
|
2019-02-22 14:27:21 +08:00
|
|
|
* replace it as an h2 bind later. So don't take this seriously if the
|
|
|
|
* default is disabled (ws upgrade caees properly about it)
|
|
|
|
*/
|
|
|
|
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
if (!vh_prot_name && wsi->a.vhost->default_protocol_index <
|
|
|
|
wsi->a.vhost->count_protocols)
|
|
|
|
wsi->a.protocol = &wsi->a.vhost->protocols[
|
|
|
|
wsi->a.vhost->default_protocol_index];
|
2019-02-22 14:27:21 +08:00
|
|
|
else
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
wsi->a.protocol = &wsi->a.vhost->protocols[0];
|
2018-05-10 16:13:26 +08:00
|
|
|
|
|
|
|
/* the transport is accepted... give him time to negotiate */
|
|
|
|
lws_set_timeout(wsi, PENDING_TIMEOUT_ESTABLISH_WITH_SERVER,
|
2020-12-12 06:21:40 +00:00
|
|
|
(int)wsi->a.context->timeout_secs);
|
2018-05-10 16:13:26 +08:00
|
|
|
|
|
|
|
return 1; /* bound */
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2019-08-18 05:04:15 +01:00
|
|
|
#if defined(LWS_WITH_CLIENT)
|
2018-05-10 16:13:26 +08:00
|
|
|
|
|
|
|
static const char * const http_methods[] = {
|
2020-01-21 12:59:46 +00:00
|
|
|
"GET", "POST", "OPTIONS", "HEAD", "PUT", "PATCH", "DELETE", "CONNECT"
|
2018-05-10 16:13:26 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
static int
|
|
|
|
rops_client_bind_h1(struct lws *wsi, const struct lws_client_connect_info *i)
|
|
|
|
{
|
|
|
|
int n;
|
|
|
|
|
|
|
|
if (!i) {
|
|
|
|
/* we are finalizing an already-selected role */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we stay in http, assuming there wasn't already-set
|
|
|
|
* external user_space, since we know our initial protocol
|
|
|
|
* we can assign the user space now, otherwise do it after the
|
|
|
|
* ws subprotocol negotiated
|
|
|
|
*/
|
2019-08-17 20:46:53 +01:00
|
|
|
if (!wsi->user_space && wsi->stash->cis[CIS_METHOD])
|
2018-05-10 16:13:26 +08:00
|
|
|
if (lws_ensure_user_space(wsi))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* For ws, default to http/1.1 only. If i->alpn had been set
|
|
|
|
* though, defer to whatever he has set in there (eg, "h2").
|
|
|
|
*
|
|
|
|
* The problem is he has to commit to h2 before he can find
|
|
|
|
* out if the server has the SETTINGS for ws-over-h2 enabled;
|
|
|
|
* if not then ws is not possible on that connection. So we
|
|
|
|
* only try h2 if he assertively said to use h2 alpn, otherwise
|
|
|
|
* ws implies alpn restriction to h1.
|
|
|
|
*/
|
2019-08-17 20:46:53 +01:00
|
|
|
if (!wsi->stash->cis[CIS_METHOD] && !wsi->stash->cis[CIS_ALPN])
|
|
|
|
wsi->stash->cis[CIS_ALPN] = "http/1.1";
|
2018-05-10 16:13:26 +08:00
|
|
|
|
|
|
|
/* if we went on the ah waiting list, it's ok, we can wait.
|
|
|
|
*
|
|
|
|
* When we do get the ah, now or later, he will end up at
|
|
|
|
* lws_http_client_connect_via_info2().
|
|
|
|
*/
|
2019-07-13 11:32:15 -07:00
|
|
|
if (lws_header_table_attach(wsi, 0)
|
2019-08-18 05:04:15 +01:00
|
|
|
#if defined(LWS_WITH_CLIENT)
|
2019-07-13 11:32:15 -07:00
|
|
|
< 0)
|
2018-05-10 16:13:26 +08:00
|
|
|
/*
|
|
|
|
* if we failed here, the connection is already closed
|
|
|
|
* and freed.
|
|
|
|
*/
|
|
|
|
return -1;
|
2019-07-13 11:32:15 -07:00
|
|
|
#else
|
|
|
|
)
|
|
|
|
return 0;
|
|
|
|
#endif
|
2018-05-10 16:13:26 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Clients that want to be h1, h2, or ws all start out as h1
|
2020-01-02 08:32:23 +00:00
|
|
|
* (we don't yet know if the server supports h2 or ws), unless their
|
|
|
|
* alpn is only "h2"
|
2018-05-10 16:13:26 +08:00
|
|
|
*/
|
|
|
|
|
2020-01-02 08:32:23 +00:00
|
|
|
// if (i->alpn && !strcmp(i->alpn, "h2"))
|
|
|
|
// return 0; /* we are h1, he only wants h2 */
|
|
|
|
|
2018-05-10 16:13:26 +08:00
|
|
|
if (!i->method) { /* websockets */
|
|
|
|
#if defined(LWS_ROLE_WS)
|
|
|
|
if (lws_create_client_ws_object(i, wsi))
|
|
|
|
goto fail_wsi;
|
2020-08-19 06:46:19 +01:00
|
|
|
|
|
|
|
goto bind_h1;
|
2018-05-10 16:13:26 +08:00
|
|
|
#else
|
|
|
|
lwsl_err("%s: ws role not configured\n", __func__);
|
|
|
|
|
|
|
|
goto fail_wsi;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if a recognized http method, bind to it */
|
|
|
|
|
|
|
|
for (n = 0; n < (int)LWS_ARRAY_SIZE(http_methods); n++)
|
|
|
|
if (!strcmp(i->method, http_methods[n]))
|
|
|
|
goto bind_h1;
|
|
|
|
|
|
|
|
/* other roles may bind to it */
|
|
|
|
|
|
|
|
return 0; /* no match */
|
|
|
|
|
|
|
|
bind_h1:
|
|
|
|
/* assert the mode and union status (hdr) clearly */
|
|
|
|
lws_role_transition(wsi, LWSIFR_CLIENT, LRS_UNCONNECTED, &role_ops_h1);
|
|
|
|
|
|
|
|
return 1; /* matched */
|
|
|
|
|
|
|
|
fail_wsi:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2018-09-04 08:06:46 +08:00
|
|
|
static int
|
|
|
|
rops_close_kill_connection_h1(struct lws *wsi, enum lws_close_status reason)
|
|
|
|
{
|
|
|
|
#if defined(LWS_WITH_HTTP_PROXY)
|
2020-01-30 13:19:11 +00:00
|
|
|
if (!wsi->http.proxy_clientside)
|
2018-09-04 08:06:46 +08:00
|
|
|
return 0;
|
|
|
|
|
2020-01-30 13:19:11 +00:00
|
|
|
wsi->http.proxy_clientside = 0;
|
2018-09-04 08:06:46 +08:00
|
|
|
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
if (user_callback_handle_rxflow(wsi->a.protocol->callback, wsi,
|
2018-09-04 08:06:46 +08:00
|
|
|
LWS_CALLBACK_COMPLETED_CLIENT_HTTP,
|
2020-01-30 13:19:11 +00:00
|
|
|
wsi->user_space, NULL, 0))
|
2018-09-04 08:06:46 +08:00
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-08-09 10:12:09 +01:00
|
|
|
int
|
2019-09-18 13:09:32 +01:00
|
|
|
rops_pt_init_destroy_h1(struct lws_context *context,
|
|
|
|
const struct lws_context_creation_info *info,
|
|
|
|
struct lws_context_per_thread *pt, int destroy)
|
2019-08-09 10:12:09 +01:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* We only want to do this once... we will do it if no h2 support
|
|
|
|
* otherwise let h2 ops do it.
|
|
|
|
*/
|
2019-08-18 05:04:15 +01:00
|
|
|
#if !defined(LWS_ROLE_H2) && defined(LWS_WITH_SERVER)
|
2019-09-18 13:09:32 +01:00
|
|
|
if (!destroy) {
|
2019-08-09 10:12:09 +01:00
|
|
|
|
|
|
|
pt->sul_ah_lifecheck.cb = lws_sul_http_ah_lifecheck;
|
|
|
|
|
2020-08-22 18:52:13 +01:00
|
|
|
__lws_sul_insert_us(&pt->pt_sul_owner[LWSSULLI_MISS_IF_SUSPENDED],
|
|
|
|
&pt->sul_ah_lifecheck, 30 * LWS_US_PER_SEC);
|
2019-09-18 13:09:32 +01:00
|
|
|
} else
|
|
|
|
lws_dll2_remove(&pt->sul_ah_lifecheck.list);
|
2019-08-09 10:12:09 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2018-09-04 08:06:46 +08:00
|
|
|
|
roles: compress role ops structs
role ops are usually only sparsely filled, there are currently 20
function pointers but several roles only fill in two. No single
role has more than 14 of the ops. On a 32/64 bit build this part
of the ops struct takes a fixed 80 / 160 bytes then.
First reduce the type of the callback reason part from uint16_t to
uint8_t, this saves 12 bytes unconditionally.
Change to a separate function pointer array with a nybble index
array, it costs 10 bytes for the index and a pointer to the
separate array, for 32-bit the cost is
2 + (4 x ops_used)
and for 64-bit
6 + (8 x ops_used)
for 2 x ops_used it means 32-bit: 10 vs 80 / 64-bit: 22 vs 160
For a typical system with h1 (9), h2 (14), listen (2), netlink (2),
pipe (1), raw_skt (3), ws (12), == 43 ops_used out of 140, it means
the .rodata for this reduced from 32-bit: 560 -> 174 (386 byte
saving) and 64-bit: 1120 -> 350 (770 byte saving)
This doesn't account for the changed function ops calling code, two
ways were tried, a preprocessor macro and explicit functions
For an x86_64 gcc 10 build with most options, release mode,
.text + .rodata
before patch: 553282
accessor macro: 552714 (568 byte saving)
accessor functions: 553674 (392 bytes worse than without patch)
therefore we went with the macros
2020-10-19 13:55:21 +01:00
|
|
|
static const lws_rops_t rops_table_h1[] = {
|
|
|
|
/* 1 */ { .pt_init_destroy = rops_pt_init_destroy_h1 },
|
|
|
|
/* 2 */ { .handle_POLLIN = rops_handle_POLLIN_h1 },
|
|
|
|
/* 3 */ { .handle_POLLOUT = rops_handle_POLLOUT_h1 },
|
|
|
|
/* 4 */ { .write_role_protocol = rops_write_role_protocol_h1 },
|
|
|
|
/* 5 */ { .alpn_negotiated = rops_alpn_negotiated_h1 },
|
|
|
|
/* 6 */ { .close_kill_connection = rops_close_kill_connection_h1 },
|
|
|
|
/* 7 */ { .destroy_role = rops_destroy_role_h1 },
|
|
|
|
#if defined(LWS_WITH_SERVER)
|
|
|
|
/* 8 */ { .adoption_bind = rops_adoption_bind_h1 },
|
|
|
|
#endif
|
|
|
|
#if defined(LWS_WITH_CLIENT)
|
|
|
|
/* 8 if client and no server */
|
|
|
|
/* 9 */ { .client_bind = rops_client_bind_h1 },
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
2020-01-15 06:31:19 +00:00
|
|
|
const struct lws_role_ops role_ops_h1 = {
|
2018-04-12 15:56:38 +08:00
|
|
|
/* role name */ "h1",
|
|
|
|
/* alpn id */ "http/1.1",
|
roles: compress role ops structs
role ops are usually only sparsely filled, there are currently 20
function pointers but several roles only fill in two. No single
role has more than 14 of the ops. On a 32/64 bit build this part
of the ops struct takes a fixed 80 / 160 bytes then.
First reduce the type of the callback reason part from uint16_t to
uint8_t, this saves 12 bytes unconditionally.
Change to a separate function pointer array with a nybble index
array, it costs 10 bytes for the index and a pointer to the
separate array, for 32-bit the cost is
2 + (4 x ops_used)
and for 64-bit
6 + (8 x ops_used)
for 2 x ops_used it means 32-bit: 10 vs 80 / 64-bit: 22 vs 160
For a typical system with h1 (9), h2 (14), listen (2), netlink (2),
pipe (1), raw_skt (3), ws (12), == 43 ops_used out of 140, it means
the .rodata for this reduced from 32-bit: 560 -> 174 (386 byte
saving) and 64-bit: 1120 -> 350 (770 byte saving)
This doesn't account for the changed function ops calling code, two
ways were tried, a preprocessor macro and explicit functions
For an x86_64 gcc 10 build with most options, release mode,
.text + .rodata
before patch: 553282
accessor macro: 552714 (568 byte saving)
accessor functions: 553674 (392 bytes worse than without patch)
therefore we went with the macros
2020-10-19 13:55:21 +01:00
|
|
|
/* rops_table */ rops_table_h1,
|
|
|
|
/* rops_idx */ {
|
|
|
|
/* LWS_ROPS_check_upgrades */
|
|
|
|
/* LWS_ROPS_pt_init_destroy */ 0x01,
|
|
|
|
/* LWS_ROPS_init_vhost */
|
|
|
|
/* LWS_ROPS_destroy_vhost */ 0x00,
|
|
|
|
/* LWS_ROPS_service_flag_pending */
|
|
|
|
/* LWS_ROPS_handle_POLLIN */ 0x02,
|
|
|
|
/* LWS_ROPS_handle_POLLOUT */
|
|
|
|
/* LWS_ROPS_perform_user_POLLOUT */ 0x30,
|
|
|
|
/* LWS_ROPS_callback_on_writable */
|
|
|
|
/* LWS_ROPS_tx_credit */ 0x00,
|
|
|
|
/* LWS_ROPS_write_role_protocol */
|
|
|
|
/* LWS_ROPS_encapsulation_parent */ 0x40,
|
|
|
|
/* LWS_ROPS_alpn_negotiated */
|
|
|
|
/* LWS_ROPS_close_via_role_protocol */ 0x50,
|
|
|
|
/* LWS_ROPS_close_role */
|
|
|
|
/* LWS_ROPS_close_kill_connection */ 0x06,
|
|
|
|
/* LWS_ROPS_destroy_role */
|
2019-08-18 05:04:15 +01:00
|
|
|
#if defined(LWS_WITH_SERVER)
|
roles: compress role ops structs
role ops are usually only sparsely filled, there are currently 20
function pointers but several roles only fill in two. No single
role has more than 14 of the ops. On a 32/64 bit build this part
of the ops struct takes a fixed 80 / 160 bytes then.
First reduce the type of the callback reason part from uint16_t to
uint8_t, this saves 12 bytes unconditionally.
Change to a separate function pointer array with a nybble index
array, it costs 10 bytes for the index and a pointer to the
separate array, for 32-bit the cost is
2 + (4 x ops_used)
and for 64-bit
6 + (8 x ops_used)
for 2 x ops_used it means 32-bit: 10 vs 80 / 64-bit: 22 vs 160
For a typical system with h1 (9), h2 (14), listen (2), netlink (2),
pipe (1), raw_skt (3), ws (12), == 43 ops_used out of 140, it means
the .rodata for this reduced from 32-bit: 560 -> 174 (386 byte
saving) and 64-bit: 1120 -> 350 (770 byte saving)
This doesn't account for the changed function ops calling code, two
ways were tried, a preprocessor macro and explicit functions
For an x86_64 gcc 10 build with most options, release mode,
.text + .rodata
before patch: 553282
accessor macro: 552714 (568 byte saving)
accessor functions: 553674 (392 bytes worse than without patch)
therefore we went with the macros
2020-10-19 13:55:21 +01:00
|
|
|
/* LWS_ROPS_adoption_bind */ 0x78,
|
2018-05-10 16:13:26 +08:00
|
|
|
#else
|
roles: compress role ops structs
role ops are usually only sparsely filled, there are currently 20
function pointers but several roles only fill in two. No single
role has more than 14 of the ops. On a 32/64 bit build this part
of the ops struct takes a fixed 80 / 160 bytes then.
First reduce the type of the callback reason part from uint16_t to
uint8_t, this saves 12 bytes unconditionally.
Change to a separate function pointer array with a nybble index
array, it costs 10 bytes for the index and a pointer to the
separate array, for 32-bit the cost is
2 + (4 x ops_used)
and for 64-bit
6 + (8 x ops_used)
for 2 x ops_used it means 32-bit: 10 vs 80 / 64-bit: 22 vs 160
For a typical system with h1 (9), h2 (14), listen (2), netlink (2),
pipe (1), raw_skt (3), ws (12), == 43 ops_used out of 140, it means
the .rodata for this reduced from 32-bit: 560 -> 174 (386 byte
saving) and 64-bit: 1120 -> 350 (770 byte saving)
This doesn't account for the changed function ops calling code, two
ways were tried, a preprocessor macro and explicit functions
For an x86_64 gcc 10 build with most options, release mode,
.text + .rodata
before patch: 553282
accessor macro: 552714 (568 byte saving)
accessor functions: 553674 (392 bytes worse than without patch)
therefore we went with the macros
2020-10-19 13:55:21 +01:00
|
|
|
/* LWS_ROPS_adoption_bind */ 0x70,
|
2018-05-10 16:13:26 +08:00
|
|
|
#endif
|
roles: compress role ops structs
role ops are usually only sparsely filled, there are currently 20
function pointers but several roles only fill in two. No single
role has more than 14 of the ops. On a 32/64 bit build this part
of the ops struct takes a fixed 80 / 160 bytes then.
First reduce the type of the callback reason part from uint16_t to
uint8_t, this saves 12 bytes unconditionally.
Change to a separate function pointer array with a nybble index
array, it costs 10 bytes for the index and a pointer to the
separate array, for 32-bit the cost is
2 + (4 x ops_used)
and for 64-bit
6 + (8 x ops_used)
for 2 x ops_used it means 32-bit: 10 vs 80 / 64-bit: 22 vs 160
For a typical system with h1 (9), h2 (14), listen (2), netlink (2),
pipe (1), raw_skt (3), ws (12), == 43 ops_used out of 140, it means
the .rodata for this reduced from 32-bit: 560 -> 174 (386 byte
saving) and 64-bit: 1120 -> 350 (770 byte saving)
This doesn't account for the changed function ops calling code, two
ways were tried, a preprocessor macro and explicit functions
For an x86_64 gcc 10 build with most options, release mode,
.text + .rodata
before patch: 553282
accessor macro: 552714 (568 byte saving)
accessor functions: 553674 (392 bytes worse than without patch)
therefore we went with the macros
2020-10-19 13:55:21 +01:00
|
|
|
/* LWS_ROPS_client_bind */
|
2019-08-18 05:04:15 +01:00
|
|
|
#if defined(LWS_WITH_CLIENT)
|
roles: compress role ops structs
role ops are usually only sparsely filled, there are currently 20
function pointers but several roles only fill in two. No single
role has more than 14 of the ops. On a 32/64 bit build this part
of the ops struct takes a fixed 80 / 160 bytes then.
First reduce the type of the callback reason part from uint16_t to
uint8_t, this saves 12 bytes unconditionally.
Change to a separate function pointer array with a nybble index
array, it costs 10 bytes for the index and a pointer to the
separate array, for 32-bit the cost is
2 + (4 x ops_used)
and for 64-bit
6 + (8 x ops_used)
for 2 x ops_used it means 32-bit: 10 vs 80 / 64-bit: 22 vs 160
For a typical system with h1 (9), h2 (14), listen (2), netlink (2),
pipe (1), raw_skt (3), ws (12), == 43 ops_used out of 140, it means
the .rodata for this reduced from 32-bit: 560 -> 174 (386 byte
saving) and 64-bit: 1120 -> 350 (770 byte saving)
This doesn't account for the changed function ops calling code, two
ways were tried, a preprocessor macro and explicit functions
For an x86_64 gcc 10 build with most options, release mode,
.text + .rodata
before patch: 553282
accessor macro: 552714 (568 byte saving)
accessor functions: 553674 (392 bytes worse than without patch)
therefore we went with the macros
2020-10-19 13:55:21 +01:00
|
|
|
#if defined(LWS_WITH_SERVER)
|
|
|
|
/* LWS_ROPS_issue_keepalive */ 0x90,
|
|
|
|
#else
|
|
|
|
/* LWS_ROPS_issue_keepalive */ 0x80,
|
|
|
|
#endif
|
2018-05-10 16:13:26 +08:00
|
|
|
#else
|
roles: compress role ops structs
role ops are usually only sparsely filled, there are currently 20
function pointers but several roles only fill in two. No single
role has more than 14 of the ops. On a 32/64 bit build this part
of the ops struct takes a fixed 80 / 160 bytes then.
First reduce the type of the callback reason part from uint16_t to
uint8_t, this saves 12 bytes unconditionally.
Change to a separate function pointer array with a nybble index
array, it costs 10 bytes for the index and a pointer to the
separate array, for 32-bit the cost is
2 + (4 x ops_used)
and for 64-bit
6 + (8 x ops_used)
for 2 x ops_used it means 32-bit: 10 vs 80 / 64-bit: 22 vs 160
For a typical system with h1 (9), h2 (14), listen (2), netlink (2),
pipe (1), raw_skt (3), ws (12), == 43 ops_used out of 140, it means
the .rodata for this reduced from 32-bit: 560 -> 174 (386 byte
saving) and 64-bit: 1120 -> 350 (770 byte saving)
This doesn't account for the changed function ops calling code, two
ways were tried, a preprocessor macro and explicit functions
For an x86_64 gcc 10 build with most options, release mode,
.text + .rodata
before patch: 553282
accessor macro: 552714 (568 byte saving)
accessor functions: 553674 (392 bytes worse than without patch)
therefore we went with the macros
2020-10-19 13:55:21 +01:00
|
|
|
/* LWS_ROPS_issue_keepalive */ 0x00,
|
2018-05-10 16:13:26 +08:00
|
|
|
#endif
|
roles: compress role ops structs
role ops are usually only sparsely filled, there are currently 20
function pointers but several roles only fill in two. No single
role has more than 14 of the ops. On a 32/64 bit build this part
of the ops struct takes a fixed 80 / 160 bytes then.
First reduce the type of the callback reason part from uint16_t to
uint8_t, this saves 12 bytes unconditionally.
Change to a separate function pointer array with a nybble index
array, it costs 10 bytes for the index and a pointer to the
separate array, for 32-bit the cost is
2 + (4 x ops_used)
and for 64-bit
6 + (8 x ops_used)
for 2 x ops_used it means 32-bit: 10 vs 80 / 64-bit: 22 vs 160
For a typical system with h1 (9), h2 (14), listen (2), netlink (2),
pipe (1), raw_skt (3), ws (12), == 43 ops_used out of 140, it means
the .rodata for this reduced from 32-bit: 560 -> 174 (386 byte
saving) and 64-bit: 1120 -> 350 (770 byte saving)
This doesn't account for the changed function ops calling code, two
ways were tried, a preprocessor macro and explicit functions
For an x86_64 gcc 10 build with most options, release mode,
.text + .rodata
before patch: 553282
accessor macro: 552714 (568 byte saving)
accessor functions: 553674 (392 bytes worse than without patch)
therefore we went with the macros
2020-10-19 13:55:21 +01:00
|
|
|
},
|
2018-11-29 08:29:48 +08:00
|
|
|
/* adoption_cb clnt, srv */ { LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED,
|
|
|
|
LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED },
|
|
|
|
/* rx_cb clnt, srv */ { LWS_CALLBACK_RECEIVE_CLIENT_HTTP,
|
|
|
|
0 /* may be POST, etc */ },
|
2018-04-11 13:39:42 +08:00
|
|
|
/* writeable cb clnt, srv */ { LWS_CALLBACK_CLIENT_HTTP_WRITEABLE,
|
|
|
|
LWS_CALLBACK_HTTP_WRITEABLE },
|
|
|
|
/* close cb clnt, srv */ { LWS_CALLBACK_CLOSED_CLIENT_HTTP,
|
|
|
|
LWS_CALLBACK_CLOSED_HTTP },
|
2018-08-18 14:11:29 +08:00
|
|
|
/* protocol_bind cb c, srv */ { LWS_CALLBACK_CLIENT_HTTP_BIND_PROTOCOL,
|
|
|
|
LWS_CALLBACK_HTTP_BIND_PROTOCOL },
|
|
|
|
/* protocol_unbind cb c, srv */ { LWS_CALLBACK_CLIENT_HTTP_DROP_PROTOCOL,
|
|
|
|
LWS_CALLBACK_HTTP_DROP_PROTOCOL },
|
2018-04-29 10:44:36 +08:00
|
|
|
/* file_handle */ 0,
|
2018-04-11 13:39:42 +08:00
|
|
|
};
|