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

raw: adoption and processing

This commit is contained in:
Andy Green 2017-02-12 20:32:49 +08:00
parent a5f2d8b688
commit 297c0313fa
9 changed files with 857 additions and 759 deletions

View file

@ -95,6 +95,7 @@ STORE_IN_ROM static const char * const set[] = {
"http/1.0 ",
"x-forwarded-for",
"connect ",
"", /* not matchable */

File diff suppressed because it is too large Load diff

View file

@ -221,6 +221,13 @@ lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason)
}
#endif
if (wsi->mode == LWSCM_RAW) {
wsi->vhost->protocols->callback(wsi,
LWS_CALLBACK_RAW_CLOSE, wsi->user_space, NULL, 0);
wsi->socket_is_permanently_unusable = 1;
goto just_kill_connection;
}
if (wsi->mode == LWSCM_HTTP_SERVING_ACCEPTED &&
wsi->u.http.fd != LWS_INVALID_FILE) {
lws_plat_file_close(wsi, wsi->u.http.fd);
@ -424,7 +431,7 @@ just_kill_connection:
* for the POLLIN to show a zero-size rx before coming back and doing
* the actual close.
*/
if (wsi->state != LWSS_SHUTDOWN &&
if (wsi->mode != LWSCM_RAW && wsi->state != LWSS_SHUTDOWN &&
wsi->state != LWSS_CLIENT_UNCONNECTED &&
reason != LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY &&
!wsi->socket_is_permanently_unusable) {
@ -530,7 +537,7 @@ just_kill_connection:
/* tell the user it's all over for this guy */
if (wsi->protocol && wsi->protocol->callback &&
if (wsi->mode != LWSCM_RAW && wsi->protocol && wsi->protocol->callback &&
((wsi->state_pre_close == LWSS_ESTABLISHED) ||
(wsi->state_pre_close == LWSS_RETURNED_CLOSE_ALREADY) ||
(wsi->state_pre_close == LWSS_AWAITING_CLOSE_ACK) ||

View file

@ -1144,6 +1144,14 @@ enum lws_callback_reasons {
* LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK still work without this
* callback being implemented.
*/
LWS_CALLBACK_RAW_RX = 59,
/**< RAW mode connection RX */
LWS_CALLBACK_RAW_CLOSE = 60,
/**< RAW mode connection is closing */
LWS_CALLBACK_RAW_WRITEABLE = 61,
/**< RAW mode connection may be written */
LWS_CALLBACK_RAW_ADOPT = 62,
/**< RAW mode connection was adopted (equivalent to 'created') */
/****** add new things just above ---^ ******/
@ -2817,7 +2825,7 @@ enum lws_token_indexes {
WSI_TOKEN_HTTP_X_REAL_IP = 78,
WSI_TOKEN_HTTP1_0 = 79,
WSI_TOKEN_X_FORWARDED_FOR = 80,
WSI_TOKEN_CONNECT = 81,
/****** add new things just above ---^ ******/
/* use token storage to stash these internally, not for
@ -3764,6 +3772,24 @@ lws_adopt_socket(struct lws_context *context, lws_sockfd_type accept_fd);
*/
LWS_VISIBLE LWS_EXTERN struct lws *
lws_adopt_socket_vhost(struct lws_vhost *vh, lws_sockfd_type accept_fd);
/*
* lws_adopt_socket_vhost2() - adopt foreign socket as if listen socket accepted it
* for vhost, allow control over defeat SSL and raw transport mode
* \param vhost: lws vhost
* \param accept_fd: fd of already-accepted socket to adopt
* \param allow_ssl: 0 = no SSL even if vhost supports, 1 = SSL if vhost supports
* \param raw: 0 = http[s]/wss[s], 1 = raw mode semantics
*
* Either returns new wsi bound to accept_fd, or closes accept_fd and
* returns NULL, having cleaned up any new wsi pieces.
*
* LWS adopts the socket in http serving mode, it's ready to accept an upgrade
* to ws or just serve http.
*/
LWS_VISIBLE struct lws *
lws_adopt_socket_vhost2(struct lws_vhost *vh, lws_sockfd_type accept_fd,
int allow_ssl, int raw);
/**
* lws_adopt_socket_readbuf() - adopt foreign socket and first rx as if listen socket accepted it
* for the default vhost of context.

View file

@ -541,6 +541,7 @@ lws_parse(struct lws *wsi, unsigned char c)
WSI_TOKEN_PUT_URI,
WSI_TOKEN_PATCH_URI,
WSI_TOKEN_DELETE_URI,
WSI_TOKEN_CONNECT,
};
struct allocated_headers *ah = wsi->u.hdr.ah;
struct lws_context *context = wsi->context;

View file

@ -572,10 +572,14 @@ enum connection_mode {
/* transient, ssl delay hiding */
LWSCM_SSL_ACK_PENDING,
LWSCM_SSL_INIT,
/* as above, but complete into LWSCM_RAW */
LWSCM_SSL_ACK_PENDING_RAW,
LWSCM_SSL_INIT_RAW,
/* special internal types */
LWSCM_SERVER_LISTENER,
LWSCM_CGI, /* stdin, stdout, stderr for another cgi master wsi */
LWSCM_RAW, /* raw */
/* HTTP Client related */
LWSCM_HTTP_CLIENT = LWSCM_FLAG_IMPLIES_CALLBACK_CLOSED_CLIENT_HTTP,

View file

@ -333,7 +333,7 @@ lws_http_serve(struct lws *wsi, char *uri, const char *origin,
char path[256], sym[512];
unsigned char *p = (unsigned char *)sym + 32 + LWS_PRE, *start = p;
unsigned char *end = p + sizeof(sym) - 32 - LWS_PRE;
#if !defined(WIN32) && LWS_POSIX && !defined(LWS_WITH_ESP32)
#if !defined(WIN32) && LWS_POSIX
size_t len;
#endif
int n;
@ -350,7 +350,7 @@ lws_http_serve(struct lws *wsi, char *uri, const char *origin,
}
lwsl_debug(" %s mode %d\n", path, S_IFMT & st.st_mode);
#if !defined(WIN32) && LWS_POSIX && !defined(LWS_WITH_ESP32)
#if !defined(WIN32) && LWS_POSIX
if ((S_IFMT & st.st_mode) == S_IFLNK) {
len = readlink(path, sym, sizeof(sym) - 1);
if (len) {
@ -609,13 +609,14 @@ lws_http_action(struct lws *wsi)
WSI_TOKEN_PUT_URI,
WSI_TOKEN_PATCH_URI,
WSI_TOKEN_DELETE_URI,
WSI_TOKEN_CONNECT,
#ifdef LWS_USE_HTTP2
WSI_TOKEN_HTTP_COLON_PATH,
#endif
};
#if defined(_DEBUG) || defined(LWS_WITH_ACCESS_LOG)
static const char * const method_names[] = {
"GET", "POST", "OPTIONS", "PUT", "PATCH", "DELETE",
"GET", "POST", "OPTIONS", "PUT", "PATCH", "DELETE", "CONNECT",
#ifdef LWS_USE_HTTP2
":path",
#endif
@ -1211,6 +1212,17 @@ lws_handshake_server(struct lws *wsi, unsigned char **buf, size_t len)
wsi->conn_stat_done = 1;
}
if (lws_hdr_total_length(wsi, WSI_TOKEN_CONNECT)) {
lwsl_info("Changing to RAW mode\n");
lws_union_transition(wsi, LWSCM_RAW);
if (!wsi->more_rx_waiting) {
wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
//lwsl_notice("%p: dropping ah EST\n", wsi);
lws_header_table_detach(wsi, 1);
}
}
wsi->mode = LWSCM_PRE_WS_SERVING_ACCEPT;
lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
@ -1681,10 +1693,12 @@ lws_http_transaction_completed(struct lws *wsi)
}
LWS_VISIBLE struct lws *
lws_adopt_socket_vhost(struct lws_vhost *vh, lws_sockfd_type accept_fd)
lws_adopt_socket_vhost2(struct lws_vhost *vh, lws_sockfd_type accept_fd,
int allow_ssl, int raw)
{
struct lws_context *context = vh->context;
struct lws *new_wsi = lws_create_new_server_wsi(vh);
int n;
if (!new_wsi) {
compatible_close(accept_fd);
@ -1710,10 +1724,14 @@ lws_adopt_socket_vhost(struct lws_vhost *vh, lws_sockfd_type accept_fd)
/*
* A new connection was accepted. Give the user a chance to
* set properties of the newly created wsi. There's no protocol
* selected yet so we issue this to protocols[0]
* selected yet so we issue this to the vhosts's default protocol,
* itself by default protocols[0]
*/
if ((context->vhost_list->protocols[0].callback)(new_wsi,
LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED, NULL, NULL, 0)) {
n = LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED;
if (raw)
n = LWS_CALLBACK_RAW_ADOPT;
if ((context->vhost_list->protocols[vh->default_protocol_index].callback)(
new_wsi, n, NULL, NULL, 0)) {
/* force us off the timeout list by hand */
lws_set_timeout(new_wsi, NO_PENDING_TIMEOUT, 0);
compatible_close(new_wsi->sock);
@ -1724,13 +1742,18 @@ lws_adopt_socket_vhost(struct lws_vhost *vh, lws_sockfd_type accept_fd)
lws_libev_accept(new_wsi, new_wsi->sock);
lws_libuv_accept(new_wsi, new_wsi->sock);
if (!LWS_SSL_ENABLED(new_wsi->vhost)) {
if (!LWS_SSL_ENABLED(new_wsi->vhost) || allow_ssl == 0) {
if (raw)
new_wsi->mode = LWSCM_RAW;
if (insert_wsi_socket_into_fds(context, new_wsi)) {
lwsl_err("%s: fail inserting socket\n", __func__);
goto fail;
}
} else {
new_wsi->mode = LWSCM_SSL_INIT;
if (raw)
new_wsi->mode = LWSCM_SSL_INIT_RAW;
else
new_wsi->mode = LWSCM_SSL_INIT;
if (lws_server_socket_service_ssl(new_wsi, accept_fd)) {
lwsl_err("%s: fail ssl negotiation\n", __func__);
goto fail;
@ -1748,10 +1771,16 @@ fail:
return NULL;
}
LWS_VISIBLE struct lws *
lws_adopt_socket_vhost(struct lws_vhost *vh, lws_sockfd_type accept_fd)
{
return lws_adopt_socket_vhost2(vh, accept_fd, 1, 0);
}
LWS_VISIBLE struct lws *
lws_adopt_socket(struct lws_context *context, lws_sockfd_type accept_fd)
{
return lws_adopt_socket_vhost(context->vhost_list, accept_fd);
return lws_adopt_socket_vhost2(context->vhost_list, accept_fd, 1, 0);
}
/* Common read-buffer adoption for lws_adopt_*_readbuf */
@ -1903,6 +1932,7 @@ lws_server_socket_service(struct lws_context *context, struct lws *wsi,
goto try_pollout;
}
#endif
/* these states imply we MUST have an ah attached */
if (wsi->state == LWSS_HTTP ||
@ -1991,6 +2021,17 @@ lws_server_socket_service(struct lws_context *context, struct lws *wsi,
goto try_pollout;
}
if (wsi->mode == LWSCM_RAW) {
n = user_callback_handle_rxflow(wsi->protocol->callback,
wsi, LWS_CALLBACK_RAW_RX,
wsi->user_space, pt->serv_buf, len);
if (n < 0) {
lwsl_info("raw writeable_fail\n");
goto fail;
}
break;
}
/* just ignore incoming if waiting for close */
if (wsi->state != LWSS_FLUSHING_STORED_SEND_BEFORE_CLOSE) {
/*
@ -2138,13 +2179,13 @@ lws_serve_http_file(struct lws *wsi, const char *file, const char *content_type,
int ranges;
#endif
if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_ACCEPT_ENCODING)) {
char *accept = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_ACCEPT_ENCODING);
if (strstr(accept, "gzip") && strstr(accept, "deflate")) {
lwsl_debug("client indicates GZIP is acceptable\n");
fflags |= LWS_FOP_FLAG_COMPR_ACCEPTABLE_GZIP;
}
}
if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_ACCEPT_ENCODING))
if (strstr("gzip", lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_ACCEPT_ENCODING)) &&
strstr("deflate", lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_ACCEPT_ENCODING))) {
lwsl_debug("client indicates GZIP is acceptable\n");
fflags |= LWS_FOP_FLAG_COMPR_ACCEPTABLE_GZIP;
}
wsi->u.http.fd = lws_plat_file_open(wsi, file, &wsi->u.http.filelen,
&fflags);
@ -2155,6 +2196,16 @@ lws_serve_http_file(struct lws *wsi, const char *file, const char *content_type,
}
computed_total_content_length = wsi->u.http.filelen;
if ((fflags & (LWS_FOP_FLAG_COMPR_ACCEPTABLE_GZIP |
LWS_FOP_FLAG_COMPR_IS_GZIP)) ==
(LWS_FOP_FLAG_COMPR_ACCEPTABLE_GZIP | LWS_FOP_FLAG_COMPR_IS_GZIP)) {
if (lws_add_http_header_by_token(wsi,
WSI_TOKEN_HTTP_CONTENT_ENCODING,
(unsigned char *)"gzip, deflate", 13, &p, end))
return -1;
lwsl_debug("file is being provided in gzip\n");
}
#if defined(LWS_WITH_RANGES)
ranges = lws_ranges_init(wsi, rp, wsi->u.http.filelen);
@ -2181,16 +2232,6 @@ lws_serve_http_file(struct lws *wsi, const char *file, const char *content_type,
if (lws_add_http_header_status(wsi, n, &p, end))
return -1;
if ((fflags & (LWS_FOP_FLAG_COMPR_ACCEPTABLE_GZIP |
LWS_FOP_FLAG_COMPR_IS_GZIP)) ==
(LWS_FOP_FLAG_COMPR_ACCEPTABLE_GZIP | LWS_FOP_FLAG_COMPR_IS_GZIP)) {
if (lws_add_http_header_by_token(wsi,
WSI_TOKEN_HTTP_CONTENT_ENCODING,
(unsigned char *)"gzip", 4, &p, end))
return -1;
lwsl_debug("file is being provided in gzip\n");
}
#if defined(LWS_WITH_RANGES)
if (ranges < 2 && content_type && content_type[0])
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
@ -2372,7 +2413,7 @@ lws_server_get_canonical_hostname(struct lws_context *context,
{
if (lws_check_opt(info->options, LWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME))
return;
#if LWS_POSIX && !defined(LWS_WITH_ESP32)
#if LWS_POSIX
/* find canonical hostname */
gethostname((char *)context->canonical_hostname,
sizeof(context->canonical_hostname) - 1);

View file

@ -27,6 +27,9 @@ lws_calllback_as_writeable(struct lws *wsi)
int n;
switch (wsi->mode) {
case LWSCM_RAW:
n = LWS_CALLBACK_RAW_WRITEABLE;
break;
case LWSCM_WS_CLIENT:
n = LWS_CALLBACK_CLIENT_WRITEABLE;
break;
@ -195,6 +198,8 @@ lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd)
*/
ret = 1;
if (wsi->mode == LWSCM_RAW)
ret = 0;
while (ret == 1) {
/* default to nobody has more to spill */
@ -841,6 +846,7 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd, int t
case LWSCM_HTTP_SERVING_ACCEPTED:
case LWSCM_SERVER_LISTENER:
case LWSCM_SSL_ACK_PENDING:
case LWSCM_SSL_ACK_PENDING_RAW:
if (wsi->state == LWSS_CLIENT_HTTP_ESTABLISHED)
goto handled;
@ -861,15 +867,17 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd, int t
case LWSCM_WS_CLIENT:
case LWSCM_HTTP2_SERVING:
case LWSCM_HTTP_CLIENT_ACCEPTED:
case LWSCM_RAW:
/* 1: something requested a callback when it was OK to write */
if ((pollfd->revents & LWS_POLLOUT) &&
((wsi->mode == LWSCM_RAW) ||
(wsi->state == LWSS_ESTABLISHED ||
wsi->state == LWSS_HTTP2_ESTABLISHED ||
wsi->state == LWSS_HTTP2_ESTABLISHED_PRE_SETTINGS ||
wsi->state == LWSS_RETURNED_CLOSE_ALREADY ||
wsi->state == LWSS_FLUSHING_STORED_SEND_BEFORE_CLOSE) &&
wsi->state == LWSS_FLUSHING_STORED_SEND_BEFORE_CLOSE)) &&
lws_handle_POLLOUT_event(wsi, pollfd)) {
if (wsi->state == LWSS_RETURNED_CLOSE_ALREADY)
wsi->state = LWSS_FLUSHING_STORED_SEND_BEFORE_CLOSE;

View file

@ -496,7 +496,7 @@ lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd)
switch (wsi->mode) {
case LWSCM_SSL_INIT:
case LWSCM_SSL_INIT_RAW:
if (wsi->ssl)
lwsl_err("%s: leaking ssl\n", __func__);
if (accept_fd == LWS_SOCK_INVALID)
@ -590,7 +590,11 @@ lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd)
* pieces come if we're not sorted yet
*/
wsi->mode = LWSCM_SSL_ACK_PENDING;
if (wsi->mode == LWSCM_SSL_INIT)
wsi->mode = LWSCM_SSL_ACK_PENDING;
else
wsi->mode = LWSCM_SSL_ACK_PENDING_RAW;
if (insert_wsi_socket_into_fds(context, wsi)) {
lwsl_err("%s: failed to insert into fds\n", __func__);
goto fail;
@ -604,7 +608,7 @@ lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd)
/* fallthru */
case LWSCM_SSL_ACK_PENDING:
case LWSCM_SSL_ACK_PENDING_RAW:
if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) {
lwsl_err("%s: lws_change_pollfd failed\n", __func__);
goto fail;
@ -715,7 +719,10 @@ accepted:
lws_set_timeout(wsi, PENDING_TIMEOUT_ESTABLISH_WITH_SERVER,
context->timeout_secs);
wsi->mode = LWSCM_HTTP_SERVING;
if (wsi->mode == LWSCM_SSL_ACK_PENDING_RAW)
wsi->mode = LWSCM_RAW;
else
wsi->mode = LWSCM_HTTP_SERVING;
lws_http2_configure_if_upgraded(wsi);