mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-09 00:00:04 +01:00
http proxy: client: unix socket support
This allows the client stuff to understand that addresses beginning with '+' represent unix sockets. If the first character after the '+' is '@', it understands that the '@' should be read as '\0', in order to use Linux "abstract namespace" sockets. Further the lws_parse_uri() helper is extended to understand the convention that an address starting with + is a unix socket, and treats the socket path as delimited by ':', eg http://+/var/run/mysocket:/my/path HTTP Proxy is updated to allow mounts to these unix socket paths. Proxy connections go out on h1, but are dynamically translated to h1 or h2 on the incoming side. Proxy usage of libhubbub is separated out... LWS_WITH_HTTP_PROXY is on by default, and LWS_WITH_HUBBUB is off by default.
This commit is contained in:
parent
dc38eea060
commit
fd810f198a
27 changed files with 1058 additions and 454 deletions
|
@ -29,7 +29,7 @@ option(LWS_WITH_CGI "Include CGI (spawn process with network-connected stdin/out
|
|||
option(LWS_IPV6 "Compile with support for ipv6" OFF)
|
||||
option(LWS_UNIX_SOCK "Compile with support for UNIX domain socket" ON)
|
||||
option(LWS_WITH_PLUGINS "Support plugins for protocols and extensions" OFF)
|
||||
option(LWS_WITH_HTTP_PROXY "Support for rewriting HTTP proxying (requires libhubbub)" OFF)
|
||||
option(LWS_WITH_HTTP_PROXY "Support for HTTP proxying" ON)
|
||||
option(LWS_WITH_ZIP_FOPS "Support serving pre-zipped files" OFF)
|
||||
option(LWS_WITH_SOCKS5 "Allow use of SOCKS5 proxy on client connections" OFF)
|
||||
option(LWS_WITH_GENERIC_SESSIONS "With the Generic Sessions plugin" OFF)
|
||||
|
@ -41,6 +41,7 @@ option(LWS_WITH_THREADPOOL "Managed worker thread pool support (relies on pthrea
|
|||
option(LWS_WITH_HTTP_STREAM_COMPRESSION "Support HTTP stream compression" OFF)
|
||||
option(LWS_WITH_HTTP_BROTLI "Also offer brotli http stream compression (requires LWS_WITH_HTTP_STREAM_COMPRESSION)" OFF)
|
||||
option(LWS_WITH_ACME "Enable support for ACME automatic cert acquisition + maintenance (letsencrypt etc)" OFF)
|
||||
option(LWS_WITH_HUBBUB "Enable libhubbub rewriting support" OFF)
|
||||
#
|
||||
# TLS library options... all except mbedTLS are basically OpenSSL variants.
|
||||
#
|
||||
|
@ -134,6 +135,12 @@ if(NOT DEFINED CMAKE_BUILD_TYPE)
|
|||
set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type")
|
||||
endif()
|
||||
|
||||
# microsoft... that's why you can't have nice things
|
||||
|
||||
if (WIN32 OR LWS_WITH_ESP32)
|
||||
set(LWS_UNIX_SOCK 0)
|
||||
endif()
|
||||
|
||||
project(libwebsockets C)
|
||||
|
||||
set(PACKAGE "libwebsockets")
|
||||
|
@ -333,7 +340,8 @@ endif()
|
|||
|
||||
|
||||
if (LWS_WITH_HTTP_PROXY AND (LWS_WITHOUT_CLIENT OR LWS_WITHOUT_SERVER))
|
||||
message(FATAL_ERROR "You have to enable both client and server for http proxy")
|
||||
message("You have to enable both client and server for http proxy")
|
||||
set(LWS_WITH_HTTP_PROXY 0)
|
||||
endif()
|
||||
|
||||
# Allow the user to override installation directories.
|
||||
|
@ -744,6 +752,7 @@ set(HDR_PUBLIC
|
|||
set(SOURCES
|
||||
lib/core/alloc.c
|
||||
lib/core/context.c
|
||||
lib/core/dummy-callback.c
|
||||
lib/core/libwebsockets.c
|
||||
lib/core/output.c
|
||||
lib/core/pollfd.c
|
||||
|
@ -1402,7 +1411,7 @@ if (LWS_WITH_SQLITE3)
|
|||
endif()
|
||||
|
||||
|
||||
if (LWS_WITH_HTTP_PROXY)
|
||||
if (LWS_WITH_HUBBUB)
|
||||
find_library(LIBHUBBUB_LIBRARIES NAMES hubbub)
|
||||
list(APPEND LIB_LIST ${LIBHUBBUB_LIBRARIES} )
|
||||
endif()
|
||||
|
|
95
READMEs/README.unix-domain-reverse-proxy.md
Normal file
95
READMEs/README.unix-domain-reverse-proxy.md
Normal file
|
@ -0,0 +1,95 @@
|
|||
## Unix Domain Sockets Reverse Proxy
|
||||
|
||||
### Introduction
|
||||
|
||||
lws is able to use a mount to place reverse proxies into the URL space.
|
||||
|
||||
These are particularly useful when using Unix Domain Sockets, basically
|
||||
files in the server filesystem, to communicate between lws and a separate
|
||||
server process and integrate the result into a coherent URL namespace on
|
||||
the lws side.
|
||||
|
||||
This has the advantage that the actual web server that forwards the
|
||||
data from the unix socket owner is in a different process than the server
|
||||
that serves on the unix socket. If it has problems, they do not affect
|
||||
the actual public-facing web server. The unix domain socket server may
|
||||
be in a completely different language than the web server.
|
||||
|
||||
Compared to CGI, there are no forks to make a connection to the unix
|
||||
domain socket server.
|
||||
|
||||
### Mount origin format
|
||||
|
||||
Unix Domain Sockets are effectively "files" in the server filesystem, and
|
||||
are defined by their filepath. The "server" side that is to be proxied opens
|
||||
the socket and listens on it, which creates a file in the server filesystem.
|
||||
The socket understands either http or https protocol.
|
||||
|
||||
Lws can be told to act as a proxy for that at a mountpoint in the lws vhost
|
||||
url space.
|
||||
|
||||
If your mount is expressed in C code, then the mount type is LWSMPRO_HTTP or
|
||||
LWSMPRO_HTTPS depending on the protocol the unix socket understands, and the
|
||||
origin address has the form `+/path/to/unix/socket:/path/inside/mount`.
|
||||
|
||||
The + at the start indicates it is a local unix socket we are proxying, and
|
||||
the ':' acts as a delimiter for the socket path, since unlike other addresses
|
||||
the unix socket path can contain '/' itself.
|
||||
|
||||
### Connectivity rules and translations
|
||||
|
||||
Onward proxy connections from lws to the Unix Domain Socket happen using
|
||||
http/1.1. That implies `transfer-encoding: chunking` in the case that the
|
||||
length of the output is not known beforehand.
|
||||
|
||||
Lws takes care of stripping any chunking (which is illegal in h2) and
|
||||
translating between h1 and h2 header formats if the return connection is
|
||||
actually in http/2.
|
||||
|
||||
The h1 onward proxy connection translates the following headers from the return
|
||||
connection, which may be h1 or h2:
|
||||
|
||||
Header|Function
|
||||
---|---
|
||||
host|Which vhost
|
||||
etag|Information on any etag the client has cached for this URI
|
||||
if-modified-since|Information on the freshness of any etag the client has cached for this URI
|
||||
accept-language|Which languages the return path client prefers
|
||||
accept-encoding|Which compression encodings the client can accept
|
||||
cache-control|Information from the return path client about cache acceptability
|
||||
x-forwarded-for|The IP address of the return path client
|
||||
|
||||
This implies that the proxied connection can
|
||||
|
||||
- return 301 etc to say the return path client's etag is still valid
|
||||
|
||||
- choose to compress using an acceptable content-encoding
|
||||
|
||||
The following headers are translated from the headers replied via the onward
|
||||
connection (always h1) back to the return path (which may be h1 or h2)
|
||||
|
||||
Header|Function
|
||||
---|---
|
||||
content-length|If present, an assertion of how much payload is expected
|
||||
content-type|The mimetype of the payload
|
||||
etag|The canonical etag for the content at this URI
|
||||
accept-language|This is returned to the return path client because there is no easy way for the return path client to know what it sent originally. It allows clientside selection of i18n.
|
||||
content-encoding|Any compression format on the payload (selected from what the client sent in accept-encoding, if anything)
|
||||
cache-control|The onward server's response about cacheability of its payload
|
||||
|
||||
### h1 -> h2 conversion
|
||||
|
||||
Chunked encoding that may have been used on the outgoing proxy client connection
|
||||
is removed for h2 return connections (chunked encoding is illegal for h2).
|
||||
|
||||
Headers are converted to all lower-case and hpack format for h2 return connections.
|
||||
|
||||
Header and payload proxying is staged according to when the return connection
|
||||
(which may be an h2 child stream) is writable.
|
||||
|
||||
### Behaviour is unix domain socket server unavailable
|
||||
|
||||
If the server that listens on the unix domain socket is down or being restarted,
|
||||
lws understands that it couldn't connect to it and returns a clean 503 response
|
||||
`HTTP_STATUS_SERVICE_UNAVAILABLE` along with a brief human-readable explanation.
|
||||
|
|
@ -485,7 +485,7 @@ enum lws_callback_reasons {
|
|||
/**< after your client connection completed the websocket upgrade
|
||||
* handshake with the remote server */
|
||||
|
||||
LWS_CALLBACK_CLIENT_CLOSED = 75,
|
||||
LWS_CALLBACK_CLIENT_CLOSED = 75,
|
||||
/**< when a client websocket session ends */
|
||||
|
||||
LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER = 24,
|
||||
|
@ -497,21 +497,11 @@ enum lws_callback_reasons {
|
|||
* which is typically some hundreds of bytes. So, to add a canned
|
||||
* cookie, your handler code might look similar to:
|
||||
*
|
||||
* char **p = (char **)in;
|
||||
* char **p = (char **)in, *end = (*p) + len;
|
||||
*
|
||||
* if (len < 100)
|
||||
* return 1;
|
||||
*
|
||||
* *p += sprintf(*p, "Cookie: a=b\x0d\x0a");
|
||||
*
|
||||
* return 0;
|
||||
*
|
||||
* Notice if you add anything, you just have to take care about
|
||||
* the CRLF on the line you added. Obviously this callback is
|
||||
* optional, if you don't handle it everything is fine.
|
||||
*
|
||||
* Notice the callback is coming to protocols[0] all the time,
|
||||
* because there is no specific protocol negotiated yet.
|
||||
* if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_COOKIE,
|
||||
* (unsigned char)"a=b", 3, p, end))
|
||||
* return -1;
|
||||
*
|
||||
* See LWS_CALLBACK_ADD_HEADERS for adding headers to server
|
||||
* transactions.
|
||||
|
@ -798,4 +788,6 @@ lws_callback_function(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
#define LWS_CB_REASON_AUX_BF__PROXY 2
|
||||
#define LWS_CB_REASON_AUX_BF__CGI_CHUNK_END 4
|
||||
#define LWS_CB_REASON_AUX_BF__CGI_HEADERS 8
|
||||
#define LWS_CB_REASON_AUX_BF__PROXY_TRANS_END 16
|
||||
#define LWS_CB_REASON_AUX_BF__PROXY_HEADERS 32
|
||||
///@}
|
||||
|
|
|
@ -45,8 +45,9 @@ enum lws_log_levels {
|
|||
LLL_CLIENT = 1 << 8,
|
||||
LLL_LATENCY = 1 << 9,
|
||||
LLL_USER = 1 << 10,
|
||||
LLL_THREAD = 1 << 11,
|
||||
|
||||
LLL_COUNT = 11 /* set to count of valid flags */
|
||||
LLL_COUNT = 12 /* set to count of valid flags */
|
||||
};
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void _lws_log(int filter, const char *format, ...) LWS_FORMAT(2);
|
||||
|
@ -92,6 +93,7 @@ lwsl_timestamp(int level, char *p, int len);
|
|||
#define lwsl_ext(...) _lws_log(LLL_EXT, __VA_ARGS__)
|
||||
#define lwsl_client(...) _lws_log(LLL_CLIENT, __VA_ARGS__)
|
||||
#define lwsl_latency(...) _lws_log(LLL_LATENCY, __VA_ARGS__)
|
||||
#define lwsl_thread(...) _lws_log(LLL_THREAD, __VA_ARGS__)
|
||||
|
||||
#else /* no debug */
|
||||
#if defined(LWS_WITH_NO_LOGS)
|
||||
|
@ -105,6 +107,7 @@ lwsl_timestamp(int level, char *p, int len);
|
|||
#define lwsl_ext(...) do {} while(0)
|
||||
#define lwsl_client(...) do {} while(0)
|
||||
#define lwsl_latency(...) do {} while(0)
|
||||
#define lwsl_thread(...) do {} while(0)
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -392,6 +392,17 @@ lws_set_wsi_user(struct lws *wsi, void *user);
|
|||
* \param ads: result pointer for address part
|
||||
* \param port: result pointer for port part
|
||||
* \param path: result pointer for path part
|
||||
*
|
||||
* You may also refer to unix socket addresses, using a '+' at the start of
|
||||
* the address. In this case, the address should end with ':', which is
|
||||
* treated as the separator between the address and path (the normal separator
|
||||
* '/' is a valid part of the socket path). Eg,
|
||||
*
|
||||
* http://+/var/run/mysocket:/my/path
|
||||
*
|
||||
* If the first character after the + is '@', it's interpreted by lws client
|
||||
* processing as meaning to use linux abstract namespace sockets, the @ is
|
||||
* replaced with a '\0' before use.
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT
|
||||
lws_parse_uri(char *p, const char **prot, const char **ads, int *port,
|
||||
|
@ -422,6 +433,12 @@ lws_cmdline_option(int argc, const char **argv, const char *val);
|
|||
LWS_VISIBLE LWS_EXTERN unsigned long
|
||||
lws_now_secs(void);
|
||||
|
||||
/**
|
||||
* lws_now_usecs(): return useconds since 1970-1-1
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN lws_usec_t
|
||||
lws_now_usecs(void);
|
||||
|
||||
/**
|
||||
* lws_compare_time_t(): return relationship between two time_t
|
||||
*
|
||||
|
|
|
@ -63,6 +63,7 @@ enum pending_timeout {
|
|||
PENDING_TIMEOUT_LAGGING = 28,
|
||||
PENDING_TIMEOUT_THREADPOOL = 29,
|
||||
PENDING_TIMEOUT_THREADPOOL_TASK = 30,
|
||||
PENDING_TIMEOUT_KILLED_BY_PROXY_CLIENT_CLOSE = 31,
|
||||
|
||||
/****** add new things just above ---^ ******/
|
||||
|
||||
|
|
|
@ -86,6 +86,14 @@ enum lws_write_protocol {
|
|||
|
||||
/* flags */
|
||||
|
||||
LWS_WRITE_BUFLIST = 0x20,
|
||||
/**< Don't actually write it... stick it on the output buflist and
|
||||
* write it as soon as possible. Useful if you learn you have to
|
||||
* write something, have the data to write to hand but the timing is
|
||||
* unrelated as to whether the connection is writable or not, and were
|
||||
* otherwise going to have to allocate a temp buffer and write it
|
||||
* later anyway */
|
||||
|
||||
LWS_WRITE_NO_FIN = 0x40,
|
||||
/**< This part of the message is not the end of the message */
|
||||
|
||||
|
|
|
@ -241,6 +241,9 @@ bail:
|
|||
parent->child_list = new_wsi->sibling_list;
|
||||
if (new_wsi->user_space)
|
||||
lws_free(new_wsi->user_space);
|
||||
|
||||
vh->context->count_wsi_allocated--;
|
||||
|
||||
lws_vhost_unbind_wsi(new_wsi);
|
||||
lws_free(new_wsi);
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ lws_client_stash_destroy(struct lws *wsi)
|
|||
LWS_VISIBLE struct lws *
|
||||
lws_client_connect_via_info(const struct lws_client_connect_info *i)
|
||||
{
|
||||
struct lws *wsi;
|
||||
struct lws *wsi, *safe = NULL;
|
||||
const struct lws_protocols *p;
|
||||
const char *local = i->protocol;
|
||||
#if LWS_MAX_SMP > 1
|
||||
|
@ -219,6 +219,21 @@ lws_client_connect_via_info(const struct lws_client_connect_info *i)
|
|||
goto bail1;
|
||||
}
|
||||
|
||||
/*
|
||||
* at this point user callbacks like
|
||||
* LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER will be interested to
|
||||
* know the parent... eg for proxying we can grab extra headers from
|
||||
* the parent's incoming ah and add them to the child client handshake
|
||||
*/
|
||||
|
||||
if (i->parent_wsi) {
|
||||
lwsl_info("%s: created child %p of parent %p\n", __func__,
|
||||
wsi, i->parent_wsi);
|
||||
wsi->parent = i->parent_wsi;
|
||||
safe = wsi->sibling_list = i->parent_wsi->child_list;
|
||||
i->parent_wsi->child_list = wsi;
|
||||
}
|
||||
|
||||
/*
|
||||
* PHASE 7: Do any role-specific finalization processing. We can still
|
||||
* see important info things via wsi->stash
|
||||
|
@ -227,6 +242,12 @@ lws_client_connect_via_info(const struct lws_client_connect_info *i)
|
|||
if (wsi->role_ops->client_bind) {
|
||||
int n = wsi->role_ops->client_bind(wsi, NULL);
|
||||
|
||||
if (n && i->parent_wsi) {
|
||||
/* unpick from parent */
|
||||
|
||||
i->parent_wsi->child_list = safe;
|
||||
}
|
||||
|
||||
if (n < 0)
|
||||
/* we didn't survive, wsi is freed */
|
||||
goto bail2;
|
||||
|
@ -241,14 +262,8 @@ lws_client_connect_via_info(const struct lws_client_connect_info *i)
|
|||
if (i->pwsi)
|
||||
*i->pwsi = wsi;
|
||||
|
||||
if (i->parent_wsi) {
|
||||
lwsl_info("%s: created child %p of parent %p\n", __func__,
|
||||
wsi, i->parent_wsi);
|
||||
wsi->parent = i->parent_wsi;
|
||||
wsi->sibling_list = i->parent_wsi->child_list;
|
||||
i->parent_wsi->child_list = wsi;
|
||||
}
|
||||
#ifdef LWS_WITH_HTTP_PROXY
|
||||
|
||||
#if defined(LWS_WITH_HUBBUB)
|
||||
if (i->uri_replace_to)
|
||||
wsi->http.rw = lws_rewrite_create(wsi, html_parser_cb,
|
||||
i->uri_replace_from,
|
||||
|
|
|
@ -339,347 +339,6 @@ next:
|
|||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
|
||||
void *user, void *in, size_t len)
|
||||
{
|
||||
struct lws_ssl_info *si;
|
||||
#ifdef LWS_WITH_CGI
|
||||
struct lws_cgi_args *args;
|
||||
#endif
|
||||
#if defined(LWS_WITH_CGI) || defined(LWS_WITH_HTTP_PROXY)
|
||||
char buf[128];
|
||||
int n;
|
||||
#endif
|
||||
|
||||
switch (reason) {
|
||||
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
|
||||
case LWS_CALLBACK_HTTP:
|
||||
#ifndef LWS_NO_SERVER
|
||||
if (lws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND, NULL))
|
||||
return -1;
|
||||
|
||||
if (lws_http_transaction_completed(wsi))
|
||||
#endif
|
||||
return -1;
|
||||
break;
|
||||
#if !defined(LWS_NO_SERVER)
|
||||
case LWS_CALLBACK_HTTP_BODY_COMPLETION:
|
||||
case LWS_CALLBACK_HTTP_FILE_COMPLETION:
|
||||
if (lws_http_transaction_completed(wsi))
|
||||
return -1;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case LWS_CALLBACK_HTTP_WRITEABLE:
|
||||
#ifdef LWS_WITH_CGI
|
||||
if (wsi->reason_bf & (LWS_CB_REASON_AUX_BF__CGI_HEADERS |
|
||||
LWS_CB_REASON_AUX_BF__CGI)) {
|
||||
n = lws_cgi_write_split_stdout_headers(wsi);
|
||||
if (n < 0) {
|
||||
lwsl_debug("AUX_BF__CGI forcing close\n");
|
||||
return -1;
|
||||
}
|
||||
if (!n)
|
||||
lws_rx_flow_control(
|
||||
wsi->http.cgi->stdwsi[LWS_STDOUT], 1);
|
||||
|
||||
if (wsi->reason_bf & LWS_CB_REASON_AUX_BF__CGI_HEADERS)
|
||||
wsi->reason_bf &=
|
||||
~LWS_CB_REASON_AUX_BF__CGI_HEADERS;
|
||||
else
|
||||
wsi->reason_bf &= ~LWS_CB_REASON_AUX_BF__CGI;
|
||||
|
||||
if (wsi->http.cgi && wsi->http.cgi->cgi_transaction_over)
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (wsi->reason_bf & LWS_CB_REASON_AUX_BF__CGI_CHUNK_END) {
|
||||
if (!wsi->http2_substream) {
|
||||
memcpy(buf + LWS_PRE, "0\x0d\x0a\x0d\x0a", 5);
|
||||
lwsl_debug("writing chunk term and exiting\n");
|
||||
n = lws_write(wsi, (unsigned char *)buf +
|
||||
LWS_PRE, 5, LWS_WRITE_HTTP);
|
||||
} else
|
||||
n = lws_write(wsi, (unsigned char *)buf +
|
||||
LWS_PRE, 0,
|
||||
LWS_WRITE_HTTP_FINAL);
|
||||
|
||||
/* always close after sending it */
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
#if defined(LWS_WITH_HTTP_PROXY)
|
||||
if (wsi->reason_bf & LWS_CB_REASON_AUX_BF__PROXY) {
|
||||
char *px = buf + LWS_PRE;
|
||||
int lenx = sizeof(buf) - LWS_PRE;
|
||||
|
||||
/*
|
||||
* our sink is writeable and our source has something
|
||||
* to read. So read a lump of source material of
|
||||
* suitable size to send or what's available, whichever
|
||||
* is the smaller.
|
||||
*/
|
||||
wsi->reason_bf &= ~LWS_CB_REASON_AUX_BF__PROXY;
|
||||
if (!lws_get_child(wsi))
|
||||
break;
|
||||
if (lws_http_client_read(lws_get_child(wsi), &px,
|
||||
&lenx) < 0)
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
#if defined(LWS_WITH_HTTP_PROXY)
|
||||
case LWS_CALLBACK_RECEIVE_CLIENT_HTTP:
|
||||
assert(lws_get_parent(wsi));
|
||||
if (!lws_get_parent(wsi))
|
||||
break;
|
||||
lws_get_parent(wsi)->reason_bf |= LWS_CB_REASON_AUX_BF__PROXY;
|
||||
lws_callback_on_writable(lws_get_parent(wsi));
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ:
|
||||
assert(lws_get_parent(wsi));
|
||||
n = lws_write(lws_get_parent(wsi), (unsigned char *)in,
|
||||
len, LWS_WRITE_HTTP);
|
||||
if (n < 0)
|
||||
return -1;
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP: {
|
||||
unsigned char *p, *end;
|
||||
char ctype[64], ctlen = 0;
|
||||
|
||||
p = (unsigned char *)buf + LWS_PRE;
|
||||
end = p + sizeof(buf) - LWS_PRE;
|
||||
|
||||
if (lws_add_http_header_status(lws_get_parent(wsi),
|
||||
HTTP_STATUS_OK, &p, end))
|
||||
return 1;
|
||||
if (lws_add_http_header_by_token(lws_get_parent(wsi),
|
||||
WSI_TOKEN_HTTP_SERVER,
|
||||
(unsigned char *)"libwebsockets",
|
||||
13, &p, end))
|
||||
return 1;
|
||||
|
||||
ctlen = lws_hdr_copy(wsi, ctype, sizeof(ctype),
|
||||
WSI_TOKEN_HTTP_CONTENT_TYPE);
|
||||
if (ctlen > 0) {
|
||||
if (lws_add_http_header_by_token(lws_get_parent(wsi),
|
||||
WSI_TOKEN_HTTP_CONTENT_TYPE,
|
||||
(unsigned char *)ctype, ctlen, &p, end))
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (lws_finalize_http_header(lws_get_parent(wsi), &p, end))
|
||||
return 1;
|
||||
|
||||
*p = '\0';
|
||||
n = lws_write(lws_get_parent(wsi),
|
||||
(unsigned char *)buf + LWS_PRE,
|
||||
p - ((unsigned char *)buf + LWS_PRE),
|
||||
LWS_WRITE_HTTP_HEADERS);
|
||||
if (n < 0)
|
||||
return -1;
|
||||
|
||||
break; }
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef LWS_WITH_CGI
|
||||
/* CGI IO events (POLLIN/OUT) appear here, our default policy is:
|
||||
*
|
||||
* - POST data goes on subprocess stdin
|
||||
* - subprocess stdout goes on http via writeable callback
|
||||
* - subprocess stderr goes to the logs
|
||||
*/
|
||||
case LWS_CALLBACK_CGI:
|
||||
args = (struct lws_cgi_args *)in;
|
||||
switch (args->ch) { /* which of stdin/out/err ? */
|
||||
case LWS_STDIN:
|
||||
/* TBD stdin rx flow control */
|
||||
break;
|
||||
case LWS_STDOUT:
|
||||
/* quench POLLIN on STDOUT until MASTER got writeable */
|
||||
lws_rx_flow_control(args->stdwsi[LWS_STDOUT], 0);
|
||||
wsi->reason_bf |= LWS_CB_REASON_AUX_BF__CGI;
|
||||
/* when writing to MASTER would not block */
|
||||
lws_callback_on_writable(wsi);
|
||||
break;
|
||||
case LWS_STDERR:
|
||||
n = lws_get_socket_fd(args->stdwsi[LWS_STDERR]);
|
||||
if (n < 0)
|
||||
break;
|
||||
n = read(n, buf, sizeof(buf) - 2);
|
||||
if (n > 0) {
|
||||
if (buf[n - 1] != '\n')
|
||||
buf[n++] = '\n';
|
||||
buf[n] = '\0';
|
||||
lwsl_notice("CGI-stderr: %s\n", buf);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_CGI_TERMINATED:
|
||||
lwsl_debug("LWS_CALLBACK_CGI_TERMINATED: %d %" PRIu64 "\n",
|
||||
wsi->http.cgi->explicitly_chunked,
|
||||
(uint64_t)wsi->http.cgi->content_length);
|
||||
if (!wsi->http.cgi->explicitly_chunked &&
|
||||
!wsi->http.cgi->content_length) {
|
||||
/* send terminating chunk */
|
||||
lwsl_debug("LWS_CALLBACK_CGI_TERMINATED: ending\n");
|
||||
wsi->reason_bf |= LWS_CB_REASON_AUX_BF__CGI_CHUNK_END;
|
||||
lws_callback_on_writable(wsi);
|
||||
lws_set_timeout(wsi, PENDING_TIMEOUT_CGI, 3);
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
|
||||
case LWS_CALLBACK_CGI_STDIN_DATA: /* POST body for stdin */
|
||||
args = (struct lws_cgi_args *)in;
|
||||
args->data[args->len] = '\0';
|
||||
if (!args->stdwsi[LWS_STDIN])
|
||||
return -1;
|
||||
n = lws_get_socket_fd(args->stdwsi[LWS_STDIN]);
|
||||
if (n < 0)
|
||||
return -1;
|
||||
|
||||
#if defined(LWS_WITH_ZLIB)
|
||||
if (wsi->http.cgi->gzip_inflate) {
|
||||
/* gzip handling */
|
||||
|
||||
if (!wsi->http.cgi->gzip_init) {
|
||||
lwsl_err("inflating gzip\n");
|
||||
|
||||
memset(&wsi->http.cgi->inflate, 0, sizeof(wsi->http.cgi->inflate));
|
||||
|
||||
if (inflateInit2(&wsi->http.cgi->inflate, 16 + 15) != Z_OK) {
|
||||
lwsl_err("%s: iniflateInit failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
wsi->http.cgi->gzip_init = 1;
|
||||
}
|
||||
|
||||
wsi->http.cgi->inflate.next_in = args->data;
|
||||
wsi->http.cgi->inflate.avail_in = args->len;
|
||||
|
||||
do {
|
||||
|
||||
wsi->http.cgi->inflate.next_out = wsi->http.cgi->inflate_buf;
|
||||
wsi->http.cgi->inflate.avail_out = sizeof(wsi->http.cgi->inflate_buf);
|
||||
|
||||
n = inflate(&wsi->http.cgi->inflate, Z_SYNC_FLUSH);
|
||||
lwsl_err("inflate: %d\n", n);
|
||||
switch (n) {
|
||||
case Z_NEED_DICT:
|
||||
case Z_STREAM_ERROR:
|
||||
case Z_DATA_ERROR:
|
||||
case Z_MEM_ERROR:
|
||||
inflateEnd(&wsi->http.cgi->inflate);
|
||||
wsi->http.cgi->gzip_init = 0;
|
||||
lwsl_err("zlib error inflate %d\n", n);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (wsi->http.cgi->inflate.avail_out != sizeof(wsi->http.cgi->inflate_buf)) {
|
||||
int written;
|
||||
|
||||
// lwsl_hexdump_notice(wsi->http.cgi->inflate_buf,
|
||||
// sizeof(wsi->http.cgi->inflate_buf) - wsi->http.cgi->inflate.avail_out);
|
||||
|
||||
written = write(args->stdwsi[LWS_STDIN]->desc.filefd, wsi->http.cgi->inflate_buf,
|
||||
sizeof(wsi->http.cgi->inflate_buf) - wsi->http.cgi->inflate.avail_out);
|
||||
|
||||
if (written != (int)(sizeof(wsi->http.cgi->inflate_buf) - wsi->http.cgi->inflate.avail_out)) {
|
||||
lwsl_notice("LWS_CALLBACK_CGI_STDIN_DATA: "
|
||||
"sent %d only %d went", n, args->len);
|
||||
}
|
||||
lwsl_err("send inflated on fd %d says %d\n", args->stdwsi[LWS_STDIN]->desc.filefd, written);
|
||||
|
||||
if (n == Z_STREAM_END) {
|
||||
lwsl_err("gzip inflate end\n");
|
||||
inflateEnd(&wsi->http.cgi->inflate);
|
||||
wsi->http.cgi->gzip_init = 0;
|
||||
|
||||
//compatible_close(args->stdwsi[LWS_STDIN]->desc.filefd);
|
||||
//args->stdwsi[LWS_STDIN]->desc.filefd = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
} else
|
||||
break;
|
||||
|
||||
if (wsi->http.cgi->inflate.avail_out)
|
||||
break;
|
||||
|
||||
} while (1);
|
||||
|
||||
return args->len;
|
||||
}
|
||||
#endif /* WITH_ZLIB */
|
||||
|
||||
n = write(n, args->data, args->len);
|
||||
// lwsl_hexdump_notice(args->data, args->len);
|
||||
if (n < args->len)
|
||||
lwsl_notice("LWS_CALLBACK_CGI_STDIN_DATA: "
|
||||
"sent %d only %d went", n, args->len);
|
||||
|
||||
if (wsi->http.cgi->post_in_expected && args->stdwsi[LWS_STDIN] &&
|
||||
args->stdwsi[LWS_STDIN]->desc.filefd > 0) {
|
||||
wsi->http.cgi->post_in_expected -= n;
|
||||
if (!wsi->http.cgi->post_in_expected) {
|
||||
struct lws *siwsi = args->stdwsi[LWS_STDIN];
|
||||
|
||||
lwsl_debug("%s: expected POST in end: "
|
||||
"closing stdin wsi %p, fd %d\n",
|
||||
__func__, siwsi, siwsi->desc.sockfd);
|
||||
|
||||
__remove_wsi_socket_from_fds(siwsi);
|
||||
lwsi_set_state(siwsi, LRS_DEAD_SOCKET);
|
||||
siwsi->socket_is_permanently_unusable = 1;
|
||||
lws_remove_child_from_any_parent(siwsi);
|
||||
if (wsi->context->event_loop_ops->
|
||||
close_handle_manually) {
|
||||
wsi->context->event_loop_ops->
|
||||
close_handle_manually(siwsi);
|
||||
siwsi->told_event_loop_closed = 1;
|
||||
} else {
|
||||
compatible_close(siwsi->desc.sockfd);
|
||||
__lws_free_wsi(siwsi);
|
||||
}
|
||||
wsi->http.cgi->pipe_fds[LWS_STDIN][1] = -1;
|
||||
|
||||
args->stdwsi[LWS_STDIN] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
#endif /* WITH_CGI */
|
||||
#endif /* ROLE_ H1 / H2 */
|
||||
case LWS_CALLBACK_SSL_INFO:
|
||||
si = in;
|
||||
|
||||
(void)si;
|
||||
lwsl_notice("LWS_CALLBACK_SSL_INFO: where: 0x%x, ret: 0x%x\n",
|
||||
si->where, si->ret);
|
||||
break;
|
||||
|
||||
#if LWS_MAX_SMP > 1
|
||||
case LWS_CALLBACK_GET_THREAD_ID:
|
||||
return (int)(unsigned long long)pthread_self();
|
||||
#endif
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* list of supported protocols and callbacks */
|
||||
|
||||
|
@ -1142,6 +801,7 @@ lws_destroy_event_pipe(struct lws *wsi)
|
|||
if (wsi->context->event_loop_ops->wsi_logical_close) {
|
||||
wsi->context->event_loop_ops->wsi_logical_close(wsi);
|
||||
lws_plat_pipe_close(wsi);
|
||||
wsi->context->count_wsi_allocated--;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1668,13 +1328,14 @@ lws_vhost_destroy1(struct lws_vhost *vh)
|
|||
assert(v->lserv_wsi == NULL);
|
||||
v->lserv_wsi = vh->lserv_wsi;
|
||||
|
||||
lwsl_notice("%s: listen skt from %s to %s\n",
|
||||
__func__, vh->name, v->name);
|
||||
|
||||
if (v->lserv_wsi) {
|
||||
lws_vhost_unbind_wsi(vh->lserv_wsi);
|
||||
lws_vhost_bind_wsi(v, v->lserv_wsi);
|
||||
}
|
||||
|
||||
lwsl_notice("%s: listen skt from %s to %s\n",
|
||||
__func__, vh->name, v->name);
|
||||
break;
|
||||
}
|
||||
} lws_end_foreach_ll(v, vhost_next);
|
||||
|
|
605
lib/core/dummy-callback.c
Normal file
605
lib/core/dummy-callback.c
Normal file
|
@ -0,0 +1,605 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2017 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation:
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "core/private.h"
|
||||
|
||||
#if defined(LWS_WITH_HTTP_PROXY)
|
||||
static int
|
||||
proxy_header(struct lws *wsi, struct lws *par, unsigned char *temp,
|
||||
int temp_len, int index, unsigned char **p, unsigned char *end)
|
||||
{
|
||||
int n = lws_hdr_total_length(par, index);
|
||||
|
||||
if (n < 1) {
|
||||
lwsl_debug("%s: no index %d:\n", __func__, index);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lws_hdr_copy(par, (char *)temp, temp_len, index) < 0)
|
||||
return -1;
|
||||
|
||||
lwsl_debug("%s: index %d: %s\n", __func__, index, (char *)temp);
|
||||
|
||||
if (lws_add_http_header_by_token(wsi, index, temp, n, p, end))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
stream_close(struct lws *wsi)
|
||||
{
|
||||
char buf[LWS_PRE + 6], *out = buf + LWS_PRE;
|
||||
|
||||
if (wsi->http.did_stream_close)
|
||||
return 0;
|
||||
|
||||
wsi->http.did_stream_close = 1;
|
||||
|
||||
if (wsi->http2_substream) {
|
||||
if (lws_write(wsi, (unsigned char *)buf + LWS_PRE, 0,
|
||||
LWS_WRITE_HTTP_FINAL) < 0) {
|
||||
lwsl_info("%s: COMPL_CLIENT_HTTP: h2 fin wr failed\n",
|
||||
__func__);
|
||||
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
*out++ = '0';
|
||||
*out++ = '\x0d';
|
||||
*out++ = '\x0a';
|
||||
*out++ = '\x0d';
|
||||
*out++ = '\x0a';
|
||||
|
||||
if (lws_write(wsi, (unsigned char *)buf + LWS_PRE, 5,
|
||||
LWS_WRITE_HTTP_FINAL) < 0) {
|
||||
lwsl_err("%s: COMPL_CLIENT_HTTP: "
|
||||
"h2 final write failed\n", __func__);
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
|
||||
void *user, void *in, size_t len)
|
||||
{
|
||||
struct lws_ssl_info *si;
|
||||
#ifdef LWS_WITH_CGI
|
||||
struct lws_cgi_args *args;
|
||||
#endif
|
||||
#if defined(LWS_WITH_CGI) || defined(LWS_WITH_HTTP_PROXY)
|
||||
char buf[8192];
|
||||
int n;
|
||||
#endif
|
||||
#if defined(LWS_WITH_HTTP_PROXY)
|
||||
unsigned char **p, *end;
|
||||
struct lws *parent;
|
||||
#endif
|
||||
|
||||
switch (reason) {
|
||||
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
|
||||
case LWS_CALLBACK_HTTP:
|
||||
#ifndef LWS_NO_SERVER
|
||||
if (lws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND, NULL))
|
||||
return -1;
|
||||
|
||||
if (lws_http_transaction_completed(wsi))
|
||||
#endif
|
||||
return -1;
|
||||
break;
|
||||
#if !defined(LWS_NO_SERVER)
|
||||
case LWS_CALLBACK_HTTP_BODY_COMPLETION:
|
||||
case LWS_CALLBACK_HTTP_FILE_COMPLETION:
|
||||
if (lws_http_transaction_completed(wsi))
|
||||
return -1;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case LWS_CALLBACK_HTTP_WRITEABLE:
|
||||
#ifdef LWS_WITH_CGI
|
||||
if (wsi->reason_bf & (LWS_CB_REASON_AUX_BF__CGI_HEADERS |
|
||||
LWS_CB_REASON_AUX_BF__CGI)) {
|
||||
n = lws_cgi_write_split_stdout_headers(wsi);
|
||||
if (n < 0) {
|
||||
lwsl_debug("AUX_BF__CGI forcing close\n");
|
||||
return -1;
|
||||
}
|
||||
if (!n)
|
||||
lws_rx_flow_control(
|
||||
wsi->http.cgi->stdwsi[LWS_STDOUT], 1);
|
||||
|
||||
if (wsi->reason_bf & LWS_CB_REASON_AUX_BF__CGI_HEADERS)
|
||||
wsi->reason_bf &=
|
||||
~LWS_CB_REASON_AUX_BF__CGI_HEADERS;
|
||||
else
|
||||
wsi->reason_bf &= ~LWS_CB_REASON_AUX_BF__CGI;
|
||||
|
||||
if (wsi->http.cgi && wsi->http.cgi->cgi_transaction_over)
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (wsi->reason_bf & LWS_CB_REASON_AUX_BF__CGI_CHUNK_END) {
|
||||
if (!wsi->http2_substream) {
|
||||
memcpy(buf + LWS_PRE, "0\x0d\x0a\x0d\x0a", 5);
|
||||
lwsl_debug("writing chunk term and exiting\n");
|
||||
n = lws_write(wsi, (unsigned char *)buf +
|
||||
LWS_PRE, 5, LWS_WRITE_HTTP);
|
||||
} else
|
||||
n = lws_write(wsi, (unsigned char *)buf +
|
||||
LWS_PRE, 0,
|
||||
LWS_WRITE_HTTP_FINAL);
|
||||
|
||||
/* always close after sending it */
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
#if defined(LWS_WITH_HTTP_PROXY)
|
||||
|
||||
if (wsi->reason_bf & LWS_CB_REASON_AUX_BF__PROXY_HEADERS) {
|
||||
|
||||
wsi->reason_bf &= ~LWS_CB_REASON_AUX_BF__PROXY_HEADERS;
|
||||
|
||||
lwsl_notice("%s: %p: issuing proxy headers\n",
|
||||
__func__, wsi);
|
||||
n = lws_write(wsi, wsi->http.pending_return_headers + LWS_PRE,
|
||||
wsi->http.pending_return_headers_len,
|
||||
LWS_WRITE_HTTP_HEADERS);
|
||||
|
||||
lws_free_set_NULL(wsi->http.pending_return_headers);
|
||||
|
||||
if (n < 0) {
|
||||
lwsl_err("%s: EST_CLIENT_HTTP: write failed\n",
|
||||
__func__);
|
||||
return -1;
|
||||
}
|
||||
lws_callback_on_writable(wsi);
|
||||
break;
|
||||
}
|
||||
|
||||
if (wsi->reason_bf & LWS_CB_REASON_AUX_BF__PROXY) {
|
||||
char *px = buf + LWS_PRE;
|
||||
int lenx = sizeof(buf) - LWS_PRE - 32;
|
||||
|
||||
/*
|
||||
* our sink is writeable and our source has something
|
||||
* to read. So read a lump of source material of
|
||||
* suitable size to send or what's available, whichever
|
||||
* is the smaller.
|
||||
*/
|
||||
wsi->reason_bf &= ~LWS_CB_REASON_AUX_BF__PROXY;
|
||||
if (!lws_get_child(wsi))
|
||||
break;
|
||||
|
||||
/* this causes LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ */
|
||||
if (lws_http_client_read(lws_get_child(wsi), &px,
|
||||
&lenx) < 0) {
|
||||
lwsl_info("%s: LWS_CB_REASON_AUX_BF__PROXY: "
|
||||
"client closed\n", __func__);
|
||||
|
||||
stream_close(wsi);
|
||||
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (wsi->reason_bf & LWS_CB_REASON_AUX_BF__PROXY_TRANS_END) {
|
||||
lwsl_info("%s: LWS_CB_REASON_AUX_BF__PROXY_TRANS_END\n",
|
||||
__func__);
|
||||
|
||||
wsi->reason_bf &= ~LWS_CB_REASON_AUX_BF__PROXY_TRANS_END;
|
||||
|
||||
if (stream_close(wsi))
|
||||
return -1;
|
||||
|
||||
if (lws_http_transaction_completed(wsi))
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
#if defined(LWS_WITH_HTTP_PROXY)
|
||||
case LWS_CALLBACK_RECEIVE_CLIENT_HTTP:
|
||||
assert(lws_get_parent(wsi));
|
||||
if (!lws_get_parent(wsi))
|
||||
break;
|
||||
lws_get_parent(wsi)->reason_bf |= LWS_CB_REASON_AUX_BF__PROXY;
|
||||
lws_callback_on_writable(lws_get_parent(wsi));
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ: {
|
||||
char *out = buf + LWS_PRE;
|
||||
|
||||
assert(lws_get_parent(wsi));
|
||||
|
||||
if (wsi->http.proxy_parent_chunked) {
|
||||
|
||||
if (len > sizeof(buf) - LWS_PRE - 16) {
|
||||
lwsl_err("oversize buf %d %d\n", (int)len,
|
||||
(int)sizeof(buf) - LWS_PRE - 16);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* this only needs dealing with on http/1.1 to allow
|
||||
* pipelining
|
||||
*/
|
||||
n = lws_snprintf(out, 14, "%X\x0d\x0a", (int)len);
|
||||
out += n;
|
||||
memcpy(out, in, len);
|
||||
out += len;
|
||||
*out++ = '\x0d';
|
||||
*out++ = '\x0a';
|
||||
|
||||
n = lws_write(lws_get_parent(wsi),
|
||||
(unsigned char *)buf + LWS_PRE,
|
||||
len + n + 2, LWS_WRITE_HTTP);
|
||||
} else
|
||||
n = lws_write(lws_get_parent(wsi), (unsigned char *)in,
|
||||
len, LWS_WRITE_HTTP);
|
||||
if (n < 0)
|
||||
return -1;
|
||||
break; }
|
||||
|
||||
|
||||
/* this handles the proxy case... */
|
||||
case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP: {
|
||||
unsigned char *start, *p, *end;
|
||||
|
||||
/*
|
||||
* We want to proxy these headers, but we are being called
|
||||
* at the point the onward client was established, which is
|
||||
* unrelated to the state or writability of our proxy
|
||||
* connection.
|
||||
*
|
||||
* Therefore produce the headers using the onward client ah
|
||||
* while we have it, and stick them on the output buflist to be
|
||||
* written on the proxy connection as soon as convenient.
|
||||
*/
|
||||
|
||||
parent = lws_get_parent(wsi);
|
||||
|
||||
if (!parent)
|
||||
return 0;
|
||||
|
||||
start = p = (unsigned char *)buf + LWS_PRE;
|
||||
end = p + sizeof(buf) - LWS_PRE - 256;
|
||||
|
||||
if (lws_add_http_header_status(lws_get_parent(wsi),
|
||||
lws_http_client_http_response(wsi), &p, end))
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* copy these headers from the client connection to the parent
|
||||
*/
|
||||
|
||||
proxy_header(parent, wsi, end, 256,
|
||||
WSI_TOKEN_HTTP_CONTENT_LENGTH, &p, end);
|
||||
proxy_header(parent, wsi, end, 256,
|
||||
WSI_TOKEN_HTTP_CONTENT_TYPE, &p, end);
|
||||
proxy_header(parent, wsi, end, 256,
|
||||
WSI_TOKEN_HTTP_ETAG, &p, end);
|
||||
proxy_header(parent, wsi, end, 256,
|
||||
WSI_TOKEN_HTTP_ACCEPT_LANGUAGE, &p, end);
|
||||
proxy_header(parent, wsi, end, 256,
|
||||
WSI_TOKEN_HTTP_CONTENT_ENCODING, &p, end);
|
||||
proxy_header(parent, wsi, end, 256,
|
||||
WSI_TOKEN_HTTP_CACHE_CONTROL, &p, end);
|
||||
|
||||
if (!parent->http2_substream)
|
||||
if (lws_add_http_header_by_token(parent,
|
||||
WSI_TOKEN_CONNECTION, (unsigned char *)"close",
|
||||
5, &p, end))
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* We proxy using h1 only atm, and strip any chunking so it
|
||||
* can go back out on h2 just fine.
|
||||
*
|
||||
* However if we are actually going out on h1, we need to add
|
||||
* our own chunking since we still don't know the size.
|
||||
*/
|
||||
|
||||
if (!parent->http2_substream &&
|
||||
!lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) {
|
||||
lwsl_debug("downstream parent chunked\n");
|
||||
if (lws_add_http_header_by_token(parent,
|
||||
WSI_TOKEN_HTTP_TRANSFER_ENCODING,
|
||||
(unsigned char *)"chunked", 7, &p, end))
|
||||
return -1;
|
||||
|
||||
wsi->http.proxy_parent_chunked = 1;
|
||||
}
|
||||
|
||||
if (lws_finalize_http_header(parent, &p, end))
|
||||
return 1;
|
||||
|
||||
parent->http.pending_return_headers_len = lws_ptr_diff(p, start);
|
||||
parent->http.pending_return_headers =
|
||||
lws_malloc(parent->http.pending_return_headers_len + LWS_PRE,
|
||||
"return proxy headers");
|
||||
if (!parent->http.pending_return_headers)
|
||||
return -1;
|
||||
|
||||
memcpy(parent->http.pending_return_headers + LWS_PRE, start,
|
||||
parent->http.pending_return_headers_len);
|
||||
|
||||
parent->reason_bf |= LWS_CB_REASON_AUX_BF__PROXY_HEADERS;
|
||||
|
||||
lwsl_notice("%s: LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP: prepared headers\n", __func__);
|
||||
lws_callback_on_writable(parent);
|
||||
|
||||
break; }
|
||||
|
||||
case LWS_CALLBACK_COMPLETED_CLIENT_HTTP:
|
||||
lwsl_info("%s: COMPLETED_CLIENT_HTTP: %p (parent %p)\n",
|
||||
__func__, wsi, lws_get_parent(wsi));
|
||||
if (!lws_get_parent(wsi))
|
||||
break;
|
||||
lws_get_parent(wsi)->reason_bf |=
|
||||
LWS_CB_REASON_AUX_BF__PROXY_TRANS_END;
|
||||
lws_callback_on_writable(lws_get_parent(wsi));
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
|
||||
if (!lws_get_parent(wsi))
|
||||
break;
|
||||
lwsl_err("%s: LWS_CALLBACK_CLOSED_CLIENT_HTTP\n", __func__);
|
||||
lws_set_timeout(lws_get_parent(wsi), LWS_TO_KILL_ASYNC,
|
||||
PENDING_TIMEOUT_KILLED_BY_PROXY_CLIENT_CLOSE);
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER:
|
||||
parent = lws_get_parent(wsi);
|
||||
|
||||
if (!parent)
|
||||
break;
|
||||
|
||||
p = (unsigned char **)in;
|
||||
end = (*p) + len;
|
||||
|
||||
/*
|
||||
* copy these headers from the parent request to the client
|
||||
* connection's request
|
||||
*/
|
||||
|
||||
proxy_header(wsi, parent, (unsigned char *)buf, sizeof(buf),
|
||||
WSI_TOKEN_HOST, p, end);
|
||||
proxy_header(wsi, parent, (unsigned char *)buf, sizeof(buf),
|
||||
WSI_TOKEN_HTTP_ETAG, p, end);
|
||||
proxy_header(wsi, parent, (unsigned char *)buf, sizeof(buf),
|
||||
WSI_TOKEN_HTTP_IF_MODIFIED_SINCE, p, end);
|
||||
proxy_header(wsi, parent, (unsigned char *)buf, sizeof(buf),
|
||||
WSI_TOKEN_HTTP_ACCEPT_LANGUAGE, p, end);
|
||||
proxy_header(wsi, parent, (unsigned char *)buf, sizeof(buf),
|
||||
WSI_TOKEN_HTTP_ACCEPT_ENCODING, p, end);
|
||||
proxy_header(wsi, parent, (unsigned char *)buf, sizeof(buf),
|
||||
WSI_TOKEN_HTTP_CACHE_CONTROL, p, end);
|
||||
|
||||
buf[0] = '\0';
|
||||
lws_get_peer_simple(parent, buf, sizeof(buf));
|
||||
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_X_FORWARDED_FOR,
|
||||
(unsigned char *)buf, strlen(buf), p, end))
|
||||
return -1;
|
||||
|
||||
break;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef LWS_WITH_CGI
|
||||
/* CGI IO events (POLLIN/OUT) appear here, our default policy is:
|
||||
*
|
||||
* - POST data goes on subprocess stdin
|
||||
* - subprocess stdout goes on http via writeable callback
|
||||
* - subprocess stderr goes to the logs
|
||||
*/
|
||||
case LWS_CALLBACK_CGI:
|
||||
args = (struct lws_cgi_args *)in;
|
||||
switch (args->ch) { /* which of stdin/out/err ? */
|
||||
case LWS_STDIN:
|
||||
/* TBD stdin rx flow control */
|
||||
break;
|
||||
case LWS_STDOUT:
|
||||
/* quench POLLIN on STDOUT until MASTER got writeable */
|
||||
lws_rx_flow_control(args->stdwsi[LWS_STDOUT], 0);
|
||||
wsi->reason_bf |= LWS_CB_REASON_AUX_BF__CGI;
|
||||
/* when writing to MASTER would not block */
|
||||
lws_callback_on_writable(wsi);
|
||||
break;
|
||||
case LWS_STDERR:
|
||||
n = lws_get_socket_fd(args->stdwsi[LWS_STDERR]);
|
||||
if (n < 0)
|
||||
break;
|
||||
n = read(n, buf, sizeof(buf) - 2);
|
||||
if (n > 0) {
|
||||
if (buf[n - 1] != '\n')
|
||||
buf[n++] = '\n';
|
||||
buf[n] = '\0';
|
||||
lwsl_notice("CGI-stderr: %s\n", buf);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_CGI_TERMINATED:
|
||||
lwsl_debug("LWS_CALLBACK_CGI_TERMINATED: %d %" PRIu64 "\n",
|
||||
wsi->http.cgi->explicitly_chunked,
|
||||
(uint64_t)wsi->http.cgi->content_length);
|
||||
if (!wsi->http.cgi->explicitly_chunked &&
|
||||
!wsi->http.cgi->content_length) {
|
||||
/* send terminating chunk */
|
||||
lwsl_debug("LWS_CALLBACK_CGI_TERMINATED: ending\n");
|
||||
wsi->reason_bf |= LWS_CB_REASON_AUX_BF__CGI_CHUNK_END;
|
||||
lws_callback_on_writable(wsi);
|
||||
lws_set_timeout(wsi, PENDING_TIMEOUT_CGI, 3);
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
|
||||
case LWS_CALLBACK_CGI_STDIN_DATA: /* POST body for stdin */
|
||||
args = (struct lws_cgi_args *)in;
|
||||
args->data[args->len] = '\0';
|
||||
if (!args->stdwsi[LWS_STDIN])
|
||||
return -1;
|
||||
n = lws_get_socket_fd(args->stdwsi[LWS_STDIN]);
|
||||
if (n < 0)
|
||||
return -1;
|
||||
|
||||
#if defined(LWS_WITH_ZLIB)
|
||||
if (wsi->http.cgi->gzip_inflate) {
|
||||
/* gzip handling */
|
||||
|
||||
if (!wsi->http.cgi->gzip_init) {
|
||||
lwsl_err("inflating gzip\n");
|
||||
|
||||
memset(&wsi->http.cgi->inflate, 0, sizeof(wsi->http.cgi->inflate));
|
||||
|
||||
if (inflateInit2(&wsi->http.cgi->inflate, 16 + 15) != Z_OK) {
|
||||
lwsl_err("%s: iniflateInit failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
wsi->http.cgi->gzip_init = 1;
|
||||
}
|
||||
|
||||
wsi->http.cgi->inflate.next_in = args->data;
|
||||
wsi->http.cgi->inflate.avail_in = args->len;
|
||||
|
||||
do {
|
||||
|
||||
wsi->http.cgi->inflate.next_out =
|
||||
wsi->http.cgi->inflate_buf;
|
||||
wsi->http.cgi->inflate.avail_out =
|
||||
sizeof(wsi->http.cgi->inflate_buf);
|
||||
|
||||
n = inflate(&wsi->http.cgi->inflate,
|
||||
Z_SYNC_FLUSH);
|
||||
|
||||
switch (n) {
|
||||
case Z_NEED_DICT:
|
||||
case Z_STREAM_ERROR:
|
||||
case Z_DATA_ERROR:
|
||||
case Z_MEM_ERROR:
|
||||
inflateEnd(&wsi->http.cgi->inflate);
|
||||
wsi->http.cgi->gzip_init = 0;
|
||||
lwsl_err("zlib error inflate %d\n", n);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (wsi->http.cgi->inflate.avail_out !=
|
||||
sizeof(wsi->http.cgi->inflate_buf)) {
|
||||
int written;
|
||||
|
||||
written = write(args->stdwsi[LWS_STDIN]->desc.filefd,
|
||||
wsi->http.cgi->inflate_buf,
|
||||
sizeof(wsi->http.cgi->inflate_buf) -
|
||||
wsi->http.cgi->inflate.avail_out);
|
||||
|
||||
if (written != (int)(
|
||||
sizeof(wsi->http.cgi->inflate_buf) -
|
||||
wsi->http.cgi->inflate.avail_out)) {
|
||||
lwsl_notice("LWS_CALLBACK_CGI_STDIN_DATA: "
|
||||
"sent %d only %d went", n, args->len);
|
||||
}
|
||||
|
||||
if (n == Z_STREAM_END) {
|
||||
lwsl_err("gzip inflate end\n");
|
||||
inflateEnd(&wsi->http.cgi->inflate);
|
||||
wsi->http.cgi->gzip_init = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
} else
|
||||
break;
|
||||
|
||||
if (wsi->http.cgi->inflate.avail_out)
|
||||
break;
|
||||
|
||||
} while (1);
|
||||
|
||||
return args->len;
|
||||
}
|
||||
#endif /* WITH_ZLIB */
|
||||
|
||||
n = write(n, args->data, args->len);
|
||||
// lwsl_hexdump_notice(args->data, args->len);
|
||||
if (n < args->len)
|
||||
lwsl_notice("LWS_CALLBACK_CGI_STDIN_DATA: "
|
||||
"sent %d only %d went", n, args->len);
|
||||
|
||||
if (wsi->http.cgi->post_in_expected && args->stdwsi[LWS_STDIN] &&
|
||||
args->stdwsi[LWS_STDIN]->desc.filefd > 0) {
|
||||
wsi->http.cgi->post_in_expected -= n;
|
||||
if (!wsi->http.cgi->post_in_expected) {
|
||||
struct lws *siwsi = args->stdwsi[LWS_STDIN];
|
||||
|
||||
lwsl_debug("%s: expected POST in end: "
|
||||
"closing stdin wsi %p, fd %d\n",
|
||||
__func__, siwsi, siwsi->desc.sockfd);
|
||||
|
||||
__remove_wsi_socket_from_fds(siwsi);
|
||||
lwsi_set_state(siwsi, LRS_DEAD_SOCKET);
|
||||
siwsi->socket_is_permanently_unusable = 1;
|
||||
lws_remove_child_from_any_parent(siwsi);
|
||||
if (wsi->context->event_loop_ops->
|
||||
close_handle_manually) {
|
||||
wsi->context->event_loop_ops->
|
||||
close_handle_manually(siwsi);
|
||||
siwsi->told_event_loop_closed = 1;
|
||||
} else {
|
||||
compatible_close(siwsi->desc.sockfd);
|
||||
__lws_free_wsi(siwsi);
|
||||
}
|
||||
wsi->http.cgi->pipe_fds[LWS_STDIN][1] = -1;
|
||||
|
||||
args->stdwsi[LWS_STDIN] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
#endif /* WITH_CGI */
|
||||
#endif /* ROLE_ H1 / H2 */
|
||||
case LWS_CALLBACK_SSL_INFO:
|
||||
si = in;
|
||||
|
||||
(void)si;
|
||||
lwsl_notice("LWS_CALLBACK_SSL_INFO: where: 0x%x, ret: 0x%x\n",
|
||||
si->where, si->ret);
|
||||
break;
|
||||
|
||||
#if LWS_MAX_SMP > 1
|
||||
case LWS_CALLBACK_GET_THREAD_ID:
|
||||
return (int)(unsigned long long)pthread_self();
|
||||
#endif
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -53,6 +53,7 @@ static const char * const log_level_names[] = {
|
|||
"CLIENT",
|
||||
"LATENCY",
|
||||
"USER",
|
||||
"THREAD",
|
||||
"?",
|
||||
"?"
|
||||
};
|
||||
|
@ -374,6 +375,15 @@ __lws_set_timer_usecs(struct lws *wsi, lws_usec_t usecs)
|
|||
// lws_dll_dump(&pt->dll_head_hrtimer, "after set_timer_usec");
|
||||
}
|
||||
|
||||
LWS_VISIBLE lws_usec_t
|
||||
lws_now_usecs(void)
|
||||
{
|
||||
struct timeval now;
|
||||
|
||||
gettimeofday(&now, NULL);
|
||||
return (now.tv_sec * 1000000ll) + now.tv_usec;
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_set_timer_usecs(struct lws *wsi, lws_usec_t usecs)
|
||||
{
|
||||
|
@ -867,12 +877,16 @@ just_kill_connection:
|
|||
lwsl_debug("%s: real just_kill_connection: %p (sockfd %d)\n", __func__,
|
||||
wsi, wsi->desc.sockfd);
|
||||
|
||||
#ifdef LWS_WITH_HTTP_PROXY
|
||||
#ifdef LWS_WITH_HUBBUB
|
||||
if (wsi->http.rw) {
|
||||
lws_rewrite_destroy(wsi->http.rw);
|
||||
wsi->http.rw = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (wsi->http.pending_return_headers)
|
||||
lws_free_set_NULL(wsi->http.pending_return_headers);
|
||||
|
||||
/*
|
||||
* we won't be servicing or receiving anything further from this guy
|
||||
* delete socket from the internal poll list if still present
|
||||
|
@ -2029,6 +2043,7 @@ static const char * const colours[] = {
|
|||
"[33m", /* LLL_CLIENT */
|
||||
"[33;1m", /* LLL_LATENCY */
|
||||
"[30;1m", /* LLL_USER */
|
||||
"[31m", /* LLL_THREAD */
|
||||
};
|
||||
|
||||
LWS_VISIBLE void lwsl_emit_stderr(int level, const char *line)
|
||||
|
@ -2394,7 +2409,7 @@ lws_parse_uri(char *p, const char **prot, const char **ads, int *port,
|
|||
const char **path)
|
||||
{
|
||||
const char *end;
|
||||
static const char *slash = "/";
|
||||
char unix_skt = 0;
|
||||
|
||||
/* cut up the location into address, port and path */
|
||||
*prot = p;
|
||||
|
@ -2408,32 +2423,32 @@ lws_parse_uri(char *p, const char **prot, const char **ads, int *port,
|
|||
*p = '\0';
|
||||
p += 3;
|
||||
}
|
||||
if (*p == '+') /* unix skt */
|
||||
unix_skt = 1;
|
||||
|
||||
*ads = p;
|
||||
if (!strcmp(*prot, "http") || !strcmp(*prot, "ws"))
|
||||
*port = 80;
|
||||
else if (!strcmp(*prot, "https") || !strcmp(*prot, "wss"))
|
||||
*port = 443;
|
||||
|
||||
if (*p == '[')
|
||||
{
|
||||
++(*ads);
|
||||
while (*p && *p != ']')
|
||||
p++;
|
||||
if (*p)
|
||||
*p++ = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
while (*p && *p != ':' && *p != '/')
|
||||
p++;
|
||||
}
|
||||
if (*p == '[') {
|
||||
++(*ads);
|
||||
while (*p && *p != ']')
|
||||
p++;
|
||||
if (*p)
|
||||
*p++ = '\0';
|
||||
} else
|
||||
while (*p && *p != ':' && (unix_skt || *p != '/'))
|
||||
p++;
|
||||
|
||||
if (*p == ':') {
|
||||
*p++ = '\0';
|
||||
*port = atoi(p);
|
||||
while (*p && *p != '/')
|
||||
p++;
|
||||
}
|
||||
*path = slash;
|
||||
*path = "/";
|
||||
if (*p) {
|
||||
*p++ = '\0';
|
||||
if (*p)
|
||||
|
|
|
@ -251,6 +251,10 @@ lws_ssl_capable_read_no_ssl(struct lws *wsi, unsigned char *buf, int len)
|
|||
n = recv(wsi->desc.sockfd, (char *)buf, len, 0);
|
||||
|
||||
if (n >= 0) {
|
||||
|
||||
if (!n && wsi->unix_skt)
|
||||
return LWS_SSL_CAPABLE_ERROR;
|
||||
|
||||
if (wsi->vhost)
|
||||
wsi->vhost->conn_stats.rx += n;
|
||||
lws_stats_atomic_bump(context, pt, LWSSTATS_B_READ, n);
|
||||
|
|
|
@ -959,6 +959,7 @@ struct lws {
|
|||
unsigned int on_same_vh_list:1;
|
||||
unsigned int handling_404:1;
|
||||
unsigned int protocol_bind_balance:1;
|
||||
unsigned int unix_skt:1;
|
||||
|
||||
unsigned int could_have_pending:1; /* detect back-to-back writes */
|
||||
unsigned int outer_will_close:1;
|
||||
|
@ -1156,7 +1157,8 @@ user_callback_handle_rxflow(lws_callback_function, struct lws *wsi,
|
|||
void *in, size_t len);
|
||||
|
||||
LWS_EXTERN int
|
||||
lws_plat_set_socket_options(struct lws_vhost *vhost, lws_sockfd_type fd);
|
||||
lws_plat_set_socket_options(struct lws_vhost *vhost, lws_sockfd_type fd,
|
||||
int unix_skt);
|
||||
|
||||
LWS_EXTERN int
|
||||
lws_plat_check_connection_error(struct lws *wsi);
|
||||
|
@ -1493,7 +1495,7 @@ void
|
|||
lws_peer_dump_from_wsi(struct lws *wsi);
|
||||
#endif
|
||||
|
||||
#ifdef LWS_WITH_HTTP_PROXY
|
||||
#ifdef LWS_WITH_HUBBUB
|
||||
hubbub_error
|
||||
html_parser_cb(const hubbub_token *token, void *pw);
|
||||
#endif
|
||||
|
|
|
@ -974,6 +974,26 @@ cleanup:
|
|||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
rops_close_kill_connection_h1(struct lws *wsi, enum lws_close_status reason)
|
||||
{
|
||||
#if defined(LWS_WITH_HTTP_PROXY)
|
||||
struct lws *wsi_eff = lws_client_wsi_effective(wsi);
|
||||
|
||||
if (!wsi_eff->http.proxy_clientside)
|
||||
return 0;
|
||||
|
||||
wsi_eff->http.proxy_clientside = 0;
|
||||
|
||||
if (user_callback_handle_rxflow(wsi_eff->protocol->callback, wsi_eff,
|
||||
LWS_CALLBACK_COMPLETED_CLIENT_HTTP,
|
||||
wsi_eff->user_space, NULL, 0))
|
||||
return 0;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct lws_role_ops role_ops_h1 = {
|
||||
/* role name */ "h1",
|
||||
/* alpn id */ "http/1.1",
|
||||
|
@ -993,7 +1013,7 @@ struct lws_role_ops role_ops_h1 = {
|
|||
/* alpn_negotiated */ rops_alpn_negotiated_h1,
|
||||
/* close_via_role_protocol */ NULL,
|
||||
/* close_role */ NULL,
|
||||
/* close_kill_connection */ NULL,
|
||||
/* close_kill_connection */ rops_close_kill_connection_h1,
|
||||
/* destroy_role */ rops_destroy_role_h1,
|
||||
#if !defined(LWS_NO_SERVER)
|
||||
/* adoption_bind */ rops_adoption_bind_h1,
|
||||
|
|
|
@ -219,6 +219,8 @@ bail1:
|
|||
parent_wsi->h2.child_list = wsi->h2.sibling_list;
|
||||
parent_wsi->h2.child_count--;
|
||||
|
||||
vh->context->count_wsi_allocated--;
|
||||
|
||||
if (wsi->user_space)
|
||||
lws_free_set_NULL(wsi->user_space);
|
||||
vh->protocols[0].callback(wsi, LWS_CALLBACK_WSI_DESTROY, NULL, NULL, 0);
|
||||
|
@ -381,6 +383,9 @@ lws_h2_rst_stream(struct lws *wsi, uint32_t err, const char *reason)
|
|||
struct lws_h2_netconn *h2n = nwsi->h2.h2n;
|
||||
struct lws_h2_protocol_send *pps;
|
||||
|
||||
if (!h2n)
|
||||
return 0;
|
||||
|
||||
if (h2n->type == LWS_H2_FRAME_TYPE_COUNT)
|
||||
return 0;
|
||||
|
||||
|
|
|
@ -578,6 +578,19 @@ rops_close_kill_connection_h2(struct lws *wsi, enum lws_close_status reason)
|
|||
{
|
||||
struct lws *wsi2;
|
||||
|
||||
#if defined(LWS_WITH_HTTP_PROXY)
|
||||
if (wsi->http.proxy_clientside) {
|
||||
struct lws *wsi_eff = lws_client_wsi_effective(wsi);
|
||||
|
||||
wsi->http.proxy_clientside = 0;
|
||||
|
||||
if (user_callback_handle_rxflow(wsi_eff->protocol->callback, wsi_eff,
|
||||
LWS_CALLBACK_COMPLETED_CLIENT_HTTP,
|
||||
wsi_eff->user_space, NULL, 0))
|
||||
wsi->http.proxy_clientside = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (wsi->http2_substream && wsi->h2_stream_carries_ws)
|
||||
lws_h2_rst_stream(wsi, 0, "none");
|
||||
|
||||
|
@ -960,7 +973,8 @@ rops_perform_user_POLLOUT_h2(struct lws *wsi)
|
|||
* states. In those cases we will hear about
|
||||
* END_STREAM going out in the POLLOUT handler.
|
||||
*/
|
||||
if (n || w->h2.send_END_STREAM) {
|
||||
if (!w->h2.pending_status_body &&
|
||||
(n || w->h2.send_END_STREAM)) {
|
||||
lwsl_info("closing stream after h2 action\n");
|
||||
lws_close_free_wsi(w, LWS_CLOSE_STATUS_NOSTATUS,
|
||||
"h2 end stream");
|
||||
|
|
|
@ -37,8 +37,13 @@ lws_client_connect_2(struct lws *wsi)
|
|||
ssize_t plen = 0;
|
||||
#endif
|
||||
struct addrinfo *result;
|
||||
#if defined(LWS_WITH_UNIX_SOCK)
|
||||
struct sockaddr_un sau;
|
||||
char unix_skt = 0;
|
||||
#endif
|
||||
const char *ads;
|
||||
sockaddr46 sa46;
|
||||
const struct sockaddr *psa;
|
||||
int n, port;
|
||||
const char *cce = "", *iface;
|
||||
const char *meth = NULL;
|
||||
|
@ -183,6 +188,29 @@ create_new_conn:
|
|||
lws_vhost_unlock(wsi->vhost);
|
||||
}
|
||||
|
||||
/*
|
||||
* unix socket destination?
|
||||
*/
|
||||
|
||||
ads = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS);
|
||||
#if defined(LWS_WITH_UNIX_SOCK)
|
||||
if (*ads == '+') {
|
||||
ads++;
|
||||
memset(&sau, 0, sizeof(sau));
|
||||
sau.sun_family = AF_UNIX;
|
||||
strncpy(sau.sun_path, ads, sizeof(sau.sun_path));
|
||||
sau.sun_path[sizeof(sau.sun_path) - 1] = '\0';
|
||||
|
||||
lwsl_info("%s: Unix skt: %s\n", __func__, ads);
|
||||
|
||||
if (sau.sun_path[0] == '@')
|
||||
sau.sun_path[0] = '\0';
|
||||
|
||||
unix_skt = 1;
|
||||
goto ads_known;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* start off allowing ipv6 on connection if vhost allows it
|
||||
*/
|
||||
|
@ -341,6 +369,10 @@ create_new_conn:
|
|||
if (result)
|
||||
freeaddrinfo(result);
|
||||
|
||||
#if defined(LWS_WITH_UNIX_SOCK)
|
||||
ads_known:
|
||||
#endif
|
||||
|
||||
/* now we decided on ipv4 or ipv6, set the port */
|
||||
|
||||
if (!lws_socket_is_valid(wsi->desc.sockfd)) {
|
||||
|
@ -351,12 +383,21 @@ create_new_conn:
|
|||
goto oom4;
|
||||
}
|
||||
|
||||
#if defined(LWS_WITH_UNIX_SOCK)
|
||||
if (unix_skt) {
|
||||
wsi->unix_skt = 1;
|
||||
wsi->desc.sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
|
||||
#ifdef LWS_WITH_IPV6
|
||||
if (wsi->ipv6)
|
||||
wsi->desc.sockfd = socket(AF_INET6, SOCK_STREAM, 0);
|
||||
else
|
||||
#endif
|
||||
wsi->desc.sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
}
|
||||
|
||||
if (!lws_socket_is_valid(wsi->desc.sockfd)) {
|
||||
lwsl_warn("Unable to open socket\n");
|
||||
|
@ -364,7 +405,12 @@ create_new_conn:
|
|||
goto oom4;
|
||||
}
|
||||
|
||||
if (lws_plat_set_socket_options(wsi->vhost, wsi->desc.sockfd)) {
|
||||
if (lws_plat_set_socket_options(wsi->vhost, wsi->desc.sockfd,
|
||||
#if defined(LWS_WITH_UNIX_SOCK)
|
||||
unix_skt)) {
|
||||
#else
|
||||
0)) {
|
||||
#endif
|
||||
lwsl_err("Failed to set wsi socket options\n");
|
||||
compatible_close(wsi->desc.sockfd);
|
||||
cce = "set socket opts failed";
|
||||
|
@ -409,18 +455,29 @@ create_new_conn:
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef LWS_WITH_IPV6
|
||||
if (wsi->ipv6) {
|
||||
sa46.sa6.sin6_port = htons(port);
|
||||
n = sizeof(struct sockaddr_in6);
|
||||
#if defined(LWS_WITH_UNIX_SOCK)
|
||||
if (unix_skt) {
|
||||
psa = (const struct sockaddr *)&sau;
|
||||
n = sizeof(sau);
|
||||
} else
|
||||
#endif
|
||||
|
||||
{
|
||||
sa46.sa4.sin_port = htons(port);
|
||||
n = sizeof(struct sockaddr);
|
||||
#ifdef LWS_WITH_IPV6
|
||||
if (wsi->ipv6) {
|
||||
sa46.sa6.sin6_port = htons(port);
|
||||
n = sizeof(struct sockaddr_in6);
|
||||
psa = (const struct sockaddr *)&sa46;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
sa46.sa4.sin_port = htons(port);
|
||||
n = sizeof(struct sockaddr);
|
||||
psa = (const struct sockaddr *)&sa46;
|
||||
}
|
||||
}
|
||||
|
||||
if (connect(wsi->desc.sockfd, (const struct sockaddr *)&sa46, n) == -1 ||
|
||||
if (connect(wsi->desc.sockfd, (const struct sockaddr *)psa, n) == -1 ||
|
||||
LWS_ERRNO == LWS_EISCONN) {
|
||||
if (LWS_ERRNO == LWS_EALREADY ||
|
||||
LWS_ERRNO == LWS_EINPROGRESS ||
|
||||
|
@ -729,7 +786,7 @@ lws_client_reset(struct lws **pwsi, int ssl, const char *address, int port,
|
|||
return *pwsi;
|
||||
}
|
||||
|
||||
#ifdef LWS_WITH_HTTP_PROXY
|
||||
#if defined(LWS_WITH_HTTP_PROXY) && defined(LWS_WITH_HUBBUB)
|
||||
hubbub_error
|
||||
html_parser_cb(const hubbub_token *token, void *pw)
|
||||
{
|
||||
|
|
|
@ -882,7 +882,7 @@ lws_client_interpret_server_handshake(struct lws *wsi)
|
|||
if (!strncmp(lws_hdr_simple_ptr(wsi,
|
||||
WSI_TOKEN_HTTP_CONTENT_TYPE),
|
||||
"text/html", 9))
|
||||
wsi->http.perform_rewrite = 1;
|
||||
wsi->http.perform_rewrite = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -993,7 +993,9 @@ bail2:
|
|||
}
|
||||
wsi->already_did_cce = 1;
|
||||
|
||||
lwsl_info("closing connection due to bail2 connection error\n");
|
||||
lwsl_info("closing connection (prot %s) "
|
||||
"due to bail2 connection error: %s\n", wsi->protocol ?
|
||||
wsi->protocol->name : "unknown", cce);
|
||||
|
||||
/* closing will free up his parsing allocations */
|
||||
lws_close_free_wsi(wsi, close_reason, "c hs interp");
|
||||
|
@ -1065,6 +1067,9 @@ lws_generate_client_handshake(struct lws *wsi, char *pkt)
|
|||
p += sprintf(p, "Pragma: no-cache\x0d\x0a"
|
||||
"Cache-Control: no-cache\x0d\x0a");
|
||||
|
||||
if (!wsi->client_pipeline)
|
||||
p += sprintf(p, "connection: close\x0d\x0a");
|
||||
|
||||
p += sprintf(p, "Host: %s\x0d\x0a",
|
||||
lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_HOST));
|
||||
|
||||
|
@ -1196,7 +1201,7 @@ spin_chunks:
|
|||
wsi->chunk_remaining < n)
|
||||
n = wsi->chunk_remaining;
|
||||
|
||||
#ifdef LWS_WITH_HTTP_PROXY
|
||||
#if defined(LWS_WITH_HTTP_PROXY) && defined(LWS_WITH_HUBBUB)
|
||||
/* hubbub */
|
||||
if (wsi->http.perform_rewrite)
|
||||
lws_rewrite_parse(wsi->http.rw, (unsigned char *)*buf, n);
|
||||
|
|
|
@ -384,7 +384,7 @@ lws_return_http_status(struct lws *wsi, unsigned int code,
|
|||
|
||||
#if defined(LWS_WITH_HTTP2)
|
||||
if (wsi->http2_substream) {
|
||||
unsigned char *body = p + 512;
|
||||
char *body = (char *)start + context->pt_serv_buf_size - 512;
|
||||
|
||||
/*
|
||||
* for HTTP/2, the headers must be sent separately, since they
|
||||
|
@ -398,7 +398,8 @@ lws_return_http_status(struct lws *wsi, unsigned int code,
|
|||
*
|
||||
* Solve it by writing the headers now...
|
||||
*/
|
||||
m = lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS);
|
||||
m = lws_write(wsi, start, lws_ptr_diff(p, start),
|
||||
LWS_WRITE_HTTP_HEADERS);
|
||||
if (m != lws_ptr_diff(p, start))
|
||||
return 1;
|
||||
|
||||
|
@ -407,8 +408,7 @@ lws_return_http_status(struct lws *wsi, unsigned int code,
|
|||
* handle_POLLOUT
|
||||
*/
|
||||
|
||||
len = sprintf((char *)body,
|
||||
"<html><body><h1>%u</h1>%s</body></html>",
|
||||
len = sprintf(body, "<html><body><h1>%u</h1>%s</body></html>",
|
||||
code, html_body);
|
||||
wsi->http.tx_content_length = len;
|
||||
wsi->http.tx_content_remain = len;
|
||||
|
@ -418,8 +418,7 @@ lws_return_http_status(struct lws *wsi, unsigned int code,
|
|||
if (!wsi->h2.pending_status_body)
|
||||
return -1;
|
||||
|
||||
strcpy(wsi->h2.pending_status_body + LWS_PRE,
|
||||
(const char *)body);
|
||||
strcpy(wsi->h2.pending_status_body + LWS_PRE, body);
|
||||
lws_callback_on_writable(wsi);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
* enabled
|
||||
*/
|
||||
|
||||
#if defined(LWS_WITH_HTTP_PROXY)
|
||||
#if defined(LWS_WITH_HUBBUB)
|
||||
#include <hubbub/hubbub.h>
|
||||
#include <hubbub/parser.h>
|
||||
#endif
|
||||
|
@ -137,7 +137,7 @@ struct allocated_headers {
|
|||
|
||||
|
||||
|
||||
#if defined(LWS_WITH_HTTP_PROXY)
|
||||
#if defined(LWS_WITH_HUBBUB)
|
||||
struct lws_rewrite {
|
||||
hubbub_parser *parser;
|
||||
hubbub_parser_optparams params;
|
||||
|
@ -202,6 +202,9 @@ struct lws_access_log {
|
|||
struct _lws_http_mode_related {
|
||||
struct lws *new_wsi_list;
|
||||
|
||||
unsigned char *pending_return_headers;
|
||||
size_t pending_return_headers_len;
|
||||
|
||||
#if defined(LWS_WITH_HTTP_PROXY)
|
||||
struct lws_rewrite *rw;
|
||||
#endif
|
||||
|
@ -238,9 +241,12 @@ struct _lws_http_mode_related {
|
|||
|
||||
#if defined(LWS_WITH_HTTP_PROXY)
|
||||
unsigned int perform_rewrite:1;
|
||||
unsigned int proxy_clientside:1;
|
||||
unsigned int proxy_parent_chunked:1;
|
||||
#endif
|
||||
unsigned int deferred_transaction_completed:1;
|
||||
unsigned int content_length_explicitly_zero:1;
|
||||
unsigned int did_stream_close:1;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -93,7 +93,7 @@ lws_prepare_access_log_info(struct lws *wsi, char *uri_ptr, int uri_len, int met
|
|||
pa, da, me, uri,
|
||||
hver[wsi->http.request_version]);
|
||||
|
||||
lwsl_notice("%s\n", wsi->http.access_log.header_log);
|
||||
//lwsl_notice("%s\n", wsi->http.access_log.header_log);
|
||||
|
||||
l = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_USER_AGENT);
|
||||
if (l) {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "core/private.h"
|
||||
|
||||
#if defined(LWS_WITH_HUBBUB)
|
||||
|
||||
LWS_EXTERN struct lws_rewrite *
|
||||
lws_rewrite_create(struct lws *wsi, hubbub_callback_t cb, const char *from, const char *to)
|
||||
|
@ -50,3 +51,4 @@ lws_rewrite_destroy(struct lws_rewrite *r)
|
|||
lws_free(r);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -223,7 +223,7 @@ done_list:
|
|||
}
|
||||
#endif
|
||||
#endif
|
||||
lws_plat_set_socket_options(vhost, sockfd);
|
||||
lws_plat_set_socket_options(vhost, sockfd, 0);
|
||||
|
||||
is = lws_socket_bind(vhost, sockfd, vhost->listen_port, vhost->iface);
|
||||
/*
|
||||
|
@ -236,15 +236,24 @@ done_list:
|
|||
compatible_close(sockfd);
|
||||
goto deal;
|
||||
}
|
||||
vhost->listen_port = is;
|
||||
|
||||
lwsl_debug("%s: lws_socket_bind says %d\n", __func__, is);
|
||||
|
||||
wsi = lws_zalloc(sizeof(struct lws), "listen wsi");
|
||||
if (wsi == NULL) {
|
||||
lwsl_err("Out of mem\n");
|
||||
goto bail;
|
||||
}
|
||||
|
||||
#ifdef LWS_WITH_UNIX_SOCK
|
||||
if (!LWS_UNIX_SOCK_ENABLED(vhost))
|
||||
#endif
|
||||
{
|
||||
wsi->unix_skt = 1;
|
||||
vhost->listen_port = is;
|
||||
|
||||
lwsl_debug("%s: lws_socket_bind says %d\n", __func__,
|
||||
is);
|
||||
}
|
||||
|
||||
wsi->context = vhost->context;
|
||||
wsi->desc.sockfd = sockfd;
|
||||
lws_role_transition(wsi, 0, LRS_UNCONNECTED, &role_ops_listen);
|
||||
|
@ -327,7 +336,7 @@ lws_select_vhost(struct lws_context *context, int port, const char *servername)
|
|||
vhost = context->vhost_list;
|
||||
while (vhost) {
|
||||
m = (int)strlen(vhost->name);
|
||||
if (port == vhost->listen_port &&
|
||||
if (port && port == vhost->listen_port &&
|
||||
m <= (colon - 2) &&
|
||||
servername[colon - m - 1] == '.' &&
|
||||
!strncmp(vhost->name, servername + colon - m, m)) {
|
||||
|
@ -342,7 +351,7 @@ lws_select_vhost(struct lws_context *context, int port, const char *servername)
|
|||
|
||||
vhost = context->vhost_list;
|
||||
while (vhost) {
|
||||
if (port == vhost->listen_port) {
|
||||
if (port && port == vhost->listen_port) {
|
||||
lwsl_info("%s: vhost match to %s based on port %d\n",
|
||||
__func__, vhost->name, port);
|
||||
return vhost;
|
||||
|
@ -784,7 +793,7 @@ lws_unauthorised_basic_auth(struct lws *wsi)
|
|||
{
|
||||
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
|
||||
unsigned char *start = pt->serv_buf + LWS_PRE,
|
||||
*p = start, *end = p + 512;
|
||||
*p = start, *end = p + 2048;
|
||||
char buf[64];
|
||||
int n;
|
||||
|
||||
|
@ -1011,7 +1020,7 @@ lws_http_action(struct lws *wsi)
|
|||
* URI from the host: header and ignore the path part
|
||||
*/
|
||||
unsigned char *start = pt->serv_buf + LWS_PRE, *p = start,
|
||||
*end = p + 512;
|
||||
*end = p + wsi->context->pt_serv_buf_size - LWS_PRE;
|
||||
|
||||
if (!lws_hdr_total_length(wsi, WSI_TOKEN_HOST))
|
||||
goto bail_nuke_ah;
|
||||
|
@ -1077,9 +1086,10 @@ lws_http_action(struct lws *wsi)
|
|||
(hit->origin_protocol != LWSMPRO_CGI &&
|
||||
hit->origin_protocol != LWSMPRO_CALLBACK)) {
|
||||
unsigned char *start = pt->serv_buf + LWS_PRE,
|
||||
*p = start, *end = p + 512;
|
||||
*p = start, *end = p + wsi->context->pt_serv_buf_size -
|
||||
LWS_PRE - 512;
|
||||
|
||||
lwsl_debug("Doing 301 '%s' org %s\n", s, hit->origin);
|
||||
lwsl_info("Doing 301 '%s' org %s\n", s, hit->origin);
|
||||
|
||||
/* > at start indicates deal with by redirect */
|
||||
if (hit->origin_protocol == LWSMPRO_REDIR_HTTP ||
|
||||
|
@ -1162,15 +1172,21 @@ lws_http_action(struct lws *wsi)
|
|||
* The mount is a reverse proxy?
|
||||
*/
|
||||
|
||||
// lwsl_notice("%s: origin_protocol: %d\n", __func__, hit->origin_protocol);
|
||||
|
||||
if (hit->origin_protocol == LWSMPRO_HTTPS ||
|
||||
hit->origin_protocol == LWSMPRO_HTTP) {
|
||||
struct lws_client_connect_info i;
|
||||
char ads[96], rpath[256], *pcolon, *pslash, *p;
|
||||
struct lws *cwsi;
|
||||
char ads[96], rpath[256], *pcolon, *pslash, *p, unix_skt = 0;
|
||||
int n, na;
|
||||
|
||||
memset(&i, 0, sizeof(i));
|
||||
i.context = lws_get_context(wsi);
|
||||
|
||||
if (hit->origin[0] == '+')
|
||||
unix_skt = 1;
|
||||
|
||||
pcolon = strchr(hit->origin, ':');
|
||||
pslash = strchr(hit->origin, '/');
|
||||
if (!pslash) {
|
||||
|
@ -1178,16 +1194,28 @@ lws_http_action(struct lws *wsi)
|
|||
hit->origin);
|
||||
return -1;
|
||||
}
|
||||
if (pcolon > pslash)
|
||||
pcolon = NULL;
|
||||
|
||||
if (pcolon)
|
||||
n = pcolon - hit->origin;
|
||||
else
|
||||
n = pslash - hit->origin;
|
||||
if (unix_skt) {
|
||||
if (!pcolon) {
|
||||
lwsl_err("Proxy mount origin for unix skt must "
|
||||
"have address delimited by :\n");
|
||||
|
||||
if (n >= (int)sizeof(ads) - 2)
|
||||
n = sizeof(ads) - 2;
|
||||
return -1;
|
||||
}
|
||||
n = lws_ptr_diff(pcolon, hit->origin);
|
||||
pslash = pcolon;
|
||||
} else {
|
||||
if (pcolon > pslash)
|
||||
pcolon = NULL;
|
||||
|
||||
if (pcolon)
|
||||
n = pcolon - hit->origin;
|
||||
else
|
||||
n = pslash - hit->origin;
|
||||
|
||||
if (n >= (int)sizeof(ads) - 2)
|
||||
n = sizeof(ads) - 2;
|
||||
}
|
||||
|
||||
memcpy(ads, hit->origin, n);
|
||||
ads[n] = '\0';
|
||||
|
@ -1217,25 +1245,48 @@ lws_http_action(struct lws *wsi)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
i.path = rpath;
|
||||
i.host = i.address;
|
||||
if (i.address[0] != '+' ||
|
||||
!lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST))
|
||||
i.host = i.address;
|
||||
else
|
||||
i.host = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST);
|
||||
i.origin = NULL;
|
||||
i.method = "GET";
|
||||
i.alpn = "http/1.1";
|
||||
i.parent_wsi = wsi;
|
||||
i.uri_replace_from = hit->origin;
|
||||
i.uri_replace_to = hit->mountpoint;
|
||||
i.pwsi = &cwsi;
|
||||
|
||||
lwsl_notice("proxying to %s port %d url %s, ssl %d, "
|
||||
// i.uri_replace_from = hit->origin;
|
||||
// i.uri_replace_to = hit->mountpoint;
|
||||
|
||||
lwsl_info("proxying to %s port %d url %s, ssl %d, "
|
||||
"from %s, to %s\n",
|
||||
i.address, i.port, i.path, i.ssl_connection,
|
||||
i.uri_replace_from, i.uri_replace_to);
|
||||
|
||||
if (!lws_client_connect_via_info(&i)) {
|
||||
lwsl_err("proxy connect fail\n");
|
||||
|
||||
/*
|
||||
* ... we can't do the proxy action, but we can
|
||||
* cleanly return him a 503 and a description
|
||||
*/
|
||||
|
||||
lws_return_http_status(wsi,
|
||||
HTTP_STATUS_SERVICE_UNAVAILABLE,
|
||||
"<h1>Service Temporarily Unavailable</h1>"
|
||||
"The server is temporarily unable to service "
|
||||
"your request due to maintenance downtime or "
|
||||
"capacity problems. Please try again later.");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
lwsl_info("%s: setting proxy clientside on %p (parent %p)\n",
|
||||
__func__, cwsi, lws_get_parent(cwsi));
|
||||
cwsi->http.proxy_clientside = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
@ -1531,7 +1582,8 @@ raw_transition:
|
|||
|
||||
/* select vhost */
|
||||
|
||||
if (lws_hdr_total_length(wsi, WSI_TOKEN_HOST)) {
|
||||
if (wsi->vhost->listen_port &&
|
||||
lws_hdr_total_length(wsi, WSI_TOKEN_HOST)) {
|
||||
struct lws_vhost *vhost = lws_select_vhost(
|
||||
context, wsi->vhost->listen_port,
|
||||
lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST));
|
||||
|
@ -1744,7 +1796,7 @@ lws_http_transaction_completed(struct lws *wsi)
|
|||
return 0;
|
||||
}
|
||||
|
||||
lwsl_debug("%s: wsi %p\n", __func__, wsi);
|
||||
lwsl_info("%s: wsi %p\n", __func__, wsi);
|
||||
|
||||
#if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
|
||||
lws_http_compression_destroy(wsi);
|
||||
|
@ -2056,20 +2108,24 @@ lws_serve_http_file(struct lws *wsi, const char *file, const char *content_type,
|
|||
total_content_length, &p, end))
|
||||
return -1;
|
||||
} else {
|
||||
/* ...otherwise, for http 1 it must go chunked. For
|
||||
* the compression case, the reason is we compress on
|
||||
* the fly and do not know the compressed content-length
|
||||
* until it has all been sent. Http/1.1 pipelining must
|
||||
* be able to know where the transaction boundaries are
|
||||
* ... so chunking...
|
||||
*/
|
||||
if (lws_add_http_header_by_token(wsi,
|
||||
WSI_TOKEN_HTTP_TRANSFER_ENCODING,
|
||||
(unsigned char *)"chunked", 7, &p, end))
|
||||
return -1;
|
||||
|
||||
#if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
|
||||
if (wsi->http.lcs) {
|
||||
|
||||
/* ...otherwise, for http 1 it must go chunked.
|
||||
* For the compression case, the reason is we
|
||||
* compress on the fly and do not know the
|
||||
* compressed content-length until it has all
|
||||
* been sent. Http/1.1 pipelining must be able
|
||||
* to know where the transaction boundaries are
|
||||
* ... so chunking...
|
||||
*/
|
||||
if (lws_add_http_header_by_token(wsi,
|
||||
WSI_TOKEN_HTTP_TRANSFER_ENCODING,
|
||||
(unsigned char *)"chunked", 7,
|
||||
&p, end))
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* ...this is fun, isn't it :-) For h1 that is
|
||||
* using an http compression translation, the
|
||||
|
@ -2093,7 +2149,8 @@ lws_serve_http_file(struct lws *wsi, const char *file, const char *content_type,
|
|||
wsi->cache_secs);
|
||||
} else {
|
||||
cc = cache_control;
|
||||
cclen = sprintf(cache_control, "must-revalidate, %s, max-age=%u",
|
||||
cclen = sprintf(cache_control,
|
||||
"must-revalidate, %s, max-age=%u",
|
||||
intermediates[wsi->cache_intermediaries],
|
||||
wsi->cache_secs);
|
||||
|
||||
|
|
|
@ -93,7 +93,7 @@ rops_handle_POLLIN_listen(struct lws_context_per_thread *pt, struct lws *wsi,
|
|||
break;
|
||||
}
|
||||
|
||||
lws_plat_set_socket_options(wsi->vhost, accept_fd);
|
||||
lws_plat_set_socket_options(wsi->vhost, accept_fd, 0);
|
||||
|
||||
#if defined(LWS_WITH_IPV6)
|
||||
lwsl_debug("accepted new conn port %u on fd=%d\n",
|
||||
|
|
|
@ -1495,7 +1495,11 @@ rops_close_via_role_protocol_ws(struct lws *wsi, enum lws_close_status reason)
|
|||
static int
|
||||
rops_close_role_ws(struct lws_context_per_thread *pt, struct lws *wsi)
|
||||
{
|
||||
if (!wsi->ws)
|
||||
return 0;
|
||||
|
||||
#if !defined(LWS_WITHOUT_EXTENSIONS)
|
||||
|
||||
if (wsi->ws->rx_draining_ext) {
|
||||
struct lws **w = &pt->ws.rx_draining_ext_list;
|
||||
|
||||
|
|
|
@ -672,9 +672,12 @@ int main(int argc, char **argv)
|
|||
goto usage;
|
||||
|
||||
/* add back the leading / on path */
|
||||
path[0] = '/';
|
||||
lws_strncpy(path + 1, p, sizeof(path) - 1);
|
||||
i.path = path;
|
||||
if (p[0] != '/') {
|
||||
path[0] = '/';
|
||||
lws_strncpy(path + 1, p, sizeof(path) - 1);
|
||||
i.path = path;
|
||||
} else
|
||||
i.path = p;
|
||||
|
||||
if (!strcmp(prot, "http") || !strcmp(prot, "ws"))
|
||||
use_ssl = 0;
|
||||
|
@ -682,6 +685,8 @@ int main(int argc, char **argv)
|
|||
if (!use_ssl)
|
||||
use_ssl = LCCSCF_USE_SSL;
|
||||
|
||||
lwsl_debug("'%s' %p '%s' %p\n", i.address, i.address, i.path, i.path);
|
||||
|
||||
/*
|
||||
* create the websockets context. This tracks open connections and
|
||||
* knows how to route any traffic and which protocol version to use,
|
||||
|
|
Loading…
Add table
Reference in a new issue