Project homepage Mailing List  Warmcat.com  API Docs  Github Mirror 
{"schema":"libjg2-1", "vpath":"/git/", "avatar":"/git/avatar/", "alang":"en-US,en;q\u003d0.5", "gen_ut":1638107504, "reponame":"libwebsockets", "desc":"libwebsockets lightweight C networking library", "owner": { "name": "Andy Green", "email": "andy@warmcat.com", "md5": "c50933ca2aa61e0fe2c43d46bb6b59cb" },"url":"https://libwebsockets.org/repo/libwebsockets", "f":3, "items": [ {"schema":"libjg2-1", "cid":"1e12cf53b5507237bccffbd25a79dc0e", "oid":{ "oid": "e19b806e13886fae5cfcdef34fd972af6cbf83e4", "alias": [ "refs/heads/v3.0-stable"]},"blobname": "lib/roles/http/server/server.c", "blob": "/*\n * libwebsockets - small server side websockets and web server implementation\n *\n * Copyright (C) 2010-2018 Andy Green \u003candy@warmcat.com\u003e\n *\n * This library is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation:\n * version 2.1 of the License.\n *\n * This library is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with this library; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n * MA 02110-1301 USA\n */\n\n#include \u0022core/private.h\u0022\n\nconst char * const method_names[] \u003d {\n\t\u0022GET\u0022, \u0022POST\u0022, \u0022OPTIONS\u0022, \u0022PUT\u0022, \u0022PATCH\u0022, \u0022DELETE\u0022, \u0022CONNECT\u0022, \u0022HEAD\u0022,\n#ifdef LWS_WITH_HTTP2\n\t\u0022:path\u0022,\n#endif\n\t};\n\n/*\n * return 0: all done\n * 1: nonfatal error\n * \u003c0: fatal error\n *\n * REQUIRES CONTEXT LOCK HELD\n */\n\nint\n_lws_vhost_init_server(const struct lws_context_creation_info *info,\n\t\t\t struct lws_vhost *vhost)\n{\n\tint n, opt \u003d 1, limit \u003d 1;\n\tlws_sockfd_type sockfd;\n\tstruct lws_vhost *vh;\n\tstruct lws *wsi;\n\tint m \u003d 0, is;\n\n\t(void)method_names;\n\t(void)opt;\n\n\tif (info) {\n\t\tvhost-\u003eiface \u003d info-\u003eiface;\n\t\tvhost-\u003elisten_port \u003d info-\u003eport;\n\t}\n\n\t/* set up our external listening socket we serve on */\n\n\tif (vhost-\u003elisten_port \u003d\u003d CONTEXT_PORT_NO_LISTEN ||\n\t vhost-\u003elisten_port \u003d\u003d CONTEXT_PORT_NO_LISTEN_SERVER)\n\t\treturn 0;\n\n\tvh \u003d vhost-\u003econtext-\u003evhost_list;\n\twhile (vh) {\n\t\tif (vh-\u003elisten_port \u003d\u003d vhost-\u003elisten_port) {\n\t\t\tif (((!vhost-\u003eiface \u0026\u0026 !vh-\u003eiface) ||\n\t\t\t (vhost-\u003eiface \u0026\u0026 vh-\u003eiface \u0026\u0026\n\t\t\t !strcmp(vhost-\u003eiface, vh-\u003eiface))) \u0026\u0026\n\t\t\t vh-\u003elserv_wsi\n\t\t\t) {\n\t\t\t\tlwsl_notice(\u0022 using listen skt from vhost %s\u005cn\u0022,\n\t\t\t\t\t vh-\u003ename);\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t}\n\t\tvh \u003d vh-\u003evhost_next;\n\t}\n\n\tif (vhost-\u003eiface) {\n\t\t/*\n\t\t * let's check before we do anything else about the disposition\n\t\t * of the interface he wants to bind to...\n\t\t */\n\t\tis \u003d lws_socket_bind(vhost, LWS_SOCK_INVALID, vhost-\u003elisten_port, vhost-\u003eiface);\n\t\tlwsl_debug(\u0022initial if check says %d\u005cn\u0022, is);\ndeal:\n\n\t\tlws_start_foreach_llp(struct lws_vhost **, pv,\n\t\t\t\t vhost-\u003econtext-\u003eno_listener_vhost_list) {\n\t\t\tif (is \u003e\u003d LWS_ITOSA_USABLE \u0026\u0026 *pv \u003d\u003d vhost) {\n\t\t\t\t/* on the list and shouldn't be: remove it */\n\t\t\t\tlwsl_debug(\u0022deferred iface: removing vh %s\u005cn\u0022, (*pv)-\u003ename);\n\t\t\t\t*pv \u003d vhost-\u003eno_listener_vhost_list;\n\t\t\t\tvhost-\u003eno_listener_vhost_list \u003d NULL;\n\t\t\t\tgoto done_list;\n\t\t\t}\n\t\t\tif (is \u003c LWS_ITOSA_USABLE \u0026\u0026 *pv \u003d\u003d vhost)\n\t\t\t\tgoto done_list;\n\t\t} lws_end_foreach_llp(pv, no_listener_vhost_list);\n\n\t\t/* not on the list... */\n\n\t\tif (is \u003c LWS_ITOSA_USABLE) {\n\n\t\t\t/* ... but needs to be: so add it */\n\n\t\t\tlwsl_debug(\u0022deferred iface: adding vh %s\u005cn\u0022, vhost-\u003ename);\n\t\t\tvhost-\u003eno_listener_vhost_list \u003d vhost-\u003econtext-\u003eno_listener_vhost_list;\n\t\t\tvhost-\u003econtext-\u003eno_listener_vhost_list \u003d vhost;\n\t\t}\n\ndone_list:\n\n\t\tswitch (is) {\n\t\tdefault:\n\t\t\tbreak;\n\t\tcase LWS_ITOSA_NOT_EXIST:\n\t\t\t/* can't add it */\n\t\t\tif (info) /* first time */\n\t\t\t\tlwsl_err(\u0022VH %s: iface %s port %d DOESN'T EXIST\u005cn\u0022,\n\t\t\t\t vhost-\u003ename, vhost-\u003eiface, vhost-\u003elisten_port);\n\t\t\treturn 1;\n\t\tcase LWS_ITOSA_NOT_USABLE:\n\t\t\t/* can't add it */\n\t\t\tif (info) /* first time */\n\t\t\t\tlwsl_err(\u0022VH %s: iface %s port %d NOT USABLE\u005cn\u0022,\n\t\t\t\t vhost-\u003ename, vhost-\u003eiface, vhost-\u003elisten_port);\n\t\t\treturn 1;\n\t\t}\n\t}\n\n\t(void)n;\n#if defined(__linux__)\n#ifdef LWS_WITH_UNIX_SOCK\n\t/*\n\t * A Unix domain sockets cannot be bound for several times, even if we set\n\t * the SO_REUSE* options on.\n\t * However, fortunately, each thread is able to independently listen when\n\t * running on a reasonably new Linux kernel. So we can safely assume\n\t * creating just one listening socket for a multi-threaded environment won't\n\t * fail in most cases.\n\t */\n\tif (!LWS_UNIX_SOCK_ENABLED(vhost))\n#endif\n\tlimit \u003d vhost-\u003econtext-\u003ecount_threads;\n#endif\n\n\tfor (m \u003d 0; m \u003c limit; m++) {\n#ifdef LWS_WITH_UNIX_SOCK\n\t\tif (LWS_UNIX_SOCK_ENABLED(vhost))\n\t\t\tsockfd \u003d socket(AF_UNIX, SOCK_STREAM, 0);\n\t\telse\n#endif\n#ifdef LWS_WITH_IPV6\n\t\tif (LWS_IPV6_ENABLED(vhost))\n\t\t\tsockfd \u003d socket(AF_INET6, SOCK_STREAM, 0);\n\t\telse\n#endif\n\t\t\tsockfd \u003d socket(AF_INET, SOCK_STREAM, 0);\n\n\t\tif (sockfd \u003d\u003d LWS_SOCK_INVALID) {\n\t\t\tlwsl_err(\u0022ERROR opening socket\u005cn\u0022);\n\t\t\treturn 1;\n\t\t}\n#if !defined(LWS_WITH_ESP32)\n#if (defined(WIN32) || defined(_WIN32)) \u0026\u0026 defined(SO_EXCLUSIVEADDRUSE)\n\t\t/*\n\t\t * only accept that we are the only listener on the port\n\t\t * https://msdn.microsoft.com/zh-tw/library/\n\t\t * windows/desktop/ms740621(v\u003dvs.85).aspx\n\t\t *\n\t\t * for lws, to match Linux, we default to exclusive listen\n\t\t */\n\t\tif (!lws_check_opt(vhost-\u003eoptions,\n\t\t\t\tLWS_SERVER_OPTION_ALLOW_LISTEN_SHARE)) {\n\t\t\tif (setsockopt(sockfd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,\n\t\t\t\t (const void *)\u0026opt, sizeof(opt)) \u003c 0) {\n\t\t\t\tlwsl_err(\u0022reuseaddr failed\u005cn\u0022);\n\t\t\t\tcompatible_close(sockfd);\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t} else\n#endif\n\n\t\t/*\n\t\t * allow us to restart even if old sockets in TIME_WAIT\n\t\t */\n\t\tif (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,\n\t\t\t (const void *)\u0026opt, sizeof(opt)) \u003c 0) {\n\t\t\tlwsl_err(\u0022reuseaddr failed\u005cn\u0022);\n\t\t\tcompatible_close(sockfd);\n\t\t\treturn -1;\n\t\t}\n\n#if defined(LWS_WITH_IPV6) \u0026\u0026 defined(IPV6_V6ONLY)\n\t\tif (LWS_IPV6_ENABLED(vhost) \u0026\u0026\n\t\t vhost-\u003eoptions \u0026 LWS_SERVER_OPTION_IPV6_V6ONLY_MODIFY) {\n\t\t\tint value \u003d (vhost-\u003eoptions \u0026\n\t\t\t\tLWS_SERVER_OPTION_IPV6_V6ONLY_VALUE) ? 1 : 0;\n\t\t\tif (setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY,\n\t\t\t\t (const void*)\u0026value, sizeof(value)) \u003c 0) {\n\t\t\t\tcompatible_close(sockfd);\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n#endif\n\n#if defined(__linux__) \u0026\u0026 defined(SO_REUSEPORT)\n\t\t/* keep coverity happy */\n#if LWS_MAX_SMP \u003e 1\n\t\tn \u003d 1;\n#else\n\t\tn \u003d lws_check_opt(vhost-\u003eoptions,\n\t\t\t\t LWS_SERVER_OPTION_ALLOW_LISTEN_SHARE);\n#endif\n\t\tif (n \u0026\u0026 vhost-\u003econtext-\u003ecount_threads \u003e 1)\n\t\t\tif (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT,\n\t\t\t\t\t(const void *)\u0026opt, sizeof(opt)) \u003c 0) {\n\t\t\t\tcompatible_close(sockfd);\n\t\t\t\treturn -1;\n\t\t\t}\n#endif\n#endif\n\t\tlws_plat_set_socket_options(vhost, sockfd);\n\n\t\tis \u003d lws_socket_bind(vhost, sockfd, vhost-\u003elisten_port, vhost-\u003eiface);\n\t\t/*\n\t\t * There is a race where the network device may come up and then\n\t\t * go away and fail here. So correctly handle unexpected failure\n\t\t * here despite we earlier confirmed it.\n\t\t */\n\t\tif (is \u003c 0) {\n\t\t\tlwsl_info(\u0022%s: lws_socket_bind says %d\u005cn\u0022, __func__, is);\n\t\t\tcompatible_close(sockfd);\n\t\t\tgoto deal;\n\t\t}\n\t\tvhost-\u003elisten_port \u003d is;\n\n\t\tlwsl_debug(\u0022%s: lws_socket_bind says %d\u005cn\u0022, __func__, is);\n\n\t\twsi \u003d lws_zalloc(sizeof(struct lws), \u0022listen wsi\u0022);\n\t\tif (wsi \u003d\u003d NULL) {\n\t\t\tlwsl_err(\u0022Out of mem\u005cn\u0022);\n\t\t\tgoto bail;\n\t\t}\n\t\twsi-\u003econtext \u003d vhost-\u003econtext;\n\t\twsi-\u003edesc.sockfd \u003d sockfd;\n\t\tlws_role_transition(wsi, 0, LRS_UNCONNECTED, \u0026role_ops_listen);\n\t\twsi-\u003eprotocol \u003d vhost-\u003eprotocols;\n\t\twsi-\u003etsi \u003d m;\n\t\twsi-\u003evhost \u003d vhost;\n\t\twsi-\u003elistener \u003d 1;\n\n\t\tif (wsi-\u003econtext-\u003eevent_loop_ops-\u003einit_vhost_listen_wsi)\n\t\t\twsi-\u003econtext-\u003eevent_loop_ops-\u003einit_vhost_listen_wsi(wsi);\n\n\t\tif (__insert_wsi_socket_into_fds(vhost-\u003econtext, wsi)) {\n\t\t\tlwsl_notice(\u0022inserting wsi socket into fds failed\u005cn\u0022);\n\t\t\tgoto bail;\n\t\t}\n\n\t\tvhost-\u003econtext-\u003ecount_wsi_allocated++;\n\t\tvhost-\u003elserv_wsi \u003d wsi;\n\n\t\tn \u003d listen(wsi-\u003edesc.sockfd, LWS_SOMAXCONN);\n\t\tif (n \u003c 0) {\n\t\t\tlwsl_err(\u0022listen failed with error %d\u005cn\u0022, LWS_ERRNO);\n\t\t\tvhost-\u003elserv_wsi \u003d NULL;\n\t\t\tvhost-\u003econtext-\u003ecount_wsi_allocated--;\n\t\t\t__remove_wsi_socket_from_fds(wsi);\n\t\t\tgoto bail;\n\t\t}\n\t} /* for each thread able to independently listen */\n\n\tif (!lws_check_opt(vhost-\u003econtext-\u003eoptions, LWS_SERVER_OPTION_EXPLICIT_VHOSTS)) {\n#ifdef LWS_WITH_UNIX_SOCK\n\t\tif (LWS_UNIX_SOCK_ENABLED(vhost))\n\t\t\tlwsl_info(\u0022 Listening on \u005c\u0022%s\u005c\u0022\u005cn\u0022, vhost-\u003eiface);\n\t\telse\n#endif\n\t\t\tlwsl_info(\u0022 Listening on port %d\u005cn\u0022, vhost-\u003elisten_port);\n }\n\n\t// info-\u003eport \u003d vhost-\u003elisten_port;\n\n\treturn 0;\n\nbail:\n\tcompatible_close(sockfd);\n\n\treturn -1;\n}\n\nstruct lws_vhost *\nlws_select_vhost(struct lws_context *context, int port, const char *servername)\n{\n\tstruct lws_vhost *vhost \u003d context-\u003evhost_list;\n\tconst char *p;\n\tint n, m, colon;\n\n\tn \u003d (int)strlen(servername);\n\tcolon \u003d n;\n\tp \u003d strchr(servername, ':');\n\tif (p)\n\t\tcolon \u003d lws_ptr_diff(p, servername);\n\n\t/* Priotity 1: first try exact matches */\n\n\twhile (vhost) {\n\t\tif (port \u003d\u003d vhost-\u003elisten_port \u0026\u0026\n\t\t !strncmp(vhost-\u003ename, servername, colon)) {\n\t\t\tlwsl_info(\u0022SNI: Found: %s\u005cn\u0022, servername);\n\t\t\treturn vhost;\n\t\t}\n\t\tvhost \u003d vhost-\u003evhost_next;\n\t}\n\n\t/*\n\t * Priority 2: if no exact matches, try matching *.vhost-name\n\t * unintentional matches are possible but resolve to x.com for *.x.com\n\t * which is reasonable. If exact match exists we already chose it and\n\t * never reach here. SSL will still fail it if the cert doesn't allow\n\t * *.x.com.\n\t */\n\tvhost \u003d context-\u003evhost_list;\n\twhile (vhost) {\n\t\tm \u003d (int)strlen(vhost-\u003ename);\n\t\tif (port \u003d\u003d vhost-\u003elisten_port \u0026\u0026\n\t\t m \u003c\u003d (colon - 2) \u0026\u0026\n\t\t servername[colon - m - 1] \u003d\u003d '.' \u0026\u0026\n\t\t !strncmp(vhost-\u003ename, servername + colon - m, m)) {\n\t\t\tlwsl_info(\u0022SNI: Found %s on wildcard: %s\u005cn\u0022,\n\t\t\t\t servername, vhost-\u003ename);\n\t\t\treturn vhost;\n\t\t}\n\t\tvhost \u003d vhost-\u003evhost_next;\n\t}\n\n\t/* Priority 3: match the first vhost on our port */\n\n\tvhost \u003d context-\u003evhost_list;\n\twhile (vhost) {\n\t\tif (port \u003d\u003d vhost-\u003elisten_port) {\n\t\t\tlwsl_info(\u0022%s: vhost match to %s based on port %d\u005cn\u0022,\n\t\t\t\t\t__func__, vhost-\u003ename, port);\n\t\t\treturn vhost;\n\t\t}\n\t\tvhost \u003d vhost-\u003evhost_next;\n\t}\n\n\t/* no match */\n\n\treturn NULL;\n}\n\nLWS_VISIBLE LWS_EXTERN const char *\nlws_get_mimetype(const char *file, const struct lws_http_mount *m)\n{\n\tint n \u003d (int)strlen(file);\n\tconst struct lws_protocol_vhost_options *pvo \u003d NULL;\n\n\tif (m)\n\t\tpvo \u003d m-\u003eextra_mimetypes;\n\n\tif (n \u003c 5)\n\t\treturn NULL;\n\n\tif (!strcmp(\u0026file[n - 4], \u0022.ico\u0022))\n\t\treturn \u0022image/x-icon\u0022;\n\n\tif (!strcmp(\u0026file[n - 4], \u0022.gif\u0022))\n\t\treturn \u0022image/gif\u0022;\n\n\tif (!strcmp(\u0026file[n - 3], \u0022.js\u0022))\n\t\treturn \u0022text/javascript\u0022;\n\n\tif (!strcmp(\u0026file[n - 4], \u0022.png\u0022))\n\t\treturn \u0022image/png\u0022;\n\n\tif (!strcmp(\u0026file[n - 4], \u0022.jpg\u0022))\n\t\treturn \u0022image/jpeg\u0022;\n\n\tif (!strcmp(\u0026file[n - 3], \u0022.gz\u0022))\n\t\treturn \u0022application/gzip\u0022;\n\n\tif (!strcmp(\u0026file[n - 4], \u0022.JPG\u0022))\n\t\treturn \u0022image/jpeg\u0022;\n\n\tif (!strcmp(\u0026file[n - 5], \u0022.html\u0022))\n\t\treturn \u0022text/html\u0022;\n\n\tif (!strcmp(\u0026file[n - 4], \u0022.css\u0022))\n\t\treturn \u0022text/css\u0022;\n\n\tif (!strcmp(\u0026file[n - 4], \u0022.txt\u0022))\n\t\treturn \u0022text/plain\u0022;\n\n\tif (!strcmp(\u0026file[n - 4], \u0022.svg\u0022))\n\t\treturn \u0022image/svg+xml\u0022;\n\n\tif (!strcmp(\u0026file[n - 4], \u0022.ttf\u0022))\n\t\treturn \u0022application/x-font-ttf\u0022;\n\n\tif (!strcmp(\u0026file[n - 4], \u0022.otf\u0022))\n\t\treturn \u0022application/font-woff\u0022;\n\n\tif (!strcmp(\u0026file[n - 5], \u0022.woff\u0022))\n\t\treturn \u0022application/font-woff\u0022;\n\n\tif (!strcmp(\u0026file[n - 4], \u0022.xml\u0022))\n\t\treturn \u0022application/xml\u0022;\n\n\twhile (pvo) {\n\t\tif (pvo-\u003ename[0] \u003d\u003d '*') /* ie, match anything */\n\t\t\treturn pvo-\u003evalue;\n\n\t\tif (!strcmp(\u0026file[n - strlen(pvo-\u003ename)], pvo-\u003ename))\n\t\t\treturn pvo-\u003evalue;\n\n\t\tpvo \u003d pvo-\u003enext;\n\t}\n\n\treturn NULL;\n}\nstatic lws_fop_flags_t\nlws_vfs_prepare_flags(struct lws *wsi)\n{\n\tlws_fop_flags_t f \u003d 0;\n\n\tif (!lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_ACCEPT_ENCODING))\n\t\treturn f;\n\n\tif (strstr(lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_ACCEPT_ENCODING),\n\t\t \u0022gzip\u0022)) {\n\t\tlwsl_info(\u0022client indicates GZIP is acceptable\u005cn\u0022);\n\t\tf |\u003d LWS_FOP_FLAG_COMPR_ACCEPTABLE_GZIP;\n\t}\n\n\treturn f;\n}\n\nstatic int\nlws_http_serve(struct lws *wsi, char *uri, const char *origin,\n\t const struct lws_http_mount *m)\n{\n\tconst struct lws_protocol_vhost_options *pvo \u003d m-\u003einterpret;\n\tstruct lws_process_html_args args;\n\tconst char *mimetype;\n#if !defined(_WIN32_WCE)\n\tconst struct lws_plat_file_ops *fops;\n\tconst char *vpath;\n\tlws_fop_flags_t fflags \u003d LWS_O_RDONLY;\n#if defined(WIN32) \u0026\u0026 defined(LWS_HAVE__STAT32I64)\n\tstruct _stat32i64 st;\n#else\n\tstruct stat st;\n#endif\n\tint spin \u003d 0;\n#endif\n\tchar path[256], sym[512];\n\tunsigned char *p \u003d (unsigned char *)sym + 32 + LWS_PRE, *start \u003d p;\n\tunsigned char *end \u003d p + sizeof(sym) - 32 - LWS_PRE;\n#if !defined(WIN32) \u0026\u0026 !defined(LWS_WITH_ESP32)\n\tsize_t len;\n#endif\n\tint n;\n\n\twsi-\u003ehandling_404 \u003d 0;\n\tif (!wsi-\u003evhost)\n\t\treturn -1;\n\n#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)\n\tif (wsi-\u003evhost-\u003ehttp.error_document_404 \u0026\u0026\n\t !strcmp(uri, wsi-\u003evhost-\u003ehttp.error_document_404))\n\t\twsi-\u003ehandling_404 \u003d 1;\n#endif\n\n\tlws_snprintf(path, sizeof(path) - 1, \u0022%s/%s\u0022, origin, uri);\n\n#if !defined(_WIN32_WCE)\n\n\tfflags |\u003d lws_vfs_prepare_flags(wsi);\n\n\tdo {\n\t\tspin++;\n\t\tfops \u003d lws_vfs_select_fops(wsi-\u003econtext-\u003efops, path, \u0026vpath);\n\n\t\tif (wsi-\u003ehttp.fop_fd)\n\t\t\tlws_vfs_file_close(\u0026wsi-\u003ehttp.fop_fd);\n\n\t\twsi-\u003ehttp.fop_fd \u003d fops-\u003eLWS_FOP_OPEN(wsi-\u003econtext-\u003efops,\n\t\t\t\t\t\t\tpath, vpath, \u0026fflags);\n\t\tif (!wsi-\u003ehttp.fop_fd) {\n\t\t\tlwsl_info(\u0022%s: Unable to open '%s': errno %d\u005cn\u0022,\n\t\t\t\t __func__, path, errno);\n\n\t\t\treturn -1;\n\t\t}\n\n\t\t/* if it can't be statted, don't try */\n\t\tif (fflags \u0026 LWS_FOP_FLAG_VIRTUAL)\n\t\t\tbreak;\n#if defined(LWS_WITH_ESP32)\n\t\tbreak;\n#endif\n#if !defined(WIN32)\n\t\tif (fstat(wsi-\u003ehttp.fop_fd-\u003efd, \u0026st)) {\n\t\t\tlwsl_info(\u0022unable to stat %s\u005cn\u0022, path);\n\t\t\tgoto bail;\n\t\t}\n#else\n#if defined(LWS_HAVE__STAT32I64)\n\t\tif (_stat32i64(path, \u0026st)) {\n\t\t\tlwsl_info(\u0022unable to stat %s\u005cn\u0022, path);\n\t\t\tgoto bail;\n\t\t}\n#else\n\t\tif (stat(path, \u0026st)) {\n\t\t\tlwsl_info(\u0022unable to stat %s\u005cn\u0022, path);\n\t\t\tgoto bail;\n\t\t}\n#endif\n#endif\n\n\t\twsi-\u003ehttp.fop_fd-\u003emod_time \u003d (uint32_t)st.st_mtime;\n\t\tfflags |\u003d LWS_FOP_FLAG_MOD_TIME_VALID;\n\n#if !defined(WIN32) \u0026\u0026 !defined(LWS_WITH_ESP32)\n\t\tif ((S_IFMT \u0026 st.st_mode) \u003d\u003d S_IFLNK) {\n\t\t\tlen \u003d readlink(path, sym, sizeof(sym) - 1);\n\t\t\tif (len) {\n\t\t\t\tlwsl_err(\u0022Failed to read link %s\u005cn\u0022, path);\n\t\t\t\tgoto bail;\n\t\t\t}\n\t\t\tsym[len] \u003d '\u005c0';\n\t\t\tlwsl_debug(\u0022symlink %s -\u003e %s\u005cn\u0022, path, sym);\n\t\t\tlws_snprintf(path, sizeof(path) - 1, \u0022%s\u0022, sym);\n\t\t}\n#endif\n\t\tif ((S_IFMT \u0026 st.st_mode) \u003d\u003d S_IFDIR) {\n\t\t\tlwsl_debug(\u0022default filename append to dir\u005cn\u0022);\n\t\t\tlws_snprintf(path, sizeof(path) - 1, \u0022%s/%s/index.html\u0022,\n\t\t\t\t origin, uri);\n\t\t}\n\n\t} while ((S_IFMT \u0026 st.st_mode) !\u003d S_IFREG \u0026\u0026 spin \u003c 5);\n\n\tif (spin \u003d\u003d 5)\n\t\tlwsl_err(\u0022symlink loop %s \u005cn\u0022, path);\n\n\tn \u003d sprintf(sym, \u0022%08llX%08lX\u0022,\n\t\t (unsigned long long)lws_vfs_get_length(wsi-\u003ehttp.fop_fd),\n\t\t (unsigned long)lws_vfs_get_mod_time(wsi-\u003ehttp.fop_fd));\n\n\t/* disable ranges if IF_RANGE token invalid */\n\n\tif (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_IF_RANGE))\n\t\tif (strcmp(sym, lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_IF_RANGE)))\n\t\t\t/* differs - defeat Range: */\n\t\t\twsi-\u003ehttp.ah-\u003efrag_index[WSI_TOKEN_HTTP_RANGE] \u003d 0;\n\n\tif (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_IF_NONE_MATCH)) {\n\t\t/*\n\t\t * he thinks he has some version of it already,\n\t\t * check if the tag matches\n\t\t */\n\t\tif (!strcmp(sym, lws_hdr_simple_ptr(wsi,\n\t\t\t\t\tWSI_TOKEN_HTTP_IF_NONE_MATCH))) {\n\n\t\t\tlwsl_debug(\u0022%s: ETAG match %s %s\u005cn\u0022, __func__,\n\t\t\t\t uri, origin);\n\n\t\t\t/* we don't need to send the payload */\n\t\t\tif (lws_add_http_header_status(wsi,\n\t\t\t\t\tHTTP_STATUS_NOT_MODIFIED, \u0026p, end))\n\t\t\t\treturn -1;\n\n\t\t\tif (lws_add_http_header_by_token(wsi,\n\t\t\t\t\tWSI_TOKEN_HTTP_ETAG,\n\t\t\t\t\t(unsigned char *)sym, n, \u0026p, end))\n\t\t\t\treturn -1;\n\n\t\t\tif (lws_finalize_http_header(wsi, \u0026p, end))\n\t\t\t\treturn -1;\n\n\t\t\tn \u003d lws_write(wsi, start, p - start,\n\t\t\t\t LWS_WRITE_HTTP_HEADERS |\n\t\t\t\t LWS_WRITE_H2_STREAM_END);\n\t\t\tif (n !\u003d (p - start)) {\n\t\t\t\tlwsl_err(\u0022_write returned %d from %ld\u005cn\u0022, n,\n\t\t\t\t\t (long)(p - start));\n\t\t\t\treturn -1;\n\t\t\t}\n\n\t\t\tlws_vfs_file_close(\u0026wsi-\u003ehttp.fop_fd);\n\n\t\t\treturn lws_http_transaction_completed(wsi);\n\t\t}\n\t}\n\n\tif (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_ETAG,\n\t\t\t(unsigned char *)sym, n, \u0026p, end))\n\t\treturn -1;\n#endif\n\n\tmimetype \u003d lws_get_mimetype(path, m);\n\tif (!mimetype) {\n\t\tlwsl_err(\u0022unknown mimetype for %s\u005cn\u0022, path);\n goto bail;\n\t}\n\tif (!mimetype[0])\n\t\tlwsl_debug(\u0022sending no mimetype for %s\u005cn\u0022, path);\n\n\twsi-\u003esending_chunked \u003d 0;\n\n\t/*\n\t * check if this is in the list of file suffixes to be interpreted by\n\t * a protocol\n\t */\n\twhile (pvo) {\n\t\tn \u003d (int)strlen(path);\n\t\tif (n \u003e (int)strlen(pvo-\u003ename) \u0026\u0026\n\t\t !strcmp(\u0026path[n - strlen(pvo-\u003ename)], pvo-\u003ename)) {\n\t\t\twsi-\u003einterpreting \u003d 1;\n\t\t\tif (!wsi-\u003ehttp2_substream)\n\t\t\t\twsi-\u003esending_chunked \u003d 1;\n\t\t\twsi-\u003eprotocol_interpret_idx \u003d\n\t\t\t\t\t(char)(lws_intptr_t)pvo-\u003evalue;\n\t\t\tlwsl_info(\u0022want %s interpreted by %s\u005cn\u0022, path,\n\t\t\t\t wsi-\u003evhost-\u003eprotocols[\n\t\t\t\t (int)(lws_intptr_t)(pvo-\u003evalue)].name);\n\t\t\twsi-\u003eprotocol \u003d \u0026wsi-\u003evhost-\u003eprotocols[\n\t\t\t (int)(lws_intptr_t)(pvo-\u003evalue)];\n\t\t\tif (lws_ensure_user_space(wsi))\n\t\t\t\treturn -1;\n\t\t\tbreak;\n\t\t}\n\t\tpvo \u003d pvo-\u003enext;\n\t}\n\n\tif (m-\u003eprotocol) {\n\t\tconst struct lws_protocols *pp \u003d lws_vhost_name_to_protocol(\n\t\t\t\t\t\t wsi-\u003evhost, m-\u003eprotocol);\n\n\t\tif (lws_bind_protocol(wsi, pp))\n\t\t\treturn 1;\n\t\targs.p \u003d (char *)p;\n\t\targs.max_len \u003d lws_ptr_diff(end, p);\n\t\tif (pp-\u003ecallback(wsi, LWS_CALLBACK_ADD_HEADERS,\n\t\t\t\t\t wsi-\u003euser_space, \u0026args, 0))\n\t\t\treturn -1;\n\t\tp \u003d (unsigned char *)args.p;\n\t}\n\n\tn \u003d lws_serve_http_file(wsi, path, mimetype, (char *)start,\n\t\t\t\tlws_ptr_diff(p, start));\n\n\tif (n \u003c 0 || ((n \u003e 0) \u0026\u0026 lws_http_transaction_completed(wsi)))\n\t\treturn -1; /* error or can't reuse connection: close the socket */\n\n\treturn 0;\nbail:\n\n\treturn -1;\n}\n\n#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)\nconst struct lws_http_mount *\nlws_find_mount(struct lws *wsi, const char *uri_ptr, int uri_len)\n{\n\tconst struct lws_http_mount *hm, *hit \u003d NULL;\n\tint best \u003d 0;\n\n\thm \u003d wsi-\u003evhost-\u003ehttp.mount_list;\n\twhile (hm) {\n\t\tif (uri_len \u003e\u003d hm-\u003emountpoint_len \u0026\u0026\n\t\t !strncmp(uri_ptr, hm-\u003emountpoint, hm-\u003emountpoint_len) \u0026\u0026\n\t\t (uri_ptr[hm-\u003emountpoint_len] \u003d\u003d '\u005c0' ||\n\t\t uri_ptr[hm-\u003emountpoint_len] \u003d\u003d '/' ||\n\t\t hm-\u003emountpoint_len \u003d\u003d 1)\n\t\t ) {\n\t\t\tif (hm-\u003eorigin_protocol \u003d\u003d LWSMPRO_CALLBACK ||\n\t\t\t ((hm-\u003eorigin_protocol \u003d\u003d LWSMPRO_CGI ||\n\t\t\t lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI) ||\n\t\t\t (wsi-\u003ehttp2_substream \u0026\u0026\n\t\t\t\tlws_hdr_total_length(wsi,\n\t\t\t\t\t\tWSI_TOKEN_HTTP_COLON_PATH)) ||\n\t\t\t hm-\u003eprotocol) \u0026\u0026\n\t\t\t hm-\u003emountpoint_len \u003e best)) {\n\t\t\t\tbest \u003d hm-\u003emountpoint_len;\n\t\t\t\thit \u003d hm;\n\t\t\t}\n\t\t}\n\t\thm \u003d hm-\u003emount_next;\n\t}\n\n\treturn hit;\n}\n#endif\n\n#if !defined(LWS_WITH_ESP32)\nstatic int\nlws_find_string_in_file(const char *filename, const char *string, int stringlen)\n{\n\tchar buf[128];\n\tint fd, match \u003d 0, pos \u003d 0, n \u003d 0, hit \u003d 0;\n\n\tfd \u003d lws_open(filename, O_RDONLY);\n\tif (fd \u003c 0) {\n\t\tlwsl_err(\u0022can't open auth file: %s\u005cn\u0022, filename);\n\t\treturn 0;\n\t}\n\n\twhile (1) {\n\t\tif (pos \u003d\u003d n) {\n\t\t\tn \u003d read(fd, buf, sizeof(buf));\n\t\t\tif (n \u003c\u003d 0) {\n\t\t\t\tif (match \u003d\u003d stringlen)\n\t\t\t\t\thit \u003d 1;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tpos \u003d 0;\n\t\t}\n\n\t\tif (match \u003d\u003d stringlen) {\n\t\t\tif (buf[pos] \u003d\u003d '\u005cr' || buf[pos] \u003d\u003d '\u005cn') {\n\t\t\t\thit \u003d 1;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tmatch \u003d 0;\n\t\t}\n\n\t\tif (buf[pos] \u003d\u003d string[match])\n\t\t\tmatch++;\n\t\telse\n\t\t\tmatch \u003d 0;\n\n\t\tpos++;\n\t}\n\n\tclose(fd);\n\n\treturn hit;\n}\n#endif\n\nstatic int\nlws_unauthorised_basic_auth(struct lws *wsi)\n{\n\tstruct lws_context_per_thread *pt \u003d \u0026wsi-\u003econtext-\u003ept[(int)wsi-\u003etsi];\n\tunsigned char *start \u003d pt-\u003eserv_buf + LWS_PRE,\n\t\t *p \u003d start, *end \u003d p + 512;\n\tchar buf[64];\n\tint n;\n\n\t/* no auth... tell him it is required */\n\n\tif (lws_add_http_header_status(wsi, HTTP_STATUS_UNAUTHORIZED, \u0026p, end))\n\t\treturn -1;\n\n\tn \u003d lws_snprintf(buf, sizeof(buf), \u0022Basic realm\u003d\u005c\u0022lwsws\u005c\u0022\u0022);\n\tif (lws_add_http_header_by_token(wsi,\n\t\t\tWSI_TOKEN_HTTP_WWW_AUTHENTICATE,\n\t\t\t(unsigned char *)buf, n, \u0026p, end))\n\t\treturn -1;\n\n\tif (lws_finalize_http_header(wsi, \u0026p, end))\n\t\treturn -1;\n\n\tn \u003d lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS |\n\t\t\t\t\t LWS_WRITE_H2_STREAM_END);\n\tif (n \u003c 0)\n\t\treturn -1;\n\n\treturn lws_http_transaction_completed(wsi);\n\n}\n\nint lws_clean_url(char *p)\n{\n\tif (p[0] \u003d\u003d 'h' \u0026\u0026 p[1] \u003d\u003d 't' \u0026\u0026 p[2] \u003d\u003d 't' \u0026\u0026 p[3] \u003d\u003d 'p') {\n\t\tp +\u003d 4;\n\t\tif (*p \u003d\u003d 's')\n\t\tp++;\n\t\tif (*p \u003d\u003d ':') {\n\t\t\tp++;\n\t\t\tif (*p \u003d\u003d '/')\n\t\t\tp++;\n\t\t}\n\t}\n\n\twhile (*p) {\n\t\tif (p[0] \u003d\u003d '/' \u0026\u0026 p[1] \u003d\u003d '/') {\n\t\t\tchar *p1 \u003d p;\n\t\t\twhile (*p1) {\n\t\t\t\t*p1 \u003d p1[1];\n\t\t\t\tp1++;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tp++;\n\t}\n\n\treturn 0;\n}\n\nstatic const unsigned char methods[] \u003d {\n\tWSI_TOKEN_GET_URI,\n\tWSI_TOKEN_POST_URI,\n\tWSI_TOKEN_OPTIONS_URI,\n\tWSI_TOKEN_PUT_URI,\n\tWSI_TOKEN_PATCH_URI,\n\tWSI_TOKEN_DELETE_URI,\n\tWSI_TOKEN_CONNECT,\n\tWSI_TOKEN_HEAD_URI,\n#ifdef LWS_WITH_HTTP2\n\tWSI_TOKEN_HTTP_COLON_PATH,\n#endif\n};\n\nstatic int\nlws_http_get_uri_and_method(struct lws *wsi, char **puri_ptr, int *puri_len)\n{\n\tint n, count \u003d 0;\n\n\tfor (n \u003d 0; n \u003c (int)LWS_ARRAY_SIZE(methods); n++)\n\t\tif (lws_hdr_total_length(wsi, methods[n]))\n\t\t\tcount++;\n\tif (!count) {\n\t\tlwsl_warn(\u0022Missing URI in HTTP request\u005cn\u0022);\n\t\treturn -1;\n\t}\n\n\tif (count !\u003d 1 \u0026\u0026\n\t !(wsi-\u003ehttp2_substream \u0026\u0026\n\t lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COLON_PATH))) {\n\t\tlwsl_warn(\u0022multiple methods?\u005cn\u0022);\n\t\treturn -1;\n\t}\n\n\tfor (n \u003d 0; n \u003c (int)LWS_ARRAY_SIZE(methods); n++)\n\t\tif (lws_hdr_total_length(wsi, methods[n])) {\n\t\t\t*puri_ptr \u003d lws_hdr_simple_ptr(wsi, methods[n]);\n\t\t\t*puri_len \u003d lws_hdr_total_length(wsi, methods[n]);\n\t\t\treturn n;\n\t\t}\n\n\treturn -1;\n}\n\nint\nlws_http_action(struct lws *wsi)\n{\n\tstruct lws_context_per_thread *pt \u003d \u0026wsi-\u003econtext-\u003ept[(int)wsi-\u003etsi];\n\tenum http_connection_type connection_type;\n\tenum http_version request_version;\n\tchar content_length_str[32];\n\tstruct lws_process_html_args args;\n\tconst struct lws_http_mount *hit \u003d NULL;\n\tunsigned int n;\n\tchar http_version_str[10];\n\tchar http_conn_str[20];\n\tint http_version_len;\n\tchar *uri_ptr \u003d NULL, *s;\n\tint uri_len \u003d 0, meth;\n\tstatic const char * const oprot[] \u003d {\n\t\t\u0022http://\u0022, \u0022https://\u0022\n\t};\n\n\tmeth \u003d lws_http_get_uri_and_method(wsi, \u0026uri_ptr, \u0026uri_len);\n\tif (meth \u003c 0 || meth \u003e\u003d (int)LWS_ARRAY_SIZE(method_names))\n\t\tgoto bail_nuke_ah;\n\n\t/* we insist on absolute paths */\n\n\tif (!uri_ptr || uri_ptr[0] !\u003d '/') {\n\t\tlws_return_http_status(wsi, HTTP_STATUS_FORBIDDEN, NULL);\n\n\t\tgoto bail_nuke_ah;\n\t}\n\n\tlwsl_info(\u0022Method: '%s' (%d), request for '%s'\u005cn\u0022, method_names[meth],\n\t\t meth, uri_ptr);\n\n\tif (wsi-\u003erole_ops \u0026\u0026 wsi-\u003erole_ops-\u003echeck_upgrades)\n\t\tswitch (wsi-\u003erole_ops-\u003echeck_upgrades(wsi)) {\n\t\tcase LWS_UPG_RET_DONE:\n\t\t\treturn 0;\n\t\tcase LWS_UPG_RET_CONTINUE:\n\t\t\tbreak;\n\t\tcase LWS_UPG_RET_BAIL:\n\t\t\tgoto bail_nuke_ah;\n\t\t}\n\n\tif (lws_ensure_user_space(wsi))\n\t\tgoto bail_nuke_ah;\n\n\t/* HTTP header had a content length? */\n\n\twsi-\u003ehttp.rx_content_length \u003d 0;\n\tif (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI) ||\n\t\tlws_hdr_total_length(wsi, WSI_TOKEN_PATCH_URI) ||\n\t\tlws_hdr_total_length(wsi, WSI_TOKEN_PUT_URI))\n\t\twsi-\u003ehttp.rx_content_length \u003d 100 * 1024 * 1024;\n\n\tif (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) {\n\t\tlws_hdr_copy(wsi, content_length_str,\n\t\t\t sizeof(content_length_str) - 1,\n\t\t\t WSI_TOKEN_HTTP_CONTENT_LENGTH);\n\t\twsi-\u003ehttp.rx_content_length \u003d atoll(content_length_str);\n\t}\n\n\tif (wsi-\u003ehttp2_substream) {\n\t\twsi-\u003ehttp.request_version \u003d HTTP_VERSION_2;\n\t} else {\n\t\t/* http_version? Default to 1.0, override with token: */\n\t\trequest_version \u003d HTTP_VERSION_1_0;\n\n\t\t/* Works for single digit HTTP versions. : */\n\t\thttp_version_len \u003d lws_hdr_total_length(wsi, WSI_TOKEN_HTTP);\n\t\tif (http_version_len \u003e 7) {\n\t\t\tlws_hdr_copy(wsi, http_version_str,\n\t\t\t\t sizeof(http_version_str) - 1,\n\t\t\t\t WSI_TOKEN_HTTP);\n\t\t\tif (http_version_str[5] \u003d\u003d '1' \u0026\u0026\n\t\t\t http_version_str[7] \u003d\u003d '1')\n\t\t\t\trequest_version \u003d HTTP_VERSION_1_1;\n\t\t}\n\t\twsi-\u003ehttp.request_version \u003d request_version;\n\n\t\t/* HTTP/1.1 defaults to \u0022keep-alive\u0022, 1.0 to \u0022close\u0022 */\n\t\tif (request_version \u003d\u003d HTTP_VERSION_1_1)\n\t\t\tconnection_type \u003d HTTP_CONNECTION_KEEP_ALIVE;\n\t\telse\n\t\t\tconnection_type \u003d HTTP_CONNECTION_CLOSE;\n\n\t\t/* Override default if http \u0022Connection:\u0022 header: */\n\t\tif (lws_hdr_total_length(wsi, WSI_TOKEN_CONNECTION)) {\n\t\t\tlws_hdr_copy(wsi, http_conn_str,\n\t\t\t\t sizeof(http_conn_str) - 1,\n\t\t\t\t WSI_TOKEN_CONNECTION);\n\t\t\thttp_conn_str[sizeof(http_conn_str) - 1] \u003d '\u005c0';\n\t\t\tif (!strcasecmp(http_conn_str, \u0022keep-alive\u0022))\n\t\t\t\tconnection_type \u003d HTTP_CONNECTION_KEEP_ALIVE;\n\t\t\telse\n\t\t\t\tif (!strcasecmp(http_conn_str, \u0022close\u0022))\n\t\t\t\t\tconnection_type \u003d HTTP_CONNECTION_CLOSE;\n\t\t}\n\t\twsi-\u003ehttp.connection_type \u003d connection_type;\n\t}\n\n\tn \u003d wsi-\u003eprotocol-\u003ecallback(wsi, LWS_CALLBACK_FILTER_HTTP_CONNECTION,\n\t\t\t\t wsi-\u003euser_space, uri_ptr, uri_len);\n\tif (n) {\n\t\tlwsl_info(\u0022LWS_CALLBACK_HTTP closing\u005cn\u0022);\n\n\t\treturn 1;\n\t}\n\t/*\n\t * if there is content supposed to be coming,\n\t * put a timeout on it having arrived\n\t */\n\tlws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_CONTENT,\n\t\t\twsi-\u003econtext-\u003etimeout_secs);\n#ifdef LWS_WITH_TLS\n\tif (wsi-\u003etls.redirect_to_https) {\n\t\t/*\n\t\t * we accepted http:// only so we could redirect to\n\t\t * https://, so issue the redirect. Create the redirection\n\t\t * URI from the host: header and ignore the path part\n\t\t */\n\t\tunsigned char *start \u003d pt-\u003eserv_buf + LWS_PRE, *p \u003d start,\n\t\t\t *end \u003d p + 512;\n\n\t\tif (!lws_hdr_total_length(wsi, WSI_TOKEN_HOST))\n\t\t\tgoto bail_nuke_ah;\n\n\t\tn \u003d sprintf((char *)end, \u0022https://%s/\u0022,\n\t\t\t lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST));\n\n\t\tn \u003d lws_http_redirect(wsi, HTTP_STATUS_MOVED_PERMANENTLY,\n\t\t\t\t end, n, \u0026p, end);\n\t\tif ((int)n \u003c 0)\n\t\t\tgoto bail_nuke_ah;\n\n\t\treturn lws_http_transaction_completed(wsi);\n\t}\n#endif\n\n#ifdef LWS_WITH_ACCESS_LOG\n\tlws_prepare_access_log_info(wsi, uri_ptr, meth);\n#endif\n\n\t/* can we serve it from the mount list? */\n\n\thit \u003d lws_find_mount(wsi, uri_ptr, uri_len);\n\tif (!hit) {\n\t\t/* deferred cleanup and reset to protocols[0] */\n\n\t\tlwsl_info(\u0022no hit\u005cn\u0022);\n\n\t\tif (lws_bind_protocol(wsi, \u0026wsi-\u003evhost-\u003eprotocols[0]))\n\t\t\treturn 1;\n\n\t\tlwsi_set_state(wsi, LRS_DOING_TRANSACTION);\n\n\t\tn \u003d wsi-\u003eprotocol-\u003ecallback(wsi, LWS_CALLBACK_HTTP,\n\t\t\t\t wsi-\u003euser_space, uri_ptr, uri_len);\n\n\t\tgoto after;\n\t}\n\n\ts \u003d uri_ptr + hit-\u003emountpoint_len;\n\n\t/*\n\t * if we have a mountpoint like https://xxx.com/yyy\n\t * there is an implied / at the end for our purposes since\n\t * we can only mount on a \u0022directory\u0022.\n\t *\n\t * But if we just go with that, the browser cannot understand\n\t * that he is actually looking down one \u0022directory level\u0022, so\n\t * even though we give him /yyy/abc.html he acts like the\n\t * current directory level is /. So relative urls like \u0022x.png\u0022\n\t * wrongly look outside the mountpoint.\n\t *\n\t * Therefore if we didn't come in on a url with an explicit\n\t * / at the end, we must redirect to add it so the browser\n\t * understands he is one \u0022directory level\u0022 down.\n\t */\n\tif ((hit-\u003emountpoint_len \u003e 1 ||\n\t (hit-\u003eorigin_protocol \u003d\u003d LWSMPRO_REDIR_HTTP ||\n\t hit-\u003eorigin_protocol \u003d\u003d LWSMPRO_REDIR_HTTPS)) \u0026\u0026\n\t (*s !\u003d '/' ||\n\t (hit-\u003eorigin_protocol \u003d\u003d LWSMPRO_REDIR_HTTP ||\n\t hit-\u003eorigin_protocol \u003d\u003d LWSMPRO_REDIR_HTTPS)) \u0026\u0026\n\t (hit-\u003eorigin_protocol !\u003d LWSMPRO_CGI \u0026\u0026\n\t hit-\u003eorigin_protocol !\u003d LWSMPRO_CALLBACK)) {\n\t\tunsigned char *start \u003d pt-\u003eserv_buf + LWS_PRE,\n\t\t\t *p \u003d start, *end \u003d p + 512;\n\n\t\tlwsl_debug(\u0022Doing 301 '%s' org %s\u005cn\u0022, s, hit-\u003eorigin);\n\n\t\t/* \u003e at start indicates deal with by redirect */\n\t\tif (hit-\u003eorigin_protocol \u003d\u003d LWSMPRO_REDIR_HTTP ||\n\t\t hit-\u003eorigin_protocol \u003d\u003d LWSMPRO_REDIR_HTTPS)\n\t\t\tn \u003d lws_snprintf((char *)end, 256, \u0022%s%s\u0022,\n\t\t\t\t oprot[hit-\u003eorigin_protocol \u0026 1],\n\t\t\t\t hit-\u003eorigin);\n\t\telse {\n\t\t\tif (!lws_hdr_total_length(wsi, WSI_TOKEN_HOST)) {\n\t\t\t\tif (!lws_hdr_total_length(wsi,\n\t\t\t\t\t\tWSI_TOKEN_HTTP_COLON_AUTHORITY))\n\t\t\t\t\tgoto bail_nuke_ah;\n\t\t\t\tn \u003d lws_snprintf((char *)end, 256,\n\t\t\t\t \u0022%s%s%s/\u0022, oprot[!!lws_is_ssl(wsi)],\n\t\t\t\t lws_hdr_simple_ptr(wsi,\n\t\t\t\t\t\tWSI_TOKEN_HTTP_COLON_AUTHORITY),\n\t\t\t\t uri_ptr);\n\t\t\t} else\n\t\t\t\tn \u003d lws_snprintf((char *)end, 256,\n\t\t\t\t \u0022%s%s%s/\u0022, oprot[!!lws_is_ssl(wsi)],\n\t\t\t\t lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST),\n\t\t\t\t uri_ptr);\n\t\t}\n\n\t\tlws_clean_url((char *)end);\n\t\tn \u003d lws_http_redirect(wsi, HTTP_STATUS_MOVED_PERMANENTLY,\n\t\t\t\t end, n, \u0026p, end);\n\t\tif ((int)n \u003c 0)\n\t\t\tgoto bail_nuke_ah;\n\n\t\treturn lws_http_transaction_completed(wsi);\n\t}\n\n\t/* basic auth? */\n\n\tif (hit-\u003ebasic_auth_login_file) {\n\t\tchar b64[160], plain[(sizeof(b64) * 3) / 4];\n\t\tint m;\n\n\t\t/* Did he send auth? */\n\t\tif (!lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_AUTHORIZATION))\n\t\t\treturn lws_unauthorised_basic_auth(wsi);\n\n\t\tn \u003d HTTP_STATUS_FORBIDDEN;\n\n\t\tm \u003d lws_hdr_copy(wsi, b64, sizeof(b64),\n\t\t\t\t WSI_TOKEN_HTTP_AUTHORIZATION);\n\t\tif (m \u003c 7) {\n\t\t\tlwsl_err(\u0022b64 auth too long\u005cn\u0022);\n\t\t\tgoto transaction_result_n;\n\t\t}\n\n\t\tb64[5] \u003d '\u005c0';\n\t\tif (strcasecmp(b64, \u0022Basic\u0022)) {\n\t\t\tlwsl_err(\u0022auth missing basic: %s\u005cn\u0022, b64);\n\t\t\tgoto transaction_result_n;\n\t\t}\n\n\t\t/* It'll be like Authorization: Basic QWxhZGRpbjpPcGVuU2VzYW1l */\n\n\t\tm \u003d lws_b64_decode_string(b64 + 6, plain, sizeof(plain));\n\t\tif (m \u003c 0) {\n\t\t\tlwsl_err(\u0022plain auth too long\u005cn\u0022);\n\t\t\tgoto transaction_result_n;\n\t\t}\n\n\t\tif (!lws_find_string_in_file(hit-\u003ebasic_auth_login_file,\n\t\t\t\t\t plain, m)) {\n\t\t\tlwsl_err(\u0022basic auth lookup failed\u005cn\u0022);\n\t\t\treturn lws_unauthorised_basic_auth(wsi);\n\t\t}\n\n\t\tlwsl_info(\u0022basic auth accepted\u005cn\u0022);\n\n\t\t/* accept the auth */\n\t}\n\n#if defined(LWS_WITH_HTTP_PROXY)\n\t/*\n\t * The mount is a reverse proxy?\n\t */\n\n\tif (hit-\u003eorigin_protocol \u003d\u003d LWSMPRO_HTTPS ||\n\t hit-\u003eorigin_protocol \u003d\u003d LWSMPRO_HTTP) {\n\t\tstruct lws_client_connect_info i;\n\t\tchar ads[96], rpath[256], *pcolon, *pslash, *p;\n\t\tint n, na;\n\n\t\tmemset(\u0026i, 0, sizeof(i));\n\t\ti.context \u003d lws_get_context(wsi);\n\n\t\tpcolon \u003d strchr(hit-\u003eorigin, ':');\n\t\tpslash \u003d strchr(hit-\u003eorigin, '/');\n\t\tif (!pslash) {\n\t\t\tlwsl_err(\u0022Proxy mount origin '%s' must have /\u005cn\u0022,\n\t\t\t\t hit-\u003eorigin);\n\t\t\treturn -1;\n\t\t}\n\t\tif (pcolon \u003e pslash)\n\t\t\tpcolon \u003d NULL;\n\n\t\tif (pcolon)\n\t\t\tn \u003d pcolon - hit-\u003eorigin;\n\t\telse\n\t\t\tn \u003d pslash - hit-\u003eorigin;\n\n\t\tif (n \u003e\u003d (int)sizeof(ads) - 2)\n\t\t\tn \u003d sizeof(ads) - 2;\n\n\t\tmemcpy(ads, hit-\u003eorigin, n);\n\t\tads[n] \u003d '\u005c0';\n\n\t\ti.address \u003d ads;\n\t\ti.port \u003d 80;\n\t\tif (hit-\u003eorigin_protocol \u003d\u003d LWSMPRO_HTTPS) {\n\t\t\ti.port \u003d 443;\n\t\t\ti.ssl_connection \u003d 1;\n\t\t}\n\t\tif (pcolon)\n\t\t\ti.port \u003d atoi(pcolon + 1);\n\n\t\tlws_snprintf(rpath, sizeof(rpath) - 1, \u0022/%s/%s\u0022, pslash + 1,\n\t\t\t uri_ptr + hit-\u003emountpoint_len);\n\t\tlws_clean_url(rpath);\n\t\tna \u003d lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_URI_ARGS);\n\t\tif (na) {\n\t\t\tp \u003d rpath + strlen(rpath);\n\t\t\t*p++ \u003d '?';\n\t\t\tlws_hdr_copy(wsi, p, \u0026rpath[sizeof(rpath) - 1] - p,\n\t\t\t\t WSI_TOKEN_HTTP_URI_ARGS);\n\t\t\twhile (--na) {\n\t\t\t\tif (*p \u003d\u003d '\u005c0')\n\t\t\t\t\t*p \u003d '\u0026';\n\t\t\t\tp++;\n\t\t\t}\n\t\t}\n\n\n\t\ti.path \u003d rpath;\n\t\ti.host \u003d i.address;\n\t\ti.origin \u003d NULL;\n\t\ti.method \u003d \u0022GET\u0022;\n\t\ti.parent_wsi \u003d wsi;\n\t\ti.uri_replace_from \u003d hit-\u003eorigin;\n\t\ti.uri_replace_to \u003d hit-\u003emountpoint;\n\n\t\tlwsl_notice(\u0022proxying to %s port %d url %s, ssl %d, \u0022\n\t\t\t \u0022from %s, to %s\u005cn\u0022,\n\t\t\t i.address, i.port, i.path, i.ssl_connection,\n\t\t\t i.uri_replace_from, i.uri_replace_to);\n\n\t\tif (!lws_client_connect_via_info(\u0026i)) {\n\t\t\tlwsl_err(\u0022proxy connect fail\u005cn\u0022);\n\t\t\treturn 1;\n\t\t}\n\n\t\treturn 0;\n\t}\n#endif\n\n\t/*\n\t * A particular protocol callback is mounted here?\n\t *\n\t * For the duration of this http transaction, bind us to the\n\t * associated protocol\n\t */\n\tif (hit-\u003eorigin_protocol \u003d\u003d LWSMPRO_CALLBACK || hit-\u003eprotocol) {\n\t\tconst struct lws_protocols *pp;\n\t\tconst char *name \u003d hit-\u003eorigin;\n\t\tif (hit-\u003eprotocol)\n\t\t\tname \u003d hit-\u003eprotocol;\n\n\t\tpp \u003d lws_vhost_name_to_protocol(wsi-\u003evhost, name);\n\t\tif (!pp) {\n\t\t\tn \u003d -1;\n\t\t\tlwsl_err(\u0022Unable to find plugin '%s'\u005cn\u0022,\n\t\t\t\t hit-\u003eorigin);\n\t\t\treturn 1;\n\t\t}\n\n\t\tif (lws_bind_protocol(wsi, pp))\n\t\t\treturn 1;\n\n\t\targs.p \u003d uri_ptr;\n\t\targs.len \u003d uri_len;\n\t\targs.max_len \u003d hit-\u003eauth_mask;\n\t\targs.final \u003d 0; /* used to signal callback dealt with it */\n\t\targs.chunked \u003d 0;\n\n\t\tn \u003d wsi-\u003eprotocol-\u003ecallback(wsi,\n\t\t\t\t\t LWS_CALLBACK_CHECK_ACCESS_RIGHTS,\n\t\t\t\t\t wsi-\u003euser_space, \u0026args, 0);\n\t\tif (n) {\n\t\t\tlws_return_http_status(wsi, HTTP_STATUS_UNAUTHORIZED,\n\t\t\t\t\t NULL);\n\t\t\tgoto bail_nuke_ah;\n\t\t}\n\t\tif (args.final) /* callback completely handled it well */\n\t\t\treturn 0;\n\n\t\tif (hit-\u003ecgienv \u0026\u0026 wsi-\u003eprotocol-\u003ecallback(wsi,\n\t\t\t\tLWS_CALLBACK_HTTP_PMO,\n\t\t\t\twsi-\u003euser_space, (void *)hit-\u003ecgienv, 0))\n\t\t\treturn 1;\n\n\t\tif (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)) {\n\t\t\tn \u003d wsi-\u003eprotocol-\u003ecallback(wsi, LWS_CALLBACK_HTTP,\n\t\t\t\t\t wsi-\u003euser_space,\n\t\t\t\t\t uri_ptr + hit-\u003emountpoint_len,\n\t\t\t\t\t uri_len - hit-\u003emountpoint_len);\n\t\t\tgoto after;\n\t\t}\n\t}\n\n#ifdef LWS_WITH_CGI\n\t/* did we hit something with a cgi:// origin? */\n\tif (hit-\u003eorigin_protocol \u003d\u003d LWSMPRO_CGI) {\n\t\tconst char *cmd[] \u003d {\n\t\t\tNULL, /* replace with cgi path */\n\t\t\tNULL\n\t\t};\n\n\t\tlwsl_debug(\u0022%s: cgi\u005cn\u0022, __func__);\n\t\tcmd[0] \u003d hit-\u003eorigin;\n\n\t\tn \u003d 5;\n\t\tif (hit-\u003ecgi_timeout)\n\t\t\tn \u003d hit-\u003ecgi_timeout;\n\n\t\tn \u003d lws_cgi(wsi, cmd, hit-\u003emountpoint_len, n,\n\t\t\t hit-\u003ecgienv);\n\t\tif (n) {\n\t\t\tlwsl_err(\u0022%s: cgi failed\u005cn\u0022, __func__);\n\t\t\treturn -1;\n\t\t}\n\n\t\tgoto deal_body;\n\t}\n#endif\n\n\tn \u003d (int)strlen(s);\n\tif (s[0] \u003d\u003d '\u005c0' || (n \u003d\u003d 1 \u0026\u0026 s[n - 1] \u003d\u003d '/'))\n\t\ts \u003d (char *)hit-\u003edef;\n\tif (!s)\n\t\ts \u003d \u0022index.html\u0022;\n\n\twsi-\u003ecache_secs \u003d hit-\u003ecache_max_age;\n\twsi-\u003ecache_reuse \u003d hit-\u003ecache_reusable;\n\twsi-\u003ecache_revalidate \u003d hit-\u003ecache_revalidate;\n\twsi-\u003ecache_intermediaries \u003d hit-\u003ecache_intermediaries;\n\n\tn \u003d 1;\n\tif (hit-\u003eorigin_protocol \u003d\u003d LWSMPRO_FILE)\n\t\tn \u003d lws_http_serve(wsi, s, hit-\u003eorigin, hit);\n\tif (n) {\n\t\t/*\n\t\t * lws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND, NULL);\n\t\t */\n\t\tif (hit-\u003eprotocol) {\n\t\t\tconst struct lws_protocols *pp \u003d\n\t\t\t\t\tlws_vhost_name_to_protocol(\n\t\t\t\t\t\twsi-\u003evhost, hit-\u003eprotocol);\n\n\t\t\tif (lws_bind_protocol(wsi, pp))\n\t\t\t\treturn 1;\n\n\t\t\tn \u003d pp-\u003ecallback(wsi, LWS_CALLBACK_HTTP,\n\t\t\t\t\t wsi-\u003euser_space,\n\t\t\t\t\t uri_ptr + hit-\u003emountpoint_len,\n\t\t\t\t\t uri_len - hit-\u003emountpoint_len);\n\t\t} else\n\t\t\tn \u003d wsi-\u003eprotocol-\u003ecallback(wsi, LWS_CALLBACK_HTTP,\n\t\t\t\t wsi-\u003euser_space, uri_ptr, uri_len);\n\t}\n\nafter:\n\tif (n) {\n\t\tlwsl_info(\u0022LWS_CALLBACK_HTTP closing\u005cn\u0022);\n\n\t\treturn 1;\n\t}\n\n#ifdef LWS_WITH_CGI\ndeal_body:\n#endif\n\t/*\n\t * If we're not issuing a file, check for content_length or\n\t * HTTP keep-alive. No keep-alive header allocation for\n\t * ISSUING_FILE, as this uses HTTP/1.0.\n\t *\n\t * In any case, return 0 and let lws_read decide how to\n\t * proceed based on state\n\t */\n\tif (lwsi_state(wsi) !\u003d LRS_ISSUING_FILE) {\n\t\t/* Prepare to read body if we have a content length: */\n\t\tlwsl_debug(\u0022wsi-\u003ehttp.rx_content_length %lld %d %d\u005cn\u0022,\n\t\t\t (long long)wsi-\u003ehttp.rx_content_length,\n\t\t\t wsi-\u003eupgraded_to_http2, wsi-\u003ehttp2_substream);\n\t\tif (wsi-\u003ehttp.rx_content_length \u003e 0) {\n\t\t\tstruct lws_tokens ebuf;\n\t\t\tint m;\n\n\t\t\tlwsi_set_state(wsi, LRS_BODY);\n\t\t\tlwsl_info(\u0022%s: %p: LRS_BODY state set (0x%x)\u005cn\u0022,\n\t\t\t\t __func__, wsi, wsi-\u003ewsistate);\n\t\t\twsi-\u003ehttp.rx_content_remain \u003d\n\t\t\t\t\twsi-\u003ehttp.rx_content_length;\n\n\t\t\t/*\n\t\t\t * At this point we have transitioned from deferred\n\t\t\t * action to expecting BODY on the stream wsi, if it's\n\t\t\t * in a bundle like h2. So if the stream wsi has its\n\t\t\t * own buflist, we need to deal with that first.\n\t\t\t */\n\n\t\t\twhile (1) {\n\t\t\t\tebuf.len \u003d (int)lws_buflist_next_segment_len(\n\t\t\t\t\t\t\u0026wsi-\u003ebuflist, (uint8_t **)\u0026ebuf.token);\n\t\t\t\tif (!ebuf.len)\n\t\t\t\t\tbreak;\n\t\t\t\tlwsl_notice(\u0022%s: consuming %d\u005cn\u0022, __func__, (int)ebuf.len);\n\t\t\t\tm \u003d lws_read_h1(wsi, (uint8_t *)ebuf.token, ebuf.len);\n\t\t\t\tif (m \u003c 0)\n\t\t\t\t\treturn -1;\n\n\t\t\t\tif (lws_buflist_aware_consume(wsi, \u0026ebuf, m, 1))\n\t\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn 0;\n\nbail_nuke_ah:\n\tlws_header_table_detach(wsi, 1);\n\n\treturn 1;\n\ntransaction_result_n:\n\tlws_return_http_status(wsi, n, NULL);\n\n\treturn lws_http_transaction_completed(wsi);\n}\n\nint\nlws_handshake_server(struct lws *wsi, unsigned char **buf, size_t len)\n{\n\tstruct lws_context *context \u003d lws_get_context(wsi);\n\tunsigned char *obuf \u003d *buf;\n#if defined(LWS_WITH_HTTP2)\n\tchar tbuf[128], *p;\n#endif\n\tsize_t olen \u003d len;\n\tint n \u003d 0, m, i;\n\n\tif (len \u003e\u003d 10000000) {\n\t\tlwsl_err(\u0022%s: assert: len %ld\u005cn\u0022, __func__, (long)len);\n\t\tassert(0);\n\t}\n\n\tif (!wsi-\u003ehttp.ah) {\n\t\tlwsl_err(\u0022%s: assert: NULL ah\u005cn\u0022, __func__);\n\t\tassert(0);\n\t}\n\n\twhile (len) {\n\t\tif (!lwsi_role_server(wsi) || !lwsi_role_http(wsi)) {\n\t\t\tlwsl_err(\u0022%s: bad wsi role 0x%x\u005cn\u0022, __func__,\n\t\t\t\t\tlwsi_role(wsi));\n\t\t\tgoto bail_nuke_ah;\n\t\t}\n\n\t\ti \u003d (int)len;\n\t\tm \u003d lws_parse(wsi, *buf, \u0026i);\n\t\tlwsl_info(\u0022%s: parsed count %d\u005cn\u0022, __func__, (int)len - i);\n\t\t(*buf) +\u003d (int)len - i;\n\t\tlen \u003d i;\n\t\tif (m) {\n\t\t\tif (m \u003d\u003d 2) {\n\t\t\t\t/*\n\t\t\t\t * we are transitioning from http with\n\t\t\t\t * an AH, to raw. Drop the ah and set\n\t\t\t\t * the mode.\n\t\t\t\t */\nraw_transition:\n\t\t\t\tlws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);\n\t\t\t\tlws_bind_protocol(wsi, \u0026wsi-\u003evhost-\u003eprotocols[\n\t\t\t\t wsi-\u003evhost-\u003e\n\t\t\t\t raw_protocol_index]);\n\t\t\t\tlwsl_info(\u0022transition to raw vh %s prot %d\u005cn\u0022,\n\t\t\t\t\t wsi-\u003evhost-\u003ename,\n\t\t\t\t\t wsi-\u003evhost-\u003eraw_protocol_index);\n\t\t\t\tif ((wsi-\u003eprotocol-\u003ecallback)(wsi,\n\t\t\t\t\t\tLWS_CALLBACK_RAW_ADOPT,\n\t\t\t\t\t\twsi-\u003euser_space, NULL, 0))\n\t\t\t\t\tgoto bail_nuke_ah;\n\n\t\t\t\tlws_role_transition(wsi, 0, LRS_ESTABLISHED,\n\t\t\t\t\t\t \u0026role_ops_raw_skt);\n\t\t\t\tlws_header_table_detach(wsi, 1);\n\n\t\t\t\tif (m \u003d\u003d 2 \u0026\u0026 (wsi-\u003eprotocol-\u003ecallback)(wsi,\n\t\t\t\t\t\tLWS_CALLBACK_RAW_RX,\n\t\t\t\t\t\twsi-\u003euser_space, obuf, olen))\n\t\t\t\t\treturn 1;\n\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tlwsl_info(\u0022lws_parse failed\u005cn\u0022);\n\t\t\tgoto bail_nuke_ah;\n\t\t}\n\n\t\tif (wsi-\u003ehttp.ah-\u003eparser_state !\u003d WSI_PARSING_COMPLETE)\n\t\t\tcontinue;\n\n\t\tlwsl_parser(\u0022%s: lws_parse sees parsing complete\u005cn\u0022, __func__);\n\n\t\t/* select vhost */\n\n\t\tif (lws_hdr_total_length(wsi, WSI_TOKEN_HOST)) {\n\t\t\tstruct lws_vhost *vhost \u003d lws_select_vhost(\n\t\t\t\tcontext, wsi-\u003evhost-\u003elisten_port,\n\t\t\t\tlws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST));\n\n\t\t\tif (vhost)\n\t\t\t\twsi-\u003evhost \u003d vhost;\n\t\t} else\n\t\t\tlwsl_info(\u0022no host\u005cn\u0022);\n\n\t\tif (!lwsi_role_h2(wsi) || !lwsi_role_server(wsi)) {\n\t\t\twsi-\u003evhost-\u003econn_stats.h1_trans++;\n\t\t\tif (!wsi-\u003econn_stat_done) {\n\t\t\t\twsi-\u003evhost-\u003econn_stats.h1_conn++;\n\t\t\t\twsi-\u003econn_stat_done \u003d 1;\n\t\t\t}\n\t\t}\n\n\t\t/* check for unwelcome guests */\n\n\t\tif (wsi-\u003econtext-\u003ereject_service_keywords) {\n\t\t\tconst struct lws_protocol_vhost_options *rej \u003d\n\t\t\t\t\twsi-\u003econtext-\u003ereject_service_keywords;\n\t\t\tchar ua[384], *msg \u003d NULL;\n\n\t\t\tif (lws_hdr_copy(wsi, ua, sizeof(ua) - 1,\n\t\t\t\t\t WSI_TOKEN_HTTP_USER_AGENT) \u003e 0) {\n#ifdef LWS_WITH_ACCESS_LOG\n\t\t\t\tchar *uri_ptr \u003d NULL;\n\t\t\t\tint meth, uri_len;\n#endif\n\t\t\t\tua[sizeof(ua) - 1] \u003d '\u005c0';\n\t\t\t\twhile (rej) {\n\t\t\t\t\tif (!strstr(ua, rej-\u003ename)) {\n\t\t\t\t\t\trej \u003d rej-\u003enext;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tmsg \u003d strchr(rej-\u003evalue, ' ');\n\t\t\t\t\tif (msg)\n\t\t\t\t\t\tmsg++;\n\t\t\t\t\tlws_return_http_status(wsi,\n\t\t\t\t\t\tatoi(rej-\u003evalue), msg);\n#ifdef LWS_WITH_ACCESS_LOG\n\t\t\t\t\tmeth \u003d lws_http_get_uri_and_method(wsi,\n\t\t\t\t\t\t\t\u0026uri_ptr, \u0026uri_len);\n\t\t\t\t\tif (meth \u003e\u003d 0)\n\t\t\t\t\t\tlws_prepare_access_log_info(wsi,\n\t\t\t\t\t\t\t\turi_ptr, meth);\n\n\t\t\t\t\t/* wsi close will do the log */\n#endif\n\t\t\t\t\twsi-\u003evhost-\u003econn_stats.rejected++;\n\t\t\t\t\t/*\n\t\t\t\t\t * We don't want anything from\n\t\t\t\t\t * this rejected guy. Follow\n\t\t\t\t\t * the close flow, not the\n\t\t\t\t\t * transaction complete flow.\n\t\t\t\t\t */\n\t\t\t\t\tgoto bail_nuke_ah;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\n\t\tif (lws_hdr_total_length(wsi, WSI_TOKEN_CONNECT)) {\n\t\t\tlwsl_info(\u0022Changing to RAW mode\u005cn\u0022);\n\t\t\tm \u003d 0;\n\t\t\tgoto raw_transition;\n\t\t}\n\n\t\tlwsi_set_state(wsi, LRS_PRE_WS_SERVING_ACCEPT);\n\t\tlws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);\n\n\t\t/* is this websocket protocol or normal http 1.0? */\n\n\t\tif (lws_hdr_total_length(wsi, WSI_TOKEN_UPGRADE)) {\n\t\t\tif (!strcasecmp(lws_hdr_simple_ptr(wsi,\n\t\t\t\t\t\t\t WSI_TOKEN_UPGRADE),\n\t\t\t\t\t\u0022websocket\u0022)) {\n#if defined(LWS_ROLE_WS)\n\t\t\t\twsi-\u003evhost-\u003econn_stats.ws_upg++;\n\t\t\t\tlwsl_info(\u0022Upgrade to ws\u005cn\u0022);\n\t\t\t\tgoto upgrade_ws;\n#endif\n\t\t\t}\n#if defined(LWS_WITH_HTTP2)\n\t\t\tif (!strcasecmp(lws_hdr_simple_ptr(wsi,\n\t\t\t\t\t\t\t WSI_TOKEN_UPGRADE),\n\t\t\t\t\t\u0022h2c\u0022)) {\n\t\t\t\twsi-\u003evhost-\u003econn_stats.h2_upg++;\n\t\t\t\tlwsl_info(\u0022Upgrade to h2c\u005cn\u0022);\n\t\t\t\tgoto upgrade_h2c;\n\t\t\t}\n#endif\n\t\t\tlwsl_info(\u0022Unknown upgrade\u005cn\u0022);\n\t\t\t/* dunno what he wanted to upgrade to */\n\t\t\tgoto bail_nuke_ah;\n\t\t}\n\n\t\t/* no upgrade ack... he remained as HTTP */\n\n\t\tlwsl_info(\u0022%s: %p: No upgrade\u005cn\u0022, __func__, wsi);\n\n\t\tlwsi_set_state(wsi, LRS_ESTABLISHED);\n\t\twsi-\u003ehttp.fop_fd \u003d NULL;\n\n\t\tlwsl_debug(\u0022%s: wsi %p: ah %p\u005cn\u0022, __func__, (void *)wsi,\n\t\t\t (void *)wsi-\u003ehttp.ah);\n\n\t\tn \u003d lws_http_action(wsi);\n\n\t\treturn n;\n\n#if defined(LWS_WITH_HTTP2)\nupgrade_h2c:\n\t\tif (!lws_hdr_total_length(wsi, WSI_TOKEN_HTTP2_SETTINGS)) {\n\t\t\tlwsl_info(\u0022missing http2_settings\u005cn\u0022);\n\t\t\tgoto bail_nuke_ah;\n\t\t}\n\n\t\tlwsl_info(\u0022h2c upgrade...\u005cn\u0022);\n\n\t\tp \u003d lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP2_SETTINGS);\n\t\t/* convert the peer's HTTP-Settings */\n\t\tn \u003d lws_b64_decode_string(p, tbuf, sizeof(tbuf));\n\t\tif (n \u003c 0) {\n\t\t\tlwsl_parser(\u0022HTTP2_SETTINGS too long\u005cn\u0022);\n\t\t\treturn 1;\n\t\t}\n\n\t\t/* adopt the header info */\n\n\t\tif (!wsi-\u003eh2.h2n) {\n\t\t\twsi-\u003eh2.h2n \u003d lws_zalloc(sizeof(*wsi-\u003eh2.h2n),\n\t\t\t\t\t\t \u0022h2n\u0022);\n\t\t\tif (!wsi-\u003eh2.h2n)\n\t\t\t\treturn 1;\n\t\t}\n\n\t\tlws_h2_init(wsi);\n\n\t\t/* HTTP2 union */\n\n\t\tlws_h2_settings(wsi, \u0026wsi-\u003eh2.h2n-\u003eset, (unsigned char *)tbuf, n);\n\n\t\tlws_hpack_dynamic_size(wsi, wsi-\u003eh2.h2n-\u003eset.s[\n\t\t H2SET_HEADER_TABLE_SIZE]);\n\n\t\tstrcpy(tbuf, \u0022HTTP/1.1 101 Switching Protocols\u005cx0d\u005cx0a\u0022\n\t\t\t \u0022Connection: Upgrade\u005cx0d\u005cx0a\u0022\n\t\t\t \u0022Upgrade: h2c\u005cx0d\u005cx0a\u005cx0d\u005cx0a\u0022);\n\t\tm \u003d (int)strlen(tbuf);\n\t\tn \u003d lws_issue_raw(wsi, (unsigned char *)tbuf, m);\n\t\tif (n !\u003d m) {\n\t\t\tlwsl_debug(\u0022http2 switch: ERROR writing to socket\u005cn\u0022);\n\t\t\treturn 1;\n\t\t}\n\n\t\tlwsi_set_state(wsi, LRS_H2_AWAIT_PREFACE);\n\t\twsi-\u003eupgraded_to_http2 \u003d 1;\n\n\t\treturn 0;\n#endif\n#if defined(LWS_ROLE_WS)\nupgrade_ws:\n\t\tif (lws_process_ws_upgrade(wsi))\n\t\t\tgoto bail_nuke_ah;\n\n\t\treturn 0;\n#endif\n\t} /* while all chars are handled */\n\n\treturn 0;\n\nbail_nuke_ah:\n\t/* drop the header info */\n\tlws_header_table_detach(wsi, 1);\n\n\treturn 1;\n}\n\n\nstatic int\nlws_get_idlest_tsi(struct lws_context *context)\n{\n\tunsigned int lowest \u003d ~0;\n\tint n \u003d 0, hit \u003d -1;\n\n\tfor (; n \u003c context-\u003ecount_threads; n++) {\n\t\tif ((unsigned int)context-\u003ept[n].fds_count !\u003d\n\t\t context-\u003efd_limit_per_thread - 1 \u0026\u0026\n\t\t (unsigned int)context-\u003ept[n].fds_count \u003c lowest) {\n\t\t\tlowest \u003d context-\u003ept[n].fds_count;\n\t\t\thit \u003d n;\n\t\t}\n\t}\n\n\treturn hit;\n}\n\nstruct lws *\nlws_create_new_server_wsi(struct lws_vhost *vhost, int fixed_tsi)\n{\n\tstruct lws *new_wsi;\n\tint n \u003d fixed_tsi;\n\n\tif (n \u003c 0)\n\t\tn \u003d lws_get_idlest_tsi(vhost-\u003econtext);\n\n\tif (n \u003c 0) {\n\t\tlwsl_err(\u0022no space for new conn\u005cn\u0022);\n\t\treturn NULL;\n\t}\n\n\tnew_wsi \u003d lws_zalloc(sizeof(struct lws), \u0022new server wsi\u0022);\n\tif (new_wsi \u003d\u003d NULL) {\n\t\tlwsl_err(\u0022Out of memory for new connection\u005cn\u0022);\n\t\treturn NULL;\n\t}\n\n\tnew_wsi-\u003etsi \u003d n;\n\tlwsl_debug(\u0022new wsi %p joining vhost %s, tsi %d\u005cn\u0022, new_wsi,\n\t\t vhost-\u003ename, new_wsi-\u003etsi);\n\n\tnew_wsi-\u003evhost \u003d vhost;\n\tnew_wsi-\u003econtext \u003d vhost-\u003econtext;\n\tnew_wsi-\u003epending_timeout \u003d NO_PENDING_TIMEOUT;\n\tnew_wsi-\u003erxflow_change_to \u003d LWS_RXFLOW_ALLOW;\n\n\t/* initialize the instance struct */\n\n\tlwsi_set_state(new_wsi, LRS_UNCONNECTED);\n\tnew_wsi-\u003ehdr_parsing_completed \u003d 0;\n\n#ifdef LWS_WITH_TLS\n\tnew_wsi-\u003etls.use_ssl \u003d LWS_SSL_ENABLED(vhost);\n#endif\n\n\t/*\n\t * these can only be set once the protocol is known\n\t * we set an un-established connection's protocol pointer\n\t * to the start of the supported list, so it can look\n\t * for matching ones during the handshake\n\t */\n\tnew_wsi-\u003eprotocol \u003d vhost-\u003eprotocols;\n\tnew_wsi-\u003euser_space \u003d NULL;\n\tnew_wsi-\u003edesc.sockfd \u003d LWS_SOCK_INVALID;\n\tnew_wsi-\u003eposition_in_fds_table \u003d LWS_NO_FDS_POS;\n\n\tvhost-\u003econtext-\u003ecount_wsi_allocated++;\n\n\t/*\n\t * outermost create notification for wsi\n\t * no user_space because no protocol selection\n\t */\n\tvhost-\u003eprotocols[0].callback(new_wsi, LWS_CALLBACK_WSI_CREATE,\n\t\t\t\t NULL, NULL, 0);\n\n\treturn new_wsi;\n}\n\nLWS_VISIBLE int LWS_WARN_UNUSED_RESULT\nlws_http_transaction_completed(struct lws *wsi)\n{\n\tint n \u003d NO_PENDING_TIMEOUT;\n\n\tif (wsi-\u003etrunc_len) {\n\t\t/*\n\t\t * ...so he tried to send something large as the http reply,\n\t\t * it went as a partial, but he immediately said the\n\t\t * transaction was completed.\n\t\t *\n\t\t * Defer the transaction completed until the last part of the\n\t\t * partial is sent.\n\t\t */\n\t\tlwsl_notice(\u0022%s: deferring due to partial\u005cn\u0022, __func__);\n\t\twsi-\u003ehttp.deferred_transaction_completed \u003d 1;\n\n\t\treturn 0;\n\t}\n\n\tlwsl_info(\u0022%s: wsi %p\u005cn\u0022, __func__, wsi);\n\n\tlws_access_log(wsi);\n\n\tif (!wsi-\u003ehdr_parsing_completed) {\n\t\tchar peer[64];\n\t\tlws_get_peer_simple(wsi, peer, sizeof(peer) - 1);\n\t\tpeer[sizeof(peer) - 1] \u003d '\u005c0';\n\t\tlwsl_notice(\u0022%s: (from %s) ignoring, ah parsing incomplete\u005cn\u0022,\n\t\t\t\t__func__, peer);\n\t\treturn 0;\n\t}\n\n\t/* if we can't go back to accept new headers, drop the connection */\n\tif (wsi-\u003ehttp2_substream)\n\t\treturn 0;\n\n\tif (wsi-\u003eseen_zero_length_recv)\n\t\treturn 1;\n\n\tif (wsi-\u003ehttp.connection_type !\u003d HTTP_CONNECTION_KEEP_ALIVE) {\n\t\tlwsl_notice(\u0022%s: %p: close connection\u005cn\u0022, __func__, wsi);\n\t\treturn 1;\n\t}\n\n\tif (lws_bind_protocol(wsi, \u0026wsi-\u003evhost-\u003eprotocols[0]))\n\t\treturn 1;\n\n\t/*\n\t * otherwise set ourselves up ready to go again, but because we have no\n\t * idea about the wsi writability, we make put it in a holding state\n\t * until we can verify POLLOUT. The part of this that confirms POLLOUT\n\t * with no partials is in lws_server_socket_service() below.\n\t */\n\tlwsl_debug(\u0022%s: %p: setting DEF_ACT from 0x%x\u005cn\u0022, __func__,\n\t\t wsi, wsi-\u003ewsistate);\n\tlwsi_set_state(wsi, LRS_DEFERRING_ACTION);\n\twsi-\u003ehttp.tx_content_length \u003d 0;\n\twsi-\u003ehttp.tx_content_remain \u003d 0;\n\twsi-\u003ehdr_parsing_completed \u003d 0;\n#ifdef LWS_WITH_ACCESS_LOG\n\twsi-\u003ehttp.access_log.sent \u003d 0;\n#endif\n\n\tif (wsi-\u003evhost-\u003ekeepalive_timeout)\n\t\tn \u003d PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE;\n\tlws_set_timeout(wsi, n, wsi-\u003evhost-\u003ekeepalive_timeout);\n\n\t/*\n\t * We already know we are on http1.1 / keepalive and the next thing\n\t * coming will be another header set.\n\t *\n\t * If there is no pending rx and we still have the ah, drop it and\n\t * reacquire a new ah when the new headers start to arrive. (Otherwise\n\t * we needlessly hog an ah indefinitely.)\n\t *\n\t * However if there is pending rx and we know from the keepalive state\n\t * that is already at least the start of another header set, simply\n\t * reset the existing header table and keep it.\n\t */\n\tif (wsi-\u003ehttp.ah) {\n\t\t// lws_buflist_describe(\u0026wsi-\u003ebuflist, wsi);\n\t\tif (!lws_buflist_next_segment_len(\u0026wsi-\u003ebuflist, NULL)) {\n\t\t\tlwsl_info(\u0022%s: %p: nothing in buflist so detaching ah\u005cn\u0022,\n\t\t\t\t __func__, wsi);\n\t\t\tlws_header_table_detach(wsi, 1);\n#ifdef LWS_WITH_TLS\n\t\t\t/*\n\t\t\t * additionally... if we are hogging an SSL instance\n\t\t\t * with no pending pipelined headers (or ah now), and\n\t\t\t * SSL is scarce, drop this connection without waiting\n\t\t\t */\n\n\t\t\tif (wsi-\u003evhost-\u003etls.use_ssl \u0026\u0026\n\t\t\t wsi-\u003econtext-\u003esimultaneous_ssl_restriction \u0026\u0026\n\t\t\t wsi-\u003econtext-\u003esimultaneous_ssl \u003d\u003d\n\t\t\t\t wsi-\u003econtext-\u003esimultaneous_ssl_restriction) {\n\t\t\t\tlwsl_info(\u0022%s: simultaneous_ssl_restriction\u005cn\u0022,\n\t\t\t\t\t __func__);\n\t\t\t\treturn 1;\n\t\t\t}\n#endif\n\t\t} else {\n\t\t\tlwsl_info(\u0022%s: %p: resetting and keeping ah as pipeline\u005cn\u0022,\n\t\t\t\t __func__, wsi);\n\t\t\tlws_header_table_reset(wsi, 0);\n\t\t\t/*\n\t\t\t * If we kept the ah, we should restrict the amount\n\t\t\t * of time we are willing to keep it. Otherwise it\n\t\t\t * will be bound the whole time the connection remains\n\t\t\t * open.\n\t\t\t */\n\t\t\tlws_set_timeout(wsi, PENDING_TIMEOUT_HOLDING_AH,\n\t\t\t\t\twsi-\u003evhost-\u003ekeepalive_timeout);\n\t\t}\n\t\t/* If we're (re)starting on headers, need other implied init */\n\t\tif (wsi-\u003ehttp.ah)\n\t\t\twsi-\u003ehttp.ah-\u003eues \u003d URIES_IDLE;\n\n\t\t//lwsi_set_state(wsi, LRS_ESTABLISHED);\n\t} else\n\t\tif (lws_buflist_next_segment_len(\u0026wsi-\u003ebuflist, NULL))\n\t\t\tif (lws_header_table_attach(wsi, 0))\n\t\t\t\tlwsl_debug(\u0022acquired ah\u005cn\u0022);\n\n\tlwsl_info(\u0022%s: %p: keep-alive await new transaction\u005cn\u0022, __func__, wsi);\n\tlws_callback_on_writable(wsi);\n\n\treturn 0;\n}\n\n/* if not a socket, it's a raw, non-ssl file descriptor */\n\nLWS_VISIBLE struct lws *\nlws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type,\n\t\t\t lws_sock_file_fd_type fd, const char *vh_prot_name,\n\t\t\t struct lws *parent)\n{\n\tstruct lws_context *context \u003d vh-\u003econtext;\n\tstruct lws *new_wsi;\n\tstruct lws_context_per_thread *pt;\n\tint n, ssl \u003d 0;\n\n#if defined(LWS_WITH_PEER_LIMITS)\n\tstruct lws_peer *peer \u003d NULL;\n\n\tif (type \u0026 LWS_ADOPT_SOCKET \u0026\u0026 !(type \u0026 LWS_ADOPT_WS_PARENTIO)) {\n\t\tpeer \u003d lws_get_or_create_peer(vh, fd.sockfd);\n\n\t\tif (peer \u0026\u0026 context-\u003eip_limit_wsi \u0026\u0026\n\t\t peer-\u003ecount_wsi \u003e\u003d context-\u003eip_limit_wsi) {\n\t\t\tlwsl_notice(\u0022Peer reached wsi limit %d\u005cn\u0022,\n\t\t\t\t\tcontext-\u003eip_limit_wsi);\n\t\t\tlws_stats_atomic_bump(context, \u0026context-\u003ept[0],\n\t\t\t\t\t LWSSTATS_C_PEER_LIMIT_WSI_DENIED, 1);\n\t\t\treturn NULL;\n\t\t}\n\t}\n#endif\n\n\tn \u003d -1;\n\tif (parent)\n\t\tn \u003d parent-\u003etsi;\n\tnew_wsi \u003d lws_create_new_server_wsi(vh, n);\n\tif (!new_wsi) {\n\t\tif (type \u0026 LWS_ADOPT_SOCKET \u0026\u0026 !(type \u0026 LWS_ADOPT_WS_PARENTIO))\n\t\t\tcompatible_close(fd.sockfd);\n\t\treturn NULL;\n\t}\n#if defined(LWS_WITH_PEER_LIMITS)\n\tif (peer)\n\t\tlws_peer_add_wsi(context, peer, new_wsi);\n#endif\n\tpt \u003d \u0026context-\u003ept[(int)new_wsi-\u003etsi];\n\tlws_stats_atomic_bump(context, pt, LWSSTATS_C_CONNECTIONS, 1);\n\n\tif (parent) {\n\t\tnew_wsi-\u003eparent \u003d parent;\n\t\tnew_wsi-\u003esibling_list \u003d parent-\u003echild_list;\n\t\tparent-\u003echild_list \u003d new_wsi;\n\n\t\tif (type \u0026 LWS_ADOPT_WS_PARENTIO)\n\t\t\tnew_wsi-\u003eparent_carries_io \u003d 1;\n\t}\n\n\tnew_wsi-\u003edesc \u003d fd;\n\n\tif (vh_prot_name) {\n\t\tnew_wsi-\u003eprotocol \u003d lws_vhost_name_to_protocol(new_wsi-\u003evhost,\n\t\t\t\t\t\t\t vh_prot_name);\n\t\tif (!new_wsi-\u003eprotocol) {\n\t\t\tlwsl_err(\u0022Protocol %s not enabled on vhost %s\u005cn\u0022,\n\t\t\t\t vh_prot_name, new_wsi-\u003evhost-\u003ename);\n\t\t\tgoto bail;\n\t\t}\n if (lws_ensure_user_space(new_wsi)) {\n lwsl_notice(\u0022OOM trying to get user_space\u005cn\u0022);\n\t\t\tgoto bail;\n }\n#if defined(LWS_ROLE_WS)\n if (type \u0026 LWS_ADOPT_WS_PARENTIO) {\n\t\t\tnew_wsi-\u003edesc.sockfd \u003d LWS_SOCK_INVALID;\n\t\t\tlwsl_debug(\u0022binding to %s\u005cn\u0022, new_wsi-\u003eprotocol-\u003ename);\n\t\t\tlws_bind_protocol(new_wsi, new_wsi-\u003eprotocol);\n\t\t\tlws_role_transition(new_wsi, LWSIFR_SERVER,\n\t\t\t\t\t LRS_ESTABLISHED, \u0026role_ops_ws);\n\t\t\t/* allocate the ws struct for the wsi */\n\t\t\tnew_wsi-\u003ews \u003d lws_zalloc(sizeof(*new_wsi-\u003ews), \u0022ws struct\u0022);\n\t\t\tif (!new_wsi-\u003ews) {\n\t\t\t\tlwsl_notice(\u0022OOM\u005cn\u0022);\n\t\t\t\tgoto bail;\n\t\t\t}\n\t\t\tlws_server_init_wsi_for_ws(new_wsi);\n\n\t\t\treturn new_wsi;\n }\n#endif\n\t} else\n#if defined(LWS_ROLE_H1)\n\t\tif (type \u0026 LWS_ADOPT_HTTP) {/* he will transition later */\n\t\t\tnew_wsi-\u003eprotocol \u003d\n\t\t\t\t\u0026vh-\u003eprotocols[vh-\u003edefault_protocol_index];\n\t\t\tnew_wsi-\u003erole_ops \u003d \u0026role_ops_h1;\n\t\t}\n\t\telse\n#endif\n\t\t{ /* this is the only time he will transition */\n\t\t\tlws_bind_protocol(new_wsi,\n\t\t\t\t\u0026vh-\u003eprotocols[vh-\u003eraw_protocol_index]);\n\t\t\tlws_role_transition(new_wsi, 0, LRS_ESTABLISHED,\n\t\t\t\t\t \u0026role_ops_raw_skt);\n\t\t}\n\n\tif (type \u0026 LWS_ADOPT_SOCKET) { /* socket desc */\n\t\tlwsl_debug(\u0022%s: new wsi %p, sockfd %d\u005cn\u0022, __func__, new_wsi,\n\t\t\t (int)(lws_intptr_t)fd.sockfd);\n#if !defined(LWS_WITH_ESP32)\n\t\tif (type \u0026 LWS_ADOPT_FLAG_UDP)\n\t\t\t/*\n\t\t\t * these can be \u003e128 bytes, so just alloc for UDP\n\t\t\t */\n\t\t\tnew_wsi-\u003eudp \u003d lws_malloc(sizeof(*new_wsi-\u003eudp),\n\t\t\t\t\t\t \u0022udp struct\u0022);\n#endif\n\n\t\tif (type \u0026 LWS_ADOPT_HTTP)\n\t\t\t/* the transport is accepted...\n\t\t\t * give him time to negotiate */\n\t\t\tlws_set_timeout(new_wsi,\n\t\t\t\t\tPENDING_TIMEOUT_ESTABLISH_WITH_SERVER,\n\t\t\t\t\tcontext-\u003etimeout_secs);\n\n\t} else /* file desc */\n\t\tlwsl_debug(\u0022%s: new wsi %p, filefd %d\u005cn\u0022, __func__, new_wsi,\n\t\t\t (int)(lws_intptr_t)fd.filefd);\n\n\t/*\n\t * A new connection was accepted. Give the user a chance to\n\t * set properties of the newly created wsi. There's no protocol\n\t * selected yet so we issue this to the vhosts's default protocol,\n\t * itself by default protocols[0]\n\t */\n\tn \u003d LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED;\n\tif (!(type \u0026 LWS_ADOPT_HTTP)) {\n\t\tif (!(type \u0026 LWS_ADOPT_SOCKET))\n\t\t\tn \u003d LWS_CALLBACK_RAW_ADOPT_FILE;\n\t\telse\n\t\t\tn \u003d LWS_CALLBACK_RAW_ADOPT;\n\t}\n\n\tif (!LWS_SSL_ENABLED(new_wsi-\u003evhost) || !(type \u0026 LWS_ADOPT_ALLOW_SSL) ||\n\t !(type \u0026 LWS_ADOPT_SOCKET)) {\n\t\t/* non-SSL */\n\t\tif (!(type \u0026 LWS_ADOPT_HTTP)) {\n\t\t\tif (!(type \u0026 LWS_ADOPT_SOCKET))\n\t\t\t\tlws_role_transition(new_wsi, 0, LRS_ESTABLISHED,\n\t\t\t\t\t\t \u0026role_ops_raw_file);\n\t\t\telse\n\t\t\t\tlws_role_transition(new_wsi, 0, LRS_ESTABLISHED,\n\t\t\t\t\t\t \u0026role_ops_raw_skt);\n\t\t}\n#if defined(LWS_ROLE_H1)\n\t\telse\n\t\t\tlws_role_transition(new_wsi, LWSIFR_SERVER,\n\t\t\t\t\t LRS_HEADERS, \u0026role_ops_h1);\n#endif\n\t} else {\n\t\t/* SSL */\n\t\tif (!(type \u0026 LWS_ADOPT_HTTP))\n\t\t\tlws_role_transition(new_wsi, 0, LRS_SSL_INIT,\n\t\t\t\t\t \u0026role_ops_raw_skt);\n#if defined(LWS_ROLE_H1)\n\t\telse\n\t\t\tlws_role_transition(new_wsi, LWSIFR_SERVER,\n\t\t\t\t\t LRS_SSL_INIT, \u0026role_ops_h1);\n#endif\n\t\tssl \u003d 1;\n\t}\n\n\tlwsl_debug(\u0022new wsi wsistate 0x%x\u005cn\u0022, new_wsi-\u003ewsistate);\n\n\tif (context-\u003eevent_loop_ops-\u003eaccept)\n\t\tcontext-\u003eevent_loop_ops-\u003eaccept(new_wsi);\n\n\tif (!ssl) {\n\t\tlws_pt_lock(pt, __func__);\n\t\tif (__insert_wsi_socket_into_fds(context, new_wsi)) {\n\t\t\tlws_pt_unlock(pt);\n\t\t\tlwsl_err(\u0022%s: fail inserting socket\u005cn\u0022, __func__);\n\t\t\tgoto fail;\n\t\t}\n\t\tlws_pt_unlock(pt);\n\t} else\n\t\tif (lws_server_socket_service_ssl(new_wsi, fd.sockfd)) {\n\t\t\tlwsl_info(\u0022%s: fail ssl negotiation\u005cn\u0022, __func__);\n\t\t\tgoto fail;\n\t\t}\n\n\t/*\n\t * by deferring callback to this point, after insertion to fds,\n\t * lws_callback_on_writable() can work from the callback\n\t */\n\tif ((new_wsi-\u003eprotocol-\u003ecallback)(\n\t\t\tnew_wsi, n, new_wsi-\u003euser_space, NULL, 0))\n\t\tgoto fail;\n\n\tif (type \u0026 LWS_ADOPT_HTTP) {\n\t\tif (!lws_header_table_attach(new_wsi, 0))\n\t\t\tlwsl_debug(\u0022Attached ah immediately\u005cn\u0022);\n\t\telse\n\t\t\tlwsl_info(\u0022%s: waiting for ah\u005cn\u0022, __func__);\n\t}\n\n\tlws_cancel_service_pt(new_wsi);\n\n\treturn new_wsi;\n\nfail:\n\tif (type \u0026 LWS_ADOPT_SOCKET)\n\t\tlws_close_free_wsi(new_wsi, LWS_CLOSE_STATUS_NOSTATUS, \u0022adopt skt fail\u0022);\n\n\treturn NULL;\n\nbail:\n lwsl_notice(\u0022%s: exiting on bail\u005cn\u0022, __func__);\n\tif (parent)\n\t\tparent-\u003echild_list \u003d new_wsi-\u003esibling_list;\n\tif (new_wsi-\u003euser_space)\n\t\tlws_free(new_wsi-\u003euser_space);\n\tlws_free(new_wsi);\n compatible_close(fd.sockfd);\n\n\treturn NULL;\n}\n\nLWS_VISIBLE struct lws *\nlws_adopt_socket_vhost(struct lws_vhost *vh, lws_sockfd_type accept_fd)\n{\n\tlws_sock_file_fd_type fd;\n\n\tfd.sockfd \u003d accept_fd;\n\treturn lws_adopt_descriptor_vhost(vh, LWS_ADOPT_SOCKET |\n\t\t\tLWS_ADOPT_HTTP | LWS_ADOPT_ALLOW_SSL, fd, NULL, NULL);\n}\n\nLWS_VISIBLE struct lws *\nlws_adopt_socket(struct lws_context *context, lws_sockfd_type accept_fd)\n{\n\treturn lws_adopt_socket_vhost(context-\u003evhost_list, accept_fd);\n}\n\n/* Common read-buffer adoption for lws_adopt_*_readbuf */\nstatic struct lws*\nadopt_socket_readbuf(struct lws *wsi, const char *readbuf, size_t len)\n{\n\tstruct lws_context_per_thread *pt;\n\tstruct lws_pollfd *pfd;\n\tint n;\n\n\tif (!wsi)\n\t\treturn NULL;\n\n\tif (!readbuf || len \u003d\u003d 0)\n\t\treturn wsi;\n\n\tif (wsi-\u003eposition_in_fds_table \u003d\u003d LWS_NO_FDS_POS)\n\t\treturn wsi;\n\n\tpt \u003d \u0026wsi-\u003econtext-\u003ept[(int)wsi-\u003etsi];\n\n\tn \u003d lws_buflist_append_segment(\u0026wsi-\u003ebuflist, (const uint8_t *)readbuf, len);\n\tif (n \u003c 0)\n\t\tgoto bail;\n\tif (n)\n\t\tlws_dll_lws_add_front(\u0026wsi-\u003edll_buflist, \u0026pt-\u003edll_head_buflist);\n\n\t/*\n\t * we can't process the initial read data until we can attach an ah.\n\t *\n\t * if one is available, get it and place the data in his ah rxbuf...\n\t * wsi with ah that have pending rxbuf get auto-POLLIN service.\n\t *\n\t * no autoservice because we didn't get a chance to attach the\n\t * readbuf data to wsi or ah yet, and we will do it next if we get\n\t * the ah.\n\t */\n\tif (wsi-\u003ehttp.ah || !lws_header_table_attach(wsi, 0)) {\n\n\t\tlwsl_notice(\u0022%s: calling service on readbuf ah\u005cn\u0022, __func__);\n\n\t\t/* unlike a normal connect, we have the headers already\n\t\t * (or the first part of them anyway).\n\t\t * libuv won't come back and service us without a network\n\t\t * event, so we need to do the header service right here.\n\t\t */\n\t\tpfd \u003d \u0026pt-\u003efds[wsi-\u003eposition_in_fds_table];\n\t\tpfd-\u003erevents |\u003d LWS_POLLIN;\n\t\tlwsl_err(\u0022%s: calling service\u005cn\u0022, __func__);\n\t\tif (lws_service_fd_tsi(wsi-\u003econtext, pfd, wsi-\u003etsi))\n\t\t\t/* service closed us */\n\t\t\treturn NULL;\n\n\t\treturn wsi;\n\t}\n\tlwsl_err(\u0022%s: deferring handling ah\u005cn\u0022, __func__);\n\n\treturn wsi;\n\nbail:\n\tlws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, \u0022adopt skt readbuf fail\u0022);\n\n\treturn NULL;\n}\n\nLWS_VISIBLE struct lws *\nlws_adopt_socket_readbuf(struct lws_context *context, lws_sockfd_type accept_fd,\n\t\t\t const char *readbuf, size_t len)\n{\n return adopt_socket_readbuf(lws_adopt_socket(context, accept_fd),\n \t\t\t readbuf, len);\n}\n\nLWS_VISIBLE struct lws *\nlws_adopt_socket_vhost_readbuf(struct lws_vhost *vhost,\n\t\t\t lws_sockfd_type accept_fd,\n\t\t\t const char *readbuf, size_t len)\n{\n return adopt_socket_readbuf(lws_adopt_socket_vhost(vhost, accept_fd),\n \t\t\t readbuf, len);\n}\n\nLWS_VISIBLE int\nlws_serve_http_file(struct lws *wsi, const char *file, const char *content_type,\n\t\t const char *other_headers, int other_headers_len)\n{\n\tstatic const char * const intermediates[] \u003d { \u0022private\u0022, \u0022public\u0022 };\n\tstruct lws_context *context \u003d lws_get_context(wsi);\n\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[(int)wsi-\u003etsi];\n#if defined(LWS_WITH_RANGES)\n\tstruct lws_range_parsing *rp \u003d \u0026wsi-\u003ehttp.range;\n#endif\n\tchar cache_control[50], *cc \u003d \u0022no-store\u0022;\n\tunsigned char *response \u003d pt-\u003eserv_buf + LWS_PRE;\n\tunsigned char *p \u003d response;\n\tunsigned char *end \u003d p + context-\u003ept_serv_buf_size - LWS_PRE;\n\tlws_filepos_t total_content_length;\n\tint ret \u003d 0, cclen \u003d 8, n \u003d HTTP_STATUS_OK;\n\tlws_fop_flags_t fflags \u003d LWS_O_RDONLY;\n#if defined(LWS_WITH_RANGES)\n\tint ranges;\n#endif\n\tconst struct lws_plat_file_ops *fops;\n\tconst char *vpath;\n\n\tif (wsi-\u003ehandling_404)\n\t\tn \u003d HTTP_STATUS_NOT_FOUND;\n\n\t/*\n\t * We either call the platform fops .open with first arg platform fops,\n\t * or we call fops_zip .open with first arg platform fops, and fops_zip\n\t * open will decide whether to switch to fops_zip or stay with fops_def.\n\t *\n\t * If wsi-\u003ehttp.fop_fd is already set, the caller already opened it\n\t */\n\tif (!wsi-\u003ehttp.fop_fd) {\n\t\tfops \u003d lws_vfs_select_fops(wsi-\u003econtext-\u003efops, file, \u0026vpath);\n\t\tfflags |\u003d lws_vfs_prepare_flags(wsi);\n\t\twsi-\u003ehttp.fop_fd \u003d fops-\u003eLWS_FOP_OPEN(wsi-\u003econtext-\u003efops,\n\t\t\t\t\t\t\tfile, vpath, \u0026fflags);\n\t\tif (!wsi-\u003ehttp.fop_fd) {\n\t\t\tlwsl_info(\u0022%s: Unable to open: '%s': errno %d\u005cn\u0022,\n\t\t\t\t __func__, file, errno);\n\t\t\tif (lws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND, NULL))\n\t\t\t\t\t\treturn -1;\n\t\t\treturn !wsi-\u003ehttp2_substream;\n\t\t}\n\t}\n\twsi-\u003ehttp.filelen \u003d lws_vfs_get_length(wsi-\u003ehttp.fop_fd);\n\ttotal_content_length \u003d wsi-\u003ehttp.filelen;\n\n#if defined(LWS_WITH_RANGES)\n\tranges \u003d lws_ranges_init(wsi, rp, wsi-\u003ehttp.filelen);\n\n\tlwsl_debug(\u0022Range count %d\u005cn\u0022, ranges);\n\t/*\n\t * no ranges -\u003e 200;\n\t * 1 range -\u003e 206 + Content-Type: normal; Content-Range;\n\t * more -\u003e 206 + Content-Type: multipart/byteranges\n\t * \t\tRepeat the true Content-Type in each multipart header\n\t * \t\talong with Content-Range\n\t */\n\tif (ranges \u003c 0) {\n\t\t/* it means he expressed a range in Range:, but it was illegal */\n\t\tlws_return_http_status(wsi, HTTP_STATUS_REQ_RANGE_NOT_SATISFIABLE,\n\t\t\t\t NULL);\n\t\tif (lws_http_transaction_completed(wsi))\n\t\t\treturn -1; /* \u003c0 means just hang up */\n\n\t\tlws_vfs_file_close(\u0026wsi-\u003ehttp.fop_fd);\n\n\t\treturn 0; /* \u003d\u003d 0 means we dealt with the transaction complete */\n\t}\n\tif (ranges)\n\t\tn \u003d HTTP_STATUS_PARTIAL_CONTENT;\n#endif\n\n\tif (lws_add_http_header_status(wsi, n, \u0026p, end))\n\t\treturn -1;\n\n\tif ((wsi-\u003ehttp.fop_fd-\u003eflags \u0026 (LWS_FOP_FLAG_COMPR_ACCEPTABLE_GZIP |\n\t\t LWS_FOP_FLAG_COMPR_IS_GZIP)) \u003d\u003d\n\t (LWS_FOP_FLAG_COMPR_ACCEPTABLE_GZIP | LWS_FOP_FLAG_COMPR_IS_GZIP)) {\n\t\tif (lws_add_http_header_by_token(wsi,\n\t\t\tWSI_TOKEN_HTTP_CONTENT_ENCODING,\n\t\t\t(unsigned char *)\u0022gzip\u0022, 4, \u0026p, end))\n\t\t\treturn -1;\n\t\tlwsl_info(\u0022file is being provided in gzip\u005cn\u0022);\n\t}\n\n\tif (\n#if defined(LWS_WITH_RANGES)\n\t ranges \u003c 2 \u0026\u0026\n#endif\n\t content_type \u0026\u0026 content_type[0])\n\t\tif (lws_add_http_header_by_token(wsi,\n\t\t\t\t\t\t WSI_TOKEN_HTTP_CONTENT_TYPE,\n\t\t\t\t\t\t (unsigned char *)content_type,\n\t\t\t\t\t\t (int)strlen(content_type),\n\t\t\t\t\t\t \u0026p, end))\n\t\t\treturn -1;\n\n#if defined(LWS_WITH_RANGES)\n\tif (ranges \u003e\u003d 2) { /* multipart byteranges */\n\t\tlws_strncpy(wsi-\u003ehttp.multipart_content_type, content_type,\n\t\t\tsizeof(wsi-\u003ehttp.multipart_content_type));\n\n\t\tif (lws_add_http_header_by_token(wsi,\n\t\t\t\t\t\t WSI_TOKEN_HTTP_CONTENT_TYPE,\n\t\t\t\t\t\t (unsigned char *)\n\t\t\t\t\t\t \u0022multipart/byteranges; \u0022\n\t\t\t\t\t\t \u0022boundary\u003d_lws\u0022,\n\t\t\t \t \t \t 20, \u0026p, end))\n\t\t\treturn -1;\n\n\t\t/*\n\t\t * our overall content length has to include\n\t\t *\n\t\t * - (n + 1) x \u0022_lws\u005cr\u005cn\u0022\n\t\t * - n x Content-Type: xxx/xxx\u005cr\u005cn\n\t\t * - n x Content-Range: bytes xxx-yyy/zzz\u005cr\u005cn\n\t\t * - n x /r/n\n\t\t * - the actual payloads (aggregated in rp-\u003eagg)\n\t\t *\n\t\t * Precompute it for the main response header\n\t\t */\n\n\t\ttotal_content_length \u003d (lws_filepos_t)rp-\u003eagg +\n\t\t\t\t 6 /* final _lws\u005cr\u005cn */;\n\n\t\tlws_ranges_reset(rp);\n\t\twhile (lws_ranges_next(rp)) {\n\t\t\tn \u003d lws_snprintf(cache_control, sizeof(cache_control),\n\t\t\t\t\t\u0022bytes %llu-%llu/%llu\u0022,\n\t\t\t\t\trp-\u003estart, rp-\u003eend, rp-\u003eextent);\n\n\t\t\ttotal_content_length +\u003d\n\t\t\t\t6 /* header _lws\u005cr\u005cn */ +\n\t\t\t\t/* Content-Type: xxx/xxx\u005cr\u005cn */\n\t\t\t\t14 + strlen(content_type) + 2 +\n\t\t\t\t/* Content-Range: xxxx\u005cr\u005cn */\n\t\t\t\t15 + n + 2 +\n\t\t\t\t2; /* /r/n */\n\t\t}\n\n\t\tlws_ranges_reset(rp);\n\t\tlws_ranges_next(rp);\n\t}\n\n\tif (ranges \u003d\u003d 1) {\n\t\ttotal_content_length \u003d (lws_filepos_t)rp-\u003eagg;\n\t\tn \u003d lws_snprintf(cache_control, sizeof(cache_control),\n\t\t\t\t \u0022bytes %llu-%llu/%llu\u0022,\n\t\t\t\t rp-\u003estart, rp-\u003eend, rp-\u003eextent);\n\n\t\tif (lws_add_http_header_by_token(wsi,\n\t\t\t\t\t\t WSI_TOKEN_HTTP_CONTENT_RANGE,\n\t\t\t\t\t\t (unsigned char *)cache_control,\n\t\t\t\t\t\t n, \u0026p, end))\n\t\t\treturn -1;\n\t}\n\n\twsi-\u003ehttp.range.inside \u003d 0;\n\n\tif (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_ACCEPT_RANGES,\n\t\t\t\t\t (unsigned char *)\u0022bytes\u0022, 5, \u0026p, end))\n\t\treturn -1;\n#endif\n\n\tif (!wsi-\u003ehttp2_substream) {\n\t\tif (!wsi-\u003esending_chunked) {\n\t\t\tif (lws_add_http_header_content_length(wsi,\n\t\t\t\t\t\ttotal_content_length,\n\t\t\t\t\t \u0026p, end))\n\t\t\t\treturn -1;\n\t\t} else {\n\t\t\tif (lws_add_http_header_by_token(wsi,\n\t\t\t\t\t\t WSI_TOKEN_HTTP_TRANSFER_ENCODING,\n\t\t\t\t\t\t (unsigned char *)\u0022chunked\u0022,\n\t\t\t\t\t\t 7, \u0026p, end))\n\t\t\t\treturn -1;\n\t\t}\n\t}\n\n\tif (wsi-\u003ecache_secs \u0026\u0026 wsi-\u003ecache_reuse) {\n\t\tif (wsi-\u003ecache_revalidate) {\n\t\t\tcc \u003d cache_control;\n\t\t\tcclen \u003d sprintf(cache_control, \u0022%s max-age: %u\u0022,\n\t\t\t\t intermediates[wsi-\u003ecache_intermediaries],\n\t\t\t\t wsi-\u003ecache_secs);\n\t\t} else {\n\t\t\tcc \u003d \u0022no-cache\u0022;\n\t\t\tcclen \u003d 8;\n\t\t}\n\t}\n\n\tif (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CACHE_CONTROL,\n\t\t\t(unsigned char *)cc, cclen, \u0026p, end))\n\t\treturn -1;\n\n\tif (wsi-\u003ehttp.connection_type \u003d\u003d HTTP_CONNECTION_KEEP_ALIVE)\n\t\tif (lws_add_http_header_by_token(wsi, WSI_TOKEN_CONNECTION,\n\t\t\t\t(unsigned char *)\u0022keep-alive\u0022, 10, \u0026p, end))\n\t\t\treturn -1;\n\n\tif (other_headers) {\n\t\tif ((end - p) \u003c other_headers_len)\n\t\t\treturn -1;\n\t\tmemcpy(p, other_headers, other_headers_len);\n\t\tp +\u003d other_headers_len;\n\t}\n\n\tif (lws_finalize_http_header(wsi, \u0026p, end))\n\t\treturn -1;\n\n\tret \u003d lws_write(wsi, response, p - response, LWS_WRITE_HTTP_HEADERS);\n\tif (ret !\u003d (p - response)) {\n\t\tlwsl_err(\u0022_write returned %d from %ld\u005cn\u0022, ret,\n\t\t\t (long)(p - response));\n\t\treturn -1;\n\t}\n\n\twsi-\u003ehttp.filepos \u003d 0;\n\tlwsi_set_state(wsi, LRS_ISSUING_FILE);\n\n\tlws_callback_on_writable(wsi);\n\n\treturn 0;\n}\n\nLWS_VISIBLE int lws_serve_http_file_fragment(struct lws *wsi)\n{\n\tstruct lws_context *context \u003d wsi-\u003econtext;\n\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[(int)wsi-\u003etsi];\n\tstruct lws_process_html_args args;\n\tlws_filepos_t amount, poss;\n\tunsigned char *p, *pstart;\n#if defined(LWS_WITH_RANGES)\n\tunsigned char finished \u003d 0;\n#endif\n\tint n, m;\n\n\tlwsl_debug(\u0022wsi-\u003ehttp2_substream %d\u005cn\u0022, wsi-\u003ehttp2_substream);\n\n\tdo {\n\n\t\tif (wsi-\u003etrunc_len) {\n\t\t\tif (lws_issue_raw(wsi, wsi-\u003etrunc_alloc +\n\t\t\t\t\t wsi-\u003etrunc_offset,\n\t\t\t\t\t wsi-\u003etrunc_len) \u003c 0) {\n\t\t\t\tlwsl_info(\u0022%s: closing\u005cn\u0022, __func__);\n\t\t\t\tgoto file_had_it;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\tif (wsi-\u003ehttp.filepos \u003d\u003d wsi-\u003ehttp.filelen)\n\t\t\tgoto all_sent;\n\n\t\tn \u003d 0;\n\n\t\tpstart \u003d pt-\u003eserv_buf + LWS_H2_FRAME_HEADER_LENGTH;\n\n\t\tp \u003d pstart;\n\n#if defined(LWS_WITH_RANGES)\n\t\tif (wsi-\u003ehttp.range.count_ranges \u0026\u0026 !wsi-\u003ehttp.range.inside) {\n\n\t\t\tlwsl_notice(\u0022%s: doing range start %llu\u005cn\u0022, __func__,\n\t\t\t\t wsi-\u003ehttp.range.start);\n\n\t\t\tif ((long long)lws_vfs_file_seek_cur(wsi-\u003ehttp.fop_fd,\n\t\t\t\t\t\t wsi-\u003ehttp.range.start -\n\t\t\t\t\t\t wsi-\u003ehttp.filepos) \u003c 0)\n\t\t\t\tgoto file_had_it;\n\n\t\t\twsi-\u003ehttp.filepos \u003d wsi-\u003ehttp.range.start;\n\n\t\t\tif (wsi-\u003ehttp.range.count_ranges \u003e 1) {\n\t\t\t\tn \u003d lws_snprintf((char *)p,\n\t\t\t\t\t\tcontext-\u003ept_serv_buf_size -\n\t\t\t\t\t\tLWS_H2_FRAME_HEADER_LENGTH,\n\t\t\t\t\t\u0022_lws\u005cx0d\u005cx0a\u0022\n\t\t\t\t\t\u0022Content-Type: %s\u005cx0d\u005cx0a\u0022\n\t\t\t\t\t\u0022Content-Range: bytes %llu-%llu/%llu\u005cx0d\u005cx0a\u0022\n\t\t\t\t\t\u0022\u005cx0d\u005cx0a\u0022,\n\t\t\t\t\twsi-\u003ehttp.multipart_content_type,\n\t\t\t\t\twsi-\u003ehttp.range.start,\n\t\t\t\t\twsi-\u003ehttp.range.end,\n\t\t\t\t\twsi-\u003ehttp.range.extent);\n\t\t\t\tp +\u003d n;\n\t\t\t}\n\n\t\t\twsi-\u003ehttp.range.budget \u003d wsi-\u003ehttp.range.end -\n\t\t\t\t\t\t wsi-\u003ehttp.range.start + 1;\n\t\t\twsi-\u003ehttp.range.inside \u003d 1;\n\t\t}\n#endif\n\n\t\tposs \u003d context-\u003ept_serv_buf_size - n - LWS_H2_FRAME_HEADER_LENGTH;\n\n\t\tif (wsi-\u003ehttp.tx_content_length)\n\t\t\tif (poss \u003e wsi-\u003ehttp.tx_content_remain)\n\t\t\t\tposs \u003d wsi-\u003ehttp.tx_content_remain;\n\n\t\t/*\n\t\t * if there is a hint about how much we will do well to send at\n\t\t * one time, restrict ourselves to only trying to send that.\n\t\t */\n\t\tif (wsi-\u003eprotocol-\u003etx_packet_size \u0026\u0026\n\t\t poss \u003e wsi-\u003eprotocol-\u003etx_packet_size)\n\t\t\tposs \u003d wsi-\u003eprotocol-\u003etx_packet_size;\n\n\t\tif (wsi-\u003erole_ops-\u003etx_credit) {\n\t\t\tlws_filepos_t txc \u003d wsi-\u003erole_ops-\u003etx_credit(wsi);\n\n\t\t\tif (!txc) {\n\t\t\t\tlwsl_info(\u0022%s: came here with no tx credit\u005cn\u0022,\n\t\t\t\t\t\t__func__);\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tif (txc \u003c poss)\n\t\t\t\tposs \u003d txc;\n\n\t\t\t/*\n\t\t\t * consumption of the actual payload amount sent will be\n\t\t\t * handled when the role data frame is sent\n\t\t\t */\n\t\t}\n\n#if defined(LWS_WITH_RANGES)\n\t\tif (wsi-\u003ehttp.range.count_ranges) {\n\t\t\tif (wsi-\u003ehttp.range.count_ranges \u003e 1)\n\t\t\t\tposs -\u003d 7; /* allow for final boundary */\n\t\t\tif (poss \u003e wsi-\u003ehttp.range.budget)\n\t\t\t\tposs \u003d wsi-\u003ehttp.range.budget;\n\t\t}\n#endif\n\t\tif (wsi-\u003esending_chunked) {\n\t\t\t/* we need to drop the chunk size in here */\n\t\t\tp +\u003d 10;\n\t\t\t/* allow for the chunk to grow by 128 in translation */\n\t\t\tposs -\u003d 10 + 128;\n\t\t}\n\n\t\tif (lws_vfs_file_read(wsi-\u003ehttp.fop_fd, \u0026amount, p, poss) \u003c 0)\n\t\t\tgoto file_had_it; /* caller will close */\n\n\t\tif (wsi-\u003esending_chunked)\n\t\t\tn \u003d (int)amount;\n\t\telse\n\t\t\tn \u003d lws_ptr_diff(p, pstart) + (int)amount;\n\n\t\tlwsl_debug(\u0022%s: sending %d\u005cn\u0022, __func__, n);\n\n\t\tif (n) {\n\t\t\tlws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_CONTENT,\n\t\t\t\t\tcontext-\u003etimeout_secs);\n\n\t\t\tif (wsi-\u003einterpreting) {\n\t\t\t\targs.p \u003d (char *)p;\n\t\t\t\targs.len \u003d n;\n\t\t\t\targs.max_len \u003d (unsigned int)poss + 128;\n\t\t\t\targs.final \u003d wsi-\u003ehttp.filepos + n \u003d\u003d\n\t\t\t\t\t wsi-\u003ehttp.filelen;\n\t\t\t\targs.chunked \u003d wsi-\u003esending_chunked;\n\t\t\t\tif (user_callback_handle_rxflow(\n\t\t\t\t wsi-\u003evhost-\u003eprotocols[\n\t\t\t\t (int)wsi-\u003eprotocol_interpret_idx].callback,\n\t\t\t\t wsi, LWS_CALLBACK_PROCESS_HTML,\n\t\t\t\t wsi-\u003euser_space, \u0026args, 0) \u003c 0)\n\t\t\t\t\tgoto file_had_it;\n\t\t\t\tn \u003d args.len;\n\t\t\t\tp \u003d (unsigned char *)args.p;\n\t\t\t} else\n\t\t\t\tp \u003d pstart;\n\n#if defined(LWS_WITH_RANGES)\n\t\t\tif (wsi-\u003ehttp.range.send_ctr + 1 \u003d\u003d\n\t\t\t\twsi-\u003ehttp.range.count_ranges \u0026\u0026 // last range\n\t\t\t wsi-\u003ehttp.range.count_ranges \u003e 1 \u0026\u0026 // was 2+ ranges (ie, multipart)\n\t\t\t wsi-\u003ehttp.range.budget - amount \u003d\u003d 0) {// final part\n\t\t\t\tn +\u003d lws_snprintf((char *)pstart + n, 6,\n\t\t\t\t\t\u0022_lws\u005cx0d\u005cx0a\u0022); // append trailing boundary\n\t\t\t\tlwsl_debug(\u0022added trailing boundary\u005cn\u0022);\n\t\t\t}\n#endif\n\t\t\tm \u003d lws_write(wsi, p, n,\n\t\t\t\t wsi-\u003ehttp.filepos + amount \u003d\u003d wsi-\u003ehttp.filelen ?\n\t\t\t\t\tLWS_WRITE_HTTP_FINAL :\n\t\t\t\t\tLWS_WRITE_HTTP\n\t\t\t\t);\n\t\t\tif (m \u003c 0)\n\t\t\t\tgoto file_had_it;\n\n\t\t\twsi-\u003ehttp.filepos +\u003d amount;\n\n#if defined(LWS_WITH_RANGES)\n\t\t\tif (wsi-\u003ehttp.range.count_ranges \u003e\u003d 1) {\n\t\t\t\twsi-\u003ehttp.range.budget -\u003d amount;\n\t\t\t\tif (wsi-\u003ehttp.range.budget \u003d\u003d 0) {\n\t\t\t\t\tlwsl_notice(\u0022range budget exhausted\u005cn\u0022);\n\t\t\t\t\twsi-\u003ehttp.range.inside \u003d 0;\n\t\t\t\t\twsi-\u003ehttp.range.send_ctr++;\n\n\t\t\t\t\tif (lws_ranges_next(\u0026wsi-\u003ehttp.range) \u003c 1) {\n\t\t\t\t\t\tfinished \u003d 1;\n\t\t\t\t\t\tgoto all_sent;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n#endif\n\n\t\t\tif (m !\u003d n) {\n\t\t\t\t/* adjust for what was not sent */\n\t\t\t\tif (lws_vfs_file_seek_cur(wsi-\u003ehttp.fop_fd,\n\t\t\t\t\t\t\t m - n) \u003d\u003d\n\t\t\t\t\t\t\t (lws_fileofs_t)-1)\n\t\t\t\t\tgoto file_had_it;\n\t\t\t}\n\t\t}\n\nall_sent:\n\t\tif ((!wsi-\u003etrunc_len \u0026\u0026 wsi-\u003ehttp.filepos \u003e\u003d wsi-\u003ehttp.filelen)\n#if defined(LWS_WITH_RANGES)\n\t\t || finished)\n#else\n\t\t)\n#endif\n\t\t {\n\t\t\tlwsi_set_state(wsi, LRS_ESTABLISHED);\n\t\t\t/* we might be in keepalive, so close it off here */\n\t\t\tlws_vfs_file_close(\u0026wsi-\u003ehttp.fop_fd);\n\n\t\t\tlwsl_debug(\u0022file completed\u005cn\u0022);\n\n\t\t\tif (wsi-\u003eprotocol-\u003ecallback \u0026\u0026\n\t\t\t user_callback_handle_rxflow(wsi-\u003eprotocol-\u003ecallback,\n\t\t\t\t\t\t\twsi, LWS_CALLBACK_HTTP_FILE_COMPLETION,\n\t\t\t\t\t\t\twsi-\u003euser_space, NULL,\n\t\t\t\t\t\t\t0) \u003c 0) {\n\t\t\t\t\t/*\n\t\t\t\t\t * For http/1.x, the choices from\n\t\t\t\t\t * transaction_completed are either\n\t\t\t\t\t * 0 to use the connection for pipelined\n\t\t\t\t\t * or nonzero to hang it up.\n\t\t\t\t\t *\n\t\t\t\t\t * However for http/2. while we are\n\t\t\t\t\t * still interested in hanging up the\n\t\t\t\t\t * nwsi if there was a network-level\n\t\t\t\t\t * fatal error, simply completing the\n\t\t\t\t\t * transaction is a matter of the stream\n\t\t\t\t\t * state, not the root connection at the\n\t\t\t\t\t * network level\n\t\t\t\t\t */\n\t\t\t\t\tif (wsi-\u003ehttp2_substream)\n\t\t\t\t\t\treturn 1;\n\t\t\t\t\telse\n\t\t\t\t\t\treturn -1;\n\t\t\t\t}\n\n\t\t\treturn 1; /* \u003e0 indicates completed */\n\t\t}\n\t} while (0); // while (!lws_send_pipe_choked(wsi))\n\n\tlws_callback_on_writable(wsi);\n\n\treturn 0; /* indicates further processing must be done */\n\nfile_had_it:\n\tlws_vfs_file_close(\u0026wsi-\u003ehttp.fop_fd);\n\n\treturn -1;\n}\n\n\nLWS_VISIBLE void\nlws_server_get_canonical_hostname(struct lws_context *context,\n\t\t\t\t const struct lws_context_creation_info *info)\n{\n\tif (lws_check_opt(info-\u003eoptions,\n\t\t\tLWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME))\n\t\treturn;\n#if !defined(LWS_WITH_ESP32)\n\t/* find canonical hostname */\n\tgethostname((char *)context-\u003ecanonical_hostname,\n\t\t sizeof(context-\u003ecanonical_hostname) - 1);\n\n\tlwsl_info(\u0022 canonical_hostname \u003d %s\u005cn\u0022, context-\u003ecanonical_hostname);\n#else\n\t(void)context;\n#endif\n}\n\n\nLWS_VISIBLE LWS_EXTERN int\nlws_chunked_html_process(struct lws_process_html_args *args,\n\t\t\t struct lws_process_html_state *s)\n{\n\tchar *sp, buffer[32];\n\tconst char *pc;\n\tint old_len, n;\n\n\t/* do replacements */\n\tsp \u003d args-\u003ep;\n\told_len \u003d args-\u003elen;\n\targs-\u003elen \u003d 0;\n\ts-\u003estart \u003d sp;\n\twhile (sp \u003c args-\u003ep + old_len) {\n\n\t\tif (args-\u003elen + 7 \u003e\u003d args-\u003emax_len) {\n\t\t\tlwsl_err(\u0022Used up interpret padding\u005cn\u0022);\n\t\t\treturn -1;\n\t\t}\n\n\t\tif ((!s-\u003epos \u0026\u0026 *sp \u003d\u003d '$') || s-\u003epos) {\n\t\t\tint hits \u003d 0, hit \u003d 0;\n\n\t\t\tif (!s-\u003epos)\n\t\t\t\ts-\u003estart \u003d sp;\n\t\t\ts-\u003eswallow[s-\u003epos++] \u003d *sp;\n\t\t\tif (s-\u003epos \u003d\u003d sizeof(s-\u003eswallow) - 1)\n\t\t\t\tgoto skip;\n\t\t\tfor (n \u003d 0; n \u003c s-\u003ecount_vars; n++)\n\t\t\t\tif (!strncmp(s-\u003eswallow, s-\u003evars[n], s-\u003epos)) {\n\t\t\t\t\thits++;\n\t\t\t\t\thit \u003d n;\n\t\t\t\t}\n\t\t\tif (!hits) {\nskip:\n\t\t\t\ts-\u003eswallow[s-\u003epos] \u003d '\u005c0';\n\t\t\t\tmemcpy(s-\u003estart, s-\u003eswallow, s-\u003epos);\n\t\t\t\targs-\u003elen++;\n\t\t\t\ts-\u003epos \u003d 0;\n\t\t\t\tsp \u003d s-\u003estart + 1;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (hits \u003d\u003d 1 \u0026\u0026 s-\u003epos \u003d\u003d (int)strlen(s-\u003evars[hit])) {\n\t\t\t\tpc \u003d s-\u003ereplace(s-\u003edata, hit);\n\t\t\t\tif (!pc)\n\t\t\t\t\tpc \u003d \u0022NULL\u0022;\n\t\t\t\tn \u003d (int)strlen(pc);\n\t\t\t\ts-\u003eswallow[s-\u003epos] \u003d '\u005c0';\n\t\t\t\tif (n !\u003d s-\u003epos) {\n\t\t\t\t\tmemmove(s-\u003estart + n,\n\t\t\t\t\t\ts-\u003estart + s-\u003epos,\n\t\t\t\t\t\told_len - (sp - args-\u003ep));\n\t\t\t\t\told_len +\u003d (n - s-\u003epos) + 1;\n\t\t\t\t}\n\t\t\t\tmemcpy(s-\u003estart, pc, n);\n\t\t\t\targs-\u003elen++;\n\t\t\t\tsp \u003d s-\u003estart + 1;\n\n\t\t\t\ts-\u003epos \u003d 0;\n\t\t\t}\n\t\t\tsp++;\n\t\t\tcontinue;\n\t\t}\n\n\t\targs-\u003elen++;\n\t\tsp++;\n\t}\n\n\tif (args-\u003echunked) {\n\t\t/* no space left for final chunk trailer */\n\t\tif (args-\u003efinal \u0026\u0026 args-\u003elen + 7 \u003e\u003d args-\u003emax_len)\n\t\t\treturn -1;\n\n\t\tn \u003d sprintf(buffer, \u0022%X\u005cx0d\u005cx0a\u0022, args-\u003elen);\n\n\t\targs-\u003ep -\u003d n;\n\t\tmemcpy(args-\u003ep, buffer, n);\n\t\targs-\u003elen +\u003d n;\n\n\t\tif (args-\u003efinal) {\n\t\t\tsp \u003d args-\u003ep + args-\u003elen;\n\t\t\t*sp++ \u003d '\u005cx0d';\n\t\t\t*sp++ \u003d '\u005cx0a';\n\t\t\t*sp++ \u003d '0';\n\t\t\t*sp++ \u003d '\u005cx0d';\n\t\t\t*sp++ \u003d '\u005cx0a';\n\t\t\t*sp++ \u003d '\u005cx0d';\n\t\t\t*sp++ \u003d '\u005cx0a';\n\t\t\targs-\u003elen +\u003d 7;\n\t\t} else {\n\t\t\tsp \u003d args-\u003ep + args-\u003elen;\n\t\t\t*sp++ \u003d '\u005cx0d';\n\t\t\t*sp++ \u003d '\u005cx0a';\n\t\t\targs-\u003elen +\u003d 2;\n\t\t}\n\t}\n\n\treturn 0;\n}\n","s":{"c":1638107504,"u": 2323}} ],"g": 16382,"chitpc": 0,"ehitpc": 0,"indexed":0 , "ab": 1, "si": 0, "db":0, "di":0, "sat":0, "lfc": "0000"}