2013-01-16 11:53:05 +08:00
|
|
|
/*
|
2019-08-14 10:44:14 +01:00
|
|
|
* libwebsockets - small server side websockets and web server implementation
|
2013-01-16 11:53:05 +08:00
|
|
|
*
|
2023-12-20 06:49:51 +00:00
|
|
|
* Copyright (C) 2010 - 2023 Andy Green <andy@warmcat.com>
|
2013-01-16 11:53:05 +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:
|
2013-01-16 11:53:05 +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.
|
2013-01-16 11:53:05 +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.
|
2013-01-16 11:53:05 +08:00
|
|
|
*/
|
|
|
|
|
2019-08-15 10:49:52 +01:00
|
|
|
#include "private-lib-core.h"
|
2013-01-16 11:53:05 +08:00
|
|
|
|
2020-01-02 08:32:23 +00:00
|
|
|
void
|
2016-08-08 21:54:30 +08:00
|
|
|
lws_client_http_body_pending(struct lws *wsi, int something_left_to_send)
|
|
|
|
{
|
|
|
|
wsi->client_http_body_pending = !!something_left_to_send;
|
|
|
|
}
|
|
|
|
|
ah http1.1 deal with pipelined headers properly
Connections must hold an ah for the whole time they are
processing one header set, even if eg, the headers are
fragmented and it involves network roundtrip times.
However on http1.1 / keepalive, it must drop the ah when
there are no more header sets to deal with, and reacquire
the ah later when more data appears. It's because the
time between header sets / http1.1 requests is unbounded
and the ah would be tied up forever.
But in the case that we got pipelined http1.1 requests,
even partial already buffered, we must keep the ah,
resetting it instead of dropping it. Because we store
the rx data conveniently in a per-tsi buffer since it only
does one thing at a time per thread, we cannot go back to
the event loop to await a new ah inside one service action.
But no problem since we definitely already have an ah,
let's just reuse it at http completion time if more rx is
already buffered.
NB: attack.sh makes request with echo | nc, this
accidentally sends a trailing '\n' from the echo showing
this problem. With this patch attack.sh can complete well.
Signed-off-by: Andy Green <andy.green@linaro.org>
2016-01-30 11:43:10 +08:00
|
|
|
int
|
2020-09-19 13:27:33 +01:00
|
|
|
lws_http_client_socket_service(struct lws *wsi, struct lws_pollfd *pollfd)
|
2013-01-16 11:53:05 +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
|
|
|
struct lws_context *context = wsi->a.context;
|
2016-01-19 03:34:24 +08:00
|
|
|
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
2018-03-25 07:03:10 +08:00
|
|
|
char *p = (char *)&pt->serv_buf[0];
|
2018-04-11 13:39:42 +08:00
|
|
|
#if defined(LWS_WITH_TLS)
|
2018-03-25 07:03:10 +08:00
|
|
|
char ebuf[128];
|
|
|
|
#endif
|
2016-07-01 08:54:39 +08:00
|
|
|
const char *cce = NULL;
|
|
|
|
char *sb = p;
|
2017-09-01 15:37:53 +08:00
|
|
|
int n = 0;
|
2013-01-16 11:53:05 +08:00
|
|
|
|
2018-04-02 11:55:17 +08:00
|
|
|
switch (lwsi_state(wsi)) {
|
2013-01-16 11:53:05 +08:00
|
|
|
|
2019-09-19 06:54:53 +01:00
|
|
|
case LRS_WAITING_DNS:
|
2013-09-20 20:26:12 +08:00
|
|
|
/*
|
|
|
|
* we are under PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE
|
|
|
|
* timeout protection set in client-handshake.c
|
|
|
|
*/
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_err("%s: %s: WAITING_DNS\n", __func__, lws_wsi_tag(wsi));
|
2019-09-19 06:54:53 +01:00
|
|
|
if (!lws_client_connect_2_dnsreq(wsi)) {
|
2013-09-20 20:26:12 +08:00
|
|
|
/* closed */
|
|
|
|
lwsl_client("closed\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* either still pending connection, or changed mode */
|
|
|
|
return 0;
|
2019-08-23 16:10:36 +01:00
|
|
|
|
2019-09-19 06:54:53 +01:00
|
|
|
case LRS_WAITING_CONNECT:
|
|
|
|
|
|
|
|
/*
|
|
|
|
* we are under PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE
|
|
|
|
* timeout protection set in client-handshake.c
|
|
|
|
*/
|
|
|
|
if (pollfd->revents & LWS_POLLOUT)
|
2021-01-06 15:08:22 +00:00
|
|
|
if (lws_client_connect_3_connect(wsi, NULL, NULL, 0, NULL) == NULL) {
|
|
|
|
lwsl_client("closed\n");
|
|
|
|
return -1;
|
|
|
|
}
|
2019-09-19 06:54:53 +01:00
|
|
|
break;
|
2013-09-20 20:26:12 +08:00
|
|
|
|
2017-05-05 11:38:34 -04:00
|
|
|
#if defined(LWS_WITH_SOCKS5)
|
|
|
|
/* SOCKS Greeting Reply */
|
2018-04-02 11:55:17 +08:00
|
|
|
case LRS_WAITING_SOCKS_GREETING_REPLY:
|
|
|
|
case LRS_WAITING_SOCKS_AUTH_REPLY:
|
|
|
|
case LRS_WAITING_SOCKS_CONNECT_REPLY:
|
2017-05-05 11:38:34 -04:00
|
|
|
|
2020-02-18 14:27:27 +00:00
|
|
|
switch (lws_socks5c_handle_state(wsi, pollfd, &cce)) {
|
|
|
|
case LW5CHS_RET_RET0:
|
|
|
|
return 0;
|
|
|
|
case LW5CHS_RET_BAIL3:
|
2017-09-01 19:09:47 +08:00
|
|
|
goto bail3;
|
2020-02-18 14:27:27 +00:00
|
|
|
case LW5CHS_RET_STARTHS:
|
2017-09-01 19:09:47 +08:00
|
|
|
goto start_ws_handshake;
|
2018-05-25 21:43:31 +08:00
|
|
|
default:
|
|
|
|
break;
|
2017-09-01 19:09:47 +08:00
|
|
|
}
|
|
|
|
break;
|
2017-05-05 11:38:34 -04:00
|
|
|
#endif
|
2017-09-01 19:09:47 +08:00
|
|
|
|
2020-02-28 09:29:25 +00:00
|
|
|
#if defined(LWS_CLIENT_HTTP_PROXYING) && (defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2))
|
|
|
|
|
2018-04-02 11:55:17 +08:00
|
|
|
case LRS_WAITING_PROXY_REPLY:
|
2013-01-16 11:53:05 +08:00
|
|
|
|
|
|
|
/* handle proxy hung up on us */
|
|
|
|
|
2014-03-30 09:18:05 +02:00
|
|
|
if (pollfd->revents & LWS_POLLHUP) {
|
2013-01-16 11:53:05 +08:00
|
|
|
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_warn("Proxy conn %s (fd=%d) dead\n",
|
|
|
|
lws_wsi_tag(wsi), pollfd->fd);
|
2013-01-16 11:53:05 +08:00
|
|
|
|
2019-07-24 16:48:24 -07:00
|
|
|
cce = "proxy conn dead";
|
2017-09-01 19:09:47 +08:00
|
|
|
goto bail3;
|
2013-01-16 11:53:05 +08:00
|
|
|
}
|
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
n = (int)recv(wsi->desc.sockfd, sb, context->pt_serv_buf_size, 0);
|
2013-01-16 11:53:05 +08:00
|
|
|
if (n < 0) {
|
2014-02-28 12:37:52 +01:00
|
|
|
if (LWS_ERRNO == LWS_EAGAIN) {
|
2017-11-16 09:37:04 +08:00
|
|
|
lwsl_debug("Proxy read EAGAIN... retrying\n");
|
2013-10-25 15:50:21 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2013-01-16 11:53:05 +08:00
|
|
|
lwsl_err("ERROR reading from proxy socket\n");
|
2019-07-24 16:48:24 -07:00
|
|
|
cce = "proxy read err";
|
2017-09-01 19:09:47 +08:00
|
|
|
goto bail3;
|
2013-01-16 11:53:05 +08:00
|
|
|
}
|
|
|
|
|
2021-03-18 10:13:12 +00:00
|
|
|
/* sanity check what we were sent... */
|
|
|
|
|
2016-01-19 03:34:24 +08:00
|
|
|
pt->serv_buf[13] = '\0';
|
2021-03-18 10:13:12 +00:00
|
|
|
if (n < 13 || strncmp(sb, "HTTP/1.", 7) ||
|
|
|
|
(sb[7] != '0' && sb[7] != '1') || sb[8] != ' ') {
|
2019-11-15 08:28:50 +00:00
|
|
|
/* lwsl_hexdump_notice(sb, n); */
|
2021-03-18 10:13:12 +00:00
|
|
|
cce = "http_proxy fail";
|
|
|
|
goto bail3;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* it's h1 alright... what's his logical response code? */
|
|
|
|
n = atoi(&sb[9]);
|
|
|
|
if (n != 200) {
|
|
|
|
lws_snprintf(sb, 20, "http_proxy -> %u",
|
|
|
|
(unsigned int)n);
|
|
|
|
cce = sb;
|
2017-09-01 19:09:47 +08:00
|
|
|
goto bail3;
|
2013-01-16 11:53:05 +08:00
|
|
|
}
|
|
|
|
|
2019-11-15 08:28:50 +00:00
|
|
|
lwsl_info("%s: proxy connection extablished\n", __func__);
|
|
|
|
|
2013-01-16 11:53:05 +08:00
|
|
|
/* clear his proxy connection timeout */
|
|
|
|
|
2015-12-04 08:43:54 +08:00
|
|
|
lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
|
2013-01-16 11:53:05 +08:00
|
|
|
|
2021-06-24 17:25:38 +01:00
|
|
|
/* fallthru */
|
2013-01-16 11:53:05 +08:00
|
|
|
|
2020-02-28 09:29:25 +00:00
|
|
|
#endif
|
|
|
|
|
2021-06-24 17:25:38 +01:00
|
|
|
/* dummy fallthru to satisfy compiler */
|
|
|
|
/* fallthru */
|
2018-04-02 11:55:17 +08:00
|
|
|
case LRS_H1C_ISSUE_HANDSHAKE:
|
2013-01-16 11:53:05 +08:00
|
|
|
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_debug("%s: LRS_H1C_ISSUE_HANDSHAKE\n", __func__);
|
2020-12-19 09:13:24 +00:00
|
|
|
|
2013-01-16 11:53:05 +08:00
|
|
|
/*
|
|
|
|
* we are under PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE
|
|
|
|
* timeout protection set in client-handshake.c
|
2016-01-29 21:18:54 +08:00
|
|
|
*
|
2015-12-04 08:43:54 +08:00
|
|
|
* take care of our lws_callback_on_writable
|
2013-01-16 11:53:05 +08:00
|
|
|
* happening at a time when there's no real connection yet
|
|
|
|
*/
|
2017-05-05 11:38:34 -04:00
|
|
|
#if defined(LWS_WITH_SOCKS5)
|
2017-09-01 19:09:47 +08:00
|
|
|
start_ws_handshake:
|
2017-05-05 11:38:34 -04:00
|
|
|
#endif
|
2014-04-02 14:25:10 +08:00
|
|
|
if (lws_change_pollfd(wsi, LWS_POLLOUT, 0))
|
|
|
|
return -1;
|
2013-12-18 09:48:26 +08:00
|
|
|
|
2020-12-19 09:13:24 +00:00
|
|
|
#if defined(LWS_ROLE_H2) || defined(LWS_WITH_TLS)
|
|
|
|
if (
|
|
|
|
#if defined(LWS_WITH_TLS)
|
|
|
|
!(wsi->tls.use_ssl & LCCSCF_USE_SSL)
|
|
|
|
#endif
|
|
|
|
#if defined(LWS_ROLE_H2) && defined(LWS_WITH_TLS)
|
|
|
|
&&
|
|
|
|
#endif
|
|
|
|
#if defined(LWS_ROLE_H2)
|
|
|
|
!(wsi->flags & LCCSCF_H2_PRIOR_KNOWLEDGE)
|
|
|
|
#endif
|
|
|
|
)
|
|
|
|
goto hs2;
|
|
|
|
#endif
|
|
|
|
|
2018-04-11 13:39:42 +08:00
|
|
|
#if defined(LWS_WITH_TLS)
|
2020-03-07 20:03:58 +00:00
|
|
|
n = lws_client_create_tls(wsi, &cce, 1);
|
2020-12-19 09:13:24 +00:00
|
|
|
if (n == CCTLS_RETURN_ERROR)
|
2020-03-07 20:03:58 +00:00
|
|
|
goto bail3;
|
2020-12-19 09:13:24 +00:00
|
|
|
if (n == CCTLS_RETURN_RETRY)
|
2020-03-07 20:03:58 +00:00
|
|
|
return 0;
|
2013-01-16 11:53:05 +08:00
|
|
|
|
2020-12-19 09:13:24 +00:00
|
|
|
/*
|
|
|
|
* lws_client_create_tls() can already have done the
|
|
|
|
* whole tls setup and preface send... if so he set our state
|
|
|
|
* to LRS_H1C_ISSUE_HANDSHAKE2... let's proceed but be prepared
|
|
|
|
* to notice our state and not resend the preface...
|
|
|
|
*/
|
|
|
|
|
2020-12-29 12:10:24 +00:00
|
|
|
lwsl_debug("%s: LRS_H1C_ISSUE_HANDSHAKE fallthru\n", __func__);
|
2020-12-19 09:13:24 +00:00
|
|
|
|
2013-10-25 15:52:47 +02:00
|
|
|
/* fallthru */
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2018-04-02 11:55:17 +08:00
|
|
|
case LRS_WAITING_SSL:
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2018-05-01 12:41:42 +08:00
|
|
|
if (wsi->tls.use_ssl & LCCSCF_USE_SSL) {
|
2018-03-24 17:52:57 +01:00
|
|
|
n = lws_ssl_client_connect2(wsi, ebuf, sizeof(ebuf));
|
2016-05-03 07:26:10 +08:00
|
|
|
if (!n)
|
2016-03-28 12:43:55 +08:00
|
|
|
return 0;
|
2016-07-01 08:54:39 +08:00
|
|
|
if (n < 0) {
|
2018-03-24 17:52:57 +01:00
|
|
|
cce = ebuf;
|
2016-05-03 07:26:10 +08:00
|
|
|
goto bail3;
|
2016-07-01 08:54:39 +08:00
|
|
|
}
|
2020-05-07 15:21:48 -07:00
|
|
|
} else {
|
2018-05-01 12:41:42 +08:00
|
|
|
wsi->tls.ssl = NULL;
|
2020-12-19 09:13:24 +00:00
|
|
|
if (wsi->flags & LCCSCF_H2_PRIOR_KNOWLEDGE) {
|
2020-05-07 15:21:48 -07:00
|
|
|
lwsl_info("h2 prior knowledge\n");
|
|
|
|
lws_role_call_alpn_negotiated(wsi, "h2");
|
|
|
|
}
|
|
|
|
}
|
2013-02-11 17:13:32 +08:00
|
|
|
#endif
|
2020-12-19 09:13:24 +00:00
|
|
|
|
2018-03-27 09:17:19 +08:00
|
|
|
#if defined (LWS_WITH_HTTP2)
|
2021-06-17 10:07:04 +01:00
|
|
|
if (wsi->client_h2_alpn //&&
|
|
|
|
//lwsi_state(wsi) != LRS_H1C_ISSUE_HANDSHAKE2
|
|
|
|
) {
|
2018-03-27 09:17:19 +08:00
|
|
|
/*
|
2020-05-07 15:21:48 -07:00
|
|
|
* We connected to the server and set up tls and
|
|
|
|
* negotiated "h2" or connected as clear text
|
|
|
|
* with http/2 prior knowledge.
|
2018-03-27 09:17:19 +08:00
|
|
|
*
|
2020-10-11 07:43:46 +01:00
|
|
|
* So this is it, we are an h2 nwsi client connection
|
2018-03-27 09:17:19 +08:00
|
|
|
* now, not an h1 client connection.
|
|
|
|
*/
|
2020-05-07 15:21:48 -07:00
|
|
|
|
2021-06-17 10:07:04 +01:00
|
|
|
lwsl_info("%s: doing h2 hello path\n", __func__);
|
2018-03-27 09:17:19 +08:00
|
|
|
|
2021-06-17 10:07:04 +01:00
|
|
|
/*
|
|
|
|
* send the H2 preface to legitimize the connection
|
|
|
|
*
|
|
|
|
* transitions us to LRS_H2_WAITING_TO_SEND_HEADERS
|
|
|
|
*/
|
|
|
|
if (wsi->client_h2_alpn)
|
|
|
|
if (lws_h2_issue_preface(wsi)) {
|
|
|
|
cce = "error sending h2 preface";
|
|
|
|
goto bail3;
|
|
|
|
}
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2020-03-07 20:03:58 +00:00
|
|
|
// lwsi_set_state(wsi, LRS_H1C_ISSUE_HANDSHAKE2);
|
|
|
|
lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_CLIENT_HS_SEND,
|
2020-12-12 06:21:40 +00:00
|
|
|
(int)context->timeout_secs);
|
2020-03-07 20:03:58 +00:00
|
|
|
|
2018-03-27 09:17:19 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif
|
2014-04-05 16:48:48 +01:00
|
|
|
|
|
|
|
/* fallthru */
|
2013-01-16 11:53:05 +08:00
|
|
|
|
2018-04-02 11:55:17 +08:00
|
|
|
case LRS_H1C_ISSUE_HANDSHAKE2:
|
2020-12-19 09:13:24 +00:00
|
|
|
|
|
|
|
hs2:
|
|
|
|
|
2015-12-15 21:15:58 +08:00
|
|
|
p = lws_generate_client_handshake(wsi, p);
|
2013-01-16 13:40:43 +08:00
|
|
|
if (p == NULL) {
|
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
|
|
|
|
)
|
2017-03-07 16:06:05 +08:00
|
|
|
return 0;
|
|
|
|
|
2013-02-11 17:13:32 +08:00
|
|
|
lwsl_err("Failed to generate handshake for client\n");
|
2018-11-23 08:47:56 +08:00
|
|
|
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS,
|
|
|
|
"chs");
|
2022-07-12 09:47:00 +01:00
|
|
|
return -1;
|
2013-01-16 13:40:43 +08:00
|
|
|
}
|
2013-01-16 11:53:05 +08:00
|
|
|
|
|
|
|
/* send our request to the server */
|
|
|
|
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_info("%s: HANDSHAKE2: %s: sending headers "
|
2020-01-30 13:19:11 +00:00
|
|
|
"(wsistate 0x%lx), w sock %d\n",
|
2020-12-25 05:54:19 +00:00
|
|
|
__func__, lws_wsi_tag(wsi),
|
|
|
|
(unsigned long)wsi->wsistate, wsi->desc.sockfd);
|
2021-01-06 15:08:22 +00:00
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
n = lws_ssl_capable_write(wsi, (unsigned char *)sb, lws_ptr_diff_size_t(p, sb));
|
2014-04-05 16:48:48 +01:00
|
|
|
switch (n) {
|
|
|
|
case LWS_SSL_CAPABLE_ERROR:
|
2013-01-16 11:53:05 +08:00
|
|
|
lwsl_debug("ERROR writing to client socket\n");
|
2018-11-23 08:47:56 +08:00
|
|
|
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS,
|
|
|
|
"cws");
|
2013-01-16 13:40:43 +08:00
|
|
|
return 0;
|
2014-04-05 16:48:48 +01:00
|
|
|
case LWS_SSL_CAPABLE_MORE_SERVICE:
|
2015-12-16 18:19:08 +08:00
|
|
|
lws_callback_on_writable(wsi);
|
2014-04-05 16:48:48 +01:00
|
|
|
break;
|
2013-01-16 11:53:05 +08:00
|
|
|
}
|
|
|
|
|
2021-03-23 07:14:26 +00:00
|
|
|
if (wsi->client_http_body_pending || lws_has_buffered_out(wsi)) {
|
2019-03-22 06:22:40 +08:00
|
|
|
lwsl_debug("body pending\n");
|
2018-04-02 11:55:17 +08:00
|
|
|
lwsi_set_state(wsi, LRS_ISSUE_HTTP_BODY);
|
2017-11-16 09:37:04 +08:00
|
|
|
lws_set_timeout(wsi,
|
|
|
|
PENDING_TIMEOUT_CLIENT_ISSUE_PAYLOAD,
|
2020-12-12 06:21:40 +00:00
|
|
|
(int)context->timeout_secs);
|
2019-10-09 19:11:20 +01:00
|
|
|
|
|
|
|
if (wsi->flags & LCCSCF_HTTP_X_WWW_FORM_URLENCODED)
|
|
|
|
lws_callback_on_writable(wsi);
|
2019-03-22 06:22:40 +08:00
|
|
|
#if defined(LWS_WITH_HTTP_PROXY)
|
2021-08-13 21:16:24 +01:00
|
|
|
if (wsi->http.proxy_clientside && wsi->parent &&
|
|
|
|
wsi->parent->http.buflist_post_body)
|
2019-03-22 06:22:40 +08:00
|
|
|
lws_callback_on_writable(wsi);
|
|
|
|
#endif
|
2016-08-08 21:54:30 +08:00
|
|
|
/* user code must ask for writable callback */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2018-04-11 13:39:42 +08:00
|
|
|
lwsi_set_state(wsi, LRS_WAITING_SERVER_REPLY);
|
|
|
|
wsi->hdr_parsing_completed = 0;
|
|
|
|
|
2020-01-30 13:19:11 +00:00
|
|
|
if (lwsi_state(wsi) == LRS_IDLING) {
|
|
|
|
lwsi_set_state(wsi, LRS_WAITING_SERVER_REPLY);
|
|
|
|
wsi->hdr_parsing_completed = 0;
|
2018-04-27 19:16:50 +08:00
|
|
|
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
|
2020-01-30 13:19:11 +00:00
|
|
|
wsi->http.ah->parser_state = WSI_TOKEN_NAME_PART;
|
|
|
|
wsi->http.ah->lextable_pos = 0;
|
|
|
|
wsi->http.ah->unk_pos = 0;
|
2018-11-23 08:47:56 +08:00
|
|
|
/* If we're (re)starting on hdr, need other implied init */
|
2018-04-27 15:20:56 +08:00
|
|
|
wsi->http.ah->ues = URIES_IDLE;
|
2018-04-27 19:16:50 +08:00
|
|
|
#endif
|
2018-04-11 13:39:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_SERVER_RESPONSE,
|
2020-12-12 06:21:40 +00:00
|
|
|
(int)wsi->a.context->timeout_secs);
|
2018-04-11 13:39:42 +08:00
|
|
|
|
2020-01-30 13:19:11 +00:00
|
|
|
lws_callback_on_writable(wsi);
|
2018-03-26 12:05:04 +08:00
|
|
|
|
2016-08-08 21:54:30 +08:00
|
|
|
goto client_http_body_sent;
|
|
|
|
|
2018-04-02 11:55:17 +08:00
|
|
|
case LRS_ISSUE_HTTP_BODY:
|
2019-03-22 06:22:40 +08:00
|
|
|
#if defined(LWS_WITH_HTTP_PROXY)
|
2021-08-13 21:16:24 +01:00
|
|
|
if (wsi->http.proxy_clientside && wsi->parent &&
|
|
|
|
wsi->parent->http.buflist_post_body)
|
2019-03-22 06:22:40 +08:00
|
|
|
lws_callback_on_writable(wsi);
|
|
|
|
#endif
|
2021-03-23 07:14:26 +00:00
|
|
|
if (wsi->client_http_body_pending || lws_has_buffered_out(wsi)) {
|
2018-04-17 11:43:20 +08:00
|
|
|
//lws_set_timeout(wsi,
|
|
|
|
// PENDING_TIMEOUT_CLIENT_ISSUE_PAYLOAD,
|
|
|
|
// context->timeout_secs);
|
2016-08-08 21:54:30 +08:00
|
|
|
/* user code must ask for writable callback */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
client_http_body_sent:
|
2018-04-27 19:16:50 +08:00
|
|
|
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
|
2018-03-26 12:05:04 +08:00
|
|
|
/* prepare ourselves to do the parsing */
|
2018-04-27 15:20:56 +08:00
|
|
|
wsi->http.ah->parser_state = WSI_TOKEN_NAME_PART;
|
|
|
|
wsi->http.ah->lextable_pos = 0;
|
2019-02-26 17:18:24 +08:00
|
|
|
wsi->http.ah->unk_pos = 0;
|
2018-04-27 19:16:50 +08:00
|
|
|
#endif
|
2018-04-02 11:55:17 +08:00
|
|
|
lwsi_set_state(wsi, LRS_WAITING_SERVER_REPLY);
|
2015-12-06 10:05:37 +08:00
|
|
|
lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_SERVER_RESPONSE,
|
2020-12-12 06:21:40 +00:00
|
|
|
(int)context->timeout_secs);
|
2013-01-16 11:53:05 +08:00
|
|
|
break;
|
|
|
|
|
2018-04-02 11:55:17 +08:00
|
|
|
case LRS_WAITING_SERVER_REPLY:
|
2017-10-13 10:33:02 +08:00
|
|
|
/*
|
|
|
|
* handle server hanging up on us...
|
|
|
|
* but if there is POLLIN waiting, handle that first
|
|
|
|
*/
|
|
|
|
if ((pollfd->revents & (LWS_POLLIN | LWS_POLLHUP)) ==
|
|
|
|
LWS_POLLHUP) {
|
2013-01-16 11:53:05 +08:00
|
|
|
|
2021-01-26 08:04:16 +00:00
|
|
|
if (lws_buflist_total_len(&wsi->buflist))
|
|
|
|
lws_set_timeout(wsi, PENDING_TIMEOUT_CLOSE_ACK, 3);
|
|
|
|
else {
|
|
|
|
lwsl_debug("Server conn %s (fd=%d) dead\n",
|
|
|
|
lws_wsi_tag(wsi), pollfd->fd);
|
|
|
|
cce = "Peer hung up";
|
|
|
|
goto bail3;
|
|
|
|
}
|
2013-01-16 11:53:05 +08:00
|
|
|
}
|
|
|
|
|
2020-12-19 09:13:24 +00:00
|
|
|
if (pollfd->revents & LWS_POLLOUT)
|
|
|
|
if (lws_change_pollfd(wsi, LWS_POLLOUT, 0))
|
|
|
|
return -1;
|
|
|
|
|
2014-03-30 09:18:05 +02:00
|
|
|
if (!(pollfd->revents & LWS_POLLIN))
|
2013-03-09 09:09:46 +08:00
|
|
|
break;
|
2013-01-16 11:53:05 +08:00
|
|
|
|
2018-04-27 19:16:50 +08:00
|
|
|
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
|
2017-10-13 10:33:02 +08:00
|
|
|
/* interpret the server response
|
|
|
|
*
|
2013-01-16 11:53:05 +08:00
|
|
|
* HTTP/1.1 101 Switching Protocols
|
|
|
|
* Upgrade: websocket
|
|
|
|
* Connection: Upgrade
|
|
|
|
* Sec-WebSocket-Accept: me89jWimTRKTWwrS3aRrL53YZSo=
|
|
|
|
* Sec-WebSocket-Nonce: AQIDBAUGBwgJCgsMDQ4PEC==
|
|
|
|
* Sec-WebSocket-Protocol: chat
|
2017-10-13 10:33:02 +08:00
|
|
|
*
|
2013-01-16 11:53:05 +08:00
|
|
|
* we have to take some care here to only take from the
|
|
|
|
* socket bytewise. The browser may (and has been seen to
|
|
|
|
* in the case that onopen() performs websocket traffic)
|
|
|
|
* coalesce both handshake response and websocket traffic
|
|
|
|
* in one packet, since at that point the connection is
|
|
|
|
* definitively ready from browser pov.
|
|
|
|
*/
|
2019-08-27 06:06:13 +01:00
|
|
|
while (wsi->http.ah->parser_state != WSI_PARSING_COMPLETE) {
|
|
|
|
struct lws_tokens eb;
|
|
|
|
int n, m, buffered;
|
|
|
|
|
|
|
|
eb.token = NULL;
|
|
|
|
eb.len = 0;
|
2020-01-20 10:02:56 +00:00
|
|
|
buffered = lws_buflist_aware_read(pt, wsi, &eb, 0, __func__);
|
2019-08-27 06:06:13 +01:00
|
|
|
lwsl_debug("%s: buflist-aware-read %d %d\n", __func__,
|
|
|
|
buffered, eb.len);
|
|
|
|
if (eb.len == LWS_SSL_CAPABLE_MORE_SERVICE)
|
|
|
|
return 0;
|
|
|
|
if (buffered < 0 || eb.len < 0) {
|
2016-07-01 08:54:39 +08:00
|
|
|
cce = "read failed";
|
2013-01-30 12:27:27 +08:00
|
|
|
goto bail3;
|
2013-02-11 20:03:59 +08:00
|
|
|
}
|
2019-08-27 06:06:13 +01:00
|
|
|
if (!eb.len)
|
|
|
|
return 0;
|
2013-01-30 12:27:27 +08:00
|
|
|
|
2019-08-27 06:06:13 +01:00
|
|
|
n = eb.len;
|
|
|
|
if (lws_parse(wsi, eb.token, &n)) {
|
2013-02-11 20:03:59 +08:00
|
|
|
lwsl_warn("problems parsing header\n");
|
2019-07-24 16:48:24 -07:00
|
|
|
cce = "problems parsing header";
|
2013-02-04 08:55:42 +08:00
|
|
|
goto bail3;
|
|
|
|
}
|
2019-08-27 06:06:13 +01:00
|
|
|
|
|
|
|
m = eb.len - n;
|
2021-06-10 00:08:37 -07:00
|
|
|
#if defined(LWS_WITH_SECURE_STREAMS_BUFFER_DUMP)
|
|
|
|
do {
|
|
|
|
lws_ss_handle_t *h = (lws_ss_handle_t *)lws_get_opaque_user_data(wsi);
|
|
|
|
if (!h)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (h->info.dump) {
|
|
|
|
h->info.dump(ss_to_userobj(h),
|
|
|
|
(const uint8_t *)eb.token,
|
|
|
|
(size_t)m,
|
|
|
|
(wsi->http.ah->parser_state ==
|
|
|
|
WSI_PARSING_COMPLETE) ? 1 : 0);
|
|
|
|
}
|
|
|
|
} while (0);
|
|
|
|
#endif
|
2019-08-27 06:06:13 +01:00
|
|
|
if (lws_buflist_aware_finished_consuming(wsi, &eb, m,
|
|
|
|
buffered,
|
|
|
|
__func__))
|
|
|
|
return -1;
|
2020-08-18 11:23:24 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* coverity: uncomment if extended
|
|
|
|
*
|
|
|
|
* eb.token += m;
|
|
|
|
* eb.len -= m;
|
|
|
|
*/
|
2019-08-27 06:06:13 +01:00
|
|
|
|
|
|
|
if (n) {
|
|
|
|
assert(wsi->http.ah->parser_state ==
|
|
|
|
WSI_PARSING_COMPLETE);
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
2013-01-16 11:53:05 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* hs may also be coming in multiple packets, there is a 5-sec
|
|
|
|
* libwebsocket timeout still active here too, so if parsing did
|
|
|
|
* not complete just wait for next packet coming in this state
|
|
|
|
*/
|
2018-04-27 15:20:56 +08:00
|
|
|
if (wsi->http.ah->parser_state != WSI_PARSING_COMPLETE)
|
2013-01-16 11:53:05 +08:00
|
|
|
break;
|
2018-04-27 19:16:50 +08:00
|
|
|
#endif
|
2018-04-11 13:39:42 +08:00
|
|
|
|
2013-01-16 11:53:05 +08:00
|
|
|
/*
|
|
|
|
* otherwise deal with the handshake. If there's any
|
|
|
|
* packet traffic already arrived we'll trigger poll() again
|
|
|
|
* right away and deal with it that way
|
|
|
|
*/
|
2015-12-15 21:15:58 +08:00
|
|
|
return lws_client_interpret_server_handshake(wsi);
|
2013-01-16 11:53:05 +08:00
|
|
|
|
|
|
|
bail3:
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_info("%s: closing conn at LWS_CONNMODE...SERVER_REPLY, %s, state 0x%x\n",
|
|
|
|
__func__, lws_wsi_tag(wsi), lwsi_state(wsi));
|
2017-03-16 10:46:31 +08:00
|
|
|
if (cce)
|
|
|
|
lwsl_info("reason: %s\n", cce);
|
2020-04-14 19:04:13 +01:00
|
|
|
else
|
|
|
|
cce = "unknown";
|
2019-08-10 09:20:27 +01:00
|
|
|
lws_inform_client_conn_fail(wsi, (void *)cce, strlen(cce));
|
|
|
|
|
2018-02-03 13:48:18 +08:00
|
|
|
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "cbail3");
|
2013-09-18 21:01:02 +08:00
|
|
|
return -1;
|
2013-01-16 11:53:05 +08:00
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-04-27 19:16:50 +08:00
|
|
|
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
|
2013-01-16 11:53:05 +08:00
|
|
|
|
2016-03-20 11:55:25 +08:00
|
|
|
int LWS_WARN_UNUSED_RESULT
|
2016-02-29 13:18:30 +08:00
|
|
|
lws_http_transaction_completed_client(struct lws *wsi)
|
|
|
|
{
|
2020-08-31 09:27:16 +01:00
|
|
|
struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
|
2019-09-23 04:23:07 -07:00
|
|
|
int n;
|
2018-03-26 12:05:04 +08:00
|
|
|
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_info("%s: %s (%s)\n", __func__, lws_wsi_tag(wsi),
|
|
|
|
wsi->a.protocol->name);
|
2018-03-26 12:05:04 +08:00
|
|
|
|
2021-01-06 15:08:22 +00:00
|
|
|
// if (wsi->http.ah && wsi->http.ah->http_response)
|
|
|
|
/* we're only judging if any (200, or 500 etc) http txn completed */
|
|
|
|
lws_metrics_caliper_report(wsi->cal_conn, METRES_GO);
|
|
|
|
|
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-08-15 12:49:32 +08:00
|
|
|
LWS_CALLBACK_COMPLETED_CLIENT_HTTP,
|
2020-01-30 13:19:11 +00:00
|
|
|
wsi->user_space, NULL, 0)) {
|
2019-06-07 11:11:46 +01:00
|
|
|
lwsl_debug("%s: Completed call returned nonzero (role 0x%lx)\n",
|
2020-01-30 13:19:11 +00:00
|
|
|
__func__, (unsigned long)lwsi_role(wsi));
|
2018-03-26 12:05:04 +08:00
|
|
|
return -1;
|
2016-02-29 13:18:30 +08:00
|
|
|
}
|
|
|
|
|
2020-01-30 13:19:11 +00:00
|
|
|
wsi->http.rx_content_length = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* For h1, wsi may pass some assets on to a queued child and be
|
|
|
|
* destroyed during this.
|
|
|
|
*/
|
2020-08-31 09:27:16 +01:00
|
|
|
lws_pt_lock(pt, __func__);
|
2020-04-15 20:57:00 +01:00
|
|
|
n = _lws_generic_transaction_completed_active_conn(&wsi, 1);
|
2020-08-31 09:27:16 +01:00
|
|
|
lws_pt_unlock(pt);
|
2018-03-26 12:05:04 +08:00
|
|
|
|
2019-11-08 08:43:33 +00:00
|
|
|
if (wsi->http.ah) {
|
2019-12-23 11:31:57 +00:00
|
|
|
if (wsi->client_mux_substream)
|
2019-11-08 08:43:33 +00:00
|
|
|
/*
|
|
|
|
* As an h2 client, once we did our transaction, that is
|
|
|
|
* it for us. Further transactions will happen as new
|
|
|
|
* SIDs on the connection.
|
|
|
|
*/
|
|
|
|
__lws_header_table_detach(wsi, 0);
|
|
|
|
else
|
2020-01-30 13:19:11 +00:00
|
|
|
if (!n)
|
|
|
|
_lws_header_table_reset(wsi->http.ah);
|
2019-11-08 08:43:33 +00:00
|
|
|
}
|
2018-03-26 12:05:04 +08:00
|
|
|
|
2019-11-06 21:34:14 +00:00
|
|
|
if (!n || !wsi->http.ah)
|
2018-03-26 12:05:04 +08:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
/*
|
2018-04-11 13:39:42 +08:00
|
|
|
* H1: we can serialize the queued guys into the same ah
|
2018-04-02 11:55:17 +08:00
|
|
|
* H2: everybody needs their own ah until their own STREAM_END
|
2018-03-26 12:05:04 +08:00
|
|
|
*/
|
|
|
|
|
2016-02-29 13:18:30 +08:00
|
|
|
/* otherwise set ourselves up ready to go again */
|
2018-04-02 11:55:17 +08:00
|
|
|
lwsi_set_state(wsi, LRS_WAITING_SERVER_REPLY);
|
2016-02-29 13:18:30 +08:00
|
|
|
|
2018-04-27 15:20:56 +08:00
|
|
|
wsi->http.ah->parser_state = WSI_TOKEN_NAME_PART;
|
|
|
|
wsi->http.ah->lextable_pos = 0;
|
2019-02-26 17:18:24 +08:00
|
|
|
wsi->http.ah->unk_pos = 0;
|
2016-02-29 13:18:30 +08:00
|
|
|
|
2018-03-26 12:05:04 +08:00
|
|
|
lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_SERVER_RESPONSE,
|
2020-12-12 06:21:40 +00:00
|
|
|
(int)wsi->a.context->timeout_secs);
|
2016-02-29 13:18:30 +08:00
|
|
|
|
|
|
|
/* If we're (re)starting on headers, need other implied init */
|
2018-04-27 15:20:56 +08:00
|
|
|
wsi->http.ah->ues = URIES_IDLE;
|
2020-01-30 13:19:11 +00:00
|
|
|
lwsi_set_state(wsi, LRS_H1C_ISSUE_HANDSHAKE2);
|
2016-02-29 13:18:30 +08:00
|
|
|
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_info("%s: %s: new queued transaction\n", __func__, lws_wsi_tag(wsi));
|
2018-03-26 12:05:04 +08:00
|
|
|
lws_callback_on_writable(wsi);
|
2016-02-29 13:18:30 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-01-02 08:32:23 +00:00
|
|
|
unsigned int
|
2020-01-30 13:19:11 +00:00
|
|
|
lws_http_client_http_response(struct lws *wsi)
|
2016-10-21 23:12:21 +08:00
|
|
|
{
|
2020-01-30 13:19:11 +00:00
|
|
|
if (wsi->http.ah && wsi->http.ah->http_response)
|
|
|
|
return wsi->http.ah->http_response;
|
2018-07-20 08:39:00 +08:00
|
|
|
|
2020-01-30 13:19:11 +00:00
|
|
|
return 0;
|
2016-10-21 23:12:21 +08:00
|
|
|
}
|
2018-04-27 19:16:50 +08:00
|
|
|
#endif
|
2016-10-21 23:12:21 +08:00
|
|
|
|
2023-12-08 07:30:50 +00:00
|
|
|
|
2024-02-16 15:43:48 +00:00
|
|
|
#if defined(LWS_WITH_HTTP_DIGEST_AUTH) && defined(LWS_WITH_TLS)
|
2023-12-08 07:30:50 +00:00
|
|
|
|
|
|
|
static const char *digest_toks[] = {
|
|
|
|
"Digest", // 1 << 0
|
|
|
|
"username", // 1 << 1
|
|
|
|
"realm", // 1 << 2
|
|
|
|
"nonce", // 1 << 3
|
|
|
|
"uri", // 1 << 4 optional
|
|
|
|
"response", // 1 << 5
|
|
|
|
"opaque", // 1 << 6
|
|
|
|
"qop", // 1 << 7
|
2024-01-15 15:32:56 +00:00
|
|
|
"algorithm", // 1 << 8
|
2023-12-08 07:30:50 +00:00
|
|
|
"nc", // 1 << 9
|
|
|
|
"cnonce", // 1 << 10
|
|
|
|
"domain", // 1 << 11
|
|
|
|
};
|
|
|
|
|
|
|
|
#define PEND_NAME_EQ -1
|
|
|
|
#define PEND_DELIM -2
|
|
|
|
|
|
|
|
enum lws_check_basic_auth_results
|
|
|
|
lws_http_digest_auth(struct lws* wsi)
|
|
|
|
{
|
2023-12-20 06:49:51 +00:00
|
|
|
uint8_t nonce[256], response[LWS_GENHASH_LARGEST], qop[32];
|
2024-01-15 15:32:56 +00:00
|
|
|
int seen = 0, n, pend = -1;
|
2023-12-20 06:49:51 +00:00
|
|
|
char *tmp_digest = NULL;
|
2023-12-08 07:30:50 +00:00
|
|
|
struct lws_tokenize ts;
|
|
|
|
char resp_username[32];
|
|
|
|
lws_tokenize_elem e;
|
|
|
|
char realm[64];
|
|
|
|
char b64[512];
|
|
|
|
int m, ml, fi;
|
|
|
|
|
|
|
|
/* Did he send auth? */
|
|
|
|
ml = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_WWW_AUTHENTICATE);
|
|
|
|
if (!ml)
|
|
|
|
return LCBA_FAILED_AUTH;
|
|
|
|
|
|
|
|
/* Disallow fragmentation monkey business */
|
|
|
|
|
|
|
|
fi = wsi->http.ah->frag_index[WSI_TOKEN_HTTP_WWW_AUTHENTICATE];
|
|
|
|
if (wsi->http.ah->frags[fi].nfrag) {
|
|
|
|
lwsl_wsi_err(wsi, "fragmented http auth header not allowed\n");
|
|
|
|
return LCBA_FAILED_AUTH;
|
|
|
|
}
|
|
|
|
|
|
|
|
m = lws_hdr_copy(wsi, b64, sizeof(b64), WSI_TOKEN_HTTP_WWW_AUTHENTICATE);
|
|
|
|
if (m < 7) {
|
|
|
|
lwsl_wsi_err(wsi, "HTTP auth length bad\n");
|
|
|
|
return LCBA_END_TRANSACTION;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We are expecting AUTHORIZATION to have something like this
|
|
|
|
*
|
|
|
|
* Authorization: Digest
|
|
|
|
* username="Mufasa",
|
|
|
|
* realm="testrealm@host.com",
|
|
|
|
* nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
|
|
|
|
* uri="/dir/index.html",
|
|
|
|
* response="e966c932a9242554e42c8ee200cec7f6",
|
|
|
|
* opaque="5ccc069c403ebaf9f0171e9517f40e41"
|
|
|
|
*
|
|
|
|
* but the order, whitespace etc is quite open. uri is optional
|
|
|
|
*/
|
2023-12-20 06:49:51 +00:00
|
|
|
lws_tokenize_init(&ts,b64, LWS_TOKENIZE_F_MINUS_NONTERM |
|
|
|
|
LWS_TOKENIZE_F_NO_INTEGERS |
|
|
|
|
LWS_TOKENIZE_F_RFC7230_DELIMS);
|
2023-12-08 07:30:50 +00:00
|
|
|
|
|
|
|
do {
|
|
|
|
e = lws_tokenize(&ts);
|
|
|
|
switch (e) {
|
|
|
|
case LWS_TOKZE_TOKEN:
|
|
|
|
if (pend == 8) {
|
|
|
|
/* algorithm name */
|
|
|
|
|
2023-12-20 06:49:51 +00:00
|
|
|
if (!strncasecmp(ts.token, "MD5", ts.token_len)) {
|
2023-12-08 07:30:50 +00:00
|
|
|
lwsl_wsi_err(wsi, "wrong alg %.*s\n",
|
|
|
|
(int)ts.token_len,
|
|
|
|
ts.token);
|
|
|
|
return LCBA_END_TRANSACTION;
|
|
|
|
}
|
|
|
|
pend = PEND_DELIM;
|
|
|
|
break;
|
|
|
|
}
|
2023-12-20 06:49:51 +00:00
|
|
|
if (!strncasecmp(ts.token, "Digest", ts.token_len)) {
|
2023-12-08 07:30:50 +00:00
|
|
|
seen |= 1 << 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (seen) /* we must be first and one time */
|
|
|
|
return LCBA_END_TRANSACTION;
|
|
|
|
|
|
|
|
seen |= 1 << 15;
|
|
|
|
pend = PEND_NAME_EQ;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LWS_TOKZE_TOKEN_NAME_EQUALS:
|
2023-12-20 06:49:51 +00:00
|
|
|
if ((seen & (1 << 15)) == (1 << 15) || pend != -1)
|
2023-12-08 07:30:50 +00:00
|
|
|
/* no auth type token or disordered */
|
|
|
|
return LCBA_END_TRANSACTION;
|
|
|
|
|
|
|
|
for (n = 0; n < (int)LWS_ARRAY_SIZE(digest_toks); n++)
|
|
|
|
if (!strncmp(ts.token, digest_toks[n], ts.token_len))
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (n == LWS_ARRAY_SIZE(digest_toks)) {
|
|
|
|
lwsl_wsi_notice(wsi, "c: '%.*s'\n",
|
|
|
|
(int)ts.token_len,
|
|
|
|
ts.token);
|
|
|
|
|
|
|
|
return LCBA_END_TRANSACTION;
|
|
|
|
}
|
|
|
|
|
2023-12-20 06:49:51 +00:00
|
|
|
if (seen & (1 << n) || (seen & (1 << 15)) == (1 << 15))
|
2023-12-08 07:30:50 +00:00
|
|
|
/* dup or no auth type token */
|
|
|
|
return LCBA_END_TRANSACTION;
|
|
|
|
|
|
|
|
seen |= 1 << n;
|
|
|
|
pend = n;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LWS_TOKZE_QUOTED_STRING:
|
|
|
|
if (pend < 0)
|
|
|
|
return LCBA_END_TRANSACTION;
|
|
|
|
|
|
|
|
switch (pend) {
|
|
|
|
case 1: /* username */
|
|
|
|
if (ts.token_len >= (int)sizeof(resp_username))
|
|
|
|
return LCBA_END_TRANSACTION;
|
|
|
|
|
|
|
|
strncpy(resp_username, ts.token, ts.token_len);
|
|
|
|
break;
|
|
|
|
case 2: /* realm */
|
|
|
|
if (ts.token_len >= (int)sizeof(realm))
|
|
|
|
return LCBA_END_TRANSACTION;
|
|
|
|
|
|
|
|
strncpy(realm, ts.token, ts.token_len);
|
|
|
|
realm[ts.token_len] = 0;
|
|
|
|
break;
|
|
|
|
case 3: /* nonce */
|
|
|
|
if (ts.token_len >= (int)sizeof(nonce))
|
|
|
|
return LCBA_END_TRANSACTION;
|
|
|
|
|
|
|
|
strncpy((char *)nonce, ts.token, ts.token_len);
|
|
|
|
nonce[ts.token_len] = 0;
|
|
|
|
break;
|
|
|
|
case 4: /* uri */
|
|
|
|
break;
|
|
|
|
case 5: /* response */
|
|
|
|
if (ts.token_len !=
|
|
|
|
lws_genhash_size(LWS_GENHASH_TYPE_MD5) * 2)
|
|
|
|
return LCBA_END_TRANSACTION;
|
|
|
|
|
|
|
|
if (lws_hex_len_to_byte_array(ts.token, ts.token_len,
|
|
|
|
response,
|
|
|
|
sizeof(response)) < 0)
|
|
|
|
return LCBA_END_TRANSACTION;
|
|
|
|
break;
|
|
|
|
case 6: /* opaque */
|
|
|
|
break;
|
|
|
|
case 7: /* qop */
|
|
|
|
if (strncmp(ts.token, "auth", ts.token_len))
|
|
|
|
return LCBA_END_TRANSACTION;
|
|
|
|
|
|
|
|
strncpy((char *)qop, ts.token, ts.token_len);
|
|
|
|
qop[ts.token_len] = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
pend = PEND_DELIM;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LWS_TOKZE_DELIMITER:
|
|
|
|
if (*ts.token == ',') {
|
|
|
|
if (pend != PEND_DELIM)
|
|
|
|
return LCBA_END_TRANSACTION;
|
|
|
|
|
|
|
|
pend = PEND_NAME_EQ;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (*ts.token == ';') {
|
|
|
|
/* it's the end */
|
|
|
|
e = LWS_TOKZE_ENDED;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LWS_TOKZE_ENDED:
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
lwsl_wsi_notice(wsi, "unexpected token %d\n", e);
|
|
|
|
return LCBA_END_TRANSACTION;
|
|
|
|
}
|
|
|
|
|
|
|
|
} while (e > 0);
|
|
|
|
|
2023-12-20 06:49:51 +00:00
|
|
|
/* we got all the parts we care about? Realm + Nonce... */
|
2023-12-08 07:30:50 +00:00
|
|
|
|
|
|
|
if ((seen & 0xc) != 0xc) {
|
|
|
|
lwsl_wsi_err(wsi,
|
|
|
|
"%s: Not all digest auth tokens found! "
|
|
|
|
"m: 0x%x\nServer sent: %s",
|
|
|
|
__func__, seen & 0x81ef, b64);
|
|
|
|
|
|
|
|
return LCBA_END_TRANSACTION;
|
|
|
|
}
|
|
|
|
|
|
|
|
lwsl_wsi_info(wsi, "HTTP digest auth realm %s nonce %s\n", realm, nonce);
|
|
|
|
|
2023-12-20 06:49:51 +00:00
|
|
|
if (wsi->stash &&
|
2023-12-08 07:30:50 +00:00
|
|
|
wsi->stash->cis[CIS_PATH]) {
|
|
|
|
char *username = wsi->stash->cis[CIS_USERNAME];
|
|
|
|
char *password = wsi->stash->cis[CIS_PASSWORD];
|
|
|
|
uint8_t digest[LWS_GENHASH_LARGEST * 2 + 1];
|
|
|
|
char *uri = wsi->stash->cis[CIS_PATH];
|
|
|
|
char a1[LWS_GENHASH_LARGEST * 2 + 1];
|
|
|
|
char a2[LWS_GENHASH_LARGEST * 2 + 1];
|
|
|
|
char nc[sizeof(int) * 2 + 1];
|
|
|
|
struct lws_genhash_ctx hc;
|
|
|
|
int ncount = 1, ssl;
|
|
|
|
const char *a, *p;
|
|
|
|
struct lws *nwsi;
|
2023-12-20 06:49:51 +00:00
|
|
|
char cnonce[256];
|
2023-12-08 07:30:50 +00:00
|
|
|
size_t l;
|
|
|
|
|
2023-12-20 06:49:51 +00:00
|
|
|
l = sizeof(a1) + sizeof(a2) + sizeof(nonce) +
|
|
|
|
(sizeof(ncount) *2) + sizeof(response) +
|
|
|
|
sizeof(cnonce) + sizeof(qop) + strlen(uri) +
|
|
|
|
strlen(username) + strlen(password) +
|
|
|
|
strlen(realm) + 111;
|
2023-12-08 07:30:50 +00:00
|
|
|
|
2023-12-20 06:49:51 +00:00
|
|
|
tmp_digest = lws_malloc(l, __func__);
|
|
|
|
if (!tmp_digest)
|
2024-05-31 17:08:56 +01:00
|
|
|
return LCBA_FAILED_AUTH;
|
2023-12-08 07:30:50 +00:00
|
|
|
|
2023-12-20 06:49:51 +00:00
|
|
|
n = lws_snprintf(tmp_digest, l, "%s:%s:%s",
|
2023-12-08 07:30:50 +00:00
|
|
|
username, realm, password);
|
|
|
|
|
|
|
|
if (lws_genhash_init(&hc, LWS_GENHASH_TYPE_MD5) ||
|
|
|
|
lws_genhash_update(&hc,
|
2023-12-20 06:49:51 +00:00
|
|
|
tmp_digest,
|
|
|
|
(size_t)n) ||
|
2023-12-08 07:30:50 +00:00
|
|
|
lws_genhash_destroy(&hc, digest)) {
|
|
|
|
lws_genhash_destroy(&hc, NULL);
|
|
|
|
|
|
|
|
goto bail;
|
|
|
|
}
|
|
|
|
|
|
|
|
lws_hex_from_byte_array(digest,
|
|
|
|
lws_genhash_size(LWS_GENHASH_TYPE_MD5),
|
|
|
|
a1, sizeof(a1));
|
|
|
|
lwsl_debug("A1: %s:%s:%s = %s\n", username, realm, password, a1);
|
|
|
|
|
2023-12-20 06:49:51 +00:00
|
|
|
/*
|
|
|
|
* In case of Websocket upgrade, method is NULL
|
|
|
|
* we assume it is a GET
|
|
|
|
*/
|
|
|
|
|
|
|
|
n = lws_snprintf(tmp_digest, l, "%s:%s",
|
|
|
|
wsi->stash->cis[CIS_METHOD] ?
|
|
|
|
wsi->stash->cis[CIS_METHOD] : "GET", uri);
|
2023-12-08 07:30:50 +00:00
|
|
|
|
|
|
|
if (lws_genhash_init(&hc, LWS_GENHASH_TYPE_MD5) ||
|
|
|
|
lws_genhash_update(&hc,
|
2023-12-20 06:49:51 +00:00
|
|
|
tmp_digest,
|
2023-12-08 07:30:50 +00:00
|
|
|
(size_t)n) ||
|
|
|
|
lws_genhash_destroy(&hc, digest)) {
|
|
|
|
lws_genhash_destroy(&hc, NULL);
|
|
|
|
lwsl_err("%s: hash failed\n", __func__);
|
|
|
|
|
|
|
|
goto bail;
|
|
|
|
}
|
|
|
|
lws_hex_from_byte_array(digest,
|
|
|
|
lws_genhash_size(LWS_GENHASH_TYPE_MD5),
|
|
|
|
a2, sizeof(a2));
|
|
|
|
lwsl_debug("A2: %s:%s = %s\n", wsi->stash->cis[CIS_METHOD],
|
|
|
|
uri, a2);
|
|
|
|
|
|
|
|
lws_hex_random(lws_get_context(wsi), cnonce, sizeof(cnonce));
|
|
|
|
lws_hex_from_byte_array((const uint8_t *)&ncount,
|
|
|
|
sizeof(ncount), nc, sizeof(nc));
|
|
|
|
|
2023-12-20 06:49:51 +00:00
|
|
|
n = lws_snprintf(tmp_digest, l, "%s:%s:%08x:%s:%s:%s", a1,
|
2023-12-08 07:30:50 +00:00
|
|
|
nonce, ncount, cnonce, qop, a2);
|
|
|
|
|
2023-12-20 06:49:51 +00:00
|
|
|
lwsl_wsi_debug(wsi, "digest response: %s\n", tmp_digest);
|
2023-12-08 07:30:50 +00:00
|
|
|
|
|
|
|
|
|
|
|
if (lws_genhash_init(&hc, LWS_GENHASH_TYPE_MD5) ||
|
2023-12-20 06:49:51 +00:00
|
|
|
lws_genhash_update(&hc, tmp_digest, (size_t)n) ||
|
2023-12-08 07:30:50 +00:00
|
|
|
lws_genhash_destroy(&hc, digest)) {
|
|
|
|
lws_genhash_destroy(&hc, NULL);
|
|
|
|
lwsl_wsi_err(wsi, "hash failed\n");
|
|
|
|
|
|
|
|
goto bail;
|
|
|
|
}
|
|
|
|
lws_hex_from_byte_array(digest,
|
|
|
|
lws_genhash_size(LWS_GENHASH_TYPE_MD5),
|
|
|
|
(char *)response,
|
|
|
|
lws_genhash_size(LWS_GENHASH_TYPE_MD5) * 2 + 1);
|
|
|
|
|
2023-12-20 06:49:51 +00:00
|
|
|
n = lws_snprintf(tmp_digest, l,
|
|
|
|
"Digest username=\"%s\", realm=\"%s\", "
|
|
|
|
"nonce=\"%s\", uri=\"%s\", qop=%s, nc=%08x, "
|
|
|
|
"cnonce=\"%s\", response=\"%s\", "
|
|
|
|
"algorithm=\"MD5\"",
|
|
|
|
username, realm, nonce, uri, qop, ncount,
|
|
|
|
cnonce, response);
|
2023-12-08 07:30:50 +00:00
|
|
|
|
2023-12-20 06:49:51 +00:00
|
|
|
lwsl_hexdump(tmp_digest, l);
|
2023-12-08 07:30:50 +00:00
|
|
|
|
|
|
|
if (lws_hdr_simple_create(wsi, WSI_TOKEN_HTTP_AUTHORIZATION,
|
2023-12-20 06:49:51 +00:00
|
|
|
tmp_digest)) {
|
2023-12-08 07:30:50 +00:00
|
|
|
lwsl_wsi_err(wsi, "Failed to add Digest auth header");
|
|
|
|
goto bail;
|
|
|
|
}
|
|
|
|
|
|
|
|
nwsi = lws_get_network_wsi(wsi);
|
|
|
|
ssl = nwsi->tls.use_ssl & LCCSCF_USE_SSL;
|
|
|
|
|
|
|
|
a = wsi->stash->cis[CIS_ADDRESS];
|
|
|
|
p = &wsi->stash->cis[CIS_PATH][1];
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This prevents connection pipelining when two
|
|
|
|
* HTTP connection use the same tcp socket.
|
|
|
|
*/
|
|
|
|
wsi->keepalive_rejected = 1;
|
|
|
|
|
|
|
|
if (!lws_client_reset(&wsi, ssl, a, wsi->c_port, p, a, 1)) {
|
|
|
|
lwsl_wsi_err(wsi, "Failed to reset WSI for Digest auth");
|
|
|
|
|
|
|
|
goto bail;
|
|
|
|
}
|
|
|
|
|
2023-12-20 06:49:51 +00:00
|
|
|
/*
|
|
|
|
* Keep track of digest auth to send it at next attempt, lws_client_reset will free it
|
|
|
|
*/
|
|
|
|
|
|
|
|
wsi->http.digest_auth_hdr = tmp_digest;
|
2023-12-08 07:30:50 +00:00
|
|
|
wsi->client_pipeline = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
bail:
|
2023-12-20 06:49:51 +00:00
|
|
|
lws_free(tmp_digest);
|
2023-12-08 07:30:50 +00:00
|
|
|
|
2024-05-31 17:08:56 +01:00
|
|
|
return LCBA_FAILED_AUTH;
|
2023-12-08 07:30:50 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2018-04-27 19:16:50 +08:00
|
|
|
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
|
2019-11-17 10:47:01 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
lws_http_is_redirected_to_get(struct lws *wsi)
|
|
|
|
{
|
|
|
|
return wsi->redirected_to_get;
|
|
|
|
}
|
|
|
|
|
2013-01-16 11:53:05 +08:00
|
|
|
int
|
2015-12-15 21:15:58 +08:00
|
|
|
lws_client_interpret_server_handshake(struct lws *wsi)
|
2013-01-16 11:53:05 +08:00
|
|
|
{
|
2018-04-11 13:39:42 +08:00
|
|
|
int n, port = 0, ssl = 0;
|
2015-12-06 08:40:00 +08:00
|
|
|
int close_reason = LWS_CLOSE_STATUS_PROTOCOL_ERR;
|
2018-04-11 13:39:42 +08:00
|
|
|
const char *prot, *ads = NULL, *path, *cce = NULL;
|
2020-01-21 12:56:40 +00:00
|
|
|
struct allocated_headers *ah, *ah1;
|
2019-11-17 10:47:01 +00:00
|
|
|
struct lws *nwsi = lws_get_network_wsi(wsi);
|
2020-08-19 06:40:13 +01:00
|
|
|
char *p = NULL, *q, *simp;
|
2017-02-22 09:25:24 +00:00
|
|
|
char new_path[300];
|
2021-08-19 08:57:53 +01:00
|
|
|
void *opaque;
|
2018-04-11 13:39:42 +08:00
|
|
|
|
2021-04-01 22:31:13 +01:00
|
|
|
// lws_free_set_NULL(wsi->stash);
|
2013-01-16 11:53:05 +08:00
|
|
|
|
2021-03-15 05:20:15 +00:00
|
|
|
#if defined(LWS_WITH_CONMON)
|
|
|
|
wsi->conmon.ciu_txn_resp = (lws_conmon_interval_us_t)
|
|
|
|
(lws_now_usecs() - wsi->conmon_datum);
|
|
|
|
#endif
|
2023-12-08 07:30:50 +00:00
|
|
|
// lws_free_set_NULL(wsi->stash);
|
2021-03-15 05:20:15 +00:00
|
|
|
|
2018-04-27 15:20:56 +08:00
|
|
|
ah = wsi->http.ah;
|
2016-02-29 13:18:30 +08:00
|
|
|
if (!wsi->do_ws) {
|
|
|
|
/* we are being an http client...
|
|
|
|
*/
|
2018-04-11 13:39:42 +08:00
|
|
|
#if defined(LWS_ROLE_H2)
|
2019-12-23 11:31:57 +00:00
|
|
|
if (wsi->client_h2_alpn || wsi->client_mux_substream) {
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_debug("%s: %s: transitioning to h2 client\n",
|
|
|
|
__func__, lws_wsi_tag(wsi));
|
2018-04-11 13:39:42 +08:00
|
|
|
lws_role_transition(wsi, LWSIFR_CLIENT,
|
|
|
|
LRS_ESTABLISHED, &role_ops_h2);
|
2018-04-17 11:43:20 +08:00
|
|
|
} else
|
2018-04-11 13:39:42 +08:00
|
|
|
#endif
|
2018-04-17 11:43:20 +08:00
|
|
|
{
|
2018-04-27 19:16:50 +08:00
|
|
|
#if defined(LWS_ROLE_H1)
|
|
|
|
{
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_debug("%s: %s: transitioning to h1 client\n",
|
|
|
|
__func__, lws_wsi_tag(wsi));
|
2018-04-11 13:39:42 +08:00
|
|
|
lws_role_transition(wsi, LWSIFR_CLIENT,
|
|
|
|
LRS_ESTABLISHED, &role_ops_h1);
|
2018-04-27 19:16:50 +08:00
|
|
|
}
|
|
|
|
#else
|
|
|
|
return -1;
|
|
|
|
#endif
|
2018-04-17 11:43:20 +08:00
|
|
|
}
|
2018-04-02 11:55:17 +08:00
|
|
|
|
2018-04-27 15:20:56 +08:00
|
|
|
wsi->http.ah = ah;
|
2016-10-21 23:12:21 +08:00
|
|
|
ah->http_response = 0;
|
2016-02-29 13:18:30 +08:00
|
|
|
}
|
|
|
|
|
2021-07-05 16:41:41 +08:00
|
|
|
#if defined(LWS_WITH_CACHE_NSCOOKIEJAR) && defined(LWS_WITH_CLIENT)
|
|
|
|
|
|
|
|
if ((wsi->flags & LCCSCF_CACHE_COOKIES) &&
|
|
|
|
lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_SET_COOKIE))
|
|
|
|
lws_parse_set_cookie(wsi);
|
|
|
|
|
|
|
|
#endif
|
2013-01-16 11:53:05 +08:00
|
|
|
/*
|
|
|
|
* well, what the server sent looked reasonable for syntax.
|
|
|
|
* Now let's confirm it sent all the necessary headers
|
2016-02-29 13:18:30 +08:00
|
|
|
*
|
|
|
|
* http (non-ws) client will expect something like this
|
|
|
|
*
|
|
|
|
* HTTP/1.0.200
|
|
|
|
* server:.libwebsockets
|
|
|
|
* content-type:.text/html
|
|
|
|
* content-length:.17703
|
|
|
|
* set-cookie:.test=LWS_1456736240_336776_COOKIE;Max-Age=360000
|
2013-01-16 11:53:05 +08:00
|
|
|
*/
|
2016-02-29 13:18:30 +08:00
|
|
|
|
2018-09-02 14:35:37 +08:00
|
|
|
wsi->http.conn_type = HTTP_CONNECTION_KEEP_ALIVE;
|
2019-12-23 11:31:57 +00:00
|
|
|
if (!wsi->client_mux_substream) {
|
2018-03-27 09:17:19 +08:00
|
|
|
p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP);
|
2020-01-10 11:03:00 +00:00
|
|
|
/*
|
2018-03-27 09:17:19 +08:00
|
|
|
if (wsi->do_ws && !p) {
|
|
|
|
lwsl_info("no URI\n");
|
|
|
|
cce = "HS: URI missing";
|
|
|
|
goto bail3;
|
|
|
|
}
|
2020-01-10 11:03:00 +00:00
|
|
|
*/
|
2018-03-27 09:17:19 +08:00
|
|
|
if (!p) {
|
|
|
|
p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP1_0);
|
2018-09-02 14:35:37 +08:00
|
|
|
wsi->http.conn_type = HTTP_CONNECTION_CLOSE;
|
2018-03-27 09:17:19 +08:00
|
|
|
}
|
|
|
|
if (!p) {
|
|
|
|
cce = "HS: URI missing";
|
|
|
|
lwsl_info("no URI\n");
|
|
|
|
goto bail3;
|
|
|
|
}
|
2020-02-28 10:31:04 +00:00
|
|
|
#if defined(LWS_ROLE_H2)
|
2018-04-04 10:39:31 +08:00
|
|
|
} else {
|
2018-03-27 09:17:19 +08:00
|
|
|
p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_STATUS);
|
2018-04-04 10:39:31 +08:00
|
|
|
if (!p) {
|
|
|
|
cce = "HS: :status missing";
|
|
|
|
lwsl_info("no status\n");
|
|
|
|
goto bail3;
|
|
|
|
}
|
2020-02-28 10:31:04 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#if !defined(LWS_ROLE_H2)
|
|
|
|
if (!p) {
|
|
|
|
cce = "HS: :status missing";
|
|
|
|
lwsl_info("no status\n");
|
|
|
|
goto bail3;
|
2018-04-04 10:39:31 +08:00
|
|
|
}
|
2020-02-28 10:31:04 +00:00
|
|
|
#endif
|
2016-01-14 11:37:56 +08:00
|
|
|
n = atoi(p);
|
2023-12-08 07:30:50 +00:00
|
|
|
|
2024-02-16 15:43:48 +00:00
|
|
|
#if defined(LWS_WITH_HTTP_DIGEST_AUTH) && defined(LWS_WITH_TLS)
|
2024-01-15 15:32:56 +00:00
|
|
|
if (n == 401 && lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_WWW_AUTHENTICATE)) {
|
|
|
|
if (!(wsi->stash && wsi->stash->cis[CIS_USERNAME] &&
|
|
|
|
wsi->stash->cis[CIS_PASSWORD])) {
|
|
|
|
lwsl_err("Digest auth requested by server but no credentials provided by user\n");
|
|
|
|
|
|
|
|
return LCBA_FAILED_AUTH;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lws_http_digest_auth(wsi))
|
|
|
|
goto bail3;
|
2023-12-08 07:30:50 +00:00
|
|
|
|
|
|
|
opaque = wsi->a.opaque_user_data;
|
|
|
|
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "digest_auth_step2");
|
|
|
|
wsi->a.opaque_user_data = opaque;
|
|
|
|
|
|
|
|
return -1;
|
2024-01-15 15:32:56 +00:00
|
|
|
}
|
2023-12-08 07:30:50 +00:00
|
|
|
|
|
|
|
ah = wsi->http.ah;
|
|
|
|
#endif
|
2016-10-21 23:12:21 +08:00
|
|
|
if (ah)
|
2020-12-12 06:21:40 +00:00
|
|
|
ah->http_response = (unsigned int)n;
|
2016-10-21 23:12:21 +08:00
|
|
|
|
2020-01-21 13:27:36 +00:00
|
|
|
if (!wsi->client_no_follow_redirect &&
|
2019-04-21 19:57:19 +01:00
|
|
|
#if defined(LWS_WITH_HTTP_PROXY)
|
|
|
|
!wsi->http.proxy_clientside &&
|
|
|
|
#endif
|
|
|
|
(n == 301 || n == 302 || n == 303 || n == 307 || n == 308)) {
|
2016-01-14 11:37:56 +08:00
|
|
|
p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_LOCATION);
|
2016-07-01 08:54:39 +08:00
|
|
|
if (!p) {
|
|
|
|
cce = "HS: Redirect code but no Location";
|
2016-01-14 11:37:56 +08:00
|
|
|
goto bail3;
|
2016-07-01 08:54:39 +08:00
|
|
|
}
|
2016-01-14 11:37:56 +08:00
|
|
|
|
2021-08-19 08:57:53 +01:00
|
|
|
#if defined(LWS_WITH_CONMON)
|
|
|
|
if (wsi->conmon.pcol == LWSCONMON_PCOL_NONE) {
|
|
|
|
wsi->conmon.pcol = LWSCONMON_PCOL_HTTP;
|
|
|
|
wsi->conmon.protocol_specific.http.response = n;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(LWS_WITH_SECURE_STREAMS)
|
|
|
|
if (wsi->for_ss
|
|
|
|
#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
|
|
|
|
&& !wsi->client_bound_sspc
|
|
|
|
#endif
|
|
|
|
) {
|
|
|
|
|
|
|
|
lws_ss_handle_t *h = (lws_ss_handle_t *)lws_get_opaque_user_data(wsi);
|
|
|
|
|
|
|
|
if (h)
|
|
|
|
lws_conmon_ss_json(h);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
2020-03-11 12:44:01 +00:00
|
|
|
/* let's let the user code know, if he cares */
|
|
|
|
|
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 (wsi->a.protocol->callback(wsi,
|
2020-03-11 12:44:01 +00:00
|
|
|
LWS_CALLBACK_CLIENT_HTTP_REDIRECT,
|
2020-12-12 06:21:40 +00:00
|
|
|
wsi->user_space, p, (unsigned int)n)) {
|
2020-03-11 12:44:01 +00:00
|
|
|
cce = "HS: user code rejected redirect";
|
|
|
|
goto bail3;
|
|
|
|
}
|
|
|
|
|
2019-11-17 10:47:01 +00:00
|
|
|
/*
|
|
|
|
* Some redirect codes imply we have to change the method
|
|
|
|
* used for the subsequent transaction, commonly POST ->
|
|
|
|
* 303 -> GET.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (n == 303) {
|
|
|
|
char *mp = lws_hdr_simple_ptr(wsi,_WSI_TOKEN_CLIENT_METHOD);
|
|
|
|
int ml = lws_hdr_total_length(wsi, _WSI_TOKEN_CLIENT_METHOD);
|
|
|
|
|
|
|
|
if (ml >= 3 && mp) {
|
|
|
|
lwsl_info("%s: 303 switching to GET\n", __func__);
|
|
|
|
memcpy(mp, "GET", 4);
|
|
|
|
wsi->redirected_to_get = 1;
|
|
|
|
wsi->http.ah->frags[wsi->http.ah->frag_index[
|
|
|
|
_WSI_TOKEN_CLIENT_METHOD]].len = 3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-22 09:25:24 +00:00
|
|
|
/* Relative reference absolute path */
|
2019-11-17 10:47:01 +00:00
|
|
|
if (p[0] == '/' || !strchr(p, ':')) {
|
2018-04-11 13:39:42 +08:00
|
|
|
#if defined(LWS_WITH_TLS)
|
2019-11-17 10:47:01 +00:00
|
|
|
ssl = nwsi->tls.use_ssl & LCCSCF_USE_SSL;
|
2017-02-22 09:25:24 +00:00
|
|
|
#endif
|
2017-11-16 09:37:04 +08:00
|
|
|
ads = lws_hdr_simple_ptr(wsi,
|
|
|
|
_WSI_TOKEN_CLIENT_PEER_ADDRESS);
|
2019-11-17 10:47:01 +00:00
|
|
|
port = nwsi->c_port;
|
|
|
|
path = p;
|
|
|
|
/* lws_client_reset expects leading / omitted */
|
|
|
|
if (*path == '/')
|
|
|
|
path++;
|
2016-07-01 08:54:39 +08:00
|
|
|
}
|
2017-02-22 09:25:24 +00:00
|
|
|
/* Absolute (Full) URI */
|
2017-11-16 09:37:04 +08:00
|
|
|
else if (strchr(p, ':')) {
|
2017-02-22 09:25:24 +00:00
|
|
|
if (lws_parse_uri(p, &prot, &ads, &port, &path)) {
|
|
|
|
cce = "HS: URI did not parse";
|
|
|
|
goto bail3;
|
|
|
|
}
|
2016-01-14 11:37:56 +08:00
|
|
|
|
2017-02-22 09:25:24 +00:00
|
|
|
if (!strcmp(prot, "wss") || !strcmp(prot, "https"))
|
2019-11-17 10:47:01 +00:00
|
|
|
ssl = LCCSCF_USE_SSL;
|
2017-02-22 09:25:24 +00:00
|
|
|
}
|
|
|
|
/* Relative reference relative path */
|
2017-11-16 09:37:04 +08:00
|
|
|
else {
|
|
|
|
/* This doesn't try to calculate an absolute path,
|
|
|
|
* that will be left to the server */
|
2018-04-11 13:39:42 +08:00
|
|
|
#if defined(LWS_WITH_TLS)
|
2019-11-17 10:47:01 +00:00
|
|
|
ssl = nwsi->tls.use_ssl & LCCSCF_USE_SSL;
|
2017-02-22 09:25:24 +00:00
|
|
|
#endif
|
2017-11-16 09:37:04 +08:00
|
|
|
ads = lws_hdr_simple_ptr(wsi,
|
|
|
|
_WSI_TOKEN_CLIENT_PEER_ADDRESS);
|
2017-02-22 09:25:24 +00:00
|
|
|
port = wsi->c_port;
|
2017-11-16 09:37:04 +08:00
|
|
|
/* +1 as lws_client_reset expects leading / omitted */
|
|
|
|
path = new_path + 1;
|
2020-01-02 08:32:23 +00:00
|
|
|
if (lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_URI))
|
2019-08-07 07:42:27 +01:00
|
|
|
lws_strncpy(new_path, lws_hdr_simple_ptr(wsi,
|
2018-03-12 09:28:26 +08:00
|
|
|
_WSI_TOKEN_CLIENT_URI), sizeof(new_path));
|
2019-08-07 07:42:27 +01:00
|
|
|
else {
|
|
|
|
new_path[0] = '/';
|
|
|
|
new_path[1] = '\0';
|
|
|
|
}
|
2017-02-22 09:25:24 +00:00
|
|
|
q = strrchr(new_path, '/');
|
2018-03-12 09:28:26 +08:00
|
|
|
if (q)
|
|
|
|
lws_strncpy(q + 1, p, sizeof(new_path) -
|
2020-12-12 06:21:40 +00:00
|
|
|
(unsigned int)(q - new_path) - 1);
|
2018-03-12 09:28:26 +08:00
|
|
|
else
|
2017-02-22 09:25:24 +00:00
|
|
|
path = p;
|
|
|
|
}
|
2016-01-13 18:48:50 +08:00
|
|
|
|
2018-04-11 13:39:42 +08:00
|
|
|
#if defined(LWS_WITH_TLS)
|
2021-06-16 07:21:48 +01:00
|
|
|
if ((wsi->tls.use_ssl & LCCSCF_USE_SSL) && !ssl &&
|
|
|
|
!(wsi->flags & LCCSCF_ACCEPT_TLS_DOWNGRADE_REDIRECTS)) {
|
2017-02-22 11:25:47 +00:00
|
|
|
cce = "HS: Redirect attempted SSL downgrade";
|
|
|
|
goto bail3;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2019-07-24 16:48:24 -07:00
|
|
|
if (!ads) /* make coverity happy */ {
|
|
|
|
cce = "no ads";
|
2019-07-16 10:02:54 -07:00
|
|
|
goto bail3;
|
2019-07-24 16:48:24 -07:00
|
|
|
}
|
2019-07-16 10:02:54 -07:00
|
|
|
|
2020-01-10 11:47:01 +00:00
|
|
|
if (!lws_client_reset(&wsi, ssl, ads, port, path, ads, 1)) {
|
2016-01-14 11:37:56 +08:00
|
|
|
lwsl_err("Redirect failed\n");
|
2016-07-01 08:54:39 +08:00
|
|
|
cce = "HS: Redirect failed";
|
2021-10-17 07:48:40 +01:00
|
|
|
goto bail3;
|
2016-01-14 11:37:56 +08:00
|
|
|
}
|
2021-06-17 10:07:04 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We are redirecting, let's close in order to extricate
|
|
|
|
* ourselves from the current wsi usage, eg, h2 mux cleanly.
|
|
|
|
*
|
|
|
|
* We will notice close_is_redirect and switch to redirect
|
|
|
|
* flow late in the close action.
|
|
|
|
*/
|
|
|
|
|
2021-08-19 08:57:53 +01:00
|
|
|
opaque = wsi->a.opaque_user_data;
|
2021-06-17 10:07:04 +01:00
|
|
|
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "redir");
|
2021-08-19 08:57:53 +01:00
|
|
|
wsi->a.opaque_user_data = opaque;
|
2021-06-17 10:07:04 +01:00
|
|
|
|
|
|
|
return -1;
|
2016-01-14 11:37:56 +08:00
|
|
|
}
|
2016-02-29 13:18:30 +08:00
|
|
|
|
2020-03-01 12:24:29 -05:00
|
|
|
/* if h1 KA is allowed, enable the queued pipeline guys */
|
2016-02-29 13:18:30 +08:00
|
|
|
|
2020-03-01 12:24:29 -05:00
|
|
|
if (!wsi->client_h2_alpn && !wsi->client_mux_substream) {
|
|
|
|
/* ie, coming to this for the first time */
|
|
|
|
if (wsi->http.conn_type == HTTP_CONNECTION_KEEP_ALIVE)
|
|
|
|
wsi->keepalive_active = 1;
|
|
|
|
else {
|
|
|
|
/*
|
|
|
|
* Ugh... now the main http connection has seen
|
|
|
|
* both sides, we learn the server doesn't
|
|
|
|
* support keepalive.
|
|
|
|
*
|
|
|
|
* That means any guys queued on us are going
|
|
|
|
* to have to be restarted from connect2 with
|
|
|
|
* their own connections.
|
|
|
|
*/
|
2018-03-26 12:05:04 +08:00
|
|
|
|
2020-03-01 12:24:29 -05:00
|
|
|
/*
|
|
|
|
* stick around telling any new guys they can't
|
|
|
|
* pipeline to this server
|
|
|
|
*/
|
|
|
|
wsi->keepalive_rejected = 1;
|
|
|
|
|
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
|
|
|
lws_vhost_lock(wsi->a.vhost);
|
2020-03-01 12:24:29 -05:00
|
|
|
lws_start_foreach_dll_safe(struct lws_dll2 *,
|
|
|
|
d, d1,
|
|
|
|
wsi->dll2_cli_txn_queue_owner.head) {
|
|
|
|
struct lws *ww = lws_container_of(d,
|
|
|
|
struct lws,
|
|
|
|
dll2_cli_txn_queue);
|
|
|
|
|
|
|
|
/* remove him from our queue */
|
|
|
|
lws_dll2_remove(&ww->dll2_cli_txn_queue);
|
|
|
|
/* give up on pipelining */
|
|
|
|
ww->client_pipeline = 0;
|
|
|
|
|
|
|
|
/* go back to "trying to connect" state */
|
|
|
|
lws_role_transition(ww, LWSIFR_CLIENT,
|
|
|
|
LRS_UNCONNECTED,
|
2018-04-27 19:16:50 +08:00
|
|
|
#if defined(LWS_ROLE_H1)
|
2020-03-01 12:24:29 -05:00
|
|
|
&role_ops_h1);
|
2018-04-27 19:16:50 +08:00
|
|
|
#else
|
|
|
|
#if defined (LWS_ROLE_H2)
|
2020-03-01 12:24:29 -05:00
|
|
|
&role_ops_h2);
|
2018-04-27 19:16:50 +08:00
|
|
|
#else
|
2020-03-01 12:24:29 -05:00
|
|
|
&role_ops_raw);
|
2018-04-27 19:16:50 +08:00
|
|
|
#endif
|
|
|
|
#endif
|
2020-03-01 12:24:29 -05:00
|
|
|
ww->user_space = NULL;
|
|
|
|
} lws_end_foreach_dll_safe(d, d1);
|
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
|
|
|
lws_vhost_unlock(wsi->a.vhost);
|
2018-03-26 12:05:04 +08:00
|
|
|
}
|
2020-03-01 12:24:29 -05:00
|
|
|
}
|
2018-03-26 12:05:04 +08:00
|
|
|
|
2016-03-20 11:55:25 +08:00
|
|
|
#ifdef LWS_WITH_HTTP_PROXY
|
2020-03-01 12:24:29 -05:00
|
|
|
wsi->http.perform_rewrite = 0;
|
|
|
|
if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE)) {
|
|
|
|
if (!strncmp(lws_hdr_simple_ptr(wsi,
|
|
|
|
WSI_TOKEN_HTTP_CONTENT_TYPE),
|
|
|
|
"text/html", 9))
|
|
|
|
wsi->http.perform_rewrite = 0;
|
|
|
|
}
|
2016-03-20 11:59:53 +08:00
|
|
|
#endif
|
|
|
|
|
2020-03-01 12:24:29 -05:00
|
|
|
/* he may choose to send us stuff in chunked transfer-coding */
|
|
|
|
wsi->chunked = 0;
|
|
|
|
wsi->chunk_remaining = 0; /* ie, next thing is chunk size */
|
2020-08-19 06:40:13 +01:00
|
|
|
if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_TRANSFER_ENCODING)) {
|
|
|
|
simp = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_TRANSFER_ENCODING);
|
|
|
|
|
|
|
|
/* cannot be NULL, since it has nonzero length... coverity */
|
|
|
|
if (!simp)
|
|
|
|
goto bail2;
|
|
|
|
wsi->chunked = !strcmp(simp, "chunked");
|
2020-03-01 12:24:29 -05:00
|
|
|
/* first thing is hex, after payload there is crlf */
|
|
|
|
wsi->chunk_parser = ELCP_HEX;
|
|
|
|
}
|
|
|
|
|
|
|
|
wsi->http.content_length_given = 0;
|
|
|
|
if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) {
|
2020-08-19 06:40:13 +01:00
|
|
|
simp = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH);
|
|
|
|
|
|
|
|
/* cannot be NULL, since it has nonzero length... coverity */
|
|
|
|
if (!simp)
|
|
|
|
goto bail2;
|
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
wsi->http.rx_content_length = (lws_filepos_t)atoll(simp);
|
2020-03-01 12:24:29 -05:00
|
|
|
lwsl_info("%s: incoming content length %llu\n",
|
|
|
|
__func__, (unsigned long long)
|
|
|
|
wsi->http.rx_content_length);
|
|
|
|
wsi->http.rx_content_remain =
|
|
|
|
wsi->http.rx_content_length;
|
|
|
|
wsi->http.content_length_given = 1;
|
|
|
|
} else { /* can't do 1.1 without a content length or chunked */
|
|
|
|
if (!wsi->chunked)
|
|
|
|
wsi->http.conn_type = HTTP_CONNECTION_CLOSE;
|
|
|
|
lwsl_debug("%s: no content length\n", __func__);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (wsi->do_ws) {
|
|
|
|
/*
|
|
|
|
* Give one last opportunity to ws protocols to inspect server reply
|
|
|
|
* before the ws upgrade code discard it. ie: download reply body in case
|
|
|
|
* of any other response code than 101.
|
|
|
|
*/
|
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 (wsi->a.protocol->callback(wsi,
|
2020-03-01 12:24:29 -05:00
|
|
|
LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP,
|
|
|
|
wsi->user_space, NULL, 0)) {
|
|
|
|
|
|
|
|
cce = "HS: disallowed by client filter";
|
|
|
|
goto bail2;
|
|
|
|
}
|
|
|
|
} else {
|
2016-02-29 13:18:30 +08:00
|
|
|
/* allocate the per-connection user memory (if any) */
|
|
|
|
if (lws_ensure_user_space(wsi)) {
|
|
|
|
lwsl_err("Problem allocating wsi user mem\n");
|
2016-07-01 08:54:39 +08:00
|
|
|
cce = "HS: OOM";
|
2016-02-29 13:18:30 +08:00
|
|
|
goto bail2;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* we seem to be good to go, give client last chance to check
|
|
|
|
* headers and OK it
|
|
|
|
*/
|
2020-01-30 13:19:11 +00:00
|
|
|
ah1 = wsi->http.ah;
|
|
|
|
wsi->http.ah = ah;
|
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 (wsi->a.protocol->callback(wsi,
|
2017-11-16 09:37:04 +08:00
|
|
|
LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH,
|
2020-01-30 13:19:11 +00:00
|
|
|
wsi->user_space, NULL, 0)) {
|
|
|
|
wsi->http.ah = ah1;
|
2016-07-01 08:54:39 +08:00
|
|
|
cce = "HS: disallowed by client filter";
|
2016-02-29 13:18:30 +08:00
|
|
|
goto bail2;
|
2016-07-01 08:54:39 +08:00
|
|
|
}
|
2016-02-29 13:18:30 +08:00
|
|
|
|
|
|
|
/* clear his proxy connection timeout */
|
|
|
|
lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
|
|
|
|
|
|
|
|
wsi->rxflow_change_to = LWS_RXFLOW_ALLOW;
|
|
|
|
|
|
|
|
/* call him back to inform him he is up */
|
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 (wsi->a.protocol->callback(wsi,
|
2016-04-18 17:26:14 +08:00
|
|
|
LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP,
|
2020-01-30 13:19:11 +00:00
|
|
|
wsi->user_space, NULL, 0)) {
|
|
|
|
wsi->http.ah = ah1;
|
2016-07-01 08:54:39 +08:00
|
|
|
cce = "HS: disallowed at ESTABLISHED";
|
2016-02-29 13:18:30 +08:00
|
|
|
goto bail3;
|
2016-07-01 08:54:39 +08:00
|
|
|
}
|
2016-02-29 13:18:30 +08:00
|
|
|
|
2020-01-30 13:19:11 +00:00
|
|
|
wsi->http.ah = ah1;
|
2016-02-29 13:18:30 +08:00
|
|
|
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_info("%s: %s: client conn up\n", __func__, lws_wsi_tag(wsi));
|
2016-02-29 13:18:30 +08:00
|
|
|
|
2018-07-21 10:26:47 +08:00
|
|
|
/*
|
|
|
|
* Did we get a response from the server with an explicit
|
2021-01-28 19:32:11 +00:00
|
|
|
* content-length of zero? If so, and it's not H2 which will
|
|
|
|
* notice it via END_STREAM, this transaction is already
|
2018-07-21 10:26:47 +08:00
|
|
|
* completed at the end of the header processing...
|
2024-10-20 15:39:06 +02:00
|
|
|
* We also completed it if the request method is HEAD which as
|
|
|
|
* no content leftover.
|
2018-07-21 10:26:47 +08:00
|
|
|
*/
|
2024-10-20 15:39:06 +02:00
|
|
|
simp = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_METHOD);
|
|
|
|
if (!wsi->mux_substream &&
|
|
|
|
!wsi->client_mux_substream &&
|
2021-01-28 19:32:11 +00:00
|
|
|
lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH) &&
|
2024-10-20 15:39:06 +02:00
|
|
|
(!wsi->http.rx_content_length ||
|
|
|
|
(simp && !strcmp(simp,"HEAD"))))
|
2018-07-21 10:26:47 +08:00
|
|
|
return !!lws_http_transaction_completed_client(wsi);
|
|
|
|
|
2020-05-19 18:34:38 +01:00
|
|
|
/*
|
|
|
|
* We can also get a case where it's http/1 and there's no
|
|
|
|
* content-length at all, so anything that comes is the body
|
|
|
|
* until it hangs up on us. With that situation, hanging up
|
|
|
|
* on us past this point should generate a valid
|
|
|
|
* LWS_CALLBACK_COMPLETED_CLIENT_HTTP.
|
|
|
|
*
|
|
|
|
* In that situation, he can't pipeline because in h1 there's
|
|
|
|
* no post-header in-band way to signal the end of the
|
|
|
|
* transaction except hangup.
|
|
|
|
*
|
|
|
|
* lws_http_transaction_completed_client() is the right guy to
|
|
|
|
* issue it when we see the peer has hung up on us.
|
|
|
|
*/
|
|
|
|
|
2016-02-29 13:18:30 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-04-11 13:39:42 +08:00
|
|
|
#if defined(LWS_ROLE_WS)
|
|
|
|
switch (lws_client_ws_upgrade(wsi, &cce)) {
|
|
|
|
case 2:
|
2013-03-23 09:53:17 +08:00
|
|
|
goto bail2;
|
2018-04-11 13:39:42 +08:00
|
|
|
case 3:
|
2015-12-18 00:50:14 +08:00
|
|
|
goto bail3;
|
2016-07-01 08:54:39 +08:00
|
|
|
}
|
2013-01-16 11:53:05 +08:00
|
|
|
|
|
|
|
return 0;
|
2018-04-11 13:39:42 +08:00
|
|
|
#endif
|
2013-01-16 11:53:05 +08:00
|
|
|
|
|
|
|
bail3:
|
2013-03-23 09:53:17 +08:00
|
|
|
close_reason = LWS_CLOSE_STATUS_NOSTATUS;
|
2013-01-16 11:53:05 +08:00
|
|
|
|
|
|
|
bail2:
|
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 (wsi->a.protocol) {
|
2018-03-19 08:05:37 +08:00
|
|
|
n = 0;
|
|
|
|
if (cce)
|
2018-04-16 19:52:28 +08:00
|
|
|
n = (int)strlen(cce);
|
2019-08-10 09:20:27 +01:00
|
|
|
|
|
|
|
lws_inform_client_conn_fail(wsi, (void *)cce, (unsigned int)n);
|
2018-03-19 08:05:37 +08:00
|
|
|
}
|
replace per header mallocs with single malloc 3 level struct
This big patch replaces the malloc / realloc per header
approach used until now with a single three-level struct
that gets malloc'd during the header union phase and freed
in one go when we transition to a different union phase.
It's more expensive in that we malloc a bit more than 4Kbytes,
but it's a lot cheaper in terms of malloc, frees, heap fragmentation,
no reallocs, nothing to configure. It also moves from arrays of
pointers (8 bytes on x86_64) to unsigned short offsets into the
data array, (2 bytes on all platforms).
The 3-level thing is all in one struct
- array indexed by the header enum, pointing to first "fragment" index
(ie, header type to fragment lookup, or 0 for none)
- array of fragments indexes, enough for 2 x the number of known headers
(fragment array... note that fragments can point to a "next"
fragment if the same header is spread across multiple entries)
- linear char array where the known header payload gets written
(fragments point into null-terminated strings stored in here,
only the known header content is stored)
http headers can legally be split over multiple headers of the same
name which should be concatenated. This scheme does not linearly
conatenate them but uses a linked list in the fragment structs to
link them. There are apis to get the total length and copy out a
linear, concatenated version to a buffer.
Signed-off-by: Andy Green <andy.green@linaro.org>
2013-02-10 18:02:31 +08:00
|
|
|
|
2018-09-04 08:06:46 +08:00
|
|
|
lwsl_info("closing connection (prot %s) "
|
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
|
|
|
"due to bail2 connection error: %s\n", wsi->a.protocol ?
|
|
|
|
wsi->a.protocol->name : "unknown", cce);
|
replace per header mallocs with single malloc 3 level struct
This big patch replaces the malloc / realloc per header
approach used until now with a single three-level struct
that gets malloc'd during the header union phase and freed
in one go when we transition to a different union phase.
It's more expensive in that we malloc a bit more than 4Kbytes,
but it's a lot cheaper in terms of malloc, frees, heap fragmentation,
no reallocs, nothing to configure. It also moves from arrays of
pointers (8 bytes on x86_64) to unsigned short offsets into the
data array, (2 bytes on all platforms).
The 3-level thing is all in one struct
- array indexed by the header enum, pointing to first "fragment" index
(ie, header type to fragment lookup, or 0 for none)
- array of fragments indexes, enough for 2 x the number of known headers
(fragment array... note that fragments can point to a "next"
fragment if the same header is spread across multiple entries)
- linear char array where the known header payload gets written
(fragments point into null-terminated strings stored in here,
only the known header content is stored)
http headers can legally be split over multiple headers of the same
name which should be concatenated. This scheme does not linearly
conatenate them but uses a linked list in the fragment structs to
link them. There are apis to get the total length and copy out a
linear, concatenated version to a buffer.
Signed-off-by: Andy Green <andy.green@linaro.org>
2013-02-10 18:02:31 +08:00
|
|
|
|
2016-01-13 18:48:50 +08:00
|
|
|
/* closing will free up his parsing allocations */
|
2020-12-12 06:21:40 +00:00
|
|
|
lws_close_free_wsi(wsi, (enum lws_close_status)close_reason, "c hs interp");
|
2013-01-16 11:53:05 +08:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
2018-04-27 19:16:50 +08:00
|
|
|
#endif
|
2013-01-16 11:53:05 +08:00
|
|
|
|
2019-10-07 14:28:18 +01:00
|
|
|
/*
|
|
|
|
* set the boundary string and the content-type for client multipart mime
|
|
|
|
*/
|
|
|
|
|
|
|
|
uint8_t *
|
|
|
|
lws_http_multipart_headers(struct lws *wsi, uint8_t *p)
|
|
|
|
{
|
|
|
|
char buf[10], arg[48];
|
|
|
|
int n;
|
|
|
|
|
2020-08-14 09:07:27 +01:00
|
|
|
if (lws_get_random(wsi->a.context, (uint8_t *)buf, sizeof(buf)) !=
|
|
|
|
sizeof(buf))
|
|
|
|
return NULL;
|
|
|
|
|
2019-10-07 14:28:18 +01:00
|
|
|
lws_b64_encode_string(buf, sizeof(buf),
|
|
|
|
wsi->http.multipart_boundary,
|
|
|
|
sizeof(wsi->http.multipart_boundary));
|
|
|
|
|
2020-06-12 07:22:59 +01:00
|
|
|
n = lws_snprintf(arg, sizeof(arg), "multipart/form-data; boundary=\"%s\"",
|
2019-10-07 14:28:18 +01:00
|
|
|
wsi->http.multipart_boundary);
|
|
|
|
|
|
|
|
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
|
|
|
|
(uint8_t *)arg, n, &p, p + 100))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
wsi->http.multipart = wsi->http.multipart_issue_boundary = 1;
|
2020-01-02 08:32:23 +00:00
|
|
|
lws_client_http_body_pending(wsi, 1);
|
2019-10-07 14:28:18 +01:00
|
|
|
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
lws_client_http_multipart(struct lws *wsi, const char *name,
|
|
|
|
const char *filename, const char *content_type,
|
|
|
|
char **p, char *end)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Client conn must have been created with LCCSCF_HTTP_MULTIPART_MIME
|
|
|
|
* flag to use this api
|
|
|
|
*/
|
|
|
|
assert(wsi->http.multipart);
|
|
|
|
|
|
|
|
if (!name) {
|
2020-12-12 06:21:40 +00:00
|
|
|
*p += lws_snprintf((char *)(*p), lws_ptr_diff_size_t(end, *p),
|
2019-10-07 14:28:18 +01:00
|
|
|
"\xd\xa--%s--\xd\xa",
|
|
|
|
wsi->http.multipart_boundary);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-01-02 08:32:23 +00:00
|
|
|
if (wsi->client_subsequent_mime_part)
|
2020-12-12 06:21:40 +00:00
|
|
|
*p += lws_snprintf((char *)(*p), lws_ptr_diff_size_t(end, *p), "\xd\xa");
|
2020-01-02 08:32:23 +00:00
|
|
|
wsi->client_subsequent_mime_part = 1;
|
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
*p += lws_snprintf((char *)(*p), lws_ptr_diff_size_t(end, *p), "--%s\xd\xa"
|
2019-10-07 14:28:18 +01:00
|
|
|
"Content-Disposition: form-data; "
|
|
|
|
"name=\"%s\"",
|
|
|
|
wsi->http.multipart_boundary, name);
|
|
|
|
if (filename)
|
2020-12-12 06:21:40 +00:00
|
|
|
*p += lws_snprintf((char *)(*p), lws_ptr_diff_size_t(end, *p),
|
2019-10-07 14:28:18 +01:00
|
|
|
"; filename=\"%s\"", filename);
|
|
|
|
|
|
|
|
if (content_type)
|
2020-12-12 06:21:40 +00:00
|
|
|
*p += lws_snprintf((char *)(*p), lws_ptr_diff_size_t(end, *p), "\xd\xa"
|
2019-10-07 14:28:18 +01:00
|
|
|
"Content-Type: %s", content_type);
|
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
*p += lws_snprintf((char *)(*p), lws_ptr_diff_size_t(end, *p), "\xd\xa\xd\xa");
|
2019-10-07 14:28:18 +01:00
|
|
|
|
|
|
|
return *p == end;
|
|
|
|
}
|
|
|
|
|
2013-01-16 11:53:05 +08:00
|
|
|
char *
|
2015-12-15 21:15:58 +08:00
|
|
|
lws_generate_client_handshake(struct lws *wsi, char *pkt)
|
2013-01-16 11:53:05 +08:00
|
|
|
{
|
2019-10-07 14:28:18 +01:00
|
|
|
const char *meth, *pp = lws_hdr_simple_ptr(wsi,
|
2021-06-17 10:07:04 +01:00
|
|
|
_WSI_TOKEN_CLIENT_SENT_PROTOCOLS), *path;
|
2021-03-02 16:34:33 +00:00
|
|
|
char *p = pkt, *p1, *end = p + wsi->a.context->pt_serv_buf_size;
|
2013-01-16 11:53:05 +08:00
|
|
|
|
2016-02-29 13:18:30 +08:00
|
|
|
meth = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_METHOD);
|
|
|
|
if (!meth) {
|
|
|
|
meth = "GET";
|
|
|
|
wsi->do_ws = 1;
|
2017-03-16 10:46:31 +08:00
|
|
|
} else {
|
2016-02-29 13:18:30 +08:00
|
|
|
wsi->do_ws = 0;
|
2017-03-16 10:46:31 +08:00
|
|
|
}
|
2016-02-29 13:18:30 +08:00
|
|
|
|
2017-03-07 16:06:05 +08:00
|
|
|
if (!strcmp(meth, "RAW")) {
|
|
|
|
lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
|
|
|
|
lwsl_notice("client transition to raw\n");
|
2017-03-16 10:46:31 +08:00
|
|
|
|
2017-03-07 16:06:05 +08:00
|
|
|
if (pp) {
|
|
|
|
const struct lws_protocols *pr;
|
|
|
|
|
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
|
|
|
pr = lws_vhost_name_to_protocol(wsi->a.vhost, pp);
|
2017-03-07 16:06:05 +08:00
|
|
|
|
|
|
|
if (!pr) {
|
|
|
|
lwsl_err("protocol %s not enabled on vhost\n",
|
|
|
|
pp);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-09-02 14:35:37 +08:00
|
|
|
lws_bind_protocol(wsi, pr, __func__);
|
2017-03-07 16:06:05 +08:00
|
|
|
}
|
2017-03-16 10:46:31 +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 ((wsi->a.protocol->callback)(wsi, LWS_CALLBACK_RAW_ADOPT,
|
2018-04-11 13:39:42 +08:00
|
|
|
wsi->user_space, NULL, 0))
|
2017-03-07 16:06:05 +08:00
|
|
|
return NULL;
|
|
|
|
|
2018-11-29 08:29:48 +08:00
|
|
|
lws_role_transition(wsi, LWSIFR_CLIENT, LRS_ESTABLISHED,
|
|
|
|
&role_ops_raw_skt);
|
2017-03-07 16:06:05 +08:00
|
|
|
lws_header_table_detach(wsi, 1);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-01-16 11:53:05 +08:00
|
|
|
/*
|
|
|
|
* 04 example client handshake
|
|
|
|
*
|
|
|
|
* GET /chat HTTP/1.1
|
|
|
|
* Host: server.example.com
|
|
|
|
* Upgrade: websocket
|
|
|
|
* Connection: Upgrade
|
|
|
|
* Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
|
|
|
|
* Sec-WebSocket-Origin: http://example.com
|
|
|
|
* Sec-WebSocket-Protocol: chat, superchat
|
|
|
|
* Sec-WebSocket-Version: 4
|
|
|
|
*/
|
|
|
|
|
2021-06-17 10:07:04 +01:00
|
|
|
path = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_URI);
|
|
|
|
if (!path) {
|
|
|
|
if (wsi->stash && wsi->stash->cis[CIS_PATH] &&
|
|
|
|
wsi->stash->cis[CIS_PATH][0])
|
|
|
|
path = wsi->stash->cis[CIS_PATH];
|
|
|
|
else
|
|
|
|
path = "/";
|
|
|
|
}
|
|
|
|
|
2021-03-02 16:34:33 +00:00
|
|
|
p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
|
2021-06-17 10:07:04 +01:00
|
|
|
"%s %s HTTP/1.1\x0d\x0a", meth, path);
|
2013-01-16 11:53:05 +08:00
|
|
|
|
2021-11-11 23:27:12 +07:00
|
|
|
if (!(wsi->flags & LCCSCF_HTTP_NO_CACHE_CONTROL))
|
|
|
|
p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
|
|
|
|
"Pragma: no-cache\x0d\x0a"
|
|
|
|
"Cache-Control: no-cache\x0d\x0a");
|
2013-01-16 11:53:05 +08:00
|
|
|
|
2021-03-02 16:34:33 +00:00
|
|
|
p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
|
|
|
|
"Host: %s\x0d\x0a",
|
|
|
|
lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_HOST));
|
2016-02-29 13:18:30 +08:00
|
|
|
|
2017-01-23 19:52:27 +08:00
|
|
|
if (lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN)) {
|
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 (lws_check_opt(wsi->a.context->options,
|
2017-11-16 09:37:04 +08:00
|
|
|
LWS_SERVER_OPTION_JUST_USE_RAW_ORIGIN))
|
2021-03-02 16:34:33 +00:00
|
|
|
p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
|
|
|
|
"Origin: %s\x0d\x0a",
|
|
|
|
lws_hdr_simple_ptr(wsi,
|
2017-11-16 09:37:04 +08:00
|
|
|
_WSI_TOKEN_CLIENT_ORIGIN));
|
2017-01-23 19:52:27 +08:00
|
|
|
else
|
2021-03-02 16:34:33 +00:00
|
|
|
p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
|
2021-06-17 10:07:04 +01:00
|
|
|
"Origin: %s://%s\x0d\x0a",
|
|
|
|
wsi->flags & LCCSCF_USE_SSL ?
|
|
|
|
"https" : "http",
|
2021-03-02 16:34:33 +00:00
|
|
|
lws_hdr_simple_ptr(wsi,
|
2017-11-16 09:37:04 +08:00
|
|
|
_WSI_TOKEN_CLIENT_ORIGIN));
|
2017-01-23 19:52:27 +08:00
|
|
|
}
|
2019-03-22 06:22:40 +08:00
|
|
|
|
2019-10-07 14:28:18 +01:00
|
|
|
if (wsi->flags & LCCSCF_HTTP_MULTIPART_MIME) {
|
|
|
|
p1 = (char *)lws_http_multipart_headers(wsi, (uint8_t *)p);
|
|
|
|
if (!p1)
|
|
|
|
return NULL;
|
|
|
|
p = p1;
|
|
|
|
}
|
|
|
|
|
2019-03-22 06:22:40 +08:00
|
|
|
#if defined(LWS_WITH_HTTP_PROXY)
|
|
|
|
if (wsi->parent &&
|
|
|
|
lws_hdr_total_length(wsi->parent, WSI_TOKEN_HTTP_CONTENT_LENGTH)) {
|
2021-03-02 16:34:33 +00:00
|
|
|
p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
|
|
|
|
"Content-Length: %s\x0d\x0a",
|
2019-03-22 06:22:40 +08:00
|
|
|
lws_hdr_simple_ptr(wsi->parent, WSI_TOKEN_HTTP_CONTENT_LENGTH));
|
|
|
|
if (atoi(lws_hdr_simple_ptr(wsi->parent, WSI_TOKEN_HTTP_CONTENT_LENGTH)))
|
|
|
|
wsi->client_http_body_pending = 1;
|
|
|
|
}
|
2019-03-22 18:52:08 +08:00
|
|
|
if (wsi->parent &&
|
|
|
|
lws_hdr_total_length(wsi->parent, WSI_TOKEN_HTTP_AUTHORIZATION)) {
|
2021-03-02 16:34:33 +00:00
|
|
|
p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
|
|
|
|
"Authorization: %s\x0d\x0a",
|
2019-03-22 18:52:08 +08:00
|
|
|
lws_hdr_simple_ptr(wsi->parent, WSI_TOKEN_HTTP_AUTHORIZATION));
|
|
|
|
}
|
2019-03-22 06:22:40 +08:00
|
|
|
if (wsi->parent &&
|
|
|
|
lws_hdr_total_length(wsi->parent, WSI_TOKEN_HTTP_CONTENT_TYPE)) {
|
2021-03-02 16:34:33 +00:00
|
|
|
p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
|
|
|
|
"Content-Type: %s\x0d\x0a",
|
2019-03-22 06:22:40 +08:00
|
|
|
lws_hdr_simple_ptr(wsi->parent, WSI_TOKEN_HTTP_CONTENT_TYPE));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2023-12-08 07:30:50 +00:00
|
|
|
#if defined(LWS_WITH_HTTP_DIGEST_AUTH)
|
|
|
|
if (wsi->http.digest_auth_hdr) {
|
|
|
|
p += lws_snprintf(p, 1024, "Authorization: %s\x0d\x0a",
|
|
|
|
wsi->http.digest_auth_hdr);
|
|
|
|
lws_free(wsi->http.digest_auth_hdr);
|
|
|
|
wsi->http.digest_auth_hdr = NULL;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2018-04-25 08:42:18 +08:00
|
|
|
#if defined(LWS_ROLE_WS)
|
2018-10-12 05:05:33 +08:00
|
|
|
if (wsi->do_ws) {
|
|
|
|
const char *conn1 = "";
|
2019-07-14 15:45:32 -07:00
|
|
|
// if (!wsi->client_pipeline)
|
|
|
|
// conn1 = "close, ";
|
2018-10-12 05:05:33 +08:00
|
|
|
p = lws_generate_client_ws_handshake(wsi, p, conn1);
|
2024-06-24 15:11:17 +08:00
|
|
|
if (!p)
|
|
|
|
return NULL;
|
2018-10-12 05:05:33 +08:00
|
|
|
} else
|
2018-04-25 08:42:18 +08:00
|
|
|
#endif
|
2019-07-13 11:49:06 -07:00
|
|
|
{
|
2018-10-12 05:05:33 +08:00
|
|
|
if (!wsi->client_pipeline)
|
2019-08-01 23:03:14 +08:00
|
|
|
p += lws_snprintf(p, 64, "connection: close\x0d\x0a");
|
2019-07-13 11:49:06 -07:00
|
|
|
}
|
2018-04-11 13:39:42 +08:00
|
|
|
|
|
|
|
/* give userland a chance to append, eg, cookies */
|
|
|
|
|
2021-07-05 16:41:41 +08:00
|
|
|
#if defined(LWS_WITH_CACHE_NSCOOKIEJAR) && defined(LWS_WITH_CLIENT)
|
|
|
|
if (wsi->flags & LCCSCF_CACHE_COOKIES)
|
|
|
|
lws_cookie_send_cookies(wsi, &p, end);
|
|
|
|
#endif
|
|
|
|
|
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 (wsi->a.protocol->callback(wsi,
|
2018-11-23 08:47:56 +08:00
|
|
|
LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER,
|
|
|
|
wsi->user_space, &p,
|
2020-12-12 06:21:40 +00:00
|
|
|
(unsigned int)((pkt + wsi->a.context->pt_serv_buf_size) - p - 12)))
|
2018-04-11 13:39:42 +08:00
|
|
|
return NULL;
|
|
|
|
|
2019-10-09 19:11:20 +01:00
|
|
|
if (wsi->flags & LCCSCF_HTTP_X_WWW_FORM_URLENCODED) {
|
2021-03-02 16:34:33 +00:00
|
|
|
p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "Content-Type: application/x-www-form-urlencoded\x0d\x0a");
|
|
|
|
p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "Content-Length: %lu\x0d\x0a", wsi->http.writeable_len);
|
2019-10-09 19:11:20 +01:00
|
|
|
lws_client_http_body_pending(wsi, 1);
|
|
|
|
}
|
|
|
|
|
2021-03-02 16:34:33 +00:00
|
|
|
p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "\x0d\x0a");
|
2018-04-11 13:39:42 +08:00
|
|
|
|
2021-03-23 07:14:26 +00:00
|
|
|
if (wsi->client_http_body_pending || lws_has_buffered_out(wsi))
|
2020-01-02 08:32:23 +00:00
|
|
|
lws_callback_on_writable(wsi);
|
|
|
|
|
2021-01-06 15:08:22 +00:00
|
|
|
lws_metrics_caliper_bind(wsi->cal_conn, wsi->a.context->mt_http_txn);
|
2021-03-15 05:20:15 +00:00
|
|
|
#if defined(LWS_WITH_CONMON)
|
|
|
|
wsi->conmon_datum = lws_now_usecs();
|
|
|
|
#endif
|
2021-01-06 15:08:22 +00:00
|
|
|
|
2019-03-22 18:52:08 +08:00
|
|
|
// puts(pkt);
|
|
|
|
|
2018-04-11 13:39:42 +08:00
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2018-04-27 19:16:50 +08:00
|
|
|
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
|
2020-02-28 09:29:25 +00:00
|
|
|
#if defined(LWS_WITH_HTTP_BASIC_AUTH)
|
2018-04-27 19:16:50 +08:00
|
|
|
|
2019-12-22 04:58:44 +00:00
|
|
|
int
|
2024-03-11 07:47:27 +00:00
|
|
|
lws_http_basic_auth_gen2(const char *user, const void *pw, size_t pwd_len,
|
|
|
|
char *buf, size_t len)
|
2019-12-22 04:58:44 +00:00
|
|
|
{
|
2024-03-11 07:47:27 +00:00
|
|
|
size_t n = strlen(user), m = pwd_len;
|
2019-12-22 04:58:44 +00:00
|
|
|
char b[128];
|
|
|
|
|
|
|
|
if (len < 6 + ((4 * (n + m + 1)) / 3) + 1)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
memcpy(buf, "Basic ", 6);
|
|
|
|
|
2024-03-11 07:47:27 +00:00
|
|
|
n = (unsigned int)lws_snprintf(b, sizeof(b), "%s:", user);
|
|
|
|
if ((n + pwd_len) >= sizeof(b) - 2)
|
2019-12-22 04:58:44 +00:00
|
|
|
return 2;
|
|
|
|
|
2024-03-11 07:47:27 +00:00
|
|
|
memcpy(&b[n], pw, pwd_len);
|
|
|
|
n += pwd_len;
|
|
|
|
|
2020-01-11 14:04:50 +00:00
|
|
|
lws_b64_encode_string(b, (int)n, buf + 6, (int)len - 6);
|
2019-12-22 04:58:44 +00:00
|
|
|
buf[len - 1] = '\0';
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2024-03-11 07:47:27 +00:00
|
|
|
int lws_http_basic_auth_gen(const char *user, const char *pw, char *buf, size_t len)
|
|
|
|
{
|
|
|
|
return lws_http_basic_auth_gen2(user, pw, strlen(pw), buf, len);
|
|
|
|
}
|
|
|
|
|
2020-02-28 09:29:25 +00:00
|
|
|
#endif
|
|
|
|
|
2020-01-02 08:32:23 +00:00
|
|
|
int
|
2018-04-11 13:39:42 +08:00
|
|
|
lws_http_client_read(struct lws *wsi, char **buf, int *len)
|
|
|
|
{
|
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];
|
2019-08-27 06:06:13 +01:00
|
|
|
struct lws_tokens eb;
|
|
|
|
int buffered, n, consumed = 0;
|
|
|
|
|
2020-01-20 10:02:56 +00:00
|
|
|
/*
|
|
|
|
* If the caller provided a non-NULL *buf and nonzero *len, we should
|
|
|
|
* use that as the buffer for the read action, limititing it to *len
|
|
|
|
* (actual payload will be less if chunked headers inside).
|
|
|
|
*
|
|
|
|
* If it's NULL / 0 length, buflist_aware_read will use the pt_serv_buf
|
|
|
|
*/
|
|
|
|
|
|
|
|
eb.token = (unsigned char *)*buf;
|
|
|
|
eb.len = *len;
|
2018-04-11 13:39:42 +08:00
|
|
|
|
2020-01-20 10:02:56 +00:00
|
|
|
buffered = lws_buflist_aware_read(pt, wsi, &eb, 0, __func__);
|
|
|
|
*buf = (char *)eb.token; /* may be pointing to buflist or pt_serv_buf */
|
2018-04-11 13:39:42 +08:00
|
|
|
*len = 0;
|
|
|
|
|
2019-08-27 06:06:13 +01:00
|
|
|
/*
|
|
|
|
* we're taking on responsibility for handling used / unused eb
|
|
|
|
* when we leave, via lws_buflist_aware_finished_consuming()
|
|
|
|
*/
|
|
|
|
|
|
|
|
// lwsl_notice("%s: eb.len %d ENTRY chunk remaining %d\n", __func__, eb.len,
|
|
|
|
// wsi->chunk_remaining);
|
2018-04-11 13:39:42 +08:00
|
|
|
|
|
|
|
/* allow the source to signal he has data again next time */
|
2019-07-13 11:32:34 -07:00
|
|
|
if (lws_change_pollfd(wsi, 0, LWS_POLLIN))
|
|
|
|
return -1;
|
2018-04-11 13:39:42 +08:00
|
|
|
|
2019-08-27 06:06:13 +01:00
|
|
|
if (buffered < 0) {
|
2018-10-12 10:57:11 +08:00
|
|
|
lwsl_debug("%s: SSL capable error\n", __func__);
|
2020-05-19 18:34:38 +01:00
|
|
|
|
|
|
|
if (wsi->http.ah &&
|
|
|
|
wsi->http.ah->parser_state == WSI_PARSING_COMPLETE &&
|
|
|
|
!lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH))
|
|
|
|
/*
|
|
|
|
* We had the headers from this stream, but as there
|
|
|
|
* was no content-length: we had to wait until the
|
|
|
|
* stream ended to inform the user code the transaction
|
|
|
|
* has completed to the best of our knowledge
|
|
|
|
*/
|
|
|
|
if (lws_http_transaction_completed_client(wsi))
|
|
|
|
/*
|
|
|
|
* We're going to close anyway, but that api has
|
|
|
|
* warn_unused_result
|
|
|
|
*/
|
|
|
|
return -1;
|
|
|
|
|
2018-04-11 13:39:42 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2019-08-27 06:06:13 +01:00
|
|
|
if (eb.len <= 0)
|
2018-04-11 13:39:42 +08:00
|
|
|
return 0;
|
|
|
|
|
2019-08-27 06:06:13 +01:00
|
|
|
*len = eb.len;
|
2018-04-11 13:39:42 +08:00
|
|
|
wsi->client_rx_avail = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* server may insist on transfer-encoding: chunked,
|
|
|
|
* so http client must deal with it
|
|
|
|
*/
|
|
|
|
spin_chunks:
|
2019-08-27 06:06:13 +01:00
|
|
|
//lwsl_notice("%s: len %d SPIN chunk remaining %d\n", __func__, *len,
|
|
|
|
// wsi->chunk_remaining);
|
2018-04-11 13:39:42 +08:00
|
|
|
while (wsi->chunked && (wsi->chunk_parser != ELCP_CONTENT) && *len) {
|
|
|
|
switch (wsi->chunk_parser) {
|
|
|
|
case ELCP_HEX:
|
|
|
|
if ((*buf)[0] == '\x0d') {
|
|
|
|
wsi->chunk_parser = ELCP_CR;
|
|
|
|
break;
|
2016-02-29 13:18:30 +08:00
|
|
|
}
|
2018-04-11 13:39:42 +08:00
|
|
|
n = char_to_hex((*buf)[0]);
|
|
|
|
if (n < 0) {
|
2019-08-27 06:06:13 +01:00
|
|
|
lwsl_err("%s: chunking failure A\n", __func__);
|
2018-04-11 13:39:42 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
wsi->chunk_remaining <<= 4;
|
|
|
|
wsi->chunk_remaining |= n;
|
|
|
|
break;
|
|
|
|
case ELCP_CR:
|
|
|
|
if ((*buf)[0] != '\x0a') {
|
2019-08-27 06:06:13 +01:00
|
|
|
lwsl_err("%s: chunking failure B\n", __func__);
|
2018-04-11 13:39:42 +08:00
|
|
|
return -1;
|
|
|
|
}
|
2020-01-30 13:19:11 +00:00
|
|
|
if (wsi->chunk_remaining) {
|
|
|
|
wsi->chunk_parser = ELCP_CONTENT;
|
|
|
|
//lwsl_notice("starting chunk size %d (block rem %d)\n",
|
|
|
|
// wsi->chunk_remaining, *len);
|
2018-04-11 13:39:42 +08:00
|
|
|
break;
|
2020-01-30 13:19:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
wsi->chunk_parser = ELCP_TRAILER_CR;
|
|
|
|
break;
|
2013-01-16 11:53:05 +08:00
|
|
|
|
2018-04-11 13:39:42 +08:00
|
|
|
case ELCP_CONTENT:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ELCP_POST_CR:
|
|
|
|
if ((*buf)[0] != '\x0d') {
|
2019-08-27 06:06:13 +01:00
|
|
|
lwsl_err("%s: chunking failure C\n", __func__);
|
2020-12-12 06:21:40 +00:00
|
|
|
lwsl_hexdump_err(*buf, (unsigned int)*len);
|
2016-02-29 13:18:30 +08:00
|
|
|
|
2018-04-11 13:39:42 +08:00
|
|
|
return -1;
|
2016-02-29 13:18:30 +08:00
|
|
|
}
|
|
|
|
|
2018-04-11 13:39:42 +08:00
|
|
|
wsi->chunk_parser = ELCP_POST_LF;
|
|
|
|
break;
|
2016-02-29 13:18:30 +08:00
|
|
|
|
2018-04-11 13:39:42 +08:00
|
|
|
case ELCP_POST_LF:
|
2018-09-10 08:53:41 +08:00
|
|
|
if ((*buf)[0] != '\x0a') {
|
2019-08-27 06:06:13 +01:00
|
|
|
lwsl_err("%s: chunking failure D\n", __func__);
|
2018-09-10 08:53:41 +08:00
|
|
|
|
2018-04-11 13:39:42 +08:00
|
|
|
return -1;
|
2018-09-10 08:53:41 +08:00
|
|
|
}
|
2013-01-16 11:53:05 +08:00
|
|
|
|
2018-04-11 13:39:42 +08:00
|
|
|
wsi->chunk_parser = ELCP_HEX;
|
|
|
|
wsi->chunk_remaining = 0;
|
|
|
|
break;
|
2020-01-30 13:19:11 +00:00
|
|
|
|
|
|
|
case ELCP_TRAILER_CR:
|
|
|
|
if ((*buf)[0] != '\x0d') {
|
|
|
|
lwsl_err("%s: chunking failure F\n", __func__);
|
2020-12-12 06:21:40 +00:00
|
|
|
lwsl_hexdump_err(*buf, (unsigned int)*len);
|
2020-01-30 13:19:11 +00:00
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
wsi->chunk_parser = ELCP_TRAILER_LF;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ELCP_TRAILER_LF:
|
|
|
|
if ((*buf)[0] != '\x0a') {
|
|
|
|
lwsl_err("%s: chunking failure F\n", __func__);
|
2020-12-12 06:21:40 +00:00
|
|
|
lwsl_hexdump_err(*buf, (unsigned int)*len);
|
2020-01-30 13:19:11 +00:00
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
(*buf)++;
|
|
|
|
(*len)--;
|
|
|
|
consumed++;
|
|
|
|
|
|
|
|
lwsl_info("final chunk\n");
|
|
|
|
goto completed;
|
2013-01-16 11:53:05 +08:00
|
|
|
}
|
2018-04-11 13:39:42 +08:00
|
|
|
(*buf)++;
|
|
|
|
(*len)--;
|
2019-08-27 06:06:13 +01:00
|
|
|
consumed++;
|
2018-04-11 13:39:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (wsi->chunked && !wsi->chunk_remaining)
|
2019-08-27 06:06:13 +01:00
|
|
|
goto account_and_ret;
|
2013-01-16 11:53:05 +08:00
|
|
|
|
2018-04-11 13:39:42 +08:00
|
|
|
if (wsi->http.rx_content_remain &&
|
|
|
|
wsi->http.rx_content_remain < (unsigned int)*len)
|
|
|
|
n = (int)wsi->http.rx_content_remain;
|
|
|
|
else
|
|
|
|
n = *len;
|
2013-01-16 11:53:05 +08:00
|
|
|
|
2018-04-11 13:39:42 +08:00
|
|
|
if (wsi->chunked && wsi->chunk_remaining &&
|
|
|
|
wsi->chunk_remaining < n)
|
|
|
|
n = wsi->chunk_remaining;
|
2013-01-16 11:53:05 +08:00
|
|
|
|
2018-09-04 08:06:46 +08:00
|
|
|
#if defined(LWS_WITH_HTTP_PROXY) && defined(LWS_WITH_HUBBUB)
|
2018-04-11 13:39:42 +08:00
|
|
|
/* hubbub */
|
2018-04-27 14:36:10 +08:00
|
|
|
if (wsi->http.perform_rewrite)
|
|
|
|
lws_rewrite_parse(wsi->http.rw, (unsigned char *)*buf, n);
|
2018-04-11 13:39:42 +08:00
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
2019-04-21 19:57:19 +01:00
|
|
|
if (
|
|
|
|
#if defined(LWS_WITH_HTTP_PROXY)
|
2020-01-30 13:19:11 +00:00
|
|
|
!wsi->protocol_bind_balance ==
|
|
|
|
!!wsi->http.proxy_clientside
|
2019-04-21 19:57:19 +01:00
|
|
|
#else
|
2020-01-30 13:19:11 +00:00
|
|
|
!!wsi->protocol_bind_balance
|
2019-04-21 19:57:19 +01:00
|
|
|
#endif
|
2019-11-12 10:17:36 +00:00
|
|
|
) {
|
2020-07-20 14:41:28 +01:00
|
|
|
int q;
|
|
|
|
|
|
|
|
q = user_callback_handle_rxflow(wsi->a.protocol->callback,
|
2020-01-30 13:19:11 +00:00
|
|
|
wsi, LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ,
|
2020-12-12 06:21:40 +00:00
|
|
|
wsi->user_space, *buf, (unsigned int)n);
|
2020-07-20 14:41:28 +01:00
|
|
|
if (q) {
|
|
|
|
lwsl_info("%s: RECEIVE_CLIENT_HTTP_READ returned %d\n",
|
|
|
|
__func__, q);
|
2016-02-29 13:18:30 +08:00
|
|
|
|
2020-07-20 14:41:28 +01:00
|
|
|
return q;
|
2019-11-12 10:17:36 +00:00
|
|
|
}
|
|
|
|
} else
|
|
|
|
lwsl_notice("%s: swallowed read (%d)\n", __func__, n);
|
2016-02-29 13:18:30 +08:00
|
|
|
}
|
2013-01-16 11:53:05 +08:00
|
|
|
|
2019-08-27 06:06:13 +01:00
|
|
|
(*buf) += n;
|
|
|
|
*len -= n;
|
|
|
|
if (wsi->chunked && wsi->chunk_remaining)
|
2018-04-11 13:39:42 +08:00
|
|
|
wsi->chunk_remaining -= n;
|
2019-08-27 06:06:13 +01:00
|
|
|
|
|
|
|
//lwsl_notice("chunk_remaining <- %d, block remaining %d\n",
|
|
|
|
// wsi->chunk_remaining, *len);
|
|
|
|
|
|
|
|
consumed += n;
|
|
|
|
//eb.token += n;
|
|
|
|
//eb.len -= n;
|
2013-01-16 11:53:05 +08:00
|
|
|
|
2018-04-11 13:39:42 +08:00
|
|
|
if (wsi->chunked && !wsi->chunk_remaining)
|
|
|
|
wsi->chunk_parser = ELCP_POST_CR;
|
2013-01-16 11:53:05 +08:00
|
|
|
|
2018-04-11 13:39:42 +08:00
|
|
|
if (wsi->chunked && *len)
|
|
|
|
goto spin_chunks;
|
2013-01-16 11:53:05 +08:00
|
|
|
|
2018-04-11 13:39:42 +08:00
|
|
|
if (wsi->chunked)
|
2019-08-27 06:06:13 +01:00
|
|
|
goto account_and_ret;
|
2018-04-11 13:39:42 +08:00
|
|
|
|
|
|
|
/* if we know the content length, decrement the content remaining */
|
|
|
|
if (wsi->http.rx_content_length > 0)
|
2020-12-12 06:21:40 +00:00
|
|
|
wsi->http.rx_content_remain -= (unsigned int)n;
|
2018-04-11 13:39:42 +08:00
|
|
|
|
2020-02-28 10:31:04 +00:00
|
|
|
// lwsl_notice("rx_content_remain %lld, rx_content_length %lld, giv %d\n",
|
|
|
|
// wsi->http.rx_content_remain, wsi->http.rx_content_length,
|
|
|
|
// wsi->http.content_length_given);
|
2018-04-11 13:39:42 +08:00
|
|
|
|
2020-02-28 10:31:04 +00:00
|
|
|
if (wsi->http.rx_content_remain || !wsi->http.content_length_given)
|
2019-08-27 06:06:13 +01:00
|
|
|
goto account_and_ret;
|
2018-04-11 13:39:42 +08:00
|
|
|
|
|
|
|
completed:
|
|
|
|
|
|
|
|
if (lws_http_transaction_completed_client(wsi)) {
|
2020-12-08 10:30:55 +00:00
|
|
|
lwsl_info("%s: transaction completed says -1\n", __func__);
|
2018-04-11 13:39:42 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2019-08-27 06:06:13 +01:00
|
|
|
account_and_ret:
|
|
|
|
// lwsl_warn("%s: on way out, consuming %d / %d\n", __func__, consumed, eb.len);
|
|
|
|
if (lws_buflist_aware_finished_consuming(wsi, &eb, consumed, buffered,
|
|
|
|
__func__))
|
|
|
|
return -1;
|
|
|
|
|
2018-04-11 13:39:42 +08:00
|
|
|
return 0;
|
2013-01-16 11:53:05 +08:00
|
|
|
}
|
2018-04-27 19:16:50 +08:00
|
|
|
|
2018-06-04 07:14:42 +08:00
|
|
|
#endif
|
2020-09-19 13:27:33 +01:00
|
|
|
|
|
|
|
static uint8_t hnames2[] = {
|
|
|
|
_WSI_TOKEN_CLIENT_ORIGIN,
|
|
|
|
_WSI_TOKEN_CLIENT_SENT_PROTOCOLS,
|
|
|
|
_WSI_TOKEN_CLIENT_METHOD,
|
2021-06-17 10:07:04 +01:00
|
|
|
_WSI_TOKEN_CLIENT_IFACE
|
2020-09-19 13:27:33 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* lws_client_reset() - retarget a connected wsi to start over with a new
|
|
|
|
* connection (ie, redirect)
|
|
|
|
* this only works if still in HTTP, ie, not upgraded yet
|
|
|
|
* wsi: connection to reset
|
|
|
|
* address: network address of the new server
|
|
|
|
* port: port to connect to
|
|
|
|
* path: uri path to connect to on the new server
|
|
|
|
* host: host header to send to the new server
|
|
|
|
*/
|
|
|
|
struct lws *
|
|
|
|
lws_client_reset(struct lws **pwsi, int ssl, const char *address, int port,
|
|
|
|
const char *path, const char *host, char weak)
|
|
|
|
{
|
2021-04-09 15:23:06 +01:00
|
|
|
struct lws_context_per_thread *pt;
|
2020-09-19 13:27:33 +01:00
|
|
|
#if defined(LWS_ROLE_WS)
|
|
|
|
struct _lws_websocket_related *ws;
|
|
|
|
#endif
|
2021-06-17 10:07:04 +01:00
|
|
|
const char *cisin[CIS_COUNT];
|
2020-09-19 13:27:33 +01:00
|
|
|
struct lws *wsi;
|
2021-06-17 10:07:04 +01:00
|
|
|
size_t o;
|
2020-09-19 13:27:33 +01:00
|
|
|
int n;
|
|
|
|
|
|
|
|
if (!pwsi)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
wsi = *pwsi;
|
2021-04-09 15:23:06 +01:00
|
|
|
pt = &wsi->a.context->pt[(int)wsi->tsi];
|
2020-09-19 13:27:33 +01:00
|
|
|
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_debug("%s: %s: redir %d: %s\n", __func__, lws_wsi_tag(wsi),
|
|
|
|
wsi->redirects, address);
|
2020-09-19 13:27:33 +01:00
|
|
|
|
2021-06-17 10:07:04 +01:00
|
|
|
if (wsi->redirects == 4) {
|
2020-09-19 13:27:33 +01:00
|
|
|
lwsl_err("%s: Too many redirects\n", __func__);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
wsi->redirects++;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* goal is to close our role part, close the sockfd, detach the ah
|
|
|
|
* but leave our wsi extant and still bound to whatever vhost it was
|
|
|
|
*/
|
|
|
|
|
2021-06-17 10:07:04 +01:00
|
|
|
o = path[0] == '/' && path[1] == '/';
|
2020-09-19 13:27:33 +01:00
|
|
|
|
2021-06-17 10:07:04 +01:00
|
|
|
memset((char *)cisin, 0, sizeof(cisin));
|
2020-09-19 13:27:33 +01:00
|
|
|
|
2021-06-17 10:07:04 +01:00
|
|
|
cisin[CIS_ADDRESS] = address;
|
|
|
|
cisin[CIS_PATH] = path + o;
|
|
|
|
cisin[CIS_HOST] = host;
|
2020-09-19 13:27:33 +01:00
|
|
|
|
|
|
|
for (n = 0; n < (int)LWS_ARRAY_SIZE(hnames2); n++)
|
2021-06-17 10:07:04 +01:00
|
|
|
cisin[n + 3] = lws_hdr_simple_ptr(wsi, hnames2[n]);
|
2020-09-19 13:27:33 +01:00
|
|
|
|
2021-06-17 10:07:04 +01:00
|
|
|
#if defined(LWS_WITH_TLS)
|
|
|
|
cisin[CIS_ALPN] = wsi->alpn;
|
|
|
|
#endif
|
|
|
|
|
2023-12-08 07:30:50 +00:00
|
|
|
if (!wsi->stash && lws_client_stash_create(wsi, cisin))
|
2021-06-17 10:07:04 +01:00
|
|
|
return NULL;
|
2020-09-19 13:27:33 +01:00
|
|
|
|
|
|
|
if (!port) {
|
|
|
|
lwsl_info("%s: forcing port 443\n", __func__);
|
|
|
|
|
|
|
|
port = 443;
|
|
|
|
ssl = 1;
|
|
|
|
}
|
|
|
|
|
2021-06-17 10:07:04 +01:00
|
|
|
wsi->c_port = (uint16_t)port;
|
|
|
|
|
|
|
|
wsi->flags = (wsi->flags & (~LCCSCF_USE_SSL)) |
|
|
|
|
(ssl ? LCCSCF_USE_SSL : 0);
|
|
|
|
|
2021-07-27 11:08:08 +01:00
|
|
|
if (!cisin[CIS_ALPN] || !cisin[CIS_ALPN][0])
|
|
|
|
#if defined(LWS_ROLE_H2)
|
|
|
|
cisin[CIS_ALPN] = "h2,http/1.1";
|
|
|
|
#else
|
|
|
|
cisin[CIS_ALPN] = "http/1.1";
|
|
|
|
#endif
|
|
|
|
|
2021-06-17 10:07:04 +01:00
|
|
|
lwsl_notice("%s: REDIRECT %s:%d, path='%s', ssl = %d, alpn='%s'\n",
|
|
|
|
__func__, address, port, path, ssl, cisin[CIS_ALPN]);
|
|
|
|
|
2021-04-09 15:23:06 +01:00
|
|
|
lws_pt_lock(pt, __func__);
|
2020-09-19 13:27:33 +01:00
|
|
|
__remove_wsi_socket_from_fds(wsi);
|
2021-04-09 15:23:06 +01:00
|
|
|
lws_pt_unlock(pt);
|
|
|
|
|
2020-09-19 13:27:33 +01:00
|
|
|
#if defined(LWS_ROLE_WS)
|
|
|
|
if (weak) {
|
|
|
|
ws = wsi->ws;
|
|
|
|
wsi->ws = NULL;
|
|
|
|
}
|
|
|
|
#endif
|
2021-06-17 10:07:04 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* After this point we can't trust the incoming strings like address,
|
|
|
|
* path any more, since they may have been pointing into the old ah.
|
|
|
|
*
|
|
|
|
* We must use the copies in the wsi->stash instead if we want them.
|
|
|
|
*/
|
|
|
|
|
2020-09-19 13:27:33 +01:00
|
|
|
__lws_reset_wsi(wsi); /* detaches ah here */
|
|
|
|
#if defined(LWS_ROLE_WS)
|
|
|
|
if (weak)
|
|
|
|
wsi->ws = ws;
|
|
|
|
#endif
|
|
|
|
wsi->client_pipeline = 1;
|
|
|
|
|
|
|
|
/*
|
2021-06-17 10:07:04 +01:00
|
|
|
* Will complete at close flow
|
2020-09-19 13:27:33 +01:00
|
|
|
*/
|
|
|
|
|
2021-06-17 10:07:04 +01:00
|
|
|
wsi->close_is_redirect = 1;
|
2020-09-19 13:27:33 +01:00
|
|
|
|
|
|
|
return *pwsi;
|
|
|
|
}
|